cell.c 23.4 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
D
David Howells 已提交
2
/* AFS cell and server record management
L
Linus Torvalds 已提交
3
 *
4
 * Copyright (C) 2002, 2017 Red Hat, Inc. All Rights Reserved.
L
Linus Torvalds 已提交
5 6 7 8
 * Written by David Howells (dhowells@redhat.com)
 */

#include <linux/slab.h>
D
David Howells 已提交
9 10
#include <linux/key.h>
#include <linux/ctype.h>
11
#include <linux/dns_resolver.h>
A
Alexey Dobriyan 已提交
12
#include <linux/sched.h>
13
#include <linux/inet.h>
14
#include <linux/namei.h>
D
David Howells 已提交
15
#include <keys/rxrpc-type.h>
L
Linus Torvalds 已提交
16 17
#include "internal.h"

D
David Howells 已提交
18
static unsigned __read_mostly afs_cell_gc_delay = 10;
19 20
static unsigned __read_mostly afs_cell_min_ttl = 10 * 60;
static unsigned __read_mostly afs_cell_max_ttl = 24 * 60 * 60;
21
static atomic_t cell_debug_id;
22

D
David Howells 已提交
23
static void afs_queue_cell_manager(struct afs_net *);
24
static void afs_manage_cell_work(struct work_struct *);
25 26 27 28

static void afs_dec_cells_outstanding(struct afs_net *net)
{
	if (atomic_dec_and_test(&net->cells_outstanding))
29
		wake_up_var(&net->cells_outstanding);
30 31
}

L
Linus Torvalds 已提交
32
/*
33 34
 * Set the cell timer to fire after a given delay, assuming it's not already
 * set for an earlier time.
L
Linus Torvalds 已提交
35
 */
36
static void afs_set_cell_timer(struct afs_net *net, time64_t delay)
L
Linus Torvalds 已提交
37
{
38 39 40 41
	if (net->live) {
		atomic_inc(&net->cells_outstanding);
		if (timer_reduce(&net->cells_timer, jiffies + delay * HZ))
			afs_dec_cells_outstanding(net);
D
David Howells 已提交
42 43
	} else {
		afs_queue_cell_manager(net);
44 45 46 47
	}
}

/*
48 49
 * Look up and get an activation reference on a cell record.  The caller must
 * hold net->cells_lock at least read-locked.
50
 */
51
static struct afs_cell *afs_find_cell_locked(struct afs_net *net,
52 53
					     const char *name, unsigned int namesz,
					     enum afs_cell_trace reason)
54 55 56
{
	struct afs_cell *cell = NULL;
	struct rb_node *p;
57
	int n;
58 59 60 61 62 63 64 65

	_enter("%*.*s", namesz, namesz, name);

	if (name && namesz == 0)
		return ERR_PTR(-EINVAL);
	if (namesz > AFS_MAXCELLNAME)
		return ERR_PTR(-ENAMETOOLONG);

66 67 68 69
	if (!name) {
		cell = net->ws_cell;
		if (!cell)
			return ERR_PTR(-EDESTADDRREQ);
70
		goto found;
71
	}
72

73 74 75
	p = net->cells.rb_node;
	while (p) {
		cell = rb_entry(p, struct afs_cell, net_node);
L
Linus Torvalds 已提交
76

77 78 79 80 81 82 83 84 85 86 87 88 89
		n = strncasecmp(cell->name, name,
				min_t(size_t, cell->name_len, namesz));
		if (n == 0)
			n = cell->name_len - namesz;
		if (n < 0)
			p = p->rb_left;
		else if (n > 0)
			p = p->rb_right;
		else
			goto found;
	}

	return ERR_PTR(-ENOENT);
L
Linus Torvalds 已提交
90

91
found:
92
	return afs_use_cell(cell, reason);
93
}
94

95 96 97
/*
 * Look up and get an activation reference on a cell record.
 */
98
struct afs_cell *afs_find_cell(struct afs_net *net,
99 100
			       const char *name, unsigned int namesz,
			       enum afs_cell_trace reason)
101 102 103 104
{
	struct afs_cell *cell;

	down_read(&net->cells_lock);
105
	cell = afs_find_cell_locked(net, name, namesz, reason);
106 107
	up_read(&net->cells_lock);
	return cell;
108 109 110 111 112 113 114 115
}

/*
 * Set up a cell record and fill in its name, VL server address list and
 * allocate an anonymous key
 */
static struct afs_cell *afs_alloc_cell(struct afs_net *net,
				       const char *name, unsigned int namelen,
D
David Howells 已提交
116
				       const char *addresses)
