Commit | Line | Data |
---|---|---|
0626e664 NJ |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> | |
4 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. | |
5 | */ | |
6 | ||
7 | #include "glob.h" | |
8 | #include "oplock.h" | |
9 | #include "misc.h" | |
10 | #include <linux/sched/signal.h> | |
11 | #include <linux/workqueue.h> | |
12 | #include <linux/sysfs.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/moduleparam.h> | |
15 | ||
16 | #include "server.h" | |
17 | #include "smb_common.h" | |
18 | #include "smbstatus.h" | |
0626e664 NJ |
19 | #include "connection.h" |
20 | #include "transport_ipc.h" | |
21 | #include "mgmt/user_session.h" | |
22 | #include "crypto_ctx.h" | |
23 | #include "auth.h" | |
24 | ||
25 | int ksmbd_debug_types; | |
26 | ||
27 | struct ksmbd_server_config server_conf; | |
28 | ||
29 | enum SERVER_CTRL_TYPE { | |
30 | SERVER_CTRL_TYPE_INIT, | |
31 | SERVER_CTRL_TYPE_RESET, | |
32 | }; | |
33 | ||
34 | struct server_ctrl_struct { | |
35 | int type; | |
36 | struct work_struct ctrl_work; | |
37 | }; | |
38 | ||
39 | static DEFINE_MUTEX(ctrl_lock); | |
40 | ||
41 | static int ___server_conf_set(int idx, char *val) | |
42 | { | |
43 | if (idx >= ARRAY_SIZE(server_conf.conf)) | |
44 | return -EINVAL; | |
45 | ||
46 | if (!val || val[0] == 0x00) | |
47 | return -EINVAL; | |
48 | ||
49 | kfree(server_conf.conf[idx]); | |
50 | server_conf.conf[idx] = kstrdup(val, GFP_KERNEL); | |
51 | if (!server_conf.conf[idx]) | |
52 | return -ENOMEM; | |
53 | return 0; | |
54 | } | |
55 | ||
56 | int ksmbd_set_netbios_name(char *v) | |
57 | { | |
58 | return ___server_conf_set(SERVER_CONF_NETBIOS_NAME, v); | |
59 | } | |
60 | ||
61 | int ksmbd_set_server_string(char *v) | |
62 | { | |
63 | return ___server_conf_set(SERVER_CONF_SERVER_STRING, v); | |
64 | } | |
65 | ||
66 | int ksmbd_set_work_group(char *v) | |
67 | { | |
68 | return ___server_conf_set(SERVER_CONF_WORK_GROUP, v); | |
69 | } | |
70 | ||
71 | char *ksmbd_netbios_name(void) | |
72 | { | |
73 | return server_conf.conf[SERVER_CONF_NETBIOS_NAME]; | |
74 | } | |
75 | ||
76 | char *ksmbd_server_string(void) | |
77 | { | |
78 | return server_conf.conf[SERVER_CONF_SERVER_STRING]; | |
79 | } | |
80 | ||
81 | char *ksmbd_work_group(void) | |
82 | { | |
83 | return server_conf.conf[SERVER_CONF_WORK_GROUP]; | |
84 | } | |
85 | ||
86 | /** | |
87 | * check_conn_state() - check state of server thread connection | |
95fa1ce9 | 88 | * @work: smb work containing server thread information |
0626e664 NJ |
89 | * |
90 | * Return: 0 on valid connection, otherwise 1 to reconnect | |
91 | */ | |
92 | static inline int check_conn_state(struct ksmbd_work *work) | |
93 | { | |
94 | struct smb_hdr *rsp_hdr; | |
95 | ||
f5c779b7 NJ |
96 | if (ksmbd_conn_exiting(work->conn) || |
97 | ksmbd_conn_need_reconnect(work->conn)) { | |
e5066499 | 98 | rsp_hdr = work->response_buf; |
0626e664 NJ |
99 | rsp_hdr->Status.CifsError = STATUS_CONNECTION_DISCONNECTED; |
100 | return 1; | |
101 | } | |
102 | return 0; | |
103 | } | |
104 | ||
67307023 NJ |
105 | #define SERVER_HANDLER_CONTINUE 0 |
106 | #define SERVER_HANDLER_ABORT 1 | |
0626e664 | 107 | |
64b39f4a | 108 | static int __process_request(struct ksmbd_work *work, struct ksmbd_conn *conn, |
fc2d1b58 | 109 | u16 *cmd) |
0626e664 NJ |
110 | { |
111 | struct smb_version_cmds *cmds; | |
fc2d1b58 | 112 | u16 command; |
0626e664 NJ |
113 | int ret; |
114 | ||
115 | if (check_conn_state(work)) | |
67307023 | 116 | return SERVER_HANDLER_CONTINUE; |
0626e664 NJ |
117 | |
118 | if (ksmbd_verify_smb_message(work)) | |
67307023 | 119 | return SERVER_HANDLER_ABORT; |
0626e664 NJ |
120 | |
121 | command = conn->ops->get_cmd_val(work); | |
122 | *cmd = command; | |
123 | ||
124 | andx_again: | |
125 | if (command >= conn->max_cmds) { | |
126 | conn->ops->set_rsp_status(work, STATUS_INVALID_PARAMETER); | |
67307023 | 127 | return SERVER_HANDLER_CONTINUE; |
0626e664 NJ |
128 | } |
129 | ||
130 | cmds = &conn->cmds[command]; | |
131 | if (!cmds->proc) { | |
132 | ksmbd_debug(SMB, "*** not implemented yet cmd = %x\n", command); | |
133 | conn->ops->set_rsp_status(work, STATUS_NOT_IMPLEMENTED); | |
67307023 | 134 | return SERVER_HANDLER_CONTINUE; |
0626e664 NJ |
135 | } |
136 | ||
137 | if (work->sess && conn->ops->is_sign_req(work, command)) { | |
138 | ret = conn->ops->check_sign_req(work); | |
139 | if (!ret) { | |
140 | conn->ops->set_rsp_status(work, STATUS_ACCESS_DENIED); | |
67307023 | 141 | return SERVER_HANDLER_CONTINUE; |
0626e664 NJ |
142 | } |
143 | } | |
144 | ||
145 | ret = cmds->proc(work); | |
146 | ||
147 | if (ret < 0) | |
148 | ksmbd_debug(CONN, "Failed to process %u [%d]\n", command, ret); | |
149 | /* AndX commands - chained request can return positive values */ | |
150 | else if (ret > 0) { | |
151 | command = ret; | |
152 | *cmd = command; | |
153 | goto andx_again; | |
154 | } | |
155 | ||
156 | if (work->send_no_response) | |
67307023 NJ |
157 | return SERVER_HANDLER_ABORT; |
158 | return SERVER_HANDLER_CONTINUE; | |
0626e664 NJ |
159 | } |
160 | ||
161 | static void __handle_ksmbd_work(struct ksmbd_work *work, | |
070fb21e | 162 | struct ksmbd_conn *conn) |
0626e664 | 163 | { |
64b39f4a | 164 | u16 command = 0; |
0626e664 NJ |
165 | int rc; |
166 | ||
167 | if (conn->ops->allocate_rsp_buf(work)) | |
168 | return; | |
169 | ||
170 | if (conn->ops->is_transform_hdr && | |
64b39f4a | 171 | conn->ops->is_transform_hdr(work->request_buf)) { |
0626e664 NJ |
172 | rc = conn->ops->decrypt_req(work); |
173 | if (rc < 0) { | |
174 | conn->ops->set_rsp_status(work, STATUS_DATA_ERROR); | |
175 | goto send; | |
176 | } | |
177 | ||
178 | work->encrypted = true; | |
179 | } | |
180 | ||
181 | rc = conn->ops->init_rsp_hdr(work); | |
182 | if (rc) { | |
183 | /* either uid or tid is not correct */ | |
184 | conn->ops->set_rsp_status(work, STATUS_INVALID_HANDLE); | |
185 | goto send; | |
186 | } | |
187 | ||
188 | if (conn->ops->check_user_session) { | |
189 | rc = conn->ops->check_user_session(work); | |
190 | if (rc < 0) { | |
191 | command = conn->ops->get_cmd_val(work); | |
192 | conn->ops->set_rsp_status(work, | |
193 | STATUS_USER_SESSION_DELETED); | |
194 | goto send; | |
195 | } else if (rc > 0) { | |
196 | rc = conn->ops->get_ksmbd_tcon(work); | |
197 | if (rc < 0) { | |
198 | conn->ops->set_rsp_status(work, | |
199 | STATUS_NETWORK_NAME_DELETED); | |
200 | goto send; | |
201 | } | |
202 | } | |
203 | } | |
204 | ||
205 | do { | |
206 | rc = __process_request(work, conn, &command); | |
67307023 | 207 | if (rc == SERVER_HANDLER_ABORT) |
0626e664 NJ |
208 | break; |
209 | ||
210 | /* | |
211 | * Call smb2_set_rsp_credits() function to set number of credits | |
212 | * granted in hdr of smb2 response. | |
213 | */ | |
214 | if (conn->ops->set_rsp_credits) { | |
215 | spin_lock(&conn->credits_lock); | |
216 | rc = conn->ops->set_rsp_credits(work); | |
217 | spin_unlock(&conn->credits_lock); | |
218 | if (rc < 0) { | |
219 | conn->ops->set_rsp_status(work, | |
220 | STATUS_INVALID_PARAMETER); | |
221 | goto send; | |
222 | } | |
223 | } | |
224 | ||
070fb21e NJ |
225 | if (work->sess && |
226 | (work->sess->sign || smb3_11_final_sess_setup_resp(work) || | |
0626e664 NJ |
227 | conn->ops->is_sign_req(work, command))) |
228 | conn->ops->set_sign_rsp(work); | |
229 | } while (is_chained_smb2_message(work)); | |
230 | ||
231 | if (work->send_no_response) | |
232 | return; | |
233 | ||
234 | send: | |
235 | smb3_preauth_hash_rsp(work); | |
236 | if (work->sess && work->sess->enc && work->encrypted && | |
64b39f4a | 237 | conn->ops->encrypt_resp) { |
0626e664 | 238 | rc = conn->ops->encrypt_resp(work); |
360c8ee6 | 239 | if (rc < 0) |
0626e664 | 240 | conn->ops->set_rsp_status(work, STATUS_DATA_ERROR); |
0626e664 NJ |
241 | } |
242 | ||
243 | ksmbd_conn_write(work); | |
244 | } | |
245 | ||
246 | /** | |
247 | * handle_ksmbd_work() - process pending smb work requests | |
95fa1ce9 | 248 | * @wk: smb work containing request command buffer |
0626e664 NJ |
249 | * |
250 | * called by kworker threads to processing remaining smb work requests | |
251 | */ | |
252 | static void handle_ksmbd_work(struct work_struct *wk) | |
253 | { | |
254 | struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work); | |
255 | struct ksmbd_conn *conn = work->conn; | |
256 | ||
257 | atomic64_inc(&conn->stats.request_served); | |
258 | ||
259 | __handle_ksmbd_work(work, conn); | |
260 | ||
261 | ksmbd_conn_try_dequeue_request(work); | |
262 | ksmbd_free_work_struct(work); | |
a14c5738 NJ |
263 | /* |
264 | * Checking waitqueue to dropping pending requests on | |
265 | * disconnection. waitqueue_active is safe because it | |
266 | * uses atomic operation for condition. | |
267 | */ | |
268 | if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q)) | |
269 | wake_up(&conn->r_count_q); | |
0626e664 NJ |
270 | } |
271 | ||
272 | /** | |
273 | * queue_ksmbd_work() - queue a smb request to worker thread queue | |
274 | * for proccessing smb command and sending response | |
275 | * @conn: connection instance | |
276 | * | |
277 | * read remaining data from socket create and submit work. | |
278 | */ | |
279 | static int queue_ksmbd_work(struct ksmbd_conn *conn) | |
280 | { | |
281 | struct ksmbd_work *work; | |
282 | ||
283 | work = ksmbd_alloc_work_struct(); | |
284 | if (!work) { | |
bde1694a | 285 | pr_err("allocation for work failed\n"); |
0626e664 NJ |
286 | return -ENOMEM; |
287 | } | |
288 | ||
289 | work->conn = conn; | |
290 | work->request_buf = conn->request_buf; | |
291 | conn->request_buf = NULL; | |
292 | ||
dc8289f9 | 293 | ksmbd_init_smb_server(work); |
0626e664 NJ |
294 | |
295 | ksmbd_conn_enqueue_request(work); | |
296 | atomic_inc(&conn->r_count); | |
297 | /* update activity on connection */ | |
298 | conn->last_active = jiffies; | |
299 | INIT_WORK(&work->work, handle_ksmbd_work); | |
300 | ksmbd_queue_work(work); | |
301 | return 0; | |
302 | } | |
303 | ||
304 | static int ksmbd_server_process_request(struct ksmbd_conn *conn) | |
305 | { | |
306 | return queue_ksmbd_work(conn); | |
307 | } | |
308 | ||
309 | static int ksmbd_server_terminate_conn(struct ksmbd_conn *conn) | |
310 | { | |
311 | ksmbd_sessions_deregister(conn); | |
312 | destroy_lease_table(conn); | |
313 | return 0; | |
314 | } | |
315 | ||
316 | static void ksmbd_server_tcp_callbacks_init(void) | |
317 | { | |
318 | struct ksmbd_conn_ops ops; | |
319 | ||
320 | ops.process_fn = ksmbd_server_process_request; | |
321 | ops.terminate_fn = ksmbd_server_terminate_conn; | |
322 | ||
323 | ksmbd_conn_init_server_callbacks(&ops); | |
324 | } | |
325 | ||
326 | static void server_conf_free(void) | |
327 | { | |
328 | int i; | |
329 | ||
330 | for (i = 0; i < ARRAY_SIZE(server_conf.conf); i++) { | |
331 | kfree(server_conf.conf[i]); | |
332 | server_conf.conf[i] = NULL; | |
333 | } | |
334 | } | |
335 | ||
336 | static int server_conf_init(void) | |
337 | { | |
338 | WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP); | |
339 | server_conf.enforced_signing = 0; | |
340 | server_conf.min_protocol = ksmbd_min_protocol(); | |
341 | server_conf.max_protocol = ksmbd_max_protocol(); | |
342 | server_conf.auth_mechs = KSMBD_AUTH_NTLMSSP; | |
343 | #ifdef CONFIG_SMB_SERVER_KERBEROS5 | |
344 | server_conf.auth_mechs |= KSMBD_AUTH_KRB5 | | |
345 | KSMBD_AUTH_MSKRB5; | |
346 | #endif | |
347 | return 0; | |
348 | } | |
349 | ||
350 | static void server_ctrl_handle_init(struct server_ctrl_struct *ctrl) | |
351 | { | |
352 | int ret; | |
353 | ||
354 | ret = ksmbd_conn_transport_init(); | |
355 | if (ret) { | |
356 | server_queue_ctrl_reset_work(); | |
357 | return; | |
358 | } | |
359 | ||
360 | WRITE_ONCE(server_conf.state, SERVER_STATE_RUNNING); | |
361 | } | |
362 | ||
363 | static void server_ctrl_handle_reset(struct server_ctrl_struct *ctrl) | |
364 | { | |
365 | ksmbd_ipc_soft_reset(); | |
366 | ksmbd_conn_transport_destroy(); | |
367 | server_conf_free(); | |
368 | server_conf_init(); | |
369 | WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP); | |
370 | } | |
371 | ||
372 | static void server_ctrl_handle_work(struct work_struct *work) | |
373 | { | |
374 | struct server_ctrl_struct *ctrl; | |
375 | ||
376 | ctrl = container_of(work, struct server_ctrl_struct, ctrl_work); | |
377 | ||
378 | mutex_lock(&ctrl_lock); | |
379 | switch (ctrl->type) { | |
380 | case SERVER_CTRL_TYPE_INIT: | |
381 | server_ctrl_handle_init(ctrl); | |
382 | break; | |
383 | case SERVER_CTRL_TYPE_RESET: | |
384 | server_ctrl_handle_reset(ctrl); | |
385 | break; | |
386 | default: | |
387 | pr_err("Unknown server work type: %d\n", ctrl->type); | |
388 | } | |
389 | mutex_unlock(&ctrl_lock); | |
390 | kfree(ctrl); | |
391 | module_put(THIS_MODULE); | |
392 | } | |
393 | ||
394 | static int __queue_ctrl_work(int type) | |
395 | { | |
396 | struct server_ctrl_struct *ctrl; | |
397 | ||
398 | ctrl = kmalloc(sizeof(struct server_ctrl_struct), GFP_KERNEL); | |
399 | if (!ctrl) | |
400 | return -ENOMEM; | |
401 | ||
402 | __module_get(THIS_MODULE); | |
403 | ctrl->type = type; | |
404 | INIT_WORK(&ctrl->ctrl_work, server_ctrl_handle_work); | |
405 | queue_work(system_long_wq, &ctrl->ctrl_work); | |
406 | return 0; | |
407 | } | |
408 | ||
409 | int server_queue_ctrl_init_work(void) | |
410 | { | |
411 | return __queue_ctrl_work(SERVER_CTRL_TYPE_INIT); | |
412 | } | |
413 | ||
414 | int server_queue_ctrl_reset_work(void) | |
415 | { | |
416 | return __queue_ctrl_work(SERVER_CTRL_TYPE_RESET); | |
417 | } | |
418 | ||
75a2d422 | 419 | static ssize_t stats_show(const struct class *class, const struct class_attribute *attr, |
070fb21e | 420 | char *buf) |
0626e664 NJ |
421 | { |
422 | /* | |
423 | * Inc this each time you change stats output format, | |
424 | * so user space will know what to do. | |
425 | */ | |
426 | static int stats_version = 2; | |
427 | static const char * const state[] = { | |
428 | "startup", | |
429 | "running", | |
430 | "reset", | |
431 | "shutdown" | |
432 | }; | |
72ee45fd | 433 | return sysfs_emit(buf, "%d %s %d %lu\n", stats_version, |
434 | state[server_conf.state], server_conf.tcp_port, | |
435 | server_conf.ipc_last_active / HZ); | |
0626e664 NJ |
436 | } |
437 | ||
75a2d422 GKH |
438 | static ssize_t kill_server_store(const struct class *class, |
439 | const struct class_attribute *attr, const char *buf, | |
070fb21e | 440 | size_t len) |
0626e664 NJ |
441 | { |
442 | if (!sysfs_streq(buf, "hard")) | |
443 | return len; | |
444 | ||
bde1694a | 445 | pr_info("kill command received\n"); |
0626e664 NJ |
446 | mutex_lock(&ctrl_lock); |
447 | WRITE_ONCE(server_conf.state, SERVER_STATE_RESETTING); | |
448 | __module_get(THIS_MODULE); | |
449 | server_ctrl_handle_reset(NULL); | |
450 | module_put(THIS_MODULE); | |
451 | mutex_unlock(&ctrl_lock); | |
452 | return len; | |
453 | } | |
454 | ||
455 | static const char * const debug_type_strings[] = {"smb", "auth", "vfs", | |
070fb21e NJ |
456 | "oplock", "ipc", "conn", |
457 | "rdma"}; | |
0626e664 | 458 | |
75a2d422 | 459 | static ssize_t debug_show(const struct class *class, const struct class_attribute *attr, |
070fb21e | 460 | char *buf) |
0626e664 NJ |
461 | { |
462 | ssize_t sz = 0; | |
463 | int i, pos = 0; | |
464 | ||
465 | for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++) { | |
466 | if ((ksmbd_debug_types >> i) & 1) { | |
72ee45fd | 467 | pos = sysfs_emit_at(buf, sz, "[%s] ", debug_type_strings[i]); |
0626e664 | 468 | } else { |
72ee45fd | 469 | pos = sysfs_emit_at(buf, sz, "%s ", debug_type_strings[i]); |
0626e664 NJ |
470 | } |
471 | sz += pos; | |
0626e664 | 472 | } |
72ee45fd | 473 | sz += sysfs_emit_at(buf, sz, "\n"); |
0626e664 NJ |
474 | return sz; |
475 | } | |
476 | ||
75a2d422 | 477 | static ssize_t debug_store(const struct class *class, const struct class_attribute *attr, |
070fb21e | 478 | const char *buf, size_t len) |
0626e664 NJ |
479 | { |
480 | int i; | |
481 | ||
482 | for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++) { | |
483 | if (sysfs_streq(buf, "all")) { | |
484 | if (ksmbd_debug_types == KSMBD_DEBUG_ALL) | |
485 | ksmbd_debug_types = 0; | |
486 | else | |
487 | ksmbd_debug_types = KSMBD_DEBUG_ALL; | |
488 | break; | |
489 | } | |
490 | ||
491 | if (sysfs_streq(buf, debug_type_strings[i])) { | |
492 | if (ksmbd_debug_types & (1 << i)) | |
493 | ksmbd_debug_types &= ~(1 << i); | |
494 | else | |
495 | ksmbd_debug_types |= (1 << i); | |
496 | break; | |
497 | } | |
498 | } | |
499 | ||
500 | return len; | |
501 | } | |
502 | ||
503 | static CLASS_ATTR_RO(stats); | |
504 | static CLASS_ATTR_WO(kill_server); | |
505 | static CLASS_ATTR_RW(debug); | |
506 | ||
507 | static struct attribute *ksmbd_control_class_attrs[] = { | |
508 | &class_attr_stats.attr, | |
509 | &class_attr_kill_server.attr, | |
510 | &class_attr_debug.attr, | |
511 | NULL, | |
512 | }; | |
513 | ATTRIBUTE_GROUPS(ksmbd_control_class); | |
514 | ||
515 | static struct class ksmbd_control_class = { | |
516 | .name = "ksmbd-control", | |
0626e664 NJ |
517 | .class_groups = ksmbd_control_class_groups, |
518 | }; | |
519 | ||
520 | static int ksmbd_server_shutdown(void) | |
521 | { | |
522 | WRITE_ONCE(server_conf.state, SERVER_STATE_SHUTTING_DOWN); | |
523 | ||
524 | class_unregister(&ksmbd_control_class); | |
525 | ksmbd_workqueue_destroy(); | |
526 | ksmbd_ipc_release(); | |
527 | ksmbd_conn_transport_destroy(); | |
0626e664 NJ |
528 | ksmbd_crypto_destroy(); |
529 | ksmbd_free_global_file_table(); | |
530 | destroy_lease_table(NULL); | |
c30f4eb8 NJ |
531 | ksmbd_work_pool_destroy(); |
532 | ksmbd_exit_file_cache(); | |
0626e664 NJ |
533 | server_conf_free(); |
534 | return 0; | |
535 | } | |
536 | ||
537 | static int __init ksmbd_server_init(void) | |
538 | { | |
539 | int ret; | |
540 | ||
541 | ret = class_register(&ksmbd_control_class); | |
542 | if (ret) { | |
bde1694a | 543 | pr_err("Unable to register ksmbd-control class\n"); |
0626e664 NJ |
544 | return ret; |
545 | } | |
546 | ||
547 | ksmbd_server_tcp_callbacks_init(); | |
548 | ||
549 | ret = server_conf_init(); | |
550 | if (ret) | |
849f59e1 | 551 | goto err_unregister; |
0626e664 | 552 | |
c30f4eb8 | 553 | ret = ksmbd_work_pool_init(); |
0626e664 | 554 | if (ret) |
849f59e1 | 555 | goto err_unregister; |
0626e664 | 556 | |
c30f4eb8 NJ |
557 | ret = ksmbd_init_file_cache(); |
558 | if (ret) | |
559 | goto err_destroy_work_pools; | |
560 | ||
0626e664 NJ |
561 | ret = ksmbd_ipc_init(); |
562 | if (ret) | |
c30f4eb8 | 563 | goto err_exit_file_cache; |
0626e664 NJ |
564 | |
565 | ret = ksmbd_init_global_file_table(); | |
566 | if (ret) | |
849f59e1 | 567 | goto err_ipc_release; |
0626e664 NJ |
568 | |
569 | ret = ksmbd_inode_hash_init(); | |
570 | if (ret) | |
849f59e1 | 571 | goto err_destroy_file_table; |
0626e664 NJ |
572 | |
573 | ret = ksmbd_crypto_create(); | |
574 | if (ret) | |
849f59e1 | 575 | goto err_release_inode_hash; |
0626e664 NJ |
576 | |
577 | ret = ksmbd_workqueue_init(); | |
578 | if (ret) | |
849f59e1 | 579 | goto err_crypto_destroy; |
e44fd508 | 580 | |
adc32821 | 581 | pr_warn_once("The ksmbd server is experimental\n"); |
e44fd508 | 582 | |
0626e664 NJ |
583 | return 0; |
584 | ||
849f59e1 DC |
585 | err_crypto_destroy: |
586 | ksmbd_crypto_destroy(); | |
587 | err_release_inode_hash: | |
588 | ksmbd_release_inode_hash(); | |
589 | err_destroy_file_table: | |
590 | ksmbd_free_global_file_table(); | |
591 | err_ipc_release: | |
592 | ksmbd_ipc_release(); | |
c30f4eb8 NJ |
593 | err_exit_file_cache: |
594 | ksmbd_exit_file_cache(); | |
595 | err_destroy_work_pools: | |
596 | ksmbd_work_pool_destroy(); | |
849f59e1 DC |
597 | err_unregister: |
598 | class_unregister(&ksmbd_control_class); | |
599 | ||
0626e664 NJ |
600 | return ret; |
601 | } | |
602 | ||
603 | /** | |
95fa1ce9 | 604 | * ksmbd_server_exit() - shutdown forker thread and free memory at module exit |
0626e664 NJ |
605 | */ |
606 | static void __exit ksmbd_server_exit(void) | |
607 | { | |
608 | ksmbd_server_shutdown(); | |
eb307d09 | 609 | rcu_barrier(); |
0626e664 NJ |
610 | ksmbd_release_inode_hash(); |
611 | } | |
612 | ||
613 | MODULE_AUTHOR("Namjae Jeon <linkinjeon@kernel.org>"); | |
614 | MODULE_VERSION(KSMBD_VERSION); | |
615 | MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER"); | |
616 | MODULE_LICENSE("GPL"); | |
0626e664 NJ |
617 | MODULE_SOFTDEP("pre: ecb"); |
618 | MODULE_SOFTDEP("pre: hmac"); | |
0626e664 NJ |
619 | MODULE_SOFTDEP("pre: md5"); |
620 | MODULE_SOFTDEP("pre: nls"); | |
621 | MODULE_SOFTDEP("pre: aes"); | |
622 | MODULE_SOFTDEP("pre: cmac"); | |
623 | MODULE_SOFTDEP("pre: sha256"); | |
624 | MODULE_SOFTDEP("pre: sha512"); | |
625 | MODULE_SOFTDEP("pre: aead2"); | |
626 | MODULE_SOFTDEP("pre: ccm"); | |
627 | MODULE_SOFTDEP("pre: gcm"); | |
5d2f0b10 | 628 | MODULE_SOFTDEP("pre: crc32"); |
0626e664 NJ |
629 | module_init(ksmbd_server_init) |
630 | module_exit(ksmbd_server_exit) |