Commit c5066945b7ea346a11424dbeb7830b7d7d00c206
Committed by
Trond Myklebust
1 parent
cff298c721
Exists in
master
and in
20 other branches
NFS: Clear key construction data if the idmap upcall fails
idmap_pipe_downcall already clears this field if the upcall succeeds, but if it fails (rpc.idmapd isn't running) the field will still be set on the next call triggering a BUG_ON(). This patch tries to handle all possible ways that the upcall could fail and clear the idmap key data for each one. Signed-off-by: Bryan Schumaker <bjschuma@netapp.com> Tested-by: William Dauchy <wdauchy@gmail.com> Cc: stable@vger.kernel.org [>= 3.4] Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Showing 1 changed file with 42 additions and 14 deletions Side-by-side Diff
fs/nfs/idmap.c
... | ... | @@ -61,6 +61,12 @@ |
61 | 61 | struct mutex idmap_mutex; |
62 | 62 | }; |
63 | 63 | |
64 | +struct idmap_legacy_upcalldata { | |
65 | + struct rpc_pipe_msg pipe_msg; | |
66 | + struct idmap_msg idmap_msg; | |
67 | + struct idmap *idmap; | |
68 | +}; | |
69 | + | |
64 | 70 | /** |
65 | 71 | * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields |
66 | 72 | * @fattr: fully initialised struct nfs_fattr |
... | ... | @@ -324,6 +330,7 @@ |
324 | 330 | ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, |
325 | 331 | name, namelen, type, data, |
326 | 332 | data_size, idmap); |
333 | + idmap->idmap_key_cons = NULL; | |
327 | 334 | mutex_unlock(&idmap->idmap_mutex); |
328 | 335 | } |
329 | 336 | return ret; |
330 | 337 | |
... | ... | @@ -380,11 +387,13 @@ |
380 | 387 | static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *); |
381 | 388 | static ssize_t idmap_pipe_downcall(struct file *, const char __user *, |
382 | 389 | size_t); |
390 | +static void idmap_release_pipe(struct inode *); | |
383 | 391 | static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *); |
384 | 392 | |
385 | 393 | static const struct rpc_pipe_ops idmap_upcall_ops = { |
386 | 394 | .upcall = rpc_pipe_generic_upcall, |
387 | 395 | .downcall = idmap_pipe_downcall, |
396 | + .release_pipe = idmap_release_pipe, | |
388 | 397 | .destroy_msg = idmap_pipe_destroy_msg, |
389 | 398 | }; |
390 | 399 | |
... | ... | @@ -616,7 +625,8 @@ |
616 | 625 | nfs_idmap_quit_keyring(); |
617 | 626 | } |
618 | 627 | |
619 | -static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im, | |
628 | +static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap, | |
629 | + struct idmap_msg *im, | |
620 | 630 | struct rpc_pipe_msg *msg) |
621 | 631 | { |
622 | 632 | substring_t substr; |
... | ... | @@ -659,6 +669,7 @@ |
659 | 669 | const char *op, |
660 | 670 | void *aux) |
661 | 671 | { |
672 | + struct idmap_legacy_upcalldata *data; | |
662 | 673 | struct rpc_pipe_msg *msg; |
663 | 674 | struct idmap_msg *im; |
664 | 675 | struct idmap *idmap = (struct idmap *)aux; |
665 | 676 | |
... | ... | @@ -666,15 +677,15 @@ |
666 | 677 | int ret = -ENOMEM; |
667 | 678 | |
668 | 679 | /* msg and im are freed in idmap_pipe_destroy_msg */ |
669 | - msg = kmalloc(sizeof(*msg), GFP_KERNEL); | |
670 | - if (!msg) | |
671 | - goto out0; | |
672 | - | |
673 | - im = kmalloc(sizeof(*im), GFP_KERNEL); | |
674 | - if (!im) | |
680 | + data = kmalloc(sizeof(*data), GFP_KERNEL); | |
681 | + if (!data) | |
675 | 682 | goto out1; |
676 | 683 | |
677 | - ret = nfs_idmap_prepare_message(key->description, im, msg); | |
684 | + msg = &data->pipe_msg; | |
685 | + im = &data->idmap_msg; | |
686 | + data->idmap = idmap; | |
687 | + | |
688 | + ret = nfs_idmap_prepare_message(key->description, idmap, im, msg); | |
678 | 689 | if (ret < 0) |
679 | 690 | goto out2; |
680 | 691 | |
681 | 692 | |
682 | 693 | |
683 | 694 | |
... | ... | @@ -683,15 +694,15 @@ |
683 | 694 | |
684 | 695 | ret = rpc_queue_upcall(idmap->idmap_pipe, msg); |
685 | 696 | if (ret < 0) |
686 | - goto out2; | |
697 | + goto out3; | |
687 | 698 | |
688 | 699 | return ret; |
689 | 700 | |
701 | +out3: | |
702 | + idmap->idmap_key_cons = NULL; | |
690 | 703 | out2: |
691 | - kfree(im); | |
704 | + kfree(data); | |
692 | 705 | out1: |
693 | - kfree(msg); | |
694 | -out0: | |
695 | 706 | complete_request_key(cons, ret); |
696 | 707 | return ret; |
697 | 708 | } |
698 | 709 | |
... | ... | @@ -775,9 +786,26 @@ |
775 | 786 | static void |
776 | 787 | idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) |
777 | 788 | { |
789 | + struct idmap_legacy_upcalldata *data = container_of(msg, | |
790 | + struct idmap_legacy_upcalldata, | |
791 | + pipe_msg); | |
792 | + struct idmap *idmap = data->idmap; | |
793 | + struct key_construction *cons; | |
794 | + if (msg->errno) { | |
795 | + cons = ACCESS_ONCE(idmap->idmap_key_cons); | |
796 | + idmap->idmap_key_cons = NULL; | |
797 | + complete_request_key(cons, msg->errno); | |
798 | + } | |
778 | 799 | /* Free memory allocated in nfs_idmap_legacy_upcall() */ |
779 | - kfree(msg->data); | |
780 | - kfree(msg); | |
800 | + kfree(data); | |
801 | +} | |
802 | + | |
803 | +static void | |
804 | +idmap_release_pipe(struct inode *inode) | |
805 | +{ | |
806 | + struct rpc_inode *rpci = RPC_I(inode); | |
807 | + struct idmap *idmap = (struct idmap *)rpci->private; | |
808 | + idmap->idmap_key_cons = NULL; | |
781 | 809 | } |
782 | 810 | |
783 | 811 | int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) |