Commit be285c71 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher Committed by Al Viro

[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: default avatarAndreas Gruenbacher <agruen@suse.de>
Signed-off-by: default avatarJohn Johansen <jjohansen@suse.de>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
Acked-by: default avatarChristoph Hellwig <hch@infradead.org>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent f9f48ec7
...@@ -1782,6 +1782,7 @@ char *__d_path(const struct path *path, struct path *root, ...@@ -1782,6 +1782,7 @@ char *__d_path(const struct path *path, struct path *root,
char * end = buffer+buflen; char * end = buffer+buflen;
char * retval; char * retval;
spin_lock(&vfsmount_lock);
prepend(&end, &buflen, "\0", 1); prepend(&end, &buflen, "\0", 1);
if (!IS_ROOT(dentry) && d_unhashed(dentry) && if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
(prepend(&end, &buflen, " (deleted)", 10) != 0)) (prepend(&end, &buflen, " (deleted)", 10) != 0))
...@@ -1800,14 +1801,11 @@ char *__d_path(const struct path *path, struct path *root, ...@@ -1800,14 +1801,11 @@ char *__d_path(const struct path *path, struct path *root,
break; break;
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
/* Global root? */ /* Global root? */
spin_lock(&vfsmount_lock);
if (vfsmnt->mnt_parent == vfsmnt) { if (vfsmnt->mnt_parent == vfsmnt) {
spin_unlock(&vfsmount_lock);
goto global_root; goto global_root;
} }
dentry = vfsmnt->mnt_mountpoint; dentry = vfsmnt->mnt_mountpoint;
vfsmnt = vfsmnt->mnt_parent; vfsmnt = vfsmnt->mnt_parent;
spin_unlock(&vfsmount_lock);
continue; continue;
} }
parent = dentry->d_parent; parent = dentry->d_parent;
...@@ -1820,6 +1818,8 @@ char *__d_path(const struct path *path, struct path *root, ...@@ -1820,6 +1818,8 @@ char *__d_path(const struct path *path, struct path *root,
dentry = parent; dentry = parent;
} }
out:
spin_unlock(&vfsmount_lock);
return retval; return retval;
global_root: global_root:
...@@ -1829,9 +1829,11 @@ char *__d_path(const struct path *path, struct path *root, ...@@ -1829,9 +1829,11 @@ char *__d_path(const struct path *path, struct path *root,
goto Elong; goto Elong;
root->mnt = vfsmnt; root->mnt = vfsmnt;
root->dentry = dentry; root->dentry = dentry;
return retval; goto out;
Elong: Elong:
return ERR_PTR(-ENAMETOOLONG); retval = ERR_PTR(-ENAMETOOLONG);
goto out;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment