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_lookup_cell_rcu(net, name, len);
 127        if (!IS_ERR(cell)) {
 128                afs_put_cell(net, cell);
 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        unsigned int seq = 0;
 183        char *name;
 184        int len;
 185
 186        if (!net->ws_cell)
 187                return ERR_PTR(-ENOENT);
 188
 189        ret = ERR_PTR(-ENOMEM);
 190        name = kmalloc(AFS_MAXCELLNAME + 1, GFP_KERNEL);
 191        if (!name)
 192                goto out_p;
 193
 194        rcu_read_lock();
 195        do {
 196                read_seqbegin_or_lock(&net->cells_lock, &seq);
 197                cell = rcu_dereference_raw(net->ws_cell);
 198                if (cell) {
 199                        len = cell->name_len;
 200                        memcpy(name, cell->name, len + 1);
 201                }
 202        } while (need_seqretry(&net->cells_lock, seq));
 203        done_seqretry(&net->cells_lock, seq);
 204        rcu_read_unlock();
 205
 206        ret = ERR_PTR(-ENOENT);
 207        if (!cell)
 208                goto out_n;
 209
 210        ret = lookup_one_len(name, dentry->d_parent, len);
 211
 212        /* We don't want to d_add() the @cell dentry here as we don't want to
 213         * the cached dentry to hide changes to the local cell name.
 214         */
 215
 216out_n:
 217        kfree(name);
 218out_p:
 219        return ret;
 220}
 221
 222/*
 223 * Look up an entry in a dynroot directory.
 224 */
 225static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
 226                                         unsigned int flags)
 227{
 228        _enter("%pd", dentry);
 229
 230        ASSERTCMP(d_inode(dentry), ==, NULL);
 231
 232        if (flags & LOOKUP_CREATE)
 233                return ERR_PTR(-EOPNOTSUPP);
 234
 235        if (dentry->d_name.len >= AFSNAMEMAX) {
 236                _leave(" = -ENAMETOOLONG");
 237                return ERR_PTR(-ENAMETOOLONG);
 238        }
 239
 240        if (dentry->d_name.len == 5 &&
 241            memcmp(dentry->d_name.name, "@cell", 5) == 0)
 242                return afs_lookup_atcell(dentry);
 243
 244        return d_splice_alias(afs_try_auto_mntpt(dentry, dir), dentry);
 245}
 246
 247const struct inode_operations afs_dynroot_inode_operations = {
 248        .lookup         = afs_dynroot_lookup,
 249};
 250
 251/*
 252 * Dirs in the dynamic root don't need revalidation.
 253 */
 254static int afs_dynroot_d_revalidate(struct dentry *dentry, unsigned int flags)
 255{
 256        return 1;
 257}
 258
 259/*
 260 * Allow the VFS to enquire as to whether a dentry should be unhashed (mustn't
 261 * sleep)
 262 * - called from dput() when d_count is going to 0.
 263 * - return 1 to request dentry be unhashed, 0 otherwise
 264 */
 265static int afs_dynroot_d_delete(const struct dentry *dentry)
 266{
 267        return d_really_is_positive(dentry);
 268}
 269
 270const struct dentry_operations afs_dynroot_dentry_operations = {
 271        .d_revalidate   = afs_dynroot_d_revalidate,
 272        .d_delete       = afs_dynroot_d_delete,
 273        .d_release      = afs_d_release,
 274        .d_automount    = afs_d_automount,
 275};
 276
 277/*
 278 * Create a manually added cell mount directory.
 279 * - The caller must hold net->proc_cells_lock
 280 */
 281int afs_dynroot_mkdir(struct afs_net *net, struct afs_cell *cell)
 282{
 283        struct super_block *sb = net->dynroot_sb;
 284        struct dentry *root, *subdir;
 285        int ret;
 286
 287        if (!sb || atomic_read(&sb->s_active) == 0)
 288                return 0;
 289
 290        /* Let the ->lookup op do the creation */
 291        root = sb->s_root;
 292        inode_lock(root->d_inode);
 293        subdir = lookup_one_len(cell->name, root, cell->name_len);
 294        if (IS_ERR(subdir)) {
 295                ret = PTR_ERR(subdir);
 296                goto unlock;
 297        }
 298
 299        /* Note that we're retaining an extra ref on the dentry */
 300        subdir->d_fsdata = (void *)1UL;
 301        ret = 0;
 302unlock:
 303        inode_unlock(root->d_inode);
 304        return ret;
 305}
 306
 307/*
 308 * Remove a manually added cell mount directory.
 309 * - The caller must hold net->proc_cells_lock
 310 */
 311void afs_dynroot_rmdir(struct afs_net *net, struct afs_cell *cell)
 312{
 313        struct super_block *sb = net->dynroot_sb;
 314        struct dentry *root, *subdir;
 315
 316        if (!sb || atomic_read(&sb->s_active) == 0)
 317                return;
 318
 319        root = sb->s_root;
 320        inode_lock(root->d_inode);
 321
 322        /* Don't want to trigger a lookup call, which will re-add the cell */
 323        subdir = try_lookup_one_len(cell->name, root, cell->name_len);
 324        if (IS_ERR_OR_NULL(subdir)) {
 325                _debug("lookup %ld", PTR_ERR(subdir));
 326                goto no_dentry;
 327        }
 328
 329        _debug("rmdir %pd %u", subdir, d_count(subdir));
 330
 331        if (subdir->d_fsdata) {
 332                _debug("unpin %u", d_count(subdir));
 333                subdir->d_fsdata = NULL;
 334                dput(subdir);
 335        }
 336        dput(subdir);
 337no_dentry:
 338        inode_unlock(root->d_inode);
 339        _leave("");
 340}
 341
 342/*
 343 * Populate a newly created dynamic root with cell names.
 344 */
 345int afs_dynroot_populate(struct super_block *sb)
 346{
 347        struct afs_cell *cell;
 348        struct afs_net *net = afs_sb2net(sb);
 349        int ret;
 350
 351        mutex_lock(&net->proc_cells_lock);
 352
 353        net->dynroot_sb = sb;
 354        hlist_for_each_entry(cell, &net->proc_cells, proc_link) {
 355                ret = afs_dynroot_mkdir(net, cell);
 356                if (ret < 0)
 357                        goto error;
 358        }
 359
 360        ret = 0;
 361out:
 362        mutex_unlock(&net->proc_cells_lock);
 363        return ret;
 364
 365error:
 366        net->dynroot_sb = NULL;
 367        goto out;
 368}
 369
 370/*
 371 * When a dynamic root that's in the process of being destroyed, depopulate it
 372 * of pinned directories.
 373 */
 374void afs_dynroot_depopulate(struct super_block *sb)
 375{
 376        struct afs_net *net = afs_sb2net(sb);
 377        struct dentry *root = sb->s_root, *subdir, *tmp;
 378
 379        /* Prevent more subdirs from being created */
 380        mutex_lock(&net->proc_cells_lock);
 381        if (net->dynroot_sb == sb)
 382                net->dynroot_sb = NULL;
 383        mutex_unlock(&net->proc_cells_lock);
 384
 385        if (root) {
 386                inode_lock(root->d_inode);
 387
 388                /* Remove all the pins for dirs created for manually added cells */
 389                list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) {
 390                        if (subdir->d_fsdata) {
 391                                subdir->d_fsdata = NULL;
 392                                dput(subdir);
 393                        }
 394                }
 395
 396                inode_unlock(root->d_inode);
 397        }
 398}
 399