summary refs log tree commit diff
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@suse.de>2008-06-16 13:28:07 +0200
committerAl Viro <viro@zeniv.linux.org.uk>2008-06-23 13:06:13 -0400
commitbe285c712bbbe5db43e503782fbef2bfeaa345f9 (patch)
tree3143d1d4c49c68ebb59815d03a5c79e9e3290a91 /fs/dcache.c
parentf9f48ec72bfc9489a30bc6ddbfcf27d86a8bc651 (diff)
downloadlinux-be285c712bbbe5db43e503782fbef2bfeaa345f9.tar.gz
[patch 3/3] vfs: make d_path() consistent across mount operations
The path that __d_path() computes can become slightly inconsistent when it
races with mount operations: it grabs the vfsmount_lock when traversing mount
points but immediately drops it again, only to re-grab it when it reaches the
next mount point.  The result is that the filename computed is not always
consisent, and the file may never have had that name. (This is unlikely, but
still possible.)

Fix this by grabbing the vfsmount_lock for the whole duration of
__d_path().

Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Acked-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index c4c9072d810c..2b479de10a0a 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1782,6 +1782,7 @@ char *__d_path(const struct path *path, struct path *root,
 	char * end = buffer+buflen;
 	char * retval;
 
+	spin_lock(&vfsmount_lock);
 	prepend(&end, &buflen, "\0", 1);
 	if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
 		(prepend(&end, &buflen, " (deleted)", 10) != 0))
@@ -1800,14 +1801,11 @@ char *__d_path(const struct path *path, struct path *root,
 			break;
 		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
 			/* Global root? */
-			spin_lock(&vfsmount_lock);
 			if (vfsmnt->mnt_parent == vfsmnt) {
-				spin_unlock(&vfsmount_lock);
 				goto global_root;
 			}
 			dentry = vfsmnt->mnt_mountpoint;
 			vfsmnt = vfsmnt->mnt_parent;
-			spin_unlock(&vfsmount_lock);
 			continue;
 		}
 		parent = dentry->d_parent;
@@ -1820,6 +1818,8 @@ char *__d_path(const struct path *path, struct path *root,
 		dentry = parent;
 	}
 
+out:
+	spin_unlock(&vfsmount_lock);
 	return retval;
 
 global_root:
@@ -1829,9 +1829,11 @@ global_root:
 		goto Elong;
 	root->mnt = vfsmnt;
 	root->dentry = dentry;
-	return retval;
+	goto out;
+
 Elong:
-	return ERR_PTR(-ENAMETOOLONG);
+	retval = ERR_PTR(-ENAMETOOLONG);
+	goto out;
 }
 
 /**