Changeset View
Changeset View
Standalone View
Standalone View
sys/contrib/openzfs/module/os/linux/zfs/vdev_disk.c
Show First 20 Lines • Show All 344 Lines • ▼ Show 20 Lines | vdev_disk_close(vdev_t *v) | ||||
rw_destroy(&vd->vd_lock); | rw_destroy(&vd->vd_lock); | ||||
kmem_free(vd, sizeof (vdev_disk_t)); | kmem_free(vd, sizeof (vdev_disk_t)); | ||||
v->vdev_tsd = NULL; | v->vdev_tsd = NULL; | ||||
} | } | ||||
static dio_request_t * | static dio_request_t * | ||||
vdev_disk_dio_alloc(int bio_count) | vdev_disk_dio_alloc(int bio_count) | ||||
{ | { | ||||
dio_request_t *dr; | dio_request_t *dr = kmem_zalloc(sizeof (dio_request_t) + | ||||
int i; | |||||
dr = kmem_zalloc(sizeof (dio_request_t) + | |||||
sizeof (struct bio *) * bio_count, KM_SLEEP); | sizeof (struct bio *) * bio_count, KM_SLEEP); | ||||
if (dr) { | |||||
atomic_set(&dr->dr_ref, 0); | atomic_set(&dr->dr_ref, 0); | ||||
dr->dr_bio_count = bio_count; | dr->dr_bio_count = bio_count; | ||||
dr->dr_error = 0; | dr->dr_error = 0; | ||||
for (i = 0; i < dr->dr_bio_count; i++) | for (int i = 0; i < dr->dr_bio_count; i++) | ||||
dr->dr_bio[i] = NULL; | dr->dr_bio[i] = NULL; | ||||
} | |||||
return (dr); | return (dr); | ||||
} | } | ||||
static void | static void | ||||
vdev_disk_dio_free(dio_request_t *dr) | vdev_disk_dio_free(dio_request_t *dr) | ||||
{ | { | ||||
int i; | int i; | ||||
▲ Show 20 Lines • Show All 157 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
__vdev_disk_physio(struct block_device *bdev, zio_t *zio, | __vdev_disk_physio(struct block_device *bdev, zio_t *zio, | ||||
size_t io_size, uint64_t io_offset, int rw, int flags) | size_t io_size, uint64_t io_offset, int rw, int flags) | ||||
{ | { | ||||
dio_request_t *dr; | dio_request_t *dr; | ||||
uint64_t abd_offset; | uint64_t abd_offset; | ||||
uint64_t bio_offset; | uint64_t bio_offset; | ||||
int bio_size, bio_count = 16; | int bio_size; | ||||
int i = 0, error = 0; | int bio_count = 16; | ||||
int error = 0; | |||||
struct blk_plug plug; | struct blk_plug plug; | ||||
/* | /* | ||||
* Accessing outside the block device is never allowed. | * Accessing outside the block device is never allowed. | ||||
*/ | */ | ||||
if (io_offset + io_size > bdev->bd_inode->i_size) { | if (io_offset + io_size > bdev->bd_inode->i_size) { | ||||
vdev_dbgmsg(zio->io_vd, | vdev_dbgmsg(zio->io_vd, | ||||
"Illegal access %llu size %llu, device size %llu", | "Illegal access %llu size %llu, device size %llu", | ||||
io_offset, io_size, i_size_read(bdev->bd_inode)); | io_offset, io_size, i_size_read(bdev->bd_inode)); | ||||
return (SET_ERROR(EIO)); | return (SET_ERROR(EIO)); | ||||
} | } | ||||
retry: | retry: | ||||
dr = vdev_disk_dio_alloc(bio_count); | dr = vdev_disk_dio_alloc(bio_count); | ||||
if (dr == NULL) | |||||
return (SET_ERROR(ENOMEM)); | |||||
if (zio && !(zio->io_flags & (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD))) | if (zio && !(zio->io_flags & (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD))) | ||||
bio_set_flags_failfast(bdev, &flags); | bio_set_flags_failfast(bdev, &flags); | ||||
dr->dr_zio = zio; | dr->dr_zio = zio; | ||||
/* | /* | ||||
* When the IO size exceeds the maximum bio size for the request | * Since bio's can have up to BIO_MAX_PAGES=256 iovec's, each of which | ||||
* queue we are forced to break the IO in multiple bio's and wait | * is at least 512 bytes and at most PAGESIZE (typically 4K), one bio | ||||
* for them all to complete. Ideally, all pool users will set | * can cover at least 128KB and at most 1MB. When the required number | ||||
* their volume block size to match the maximum request size and | * of iovec's exceeds this, we are forced to break the IO in multiple | ||||
* the common case will be one bio per vdev IO request. | * bio's and wait for them all to complete. This is likely if the | ||||
* recordsize property is increased beyond 1MB. The default | |||||
* bio_count=16 should typically accommodate the maximum-size zio of | |||||
* 16MB. | |||||
*/ | */ | ||||
abd_offset = 0; | abd_offset = 0; | ||||
bio_offset = io_offset; | bio_offset = io_offset; | ||||
bio_size = io_size; | bio_size = io_size; | ||||
for (i = 0; i <= dr->dr_bio_count; i++) { | for (int i = 0; i <= dr->dr_bio_count; i++) { | ||||
/* Finished constructing bio's for given buffer */ | /* Finished constructing bio's for given buffer */ | ||||
if (bio_size <= 0) | if (bio_size <= 0) | ||||
break; | break; | ||||
/* | /* | ||||
* By default only 'bio_count' bio's per dio are allowed. | * If additional bio's are required, we have to retry, but | ||||
* However, if we find ourselves in a situation where more | * this should be rare - see the comment above. | ||||
* are needed we allocate a larger dio and warn the user. | |||||
*/ | */ | ||||
if (dr->dr_bio_count == i) { | if (dr->dr_bio_count == i) { | ||||
vdev_disk_dio_free(dr); | vdev_disk_dio_free(dr); | ||||
bio_count *= 2; | bio_count *= 2; | ||||
goto retry; | goto retry; | ||||
} | } | ||||
/* bio_alloc() with __GFP_WAIT never returns NULL */ | /* bio_alloc() with __GFP_WAIT never returns NULL */ | ||||
Show All 25 Lines | retry: | ||||
/* Extra reference to protect dio_request during vdev_submit_bio */ | /* Extra reference to protect dio_request during vdev_submit_bio */ | ||||
vdev_disk_dio_get(dr); | vdev_disk_dio_get(dr); | ||||
if (dr->dr_bio_count > 1) | if (dr->dr_bio_count > 1) | ||||
blk_start_plug(&plug); | blk_start_plug(&plug); | ||||
/* Submit all bio's associated with this dio */ | /* Submit all bio's associated with this dio */ | ||||
for (i = 0; i < dr->dr_bio_count; i++) | for (int i = 0; i < dr->dr_bio_count; i++) { | ||||
if (dr->dr_bio[i]) | if (dr->dr_bio[i]) | ||||
vdev_submit_bio(dr->dr_bio[i]); | vdev_submit_bio(dr->dr_bio[i]); | ||||
} | |||||
if (dr->dr_bio_count > 1) | if (dr->dr_bio_count > 1) | ||||
blk_finish_plug(&plug); | blk_finish_plug(&plug); | ||||
(void) vdev_disk_dio_put(dr); | (void) vdev_disk_dio_put(dr); | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 287 Lines • Show Last 20 Lines |