1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* AFS client file system |
3 | * |
4 | * Copyright (C) 2002,5 Red Hat, Inc. All Rights Reserved. |
5 | * Written by David Howells (dhowells@redhat.com) |
6 | */ |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/moduleparam.h> |
10 | #include <linux/init.h> |
11 | #include <linux/completion.h> |
12 | #include <linux/sched.h> |
13 | #include <linux/random.h> |
14 | #include <linux/proc_fs.h> |
15 | #define CREATE_TRACE_POINTS |
16 | #include "internal.h" |
17 | |
18 | MODULE_DESCRIPTION("AFS Client File System" ); |
19 | MODULE_AUTHOR("Red Hat, Inc." ); |
20 | MODULE_LICENSE("GPL" ); |
21 | |
22 | unsigned afs_debug; |
23 | module_param_named(debug, afs_debug, uint, S_IWUSR | S_IRUGO); |
24 | MODULE_PARM_DESC(debug, "AFS debugging mask" ); |
25 | |
26 | static char *rootcell; |
27 | |
28 | module_param(rootcell, charp, 0); |
29 | MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list" ); |
30 | |
31 | struct workqueue_struct *afs_wq; |
32 | static struct proc_dir_entry *afs_proc_symlink; |
33 | |
34 | #if defined(CONFIG_ALPHA) |
35 | const char afs_init_sysname[] = "alpha_linux26" ; |
36 | #elif defined(CONFIG_X86_64) |
37 | const char afs_init_sysname[] = "amd64_linux26" ; |
38 | #elif defined(CONFIG_ARM) |
39 | const char afs_init_sysname[] = "arm_linux26" ; |
40 | #elif defined(CONFIG_ARM64) |
41 | const char afs_init_sysname[] = "aarch64_linux26" ; |
42 | #elif defined(CONFIG_X86_32) |
43 | const char afs_init_sysname[] = "i386_linux26" ; |
44 | #elif defined(CONFIG_PPC64) |
45 | const char afs_init_sysname[] = "ppc64_linux26" ; |
46 | #elif defined(CONFIG_PPC32) |
47 | const char afs_init_sysname[] = "ppc_linux26" ; |
48 | #elif defined(CONFIG_S390) |
49 | #ifdef CONFIG_64BIT |
50 | const char afs_init_sysname[] = "s390x_linux26" ; |
51 | #else |
52 | const char afs_init_sysname[] = "s390_linux26" ; |
53 | #endif |
54 | #elif defined(CONFIG_SPARC64) |
55 | const char afs_init_sysname[] = "sparc64_linux26" ; |
56 | #elif defined(CONFIG_SPARC32) |
57 | const char afs_init_sysname[] = "sparc_linux26" ; |
58 | #else |
59 | const char afs_init_sysname[] = "unknown_linux26" ; |
60 | #endif |
61 | |
62 | /* |
63 | * Initialise an AFS network namespace record. |
64 | */ |
65 | static int __net_init afs_net_init(struct net *net_ns) |
66 | { |
67 | struct afs_sysnames *sysnames; |
68 | struct afs_net *net = afs_net(net: net_ns); |
69 | int ret; |
70 | |
71 | net->net = net_ns; |
72 | net->live = true; |
73 | generate_random_uuid(uuid: (unsigned char *)&net->uuid); |
74 | |
75 | INIT_WORK(&net->charge_preallocation_work, afs_charge_preallocation); |
76 | mutex_init(&net->socket_mutex); |
77 | |
78 | net->cells = RB_ROOT; |
79 | init_rwsem(&net->cells_lock); |
80 | INIT_WORK(&net->cells_manager, afs_manage_cells); |
81 | timer_setup(&net->cells_timer, afs_cells_timer, 0); |
82 | |
83 | mutex_init(&net->cells_alias_lock); |
84 | mutex_init(&net->proc_cells_lock); |
85 | INIT_HLIST_HEAD(&net->proc_cells); |
86 | |
87 | seqlock_init(&net->fs_lock); |
88 | net->fs_servers = RB_ROOT; |
89 | INIT_LIST_HEAD(list: &net->fs_probe_fast); |
90 | INIT_LIST_HEAD(list: &net->fs_probe_slow); |
91 | INIT_HLIST_HEAD(&net->fs_proc); |
92 | |
93 | INIT_HLIST_HEAD(&net->fs_addresses4); |
94 | INIT_HLIST_HEAD(&net->fs_addresses6); |
95 | seqlock_init(&net->fs_addr_lock); |
96 | |
97 | INIT_WORK(&net->fs_manager, afs_manage_servers); |
98 | timer_setup(&net->fs_timer, afs_servers_timer, 0); |
99 | INIT_WORK(&net->fs_prober, afs_fs_probe_dispatcher); |
100 | timer_setup(&net->fs_probe_timer, afs_fs_probe_timer, 0); |
101 | atomic_set(v: &net->servers_outstanding, i: 1); |
102 | |
103 | ret = -ENOMEM; |
104 | sysnames = kzalloc(size: sizeof(*sysnames), GFP_KERNEL); |
105 | if (!sysnames) |
106 | goto error_sysnames; |
107 | sysnames->subs[0] = (char *)&afs_init_sysname; |
108 | sysnames->nr = 1; |
109 | refcount_set(r: &sysnames->usage, n: 1); |
110 | net->sysnames = sysnames; |
111 | rwlock_init(&net->sysnames_lock); |
112 | |
113 | /* Register the /proc stuff */ |
114 | ret = afs_proc_init(net); |
115 | if (ret < 0) |
116 | goto error_proc; |
117 | |
118 | /* Initialise the cell DB */ |
119 | ret = afs_cell_init(net, rootcell); |
120 | if (ret < 0) |
121 | goto error_cell_init; |
122 | |
123 | /* Create the RxRPC transport */ |
124 | ret = afs_open_socket(net); |
125 | if (ret < 0) |
126 | goto error_open_socket; |
127 | |
128 | return 0; |
129 | |
130 | error_open_socket: |
131 | net->live = false; |
132 | afs_fs_probe_cleanup(net); |
133 | afs_cell_purge(net); |
134 | afs_purge_servers(net); |
135 | error_cell_init: |
136 | net->live = false; |
137 | afs_proc_cleanup(net); |
138 | error_proc: |
139 | afs_put_sysnames(net->sysnames); |
140 | error_sysnames: |
141 | net->live = false; |
142 | return ret; |
143 | } |
144 | |
145 | /* |
146 | * Clean up and destroy an AFS network namespace record. |
147 | */ |
148 | static void __net_exit afs_net_exit(struct net *net_ns) |
149 | { |
150 | struct afs_net *net = afs_net(net: net_ns); |
151 | |
152 | net->live = false; |
153 | afs_fs_probe_cleanup(net); |
154 | afs_cell_purge(net); |
155 | afs_purge_servers(net); |
156 | afs_close_socket(net); |
157 | afs_proc_cleanup(net); |
158 | afs_put_sysnames(net->sysnames); |
159 | } |
160 | |
161 | static struct pernet_operations afs_net_ops = { |
162 | .init = afs_net_init, |
163 | .exit = afs_net_exit, |
164 | .id = &afs_net_id, |
165 | .size = sizeof(struct afs_net), |
166 | }; |
167 | |
168 | /* |
169 | * initialise the AFS client FS module |
170 | */ |
171 | static int __init afs_init(void) |
172 | { |
173 | int ret = -ENOMEM; |
174 | |
175 | printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n" ); |
176 | |
177 | afs_wq = alloc_workqueue(fmt: "afs" , flags: 0, max_active: 0); |
178 | if (!afs_wq) |
179 | goto error_afs_wq; |
180 | afs_async_calls = alloc_workqueue(fmt: "kafsd" , flags: WQ_MEM_RECLAIM, max_active: 0); |
181 | if (!afs_async_calls) |
182 | goto error_async; |
183 | afs_lock_manager = alloc_workqueue(fmt: "kafs_lockd" , flags: WQ_MEM_RECLAIM, max_active: 0); |
184 | if (!afs_lock_manager) |
185 | goto error_lockmgr; |
186 | |
187 | ret = register_pernet_device(&afs_net_ops); |
188 | if (ret < 0) |
189 | goto error_net; |
190 | |
191 | /* register the filesystems */ |
192 | ret = afs_fs_init(); |
193 | if (ret < 0) |
194 | goto error_fs; |
195 | |
196 | afs_proc_symlink = proc_symlink("fs/afs" , NULL, "../self/net/afs" ); |
197 | if (!afs_proc_symlink) { |
198 | ret = -ENOMEM; |
199 | goto error_proc; |
200 | } |
201 | |
202 | return ret; |
203 | |
204 | error_proc: |
205 | afs_fs_exit(); |
206 | error_fs: |
207 | unregister_pernet_device(&afs_net_ops); |
208 | error_net: |
209 | destroy_workqueue(wq: afs_lock_manager); |
210 | error_lockmgr: |
211 | destroy_workqueue(wq: afs_async_calls); |
212 | error_async: |
213 | destroy_workqueue(wq: afs_wq); |
214 | error_afs_wq: |
215 | rcu_barrier(); |
216 | printk(KERN_ERR "kAFS: failed to register: %d\n" , ret); |
217 | return ret; |
218 | } |
219 | |
220 | /* XXX late_initcall is kludgy, but the only alternative seems to create |
221 | * a transport upon the first mount, which is worse. Or is it? |
222 | */ |
223 | late_initcall(afs_init); /* must be called after net/ to create socket */ |
224 | |
225 | /* |
226 | * clean up on module removal |
227 | */ |
228 | static void __exit afs_exit(void) |
229 | { |
230 | printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n" ); |
231 | |
232 | proc_remove(afs_proc_symlink); |
233 | afs_fs_exit(); |
234 | unregister_pernet_device(&afs_net_ops); |
235 | destroy_workqueue(wq: afs_lock_manager); |
236 | destroy_workqueue(wq: afs_async_calls); |
237 | destroy_workqueue(wq: afs_wq); |
238 | afs_clean_up_permit_cache(); |
239 | rcu_barrier(); |
240 | } |
241 | |
242 | module_exit(afs_exit); |
243 | |