Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* AFS dynamic root handling
0003  *
0004  * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  */
0007 
0008 #include <linux/fs.h>
0009 #include <linux/namei.h>
0010 #include <linux/dns_resolver.h>
0011 #include "internal.h"
0012 
0013 static atomic_t afs_autocell_ino;
0014 
0015 /*
0016  * iget5() comparator for inode created by autocell operations
0017  *
0018  * These pseudo inodes don't match anything.
0019  */
0020 static int afs_iget5_pseudo_test(struct inode *inode, void *opaque)
0021 {
0022     return 0;
0023 }
0024 
0025 /*
0026  * iget5() inode initialiser
0027  */
0028 static int afs_iget5_pseudo_set(struct inode *inode, void *opaque)
0029 {
0030     struct afs_super_info *as = AFS_FS_S(inode->i_sb);
0031     struct afs_vnode *vnode = AFS_FS_I(inode);
0032     struct afs_fid *fid = opaque;
0033 
0034     vnode->volume       = as->volume;
0035     vnode->fid      = *fid;
0036     inode->i_ino        = fid->vnode;
0037     inode->i_generation = fid->unique;
0038     return 0;
0039 }
0040 
0041 /*
0042  * Create an inode for a dynamic root directory or an autocell dynamic
0043  * automount dir.
0044  */
0045 struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root)
0046 {
0047     struct afs_super_info *as = AFS_FS_S(sb);
0048     struct afs_vnode *vnode;
0049     struct inode *inode;
0050     struct afs_fid fid = {};
0051 
0052     _enter("");
0053 
0054     if (as->volume)
0055         fid.vid = as->volume->vid;
0056     if (root) {
0057         fid.vnode = 1;
0058         fid.unique = 1;
0059     } else {
0060         fid.vnode = atomic_inc_return(&afs_autocell_ino);
0061         fid.unique = 0;
0062     }
0063 
0064     inode = iget5_locked(sb, fid.vnode,
0065                  afs_iget5_pseudo_test, afs_iget5_pseudo_set, &fid);
0066     if (!inode) {
0067         _leave(" = -ENOMEM");
0068         return ERR_PTR(-ENOMEM);
0069     }
0070 
0071     _debug("GOT INODE %p { ino=%lu, vl=%llx, vn=%llx, u=%x }",
0072            inode, inode->i_ino, fid.vid, fid.vnode, fid.unique);
0073 
0074     vnode = AFS_FS_I(inode);
0075 
0076     /* there shouldn't be an existing inode */
0077     BUG_ON(!(inode->i_state & I_NEW));
0078 
0079     netfs_inode_init(&vnode->netfs, NULL);
0080     inode->i_size       = 0;
0081     inode->i_mode       = S_IFDIR | S_IRUGO | S_IXUGO;
0082     if (root) {
0083         inode->i_op = &afs_dynroot_inode_operations;
0084         inode->i_fop    = &simple_dir_operations;
0085     } else {
0086         inode->i_op = &afs_autocell_inode_operations;
0087     }
0088     set_nlink(inode, 2);
0089     inode->i_uid        = GLOBAL_ROOT_UID;
0090     inode->i_gid        = GLOBAL_ROOT_GID;
0091     inode->i_ctime = inode->i_atime = inode->i_mtime = current_time(inode);
0092     inode->i_blocks     = 0;
0093     inode->i_generation = 0;
0094 
0095     set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags);
0096     if (!root) {
0097         set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
0098         inode->i_flags |= S_AUTOMOUNT;
0099     }
0100 
0101     inode->i_flags |= S_NOATIME;
0102     unlock_new_inode(inode);
0103     _leave(" = %p", inode);
0104     return inode;
0105 }
0106 
0107 /*
0108  * Probe to see if a cell may exist.  This prevents positive dentries from
0109  * being created unnecessarily.
0110  */
0111 static int afs_probe_cell_name(struct dentry *dentry)
0112 {
0113     struct afs_cell *cell;
0114     struct afs_net *net = afs_d2net(dentry);
0115     const char *name = dentry->d_name.name;
0116     size_t len = dentry->d_name.len;
0117     int ret;
0118 
0119     /* Names prefixed with a dot are R/W mounts. */
0120     if (name[0] == '.') {
0121         if (len == 1)
0122             return -EINVAL;
0123         name++;
0124         len--;
0125     }
0126 
0127     cell = afs_find_cell(net, name, len, afs_cell_trace_use_probe);
0128     if (!IS_ERR(cell)) {
0129         afs_unuse_cell(net, cell, afs_cell_trace_unuse_probe);
0130         return 0;
0131     }
0132 
0133     ret = dns_query(net->net, "afsdb", name, len, "srv=1",
0134             NULL, NULL, false);
0135     if (ret == -ENODATA)
0136         ret = -EDESTADDRREQ;
0137     return ret;
0138 }
0139 
0140 /*
0141  * Try to auto mount the mountpoint with pseudo directory, if the autocell
0142  * operation is setted.
0143  */
0144 struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir)
0145 {
0146     struct afs_vnode *vnode = AFS_FS_I(dir);
0147     struct inode *inode;
0148     int ret = -ENOENT;
0149 
0150     _enter("%p{%pd}, {%llx:%llu}",
0151            dentry, dentry, vnode->fid.vid, vnode->fid.vnode);
0152 
0153     if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
0154         goto out;
0155 
0156     ret = afs_probe_cell_name(dentry);
0157     if (ret < 0)
0158         goto out;
0159 
0160     inode = afs_iget_pseudo_dir(dir->i_sb, false);
0161     if (IS_ERR(inode)) {
0162         ret = PTR_ERR(inode);
0163         goto out;
0164     }
0165 
0166     _leave("= %p", inode);
0167     return inode;
0168 
0169 out:
0170     _leave("= %d", ret);
0171     return ret == -ENOENT ? NULL : ERR_PTR(ret);
0172 }
0173 
0174 /*
0175  * Look up @cell in a dynroot directory.  This is a substitution for the
0176  * local cell name for the net namespace.
0177  */
0178 static struct dentry *afs_lookup_atcell(struct dentry *dentry)
0179 {
0180     struct afs_cell *cell;
0181     struct afs_net *net = afs_d2net(dentry);
0182     struct dentry *ret;
0183     char *name;
0184     int len;
0185 
0186     if (!net->ws_cell)
0187         return ERR_PTR(-ENOENT);
0188 
0189     ret = ERR_PTR(-ENOMEM);
0190     name = kmalloc(AFS_MAXCELLNAME + 1, GFP_KERNEL);
0191     if (!name)
0192         goto out_p;
0193 
0194     down_read(&net->cells_lock);
0195     cell = net->ws_cell;
0196     if (cell) {
0197         len = cell->name_len;
0198         memcpy(name, cell->name, len + 1);
0199     }
0200     up_read(&net->cells_lock);
0201 
0202     ret = ERR_PTR(-ENOENT);
0203     if (!cell)
0204         goto out_n;
0205 
0206     ret = lookup_one_len(name, dentry->d_parent, len);
0207 
0208     /* We don't want to d_add() the @cell dentry here as we don't want to
0209      * the cached dentry to hide changes to the local cell name.
0210      */
0211 
0212 out_n:
0213     kfree(name);
0214 out_p:
0215     return ret;
0216 }
0217 
0218 /*
0219  * Look up an entry in a dynroot directory.
0220  */
0221 static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
0222                      unsigned int flags)
0223 {
0224     _enter("%pd", dentry);
0225 
0226     ASSERTCMP(d_inode(dentry), ==, NULL);
0227 
0228     if (flags & LOOKUP_CREATE)
0229         return ERR_PTR(-EOPNOTSUPP);
0230 
0231     if (dentry->d_name.len >= AFSNAMEMAX) {
0232         _leave(" = -ENAMETOOLONG");
0233         return ERR_PTR(-ENAMETOOLONG);
0234     }
0235 
0236     if (dentry->d_name.len == 5 &&
0237         memcmp(dentry->d_name.name, "@cell", 5) == 0)
0238         return afs_lookup_atcell(dentry);
0239 
0240     return d_splice_alias(afs_try_auto_mntpt(dentry, dir), dentry);
0241 }
0242 
0243 const struct inode_operations afs_dynroot_inode_operations = {
0244     .lookup     = afs_dynroot_lookup,
0245 };
0246 
0247 /*
0248  * Dirs in the dynamic root don't need revalidation.
0249  */
0250 static int afs_dynroot_d_revalidate(struct dentry *dentry, unsigned int flags)
0251 {
0252     return 1;
0253 }
0254 
0255 /*
0256  * Allow the VFS to enquire as to whether a dentry should be unhashed (mustn't
0257  * sleep)
0258  * - called from dput() when d_count is going to 0.
0259  * - return 1 to request dentry be unhashed, 0 otherwise
0260  */
0261 static int afs_dynroot_d_delete(const struct dentry *dentry)
0262 {
0263     return d_really_is_positive(dentry);
0264 }
0265 
0266 const struct dentry_operations afs_dynroot_dentry_operations = {
0267     .d_revalidate   = afs_dynroot_d_revalidate,
0268     .d_delete   = afs_dynroot_d_delete,
0269     .d_release  = afs_d_release,
0270     .d_automount    = afs_d_automount,
0271 };
0272 
0273 /*
0274  * Create a manually added cell mount directory.
0275  * - The caller must hold net->proc_cells_lock
0276  */
0277 int afs_dynroot_mkdir(struct afs_net *net, struct afs_cell *cell)
0278 {
0279     struct super_block *sb = net->dynroot_sb;
0280     struct dentry *root, *subdir;
0281     int ret;
0282 
0283     if (!sb || atomic_read(&sb->s_active) == 0)
0284         return 0;
0285 
0286     /* Let the ->lookup op do the creation */
0287     root = sb->s_root;
0288     inode_lock(root->d_inode);
0289     subdir = lookup_one_len(cell->name, root, cell->name_len);
0290     if (IS_ERR(subdir)) {
0291         ret = PTR_ERR(subdir);
0292         goto unlock;
0293     }
0294 
0295     /* Note that we're retaining an extra ref on the dentry */
0296     subdir->d_fsdata = (void *)1UL;
0297     ret = 0;
0298 unlock:
0299     inode_unlock(root->d_inode);
0300     return ret;
0301 }
0302 
0303 /*
0304  * Remove a manually added cell mount directory.
0305  * - The caller must hold net->proc_cells_lock
0306  */
0307 void afs_dynroot_rmdir(struct afs_net *net, struct afs_cell *cell)
0308 {
0309     struct super_block *sb = net->dynroot_sb;
0310     struct dentry *root, *subdir;
0311 
0312     if (!sb || atomic_read(&sb->s_active) == 0)
0313         return;
0314 
0315     root = sb->s_root;
0316     inode_lock(root->d_inode);
0317 
0318     /* Don't want to trigger a lookup call, which will re-add the cell */
0319     subdir = try_lookup_one_len(cell->name, root, cell->name_len);
0320     if (IS_ERR_OR_NULL(subdir)) {
0321         _debug("lookup %ld", PTR_ERR(subdir));
0322         goto no_dentry;
0323     }
0324 
0325     _debug("rmdir %pd %u", subdir, d_count(subdir));
0326 
0327     if (subdir->d_fsdata) {
0328         _debug("unpin %u", d_count(subdir));
0329         subdir->d_fsdata = NULL;
0330         dput(subdir);
0331     }
0332     dput(subdir);
0333 no_dentry:
0334     inode_unlock(root->d_inode);
0335     _leave("");
0336 }
0337 
0338 /*
0339  * Populate a newly created dynamic root with cell names.
0340  */
0341 int afs_dynroot_populate(struct super_block *sb)
0342 {
0343     struct afs_cell *cell;
0344     struct afs_net *net = afs_sb2net(sb);
0345     int ret;
0346 
0347     mutex_lock(&net->proc_cells_lock);
0348 
0349     net->dynroot_sb = sb;
0350     hlist_for_each_entry(cell, &net->proc_cells, proc_link) {
0351         ret = afs_dynroot_mkdir(net, cell);
0352         if (ret < 0)
0353             goto error;
0354     }
0355 
0356     ret = 0;
0357 out:
0358     mutex_unlock(&net->proc_cells_lock);
0359     return ret;
0360 
0361 error:
0362     net->dynroot_sb = NULL;
0363     goto out;
0364 }
0365 
0366 /*
0367  * When a dynamic root that's in the process of being destroyed, depopulate it
0368  * of pinned directories.
0369  */
0370 void afs_dynroot_depopulate(struct super_block *sb)
0371 {
0372     struct afs_net *net = afs_sb2net(sb);
0373     struct dentry *root = sb->s_root, *subdir, *tmp;
0374 
0375     /* Prevent more subdirs from being created */
0376     mutex_lock(&net->proc_cells_lock);
0377     if (net->dynroot_sb == sb)
0378         net->dynroot_sb = NULL;
0379     mutex_unlock(&net->proc_cells_lock);
0380 
0381     if (root) {
0382         inode_lock(root->d_inode);
0383 
0384         /* Remove all the pins for dirs created for manually added cells */
0385         list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) {
0386             if (subdir->d_fsdata) {
0387                 subdir->d_fsdata = NULL;
0388                 dput(subdir);
0389             }
0390         }
0391 
0392         inode_unlock(root->d_inode);
0393     }
0394 }