|
@@ -20,7 +20,6 @@ struct dmz_bioctx {
|
|
struct dm_zone *zone;
|
|
struct dm_zone *zone;
|
|
struct bio *bio;
|
|
struct bio *bio;
|
|
refcount_t ref;
|
|
refcount_t ref;
|
|
- blk_status_t status;
|
|
|
|
};
|
|
};
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -78,65 +77,66 @@ static inline void dmz_bio_endio(struct bio *bio, blk_status_t status)
|
|
{
|
|
{
|
|
struct dmz_bioctx *bioctx = dm_per_bio_data(bio, sizeof(struct dmz_bioctx));
|
|
struct dmz_bioctx *bioctx = dm_per_bio_data(bio, sizeof(struct dmz_bioctx));
|
|
|
|
|
|
- if (bioctx->status == BLK_STS_OK && status != BLK_STS_OK)
|
|
|
|
- bioctx->status = status;
|
|
|
|
- bio_endio(bio);
|
|
|
|
|
|
+ if (status != BLK_STS_OK && bio->bi_status == BLK_STS_OK)
|
|
|
|
+ bio->bi_status = status;
|
|
|
|
+
|
|
|
|
+ if (refcount_dec_and_test(&bioctx->ref)) {
|
|
|
|
+ struct dm_zone *zone = bioctx->zone;
|
|
|
|
+
|
|
|
|
+ if (zone) {
|
|
|
|
+ if (bio->bi_status != BLK_STS_OK &&
|
|
|
|
+ bio_op(bio) == REQ_OP_WRITE &&
|
|
|
|
+ dmz_is_seq(zone))
|
|
|
|
+ set_bit(DMZ_SEQ_WRITE_ERR, &zone->flags);
|
|
|
|
+ dmz_deactivate_zone(zone);
|
|
|
|
+ }
|
|
|
|
+ bio_endio(bio);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Partial clone read BIO completion callback. This terminates the
|
|
|
|
|
|
+ * Completion callback for an internally cloned target BIO. This terminates the
|
|
* target BIO when there are no more references to its context.
|
|
* target BIO when there are no more references to its context.
|
|
*/
|
|
*/
|
|
-static void dmz_read_bio_end_io(struct bio *bio)
|
|
|
|
|
|
+static void dmz_clone_endio(struct bio *clone)
|
|
{
|
|
{
|
|
- struct dmz_bioctx *bioctx = bio->bi_private;
|
|
|
|
- blk_status_t status = bio->bi_status;
|
|
|
|
|
|
+ struct dmz_bioctx *bioctx = clone->bi_private;
|
|
|
|
+ blk_status_t status = clone->bi_status;
|
|
|
|
|
|
- bio_put(bio);
|
|
|
|
|
|
+ bio_put(clone);
|
|
dmz_bio_endio(bioctx->bio, status);
|
|
dmz_bio_endio(bioctx->bio, status);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Issue a BIO to a zone. The BIO may only partially process the
|
|
|
|
|
|
+ * Issue a clone of a target BIO. The clone may only partially process the
|
|
* original target BIO.
|
|
* original target BIO.
|
|
*/
|
|
*/
|
|
-static int dmz_submit_read_bio(struct dmz_target *dmz, struct dm_zone *zone,
|
|
|
|
- struct bio *bio, sector_t chunk_block,
|
|
|
|
- unsigned int nr_blocks)
|
|
|
|
|
|
+static int dmz_submit_bio(struct dmz_target *dmz, struct dm_zone *zone,
|
|
|
|
+ struct bio *bio, sector_t chunk_block,
|
|
|
|
+ unsigned int nr_blocks)
|
|
{
|
|
{
|
|
struct dmz_bioctx *bioctx = dm_per_bio_data(bio, sizeof(struct dmz_bioctx));
|
|
struct dmz_bioctx *bioctx = dm_per_bio_data(bio, sizeof(struct dmz_bioctx));
|
|
- sector_t sector;
|
|
|
|
struct bio *clone;
|
|
struct bio *clone;
|
|
|
|
|
|
- /* BIO remap sector */
|
|
|
|
- sector = dmz_start_sect(dmz->metadata, zone) + dmz_blk2sect(chunk_block);
|
|
|
|
-
|
|
|
|
- /* If the read is not partial, there is no need to clone the BIO */
|
|
|
|
- if (nr_blocks == dmz_bio_blocks(bio)) {
|
|
|
|
- /* Setup and submit the BIO */
|
|
|
|
- bio->bi_iter.bi_sector = sector;
|
|
|
|
- refcount_inc(&bioctx->ref);
|
|
|
|
- generic_make_request(bio);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Partial BIO: we need to clone the BIO */
|
|
|
|
clone = bio_clone_fast(bio, GFP_NOIO, &dmz->bio_set);
|
|
clone = bio_clone_fast(bio, GFP_NOIO, &dmz->bio_set);
|
|
if (!clone)
|
|
if (!clone)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
- /* Setup the clone */
|
|
|
|
- clone->bi_iter.bi_sector = sector;
|
|
|
|
|
|
+ bio_set_dev(clone, dmz->dev->bdev);
|
|
|
|
+ clone->bi_iter.bi_sector =
|
|
|
|
+ dmz_start_sect(dmz->metadata, zone) + dmz_blk2sect(chunk_block);
|
|
clone->bi_iter.bi_size = dmz_blk2sect(nr_blocks) << SECTOR_SHIFT;
|
|
clone->bi_iter.bi_size = dmz_blk2sect(nr_blocks) << SECTOR_SHIFT;
|
|
- clone->bi_end_io = dmz_read_bio_end_io;
|
|
|
|
|
|
+ clone->bi_end_io = dmz_clone_endio;
|
|
clone->bi_private = bioctx;
|
|
clone->bi_private = bioctx;
|
|
|
|
|
|
bio_advance(bio, clone->bi_iter.bi_size);
|
|
bio_advance(bio, clone->bi_iter.bi_size);
|
|
|
|
|
|
- /* Submit the clone */
|
|
|
|
refcount_inc(&bioctx->ref);
|
|
refcount_inc(&bioctx->ref);
|
|
generic_make_request(clone);
|
|
generic_make_request(clone);
|
|
|
|
|
|
|
|
+ if (bio_op(bio) == REQ_OP_WRITE && dmz_is_seq(zone))
|
|
|
|
+ zone->wp_block += nr_blocks;
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -214,7 +214,7 @@ static int dmz_handle_read(struct dmz_target *dmz, struct dm_zone *zone,
|
|
if (nr_blocks) {
|
|
if (nr_blocks) {
|
|
/* Valid blocks found: read them */
|
|
/* Valid blocks found: read them */
|
|
nr_blocks = min_t(unsigned int, nr_blocks, end_block - chunk_block);
|
|
nr_blocks = min_t(unsigned int, nr_blocks, end_block - chunk_block);
|
|
- ret = dmz_submit_read_bio(dmz, rzone, bio, chunk_block, nr_blocks);
|
|
|
|
|
|
+ ret = dmz_submit_bio(dmz, rzone, bio, chunk_block, nr_blocks);
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
chunk_block += nr_blocks;
|
|
chunk_block += nr_blocks;
|
|
@@ -228,25 +228,6 @@ static int dmz_handle_read(struct dmz_target *dmz, struct dm_zone *zone,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * Issue a write BIO to a zone.
|
|
|
|
- */
|
|
|
|
-static void dmz_submit_write_bio(struct dmz_target *dmz, struct dm_zone *zone,
|
|
|
|
- struct bio *bio, sector_t chunk_block,
|
|
|
|
- unsigned int nr_blocks)
|
|
|
|
-{
|
|
|
|
- struct dmz_bioctx *bioctx = dm_per_bio_data(bio, sizeof(struct dmz_bioctx));
|
|
|
|
-
|
|
|
|
- /* Setup and submit the BIO */
|
|
|
|
- bio_set_dev(bio, dmz->dev->bdev);
|
|
|
|
- bio->bi_iter.bi_sector = dmz_start_sect(dmz->metadata, zone) + dmz_blk2sect(chunk_block);
|
|
|
|
- refcount_inc(&bioctx->ref);
|
|
|
|
- generic_make_request(bio);
|
|
|
|
-
|
|
|
|
- if (dmz_is_seq(zone))
|
|
|
|
- zone->wp_block += nr_blocks;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* Write blocks directly in a data zone, at the write pointer.
|
|
* Write blocks directly in a data zone, at the write pointer.
|
|
* If a buffer zone is assigned, invalidate the blocks written
|
|
* If a buffer zone is assigned, invalidate the blocks written
|
|
@@ -265,7 +246,9 @@ static int dmz_handle_direct_write(struct dmz_target *dmz,
|
|
return -EROFS;
|
|
return -EROFS;
|
|
|
|
|
|
/* Submit write */
|
|
/* Submit write */
|
|
- dmz_submit_write_bio(dmz, zone, bio, chunk_block, nr_blocks);
|
|
|
|
|
|
+ ret = dmz_submit_bio(dmz, zone, bio, chunk_block, nr_blocks);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Validate the blocks in the data zone and invalidate
|
|
* Validate the blocks in the data zone and invalidate
|
|
@@ -301,7 +284,9 @@ static int dmz_handle_buffered_write(struct dmz_target *dmz,
|
|
return -EROFS;
|
|
return -EROFS;
|
|
|
|
|
|
/* Submit write */
|
|
/* Submit write */
|
|
- dmz_submit_write_bio(dmz, bzone, bio, chunk_block, nr_blocks);
|
|
|
|
|
|
+ ret = dmz_submit_bio(dmz, bzone, bio, chunk_block, nr_blocks);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Validate the blocks in the buffer zone
|
|
* Validate the blocks in the buffer zone
|
|
@@ -600,7 +585,6 @@ static int dmz_map(struct dm_target *ti, struct bio *bio)
|
|
bioctx->zone = NULL;
|
|
bioctx->zone = NULL;
|
|
bioctx->bio = bio;
|
|
bioctx->bio = bio;
|
|
refcount_set(&bioctx->ref, 1);
|
|
refcount_set(&bioctx->ref, 1);
|
|
- bioctx->status = BLK_STS_OK;
|
|
|
|
|
|
|
|
/* Set the BIO pending in the flush list */
|
|
/* Set the BIO pending in the flush list */
|
|
if (!nr_sectors && bio_op(bio) == REQ_OP_WRITE) {
|
|
if (!nr_sectors && bio_op(bio) == REQ_OP_WRITE) {
|
|
@@ -623,35 +607,6 @@ static int dmz_map(struct dm_target *ti, struct bio *bio)
|
|
return DM_MAPIO_SUBMITTED;
|
|
return DM_MAPIO_SUBMITTED;
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * Completed target BIO processing.
|
|
|
|
- */
|
|
|
|
-static int dmz_end_io(struct dm_target *ti, struct bio *bio, blk_status_t *error)
|
|
|
|
-{
|
|
|
|
- struct dmz_bioctx *bioctx = dm_per_bio_data(bio, sizeof(struct dmz_bioctx));
|
|
|
|
-
|
|
|
|
- if (bioctx->status == BLK_STS_OK && *error)
|
|
|
|
- bioctx->status = *error;
|
|
|
|
-
|
|
|
|
- if (!refcount_dec_and_test(&bioctx->ref))
|
|
|
|
- return DM_ENDIO_INCOMPLETE;
|
|
|
|
-
|
|
|
|
- /* Done */
|
|
|
|
- bio->bi_status = bioctx->status;
|
|
|
|
-
|
|
|
|
- if (bioctx->zone) {
|
|
|
|
- struct dm_zone *zone = bioctx->zone;
|
|
|
|
-
|
|
|
|
- if (*error && bio_op(bio) == REQ_OP_WRITE) {
|
|
|
|
- if (dmz_is_seq(zone))
|
|
|
|
- set_bit(DMZ_SEQ_WRITE_ERR, &zone->flags);
|
|
|
|
- }
|
|
|
|
- dmz_deactivate_zone(zone);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return DM_ENDIO_DONE;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* Get zoned device information.
|
|
* Get zoned device information.
|
|
*/
|
|
*/
|
|
@@ -946,7 +901,6 @@ static struct target_type dmz_type = {
|
|
.ctr = dmz_ctr,
|
|
.ctr = dmz_ctr,
|
|
.dtr = dmz_dtr,
|
|
.dtr = dmz_dtr,
|
|
.map = dmz_map,
|
|
.map = dmz_map,
|
|
- .end_io = dmz_end_io,
|
|
|
|
.io_hints = dmz_io_hints,
|
|
.io_hints = dmz_io_hints,
|
|
.prepare_ioctl = dmz_prepare_ioctl,
|
|
.prepare_ioctl = dmz_prepare_ioctl,
|
|
.postsuspend = dmz_suspend,
|
|
.postsuspend = dmz_suspend,
|