linux/fs/afs/dynroot.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* AFS dynamic root handling
   3 *
   4 * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
   5 * Written by David Howells (dhowells@redhat.com)
   6 */
   7
   8#include <linux/fs.h>
   9#include <linux/namei.h>
  10#include <linux/dns_resolver.h>
  11#include "internal.h"
  12
  13static atomic_t afs_autocell_ino;
  14
  15/*
  16 * iget5() comparator for inode created by autocell operations
  17 *
  18 * These pseudo inodes don't match anything.
  19 */
  20static int afs_iget5_pseudo_test(struct inode *inode, void *opaque)
  21{
  22        return 0;
  23}
  24
  25/*
  26 * iget5() inode initialiser
  27 */
  28static int afs_iget5_pseudo_set(struct inode *inode, void *opaque)
  29{
  30        struct afs_super_info *as = AFS_FS_S(inode->i_sb);
  31        struct afs_vnode *vnode = AFS_FS_I(inode);
  32        struct afs_fid *fid = opaque;
  33
  34        vnode->volume           = as->volume;
  35        vnode->fid              = *fid;
  36        inode->i_ino            = fid->vnode;
  37        inode->i_generation     = fid->unique;
  38        return 0;
  39}
  40
  41/*
  42 * Create an inode for a dynamic root directory or an autocell dynamic
  43 * automount dir.
  44 */
  45struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root)
  46{
  47        struct afs_super_info *as = AFS_FS_S(sb);
  48        struct afs_vnode *vnode;
  49        struct inode *inode;
  50        struct afs_fid fid = {};
  51
  52        _enter("");
  53
  54        if (as->volume)
  55                fid.vid = as->volume->vid;
  56        if (root) {
  57                fid.vnode = 1;
  58                fid.unique = 1;
  59        } else {
  60                fid.vnode = atomic_inc_return(&afs_autocell_ino);
  61                fid.unique = 0;
  62        }
  63
  64        inode = iget5_locked(sb, fid.vnode,
  65                             afs_iget5_pseudo_test, afs_iget5_pseudo_set, &fid);
  66        if (!inode) {
  67                _leave(" = -ENOMEM");
  68                return ERR_PTR(-ENOMEM);
  69        }
  70
  71        _debug("GOT INODE %p { ino=%lu, vl=%llx, vn=%llx, u=%x }",
  72               inode, inode->i_ino, fid.vid, fid.vnode, fid.unique);
  73
  74        vnode = AFS_FS_I(inode);
  75
  76        /* there shouldn't be an existing inode */
  77        BUG_ON(!(inode->i_state & I_NEW));
  78
  79        inode->i_size           = 0;
  80        inode->i_mode           = S_IFDIR | S_IRUGO | S_IXUGO;
  81        if (root) {
  82                inode->i_op     = &afs_dynroot_inode_operations;
  83                inode->i_fop    = &simple_dir_operations;
  84        } else {
  85                inode->i_op     = &afs_autocell_inode_operations;
  86        }
  87        set_nlink(inode, 2);
  88        inode->i_uid            = GLOBAL_ROOT_UID;
  89        inode->i_gid            = GLOBAL_ROOT_GID;
  90        inode->i_ctime = inode->i_atime = inode->i_mtime = current_time(inode);
  91        inode->i_blocks         = 0;
  92        inode->i_generation     = 0;
  93
  94        set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags);
  95        if (!root) {
  96                set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
  97                inode->i_flags |= S_AUTOMOUNT;
  98        }
  99
 100        inode->i_flags |= S_NOATIME;
 101        unlock_new_inode(inode);
 102        _leave(" = %p", inode);
 103        return inode;
 104}
 105
 106/*
 107 * Probe to see if a cell may exist.  This prevents positive dentries from
 108 * being created unnecessarily.
 109 */
 110static int afs_probe_cell_name(struct dentry *dentry)
 111{
 112        struct afs_cell *cell;
 113        struct afs_net *net = afs_d2net(dentry);
 114        const char *name = dentry->d_name.name;
 115        size_t len = dentry->d_name.len;
 116        int ret;
 117
 118        /* Names prefixed with a dot are R/W mounts. */
 119        if (name[0] == '.') {
 120                if (len == 1)
 121                        return -EINVAL;
 122                name++;
 123                len--;
 124        }
 125
 126        cell = afs_find_cell(net, name, len, afs_cell_trace_use_probe);
 127        if (!IS_ERR(cell)) {
 128                afs_unuse_cell(net, cell, afs_cell_trace_unuse_probe);
 129                return 0;
 130        }
 131
 132        ret = dns_query(net->net, "afsdb", name, len, "srv=1",
 133                        NULL, NULL, false);
 134        if (ret == -ENODATA)
 135                ret = -EDESTADDRREQ;
 136        return ret;
 137}
 138
 139/*
 140 * Try to auto mount the mountpoint with pseudo directory, if the autocell
 141 * operation is setted.
 142 */
 143struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir)
 144{
 145        struct afs_vnode *vnode = AFS_FS_I(dir);
 146        struct inode *inode;
 147        int ret = -ENOENT;
 148
 149        _enter("%p{%pd}, {%llx:%llu}",
 150               dentry, dentry, vnode->fid.vid, vnode->fid.vnode);
 151
 152        if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
 153                goto out;
 154
 155        ret = afs_probe_cell_name(dentry);
 156        if (ret < 0)
 157                goto out;
 158
 159        inode = afs_iget_pseudo_dir(dir->i_sb, false);
 160        if (IS_ERR(inode)) {
 161                ret = PTR_ERR(inode);
 162                goto out;
 163        }
 164
 165        _leave("= %p", inode);
 166        return inode;
 167
 168out:
 169        _leave("= %d", ret);
 170        return ret == -ENOENT ? NULL : ERR_PTR(ret);
 171}
 172
 173/*
 174 * Look up @cell in a dynroot directory.  This is a substitution for the
 175 * local cell name for the net namespace.
 176 */
 177static struct dentry *afs_lookup_atcell(struct dentry *dentry)
 178{
 179        struct afs_cell *cell;
 180        struct afs_net *net = afs_d2net(dentry);
 181        struct dentry *ret;
 182        char *name;
 183        int len;
 184
 185        if (!net->ws_cell)
 186                return ERR_PTR(-ENOENT);
 187
 188        ret = ERR_PTR(-ENOMEM);
 189        name = kmalloc(AFS_MAXCELLNAME + 1, GFP_KERNEL);
 190        if (!name)
 191                goto out_p;
 192
 193        down_read(&net->cells_lock);
 194        cell = net->ws_cell;
 195        if (cell) {
 196                len = cell->name_len;
 197                memcpy(name, cell->name, len + 1);
 198        }
 199        up_read(&net->cells_lock);
 200
 201        ret = ERR_PTR(-ENOENT);
 202        if (!cell)
 203                goto out_n;
 204
 205        ret = lookup_one_len(name, dentry->d_parent, len);
 206
 207        /* We don't want to d_add() the @cell dentry here as we don't want to
 208         * the cached dentry to hide changes to the local cell name.
 209         */
 210
 211out_n:
 212        kfree(name);
 213out_p:
 214        return ret;
 215}
 216
 217/*
 218 * Look up an entry in a dynroot directory.
 219 */
 220static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
 221                                         unsigned int flags)
 222{
 223        _enter("%pd", dentry);
 224
 225        ASSERTCMP(d_inode(dentry), ==, NULL);
 226
 227        if (flags & LOOKUP_CREATE)
 228                return ERR_PTR(-EOPNOTSUPP);
 229
 230        if (dentry->d_name.len >= AFSNAMEMAX) {
 231                _leave(" = -ENAMETOOLONG");
 232                return ERR_PTR(-ENAMETOOLONG);
 233        }
 234
 235        if (dentry->d_name.len == 5 &&
 236            memcmp(dentry->d_name.name, "@cell", 5) == 0)
 237                return afs_lookup_atcell(dentry);
 238
 239        return d_splice_alias(afs_try_auto_mntpt(dentry, dir), dentry);
 240}
 241
 242const struct inode_operations afs_dynroot_inode_operations = {
 243        .lookup         = afs_dynroot_lookup,
 244};
 245
 246/*
 247 * Dirs in the dynamic root don't need revalidation.
 248 */
 249static int afs_dynroot_d_revalidate(struct dentry *dentry, unsigned int flags)
 250{
 251        return 1;
 252}
 253
 254/*
 255 * Allow the VFS to enquire as to whether a dentry should be unhashed (mustn't
 256 * sleep)
 257 * - called from dput() when d_count is going to 0.
 258 * - return 1 to request dentry be unhashed, 0 otherwise
 259 */
 260static int afs_dynroot_d_delete(const struct dentry *dentry)
 261{
 262        return d_really_is_positive(dentry);
 263}
 264
 265const struct dentry_operations afs_dynroot_dentry_operations = {
 266        .d_revalidate   = afs_dynroot_d_revalidate,
 267        .d_delete       = afs_dynroot_d_delete,
 268        .d_release      = afs_d_release,
 269        .d_automount    = afs_d_automount,
 270};
 271
 272/*
 273 * Create a manually added cell mount directory.
 274 * - The caller must hold net->proc_cells_lock
 275 */
 276int afs_dynroot_mkdir(struct afs_net *net, struct afs_cell *cell)
 277{
 278        struct super_block *sb = net->dynroot_sb;
 279        struct dentry *root, *subdir;
 280        int ret;
 281
 282        if (!sb || atomic_read(&sb->s_active) == 0)
 283                return 0;
 284
 285        /* Let the ->lookup op do the creation */
 286        root = sb->s_root;
 287        inode_lock(root->d_inode);
 288        subdir = lookup_one_len(cell->name, root, cell->name_len);
 289        if (IS_ERR(subdir)) {
 290                ret = PTR_ERR(subdir);
 291                goto unlock;
 292        }
 293
 294        /* Note that we're retaining an extra ref on the dentry */
 295        subdir->d_fsdata = (void *)1UL;
 296        ret = 0;
 297unlock:
 298        inode_unlock(root->d_inode);
 299        return ret;
 300}
 301
 302/*
 303 * Remove a manually added cell mount directory.
 304 * - The caller must hold net->proc_cells_lock
 305 */
 306void afs_dynroot_rmdir(struct afs_net *net, struct afs_cell *cell)
 307{
 308        struct super_block *sb = net->dynroot_sb;
 309        struct dentry *root, *subdir;
 310
 311        if (!sb || atomic_read(&sb->s_active) == 0)
 312                return;
 313
 314        root = sb->s_root;
 315        inode_lock(root->d_inode);
 316
 317        /* Don't want to trigger a lookup call, which will re-add the cell */
 318        subdir = try_lookup_one_len(cell->name, root, cell->name_len);
 319        if (IS_ERR_OR_NULL(subdir)) {
 320                _debug("lookup %ld", PTR_ERR(subdir));
 321                goto no_dentry;
 322        }
 323
 324        _debug("rmdir %pd %u", subdir, d_count(subdir));
 325
 326        if (subdir->d_fsdata) {
 327                _debug("unpin %u", d_count(subdir));
 328                subdir->d_fsdata = NULL;
 329                dput(subdir);
 330        }
 331        dput(subdir);
 332no_dentry:
 333        inode_unlock(root->d_inode);
 334        _leave("");
 335}
 336
 337/*
 338 * Populate a newly created dynamic root with cell names.
 339 */
 340int afs_dynroot_populate(struct super_block *sb)
 341{
 342        struct afs_cell *cell;
 343        struct afs_net *net = afs_sb2net(sb);
 344        int ret;
 345
 346        mutex_lock(&net->proc_cells_lock);
 347
 348        net->dynroot_sb = sb;
 349        hlist_for_each_entry(cell, &net->proc_cells, proc_link) {
 350                ret = afs_dynroot_mkdir(net, cell);
 351                if (ret < 0)
 352                        goto error;
 353        }
 354
 355        ret = 0;
 356out:
 357        mutex_unlock(&net->proc_cells_lock);
 358        return ret;
 359
 360error:
 361        net->dynroot_sb = NULL;
 362        goto out;
 363}
 364
 365/*
 366 * When a dynamic root that's in the process of being destroyed, depopulate it
 367 * of pinned directories.
 368 */
 369void afs_dynroot_depopulate(struct super_block *sb)
 370{
 371        struct afs_net *net = afs_sb2net(sb);
 372        struct dentry *root = sb->s_root, *subdir, *tmp;
 373
 374        /* Prevent more subdirs from being created */
 375        mutex_lock(&net->proc_cells_lock);
 376        if (net->dynroot_sb == sb)
 377                net->dynroot_sb = NULL;
 378        mutex_unlock(&net->proc_cells_lock);
 379
 380        if (root) {
 381                inode_lock(root->d_inode);
 382
 383                /* Remove all the pins for dirs created for manually added cells */
 384                list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) {
 385                        if (subdir->d_fsdata) {
 386                                subdir->d_fsdata = NULL;
 387                                dput(subdir);
 388                        }
 389                }
 390
 391                inode_unlock(root->d_inode);
 392        }
 393}
 394