[dm-devel] dm thin: fix pool target flags that control discard

Mike Snitzer snitzer at redhat.com
Mon Mar 26 19:56:14 UTC 2012


On Mon, Mar 26 2012 at 11:33am -0400,
Mike Snitzer <snitzer at redhat.com> wrote:

> On Mon, Mar 26 2012 at 10:15am -0400,
> Joe Thornber <thornber at redhat.com> wrote:
> 
> > On Fri, Mar 23, 2012 at 05:55:02PM -0400, Mike Snitzer wrote:
> > > On Fri, Mar 23 2012 at  8:37am -0400,
> > > Alasdair G Kergon <agk at redhat.com> wrote:
> > > 
> > > > On Fri, Mar 16, 2012 at 03:22:34PM +0000, Joe Thornber wrote:
> > > > > +      'ignore_discard': disable discard support
> > > > > +      'no_discard_passdown': don't pass discards down to the underlying data device
> > > > 
> > > > If someone reloads the pool target changing either of these options, how do connected
> > > > thin targets pick up the change?  If they don't pick it up automatically, how do you
> > > > determine whether they did or didn't pick it up - is that internal state not
> > > > exposed to userspace yet?
> > > 
> > > Here are various fixes for dm_thin-add-pool-target-flags-to-control-discard.patch
> > > 
> > > o wire up 'discard_passdown' so that it does control whether or not the
> > >   discard is passed to the pool's underlying data device
> > 
> > This already works, see test_{enable,disable}_passdown() tests here:
> > 
> >   https://github.com/jthornber/thinp-test-suite/blob/master/discard_tests.rb
> > 
> > You've got to remember that there are 2 different interacting targets:
> > 
> >  i) discard enabled in the 'thin' target will cause mappings to be removed from the btree.
> > 
> >  ii) discard enabled in the 'pool' device will cause discards to be passed down.
> > 
> > The following logic is in the pool_ctr:
> > 
> >         if (pf.discard_enabled && pf.discard_passdown) {
> >                 ti->discards_supported = 1;
> >                 ti->num_discard_requests = 1;
> >         }
> 
> We reasoned through this already, your code did work.  But for the
> benefit of others this is why it worked:
> 
> thin will process_discard() via bio being deferring in thin_bio_map() --
> provided pf.discard_enabled.  Then thin will pass the discard on to the
> pool device regardless of pf.discard_passdown.  dm-core will then drop
> the discard because ti->num_discard_requests is 0; but that results in
> -EOPNOTSUPP.
> 
> Thing is, we don't want to return -EOPNOTSUPP if passdown was disabled.
> So I think my change is an improvement (because process_prepared_discard
> will now properly bio_endio(m->bio, 0) the discard).
> 
> > > o disallow disabling discards if a pool was already configured with
> > >   discards enabled (the default)
> > >   - justification is inlined in the code
> > >   - required pool_ctr knowing whether pool was created or not; so added
> > >     'created' flag to __pool_find()
> > 
> > ack, this needs fixing.
> 
> We've discussed that it is easier to just disallow changing discard
> configuration.  And that there was a bug in my early return.  So you'll
> be sending a follow-up fixup patch.

Here is a fixup patch that builds on what Alasdair already has staged
in dm_thin-add-pool-target-flags-to-control-discard.patch

I've added comments to help explain the subtlety of the initial thinp
discard code.

---
 drivers/md/dm-thin.c |   30 +++++++++++++++++++++++-------
 1 file changed, 23 insertions(+), 7 deletions(-)

Index: linux/drivers/md/dm-thin.c
===================================================================
--- linux.orig/drivers/md/dm-thin.c
+++ linux/drivers/md/dm-thin.c
@@ -1972,19 +1972,20 @@ static int pool_ctr(struct dm_target *ti
 
 	/*
 	 * 'pool_created' reflects whether this is the first table load.
-	 * Discard support is not allowed to be disabled after initial load.
-	 * Disabling it would require a pool reload to trigger thin device
-	 * changes (e.g. ti->discards_supported and QUEUE_FLAG_DISCARD).
+	 * Top level discard support is not allowed to be changed after
+	 * initial load.  This would require a pool reload to trigger thin
+	 * device changes.
 	 */
-	if (!pool_created && !pf.discard_enabled && pool->pf.discard_enabled) {
+	if (!pool_created && pf.discard_enabled != pool->pf.discard_enabled) {
 		ti->error = "Discard support cannot be disabled once enabled";
 		r = -EINVAL;
-		goto out_free_pt;
+		goto out_flags_changed;
 	}
 
 	/*
 	 * If discard_passdown was enabled verify that the data device
-	 * supports discards.  Disable discard_passdown if not.
+	 * supports discards.  Disable discard_passdown if not; otherwise
+	 * -EOPNOTSUPP will be returned.
 	 */
 	if (pf.discard_passdown) {
 		struct request_queue *q = bdev_get_queue(data_dev->bdev);
@@ -2001,8 +2002,18 @@ static int pool_ctr(struct dm_target *ti
 	pt->low_water_blocks = low_water_blocks;
 	pt->pf = pf;
 	ti->num_flush_requests = 1;
-	if (pf.discard_enabled) {
+	/*
+	 * Only need to enable discards if the pool should pass
+	 * them down to the data device.  The thin device's discard
+	 * processing will cause mappings to be removed from the btree.
+	 */
+	if (pf.discard_enabled && pf.discard_passdown) {
 		ti->num_discard_requests = 1;
+		/*
+		 * Setting 'discards_supported' circumvents the normal
+		 * stacking of discard limits (this keeps the pool and
+		 * thin devices' discard limits consistent).
+		 */
 		ti->discards_supported = 1;
 	}
 	ti->private = pt;
@@ -2014,6 +2025,8 @@ static int pool_ctr(struct dm_target *ti
 
 	return 0;
 
+out_flags_changed:
+	__pool_dec(pool);
 out_free_pt:
 	kfree(pt);
 out:
@@ -2408,6 +2421,9 @@ static int pool_merge(struct dm_target *
 
 static void set_discard_limits(struct pool *pool, struct queue_limits *limits)
 {
+	/*
+	 * FIXME: these limits may be incompatible with the pool's data device
+	 */
 	limits->max_discard_sectors = pool->sectors_per_block;
 
 	/*




More information about the dm-devel mailing list