aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/idmap.c
diff options
context:
space:
mode:
authorBryan Schumaker <bjschuma@netapp.com>2012-02-24 14:14:51 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-03-01 17:10:16 -0500
commit57e62324e469e092ecc6c94a7a86fe4bd6ac5172 (patch)
tree162a5ecd487bc842bc07cc8d4c14d4d1a337813d /fs/nfs/idmap.c
parent59e6b9c11341e3b8ac5925427c903d4eae435bd8 (diff)
NFS: Store the legacy idmapper result in the keyring
This patch removes the old hashmap-based caching and instead uses a "request key actor" to place an upcall to the legacy idmapper rather than going through /sbin/request-key. This will only be used as a fallback if /etc/request-key.conf isn't configured to use nfsidmap. Signed-off-by: Bryan Schumaker <bjschuma@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/idmap.c')
-rw-r--r--fs/nfs/idmap.c554
1 files changed, 166 insertions, 388 deletions
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index d4db3b6f4b8e..f72c1fc074e1 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -34,42 +34,28 @@
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>
42#include <linux/cred.h>
43#include <linux/sunrpc/sched.h>
44#include <linux/nfs4.h>
45#include <linux/nfs_fs_sb.h> 43#include <linux/nfs_fs_sb.h>
44#include <linux/key.h>
46#include <linux/keyctl.h> 45#include <linux/keyctl.h>
47#include <linux/key-type.h> 46#include <linux/key-type.h>
48#include <linux/rcupdate.h>
49#include <linux/err.h>
50#include <keys/user-type.h> 47#include <keys/user-type.h>
51
52/* include files needed by legacy idmapper */
53#include <linux/module.h> 48#include <linux/module.h>
54#include <linux/mutex.h> 49
55#include <linux/init.h>
56#include <linux/socket.h>
57#include <linux/in.h>
58#include <linux/sched.h>
59#include <linux/sunrpc/clnt.h>
60#include <linux/workqueue.h>
61#include <linux/sunrpc/rpc_pipe_fs.h>
62#include <linux/nfs_fs.h>
63#include "nfs4_fs.h"
64#include "internal.h" 50#include "internal.h"
65#include "netns.h" 51#include "netns.h"
66 52
67#define NFS_UINT_MAXLEN 11 53#define NFS_UINT_MAXLEN 11
68#define IDMAP_HASH_SZ 128
69 54
70/* Default cache timeout is 10 minutes */ 55/* Default cache timeout is 10 minutes */
71unsigned int nfs_idmap_cache_timeout = 600 * HZ; 56unsigned int nfs_idmap_cache_timeout = 600;
72const struct cred *id_resolver_cache; 57const struct cred *id_resolver_cache;
58struct key_type key_type_id_resolver_legacy;
73 59
74 60
75/** 61/**
@@ -261,8 +247,10 @@ static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen,
261 return desclen; 247 return desclen;
262} 248}
263 249
264static ssize_t nfs_idmap_request_key(const char *name, size_t namelen, 250static ssize_t nfs_idmap_request_key(struct key_type *key_type,
265 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)
266{ 254{
267 const struct cred *saved_cred; 255 const struct cred *saved_cred;
268 struct key *rkey; 256 struct key *rkey;
@@ -275,8 +263,12 @@ static ssize_t nfs_idmap_request_key(const char *name, size_t namelen,
275 goto out; 263 goto out;
276 264
277 saved_cred = override_creds(id_resolver_cache); 265 saved_cred = override_creds(id_resolver_cache);
278 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, "");
279 revert_creds(saved_cred); 270 revert_creds(saved_cred);
271
280 kfree(desc); 272 kfree(desc);
281 if (IS_ERR(rkey)) { 273 if (IS_ERR(rkey)) {
282 ret = PTR_ERR(rkey); 274 ret = PTR_ERR(rkey);
@@ -309,31 +301,46 @@ out:
309 return ret; 301 return ret;
310} 302}
311 303
304static 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}
312 318
313/* ID -> Name */ 319/* ID -> Name */
314static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, size_t buflen) 320static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf,
321 size_t buflen, struct idmap *idmap)
315{ 322{
316 char id_str[NFS_UINT_MAXLEN]; 323 char id_str[NFS_UINT_MAXLEN];
317 int id_len; 324 int id_len;
318 ssize_t ret; 325 ssize_t ret;
319 326
320 id_len = snprintf(id_str, sizeof(id_str), "%u", id); 327 id_len = snprintf(id_str, sizeof(id_str), "%u", id);
321 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);
322 if (ret < 0) 329 if (ret < 0)
323 return -EINVAL; 330 return -EINVAL;
324 return ret; 331 return ret;
325} 332}
326 333
327/* Name -> ID */ 334/* Name -> ID */
328static int nfs_idmap_lookup_id(const char *name, size_t namelen, 335static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *type,
329 const char *type, __u32 *id) 336 __u32 *id, struct idmap *idmap)
330{ 337{
331 char id_str[NFS_UINT_MAXLEN]; 338 char id_str[NFS_UINT_MAXLEN];
332 long id_long; 339 long id_long;
333 ssize_t data_size; 340 ssize_t data_size;
334 int ret = 0; 341 int ret = 0;
335 342
336 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);
337 if (data_size <= 0) { 344 if (data_size <= 0) {
338 ret = -EINVAL; 345 ret = -EINVAL;
339 } else { 346 } else {
@@ -344,54 +351,47 @@ static int nfs_idmap_lookup_id(const char *name, size_t namelen,
344} 351}
345 352
346/* idmap classic begins here */ 353/* idmap classic begins here */
347static int param_set_idmap_timeout(const char *val, struct kernel_param *kp) 354module_param(nfs_idmap_cache_timeout, int, 0644);
348{
349 char *endp;
350 int num = simple_strtol(val, &endp, 0);
351 int jif = num * HZ;
352 if (endp == val || *endp || num < 0 || jif < num)
353 return -EINVAL;
354 *((int *)kp->arg) = jif;
355 return 0;
356}
357
358module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
359 &nfs_idmap_cache_timeout, 0644);
360 355
361struct idmap_hashent { 356struct idmap {
362 unsigned long ih_expires; 357 struct rpc_pipe *idmap_pipe;
363 __u32 ih_id; 358 struct key_construction *idmap_key_cons;
364 size_t ih_namelen;
365 const char *ih_name;
366}; 359};
367 360
368struct idmap_hashtable { 361enum {
369 __u8 h_type; 362 Opt_find_uid, Opt_find_gid, Opt_find_user, Opt_find_group, Opt_find_err
370 struct idmap_hashent *h_entries;
371}; 363};
372 364
373struct idmap { 365static const match_table_t nfs_idmap_tokens = {
374 struct rpc_pipe *idmap_pipe; 366 { Opt_find_uid, "uid:%s" },
375 wait_queue_head_t idmap_wq; 367 { Opt_find_gid, "gid:%s" },
376 struct idmap_msg idmap_im; 368 { Opt_find_user, "user:%s" },
377 struct mutex idmap_lock; /* Serializes upcalls */ 369 { Opt_find_group, "group:%s" },
378 struct mutex idmap_im_lock; /* Protects the hashtable */ 370 { Opt_find_err, NULL }
379 struct idmap_hashtable idmap_user_hash;
380 struct idmap_hashtable idmap_group_hash;
381}; 371};
382 372
373static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *);
383static ssize_t idmap_pipe_downcall(struct file *, const char __user *, 374static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
384 size_t); 375 size_t);
385static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); 376static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
386 377
387static unsigned int fnvhash32(const void *, size_t);
388
389static const struct rpc_pipe_ops idmap_upcall_ops = { 378static const struct rpc_pipe_ops idmap_upcall_ops = {
390 .upcall = rpc_pipe_generic_upcall, 379 .upcall = rpc_pipe_generic_upcall,
391 .downcall = idmap_pipe_downcall, 380 .downcall = idmap_pipe_downcall,
392 .destroy_msg = idmap_pipe_destroy_msg, 381 .destroy_msg = idmap_pipe_destroy_msg,
393}; 382};
394 383
384struct 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
395static void __nfs_idmap_unregister(struct rpc_pipe *pipe) 395static void __nfs_idmap_unregister(struct rpc_pipe *pipe)
396{ 396{
397 if (pipe->dentry) 397 if (pipe->dentry)
@@ -468,38 +468,11 @@ nfs_idmap_new(struct nfs_client *clp)
468 return error; 468 return error;
469 } 469 }
470 idmap->idmap_pipe = pipe; 470 idmap->idmap_pipe = pipe;
471 mutex_init(&idmap->idmap_lock);
472 mutex_init(&idmap->idmap_im_lock);
473 init_waitqueue_head(&idmap->idmap_wq);
474 idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER;
475 idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP;
476 471
477 clp->cl_idmap = idmap; 472 clp->cl_idmap = idmap;
478 return 0; 473 return 0;
479} 474}
480 475
481static void
482idmap_alloc_hashtable(struct idmap_hashtable *h)
483{
484 if (h->h_entries != NULL)
485 return;
486 h->h_entries = kcalloc(IDMAP_HASH_SZ,
487 sizeof(*h->h_entries),
488 GFP_KERNEL);
489}
490
491static void
492idmap_free_hashtable(struct idmap_hashtable *h)
493{
494 int i;
495
496 if (h->h_entries == NULL)
497 return;
498 for (i = 0; i < IDMAP_HASH_SZ; i++)
499 kfree(h->h_entries[i].ih_name);
500 kfree(h->h_entries);
501}
502
503void 476void
504nfs_idmap_delete(struct nfs_client *clp) 477nfs_idmap_delete(struct nfs_client *clp)
505{ 478{
@@ -510,8 +483,6 @@ nfs_idmap_delete(struct nfs_client *clp)
510 nfs_idmap_unregister(clp, idmap->idmap_pipe); 483 nfs_idmap_unregister(clp, idmap->idmap_pipe);
511 rpc_destroy_pipe_data(idmap->idmap_pipe); 484 rpc_destroy_pipe_data(idmap->idmap_pipe);
512 clp->cl_idmap = NULL; 485 clp->cl_idmap = NULL;
513 idmap_free_hashtable(&idmap->idmap_user_hash);
514 idmap_free_hashtable(&idmap->idmap_group_hash);
515 kfree(idmap); 486 kfree(idmap);
516} 487}
517 488
@@ -617,222 +588,107 @@ void nfs_idmap_quit(void)
617 nfs_idmap_quit_keyring(); 588 nfs_idmap_quit_keyring();
618} 589}
619 590
620/* 591static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im,
621 * Helper routines for manipulating the hashtable 592 struct rpc_pipe_msg *msg)
622 */
623static inline struct idmap_hashent *
624idmap_name_hash(struct idmap_hashtable* h, const char *name, size_t len)
625{
626 if (h->h_entries == NULL)
627 return NULL;
628 return &h->h_entries[fnvhash32(name, len) % IDMAP_HASH_SZ];
629}
630
631static struct idmap_hashent *
632idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len)
633{ 593{
634 struct idmap_hashent *he = idmap_name_hash(h, name, len); 594 substring_t substr;
595 int token, ret;
635 596
636 if (he == NULL) 597 memset(im, 0, sizeof(*im));
637 return NULL; 598 memset(msg, 0, sizeof(*msg));
638 if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0)
639 return NULL;
640 if (time_after(jiffies, he->ih_expires))
641 return NULL;
642 return he;
643}
644 599
645static inline struct idmap_hashent * 600 im->im_type = IDMAP_TYPE_GROUP;
646idmap_id_hash(struct idmap_hashtable* h, __u32 id) 601 token = match_token(desc, nfs_idmap_tokens, &substr);
647{
648 if (h->h_entries == NULL)
649 return NULL;
650 return &h->h_entries[fnvhash32(&id, sizeof(id)) % IDMAP_HASH_SZ];
651}
652 602
653static struct idmap_hashent * 603 switch (token) {
654idmap_lookup_id(struct idmap_hashtable *h, __u32 id) 604 case Opt_find_uid:
655{ 605 im->im_type = IDMAP_TYPE_USER;
656 struct idmap_hashent *he = idmap_id_hash(h, id); 606 case Opt_find_gid:
607 im->im_conv = IDMAP_CONV_NAMETOID;
608 ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ);
609 break;
657 610
658 if (he == NULL) 611 case Opt_find_user:
659 return NULL; 612 im->im_type = IDMAP_TYPE_USER;
660 if (he->ih_id != id || he->ih_namelen == 0) 613 case Opt_find_group:
661 return NULL; 614 im->im_conv = IDMAP_CONV_IDTONAME;
662 if (time_after(jiffies, he->ih_expires)) 615 ret = match_int(&substr, &im->im_id);
663 return NULL; 616 break;
664 return he;
665}
666 617
667/* 618 default:
668 * Routines for allocating new entries in the hashtable. 619 ret = -EINVAL;
669 * For now, we just have 1 entry per bucket, so it's all 620 goto out;
670 * pretty trivial. 621 }
671 */
672static inline struct idmap_hashent *
673idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len)
674{
675 idmap_alloc_hashtable(h);
676 return idmap_name_hash(h, name, len);
677}
678 622
679static inline struct idmap_hashent * 623 msg->data = im;
680idmap_alloc_id(struct idmap_hashtable *h, __u32 id) 624 msg->len = sizeof(struct idmap_msg);
681{
682 idmap_alloc_hashtable(h);
683 return idmap_id_hash(h, id);
684}
685 625
686static void 626out:
687idmap_update_entry(struct idmap_hashent *he, const char *name, 627 return ret;
688 size_t namelen, __u32 id)
689{
690 char *str = kmalloc(namelen + 1, GFP_KERNEL);
691 if (str == NULL)
692 return;
693 kfree(he->ih_name);
694 he->ih_id = id;
695 memcpy(str, name, namelen);
696 str[namelen] = '\0';
697 he->ih_name = str;
698 he->ih_namelen = namelen;
699 he->ih_expires = jiffies + nfs_idmap_cache_timeout;
700} 628}
701 629
702/* 630static int nfs_idmap_legacy_upcall(struct key_construction *cons,
703 * Name -> ID 631 const char *op,
704 */ 632 void *aux)
705static int
706nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h,
707 const char *name, size_t namelen, __u32 *id)
708{ 633{
709 struct rpc_pipe_msg msg; 634 struct rpc_pipe_msg *msg;
710 struct idmap_msg *im; 635 struct idmap_msg *im;
711 struct idmap_hashent *he; 636 struct idmap *idmap = (struct idmap *)aux;
712 DECLARE_WAITQUEUE(wq, current); 637 struct key *key = cons->key;
713 int ret = -EIO; 638 int ret;
714
715 im = &idmap->idmap_im;
716
717 /*
718 * String sanity checks
719 * Note that the userland daemon expects NUL terminated strings
720 */
721 for (;;) {
722 if (namelen == 0)
723 return -EINVAL;
724 if (name[namelen-1] != '\0')
725 break;
726 namelen--;
727 }
728 if (namelen >= IDMAP_NAMESZ)
729 return -EINVAL;
730
731 mutex_lock(&idmap->idmap_lock);
732 mutex_lock(&idmap->idmap_im_lock);
733 639
734 he = idmap_lookup_name(h, name, namelen); 640 /* msg and im are freed in idmap_pipe_destroy_msg */
735 if (he != NULL) { 641 msg = kmalloc(sizeof(*msg), GFP_KERNEL);
736 *id = he->ih_id; 642 if (IS_ERR(msg)) {
737 ret = 0; 643 ret = PTR_ERR(msg);
738 goto out; 644 goto out0;
739 } 645 }
740 646
741 memset(im, 0, sizeof(*im)); 647 im = kmalloc(sizeof(*im), GFP_KERNEL);
742 memcpy(im->im_name, name, namelen); 648 if (IS_ERR(im)) {
743 649 ret = PTR_ERR(im);
744 im->im_type = h->h_type; 650 goto out1;
745 im->im_conv = IDMAP_CONV_NAMETOID;
746
747 memset(&msg, 0, sizeof(msg));
748 msg.data = im;
749 msg.len = sizeof(*im);
750
751 add_wait_queue(&idmap->idmap_wq, &wq);
752 if (rpc_queue_upcall(idmap->idmap_pipe, &msg) < 0) {
753 remove_wait_queue(&idmap->idmap_wq, &wq);
754 goto out;
755 } 651 }
756 652
757 set_current_state(TASK_UNINTERRUPTIBLE); 653 ret = nfs_idmap_prepare_message(key->description, im, msg);
758 mutex_unlock(&idmap->idmap_im_lock); 654 if (ret < 0)
759 schedule(); 655 goto out2;
760 __set_current_state(TASK_RUNNING);
761 remove_wait_queue(&idmap->idmap_wq, &wq);
762 mutex_lock(&idmap->idmap_im_lock);
763 656
764 if (im->im_status & IDMAP_STATUS_SUCCESS) { 657 idmap->idmap_key_cons = cons;
765 *id = im->im_id;
766 ret = 0;
767 }
768 658
769 out: 659 return rpc_queue_upcall(idmap->idmap_pipe, msg);
770 memset(im, 0, sizeof(*im)); 660
771 mutex_unlock(&idmap->idmap_im_lock); 661out2:
772 mutex_unlock(&idmap->idmap_lock); 662 kfree(im);
663out1:
664 kfree(msg);
665out0:
666 complete_request_key(cons, ret);
773 return ret; 667 return ret;
774} 668}
775 669
776/* 670static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data)
777 * ID -> Name
778 */
779static int
780nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h,
781 __u32 id, char *name)
782{ 671{
783 struct rpc_pipe_msg msg; 672 return key_instantiate_and_link(key, data, strlen(data) + 1,
784 struct idmap_msg *im; 673 id_resolver_cache->thread_keyring,
785 struct idmap_hashent *he; 674 authkey);
786 DECLARE_WAITQUEUE(wq, current); 675}
787 int ret = -EIO;
788 unsigned int len;
789
790 im = &idmap->idmap_im;
791
792 mutex_lock(&idmap->idmap_lock);
793 mutex_lock(&idmap->idmap_im_lock);
794
795 he = idmap_lookup_id(h, id);
796 if (he) {
797 memcpy(name, he->ih_name, he->ih_namelen);
798 ret = he->ih_namelen;
799 goto out;
800 }
801
802 memset(im, 0, sizeof(*im));
803 im->im_type = h->h_type;
804 im->im_conv = IDMAP_CONV_IDTONAME;
805 im->im_id = id;
806
807 memset(&msg, 0, sizeof(msg));
808 msg.data = im;
809 msg.len = sizeof(*im);
810
811 add_wait_queue(&idmap->idmap_wq, &wq);
812 676
813 if (rpc_queue_upcall(idmap->idmap_pipe, &msg) < 0) { 677static int nfs_idmap_read_message(struct idmap_msg *im, struct key *key, struct key *authkey)
814 remove_wait_queue(&idmap->idmap_wq, &wq); 678{
815 goto out; 679 char id_str[NFS_UINT_MAXLEN];
816 } 680 int ret = -EINVAL;
817 681
818 set_current_state(TASK_UNINTERRUPTIBLE); 682 switch (im->im_conv) {
819 mutex_unlock(&idmap->idmap_im_lock); 683 case IDMAP_CONV_NAMETOID:
820 schedule(); 684 sprintf(id_str, "%d", im->im_id);
821 __set_current_state(TASK_RUNNING); 685 ret = nfs_idmap_instantiate(key, authkey, id_str);
822 remove_wait_queue(&idmap->idmap_wq, &wq); 686 break;
823 mutex_lock(&idmap->idmap_im_lock); 687 case IDMAP_CONV_IDTONAME:
824 688 ret = nfs_idmap_instantiate(key, authkey, im->im_name);
825 if (im->im_status & IDMAP_STATUS_SUCCESS) { 689 break;
826 if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0)
827 goto out;
828 memcpy(name, im->im_name, len);
829 ret = len;
830 } 690 }
831 691
832 out:
833 memset(im, 0, sizeof(*im));
834 mutex_unlock(&idmap->idmap_im_lock);
835 mutex_unlock(&idmap->idmap_lock);
836 return ret; 692 return ret;
837} 693}
838 694
@@ -841,141 +697,69 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
841{ 697{
842 struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode); 698 struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode);
843 struct idmap *idmap = (struct idmap *)rpci->private; 699 struct idmap *idmap = (struct idmap *)rpci->private;
844 struct idmap_msg im_in, *im = &idmap->idmap_im; 700 struct key_construction *cons = idmap->idmap_key_cons;
845 struct idmap_hashtable *h; 701 struct idmap_msg im;
846 struct idmap_hashent *he = NULL;
847 size_t namelen_in; 702 size_t namelen_in;
848 int ret; 703 int ret;
849 704
850 if (mlen != sizeof(im_in)) 705 if (mlen != sizeof(im)) {
851 return -ENOSPC; 706 ret = -ENOSPC;
852
853 if (copy_from_user(&im_in, src, mlen) != 0)
854 return -EFAULT;
855
856 mutex_lock(&idmap->idmap_im_lock);
857
858 ret = mlen;
859 im->im_status = im_in.im_status;
860 /* If we got an error, terminate now, and wake up pending upcalls */
861 if (!(im_in.im_status & IDMAP_STATUS_SUCCESS)) {
862 wake_up(&idmap->idmap_wq);
863 goto out; 707 goto out;
864 } 708 }
865 709
866 /* Sanity checking of strings */ 710 if (copy_from_user(&im, src, mlen) != 0) {
867 ret = -EINVAL; 711 ret = -EFAULT;
868 namelen_in = strnlen(im_in.im_name, IDMAP_NAMESZ);
869 if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ)
870 goto out; 712 goto out;
713 }
871 714
872 switch (im_in.im_type) { 715 if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
873 case IDMAP_TYPE_USER: 716 ret = mlen;
874 h = &idmap->idmap_user_hash; 717 complete_request_key(idmap->idmap_key_cons, -ENOKEY);
875 break; 718 goto out_incomplete;
876 case IDMAP_TYPE_GROUP:
877 h = &idmap->idmap_group_hash;
878 break;
879 default:
880 goto out;
881 } 719 }
882 720
883 switch (im_in.im_conv) { 721 namelen_in = strnlen(im.im_name, IDMAP_NAMESZ);
884 case IDMAP_CONV_IDTONAME: 722 if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) {
885 /* Did we match the current upcall? */ 723 ret = -EINVAL;
886 if (im->im_conv == IDMAP_CONV_IDTONAME
887 && im->im_type == im_in.im_type
888 && im->im_id == im_in.im_id) {
889 /* Yes: copy string, including the terminating '\0' */
890 memcpy(im->im_name, im_in.im_name, namelen_in);
891 im->im_name[namelen_in] = '\0';
892 wake_up(&idmap->idmap_wq);
893 }
894 he = idmap_alloc_id(h, im_in.im_id);
895 break;
896 case IDMAP_CONV_NAMETOID:
897 /* Did we match the current upcall? */
898 if (im->im_conv == IDMAP_CONV_NAMETOID
899 && im->im_type == im_in.im_type
900 && strnlen(im->im_name, IDMAP_NAMESZ) == namelen_in
901 && memcmp(im->im_name, im_in.im_name, namelen_in) == 0) {
902 im->im_id = im_in.im_id;
903 wake_up(&idmap->idmap_wq);
904 }
905 he = idmap_alloc_name(h, im_in.im_name, namelen_in);
906 break;
907 default:
908 goto out; 724 goto out;
909 } 725 }
910 726
911 /* If the entry is valid, also copy it to the cache */ 727 ret = nfs_idmap_read_message(&im, cons->key, cons->authkey);
912 if (he != NULL) 728 if (ret >= 0) {
913 idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id); 729 key_set_timeout(cons->key, nfs_idmap_cache_timeout);
914 ret = mlen; 730 ret = mlen;
731 }
732
915out: 733out:
916 mutex_unlock(&idmap->idmap_im_lock); 734 complete_request_key(idmap->idmap_key_cons, ret);
735out_incomplete:
917 return ret; 736 return ret;
918} 737}
919 738
920static void 739static void
921idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) 740idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
922{ 741{
923 struct idmap_msg *im = msg->data; 742 /* Free memory allocated in nfs_idmap_legacy_upcall() */
924 struct idmap *idmap = container_of(im, struct idmap, idmap_im); 743 kfree(msg->data);
925 744 kfree(msg);
926 if (msg->errno >= 0)
927 return;
928 mutex_lock(&idmap->idmap_im_lock);
929 im->im_status = IDMAP_STATUS_LOOKUPFAIL;
930 wake_up(&idmap->idmap_wq);
931 mutex_unlock(&idmap->idmap_im_lock);
932}
933
934/*
935 * Fowler/Noll/Vo hash
936 * http://www.isthe.com/chongo/tech/comp/fnv/
937 */
938
939#define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */
940#define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */
941
942static unsigned int fnvhash32(const void *buf, size_t buflen)
943{
944 const unsigned char *p, *end = (const unsigned char *)buf + buflen;
945 unsigned int hash = FNV_1_32;
946
947 for (p = buf; p < end; p++) {
948 hash *= FNV_P_32;
949 hash ^= (unsigned int)*p;
950 }
951
952 return hash;
953} 745}
954 746
955int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) 747int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
956{ 748{
957 struct idmap *idmap = server->nfs_client->cl_idmap; 749 struct idmap *idmap = server->nfs_client->cl_idmap;
958 int ret = -EINVAL;
959 750
960 if (nfs_map_string_to_numeric(name, namelen, uid)) 751 if (nfs_map_string_to_numeric(name, namelen, uid))
961 return 0; 752 return 0;
962 ret = nfs_idmap_lookup_id(name, namelen, "uid", uid); 753 return nfs_idmap_lookup_id(name, namelen, "uid", uid, idmap);
963 if (ret < 0)
964 ret = nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid);
965 return ret;
966} 754}
967 755
968int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid) 756int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid)
969{ 757{
970 struct idmap *idmap = server->nfs_client->cl_idmap; 758 struct idmap *idmap = server->nfs_client->cl_idmap;
971 int ret = -EINVAL;
972 759
973 if (nfs_map_string_to_numeric(name, namelen, gid)) 760 if (nfs_map_string_to_numeric(name, namelen, gid))
974 return 0; 761 return 0;
975 ret = nfs_idmap_lookup_id(name, namelen, "gid", gid); 762 return nfs_idmap_lookup_id(name, namelen, "gid", gid, idmap);
976 if (ret < 0)
977 ret = nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, gid);
978 return ret;
979} 763}
980 764
981int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) 765int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
@@ -983,11 +767,8 @@ int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, s
983 struct idmap *idmap = server->nfs_client->cl_idmap; 767 struct idmap *idmap = server->nfs_client->cl_idmap;
984 int ret = -EINVAL; 768 int ret = -EINVAL;
985 769
986 if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) { 770 if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
987 ret = nfs_idmap_lookup_name(uid, "user", buf, buflen); 771 ret = nfs_idmap_lookup_name(uid, "user", buf, buflen, idmap);
988 if (ret < 0)
989 ret = nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
990 }
991 if (ret < 0) 772 if (ret < 0)
992 ret = nfs_map_numeric_to_string(uid, buf, buflen); 773 ret = nfs_map_numeric_to_string(uid, buf, buflen);
993 return ret; 774 return ret;
@@ -997,11 +778,8 @@ int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf,
997 struct idmap *idmap = server->nfs_client->cl_idmap; 778 struct idmap *idmap = server->nfs_client->cl_idmap;
998 int ret = -EINVAL; 779 int ret = -EINVAL;
999 780
1000 if (!(server->caps & NFS_CAP_UIDGID_NOMAP)) { 781 if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
1001 ret = nfs_idmap_lookup_name(gid, "group", buf, buflen); 782 ret = nfs_idmap_lookup_name(gid, "group", buf, buflen, idmap);
1002 if (ret < 0)
1003 ret = nfs_idmap_name(idmap, &idmap->idmap_group_hash, gid, buf);
1004 }
1005 if (ret < 0) 783 if (ret < 0)
1006 ret = nfs_map_numeric_to_string(gid, buf, buflen); 784 ret = nfs_map_numeric_to_string(gid, buf, buflen);
1007 return ret; 785 return ret;