diff options
Diffstat (limited to 'fs/nfs/idmap.c')
-rw-r--r-- | fs/nfs/idmap.c | 195 |
1 files changed, 43 insertions, 152 deletions
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index c2c4163d5683..567983d2c0eb 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -49,6 +49,7 @@ | |||
49 | 49 | ||
50 | #include "internal.h" | 50 | #include "internal.h" |
51 | #include "netns.h" | 51 | #include "netns.h" |
52 | #include "nfs4trace.h" | ||
52 | 53 | ||
53 | #define NFS_UINT_MAXLEN 11 | 54 | #define NFS_UINT_MAXLEN 11 |
54 | 55 | ||
@@ -63,6 +64,7 @@ struct idmap_legacy_upcalldata { | |||
63 | }; | 64 | }; |
64 | 65 | ||
65 | struct idmap { | 66 | struct idmap { |
67 | struct rpc_pipe_dir_object idmap_pdo; | ||
66 | struct rpc_pipe *idmap_pipe; | 68 | struct rpc_pipe *idmap_pipe; |
67 | struct idmap_legacy_upcalldata *idmap_upcall_data; | 69 | struct idmap_legacy_upcalldata *idmap_upcall_data; |
68 | struct mutex idmap_mutex; | 70 | struct mutex idmap_mutex; |
@@ -310,7 +312,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen, | |||
310 | if (ret < 0) | 312 | if (ret < 0) |
311 | goto out_up; | 313 | goto out_up; |
312 | 314 | ||
313 | payload = rcu_dereference(rkey->payload.data); | 315 | payload = rcu_dereference(rkey->payload.rcudata); |
314 | if (IS_ERR_OR_NULL(payload)) { | 316 | if (IS_ERR_OR_NULL(payload)) { |
315 | ret = PTR_ERR(payload); | 317 | ret = PTR_ERR(payload); |
316 | goto out_up; | 318 | goto out_up; |
@@ -401,16 +403,23 @@ static struct key_type key_type_id_resolver_legacy = { | |||
401 | .request_key = nfs_idmap_legacy_upcall, | 403 | .request_key = nfs_idmap_legacy_upcall, |
402 | }; | 404 | }; |
403 | 405 | ||
404 | static void __nfs_idmap_unregister(struct rpc_pipe *pipe) | 406 | static void nfs_idmap_pipe_destroy(struct dentry *dir, |
407 | struct rpc_pipe_dir_object *pdo) | ||
405 | { | 408 | { |
406 | if (pipe->dentry) | 409 | struct idmap *idmap = pdo->pdo_data; |
410 | struct rpc_pipe *pipe = idmap->idmap_pipe; | ||
411 | |||
412 | if (pipe->dentry) { | ||
407 | rpc_unlink(pipe->dentry); | 413 | rpc_unlink(pipe->dentry); |
414 | pipe->dentry = NULL; | ||
415 | } | ||
408 | } | 416 | } |
409 | 417 | ||
410 | static int __nfs_idmap_register(struct dentry *dir, | 418 | static int nfs_idmap_pipe_create(struct dentry *dir, |
411 | struct idmap *idmap, | 419 | struct rpc_pipe_dir_object *pdo) |
412 | struct rpc_pipe *pipe) | ||
413 | { | 420 | { |
421 | struct idmap *idmap = pdo->pdo_data; | ||
422 | struct rpc_pipe *pipe = idmap->idmap_pipe; | ||
414 | struct dentry *dentry; | 423 | struct dentry *dentry; |
415 | 424 | ||
416 | dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe); | 425 | dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe); |
@@ -420,36 +429,10 @@ static int __nfs_idmap_register(struct dentry *dir, | |||
420 | return 0; | 429 | return 0; |
421 | } | 430 | } |
422 | 431 | ||
423 | static void nfs_idmap_unregister(struct nfs_client *clp, | 432 | static const struct rpc_pipe_dir_object_ops nfs_idmap_pipe_dir_object_ops = { |
424 | struct rpc_pipe *pipe) | 433 | .create = nfs_idmap_pipe_create, |
425 | { | 434 | .destroy = nfs_idmap_pipe_destroy, |
426 | struct net *net = clp->cl_net; | 435 | }; |
427 | struct super_block *pipefs_sb; | ||
428 | |||
429 | pipefs_sb = rpc_get_sb_net(net); | ||
430 | if (pipefs_sb) { | ||
431 | __nfs_idmap_unregister(pipe); | ||
432 | rpc_put_sb_net(net); | ||
433 | } | ||
434 | } | ||
435 | |||
436 | static int nfs_idmap_register(struct nfs_client *clp, | ||
437 | struct idmap *idmap, | ||
438 | struct rpc_pipe *pipe) | ||
439 | { | ||
440 | struct net *net = clp->cl_net; | ||
441 | struct super_block *pipefs_sb; | ||
442 | int err = 0; | ||
443 | |||
444 | pipefs_sb = rpc_get_sb_net(net); | ||
445 | if (pipefs_sb) { | ||
446 | if (clp->cl_rpcclient->cl_dentry) | ||
447 | err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, | ||
448 | idmap, pipe); | ||
449 | rpc_put_sb_net(net); | ||
450 | } | ||
451 | return err; | ||
452 | } | ||
453 | 436 | ||
454 | int | 437 | int |
455 | nfs_idmap_new(struct nfs_client *clp) | 438 | nfs_idmap_new(struct nfs_client *clp) |
@@ -462,23 +445,31 @@ nfs_idmap_new(struct nfs_client *clp) | |||
462 | if (idmap == NULL) | 445 | if (idmap == NULL) |
463 | return -ENOMEM; | 446 | return -ENOMEM; |
464 | 447 | ||
448 | rpc_init_pipe_dir_object(&idmap->idmap_pdo, | ||
449 | &nfs_idmap_pipe_dir_object_ops, | ||
450 | idmap); | ||
451 | |||
465 | pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0); | 452 | pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0); |
466 | if (IS_ERR(pipe)) { | 453 | if (IS_ERR(pipe)) { |
467 | error = PTR_ERR(pipe); | 454 | error = PTR_ERR(pipe); |
468 | kfree(idmap); | 455 | goto err; |
469 | return error; | ||
470 | } | ||
471 | error = nfs_idmap_register(clp, idmap, pipe); | ||
472 | if (error) { | ||
473 | rpc_destroy_pipe_data(pipe); | ||
474 | kfree(idmap); | ||
475 | return error; | ||
476 | } | 456 | } |
477 | idmap->idmap_pipe = pipe; | 457 | idmap->idmap_pipe = pipe; |
478 | mutex_init(&idmap->idmap_mutex); | 458 | mutex_init(&idmap->idmap_mutex); |
479 | 459 | ||
460 | error = rpc_add_pipe_dir_object(clp->cl_net, | ||
461 | &clp->cl_rpcclient->cl_pipedir_objects, | ||
462 | &idmap->idmap_pdo); | ||
463 | if (error) | ||
464 | goto err_destroy_pipe; | ||
465 | |||
480 | clp->cl_idmap = idmap; | 466 | clp->cl_idmap = idmap; |
481 | return 0; | 467 | return 0; |
468 | err_destroy_pipe: | ||
469 | rpc_destroy_pipe_data(idmap->idmap_pipe); | ||
470 | err: | ||
471 | kfree(idmap); | ||
472 | return error; | ||
482 | } | 473 | } |
483 | 474 | ||
484 | void | 475 | void |
@@ -488,130 +479,26 @@ nfs_idmap_delete(struct nfs_client *clp) | |||
488 | 479 | ||
489 | if (!idmap) | 480 | if (!idmap) |
490 | return; | 481 | return; |
491 | nfs_idmap_unregister(clp, idmap->idmap_pipe); | ||
492 | rpc_destroy_pipe_data(idmap->idmap_pipe); | ||
493 | clp->cl_idmap = NULL; | 482 | clp->cl_idmap = NULL; |
483 | rpc_remove_pipe_dir_object(clp->cl_net, | ||
484 | &clp->cl_rpcclient->cl_pipedir_objects, | ||
485 | &idmap->idmap_pdo); | ||
486 | rpc_destroy_pipe_data(idmap->idmap_pipe); | ||
494 | kfree(idmap); | 487 | kfree(idmap); |
495 | } | 488 | } |
496 | 489 | ||
497 | static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event, | ||
498 | struct super_block *sb) | ||
499 | { | ||
500 | int err = 0; | ||
501 | |||
502 | switch (event) { | ||
503 | case RPC_PIPEFS_MOUNT: | ||
504 | err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, | ||
505 | clp->cl_idmap, | ||
506 | clp->cl_idmap->idmap_pipe); | ||
507 | break; | ||
508 | case RPC_PIPEFS_UMOUNT: | ||
509 | if (clp->cl_idmap->idmap_pipe) { | ||
510 | struct dentry *parent; | ||
511 | |||
512 | parent = clp->cl_idmap->idmap_pipe->dentry->d_parent; | ||
513 | __nfs_idmap_unregister(clp->cl_idmap->idmap_pipe); | ||
514 | /* | ||
515 | * Note: This is a dirty hack. SUNRPC hook has been | ||
516 | * called already but simple_rmdir() call for the | ||
517 | * directory returned with error because of idmap pipe | ||
518 | * inside. Thus now we have to remove this directory | ||
519 | * here. | ||
520 | */ | ||
521 | if (rpc_rmdir(parent)) | ||
522 | printk(KERN_ERR "NFS: %s: failed to remove " | ||
523 | "clnt dir!\n", __func__); | ||
524 | } | ||
525 | break; | ||
526 | default: | ||
527 | printk(KERN_ERR "NFS: %s: unknown event: %ld\n", __func__, | ||
528 | event); | ||
529 | return -ENOTSUPP; | ||
530 | } | ||
531 | return err; | ||
532 | } | ||
533 | |||
534 | static struct nfs_client *nfs_get_client_for_event(struct net *net, int event) | ||
535 | { | ||
536 | struct nfs_net *nn = net_generic(net, nfs_net_id); | ||
537 | struct dentry *cl_dentry; | ||
538 | struct nfs_client *clp; | ||
539 | int err; | ||
540 | |||
541 | restart: | ||
542 | spin_lock(&nn->nfs_client_lock); | ||
543 | list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { | ||
544 | /* Wait for initialisation to finish */ | ||
545 | if (clp->cl_cons_state == NFS_CS_INITING) { | ||
546 | atomic_inc(&clp->cl_count); | ||
547 | spin_unlock(&nn->nfs_client_lock); | ||
548 | err = nfs_wait_client_init_complete(clp); | ||
549 | nfs_put_client(clp); | ||
550 | if (err) | ||
551 | return NULL; | ||
552 | goto restart; | ||
553 | } | ||
554 | /* Skip nfs_clients that failed to initialise */ | ||
555 | if (clp->cl_cons_state < 0) | ||
556 | continue; | ||
557 | smp_rmb(); | ||
558 | if (clp->rpc_ops != &nfs_v4_clientops) | ||
559 | continue; | ||
560 | cl_dentry = clp->cl_idmap->idmap_pipe->dentry; | ||
561 | if (((event == RPC_PIPEFS_MOUNT) && cl_dentry) || | ||
562 | ((event == RPC_PIPEFS_UMOUNT) && !cl_dentry)) | ||
563 | continue; | ||
564 | atomic_inc(&clp->cl_count); | ||
565 | spin_unlock(&nn->nfs_client_lock); | ||
566 | return clp; | ||
567 | } | ||
568 | spin_unlock(&nn->nfs_client_lock); | ||
569 | return NULL; | ||
570 | } | ||
571 | |||
572 | static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, | ||
573 | void *ptr) | ||
574 | { | ||
575 | struct super_block *sb = ptr; | ||
576 | struct nfs_client *clp; | ||
577 | int error = 0; | ||
578 | |||
579 | if (!try_module_get(THIS_MODULE)) | ||
580 | return 0; | ||
581 | |||
582 | while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) { | ||
583 | error = __rpc_pipefs_event(clp, event, sb); | ||
584 | nfs_put_client(clp); | ||
585 | if (error) | ||
586 | break; | ||
587 | } | ||
588 | module_put(THIS_MODULE); | ||
589 | return error; | ||
590 | } | ||
591 | |||
592 | #define PIPEFS_NFS_PRIO 1 | ||
593 | |||
594 | static struct notifier_block nfs_idmap_block = { | ||
595 | .notifier_call = rpc_pipefs_event, | ||
596 | .priority = SUNRPC_PIPEFS_NFS_PRIO, | ||
597 | }; | ||
598 | |||
599 | int nfs_idmap_init(void) | 490 | int nfs_idmap_init(void) |
600 | { | 491 | { |
601 | int ret; | 492 | int ret; |
602 | ret = nfs_idmap_init_keyring(); | 493 | ret = nfs_idmap_init_keyring(); |
603 | if (ret != 0) | 494 | if (ret != 0) |
604 | goto out; | 495 | goto out; |
605 | ret = rpc_pipefs_notifier_register(&nfs_idmap_block); | ||
606 | if (ret != 0) | ||
607 | nfs_idmap_quit_keyring(); | ||
608 | out: | 496 | out: |
609 | return ret; | 497 | return ret; |
610 | } | 498 | } |
611 | 499 | ||
612 | void nfs_idmap_quit(void) | 500 | void nfs_idmap_quit(void) |
613 | { | 501 | { |
614 | rpc_pipefs_notifier_unregister(&nfs_idmap_block); | ||
615 | nfs_idmap_quit_keyring(); | 502 | nfs_idmap_quit_keyring(); |
616 | } | 503 | } |
617 | 504 | ||
@@ -849,6 +736,7 @@ int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_ | |||
849 | if (!uid_valid(*uid)) | 736 | if (!uid_valid(*uid)) |
850 | ret = -ERANGE; | 737 | ret = -ERANGE; |
851 | } | 738 | } |
739 | trace_nfs4_map_name_to_uid(name, namelen, id, ret); | ||
852 | return ret; | 740 | return ret; |
853 | } | 741 | } |
854 | 742 | ||
@@ -865,6 +753,7 @@ int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size | |||
865 | if (!gid_valid(*gid)) | 753 | if (!gid_valid(*gid)) |
866 | ret = -ERANGE; | 754 | ret = -ERANGE; |
867 | } | 755 | } |
756 | trace_nfs4_map_group_to_gid(name, namelen, id, ret); | ||
868 | return ret; | 757 | return ret; |
869 | } | 758 | } |
870 | 759 | ||
@@ -879,6 +768,7 @@ int nfs_map_uid_to_name(const struct nfs_server *server, kuid_t uid, char *buf, | |||
879 | ret = nfs_idmap_lookup_name(id, "user", buf, buflen, idmap); | 768 | ret = nfs_idmap_lookup_name(id, "user", buf, buflen, idmap); |
880 | if (ret < 0) | 769 | if (ret < 0) |
881 | ret = nfs_map_numeric_to_string(id, buf, buflen); | 770 | ret = nfs_map_numeric_to_string(id, buf, buflen); |
771 | trace_nfs4_map_uid_to_name(buf, ret, id, ret); | ||
882 | return ret; | 772 | return ret; |
883 | } | 773 | } |
884 | int nfs_map_gid_to_group(const struct nfs_server *server, kgid_t gid, char *buf, size_t buflen) | 774 | int nfs_map_gid_to_group(const struct nfs_server *server, kgid_t gid, char *buf, size_t buflen) |
@@ -892,5 +782,6 @@ int nfs_map_gid_to_group(const struct nfs_server *server, kgid_t gid, char *buf, | |||
892 | ret = nfs_idmap_lookup_name(id, "group", buf, buflen, idmap); | 782 | ret = nfs_idmap_lookup_name(id, "group", buf, buflen, idmap); |
893 | if (ret < 0) | 783 | if (ret < 0) |
894 | ret = nfs_map_numeric_to_string(id, buf, buflen); | 784 | ret = nfs_map_numeric_to_string(id, buf, buflen); |
785 | trace_nfs4_map_gid_to_group(buf, ret, id, ret); | ||
895 | return ret; | 786 | return ret; |
896 | } | 787 | } |