]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - fs/afs/cell.c
afs: Overhaul permit caching
[mirror_ubuntu-jammy-kernel.git] / fs / afs / cell.c
CommitLineData
ec26815a 1/* AFS cell and server record management
1da177e4
LT
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>
1da177e4 13#include <linux/slab.h>
00d3b7a4
DH
14#include <linux/key.h>
15#include <linux/ctype.h>
07567a55 16#include <linux/dns_resolver.h>
e8edc6e0 17#include <linux/sched.h>
3838d3ec 18#include <linux/inet.h>
00d3b7a4 19#include <keys/rxrpc-type.h>
1da177e4
LT
20#include "internal.h"
21
1da177e4 22/*
00d3b7a4
DH
23 * allocate a cell record and fill in its name, VL server address list and
24 * allocate an anonymous key
1da177e4 25 */
f044c884
DH
26static struct afs_cell *afs_cell_alloc(struct afs_net *net,
27 const char *name, unsigned namelen,
bec5eb61 28 char *vllist)
1da177e4
LT
29{
30 struct afs_cell *cell;
76181c13 31 struct key *key;
00d3b7a4 32 char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
07567a55
WL
33 char *dvllist = NULL, *_vllist = NULL;
34 char delimiter = ':';
4d9df986 35 int ret, i;
1da177e4 36
bec5eb61 37 _enter("%*.*s,%s", namelen, namelen, name ?: "", vllist);
1da177e4
LT
38
39 BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
40
07567a55
WL
41 if (namelen > AFS_MAXCELLNAME) {
42 _leave(" = -ENAMETOOLONG");
00d3b7a4 43 return ERR_PTR(-ENAMETOOLONG);
07567a55 44 }
00d3b7a4 45
1da177e4 46 /* allocate and initialise a cell record */
00d3b7a4 47 cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL);
1da177e4
LT
48 if (!cell) {
49 _leave(" = -ENOMEM");
08e0e7c8 50 return ERR_PTR(-ENOMEM);
1da177e4
LT
51 }
52
00d3b7a4
DH
53 memcpy(cell->name, name, namelen);
54 cell->name[namelen] = 0;
1da177e4 55
08e0e7c8 56 atomic_set(&cell->usage, 1);
1da177e4 57 INIT_LIST_HEAD(&cell->link);
f044c884 58 cell->net = net;
08e0e7c8
DH
59 rwlock_init(&cell->servers_lock);
60 INIT_LIST_HEAD(&cell->servers);
1da177e4
LT
61 init_rwsem(&cell->vl_sem);
62 INIT_LIST_HEAD(&cell->vl_list);
08e0e7c8 63 spin_lock_init(&cell->vl_lock);
1da177e4 64
4d9df986
DH
65 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
07567a55
WL
73 /* 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) {
4a2d7892
WL
77 if (ret == -ENODATA || ret == -EAGAIN || ret == -ENOKEY)
78 /* translate these errors into something
79 * userspace might understand */
80 ret = -EDESTADDRREQ;
07567a55
WL
81 _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 {
3838d3ec
DH
90 if (strchr(vllist, ',') || !strchr(vllist, '.'))
91 delimiter = ',';
07567a55
WL
92 _vllist = vllist;
93 }
94
1da177e4 95 /* fill in the VL server list from the rest of the string */
1da177e4 96 do {
4d9df986 97 struct sockaddr_rxrpc *srx = &cell->vl_addrs[cell->vl_naddrs];
3838d3ec 98 const char *end;
1da177e4 99
07567a55 100 next = strchr(_vllist, delimiter);
1da177e4
LT
101 if (next)
102 *next++ = 0;
103
3838d3ec
DH
104 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 {
00d3b7a4 120 goto bad_address;
3838d3ec 121 }
1da177e4 122
4d9df986
DH
123 } while (cell->vl_naddrs++,
124 cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (_vllist = next));
00d3b7a4
DH
125
126 /* 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++);
00d3b7a4 133
76181c13
DH
134 key = rxrpc_get_null_key(keyname);
135 if (IS_ERR(key)) {
136 _debug("no key");
137 ret = PTR_ERR(key);
00d3b7a4
DH
138 goto error;
139 }
76181c13 140 cell->anonymous_key = key;
00d3b7a4
DH
141
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);
07567a55 153 kfree(dvllist);
00d3b7a4
DH
154 kfree(cell);
155 _leave(" = %d", ret);
156 return ERR_PTR(ret);
157}
1da177e4 158
00d3b7a4 159/*
bec5eb61 160 * afs_cell_crate() - create a cell record
f044c884 161 * @net: The network namespace
bec5eb61 162 * @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.
00d3b7a4 166 */
f044c884
DH
167struct afs_cell *afs_cell_create(struct afs_net *net,
168 const char *name, unsigned namesz,
bec5eb61 169 char *vllist, bool retref)
00d3b7a4
DH
170{
171 struct afs_cell *cell;
172 int ret;
173
bec5eb61 174 _enter("%*.*s,%s", namesz, namesz, name ?: "", vllist);
00d3b7a4 175
f044c884
DH
176 down_write(&net->cells_sem);
177 read_lock(&net->cells_lock);
178 list_for_each_entry(cell, &net->cells, link) {
bec5eb61 179 if (strncasecmp(cell->name, name, namesz) == 0)
5214b729
SS
180 goto duplicate_name;
181 }
f044c884 182 read_unlock(&net->cells_lock);
5214b729 183
f044c884 184 cell = afs_cell_alloc(net, name, namesz, vllist);
00d3b7a4
DH
185 if (IS_ERR(cell)) {
186 _leave(" = %ld", PTR_ERR(cell));
f044c884 187 up_write(&net->cells_sem);
00d3b7a4
DH
188 return cell;
189 }
190
08e0e7c8 191 /* add a proc directory for this cell */
f044c884 192 ret = afs_proc_cell_setup(net, cell);
1da177e4
LT
193 if (ret < 0)
194 goto error;
195
9b3f26c9
DH
196#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,
94d30ae9 200 cell, true);
1da177e4
LT
201#endif
202
203 /* add to the cell lists */
f044c884
DH
204 write_lock(&net->cells_lock);
205 list_add_tail(&cell->link, &net->cells);
206 write_unlock(&net->cells_lock);
1da177e4 207
f044c884
DH
208 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);
1da177e4 212
08e0e7c8
DH
213 _leave(" = %p", cell);
214 return cell;
1da177e4 215
ec26815a 216error:
f044c884 217 up_write(&net->cells_sem);
00d3b7a4 218 key_put(cell->anonymous_key);
1da177e4
LT
219 kfree(cell);
220 _leave(" = %d", ret);
08e0e7c8 221 return ERR_PTR(ret);
5214b729
SS
222
223duplicate_name:
bec5eb61 224 if (retref && !IS_ERR(cell))
225 afs_get_cell(cell);
226
f044c884
DH
227 read_unlock(&net->cells_lock);
228 up_write(&net->cells_sem);
bec5eb61 229
230 if (retref) {
231 _leave(" = %p", cell);
232 return cell;
233 }
234
235 _leave(" = -EEXIST");
5214b729 236 return ERR_PTR(-EEXIST);
ec26815a 237}
1da177e4 238
1da177e4 239/*
08e0e7c8
DH
240 * 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
1da177e4 243 */
f044c884 244int afs_cell_init(struct afs_net *net, char *rootcell)
1da177e4
LT
245{
246 struct afs_cell *old_root, *new_root;
247 char *cp;
1da177e4
LT
248
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 */
08e0e7c8 255 _leave(" = 0 [no root]");
1da177e4
LT
256 return 0;
257 }
258
259 cp = strchr(rootcell, ':');
07567a55
WL
260 if (!cp)
261 _debug("kAFS: no VL server IP addresses specified");
262 else
263 *cp++ = 0;
1da177e4
LT
264
265 /* allocate a cell record for the root cell */
f044c884 266 new_root = afs_cell_create(net, rootcell, strlen(rootcell), cp, false);
08e0e7c8
DH
267 if (IS_ERR(new_root)) {
268 _leave(" = %ld", PTR_ERR(new_root));
269 return PTR_ERR(new_root);
1da177e4
LT
270 }
271
08e0e7c8 272 /* install the new cell */
f044c884
DH
273 write_lock(&net->cells_lock);
274 old_root = net->ws_cell;
275 net->ws_cell = new_root;
276 write_unlock(&net->cells_lock);
9ed900b1 277 afs_put_cell(net, old_root);
1da177e4 278
08e0e7c8
DH
279 _leave(" = 0");
280 return 0;
ec26815a 281}
1da177e4 282
1da177e4
LT
283/*
284 * lookup a cell record
285 */
f044c884
DH
286struct afs_cell *afs_cell_lookup(struct afs_net *net,
287 const char *name, unsigned namesz,
bec5eb61 288 bool dns_cell)
1da177e4
LT
289{
290 struct afs_cell *cell;
1da177e4 291
bec5eb61 292 _enter("\"%*.*s\",", namesz, namesz, name ?: "");
1da177e4 293
f044c884
DH
294 down_read(&net->cells_sem);
295 read_lock(&net->cells_lock);
1da177e4
LT
296
297 if (name) {
298 /* if the cell was named, look for it in the cell record list */
f044c884 299 list_for_each_entry(cell, &net->cells, link) {
1da177e4
LT
300 if (strncmp(cell->name, name, namesz) == 0) {
301 afs_get_cell(cell);
302 goto found;
303 }
304 }
08e0e7c8 305 cell = ERR_PTR(-ENOENT);
bec5eb61 306 if (dns_cell)
307 goto create_cell;
1da177e4 308 found:
08e0e7c8 309 ;
ec26815a 310 } else {
f044c884 311 cell = net->ws_cell;
1da177e4
LT
312 if (!cell) {
313 /* this should not happen unless user tries to mount
314 * when root cell is not set. Return an impossibly
25985edc 315 * bizarre errno to alert the user. Things like
1da177e4
LT
316 * ENOENT might be "more appropriate" but they happen
317 * for other reasons.
318 */
08e0e7c8 319 cell = ERR_PTR(-EDESTADDRREQ);
ec26815a 320 } else {
1da177e4 321 afs_get_cell(cell);
1da177e4
LT
322 }
323
1da177e4
LT
324 }
325
f044c884
DH
326 read_unlock(&net->cells_lock);
327 up_read(&net->cells_sem);
08e0e7c8
DH
328 _leave(" = %p", cell);
329 return cell;
bec5eb61 330
331create_cell:
f044c884
DH
332 read_unlock(&net->cells_lock);
333 up_read(&net->cells_sem);
bec5eb61 334
f044c884 335 cell = afs_cell_create(net, name, namesz, NULL, true);
bec5eb61 336
337 _leave(" = %p", cell);
338 return cell;
ec26815a 339}
1da177e4 340
c1206a2c 341#if 0
1da177e4
LT
342/*
343 * try and get a cell record
344 */
08e0e7c8 345struct afs_cell *afs_get_cell_maybe(struct afs_cell *cell)
1da177e4 346{
f044c884 347 write_lock(&net->cells_lock);
1da177e4 348
1da177e4
LT
349 if (cell && !list_empty(&cell->link))
350 afs_get_cell(cell);
351 else
352 cell = NULL;
353
f044c884 354 write_unlock(&net->cells_lock);
1da177e4 355 return cell;
ec26815a 356}
c1206a2c 357#endif /* 0 */
1da177e4 358
1da177e4
LT
359/*
360 * destroy a cell record
361 */
9ed900b1 362void afs_put_cell(struct afs_net *net, struct afs_cell *cell)
1da177e4
LT
363{
364 if (!cell)
365 return;
366
367 _enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
368
08e0e7c8 369 ASSERTCMP(atomic_read(&cell->usage), >, 0);
1da177e4
LT
370
371 /* to prevent a race, the decrement and the dequeue must be effectively
372 * atomic */
9ed900b1 373 write_lock(&net->cells_lock);
1da177e4
LT
374
375 if (likely(!atomic_dec_and_test(&cell->usage))) {
9ed900b1 376 write_unlock(&net->cells_lock);
1da177e4
LT
377 _leave("");
378 return;
379 }
380
08e0e7c8
DH
381 ASSERT(list_empty(&cell->servers));
382 ASSERT(list_empty(&cell->vl_list));
383
9ed900b1 384 wake_up(&net->cells_freeable_wq);
1da177e4 385
9ed900b1 386 write_unlock(&net->cells_lock);
1da177e4
LT
387
388 _leave(" [unused]");
ec26815a 389}
1da177e4 390
1da177e4
LT
391/*
392 * destroy a cell record
f044c884 393 * - must be called with the net->cells_sem write-locked
08e0e7c8 394 * - cell->link should have been broken by the caller
1da177e4 395 */
f044c884 396static void afs_cell_destroy(struct afs_net *net, struct afs_cell *cell)
1da177e4
LT
397{
398 _enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
399
08e0e7c8
DH
400 ASSERTCMP(atomic_read(&cell->usage), >=, 0);
401 ASSERT(list_empty(&cell->link));
1da177e4 402
08e0e7c8
DH
403 /* wait for everyone to stop using the cell */
404 if (atomic_read(&cell->usage) > 0) {
405 DECLARE_WAITQUEUE(myself, current);
1da177e4 406
08e0e7c8
DH
407 _debug("wait for cell %s", cell->name);
408 set_current_state(TASK_UNINTERRUPTIBLE);
f044c884 409 add_wait_queue(&net->cells_freeable_wq, &myself);
1da177e4 410
08e0e7c8
DH
411 while (atomic_read(&cell->usage) > 0) {
412 schedule();
413 set_current_state(TASK_UNINTERRUPTIBLE);
414 }
1da177e4 415
f044c884 416 remove_wait_queue(&net->cells_freeable_wq, &myself);
08e0e7c8
DH
417 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));
1da177e4 424
f044c884 425 afs_proc_cell_remove(net, cell);
1da177e4 426
f044c884 427 down_write(&net->proc_cells_sem);
1da177e4 428 list_del_init(&cell->proc_link);
f044c884 429 up_write(&net->proc_cells_sem);
1da177e4 430
9b3f26c9
DH
431#ifdef CONFIG_AFS_FSCACHE
432 fscache_relinquish_cookie(cell->cache, 0);
1da177e4 433#endif
00d3b7a4 434 key_put(cell->anonymous_key);
1da177e4
LT
435 kfree(cell);
436
437 _leave(" [destroyed]");
ec26815a 438}
1da177e4 439
1da177e4
LT
440/*
441 * purge in-memory cell database on module unload or afs_init() failure
442 * - the timeout daemon is stopped before calling this
443 */
f044c884 444void afs_cell_purge(struct afs_net *net)
1da177e4 445{
1da177e4
LT
446 struct afs_cell *cell;
447
448 _enter("");
449
9ed900b1 450 afs_put_cell(net, net->ws_cell);
1da177e4 451
f044c884 452 down_write(&net->cells_sem);
08e0e7c8 453
f044c884 454 while (!list_empty(&net->cells)) {
1da177e4
LT
455 cell = NULL;
456
457 /* remove the next cell from the front of the list */
f044c884 458 write_lock(&net->cells_lock);
1da177e4 459
f044c884
DH
460 if (!list_empty(&net->cells)) {
461 cell = list_entry(net->cells.next,
1da177e4
LT
462 struct afs_cell, link);
463 list_del_init(&cell->link);
464 }
465
f044c884 466 write_unlock(&net->cells_lock);
1da177e4
LT
467
468 if (cell) {
469 _debug("PURGING CELL %s (%d)",
470 cell->name, atomic_read(&cell->usage));
471
1da177e4 472 /* now the cell should be left with no references */
f044c884 473 afs_cell_destroy(net, cell);
1da177e4
LT
474 }
475 }
476
f044c884 477 up_write(&net->cells_sem);
1da177e4 478 _leave("");
ec26815a 479}