diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-16 03:32:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-16 03:32:04 -0400 |
commit | 35773c93817c5f2df264d013978e7551056a063a (patch) | |
tree | 5ca02a3f3c680091d5b1019b27ba23b5323a038a /fs/afs | |
parent | 29d6849d88b61edf130aef500acad78206bda3cd (diff) | |
parent | 47ea0f2ebffd400d36ab5946ec8d6d6e08a67d53 (diff) |
Merge branch 'afs-proc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull AFS updates from Al Viro:
"Assorted AFS stuff - ended up in vfs.git since most of that consists
of David's AFS-related followups to Christoph's procfs series"
* 'afs-proc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
afs: Optimise callback breaking by not repeating volume lookup
afs: Display manually added cells in dynamic root mount
afs: Enable IPv6 DNS lookups
afs: Show all of a server's addresses in /proc/fs/afs/servers
afs: Handle CONFIG_PROC_FS=n
proc: Make inline name size calculation automatic
afs: Implement network namespacing
afs: Mark afs_net::ws_cell as __rcu and set using rcu functions
afs: Fix a Sparse warning in xdr_decode_AFSFetchStatus()
proc: Add a way to make network proc files writable
afs: Rearrange fs/afs/proc.c to remove remaining predeclarations.
afs: Rearrange fs/afs/proc.c to move the show routines up
afs: Rearrange fs/afs/proc.c by moving fops and open functions down
afs: Move /proc management functions to the end of the file
Diffstat (limited to 'fs/afs')
-rw-r--r-- | fs/afs/Makefile | 4 | ||||
-rw-r--r-- | fs/afs/addr_list.c | 2 | ||||
-rw-r--r-- | fs/afs/callback.c | 110 | ||||
-rw-r--r-- | fs/afs/cell.c | 24 | ||||
-rw-r--r-- | fs/afs/cmservice.c | 2 | ||||
-rw-r--r-- | fs/afs/dynroot.c | 126 | ||||
-rw-r--r-- | fs/afs/fsclient.c | 100 | ||||
-rw-r--r-- | fs/afs/internal.h | 75 | ||||
-rw-r--r-- | fs/afs/main.c | 35 | ||||
-rw-r--r-- | fs/afs/netdevices.c | 6 | ||||
-rw-r--r-- | fs/afs/proc.c | 793 | ||||
-rw-r--r-- | fs/afs/rxrpc.c | 2 | ||||
-rw-r--r-- | fs/afs/server.c | 2 | ||||
-rw-r--r-- | fs/afs/super.c | 68 |
14 files changed, 716 insertions, 633 deletions
diff --git a/fs/afs/Makefile b/fs/afs/Makefile index 532acae25453..546874057bd3 100644 --- a/fs/afs/Makefile +++ b/fs/afs/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | afs-cache-$(CONFIG_AFS_FSCACHE) := cache.o | 6 | afs-cache-$(CONFIG_AFS_FSCACHE) := cache.o |
7 | 7 | ||
8 | kafs-objs := \ | 8 | kafs-y := \ |
9 | $(afs-cache-y) \ | 9 | $(afs-cache-y) \ |
10 | addr_list.o \ | 10 | addr_list.o \ |
11 | callback.o \ | 11 | callback.o \ |
@@ -21,7 +21,6 @@ kafs-objs := \ | |||
21 | main.o \ | 21 | main.o \ |
22 | misc.o \ | 22 | misc.o \ |
23 | mntpt.o \ | 23 | mntpt.o \ |
24 | proc.o \ | ||
25 | rotate.o \ | 24 | rotate.o \ |
26 | rxrpc.o \ | 25 | rxrpc.o \ |
27 | security.o \ | 26 | security.o \ |
@@ -34,4 +33,5 @@ kafs-objs := \ | |||
34 | write.o \ | 33 | write.o \ |
35 | xattr.o | 34 | xattr.o |
36 | 35 | ||
36 | kafs-$(CONFIG_PROC_FS) += proc.o | ||
37 | obj-$(CONFIG_AFS_FS) := kafs.o | 37 | obj-$(CONFIG_AFS_FS) := kafs.o |
diff --git a/fs/afs/addr_list.c b/fs/afs/addr_list.c index 2c46c46f3a6d..025a9a5e1c32 100644 --- a/fs/afs/addr_list.c +++ b/fs/afs/addr_list.c | |||
@@ -215,7 +215,7 @@ struct afs_addr_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry) | |||
215 | _enter("%s", cell->name); | 215 | _enter("%s", cell->name); |
216 | 216 | ||
217 | ret = dns_query("afsdb", cell->name, cell->name_len, | 217 | ret = dns_query("afsdb", cell->name, cell->name_len, |
218 | "ipv4", &vllist, _expiry); | 218 | "", &vllist, _expiry); |
219 | if (ret < 0) | 219 | if (ret < 0) |
220 | return ERR_PTR(ret); | 220 | return ERR_PTR(ret); |
221 | 221 | ||
diff --git a/fs/afs/callback.c b/fs/afs/callback.c index 571437dcb252..5f261fbf2182 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c | |||
@@ -21,6 +21,66 @@ | |||
21 | #include "internal.h" | 21 | #include "internal.h" |
22 | 22 | ||
23 | /* | 23 | /* |
24 | * Create volume and callback interests on a server. | ||
25 | */ | ||
26 | static struct afs_cb_interest *afs_create_interest(struct afs_server *server, | ||
27 | struct afs_vnode *vnode) | ||
28 | { | ||
29 | struct afs_vol_interest *new_vi, *vi; | ||
30 | struct afs_cb_interest *new; | ||
31 | struct hlist_node **pp; | ||
32 | |||
33 | new_vi = kzalloc(sizeof(struct afs_vol_interest), GFP_KERNEL); | ||
34 | if (!new_vi) | ||
35 | return NULL; | ||
36 | |||
37 | new = kzalloc(sizeof(struct afs_cb_interest), GFP_KERNEL); | ||
38 | if (!new) { | ||
39 | kfree(new_vi); | ||
40 | return NULL; | ||
41 | } | ||
42 | |||
43 | new_vi->usage = 1; | ||
44 | new_vi->vid = vnode->volume->vid; | ||
45 | INIT_HLIST_NODE(&new_vi->srv_link); | ||
46 | INIT_HLIST_HEAD(&new_vi->cb_interests); | ||
47 | |||
48 | refcount_set(&new->usage, 1); | ||
49 | new->sb = vnode->vfs_inode.i_sb; | ||
50 | new->vid = vnode->volume->vid; | ||
51 | new->server = afs_get_server(server); | ||
52 | INIT_HLIST_NODE(&new->cb_vlink); | ||
53 | |||
54 | write_lock(&server->cb_break_lock); | ||
55 | |||
56 | for (pp = &server->cb_volumes.first; *pp; pp = &(*pp)->next) { | ||
57 | vi = hlist_entry(*pp, struct afs_vol_interest, srv_link); | ||
58 | if (vi->vid < new_vi->vid) | ||
59 | continue; | ||
60 | if (vi->vid > new_vi->vid) | ||
61 | break; | ||
62 | vi->usage++; | ||
63 | goto found_vi; | ||
64 | } | ||
65 | |||
66 | new_vi->srv_link.pprev = pp; | ||
67 | new_vi->srv_link.next = *pp; | ||
68 | if (*pp) | ||
69 | (*pp)->pprev = &new_vi->srv_link.next; | ||
70 | *pp = &new_vi->srv_link; | ||
71 | vi = new_vi; | ||
72 | new_vi = NULL; | ||
73 | found_vi: | ||
74 | |||
75 | new->vol_interest = vi; | ||
76 | hlist_add_head(&new->cb_vlink, &vi->cb_interests); | ||
77 | |||
78 | write_unlock(&server->cb_break_lock); | ||
79 | kfree(new_vi); | ||
80 | return new; | ||
81 | } | ||
82 | |||
83 | /* | ||
24 | * Set up an interest-in-callbacks record for a volume on a server and | 84 | * Set up an interest-in-callbacks record for a volume on a server and |
25 | * register it with the server. | 85 | * register it with the server. |
26 | * - Called with vnode->io_lock held. | 86 | * - Called with vnode->io_lock held. |
@@ -77,20 +137,10 @@ again: | |||
77 | } | 137 | } |
78 | 138 | ||
79 | if (!cbi) { | 139 | if (!cbi) { |
80 | new = kzalloc(sizeof(struct afs_cb_interest), GFP_KERNEL); | 140 | new = afs_create_interest(server, vnode); |
81 | if (!new) | 141 | if (!new) |
82 | return -ENOMEM; | 142 | return -ENOMEM; |
83 | 143 | ||
84 | refcount_set(&new->usage, 1); | ||
85 | new->sb = vnode->vfs_inode.i_sb; | ||
86 | new->vid = vnode->volume->vid; | ||
87 | new->server = afs_get_server(server); | ||
88 | INIT_LIST_HEAD(&new->cb_link); | ||
89 | |||
90 | write_lock(&server->cb_break_lock); | ||
91 | list_add_tail(&new->cb_link, &server->cb_interests); | ||
92 | write_unlock(&server->cb_break_lock); | ||
93 | |||
94 | write_lock(&slist->lock); | 144 | write_lock(&slist->lock); |
95 | if (!entry->cb_interest) { | 145 | if (!entry->cb_interest) { |
96 | entry->cb_interest = afs_get_cb_interest(new); | 146 | entry->cb_interest = afs_get_cb_interest(new); |
@@ -126,11 +176,22 @@ again: | |||
126 | */ | 176 | */ |
127 | void afs_put_cb_interest(struct afs_net *net, struct afs_cb_interest *cbi) | 177 | void afs_put_cb_interest(struct afs_net *net, struct afs_cb_interest *cbi) |
128 | { | 178 | { |
179 | struct afs_vol_interest *vi; | ||
180 | |||
129 | if (cbi && refcount_dec_and_test(&cbi->usage)) { | 181 | if (cbi && refcount_dec_and_test(&cbi->usage)) { |
130 | if (!list_empty(&cbi->cb_link)) { | 182 | if (!hlist_unhashed(&cbi->cb_vlink)) { |
131 | write_lock(&cbi->server->cb_break_lock); | 183 | write_lock(&cbi->server->cb_break_lock); |
132 | list_del_init(&cbi->cb_link); | 184 | |
185 | hlist_del_init(&cbi->cb_vlink); | ||
186 | vi = cbi->vol_interest; | ||
187 | cbi->vol_interest = NULL; | ||
188 | if (--vi->usage == 0) | ||
189 | hlist_del(&vi->srv_link); | ||
190 | else | ||
191 | vi = NULL; | ||
192 | |||
133 | write_unlock(&cbi->server->cb_break_lock); | 193 | write_unlock(&cbi->server->cb_break_lock); |
194 | kfree(vi); | ||
134 | afs_put_server(net, cbi->server); | 195 | afs_put_server(net, cbi->server); |
135 | } | 196 | } |
136 | kfree(cbi); | 197 | kfree(cbi); |
@@ -182,20 +243,34 @@ void afs_break_callback(struct afs_vnode *vnode) | |||
182 | static void afs_break_one_callback(struct afs_server *server, | 243 | static void afs_break_one_callback(struct afs_server *server, |
183 | struct afs_fid *fid) | 244 | struct afs_fid *fid) |
184 | { | 245 | { |
246 | struct afs_vol_interest *vi; | ||
185 | struct afs_cb_interest *cbi; | 247 | struct afs_cb_interest *cbi; |
186 | struct afs_iget_data data; | 248 | struct afs_iget_data data; |
187 | struct afs_vnode *vnode; | 249 | struct afs_vnode *vnode; |
188 | struct inode *inode; | 250 | struct inode *inode; |
189 | 251 | ||
190 | read_lock(&server->cb_break_lock); | 252 | read_lock(&server->cb_break_lock); |
253 | hlist_for_each_entry(vi, &server->cb_volumes, srv_link) { | ||
254 | if (vi->vid < fid->vid) | ||
255 | continue; | ||
256 | if (vi->vid > fid->vid) { | ||
257 | vi = NULL; | ||
258 | break; | ||
259 | } | ||
260 | //atomic_inc(&vi->usage); | ||
261 | break; | ||
262 | } | ||
263 | |||
264 | /* TODO: Find all matching volumes if we couldn't match the server and | ||
265 | * break them anyway. | ||
266 | */ | ||
267 | if (!vi) | ||
268 | goto out; | ||
191 | 269 | ||
192 | /* Step through all interested superblocks. There may be more than one | 270 | /* Step through all interested superblocks. There may be more than one |
193 | * because of cell aliasing. | 271 | * because of cell aliasing. |
194 | */ | 272 | */ |
195 | list_for_each_entry(cbi, &server->cb_interests, cb_link) { | 273 | hlist_for_each_entry(cbi, &vi->cb_interests, cb_vlink) { |
196 | if (cbi->vid != fid->vid) | ||
197 | continue; | ||
198 | |||
199 | if (fid->vnode == 0 && fid->unique == 0) { | 274 | if (fid->vnode == 0 && fid->unique == 0) { |
200 | /* The callback break applies to an entire volume. */ | 275 | /* The callback break applies to an entire volume. */ |
201 | struct afs_super_info *as = AFS_FS_S(cbi->sb); | 276 | struct afs_super_info *as = AFS_FS_S(cbi->sb); |
@@ -217,6 +292,7 @@ static void afs_break_one_callback(struct afs_server *server, | |||
217 | } | 292 | } |
218 | } | 293 | } |
219 | 294 | ||
295 | out: | ||
220 | read_unlock(&server->cb_break_lock); | 296 | read_unlock(&server->cb_break_lock); |
221 | } | 297 | } |
222 | 298 | ||
diff --git a/fs/afs/cell.c b/fs/afs/cell.c index fdf4c36cff79..f3d0bef16d78 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/dns_resolver.h> | 15 | #include <linux/dns_resolver.h> |
16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
17 | #include <linux/inet.h> | 17 | #include <linux/inet.h> |
18 | #include <linux/namei.h> | ||
18 | #include <keys/rxrpc-type.h> | 19 | #include <keys/rxrpc-type.h> |
19 | #include "internal.h" | 20 | #include "internal.h" |
20 | 21 | ||
@@ -341,8 +342,8 @@ int afs_cell_init(struct afs_net *net, const char *rootcell) | |||
341 | 342 | ||
342 | /* install the new cell */ | 343 | /* install the new cell */ |
343 | write_seqlock(&net->cells_lock); | 344 | write_seqlock(&net->cells_lock); |
344 | old_root = net->ws_cell; | 345 | old_root = rcu_access_pointer(net->ws_cell); |
345 | net->ws_cell = new_root; | 346 | rcu_assign_pointer(net->ws_cell, new_root); |
346 | write_sequnlock(&net->cells_lock); | 347 | write_sequnlock(&net->cells_lock); |
347 | 348 | ||
348 | afs_put_cell(net, old_root); | 349 | afs_put_cell(net, old_root); |
@@ -528,12 +529,14 @@ static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell) | |||
528 | NULL, 0, | 529 | NULL, 0, |
529 | cell, 0, true); | 530 | cell, 0, true); |
530 | #endif | 531 | #endif |
531 | ret = afs_proc_cell_setup(net, cell); | 532 | ret = afs_proc_cell_setup(cell); |
532 | if (ret < 0) | 533 | if (ret < 0) |
533 | return ret; | 534 | return ret; |
534 | spin_lock(&net->proc_cells_lock); | 535 | |
536 | mutex_lock(&net->proc_cells_lock); | ||
535 | list_add_tail(&cell->proc_link, &net->proc_cells); | 537 | list_add_tail(&cell->proc_link, &net->proc_cells); |
536 | spin_unlock(&net->proc_cells_lock); | 538 | afs_dynroot_mkdir(net, cell); |
539 | mutex_unlock(&net->proc_cells_lock); | ||
537 | return 0; | 540 | return 0; |
538 | } | 541 | } |
539 | 542 | ||
@@ -544,11 +547,12 @@ static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell) | |||
544 | { | 547 | { |
545 | _enter("%s", cell->name); | 548 | _enter("%s", cell->name); |
546 | 549 | ||
547 | afs_proc_cell_remove(net, cell); | 550 | afs_proc_cell_remove(cell); |
548 | 551 | ||
549 | spin_lock(&net->proc_cells_lock); | 552 | mutex_lock(&net->proc_cells_lock); |
550 | list_del_init(&cell->proc_link); | 553 | list_del_init(&cell->proc_link); |
551 | spin_unlock(&net->proc_cells_lock); | 554 | afs_dynroot_rmdir(net, cell); |
555 | mutex_unlock(&net->proc_cells_lock); | ||
552 | 556 | ||
553 | #ifdef CONFIG_AFS_FSCACHE | 557 | #ifdef CONFIG_AFS_FSCACHE |
554 | fscache_relinquish_cookie(cell->cache, NULL, false); | 558 | fscache_relinquish_cookie(cell->cache, NULL, false); |
@@ -755,8 +759,8 @@ void afs_cell_purge(struct afs_net *net) | |||
755 | _enter(""); | 759 | _enter(""); |
756 | 760 | ||
757 | write_seqlock(&net->cells_lock); | 761 | write_seqlock(&net->cells_lock); |
758 | ws = net->ws_cell; | 762 | ws = rcu_access_pointer(net->ws_cell); |
759 | net->ws_cell = NULL; | 763 | RCU_INIT_POINTER(net->ws_cell, NULL); |
760 | write_sequnlock(&net->cells_lock); | 764 | write_sequnlock(&net->cells_lock); |
761 | afs_put_cell(net, ws); | 765 | afs_put_cell(net, ws); |
762 | 766 | ||
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index 238fd28cfdd2..9e51d6fe7e8f 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c | |||
@@ -526,7 +526,7 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work) | |||
526 | nifs = 0; | 526 | nifs = 0; |
527 | ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL); | 527 | ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL); |
528 | if (ifs) { | 528 | if (ifs) { |
529 | nifs = afs_get_ipv4_interfaces(ifs, 32, false); | 529 | nifs = afs_get_ipv4_interfaces(call->net, ifs, 32, false); |
530 | if (nifs < 0) { | 530 | if (nifs < 0) { |
531 | kfree(ifs); | 531 | kfree(ifs); |
532 | ifs = NULL; | 532 | ifs = NULL; |
diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c index 983f3946ab57..174e843f0633 100644 --- a/fs/afs/dynroot.c +++ b/fs/afs/dynroot.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* dir.c: AFS dynamic root handling | 1 | /* AFS dynamic root handling |
2 | * | 2 | * |
3 | * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
@@ -46,7 +46,7 @@ static int afs_probe_cell_name(struct dentry *dentry) | |||
46 | return 0; | 46 | return 0; |
47 | } | 47 | } |
48 | 48 | ||
49 | ret = dns_query("afsdb", name, len, "ipv4", NULL, NULL); | 49 | ret = dns_query("afsdb", name, len, "", NULL, NULL); |
50 | if (ret == -ENODATA) | 50 | if (ret == -ENODATA) |
51 | ret = -EDESTADDRREQ; | 51 | ret = -EDESTADDRREQ; |
52 | return ret; | 52 | return ret; |
@@ -207,3 +207,125 @@ const struct dentry_operations afs_dynroot_dentry_operations = { | |||
207 | .d_release = afs_d_release, | 207 | .d_release = afs_d_release, |
208 | .d_automount = afs_d_automount, | 208 | .d_automount = afs_d_automount, |
209 | }; | 209 | }; |
210 | |||
211 | /* | ||
212 | * Create a manually added cell mount directory. | ||
213 | * - The caller must hold net->proc_cells_lock | ||
214 | */ | ||
215 | int afs_dynroot_mkdir(struct afs_net *net, struct afs_cell *cell) | ||
216 | { | ||
217 | struct super_block *sb = net->dynroot_sb; | ||
218 | struct dentry *root, *subdir; | ||
219 | int ret; | ||
220 | |||
221 | if (!sb || atomic_read(&sb->s_active) == 0) | ||
222 | return 0; | ||
223 | |||
224 | /* Let the ->lookup op do the creation */ | ||
225 | root = sb->s_root; | ||
226 | inode_lock(root->d_inode); | ||
227 | subdir = lookup_one_len(cell->name, root, cell->name_len); | ||
228 | if (IS_ERR(subdir)) { | ||
229 | ret = PTR_ERR(subdir); | ||
230 | goto unlock; | ||
231 | } | ||
232 | |||
233 | /* Note that we're retaining an extra ref on the dentry */ | ||
234 | subdir->d_fsdata = (void *)1UL; | ||
235 | ret = 0; | ||
236 | unlock: | ||
237 | inode_unlock(root->d_inode); | ||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * Remove a manually added cell mount directory. | ||
243 | * - The caller must hold net->proc_cells_lock | ||
244 | */ | ||
245 | void afs_dynroot_rmdir(struct afs_net *net, struct afs_cell *cell) | ||
246 | { | ||
247 | struct super_block *sb = net->dynroot_sb; | ||
248 | struct dentry *root, *subdir; | ||
249 | |||
250 | if (!sb || atomic_read(&sb->s_active) == 0) | ||
251 | return; | ||
252 | |||
253 | root = sb->s_root; | ||
254 | inode_lock(root->d_inode); | ||
255 | |||
256 | /* Don't want to trigger a lookup call, which will re-add the cell */ | ||
257 | subdir = try_lookup_one_len(cell->name, root, cell->name_len); | ||
258 | if (IS_ERR_OR_NULL(subdir)) { | ||
259 | _debug("lookup %ld", PTR_ERR(subdir)); | ||
260 | goto no_dentry; | ||
261 | } | ||
262 | |||
263 | _debug("rmdir %pd %u", subdir, d_count(subdir)); | ||
264 | |||
265 | if (subdir->d_fsdata) { | ||
266 | _debug("unpin %u", d_count(subdir)); | ||
267 | subdir->d_fsdata = NULL; | ||
268 | dput(subdir); | ||
269 | } | ||
270 | dput(subdir); | ||
271 | no_dentry: | ||
272 | inode_unlock(root->d_inode); | ||
273 | _leave(""); | ||
274 | } | ||
275 | |||
276 | /* | ||
277 | * Populate a newly created dynamic root with cell names. | ||
278 | */ | ||
279 | int afs_dynroot_populate(struct super_block *sb) | ||
280 | { | ||
281 | struct afs_cell *cell; | ||
282 | struct afs_net *net = afs_sb2net(sb); | ||
283 | int ret; | ||
284 | |||
285 | if (mutex_lock_interruptible(&net->proc_cells_lock) < 0) | ||
286 | return -ERESTARTSYS; | ||
287 | |||
288 | net->dynroot_sb = sb; | ||
289 | list_for_each_entry(cell, &net->proc_cells, proc_link) { | ||
290 | ret = afs_dynroot_mkdir(net, cell); | ||
291 | if (ret < 0) | ||
292 | goto error; | ||
293 | } | ||
294 | |||
295 | ret = 0; | ||
296 | out: | ||
297 | mutex_unlock(&net->proc_cells_lock); | ||
298 | return ret; | ||
299 | |||
300 | error: | ||
301 | net->dynroot_sb = NULL; | ||
302 | goto out; | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * When a dynamic root that's in the process of being destroyed, depopulate it | ||
307 | * of pinned directories. | ||
308 | */ | ||
309 | void afs_dynroot_depopulate(struct super_block *sb) | ||
310 | { | ||
311 | struct afs_net *net = afs_sb2net(sb); | ||
312 | struct dentry *root = sb->s_root, *subdir, *tmp; | ||
313 | |||
314 | /* Prevent more subdirs from being created */ | ||
315 | mutex_lock(&net->proc_cells_lock); | ||
316 | if (net->dynroot_sb == sb) | ||
317 | net->dynroot_sb = NULL; | ||
318 | mutex_unlock(&net->proc_cells_lock); | ||
319 | |||
320 | inode_lock(root->d_inode); | ||
321 | |||
322 | /* Remove all the pins for dirs created for manually added cells */ | ||
323 | list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) { | ||
324 | if (subdir->d_fsdata) { | ||
325 | subdir->d_fsdata = NULL; | ||
326 | dput(subdir); | ||
327 | } | ||
328 | } | ||
329 | |||
330 | inode_unlock(root->d_inode); | ||
331 | } | ||
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 5907601aafd0..50929cb91732 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c | |||
@@ -138,10 +138,6 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, | |||
138 | u64 data_version, size; | 138 | u64 data_version, size; |
139 | u32 type, abort_code; | 139 | u32 type, abort_code; |
140 | u8 flags = 0; | 140 | u8 flags = 0; |
141 | int ret; | ||
142 | |||
143 | if (vnode) | ||
144 | write_seqlock(&vnode->cb_lock); | ||
145 | 141 | ||
146 | abort_code = ntohl(xdr->abort_code); | 142 | abort_code = ntohl(xdr->abort_code); |
147 | 143 | ||
@@ -154,8 +150,7 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, | |||
154 | * case. | 150 | * case. |
155 | */ | 151 | */ |
156 | status->abort_code = abort_code; | 152 | status->abort_code = abort_code; |
157 | ret = 0; | 153 | return 0; |
158 | goto out; | ||
159 | } | 154 | } |
160 | 155 | ||
161 | pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version)); | 156 | pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version)); |
@@ -164,8 +159,7 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, | |||
164 | 159 | ||
165 | if (abort_code != 0 && inline_error) { | 160 | if (abort_code != 0 && inline_error) { |
166 | status->abort_code = abort_code; | 161 | status->abort_code = abort_code; |
167 | ret = 0; | 162 | return 0; |
168 | goto out; | ||
169 | } | 163 | } |
170 | 164 | ||
171 | type = ntohl(xdr->type); | 165 | type = ntohl(xdr->type); |
@@ -235,17 +229,35 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, | |||
235 | flags); | 229 | flags); |
236 | } | 230 | } |
237 | 231 | ||
238 | ret = 0; | 232 | return 0; |
239 | |||
240 | out: | ||
241 | if (vnode) | ||
242 | write_sequnlock(&vnode->cb_lock); | ||
243 | return ret; | ||
244 | 233 | ||
245 | bad: | 234 | bad: |
246 | xdr_dump_bad(*_bp); | 235 | xdr_dump_bad(*_bp); |
247 | ret = afs_protocol_error(call, -EBADMSG); | 236 | return afs_protocol_error(call, -EBADMSG); |
248 | goto out; | 237 | } |
238 | |||
239 | /* | ||
240 | * Decode the file status. We need to lock the target vnode if we're going to | ||
241 | * update its status so that stat() sees the attributes update atomically. | ||
242 | */ | ||
243 | static int afs_decode_status(struct afs_call *call, | ||
244 | const __be32 **_bp, | ||
245 | struct afs_file_status *status, | ||
246 | struct afs_vnode *vnode, | ||
247 | const afs_dataversion_t *expected_version, | ||
248 | struct afs_read *read_req) | ||
249 | { | ||
250 | int ret; | ||
251 | |||
252 | if (!vnode) | ||
253 | return xdr_decode_AFSFetchStatus(call, _bp, status, vnode, | ||
254 | expected_version, read_req); | ||
255 | |||
256 | write_seqlock(&vnode->cb_lock); | ||
257 | ret = xdr_decode_AFSFetchStatus(call, _bp, status, vnode, | ||
258 | expected_version, read_req); | ||
259 | write_sequnlock(&vnode->cb_lock); | ||
260 | return ret; | ||
249 | } | 261 | } |
250 | 262 | ||
251 | /* | 263 | /* |
@@ -387,8 +399,8 @@ static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call) | |||
387 | 399 | ||
388 | /* unmarshall the reply once we've received all of it */ | 400 | /* unmarshall the reply once we've received all of it */ |
389 | bp = call->buffer; | 401 | bp = call->buffer; |
390 | if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, | 402 | if (afs_decode_status(call, &bp, &vnode->status, vnode, |
391 | &call->expected_version, NULL) < 0) | 403 | &call->expected_version, NULL) < 0) |
392 | return afs_protocol_error(call, -EBADMSG); | 404 | return afs_protocol_error(call, -EBADMSG); |
393 | xdr_decode_AFSCallBack(call, vnode, &bp); | 405 | xdr_decode_AFSCallBack(call, vnode, &bp); |
394 | if (call->reply[1]) | 406 | if (call->reply[1]) |
@@ -568,8 +580,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) | |||
568 | return ret; | 580 | return ret; |
569 | 581 | ||
570 | bp = call->buffer; | 582 | bp = call->buffer; |
571 | if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, | 583 | if (afs_decode_status(call, &bp, &vnode->status, vnode, |
572 | &vnode->status.data_version, req) < 0) | 584 | &vnode->status.data_version, req) < 0) |
573 | return afs_protocol_error(call, -EBADMSG); | 585 | return afs_protocol_error(call, -EBADMSG); |
574 | xdr_decode_AFSCallBack(call, vnode, &bp); | 586 | xdr_decode_AFSCallBack(call, vnode, &bp); |
575 | if (call->reply[1]) | 587 | if (call->reply[1]) |
@@ -721,9 +733,9 @@ static int afs_deliver_fs_create_vnode(struct afs_call *call) | |||
721 | /* unmarshall the reply once we've received all of it */ | 733 | /* unmarshall the reply once we've received all of it */ |
722 | bp = call->buffer; | 734 | bp = call->buffer; |
723 | xdr_decode_AFSFid(&bp, call->reply[1]); | 735 | xdr_decode_AFSFid(&bp, call->reply[1]); |
724 | if (xdr_decode_AFSFetchStatus(call, &bp, call->reply[2], NULL, NULL, NULL) < 0 || | 736 | if (afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL) < 0 || |
725 | xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, | 737 | afs_decode_status(call, &bp, &vnode->status, vnode, |
726 | &call->expected_version, NULL) < 0) | 738 | &call->expected_version, NULL) < 0) |
727 | return afs_protocol_error(call, -EBADMSG); | 739 | return afs_protocol_error(call, -EBADMSG); |
728 | xdr_decode_AFSCallBack_raw(&bp, call->reply[3]); | 740 | xdr_decode_AFSCallBack_raw(&bp, call->reply[3]); |
729 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | 741 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
@@ -827,8 +839,8 @@ static int afs_deliver_fs_remove(struct afs_call *call) | |||
827 | 839 | ||
828 | /* unmarshall the reply once we've received all of it */ | 840 | /* unmarshall the reply once we've received all of it */ |
829 | bp = call->buffer; | 841 | bp = call->buffer; |
830 | if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, | 842 | if (afs_decode_status(call, &bp, &vnode->status, vnode, |
831 | &call->expected_version, NULL) < 0) | 843 | &call->expected_version, NULL) < 0) |
832 | return afs_protocol_error(call, -EBADMSG); | 844 | return afs_protocol_error(call, -EBADMSG); |
833 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | 845 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
834 | 846 | ||
@@ -917,9 +929,9 @@ static int afs_deliver_fs_link(struct afs_call *call) | |||
917 | 929 | ||
918 | /* unmarshall the reply once we've received all of it */ | 930 | /* unmarshall the reply once we've received all of it */ |
919 | bp = call->buffer; | 931 | bp = call->buffer; |
920 | if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, NULL, NULL) < 0 || | 932 | if (afs_decode_status(call, &bp, &vnode->status, vnode, NULL, NULL) < 0 || |
921 | xdr_decode_AFSFetchStatus(call, &bp, &dvnode->status, dvnode, | 933 | afs_decode_status(call, &bp, &dvnode->status, dvnode, |
922 | &call->expected_version, NULL) < 0) | 934 | &call->expected_version, NULL) < 0) |
923 | return afs_protocol_error(call, -EBADMSG); | 935 | return afs_protocol_error(call, -EBADMSG); |
924 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | 936 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
925 | 937 | ||
@@ -1004,9 +1016,9 @@ static int afs_deliver_fs_symlink(struct afs_call *call) | |||
1004 | /* unmarshall the reply once we've received all of it */ | 1016 | /* unmarshall the reply once we've received all of it */ |
1005 | bp = call->buffer; | 1017 | bp = call->buffer; |
1006 | xdr_decode_AFSFid(&bp, call->reply[1]); | 1018 | xdr_decode_AFSFid(&bp, call->reply[1]); |
1007 | if (xdr_decode_AFSFetchStatus(call, &bp, call->reply[2], NULL, NULL, NULL) || | 1019 | if (afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL) || |
1008 | xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, | 1020 | afs_decode_status(call, &bp, &vnode->status, vnode, |
1009 | &call->expected_version, NULL) < 0) | 1021 | &call->expected_version, NULL) < 0) |
1010 | return afs_protocol_error(call, -EBADMSG); | 1022 | return afs_protocol_error(call, -EBADMSG); |
1011 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | 1023 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
1012 | 1024 | ||
@@ -1110,12 +1122,12 @@ static int afs_deliver_fs_rename(struct afs_call *call) | |||
1110 | 1122 | ||
1111 | /* unmarshall the reply once we've received all of it */ | 1123 | /* unmarshall the reply once we've received all of it */ |
1112 | bp = call->buffer; | 1124 | bp = call->buffer; |
1113 | if (xdr_decode_AFSFetchStatus(call, &bp, &orig_dvnode->status, orig_dvnode, | 1125 | if (afs_decode_status(call, &bp, &orig_dvnode->status, orig_dvnode, |
1114 | &call->expected_version, NULL) < 0) | 1126 | &call->expected_version, NULL) < 0) |
1115 | return afs_protocol_error(call, -EBADMSG); | 1127 | return afs_protocol_error(call, -EBADMSG); |
1116 | if (new_dvnode != orig_dvnode && | 1128 | if (new_dvnode != orig_dvnode && |
1117 | xdr_decode_AFSFetchStatus(call, &bp, &new_dvnode->status, new_dvnode, | 1129 | afs_decode_status(call, &bp, &new_dvnode->status, new_dvnode, |
1118 | &call->expected_version_2, NULL) < 0) | 1130 | &call->expected_version_2, NULL) < 0) |
1119 | return afs_protocol_error(call, -EBADMSG); | 1131 | return afs_protocol_error(call, -EBADMSG); |
1120 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | 1132 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
1121 | 1133 | ||
@@ -1219,8 +1231,8 @@ static int afs_deliver_fs_store_data(struct afs_call *call) | |||
1219 | 1231 | ||
1220 | /* unmarshall the reply once we've received all of it */ | 1232 | /* unmarshall the reply once we've received all of it */ |
1221 | bp = call->buffer; | 1233 | bp = call->buffer; |
1222 | if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, | 1234 | if (afs_decode_status(call, &bp, &vnode->status, vnode, |
1223 | &call->expected_version, NULL) < 0) | 1235 | &call->expected_version, NULL) < 0) |
1224 | return afs_protocol_error(call, -EBADMSG); | 1236 | return afs_protocol_error(call, -EBADMSG); |
1225 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | 1237 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
1226 | 1238 | ||
@@ -1395,8 +1407,8 @@ static int afs_deliver_fs_store_status(struct afs_call *call) | |||
1395 | 1407 | ||
1396 | /* unmarshall the reply once we've received all of it */ | 1408 | /* unmarshall the reply once we've received all of it */ |
1397 | bp = call->buffer; | 1409 | bp = call->buffer; |
1398 | if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, | 1410 | if (afs_decode_status(call, &bp, &vnode->status, vnode, |
1399 | &call->expected_version, NULL) < 0) | 1411 | &call->expected_version, NULL) < 0) |
1400 | return afs_protocol_error(call, -EBADMSG); | 1412 | return afs_protocol_error(call, -EBADMSG); |
1401 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | 1413 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
1402 | 1414 | ||
@@ -2097,8 +2109,8 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call) | |||
2097 | 2109 | ||
2098 | /* unmarshall the reply once we've received all of it */ | 2110 | /* unmarshall the reply once we've received all of it */ |
2099 | bp = call->buffer; | 2111 | bp = call->buffer; |
2100 | xdr_decode_AFSFetchStatus(call, &bp, status, vnode, | 2112 | afs_decode_status(call, &bp, status, vnode, |
2101 | &call->expected_version, NULL); | 2113 | &call->expected_version, NULL); |
2102 | callback[call->count].version = ntohl(bp[0]); | 2114 | callback[call->count].version = ntohl(bp[0]); |
2103 | callback[call->count].expiry = ntohl(bp[1]); | 2115 | callback[call->count].expiry = ntohl(bp[1]); |
2104 | callback[call->count].type = ntohl(bp[2]); | 2116 | callback[call->count].type = ntohl(bp[2]); |
@@ -2209,9 +2221,9 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) | |||
2209 | 2221 | ||
2210 | bp = call->buffer; | 2222 | bp = call->buffer; |
2211 | statuses = call->reply[1]; | 2223 | statuses = call->reply[1]; |
2212 | if (xdr_decode_AFSFetchStatus(call, &bp, &statuses[call->count], | 2224 | if (afs_decode_status(call, &bp, &statuses[call->count], |
2213 | call->count == 0 ? vnode : NULL, | 2225 | call->count == 0 ? vnode : NULL, |
2214 | NULL, NULL) < 0) | 2226 | NULL, NULL) < 0) |
2215 | return afs_protocol_error(call, -EBADMSG); | 2227 | return afs_protocol_error(call, -EBADMSG); |
2216 | 2228 | ||
2217 | call->count++; | 2229 | call->count++; |
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index e3f8a46663db..9778df135717 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/backing-dev.h> | 22 | #include <linux/backing-dev.h> |
23 | #include <linux/uuid.h> | 23 | #include <linux/uuid.h> |
24 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
25 | #include <net/netns/generic.h> | ||
26 | #include <net/sock.h> | ||
25 | #include <net/af_rxrpc.h> | 27 | #include <net/af_rxrpc.h> |
26 | 28 | ||
27 | #include "afs.h" | 29 | #include "afs.h" |
@@ -40,7 +42,8 @@ struct afs_mount_params { | |||
40 | afs_voltype_t type; /* type of volume requested */ | 42 | afs_voltype_t type; /* type of volume requested */ |
41 | int volnamesz; /* size of volume name */ | 43 | int volnamesz; /* size of volume name */ |
42 | const char *volname; /* name of volume to mount */ | 44 | const char *volname; /* name of volume to mount */ |
43 | struct afs_net *net; /* Network namespace in effect */ | 45 | struct net *net_ns; /* Network namespace in effect */ |
46 | struct afs_net *net; /* the AFS net namespace stuff */ | ||
44 | struct afs_cell *cell; /* cell in which to find volume */ | 47 | struct afs_cell *cell; /* cell in which to find volume */ |
45 | struct afs_volume *volume; /* volume record */ | 48 | struct afs_volume *volume; /* volume record */ |
46 | struct key *key; /* key to use for secure mounting */ | 49 | struct key *key; /* key to use for secure mounting */ |
@@ -189,7 +192,7 @@ struct afs_read { | |||
189 | * - there's one superblock per volume | 192 | * - there's one superblock per volume |
190 | */ | 193 | */ |
191 | struct afs_super_info { | 194 | struct afs_super_info { |
192 | struct afs_net *net; /* Network namespace */ | 195 | struct net *net_ns; /* Network namespace */ |
193 | struct afs_cell *cell; /* The cell in which the volume resides */ | 196 | struct afs_cell *cell; /* The cell in which the volume resides */ |
194 | struct afs_volume *volume; /* volume record */ | 197 | struct afs_volume *volume; /* volume record */ |
195 | bool dyn_root; /* True if dynamic root */ | 198 | bool dyn_root; /* True if dynamic root */ |
@@ -210,7 +213,6 @@ struct afs_sysnames { | |||
210 | char *subs[AFS_NR_SYSNAME]; | 213 | char *subs[AFS_NR_SYSNAME]; |
211 | refcount_t usage; | 214 | refcount_t usage; |
212 | unsigned short nr; | 215 | unsigned short nr; |
213 | short error; | ||
214 | char blank[1]; | 216 | char blank[1]; |
215 | }; | 217 | }; |
216 | 218 | ||
@@ -218,6 +220,7 @@ struct afs_sysnames { | |||
218 | * AFS network namespace record. | 220 | * AFS network namespace record. |
219 | */ | 221 | */ |
220 | struct afs_net { | 222 | struct afs_net { |
223 | struct net *net; /* Backpointer to the owning net namespace */ | ||
221 | struct afs_uuid uuid; | 224 | struct afs_uuid uuid; |
222 | bool live; /* F if this namespace is being removed */ | 225 | bool live; /* F if this namespace is being removed */ |
223 | 226 | ||
@@ -231,13 +234,13 @@ struct afs_net { | |||
231 | 234 | ||
232 | /* Cell database */ | 235 | /* Cell database */ |
233 | struct rb_root cells; | 236 | struct rb_root cells; |
234 | struct afs_cell *ws_cell; | 237 | struct afs_cell __rcu *ws_cell; |
235 | struct work_struct cells_manager; | 238 | struct work_struct cells_manager; |
236 | struct timer_list cells_timer; | 239 | struct timer_list cells_timer; |
237 | atomic_t cells_outstanding; | 240 | atomic_t cells_outstanding; |
238 | seqlock_t cells_lock; | 241 | seqlock_t cells_lock; |
239 | 242 | ||
240 | spinlock_t proc_cells_lock; | 243 | struct mutex proc_cells_lock; |
241 | struct list_head proc_cells; | 244 | struct list_head proc_cells; |
242 | 245 | ||
243 | /* Known servers. Theoretically each fileserver can only be in one | 246 | /* Known servers. Theoretically each fileserver can only be in one |
@@ -261,6 +264,7 @@ struct afs_net { | |||
261 | struct mutex lock_manager_mutex; | 264 | struct mutex lock_manager_mutex; |
262 | 265 | ||
263 | /* Misc */ | 266 | /* Misc */ |
267 | struct super_block *dynroot_sb; /* Dynamic root mount superblock */ | ||
264 | struct proc_dir_entry *proc_afs; /* /proc/net/afs directory */ | 268 | struct proc_dir_entry *proc_afs; /* /proc/net/afs directory */ |
265 | struct afs_sysnames *sysnames; | 269 | struct afs_sysnames *sysnames; |
266 | rwlock_t sysnames_lock; | 270 | rwlock_t sysnames_lock; |
@@ -280,7 +284,6 @@ struct afs_net { | |||
280 | }; | 284 | }; |
281 | 285 | ||
282 | extern const char afs_init_sysname[]; | 286 | extern const char afs_init_sysname[]; |
283 | extern struct afs_net __afs_net;// Dummy AFS network namespace; TODO: replace with real netns | ||
284 | 287 | ||
285 | enum afs_cell_state { | 288 | enum afs_cell_state { |
286 | AFS_CELL_UNSET, | 289 | AFS_CELL_UNSET, |
@@ -404,16 +407,27 @@ struct afs_server { | |||
404 | rwlock_t fs_lock; /* access lock */ | 407 | rwlock_t fs_lock; /* access lock */ |
405 | 408 | ||
406 | /* callback promise management */ | 409 | /* callback promise management */ |
407 | struct list_head cb_interests; /* List of superblocks using this server */ | 410 | struct hlist_head cb_volumes; /* List of volume interests on this server */ |
408 | unsigned cb_s_break; /* Break-everything counter. */ | 411 | unsigned cb_s_break; /* Break-everything counter. */ |
409 | rwlock_t cb_break_lock; /* Volume finding lock */ | 412 | rwlock_t cb_break_lock; /* Volume finding lock */ |
410 | }; | 413 | }; |
411 | 414 | ||
412 | /* | 415 | /* |
416 | * Volume collation in the server's callback interest list. | ||
417 | */ | ||
418 | struct afs_vol_interest { | ||
419 | struct hlist_node srv_link; /* Link in server->cb_volumes */ | ||
420 | struct hlist_head cb_interests; /* List of callback interests on the server */ | ||
421 | afs_volid_t vid; /* Volume ID to match */ | ||
422 | unsigned int usage; | ||
423 | }; | ||
424 | |||
425 | /* | ||
413 | * Interest by a superblock on a server. | 426 | * Interest by a superblock on a server. |
414 | */ | 427 | */ |
415 | struct afs_cb_interest { | 428 | struct afs_cb_interest { |
416 | struct list_head cb_link; /* Link in server->cb_interests */ | 429 | struct hlist_node cb_vlink; /* Link in vol_interest->cb_interests */ |
430 | struct afs_vol_interest *vol_interest; | ||
417 | struct afs_server *server; /* Server on which this interest resides */ | 431 | struct afs_server *server; /* Server on which this interest resides */ |
418 | struct super_block *sb; /* Superblock on which inodes reside */ | 432 | struct super_block *sb; /* Superblock on which inodes reside */ |
419 | afs_volid_t vid; /* Volume ID to match */ | 433 | afs_volid_t vid; /* Volume ID to match */ |
@@ -720,6 +734,10 @@ extern const struct inode_operations afs_dynroot_inode_operations; | |||
720 | extern const struct dentry_operations afs_dynroot_dentry_operations; | 734 | extern const struct dentry_operations afs_dynroot_dentry_operations; |
721 | 735 | ||
722 | extern struct inode *afs_try_auto_mntpt(struct dentry *, struct inode *); | 736 | extern struct inode *afs_try_auto_mntpt(struct dentry *, struct inode *); |
737 | extern int afs_dynroot_mkdir(struct afs_net *, struct afs_cell *); | ||
738 | extern void afs_dynroot_rmdir(struct afs_net *, struct afs_cell *); | ||
739 | extern int afs_dynroot_populate(struct super_block *); | ||
740 | extern void afs_dynroot_depopulate(struct super_block *); | ||
723 | 741 | ||
724 | /* | 742 | /* |
725 | * file.c | 743 | * file.c |
@@ -806,34 +824,36 @@ extern int afs_drop_inode(struct inode *); | |||
806 | * main.c | 824 | * main.c |
807 | */ | 825 | */ |
808 | extern struct workqueue_struct *afs_wq; | 826 | extern struct workqueue_struct *afs_wq; |
827 | extern int afs_net_id; | ||
809 | 828 | ||
810 | static inline struct afs_net *afs_d2net(struct dentry *dentry) | 829 | static inline struct afs_net *afs_net(struct net *net) |
811 | { | 830 | { |
812 | return &__afs_net; | 831 | return net_generic(net, afs_net_id); |
813 | } | 832 | } |
814 | 833 | ||
815 | static inline struct afs_net *afs_i2net(struct inode *inode) | 834 | static inline struct afs_net *afs_sb2net(struct super_block *sb) |
816 | { | 835 | { |
817 | return &__afs_net; | 836 | return afs_net(AFS_FS_S(sb)->net_ns); |
818 | } | 837 | } |
819 | 838 | ||
820 | static inline struct afs_net *afs_v2net(struct afs_vnode *vnode) | 839 | static inline struct afs_net *afs_d2net(struct dentry *dentry) |
821 | { | 840 | { |
822 | return &__afs_net; | 841 | return afs_sb2net(dentry->d_sb); |
823 | } | 842 | } |
824 | 843 | ||
825 | static inline struct afs_net *afs_sock2net(struct sock *sk) | 844 | static inline struct afs_net *afs_i2net(struct inode *inode) |
826 | { | 845 | { |
827 | return &__afs_net; | 846 | return afs_sb2net(inode->i_sb); |
828 | } | 847 | } |
829 | 848 | ||
830 | static inline struct afs_net *afs_get_net(struct afs_net *net) | 849 | static inline struct afs_net *afs_v2net(struct afs_vnode *vnode) |
831 | { | 850 | { |
832 | return net; | 851 | return afs_i2net(&vnode->vfs_inode); |
833 | } | 852 | } |
834 | 853 | ||
835 | static inline void afs_put_net(struct afs_net *net) | 854 | static inline struct afs_net *afs_sock2net(struct sock *sk) |
836 | { | 855 | { |
856 | return net_generic(sock_net(sk), afs_net_id); | ||
837 | } | 857 | } |
838 | 858 | ||
839 | static inline void __afs_stat(atomic_t *s) | 859 | static inline void __afs_stat(atomic_t *s) |
@@ -861,16 +881,25 @@ extern void afs_mntpt_kill_timer(void); | |||
861 | /* | 881 | /* |
862 | * netdevices.c | 882 | * netdevices.c |
863 | */ | 883 | */ |
864 | extern int afs_get_ipv4_interfaces(struct afs_interface *, size_t, bool); | 884 | extern int afs_get_ipv4_interfaces(struct afs_net *, struct afs_interface *, |
885 | size_t, bool); | ||
865 | 886 | ||
866 | /* | 887 | /* |
867 | * proc.c | 888 | * proc.c |
868 | */ | 889 | */ |
890 | #ifdef CONFIG_PROC_FS | ||
869 | extern int __net_init afs_proc_init(struct afs_net *); | 891 | extern int __net_init afs_proc_init(struct afs_net *); |
870 | extern void __net_exit afs_proc_cleanup(struct afs_net *); | 892 | extern void __net_exit afs_proc_cleanup(struct afs_net *); |
871 | extern int afs_proc_cell_setup(struct afs_net *, struct afs_cell *); | 893 | extern int afs_proc_cell_setup(struct afs_cell *); |
872 | extern void afs_proc_cell_remove(struct afs_net *, struct afs_cell *); | 894 | extern void afs_proc_cell_remove(struct afs_cell *); |
873 | extern void afs_put_sysnames(struct afs_sysnames *); | 895 | extern void afs_put_sysnames(struct afs_sysnames *); |
896 | #else | ||
897 | static inline int afs_proc_init(struct afs_net *net) { return 0; } | ||
898 | static inline void afs_proc_cleanup(struct afs_net *net) {} | ||
899 | static inline int afs_proc_cell_setup(struct afs_cell *cell) { return 0; } | ||
900 | static inline void afs_proc_cell_remove(struct afs_cell *cell) {} | ||
901 | static inline void afs_put_sysnames(struct afs_sysnames *sysnames) {} | ||
902 | #endif | ||
874 | 903 | ||
875 | /* | 904 | /* |
876 | * rotate.c | 905 | * rotate.c |
@@ -1002,7 +1031,7 @@ extern bool afs_annotate_server_list(struct afs_server_list *, struct afs_server | |||
1002 | * super.c | 1031 | * super.c |
1003 | */ | 1032 | */ |
1004 | extern int __init afs_fs_init(void); | 1033 | extern int __init afs_fs_init(void); |
1005 | extern void __exit afs_fs_exit(void); | 1034 | extern void afs_fs_exit(void); |
1006 | 1035 | ||
1007 | /* | 1036 | /* |
1008 | * vlclient.c | 1037 | * vlclient.c |
diff --git a/fs/afs/main.c b/fs/afs/main.c index d7560168b3bf..e84fe822a960 100644 --- a/fs/afs/main.c +++ b/fs/afs/main.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/completion.h> | 15 | #include <linux/completion.h> |
16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
17 | #include <linux/random.h> | 17 | #include <linux/random.h> |
18 | #include <linux/proc_fs.h> | ||
18 | #define CREATE_TRACE_POINTS | 19 | #define CREATE_TRACE_POINTS |
19 | #include "internal.h" | 20 | #include "internal.h" |
20 | 21 | ||
@@ -32,7 +33,7 @@ module_param(rootcell, charp, 0); | |||
32 | MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list"); | 33 | MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list"); |
33 | 34 | ||
34 | struct workqueue_struct *afs_wq; | 35 | struct workqueue_struct *afs_wq; |
35 | struct afs_net __afs_net; | 36 | static struct proc_dir_entry *afs_proc_symlink; |
36 | 37 | ||
37 | #if defined(CONFIG_ALPHA) | 38 | #if defined(CONFIG_ALPHA) |
38 | const char afs_init_sysname[] = "alpha_linux26"; | 39 | const char afs_init_sysname[] = "alpha_linux26"; |
@@ -67,11 +68,13 @@ const char afs_init_sysname[] = "unknown_linux26"; | |||
67 | /* | 68 | /* |
68 | * Initialise an AFS network namespace record. | 69 | * Initialise an AFS network namespace record. |
69 | */ | 70 | */ |
70 | static int __net_init afs_net_init(struct afs_net *net) | 71 | static int __net_init afs_net_init(struct net *net_ns) |
71 | { | 72 | { |
72 | struct afs_sysnames *sysnames; | 73 | struct afs_sysnames *sysnames; |
74 | struct afs_net *net = afs_net(net_ns); | ||
73 | int ret; | 75 | int ret; |
74 | 76 | ||
77 | net->net = net_ns; | ||
75 | net->live = true; | 78 | net->live = true; |
76 | generate_random_uuid((unsigned char *)&net->uuid); | 79 | generate_random_uuid((unsigned char *)&net->uuid); |
77 | 80 | ||
@@ -83,7 +86,7 @@ static int __net_init afs_net_init(struct afs_net *net) | |||
83 | INIT_WORK(&net->cells_manager, afs_manage_cells); | 86 | INIT_WORK(&net->cells_manager, afs_manage_cells); |
84 | timer_setup(&net->cells_timer, afs_cells_timer, 0); | 87 | timer_setup(&net->cells_timer, afs_cells_timer, 0); |
85 | 88 | ||
86 | spin_lock_init(&net->proc_cells_lock); | 89 | mutex_init(&net->proc_cells_lock); |
87 | INIT_LIST_HEAD(&net->proc_cells); | 90 | INIT_LIST_HEAD(&net->proc_cells); |
88 | 91 | ||
89 | seqlock_init(&net->fs_lock); | 92 | seqlock_init(&net->fs_lock); |
@@ -142,8 +145,10 @@ error_sysnames: | |||
142 | /* | 145 | /* |
143 | * Clean up and destroy an AFS network namespace record. | 146 | * Clean up and destroy an AFS network namespace record. |
144 | */ | 147 | */ |
145 | static void __net_exit afs_net_exit(struct afs_net *net) | 148 | static void __net_exit afs_net_exit(struct net *net_ns) |
146 | { | 149 | { |
150 | struct afs_net *net = afs_net(net_ns); | ||
151 | |||
147 | net->live = false; | 152 | net->live = false; |
148 | afs_cell_purge(net); | 153 | afs_cell_purge(net); |
149 | afs_purge_servers(net); | 154 | afs_purge_servers(net); |
@@ -152,6 +157,13 @@ static void __net_exit afs_net_exit(struct afs_net *net) | |||
152 | afs_put_sysnames(net->sysnames); | 157 | afs_put_sysnames(net->sysnames); |
153 | } | 158 | } |
154 | 159 | ||
160 | static struct pernet_operations afs_net_ops = { | ||
161 | .init = afs_net_init, | ||
162 | .exit = afs_net_exit, | ||
163 | .id = &afs_net_id, | ||
164 | .size = sizeof(struct afs_net), | ||
165 | }; | ||
166 | |||
155 | /* | 167 | /* |
156 | * initialise the AFS client FS module | 168 | * initialise the AFS client FS module |
157 | */ | 169 | */ |
@@ -178,7 +190,7 @@ static int __init afs_init(void) | |||
178 | goto error_cache; | 190 | goto error_cache; |
179 | #endif | 191 | #endif |
180 | 192 | ||
181 | ret = afs_net_init(&__afs_net); | 193 | ret = register_pernet_subsys(&afs_net_ops); |
182 | if (ret < 0) | 194 | if (ret < 0) |
183 | goto error_net; | 195 | goto error_net; |
184 | 196 | ||
@@ -187,10 +199,18 @@ static int __init afs_init(void) | |||
187 | if (ret < 0) | 199 | if (ret < 0) |
188 | goto error_fs; | 200 | goto error_fs; |
189 | 201 | ||
202 | afs_proc_symlink = proc_symlink("fs/afs", NULL, "../self/net/afs"); | ||
203 | if (IS_ERR(afs_proc_symlink)) { | ||
204 | ret = PTR_ERR(afs_proc_symlink); | ||
205 | goto error_proc; | ||
206 | } | ||
207 | |||
190 | return ret; | 208 | return ret; |
191 | 209 | ||
210 | error_proc: | ||
211 | afs_fs_exit(); | ||
192 | error_fs: | 212 | error_fs: |
193 | afs_net_exit(&__afs_net); | 213 | unregister_pernet_subsys(&afs_net_ops); |
194 | error_net: | 214 | error_net: |
195 | #ifdef CONFIG_AFS_FSCACHE | 215 | #ifdef CONFIG_AFS_FSCACHE |
196 | fscache_unregister_netfs(&afs_cache_netfs); | 216 | fscache_unregister_netfs(&afs_cache_netfs); |
@@ -219,8 +239,9 @@ static void __exit afs_exit(void) | |||
219 | { | 239 | { |
220 | printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n"); | 240 | printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n"); |
221 | 241 | ||
242 | proc_remove(afs_proc_symlink); | ||
222 | afs_fs_exit(); | 243 | afs_fs_exit(); |
223 | afs_net_exit(&__afs_net); | 244 | unregister_pernet_subsys(&afs_net_ops); |
224 | #ifdef CONFIG_AFS_FSCACHE | 245 | #ifdef CONFIG_AFS_FSCACHE |
225 | fscache_unregister_netfs(&afs_cache_netfs); | 246 | fscache_unregister_netfs(&afs_cache_netfs); |
226 | #endif | 247 | #endif |
diff --git a/fs/afs/netdevices.c b/fs/afs/netdevices.c index 50bd5bb1c4fb..2a009d1939d7 100644 --- a/fs/afs/netdevices.c +++ b/fs/afs/netdevices.c | |||
@@ -17,8 +17,8 @@ | |||
17 | * - maxbufs must be at least 1 | 17 | * - maxbufs must be at least 1 |
18 | * - returns the number of interface records in the buffer | 18 | * - returns the number of interface records in the buffer |
19 | */ | 19 | */ |
20 | int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs, | 20 | int afs_get_ipv4_interfaces(struct afs_net *net, struct afs_interface *bufs, |
21 | bool wantloopback) | 21 | size_t maxbufs, bool wantloopback) |
22 | { | 22 | { |
23 | struct net_device *dev; | 23 | struct net_device *dev; |
24 | struct in_device *idev; | 24 | struct in_device *idev; |
@@ -27,7 +27,7 @@ int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs, | |||
27 | ASSERT(maxbufs > 0); | 27 | ASSERT(maxbufs > 0); |
28 | 28 | ||
29 | rtnl_lock(); | 29 | rtnl_lock(); |
30 | for_each_netdev(&init_net, dev) { | 30 | for_each_netdev(net->net, dev) { |
31 | if (dev->type == ARPHRD_LOOPBACK && !wantloopback) | 31 | if (dev->type == ARPHRD_LOOPBACK && !wantloopback) |
32 | continue; | 32 | continue; |
33 | idev = __in_dev_get_rtnl(dev); | 33 | idev = __in_dev_get_rtnl(dev); |
diff --git a/fs/afs/proc.c b/fs/afs/proc.c index 3aad32762989..0c3285c8db95 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c | |||
@@ -17,240 +17,78 @@ | |||
17 | #include <linux/uaccess.h> | 17 | #include <linux/uaccess.h> |
18 | #include "internal.h" | 18 | #include "internal.h" |
19 | 19 | ||
20 | static inline struct afs_net *afs_proc2net(struct file *f) | 20 | static inline struct afs_net *afs_seq2net(struct seq_file *m) |
21 | { | 21 | { |
22 | return &__afs_net; | 22 | return afs_net(seq_file_net(m)); |
23 | } | 23 | } |
24 | 24 | ||
25 | static inline struct afs_net *afs_seq2net(struct seq_file *m) | 25 | static inline struct afs_net *afs_seq2net_single(struct seq_file *m) |
26 | { | 26 | { |
27 | return &__afs_net; // TODO: use seq_file_net(m) | 27 | return afs_net(seq_file_single_net(m)); |
28 | } | 28 | } |
29 | 29 | ||
30 | static int afs_proc_cells_open(struct inode *inode, struct file *file); | ||
31 | static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos); | ||
32 | static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos); | ||
33 | static void afs_proc_cells_stop(struct seq_file *p, void *v); | ||
34 | static int afs_proc_cells_show(struct seq_file *m, void *v); | ||
35 | static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, | ||
36 | size_t size, loff_t *_pos); | ||
37 | |||
38 | static const struct seq_operations afs_proc_cells_ops = { | ||
39 | .start = afs_proc_cells_start, | ||
40 | .next = afs_proc_cells_next, | ||
41 | .stop = afs_proc_cells_stop, | ||
42 | .show = afs_proc_cells_show, | ||
43 | }; | ||
44 | |||
45 | static const struct file_operations afs_proc_cells_fops = { | ||
46 | .open = afs_proc_cells_open, | ||
47 | .read = seq_read, | ||
48 | .write = afs_proc_cells_write, | ||
49 | .llseek = seq_lseek, | ||
50 | .release = seq_release, | ||
51 | }; | ||
52 | |||
53 | static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, | ||
54 | size_t size, loff_t *_pos); | ||
55 | static ssize_t afs_proc_rootcell_write(struct file *file, | ||
56 | const char __user *buf, | ||
57 | size_t size, loff_t *_pos); | ||
58 | |||
59 | static const struct file_operations afs_proc_rootcell_fops = { | ||
60 | .read = afs_proc_rootcell_read, | ||
61 | .write = afs_proc_rootcell_write, | ||
62 | .llseek = no_llseek, | ||
63 | }; | ||
64 | |||
65 | static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos); | ||
66 | static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, | ||
67 | loff_t *pos); | ||
68 | static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v); | ||
69 | static int afs_proc_cell_volumes_show(struct seq_file *m, void *v); | ||
70 | |||
71 | static const struct seq_operations afs_proc_cell_volumes_ops = { | ||
72 | .start = afs_proc_cell_volumes_start, | ||
73 | .next = afs_proc_cell_volumes_next, | ||
74 | .stop = afs_proc_cell_volumes_stop, | ||
75 | .show = afs_proc_cell_volumes_show, | ||
76 | }; | ||
77 | |||
78 | static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos); | ||
79 | static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, | ||
80 | loff_t *pos); | ||
81 | static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v); | ||
82 | static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v); | ||
83 | |||
84 | static const struct seq_operations afs_proc_cell_vlservers_ops = { | ||
85 | .start = afs_proc_cell_vlservers_start, | ||
86 | .next = afs_proc_cell_vlservers_next, | ||
87 | .stop = afs_proc_cell_vlservers_stop, | ||
88 | .show = afs_proc_cell_vlservers_show, | ||
89 | }; | ||
90 | |||
91 | static void *afs_proc_servers_start(struct seq_file *p, loff_t *pos); | ||
92 | static void *afs_proc_servers_next(struct seq_file *p, void *v, | ||
93 | loff_t *pos); | ||
94 | static void afs_proc_servers_stop(struct seq_file *p, void *v); | ||
95 | static int afs_proc_servers_show(struct seq_file *m, void *v); | ||
96 | |||
97 | static const struct seq_operations afs_proc_servers_ops = { | ||
98 | .start = afs_proc_servers_start, | ||
99 | .next = afs_proc_servers_next, | ||
100 | .stop = afs_proc_servers_stop, | ||
101 | .show = afs_proc_servers_show, | ||
102 | }; | ||
103 | |||
104 | static int afs_proc_sysname_open(struct inode *inode, struct file *file); | ||
105 | static int afs_proc_sysname_release(struct inode *inode, struct file *file); | ||
106 | static void *afs_proc_sysname_start(struct seq_file *p, loff_t *pos); | ||
107 | static void *afs_proc_sysname_next(struct seq_file *p, void *v, | ||
108 | loff_t *pos); | ||
109 | static void afs_proc_sysname_stop(struct seq_file *p, void *v); | ||
110 | static int afs_proc_sysname_show(struct seq_file *m, void *v); | ||
111 | static ssize_t afs_proc_sysname_write(struct file *file, | ||
112 | const char __user *buf, | ||
113 | size_t size, loff_t *_pos); | ||
114 | |||
115 | static const struct seq_operations afs_proc_sysname_ops = { | ||
116 | .start = afs_proc_sysname_start, | ||
117 | .next = afs_proc_sysname_next, | ||
118 | .stop = afs_proc_sysname_stop, | ||
119 | .show = afs_proc_sysname_show, | ||
120 | }; | ||
121 | |||
122 | static const struct file_operations afs_proc_sysname_fops = { | ||
123 | .open = afs_proc_sysname_open, | ||
124 | .read = seq_read, | ||
125 | .llseek = seq_lseek, | ||
126 | .release = afs_proc_sysname_release, | ||
127 | .write = afs_proc_sysname_write, | ||
128 | }; | ||
129 | |||
130 | static int afs_proc_stats_show(struct seq_file *m, void *v); | ||
131 | |||
132 | /* | 30 | /* |
133 | * initialise the /proc/fs/afs/ directory | 31 | * Display the list of cells known to the namespace. |
134 | */ | 32 | */ |
135 | int afs_proc_init(struct afs_net *net) | 33 | static int afs_proc_cells_show(struct seq_file *m, void *v) |
136 | { | 34 | { |
137 | _enter(""); | 35 | struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link); |
138 | 36 | struct afs_net *net = afs_seq2net(m); | |
139 | net->proc_afs = proc_mkdir("fs/afs", NULL); | ||
140 | if (!net->proc_afs) | ||
141 | goto error_dir; | ||
142 | 37 | ||
143 | if (!proc_create("cells", 0644, net->proc_afs, &afs_proc_cells_fops) || | 38 | if (v == &net->proc_cells) { |
144 | !proc_create("rootcell", 0644, net->proc_afs, &afs_proc_rootcell_fops) || | 39 | /* display header on line 1 */ |
145 | !proc_create_seq("servers", 0644, net->proc_afs, &afs_proc_servers_ops) || | 40 | seq_puts(m, "USE NAME\n"); |
146 | !proc_create_single("stats", 0644, net->proc_afs, afs_proc_stats_show) || | 41 | return 0; |
147 | !proc_create("sysname", 0644, net->proc_afs, &afs_proc_sysname_fops)) | 42 | } |
148 | goto error_tree; | ||
149 | 43 | ||
150 | _leave(" = 0"); | 44 | /* display one cell per line on subsequent lines */ |
45 | seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name); | ||
151 | return 0; | 46 | return 0; |
152 | |||
153 | error_tree: | ||
154 | proc_remove(net->proc_afs); | ||
155 | error_dir: | ||
156 | _leave(" = -ENOMEM"); | ||
157 | return -ENOMEM; | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | * clean up the /proc/fs/afs/ directory | ||
162 | */ | ||
163 | void afs_proc_cleanup(struct afs_net *net) | ||
164 | { | ||
165 | proc_remove(net->proc_afs); | ||
166 | net->proc_afs = NULL; | ||
167 | } | ||
168 | |||
169 | /* | ||
170 | * open "/proc/fs/afs/cells" which provides a summary of extant cells | ||
171 | */ | ||
172 | static int afs_proc_cells_open(struct inode *inode, struct file *file) | ||
173 | { | ||
174 | return seq_open(file, &afs_proc_cells_ops); | ||
175 | } | 47 | } |
176 | 48 | ||
177 | /* | ||
178 | * set up the iterator to start reading from the cells list and return the | ||
179 | * first item | ||
180 | */ | ||
181 | static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos) | 49 | static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos) |
182 | __acquires(rcu) | 50 | __acquires(rcu) |
183 | { | 51 | { |
184 | struct afs_net *net = afs_seq2net(m); | ||
185 | |||
186 | rcu_read_lock(); | 52 | rcu_read_lock(); |
187 | return seq_list_start_head(&net->proc_cells, *_pos); | 53 | return seq_list_start_head(&afs_seq2net(m)->proc_cells, *_pos); |
188 | } | 54 | } |
189 | 55 | ||
190 | /* | ||
191 | * move to next cell in cells list | ||
192 | */ | ||
193 | static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos) | 56 | static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos) |
194 | { | 57 | { |
195 | struct afs_net *net = afs_seq2net(m); | 58 | return seq_list_next(v, &afs_seq2net(m)->proc_cells, pos); |
196 | |||
197 | return seq_list_next(v, &net->proc_cells, pos); | ||
198 | } | 59 | } |
199 | 60 | ||
200 | /* | ||
201 | * clean up after reading from the cells list | ||
202 | */ | ||
203 | static void afs_proc_cells_stop(struct seq_file *m, void *v) | 61 | static void afs_proc_cells_stop(struct seq_file *m, void *v) |
204 | __releases(rcu) | 62 | __releases(rcu) |
205 | { | 63 | { |
206 | rcu_read_unlock(); | 64 | rcu_read_unlock(); |
207 | } | 65 | } |
208 | 66 | ||
209 | /* | 67 | static const struct seq_operations afs_proc_cells_ops = { |
210 | * display a header line followed by a load of cell lines | 68 | .start = afs_proc_cells_start, |
211 | */ | 69 | .next = afs_proc_cells_next, |
212 | static int afs_proc_cells_show(struct seq_file *m, void *v) | 70 | .stop = afs_proc_cells_stop, |
213 | { | 71 | .show = afs_proc_cells_show, |
214 | struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link); | 72 | }; |
215 | struct afs_net *net = afs_seq2net(m); | ||
216 | |||
217 | if (v == &net->proc_cells) { | ||
218 | /* display header on line 1 */ | ||
219 | seq_puts(m, "USE NAME\n"); | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | /* display one cell per line on subsequent lines */ | ||
224 | seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name); | ||
225 | return 0; | ||
226 | } | ||
227 | 73 | ||
228 | /* | 74 | /* |
229 | * handle writes to /proc/fs/afs/cells | 75 | * handle writes to /proc/fs/afs/cells |
230 | * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]" | 76 | * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]" |
231 | */ | 77 | */ |
232 | static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, | 78 | static int afs_proc_cells_write(struct file *file, char *buf, size_t size) |
233 | size_t size, loff_t *_pos) | ||
234 | { | 79 | { |
235 | struct afs_net *net = afs_proc2net(file); | 80 | struct seq_file *m = file->private_data; |
236 | char *kbuf, *name, *args; | 81 | struct afs_net *net = afs_seq2net(m); |
82 | char *name, *args; | ||
237 | int ret; | 83 | int ret; |
238 | 84 | ||
239 | /* start by dragging the command into memory */ | ||
240 | if (size <= 1 || size >= PAGE_SIZE) | ||
241 | return -EINVAL; | ||
242 | |||
243 | kbuf = memdup_user_nul(buf, size); | ||
244 | if (IS_ERR(kbuf)) | ||
245 | return PTR_ERR(kbuf); | ||
246 | |||
247 | /* trim to first NL */ | 85 | /* trim to first NL */ |
248 | name = memchr(kbuf, '\n', size); | 86 | name = memchr(buf, '\n', size); |
249 | if (name) | 87 | if (name) |
250 | *name = 0; | 88 | *name = 0; |
251 | 89 | ||
252 | /* split into command, name and argslist */ | 90 | /* split into command, name and argslist */ |
253 | name = strchr(kbuf, ' '); | 91 | name = strchr(buf, ' '); |
254 | if (!name) | 92 | if (!name) |
255 | goto inval; | 93 | goto inval; |
256 | do { | 94 | do { |
@@ -269,9 +107,9 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, | |||
269 | goto inval; | 107 | goto inval; |
270 | 108 | ||
271 | /* determine command to perform */ | 109 | /* determine command to perform */ |
272 | _debug("cmd=%s name=%s args=%s", kbuf, name, args); | 110 | _debug("cmd=%s name=%s args=%s", buf, name, args); |
273 | 111 | ||
274 | if (strcmp(kbuf, "add") == 0) { | 112 | if (strcmp(buf, "add") == 0) { |
275 | struct afs_cell *cell; | 113 | struct afs_cell *cell; |
276 | 114 | ||
277 | cell = afs_lookup_cell(net, name, strlen(name), args, true); | 115 | cell = afs_lookup_cell(net, name, strlen(name), args, true); |
@@ -287,10 +125,9 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, | |||
287 | goto inval; | 125 | goto inval; |
288 | } | 126 | } |
289 | 127 | ||
290 | ret = size; | 128 | ret = 0; |
291 | 129 | ||
292 | done: | 130 | done: |
293 | kfree(kbuf); | ||
294 | _leave(" = %d", ret); | 131 | _leave(" = %d", ret); |
295 | return ret; | 132 | return ret; |
296 | 133 | ||
@@ -300,200 +137,136 @@ inval: | |||
300 | goto done; | 137 | goto done; |
301 | } | 138 | } |
302 | 139 | ||
303 | static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, | 140 | /* |
304 | size_t size, loff_t *_pos) | 141 | * Display the name of the current workstation cell. |
142 | */ | ||
143 | static int afs_proc_rootcell_show(struct seq_file *m, void *v) | ||
305 | { | 144 | { |
306 | struct afs_cell *cell; | 145 | struct afs_cell *cell; |
307 | struct afs_net *net = afs_proc2net(file); | 146 | struct afs_net *net; |
308 | unsigned int seq = 0; | 147 | |
309 | char name[AFS_MAXCELLNAME + 1]; | 148 | net = afs_seq2net_single(m); |
310 | int len; | 149 | if (rcu_access_pointer(net->ws_cell)) { |
311 | 150 | rcu_read_lock(); | |
312 | if (*_pos > 0) | 151 | cell = rcu_dereference(net->ws_cell); |
313 | return 0; | 152 | if (cell) |
314 | if (!net->ws_cell) | 153 | seq_printf(m, "%s\n", cell->name); |
315 | return 0; | 154 | rcu_read_unlock(); |
316 | 155 | } | |
317 | rcu_read_lock(); | 156 | return 0; |
318 | do { | ||
319 | read_seqbegin_or_lock(&net->cells_lock, &seq); | ||
320 | len = 0; | ||
321 | cell = rcu_dereference_raw(net->ws_cell); | ||
322 | if (cell) { | ||
323 | len = cell->name_len; | ||
324 | memcpy(name, cell->name, len); | ||
325 | } | ||
326 | } while (need_seqretry(&net->cells_lock, seq)); | ||
327 | done_seqretry(&net->cells_lock, seq); | ||
328 | rcu_read_unlock(); | ||
329 | |||
330 | if (!len) | ||
331 | return 0; | ||
332 | |||
333 | name[len++] = '\n'; | ||
334 | if (len > size) | ||
335 | len = size; | ||
336 | if (copy_to_user(buf, name, len) != 0) | ||
337 | return -EFAULT; | ||
338 | *_pos = 1; | ||
339 | return len; | ||
340 | } | 157 | } |
341 | 158 | ||
342 | /* | 159 | /* |
343 | * handle writes to /proc/fs/afs/rootcell | 160 | * Set the current workstation cell and optionally supply its list of volume |
344 | * - to initialize rootcell: echo "cell.name:192.168.231.14" | 161 | * location servers. |
162 | * | ||
163 | * echo "cell.name:192.168.231.14" >/proc/fs/afs/rootcell | ||
345 | */ | 164 | */ |
346 | static ssize_t afs_proc_rootcell_write(struct file *file, | 165 | static int afs_proc_rootcell_write(struct file *file, char *buf, size_t size) |
347 | const char __user *buf, | ||
348 | size_t size, loff_t *_pos) | ||
349 | { | 166 | { |
350 | struct afs_net *net = afs_proc2net(file); | 167 | struct seq_file *m = file->private_data; |
351 | char *kbuf, *s; | 168 | struct afs_net *net = afs_seq2net_single(m); |
169 | char *s; | ||
352 | int ret; | 170 | int ret; |
353 | 171 | ||
354 | /* start by dragging the command into memory */ | ||
355 | if (size <= 1 || size >= PAGE_SIZE) | ||
356 | return -EINVAL; | ||
357 | |||
358 | kbuf = memdup_user_nul(buf, size); | ||
359 | if (IS_ERR(kbuf)) | ||
360 | return PTR_ERR(kbuf); | ||
361 | |||
362 | ret = -EINVAL; | 172 | ret = -EINVAL; |
363 | if (kbuf[0] == '.') | 173 | if (buf[0] == '.') |
364 | goto out; | 174 | goto out; |
365 | if (memchr(kbuf, '/', size)) | 175 | if (memchr(buf, '/', size)) |
366 | goto out; | 176 | goto out; |
367 | 177 | ||
368 | /* trim to first NL */ | 178 | /* trim to first NL */ |
369 | s = memchr(kbuf, '\n', size); | 179 | s = memchr(buf, '\n', size); |
370 | if (s) | 180 | if (s) |
371 | *s = 0; | 181 | *s = 0; |
372 | 182 | ||
373 | /* determine command to perform */ | 183 | /* determine command to perform */ |
374 | _debug("rootcell=%s", kbuf); | 184 | _debug("rootcell=%s", buf); |
375 | 185 | ||
376 | ret = afs_cell_init(net, kbuf); | 186 | ret = afs_cell_init(net, buf); |
377 | if (ret >= 0) | ||
378 | ret = size; /* consume everything, always */ | ||
379 | 187 | ||
380 | out: | 188 | out: |
381 | kfree(kbuf); | ||
382 | _leave(" = %d", ret); | 189 | _leave(" = %d", ret); |
383 | return ret; | 190 | return ret; |
384 | } | 191 | } |
385 | 192 | ||
193 | static const char afs_vol_types[3][3] = { | ||
194 | [AFSVL_RWVOL] = "RW", | ||
195 | [AFSVL_ROVOL] = "RO", | ||
196 | [AFSVL_BACKVOL] = "BK", | ||
197 | }; | ||
198 | |||
386 | /* | 199 | /* |
387 | * initialise /proc/fs/afs/<cell>/ | 200 | * Display the list of volumes known to a cell. |
388 | */ | 201 | */ |
389 | int afs_proc_cell_setup(struct afs_net *net, struct afs_cell *cell) | 202 | static int afs_proc_cell_volumes_show(struct seq_file *m, void *v) |
390 | { | 203 | { |
391 | struct proc_dir_entry *dir; | 204 | struct afs_cell *cell = PDE_DATA(file_inode(m->file)); |
392 | 205 | struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link); | |
393 | _enter("%p{%s},%p", cell, cell->name, net->proc_afs); | ||
394 | 206 | ||
395 | dir = proc_mkdir(cell->name, net->proc_afs); | 207 | /* Display header on line 1 */ |
396 | if (!dir) | 208 | if (v == &cell->proc_volumes) { |
397 | goto error_dir; | 209 | seq_puts(m, "USE VID TY\n"); |
210 | return 0; | ||
211 | } | ||
398 | 212 | ||
399 | if (!proc_create_seq_data("vlservers", 0, dir, | 213 | seq_printf(m, "%3d %08x %s\n", |
400 | &afs_proc_cell_vlservers_ops, cell)) | 214 | atomic_read(&vol->usage), vol->vid, |
401 | goto error_tree; | 215 | afs_vol_types[vol->type]); |
402 | if (!proc_create_seq_data("volumes", 0, dir, &afs_proc_cell_volumes_ops, | ||
403 | cell)) | ||
404 | goto error_tree; | ||
405 | 216 | ||
406 | _leave(" = 0"); | ||
407 | return 0; | 217 | return 0; |
408 | |||
409 | error_tree: | ||
410 | remove_proc_subtree(cell->name, net->proc_afs); | ||
411 | error_dir: | ||
412 | _leave(" = -ENOMEM"); | ||
413 | return -ENOMEM; | ||
414 | } | 218 | } |
415 | 219 | ||
416 | /* | ||
417 | * remove /proc/fs/afs/<cell>/ | ||
418 | */ | ||
419 | void afs_proc_cell_remove(struct afs_net *net, struct afs_cell *cell) | ||
420 | { | ||
421 | _enter(""); | ||
422 | |||
423 | remove_proc_subtree(cell->name, net->proc_afs); | ||
424 | |||
425 | _leave(""); | ||
426 | } | ||
427 | |||
428 | /* | ||
429 | * set up the iterator to start reading from the cells list and return the | ||
430 | * first item | ||
431 | */ | ||
432 | static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos) | 220 | static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos) |
433 | __acquires(cell->proc_lock) | 221 | __acquires(cell->proc_lock) |
434 | { | 222 | { |
435 | struct afs_cell *cell = PDE_DATA(file_inode(m->file)); | 223 | struct afs_cell *cell = PDE_DATA(file_inode(m->file)); |
436 | 224 | ||
437 | _enter("cell=%p pos=%Ld", cell, *_pos); | ||
438 | |||
439 | read_lock(&cell->proc_lock); | 225 | read_lock(&cell->proc_lock); |
440 | return seq_list_start_head(&cell->proc_volumes, *_pos); | 226 | return seq_list_start_head(&cell->proc_volumes, *_pos); |
441 | } | 227 | } |
442 | 228 | ||
443 | /* | 229 | static void *afs_proc_cell_volumes_next(struct seq_file *m, void *v, |
444 | * move to next cell in cells list | ||
445 | */ | ||
446 | static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, | ||
447 | loff_t *_pos) | 230 | loff_t *_pos) |
448 | { | 231 | { |
449 | struct afs_cell *cell = PDE_DATA(file_inode(p->file)); | 232 | struct afs_cell *cell = PDE_DATA(file_inode(m->file)); |
450 | 233 | ||
451 | _enter("cell=%p pos=%Ld", cell, *_pos); | ||
452 | return seq_list_next(v, &cell->proc_volumes, _pos); | 234 | return seq_list_next(v, &cell->proc_volumes, _pos); |
453 | } | 235 | } |
454 | 236 | ||
455 | /* | 237 | static void afs_proc_cell_volumes_stop(struct seq_file *m, void *v) |
456 | * clean up after reading from the cells list | ||
457 | */ | ||
458 | static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v) | ||
459 | __releases(cell->proc_lock) | 238 | __releases(cell->proc_lock) |
460 | { | 239 | { |
461 | struct afs_cell *cell = PDE_DATA(file_inode(p->file)); | 240 | struct afs_cell *cell = PDE_DATA(file_inode(m->file)); |
462 | 241 | ||
463 | read_unlock(&cell->proc_lock); | 242 | read_unlock(&cell->proc_lock); |
464 | } | 243 | } |
465 | 244 | ||
466 | static const char afs_vol_types[3][3] = { | 245 | static const struct seq_operations afs_proc_cell_volumes_ops = { |
467 | [AFSVL_RWVOL] = "RW", | 246 | .start = afs_proc_cell_volumes_start, |
468 | [AFSVL_ROVOL] = "RO", | 247 | .next = afs_proc_cell_volumes_next, |
469 | [AFSVL_BACKVOL] = "BK", | 248 | .stop = afs_proc_cell_volumes_stop, |
249 | .show = afs_proc_cell_volumes_show, | ||
470 | }; | 250 | }; |
471 | 251 | ||
472 | /* | 252 | /* |
473 | * display a header line followed by a load of volume lines | 253 | * Display the list of Volume Location servers we're using for a cell. |
474 | */ | 254 | */ |
475 | static int afs_proc_cell_volumes_show(struct seq_file *m, void *v) | 255 | static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v) |
476 | { | 256 | { |
477 | struct afs_cell *cell = PDE_DATA(file_inode(m->file)); | 257 | struct sockaddr_rxrpc *addr = v; |
478 | struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link); | ||
479 | 258 | ||
480 | /* Display header on line 1 */ | 259 | /* display header on line 1 */ |
481 | if (v == &cell->proc_volumes) { | 260 | if (v == (void *)1) { |
482 | seq_puts(m, "USE VID TY\n"); | 261 | seq_puts(m, "ADDRESS\n"); |
483 | return 0; | 262 | return 0; |
484 | } | 263 | } |
485 | 264 | ||
486 | seq_printf(m, "%3d %08x %s\n", | 265 | /* display one cell per line on subsequent lines */ |
487 | atomic_read(&vol->usage), vol->vid, | 266 | seq_printf(m, "%pISp\n", &addr->transport); |
488 | afs_vol_types[vol->type]); | ||
489 | |||
490 | return 0; | 267 | return 0; |
491 | } | 268 | } |
492 | 269 | ||
493 | /* | ||
494 | * set up the iterator to start reading from the cells list and return the | ||
495 | * first item | ||
496 | */ | ||
497 | static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) | 270 | static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) |
498 | __acquires(rcu) | 271 | __acquires(rcu) |
499 | { | 272 | { |
@@ -516,14 +289,11 @@ static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) | |||
516 | return alist->addrs + pos; | 289 | return alist->addrs + pos; |
517 | } | 290 | } |
518 | 291 | ||
519 | /* | 292 | static void *afs_proc_cell_vlservers_next(struct seq_file *m, void *v, |
520 | * move to next cell in cells list | ||
521 | */ | ||
522 | static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, | ||
523 | loff_t *_pos) | 293 | loff_t *_pos) |
524 | { | 294 | { |
525 | struct afs_addr_list *alist; | 295 | struct afs_addr_list *alist; |
526 | struct afs_cell *cell = PDE_DATA(file_inode(p->file)); | 296 | struct afs_cell *cell = PDE_DATA(file_inode(m->file)); |
527 | loff_t pos; | 297 | loff_t pos; |
528 | 298 | ||
529 | alist = rcu_dereference(cell->vl_addrs); | 299 | alist = rcu_dereference(cell->vl_addrs); |
@@ -536,161 +306,145 @@ static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, | |||
536 | return alist->addrs + pos; | 306 | return alist->addrs + pos; |
537 | } | 307 | } |
538 | 308 | ||
539 | /* | 309 | static void afs_proc_cell_vlservers_stop(struct seq_file *m, void *v) |
540 | * clean up after reading from the cells list | ||
541 | */ | ||
542 | static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v) | ||
543 | __releases(rcu) | 310 | __releases(rcu) |
544 | { | 311 | { |
545 | rcu_read_unlock(); | 312 | rcu_read_unlock(); |
546 | } | 313 | } |
547 | 314 | ||
315 | static const struct seq_operations afs_proc_cell_vlservers_ops = { | ||
316 | .start = afs_proc_cell_vlservers_start, | ||
317 | .next = afs_proc_cell_vlservers_next, | ||
318 | .stop = afs_proc_cell_vlservers_stop, | ||
319 | .show = afs_proc_cell_vlservers_show, | ||
320 | }; | ||
321 | |||
548 | /* | 322 | /* |
549 | * display a header line followed by a load of volume lines | 323 | * Display the list of fileservers we're using within a namespace. |
550 | */ | 324 | */ |
551 | static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v) | 325 | static int afs_proc_servers_show(struct seq_file *m, void *v) |
552 | { | 326 | { |
553 | struct sockaddr_rxrpc *addr = v; | 327 | struct afs_server *server; |
328 | struct afs_addr_list *alist; | ||
329 | int i; | ||
554 | 330 | ||
555 | /* display header on line 1 */ | 331 | if (v == SEQ_START_TOKEN) { |
556 | if (v == (void *)1) { | 332 | seq_puts(m, "UUID USE ADDR\n"); |
557 | seq_puts(m, "ADDRESS\n"); | ||
558 | return 0; | 333 | return 0; |
559 | } | 334 | } |
560 | 335 | ||
561 | /* display one cell per line on subsequent lines */ | 336 | server = list_entry(v, struct afs_server, proc_link); |
562 | seq_printf(m, "%pISp\n", &addr->transport); | 337 | alist = rcu_dereference(server->addresses); |
338 | seq_printf(m, "%pU %3d %pISpc%s\n", | ||
339 | &server->uuid, | ||
340 | atomic_read(&server->usage), | ||
341 | &alist->addrs[0].transport, | ||
342 | alist->index == 0 ? "*" : ""); | ||
343 | for (i = 1; i < alist->nr_addrs; i++) | ||
344 | seq_printf(m, " %pISpc%s\n", | ||
345 | &alist->addrs[i].transport, | ||
346 | alist->index == i ? "*" : ""); | ||
563 | return 0; | 347 | return 0; |
564 | } | 348 | } |
565 | 349 | ||
566 | /* | ||
567 | * Set up the iterator to start reading from the server list and return the | ||
568 | * first item. | ||
569 | */ | ||
570 | static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos) | 350 | static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos) |
571 | __acquires(rcu) | 351 | __acquires(rcu) |
572 | { | 352 | { |
573 | struct afs_net *net = afs_seq2net(m); | ||
574 | |||
575 | rcu_read_lock(); | 353 | rcu_read_lock(); |
576 | return seq_hlist_start_head_rcu(&net->fs_proc, *_pos); | 354 | return seq_hlist_start_head_rcu(&afs_seq2net(m)->fs_proc, *_pos); |
577 | } | 355 | } |
578 | 356 | ||
579 | /* | ||
580 | * move to next cell in cells list | ||
581 | */ | ||
582 | static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos) | 357 | static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos) |
583 | { | 358 | { |
584 | struct afs_net *net = afs_seq2net(m); | 359 | return seq_hlist_next_rcu(v, &afs_seq2net(m)->fs_proc, _pos); |
585 | |||
586 | return seq_hlist_next_rcu(v, &net->fs_proc, _pos); | ||
587 | } | 360 | } |
588 | 361 | ||
589 | /* | 362 | static void afs_proc_servers_stop(struct seq_file *m, void *v) |
590 | * clean up after reading from the cells list | ||
591 | */ | ||
592 | static void afs_proc_servers_stop(struct seq_file *p, void *v) | ||
593 | __releases(rcu) | 363 | __releases(rcu) |
594 | { | 364 | { |
595 | rcu_read_unlock(); | 365 | rcu_read_unlock(); |
596 | } | 366 | } |
597 | 367 | ||
368 | static const struct seq_operations afs_proc_servers_ops = { | ||
369 | .start = afs_proc_servers_start, | ||
370 | .next = afs_proc_servers_next, | ||
371 | .stop = afs_proc_servers_stop, | ||
372 | .show = afs_proc_servers_show, | ||
373 | }; | ||
374 | |||
598 | /* | 375 | /* |
599 | * display a header line followed by a load of volume lines | 376 | * Display the list of strings that may be substituted for the @sys pathname |
377 | * macro. | ||
600 | */ | 378 | */ |
601 | static int afs_proc_servers_show(struct seq_file *m, void *v) | 379 | static int afs_proc_sysname_show(struct seq_file *m, void *v) |
602 | { | 380 | { |
603 | struct afs_server *server; | 381 | struct afs_net *net = afs_seq2net(m); |
604 | struct afs_addr_list *alist; | 382 | struct afs_sysnames *sysnames = net->sysnames; |
605 | 383 | unsigned int i = (unsigned long)v - 1; | |
606 | if (v == SEQ_START_TOKEN) { | ||
607 | seq_puts(m, "UUID USE ADDR\n"); | ||
608 | return 0; | ||
609 | } | ||
610 | 384 | ||
611 | server = list_entry(v, struct afs_server, proc_link); | 385 | if (i < sysnames->nr) |
612 | alist = rcu_dereference(server->addresses); | 386 | seq_printf(m, "%s\n", sysnames->subs[i]); |
613 | seq_printf(m, "%pU %3d %pISp\n", | ||
614 | &server->uuid, | ||
615 | atomic_read(&server->usage), | ||
616 | &alist->addrs[alist->index].transport); | ||
617 | return 0; | 387 | return 0; |
618 | } | 388 | } |
619 | 389 | ||
620 | void afs_put_sysnames(struct afs_sysnames *sysnames) | 390 | static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos) |
391 | __acquires(&net->sysnames_lock) | ||
621 | { | 392 | { |
622 | int i; | 393 | struct afs_net *net = afs_seq2net(m); |
394 | struct afs_sysnames *names; | ||
623 | 395 | ||
624 | if (sysnames && refcount_dec_and_test(&sysnames->usage)) { | 396 | read_lock(&net->sysnames_lock); |
625 | for (i = 0; i < sysnames->nr; i++) | 397 | |
626 | if (sysnames->subs[i] != afs_init_sysname && | 398 | names = net->sysnames; |
627 | sysnames->subs[i] != sysnames->blank) | 399 | if (*pos >= names->nr) |
628 | kfree(sysnames->subs[i]); | 400 | return NULL; |
629 | } | 401 | return (void *)(unsigned long)(*pos + 1); |
630 | } | 402 | } |
631 | 403 | ||
632 | /* | 404 | static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos) |
633 | * Handle opening of /proc/fs/afs/sysname. If it is opened for writing, we | ||
634 | * assume the caller wants to change the substitution list and we allocate a | ||
635 | * buffer to hold the list. | ||
636 | */ | ||
637 | static int afs_proc_sysname_open(struct inode *inode, struct file *file) | ||
638 | { | 405 | { |
639 | struct afs_sysnames *sysnames; | 406 | struct afs_net *net = afs_seq2net(m); |
640 | struct seq_file *m; | 407 | struct afs_sysnames *names = net->sysnames; |
641 | int ret; | ||
642 | |||
643 | ret = seq_open(file, &afs_proc_sysname_ops); | ||
644 | if (ret < 0) | ||
645 | return ret; | ||
646 | 408 | ||
647 | if (file->f_mode & FMODE_WRITE) { | 409 | *pos += 1; |
648 | sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL); | 410 | if (*pos >= names->nr) |
649 | if (!sysnames) { | 411 | return NULL; |
650 | seq_release(inode, file); | 412 | return (void *)(unsigned long)(*pos + 1); |
651 | return -ENOMEM; | 413 | } |
652 | } | ||
653 | 414 | ||
654 | refcount_set(&sysnames->usage, 1); | 415 | static void afs_proc_sysname_stop(struct seq_file *m, void *v) |
655 | m = file->private_data; | 416 | __releases(&net->sysnames_lock) |
656 | m->private = sysnames; | 417 | { |
657 | } | 418 | struct afs_net *net = afs_seq2net(m); |
658 | 419 | ||
659 | return 0; | 420 | read_unlock(&net->sysnames_lock); |
660 | } | 421 | } |
661 | 422 | ||
423 | static const struct seq_operations afs_proc_sysname_ops = { | ||
424 | .start = afs_proc_sysname_start, | ||
425 | .next = afs_proc_sysname_next, | ||
426 | .stop = afs_proc_sysname_stop, | ||
427 | .show = afs_proc_sysname_show, | ||
428 | }; | ||
429 | |||
662 | /* | 430 | /* |
663 | * Handle writes to /proc/fs/afs/sysname to set the @sys substitution. | 431 | * Allow the @sys substitution to be configured. |
664 | */ | 432 | */ |
665 | static ssize_t afs_proc_sysname_write(struct file *file, | 433 | static int afs_proc_sysname_write(struct file *file, char *buf, size_t size) |
666 | const char __user *buf, | ||
667 | size_t size, loff_t *_pos) | ||
668 | { | 434 | { |
669 | struct afs_sysnames *sysnames; | 435 | struct afs_sysnames *sysnames, *kill; |
670 | struct seq_file *m = file->private_data; | 436 | struct seq_file *m = file->private_data; |
671 | char *kbuf = NULL, *s, *p, *sub; | 437 | struct afs_net *net = afs_seq2net(m); |
438 | char *s, *p, *sub; | ||
672 | int ret, len; | 439 | int ret, len; |
673 | 440 | ||
674 | sysnames = m->private; | 441 | sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL); |
675 | if (!sysnames) | 442 | if (!sysnames) |
676 | return -EINVAL; | 443 | return -ENOMEM; |
677 | if (sysnames->error) | 444 | refcount_set(&sysnames->usage, 1); |
678 | return sysnames->error; | 445 | kill = sysnames; |
679 | |||
680 | if (size >= PAGE_SIZE - 1) { | ||
681 | sysnames->error = -EINVAL; | ||
682 | return -EINVAL; | ||
683 | } | ||
684 | if (size == 0) | ||
685 | return 0; | ||
686 | |||
687 | kbuf = memdup_user_nul(buf, size); | ||
688 | if (IS_ERR(kbuf)) | ||
689 | return PTR_ERR(kbuf); | ||
690 | |||
691 | inode_lock(file_inode(file)); | ||
692 | 446 | ||
693 | p = kbuf; | 447 | p = buf; |
694 | while ((s = strsep(&p, " \t\n"))) { | 448 | while ((s = strsep(&p, " \t\n"))) { |
695 | len = strlen(s); | 449 | len = strlen(s); |
696 | if (len == 0) | 450 | if (len == 0) |
@@ -731,85 +485,36 @@ static ssize_t afs_proc_sysname_write(struct file *file, | |||
731 | sysnames->nr++; | 485 | sysnames->nr++; |
732 | } | 486 | } |
733 | 487 | ||
734 | ret = size; /* consume everything, always */ | 488 | if (sysnames->nr == 0) { |
489 | sysnames->subs[0] = sysnames->blank; | ||
490 | sysnames->nr++; | ||
491 | } | ||
492 | |||
493 | write_lock(&net->sysnames_lock); | ||
494 | kill = net->sysnames; | ||
495 | net->sysnames = sysnames; | ||
496 | write_unlock(&net->sysnames_lock); | ||
497 | ret = 0; | ||
735 | out: | 498 | out: |
736 | inode_unlock(file_inode(file)); | 499 | afs_put_sysnames(kill); |
737 | kfree(kbuf); | ||
738 | return ret; | 500 | return ret; |
739 | 501 | ||
740 | invalid: | 502 | invalid: |
741 | ret = -EINVAL; | 503 | ret = -EINVAL; |
742 | error: | 504 | error: |
743 | sysnames->error = ret; | ||
744 | goto out; | 505 | goto out; |
745 | } | 506 | } |
746 | 507 | ||
747 | static int afs_proc_sysname_release(struct inode *inode, struct file *file) | 508 | void afs_put_sysnames(struct afs_sysnames *sysnames) |
748 | { | 509 | { |
749 | struct afs_sysnames *sysnames, *kill = NULL; | 510 | int i; |
750 | struct seq_file *m = file->private_data; | ||
751 | struct afs_net *net = afs_seq2net(m); | ||
752 | 511 | ||
753 | sysnames = m->private; | 512 | if (sysnames && refcount_dec_and_test(&sysnames->usage)) { |
754 | if (sysnames) { | 513 | for (i = 0; i < sysnames->nr; i++) |
755 | if (!sysnames->error) { | 514 | if (sysnames->subs[i] != afs_init_sysname && |
756 | kill = sysnames; | 515 | sysnames->subs[i] != sysnames->blank) |
757 | if (sysnames->nr == 0) { | 516 | kfree(sysnames->subs[i]); |
758 | sysnames->subs[0] = sysnames->blank; | ||
759 | sysnames->nr++; | ||
760 | } | ||
761 | write_lock(&net->sysnames_lock); | ||
762 | kill = net->sysnames; | ||
763 | net->sysnames = sysnames; | ||
764 | write_unlock(&net->sysnames_lock); | ||
765 | } | ||
766 | afs_put_sysnames(kill); | ||
767 | } | 517 | } |
768 | |||
769 | return seq_release(inode, file); | ||
770 | } | ||
771 | |||
772 | static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos) | ||
773 | __acquires(&net->sysnames_lock) | ||
774 | { | ||
775 | struct afs_net *net = afs_seq2net(m); | ||
776 | struct afs_sysnames *names = net->sysnames; | ||
777 | |||
778 | read_lock(&net->sysnames_lock); | ||
779 | |||
780 | if (*pos >= names->nr) | ||
781 | return NULL; | ||
782 | return (void *)(unsigned long)(*pos + 1); | ||
783 | } | ||
784 | |||
785 | static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos) | ||
786 | { | ||
787 | struct afs_net *net = afs_seq2net(m); | ||
788 | struct afs_sysnames *names = net->sysnames; | ||
789 | |||
790 | *pos += 1; | ||
791 | if (*pos >= names->nr) | ||
792 | return NULL; | ||
793 | return (void *)(unsigned long)(*pos + 1); | ||
794 | } | ||
795 | |||
796 | static void afs_proc_sysname_stop(struct seq_file *m, void *v) | ||
797 | __releases(&net->sysnames_lock) | ||
798 | { | ||
799 | struct afs_net *net = afs_seq2net(m); | ||
800 | |||
801 | read_unlock(&net->sysnames_lock); | ||
802 | } | ||
803 | |||
804 | static int afs_proc_sysname_show(struct seq_file *m, void *v) | ||
805 | { | ||
806 | struct afs_net *net = afs_seq2net(m); | ||
807 | struct afs_sysnames *sysnames = net->sysnames; | ||
808 | unsigned int i = (unsigned long)v - 1; | ||
809 | |||
810 | if (i < sysnames->nr) | ||
811 | seq_printf(m, "%s\n", sysnames->subs[i]); | ||
812 | return 0; | ||
813 | } | 518 | } |
814 | 519 | ||
815 | /* | 520 | /* |
@@ -817,7 +522,7 @@ static int afs_proc_sysname_show(struct seq_file *m, void *v) | |||
817 | */ | 522 | */ |
818 | static int afs_proc_stats_show(struct seq_file *m, void *v) | 523 | static int afs_proc_stats_show(struct seq_file *m, void *v) |
819 | { | 524 | { |
820 | struct afs_net *net = afs_seq2net(m); | 525 | struct afs_net *net = afs_seq2net_single(m); |
821 | 526 | ||
822 | seq_puts(m, "kAFS statistics\n"); | 527 | seq_puts(m, "kAFS statistics\n"); |
823 | 528 | ||
@@ -842,3 +547,101 @@ static int afs_proc_stats_show(struct seq_file *m, void *v) | |||
842 | atomic_long_read(&net->n_store_bytes)); | 547 | atomic_long_read(&net->n_store_bytes)); |
843 | return 0; | 548 | return 0; |
844 | } | 549 | } |
550 | |||
551 | /* | ||
552 | * initialise /proc/fs/afs/<cell>/ | ||
553 | */ | ||
554 | int afs_proc_cell_setup(struct afs_cell *cell) | ||
555 | { | ||
556 | struct proc_dir_entry *dir; | ||
557 | struct afs_net *net = cell->net; | ||
558 | |||
559 | _enter("%p{%s},%p", cell, cell->name, net->proc_afs); | ||
560 | |||
561 | dir = proc_net_mkdir(net->net, cell->name, net->proc_afs); | ||
562 | if (!dir) | ||
563 | goto error_dir; | ||
564 | |||
565 | if (!proc_create_net_data("vlservers", 0444, dir, | ||
566 | &afs_proc_cell_vlservers_ops, | ||
567 | sizeof(struct seq_net_private), | ||
568 | cell) || | ||
569 | !proc_create_net_data("volumes", 0444, dir, | ||
570 | &afs_proc_cell_volumes_ops, | ||
571 | sizeof(struct seq_net_private), | ||
572 | cell)) | ||
573 | goto error_tree; | ||
574 | |||
575 | _leave(" = 0"); | ||
576 | return 0; | ||
577 | |||
578 | error_tree: | ||
579 | remove_proc_subtree(cell->name, net->proc_afs); | ||
580 | error_dir: | ||
581 | _leave(" = -ENOMEM"); | ||
582 | return -ENOMEM; | ||
583 | } | ||
584 | |||
585 | /* | ||
586 | * remove /proc/fs/afs/<cell>/ | ||
587 | */ | ||
588 | void afs_proc_cell_remove(struct afs_cell *cell) | ||
589 | { | ||
590 | struct afs_net *net = cell->net; | ||
591 | |||
592 | _enter(""); | ||
593 | remove_proc_subtree(cell->name, net->proc_afs); | ||
594 | _leave(""); | ||
595 | } | ||
596 | |||
597 | /* | ||
598 | * initialise the /proc/fs/afs/ directory | ||
599 | */ | ||
600 | int afs_proc_init(struct afs_net *net) | ||
601 | { | ||
602 | struct proc_dir_entry *p; | ||
603 | |||
604 | _enter(""); | ||
605 | |||
606 | p = proc_net_mkdir(net->net, "afs", net->net->proc_net); | ||
607 | if (!p) | ||
608 | goto error_dir; | ||
609 | |||
610 | if (!proc_create_net_data_write("cells", 0644, p, | ||
611 | &afs_proc_cells_ops, | ||
612 | afs_proc_cells_write, | ||
613 | sizeof(struct seq_net_private), | ||
614 | NULL) || | ||
615 | !proc_create_net_single_write("rootcell", 0644, p, | ||
616 | afs_proc_rootcell_show, | ||
617 | afs_proc_rootcell_write, | ||
618 | NULL) || | ||
619 | !proc_create_net("servers", 0444, p, &afs_proc_servers_ops, | ||
620 | sizeof(struct seq_net_private)) || | ||
621 | !proc_create_net_single("stats", 0444, p, afs_proc_stats_show, NULL) || | ||
622 | !proc_create_net_data_write("sysname", 0644, p, | ||
623 | &afs_proc_sysname_ops, | ||
624 | afs_proc_sysname_write, | ||
625 | sizeof(struct seq_net_private), | ||
626 | NULL)) | ||
627 | goto error_tree; | ||
628 | |||
629 | net->proc_afs = p; | ||
630 | _leave(" = 0"); | ||
631 | return 0; | ||
632 | |||
633 | error_tree: | ||
634 | proc_remove(p); | ||
635 | error_dir: | ||
636 | _leave(" = -ENOMEM"); | ||
637 | return -ENOMEM; | ||
638 | } | ||
639 | |||
640 | /* | ||
641 | * clean up the /proc/fs/afs/ directory | ||
642 | */ | ||
643 | void afs_proc_cleanup(struct afs_net *net) | ||
644 | { | ||
645 | proc_remove(net->proc_afs); | ||
646 | net->proc_afs = NULL; | ||
647 | } | ||
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 08735948f15d..a1b18082991b 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c | |||
@@ -46,7 +46,7 @@ int afs_open_socket(struct afs_net *net) | |||
46 | 46 | ||
47 | _enter(""); | 47 | _enter(""); |
48 | 48 | ||
49 | ret = sock_create_kern(&init_net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket); | 49 | ret = sock_create_kern(net->net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket); |
50 | if (ret < 0) | 50 | if (ret < 0) |
51 | goto error_1; | 51 | goto error_1; |
52 | 52 | ||
diff --git a/fs/afs/server.c b/fs/afs/server.c index 3af4625e2f8c..1d329e6981d5 100644 --- a/fs/afs/server.c +++ b/fs/afs/server.c | |||
@@ -228,7 +228,7 @@ static struct afs_server *afs_alloc_server(struct afs_net *net, | |||
228 | server->flags = (1UL << AFS_SERVER_FL_NEW); | 228 | server->flags = (1UL << AFS_SERVER_FL_NEW); |
229 | server->update_at = ktime_get_real_seconds() + afs_server_update_delay; | 229 | server->update_at = ktime_get_real_seconds() + afs_server_update_delay; |
230 | rwlock_init(&server->fs_lock); | 230 | rwlock_init(&server->fs_lock); |
231 | INIT_LIST_HEAD(&server->cb_interests); | 231 | INIT_HLIST_HEAD(&server->cb_volumes); |
232 | rwlock_init(&server->cb_break_lock); | 232 | rwlock_init(&server->cb_break_lock); |
233 | 233 | ||
234 | afs_inc_servers_outstanding(net); | 234 | afs_inc_servers_outstanding(net); |
diff --git a/fs/afs/super.c b/fs/afs/super.c index 9e5d7966621c..4d3e274207fb 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
@@ -48,6 +48,8 @@ struct file_system_type afs_fs_type = { | |||
48 | }; | 48 | }; |
49 | MODULE_ALIAS_FS("afs"); | 49 | MODULE_ALIAS_FS("afs"); |
50 | 50 | ||
51 | int afs_net_id; | ||
52 | |||
51 | static const struct super_operations afs_super_ops = { | 53 | static const struct super_operations afs_super_ops = { |
52 | .statfs = afs_statfs, | 54 | .statfs = afs_statfs, |
53 | .alloc_inode = afs_alloc_inode, | 55 | .alloc_inode = afs_alloc_inode, |
@@ -117,7 +119,7 @@ int __init afs_fs_init(void) | |||
117 | /* | 119 | /* |
118 | * clean up the filesystem | 120 | * clean up the filesystem |
119 | */ | 121 | */ |
120 | void __exit afs_fs_exit(void) | 122 | void afs_fs_exit(void) |
121 | { | 123 | { |
122 | _enter(""); | 124 | _enter(""); |
123 | 125 | ||
@@ -351,14 +353,19 @@ static int afs_test_super(struct super_block *sb, void *data) | |||
351 | struct afs_super_info *as1 = data; | 353 | struct afs_super_info *as1 = data; |
352 | struct afs_super_info *as = AFS_FS_S(sb); | 354 | struct afs_super_info *as = AFS_FS_S(sb); |
353 | 355 | ||
354 | return (as->net == as1->net && | 356 | return (as->net_ns == as1->net_ns && |
355 | as->volume && | 357 | as->volume && |
356 | as->volume->vid == as1->volume->vid); | 358 | as->volume->vid == as1->volume->vid && |
359 | !as->dyn_root); | ||
357 | } | 360 | } |
358 | 361 | ||
359 | static int afs_dynroot_test_super(struct super_block *sb, void *data) | 362 | static int afs_dynroot_test_super(struct super_block *sb, void *data) |
360 | { | 363 | { |
361 | return false; | 364 | struct afs_super_info *as1 = data; |
365 | struct afs_super_info *as = AFS_FS_S(sb); | ||
366 | |||
367 | return (as->net_ns == as1->net_ns && | ||
368 | as->dyn_root); | ||
362 | } | 369 | } |
363 | 370 | ||
364 | static int afs_set_super(struct super_block *sb, void *data) | 371 | static int afs_set_super(struct super_block *sb, void *data) |
@@ -418,10 +425,14 @@ static int afs_fill_super(struct super_block *sb, | |||
418 | if (!sb->s_root) | 425 | if (!sb->s_root) |
419 | goto error; | 426 | goto error; |
420 | 427 | ||
421 | if (params->dyn_root) | 428 | if (as->dyn_root) { |
422 | sb->s_d_op = &afs_dynroot_dentry_operations; | 429 | sb->s_d_op = &afs_dynroot_dentry_operations; |
423 | else | 430 | ret = afs_dynroot_populate(sb); |
431 | if (ret < 0) | ||
432 | goto error; | ||
433 | } else { | ||
424 | sb->s_d_op = &afs_fs_dentry_operations; | 434 | sb->s_d_op = &afs_fs_dentry_operations; |
435 | } | ||
425 | 436 | ||
426 | _leave(" = 0"); | 437 | _leave(" = 0"); |
427 | return 0; | 438 | return 0; |
@@ -437,7 +448,7 @@ static struct afs_super_info *afs_alloc_sbi(struct afs_mount_params *params) | |||
437 | 448 | ||
438 | as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); | 449 | as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); |
439 | if (as) { | 450 | if (as) { |
440 | as->net = afs_get_net(params->net); | 451 | as->net_ns = get_net(params->net_ns); |
441 | if (params->dyn_root) | 452 | if (params->dyn_root) |
442 | as->dyn_root = true; | 453 | as->dyn_root = true; |
443 | else | 454 | else |
@@ -450,12 +461,31 @@ static void afs_destroy_sbi(struct afs_super_info *as) | |||
450 | { | 461 | { |
451 | if (as) { | 462 | if (as) { |
452 | afs_put_volume(as->cell, as->volume); | 463 | afs_put_volume(as->cell, as->volume); |
453 | afs_put_cell(as->net, as->cell); | 464 | afs_put_cell(afs_net(as->net_ns), as->cell); |
454 | afs_put_net(as->net); | 465 | put_net(as->net_ns); |
455 | kfree(as); | 466 | kfree(as); |
456 | } | 467 | } |
457 | } | 468 | } |
458 | 469 | ||
470 | static void afs_kill_super(struct super_block *sb) | ||
471 | { | ||
472 | struct afs_super_info *as = AFS_FS_S(sb); | ||
473 | struct afs_net *net = afs_net(as->net_ns); | ||
474 | |||
475 | if (as->dyn_root) | ||
476 | afs_dynroot_depopulate(sb); | ||
477 | |||
478 | /* Clear the callback interests (which will do ilookup5) before | ||
479 | * deactivating the superblock. | ||
480 | */ | ||
481 | if (as->volume) | ||
482 | afs_clear_callback_interests(net, as->volume->servers); | ||
483 | kill_anon_super(sb); | ||
484 | if (as->volume) | ||
485 | afs_deactivate_volume(as->volume); | ||
486 | afs_destroy_sbi(as); | ||
487 | } | ||
488 | |||
459 | /* | 489 | /* |
460 | * get an AFS superblock | 490 | * get an AFS superblock |
461 | */ | 491 | */ |
@@ -472,12 +502,13 @@ static struct dentry *afs_mount(struct file_system_type *fs_type, | |||
472 | _enter(",,%s,%p", dev_name, options); | 502 | _enter(",,%s,%p", dev_name, options); |
473 | 503 | ||
474 | memset(¶ms, 0, sizeof(params)); | 504 | memset(¶ms, 0, sizeof(params)); |
475 | params.net = &__afs_net; | ||
476 | 505 | ||
477 | ret = -EINVAL; | 506 | ret = -EINVAL; |
478 | if (current->nsproxy->net_ns != &init_net) | 507 | if (current->nsproxy->net_ns != &init_net) |
479 | goto error; | 508 | goto error; |
480 | 509 | params.net_ns = current->nsproxy->net_ns; | |
510 | params.net = afs_net(params.net_ns); | ||
511 | |||
481 | /* parse the options and device name */ | 512 | /* parse the options and device name */ |
482 | if (options) { | 513 | if (options) { |
483 | ret = afs_parse_options(¶ms, options, &dev_name); | 514 | ret = afs_parse_options(¶ms, options, &dev_name); |
@@ -563,21 +594,6 @@ error: | |||
563 | return ERR_PTR(ret); | 594 | return ERR_PTR(ret); |
564 | } | 595 | } |
565 | 596 | ||
566 | static void afs_kill_super(struct super_block *sb) | ||
567 | { | ||
568 | struct afs_super_info *as = AFS_FS_S(sb); | ||
569 | |||
570 | /* Clear the callback interests (which will do ilookup5) before | ||
571 | * deactivating the superblock. | ||
572 | */ | ||
573 | if (as->volume) | ||
574 | afs_clear_callback_interests(as->net, as->volume->servers); | ||
575 | kill_anon_super(sb); | ||
576 | if (as->volume) | ||
577 | afs_deactivate_volume(as->volume); | ||
578 | afs_destroy_sbi(as); | ||
579 | } | ||
580 | |||
581 | /* | 597 | /* |
582 | * Initialise an inode cache slab element prior to any use. Note that | 598 | * Initialise an inode cache slab element prior to any use. Note that |
583 | * afs_alloc_inode() *must* reset anything that could incorrectly leak from one | 599 | * afs_alloc_inode() *must* reset anything that could incorrectly leak from one |