From: Erez_Zadok Date: Sun, 18 Nov 2007 03:33:46 +0000 (-0500) Subject: Unionfs: unionfs_lookup locking consistency X-Git-Url: https://git.fsl.cs.stonybrook.edu/?a=commitdiff_plain;h=cfbb71ecbe5ab3096ca5e33cc3396e57d5f224bb;p=unionfs-odf.git Unionfs: unionfs_lookup locking consistency Ensure that our lookup locking is consistent and symmetric: if a lock existed before calling lookup_backend, it should remain so; only if performing a lookup of a known new dentry, should lookup_backend return a newly-locked dentry-inode info (and only if there was no error). Document this behavior. This cleanup allowed us to remove two unnecessary int declarations. Signed-off-by: Erez Zadok --- diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c index eace05040c..2ebf7d8df8 100644 --- a/fs/unionfs/inode.c +++ b/fs/unionfs/inode.c @@ -151,7 +151,10 @@ static struct dentry *unionfs_lookup(struct inode *parent, path_save.mnt = nd->mnt; } - /* The locking is done by unionfs_lookup_backend. */ + /* + * unionfs_lookup_backend returns a locked dentry upon success, + * so we'll have to unlock it below. + */ ret = unionfs_lookup_backend(dentry, nd, INTERPOSE_LOOKUP); /* restore the dentry & vfsmnt in namei */ @@ -164,6 +167,7 @@ static struct dentry *unionfs_lookup(struct inode *parent, dentry = ret; /* parent times may have changed */ unionfs_copy_attr_times(dentry->d_parent->d_inode); + unionfs_unlock_dentry(dentry); } unionfs_check_inode(parent); diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c index e820c31c40..92f7f3b3d8 100644 --- a/fs/unionfs/lookup.c +++ b/fs/unionfs/lookup.c @@ -27,6 +27,11 @@ static int realloc_dentry_private_data(struct dentry *dentry); * * Returns: NULL (ok), ERR_PTR if an error occurred, or a non-null non-error * PTR if d_splice returned a different dentry. + * + * If lookupmode is INTERPOSE_PARTIAL/REVAL/REVAL_NEG, the passed dentry's + * inode info must be locked. If lookupmode is INTERPOSE_LOOKUP (i.e., a + * newly looked-up dentry), then unionfs_lookup_backend will return a locked + * dentry's info, which the caller must unlock. */ struct dentry *unionfs_lookup_backend(struct dentry *dentry, struct nameidata *nd, int lookupmode) @@ -43,8 +48,6 @@ struct dentry *unionfs_lookup_backend(struct dentry *dentry, struct dentry *first_lower_dentry = NULL; struct vfsmount *first_lower_mnt = NULL; int locked_parent = 0; - int locked_child = 0; - int allocated_new_info = 0; const char *name; int namelen; struct nameidata new_nd; @@ -57,24 +60,21 @@ struct dentry *unionfs_lookup_backend(struct dentry *dentry, if (lookupmode == INTERPOSE_PARTIAL || lookupmode == INTERPOSE_REVAL || lookupmode == INTERPOSE_REVAL_NEG) verify_locked(dentry); - else { + else /* this could only be INTERPOSE_LOOKUP */ BUG_ON(UNIONFS_D(dentry) != NULL); - locked_child = 1; - } - switch(lookupmode) { - case INTERPOSE_PARTIAL: - break; - case INTERPOSE_LOOKUP: - if ((err = new_dentry_private_data(dentry))) - goto out; - allocated_new_info = 1; - break; - default: - if ((err = realloc_dentry_private_data(dentry))) - goto out; - allocated_new_info = 1; - break; + switch (lookupmode) { + case INTERPOSE_PARTIAL: + break; + case INTERPOSE_LOOKUP: + if ((err = new_dentry_private_data(dentry))) + goto out; + break; + default: + /* default: can only be INTERPOSE_REVAL/REVAL_NEG */ + if ((err = realloc_dentry_private_data(dentry))) + goto out; + break; } /* must initialize dentry operations */ @@ -352,7 +352,7 @@ out: if (locked_parent) unionfs_unlock_dentry(parent_dentry); dput(parent_dentry); - if (locked_child || (err && allocated_new_info)) + if (err && (lookupmode == INTERPOSE_LOOKUP)) unionfs_unlock_dentry(dentry); if (!err && d_interposed) return d_interposed;