Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * linux/fs/nfs/namespace.c
0004  *
0005  * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
0006  * - Modified by David Howells <dhowells@redhat.com>
0007  *
0008  * NFS namespace
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/dcache.h>
0013 #include <linux/gfp.h>
0014 #include <linux/mount.h>
0015 #include <linux/namei.h>
0016 #include <linux/nfs_fs.h>
0017 #include <linux/string.h>
0018 #include <linux/sunrpc/clnt.h>
0019 #include <linux/vfs.h>
0020 #include <linux/sunrpc/gss_api.h>
0021 #include "internal.h"
0022 #include "nfs.h"
0023 
0024 #define NFSDBG_FACILITY     NFSDBG_VFS
0025 
0026 static void nfs_expire_automounts(struct work_struct *work);
0027 
0028 static LIST_HEAD(nfs_automount_list);
0029 static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts);
0030 int nfs_mountpoint_expiry_timeout = 500 * HZ;
0031 
0032 /*
0033  * nfs_path - reconstruct the path given an arbitrary dentry
0034  * @base - used to return pointer to the end of devname part of path
0035  * @dentry_in - pointer to dentry
0036  * @buffer - result buffer
0037  * @buflen_in - length of buffer
0038  * @flags - options (see below)
0039  *
0040  * Helper function for constructing the server pathname
0041  * by arbitrary hashed dentry.
0042  *
0043  * This is mainly for use in figuring out the path on the
0044  * server side when automounting on top of an existing partition
0045  * and in generating /proc/mounts and friends.
0046  *
0047  * Supported flags:
0048  * NFS_PATH_CANONICAL: ensure there is exactly one slash after
0049  *             the original device (export) name
0050  *             (if unset, the original name is returned verbatim)
0051  */
0052 char *nfs_path(char **p, struct dentry *dentry_in, char *buffer,
0053            ssize_t buflen_in, unsigned flags)
0054 {
0055     char *end;
0056     int namelen;
0057     unsigned seq;
0058     const char *base;
0059     struct dentry *dentry;
0060     ssize_t buflen;
0061 
0062 rename_retry:
0063     buflen = buflen_in;
0064     dentry = dentry_in;
0065     end = buffer+buflen;
0066     *--end = '\0';
0067     buflen--;
0068 
0069     seq = read_seqbegin(&rename_lock);
0070     rcu_read_lock();
0071     while (1) {
0072         spin_lock(&dentry->d_lock);
0073         if (IS_ROOT(dentry))
0074             break;
0075         namelen = dentry->d_name.len;
0076         buflen -= namelen + 1;
0077         if (buflen < 0)
0078             goto Elong_unlock;
0079         end -= namelen;
0080         memcpy(end, dentry->d_name.name, namelen);
0081         *--end = '/';
0082         spin_unlock(&dentry->d_lock);
0083         dentry = dentry->d_parent;
0084     }
0085     if (read_seqretry(&rename_lock, seq)) {
0086         spin_unlock(&dentry->d_lock);
0087         rcu_read_unlock();
0088         goto rename_retry;
0089     }
0090     if ((flags & NFS_PATH_CANONICAL) && *end != '/') {
0091         if (--buflen < 0) {
0092             spin_unlock(&dentry->d_lock);
0093             rcu_read_unlock();
0094             goto Elong;
0095         }
0096         *--end = '/';
0097     }
0098     *p = end;
0099     base = dentry->d_fsdata;
0100     if (!base) {
0101         spin_unlock(&dentry->d_lock);
0102         rcu_read_unlock();
0103         WARN_ON(1);
0104         return end;
0105     }
0106     namelen = strlen(base);
0107     if (*end == '/') {
0108         /* Strip off excess slashes in base string */
0109         while (namelen > 0 && base[namelen - 1] == '/')
0110             namelen--;
0111     }
0112     buflen -= namelen;
0113     if (buflen < 0) {
0114         spin_unlock(&dentry->d_lock);
0115         rcu_read_unlock();
0116         goto Elong;
0117     }
0118     end -= namelen;
0119     memcpy(end, base, namelen);
0120     spin_unlock(&dentry->d_lock);
0121     rcu_read_unlock();
0122     return end;
0123 Elong_unlock:
0124     spin_unlock(&dentry->d_lock);
0125     rcu_read_unlock();
0126     if (read_seqretry(&rename_lock, seq))
0127         goto rename_retry;
0128 Elong:
0129     return ERR_PTR(-ENAMETOOLONG);
0130 }
0131 EXPORT_SYMBOL_GPL(nfs_path);
0132 
0133 /*
0134  * nfs_d_automount - Handle crossing a mountpoint on the server
0135  * @path - The mountpoint
0136  *
0137  * When we encounter a mountpoint on the server, we want to set up
0138  * a mountpoint on the client too, to prevent inode numbers from
0139  * colliding, and to allow "df" to work properly.
0140  * On NFSv4, we also want to allow for the fact that different
0141  * filesystems may be migrated to different servers in a failover
0142  * situation, and that different filesystems may want to use
0143  * different security flavours.
0144  */
0145 struct vfsmount *nfs_d_automount(struct path *path)
0146 {
0147     struct nfs_fs_context *ctx;
0148     struct fs_context *fc;
0149     struct vfsmount *mnt = ERR_PTR(-ENOMEM);
0150     struct nfs_server *server = NFS_SERVER(d_inode(path->dentry));
0151     struct nfs_client *client = server->nfs_client;
0152     int timeout = READ_ONCE(nfs_mountpoint_expiry_timeout);
0153     int ret;
0154 
0155     if (IS_ROOT(path->dentry))
0156         return ERR_PTR(-ESTALE);
0157 
0158     /* Open a new filesystem context, transferring parameters from the
0159      * parent superblock, including the network namespace.
0160      */
0161     fc = fs_context_for_submount(path->mnt->mnt_sb->s_type, path->dentry);
0162     if (IS_ERR(fc))
0163         return ERR_CAST(fc);
0164 
0165     ctx = nfs_fc2context(fc);
0166     ctx->clone_data.dentry  = path->dentry;
0167     ctx->clone_data.sb  = path->dentry->d_sb;
0168     ctx->clone_data.fattr   = nfs_alloc_fattr();
0169     if (!ctx->clone_data.fattr)
0170         goto out_fc;
0171 
0172     if (fc->net_ns != client->cl_net) {
0173         put_net(fc->net_ns);
0174         fc->net_ns = get_net(client->cl_net);
0175     }
0176 
0177     /* for submounts we want the same server; referrals will reassign */
0178     memcpy(&ctx->nfs_server.address, &client->cl_addr, client->cl_addrlen);
0179     ctx->nfs_server.addrlen = client->cl_addrlen;
0180     ctx->nfs_server.port    = server->port;
0181 
0182     ctx->version        = client->rpc_ops->version;
0183     ctx->minorversion   = client->cl_minorversion;
0184     ctx->nfs_mod        = client->cl_nfs_mod;
0185     __module_get(ctx->nfs_mod->owner);
0186 
0187     ret = client->rpc_ops->submount(fc, server);
0188     if (ret < 0) {
0189         mnt = ERR_PTR(ret);
0190         goto out_fc;
0191     }
0192 
0193     up_write(&fc->root->d_sb->s_umount);
0194     mnt = vfs_create_mount(fc);
0195     if (IS_ERR(mnt))
0196         goto out_fc;
0197 
0198     mntget(mnt); /* prevent immediate expiration */
0199     if (timeout <= 0)
0200         goto out_fc;
0201 
0202     mnt_set_expiry(mnt, &nfs_automount_list);
0203     schedule_delayed_work(&nfs_automount_task, timeout);
0204 
0205 out_fc:
0206     put_fs_context(fc);
0207     return mnt;
0208 }
0209 
0210 static int
0211 nfs_namespace_getattr(struct user_namespace *mnt_userns,
0212               const struct path *path, struct kstat *stat,
0213               u32 request_mask, unsigned int query_flags)
0214 {
0215     if (NFS_FH(d_inode(path->dentry))->size != 0)
0216         return nfs_getattr(mnt_userns, path, stat, request_mask,
0217                    query_flags);
0218     generic_fillattr(&init_user_ns, d_inode(path->dentry), stat);
0219     return 0;
0220 }
0221 
0222 static int
0223 nfs_namespace_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
0224               struct iattr *attr)
0225 {
0226     if (NFS_FH(d_inode(dentry))->size != 0)
0227         return nfs_setattr(mnt_userns, dentry, attr);
0228     return -EACCES;
0229 }
0230 
0231 const struct inode_operations nfs_mountpoint_inode_operations = {
0232     .getattr    = nfs_getattr,
0233     .setattr    = nfs_setattr,
0234 };
0235 
0236 const struct inode_operations nfs_referral_inode_operations = {
0237     .getattr    = nfs_namespace_getattr,
0238     .setattr    = nfs_namespace_setattr,
0239 };
0240 
0241 static void nfs_expire_automounts(struct work_struct *work)
0242 {
0243     struct list_head *list = &nfs_automount_list;
0244     int timeout = READ_ONCE(nfs_mountpoint_expiry_timeout);
0245 
0246     mark_mounts_for_expiry(list);
0247     if (!list_empty(list) && timeout > 0)
0248         schedule_delayed_work(&nfs_automount_task, timeout);
0249 }
0250 
0251 void nfs_release_automount_timer(void)
0252 {
0253     if (list_empty(&nfs_automount_list))
0254         cancel_delayed_work(&nfs_automount_task);
0255 }
0256 
0257 /**
0258  * nfs_do_submount - set up mountpoint when crossing a filesystem boundary
0259  * @fc: pointer to struct nfs_fs_context
0260  *
0261  */
0262 int nfs_do_submount(struct fs_context *fc)
0263 {
0264     struct nfs_fs_context *ctx = nfs_fc2context(fc);
0265     struct dentry *dentry = ctx->clone_data.dentry;
0266     struct nfs_server *server;
0267     char *buffer, *p;
0268     int ret;
0269 
0270     /* create a new volume representation */
0271     server = ctx->nfs_mod->rpc_ops->clone_server(NFS_SB(ctx->clone_data.sb),
0272                              ctx->mntfh,
0273                              ctx->clone_data.fattr,
0274                              ctx->selected_flavor);
0275 
0276     if (IS_ERR(server))
0277         return PTR_ERR(server);
0278 
0279     ctx->server = server;
0280 
0281     buffer = kmalloc(4096, GFP_USER);
0282     if (!buffer)
0283         return -ENOMEM;
0284 
0285     ctx->internal       = true;
0286     ctx->clone_data.inherited_bsize = ctx->clone_data.sb->s_blocksize_bits;
0287 
0288     p = nfs_devname(dentry, buffer, 4096);
0289     if (IS_ERR(p)) {
0290         nfs_errorf(fc, "NFS: Couldn't determine submount pathname");
0291         ret = PTR_ERR(p);
0292     } else {
0293         ret = vfs_parse_fs_string(fc, "source", p, buffer + 4096 - p);
0294         if (!ret)
0295             ret = vfs_get_tree(fc);
0296     }
0297     kfree(buffer);
0298     return ret;
0299 }
0300 EXPORT_SYMBOL_GPL(nfs_do_submount);
0301 
0302 int nfs_submount(struct fs_context *fc, struct nfs_server *server)
0303 {
0304     struct nfs_fs_context *ctx = nfs_fc2context(fc);
0305     struct dentry *dentry = ctx->clone_data.dentry;
0306     struct dentry *parent = dget_parent(dentry);
0307     int err;
0308 
0309     /* Look it up again to get its attributes */
0310     err = server->nfs_client->rpc_ops->lookup(d_inode(parent), dentry,
0311                           ctx->mntfh, ctx->clone_data.fattr);
0312     dput(parent);
0313     if (err != 0)
0314         return err;
0315 
0316     ctx->selected_flavor = server->client->cl_auth->au_flavor;
0317     return nfs_do_submount(fc);
0318 }
0319 EXPORT_SYMBOL_GPL(nfs_submount);
0320 
0321 static int param_set_nfs_timeout(const char *val, const struct kernel_param *kp)
0322 {
0323     long num;
0324     int ret;
0325 
0326     if (!val)
0327         return -EINVAL;
0328     ret = kstrtol(val, 0, &num);
0329     if (ret)
0330         return -EINVAL;
0331     if (num > 0) {
0332         if (num >= INT_MAX / HZ)
0333             num = INT_MAX;
0334         else
0335             num *= HZ;
0336         *((int *)kp->arg) = num;
0337         if (!list_empty(&nfs_automount_list))
0338             mod_delayed_work(system_wq, &nfs_automount_task, num);
0339     } else {
0340         *((int *)kp->arg) = -1*HZ;
0341         cancel_delayed_work(&nfs_automount_task);
0342     }
0343     return 0;
0344 }
0345 
0346 static int param_get_nfs_timeout(char *buffer, const struct kernel_param *kp)
0347 {
0348     long num = *((int *)kp->arg);
0349 
0350     if (num > 0) {
0351         if (num >= INT_MAX - (HZ - 1))
0352             num = INT_MAX / HZ;
0353         else
0354             num = (num + (HZ - 1)) / HZ;
0355     } else
0356         num = -1;
0357     return scnprintf(buffer, PAGE_SIZE, "%li\n", num);
0358 }
0359 
0360 static const struct kernel_param_ops param_ops_nfs_timeout = {
0361     .set = param_set_nfs_timeout,
0362     .get = param_get_nfs_timeout,
0363 };
0364 #define param_check_nfs_timeout(name, p) __param_check(name, p, int)
0365 
0366 module_param(nfs_mountpoint_expiry_timeout, nfs_timeout, 0644);
0367 MODULE_PARM_DESC(nfs_mountpoint_expiry_timeout,
0368         "Set the NFS automounted mountpoint timeout value (seconds)."
0369         "Values <= 0 turn expiration off.");