hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/fs/nfs/namespace.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * linux/fs/nfs/namespace.c
34 *
....@@ -18,6 +19,7 @@
1819 #include <linux/vfs.h>
1920 #include <linux/sunrpc/gss_api.h>
2021 #include "internal.h"
22
+#include "nfs.h"
2123
2224 #define NFSDBG_FACILITY NFSDBG_VFS
2325
....@@ -142,31 +144,66 @@
142144 */
143145 struct vfsmount *nfs_d_automount(struct path *path)
144146 {
145
- struct vfsmount *mnt;
146
- struct nfs_server *server = NFS_SERVER(d_inode(path->dentry));
147
- struct nfs_fh *fh = NULL;
148
- struct nfs_fattr *fattr = NULL;
147
+ struct nfs_fs_context *ctx;
148
+ struct fs_context *fc;
149
+ struct vfsmount *mnt = ERR_PTR(-ENOMEM);
150
+ struct nfs_server *server = NFS_SB(path->dentry->d_sb);
151
+ struct nfs_client *client = server->nfs_client;
152
+ int timeout = READ_ONCE(nfs_mountpoint_expiry_timeout);
153
+ int ret;
149154
150155 if (IS_ROOT(path->dentry))
151156 return ERR_PTR(-ESTALE);
152157
153
- mnt = ERR_PTR(-ENOMEM);
154
- fh = nfs_alloc_fhandle();
155
- fattr = nfs_alloc_fattr();
156
- if (fh == NULL || fattr == NULL)
157
- goto out;
158
+ /* Open a new filesystem context, transferring parameters from the
159
+ * parent superblock, including the network namespace.
160
+ */
161
+ fc = fs_context_for_submount(path->mnt->mnt_sb->s_type, path->dentry);
162
+ if (IS_ERR(fc))
163
+ return ERR_CAST(fc);
158164
159
- mnt = server->nfs_client->rpc_ops->submount(server, path->dentry, fh, fattr);
165
+ ctx = nfs_fc2context(fc);
166
+ ctx->clone_data.dentry = path->dentry;
167
+ ctx->clone_data.sb = path->dentry->d_sb;
168
+ ctx->clone_data.fattr = nfs_alloc_fattr();
169
+ if (!ctx->clone_data.fattr)
170
+ goto out_fc;
171
+
172
+ if (fc->net_ns != client->cl_net) {
173
+ put_net(fc->net_ns);
174
+ fc->net_ns = get_net(client->cl_net);
175
+ }
176
+
177
+ /* for submounts we want the same server; referrals will reassign */
178
+ memcpy(&ctx->nfs_server.address, &client->cl_addr, client->cl_addrlen);
179
+ ctx->nfs_server.addrlen = client->cl_addrlen;
180
+ ctx->nfs_server.port = server->port;
181
+
182
+ ctx->version = client->rpc_ops->version;
183
+ ctx->minorversion = client->cl_minorversion;
184
+ ctx->nfs_mod = client->cl_nfs_mod;
185
+ __module_get(ctx->nfs_mod->owner);
186
+
187
+ ret = client->rpc_ops->submount(fc, server);
188
+ if (ret < 0) {
189
+ mnt = ERR_PTR(ret);
190
+ goto out_fc;
191
+ }
192
+
193
+ up_write(&fc->root->d_sb->s_umount);
194
+ mnt = vfs_create_mount(fc);
160195 if (IS_ERR(mnt))
161
- goto out;
196
+ goto out_fc;
162197
163198 mntget(mnt); /* prevent immediate expiration */
164
- mnt_set_expiry(mnt, &nfs_automount_list);
165
- schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
199
+ if (timeout <= 0)
200
+ goto out_fc;
166201
167
-out:
168
- nfs_free_fattr(fattr);
169
- nfs_free_fhandle(fh);
202
+ mnt_set_expiry(mnt, &nfs_automount_list);
203
+ schedule_delayed_work(&nfs_automount_task, timeout);
204
+
205
+out_fc:
206
+ put_fs_context(fc);
170207 return mnt;
171208 }
172209
....@@ -201,10 +238,11 @@
201238 static void nfs_expire_automounts(struct work_struct *work)
202239 {
203240 struct list_head *list = &nfs_automount_list;
241
+ int timeout = READ_ONCE(nfs_mountpoint_expiry_timeout);
204242
205243 mark_mounts_for_expiry(list);
206
- if (!list_empty(list))
207
- schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
244
+ if (!list_empty(list) && timeout > 0)
245
+ schedule_delayed_work(&nfs_automount_task, timeout);
208246 }
209247
210248 void nfs_release_automount_timer(void)
....@@ -213,64 +251,117 @@
213251 cancel_delayed_work(&nfs_automount_task);
214252 }
215253
216
-/*
217
- * Clone a mountpoint of the appropriate type
218
- */
219
-static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
220
- const char *devname,
221
- struct nfs_clone_mount *mountdata)
222
-{
223
- return vfs_submount(mountdata->dentry, &nfs_xdev_fs_type, devname, mountdata);
224
-}
225
-
226254 /**
227255 * nfs_do_submount - set up mountpoint when crossing a filesystem boundary
228
- * @dentry - parent directory
229
- * @fh - filehandle for new root dentry
230
- * @fattr - attributes for new root inode
231
- * @authflavor - security flavor to use when performing the mount
256
+ * @fc: pointer to struct nfs_fs_context
232257 *
233258 */
234
-struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh,
235
- struct nfs_fattr *fattr, rpc_authflavor_t authflavor)
259
+int nfs_do_submount(struct fs_context *fc)
236260 {
237
- struct nfs_clone_mount mountdata = {
238
- .sb = dentry->d_sb,
239
- .dentry = dentry,
240
- .fh = fh,
241
- .fattr = fattr,
242
- .authflavor = authflavor,
243
- };
244
- struct vfsmount *mnt;
245
- char *page = (char *) __get_free_page(GFP_USER);
246
- char *devname;
261
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
262
+ struct dentry *dentry = ctx->clone_data.dentry;
263
+ struct nfs_server *server;
264
+ char *buffer, *p;
265
+ int ret;
247266
248
- if (page == NULL)
249
- return ERR_PTR(-ENOMEM);
267
+ /* create a new volume representation */
268
+ server = ctx->nfs_mod->rpc_ops->clone_server(NFS_SB(ctx->clone_data.sb),
269
+ ctx->mntfh,
270
+ ctx->clone_data.fattr,
271
+ ctx->selected_flavor);
250272
251
- devname = nfs_devname(dentry, page, PAGE_SIZE);
252
- if (IS_ERR(devname))
253
- mnt = ERR_CAST(devname);
254
- else
255
- mnt = nfs_do_clone_mount(NFS_SB(dentry->d_sb), devname, &mountdata);
273
+ if (IS_ERR(server))
274
+ return PTR_ERR(server);
256275
257
- free_page((unsigned long)page);
258
- return mnt;
276
+ ctx->server = server;
277
+
278
+ buffer = kmalloc(4096, GFP_USER);
279
+ if (!buffer)
280
+ return -ENOMEM;
281
+
282
+ ctx->internal = true;
283
+ ctx->clone_data.inherited_bsize = ctx->clone_data.sb->s_blocksize_bits;
284
+
285
+ p = nfs_devname(dentry, buffer, 4096);
286
+ if (IS_ERR(p)) {
287
+ nfs_errorf(fc, "NFS: Couldn't determine submount pathname");
288
+ ret = PTR_ERR(p);
289
+ } else {
290
+ ret = vfs_parse_fs_string(fc, "source", p, buffer + 4096 - p);
291
+ if (!ret)
292
+ ret = vfs_get_tree(fc);
293
+ }
294
+ kfree(buffer);
295
+ return ret;
259296 }
260297 EXPORT_SYMBOL_GPL(nfs_do_submount);
261298
262
-struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry,
263
- struct nfs_fh *fh, struct nfs_fattr *fattr)
299
+int nfs_submount(struct fs_context *fc, struct nfs_server *server)
264300 {
265
- int err;
301
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
302
+ struct dentry *dentry = ctx->clone_data.dentry;
266303 struct dentry *parent = dget_parent(dentry);
304
+ int err;
267305
268306 /* Look it up again to get its attributes */
269
- err = server->nfs_client->rpc_ops->lookup(d_inode(parent), &dentry->d_name, fh, fattr, NULL);
307
+ err = server->nfs_client->rpc_ops->lookup(d_inode(parent), dentry,
308
+ ctx->mntfh, ctx->clone_data.fattr,
309
+ NULL);
270310 dput(parent);
271311 if (err != 0)
272
- return ERR_PTR(err);
312
+ return err;
273313
274
- return nfs_do_submount(dentry, fh, fattr, server->client->cl_auth->au_flavor);
314
+ ctx->selected_flavor = server->client->cl_auth->au_flavor;
315
+ return nfs_do_submount(fc);
275316 }
276317 EXPORT_SYMBOL_GPL(nfs_submount);
318
+
319
+static int param_set_nfs_timeout(const char *val, const struct kernel_param *kp)
320
+{
321
+ long num;
322
+ int ret;
323
+
324
+ if (!val)
325
+ return -EINVAL;
326
+ ret = kstrtol(val, 0, &num);
327
+ if (ret)
328
+ return -EINVAL;
329
+ if (num > 0) {
330
+ if (num >= INT_MAX / HZ)
331
+ num = INT_MAX;
332
+ else
333
+ num *= HZ;
334
+ *((int *)kp->arg) = num;
335
+ if (!list_empty(&nfs_automount_list))
336
+ mod_delayed_work(system_wq, &nfs_automount_task, num);
337
+ } else {
338
+ *((int *)kp->arg) = -1*HZ;
339
+ cancel_delayed_work(&nfs_automount_task);
340
+ }
341
+ return 0;
342
+}
343
+
344
+static int param_get_nfs_timeout(char *buffer, const struct kernel_param *kp)
345
+{
346
+ long num = *((int *)kp->arg);
347
+
348
+ if (num > 0) {
349
+ if (num >= INT_MAX - (HZ - 1))
350
+ num = INT_MAX / HZ;
351
+ else
352
+ num = (num + (HZ - 1)) / HZ;
353
+ } else
354
+ num = -1;
355
+ return scnprintf(buffer, PAGE_SIZE, "%li\n", num);
356
+}
357
+
358
+static const struct kernel_param_ops param_ops_nfs_timeout = {
359
+ .set = param_set_nfs_timeout,
360
+ .get = param_get_nfs_timeout,
361
+};
362
+#define param_check_nfs_timeout(name, p) __param_check(name, p, int);
363
+
364
+module_param(nfs_mountpoint_expiry_timeout, nfs_timeout, 0644);
365
+MODULE_PARM_DESC(nfs_mountpoint_expiry_timeout,
366
+ "Set the NFS automounted mountpoint timeout value (seconds)."
367
+ "Values <= 0 turn expiration off.");