Commit 8f0d97b41523fb85a2d230f6794121e5834f0cf9
Committed by
Trond Myklebust
1 parent
015f0212d5
Exists in
master
and in
7 other branches
nfs: testing the wrong variable
The intent was to test "*desc" for allocation failures, but it tests "desc" which is always a valid pointer here. Signed-off-by: Dan Carpenter <error27@gmail.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Showing 1 changed file with 1 additions and 1 deletions Inline Diff
fs/nfs/idmap.c
1 | /* | 1 | /* |
2 | * fs/nfs/idmap.c | 2 | * fs/nfs/idmap.c |
3 | * | 3 | * |
4 | * UID and GID to name mapping for clients. | 4 | * UID and GID to name mapping for clients. |
5 | * | 5 | * |
6 | * Copyright (c) 2002 The Regents of the University of Michigan. | 6 | * Copyright (c) 2002 The Regents of the University of Michigan. |
7 | * All rights reserved. | 7 | * All rights reserved. |
8 | * | 8 | * |
9 | * Marius Aamodt Eriksen <marius@umich.edu> | 9 | * Marius Aamodt Eriksen <marius@umich.edu> |
10 | * | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | 13 | * are met: |
14 | * | 14 | * |
15 | * 1. Redistributions of source code must retain the above copyright | 15 | * 1. Redistributions of source code must retain the above copyright |
16 | * notice, this list of conditions and the following disclaimer. | 16 | * notice, this list of conditions and the following disclaimer. |
17 | * 2. Redistributions in binary form must reproduce the above copyright | 17 | * 2. Redistributions in binary form must reproduce the above copyright |
18 | * notice, this list of conditions and the following disclaimer in the | 18 | * notice, this list of conditions and the following disclaimer in the |
19 | * documentation and/or other materials provided with the distribution. | 19 | * documentation and/or other materials provided with the distribution. |
20 | * 3. Neither the name of the University nor the names of its | 20 | * 3. Neither the name of the University nor the names of its |
21 | * contributors may be used to endorse or promote products derived | 21 | * contributors may be used to endorse or promote products derived |
22 | * from this software without specific prior written permission. | 22 | * from this software without specific prior written permission. |
23 | * | 23 | * |
24 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | 24 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
25 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 25 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
26 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 26 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
27 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 27 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | 30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
31 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | 31 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
32 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | 32 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
33 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 33 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
34 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #ifdef CONFIG_NFS_USE_NEW_IDMAPPER | 37 | #ifdef CONFIG_NFS_USE_NEW_IDMAPPER |
38 | 38 | ||
39 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
40 | #include <linux/cred.h> | 40 | #include <linux/cred.h> |
41 | #include <linux/nfs_idmap.h> | 41 | #include <linux/nfs_idmap.h> |
42 | #include <linux/keyctl.h> | 42 | #include <linux/keyctl.h> |
43 | #include <linux/key-type.h> | 43 | #include <linux/key-type.h> |
44 | #include <linux/rcupdate.h> | 44 | #include <linux/rcupdate.h> |
45 | #include <linux/kernel.h> | 45 | #include <linux/kernel.h> |
46 | #include <linux/err.h> | 46 | #include <linux/err.h> |
47 | 47 | ||
48 | #include <keys/user-type.h> | 48 | #include <keys/user-type.h> |
49 | 49 | ||
50 | #define NFS_UINT_MAXLEN 11 | 50 | #define NFS_UINT_MAXLEN 11 |
51 | 51 | ||
52 | const struct cred *id_resolver_cache; | 52 | const struct cred *id_resolver_cache; |
53 | 53 | ||
54 | struct key_type key_type_id_resolver = { | 54 | struct key_type key_type_id_resolver = { |
55 | .name = "id_resolver", | 55 | .name = "id_resolver", |
56 | .instantiate = user_instantiate, | 56 | .instantiate = user_instantiate, |
57 | .match = user_match, | 57 | .match = user_match, |
58 | .revoke = user_revoke, | 58 | .revoke = user_revoke, |
59 | .destroy = user_destroy, | 59 | .destroy = user_destroy, |
60 | .describe = user_describe, | 60 | .describe = user_describe, |
61 | .read = user_read, | 61 | .read = user_read, |
62 | }; | 62 | }; |
63 | 63 | ||
64 | int nfs_idmap_init(void) | 64 | int nfs_idmap_init(void) |
65 | { | 65 | { |
66 | struct cred *cred; | 66 | struct cred *cred; |
67 | struct key *keyring; | 67 | struct key *keyring; |
68 | int ret = 0; | 68 | int ret = 0; |
69 | 69 | ||
70 | printk(KERN_NOTICE "Registering the %s key type\n", key_type_id_resolver.name); | 70 | printk(KERN_NOTICE "Registering the %s key type\n", key_type_id_resolver.name); |
71 | 71 | ||
72 | cred = prepare_kernel_cred(NULL); | 72 | cred = prepare_kernel_cred(NULL); |
73 | if (!cred) | 73 | if (!cred) |
74 | return -ENOMEM; | 74 | return -ENOMEM; |
75 | 75 | ||
76 | keyring = key_alloc(&key_type_keyring, ".id_resolver", 0, 0, cred, | 76 | keyring = key_alloc(&key_type_keyring, ".id_resolver", 0, 0, cred, |
77 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | 77 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | |
78 | KEY_USR_VIEW | KEY_USR_READ, | 78 | KEY_USR_VIEW | KEY_USR_READ, |
79 | KEY_ALLOC_NOT_IN_QUOTA); | 79 | KEY_ALLOC_NOT_IN_QUOTA); |
80 | if (IS_ERR(keyring)) { | 80 | if (IS_ERR(keyring)) { |
81 | ret = PTR_ERR(keyring); | 81 | ret = PTR_ERR(keyring); |
82 | goto failed_put_cred; | 82 | goto failed_put_cred; |
83 | } | 83 | } |
84 | 84 | ||
85 | ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); | 85 | ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); |
86 | if (ret < 0) | 86 | if (ret < 0) |
87 | goto failed_put_key; | 87 | goto failed_put_key; |
88 | 88 | ||
89 | ret = register_key_type(&key_type_id_resolver); | 89 | ret = register_key_type(&key_type_id_resolver); |
90 | if (ret < 0) | 90 | if (ret < 0) |
91 | goto failed_put_key; | 91 | goto failed_put_key; |
92 | 92 | ||
93 | cred->thread_keyring = keyring; | 93 | cred->thread_keyring = keyring; |
94 | cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; | 94 | cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; |
95 | id_resolver_cache = cred; | 95 | id_resolver_cache = cred; |
96 | return 0; | 96 | return 0; |
97 | 97 | ||
98 | failed_put_key: | 98 | failed_put_key: |
99 | key_put(keyring); | 99 | key_put(keyring); |
100 | failed_put_cred: | 100 | failed_put_cred: |
101 | put_cred(cred); | 101 | put_cred(cred); |
102 | return ret; | 102 | return ret; |
103 | } | 103 | } |
104 | 104 | ||
105 | void nfs_idmap_quit(void) | 105 | void nfs_idmap_quit(void) |
106 | { | 106 | { |
107 | key_revoke(id_resolver_cache->thread_keyring); | 107 | key_revoke(id_resolver_cache->thread_keyring); |
108 | unregister_key_type(&key_type_id_resolver); | 108 | unregister_key_type(&key_type_id_resolver); |
109 | put_cred(id_resolver_cache); | 109 | put_cred(id_resolver_cache); |
110 | } | 110 | } |
111 | 111 | ||
112 | /* | 112 | /* |
113 | * Assemble the description to pass to request_key() | 113 | * Assemble the description to pass to request_key() |
114 | * This function will allocate a new string and update dest to point | 114 | * This function will allocate a new string and update dest to point |
115 | * at it. The caller is responsible for freeing dest. | 115 | * at it. The caller is responsible for freeing dest. |
116 | * | 116 | * |
117 | * On error 0 is returned. Otherwise, the length of dest is returned. | 117 | * On error 0 is returned. Otherwise, the length of dest is returned. |
118 | */ | 118 | */ |
119 | static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen, | 119 | static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen, |
120 | const char *type, size_t typelen, char **desc) | 120 | const char *type, size_t typelen, char **desc) |
121 | { | 121 | { |
122 | char *cp; | 122 | char *cp; |
123 | size_t desclen = typelen + namelen + 2; | 123 | size_t desclen = typelen + namelen + 2; |
124 | 124 | ||
125 | *desc = kmalloc(desclen, GFP_KERNEL); | 125 | *desc = kmalloc(desclen, GFP_KERNEL); |
126 | if (!desc) | 126 | if (!*desc) |
127 | return -ENOMEM; | 127 | return -ENOMEM; |
128 | 128 | ||
129 | cp = *desc; | 129 | cp = *desc; |
130 | memcpy(cp, type, typelen); | 130 | memcpy(cp, type, typelen); |
131 | cp += typelen; | 131 | cp += typelen; |
132 | *cp++ = ':'; | 132 | *cp++ = ':'; |
133 | 133 | ||
134 | memcpy(cp, name, namelen); | 134 | memcpy(cp, name, namelen); |
135 | cp += namelen; | 135 | cp += namelen; |
136 | *cp = '\0'; | 136 | *cp = '\0'; |
137 | return desclen; | 137 | return desclen; |
138 | } | 138 | } |
139 | 139 | ||
140 | static ssize_t nfs_idmap_request_key(const char *name, size_t namelen, | 140 | static ssize_t nfs_idmap_request_key(const char *name, size_t namelen, |
141 | const char *type, void *data, size_t data_size) | 141 | const char *type, void *data, size_t data_size) |
142 | { | 142 | { |
143 | const struct cred *saved_cred; | 143 | const struct cred *saved_cred; |
144 | struct key *rkey; | 144 | struct key *rkey; |
145 | char *desc; | 145 | char *desc; |
146 | struct user_key_payload *payload; | 146 | struct user_key_payload *payload; |
147 | ssize_t ret; | 147 | ssize_t ret; |
148 | 148 | ||
149 | ret = nfs_idmap_get_desc(name, namelen, type, strlen(type), &desc); | 149 | ret = nfs_idmap_get_desc(name, namelen, type, strlen(type), &desc); |
150 | if (ret <= 0) | 150 | if (ret <= 0) |
151 | goto out; | 151 | goto out; |
152 | 152 | ||
153 | saved_cred = override_creds(id_resolver_cache); | 153 | saved_cred = override_creds(id_resolver_cache); |
154 | rkey = request_key(&key_type_id_resolver, desc, ""); | 154 | rkey = request_key(&key_type_id_resolver, desc, ""); |
155 | revert_creds(saved_cred); | 155 | revert_creds(saved_cred); |
156 | kfree(desc); | 156 | kfree(desc); |
157 | if (IS_ERR(rkey)) { | 157 | if (IS_ERR(rkey)) { |
158 | ret = PTR_ERR(rkey); | 158 | ret = PTR_ERR(rkey); |
159 | goto out; | 159 | goto out; |
160 | } | 160 | } |
161 | 161 | ||
162 | rcu_read_lock(); | 162 | rcu_read_lock(); |
163 | rkey->perm |= KEY_USR_VIEW; | 163 | rkey->perm |= KEY_USR_VIEW; |
164 | 164 | ||
165 | ret = key_validate(rkey); | 165 | ret = key_validate(rkey); |
166 | if (ret < 0) | 166 | if (ret < 0) |
167 | goto out_up; | 167 | goto out_up; |
168 | 168 | ||
169 | payload = rcu_dereference(rkey->payload.data); | 169 | payload = rcu_dereference(rkey->payload.data); |
170 | if (IS_ERR_OR_NULL(payload)) { | 170 | if (IS_ERR_OR_NULL(payload)) { |
171 | ret = PTR_ERR(payload); | 171 | ret = PTR_ERR(payload); |
172 | goto out_up; | 172 | goto out_up; |
173 | } | 173 | } |
174 | 174 | ||
175 | ret = payload->datalen; | 175 | ret = payload->datalen; |
176 | if (ret > 0 && ret <= data_size) | 176 | if (ret > 0 && ret <= data_size) |
177 | memcpy(data, payload->data, ret); | 177 | memcpy(data, payload->data, ret); |
178 | else | 178 | else |
179 | ret = -EINVAL; | 179 | ret = -EINVAL; |
180 | 180 | ||
181 | out_up: | 181 | out_up: |
182 | rcu_read_unlock(); | 182 | rcu_read_unlock(); |
183 | key_put(rkey); | 183 | key_put(rkey); |
184 | out: | 184 | out: |
185 | return ret; | 185 | return ret; |
186 | } | 186 | } |
187 | 187 | ||
188 | 188 | ||
189 | /* ID -> Name */ | 189 | /* ID -> Name */ |
190 | static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, size_t buflen) | 190 | static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, size_t buflen) |
191 | { | 191 | { |
192 | char id_str[NFS_UINT_MAXLEN]; | 192 | char id_str[NFS_UINT_MAXLEN]; |
193 | int id_len; | 193 | int id_len; |
194 | ssize_t ret; | 194 | ssize_t ret; |
195 | 195 | ||
196 | id_len = snprintf(id_str, sizeof(id_str), "%u", id); | 196 | id_len = snprintf(id_str, sizeof(id_str), "%u", id); |
197 | ret = nfs_idmap_request_key(id_str, id_len, type, buf, buflen); | 197 | ret = nfs_idmap_request_key(id_str, id_len, type, buf, buflen); |
198 | if (ret < 0) | 198 | if (ret < 0) |
199 | return -EINVAL; | 199 | return -EINVAL; |
200 | return ret; | 200 | return ret; |
201 | } | 201 | } |
202 | 202 | ||
203 | /* Name -> ID */ | 203 | /* Name -> ID */ |
204 | static int nfs_idmap_lookup_id(const char *name, size_t namelen, | 204 | static int nfs_idmap_lookup_id(const char *name, size_t namelen, |
205 | const char *type, __u32 *id) | 205 | const char *type, __u32 *id) |
206 | { | 206 | { |
207 | char id_str[NFS_UINT_MAXLEN]; | 207 | char id_str[NFS_UINT_MAXLEN]; |
208 | long id_long; | 208 | long id_long; |
209 | ssize_t data_size; | 209 | ssize_t data_size; |
210 | int ret = 0; | 210 | int ret = 0; |
211 | 211 | ||
212 | data_size = nfs_idmap_request_key(name, namelen, type, id_str, NFS_UINT_MAXLEN); | 212 | data_size = nfs_idmap_request_key(name, namelen, type, id_str, NFS_UINT_MAXLEN); |
213 | if (data_size <= 0) { | 213 | if (data_size <= 0) { |
214 | ret = -EINVAL; | 214 | ret = -EINVAL; |
215 | } else { | 215 | } else { |
216 | ret = strict_strtol(id_str, 10, &id_long); | 216 | ret = strict_strtol(id_str, 10, &id_long); |
217 | *id = (__u32)id_long; | 217 | *id = (__u32)id_long; |
218 | } | 218 | } |
219 | return ret; | 219 | return ret; |
220 | } | 220 | } |
221 | 221 | ||
222 | int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) | 222 | int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) |
223 | { | 223 | { |
224 | return nfs_idmap_lookup_id(name, namelen, "uid", uid); | 224 | return nfs_idmap_lookup_id(name, namelen, "uid", uid); |
225 | } | 225 | } |
226 | 226 | ||
227 | int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *gid) | 227 | int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *gid) |
228 | { | 228 | { |
229 | return nfs_idmap_lookup_id(name, namelen, "gid", gid); | 229 | return nfs_idmap_lookup_id(name, namelen, "gid", gid); |
230 | } | 230 | } |
231 | 231 | ||
232 | int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen) | 232 | int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen) |
233 | { | 233 | { |
234 | return nfs_idmap_lookup_name(uid, "user", buf, buflen); | 234 | return nfs_idmap_lookup_name(uid, "user", buf, buflen); |
235 | } | 235 | } |
236 | int nfs_map_gid_to_group(struct nfs_client *clp, __u32 gid, char *buf, size_t buflen) | 236 | int nfs_map_gid_to_group(struct nfs_client *clp, __u32 gid, char *buf, size_t buflen) |
237 | { | 237 | { |
238 | return nfs_idmap_lookup_name(gid, "group", buf, buflen); | 238 | return nfs_idmap_lookup_name(gid, "group", buf, buflen); |
239 | } | 239 | } |
240 | 240 | ||
241 | #else /* CONFIG_NFS_USE_IDMAPPER not defined */ | 241 | #else /* CONFIG_NFS_USE_IDMAPPER not defined */ |
242 | 242 | ||
243 | #include <linux/module.h> | 243 | #include <linux/module.h> |
244 | #include <linux/mutex.h> | 244 | #include <linux/mutex.h> |
245 | #include <linux/init.h> | 245 | #include <linux/init.h> |
246 | #include <linux/types.h> | 246 | #include <linux/types.h> |
247 | #include <linux/slab.h> | 247 | #include <linux/slab.h> |
248 | #include <linux/socket.h> | 248 | #include <linux/socket.h> |
249 | #include <linux/in.h> | 249 | #include <linux/in.h> |
250 | #include <linux/sched.h> | 250 | #include <linux/sched.h> |
251 | 251 | ||
252 | #include <linux/sunrpc/clnt.h> | 252 | #include <linux/sunrpc/clnt.h> |
253 | #include <linux/workqueue.h> | 253 | #include <linux/workqueue.h> |
254 | #include <linux/sunrpc/rpc_pipe_fs.h> | 254 | #include <linux/sunrpc/rpc_pipe_fs.h> |
255 | 255 | ||
256 | #include <linux/nfs_fs.h> | 256 | #include <linux/nfs_fs.h> |
257 | 257 | ||
258 | #include <linux/nfs_idmap.h> | 258 | #include <linux/nfs_idmap.h> |
259 | #include "nfs4_fs.h" | 259 | #include "nfs4_fs.h" |
260 | 260 | ||
261 | #define IDMAP_HASH_SZ 128 | 261 | #define IDMAP_HASH_SZ 128 |
262 | 262 | ||
263 | /* Default cache timeout is 10 minutes */ | 263 | /* Default cache timeout is 10 minutes */ |
264 | unsigned int nfs_idmap_cache_timeout = 600 * HZ; | 264 | unsigned int nfs_idmap_cache_timeout = 600 * HZ; |
265 | 265 | ||
266 | static int param_set_idmap_timeout(const char *val, struct kernel_param *kp) | 266 | static int param_set_idmap_timeout(const char *val, struct kernel_param *kp) |
267 | { | 267 | { |
268 | char *endp; | 268 | char *endp; |
269 | int num = simple_strtol(val, &endp, 0); | 269 | int num = simple_strtol(val, &endp, 0); |
270 | int jif = num * HZ; | 270 | int jif = num * HZ; |
271 | if (endp == val || *endp || num < 0 || jif < num) | 271 | if (endp == val || *endp || num < 0 || jif < num) |
272 | return -EINVAL; | 272 | return -EINVAL; |
273 | *((int *)kp->arg) = jif; | 273 | *((int *)kp->arg) = jif; |
274 | return 0; | 274 | return 0; |
275 | } | 275 | } |
276 | 276 | ||
277 | module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int, | 277 | module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int, |
278 | &nfs_idmap_cache_timeout, 0644); | 278 | &nfs_idmap_cache_timeout, 0644); |
279 | 279 | ||
280 | struct idmap_hashent { | 280 | struct idmap_hashent { |
281 | unsigned long ih_expires; | 281 | unsigned long ih_expires; |
282 | __u32 ih_id; | 282 | __u32 ih_id; |
283 | size_t ih_namelen; | 283 | size_t ih_namelen; |
284 | char ih_name[IDMAP_NAMESZ]; | 284 | char ih_name[IDMAP_NAMESZ]; |
285 | }; | 285 | }; |
286 | 286 | ||
287 | struct idmap_hashtable { | 287 | struct idmap_hashtable { |
288 | __u8 h_type; | 288 | __u8 h_type; |
289 | struct idmap_hashent h_entries[IDMAP_HASH_SZ]; | 289 | struct idmap_hashent h_entries[IDMAP_HASH_SZ]; |
290 | }; | 290 | }; |
291 | 291 | ||
292 | struct idmap { | 292 | struct idmap { |
293 | struct dentry *idmap_dentry; | 293 | struct dentry *idmap_dentry; |
294 | wait_queue_head_t idmap_wq; | 294 | wait_queue_head_t idmap_wq; |
295 | struct idmap_msg idmap_im; | 295 | struct idmap_msg idmap_im; |
296 | struct mutex idmap_lock; /* Serializes upcalls */ | 296 | struct mutex idmap_lock; /* Serializes upcalls */ |
297 | struct mutex idmap_im_lock; /* Protects the hashtable */ | 297 | struct mutex idmap_im_lock; /* Protects the hashtable */ |
298 | struct idmap_hashtable idmap_user_hash; | 298 | struct idmap_hashtable idmap_user_hash; |
299 | struct idmap_hashtable idmap_group_hash; | 299 | struct idmap_hashtable idmap_group_hash; |
300 | }; | 300 | }; |
301 | 301 | ||
302 | static ssize_t idmap_pipe_upcall(struct file *, struct rpc_pipe_msg *, | 302 | static ssize_t idmap_pipe_upcall(struct file *, struct rpc_pipe_msg *, |
303 | char __user *, size_t); | 303 | char __user *, size_t); |
304 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, | 304 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, |
305 | size_t); | 305 | size_t); |
306 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); | 306 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); |
307 | 307 | ||
308 | static unsigned int fnvhash32(const void *, size_t); | 308 | static unsigned int fnvhash32(const void *, size_t); |
309 | 309 | ||
310 | static const struct rpc_pipe_ops idmap_upcall_ops = { | 310 | static const struct rpc_pipe_ops idmap_upcall_ops = { |
311 | .upcall = idmap_pipe_upcall, | 311 | .upcall = idmap_pipe_upcall, |
312 | .downcall = idmap_pipe_downcall, | 312 | .downcall = idmap_pipe_downcall, |
313 | .destroy_msg = idmap_pipe_destroy_msg, | 313 | .destroy_msg = idmap_pipe_destroy_msg, |
314 | }; | 314 | }; |
315 | 315 | ||
316 | int | 316 | int |
317 | nfs_idmap_new(struct nfs_client *clp) | 317 | nfs_idmap_new(struct nfs_client *clp) |
318 | { | 318 | { |
319 | struct idmap *idmap; | 319 | struct idmap *idmap; |
320 | int error; | 320 | int error; |
321 | 321 | ||
322 | BUG_ON(clp->cl_idmap != NULL); | 322 | BUG_ON(clp->cl_idmap != NULL); |
323 | 323 | ||
324 | idmap = kzalloc(sizeof(*idmap), GFP_KERNEL); | 324 | idmap = kzalloc(sizeof(*idmap), GFP_KERNEL); |
325 | if (idmap == NULL) | 325 | if (idmap == NULL) |
326 | return -ENOMEM; | 326 | return -ENOMEM; |
327 | 327 | ||
328 | idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry, | 328 | idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry, |
329 | "idmap", idmap, &idmap_upcall_ops, 0); | 329 | "idmap", idmap, &idmap_upcall_ops, 0); |
330 | if (IS_ERR(idmap->idmap_dentry)) { | 330 | if (IS_ERR(idmap->idmap_dentry)) { |
331 | error = PTR_ERR(idmap->idmap_dentry); | 331 | error = PTR_ERR(idmap->idmap_dentry); |
332 | kfree(idmap); | 332 | kfree(idmap); |
333 | return error; | 333 | return error; |
334 | } | 334 | } |
335 | 335 | ||
336 | mutex_init(&idmap->idmap_lock); | 336 | mutex_init(&idmap->idmap_lock); |
337 | mutex_init(&idmap->idmap_im_lock); | 337 | mutex_init(&idmap->idmap_im_lock); |
338 | init_waitqueue_head(&idmap->idmap_wq); | 338 | init_waitqueue_head(&idmap->idmap_wq); |
339 | idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER; | 339 | idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER; |
340 | idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; | 340 | idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; |
341 | 341 | ||
342 | clp->cl_idmap = idmap; | 342 | clp->cl_idmap = idmap; |
343 | return 0; | 343 | return 0; |
344 | } | 344 | } |
345 | 345 | ||
346 | void | 346 | void |
347 | nfs_idmap_delete(struct nfs_client *clp) | 347 | nfs_idmap_delete(struct nfs_client *clp) |
348 | { | 348 | { |
349 | struct idmap *idmap = clp->cl_idmap; | 349 | struct idmap *idmap = clp->cl_idmap; |
350 | 350 | ||
351 | if (!idmap) | 351 | if (!idmap) |
352 | return; | 352 | return; |
353 | rpc_unlink(idmap->idmap_dentry); | 353 | rpc_unlink(idmap->idmap_dentry); |
354 | clp->cl_idmap = NULL; | 354 | clp->cl_idmap = NULL; |
355 | kfree(idmap); | 355 | kfree(idmap); |
356 | } | 356 | } |
357 | 357 | ||
358 | /* | 358 | /* |
359 | * Helper routines for manipulating the hashtable | 359 | * Helper routines for manipulating the hashtable |
360 | */ | 360 | */ |
361 | static inline struct idmap_hashent * | 361 | static inline struct idmap_hashent * |
362 | idmap_name_hash(struct idmap_hashtable* h, const char *name, size_t len) | 362 | idmap_name_hash(struct idmap_hashtable* h, const char *name, size_t len) |
363 | { | 363 | { |
364 | return &h->h_entries[fnvhash32(name, len) % IDMAP_HASH_SZ]; | 364 | return &h->h_entries[fnvhash32(name, len) % IDMAP_HASH_SZ]; |
365 | } | 365 | } |
366 | 366 | ||
367 | static struct idmap_hashent * | 367 | static struct idmap_hashent * |
368 | idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len) | 368 | idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len) |
369 | { | 369 | { |
370 | struct idmap_hashent *he = idmap_name_hash(h, name, len); | 370 | struct idmap_hashent *he = idmap_name_hash(h, name, len); |
371 | 371 | ||
372 | if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0) | 372 | if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0) |
373 | return NULL; | 373 | return NULL; |
374 | if (time_after(jiffies, he->ih_expires)) | 374 | if (time_after(jiffies, he->ih_expires)) |
375 | return NULL; | 375 | return NULL; |
376 | return he; | 376 | return he; |
377 | } | 377 | } |
378 | 378 | ||
379 | static inline struct idmap_hashent * | 379 | static inline struct idmap_hashent * |
380 | idmap_id_hash(struct idmap_hashtable* h, __u32 id) | 380 | idmap_id_hash(struct idmap_hashtable* h, __u32 id) |
381 | { | 381 | { |
382 | return &h->h_entries[fnvhash32(&id, sizeof(id)) % IDMAP_HASH_SZ]; | 382 | return &h->h_entries[fnvhash32(&id, sizeof(id)) % IDMAP_HASH_SZ]; |
383 | } | 383 | } |
384 | 384 | ||
385 | static struct idmap_hashent * | 385 | static struct idmap_hashent * |
386 | idmap_lookup_id(struct idmap_hashtable *h, __u32 id) | 386 | idmap_lookup_id(struct idmap_hashtable *h, __u32 id) |
387 | { | 387 | { |
388 | struct idmap_hashent *he = idmap_id_hash(h, id); | 388 | struct idmap_hashent *he = idmap_id_hash(h, id); |
389 | if (he->ih_id != id || he->ih_namelen == 0) | 389 | if (he->ih_id != id || he->ih_namelen == 0) |
390 | return NULL; | 390 | return NULL; |
391 | if (time_after(jiffies, he->ih_expires)) | 391 | if (time_after(jiffies, he->ih_expires)) |
392 | return NULL; | 392 | return NULL; |
393 | return he; | 393 | return he; |
394 | } | 394 | } |
395 | 395 | ||
396 | /* | 396 | /* |
397 | * Routines for allocating new entries in the hashtable. | 397 | * Routines for allocating new entries in the hashtable. |
398 | * For now, we just have 1 entry per bucket, so it's all | 398 | * For now, we just have 1 entry per bucket, so it's all |
399 | * pretty trivial. | 399 | * pretty trivial. |
400 | */ | 400 | */ |
401 | static inline struct idmap_hashent * | 401 | static inline struct idmap_hashent * |
402 | idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len) | 402 | idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len) |
403 | { | 403 | { |
404 | return idmap_name_hash(h, name, len); | 404 | return idmap_name_hash(h, name, len); |
405 | } | 405 | } |
406 | 406 | ||
407 | static inline struct idmap_hashent * | 407 | static inline struct idmap_hashent * |
408 | idmap_alloc_id(struct idmap_hashtable *h, __u32 id) | 408 | idmap_alloc_id(struct idmap_hashtable *h, __u32 id) |
409 | { | 409 | { |
410 | return idmap_id_hash(h, id); | 410 | return idmap_id_hash(h, id); |
411 | } | 411 | } |
412 | 412 | ||
413 | static void | 413 | static void |
414 | idmap_update_entry(struct idmap_hashent *he, const char *name, | 414 | idmap_update_entry(struct idmap_hashent *he, const char *name, |
415 | size_t namelen, __u32 id) | 415 | size_t namelen, __u32 id) |
416 | { | 416 | { |
417 | he->ih_id = id; | 417 | he->ih_id = id; |
418 | memcpy(he->ih_name, name, namelen); | 418 | memcpy(he->ih_name, name, namelen); |
419 | he->ih_name[namelen] = '\0'; | 419 | he->ih_name[namelen] = '\0'; |
420 | he->ih_namelen = namelen; | 420 | he->ih_namelen = namelen; |
421 | he->ih_expires = jiffies + nfs_idmap_cache_timeout; | 421 | he->ih_expires = jiffies + nfs_idmap_cache_timeout; |
422 | } | 422 | } |
423 | 423 | ||
424 | /* | 424 | /* |
425 | * Name -> ID | 425 | * Name -> ID |
426 | */ | 426 | */ |
427 | static int | 427 | static int |
428 | nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, | 428 | nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, |
429 | const char *name, size_t namelen, __u32 *id) | 429 | const char *name, size_t namelen, __u32 *id) |
430 | { | 430 | { |
431 | struct rpc_pipe_msg msg; | 431 | struct rpc_pipe_msg msg; |
432 | struct idmap_msg *im; | 432 | struct idmap_msg *im; |
433 | struct idmap_hashent *he; | 433 | struct idmap_hashent *he; |
434 | DECLARE_WAITQUEUE(wq, current); | 434 | DECLARE_WAITQUEUE(wq, current); |
435 | int ret = -EIO; | 435 | int ret = -EIO; |
436 | 436 | ||
437 | im = &idmap->idmap_im; | 437 | im = &idmap->idmap_im; |
438 | 438 | ||
439 | /* | 439 | /* |
440 | * String sanity checks | 440 | * String sanity checks |
441 | * Note that the userland daemon expects NUL terminated strings | 441 | * Note that the userland daemon expects NUL terminated strings |
442 | */ | 442 | */ |
443 | for (;;) { | 443 | for (;;) { |
444 | if (namelen == 0) | 444 | if (namelen == 0) |
445 | return -EINVAL; | 445 | return -EINVAL; |
446 | if (name[namelen-1] != '\0') | 446 | if (name[namelen-1] != '\0') |
447 | break; | 447 | break; |
448 | namelen--; | 448 | namelen--; |
449 | } | 449 | } |
450 | if (namelen >= IDMAP_NAMESZ) | 450 | if (namelen >= IDMAP_NAMESZ) |
451 | return -EINVAL; | 451 | return -EINVAL; |
452 | 452 | ||
453 | mutex_lock(&idmap->idmap_lock); | 453 | mutex_lock(&idmap->idmap_lock); |
454 | mutex_lock(&idmap->idmap_im_lock); | 454 | mutex_lock(&idmap->idmap_im_lock); |
455 | 455 | ||
456 | he = idmap_lookup_name(h, name, namelen); | 456 | he = idmap_lookup_name(h, name, namelen); |
457 | if (he != NULL) { | 457 | if (he != NULL) { |
458 | *id = he->ih_id; | 458 | *id = he->ih_id; |
459 | ret = 0; | 459 | ret = 0; |
460 | goto out; | 460 | goto out; |
461 | } | 461 | } |
462 | 462 | ||
463 | memset(im, 0, sizeof(*im)); | 463 | memset(im, 0, sizeof(*im)); |
464 | memcpy(im->im_name, name, namelen); | 464 | memcpy(im->im_name, name, namelen); |
465 | 465 | ||
466 | im->im_type = h->h_type; | 466 | im->im_type = h->h_type; |
467 | im->im_conv = IDMAP_CONV_NAMETOID; | 467 | im->im_conv = IDMAP_CONV_NAMETOID; |
468 | 468 | ||
469 | memset(&msg, 0, sizeof(msg)); | 469 | memset(&msg, 0, sizeof(msg)); |
470 | msg.data = im; | 470 | msg.data = im; |
471 | msg.len = sizeof(*im); | 471 | msg.len = sizeof(*im); |
472 | 472 | ||
473 | add_wait_queue(&idmap->idmap_wq, &wq); | 473 | add_wait_queue(&idmap->idmap_wq, &wq); |
474 | if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) { | 474 | if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) { |
475 | remove_wait_queue(&idmap->idmap_wq, &wq); | 475 | remove_wait_queue(&idmap->idmap_wq, &wq); |
476 | goto out; | 476 | goto out; |
477 | } | 477 | } |
478 | 478 | ||
479 | set_current_state(TASK_UNINTERRUPTIBLE); | 479 | set_current_state(TASK_UNINTERRUPTIBLE); |
480 | mutex_unlock(&idmap->idmap_im_lock); | 480 | mutex_unlock(&idmap->idmap_im_lock); |
481 | schedule(); | 481 | schedule(); |
482 | __set_current_state(TASK_RUNNING); | 482 | __set_current_state(TASK_RUNNING); |
483 | remove_wait_queue(&idmap->idmap_wq, &wq); | 483 | remove_wait_queue(&idmap->idmap_wq, &wq); |
484 | mutex_lock(&idmap->idmap_im_lock); | 484 | mutex_lock(&idmap->idmap_im_lock); |
485 | 485 | ||
486 | if (im->im_status & IDMAP_STATUS_SUCCESS) { | 486 | if (im->im_status & IDMAP_STATUS_SUCCESS) { |
487 | *id = im->im_id; | 487 | *id = im->im_id; |
488 | ret = 0; | 488 | ret = 0; |
489 | } | 489 | } |
490 | 490 | ||
491 | out: | 491 | out: |
492 | memset(im, 0, sizeof(*im)); | 492 | memset(im, 0, sizeof(*im)); |
493 | mutex_unlock(&idmap->idmap_im_lock); | 493 | mutex_unlock(&idmap->idmap_im_lock); |
494 | mutex_unlock(&idmap->idmap_lock); | 494 | mutex_unlock(&idmap->idmap_lock); |
495 | return ret; | 495 | return ret; |
496 | } | 496 | } |
497 | 497 | ||
498 | /* | 498 | /* |
499 | * ID -> Name | 499 | * ID -> Name |
500 | */ | 500 | */ |
501 | static int | 501 | static int |
502 | nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, | 502 | nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, |
503 | __u32 id, char *name) | 503 | __u32 id, char *name) |
504 | { | 504 | { |
505 | struct rpc_pipe_msg msg; | 505 | struct rpc_pipe_msg msg; |
506 | struct idmap_msg *im; | 506 | struct idmap_msg *im; |
507 | struct idmap_hashent *he; | 507 | struct idmap_hashent *he; |
508 | DECLARE_WAITQUEUE(wq, current); | 508 | DECLARE_WAITQUEUE(wq, current); |
509 | int ret = -EIO; | 509 | int ret = -EIO; |
510 | unsigned int len; | 510 | unsigned int len; |
511 | 511 | ||
512 | im = &idmap->idmap_im; | 512 | im = &idmap->idmap_im; |
513 | 513 | ||
514 | mutex_lock(&idmap->idmap_lock); | 514 | mutex_lock(&idmap->idmap_lock); |
515 | mutex_lock(&idmap->idmap_im_lock); | 515 | mutex_lock(&idmap->idmap_im_lock); |
516 | 516 | ||
517 | he = idmap_lookup_id(h, id); | 517 | he = idmap_lookup_id(h, id); |
518 | if (he) { | 518 | if (he) { |
519 | memcpy(name, he->ih_name, he->ih_namelen); | 519 | memcpy(name, he->ih_name, he->ih_namelen); |
520 | ret = he->ih_namelen; | 520 | ret = he->ih_namelen; |
521 | goto out; | 521 | goto out; |
522 | } | 522 | } |
523 | 523 | ||
524 | memset(im, 0, sizeof(*im)); | 524 | memset(im, 0, sizeof(*im)); |
525 | im->im_type = h->h_type; | 525 | im->im_type = h->h_type; |
526 | im->im_conv = IDMAP_CONV_IDTONAME; | 526 | im->im_conv = IDMAP_CONV_IDTONAME; |
527 | im->im_id = id; | 527 | im->im_id = id; |
528 | 528 | ||
529 | memset(&msg, 0, sizeof(msg)); | 529 | memset(&msg, 0, sizeof(msg)); |
530 | msg.data = im; | 530 | msg.data = im; |
531 | msg.len = sizeof(*im); | 531 | msg.len = sizeof(*im); |
532 | 532 | ||
533 | add_wait_queue(&idmap->idmap_wq, &wq); | 533 | add_wait_queue(&idmap->idmap_wq, &wq); |
534 | 534 | ||
535 | if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) { | 535 | if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) { |
536 | remove_wait_queue(&idmap->idmap_wq, &wq); | 536 | remove_wait_queue(&idmap->idmap_wq, &wq); |
537 | goto out; | 537 | goto out; |
538 | } | 538 | } |
539 | 539 | ||
540 | set_current_state(TASK_UNINTERRUPTIBLE); | 540 | set_current_state(TASK_UNINTERRUPTIBLE); |
541 | mutex_unlock(&idmap->idmap_im_lock); | 541 | mutex_unlock(&idmap->idmap_im_lock); |
542 | schedule(); | 542 | schedule(); |
543 | __set_current_state(TASK_RUNNING); | 543 | __set_current_state(TASK_RUNNING); |
544 | remove_wait_queue(&idmap->idmap_wq, &wq); | 544 | remove_wait_queue(&idmap->idmap_wq, &wq); |
545 | mutex_lock(&idmap->idmap_im_lock); | 545 | mutex_lock(&idmap->idmap_im_lock); |
546 | 546 | ||
547 | if (im->im_status & IDMAP_STATUS_SUCCESS) { | 547 | if (im->im_status & IDMAP_STATUS_SUCCESS) { |
548 | if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0) | 548 | if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0) |
549 | goto out; | 549 | goto out; |
550 | memcpy(name, im->im_name, len); | 550 | memcpy(name, im->im_name, len); |
551 | ret = len; | 551 | ret = len; |
552 | } | 552 | } |
553 | 553 | ||
554 | out: | 554 | out: |
555 | memset(im, 0, sizeof(*im)); | 555 | memset(im, 0, sizeof(*im)); |
556 | mutex_unlock(&idmap->idmap_im_lock); | 556 | mutex_unlock(&idmap->idmap_im_lock); |
557 | mutex_unlock(&idmap->idmap_lock); | 557 | mutex_unlock(&idmap->idmap_lock); |
558 | return ret; | 558 | return ret; |
559 | } | 559 | } |
560 | 560 | ||
561 | /* RPC pipefs upcall/downcall routines */ | 561 | /* RPC pipefs upcall/downcall routines */ |
562 | static ssize_t | 562 | static ssize_t |
563 | idmap_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg, | 563 | idmap_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg, |
564 | char __user *dst, size_t buflen) | 564 | char __user *dst, size_t buflen) |
565 | { | 565 | { |
566 | char *data = (char *)msg->data + msg->copied; | 566 | char *data = (char *)msg->data + msg->copied; |
567 | size_t mlen = min(msg->len, buflen); | 567 | size_t mlen = min(msg->len, buflen); |
568 | unsigned long left; | 568 | unsigned long left; |
569 | 569 | ||
570 | left = copy_to_user(dst, data, mlen); | 570 | left = copy_to_user(dst, data, mlen); |
571 | if (left == mlen) { | 571 | if (left == mlen) { |
572 | msg->errno = -EFAULT; | 572 | msg->errno = -EFAULT; |
573 | return -EFAULT; | 573 | return -EFAULT; |
574 | } | 574 | } |
575 | 575 | ||
576 | mlen -= left; | 576 | mlen -= left; |
577 | msg->copied += mlen; | 577 | msg->copied += mlen; |
578 | msg->errno = 0; | 578 | msg->errno = 0; |
579 | return mlen; | 579 | return mlen; |
580 | } | 580 | } |
581 | 581 | ||
582 | static ssize_t | 582 | static ssize_t |
583 | idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | 583 | idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) |
584 | { | 584 | { |
585 | struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); | 585 | struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); |
586 | struct idmap *idmap = (struct idmap *)rpci->private; | 586 | struct idmap *idmap = (struct idmap *)rpci->private; |
587 | struct idmap_msg im_in, *im = &idmap->idmap_im; | 587 | struct idmap_msg im_in, *im = &idmap->idmap_im; |
588 | struct idmap_hashtable *h; | 588 | struct idmap_hashtable *h; |
589 | struct idmap_hashent *he = NULL; | 589 | struct idmap_hashent *he = NULL; |
590 | size_t namelen_in; | 590 | size_t namelen_in; |
591 | int ret; | 591 | int ret; |
592 | 592 | ||
593 | if (mlen != sizeof(im_in)) | 593 | if (mlen != sizeof(im_in)) |
594 | return -ENOSPC; | 594 | return -ENOSPC; |
595 | 595 | ||
596 | if (copy_from_user(&im_in, src, mlen) != 0) | 596 | if (copy_from_user(&im_in, src, mlen) != 0) |
597 | return -EFAULT; | 597 | return -EFAULT; |
598 | 598 | ||
599 | mutex_lock(&idmap->idmap_im_lock); | 599 | mutex_lock(&idmap->idmap_im_lock); |
600 | 600 | ||
601 | ret = mlen; | 601 | ret = mlen; |
602 | im->im_status = im_in.im_status; | 602 | im->im_status = im_in.im_status; |
603 | /* If we got an error, terminate now, and wake up pending upcalls */ | 603 | /* If we got an error, terminate now, and wake up pending upcalls */ |
604 | if (!(im_in.im_status & IDMAP_STATUS_SUCCESS)) { | 604 | if (!(im_in.im_status & IDMAP_STATUS_SUCCESS)) { |
605 | wake_up(&idmap->idmap_wq); | 605 | wake_up(&idmap->idmap_wq); |
606 | goto out; | 606 | goto out; |
607 | } | 607 | } |
608 | 608 | ||
609 | /* Sanity checking of strings */ | 609 | /* Sanity checking of strings */ |
610 | ret = -EINVAL; | 610 | ret = -EINVAL; |
611 | namelen_in = strnlen(im_in.im_name, IDMAP_NAMESZ); | 611 | namelen_in = strnlen(im_in.im_name, IDMAP_NAMESZ); |
612 | if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) | 612 | if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) |
613 | goto out; | 613 | goto out; |
614 | 614 | ||
615 | switch (im_in.im_type) { | 615 | switch (im_in.im_type) { |
616 | case IDMAP_TYPE_USER: | 616 | case IDMAP_TYPE_USER: |
617 | h = &idmap->idmap_user_hash; | 617 | h = &idmap->idmap_user_hash; |
618 | break; | 618 | break; |
619 | case IDMAP_TYPE_GROUP: | 619 | case IDMAP_TYPE_GROUP: |
620 | h = &idmap->idmap_group_hash; | 620 | h = &idmap->idmap_group_hash; |
621 | break; | 621 | break; |
622 | default: | 622 | default: |
623 | goto out; | 623 | goto out; |
624 | } | 624 | } |
625 | 625 | ||
626 | switch (im_in.im_conv) { | 626 | switch (im_in.im_conv) { |
627 | case IDMAP_CONV_IDTONAME: | 627 | case IDMAP_CONV_IDTONAME: |
628 | /* Did we match the current upcall? */ | 628 | /* Did we match the current upcall? */ |
629 | if (im->im_conv == IDMAP_CONV_IDTONAME | 629 | if (im->im_conv == IDMAP_CONV_IDTONAME |
630 | && im->im_type == im_in.im_type | 630 | && im->im_type == im_in.im_type |
631 | && im->im_id == im_in.im_id) { | 631 | && im->im_id == im_in.im_id) { |
632 | /* Yes: copy string, including the terminating '\0' */ | 632 | /* Yes: copy string, including the terminating '\0' */ |
633 | memcpy(im->im_name, im_in.im_name, namelen_in); | 633 | memcpy(im->im_name, im_in.im_name, namelen_in); |
634 | im->im_name[namelen_in] = '\0'; | 634 | im->im_name[namelen_in] = '\0'; |
635 | wake_up(&idmap->idmap_wq); | 635 | wake_up(&idmap->idmap_wq); |
636 | } | 636 | } |
637 | he = idmap_alloc_id(h, im_in.im_id); | 637 | he = idmap_alloc_id(h, im_in.im_id); |
638 | break; | 638 | break; |
639 | case IDMAP_CONV_NAMETOID: | 639 | case IDMAP_CONV_NAMETOID: |
640 | /* Did we match the current upcall? */ | 640 | /* Did we match the current upcall? */ |
641 | if (im->im_conv == IDMAP_CONV_NAMETOID | 641 | if (im->im_conv == IDMAP_CONV_NAMETOID |
642 | && im->im_type == im_in.im_type | 642 | && im->im_type == im_in.im_type |
643 | && strnlen(im->im_name, IDMAP_NAMESZ) == namelen_in | 643 | && strnlen(im->im_name, IDMAP_NAMESZ) == namelen_in |
644 | && memcmp(im->im_name, im_in.im_name, namelen_in) == 0) { | 644 | && memcmp(im->im_name, im_in.im_name, namelen_in) == 0) { |
645 | im->im_id = im_in.im_id; | 645 | im->im_id = im_in.im_id; |
646 | wake_up(&idmap->idmap_wq); | 646 | wake_up(&idmap->idmap_wq); |
647 | } | 647 | } |
648 | he = idmap_alloc_name(h, im_in.im_name, namelen_in); | 648 | he = idmap_alloc_name(h, im_in.im_name, namelen_in); |
649 | break; | 649 | break; |
650 | default: | 650 | default: |
651 | goto out; | 651 | goto out; |
652 | } | 652 | } |
653 | 653 | ||
654 | /* If the entry is valid, also copy it to the cache */ | 654 | /* If the entry is valid, also copy it to the cache */ |
655 | if (he != NULL) | 655 | if (he != NULL) |
656 | idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id); | 656 | idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id); |
657 | ret = mlen; | 657 | ret = mlen; |
658 | out: | 658 | out: |
659 | mutex_unlock(&idmap->idmap_im_lock); | 659 | mutex_unlock(&idmap->idmap_im_lock); |
660 | return ret; | 660 | return ret; |
661 | } | 661 | } |
662 | 662 | ||
663 | static void | 663 | static void |
664 | idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) | 664 | idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) |
665 | { | 665 | { |
666 | struct idmap_msg *im = msg->data; | 666 | struct idmap_msg *im = msg->data; |
667 | struct idmap *idmap = container_of(im, struct idmap, idmap_im); | 667 | struct idmap *idmap = container_of(im, struct idmap, idmap_im); |
668 | 668 | ||
669 | if (msg->errno >= 0) | 669 | if (msg->errno >= 0) |
670 | return; | 670 | return; |
671 | mutex_lock(&idmap->idmap_im_lock); | 671 | mutex_lock(&idmap->idmap_im_lock); |
672 | im->im_status = IDMAP_STATUS_LOOKUPFAIL; | 672 | im->im_status = IDMAP_STATUS_LOOKUPFAIL; |
673 | wake_up(&idmap->idmap_wq); | 673 | wake_up(&idmap->idmap_wq); |
674 | mutex_unlock(&idmap->idmap_im_lock); | 674 | mutex_unlock(&idmap->idmap_im_lock); |
675 | } | 675 | } |
676 | 676 | ||
677 | /* | 677 | /* |
678 | * Fowler/Noll/Vo hash | 678 | * Fowler/Noll/Vo hash |
679 | * http://www.isthe.com/chongo/tech/comp/fnv/ | 679 | * http://www.isthe.com/chongo/tech/comp/fnv/ |
680 | */ | 680 | */ |
681 | 681 | ||
682 | #define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */ | 682 | #define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */ |
683 | #define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */ | 683 | #define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */ |
684 | 684 | ||
685 | static unsigned int fnvhash32(const void *buf, size_t buflen) | 685 | static unsigned int fnvhash32(const void *buf, size_t buflen) |
686 | { | 686 | { |
687 | const unsigned char *p, *end = (const unsigned char *)buf + buflen; | 687 | const unsigned char *p, *end = (const unsigned char *)buf + buflen; |
688 | unsigned int hash = FNV_1_32; | 688 | unsigned int hash = FNV_1_32; |
689 | 689 | ||
690 | for (p = buf; p < end; p++) { | 690 | for (p = buf; p < end; p++) { |
691 | hash *= FNV_P_32; | 691 | hash *= FNV_P_32; |
692 | hash ^= (unsigned int)*p; | 692 | hash ^= (unsigned int)*p; |
693 | } | 693 | } |
694 | 694 | ||
695 | return hash; | 695 | return hash; |
696 | } | 696 | } |
697 | 697 | ||
698 | int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) | 698 | int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) |
699 | { | 699 | { |
700 | struct idmap *idmap = clp->cl_idmap; | 700 | struct idmap *idmap = clp->cl_idmap; |
701 | 701 | ||
702 | return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid); | 702 | return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid); |
703 | } | 703 | } |
704 | 704 | ||
705 | int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) | 705 | int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) |
706 | { | 706 | { |
707 | struct idmap *idmap = clp->cl_idmap; | 707 | struct idmap *idmap = clp->cl_idmap; |
708 | 708 | ||
709 | return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid); | 709 | return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid); |
710 | } | 710 | } |
711 | 711 | ||
712 | int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen) | 712 | int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen) |
713 | { | 713 | { |
714 | struct idmap *idmap = clp->cl_idmap; | 714 | struct idmap *idmap = clp->cl_idmap; |
715 | 715 | ||
716 | return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf); | 716 | return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf); |
717 | } | 717 | } |
718 | int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen) | 718 | int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen) |
719 | { | 719 | { |
720 | struct idmap *idmap = clp->cl_idmap; | 720 | struct idmap *idmap = clp->cl_idmap; |
721 | 721 | ||
722 | return nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf); | 722 | return nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf); |
723 | } | 723 | } |
724 | 724 | ||
725 | #endif /* CONFIG_NFS_USE_NEW_IDMAPPER */ | 725 | #endif /* CONFIG_NFS_USE_NEW_IDMAPPER */ |
726 | 726 |