root/fs/afs/dynroot.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. afs_probe_cell_name
  2. afs_try_auto_mntpt
  3. afs_lookup_atcell
  4. afs_dynroot_lookup
  5. afs_dynroot_d_revalidate
  6. afs_dynroot_d_delete
  7. afs_dynroot_mkdir
  8. afs_dynroot_rmdir
  9. afs_dynroot_populate
  10. afs_dynroot_depopulate

   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 
  13 /*
  14  * Probe to see if a cell may exist.  This prevents positive dentries from
  15  * being created unnecessarily.
  16  */
  17 static int afs_probe_cell_name(struct dentry *dentry)
  18 {
  19         struct afs_cell *cell;
  20         struct afs_net *net = afs_d2net(dentry);
  21         const char *name = dentry->d_name.name;
  22         size_t len = dentry->d_name.len;
  23         int ret;
  24 
  25         /* Names prefixed with a dot are R/W mounts. */
  26         if (name[0] == '.') {
  27                 if (len == 1)
  28                         return -EINVAL;
  29                 name++;
  30                 len--;
  31         }
  32 
  33         cell = afs_lookup_cell_rcu(net, name, len);
  34         if (!IS_ERR(cell)) {
  35                 afs_put_cell(net, cell);
  36                 return 0;
  37         }
  38 
  39         ret = dns_query(net->net, "afsdb", name, len, "srv=1",
  40                         NULL, NULL, false);
  41         if (ret == -ENODATA)
  42                 ret = -EDESTADDRREQ;
  43         return ret;
  44 }
  45 
  46 /*
  47  * Try to auto mount the mountpoint with pseudo directory, if the autocell
  48  * operation is setted.
  49  */
  50 struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir)
  51 {
  52         struct afs_vnode *vnode = AFS_FS_I(dir);
  53         struct inode *inode;
  54         int ret = -ENOENT;
  55 
  56         _enter("%p{%pd}, {%llx:%llu}",
  57                dentry, dentry, vnode->fid.vid, vnode->fid.vnode);
  58 
  59         if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
  60                 goto out;
  61 
  62         ret = afs_probe_cell_name(dentry);
  63         if (ret < 0)
  64                 goto out;
  65 
  66         inode = afs_iget_pseudo_dir(dir->i_sb, false);
  67         if (IS_ERR(inode)) {
  68                 ret = PTR_ERR(inode);
  69                 goto out;
  70         }
  71 
  72         _leave("= %p", inode);
  73         return inode;
  74 
  75 out:
  76         _leave("= %d", ret);
  77         return ret == -ENOENT ? NULL : ERR_PTR(ret);
  78 }
  79 
  80 /*
  81  * Look up @cell in a dynroot directory.  This is a substitution for the
  82  * local cell name for the net namespace.
  83  */
  84 static struct dentry *afs_lookup_atcell(struct dentry *dentry)
  85 {
  86         struct afs_cell *cell;
  87         struct afs_net *net = afs_d2net(dentry);
  88         struct dentry *ret;
  89         unsigned int seq = 0;
  90         char *name;
  91         int len;
  92 
  93         if (!net->ws_cell)
  94                 return ERR_PTR(-ENOENT);
  95 
  96         ret = ERR_PTR(-ENOMEM);
  97         name = kmalloc(AFS_MAXCELLNAME + 1, GFP_KERNEL);
  98         if (!name)
  99                 goto out_p;
 100 
 101         rcu_read_lock();
 102         do {
 103                 read_seqbegin_or_lock(&net->cells_lock, &seq);
 104                 cell = rcu_dereference_raw(net->ws_cell);
 105                 if (cell) {
 106                         len = cell->name_len;
 107                         memcpy(name, cell->name, len + 1);
 108                 }
 109         } while (need_seqretry(&net->cells_lock, seq));
 110         done_seqretry(&net->cells_lock, seq);
 111         rcu_read_unlock();
 112 
 113         ret = ERR_PTR(-ENOENT);
 114         if (!cell)
 115                 goto out_n;
 116 
 117         ret = lookup_one_len(name, dentry->d_parent, len);
 118 
 119         /* We don't want to d_add() the @cell dentry here as we don't want to
 120          * the cached dentry to hide changes to the local cell name.
 121          */
 122 
 123 out_n:
 124         kfree(name);
 125 out_p:
 126         return ret;
 127 }
 128 
 129 /*
 130  * Look up an entry in a dynroot directory.
 131  */
 132 static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
 133                                          unsigned int flags)
 134 {
 135         _enter("%pd", dentry);
 136 
 137         ASSERTCMP(d_inode(dentry), ==, NULL);
 138 
 139         if (flags & LOOKUP_CREATE)
 140                 return ERR_PTR(-EOPNOTSUPP);
 141 
 142         if (dentry->d_name.len >= AFSNAMEMAX) {
 143                 _leave(" = -ENAMETOOLONG");
 144                 return ERR_PTR(-ENAMETOOLONG);
 145         }
 146 
 147         if (dentry->d_name.len == 5 &&
 148             memcmp(dentry->d_name.name, "@cell", 5) == 0)
 149                 return afs_lookup_atcell(dentry);
 150 
 151         return d_splice_alias(afs_try_auto_mntpt(dentry, dir), dentry);
 152 }
 153 
 154 const struct inode_operations afs_dynroot_inode_operations = {
 155         .lookup         = afs_dynroot_lookup,
 156 };
 157 
 158 /*
 159  * Dirs in the dynamic root don't need revalidation.
 160  */
 161 static int afs_dynroot_d_revalidate(struct dentry *dentry, unsigned int flags)
 162 {
 163         return 1;
 164 }
 165 
 166 /*
 167  * Allow the VFS to enquire as to whether a dentry should be unhashed (mustn't
 168  * sleep)
 169  * - called from dput() when d_count is going to 0.
 170  * - return 1 to request dentry be unhashed, 0 otherwise
 171  */
 172 static int afs_dynroot_d_delete(const struct dentry *dentry)
 173 {
 174         return d_really_is_positive(dentry);
 175 }
 176 
 177 const struct dentry_operations afs_dynroot_dentry_operations = {
 178         .d_revalidate   = afs_dynroot_d_revalidate,
 179         .d_delete       = afs_dynroot_d_delete,
 180         .d_release      = afs_d_release,
 181         .d_automount    = afs_d_automount,
 182 };
 183 
 184 /*
 185  * Create a manually added cell mount directory.
 186  * - The caller must hold net->proc_cells_lock
 187  */
 188 int afs_dynroot_mkdir(struct afs_net *net, struct afs_cell *cell)
 189 {
 190         struct super_block *sb = net->dynroot_sb;
 191         struct dentry *root, *subdir;
 192         int ret;
 193 
 194         if (!sb || atomic_read(&sb->s_active) == 0)
 195                 return 0;
 196 
 197         /* Let the ->lookup op do the creation */
 198         root = sb->s_root;
 199         inode_lock(root->d_inode);
 200         subdir = lookup_one_len(cell->name, root, cell->name_len);
 201         if (IS_ERR(subdir)) {
 202                 ret = PTR_ERR(subdir);
 203                 goto unlock;
 204         }
 205 
 206         /* Note that we're retaining an extra ref on the dentry */
 207         subdir->d_fsdata = (void *)1UL;
 208         ret = 0;
 209 unlock:
 210         inode_unlock(root->d_inode);
 211         return ret;
 212 }
 213 
 214 /*
 215  * Remove a manually added cell mount directory.
 216  * - The caller must hold net->proc_cells_lock
 217  */
 218 void afs_dynroot_rmdir(struct afs_net *net, struct afs_cell *cell)
 219 {
 220         struct super_block *sb = net->dynroot_sb;
 221         struct dentry *root, *subdir;
 222 
 223         if (!sb || atomic_read(&sb->s_active) == 0)
 224                 return;
 225 
 226         root = sb->s_root;
 227         inode_lock(root->d_inode);
 228 
 229         /* Don't want to trigger a lookup call, which will re-add the cell */
 230         subdir = try_lookup_one_len(cell->name, root, cell->name_len);
 231         if (IS_ERR_OR_NULL(subdir)) {
 232                 _debug("lookup %ld", PTR_ERR(subdir));
 233                 goto no_dentry;
 234         }
 235 
 236         _debug("rmdir %pd %u", subdir, d_count(subdir));
 237 
 238         if (subdir->d_fsdata) {
 239                 _debug("unpin %u", d_count(subdir));
 240                 subdir->d_fsdata = NULL;
 241                 dput(subdir);
 242         }
 243         dput(subdir);
 244 no_dentry:
 245         inode_unlock(root->d_inode);
 246         _leave("");
 247 }
 248 
 249 /*
 250  * Populate a newly created dynamic root with cell names.
 251  */
 252 int afs_dynroot_populate(struct super_block *sb)
 253 {
 254         struct afs_cell *cell;
 255         struct afs_net *net = afs_sb2net(sb);
 256         int ret;
 257 
 258         mutex_lock(&net->proc_cells_lock);
 259 
 260         net->dynroot_sb = sb;
 261         hlist_for_each_entry(cell, &net->proc_cells, proc_link) {
 262                 ret = afs_dynroot_mkdir(net, cell);
 263                 if (ret < 0)
 264                         goto error;
 265         }
 266 
 267         ret = 0;
 268 out:
 269         mutex_unlock(&net->proc_cells_lock);
 270         return ret;
 271 
 272 error:
 273         net->dynroot_sb = NULL;
 274         goto out;
 275 }
 276 
 277 /*
 278  * When a dynamic root that's in the process of being destroyed, depopulate it
 279  * of pinned directories.
 280  */
 281 void afs_dynroot_depopulate(struct super_block *sb)
 282 {
 283         struct afs_net *net = afs_sb2net(sb);
 284         struct dentry *root = sb->s_root, *subdir, *tmp;
 285 
 286         /* Prevent more subdirs from being created */
 287         mutex_lock(&net->proc_cells_lock);
 288         if (net->dynroot_sb == sb)
 289                 net->dynroot_sb = NULL;
 290         mutex_unlock(&net->proc_cells_lock);
 291 
 292         inode_lock(root->d_inode);
 293 
 294         /* Remove all the pins for dirs created for manually added cells */
 295         list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) {
 296                 if (subdir->d_fsdata) {
 297                         subdir->d_fsdata = NULL;
 298                         dput(subdir);
 299                 }
 300         }
 301 
 302         inode_unlock(root->d_inode);
 303 }

/* [<][>][^][v][top][bottom][index][help] */