117
{
118
	struct afs_vlserver_list *vllist;
119 120 121 122 123 124
	struct afs_cell *cell;
	int i, ret;

	ASSERT(name);
	if (namelen == 0)
		return ERR_PTR(-EINVAL);
125 126
	if (namelen > AFS_MAXCELLNAME) {
		_leave(" = -ENAMETOOLONG");
D
David Howells 已提交
127
		return ERR_PTR(-ENAMETOOLONG);
128
	}
129 130 131 132 133

	/* Prohibit cell names that contain unprintable chars, '/' and '@' or
	 * that begin with a dot.  This also precludes "@cell".
	 */
	if (name[0] == '.')
134
		return ERR_PTR(-EINVAL);
135 136 137 138 139
	for (i = 0; i < namelen; i++) {
		char ch = name[i];
		if (!isprint(ch) || ch == '/' || ch == '@')
			return ERR_PTR(-EINVAL);
	}
D
David Howells 已提交
140

D
David Howells 已提交
141
	_enter("%*.*s,%s", namelen, namelen, name, addresses);
142 143

	cell = kzalloc(sizeof(struct afs_cell), GFP_KERNEL);
L
Linus Torvalds 已提交
144 145
	if (!cell) {
		_leave(" = -ENOMEM");
146
		return ERR_PTR(-ENOMEM);
L
Linus Torvalds 已提交
147 148
	}

D
David Howells 已提交
149 150 151 152 153 154
	cell->name = kmalloc(namelen + 1, GFP_KERNEL);
	if (!cell->name) {
		kfree(cell);
		return ERR_PTR(-ENOMEM);
	}

155
	cell->net = net;
156 157 158
	cell->name_len = namelen;
	for (i = 0; i < namelen; i++)
		cell->name[i] = tolower(name[i]);
D
David Howells 已提交
159
	cell->name[i] = 0;
160

161
	refcount_set(&cell->ref, 1);
162 163
	atomic_set(&cell->active, 0);
	INIT_WORK(&cell->manager, afs_manage_cell_work);
164 165 166 167 168
	cell->volumes = RB_ROOT;
	INIT_HLIST_HEAD(&cell->proc_volumes);
	seqlock_init(&cell->volume_lock);
	cell->fs_servers = RB_ROOT;
	seqlock_init(&cell->fs_lock);
169 170
	INIT_LIST_HEAD(&cell->fs_open_mmaps);
	init_rwsem(&cell->fs_open_mmaps_lock);
D
David Howells 已提交
171
	rwlock_init(&cell->vl_servers_lock);
172
	cell->flags = (1 << AFS_CELL_FL_CHECK_ALIAS);
173

174 175
	/* Provide a VL server list, filling it in if we were given a list of
	 * addresses to use.
176
	 */
D
David Howells 已提交
177 178 179 180 181 182
	if (addresses) {
		vllist = afs_parse_text_addrs(net,
					      addresses, strlen(addresses), ':',
					      VL_SERVICE, AFS_VL_PORT);
		if (IS_ERR(vllist)) {
			ret = PTR_ERR(vllist);
D
David Howells 已提交
183 184
			goto parse_failed;
		}
D
David Howells 已提交
185

D
David Howells 已提交
186 187
		vllist->source = DNS_RECORD_FROM_CONFIG;
		vllist->status = DNS_LOOKUP_NOT_DONE;
188
		cell->dns_expiry = TIME64_MAX;
189
	} else {
190 191 192 193
		ret = -ENOMEM;
		vllist = afs_alloc_vlserver_list(0);
		if (!vllist)
			goto error;
D
David Howells 已提交
194 195
		vllist->source = DNS_RECORD_UNAVAILABLE;
		vllist->status = DNS_LOOKUP_NOT_DONE;
196
		cell->dns_expiry = ktime_get_real_seconds();
D
David Howells 已提交
197 198
	}

199 200
	rcu_assign_pointer(cell->vl_servers, vllist);

D
David Howells 已提交
201 202 203
	cell->dns_source = vllist->source;
	cell->dns_status = vllist->status;
	smp_store_release(&cell->dns_lookup_count, 1); /* vs source/status */
204
	atomic_inc(&net->cells_outstanding);
205 206
	cell->debug_id = atomic_inc_return(&cell_debug_id);
	trace_afs_cell(cell->debug_id, 1, 0, afs_cell_trace_alloc);
D
David Howells 已提交
207

D
David Howells 已提交
208 209 210
	_leave(" = %p", cell);
	return cell;

D
David Howells 已提交
211 212 213
parse_failed:
	if (ret == -EINVAL)
		printk(KERN_ERR "kAFS: bad VL server IP address\n");
214
error:
D
David Howells 已提交
215
	kfree(cell->name);
D
David Howells 已提交
216 217 218 219
	kfree(cell);
	_leave(" = %d", ret);
	return ERR_PTR(ret);
}
L
Linus Torvalds 已提交
220

