18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* AFS dynamic root handling 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/fs.h> 98c2ecf20Sopenharmony_ci#include <linux/namei.h> 108c2ecf20Sopenharmony_ci#include <linux/dns_resolver.h> 118c2ecf20Sopenharmony_ci#include "internal.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic atomic_t afs_autocell_ino; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * iget5() comparator for inode created by autocell operations 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * These pseudo inodes don't match anything. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_cistatic int afs_iget5_pseudo_test(struct inode *inode, void *opaque) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci return 0; 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * iget5() inode initialiser 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_cistatic int afs_iget5_pseudo_set(struct inode *inode, void *opaque) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(inode->i_sb); 318c2ecf20Sopenharmony_ci struct afs_vnode *vnode = AFS_FS_I(inode); 328c2ecf20Sopenharmony_ci struct afs_fid *fid = opaque; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci vnode->volume = as->volume; 358c2ecf20Sopenharmony_ci vnode->fid = *fid; 368c2ecf20Sopenharmony_ci inode->i_ino = fid->vnode; 378c2ecf20Sopenharmony_ci inode->i_generation = fid->unique; 388c2ecf20Sopenharmony_ci return 0; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * Create an inode for a dynamic root directory or an autocell dynamic 438c2ecf20Sopenharmony_ci * automount dir. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cistruct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct afs_super_info *as = AFS_FS_S(sb); 488c2ecf20Sopenharmony_ci struct afs_vnode *vnode; 498c2ecf20Sopenharmony_ci struct inode *inode; 508c2ecf20Sopenharmony_ci struct afs_fid fid = {}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci _enter(""); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (as->volume) 558c2ecf20Sopenharmony_ci fid.vid = as->volume->vid; 568c2ecf20Sopenharmony_ci if (root) { 578c2ecf20Sopenharmony_ci fid.vnode = 1; 588c2ecf20Sopenharmony_ci fid.unique = 1; 598c2ecf20Sopenharmony_ci } else { 608c2ecf20Sopenharmony_ci fid.vnode = atomic_inc_return(&afs_autocell_ino); 618c2ecf20Sopenharmony_ci fid.unique = 0; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci inode = iget5_locked(sb, fid.vnode, 658c2ecf20Sopenharmony_ci afs_iget5_pseudo_test, afs_iget5_pseudo_set, &fid); 668c2ecf20Sopenharmony_ci if (!inode) { 678c2ecf20Sopenharmony_ci _leave(" = -ENOMEM"); 688c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci _debug("GOT INODE %p { ino=%lu, vl=%llx, vn=%llx, u=%x }", 728c2ecf20Sopenharmony_ci inode, inode->i_ino, fid.vid, fid.vnode, fid.unique); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci vnode = AFS_FS_I(inode); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* there shouldn't be an existing inode */ 778c2ecf20Sopenharmony_ci BUG_ON(!(inode->i_state & I_NEW)); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci inode->i_size = 0; 808c2ecf20Sopenharmony_ci inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 818c2ecf20Sopenharmony_ci if (root) { 828c2ecf20Sopenharmony_ci inode->i_op = &afs_dynroot_inode_operations; 838c2ecf20Sopenharmony_ci inode->i_fop = &simple_dir_operations; 848c2ecf20Sopenharmony_ci } else { 858c2ecf20Sopenharmony_ci inode->i_op = &afs_autocell_inode_operations; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci set_nlink(inode, 2); 888c2ecf20Sopenharmony_ci inode->i_uid = GLOBAL_ROOT_UID; 898c2ecf20Sopenharmony_ci inode->i_gid = GLOBAL_ROOT_GID; 908c2ecf20Sopenharmony_ci inode->i_ctime = inode->i_atime = inode->i_mtime = current_time(inode); 918c2ecf20Sopenharmony_ci inode->i_blocks = 0; 928c2ecf20Sopenharmony_ci inode->i_generation = 0; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags); 958c2ecf20Sopenharmony_ci if (!root) { 968c2ecf20Sopenharmony_ci set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); 978c2ecf20Sopenharmony_ci inode->i_flags |= S_AUTOMOUNT; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci inode->i_flags |= S_NOATIME; 1018c2ecf20Sopenharmony_ci unlock_new_inode(inode); 1028c2ecf20Sopenharmony_ci _leave(" = %p", inode); 1038c2ecf20Sopenharmony_ci return inode; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* 1078c2ecf20Sopenharmony_ci * Probe to see if a cell may exist. This prevents positive dentries from 1088c2ecf20Sopenharmony_ci * being created unnecessarily. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_cistatic int afs_probe_cell_name(struct dentry *dentry) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct afs_cell *cell; 1138c2ecf20Sopenharmony_ci struct afs_net *net = afs_d2net(dentry); 1148c2ecf20Sopenharmony_ci const char *name = dentry->d_name.name; 1158c2ecf20Sopenharmony_ci size_t len = dentry->d_name.len; 1168c2ecf20Sopenharmony_ci char *result = NULL; 1178c2ecf20Sopenharmony_ci int ret; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* Names prefixed with a dot are R/W mounts. */ 1208c2ecf20Sopenharmony_ci if (name[0] == '.') { 1218c2ecf20Sopenharmony_ci if (len == 1) 1228c2ecf20Sopenharmony_ci return -EINVAL; 1238c2ecf20Sopenharmony_ci name++; 1248c2ecf20Sopenharmony_ci len--; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci cell = afs_find_cell(net, name, len, afs_cell_trace_use_probe); 1288c2ecf20Sopenharmony_ci if (!IS_ERR(cell)) { 1298c2ecf20Sopenharmony_ci afs_unuse_cell(net, cell, afs_cell_trace_unuse_probe); 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci ret = dns_query(net->net, "afsdb", name, len, "srv=1", 1348c2ecf20Sopenharmony_ci &result, NULL, false); 1358c2ecf20Sopenharmony_ci if (ret == -ENODATA || ret == -ENOKEY || ret == 0) 1368c2ecf20Sopenharmony_ci ret = -ENOENT; 1378c2ecf20Sopenharmony_ci if (ret > 0 && ret >= sizeof(struct dns_server_list_v1_header)) { 1388c2ecf20Sopenharmony_ci struct dns_server_list_v1_header *v1 = (void *)result; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (v1->hdr.zero == 0 && 1418c2ecf20Sopenharmony_ci v1->hdr.content == DNS_PAYLOAD_IS_SERVER_LIST && 1428c2ecf20Sopenharmony_ci v1->hdr.version == 1 && 1438c2ecf20Sopenharmony_ci (v1->status != DNS_LOOKUP_GOOD && 1448c2ecf20Sopenharmony_ci v1->status != DNS_LOOKUP_GOOD_WITH_BAD)) 1458c2ecf20Sopenharmony_ci return -ENOENT; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci kfree(result); 1508c2ecf20Sopenharmony_ci return ret; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/* 1548c2ecf20Sopenharmony_ci * Try to auto mount the mountpoint with pseudo directory, if the autocell 1558c2ecf20Sopenharmony_ci * operation is setted. 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_cistruct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct afs_vnode *vnode = AFS_FS_I(dir); 1608c2ecf20Sopenharmony_ci struct inode *inode; 1618c2ecf20Sopenharmony_ci int ret = -ENOENT; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci _enter("%p{%pd}, {%llx:%llu}", 1648c2ecf20Sopenharmony_ci dentry, dentry, vnode->fid.vid, vnode->fid.vnode); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags)) 1678c2ecf20Sopenharmony_ci goto out; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci ret = afs_probe_cell_name(dentry); 1708c2ecf20Sopenharmony_ci if (ret < 0) 1718c2ecf20Sopenharmony_ci goto out; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci inode = afs_iget_pseudo_dir(dir->i_sb, false); 1748c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 1758c2ecf20Sopenharmony_ci ret = PTR_ERR(inode); 1768c2ecf20Sopenharmony_ci goto out; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci _leave("= %p", inode); 1808c2ecf20Sopenharmony_ci return inode; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciout: 1838c2ecf20Sopenharmony_ci _leave("= %d", ret); 1848c2ecf20Sopenharmony_ci return ret == -ENOENT ? NULL : ERR_PTR(ret); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* 1888c2ecf20Sopenharmony_ci * Look up @cell in a dynroot directory. This is a substitution for the 1898c2ecf20Sopenharmony_ci * local cell name for the net namespace. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_cistatic struct dentry *afs_lookup_atcell(struct dentry *dentry) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct afs_cell *cell; 1948c2ecf20Sopenharmony_ci struct afs_net *net = afs_d2net(dentry); 1958c2ecf20Sopenharmony_ci struct dentry *ret; 1968c2ecf20Sopenharmony_ci char *name; 1978c2ecf20Sopenharmony_ci int len; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (!net->ws_cell) 2008c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci ret = ERR_PTR(-ENOMEM); 2038c2ecf20Sopenharmony_ci name = kmalloc(AFS_MAXCELLNAME + 1, GFP_KERNEL); 2048c2ecf20Sopenharmony_ci if (!name) 2058c2ecf20Sopenharmony_ci goto out_p; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci down_read(&net->cells_lock); 2088c2ecf20Sopenharmony_ci cell = net->ws_cell; 2098c2ecf20Sopenharmony_ci if (cell) { 2108c2ecf20Sopenharmony_ci len = cell->name_len; 2118c2ecf20Sopenharmony_ci memcpy(name, cell->name, len + 1); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci up_read(&net->cells_lock); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci ret = ERR_PTR(-ENOENT); 2168c2ecf20Sopenharmony_ci if (!cell) 2178c2ecf20Sopenharmony_ci goto out_n; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci ret = lookup_one_len(name, dentry->d_parent, len); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* We don't want to d_add() the @cell dentry here as we don't want to 2228c2ecf20Sopenharmony_ci * the cached dentry to hide changes to the local cell name. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ciout_n: 2268c2ecf20Sopenharmony_ci kfree(name); 2278c2ecf20Sopenharmony_ciout_p: 2288c2ecf20Sopenharmony_ci return ret; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/* 2328c2ecf20Sopenharmony_ci * Look up an entry in a dynroot directory. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_cistatic struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry, 2358c2ecf20Sopenharmony_ci unsigned int flags) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci _enter("%pd", dentry); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci ASSERTCMP(d_inode(dentry), ==, NULL); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (flags & LOOKUP_CREATE) 2428c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (dentry->d_name.len >= AFSNAMEMAX) { 2458c2ecf20Sopenharmony_ci _leave(" = -ENAMETOOLONG"); 2468c2ecf20Sopenharmony_ci return ERR_PTR(-ENAMETOOLONG); 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (dentry->d_name.len == 5 && 2508c2ecf20Sopenharmony_ci memcmp(dentry->d_name.name, "@cell", 5) == 0) 2518c2ecf20Sopenharmony_ci return afs_lookup_atcell(dentry); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci return d_splice_alias(afs_try_auto_mntpt(dentry, dir), dentry); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ciconst struct inode_operations afs_dynroot_inode_operations = { 2578c2ecf20Sopenharmony_ci .lookup = afs_dynroot_lookup, 2588c2ecf20Sopenharmony_ci}; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci/* 2618c2ecf20Sopenharmony_ci * Dirs in the dynamic root don't need revalidation. 2628c2ecf20Sopenharmony_ci */ 2638c2ecf20Sopenharmony_cistatic int afs_dynroot_d_revalidate(struct dentry *dentry, unsigned int flags) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci return 1; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ciconst struct dentry_operations afs_dynroot_dentry_operations = { 2698c2ecf20Sopenharmony_ci .d_revalidate = afs_dynroot_d_revalidate, 2708c2ecf20Sopenharmony_ci .d_delete = always_delete_dentry, 2718c2ecf20Sopenharmony_ci .d_release = afs_d_release, 2728c2ecf20Sopenharmony_ci .d_automount = afs_d_automount, 2738c2ecf20Sopenharmony_ci}; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci/* 2768c2ecf20Sopenharmony_ci * Create a manually added cell mount directory. 2778c2ecf20Sopenharmony_ci * - The caller must hold net->proc_cells_lock 2788c2ecf20Sopenharmony_ci */ 2798c2ecf20Sopenharmony_ciint afs_dynroot_mkdir(struct afs_net *net, struct afs_cell *cell) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct super_block *sb = net->dynroot_sb; 2828c2ecf20Sopenharmony_ci struct dentry *root, *subdir; 2838c2ecf20Sopenharmony_ci int ret; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (!sb || atomic_read(&sb->s_active) == 0) 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Let the ->lookup op do the creation */ 2898c2ecf20Sopenharmony_ci root = sb->s_root; 2908c2ecf20Sopenharmony_ci inode_lock(root->d_inode); 2918c2ecf20Sopenharmony_ci subdir = lookup_one_len(cell->name, root, cell->name_len); 2928c2ecf20Sopenharmony_ci if (IS_ERR(subdir)) { 2938c2ecf20Sopenharmony_ci ret = PTR_ERR(subdir); 2948c2ecf20Sopenharmony_ci goto unlock; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* Note that we're retaining an extra ref on the dentry */ 2988c2ecf20Sopenharmony_ci subdir->d_fsdata = (void *)1UL; 2998c2ecf20Sopenharmony_ci ret = 0; 3008c2ecf20Sopenharmony_ciunlock: 3018c2ecf20Sopenharmony_ci inode_unlock(root->d_inode); 3028c2ecf20Sopenharmony_ci return ret; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/* 3068c2ecf20Sopenharmony_ci * Remove a manually added cell mount directory. 3078c2ecf20Sopenharmony_ci * - The caller must hold net->proc_cells_lock 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_civoid afs_dynroot_rmdir(struct afs_net *net, struct afs_cell *cell) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct super_block *sb = net->dynroot_sb; 3128c2ecf20Sopenharmony_ci struct dentry *root, *subdir; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (!sb || atomic_read(&sb->s_active) == 0) 3158c2ecf20Sopenharmony_ci return; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci root = sb->s_root; 3188c2ecf20Sopenharmony_ci inode_lock(root->d_inode); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* Don't want to trigger a lookup call, which will re-add the cell */ 3218c2ecf20Sopenharmony_ci subdir = try_lookup_one_len(cell->name, root, cell->name_len); 3228c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(subdir)) { 3238c2ecf20Sopenharmony_ci _debug("lookup %ld", PTR_ERR(subdir)); 3248c2ecf20Sopenharmony_ci goto no_dentry; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci _debug("rmdir %pd %u", subdir, d_count(subdir)); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (subdir->d_fsdata) { 3308c2ecf20Sopenharmony_ci _debug("unpin %u", d_count(subdir)); 3318c2ecf20Sopenharmony_ci subdir->d_fsdata = NULL; 3328c2ecf20Sopenharmony_ci dput(subdir); 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci dput(subdir); 3358c2ecf20Sopenharmony_cino_dentry: 3368c2ecf20Sopenharmony_ci inode_unlock(root->d_inode); 3378c2ecf20Sopenharmony_ci _leave(""); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci/* 3418c2ecf20Sopenharmony_ci * Populate a newly created dynamic root with cell names. 3428c2ecf20Sopenharmony_ci */ 3438c2ecf20Sopenharmony_ciint afs_dynroot_populate(struct super_block *sb) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct afs_cell *cell; 3468c2ecf20Sopenharmony_ci struct afs_net *net = afs_sb2net(sb); 3478c2ecf20Sopenharmony_ci int ret; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci mutex_lock(&net->proc_cells_lock); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci net->dynroot_sb = sb; 3528c2ecf20Sopenharmony_ci hlist_for_each_entry(cell, &net->proc_cells, proc_link) { 3538c2ecf20Sopenharmony_ci ret = afs_dynroot_mkdir(net, cell); 3548c2ecf20Sopenharmony_ci if (ret < 0) 3558c2ecf20Sopenharmony_ci goto error; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci ret = 0; 3598c2ecf20Sopenharmony_ciout: 3608c2ecf20Sopenharmony_ci mutex_unlock(&net->proc_cells_lock); 3618c2ecf20Sopenharmony_ci return ret; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cierror: 3648c2ecf20Sopenharmony_ci net->dynroot_sb = NULL; 3658c2ecf20Sopenharmony_ci goto out; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci/* 3698c2ecf20Sopenharmony_ci * When a dynamic root that's in the process of being destroyed, depopulate it 3708c2ecf20Sopenharmony_ci * of pinned directories. 3718c2ecf20Sopenharmony_ci */ 3728c2ecf20Sopenharmony_civoid afs_dynroot_depopulate(struct super_block *sb) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct afs_net *net = afs_sb2net(sb); 3758c2ecf20Sopenharmony_ci struct dentry *root = sb->s_root, *subdir, *tmp; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* Prevent more subdirs from being created */ 3788c2ecf20Sopenharmony_ci mutex_lock(&net->proc_cells_lock); 3798c2ecf20Sopenharmony_ci if (net->dynroot_sb == sb) 3808c2ecf20Sopenharmony_ci net->dynroot_sb = NULL; 3818c2ecf20Sopenharmony_ci mutex_unlock(&net->proc_cells_lock); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (root) { 3848c2ecf20Sopenharmony_ci inode_lock(root->d_inode); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* Remove all the pins for dirs created for manually added cells */ 3878c2ecf20Sopenharmony_ci list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) { 3888c2ecf20Sopenharmony_ci if (subdir->d_fsdata) { 3898c2ecf20Sopenharmony_ci subdir->d_fsdata = NULL; 3908c2ecf20Sopenharmony_ci dput(subdir); 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci inode_unlock(root->d_inode); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci} 397