]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - fs/cifsd/mgmt/share_config.c
cifsd: remove wrappers of kvmalloc/kvfree
[mirror_ubuntu-jammy-kernel.git] / fs / cifsd / mgmt / share_config.c
CommitLineData
e2f34481
NJ
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2018 Samsung Electronics Co., Ltd.
4 */
5
6#include <linux/list.h>
7#include <linux/jhash.h>
8#include <linux/slab.h>
9#include <linux/rwsem.h>
10#include <linux/parser.h>
11#include <linux/namei.h>
12#include <linux/sched.h>
79f6b11a 13#include <linux/mm.h>
e2f34481
NJ
14
15#include "share_config.h"
16#include "user_config.h"
17#include "user_session.h"
18#include "../buffer_pool.h"
19#include "../transport_ipc.h"
e2f34481
NJ
20
21#define SHARE_HASH_BITS 3
22static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS);
23static DECLARE_RWSEM(shares_table_lock);
24
25struct ksmbd_veto_pattern {
26 char *pattern;
27 struct list_head list;
28};
29
30static unsigned int share_name_hash(char *name)
31{
32 return jhash(name, strlen(name), 0);
33}
34
35static void kill_share(struct ksmbd_share_config *share)
36{
37 while (!list_empty(&share->veto_list)) {
38 struct ksmbd_veto_pattern *p;
39
40 p = list_entry(share->veto_list.next,
41 struct ksmbd_veto_pattern,
42 list);
43 list_del(&p->list);
44 kfree(p->pattern);
45 kfree(p);
46 }
47
48 if (share->path)
49 path_put(&share->vfs_path);
50 kfree(share->name);
51 kfree(share->path);
52 kfree(share);
53}
54
55void __ksmbd_share_config_put(struct ksmbd_share_config *share)
56{
57 down_write(&shares_table_lock);
58 hash_del(&share->hlist);
59 up_write(&shares_table_lock);
60
61 kill_share(share);
62}
63
64static struct ksmbd_share_config *
65__get_share_config(struct ksmbd_share_config *share)
66{
67 if (!atomic_inc_not_zero(&share->refcount))
68 return NULL;
69 return share;
70}
71
72static struct ksmbd_share_config *__share_lookup(char *name)
73{
74 struct ksmbd_share_config *share;
75 unsigned int key = share_name_hash(name);
76
77 hash_for_each_possible(shares_table, share, hlist, key) {
78 if (!strcmp(name, share->name))
79 return share;
80 }
81 return NULL;
82}
83
84static int parse_veto_list(struct ksmbd_share_config *share,
85 char *veto_list,
86 int veto_list_sz)
87{
88 int sz = 0;
89
90 if (!veto_list_sz)
91 return 0;
92
93 while (veto_list_sz > 0) {
94 struct ksmbd_veto_pattern *p;
95
e2f34481
NJ
96 sz = strlen(veto_list);
97 if (!sz)
98 break;
99
c250e8f5
MUA
100 p = kzalloc(sizeof(struct ksmbd_veto_pattern), GFP_KERNEL);
101 if (!p)
102 return -ENOMEM;
103
e2f34481
NJ
104 p->pattern = kstrdup(veto_list, GFP_KERNEL);
105 if (!p->pattern) {
822bc8ea 106 kfree(p);
e2f34481
NJ
107 return -ENOMEM;
108 }
109
110 list_add(&p->list, &share->veto_list);
111
112 veto_list += sz + 1;
113 veto_list_sz -= (sz + 1);
114 }
115
116 return 0;
117}
118
119static struct ksmbd_share_config *share_config_request(char *name)
120{
121 struct ksmbd_share_config_response *resp;
122 struct ksmbd_share_config *share = NULL;
123 struct ksmbd_share_config *lookup;
124 int ret;
125
126 resp = ksmbd_ipc_share_config_request(name);
127 if (!resp)
128 return NULL;
129
130 if (resp->flags == KSMBD_SHARE_FLAG_INVALID)
131 goto out;
132
20ea7fd2 133 share = kzalloc(sizeof(struct ksmbd_share_config), GFP_KERNEL);
e2f34481
NJ
134 if (!share)
135 goto out;
136
137 share->flags = resp->flags;
138 atomic_set(&share->refcount, 1);
139 INIT_LIST_HEAD(&share->veto_list);
140 share->name = kstrdup(name, GFP_KERNEL);
141
142 if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
143 share->path = kstrdup(KSMBD_SHARE_CONFIG_PATH(resp),
144 GFP_KERNEL);
145 if (share->path)
146 share->path_sz = strlen(share->path);
147 share->create_mask = resp->create_mask;
148 share->directory_mask = resp->directory_mask;
149 share->force_create_mode = resp->force_create_mode;
150 share->force_directory_mode = resp->force_directory_mode;
151 share->force_uid = resp->force_uid;
152 share->force_gid = resp->force_gid;
153 ret = parse_veto_list(share,
154 KSMBD_SHARE_CONFIG_VETO_LIST(resp),
155 resp->veto_list_sz);
156 if (!ret && share->path) {
157 ret = kern_path(share->path, 0, &share->vfs_path);
158 if (ret) {
159 ksmbd_debug(SMB, "failed to access '%s'\n",
160 share->path);
161 /* Avoid put_path() */
162 kfree(share->path);
163 share->path = NULL;
164 }
165 }
166 if (ret || !share->name) {
167 kill_share(share);
168 share = NULL;
169 goto out;
170 }
171 }
172
173 down_write(&shares_table_lock);
174 lookup = __share_lookup(name);
175 if (lookup)
176 lookup = __get_share_config(lookup);
177 if (!lookup) {
178 hash_add(shares_table, &share->hlist, share_name_hash(name));
179 } else {
180 kill_share(share);
181 share = lookup;
182 }
183 up_write(&shares_table_lock);
184
185out:
79f6b11a 186 kvfree(resp);
e2f34481
NJ
187 return share;
188}
189
190static void strtolower(char *share_name)
191{
192 while (*share_name) {
193 *share_name = tolower(*share_name);
194 share_name++;
195 }
196}
197
198struct ksmbd_share_config *ksmbd_share_config_get(char *name)
199{
200 struct ksmbd_share_config *share;
201
202 strtolower(name);
203
204 down_read(&shares_table_lock);
205 share = __share_lookup(name);
206 if (share)
207 share = __get_share_config(share);
208 up_read(&shares_table_lock);
209
210 if (share)
211 return share;
212 return share_config_request(name);
213}
214
215bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
216 const char *filename)
217{
218 struct ksmbd_veto_pattern *p;
219
220 list_for_each_entry(p, &share->veto_list, list) {
221 if (match_wildcard(p->pattern, filename))
222 return true;
223 }
224 return false;
225}
226
227void ksmbd_share_configs_cleanup(void)
228{
229 struct ksmbd_share_config *share;
230 struct hlist_node *tmp;
231 int i;
232
233 down_write(&shares_table_lock);
234 hash_for_each_safe(shares_table, i, tmp, share, hlist) {
235 hash_del(&share->hlist);
236 kill_share(share);
237 }
238 up_write(&shares_table_lock);
239}