D
David Howells 已提交
221
/*
222
 * afs_lookup_cell - Look up or create a cell record.
223
 * @net:	The network namespace
224 225 226 227 228 229 230 231 232
 * @name:	The name of the cell.
 * @namesz:	The strlen of the cell name.
 * @vllist:	A colon/comma separated list of numeric IP addresses or NULL.
 * @excl:	T if an error should be given if the cell name already exists.
 *
 * Look up a cell record by name and query the DNS for VL server addresses if
 * needed.  Note that that actual DNS query is punted off to the manager thread
 * so that this function can return immediately if interrupted whilst allowing
 * cell records to be shared even if not yet fully constructed.
D
David Howells 已提交
233
 */
234 235 236
struct afs_cell *afs_lookup_cell(struct afs_net *net,
				 const char *name, unsigned int namesz,
				 const char *vllist, bool excl)
D
David Howells 已提交
237
{
238 239
	struct afs_cell *cell, *candidate, *cursor;
	struct rb_node *parent, **pp;
D
David Howells 已提交
240
	enum afs_cell_state state;
241 242 243 244 245
	int ret, n;

	_enter("%s,%s", name, vllist);

	if (!excl) {
246
		cell = afs_find_cell(net, name, namesz, afs_cell_trace_use_lookup);
247
		if (!IS_ERR(cell))
248 249
			goto wait_for_cell;
	}
D
David Howells 已提交
250

251 252 253 254 255 256 257 258 259 260 261
	/* Assume we're probably going to create a cell and preallocate and
	 * mostly set up a candidate record.  We can then use this to stash the
	 * name, the net namespace and VL server addresses.
	 *
	 * We also want to do this before we hold any locks as it may involve
	 * upcalling to userspace to make DNS queries.
	 */
	candidate = afs_alloc_cell(net, name, namesz, vllist);
	if (IS_ERR(candidate)) {
		_leave(" = %ld", PTR_ERR(candidate));
		return candidate;
262 263
	}

264 265 266
	/* Find the insertion point and check to see if someone else added a
	 * cell whilst we were allocating.
	 */
267
	down_write(&net->cells_lock);
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284

	pp = &net->cells.rb_node;
	parent = NULL;
	while (*pp) {
		parent = *pp;
		cursor = rb_entry(parent, struct afs_cell, net_node);

		n = strncasecmp(cursor->name, name,
				min_t(size_t, cursor->name_len, namesz));
		if (n == 0)
			n = cursor->name_len - namesz;
		if (n < 0)
			pp = &(*pp)->rb_left;
		else if (n > 0)
			pp = &(*pp)->rb_right;
		else
			goto cell_already_exists;
D
David Howells 已提交
285 286
	}

287 288
	cell = candidate;
	candidate = NULL;
289
	atomic_set(&cell->active, 2);
290
	trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), 2, afs_cell_trace_insert);
291 292
	rb_link_node_rcu(&cell->net_node, parent, pp);
	rb_insert_color(&cell->net_node, &net->cells);
293
	up_write(&net->cells_lock);
L
Linus Torvalds 已提交
294

295
	afs_queue_cell(cell, afs_cell_trace_get_queue_new);
L
Linus Torvalds 已提交
296

297
wait_for_cell:
298
	trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), atomic_read(&cell->active),
299
		       afs_cell_trace_wait);
300
	_debug("wait_for_cell");
D
David Howells 已提交
301 302 303
	wait_var_event(&cell->state,
		       ({
			       state = smp_load_acquire(&cell->state); /* vs error */
D
David Howells 已提交
304
			       state == AFS_CELL_ACTIVE || state == AFS_CELL_REMOVED;
D
David Howells 已提交
305 306 307
		       }));

	/* Check the state obtained from the wait check. */
D
David Howells 已提交
308
	if (state == AFS_CELL_REMOVED) {
309 310 311
		ret = cell->error;
		goto error;
	}
L
Linus Torvalds 已提交
312

313
	_leave(" = %p [cell]", cell);
314
	return cell;
L
Linus Torvalds 已提交
315

316 317 318 319 320 321
cell_already_exists:
	_debug("cell exists");
	cell = cursor;
	if (excl) {
		ret = -EEXIST;
	} else {
322
		afs_use_cell(cursor, afs_cell_trace_use_lookup);
323 324
		ret = 0;
	}
325
	up_write(&net->cells_lock);
326
	if (candidate)
327
		afs_put_cell(candidate, afs_cell_trace_put_candidate);
328 329
	if (ret == 0)
		goto wait_for_cell;
D
David Howells 已提交
330
	goto error_noput;
D
David Howells 已提交
331
error:
332
	afs_unuse_cell(net, cell, afs_cell_trace_unuse_lookup);
D
David Howells 已提交
333
error_noput:
334
	_leave(" = %d [error]", ret);
335
	return ERR_PTR(ret);
D
David Howells 已提交
336
}
L
Linus Torvalds 已提交
337 338

/*
339 340 341
 * set the root cell information
 * - can be called with a module parameter string
 * - can be called from a write to /proc/fs/afs/rootcell
L
Linus Torvalds 已提交
342
 */
