blob: 216821fd1a610698c90a53ec3581602803c09e64 [file] [log] [blame]
David Howellsec268152007-04-26 15:49:28 -07001/* AFS cell and server record management
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/slab.h>
David Howells00d3b7a2007-04-26 15:57:07 -070014#include <linux/key.h>
15#include <linux/ctype.h>
Wang Lei07567a52010-08-04 15:16:38 +010016#include <linux/dns_resolver.h>
Alexey Dobriyane8edc6e2007-05-21 01:22:52 +040017#include <linux/sched.h>
David Howells3838d3e2017-11-02 15:27:47 +000018#include <linux/inet.h>
David Howells00d3b7a2007-04-26 15:57:07 -070019#include <keys/rxrpc-type.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include "internal.h"
21
Linus Torvalds1da177e2005-04-16 15:20:36 -070022/*
David Howells00d3b7a2007-04-26 15:57:07 -070023 * allocate a cell record and fill in its name, VL server address list and
24 * allocate an anonymous key
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 */
David Howellsf044c882017-11-02 15:27:45 +000026static struct afs_cell *afs_cell_alloc(struct afs_net *net,
27 const char *name, unsigned namelen,
wangleibec5eb62010-08-11 09:38:04 +010028 char *vllist)
Linus Torvalds1da177e2005-04-16 15:20:36 -070029{
30 struct afs_cell *cell;
David Howells76181c12007-10-16 23:29:46 -070031 struct key *key;
David Howells00d3b7a2007-04-26 15:57:07 -070032 char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
Wang Lei07567a52010-08-04 15:16:38 +010033 char *dvllist = NULL, *_vllist = NULL;
34 char delimiter = ':';
David Howells4d9df982017-11-02 15:27:47 +000035 int ret, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
wangleibec5eb62010-08-11 09:38:04 +010037 _enter("%*.*s,%s", namelen, namelen, name ?: "", vllist);
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39 BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
40
Wang Lei07567a52010-08-04 15:16:38 +010041 if (namelen > AFS_MAXCELLNAME) {
42 _leave(" = -ENAMETOOLONG");
David Howells00d3b7a2007-04-26 15:57:07 -070043 return ERR_PTR(-ENAMETOOLONG);
Wang Lei07567a52010-08-04 15:16:38 +010044 }
David Howells00d3b7a2007-04-26 15:57:07 -070045
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 /* allocate and initialise a cell record */
David Howells00d3b7a2007-04-26 15:57:07 -070047 cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 if (!cell) {
49 _leave(" = -ENOMEM");
David Howells08e0e7c2007-04-26 15:55:03 -070050 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 }
52
David Howells00d3b7a2007-04-26 15:57:07 -070053 memcpy(cell->name, name, namelen);
54 cell->name[namelen] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
David Howells08e0e7c2007-04-26 15:55:03 -070056 atomic_set(&cell->usage, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 INIT_LIST_HEAD(&cell->link);
David Howellsf044c882017-11-02 15:27:45 +000058 cell->net = net;
David Howells08e0e7c2007-04-26 15:55:03 -070059 rwlock_init(&cell->servers_lock);
60 INIT_LIST_HEAD(&cell->servers);
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 init_rwsem(&cell->vl_sem);
62 INIT_LIST_HEAD(&cell->vl_list);
David Howells08e0e7c2007-04-26 15:55:03 -070063 spin_lock_init(&cell->vl_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
David Howells4d9df982017-11-02 15:27:47 +000065 for (i = 0; i < AFS_CELL_MAX_ADDRS; i++) {
66 struct sockaddr_rxrpc *srx = &cell->vl_addrs[i];
67 srx->srx_family = AF_RXRPC;
68 srx->srx_service = VL_SERVICE;
69 srx->transport_type = SOCK_DGRAM;
70 srx->transport.sin.sin_port = htons(AFS_VL_PORT);
71 }
72
Wang Lei07567a52010-08-04 15:16:38 +010073 /* if the ip address is invalid, try dns query */
74 if (!vllist || strlen(vllist) < 7) {
75 ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL);
76 if (ret < 0) {
Wang Lei4a2d7892010-08-11 09:37:58 +010077 if (ret == -ENODATA || ret == -EAGAIN || ret == -ENOKEY)
78 /* translate these errors into something
79 * userspace might understand */
80 ret = -EDESTADDRREQ;
Wang Lei07567a52010-08-04 15:16:38 +010081 _leave(" = %d", ret);
82 return ERR_PTR(ret);
83 }
84 _vllist = dvllist;
85
86 /* change the delimiter for user-space reply */
87 delimiter = ',';
88
89 } else {
David Howells3838d3e2017-11-02 15:27:47 +000090 if (strchr(vllist, ',') || !strchr(vllist, '.'))
91 delimiter = ',';
Wang Lei07567a52010-08-04 15:16:38 +010092 _vllist = vllist;
93 }
94
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 /* fill in the VL server list from the rest of the string */
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 do {
David Howells4d9df982017-11-02 15:27:47 +000097 struct sockaddr_rxrpc *srx = &cell->vl_addrs[cell->vl_naddrs];
David Howells3838d3e2017-11-02 15:27:47 +000098 const char *end;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Wang Lei07567a52010-08-04 15:16:38 +0100100 next = strchr(_vllist, delimiter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 if (next)
102 *next++ = 0;
103
David Howells3838d3e2017-11-02 15:27:47 +0000104 if (in4_pton(_vllist, -1, (u8 *)&srx->transport.sin6.sin6_addr.s6_addr32[3],
105 -1, &end)) {
106 srx->transport_len = sizeof(struct sockaddr_in6);
107 srx->transport.sin6.sin6_family = AF_INET6;
108 srx->transport.sin6.sin6_flowinfo = 0;
109 srx->transport.sin6.sin6_scope_id = 0;
110 srx->transport.sin6.sin6_addr.s6_addr32[0] = 0;
111 srx->transport.sin6.sin6_addr.s6_addr32[1] = 0;
112 srx->transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
113 } else if (in6_pton(_vllist, -1, srx->transport.sin6.sin6_addr.s6_addr,
114 -1, &end)) {
115 srx->transport_len = sizeof(struct sockaddr_in6);
116 srx->transport.sin6.sin6_family = AF_INET6;
117 srx->transport.sin6.sin6_flowinfo = 0;
118 srx->transport.sin6.sin6_scope_id = 0;
119 } else {
David Howells00d3b7a2007-04-26 15:57:07 -0700120 goto bad_address;
David Howells3838d3e2017-11-02 15:27:47 +0000121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
David Howells4d9df982017-11-02 15:27:47 +0000123 } while (cell->vl_naddrs++,
124 cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (_vllist = next));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
David Howells00d3b7a2007-04-26 15:57:07 -0700126 /* create a key to represent an anonymous user */
127 memcpy(keyname, "afs@", 4);
128 dp = keyname + 4;
129 cp = cell->name;
130 do {
131 *dp++ = toupper(*cp);
132 } while (*cp++);
David Howells00d3b7a2007-04-26 15:57:07 -0700133
David Howells76181c12007-10-16 23:29:46 -0700134 key = rxrpc_get_null_key(keyname);
135 if (IS_ERR(key)) {
136 _debug("no key");
137 ret = PTR_ERR(key);
David Howells00d3b7a2007-04-26 15:57:07 -0700138 goto error;
139 }
David Howells76181c12007-10-16 23:29:46 -0700140 cell->anonymous_key = key;
David Howells00d3b7a2007-04-26 15:57:07 -0700141
142 _debug("anon key %p{%x}",
143 cell->anonymous_key, key_serial(cell->anonymous_key));
144
145 _leave(" = %p", cell);
146 return cell;
147
148bad_address:
149 printk(KERN_ERR "kAFS: bad VL server IP address\n");
150 ret = -EINVAL;
151error:
152 key_put(cell->anonymous_key);
Wang Lei07567a52010-08-04 15:16:38 +0100153 kfree(dvllist);
David Howells00d3b7a2007-04-26 15:57:07 -0700154 kfree(cell);
155 _leave(" = %d", ret);
156 return ERR_PTR(ret);
157}
158
159/*
wangleibec5eb62010-08-11 09:38:04 +0100160 * afs_cell_crate() - create a cell record
David Howellsf044c882017-11-02 15:27:45 +0000161 * @net: The network namespace
wangleibec5eb62010-08-11 09:38:04 +0100162 * @name: is the name of the cell.
163 * @namsesz: is the strlen of the cell name.
164 * @vllist: is a colon separated list of IP addresses in "a.b.c.d" format.
165 * @retref: is T to return the cell reference when the cell exists.
David Howells00d3b7a2007-04-26 15:57:07 -0700166 */
David Howellsf044c882017-11-02 15:27:45 +0000167struct afs_cell *afs_cell_create(struct afs_net *net,
168 const char *name, unsigned namesz,
wangleibec5eb62010-08-11 09:38:04 +0100169 char *vllist, bool retref)
David Howells00d3b7a2007-04-26 15:57:07 -0700170{
171 struct afs_cell *cell;
172 int ret;
173
wangleibec5eb62010-08-11 09:38:04 +0100174 _enter("%*.*s,%s", namesz, namesz, name ?: "", vllist);
David Howells00d3b7a2007-04-26 15:57:07 -0700175
David Howellsf044c882017-11-02 15:27:45 +0000176 down_write(&net->cells_sem);
177 read_lock(&net->cells_lock);
178 list_for_each_entry(cell, &net->cells, link) {
wangleibec5eb62010-08-11 09:38:04 +0100179 if (strncasecmp(cell->name, name, namesz) == 0)
Sven Schnelle5214b722008-03-28 14:15:55 -0700180 goto duplicate_name;
181 }
David Howellsf044c882017-11-02 15:27:45 +0000182 read_unlock(&net->cells_lock);
Sven Schnelle5214b722008-03-28 14:15:55 -0700183
David Howellsf044c882017-11-02 15:27:45 +0000184 cell = afs_cell_alloc(net, name, namesz, vllist);
David Howells00d3b7a2007-04-26 15:57:07 -0700185 if (IS_ERR(cell)) {
186 _leave(" = %ld", PTR_ERR(cell));
David Howellsf044c882017-11-02 15:27:45 +0000187 up_write(&net->cells_sem);
David Howells00d3b7a2007-04-26 15:57:07 -0700188 return cell;
189 }
190
David Howells08e0e7c2007-04-26 15:55:03 -0700191 /* add a proc directory for this cell */
David Howellsf044c882017-11-02 15:27:45 +0000192 ret = afs_proc_cell_setup(net, cell);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 if (ret < 0)
194 goto error;
195
David Howells9b3f26c2009-04-03 16:42:41 +0100196#ifdef CONFIG_AFS_FSCACHE
197 /* put it up for caching (this never returns an error) */
198 cell->cache = fscache_acquire_cookie(afs_cache_netfs.primary_index,
199 &afs_cell_cache_index_def,
David Howells94d30ae2013-09-21 00:09:31 +0100200 cell, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201#endif
202
203 /* add to the cell lists */
David Howellsf044c882017-11-02 15:27:45 +0000204 write_lock(&net->cells_lock);
205 list_add_tail(&cell->link, &net->cells);
206 write_unlock(&net->cells_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
David Howellsf044c882017-11-02 15:27:45 +0000208 down_write(&net->proc_cells_sem);
209 list_add_tail(&cell->proc_link, &net->proc_cells);
210 up_write(&net->proc_cells_sem);
211 up_write(&net->cells_sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
David Howells08e0e7c2007-04-26 15:55:03 -0700213 _leave(" = %p", cell);
214 return cell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
David Howellsec268152007-04-26 15:49:28 -0700216error:
David Howellsf044c882017-11-02 15:27:45 +0000217 up_write(&net->cells_sem);
David Howells00d3b7a2007-04-26 15:57:07 -0700218 key_put(cell->anonymous_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 kfree(cell);
220 _leave(" = %d", ret);
David Howells08e0e7c2007-04-26 15:55:03 -0700221 return ERR_PTR(ret);
Sven Schnelle5214b722008-03-28 14:15:55 -0700222
223duplicate_name:
wangleibec5eb62010-08-11 09:38:04 +0100224 if (retref && !IS_ERR(cell))
225 afs_get_cell(cell);
226
David Howellsf044c882017-11-02 15:27:45 +0000227 read_unlock(&net->cells_lock);
228 up_write(&net->cells_sem);
wangleibec5eb62010-08-11 09:38:04 +0100229
230 if (retref) {
231 _leave(" = %p", cell);
232 return cell;
233 }
234
235 _leave(" = -EEXIST");
Sven Schnelle5214b722008-03-28 14:15:55 -0700236 return ERR_PTR(-EEXIST);
David Howellsec268152007-04-26 15:49:28 -0700237}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239/*
David Howells08e0e7c2007-04-26 15:55:03 -0700240 * set the root cell information
241 * - can be called with a module parameter string
242 * - can be called from a write to /proc/fs/afs/rootcell
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 */
David Howellsf044c882017-11-02 15:27:45 +0000244int afs_cell_init(struct afs_net *net, char *rootcell)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245{
246 struct afs_cell *old_root, *new_root;
247 char *cp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
249 _enter("");
250
251 if (!rootcell) {
252 /* module is loaded with no parameters, or built statically.
253 * - in the future we might initialize cell DB here.
254 */
David Howells08e0e7c2007-04-26 15:55:03 -0700255 _leave(" = 0 [no root]");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 return 0;
257 }
258
259 cp = strchr(rootcell, ':');
Wang Lei07567a52010-08-04 15:16:38 +0100260 if (!cp)
261 _debug("kAFS: no VL server IP addresses specified");
262 else
263 *cp++ = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
265 /* allocate a cell record for the root cell */
David Howellsf044c882017-11-02 15:27:45 +0000266 new_root = afs_cell_create(net, rootcell, strlen(rootcell), cp, false);
David Howells08e0e7c2007-04-26 15:55:03 -0700267 if (IS_ERR(new_root)) {
268 _leave(" = %ld", PTR_ERR(new_root));
269 return PTR_ERR(new_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 }
271
David Howells08e0e7c2007-04-26 15:55:03 -0700272 /* install the new cell */
David Howellsf044c882017-11-02 15:27:45 +0000273 write_lock(&net->cells_lock);
274 old_root = net->ws_cell;
275 net->ws_cell = new_root;
276 write_unlock(&net->cells_lock);
David Howells9ed900b2017-11-02 15:27:46 +0000277 afs_put_cell(net, old_root);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
David Howells08e0e7c2007-04-26 15:55:03 -0700279 _leave(" = 0");
280 return 0;
David Howellsec268152007-04-26 15:49:28 -0700281}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283/*
284 * lookup a cell record
285 */
David Howellsf044c882017-11-02 15:27:45 +0000286struct afs_cell *afs_cell_lookup(struct afs_net *net,
287 const char *name, unsigned namesz,
wangleibec5eb62010-08-11 09:38:04 +0100288 bool dns_cell)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
290 struct afs_cell *cell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
wangleibec5eb62010-08-11 09:38:04 +0100292 _enter("\"%*.*s\",", namesz, namesz, name ?: "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
David Howellsf044c882017-11-02 15:27:45 +0000294 down_read(&net->cells_sem);
295 read_lock(&net->cells_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
297 if (name) {
298 /* if the cell was named, look for it in the cell record list */
David Howellsf044c882017-11-02 15:27:45 +0000299 list_for_each_entry(cell, &net->cells, link) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 if (strncmp(cell->name, name, namesz) == 0) {
301 afs_get_cell(cell);
302 goto found;
303 }
304 }
David Howells08e0e7c2007-04-26 15:55:03 -0700305 cell = ERR_PTR(-ENOENT);
wangleibec5eb62010-08-11 09:38:04 +0100306 if (dns_cell)
307 goto create_cell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 found:
David Howells08e0e7c2007-04-26 15:55:03 -0700309 ;
David Howellsec268152007-04-26 15:49:28 -0700310 } else {
David Howellsf044c882017-11-02 15:27:45 +0000311 cell = net->ws_cell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 if (!cell) {
313 /* this should not happen unless user tries to mount
314 * when root cell is not set. Return an impossibly
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300315 * bizarre errno to alert the user. Things like
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 * ENOENT might be "more appropriate" but they happen
317 * for other reasons.
318 */
David Howells08e0e7c2007-04-26 15:55:03 -0700319 cell = ERR_PTR(-EDESTADDRREQ);
David Howellsec268152007-04-26 15:49:28 -0700320 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 afs_get_cell(cell);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 }
323
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 }
325
David Howellsf044c882017-11-02 15:27:45 +0000326 read_unlock(&net->cells_lock);
327 up_read(&net->cells_sem);
David Howells08e0e7c2007-04-26 15:55:03 -0700328 _leave(" = %p", cell);
329 return cell;
wangleibec5eb62010-08-11 09:38:04 +0100330
331create_cell:
David Howellsf044c882017-11-02 15:27:45 +0000332 read_unlock(&net->cells_lock);
333 up_read(&net->cells_sem);
wangleibec5eb62010-08-11 09:38:04 +0100334
David Howellsf044c882017-11-02 15:27:45 +0000335 cell = afs_cell_create(net, name, namesz, NULL, true);
wangleibec5eb62010-08-11 09:38:04 +0100336
337 _leave(" = %p", cell);
338 return cell;
David Howellsec268152007-04-26 15:49:28 -0700339}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Adrian Bunkc1206a22007-10-16 23:26:41 -0700341#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342/*
343 * try and get a cell record
344 */
David Howells08e0e7c2007-04-26 15:55:03 -0700345struct afs_cell *afs_get_cell_maybe(struct afs_cell *cell)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346{
David Howellsf044c882017-11-02 15:27:45 +0000347 write_lock(&net->cells_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 if (cell && !list_empty(&cell->link))
350 afs_get_cell(cell);
351 else
352 cell = NULL;
353
David Howellsf044c882017-11-02 15:27:45 +0000354 write_unlock(&net->cells_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 return cell;
David Howellsec268152007-04-26 15:49:28 -0700356}
Adrian Bunkc1206a22007-10-16 23:26:41 -0700357#endif /* 0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359/*
360 * destroy a cell record
361 */
David Howells9ed900b2017-11-02 15:27:46 +0000362void afs_put_cell(struct afs_net *net, struct afs_cell *cell)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
364 if (!cell)
365 return;
366
367 _enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
368
David Howells08e0e7c2007-04-26 15:55:03 -0700369 ASSERTCMP(atomic_read(&cell->usage), >, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371 /* to prevent a race, the decrement and the dequeue must be effectively
372 * atomic */
David Howells9ed900b2017-11-02 15:27:46 +0000373 write_lock(&net->cells_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
375 if (likely(!atomic_dec_and_test(&cell->usage))) {
David Howells9ed900b2017-11-02 15:27:46 +0000376 write_unlock(&net->cells_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 _leave("");
378 return;
379 }
380
David Howells08e0e7c2007-04-26 15:55:03 -0700381 ASSERT(list_empty(&cell->servers));
382 ASSERT(list_empty(&cell->vl_list));
383
David Howells9ed900b2017-11-02 15:27:46 +0000384 wake_up(&net->cells_freeable_wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
David Howells9ed900b2017-11-02 15:27:46 +0000386 write_unlock(&net->cells_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
388 _leave(" [unused]");
David Howellsec268152007-04-26 15:49:28 -0700389}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391/*
392 * destroy a cell record
David Howellsf044c882017-11-02 15:27:45 +0000393 * - must be called with the net->cells_sem write-locked
David Howells08e0e7c2007-04-26 15:55:03 -0700394 * - cell->link should have been broken by the caller
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 */
David Howellsf044c882017-11-02 15:27:45 +0000396static void afs_cell_destroy(struct afs_net *net, struct afs_cell *cell)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
398 _enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
399
David Howells08e0e7c2007-04-26 15:55:03 -0700400 ASSERTCMP(atomic_read(&cell->usage), >=, 0);
401 ASSERT(list_empty(&cell->link));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
David Howells08e0e7c2007-04-26 15:55:03 -0700403 /* wait for everyone to stop using the cell */
404 if (atomic_read(&cell->usage) > 0) {
405 DECLARE_WAITQUEUE(myself, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
David Howells08e0e7c2007-04-26 15:55:03 -0700407 _debug("wait for cell %s", cell->name);
408 set_current_state(TASK_UNINTERRUPTIBLE);
David Howellsf044c882017-11-02 15:27:45 +0000409 add_wait_queue(&net->cells_freeable_wq, &myself);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
David Howells08e0e7c2007-04-26 15:55:03 -0700411 while (atomic_read(&cell->usage) > 0) {
412 schedule();
413 set_current_state(TASK_UNINTERRUPTIBLE);
414 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
David Howellsf044c882017-11-02 15:27:45 +0000416 remove_wait_queue(&net->cells_freeable_wq, &myself);
David Howells08e0e7c2007-04-26 15:55:03 -0700417 set_current_state(TASK_RUNNING);
418 }
419
420 _debug("cell dead");
421 ASSERTCMP(atomic_read(&cell->usage), ==, 0);
422 ASSERT(list_empty(&cell->servers));
423 ASSERT(list_empty(&cell->vl_list));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
David Howellsf044c882017-11-02 15:27:45 +0000425 afs_proc_cell_remove(net, cell);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
David Howellsf044c882017-11-02 15:27:45 +0000427 down_write(&net->proc_cells_sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 list_del_init(&cell->proc_link);
David Howellsf044c882017-11-02 15:27:45 +0000429 up_write(&net->proc_cells_sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
David Howells9b3f26c2009-04-03 16:42:41 +0100431#ifdef CONFIG_AFS_FSCACHE
432 fscache_relinquish_cookie(cell->cache, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433#endif
David Howells00d3b7a2007-04-26 15:57:07 -0700434 key_put(cell->anonymous_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 kfree(cell);
436
437 _leave(" [destroyed]");
David Howellsec268152007-04-26 15:49:28 -0700438}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 * purge in-memory cell database on module unload or afs_init() failure
442 * - the timeout daemon is stopped before calling this
443 */
David Howellsf044c882017-11-02 15:27:45 +0000444void afs_cell_purge(struct afs_net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 struct afs_cell *cell;
447
448 _enter("");
449
David Howells9ed900b2017-11-02 15:27:46 +0000450 afs_put_cell(net, net->ws_cell);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
David Howellsf044c882017-11-02 15:27:45 +0000452 down_write(&net->cells_sem);
David Howells08e0e7c2007-04-26 15:55:03 -0700453
David Howellsf044c882017-11-02 15:27:45 +0000454 while (!list_empty(&net->cells)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 cell = NULL;
456
457 /* remove the next cell from the front of the list */
David Howellsf044c882017-11-02 15:27:45 +0000458 write_lock(&net->cells_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
David Howellsf044c882017-11-02 15:27:45 +0000460 if (!list_empty(&net->cells)) {
461 cell = list_entry(net->cells.next,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 struct afs_cell, link);
463 list_del_init(&cell->link);
464 }
465
David Howellsf044c882017-11-02 15:27:45 +0000466 write_unlock(&net->cells_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
468 if (cell) {
469 _debug("PURGING CELL %s (%d)",
470 cell->name, atomic_read(&cell->usage));
471
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 /* now the cell should be left with no references */
David Howellsf044c882017-11-02 15:27:45 +0000473 afs_cell_destroy(net, cell);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 }
475 }
476
David Howellsf044c882017-11-02 15:27:45 +0000477 up_write(&net->cells_sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 _leave("");
David Howellsec268152007-04-26 15:49:28 -0700479}