dynroot.c (8938B)
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 netfs_inode_init(&vnode->netfs, NULL); 80 inode->i_size = 0; 81 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 82 if (root) { 83 inode->i_op = &afs_dynroot_inode_operations; 84 inode->i_fop = &simple_dir_operations; 85 } else { 86 inode->i_op = &afs_autocell_inode_operations; 87 } 88 set_nlink(inode, 2); 89 inode->i_uid = GLOBAL_ROOT_UID; 90 inode->i_gid = GLOBAL_ROOT_GID; 91 inode->i_ctime = inode->i_atime = inode->i_mtime = current_time(inode); 92 inode->i_blocks = 0; 93 inode->i_generation = 0; 94 95 set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags); 96 if (!root) { 97 set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); 98 inode->i_flags |= S_AUTOMOUNT; 99 } 100 101 inode->i_flags |= S_NOATIME; 102 unlock_new_inode(inode); 103 _leave(" = %p", inode); 104 return inode; 105} 106 107/* 108 * Probe to see if a cell may exist. This prevents positive dentries from 109 * being created unnecessarily. 110 */ 111static int afs_probe_cell_name(struct dentry *dentry) 112{ 113 struct afs_cell *cell; 114 struct afs_net *net = afs_d2net(dentry); 115 const char *name = dentry->d_name.name; 116 size_t len = dentry->d_name.len; 117 int ret; 118 119 /* Names prefixed with a dot are R/W mounts. */ 120 if (name[0] == '.') { 121 if (len == 1) 122 return -EINVAL; 123 name++; 124 len--; 125 } 126 127 cell = afs_find_cell(net, name, len, afs_cell_trace_use_probe); 128 if (!IS_ERR(cell)) { 129 afs_unuse_cell(net, cell, afs_cell_trace_unuse_probe); 130 return 0; 131 } 132 133 ret = dns_query(net->net, "afsdb", name, len, "srv=1", 134 NULL, NULL, false); 135 if (ret == -ENODATA) 136 ret = -EDESTADDRREQ; 137 return ret; 138} 139 140/* 141 * Try to auto mount the mountpoint with pseudo directory, if the autocell 142 * operation is setted. 143 */ 144struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir) 145{ 146 struct afs_vnode *vnode = AFS_FS_I(dir); 147 struct inode *inode; 148 int ret = -ENOENT; 149 150 _enter("%p{%pd}, {%llx:%llu}", 151 dentry, dentry, vnode->fid.vid, vnode->fid.vnode); 152 153 if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags)) 154 goto out; 155 156 ret = afs_probe_cell_name(dentry); 157 if (ret < 0) 158 goto out; 159 160 inode = afs_iget_pseudo_dir(dir->i_sb, false); 161 if (IS_ERR(inode)) { 162 ret = PTR_ERR(inode); 163 goto out; 164 } 165 166 _leave("= %p", inode); 167 return inode; 168 169out: 170 _leave("= %d", ret); 171 return ret == -ENOENT ? NULL : ERR_PTR(ret); 172} 173 174/* 175 * Look up @cell in a dynroot directory. This is a substitution for the 176 * local cell name for the net namespace. 177 */ 178static struct dentry *afs_lookup_atcell(struct dentry *dentry) 179{ 180 struct afs_cell *cell; 181 struct afs_net *net = afs_d2net(dentry); 182 struct dentry *ret; 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 down_read(&net->cells_lock); 195 cell = net->ws_cell; 196 if (cell) { 197 len = cell->name_len; 198 memcpy(name, cell->name, len + 1); 199 } 200 up_read(&net->cells_lock); 201 202 ret = ERR_PTR(-ENOENT); 203 if (!cell) 204 goto out_n; 205 206 ret = lookup_one_len(name, dentry->d_parent, len); 207 208 /* We don't want to d_add() the @cell dentry here as we don't want to 209 * the cached dentry to hide changes to the local cell name. 210 */ 211 212out_n: 213 kfree(name); 214out_p: 215 return ret; 216} 217 218/* 219 * Look up an entry in a dynroot directory. 220 */ 221static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry, 222 unsigned int flags) 223{ 224 _enter("%pd", dentry); 225 226 ASSERTCMP(d_inode(dentry), ==, NULL); 227 228 if (flags & LOOKUP_CREATE) 229 return ERR_PTR(-EOPNOTSUPP); 230 231 if (dentry->d_name.len >= AFSNAMEMAX) { 232 _leave(" = -ENAMETOOLONG"); 233 return ERR_PTR(-ENAMETOOLONG); 234 } 235 236 if (dentry->d_name.len == 5 && 237 memcmp(dentry->d_name.name, "@cell", 5) == 0) 238 return afs_lookup_atcell(dentry); 239 240 return d_splice_alias(afs_try_auto_mntpt(dentry, dir), dentry); 241} 242 243const struct inode_operations afs_dynroot_inode_operations = { 244 .lookup = afs_dynroot_lookup, 245}; 246 247/* 248 * Dirs in the dynamic root don't need revalidation. 249 */ 250static int afs_dynroot_d_revalidate(struct dentry *dentry, unsigned int flags) 251{ 252 return 1; 253} 254 255/* 256 * Allow the VFS to enquire as to whether a dentry should be unhashed (mustn't 257 * sleep) 258 * - called from dput() when d_count is going to 0. 259 * - return 1 to request dentry be unhashed, 0 otherwise 260 */ 261static int afs_dynroot_d_delete(const struct dentry *dentry) 262{ 263 return d_really_is_positive(dentry); 264} 265 266const struct dentry_operations afs_dynroot_dentry_operations = { 267 .d_revalidate = afs_dynroot_d_revalidate, 268 .d_delete = afs_dynroot_d_delete, 269 .d_release = afs_d_release, 270 .d_automount = afs_d_automount, 271}; 272 273/* 274 * Create a manually added cell mount directory. 275 * - The caller must hold net->proc_cells_lock 276 */ 277int afs_dynroot_mkdir(struct afs_net *net, struct afs_cell *cell) 278{ 279 struct super_block *sb = net->dynroot_sb; 280 struct dentry *root, *subdir; 281 int ret; 282 283 if (!sb || atomic_read(&sb->s_active) == 0) 284 return 0; 285 286 /* Let the ->lookup op do the creation */ 287 root = sb->s_root; 288 inode_lock(root->d_inode); 289 subdir = lookup_one_len(cell->name, root, cell->name_len); 290 if (IS_ERR(subdir)) { 291 ret = PTR_ERR(subdir); 292 goto unlock; 293 } 294 295 /* Note that we're retaining an extra ref on the dentry */ 296 subdir->d_fsdata = (void *)1UL; 297 ret = 0; 298unlock: 299 inode_unlock(root->d_inode); 300 return ret; 301} 302 303/* 304 * Remove a manually added cell mount directory. 305 * - The caller must hold net->proc_cells_lock 306 */ 307void afs_dynroot_rmdir(struct afs_net *net, struct afs_cell *cell) 308{ 309 struct super_block *sb = net->dynroot_sb; 310 struct dentry *root, *subdir; 311 312 if (!sb || atomic_read(&sb->s_active) == 0) 313 return; 314 315 root = sb->s_root; 316 inode_lock(root->d_inode); 317 318 /* Don't want to trigger a lookup call, which will re-add the cell */ 319 subdir = try_lookup_one_len(cell->name, root, cell->name_len); 320 if (IS_ERR_OR_NULL(subdir)) { 321 _debug("lookup %ld", PTR_ERR(subdir)); 322 goto no_dentry; 323 } 324 325 _debug("rmdir %pd %u", subdir, d_count(subdir)); 326 327 if (subdir->d_fsdata) { 328 _debug("unpin %u", d_count(subdir)); 329 subdir->d_fsdata = NULL; 330 dput(subdir); 331 } 332 dput(subdir); 333no_dentry: 334 inode_unlock(root->d_inode); 335 _leave(""); 336} 337 338/* 339 * Populate a newly created dynamic root with cell names. 340 */ 341int afs_dynroot_populate(struct super_block *sb) 342{ 343 struct afs_cell *cell; 344 struct afs_net *net = afs_sb2net(sb); 345 int ret; 346 347 mutex_lock(&net->proc_cells_lock); 348 349 net->dynroot_sb = sb; 350 hlist_for_each_entry(cell, &net->proc_cells, proc_link) { 351 ret = afs_dynroot_mkdir(net, cell); 352 if (ret < 0) 353 goto error; 354 } 355 356 ret = 0; 357out: 358 mutex_unlock(&net->proc_cells_lock); 359 return ret; 360 361error: 362 net->dynroot_sb = NULL; 363 goto out; 364} 365 366/* 367 * When a dynamic root that's in the process of being destroyed, depopulate it 368 * of pinned directories. 369 */ 370void afs_dynroot_depopulate(struct super_block *sb) 371{ 372 struct afs_net *net = afs_sb2net(sb); 373 struct dentry *root = sb->s_root, *subdir, *tmp; 374 375 /* Prevent more subdirs from being created */ 376 mutex_lock(&net->proc_cells_lock); 377 if (net->dynroot_sb == sb) 378 net->dynroot_sb = NULL; 379 mutex_unlock(&net->proc_cells_lock); 380 381 if (root) { 382 inode_lock(root->d_inode); 383 384 /* Remove all the pins for dirs created for manually added cells */ 385 list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) { 386 if (subdir->d_fsdata) { 387 subdir->d_fsdata = NULL; 388 dput(subdir); 389 } 390 } 391 392 inode_unlock(root->d_inode); 393 } 394}