343
int afs_cell_init(struct afs_net *net, const char *rootcell)
L
Linus Torvalds 已提交
344 345
{
	struct afs_cell *old_root, *new_root;
346 347
	const char *cp, *vllist;
	size_t len;
L
Linus Torvalds 已提交
348 349 350 351 352 353 354

	_enter("");

	if (!rootcell) {
		/* module is loaded with no parameters, or built statically.
		 * - in the future we might initialize cell DB here.
		 */
355
		_leave(" = 0 [no root]");
L
Linus Torvalds 已提交
356 357 358 359
		return 0;
	}

	cp = strchr(rootcell, ':');
360
	if (!cp) {
361
		_debug("kAFS: no VL server IP addresses specified");
362 363 364 365 366 367
		vllist = NULL;
		len = strlen(rootcell);
	} else {
		vllist = cp + 1;
		len = cp - rootcell;
	}
L
Linus Torvalds 已提交
368 369

	/* allocate a cell record for the root cell */
370
	new_root = afs_lookup_cell(net, rootcell, len, vllist, false);
371 372 373
	if (IS_ERR(new_root)) {
		_leave(" = %ld", PTR_ERR(new_root));
		return PTR_ERR(new_root);
L
Linus Torvalds 已提交
374 375
	}

376
	if (!test_and_set_bit(AFS_CELL_FL_NO_GC, &new_root->flags))
377
		afs_use_cell(new_root, afs_cell_trace_use_pin);
378

379
	/* install the new cell */
380
	down_write(&net->cells_lock);
381
	afs_see_cell(new_root, afs_cell_trace_see_ws);
382 383 384
	old_root = net->ws_cell;
	net->ws_cell = new_root;
	up_write(&net->cells_lock);
L
Linus Torvalds 已提交
385

386
	afs_unuse_cell(net, old_root, afs_cell_trace_unuse_ws);
387 388
	_leave(" = 0");
	return 0;
D
David Howells 已提交
389
}
L
Linus Torvalds 已提交
390 391

/*
392
 * Update a cell's VL server address list from the DNS.
L
Linus Torvalds 已提交
393
 */
D
David Howells 已提交
394
static int afs_update_cell(struct afs_cell *cell)
L
Linus Torvalds 已提交
395
{
D
David Howells 已提交
396
	struct afs_vlserver_list *vllist, *old = NULL, *p;
397 398 399
	unsigned int min_ttl = READ_ONCE(afs_cell_min_ttl);
	unsigned int max_ttl = READ_ONCE(afs_cell_max_ttl);
	time64_t now, expiry = 0;
D
David Howells 已提交
400
	int ret = 0;
L
Linus Torvalds 已提交
401

402 403
	_enter("%s", cell->name);

D
David Howells 已提交
404
	vllist = afs_dns_query(cell, &expiry);
D
David Howells 已提交
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
	if (IS_ERR(vllist)) {
		ret = PTR_ERR(vllist);

		_debug("%s: fail %d", cell->name, ret);
		if (ret == -ENOMEM)
			goto out_wake;

		ret = -ENOMEM;
		vllist = afs_alloc_vlserver_list(0);
		if (!vllist)
			goto out_wake;

		switch (ret) {
		case -ENODATA:
		case -EDESTADDRREQ:
			vllist->status = DNS_LOOKUP_GOT_NOT_FOUND;
			break;
		case -EAGAIN:
		case -ECONNREFUSED:
			vllist->status = DNS_LOOKUP_GOT_TEMP_FAILURE;
			break;
		default:
			vllist->status = DNS_LOOKUP_GOT_LOCAL_FAILURE;
			break;
		}
	}

	_debug("%s: got list %d %d", cell->name, vllist->source, vllist->status);
	cell->dns_status = vllist->status;
434 435 436 437 438 439 440 441 442

	now = ktime_get_real_seconds();
	if (min_ttl > max_ttl)
		max_ttl = min_ttl;
	if (expiry < now + min_ttl)
		expiry = now + min_ttl;
	else if (expiry > now + max_ttl)
		expiry = now + max_ttl;

D
David Howells 已提交
443 444 445 446
	_debug("%s: status %d", cell->name, vllist->status);
	if (vllist->source == DNS_RECORD_UNAVAILABLE) {
		switch (vllist->status) {
		case DNS_LOOKUP_GOT_NOT_FOUND:
447 448 449 450
			/* The DNS said that the cell does not exist or there
			 * weren't any addresses to be had.
			 */
			cell->dns_expiry = expiry;
D
David Howells 已提交
451
			break;
452

D
David Howells 已提交
453 454 455 456
		case DNS_LOOKUP_BAD:
		case DNS_LOOKUP_GOT_LOCAL_FAILURE:
		case DNS_LOOKUP_GOT_TEMP_FAILURE:
		case DNS_LOOKUP_GOT_NS_FAILURE:
D
David Howells 已提交
457
		default:
458
			cell->dns_expiry = now + 10;
D
David Howells 已提交
459 460 461 462 463
			break;
		}
	} else {
		cell->dns_expiry = expiry;
	}
464

D
David Howells 已提交
465 466 467 468 469 470 471 472 473 474 475 476
	/* Replace the VL server list if the new record has servers or the old
	 * record doesn't.
	 */
	write_lock(&cell->vl_servers_lock);
	p = rcu_dereference_protected(cell->vl_servers, true);
	if (vllist->nr_servers > 0 || p->nr_servers == 0) {
		rcu_assign_pointer(cell->vl_servers, vllist);
		cell->dns_source = vllist->source;
		old = p;
	}
	write_unlock(&cell->vl_servers_lock);
	afs_put_vlserverlist(cell->net, old);
477

D
David Howells 已提交
478 479 480 481 482 483
out_wake:
	smp_store_release(&cell->dns_lookup_count,
			  cell->dns_lookup_count + 1); /* vs source/status */
	wake_up_var(&cell->dns_lookup_count);
	_leave(" = %d", ret);
	return ret;
D
David Howells 已提交
484
}
L
Linus Torvalds 已提交
485 486

