[dm-devel] [PATCH 4.5 052/238] dm cache: make sure every metadata function checks fail_io

Mike Snitzer snitzer at redhat.com
Tue Apr 12 17:18:52 UTC 2016


On Mon, Apr 11 2016 at  9:27pm -0400,
Ben Hutchings <ben at decadent.org.uk> wrote:

> On Sun, 2016-04-10 at 11:33 -0700, Greg Kroah-Hartman wrote:
> > 4.5-stable review patch.  If anyone has any objections, please let me know.
> 
> I've dropped stable because this isn't actually broken, but...
> 
> > ------------------
> > 
> > From: Joe Thornber <ejt at redhat.com>
> > 
> > commit d14fcf3dd79c0b8a8d0ba469c44a6b04f3a1403b upstream.
> > 
> > Otherwise operations may be attempted that will only ever go on to crash
> > (since the metadata device is either missing or unreliable if 'fail_io'
> > is set).
> > 
> > Signed-off-by: Joe Thornber <ejt at redhat.com>
> > Signed-off-by: Mike Snitzer <snitzer at redhat.com>
> > Signed-off-by: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
> > 
> > ---
> >  drivers/md/dm-cache-metadata.c |   98 ++++++++++++++++++++++++-----------------
> >  drivers/md/dm-cache-metadata.h |    4 -
> >  drivers/md/dm-cache-target.c   |   12 ++++-
> >  3 files changed, 71 insertions(+), 43 deletions(-)
> > 
> > --- a/drivers/md/dm-cache-metadata.c
> > +++ b/drivers/md/dm-cache-metadata.c
> > @@ -867,19 +867,40 @@ static int blocks_are_unmapped_or_clean(
> >  	return 0;
> >  }
> >  
> > -#define WRITE_LOCK(cmd) \
> > -	if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) \
> > +#define WRITE_LOCK(cmd)	\
> > +	down_write(&cmd->root_lock); \
> > +	if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
> > +		up_write(&cmd->root_lock); \
> >  		return -EINVAL; \
> > -	down_write(&cmd->root_lock)
> > +	}
> >  
> >  #define WRITE_LOCK_VOID(cmd) \
> > -	if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) \
> > +	down_write(&cmd->root_lock); \
> > +	if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
> > +		up_write(&cmd->root_lock); \
> >  		return; \
> > -	down_write(&cmd->root_lock)
> > +	}
> 
> Whenever a macro expands to multiple statements they should be wrapped
> up in do { ... } while (0) so the macro is safe to use in other
> compound statements.
> 
> That's not a regression for these existing macros, but:
> 
> >  #define WRITE_UNLOCK(cmd) \
> >  	up_write(&cmd->root_lock)
> >  
> > +#define READ_LOCK(cmd) \
> > +	down_read(&cmd->root_lock); \
> > +	if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
> > +		up_read(&cmd->root_lock); \
> > +		return -EINVAL; \
> > +	}
> > +
> > +#define READ_LOCK_VOID(cmd)	\
> > +	down_read(&cmd->root_lock); \
> > +	if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
> > +		up_read(&cmd->root_lock); \
> > +		return; \
> > +	}
> [...]
> 
> here you're repeating the same broken pattern in new macros.  Which
> checkpatch.pl would have complained about, if you'd thought to run it.
> 
> Hiding return statements in macros is another bad idea (who expects
> exceptions in C?).  And once we reject that bad idea, all these macros
> can be inline functions, like:
> 
> static inline bool dm_cm_read_lock(struct dm_cache_metadata *cmd)
> {
> 	down_read(&cmd->root_lock);
> 	if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) {
> 		up_read(&cmd->root_lock);
> 		return false;
> 	}
> 	return true;
> }
> 
> /* ... */
> 
> 	if (!dm_cm_read_lock(cmd))
> 		return -EINVAL;
> 
> Actually... I said this wasn't broken, but should the READ_LOCK macros
> really fail in case dm_bm_is_read_only(), or only if cmd->fail_io?

Thanks for the report!

I've staged this to go to Linus by the end of the week:
https://git.kernel.org/cgit/linux/kernel/git/device-mapper/linux-dm.git/commit/?h=dm-4.6&id=a64204672859248c89c8df796421442fb41e59ec




More information about the dm-devel mailing list