aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@suse.de>2008-06-16 07:28:07 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2008-06-23 13:06:13 -0400
commitbe285c712bbbe5db43e503782fbef2bfeaa345f9 (patch)
tree3143d1d4c49c68ebb59815d03a5c79e9e3290a91
parentf9f48ec72bfc9489a30bc6ddbfcf27d86a8bc651 (diff)
[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>
-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,
1782 char * end = buffer+buflen; 1782 char * end = buffer+buflen;
1783 char * retval; 1783 char * retval;
1784 1784
1785 spin_lock(&vfsmount_lock);
1785 prepend(&end, &buflen, "\0", 1); 1786 prepend(&end, &buflen, "\0", 1);
1786 if (!IS_ROOT(dentry) && d_unhashed(dentry) && 1787 if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
1787 (prepend(&end, &buflen, " (deleted)", 10) != 0)) 1788 (prepend(&end, &buflen, " (deleted)", 10) != 0))
@@ -1800,14 +1801,11 @@ char *__d_path(const struct path *path, struct path *root,
1800 break; 1801 break;
1801 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { 1802 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
1802 /* Global root? */ 1803 /* Global root? */
1803 spin_lock(&vfsmount_lock);
1804 if (vfsmnt->mnt_parent == vfsmnt) { 1804 if (vfsmnt->mnt_parent == vfsmnt) {
1805 spin_unlock(&vfsmount_lock);
1806 goto global_root; 1805 goto global_root;
1807 } 1806 }
1808 dentry = vfsmnt->mnt_mountpoint; 1807 dentry = vfsmnt->mnt_mountpoint;
1809 vfsmnt = vfsmnt->mnt_parent; 1808 vfsmnt = vfsmnt->mnt_parent;
1810 spin_unlock(&vfsmount_lock);
1811 continue; 1809 continue;
1812 } 1810 }
1813 parent = dentry->d_parent; 1811 parent = dentry->d_parent;
@@ -1820,6 +1818,8 @@ char *__d_path(const struct path *path, struct path *root,
1820 dentry = parent; 1818 dentry = parent;
1821 } 1819 }
1822 1820
1821out:
1822 spin_unlock(&vfsmount_lock);
1823 return retval; 1823 return retval;
1824 1824
1825global_root: 1825global_root:
@@ -1829,9 +1829,11 @@ global_root:
1829 goto Elong; 1829 goto Elong;
1830 root->mnt = vfsmnt; 1830 root->mnt = vfsmnt;
1831 root->dentry = dentry; 1831 root->dentry = dentry;
1832 return retval; 1832 goto out;
1833
1833Elong: 1834Elong:
1834 return ERR_PTR(-ENAMETOOLONG); 1835 retval = ERR_PTR(-ENAMETOOLONG);
1836 goto out;
1835} 1837}
1836 1838
1837/** 1839/**