diff --git a/dm-sflc/src/lite/flush.c b/dm-sflc/src/lite/flush.c index cac0922..25a1112 100644 --- a/dm-sflc/src/lite/flush.c +++ b/dm-sflc/src/lite/flush.c @@ -247,6 +247,7 @@ static int mark_posmap_blocks_clean(struct sflite_volume *svol) */ int sflite_flush_posmap(struct sflite_volume *svol, struct bio *orig_bio, gfp_t gfp) { + unsigned nblocks = svol->sdev->posmap_size_blocks; int err; /* To prepare the CWBs (encrypt all the `dirty` blocks from `entries` @@ -261,7 +262,7 @@ int sflite_flush_posmap(struct sflite_volume *svol, struct bio *orig_bio, gfp_t if (err) { // Clean up flush_pending: give up the FLUSH operation altogether DMWARN("FLUSH: could not prepare_cwbs(): error %d", err); - bitmap_clear(svol->posmap.flush_pending, 0, svol->sdev->posmap_size_blocks); + bitmap_clear(svol->posmap.flush_pending, 0, nblocks); } up_write(&svol->posmap.flush_lock); if (err) @@ -282,10 +283,10 @@ int sflite_flush_posmap(struct sflite_volume *svol, struct bio *orig_bio, gfp_t // Clean up and abort FLUSH operation. DMWARN("FLUSH: could not send_cwbs(): error %d", err); // All CWB callbacks have finished now, no locking needed - bitmap_clear(svol->posmap.cwb_error, 0, svol->sdev->posmap_size_blocks); + bitmap_clear(svol->posmap.cwb_error, 0, nblocks); // Need to clear this one under rwsem down_write(&svol->posmap.flush_lock); // Not killable, for simplicity - bitmap_clear(svol->posmap.flush_pending, 0, svol->sdev->posmap_size_blocks); + bitmap_clear(svol->posmap.flush_pending, 0, nblocks); up_write(&svol->posmap.flush_lock); goto out; } @@ -299,10 +300,10 @@ int sflite_flush_posmap(struct sflite_volume *svol, struct bio *orig_bio, gfp_t // Bummer, we got so far then the FLUSH failed. Clean up and abort. DMWARN("FLUSH: could not issue_lowlevel_flush(): error %d", err); // All CWB callbacks have finished now, no locking needed - bitmap_clear(svol->posmap.cwb_error, 0, svol->sdev->posmap_size_blocks); + bitmap_clear(svol->posmap.cwb_error, 0, nblocks); // Need to clear this one under rwsem down_write(&svol->posmap.flush_lock); // Not killable, for simplicity - bitmap_clear(svol->posmap.flush_pending, 0, svol->sdev->posmap_size_blocks); + bitmap_clear(svol->posmap.flush_pending, 0, nblocks); up_write(&svol->posmap.flush_lock); goto out; } @@ -312,7 +313,13 @@ int sflite_flush_posmap(struct sflite_volume *svol, struct bio *orig_bio, gfp_t * did not change while we were not holding the locks. * If some CWBs failed, we return an error (then failing the upper-layer * bio in the caller, if there is one), but that doesn't mean aborting - * entirely, because we can still mark some blocks as clean. */ + * entirely, because we can still mark some blocks as clean. + * Here, we need to lock. */ + down_write(&svol->posmap.flush_lock); // Not killable, for simplicity + err = mark_posmap_blocks_clean(svol); + bitmap_clear(svol->posmap.cwb_error, 0, nblocks); + bitmap_clear(svol->posmap.flush_pending, 0, nblocks); + up_write(&svol->posmap.flush_lock); out: if (orig_bio) { @@ -327,28 +334,16 @@ out: void sflite_flush_work_fn(struct work_struct *work) { struct sflite_io *io = container_of(work, struct sflite_io, work); - struct sflite_volume *svol = io->svol; - struct bio *orig_bio = io->orig_bio; - blk_status_t bi_status = BLK_STS_OK; int err; - // Mutual exclusion with WRITEs, not with READs - if (down_write_killable(&svol->posmap.flush_lock)) { - bi_status = BLK_STS_IOERR; - goto endio; - } - // Just flush the position map: this function sleeps. - err = sflite_flush_posmap(svol, GFP_NOIO); - if (err) { - DMERR("Could not flush position map; error %d", err); - bi_status = BLK_STS_IOERR; - } - up_write(&svol->posmap.flush_lock); - -endio: - // Signal FLUSH completion - orig_bio->bi_status = bi_status; - bio_endio(orig_bio); + /* Everything is implemented in flush_posmap(). + * As for non-reentrancy: the block layer guarantees that at most one + * FLUSH request is in-flight at any given time. The only other caller + * of flush_posmap is the volume dtr(), which cannot be invoked if the + * target is busy (e.g. I/O in flight) TODO double check */ + err = sflite_flush_posmap(io->svol, io->orig_bio, GFP_NOIO); + io->orig_bio->bi_status = errno_to_blk_status(err); + bio_endio(io->orig_bio); return;