/*
487
 * Destroy a cell record
L
Linus Torvalds 已提交
488
 */
489
static void afs_cell_destroy(struct rcu_head *rcu)
L
Linus Torvalds 已提交
490
{
491
	struct afs_cell *cell = container_of(rcu, struct afs_cell, rcu);
492
	struct afs_net *net = cell->net;
493
	int r;
L
Linus Torvalds 已提交
494

495
	_enter("%p{%s}", cell, cell->name);
L
Linus Torvalds 已提交
496

497 498 499
	r = refcount_read(&cell->ref);
	ASSERTCMP(r, ==, 0);
	trace_afs_cell(cell->debug_id, r, atomic_read(&cell->active), afs_cell_trace_free);
500

501
	afs_put_vlserverlist(net, rcu_access_pointer(cell->vl_servers));
502
	afs_unuse_cell(net, cell->alias_of, afs_cell_trace_unuse_alias);
503
	key_put(cell->anonymous_key);
D
David Howells 已提交
504
	kfree(cell->name);
505 506
	kfree(cell);

507
	afs_dec_cells_outstanding(net);
508
	_leave(" [destroyed]");
D
David Howells 已提交
509
}
L
Linus Torvalds 已提交
510 511

/*
512
 * Queue the cell manager.
L
Linus Torvalds 已提交
513
 */
514
static void afs_queue_cell_manager(struct afs_net *net)
L
Linus Torvalds 已提交
515
{
516
	int outstanding = atomic_inc_return(&net->cells_outstanding);
L
Linus Torvalds 已提交
517

518
	_enter("%d", outstanding);
L
Linus Torvalds 已提交
519

520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
	if (!queue_work(afs_wq, &net->cells_manager))
		afs_dec_cells_outstanding(net);
}

/*
 * Cell management timer.  We have an increment on cells_outstanding that we
 * need to pass along to the work item.
 */
void afs_cells_timer(struct timer_list *timer)
{
	struct afs_net *net = container_of(timer, struct afs_net, cells_timer);

	_enter("");
	if (!queue_work(afs_wq, &net->cells_manager))
		afs_dec_cells_outstanding(net);
}
L
Linus Torvalds 已提交
536

D
David Howells 已提交
537 538 539
/*
 * Get a reference on a cell record.
 */
540
struct afs_cell *afs_get_cell(struct afs_cell *cell, enum afs_cell_trace reason)
D
David Howells 已提交
541
{
542
	int r;
543

544 545
	__refcount_inc(&cell->ref, &r);
	trace_afs_cell(cell->debug_id, r + 1, atomic_read(&cell->active), reason);
D
David Howells 已提交
546 547 548
	return cell;
}

549 550 551
/*
 * Drop a reference on a cell record.
 */
552
void afs_put_cell(struct afs_cell *cell, enum afs_cell_trace reason)
553 554
{
	if (cell) {
555
		unsigned int debug_id = cell->debug_id;
556 557 558
		unsigned int a;
		bool zero;
		int r;
559

560
		a = atomic_read(&cell->active);
561 562 563
		zero = __refcount_dec_and_test(&cell->ref, &r);
		trace_afs_cell(debug_id, r - 1, a, reason);
		if (zero) {
564 565 566 567 568 569 570 571 572 573
			a = atomic_read(&cell->active);
			WARN(a != 0, "Cell active count %u > 0\n", a);
			call_rcu(&cell->rcu, afs_cell_destroy);
		}
	}
}

/*
 * Note a cell becoming more active.
 */
574
struct afs_cell *afs_use_cell(struct afs_cell *cell, enum afs_cell_trace reason)
575
{
576
	int r, a;
577

578 579
	r = refcount_read(&cell->ref);
	WARN_ON(r == 0);
580
	a = atomic_inc_return(&cell->active);
581
	trace_afs_cell(cell->debug_id, r, a, reason);
582 583 584 585 586 587 588
	return cell;
}

/*
 * Record a cell becoming less active.  When the active counter reaches 1, it
 * is scheduled for destruction, but may get reactivated.
 */
589
void afs_unuse_cell(struct afs_net *net, struct afs_cell *cell, enum afs_cell_trace reason)
590
{
591
	unsigned int debug_id;
592
	time64_t now, expire_delay;
593
	int r, a;
L
Linus Torvalds 已提交
594

595
	if (!cell)
L
Linus Torvalds 已提交
596 597
		return;

598
	_enter("%s", cell->name);
599

600 601 602
	now = ktime_get_real_seconds();
	cell->last_inactive = now;
	expire_delay = 0;
D
David Howells 已提交
603
	if (cell->vl_servers->nr_servers)
604
		expire_delay = afs_cell_gc_delay;
L
Linus Torvalds 已提交
605

606
	debug_id = cell->debug_id;
607
	r = refcount_read(&cell->ref);
608
	a = atomic_dec_return(&cell->active);
609
	trace_afs_cell(debug_id, r, a, reason);
610 611 612 613 614
	WARN_ON(a == 0);
	if (a == 1)
		/* 'cell' may now be garbage collected. */
		afs_set_cell_timer(net, expire_delay);
}
L
Linus Torvalds 已提交
615

616 617 618 619 620
/*
 * Note that a cell has been seen.
 */
void afs_see_cell(struct afs_cell *cell, enum afs_cell_trace reason)
{
621
	int r, a;
622

623
	r = refcount_read(&cell->ref);
624
	a = atomic_read(&cell->active);
625
	trace_afs_cell(cell->debug_id, r, a, reason);
626 627
}

628 629 630
/*
 * Queue a cell for management, giving the workqueue a ref to hold.
 */
631
void afs_queue_cell(struct afs_cell *cell, enum afs_cell_trace reason)
632
{
633
	afs_get_cell(cell, reason);
634
	if (!queue_work(afs_wq, &cell->manager))
635
		afs_put_cell(cell, afs_cell_trace_put_queue_fail);
D
David Howells 已提交
636
}
L
Linus Torvalds 已提交
637 638

/*
639
 * Allocate a key to use as a placeholder for anonymous user security.
L
Linus Torvalds 已提交
640
 */
641
static int afs_alloc_anon_key(struct afs_cell *cell)
L
Linus Torvalds 已提交
642
{
643 644
	struct key *key;
	char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp;
L
Linus Torvalds 已提交
645

646 647 648 649 650 651 652
	/* Create a key to represent an anonymous user. */
	memcpy(keyname, "afs@", 4);
	dp = keyname + 4;
	cp = cell->name;
	do {
		*dp++ = tolower(*cp);
	} while (*cp++);
L
Linus Torvalds 已提交
653

654 655 656
	key = rxrpc_get_null_key(keyname);
	if (IS_ERR(key))
		return PTR_ERR(key);
L
Linus Torvalds 已提交
657

658
	cell->anonymous_key = key;
L
Linus Torvalds 已提交
659

660 661 662 663
	_debug("anon key %p{%x}",
	       cell->anonymous_key, key_serial(cell->anonymous_key));
	return 0;
}
L
Linus Torvalds 已提交
664

665 666 667 668 669
/*
 * Activate a cell.
 */
static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
{
D
David Howells 已提交
670 671
	struct hlist_node **p;
	struct afs_cell *pcell;
672 673 674 675 676 677
	int ret;

	if (!cell->anonymous_key) {
		ret = afs_alloc_anon_key(cell);
		if (ret < 0)
			return ret;
678 679
	}

680
	ret = afs_proc_cell_setup(cell);
681 682
	if (ret < 0)
		return ret;
683 684

	mutex_lock(&net->proc_cells_lock);
D
David Howells 已提交
685 686 687 688 689 690 691 692 693 694 695 696
	for (p = &net->proc_cells.first; *p; p = &(*p)->next) {
		pcell = hlist_entry(*p, struct afs_cell, proc_link);
		if (strcmp(cell->name, pcell->name) < 0)
			break;
	}

	cell->proc_link.pprev = p;
	cell->proc_link.next = *p;
	rcu_assign_pointer(*p, &cell->proc_link.next);
	if (cell->proc_link.next)
		cell->proc_link.next->pprev = &cell->proc_link.next;

697 698
	afs_dynroot_mkdir(net, cell);
	mutex_unlock(&net->proc_cells_lock);
699 700 701 702 703 704 705 706 707
	return 0;
}

/*
 * Deactivate a cell.
 */
