xref: /openbmc/linux/fs/afs/cell.c (revision 64c70b1c)
1 /* AFS cell and server record management
2  *
3  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4  * 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 License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11 
12 #include <linux/module.h>
13 #include <linux/slab.h>
14 #include <linux/key.h>
15 #include <linux/ctype.h>
16 #include <linux/sched.h>
17 #include <keys/rxrpc-type.h>
18 #include "internal.h"
19 
20 DECLARE_RWSEM(afs_proc_cells_sem);
21 LIST_HEAD(afs_proc_cells);
22 
23 static struct list_head afs_cells = LIST_HEAD_INIT(afs_cells);
24 static DEFINE_RWLOCK(afs_cells_lock);
25 static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */
26 static DECLARE_WAIT_QUEUE_HEAD(afs_cells_freeable_wq);
27 static struct afs_cell *afs_cell_root;
28 
29 /*
30  * allocate a cell record and fill in its name, VL server address list and
31  * allocate an anonymous key
32  */
33 static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
34 {
35 	struct afs_cell *cell;
36 	size_t namelen;
37 	char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
38 	int ret;
39 
40 	_enter("%s,%s", name, vllist);
41 
42 	BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
43 
44 	namelen = strlen(name);
45 	if (namelen > AFS_MAXCELLNAME)
46 		return ERR_PTR(-ENAMETOOLONG);
47 
48 	/* allocate and initialise a cell record */
49 	cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL);
50 	if (!cell) {
51 		_leave(" = -ENOMEM");
52 		return ERR_PTR(-ENOMEM);
53 	}
54 
55 	memcpy(cell->name, name, namelen);
56 	cell->name[namelen] = 0;
57 
58 	atomic_set(&cell->usage, 1);
59 	INIT_LIST_HEAD(&cell->link);
60 	rwlock_init(&cell->servers_lock);
61 	INIT_LIST_HEAD(&cell->servers);
62 	init_rwsem(&cell->vl_sem);
63 	INIT_LIST_HEAD(&cell->vl_list);
64 	spin_lock_init(&cell->vl_lock);
65 
66 	/* fill in the VL server list from the rest of the string */
67 	do {
68 		unsigned a, b, c, d;
69 
70 		next = strchr(vllist, ':');
71 		if (next)
72 			*next++ = 0;
73 
74 		if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
75 			goto bad_address;
76 
77 		if (a > 255 || b > 255 || c > 255 || d > 255)
78 			goto bad_address;
79 
80 		cell->vl_addrs[cell->vl_naddrs++].s_addr =
81 			htonl((a << 24) | (b << 16) | (c << 8) | d);
82 
83 	} while (cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (vllist = next));
84 
85 	/* create a key to represent an anonymous user */
86 	memcpy(keyname, "afs@", 4);
87 	dp = keyname + 4;
88 	cp = cell->name;
89 	do {
90 		*dp++ = toupper(*cp);
91 	} while (*cp++);
92 	cell->anonymous_key = key_alloc(&key_type_rxrpc, keyname, 0, 0, current,
93 					KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
94 	if (IS_ERR(cell->anonymous_key)) {
95 		_debug("no key");
96 		ret = PTR_ERR(cell->anonymous_key);
97 		goto error;
98 	}
99 
100 	ret = key_instantiate_and_link(cell->anonymous_key, NULL, 0,
101 				       NULL, NULL);
102 	if (ret < 0) {
103 		_debug("instantiate failed");
104 		goto error;
105 	}
106 
107 	_debug("anon key %p{%x}",
108 	       cell->anonymous_key, key_serial(cell->anonymous_key));
109 
110 	_leave(" = %p", cell);
111 	return cell;
112 
113 bad_address:
114 	printk(KERN_ERR "kAFS: bad VL server IP address\n");
115 	ret = -EINVAL;
116 error:
117 	key_put(cell->anonymous_key);
118 	kfree(cell);
119 	_leave(" = %d", ret);
120 	return ERR_PTR(ret);
121 }
122 
123 /*
124  * create a cell record
125  * - "name" is the name of the cell
126  * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
127  */
128 struct afs_cell *afs_cell_create(const char *name, char *vllist)
129 {
130 	struct afs_cell *cell;
131 	int ret;
132 
133 	_enter("%s,%s", name, vllist);
134 
135 	cell = afs_cell_alloc(name, vllist);
136 	if (IS_ERR(cell)) {
137 		_leave(" = %ld", PTR_ERR(cell));
138 		return cell;
139 	}
140 
141 	down_write(&afs_cells_sem);
142 
143 	/* add a proc directory for this cell */
144 	ret = afs_proc_cell_setup(cell);
145 	if (ret < 0)
146 		goto error;
147 
148 #ifdef AFS_CACHING_SUPPORT
149 	/* put it up for caching */
150 	cachefs_acquire_cookie(afs_cache_netfs.primary_index,
151 			       &afs_vlocation_cache_index_def,
152 			       cell,
153 			       &cell->cache);
154 #endif
155 
156 	/* add to the cell lists */
157 	write_lock(&afs_cells_lock);
158 	list_add_tail(&cell->link, &afs_cells);
159 	write_unlock(&afs_cells_lock);
160 
161 	down_write(&afs_proc_cells_sem);
162 	list_add_tail(&cell->proc_link, &afs_proc_cells);
163 	up_write(&afs_proc_cells_sem);
164 	up_write(&afs_cells_sem);
165 
166 	_leave(" = %p", cell);
167 	return cell;
168 
169 error:
170 	up_write(&afs_cells_sem);
171 	key_put(cell->anonymous_key);
172 	kfree(cell);
173 	_leave(" = %d", ret);
174 	return ERR_PTR(ret);
175 }
176 
177 /*
178  * set the root cell information
179  * - can be called with a module parameter string
180  * - can be called from a write to /proc/fs/afs/rootcell
181  */
182 int afs_cell_init(char *rootcell)
183 {
184 	struct afs_cell *old_root, *new_root;
185 	char *cp;
186 
187 	_enter("");
188 
189 	if (!rootcell) {
190 		/* module is loaded with no parameters, or built statically.
191 		 * - in the future we might initialize cell DB here.
192 		 */
193 		_leave(" = 0 [no root]");
194 		return 0;
195 	}
196 
197 	cp = strchr(rootcell, ':');
198 	if (!cp) {
199 		printk(KERN_ERR "kAFS: no VL server IP addresses specified\n");
200 		_leave(" = -EINVAL");
201 		return -EINVAL;
202 	}
203 
204 	/* allocate a cell record for the root cell */
205 	*cp++ = 0;
206 	new_root = afs_cell_create(rootcell, cp);
207 	if (IS_ERR(new_root)) {
208 		_leave(" = %ld", PTR_ERR(new_root));
209 		return PTR_ERR(new_root);
210 	}
211 
212 	/* install the new cell */
213 	write_lock(&afs_cells_lock);
214 	old_root = afs_cell_root;
215 	afs_cell_root = new_root;
216 	write_unlock(&afs_cells_lock);
217 	afs_put_cell(old_root);
218 
219 	_leave(" = 0");
220 	return 0;
221 }
222 
223 /*
224  * lookup a cell record
225  */
226 struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
227 {
228 	struct afs_cell *cell;
229 
230 	_enter("\"%*.*s\",", namesz, namesz, name ? name : "");
231 
232 	down_read(&afs_cells_sem);
233 	read_lock(&afs_cells_lock);
234 
235 	if (name) {
236 		/* if the cell was named, look for it in the cell record list */
237 		list_for_each_entry(cell, &afs_cells, link) {
238 			if (strncmp(cell->name, name, namesz) == 0) {
239 				afs_get_cell(cell);
240 				goto found;
241 			}
242 		}
243 		cell = ERR_PTR(-ENOENT);
244 	found:
245 		;
246 	} else {
247 		cell = afs_cell_root;
248 		if (!cell) {
249 			/* this should not happen unless user tries to mount
250 			 * when root cell is not set. Return an impossibly
251 			 * bizzare errno to alert the user. Things like
252 			 * ENOENT might be "more appropriate" but they happen
253 			 * for other reasons.
254 			 */
255 			cell = ERR_PTR(-EDESTADDRREQ);
256 		} else {
257 			afs_get_cell(cell);
258 		}
259 
260 	}
261 
262 	read_unlock(&afs_cells_lock);
263 	up_read(&afs_cells_sem);
264 	_leave(" = %p", cell);
265 	return cell;
266 }
267 
268 /*
269  * try and get a cell record
270  */
271 struct afs_cell *afs_get_cell_maybe(struct afs_cell *cell)
272 {
273 	write_lock(&afs_cells_lock);
274 
275 	if (cell && !list_empty(&cell->link))
276 		afs_get_cell(cell);
277 	else
278 		cell = NULL;
279 
280 	write_unlock(&afs_cells_lock);
281 	return cell;
282 }
283 
284 /*
285  * destroy a cell record
286  */
287 void afs_put_cell(struct afs_cell *cell)
288 {
289 	if (!cell)
290 		return;
291 
292 	_enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
293 
294 	ASSERTCMP(atomic_read(&cell->usage), >, 0);
295 
296 	/* to prevent a race, the decrement and the dequeue must be effectively
297 	 * atomic */
298 	write_lock(&afs_cells_lock);
299 
300 	if (likely(!atomic_dec_and_test(&cell->usage))) {
301 		write_unlock(&afs_cells_lock);
302 		_leave("");
303 		return;
304 	}
305 
306 	ASSERT(list_empty(&cell->servers));
307 	ASSERT(list_empty(&cell->vl_list));
308 
309 	write_unlock(&afs_cells_lock);
310 
311 	wake_up(&afs_cells_freeable_wq);
312 
313 	_leave(" [unused]");
314 }
315 
316 /*
317  * destroy a cell record
318  * - must be called with the afs_cells_sem write-locked
319  * - cell->link should have been broken by the caller
320  */
321 static void afs_cell_destroy(struct afs_cell *cell)
322 {
323 	_enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
324 
325 	ASSERTCMP(atomic_read(&cell->usage), >=, 0);
326 	ASSERT(list_empty(&cell->link));
327 
328 	/* wait for everyone to stop using the cell */
329 	if (atomic_read(&cell->usage) > 0) {
330 		DECLARE_WAITQUEUE(myself, current);
331 
332 		_debug("wait for cell %s", cell->name);
333 		set_current_state(TASK_UNINTERRUPTIBLE);
334 		add_wait_queue(&afs_cells_freeable_wq, &myself);
335 
336 		while (atomic_read(&cell->usage) > 0) {
337 			schedule();
338 			set_current_state(TASK_UNINTERRUPTIBLE);
339 		}
340 
341 		remove_wait_queue(&afs_cells_freeable_wq, &myself);
342 		set_current_state(TASK_RUNNING);
343 	}
344 
345 	_debug("cell dead");
346 	ASSERTCMP(atomic_read(&cell->usage), ==, 0);
347 	ASSERT(list_empty(&cell->servers));
348 	ASSERT(list_empty(&cell->vl_list));
349 
350 	afs_proc_cell_remove(cell);
351 
352 	down_write(&afs_proc_cells_sem);
353 	list_del_init(&cell->proc_link);
354 	up_write(&afs_proc_cells_sem);
355 
356 #ifdef AFS_CACHING_SUPPORT
357 	cachefs_relinquish_cookie(cell->cache, 0);
358 #endif
359 
360 	key_put(cell->anonymous_key);
361 	kfree(cell);
362 
363 	_leave(" [destroyed]");
364 }
365 
366 /*
367  * purge in-memory cell database on module unload or afs_init() failure
368  * - the timeout daemon is stopped before calling this
369  */
370 void afs_cell_purge(void)
371 {
372 	struct afs_cell *cell;
373 
374 	_enter("");
375 
376 	afs_put_cell(afs_cell_root);
377 
378 	down_write(&afs_cells_sem);
379 
380 	while (!list_empty(&afs_cells)) {
381 		cell = NULL;
382 
383 		/* remove the next cell from the front of the list */
384 		write_lock(&afs_cells_lock);
385 
386 		if (!list_empty(&afs_cells)) {
387 			cell = list_entry(afs_cells.next,
388 					  struct afs_cell, link);
389 			list_del_init(&cell->link);
390 		}
391 
392 		write_unlock(&afs_cells_lock);
393 
394 		if (cell) {
395 			_debug("PURGING CELL %s (%d)",
396 			       cell->name, atomic_read(&cell->usage));
397 
398 			/* now the cell should be left with no references */
399 			afs_cell_destroy(cell);
400 		}
401 	}
402 
403 	up_write(&afs_cells_sem);
404 	_leave("");
405 }
406