diff options
Diffstat (limited to 'fs/nfs/idmap.c')
-rw-r--r-- | fs/nfs/idmap.c | 733 |
1 files changed, 344 insertions, 389 deletions
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 2c05f1991e1e..a701a83047d3 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -34,11 +34,29 @@ | |||
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 | #include <linux/types.h> | 36 | #include <linux/types.h> |
37 | #include <linux/string.h> | 37 | #include <linux/parser.h> |
38 | #include <linux/kernel.h> | 38 | #include <linux/fs.h> |
39 | #include <linux/slab.h> | ||
40 | #include <linux/nfs_idmap.h> | 39 | #include <linux/nfs_idmap.h> |
40 | #include <net/net_namespace.h> | ||
41 | #include <linux/sunrpc/rpc_pipe_fs.h> | ||
41 | #include <linux/nfs_fs.h> | 42 | #include <linux/nfs_fs.h> |
43 | #include <linux/nfs_fs_sb.h> | ||
44 | #include <linux/key.h> | ||
45 | #include <linux/keyctl.h> | ||
46 | #include <linux/key-type.h> | ||
47 | #include <keys/user-type.h> | ||
48 | #include <linux/module.h> | ||
49 | |||
50 | #include "internal.h" | ||
51 | #include "netns.h" | ||
52 | |||
53 | #define NFS_UINT_MAXLEN 11 | ||
54 | |||
55 | /* Default cache timeout is 10 minutes */ | ||
56 | unsigned int nfs_idmap_cache_timeout = 600; | ||
57 | static const struct cred *id_resolver_cache; | ||
58 | static struct key_type key_type_id_resolver_legacy; | ||
59 | |||
42 | 60 | ||
43 | /** | 61 | /** |
44 | * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields | 62 | * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields |
@@ -142,24 +160,7 @@ static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen) | |||
142 | return snprintf(buf, buflen, "%u", id); | 160 | return snprintf(buf, buflen, "%u", id); |
143 | } | 161 | } |
144 | 162 | ||
145 | #ifdef CONFIG_NFS_USE_NEW_IDMAPPER | 163 | static struct key_type key_type_id_resolver = { |
146 | |||
147 | #include <linux/cred.h> | ||
148 | #include <linux/sunrpc/sched.h> | ||
149 | #include <linux/nfs4.h> | ||
150 | #include <linux/nfs_fs_sb.h> | ||
151 | #include <linux/keyctl.h> | ||
152 | #include <linux/key-type.h> | ||
153 | #include <linux/rcupdate.h> | ||
154 | #include <linux/err.h> | ||
155 | |||
156 | #include <keys/user-type.h> | ||
157 | |||
158 | #define NFS_UINT_MAXLEN 11 | ||
159 | |||
160 | const struct cred *id_resolver_cache; | ||
161 | |||
162 | struct key_type key_type_id_resolver = { | ||
163 | .name = "id_resolver", | 164 | .name = "id_resolver", |
164 | .instantiate = user_instantiate, | 165 | .instantiate = user_instantiate, |
165 | .match = user_match, | 166 | .match = user_match, |
@@ -169,13 +170,14 @@ struct key_type key_type_id_resolver = { | |||
169 | .read = user_read, | 170 | .read = user_read, |
170 | }; | 171 | }; |
171 | 172 | ||
172 | int nfs_idmap_init(void) | 173 | static int nfs_idmap_init_keyring(void) |
173 | { | 174 | { |
174 | struct cred *cred; | 175 | struct cred *cred; |
175 | struct key *keyring; | 176 | struct key *keyring; |
176 | int ret = 0; | 177 | int ret = 0; |
177 | 178 | ||
178 | printk(KERN_NOTICE "Registering the %s key type\n", key_type_id_resolver.name); | 179 | printk(KERN_NOTICE "NFS: Registering the %s key type\n", |
180 | key_type_id_resolver.name); | ||
179 | 181 | ||
180 | cred = prepare_kernel_cred(NULL); | 182 | cred = prepare_kernel_cred(NULL); |
181 | if (!cred) | 183 | if (!cred) |
@@ -210,7 +212,7 @@ failed_put_cred: | |||
210 | return ret; | 212 | return ret; |
211 | } | 213 | } |
212 | 214 | ||
213 | void nfs_idmap_quit(void) | 215 | static void nfs_idmap_quit_keyring(void) |
214 | { | 216 | { |
215 | key_revoke(id_resolver_cache->thread_keyring); | 217 | key_revoke(id_resolver_cache->thread_keyring); |
216 | unregister_key_type(&key_type_id_resolver); | 218 | unregister_key_type(&key_type_id_resolver); |
@@ -245,8 +247,10 @@ static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen, | |||
245 | return desclen; | 247 | return desclen; |
246 | } | 248 | } |
247 | 249 | ||
248 | static ssize_t nfs_idmap_request_key(const char *name, size_t namelen, | 250 | static ssize_t nfs_idmap_request_key(struct key_type *key_type, |
249 | const char *type, void *data, size_t data_size) | 251 | const char *name, size_t namelen, |
252 | const char *type, void *data, | ||
253 | size_t data_size, struct idmap *idmap) | ||
250 | { | 254 | { |
251 | const struct cred *saved_cred; | 255 | const struct cred *saved_cred; |
252 | struct key *rkey; | 256 | struct key *rkey; |
@@ -259,8 +263,12 @@ static ssize_t nfs_idmap_request_key(const char *name, size_t namelen, | |||
259 | goto out; | 263 | goto out; |
260 | 264 | ||
261 | saved_cred = override_creds(id_resolver_cache); | 265 | saved_cred = override_creds(id_resolver_cache); |
262 | rkey = request_key(&key_type_id_resolver, desc, ""); | 266 | if (idmap) |
267 | rkey = request_key_with_auxdata(key_type, desc, "", 0, idmap); | ||
268 | else | ||
269 | rkey = request_key(&key_type_id_resolver, desc, ""); | ||
263 | revert_creds(saved_cred); | 270 | revert_creds(saved_cred); |
271 | |||
264 | kfree(desc); | 272 | kfree(desc); |
265 | if (IS_ERR(rkey)) { | 273 | if (IS_ERR(rkey)) { |
266 | ret = PTR_ERR(rkey); | 274 | ret = PTR_ERR(rkey); |
@@ -293,31 +301,46 @@ out: | |||
293 | return ret; | 301 | return ret; |
294 | } | 302 | } |
295 | 303 | ||
304 | static ssize_t nfs_idmap_get_key(const char *name, size_t namelen, | ||
305 | const char *type, void *data, | ||
306 | size_t data_size, struct idmap *idmap) | ||
307 | { | ||
308 | ssize_t ret = nfs_idmap_request_key(&key_type_id_resolver, | ||
309 | name, namelen, type, data, | ||
310 | data_size, NULL); | ||
311 | if (ret < 0) { | ||
312 | ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, | ||
313 | name, namelen, type, data, | ||
314 | data_size, idmap); | ||
315 | } | ||
316 | return ret; | ||
317 | } | ||
296 | 318 | ||
297 | /* ID -> Name */ | 319 | /* ID -> Name */ |
298 | static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, size_t buflen) | 320 | static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, |
321 | size_t buflen, struct idmap *idmap) | ||
299 | { | 322 | { |
300 | char id_str[NFS_UINT_MAXLEN]; | 323 | char id_str[NFS_UINT_MAXLEN]; |
301 | int id_len; | 324 | int id_len; |
302 | ssize_t ret; | 325 | ssize_t ret; |
303 | 326 | ||
304 | id_len = snprintf(id_str, sizeof(id_str), "%u", id); | 327 | id_len = snprintf(id_str, sizeof(id_str), "%u", id); |
305 | ret = nfs_idmap_request_key(id_str, id_len, type, buf, buflen); | 328 | ret = nfs_idmap_get_key(id_str, id_len, type, buf, buflen, idmap); |
306 | if (ret < 0) | 329 | if (ret < 0) |
307 | return -EINVAL; | 330 | return -EINVAL; |
308 | return ret; | 331 | return ret; |
309 | } | 332 | } |
310 | 333 | ||
311 | /* Name -> ID */ | 334 | /* Name -> ID */ |
312 | static int nfs_idmap_lookup_id(const char *name, size_t namelen, | 335 | static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *type, |
313 | const char *type, __u32 *id) | 336 | __u32 *id, struct idmap *idmap) |
314 | { | 337 | { |
315 | char id_str[NFS_UINT_MAXLEN]; | 338 | char id_str[NFS_UINT_MAXLEN]; |
316 | long id_long; | 339 | long id_long; |
317 | ssize_t data_size; | 340 | ssize_t data_size; |
318 | int ret = 0; | 341 | int ret = 0; |
319 | 342 | ||
320 | data_size = nfs_idmap_request_key(name, namelen, type, id_str, NFS_UINT_MAXLEN); | 343 | data_size = nfs_idmap_get_key(name, namelen, type, id_str, NFS_UINT_MAXLEN, idmap); |
321 | if (data_size <= 0) { | 344 | if (data_size <= 0) { |
322 | ret = -EINVAL; | 345 | ret = -EINVAL; |
323 | } else { | 346 | } else { |
@@ -327,114 +350,103 @@ static int nfs_idmap_lookup_id(const char *name, size_t namelen, | |||
327 | return ret; | 350 | return ret; |
328 | } | 351 | } |
329 | 352 | ||
330 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) | 353 | /* idmap classic begins here */ |
331 | { | 354 | module_param(nfs_idmap_cache_timeout, int, 0644); |
332 | if (nfs_map_string_to_numeric(name, namelen, uid)) | ||
333 | return 0; | ||
334 | return nfs_idmap_lookup_id(name, namelen, "uid", uid); | ||
335 | } | ||
336 | |||
337 | int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid) | ||
338 | { | ||
339 | if (nfs_map_string_to_numeric(name, namelen, gid)) | ||
340 | return 0; | ||
341 | return nfs_idmap_lookup_id(name, namelen, "gid", gid); | ||
342 | } | ||
343 | |||
344 | int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) | ||
345 | { | ||
346 | int ret = -EINVAL; | ||
347 | |||
348 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) | ||
349 | ret = nfs_idmap_lookup_name(uid, "user", buf, buflen); | ||
350 | if (ret < 0) | ||
351 | ret = nfs_map_numeric_to_string(uid, buf, buflen); | ||
352 | return ret; | ||
353 | } | ||
354 | int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen) | ||
355 | { | ||
356 | int ret = -EINVAL; | ||
357 | 355 | ||
358 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) | 356 | struct idmap { |
359 | ret = nfs_idmap_lookup_name(gid, "group", buf, buflen); | 357 | struct rpc_pipe *idmap_pipe; |
360 | if (ret < 0) | 358 | struct key_construction *idmap_key_cons; |
361 | ret = nfs_map_numeric_to_string(gid, buf, buflen); | ||
362 | return ret; | ||
363 | } | ||
364 | |||
365 | #else /* CONFIG_NFS_USE_NEW_IDMAPPER not defined */ | ||
366 | |||
367 | #include <linux/module.h> | ||
368 | #include <linux/mutex.h> | ||
369 | #include <linux/init.h> | ||
370 | #include <linux/socket.h> | ||
371 | #include <linux/in.h> | ||
372 | #include <linux/sched.h> | ||
373 | #include <linux/sunrpc/clnt.h> | ||
374 | #include <linux/workqueue.h> | ||
375 | #include <linux/sunrpc/rpc_pipe_fs.h> | ||
376 | |||
377 | #include <linux/nfs_fs.h> | ||
378 | |||
379 | #include "nfs4_fs.h" | ||
380 | |||
381 | #define IDMAP_HASH_SZ 128 | ||
382 | |||
383 | /* Default cache timeout is 10 minutes */ | ||
384 | unsigned int nfs_idmap_cache_timeout = 600 * HZ; | ||
385 | |||
386 | static int param_set_idmap_timeout(const char *val, struct kernel_param *kp) | ||
387 | { | ||
388 | char *endp; | ||
389 | int num = simple_strtol(val, &endp, 0); | ||
390 | int jif = num * HZ; | ||
391 | if (endp == val || *endp || num < 0 || jif < num) | ||
392 | return -EINVAL; | ||
393 | *((int *)kp->arg) = jif; | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int, | ||
398 | &nfs_idmap_cache_timeout, 0644); | ||
399 | |||
400 | struct idmap_hashent { | ||
401 | unsigned long ih_expires; | ||
402 | __u32 ih_id; | ||
403 | size_t ih_namelen; | ||
404 | char ih_name[IDMAP_NAMESZ]; | ||
405 | }; | 359 | }; |
406 | 360 | ||
407 | struct idmap_hashtable { | 361 | enum { |
408 | __u8 h_type; | 362 | Opt_find_uid, Opt_find_gid, Opt_find_user, Opt_find_group, Opt_find_err |
409 | struct idmap_hashent h_entries[IDMAP_HASH_SZ]; | ||
410 | }; | 363 | }; |
411 | 364 | ||
412 | struct idmap { | 365 | static const match_table_t nfs_idmap_tokens = { |
413 | struct dentry *idmap_dentry; | 366 | { Opt_find_uid, "uid:%s" }, |
414 | wait_queue_head_t idmap_wq; | 367 | { Opt_find_gid, "gid:%s" }, |
415 | struct idmap_msg idmap_im; | 368 | { Opt_find_user, "user:%s" }, |
416 | struct mutex idmap_lock; /* Serializes upcalls */ | 369 | { Opt_find_group, "group:%s" }, |
417 | struct mutex idmap_im_lock; /* Protects the hashtable */ | 370 | { Opt_find_err, NULL } |
418 | struct idmap_hashtable idmap_user_hash; | ||
419 | struct idmap_hashtable idmap_group_hash; | ||
420 | }; | 371 | }; |
421 | 372 | ||
373 | static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *); | ||
422 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, | 374 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, |
423 | size_t); | 375 | size_t); |
424 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); | 376 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); |
425 | 377 | ||
426 | static unsigned int fnvhash32(const void *, size_t); | ||
427 | |||
428 | static const struct rpc_pipe_ops idmap_upcall_ops = { | 378 | static const struct rpc_pipe_ops idmap_upcall_ops = { |
429 | .upcall = rpc_pipe_generic_upcall, | 379 | .upcall = rpc_pipe_generic_upcall, |
430 | .downcall = idmap_pipe_downcall, | 380 | .downcall = idmap_pipe_downcall, |
431 | .destroy_msg = idmap_pipe_destroy_msg, | 381 | .destroy_msg = idmap_pipe_destroy_msg, |
432 | }; | 382 | }; |
433 | 383 | ||
384 | static struct key_type key_type_id_resolver_legacy = { | ||
385 | .name = "id_resolver", | ||
386 | .instantiate = user_instantiate, | ||
387 | .match = user_match, | ||
388 | .revoke = user_revoke, | ||
389 | .destroy = user_destroy, | ||
390 | .describe = user_describe, | ||
391 | .read = user_read, | ||
392 | .request_key = nfs_idmap_legacy_upcall, | ||
393 | }; | ||
394 | |||
395 | static void __nfs_idmap_unregister(struct rpc_pipe *pipe) | ||
396 | { | ||
397 | if (pipe->dentry) | ||
398 | rpc_unlink(pipe->dentry); | ||
399 | } | ||
400 | |||
401 | static int __nfs_idmap_register(struct dentry *dir, | ||
402 | struct idmap *idmap, | ||
403 | struct rpc_pipe *pipe) | ||
404 | { | ||
405 | struct dentry *dentry; | ||
406 | |||
407 | dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe); | ||
408 | if (IS_ERR(dentry)) | ||
409 | return PTR_ERR(dentry); | ||
410 | pipe->dentry = dentry; | ||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static void nfs_idmap_unregister(struct nfs_client *clp, | ||
415 | struct rpc_pipe *pipe) | ||
416 | { | ||
417 | struct net *net = clp->net; | ||
418 | struct super_block *pipefs_sb; | ||
419 | |||
420 | pipefs_sb = rpc_get_sb_net(net); | ||
421 | if (pipefs_sb) { | ||
422 | __nfs_idmap_unregister(pipe); | ||
423 | rpc_put_sb_net(net); | ||
424 | } | ||
425 | } | ||
426 | |||
427 | static int nfs_idmap_register(struct nfs_client *clp, | ||
428 | struct idmap *idmap, | ||
429 | struct rpc_pipe *pipe) | ||
430 | { | ||
431 | struct net *net = clp->net; | ||
432 | struct super_block *pipefs_sb; | ||
433 | int err = 0; | ||
434 | |||
435 | pipefs_sb = rpc_get_sb_net(net); | ||
436 | if (pipefs_sb) { | ||
437 | if (clp->cl_rpcclient->cl_dentry) | ||
438 | err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, | ||
439 | idmap, pipe); | ||
440 | rpc_put_sb_net(net); | ||
441 | } | ||
442 | return err; | ||
443 | } | ||
444 | |||
434 | int | 445 | int |
435 | nfs_idmap_new(struct nfs_client *clp) | 446 | nfs_idmap_new(struct nfs_client *clp) |
436 | { | 447 | { |
437 | struct idmap *idmap; | 448 | struct idmap *idmap; |
449 | struct rpc_pipe *pipe; | ||
438 | int error; | 450 | int error; |
439 | 451 | ||
440 | BUG_ON(clp->cl_idmap != NULL); | 452 | BUG_ON(clp->cl_idmap != NULL); |
@@ -443,19 +455,19 @@ nfs_idmap_new(struct nfs_client *clp) | |||
443 | if (idmap == NULL) | 455 | if (idmap == NULL) |
444 | return -ENOMEM; | 456 | return -ENOMEM; |
445 | 457 | ||
446 | idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry, | 458 | pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0); |
447 | "idmap", idmap, &idmap_upcall_ops, 0); | 459 | if (IS_ERR(pipe)) { |
448 | if (IS_ERR(idmap->idmap_dentry)) { | 460 | error = PTR_ERR(pipe); |
449 | error = PTR_ERR(idmap->idmap_dentry); | ||
450 | kfree(idmap); | 461 | kfree(idmap); |
451 | return error; | 462 | return error; |
452 | } | 463 | } |
453 | 464 | error = nfs_idmap_register(clp, idmap, pipe); | |
454 | mutex_init(&idmap->idmap_lock); | 465 | if (error) { |
455 | mutex_init(&idmap->idmap_im_lock); | 466 | rpc_destroy_pipe_data(pipe); |
456 | init_waitqueue_head(&idmap->idmap_wq); | 467 | kfree(idmap); |
457 | idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER; | 468 | return error; |
458 | idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; | 469 | } |
470 | idmap->idmap_pipe = pipe; | ||
459 | 471 | ||
460 | clp->cl_idmap = idmap; | 472 | clp->cl_idmap = idmap; |
461 | return 0; | 473 | return 0; |
@@ -468,211 +480,220 @@ nfs_idmap_delete(struct nfs_client *clp) | |||
468 | 480 | ||
469 | if (!idmap) | 481 | if (!idmap) |
470 | return; | 482 | return; |
471 | rpc_unlink(idmap->idmap_dentry); | 483 | nfs_idmap_unregister(clp, idmap->idmap_pipe); |
484 | rpc_destroy_pipe_data(idmap->idmap_pipe); | ||
472 | clp->cl_idmap = NULL; | 485 | clp->cl_idmap = NULL; |
473 | kfree(idmap); | 486 | kfree(idmap); |
474 | } | 487 | } |
475 | 488 | ||
476 | /* | 489 | static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event, |
477 | * Helper routines for manipulating the hashtable | 490 | struct super_block *sb) |
478 | */ | ||
479 | static inline struct idmap_hashent * | ||
480 | idmap_name_hash(struct idmap_hashtable* h, const char *name, size_t len) | ||
481 | { | ||
482 | return &h->h_entries[fnvhash32(name, len) % IDMAP_HASH_SZ]; | ||
483 | } | ||
484 | |||
485 | static struct idmap_hashent * | ||
486 | idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len) | ||
487 | { | 491 | { |
488 | struct idmap_hashent *he = idmap_name_hash(h, name, len); | 492 | int err = 0; |
489 | 493 | ||
490 | if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0) | 494 | switch (event) { |
491 | return NULL; | 495 | case RPC_PIPEFS_MOUNT: |
492 | if (time_after(jiffies, he->ih_expires)) | 496 | BUG_ON(clp->cl_rpcclient->cl_dentry == NULL); |
493 | return NULL; | 497 | err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, |
494 | return he; | 498 | clp->cl_idmap, |
499 | clp->cl_idmap->idmap_pipe); | ||
500 | break; | ||
501 | case RPC_PIPEFS_UMOUNT: | ||
502 | if (clp->cl_idmap->idmap_pipe) { | ||
503 | struct dentry *parent; | ||
504 | |||
505 | parent = clp->cl_idmap->idmap_pipe->dentry->d_parent; | ||
506 | __nfs_idmap_unregister(clp->cl_idmap->idmap_pipe); | ||
507 | /* | ||
508 | * Note: This is a dirty hack. SUNRPC hook has been | ||
509 | * called already but simple_rmdir() call for the | ||
510 | * directory returned with error because of idmap pipe | ||
511 | * inside. Thus now we have to remove this directory | ||
512 | * here. | ||
513 | */ | ||
514 | if (rpc_rmdir(parent)) | ||
515 | printk(KERN_ERR "NFS: %s: failed to remove " | ||
516 | "clnt dir!\n", __func__); | ||
517 | } | ||
518 | break; | ||
519 | default: | ||
520 | printk(KERN_ERR "NFS: %s: unknown event: %ld\n", __func__, | ||
521 | event); | ||
522 | return -ENOTSUPP; | ||
523 | } | ||
524 | return err; | ||
525 | } | ||
526 | |||
527 | static struct nfs_client *nfs_get_client_for_event(struct net *net, int event) | ||
528 | { | ||
529 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
530 | struct dentry *cl_dentry; | ||
531 | struct nfs_client *clp; | ||
532 | |||
533 | spin_lock(&nn->nfs_client_lock); | ||
534 | list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { | ||
535 | if (clp->rpc_ops != &nfs_v4_clientops) | ||
536 | continue; | ||
537 | cl_dentry = clp->cl_idmap->idmap_pipe->dentry; | ||
538 | if (((event == RPC_PIPEFS_MOUNT) && cl_dentry) || | ||
539 | ((event == RPC_PIPEFS_UMOUNT) && !cl_dentry)) | ||
540 | continue; | ||
541 | atomic_inc(&clp->cl_count); | ||
542 | spin_unlock(&nn->nfs_client_lock); | ||
543 | return clp; | ||
544 | } | ||
545 | spin_unlock(&nn->nfs_client_lock); | ||
546 | return NULL; | ||
495 | } | 547 | } |
496 | 548 | ||
497 | static inline struct idmap_hashent * | 549 | static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, |
498 | idmap_id_hash(struct idmap_hashtable* h, __u32 id) | 550 | void *ptr) |
499 | { | 551 | { |
500 | return &h->h_entries[fnvhash32(&id, sizeof(id)) % IDMAP_HASH_SZ]; | 552 | struct super_block *sb = ptr; |
501 | } | 553 | struct nfs_client *clp; |
554 | int error = 0; | ||
502 | 555 | ||
503 | static struct idmap_hashent * | 556 | while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) { |
504 | idmap_lookup_id(struct idmap_hashtable *h, __u32 id) | 557 | error = __rpc_pipefs_event(clp, event, sb); |
505 | { | 558 | nfs_put_client(clp); |
506 | struct idmap_hashent *he = idmap_id_hash(h, id); | 559 | if (error) |
507 | if (he->ih_id != id || he->ih_namelen == 0) | 560 | break; |
508 | return NULL; | 561 | } |
509 | if (time_after(jiffies, he->ih_expires)) | 562 | return error; |
510 | return NULL; | ||
511 | return he; | ||
512 | } | 563 | } |
513 | 564 | ||
514 | /* | 565 | #define PIPEFS_NFS_PRIO 1 |
515 | * Routines for allocating new entries in the hashtable. | 566 | |
516 | * For now, we just have 1 entry per bucket, so it's all | 567 | static struct notifier_block nfs_idmap_block = { |
517 | * pretty trivial. | 568 | .notifier_call = rpc_pipefs_event, |
518 | */ | 569 | .priority = SUNRPC_PIPEFS_NFS_PRIO, |
519 | static inline struct idmap_hashent * | 570 | }; |
520 | idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len) | ||
521 | { | ||
522 | return idmap_name_hash(h, name, len); | ||
523 | } | ||
524 | 571 | ||
525 | static inline struct idmap_hashent * | 572 | int nfs_idmap_init(void) |
526 | idmap_alloc_id(struct idmap_hashtable *h, __u32 id) | ||
527 | { | 573 | { |
528 | return idmap_id_hash(h, id); | 574 | int ret; |
575 | ret = nfs_idmap_init_keyring(); | ||
576 | if (ret != 0) | ||
577 | goto out; | ||
578 | ret = rpc_pipefs_notifier_register(&nfs_idmap_block); | ||
579 | if (ret != 0) | ||
580 | nfs_idmap_quit_keyring(); | ||
581 | out: | ||
582 | return ret; | ||
529 | } | 583 | } |
530 | 584 | ||
531 | static void | 585 | void nfs_idmap_quit(void) |
532 | idmap_update_entry(struct idmap_hashent *he, const char *name, | ||
533 | size_t namelen, __u32 id) | ||
534 | { | 586 | { |
535 | he->ih_id = id; | 587 | rpc_pipefs_notifier_unregister(&nfs_idmap_block); |
536 | memcpy(he->ih_name, name, namelen); | 588 | nfs_idmap_quit_keyring(); |
537 | he->ih_name[namelen] = '\0'; | ||
538 | he->ih_namelen = namelen; | ||
539 | he->ih_expires = jiffies + nfs_idmap_cache_timeout; | ||
540 | } | 589 | } |
541 | 590 | ||
542 | /* | 591 | static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im, |
543 | * Name -> ID | 592 | struct rpc_pipe_msg *msg) |
544 | */ | ||
545 | static int | ||
546 | nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, | ||
547 | const char *name, size_t namelen, __u32 *id) | ||
548 | { | 593 | { |
549 | struct rpc_pipe_msg msg; | 594 | substring_t substr; |
550 | struct idmap_msg *im; | 595 | int token, ret; |
551 | struct idmap_hashent *he; | ||
552 | DECLARE_WAITQUEUE(wq, current); | ||
553 | int ret = -EIO; | ||
554 | |||
555 | im = &idmap->idmap_im; | ||
556 | |||
557 | /* | ||
558 | * String sanity checks | ||
559 | * Note that the userland daemon expects NUL terminated strings | ||
560 | */ | ||
561 | for (;;) { | ||
562 | if (namelen == 0) | ||
563 | return -EINVAL; | ||
564 | if (name[namelen-1] != '\0') | ||
565 | break; | ||
566 | namelen--; | ||
567 | } | ||
568 | if (namelen >= IDMAP_NAMESZ) | ||
569 | return -EINVAL; | ||
570 | 596 | ||
571 | mutex_lock(&idmap->idmap_lock); | 597 | memset(im, 0, sizeof(*im)); |
572 | mutex_lock(&idmap->idmap_im_lock); | 598 | memset(msg, 0, sizeof(*msg)); |
573 | |||
574 | he = idmap_lookup_name(h, name, namelen); | ||
575 | if (he != NULL) { | ||
576 | *id = he->ih_id; | ||
577 | ret = 0; | ||
578 | goto out; | ||
579 | } | ||
580 | 599 | ||
581 | memset(im, 0, sizeof(*im)); | 600 | im->im_type = IDMAP_TYPE_GROUP; |
582 | memcpy(im->im_name, name, namelen); | 601 | token = match_token(desc, nfs_idmap_tokens, &substr); |
583 | 602 | ||
584 | im->im_type = h->h_type; | 603 | switch (token) { |
585 | im->im_conv = IDMAP_CONV_NAMETOID; | 604 | case Opt_find_uid: |
605 | im->im_type = IDMAP_TYPE_USER; | ||
606 | case Opt_find_gid: | ||
607 | im->im_conv = IDMAP_CONV_NAMETOID; | ||
608 | ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ); | ||
609 | break; | ||
586 | 610 | ||
587 | memset(&msg, 0, sizeof(msg)); | 611 | case Opt_find_user: |
588 | msg.data = im; | 612 | im->im_type = IDMAP_TYPE_USER; |
589 | msg.len = sizeof(*im); | 613 | case Opt_find_group: |
614 | im->im_conv = IDMAP_CONV_IDTONAME; | ||
615 | ret = match_int(&substr, &im->im_id); | ||
616 | break; | ||
590 | 617 | ||
591 | add_wait_queue(&idmap->idmap_wq, &wq); | 618 | default: |
592 | if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) { | 619 | ret = -EINVAL; |
593 | remove_wait_queue(&idmap->idmap_wq, &wq); | ||
594 | goto out; | 620 | goto out; |
595 | } | 621 | } |
596 | 622 | ||
597 | set_current_state(TASK_UNINTERRUPTIBLE); | 623 | msg->data = im; |
598 | mutex_unlock(&idmap->idmap_im_lock); | 624 | msg->len = sizeof(struct idmap_msg); |
599 | schedule(); | ||
600 | __set_current_state(TASK_RUNNING); | ||
601 | remove_wait_queue(&idmap->idmap_wq, &wq); | ||
602 | mutex_lock(&idmap->idmap_im_lock); | ||
603 | 625 | ||
604 | if (im->im_status & IDMAP_STATUS_SUCCESS) { | 626 | out: |
605 | *id = im->im_id; | ||
606 | ret = 0; | ||
607 | } | ||
608 | |||
609 | out: | ||
610 | memset(im, 0, sizeof(*im)); | ||
611 | mutex_unlock(&idmap->idmap_im_lock); | ||
612 | mutex_unlock(&idmap->idmap_lock); | ||
613 | return ret; | 627 | return ret; |
614 | } | 628 | } |
615 | 629 | ||
616 | /* | 630 | static int nfs_idmap_legacy_upcall(struct key_construction *cons, |
617 | * ID -> Name | 631 | const char *op, |
618 | */ | 632 | void *aux) |
619 | static int | ||
620 | nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, | ||
621 | __u32 id, char *name) | ||
622 | { | 633 | { |
623 | struct rpc_pipe_msg msg; | 634 | struct rpc_pipe_msg *msg; |
624 | struct idmap_msg *im; | 635 | struct idmap_msg *im; |
625 | struct idmap_hashent *he; | 636 | struct idmap *idmap = (struct idmap *)aux; |
626 | DECLARE_WAITQUEUE(wq, current); | 637 | struct key *key = cons->key; |
627 | int ret = -EIO; | 638 | int ret; |
628 | unsigned int len; | ||
629 | |||
630 | im = &idmap->idmap_im; | ||
631 | 639 | ||
632 | mutex_lock(&idmap->idmap_lock); | 640 | /* msg and im are freed in idmap_pipe_destroy_msg */ |
633 | mutex_lock(&idmap->idmap_im_lock); | 641 | msg = kmalloc(sizeof(*msg), GFP_KERNEL); |
642 | if (IS_ERR(msg)) { | ||
643 | ret = PTR_ERR(msg); | ||
644 | goto out0; | ||
645 | } | ||
634 | 646 | ||
635 | he = idmap_lookup_id(h, id); | 647 | im = kmalloc(sizeof(*im), GFP_KERNEL); |
636 | if (he) { | 648 | if (IS_ERR(im)) { |
637 | memcpy(name, he->ih_name, he->ih_namelen); | 649 | ret = PTR_ERR(im); |
638 | ret = he->ih_namelen; | 650 | goto out1; |
639 | goto out; | ||
640 | } | 651 | } |
641 | 652 | ||
642 | memset(im, 0, sizeof(*im)); | 653 | ret = nfs_idmap_prepare_message(key->description, im, msg); |
643 | im->im_type = h->h_type; | 654 | if (ret < 0) |
644 | im->im_conv = IDMAP_CONV_IDTONAME; | 655 | goto out2; |
645 | im->im_id = id; | ||
646 | 656 | ||
647 | memset(&msg, 0, sizeof(msg)); | 657 | idmap->idmap_key_cons = cons; |
648 | msg.data = im; | ||
649 | msg.len = sizeof(*im); | ||
650 | 658 | ||
651 | add_wait_queue(&idmap->idmap_wq, &wq); | 659 | ret = rpc_queue_upcall(idmap->idmap_pipe, msg); |
660 | if (ret < 0) | ||
661 | goto out2; | ||
652 | 662 | ||
653 | if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) { | 663 | return ret; |
654 | remove_wait_queue(&idmap->idmap_wq, &wq); | 664 | |
655 | goto out; | 665 | out2: |
656 | } | 666 | kfree(im); |
667 | out1: | ||
668 | kfree(msg); | ||
669 | out0: | ||
670 | key_revoke(cons->key); | ||
671 | key_revoke(cons->authkey); | ||
672 | return ret; | ||
673 | } | ||
674 | |||
675 | static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data) | ||
676 | { | ||
677 | return key_instantiate_and_link(key, data, strlen(data) + 1, | ||
678 | id_resolver_cache->thread_keyring, | ||
679 | authkey); | ||
680 | } | ||
657 | 681 | ||
658 | set_current_state(TASK_UNINTERRUPTIBLE); | 682 | static int nfs_idmap_read_message(struct idmap_msg *im, struct key *key, struct key *authkey) |
659 | mutex_unlock(&idmap->idmap_im_lock); | 683 | { |
660 | schedule(); | 684 | char id_str[NFS_UINT_MAXLEN]; |
661 | __set_current_state(TASK_RUNNING); | 685 | int ret = -EINVAL; |
662 | remove_wait_queue(&idmap->idmap_wq, &wq); | 686 | |
663 | mutex_lock(&idmap->idmap_im_lock); | 687 | switch (im->im_conv) { |
664 | 688 | case IDMAP_CONV_NAMETOID: | |
665 | if (im->im_status & IDMAP_STATUS_SUCCESS) { | 689 | sprintf(id_str, "%d", im->im_id); |
666 | if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0) | 690 | ret = nfs_idmap_instantiate(key, authkey, id_str); |
667 | goto out; | 691 | break; |
668 | memcpy(name, im->im_name, len); | 692 | case IDMAP_CONV_IDTONAME: |
669 | ret = len; | 693 | ret = nfs_idmap_instantiate(key, authkey, im->im_name); |
694 | break; | ||
670 | } | 695 | } |
671 | 696 | ||
672 | out: | ||
673 | memset(im, 0, sizeof(*im)); | ||
674 | mutex_unlock(&idmap->idmap_im_lock); | ||
675 | mutex_unlock(&idmap->idmap_lock); | ||
676 | return ret; | 697 | return ret; |
677 | } | 698 | } |
678 | 699 | ||
@@ -681,115 +702,51 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
681 | { | 702 | { |
682 | struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); | 703 | struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); |
683 | struct idmap *idmap = (struct idmap *)rpci->private; | 704 | struct idmap *idmap = (struct idmap *)rpci->private; |
684 | struct idmap_msg im_in, *im = &idmap->idmap_im; | 705 | struct key_construction *cons = idmap->idmap_key_cons; |
685 | struct idmap_hashtable *h; | 706 | struct idmap_msg im; |
686 | struct idmap_hashent *he = NULL; | ||
687 | size_t namelen_in; | 707 | size_t namelen_in; |
688 | int ret; | 708 | int ret; |
689 | 709 | ||
690 | if (mlen != sizeof(im_in)) | 710 | if (mlen != sizeof(im)) { |
691 | return -ENOSPC; | 711 | ret = -ENOSPC; |
692 | |||
693 | if (copy_from_user(&im_in, src, mlen) != 0) | ||
694 | return -EFAULT; | ||
695 | |||
696 | mutex_lock(&idmap->idmap_im_lock); | ||
697 | |||
698 | ret = mlen; | ||
699 | im->im_status = im_in.im_status; | ||
700 | /* If we got an error, terminate now, and wake up pending upcalls */ | ||
701 | if (!(im_in.im_status & IDMAP_STATUS_SUCCESS)) { | ||
702 | wake_up(&idmap->idmap_wq); | ||
703 | goto out; | 712 | goto out; |
704 | } | 713 | } |
705 | 714 | ||
706 | /* Sanity checking of strings */ | 715 | if (copy_from_user(&im, src, mlen) != 0) { |
707 | ret = -EINVAL; | 716 | ret = -EFAULT; |
708 | namelen_in = strnlen(im_in.im_name, IDMAP_NAMESZ); | ||
709 | if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) | ||
710 | goto out; | 717 | goto out; |
718 | } | ||
711 | 719 | ||
712 | switch (im_in.im_type) { | 720 | if (!(im.im_status & IDMAP_STATUS_SUCCESS)) { |
713 | case IDMAP_TYPE_USER: | 721 | ret = mlen; |
714 | h = &idmap->idmap_user_hash; | 722 | complete_request_key(idmap->idmap_key_cons, -ENOKEY); |
715 | break; | 723 | goto out_incomplete; |
716 | case IDMAP_TYPE_GROUP: | ||
717 | h = &idmap->idmap_group_hash; | ||
718 | break; | ||
719 | default: | ||
720 | goto out; | ||
721 | } | 724 | } |
722 | 725 | ||
723 | switch (im_in.im_conv) { | 726 | namelen_in = strnlen(im.im_name, IDMAP_NAMESZ); |
724 | case IDMAP_CONV_IDTONAME: | 727 | if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) { |
725 | /* Did we match the current upcall? */ | 728 | ret = -EINVAL; |
726 | if (im->im_conv == IDMAP_CONV_IDTONAME | ||
727 | && im->im_type == im_in.im_type | ||
728 | && im->im_id == im_in.im_id) { | ||
729 | /* Yes: copy string, including the terminating '\0' */ | ||
730 | memcpy(im->im_name, im_in.im_name, namelen_in); | ||
731 | im->im_name[namelen_in] = '\0'; | ||
732 | wake_up(&idmap->idmap_wq); | ||
733 | } | ||
734 | he = idmap_alloc_id(h, im_in.im_id); | ||
735 | break; | ||
736 | case IDMAP_CONV_NAMETOID: | ||
737 | /* Did we match the current upcall? */ | ||
738 | if (im->im_conv == IDMAP_CONV_NAMETOID | ||
739 | && im->im_type == im_in.im_type | ||
740 | && strnlen(im->im_name, IDMAP_NAMESZ) == namelen_in | ||
741 | && memcmp(im->im_name, im_in.im_name, namelen_in) == 0) { | ||
742 | im->im_id = im_in.im_id; | ||
743 | wake_up(&idmap->idmap_wq); | ||
744 | } | ||
745 | he = idmap_alloc_name(h, im_in.im_name, namelen_in); | ||
746 | break; | ||
747 | default: | ||
748 | goto out; | 729 | goto out; |
749 | } | 730 | } |
750 | 731 | ||
751 | /* If the entry is valid, also copy it to the cache */ | 732 | ret = nfs_idmap_read_message(&im, cons->key, cons->authkey); |
752 | if (he != NULL) | 733 | if (ret >= 0) { |
753 | idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id); | 734 | key_set_timeout(cons->key, nfs_idmap_cache_timeout); |
754 | ret = mlen; | 735 | ret = mlen; |
736 | } | ||
737 | |||
755 | out: | 738 | out: |
756 | mutex_unlock(&idmap->idmap_im_lock); | 739 | complete_request_key(idmap->idmap_key_cons, ret); |
740 | out_incomplete: | ||
757 | return ret; | 741 | return ret; |
758 | } | 742 | } |
759 | 743 | ||
760 | static void | 744 | static void |
761 | idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) | 745 | idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) |
762 | { | 746 | { |
763 | struct idmap_msg *im = msg->data; | 747 | /* Free memory allocated in nfs_idmap_legacy_upcall() */ |
764 | struct idmap *idmap = container_of(im, struct idmap, idmap_im); | 748 | kfree(msg->data); |
765 | 749 | kfree(msg); | |
766 | if (msg->errno >= 0) | ||
767 | return; | ||
768 | mutex_lock(&idmap->idmap_im_lock); | ||
769 | im->im_status = IDMAP_STATUS_LOOKUPFAIL; | ||
770 | wake_up(&idmap->idmap_wq); | ||
771 | mutex_unlock(&idmap->idmap_im_lock); | ||
772 | } | ||
773 | |||
774 | /* | ||
775 | * Fowler/Noll/Vo hash | ||
776 | * http://www.isthe.com/chongo/tech/comp/fnv/ | ||
777 | */ | ||
778 | |||
779 | #define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */ | ||
780 | #define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */ | ||
781 | |||
782 | static unsigned int fnvhash32(const void *buf, size_t buflen) | ||
783 | { | ||
784 | const unsigned char *p, *end = (const unsigned char *)buf + buflen; | ||
785 | unsigned int hash = FNV_1_32; | ||
786 | |||
787 | for (p = buf; p < end; p++) { | ||
788 | hash *= FNV_P_32; | ||
789 | hash ^= (unsigned int)*p; | ||
790 | } | ||
791 | |||
792 | return hash; | ||
793 | } | 750 | } |
794 | 751 | ||
795 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) | 752 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) |
@@ -798,16 +755,16 @@ int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_ | |||
798 | 755 | ||
799 | if (nfs_map_string_to_numeric(name, namelen, uid)) | 756 | if (nfs_map_string_to_numeric(name, namelen, uid)) |
800 | return 0; | 757 | return 0; |
801 | return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid); | 758 | return nfs_idmap_lookup_id(name, namelen, "uid", uid, idmap); |
802 | } | 759 | } |
803 | 760 | ||
804 | int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) | 761 | int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid) |
805 | { | 762 | { |
806 | struct idmap *idmap = server->nfs_client->cl_idmap; | 763 | struct idmap *idmap = server->nfs_client->cl_idmap; |
807 | 764 | ||
808 | if (nfs_map_string_to_numeric(name, namelen, uid)) | 765 | if (nfs_map_string_to_numeric(name, namelen, gid)) |
809 | return 0; | 766 | return 0; |
810 | return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid); | 767 | return nfs_idmap_lookup_id(name, namelen, "gid", gid, idmap); |
811 | } | 768 | } |
812 | 769 | ||
813 | int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) | 770 | int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) |
@@ -816,21 +773,19 @@ int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, s | |||
816 | int ret = -EINVAL; | 773 | int ret = -EINVAL; |
817 | 774 | ||
818 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) | 775 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) |
819 | ret = nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf); | 776 | ret = nfs_idmap_lookup_name(uid, "user", buf, buflen, idmap); |
820 | if (ret < 0) | 777 | if (ret < 0) |
821 | ret = nfs_map_numeric_to_string(uid, buf, buflen); | 778 | ret = nfs_map_numeric_to_string(uid, buf, buflen); |
822 | return ret; | 779 | return ret; |
823 | } | 780 | } |
824 | int nfs_map_gid_to_group(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) | 781 | int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen) |
825 | { | 782 | { |
826 | struct idmap *idmap = server->nfs_client->cl_idmap; | 783 | struct idmap *idmap = server->nfs_client->cl_idmap; |
827 | int ret = -EINVAL; | 784 | int ret = -EINVAL; |
828 | 785 | ||
829 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) | 786 | if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) |
830 | ret = nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf); | 787 | ret = nfs_idmap_lookup_name(gid, "group", buf, buflen, idmap); |
831 | if (ret < 0) | 788 | if (ret < 0) |
832 | ret = nfs_map_numeric_to_string(uid, buf, buflen); | 789 | ret = nfs_map_numeric_to_string(gid, buf, buflen); |
833 | return ret; | 790 | return ret; |
834 | } | 791 | } |
835 | |||
836 | #endif /* CONFIG_NFS_USE_NEW_IDMAPPER */ | ||