aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/namespace.c')
-rw-r--r--fs/nfs/namespace.c69
1 files changed, 45 insertions, 24 deletions
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index f32b8603dca8..859cdaba4c1c 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -25,33 +25,31 @@ static LIST_HEAD(nfs_automount_list);
25static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts); 25static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts);
26int nfs_mountpoint_expiry_timeout = 500 * HZ; 26int nfs_mountpoint_expiry_timeout = 500 * HZ;
27 27
28static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, 28static struct vfsmount *nfs_do_submount(struct super_block *sb,
29 const struct dentry *dentry, 29 struct dentry *dentry,
30 struct nfs_fh *fh, 30 struct nfs_fh *fh,
31 struct nfs_fattr *fattr); 31 struct nfs_fattr *fattr);
32 32
33/* 33/*
34 * nfs_path - reconstruct the path given an arbitrary dentry 34 * nfs_path - reconstruct the path given an arbitrary dentry
35 * @base - arbitrary string to prepend to the path 35 * @base - used to return pointer to the end of devname part of path
36 * @droot - pointer to root dentry for mountpoint
37 * @dentry - pointer to dentry 36 * @dentry - pointer to dentry
38 * @buffer - result buffer 37 * @buffer - result buffer
39 * @buflen - length of buffer 38 * @buflen - length of buffer
40 * 39 *
41 * Helper function for constructing the path from the 40 * Helper function for constructing the server pathname
42 * root dentry to an arbitrary hashed dentry. 41 * by arbitrary hashed dentry.
43 * 42 *
44 * This is mainly for use in figuring out the path on the 43 * This is mainly for use in figuring out the path on the
45 * server side when automounting on top of an existing partition. 44 * server side when automounting on top of an existing partition
45 * and in generating /proc/mounts and friends.
46 */ 46 */
47char *nfs_path(const char *base, 47char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen)
48 const struct dentry *droot,
49 const struct dentry *dentry,
50 char *buffer, ssize_t buflen)
51{ 48{
52 char *end; 49 char *end;
53 int namelen; 50 int namelen;
54 unsigned seq; 51 unsigned seq;
52 const char *base;
55 53
56rename_retry: 54rename_retry:
57 end = buffer+buflen; 55 end = buffer+buflen;
@@ -60,7 +58,10 @@ rename_retry:
60 58
61 seq = read_seqbegin(&rename_lock); 59 seq = read_seqbegin(&rename_lock);
62 rcu_read_lock(); 60 rcu_read_lock();
63 while (!IS_ROOT(dentry) && dentry != droot) { 61 while (1) {
62 spin_lock(&dentry->d_lock);
63 if (IS_ROOT(dentry))
64 break;
64 namelen = dentry->d_name.len; 65 namelen = dentry->d_name.len;
65 buflen -= namelen + 1; 66 buflen -= namelen + 1;
66 if (buflen < 0) 67 if (buflen < 0)
@@ -68,27 +69,47 @@ rename_retry:
68 end -= namelen; 69 end -= namelen;
69 memcpy(end, dentry->d_name.name, namelen); 70 memcpy(end, dentry->d_name.name, namelen);
70 *--end = '/'; 71 *--end = '/';
72 spin_unlock(&dentry->d_lock);
71 dentry = dentry->d_parent; 73 dentry = dentry->d_parent;
72 } 74 }
73 rcu_read_unlock(); 75 if (read_seqretry(&rename_lock, seq)) {
74 if (read_seqretry(&rename_lock, seq)) 76 spin_unlock(&dentry->d_lock);
77 rcu_read_unlock();
75 goto rename_retry; 78 goto rename_retry;
79 }
76 if (*end != '/') { 80 if (*end != '/') {
77 if (--buflen < 0) 81 if (--buflen < 0) {
82 spin_unlock(&dentry->d_lock);
83 rcu_read_unlock();
78 goto Elong; 84 goto Elong;
85 }
79 *--end = '/'; 86 *--end = '/';
80 } 87 }
88 *p = end;
89 base = dentry->d_fsdata;
90 if (!base) {
91 spin_unlock(&dentry->d_lock);
92 rcu_read_unlock();
93 WARN_ON(1);
94 return end;
95 }
81 namelen = strlen(base); 96 namelen = strlen(base);
82 /* Strip off excess slashes in base string */ 97 /* Strip off excess slashes in base string */
83 while (namelen > 0 && base[namelen - 1] == '/') 98 while (namelen > 0 && base[namelen - 1] == '/')
84 namelen--; 99 namelen--;
85 buflen -= namelen; 100 buflen -= namelen;
86 if (buflen < 0) 101 if (buflen < 0) {
102 spin_lock(&dentry->d_lock);
103 rcu_read_unlock();
87 goto Elong; 104 goto Elong;
105 }
88 end -= namelen; 106 end -= namelen;
89 memcpy(end, base, namelen); 107 memcpy(end, base, namelen);
108 spin_unlock(&dentry->d_lock);
109 rcu_read_unlock();
90 return end; 110 return end;
91Elong_unlock: 111Elong_unlock:
112 spin_lock(&dentry->d_lock);
92 rcu_read_unlock(); 113 rcu_read_unlock();
93 if (read_seqretry(&rename_lock, seq)) 114 if (read_seqretry(&rename_lock, seq))
94 goto rename_retry; 115 goto rename_retry;
@@ -143,9 +164,9 @@ struct vfsmount *nfs_d_automount(struct path *path)
143 } 164 }
144 165
145 if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) 166 if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
146 mnt = nfs_do_refmount(path->mnt, path->dentry); 167 mnt = nfs_do_refmount(path->mnt->mnt_sb, path->dentry);
147 else 168 else
148 mnt = nfs_do_submount(path->mnt, path->dentry, fh, fattr); 169 mnt = nfs_do_submount(path->mnt->mnt_sb, path->dentry, fh, fattr);
149 if (IS_ERR(mnt)) 170 if (IS_ERR(mnt))
150 goto out; 171 goto out;
151 172
@@ -209,19 +230,19 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
209 230
210/** 231/**
211 * nfs_do_submount - set up mountpoint when crossing a filesystem boundary 232 * nfs_do_submount - set up mountpoint when crossing a filesystem boundary
212 * @mnt_parent - mountpoint of parent directory 233 * @sb - superblock of parent directory
213 * @dentry - parent directory 234 * @dentry - parent directory
214 * @fh - filehandle for new root dentry 235 * @fh - filehandle for new root dentry
215 * @fattr - attributes for new root inode 236 * @fattr - attributes for new root inode
216 * 237 *
217 */ 238 */
218static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, 239static struct vfsmount *nfs_do_submount(struct super_block *sb,
219 const struct dentry *dentry, 240 struct dentry *dentry,
220 struct nfs_fh *fh, 241 struct nfs_fh *fh,
221 struct nfs_fattr *fattr) 242 struct nfs_fattr *fattr)
222{ 243{
223 struct nfs_clone_mount mountdata = { 244 struct nfs_clone_mount mountdata = {
224 .sb = mnt_parent->mnt_sb, 245 .sb = sb,
225 .dentry = dentry, 246 .dentry = dentry,
226 .fh = fh, 247 .fh = fh,
227 .fattr = fattr, 248 .fattr = fattr,
@@ -237,11 +258,11 @@ static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
237 dentry->d_name.name); 258 dentry->d_name.name);
238 if (page == NULL) 259 if (page == NULL)
239 goto out; 260 goto out;
240 devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE); 261 devname = nfs_devname(dentry, page, PAGE_SIZE);
241 mnt = (struct vfsmount *)devname; 262 mnt = (struct vfsmount *)devname;
242 if (IS_ERR(devname)) 263 if (IS_ERR(devname))
243 goto free_page; 264 goto free_page;
244 mnt = nfs_do_clone_mount(NFS_SB(mnt_parent->mnt_sb), devname, &mountdata); 265 mnt = nfs_do_clone_mount(NFS_SB(sb), devname, &mountdata);
245free_page: 266free_page:
246 free_page((unsigned long)page); 267 free_page((unsigned long)page);
247out: 268out: