.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* AFS dynamic root handling |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. |
---|
4 | 5 | * Written by David Howells (dhowells@redhat.com) |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or |
---|
7 | | - * modify it under the terms of the GNU General Public Licence |
---|
8 | | - * as published by the Free Software Foundation; either version |
---|
9 | | - * 2 of the Licence, or (at your option) any later version. |
---|
10 | 6 | */ |
---|
11 | 7 | |
---|
12 | 8 | #include <linux/fs.h> |
---|
.. | .. |
---|
14 | 10 | #include <linux/dns_resolver.h> |
---|
15 | 11 | #include "internal.h" |
---|
16 | 12 | |
---|
17 | | -const struct file_operations afs_dynroot_file_operations = { |
---|
18 | | - .open = dcache_dir_open, |
---|
19 | | - .release = dcache_dir_close, |
---|
20 | | - .iterate_shared = dcache_readdir, |
---|
21 | | - .llseek = dcache_dir_lseek, |
---|
22 | | -}; |
---|
| 13 | +static 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 | + */ |
---|
| 20 | +static int afs_iget5_pseudo_test(struct inode *inode, void *opaque) |
---|
| 21 | +{ |
---|
| 22 | + return 0; |
---|
| 23 | +} |
---|
| 24 | + |
---|
| 25 | +/* |
---|
| 26 | + * iget5() inode initialiser |
---|
| 27 | + */ |
---|
| 28 | +static 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 | + */ |
---|
| 45 | +struct 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 | +} |
---|
23 | 105 | |
---|
24 | 106 | /* |
---|
25 | 107 | * Probe to see if a cell may exist. This prevents positive dentries from |
---|
.. | .. |
---|
28 | 110 | static int afs_probe_cell_name(struct dentry *dentry) |
---|
29 | 111 | { |
---|
30 | 112 | struct afs_cell *cell; |
---|
| 113 | + struct afs_net *net = afs_d2net(dentry); |
---|
31 | 114 | const char *name = dentry->d_name.name; |
---|
32 | 115 | size_t len = dentry->d_name.len; |
---|
33 | 116 | int ret; |
---|
.. | .. |
---|
40 | 123 | len--; |
---|
41 | 124 | } |
---|
42 | 125 | |
---|
43 | | - cell = afs_lookup_cell_rcu(afs_d2net(dentry), name, len); |
---|
| 126 | + cell = afs_find_cell(net, name, len, afs_cell_trace_use_probe); |
---|
44 | 127 | if (!IS_ERR(cell)) { |
---|
45 | | - afs_put_cell(afs_d2net(dentry), cell); |
---|
| 128 | + afs_unuse_cell(net, cell, afs_cell_trace_unuse_probe); |
---|
46 | 129 | return 0; |
---|
47 | 130 | } |
---|
48 | 131 | |
---|
49 | | - ret = dns_query("afsdb", name, len, "", NULL, NULL); |
---|
| 132 | + ret = dns_query(net->net, "afsdb", name, len, "srv=1", |
---|
| 133 | + NULL, NULL, false); |
---|
50 | 134 | if (ret == -ENODATA) |
---|
51 | 135 | ret = -EDESTADDRREQ; |
---|
52 | 136 | return ret; |
---|
.. | .. |
---|
62 | 146 | struct inode *inode; |
---|
63 | 147 | int ret = -ENOENT; |
---|
64 | 148 | |
---|
65 | | - _enter("%p{%pd}, {%x:%u}", |
---|
| 149 | + _enter("%p{%pd}, {%llx:%llu}", |
---|
66 | 150 | dentry, dentry, vnode->fid.vid, vnode->fid.vnode); |
---|
67 | 151 | |
---|
68 | 152 | if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags)) |
---|
.. | .. |
---|
95 | 179 | struct afs_cell *cell; |
---|
96 | 180 | struct afs_net *net = afs_d2net(dentry); |
---|
97 | 181 | struct dentry *ret; |
---|
98 | | - unsigned int seq = 0; |
---|
99 | 182 | char *name; |
---|
100 | 183 | int len; |
---|
101 | 184 | |
---|
.. | .. |
---|
107 | 190 | if (!name) |
---|
108 | 191 | goto out_p; |
---|
109 | 192 | |
---|
110 | | - rcu_read_lock(); |
---|
111 | | - do { |
---|
112 | | - read_seqbegin_or_lock(&net->cells_lock, &seq); |
---|
113 | | - cell = rcu_dereference_raw(net->ws_cell); |
---|
114 | | - if (cell) { |
---|
115 | | - len = cell->name_len; |
---|
116 | | - memcpy(name, cell->name, len + 1); |
---|
117 | | - } |
---|
118 | | - } while (need_seqretry(&net->cells_lock, seq)); |
---|
119 | | - done_seqretry(&net->cells_lock, seq); |
---|
120 | | - rcu_read_unlock(); |
---|
| 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); |
---|
121 | 200 | |
---|
122 | 201 | ret = ERR_PTR(-ENOENT); |
---|
123 | 202 | if (!cell) |
---|
.. | .. |
---|
264 | 343 | struct afs_net *net = afs_sb2net(sb); |
---|
265 | 344 | int ret; |
---|
266 | 345 | |
---|
267 | | - if (mutex_lock_interruptible(&net->proc_cells_lock) < 0) |
---|
268 | | - return -ERESTARTSYS; |
---|
| 346 | + mutex_lock(&net->proc_cells_lock); |
---|
269 | 347 | |
---|
270 | 348 | net->dynroot_sb = sb; |
---|
271 | 349 | hlist_for_each_entry(cell, &net->proc_cells, proc_link) { |
---|