• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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