diff options
author | Chunwei Chen <[email protected]> | 2015-12-08 12:37:24 -0800 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2015-12-15 16:21:43 -0800 |
commit | 2727b9d3b63a938c1797d31378e6a5a1dcd43573 (patch) | |
tree | f85bd88b0ab3c09fecf27f39af6e736f8ae20815 | |
parent | 502923bb447cdf4f9bc1271a46dfc11d5e0f2e9b (diff) |
Use uio for zvol_{read,write}
Since uio now supports bvec, we can convert bio into uio and reuse
dmu_{read,write}_uio. This way, we can remove some duplicate code.
Signed-off-by: Chunwei Chen <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Closes #4078
-rw-r--r-- | include/linux/blkdev_compat.h | 2 | ||||
-rw-r--r-- | include/sys/dmu.h | 3 | ||||
-rw-r--r-- | module/zfs/dmu.c | 164 | ||||
-rw-r--r-- | module/zfs/zvol.c | 27 |
4 files changed, 24 insertions, 172 deletions
diff --git a/include/linux/blkdev_compat.h b/include/linux/blkdev_compat.h index 868b89c55..0cb07207e 100644 --- a/include/linux/blkdev_compat.h +++ b/include/linux/blkdev_compat.h @@ -118,6 +118,7 @@ get_disk_ro(struct gendisk *disk) #define BIO_BI_SECTOR(bio) (bio)->bi_iter.bi_sector #define BIO_BI_SIZE(bio) (bio)->bi_iter.bi_size #define BIO_BI_IDX(bio) (bio)->bi_iter.bi_idx +#define BIO_BI_SKIP(bio) (bio)->bi_iter.bi_bvec_done #define bio_for_each_segment4(bv, bvp, b, i) \ bio_for_each_segment((bv), (b), (i)) typedef struct bvec_iter bvec_iterator_t; @@ -125,6 +126,7 @@ typedef struct bvec_iter bvec_iterator_t; #define BIO_BI_SECTOR(bio) (bio)->bi_sector #define BIO_BI_SIZE(bio) (bio)->bi_size #define BIO_BI_IDX(bio) (bio)->bi_idx +#define BIO_BI_SKIP(bio) (0) #define bio_for_each_segment4(bv, bvp, b, i) \ bio_for_each_segment((bvp), (b), (i)) typedef int bvec_iterator_t; diff --git a/include/sys/dmu.h b/include/sys/dmu.h index d9434db46..6bf51975e 100644 --- a/include/sys/dmu.h +++ b/include/sys/dmu.h @@ -710,9 +710,6 @@ void dmu_prealloc(objset_t *os, uint64_t object, uint64_t offset, uint64_t size, dmu_tx_t *tx); #ifdef _KERNEL #include <linux/blkdev_compat.h> -int dmu_read_bio(objset_t *os, uint64_t object, struct bio *bio); -int dmu_write_bio(objset_t *os, uint64_t object, struct bio *bio, - dmu_tx_t *tx); int dmu_read_uio(objset_t *os, uint64_t object, struct uio *uio, uint64_t size); int dmu_read_uio_dbuf(dmu_buf_t *zdb, struct uio *uio, uint64_t size); int dmu_write_uio(objset_t *os, uint64_t object, struct uio *uio, uint64_t size, diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index 5e2a1db60..f4027af9c 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -1041,170 +1041,6 @@ xuio_stat_wbuf_nocopy() } #ifdef _KERNEL - -/* - * Copy up to size bytes between arg_buf and req based on the data direction - * described by the req. If an entire req's data cannot be transfered in one - * pass, you should pass in @req_offset to indicate where to continue. The - * return value is the number of bytes successfully copied to arg_buf. - */ -static int -dmu_bio_copy(void *arg_buf, int size, struct bio *bio, size_t bio_offset) -{ - struct bio_vec bv, *bvp = &bv; - bvec_iterator_t iter; - char *bv_buf; - int tocpy, bv_len, bv_offset; - int offset = 0; - - bio_for_each_segment4(bv, bvp, bio, iter) { - - /* - * Fully consumed the passed arg_buf. We use goto here because - * rq_for_each_segment is a double loop - */ - ASSERT3S(offset, <=, size); - if (size == offset) - goto out; - - /* Skip already copied bvp */ - if (bio_offset >= bvp->bv_len) { - bio_offset -= bvp->bv_len; - continue; - } - - bv_len = bvp->bv_len - bio_offset; - bv_offset = bvp->bv_offset + bio_offset; - bio_offset = 0; - - tocpy = MIN(bv_len, size - offset); - ASSERT3S(tocpy, >=, 0); - - bv_buf = page_address(bvp->bv_page) + bv_offset; - ASSERT3P(bv_buf, !=, NULL); - - if (bio_data_dir(bio) == WRITE) - memcpy(arg_buf + offset, bv_buf, tocpy); - else - memcpy(bv_buf, arg_buf + offset, tocpy); - - offset += tocpy; - } -out: - return (offset); -} - -int -dmu_read_bio(objset_t *os, uint64_t object, struct bio *bio) -{ - uint64_t offset = BIO_BI_SECTOR(bio) << 9; - uint64_t size = BIO_BI_SIZE(bio); - dmu_buf_t **dbp; - int numbufs, i, err; - size_t bio_offset; - - /* - * NB: we could do this block-at-a-time, but it's nice - * to be reading in parallel. - */ - err = dmu_buf_hold_array(os, object, offset, size, TRUE, FTAG, - &numbufs, &dbp); - if (err) - return (err); - - bio_offset = 0; - for (i = 0; i < numbufs; i++) { - uint64_t tocpy; - int64_t bufoff; - int didcpy; - dmu_buf_t *db = dbp[i]; - - bufoff = offset - db->db_offset; - ASSERT3S(bufoff, >=, 0); - - tocpy = MIN(db->db_size - bufoff, size); - if (tocpy == 0) - break; - - didcpy = dmu_bio_copy(db->db_data + bufoff, tocpy, bio, - bio_offset); - - if (didcpy < tocpy) - err = EIO; - - if (err) - break; - - size -= tocpy; - offset += didcpy; - bio_offset += didcpy; - err = 0; - } - dmu_buf_rele_array(dbp, numbufs, FTAG); - - return (err); -} - -int -dmu_write_bio(objset_t *os, uint64_t object, struct bio *bio, dmu_tx_t *tx) -{ - uint64_t offset = BIO_BI_SECTOR(bio) << 9; - uint64_t size = BIO_BI_SIZE(bio); - dmu_buf_t **dbp; - int numbufs, i, err; - size_t bio_offset; - - if (size == 0) - return (0); - - err = dmu_buf_hold_array(os, object, offset, size, FALSE, FTAG, - &numbufs, &dbp); - if (err) - return (err); - - bio_offset = 0; - for (i = 0; i < numbufs; i++) { - uint64_t tocpy; - int64_t bufoff; - int didcpy; - dmu_buf_t *db = dbp[i]; - - bufoff = offset - db->db_offset; - ASSERT3S(bufoff, >=, 0); - - tocpy = MIN(db->db_size - bufoff, size); - if (tocpy == 0) - break; - - ASSERT(i == 0 || i == numbufs-1 || tocpy == db->db_size); - - if (tocpy == db->db_size) - dmu_buf_will_fill(db, tx); - else - dmu_buf_will_dirty(db, tx); - - didcpy = dmu_bio_copy(db->db_data + bufoff, tocpy, bio, - bio_offset); - - if (tocpy == db->db_size) - dmu_buf_fill_done(db, tx); - - if (didcpy < tocpy) - err = EIO; - - if (err) - break; - - size -= tocpy; - offset += didcpy; - bio_offset += didcpy; - err = 0; - } - - dmu_buf_rele_array(dbp, numbufs, FTAG); - return (err); -} - static int dmu_read_uio_dnode(dnode_t *dn, uio_t *uio, uint64_t size) { diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index 574d3c306..8208d29f3 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -597,6 +597,7 @@ zvol_write(struct bio *bio) int error = 0; dmu_tx_t *tx; rl_t *rl; + uio_t uio; if (bio->bi_rw & VDEV_REQ_FLUSH) zil_commit(zv->zv_zilog, ZVOL_OBJ); @@ -607,6 +608,14 @@ zvol_write(struct bio *bio) if (size == 0) goto out; + uio.uio_bvec = &bio->bi_io_vec[BIO_BI_IDX(bio)]; + uio.uio_skip = BIO_BI_SKIP(bio); + uio.uio_resid = size; + uio.uio_iovcnt = bio->bi_vcnt - BIO_BI_IDX(bio); + uio.uio_loffset = offset; + uio.uio_limit = MAXOFFSET_T; + uio.uio_segflg = UIO_BVEC; + rl = zfs_range_lock(&zv->zv_znode, offset, size, RL_WRITER); tx = dmu_tx_create(zv->zv_objset); @@ -620,7 +629,7 @@ zvol_write(struct bio *bio) goto out; } - error = dmu_write_bio(zv->zv_objset, ZVOL_OBJ, bio, tx); + error = dmu_write_uio(zv->zv_objset, ZVOL_OBJ, &uio, size, tx); if (error == 0) zvol_log_write(zv, tx, offset, size, !!(bio->bi_rw & VDEV_REQ_FUA)); @@ -686,17 +695,25 @@ zvol_read(struct bio *bio) { zvol_state_t *zv = bio->bi_bdev->bd_disk->private_data; uint64_t offset = BIO_BI_SECTOR(bio) << 9; - uint64_t len = BIO_BI_SIZE(bio); + uint64_t size = BIO_BI_SIZE(bio); int error; rl_t *rl; + uio_t uio; - if (len == 0) + if (size == 0) return (0); + uio.uio_bvec = &bio->bi_io_vec[BIO_BI_IDX(bio)]; + uio.uio_skip = BIO_BI_SKIP(bio); + uio.uio_resid = size; + uio.uio_iovcnt = bio->bi_vcnt - BIO_BI_IDX(bio); + uio.uio_loffset = offset; + uio.uio_limit = MAXOFFSET_T; + uio.uio_segflg = UIO_BVEC; - rl = zfs_range_lock(&zv->zv_znode, offset, len, RL_READER); + rl = zfs_range_lock(&zv->zv_znode, offset, size, RL_READER); - error = dmu_read_bio(zv->zv_objset, ZVOL_OBJ, bio); + error = dmu_read_uio(zv->zv_objset, ZVOL_OBJ, &uio, size); zfs_range_unlock(rl); |