diff options
author | Bryan Schumaker <bjschuma@netapp.com> | 2012-02-24 14:14:51 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-03-01 17:10:16 -0500 |
commit | 57e62324e469e092ecc6c94a7a86fe4bd6ac5172 (patch) | |
tree | 162a5ecd487bc842bc07cc8d4c14d4d1a337813d /fs/nfs/idmap.c | |
parent | 59e6b9c11341e3b8ac5925427c903d4eae435bd8 (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.c | 554 |
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 */ |
71 | unsigned int nfs_idmap_cache_timeout = 600 * HZ; | 56 | unsigned int nfs_idmap_cache_timeout = 600; |
72 | const struct cred *id_resolver_cache; | 57 | const struct cred *id_resolver_cache; |
58 | struct 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 | ||
264 | 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, |
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 | ||
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 | } | ||
312 | 318 | ||
313 | /* ID -> Name */ | 319 | /* ID -> Name */ |
314 | 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) | ||
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 */ |
328 | 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, |
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 */ |
347 | static int param_set_idmap_timeout(const char *val, struct kernel_param *kp) | 354 | module_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 | |||
358 | module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int, | ||
359 | &nfs_idmap_cache_timeout, 0644); | ||
360 | 355 | ||
361 | struct idmap_hashent { | 356 | struct 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 | ||
368 | struct idmap_hashtable { | 361 | enum { |
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 | ||
373 | struct idmap { | 365 | static 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 | ||
373 | static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *); | ||
383 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, | 374 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, |
384 | size_t); | 375 | size_t); |
385 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); | 376 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); |
386 | 377 | ||
387 | static unsigned int fnvhash32(const void *, size_t); | ||
388 | |||
389 | static const struct rpc_pipe_ops idmap_upcall_ops = { | 378 | static 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 | ||
384 | 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) | 395 | static 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 | ||
481 | static void | ||
482 | idmap_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 | |||
491 | static void | ||
492 | idmap_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 | |||
503 | void | 476 | void |
504 | nfs_idmap_delete(struct nfs_client *clp) | 477 | nfs_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 | /* | 591 | static 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 | */ | ||
623 | static inline struct idmap_hashent * | ||
624 | idmap_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 | |||
631 | static struct idmap_hashent * | ||
632 | idmap_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 | ||
645 | static inline struct idmap_hashent * | 600 | im->im_type = IDMAP_TYPE_GROUP; |
646 | idmap_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 | ||
653 | static struct idmap_hashent * | 603 | switch (token) { |
654 | idmap_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 | */ | ||
672 | static inline struct idmap_hashent * | ||
673 | idmap_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 | ||
679 | static inline struct idmap_hashent * | 623 | msg->data = im; |
680 | idmap_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 | ||
686 | static void | 626 | out: |
687 | idmap_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 | /* | 630 | static int nfs_idmap_legacy_upcall(struct key_construction *cons, |
703 | * Name -> ID | 631 | const char *op, |
704 | */ | 632 | void *aux) |
705 | static int | ||
706 | nfs_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); | 661 | out2: |
772 | mutex_unlock(&idmap->idmap_lock); | 662 | kfree(im); |
663 | out1: | ||
664 | kfree(msg); | ||
665 | out0: | ||
666 | complete_request_key(cons, ret); | ||
773 | return ret; | 667 | return ret; |
774 | } | 668 | } |
775 | 669 | ||
776 | /* | 670 | static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data) |
777 | * ID -> Name | ||
778 | */ | ||
779 | static int | ||
780 | nfs_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) { | 677 | static 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 | |||
915 | out: | 733 | out: |
916 | mutex_unlock(&idmap->idmap_im_lock); | 734 | complete_request_key(idmap->idmap_key_cons, ret); |
735 | out_incomplete: | ||
917 | return ret; | 736 | return ret; |
918 | } | 737 | } |
919 | 738 | ||
920 | static void | 739 | static void |
921 | idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) | 740 | idmap_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 | |||
942 | static 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 | ||
955 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) | 747 | int 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 | ||
968 | int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid) | 756 | int 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 | ||
981 | int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen) | 765 | int 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; |