Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* mountpoint management
0003  *
0004  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/init.h>
0011 #include <linux/fs.h>
0012 #include <linux/pagemap.h>
0013 #include <linux/mount.h>
0014 #include <linux/namei.h>
0015 #include <linux/gfp.h>
0016 #include <linux/fs_context.h>
0017 #include "internal.h"
0018 
0019 
0020 static struct dentry *afs_mntpt_lookup(struct inode *dir,
0021                        struct dentry *dentry,
0022                        unsigned int flags);
0023 static int afs_mntpt_open(struct inode *inode, struct file *file);
0024 static void afs_mntpt_expiry_timed_out(struct work_struct *work);
0025 
0026 const struct file_operations afs_mntpt_file_operations = {
0027     .open       = afs_mntpt_open,
0028     .llseek     = noop_llseek,
0029 };
0030 
0031 const struct inode_operations afs_mntpt_inode_operations = {
0032     .lookup     = afs_mntpt_lookup,
0033     .readlink   = page_readlink,
0034     .getattr    = afs_getattr,
0035 };
0036 
0037 const struct inode_operations afs_autocell_inode_operations = {
0038     .getattr    = afs_getattr,
0039 };
0040 
0041 static LIST_HEAD(afs_vfsmounts);
0042 static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out);
0043 
0044 static unsigned long afs_mntpt_expiry_timeout = 10 * 60;
0045 
0046 static const char afs_root_volume[] = "root.cell";
0047 
0048 /*
0049  * no valid lookup procedure on this sort of dir
0050  */
0051 static struct dentry *afs_mntpt_lookup(struct inode *dir,
0052                        struct dentry *dentry,
0053                        unsigned int flags)
0054 {
0055     _enter("%p,%p{%pd2}", dir, dentry, dentry);
0056     return ERR_PTR(-EREMOTE);
0057 }
0058 
0059 /*
0060  * no valid open procedure on this sort of dir
0061  */
0062 static int afs_mntpt_open(struct inode *inode, struct file *file)
0063 {
0064     _enter("%p,%p{%pD2}", inode, file, file);
0065     return -EREMOTE;
0066 }
0067 
0068 /*
0069  * Set the parameters for the proposed superblock.
0070  */
0071 static int afs_mntpt_set_params(struct fs_context *fc, struct dentry *mntpt)
0072 {
0073     struct afs_fs_context *ctx = fc->fs_private;
0074     struct afs_super_info *src_as = AFS_FS_S(mntpt->d_sb);
0075     struct afs_vnode *vnode = AFS_FS_I(d_inode(mntpt));
0076     struct afs_cell *cell;
0077     const char *p;
0078     int ret;
0079 
0080     if (fc->net_ns != src_as->net_ns) {
0081         put_net(fc->net_ns);
0082         fc->net_ns = get_net(src_as->net_ns);
0083     }
0084 
0085     if (src_as->volume && src_as->volume->type == AFSVL_RWVOL) {
0086         ctx->type = AFSVL_RWVOL;
0087         ctx->force = true;
0088     }
0089     if (ctx->cell) {
0090         afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_mntpt);
0091         ctx->cell = NULL;
0092     }
0093     if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) {
0094         /* if the directory is a pseudo directory, use the d_name */
0095         unsigned size = mntpt->d_name.len;
0096 
0097         if (size < 2)
0098             return -ENOENT;
0099 
0100         p = mntpt->d_name.name;
0101         if (mntpt->d_name.name[0] == '.') {
0102             size--;
0103             p++;
0104             ctx->type = AFSVL_RWVOL;
0105             ctx->force = true;
0106         }
0107         if (size > AFS_MAXCELLNAME)
0108             return -ENAMETOOLONG;
0109 
0110         cell = afs_lookup_cell(ctx->net, p, size, NULL, false);
0111         if (IS_ERR(cell)) {
0112             pr_err("kAFS: unable to lookup cell '%pd'\n", mntpt);
0113             return PTR_ERR(cell);
0114         }
0115         ctx->cell = cell;
0116 
0117         ctx->volname = afs_root_volume;
0118         ctx->volnamesz = sizeof(afs_root_volume) - 1;
0119     } else {
0120         /* read the contents of the AFS special symlink */
0121         struct page *page;
0122         loff_t size = i_size_read(d_inode(mntpt));
0123         char *buf;
0124 
0125         if (src_as->cell)
0126             ctx->cell = afs_use_cell(src_as->cell, afs_cell_trace_use_mntpt);
0127 
0128         if (size < 2 || size > PAGE_SIZE - 1)
0129             return -EINVAL;
0130 
0131         page = read_mapping_page(d_inode(mntpt)->i_mapping, 0, NULL);
0132         if (IS_ERR(page))
0133             return PTR_ERR(page);
0134 
0135         buf = kmap(page);
0136         ret = -EINVAL;
0137         if (buf[size - 1] == '.')
0138             ret = vfs_parse_fs_string(fc, "source", buf, size - 1);
0139         kunmap(page);
0140         put_page(page);
0141         if (ret < 0)
0142             return ret;
0143     }
0144 
0145     return 0;
0146 }
0147 
0148 /*
0149  * create a vfsmount to be automounted
0150  */
0151 static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
0152 {
0153     struct fs_context *fc;
0154     struct vfsmount *mnt;
0155     int ret;
0156 
0157     BUG_ON(!d_inode(mntpt));
0158 
0159     fc = fs_context_for_submount(&afs_fs_type, mntpt);
0160     if (IS_ERR(fc))
0161         return ERR_CAST(fc);
0162 
0163     ret = afs_mntpt_set_params(fc, mntpt);
0164     if (!ret)
0165         mnt = fc_mount(fc);
0166     else
0167         mnt = ERR_PTR(ret);
0168 
0169     put_fs_context(fc);
0170     return mnt;
0171 }
0172 
0173 /*
0174  * handle an automount point
0175  */
0176 struct vfsmount *afs_d_automount(struct path *path)
0177 {
0178     struct vfsmount *newmnt;
0179 
0180     _enter("{%pd}", path->dentry);
0181 
0182     newmnt = afs_mntpt_do_automount(path->dentry);
0183     if (IS_ERR(newmnt))
0184         return newmnt;
0185 
0186     mntget(newmnt); /* prevent immediate expiration */
0187     mnt_set_expiry(newmnt, &afs_vfsmounts);
0188     queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
0189                afs_mntpt_expiry_timeout * HZ);
0190     _leave(" = %p", newmnt);
0191     return newmnt;
0192 }
0193 
0194 /*
0195  * handle mountpoint expiry timer going off
0196  */
0197 static void afs_mntpt_expiry_timed_out(struct work_struct *work)
0198 {
0199     _enter("");
0200 
0201     if (!list_empty(&afs_vfsmounts)) {
0202         mark_mounts_for_expiry(&afs_vfsmounts);
0203         queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
0204                    afs_mntpt_expiry_timeout * HZ);
0205     }
0206 
0207     _leave("");
0208 }
0209 
0210 /*
0211  * kill the AFS mountpoint timer if it's still running
0212  */
0213 void afs_mntpt_kill_timer(void)
0214 {
0215     _enter("");
0216 
0217     ASSERT(list_empty(&afs_vfsmounts));
0218     cancel_delayed_work_sync(&afs_mntpt_expiry_timer);
0219 }