Commit 36d43a43761b004ad1879ac21471d8fc5f3157ec

Authored by David Howells
Committed by Al Viro
1 parent d18610b0ce

NFS: Use d_automount() rather than abusing follow_link()

Make NFS use the new d_automount() dentry operation rather than abusing
follow_link() on directories.

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Acked-by: Ian Kent <raven@themaw.net>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Showing 5 changed files with 46 additions and 48 deletions Side-by-side Diff

... ... @@ -970,7 +970,7 @@
970 970 {
971 971 struct nfs_server *server = NFS_SERVER(inode);
972 972  
973   - if (test_bit(NFS_INO_MOUNTPOINT, &NFS_I(inode)->flags))
  973 + if (IS_AUTOMOUNT(inode))
974 974 return 0;
975 975 if (nd != NULL) {
976 976 /* VFS wants an on-the-wire revalidation */
... ... @@ -1173,6 +1173,7 @@
1173 1173 .d_revalidate = nfs_lookup_revalidate,
1174 1174 .d_delete = nfs_dentry_delete,
1175 1175 .d_iput = nfs_dentry_iput,
  1176 + .d_automount = nfs_d_automount,
1176 1177 };
1177 1178  
1178 1179 static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
... ... @@ -1246,6 +1247,7 @@
1246 1247 .d_revalidate = nfs_open_revalidate,
1247 1248 .d_delete = nfs_dentry_delete,
1248 1249 .d_iput = nfs_dentry_iput,
  1250 + .d_automount = nfs_d_automount,
1249 1251 };
1250 1252  
1251 1253 /*
... ... @@ -300,7 +300,7 @@
300 300 else
301 301 inode->i_op = &nfs_mountpoint_inode_operations;
302 302 inode->i_fop = NULL;
303   - set_bit(NFS_INO_MOUNTPOINT, &nfsi->flags);
  303 + inode->i_flags |= S_AUTOMOUNT;
304 304 }
305 305 } else if (S_ISLNK(inode->i_mode))
306 306 inode->i_op = &nfs_symlink_inode_operations;
... ... @@ -1208,7 +1208,7 @@
1208 1208 /* Update the fsid? */
1209 1209 if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) &&
1210 1210 !nfs_fsid_equal(&server->fsid, &fattr->fsid) &&
1211   - !test_bit(NFS_INO_MOUNTPOINT, &nfsi->flags))
  1211 + !IS_AUTOMOUNT(inode))
1212 1212 server->fsid = fattr->fsid;
1213 1213  
1214 1214 /*
... ... @@ -252,6 +252,7 @@
252 252 const struct dentry *droot,
253 253 const struct dentry *dentry,
254 254 char *buffer, ssize_t buflen);
  255 +extern struct vfsmount *nfs_d_automount(struct path *path);
255 256  
256 257 /* getroot.c */
257 258 extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *);
... ... @@ -97,9 +97,8 @@
97 97 }
98 98  
99 99 /*
100   - * nfs_follow_mountpoint - handle crossing a mountpoint on the server
101   - * @dentry - dentry of mountpoint
102   - * @nd - nameidata info
  100 + * nfs_d_automount - Handle crossing a mountpoint on the server
  101 + * @path - The mountpoint
103 102 *
104 103 * When we encounter a mountpoint on the server, we want to set up
105 104 * a mountpoint on the client too, to prevent inode numbers from
106 105  
107 106  
108 107  
109 108  
110 109  
111 110  
112 111  
113 112  
114 113  
115 114  
116 115  
117 116  
118 117  
119 118  
120 119  
121 120  
122 121  
123 122  
124 123  
... ... @@ -109,84 +108,81 @@
109 108 * situation, and that different filesystems may want to use
110 109 * different security flavours.
111 110 */
112   -static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
  111 +struct vfsmount *nfs_d_automount(struct path *path)