static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell)
{
	_enter("%s", cell->name);
L
Linus Torvalds 已提交
708

709
	afs_proc_cell_remove(cell);
L
Linus Torvalds 已提交
710

711
	mutex_lock(&net->proc_cells_lock);
D
David Howells 已提交
712
	hlist_del_rcu(&cell->proc_link);
713 714
	afs_dynroot_rmdir(net, cell);
	mutex_unlock(&net->proc_cells_lock);
L
Linus Torvalds 已提交
715

716
	_leave("");
D
David Howells 已提交
717
}
L
Linus Torvalds 已提交
718 719

/*
720 721
 * Manage a cell record, initialising and destroying it, maintaining its DNS
 * records.
L
Linus Torvalds 已提交
722
 */
723
static void afs_manage_cell(struct afs_cell *cell)
L
Linus Torvalds 已提交
724
{
725
	struct afs_net *net = cell->net;
726
	int ret, active;
727 728 729 730 731 732 733 734

	_enter("%s", cell->name);

again:
	_debug("state %u", cell->state);
	switch (cell->state) {
	case AFS_CELL_INACTIVE:
	case AFS_CELL_FAILED:
735
		down_write(&net->cells_lock);
736
		active = 1;
D
David Howells 已提交
737
		if (atomic_try_cmpxchg_relaxed(&cell->active, &active, 0)) {
738
			rb_erase(&cell->net_node, &net->cells);
739
			trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), 0,
740
				       afs_cell_trace_unuse_delete);
D
David Howells 已提交
741
			smp_store_release(&cell->state, AFS_CELL_REMOVED);
742
		}
743
		up_write(&net->cells_lock);
D
David Howells 已提交
744 745
		if (cell->state == AFS_CELL_REMOVED) {
			wake_up_var(&cell->state);
746
			goto final_destruction;
D
David Howells 已提交
747
		}
748 749
		if (cell->state == AFS_CELL_FAILED)
			goto done;
D
David Howells 已提交
750 751
		smp_store_release(&cell->state, AFS_CELL_UNSET);
		wake_up_var(&cell->state);
752 753 754
		goto again;

	case AFS_CELL_UNSET:
D
David Howells 已提交
755 756
		smp_store_release(&cell->state, AFS_CELL_ACTIVATING);
		wake_up_var(&cell->state);
757 758 759 760 761 762 763
		goto again;

	case AFS_CELL_ACTIVATING:
		ret = afs_activate_cell(net, cell);
		if (ret < 0)
			goto activation_failed;

D
David Howells 已提交
764 765
		smp_store_release(&cell->state, AFS_CELL_ACTIVE);
		wake_up_var(&cell->state);
766 767 768
		goto again;

	case AFS_CELL_ACTIVE:
769
		if (atomic_read(&cell->active) > 1) {
D
David Howells 已提交
770 771 772 773 774
			if (test_and_clear_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags)) {
				ret = afs_update_cell(cell);
				if (ret < 0)
					cell->error = ret;
			}
775 776
			goto done;
		}
D
David Howells 已提交
777 778
		smp_store_release(&cell->state, AFS_CELL_DEACTIVATING);
		wake_up_var(&cell->state);
779 780 781
		goto again;

	case AFS_CELL_DEACTIVATING:
782
		if (atomic_read(&cell->active) > 1)
783 784
			goto reverse_deactivation;
		afs_deactivate_cell(net, cell);
D
David Howells 已提交
785 786
		smp_store_release(&cell->state, AFS_CELL_INACTIVE);
		wake_up_var(&cell->state);
787 788
		goto again;

D
David Howells 已提交
789 790 791
	case AFS_CELL_REMOVED:
		goto done;

792 793 794 795 796 797 798 799 800 801
	default:
		break;
	}
	_debug("bad state %u", cell->state);
	BUG(); /* Unhandled state */

activation_failed:
	cell->error = ret;
	afs_deactivate_cell(net, cell);

D
David Howells 已提交
802 803
	smp_store_release(&cell->state, AFS_CELL_FAILED); /* vs error */
	wake_up_var(&cell->state);
804 805 806
	goto again;

reverse_deactivation:
D
David Howells 已提交
807 808
	smp_store_release(&cell->state, AFS_CELL_ACTIVE);
	wake_up_var(&cell->state);
809 810 811 812 813 814 815 816
	_leave(" [deact->act]");
	return;

done:
	_leave(" [done %u]", cell->state);
	return;

final_destruction:
817 818 819
	/* The root volume is pinning the cell */
	afs_put_volume(cell->net, cell->root_volume, afs_volume_trace_put_cell_root);
	cell->root_volume = NULL;
820
	afs_put_cell(cell, afs_cell_trace_put_destroy);
821 822 823 824 825 826 827
}

static void afs_manage_cell_work(struct work_struct *work)
{
	struct afs_cell *cell = container_of(work, struct afs_cell, manager);

	afs_manage_cell(cell);
828
	afs_put_cell(cell, afs_cell_trace_put_queue_work);
829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
}

