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