aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/idmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/idmap.c')
-rw-r--r--fs/nfs/idmap.c195
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
65struct idmap { 66struct 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
404static void __nfs_idmap_unregister(struct rpc_pipe *pipe) 406static 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
410static int __nfs_idmap_register(struct dentry *dir, 418static 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
423static void nfs_idmap_unregister(struct nfs_client *clp, 432static 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
436static 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
454int 437int
455nfs_idmap_new(struct nfs_client *clp) 438nfs_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;
468err_destroy_pipe:
469 rpc_destroy_pipe_data(idmap->idmap_pipe);
470err:
471 kfree(idmap);
472 return error;
482} 473}
483 474
484void 475void
@@ -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
497static 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
534static 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
541restart:
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
572static 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
594static struct notifier_block nfs_idmap_block = {
595 .notifier_call = rpc_pipefs_event,
596 .priority = SUNRPC_PIPEFS_NFS_PRIO,
597};
598
599int nfs_idmap_init(void) 490int 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();
608out: 496out:
609 return ret; 497 return ret;
610} 498}
611 499
612void nfs_idmap_quit(void) 500void 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}
884int nfs_map_gid_to_group(const struct nfs_server *server, kgid_t gid, char *buf, size_t buflen) 774int 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}