/*
 * Manage the records of cells known to a network namespace.  This includes
 * updating the DNS records and garbage collecting unused cells that were
 * automatically added.
 *
 * Note that constructed cell records may only be removed from net->cells by
 * this work item, so it is safe for this work item to stash a cursor pointing
 * into the tree and then return to caller (provided it skips cells that are
 * still under construction).
 *
 * Note also that we were given an increment on net->cells_outstanding by
 * whoever queued us that we need to deal with before returning.
 */
void afs_manage_cells(struct work_struct *work)
{
	struct afs_net *net = container_of(work, struct afs_net, cells_manager);
	struct rb_node *cursor;
	time64_t now = ktime_get_real_seconds(), next_manage = TIME64_MAX;
	bool purging = !net->live;
L
Linus Torvalds 已提交
850 851 852

	_enter("");

853 854 855 856
	/* Trawl the cell database looking for cells that have expired from
	 * lack of use and cells whose DNS results have expired and dispatch
	 * their managers.
	 */
857
	down_read(&net->cells_lock);
L
Linus Torvalds 已提交
858

859 860 861
	for (cursor = rb_first(&net->cells); cursor; cursor = rb_next(cursor)) {
		struct afs_cell *cell =
			rb_entry(cursor, struct afs_cell, net_node);
862
		unsigned active;
863
		bool sched_cell = false;
864

865
		active = atomic_read(&cell->active);
866
		trace_afs_cell(cell->debug_id, refcount_read(&cell->ref),
867
			       active, afs_cell_trace_manage);
868

869
		ASSERTCMP(active, >=, 1);
870 871

		if (purging) {
872 873
			if (test_and_clear_bit(AFS_CELL_FL_NO_GC, &cell->flags)) {
				active = atomic_dec_return(&cell->active);
874
				trace_afs_cell(cell->debug_id, refcount_read(&cell->ref),
875 876
					       active, afs_cell_trace_unuse_pin);
			}
877
		}
L
Linus Torvalds 已提交
878

879
		if (active == 1) {
D
David Howells 已提交
880
			struct afs_vlserver_list *vllist;
881
			time64_t expire_at = cell->last_inactive;
L
Linus Torvalds 已提交
882

D
David Howells 已提交
883 884 885 886 887
			read_lock(&cell->vl_servers_lock);
			vllist = rcu_dereference_protected(
				cell->vl_servers,
				lockdep_is_held(&cell->vl_servers_lock));
			if (vllist->nr_servers > 0)
888
				expire_at += afs_cell_gc_delay;
D
David Howells 已提交
889
			read_unlock(&cell->vl_servers_lock);
890 891 892 893
			if (purging || expire_at <= now)
				sched_cell = true;
			else if (expire_at < next_manage)
				next_manage = expire_at;
L
Linus Torvalds 已提交
894 895
		}

896
		if (!purging) {
D
David Howells 已提交
897
			if (test_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags))
898 899 900 901
				sched_cell = true;
		}

		if (sched_cell)
902
			afs_queue_cell(cell, afs_cell_trace_get_queue_manage);
903 904
	}

905
	up_read(&net->cells_lock);
L
Linus Torvalds 已提交
906

907 908 909 910 911 912
	/* Update the timer on the way out.  We have to pass an increment on
	 * cells_outstanding in the namespace that we are in to the timer or
	 * the work scheduler.
	 */
	if (!purging && next_manage < TIME64_MAX) {
		now = ktime_get_real_seconds();
L
Linus Torvalds 已提交
913

914 915 916 917 918
		if (next_manage - now <= 0) {
			if (queue_work(afs_wq, &net->cells_manager))
				atomic_inc(&net->cells_outstanding);
		} else {
			afs_set_cell_timer(net, next_manage - now);
L
Linus Torvalds 已提交
919 920 921
		}
	}

922 923 924 925 926 927 928 929 930 931 932 933 934
	afs_dec_cells_outstanding(net);
	_leave(" [%d]", atomic_read(&net->cells_outstanding));
}

/*
 * Purge in-memory cell database.
 */
void afs_cell_purge(struct afs_net *net)
{
	struct afs_cell *ws;

	_enter("");

935 936 937 938
	down_write(&net->cells_lock);
	ws = net->ws_cell;
	net->ws_cell = NULL;
	up_write(&net->cells_lock);
939
	afs_unuse_cell(net, ws, afs_cell_trace_unuse_ws);
940 941 942 943 944 945 946 947 948

	_debug("del timer");
	if (del_timer_sync(&net->cells_timer))
		atomic_dec(&net->cells_outstanding);

	_debug("kick mgr");
	afs_queue_cell_manager(net);

	_debug("wait");
949 950
	wait_var_event(&net->cells_outstanding,
		       !atomic_read(&net->cells_outstanding));
L
Linus Torvalds 已提交
951
	_leave("");
D
David Howells 已提交
952
}