113 112 {
114 113 struct vfsmount *mnt;
115   - struct nfs_server *server = NFS_SERVER(dentry->d_inode);
  114 + struct nfs_server *server = NFS_SERVER(path->dentry->d_inode);
116 115 struct dentry *parent;
117 116 struct nfs_fh *fh = NULL;
118 117 struct nfs_fattr *fattr = NULL;
119 118 int err;
120 119  
121   - dprintk("--> nfs_follow_mountpoint()\n");
  120 + dprintk("--> nfs_d_automount()\n");
122 121  
123   - err = -ESTALE;
124   - if (IS_ROOT(dentry))
125   - goto out_err;
  122 + mnt = ERR_PTR(-ESTALE);
  123 + if (IS_ROOT(path->dentry))
  124 + goto out_nofree;
126 125  
127   - err = -ENOMEM;
  126 + mnt = ERR_PTR(-ENOMEM);
128 127 fh = nfs_alloc_fhandle();
129 128 fattr = nfs_alloc_fattr();
130 129 if (fh == NULL || fattr == NULL)
131   - goto out_err;
  130 + goto out;
132 131  
133 132 dprintk("%s: enter\n", __func__);
134   - dput(nd->path.dentry);
135   - nd->path.dentry = dget(dentry);
136 133  
137   - /* Look it up again */
138   - parent = dget_parent(nd->path.dentry);
  134 + /* Look it up again to get its attributes */
  135 + parent = dget_parent(path->dentry);
139 136 err = server->nfs_client->rpc_ops->lookup(parent->d_inode,
140   - &nd->path.dentry->d_name,
  137 + &path->dentry->d_name,
141 138 fh, fattr);
142 139 dput(parent);
143   - if (err != 0)
144   - goto out_err;
  140 + if (err != 0) {
  141 + mnt = ERR_PTR(err);
  142 + goto out;
  143 + }
145 144  
146 145 if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
147   - mnt = nfs_do_refmount(nd->path.mnt, nd->path.dentry);
  146 + mnt = nfs_do_refmount(path->mnt, path->dentry);
148 147 else
149   - mnt = nfs_do_submount(nd->path.mnt, nd->path.dentry, fh,
150   - fattr);
151   - err = PTR_ERR(mnt);
  148 + mnt = nfs_do_submount(path->mnt, path->dentry, fh, fattr);
152 149 if (IS_ERR(mnt))
153   - goto out_err;
  150 + goto out;
154 151  
155 152 mntget(mnt);
156   - err = do_add_mount(mnt, &nd->path, nd->path.mnt->mnt_flags|MNT_SHRINKABLE,
  153 + err = do_add_mount(mnt, path, path->mnt->mnt_flags | MNT_SHRINKABLE,
157 154 &nfs_automount_list);
158   - if (err < 0) {
  155 + switch (err) {
  156 + case 0:
  157 + dprintk("%s: done, success\n", __func__);
  158 + schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
  159 + break;
  160 + case -EBUSY:
  161 + /* someone else made a mount here whilst we were busy */
159 162 mntput(mnt);
160   - if (err == -EBUSY)
161   - goto out_follow;
162   - goto out_err;
  163 + dprintk("%s: done, collision\n", __func__);
  164 + mnt = NULL;
  165 + break;
  166 + default:
  167 + mntput(mnt);
  168 + dprintk("%s: done, error %d\n", __func__, err);
  169 + mnt = ERR_PTR(err);
  170 + break;
163 171 }
164   - path_put(&nd->path);
165   - nd->path.mnt = mnt;
166   - nd->path.dentry = dget(mnt->mnt_root);
167   - schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
  172 +
168 173 out:
169 174 nfs_free_fattr(fattr);
170 175 nfs_free_fhandle(fh);
171   - dprintk("%s: done, returned %d\n", __func__, err);
172   -
173   - dprintk("<-- nfs_follow_mountpoint() = %d\n", err);
174   - return ERR_PTR(err);
175   -out_err:
176   - path_put(&nd->path);
177   - goto out;
178   -out_follow:
179   - err = follow_down(&nd->path, false);
180   - goto out;
  176 +out_nofree:
  177 + dprintk("<-- nfs_follow_mountpoint() = %p\n", mnt);
  178 + return mnt;
181 179 }
182 180  
183 181 const struct inode_operations nfs_mountpoint_inode_operations = {
184   - .follow_link = nfs_follow_mountpoint,
185 182 .getattr = nfs_getattr,
186 183 };
187 184  
188 185 const struct inode_operations nfs_referral_inode_operations = {
189   - .follow_link = nfs_follow_mountpoint,
190 186 };
191 187  
192 188 static void nfs_expire_automounts(struct work_struct *work)
include/linux/nfs_fs.h
... ... @@ -215,7 +215,6 @@
215 215 #define NFS_INO_ADVISE_RDPLUS (0) /* advise readdirplus */
216 216 #define NFS_INO_STALE (1) /* possible stale inode */
217 217 #define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */
218   -#define NFS_INO_MOUNTPOINT (3) /* inode is remote mountpoint */
219 218 #define NFS_INO_FLUSHING (4) /* inode is flushing out data */
220 219 #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */
221 220 #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */