.. | .. |
---|
59 | 59 | void (*remove)(struct nfs4_client *); |
---|
60 | 60 | int (*check)(struct nfs4_client *); |
---|
61 | 61 | void (*grace_done)(struct nfsd_net *); |
---|
| 62 | + uint8_t version; |
---|
| 63 | + size_t msglen; |
---|
62 | 64 | }; |
---|
| 65 | + |
---|
| 66 | +static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops; |
---|
| 67 | +static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v2; |
---|
63 | 68 | |
---|
64 | 69 | /* Globals */ |
---|
65 | 70 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; |
---|
.. | .. |
---|
122 | 127 | goto out; |
---|
123 | 128 | } |
---|
124 | 129 | |
---|
125 | | - { |
---|
126 | | - SHASH_DESC_ON_STACK(desc, tfm); |
---|
127 | | - |
---|
128 | | - desc->tfm = tfm; |
---|
129 | | - desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; |
---|
130 | | - |
---|
131 | | - status = crypto_shash_digest(desc, clname->data, clname->len, |
---|
132 | | - cksum.data); |
---|
133 | | - shash_desc_zero(desc); |
---|
134 | | - } |
---|
135 | | - |
---|
| 130 | + status = crypto_shash_tfm_digest(tfm, clname->data, clname->len, |
---|
| 131 | + cksum.data); |
---|
136 | 132 | if (status) |
---|
137 | 133 | goto out; |
---|
138 | 134 | |
---|
.. | .. |
---|
170 | 166 | } |
---|
171 | 167 | |
---|
172 | 168 | static void |
---|
| 169 | +__nfsd4_create_reclaim_record_grace(struct nfs4_client *clp, |
---|
| 170 | + const char *dname, int len, struct nfsd_net *nn) |
---|
| 171 | +{ |
---|
| 172 | + struct xdr_netobj name; |
---|
| 173 | + struct xdr_netobj princhash = { .len = 0, .data = NULL }; |
---|
| 174 | + struct nfs4_client_reclaim *crp; |
---|
| 175 | + |
---|
| 176 | + name.data = kmemdup(dname, len, GFP_KERNEL); |
---|
| 177 | + if (!name.data) { |
---|
| 178 | + dprintk("%s: failed to allocate memory for name.data!\n", |
---|
| 179 | + __func__); |
---|
| 180 | + return; |
---|
| 181 | + } |
---|
| 182 | + name.len = len; |
---|
| 183 | + crp = nfs4_client_to_reclaim(name, princhash, nn); |
---|
| 184 | + if (!crp) { |
---|
| 185 | + kfree(name.data); |
---|
| 186 | + return; |
---|
| 187 | + } |
---|
| 188 | + crp->cr_clp = clp; |
---|
| 189 | +} |
---|
| 190 | + |
---|
| 191 | +static void |
---|
173 | 192 | nfsd4_create_clid_dir(struct nfs4_client *clp) |
---|
174 | 193 | { |
---|
175 | 194 | const struct cred *original_cred; |
---|
176 | 195 | char dname[HEXDIR_LEN]; |
---|
177 | 196 | struct dentry *dir, *dentry; |
---|
178 | | - struct nfs4_client_reclaim *crp; |
---|
179 | 197 | int status; |
---|
180 | 198 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
---|
181 | 199 | |
---|
.. | .. |
---|
221 | 239 | out_unlock: |
---|
222 | 240 | inode_unlock(d_inode(dir)); |
---|
223 | 241 | if (status == 0) { |
---|
224 | | - if (nn->in_grace) { |
---|
225 | | - crp = nfs4_client_to_reclaim(dname, nn); |
---|
226 | | - if (crp) |
---|
227 | | - crp->cr_clp = clp; |
---|
228 | | - } |
---|
| 242 | + if (nn->in_grace) |
---|
| 243 | + __nfsd4_create_reclaim_record_grace(clp, dname, |
---|
| 244 | + HEXDIR_LEN, nn); |
---|
229 | 245 | vfs_fsync(nn->rec_file, 0); |
---|
230 | 246 | } else { |
---|
231 | 247 | printk(KERN_ERR "NFSD: failed to write recovery record" |
---|
.. | .. |
---|
346 | 362 | } |
---|
347 | 363 | |
---|
348 | 364 | static void |
---|
| 365 | +__nfsd4_remove_reclaim_record_grace(const char *dname, int len, |
---|
| 366 | + struct nfsd_net *nn) |
---|
| 367 | +{ |
---|
| 368 | + struct xdr_netobj name; |
---|
| 369 | + struct nfs4_client_reclaim *crp; |
---|
| 370 | + |
---|
| 371 | + name.data = kmemdup(dname, len, GFP_KERNEL); |
---|
| 372 | + if (!name.data) { |
---|
| 373 | + dprintk("%s: failed to allocate memory for name.data!\n", |
---|
| 374 | + __func__); |
---|
| 375 | + return; |
---|
| 376 | + } |
---|
| 377 | + name.len = len; |
---|
| 378 | + crp = nfsd4_find_reclaim_client(name, nn); |
---|
| 379 | + kfree(name.data); |
---|
| 380 | + if (crp) |
---|
| 381 | + nfs4_remove_reclaim_record(crp, nn); |
---|
| 382 | +} |
---|
| 383 | + |
---|
| 384 | +static void |
---|
349 | 385 | nfsd4_remove_clid_dir(struct nfs4_client *clp) |
---|
350 | 386 | { |
---|
351 | 387 | const struct cred *original_cred; |
---|
352 | | - struct nfs4_client_reclaim *crp; |
---|
353 | 388 | char dname[HEXDIR_LEN]; |
---|
354 | 389 | int status; |
---|
355 | 390 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
---|
.. | .. |
---|
374 | 409 | nfs4_reset_creds(original_cred); |
---|
375 | 410 | if (status == 0) { |
---|
376 | 411 | vfs_fsync(nn->rec_file, 0); |
---|
377 | | - if (nn->in_grace) { |
---|
378 | | - /* remove reclaim record */ |
---|
379 | | - crp = nfsd4_find_reclaim_client(dname, nn); |
---|
380 | | - if (crp) |
---|
381 | | - nfs4_remove_reclaim_record(crp, nn); |
---|
382 | | - } |
---|
| 412 | + if (nn->in_grace) |
---|
| 413 | + __nfsd4_remove_reclaim_record_grace(dname, |
---|
| 414 | + HEXDIR_LEN, nn); |
---|
383 | 415 | } |
---|
384 | 416 | out_drop_write: |
---|
385 | 417 | mnt_drop_write_file(nn->rec_file); |
---|
.. | .. |
---|
393 | 425 | purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) |
---|
394 | 426 | { |
---|
395 | 427 | int status; |
---|
| 428 | + struct xdr_netobj name; |
---|
396 | 429 | |
---|
397 | | - if (nfs4_has_reclaimed_state(child->d_name.name, nn)) |
---|
| 430 | + if (child->d_name.len != HEXDIR_LEN - 1) { |
---|
| 431 | + printk("%s: illegal name %pd in recovery directory\n", |
---|
| 432 | + __func__, child); |
---|
| 433 | + /* Keep trying; maybe the others are OK: */ |
---|
398 | 434 | return 0; |
---|
| 435 | + } |
---|
| 436 | + name.data = kmemdup_nul(child->d_name.name, child->d_name.len, GFP_KERNEL); |
---|
| 437 | + if (!name.data) { |
---|
| 438 | + dprintk("%s: failed to allocate memory for name.data!\n", |
---|
| 439 | + __func__); |
---|
| 440 | + goto out; |
---|
| 441 | + } |
---|
| 442 | + name.len = HEXDIR_LEN; |
---|
| 443 | + if (nfs4_has_reclaimed_state(name, nn)) |
---|
| 444 | + goto out_free; |
---|
399 | 445 | |
---|
400 | 446 | status = vfs_rmdir(d_inode(parent), child); |
---|
401 | 447 | if (status) |
---|
402 | 448 | printk("failed to remove client recovery directory %pd\n", |
---|
403 | 449 | child); |
---|
| 450 | +out_free: |
---|
| 451 | + kfree(name.data); |
---|
| 452 | +out: |
---|
404 | 453 | /* Keep trying, success or failure: */ |
---|
405 | 454 | return 0; |
---|
406 | 455 | } |
---|
.. | .. |
---|
430 | 479 | static int |
---|
431 | 480 | load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) |
---|
432 | 481 | { |
---|
| 482 | + struct xdr_netobj name; |
---|
| 483 | + struct xdr_netobj princhash = { .len = 0, .data = NULL }; |
---|
| 484 | + |
---|
433 | 485 | if (child->d_name.len != HEXDIR_LEN - 1) { |
---|
434 | | - printk("nfsd4: illegal name %pd in recovery directory\n", |
---|
435 | | - child); |
---|
| 486 | + printk("%s: illegal name %pd in recovery directory\n", |
---|
| 487 | + __func__, child); |
---|
436 | 488 | /* Keep trying; maybe the others are OK: */ |
---|
437 | 489 | return 0; |
---|
438 | 490 | } |
---|
439 | | - nfs4_client_to_reclaim(child->d_name.name, nn); |
---|
| 491 | + name.data = kmemdup_nul(child->d_name.name, child->d_name.len, GFP_KERNEL); |
---|
| 492 | + if (!name.data) { |
---|
| 493 | + dprintk("%s: failed to allocate memory for name.data!\n", |
---|
| 494 | + __func__); |
---|
| 495 | + goto out; |
---|
| 496 | + } |
---|
| 497 | + name.len = HEXDIR_LEN; |
---|
| 498 | + if (!nfs4_client_to_reclaim(name, princhash, nn)) |
---|
| 499 | + kfree(name.data); |
---|
| 500 | +out: |
---|
440 | 501 | return 0; |
---|
441 | 502 | } |
---|
442 | 503 | |
---|
.. | .. |
---|
565 | 626 | status = nfsd4_load_reboot_recovery_data(net); |
---|
566 | 627 | if (status) |
---|
567 | 628 | goto err; |
---|
| 629 | + printk("NFSD: Using legacy client tracking operations.\n"); |
---|
568 | 630 | return 0; |
---|
569 | 631 | |
---|
570 | 632 | err: |
---|
.. | .. |
---|
616 | 678 | char dname[HEXDIR_LEN]; |
---|
617 | 679 | struct nfs4_client_reclaim *crp; |
---|
618 | 680 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
---|
| 681 | + struct xdr_netobj name; |
---|
619 | 682 | |
---|
620 | 683 | /* did we already find that this client is stable? */ |
---|
621 | 684 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
---|
.. | .. |
---|
628 | 691 | } |
---|
629 | 692 | |
---|
630 | 693 | /* look for it in the reclaim hashtable otherwise */ |
---|
631 | | - crp = nfsd4_find_reclaim_client(dname, nn); |
---|
| 694 | + name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL); |
---|
| 695 | + if (!name.data) { |
---|
| 696 | + dprintk("%s: failed to allocate memory for name.data!\n", |
---|
| 697 | + __func__); |
---|
| 698 | + goto out_enoent; |
---|
| 699 | + } |
---|
| 700 | + name.len = HEXDIR_LEN; |
---|
| 701 | + crp = nfsd4_find_reclaim_client(name, nn); |
---|
| 702 | + kfree(name.data); |
---|
632 | 703 | if (crp) { |
---|
633 | 704 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
---|
634 | 705 | crp->cr_clp = clp; |
---|
635 | 706 | return 0; |
---|
636 | 707 | } |
---|
637 | 708 | |
---|
| 709 | +out_enoent: |
---|
638 | 710 | return -ENOENT; |
---|
639 | 711 | } |
---|
640 | 712 | |
---|
.. | .. |
---|
645 | 717 | .remove = nfsd4_remove_clid_dir, |
---|
646 | 718 | .check = nfsd4_check_legacy_client, |
---|
647 | 719 | .grace_done = nfsd4_recdir_purge_old, |
---|
| 720 | + .version = 1, |
---|
| 721 | + .msglen = 0, |
---|
648 | 722 | }; |
---|
649 | 723 | |
---|
650 | 724 | /* Globals */ |
---|
.. | .. |
---|
657 | 731 | spinlock_t cn_lock; |
---|
658 | 732 | struct list_head cn_list; |
---|
659 | 733 | unsigned int cn_xid; |
---|
| 734 | + bool cn_has_legacy; |
---|
| 735 | + struct crypto_shash *cn_tfm; |
---|
660 | 736 | }; |
---|
661 | 737 | |
---|
662 | 738 | struct cld_upcall { |
---|
663 | 739 | struct list_head cu_list; |
---|
664 | 740 | struct cld_net *cu_net; |
---|
665 | 741 | struct completion cu_done; |
---|
666 | | - struct cld_msg cu_msg; |
---|
| 742 | + union { |
---|
| 743 | + struct cld_msg_hdr cu_hdr; |
---|
| 744 | + struct cld_msg cu_msg; |
---|
| 745 | + struct cld_msg_v2 cu_msg_v2; |
---|
| 746 | + } cu_u; |
---|
667 | 747 | }; |
---|
668 | 748 | |
---|
669 | 749 | static int |
---|
670 | | -__cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg) |
---|
| 750 | +__cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg, struct nfsd_net *nn) |
---|
671 | 751 | { |
---|
672 | 752 | int ret; |
---|
673 | 753 | struct rpc_pipe_msg msg; |
---|
674 | | - struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, cu_msg); |
---|
| 754 | + struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, cu_u); |
---|
675 | 755 | |
---|
676 | 756 | memset(&msg, 0, sizeof(msg)); |
---|
677 | 757 | msg.data = cmsg; |
---|
678 | | - msg.len = sizeof(*cmsg); |
---|
| 758 | + msg.len = nn->client_tracking_ops->msglen; |
---|
679 | 759 | |
---|
680 | 760 | ret = rpc_queue_upcall(pipe, &msg); |
---|
681 | 761 | if (ret < 0) { |
---|
.. | .. |
---|
691 | 771 | } |
---|
692 | 772 | |
---|
693 | 773 | static int |
---|
694 | | -cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg) |
---|
| 774 | +cld_pipe_upcall(struct rpc_pipe *pipe, void *cmsg, struct nfsd_net *nn) |
---|
695 | 775 | { |
---|
696 | 776 | int ret; |
---|
697 | 777 | |
---|
.. | .. |
---|
700 | 780 | * upcalls queued. |
---|
701 | 781 | */ |
---|
702 | 782 | do { |
---|
703 | | - ret = __cld_pipe_upcall(pipe, cmsg); |
---|
| 783 | + ret = __cld_pipe_upcall(pipe, cmsg, nn); |
---|
704 | 784 | } while (ret == -EAGAIN); |
---|
705 | 785 | |
---|
706 | 786 | return ret; |
---|
707 | 787 | } |
---|
708 | 788 | |
---|
709 | 789 | static ssize_t |
---|
| 790 | +__cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg, |
---|
| 791 | + struct nfsd_net *nn) |
---|
| 792 | +{ |
---|
| 793 | + uint8_t cmd, princhashlen; |
---|
| 794 | + struct xdr_netobj name, princhash = { .len = 0, .data = NULL }; |
---|
| 795 | + uint16_t namelen; |
---|
| 796 | + struct cld_net *cn = nn->cld_net; |
---|
| 797 | + |
---|
| 798 | + if (get_user(cmd, &cmsg->cm_cmd)) { |
---|
| 799 | + dprintk("%s: error when copying cmd from userspace", __func__); |
---|
| 800 | + return -EFAULT; |
---|
| 801 | + } |
---|
| 802 | + if (cmd == Cld_GraceStart) { |
---|
| 803 | + if (nn->client_tracking_ops->version >= 2) { |
---|
| 804 | + const struct cld_clntinfo __user *ci; |
---|
| 805 | + |
---|
| 806 | + ci = &cmsg->cm_u.cm_clntinfo; |
---|
| 807 | + if (get_user(namelen, &ci->cc_name.cn_len)) |
---|
| 808 | + return -EFAULT; |
---|
| 809 | + name.data = memdup_user(&ci->cc_name.cn_id, namelen); |
---|
| 810 | + if (IS_ERR_OR_NULL(name.data)) |
---|
| 811 | + return -EFAULT; |
---|
| 812 | + name.len = namelen; |
---|
| 813 | + get_user(princhashlen, &ci->cc_princhash.cp_len); |
---|
| 814 | + if (princhashlen > 0) { |
---|
| 815 | + princhash.data = memdup_user( |
---|
| 816 | + &ci->cc_princhash.cp_data, |
---|
| 817 | + princhashlen); |
---|
| 818 | + if (IS_ERR_OR_NULL(princhash.data)) { |
---|
| 819 | + kfree(name.data); |
---|
| 820 | + return -EFAULT; |
---|
| 821 | + } |
---|
| 822 | + princhash.len = princhashlen; |
---|
| 823 | + } else |
---|
| 824 | + princhash.len = 0; |
---|
| 825 | + } else { |
---|
| 826 | + const struct cld_name __user *cnm; |
---|
| 827 | + |
---|
| 828 | + cnm = &cmsg->cm_u.cm_name; |
---|
| 829 | + if (get_user(namelen, &cnm->cn_len)) |
---|
| 830 | + return -EFAULT; |
---|
| 831 | + name.data = memdup_user(&cnm->cn_id, namelen); |
---|
| 832 | + if (IS_ERR_OR_NULL(name.data)) |
---|
| 833 | + return -EFAULT; |
---|
| 834 | + name.len = namelen; |
---|
| 835 | + } |
---|
| 836 | + if (name.len > 5 && memcmp(name.data, "hash:", 5) == 0) { |
---|
| 837 | + name.len = name.len - 5; |
---|
| 838 | + memmove(name.data, name.data + 5, name.len); |
---|
| 839 | + cn->cn_has_legacy = true; |
---|
| 840 | + } |
---|
| 841 | + if (!nfs4_client_to_reclaim(name, princhash, nn)) { |
---|
| 842 | + kfree(name.data); |
---|
| 843 | + kfree(princhash.data); |
---|
| 844 | + return -EFAULT; |
---|
| 845 | + } |
---|
| 846 | + return nn->client_tracking_ops->msglen; |
---|
| 847 | + } |
---|
| 848 | + return -EFAULT; |
---|
| 849 | +} |
---|
| 850 | + |
---|
| 851 | +static ssize_t |
---|
710 | 852 | cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) |
---|
711 | 853 | { |
---|
712 | 854 | struct cld_upcall *tmp, *cup; |
---|
713 | | - struct cld_msg __user *cmsg = (struct cld_msg __user *)src; |
---|
| 855 | + struct cld_msg_hdr __user *hdr = (struct cld_msg_hdr __user *)src; |
---|
| 856 | + struct cld_msg_v2 __user *cmsg = (struct cld_msg_v2 __user *)src; |
---|
714 | 857 | uint32_t xid; |
---|
715 | 858 | struct nfsd_net *nn = net_generic(file_inode(filp)->i_sb->s_fs_info, |
---|
716 | 859 | nfsd_net_id); |
---|
717 | 860 | struct cld_net *cn = nn->cld_net; |
---|
| 861 | + int16_t status; |
---|
718 | 862 | |
---|
719 | | - if (mlen != sizeof(*cmsg)) { |
---|
| 863 | + if (mlen != nn->client_tracking_ops->msglen) { |
---|
720 | 864 | dprintk("%s: got %zu bytes, expected %zu\n", __func__, mlen, |
---|
721 | | - sizeof(*cmsg)); |
---|
| 865 | + nn->client_tracking_ops->msglen); |
---|
722 | 866 | return -EINVAL; |
---|
723 | 867 | } |
---|
724 | 868 | |
---|
725 | 869 | /* copy just the xid so we can try to find that */ |
---|
726 | | - if (copy_from_user(&xid, &cmsg->cm_xid, sizeof(xid)) != 0) { |
---|
| 870 | + if (copy_from_user(&xid, &hdr->cm_xid, sizeof(xid)) != 0) { |
---|
727 | 871 | dprintk("%s: error when copying xid from userspace", __func__); |
---|
| 872 | + return -EFAULT; |
---|
| 873 | + } |
---|
| 874 | + |
---|
| 875 | + /* |
---|
| 876 | + * copy the status so we know whether to remove the upcall from the |
---|
| 877 | + * list (for -EINPROGRESS, we just want to make sure the xid is |
---|
| 878 | + * valid, not remove the upcall from the list) |
---|
| 879 | + */ |
---|
| 880 | + if (get_user(status, &hdr->cm_status)) { |
---|
| 881 | + dprintk("%s: error when copying status from userspace", __func__); |
---|
728 | 882 | return -EFAULT; |
---|
729 | 883 | } |
---|
730 | 884 | |
---|
.. | .. |
---|
732 | 886 | cup = NULL; |
---|
733 | 887 | spin_lock(&cn->cn_lock); |
---|
734 | 888 | list_for_each_entry(tmp, &cn->cn_list, cu_list) { |
---|
735 | | - if (get_unaligned(&tmp->cu_msg.cm_xid) == xid) { |
---|
| 889 | + if (get_unaligned(&tmp->cu_u.cu_hdr.cm_xid) == xid) { |
---|
736 | 890 | cup = tmp; |
---|
737 | | - list_del_init(&cup->cu_list); |
---|
| 891 | + if (status != -EINPROGRESS) |
---|
| 892 | + list_del_init(&cup->cu_list); |
---|
738 | 893 | break; |
---|
739 | 894 | } |
---|
740 | 895 | } |
---|
.. | .. |
---|
746 | 901 | return -EINVAL; |
---|
747 | 902 | } |
---|
748 | 903 | |
---|
749 | | - if (copy_from_user(&cup->cu_msg, src, mlen) != 0) |
---|
| 904 | + if (status == -EINPROGRESS) |
---|
| 905 | + return __cld_pipe_inprogress_downcall(cmsg, nn); |
---|
| 906 | + |
---|
| 907 | + if (copy_from_user(&cup->cu_u.cu_msg_v2, src, mlen) != 0) |
---|
750 | 908 | return -EFAULT; |
---|
751 | 909 | |
---|
752 | 910 | complete(&cup->cu_done); |
---|
.. | .. |
---|
758 | 916 | { |
---|
759 | 917 | struct cld_msg *cmsg = msg->data; |
---|
760 | 918 | struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, |
---|
761 | | - cu_msg); |
---|
| 919 | + cu_u.cu_msg); |
---|
762 | 920 | |
---|
763 | 921 | /* errno >= 0 means we got a downcall */ |
---|
764 | 922 | if (msg->errno >= 0) |
---|
.. | .. |
---|
821 | 979 | |
---|
822 | 980 | /* Initialize rpc_pipefs pipe for communication with client tracking daemon */ |
---|
823 | 981 | static int |
---|
824 | | -nfsd4_init_cld_pipe(struct net *net) |
---|
| 982 | +__nfsd4_init_cld_pipe(struct net *net) |
---|
825 | 983 | { |
---|
826 | 984 | int ret; |
---|
827 | 985 | struct dentry *dentry; |
---|
.. | .. |
---|
852 | 1010 | } |
---|
853 | 1011 | |
---|
854 | 1012 | cn->cn_pipe->dentry = dentry; |
---|
| 1013 | + cn->cn_has_legacy = false; |
---|
855 | 1014 | nn->cld_net = cn; |
---|
856 | 1015 | return 0; |
---|
857 | 1016 | |
---|
.. | .. |
---|
864 | 1023 | return ret; |
---|
865 | 1024 | } |
---|
866 | 1025 | |
---|
| 1026 | +static int |
---|
| 1027 | +nfsd4_init_cld_pipe(struct net *net) |
---|
| 1028 | +{ |
---|
| 1029 | + int status; |
---|
| 1030 | + |
---|
| 1031 | + status = __nfsd4_init_cld_pipe(net); |
---|
| 1032 | + if (!status) |
---|
| 1033 | + printk("NFSD: Using old nfsdcld client tracking operations.\n"); |
---|
| 1034 | + return status; |
---|
| 1035 | +} |
---|
| 1036 | + |
---|
867 | 1037 | static void |
---|
868 | 1038 | nfsd4_remove_cld_pipe(struct net *net) |
---|
869 | 1039 | { |
---|
.. | .. |
---|
872 | 1042 | |
---|
873 | 1043 | nfsd4_cld_unregister_net(net, cn->cn_pipe); |
---|
874 | 1044 | rpc_destroy_pipe_data(cn->cn_pipe); |
---|
| 1045 | + if (cn->cn_tfm) |
---|
| 1046 | + crypto_free_shash(cn->cn_tfm); |
---|
875 | 1047 | kfree(nn->cld_net); |
---|
876 | 1048 | nn->cld_net = NULL; |
---|
877 | 1049 | } |
---|
878 | 1050 | |
---|
879 | 1051 | static struct cld_upcall * |
---|
880 | | -alloc_cld_upcall(struct cld_net *cn) |
---|
| 1052 | +alloc_cld_upcall(struct nfsd_net *nn) |
---|
881 | 1053 | { |
---|
882 | 1054 | struct cld_upcall *new, *tmp; |
---|
| 1055 | + struct cld_net *cn = nn->cld_net; |
---|
883 | 1056 | |
---|
884 | 1057 | new = kzalloc(sizeof(*new), GFP_KERNEL); |
---|
885 | 1058 | if (!new) |
---|
.. | .. |
---|
889 | 1062 | restart_search: |
---|
890 | 1063 | spin_lock(&cn->cn_lock); |
---|
891 | 1064 | list_for_each_entry(tmp, &cn->cn_list, cu_list) { |
---|
892 | | - if (tmp->cu_msg.cm_xid == cn->cn_xid) { |
---|
| 1065 | + if (tmp->cu_u.cu_msg.cm_xid == cn->cn_xid) { |
---|
893 | 1066 | cn->cn_xid++; |
---|
894 | 1067 | spin_unlock(&cn->cn_lock); |
---|
895 | 1068 | goto restart_search; |
---|
896 | 1069 | } |
---|
897 | 1070 | } |
---|
898 | 1071 | init_completion(&new->cu_done); |
---|
899 | | - new->cu_msg.cm_vers = CLD_UPCALL_VERSION; |
---|
900 | | - put_unaligned(cn->cn_xid++, &new->cu_msg.cm_xid); |
---|
| 1072 | + new->cu_u.cu_msg.cm_vers = nn->client_tracking_ops->version; |
---|
| 1073 | + put_unaligned(cn->cn_xid++, &new->cu_u.cu_msg.cm_xid); |
---|
901 | 1074 | new->cu_net = cn; |
---|
902 | 1075 | list_add(&new->cu_list, &cn->cn_list); |
---|
903 | 1076 | spin_unlock(&cn->cn_lock); |
---|
904 | 1077 | |
---|
905 | | - dprintk("%s: allocated xid %u\n", __func__, new->cu_msg.cm_xid); |
---|
| 1078 | + dprintk("%s: allocated xid %u\n", __func__, new->cu_u.cu_msg.cm_xid); |
---|
906 | 1079 | |
---|
907 | 1080 | return new; |
---|
908 | 1081 | } |
---|
.. | .. |
---|
931 | 1104 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
---|
932 | 1105 | return; |
---|
933 | 1106 | |
---|
934 | | - cup = alloc_cld_upcall(cn); |
---|
| 1107 | + cup = alloc_cld_upcall(nn); |
---|
935 | 1108 | if (!cup) { |
---|
936 | 1109 | ret = -ENOMEM; |
---|
937 | 1110 | goto out_err; |
---|
938 | 1111 | } |
---|
939 | 1112 | |
---|
940 | | - cup->cu_msg.cm_cmd = Cld_Create; |
---|
941 | | - cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; |
---|
942 | | - memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, |
---|
| 1113 | + cup->cu_u.cu_msg.cm_cmd = Cld_Create; |
---|
| 1114 | + cup->cu_u.cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; |
---|
| 1115 | + memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, |
---|
943 | 1116 | clp->cl_name.len); |
---|
944 | 1117 | |
---|
945 | | - ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); |
---|
| 1118 | + ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn); |
---|
946 | 1119 | if (!ret) { |
---|
947 | | - ret = cup->cu_msg.cm_status; |
---|
| 1120 | + ret = cup->cu_u.cu_msg.cm_status; |
---|
948 | 1121 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
---|
949 | 1122 | } |
---|
950 | 1123 | |
---|
.. | .. |
---|
953 | 1126 | if (ret) |
---|
954 | 1127 | printk(KERN_ERR "NFSD: Unable to create client " |
---|
955 | 1128 | "record on stable storage: %d\n", ret); |
---|
| 1129 | +} |
---|
| 1130 | + |
---|
| 1131 | +/* Ask daemon to create a new record */ |
---|
| 1132 | +static void |
---|
| 1133 | +nfsd4_cld_create_v2(struct nfs4_client *clp) |
---|
| 1134 | +{ |
---|
| 1135 | + int ret; |
---|
| 1136 | + struct cld_upcall *cup; |
---|
| 1137 | + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
---|
| 1138 | + struct cld_net *cn = nn->cld_net; |
---|
| 1139 | + struct cld_msg_v2 *cmsg; |
---|
| 1140 | + struct crypto_shash *tfm = cn->cn_tfm; |
---|
| 1141 | + struct xdr_netobj cksum; |
---|
| 1142 | + char *principal = NULL; |
---|
| 1143 | + |
---|
| 1144 | + /* Don't upcall if it's already stored */ |
---|
| 1145 | + if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
---|
| 1146 | + return; |
---|
| 1147 | + |
---|
| 1148 | + cup = alloc_cld_upcall(nn); |
---|
| 1149 | + if (!cup) { |
---|
| 1150 | + ret = -ENOMEM; |
---|
| 1151 | + goto out_err; |
---|
| 1152 | + } |
---|
| 1153 | + |
---|
| 1154 | + cmsg = &cup->cu_u.cu_msg_v2; |
---|
| 1155 | + cmsg->cm_cmd = Cld_Create; |
---|
| 1156 | + cmsg->cm_u.cm_clntinfo.cc_name.cn_len = clp->cl_name.len; |
---|
| 1157 | + memcpy(cmsg->cm_u.cm_clntinfo.cc_name.cn_id, clp->cl_name.data, |
---|
| 1158 | + clp->cl_name.len); |
---|
| 1159 | + if (clp->cl_cred.cr_raw_principal) |
---|
| 1160 | + principal = clp->cl_cred.cr_raw_principal; |
---|
| 1161 | + else if (clp->cl_cred.cr_principal) |
---|
| 1162 | + principal = clp->cl_cred.cr_principal; |
---|
| 1163 | + if (principal) { |
---|
| 1164 | + cksum.len = crypto_shash_digestsize(tfm); |
---|
| 1165 | + cksum.data = kmalloc(cksum.len, GFP_KERNEL); |
---|
| 1166 | + if (cksum.data == NULL) { |
---|
| 1167 | + ret = -ENOMEM; |
---|
| 1168 | + goto out; |
---|
| 1169 | + } |
---|
| 1170 | + ret = crypto_shash_tfm_digest(tfm, principal, strlen(principal), |
---|
| 1171 | + cksum.data); |
---|
| 1172 | + if (ret) { |
---|
| 1173 | + kfree(cksum.data); |
---|
| 1174 | + goto out; |
---|
| 1175 | + } |
---|
| 1176 | + cmsg->cm_u.cm_clntinfo.cc_princhash.cp_len = cksum.len; |
---|
| 1177 | + memcpy(cmsg->cm_u.cm_clntinfo.cc_princhash.cp_data, |
---|
| 1178 | + cksum.data, cksum.len); |
---|
| 1179 | + kfree(cksum.data); |
---|
| 1180 | + } else |
---|
| 1181 | + cmsg->cm_u.cm_clntinfo.cc_princhash.cp_len = 0; |
---|
| 1182 | + |
---|
| 1183 | + ret = cld_pipe_upcall(cn->cn_pipe, cmsg, nn); |
---|
| 1184 | + if (!ret) { |
---|
| 1185 | + ret = cmsg->cm_status; |
---|
| 1186 | + set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
---|
| 1187 | + } |
---|
| 1188 | + |
---|
| 1189 | +out: |
---|
| 1190 | + free_cld_upcall(cup); |
---|
| 1191 | +out_err: |
---|
| 1192 | + if (ret) |
---|
| 1193 | + pr_err("NFSD: Unable to create client record on stable storage: %d\n", |
---|
| 1194 | + ret); |
---|
956 | 1195 | } |
---|
957 | 1196 | |
---|
958 | 1197 | /* Ask daemon to create a new record */ |
---|
.. | .. |
---|
968 | 1207 | if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
---|
969 | 1208 | return; |
---|
970 | 1209 | |
---|
971 | | - cup = alloc_cld_upcall(cn); |
---|
| 1210 | + cup = alloc_cld_upcall(nn); |
---|
972 | 1211 | if (!cup) { |
---|
973 | 1212 | ret = -ENOMEM; |
---|
974 | 1213 | goto out_err; |
---|
975 | 1214 | } |
---|
976 | 1215 | |
---|
977 | | - cup->cu_msg.cm_cmd = Cld_Remove; |
---|
978 | | - cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; |
---|
979 | | - memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, |
---|
| 1216 | + cup->cu_u.cu_msg.cm_cmd = Cld_Remove; |
---|
| 1217 | + cup->cu_u.cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; |
---|
| 1218 | + memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, |
---|
980 | 1219 | clp->cl_name.len); |
---|
981 | 1220 | |
---|
982 | | - ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); |
---|
| 1221 | + ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn); |
---|
983 | 1222 | if (!ret) { |
---|
984 | | - ret = cup->cu_msg.cm_status; |
---|
| 1223 | + ret = cup->cu_u.cu_msg.cm_status; |
---|
985 | 1224 | clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
---|
986 | 1225 | } |
---|
987 | 1226 | |
---|
.. | .. |
---|
992 | 1231 | "record from stable storage: %d\n", ret); |
---|
993 | 1232 | } |
---|
994 | 1233 | |
---|
995 | | -/* Check for presence of a record, and update its timestamp */ |
---|
| 1234 | +/* |
---|
| 1235 | + * For older nfsdcld's that do not allow us to "slurp" the clients |
---|
| 1236 | + * from the tracking database during startup. |
---|
| 1237 | + * |
---|
| 1238 | + * Check for presence of a record, and update its timestamp |
---|
| 1239 | + */ |
---|
996 | 1240 | static int |
---|
997 | | -nfsd4_cld_check(struct nfs4_client *clp) |
---|
| 1241 | +nfsd4_cld_check_v0(struct nfs4_client *clp) |
---|
998 | 1242 | { |
---|
999 | 1243 | int ret; |
---|
1000 | 1244 | struct cld_upcall *cup; |
---|
.. | .. |
---|
1005 | 1249 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
---|
1006 | 1250 | return 0; |
---|
1007 | 1251 | |
---|
1008 | | - cup = alloc_cld_upcall(cn); |
---|
| 1252 | + cup = alloc_cld_upcall(nn); |
---|
1009 | 1253 | if (!cup) { |
---|
1010 | 1254 | printk(KERN_ERR "NFSD: Unable to check client record on " |
---|
1011 | 1255 | "stable storage: %d\n", -ENOMEM); |
---|
1012 | 1256 | return -ENOMEM; |
---|
1013 | 1257 | } |
---|
1014 | 1258 | |
---|
1015 | | - cup->cu_msg.cm_cmd = Cld_Check; |
---|
1016 | | - cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; |
---|
1017 | | - memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, |
---|
| 1259 | + cup->cu_u.cu_msg.cm_cmd = Cld_Check; |
---|
| 1260 | + cup->cu_u.cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; |
---|
| 1261 | + memcpy(cup->cu_u.cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, |
---|
1018 | 1262 | clp->cl_name.len); |
---|
1019 | 1263 | |
---|
1020 | | - ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); |
---|
| 1264 | + ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn); |
---|
1021 | 1265 | if (!ret) { |
---|
1022 | | - ret = cup->cu_msg.cm_status; |
---|
| 1266 | + ret = cup->cu_u.cu_msg.cm_status; |
---|
1023 | 1267 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
---|
1024 | 1268 | } |
---|
1025 | 1269 | |
---|
.. | .. |
---|
1027 | 1271 | return ret; |
---|
1028 | 1272 | } |
---|
1029 | 1273 | |
---|
1030 | | -static void |
---|
1031 | | -nfsd4_cld_grace_done(struct nfsd_net *nn) |
---|
| 1274 | +/* |
---|
| 1275 | + * For newer nfsdcld's that allow us to "slurp" the clients |
---|
| 1276 | + * from the tracking database during startup. |
---|
| 1277 | + * |
---|
| 1278 | + * Check for presence of a record in the reclaim_str_hashtbl |
---|
| 1279 | + */ |
---|
| 1280 | +static int |
---|
| 1281 | +nfsd4_cld_check(struct nfs4_client *clp) |
---|
| 1282 | +{ |
---|
| 1283 | + struct nfs4_client_reclaim *crp; |
---|
| 1284 | + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
---|
| 1285 | + struct cld_net *cn = nn->cld_net; |
---|
| 1286 | + int status; |
---|
| 1287 | + char dname[HEXDIR_LEN]; |
---|
| 1288 | + struct xdr_netobj name; |
---|
| 1289 | + |
---|
| 1290 | + /* did we already find that this client is stable? */ |
---|
| 1291 | + if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
---|
| 1292 | + return 0; |
---|
| 1293 | + |
---|
| 1294 | + /* look for it in the reclaim hashtable otherwise */ |
---|
| 1295 | + crp = nfsd4_find_reclaim_client(clp->cl_name, nn); |
---|
| 1296 | + if (crp) |
---|
| 1297 | + goto found; |
---|
| 1298 | + |
---|
| 1299 | + if (cn->cn_has_legacy) { |
---|
| 1300 | + status = nfs4_make_rec_clidname(dname, &clp->cl_name); |
---|
| 1301 | + if (status) |
---|
| 1302 | + return -ENOENT; |
---|
| 1303 | + |
---|
| 1304 | + name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL); |
---|
| 1305 | + if (!name.data) { |
---|
| 1306 | + dprintk("%s: failed to allocate memory for name.data!\n", |
---|
| 1307 | + __func__); |
---|
| 1308 | + return -ENOENT; |
---|
| 1309 | + } |
---|
| 1310 | + name.len = HEXDIR_LEN; |
---|
| 1311 | + crp = nfsd4_find_reclaim_client(name, nn); |
---|
| 1312 | + kfree(name.data); |
---|
| 1313 | + if (crp) |
---|
| 1314 | + goto found; |
---|
| 1315 | + |
---|
| 1316 | + } |
---|
| 1317 | + return -ENOENT; |
---|
| 1318 | +found: |
---|
| 1319 | + crp->cr_clp = clp; |
---|
| 1320 | + return 0; |
---|
| 1321 | +} |
---|
| 1322 | + |
---|
| 1323 | +static int |
---|
| 1324 | +nfsd4_cld_check_v2(struct nfs4_client *clp) |
---|
| 1325 | +{ |
---|
| 1326 | + struct nfs4_client_reclaim *crp; |
---|
| 1327 | + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
---|
| 1328 | + struct cld_net *cn = nn->cld_net; |
---|
| 1329 | + int status; |
---|
| 1330 | + char dname[HEXDIR_LEN]; |
---|
| 1331 | + struct xdr_netobj name; |
---|
| 1332 | + struct crypto_shash *tfm = cn->cn_tfm; |
---|
| 1333 | + struct xdr_netobj cksum; |
---|
| 1334 | + char *principal = NULL; |
---|
| 1335 | + |
---|
| 1336 | + /* did we already find that this client is stable? */ |
---|
| 1337 | + if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
---|
| 1338 | + return 0; |
---|
| 1339 | + |
---|
| 1340 | + /* look for it in the reclaim hashtable otherwise */ |
---|
| 1341 | + crp = nfsd4_find_reclaim_client(clp->cl_name, nn); |
---|
| 1342 | + if (crp) |
---|
| 1343 | + goto found; |
---|
| 1344 | + |
---|
| 1345 | + if (cn->cn_has_legacy) { |
---|
| 1346 | + status = nfs4_make_rec_clidname(dname, &clp->cl_name); |
---|
| 1347 | + if (status) |
---|
| 1348 | + return -ENOENT; |
---|
| 1349 | + |
---|
| 1350 | + name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL); |
---|
| 1351 | + if (!name.data) { |
---|
| 1352 | + dprintk("%s: failed to allocate memory for name.data\n", |
---|
| 1353 | + __func__); |
---|
| 1354 | + return -ENOENT; |
---|
| 1355 | + } |
---|
| 1356 | + name.len = HEXDIR_LEN; |
---|
| 1357 | + crp = nfsd4_find_reclaim_client(name, nn); |
---|
| 1358 | + kfree(name.data); |
---|
| 1359 | + if (crp) |
---|
| 1360 | + goto found; |
---|
| 1361 | + |
---|
| 1362 | + } |
---|
| 1363 | + return -ENOENT; |
---|
| 1364 | +found: |
---|
| 1365 | + if (crp->cr_princhash.len) { |
---|
| 1366 | + if (clp->cl_cred.cr_raw_principal) |
---|
| 1367 | + principal = clp->cl_cred.cr_raw_principal; |
---|
| 1368 | + else if (clp->cl_cred.cr_principal) |
---|
| 1369 | + principal = clp->cl_cred.cr_principal; |
---|
| 1370 | + if (principal == NULL) |
---|
| 1371 | + return -ENOENT; |
---|
| 1372 | + cksum.len = crypto_shash_digestsize(tfm); |
---|
| 1373 | + cksum.data = kmalloc(cksum.len, GFP_KERNEL); |
---|
| 1374 | + if (cksum.data == NULL) |
---|
| 1375 | + return -ENOENT; |
---|
| 1376 | + status = crypto_shash_tfm_digest(tfm, principal, |
---|
| 1377 | + strlen(principal), cksum.data); |
---|
| 1378 | + if (status) { |
---|
| 1379 | + kfree(cksum.data); |
---|
| 1380 | + return -ENOENT; |
---|
| 1381 | + } |
---|
| 1382 | + if (memcmp(crp->cr_princhash.data, cksum.data, |
---|
| 1383 | + crp->cr_princhash.len)) { |
---|
| 1384 | + kfree(cksum.data); |
---|
| 1385 | + return -ENOENT; |
---|
| 1386 | + } |
---|
| 1387 | + kfree(cksum.data); |
---|
| 1388 | + } |
---|
| 1389 | + crp->cr_clp = clp; |
---|
| 1390 | + return 0; |
---|
| 1391 | +} |
---|
| 1392 | + |
---|
| 1393 | +static int |
---|
| 1394 | +nfsd4_cld_grace_start(struct nfsd_net *nn) |
---|
1032 | 1395 | { |
---|
1033 | 1396 | int ret; |
---|
1034 | 1397 | struct cld_upcall *cup; |
---|
1035 | 1398 | struct cld_net *cn = nn->cld_net; |
---|
1036 | 1399 | |
---|
1037 | | - cup = alloc_cld_upcall(cn); |
---|
| 1400 | + cup = alloc_cld_upcall(nn); |
---|
1038 | 1401 | if (!cup) { |
---|
1039 | 1402 | ret = -ENOMEM; |
---|
1040 | 1403 | goto out_err; |
---|
1041 | 1404 | } |
---|
1042 | 1405 | |
---|
1043 | | - cup->cu_msg.cm_cmd = Cld_GraceDone; |
---|
1044 | | - cup->cu_msg.cm_u.cm_gracetime = (int64_t)nn->boot_time; |
---|
1045 | | - ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); |
---|
| 1406 | + cup->cu_u.cu_msg.cm_cmd = Cld_GraceStart; |
---|
| 1407 | + ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn); |
---|
1046 | 1408 | if (!ret) |
---|
1047 | | - ret = cup->cu_msg.cm_status; |
---|
| 1409 | + ret = cup->cu_u.cu_msg.cm_status; |
---|
| 1410 | + |
---|
| 1411 | + free_cld_upcall(cup); |
---|
| 1412 | +out_err: |
---|
| 1413 | + if (ret) |
---|
| 1414 | + dprintk("%s: Unable to get clients from userspace: %d\n", |
---|
| 1415 | + __func__, ret); |
---|
| 1416 | + return ret; |
---|
| 1417 | +} |
---|
| 1418 | + |
---|
| 1419 | +/* For older nfsdcld's that need cm_gracetime */ |
---|
| 1420 | +static void |
---|
| 1421 | +nfsd4_cld_grace_done_v0(struct nfsd_net *nn) |
---|
| 1422 | +{ |
---|
| 1423 | + int ret; |
---|
| 1424 | + struct cld_upcall *cup; |
---|
| 1425 | + struct cld_net *cn = nn->cld_net; |
---|
| 1426 | + |
---|
| 1427 | + cup = alloc_cld_upcall(nn); |
---|
| 1428 | + if (!cup) { |
---|
| 1429 | + ret = -ENOMEM; |
---|
| 1430 | + goto out_err; |
---|
| 1431 | + } |
---|
| 1432 | + |
---|
| 1433 | + cup->cu_u.cu_msg.cm_cmd = Cld_GraceDone; |
---|
| 1434 | + cup->cu_u.cu_msg.cm_u.cm_gracetime = nn->boot_time; |
---|
| 1435 | + ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn); |
---|
| 1436 | + if (!ret) |
---|
| 1437 | + ret = cup->cu_u.cu_msg.cm_status; |
---|
1048 | 1438 | |
---|
1049 | 1439 | free_cld_upcall(cup); |
---|
1050 | 1440 | out_err: |
---|
.. | .. |
---|
1052 | 1442 | printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret); |
---|
1053 | 1443 | } |
---|
1054 | 1444 | |
---|
1055 | | -static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = { |
---|
| 1445 | +/* |
---|
| 1446 | + * For newer nfsdcld's that do not need cm_gracetime. We also need to call |
---|
| 1447 | + * nfs4_release_reclaim() to clear out the reclaim_str_hashtbl. |
---|
| 1448 | + */ |
---|
| 1449 | +static void |
---|
| 1450 | +nfsd4_cld_grace_done(struct nfsd_net *nn) |
---|
| 1451 | +{ |
---|
| 1452 | + int ret; |
---|
| 1453 | + struct cld_upcall *cup; |
---|
| 1454 | + struct cld_net *cn = nn->cld_net; |
---|
| 1455 | + |
---|
| 1456 | + cup = alloc_cld_upcall(nn); |
---|
| 1457 | + if (!cup) { |
---|
| 1458 | + ret = -ENOMEM; |
---|
| 1459 | + goto out_err; |
---|
| 1460 | + } |
---|
| 1461 | + |
---|
| 1462 | + cup->cu_u.cu_msg.cm_cmd = Cld_GraceDone; |
---|
| 1463 | + ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn); |
---|
| 1464 | + if (!ret) |
---|
| 1465 | + ret = cup->cu_u.cu_msg.cm_status; |
---|
| 1466 | + |
---|
| 1467 | + free_cld_upcall(cup); |
---|
| 1468 | +out_err: |
---|
| 1469 | + nfs4_release_reclaim(nn); |
---|
| 1470 | + if (ret) |
---|
| 1471 | + printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret); |
---|
| 1472 | +} |
---|
| 1473 | + |
---|
| 1474 | +static int |
---|
| 1475 | +nfs4_cld_state_init(struct net *net) |
---|
| 1476 | +{ |
---|
| 1477 | + struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
---|
| 1478 | + int i; |
---|
| 1479 | + |
---|
| 1480 | + nn->reclaim_str_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, |
---|
| 1481 | + sizeof(struct list_head), |
---|
| 1482 | + GFP_KERNEL); |
---|
| 1483 | + if (!nn->reclaim_str_hashtbl) |
---|
| 1484 | + return -ENOMEM; |
---|
| 1485 | + |
---|
| 1486 | + for (i = 0; i < CLIENT_HASH_SIZE; i++) |
---|
| 1487 | + INIT_LIST_HEAD(&nn->reclaim_str_hashtbl[i]); |
---|
| 1488 | + nn->reclaim_str_hashtbl_size = 0; |
---|
| 1489 | + nn->track_reclaim_completes = true; |
---|
| 1490 | + atomic_set(&nn->nr_reclaim_complete, 0); |
---|
| 1491 | + |
---|
| 1492 | + return 0; |
---|
| 1493 | +} |
---|
| 1494 | + |
---|
| 1495 | +static void |
---|
| 1496 | +nfs4_cld_state_shutdown(struct net *net) |
---|
| 1497 | +{ |
---|
| 1498 | + struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
---|
| 1499 | + |
---|
| 1500 | + nn->track_reclaim_completes = false; |
---|
| 1501 | + kfree(nn->reclaim_str_hashtbl); |
---|
| 1502 | +} |
---|
| 1503 | + |
---|
| 1504 | +static bool |
---|
| 1505 | +cld_running(struct nfsd_net *nn) |
---|
| 1506 | +{ |
---|
| 1507 | + struct cld_net *cn = nn->cld_net; |
---|
| 1508 | + struct rpc_pipe *pipe = cn->cn_pipe; |
---|
| 1509 | + |
---|
| 1510 | + return pipe->nreaders || pipe->nwriters; |
---|
| 1511 | +} |
---|
| 1512 | + |
---|
| 1513 | +static int |
---|
| 1514 | +nfsd4_cld_get_version(struct nfsd_net *nn) |
---|
| 1515 | +{ |
---|
| 1516 | + int ret = 0; |
---|
| 1517 | + struct cld_upcall *cup; |
---|
| 1518 | + struct cld_net *cn = nn->cld_net; |
---|
| 1519 | + uint8_t version; |
---|
| 1520 | + |
---|
| 1521 | + cup = alloc_cld_upcall(nn); |
---|
| 1522 | + if (!cup) { |
---|
| 1523 | + ret = -ENOMEM; |
---|
| 1524 | + goto out_err; |
---|
| 1525 | + } |
---|
| 1526 | + cup->cu_u.cu_msg.cm_cmd = Cld_GetVersion; |
---|
| 1527 | + ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_u.cu_msg, nn); |
---|
| 1528 | + if (!ret) { |
---|
| 1529 | + ret = cup->cu_u.cu_msg.cm_status; |
---|
| 1530 | + if (ret) |
---|
| 1531 | + goto out_free; |
---|
| 1532 | + version = cup->cu_u.cu_msg.cm_u.cm_version; |
---|
| 1533 | + dprintk("%s: userspace returned version %u\n", |
---|
| 1534 | + __func__, version); |
---|
| 1535 | + if (version < 1) |
---|
| 1536 | + version = 1; |
---|
| 1537 | + else if (version > CLD_UPCALL_VERSION) |
---|
| 1538 | + version = CLD_UPCALL_VERSION; |
---|
| 1539 | + |
---|
| 1540 | + switch (version) { |
---|
| 1541 | + case 1: |
---|
| 1542 | + nn->client_tracking_ops = &nfsd4_cld_tracking_ops; |
---|
| 1543 | + break; |
---|
| 1544 | + case 2: |
---|
| 1545 | + nn->client_tracking_ops = &nfsd4_cld_tracking_ops_v2; |
---|
| 1546 | + break; |
---|
| 1547 | + default: |
---|
| 1548 | + break; |
---|
| 1549 | + } |
---|
| 1550 | + } |
---|
| 1551 | +out_free: |
---|
| 1552 | + free_cld_upcall(cup); |
---|
| 1553 | +out_err: |
---|
| 1554 | + if (ret) |
---|
| 1555 | + dprintk("%s: Unable to get version from userspace: %d\n", |
---|
| 1556 | + __func__, ret); |
---|
| 1557 | + return ret; |
---|
| 1558 | +} |
---|
| 1559 | + |
---|
| 1560 | +static int |
---|
| 1561 | +nfsd4_cld_tracking_init(struct net *net) |
---|
| 1562 | +{ |
---|
| 1563 | + int status; |
---|
| 1564 | + struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
---|
| 1565 | + bool running; |
---|
| 1566 | + int retries = 10; |
---|
| 1567 | + struct crypto_shash *tfm; |
---|
| 1568 | + |
---|
| 1569 | + status = nfs4_cld_state_init(net); |
---|
| 1570 | + if (status) |
---|
| 1571 | + return status; |
---|
| 1572 | + |
---|
| 1573 | + status = __nfsd4_init_cld_pipe(net); |
---|
| 1574 | + if (status) |
---|
| 1575 | + goto err_shutdown; |
---|
| 1576 | + |
---|
| 1577 | + /* |
---|
| 1578 | + * rpc pipe upcalls take 30 seconds to time out, so we don't want to |
---|
| 1579 | + * queue an upcall unless we know that nfsdcld is running (because we |
---|
| 1580 | + * want this to fail fast so that nfsd4_client_tracking_init() can try |
---|
| 1581 | + * the next client tracking method). nfsdcld should already be running |
---|
| 1582 | + * before nfsd is started, so the wait here is for nfsdcld to open the |
---|
| 1583 | + * pipefs file we just created. |
---|
| 1584 | + */ |
---|
| 1585 | + while (!(running = cld_running(nn)) && retries--) |
---|
| 1586 | + msleep(100); |
---|
| 1587 | + |
---|
| 1588 | + if (!running) { |
---|
| 1589 | + status = -ETIMEDOUT; |
---|
| 1590 | + goto err_remove; |
---|
| 1591 | + } |
---|
| 1592 | + tfm = crypto_alloc_shash("sha256", 0, 0); |
---|
| 1593 | + if (IS_ERR(tfm)) { |
---|
| 1594 | + status = PTR_ERR(tfm); |
---|
| 1595 | + goto err_remove; |
---|
| 1596 | + } |
---|
| 1597 | + nn->cld_net->cn_tfm = tfm; |
---|
| 1598 | + |
---|
| 1599 | + status = nfsd4_cld_get_version(nn); |
---|
| 1600 | + if (status == -EOPNOTSUPP) |
---|
| 1601 | + pr_warn("NFSD: nfsdcld GetVersion upcall failed. Please upgrade nfsdcld.\n"); |
---|
| 1602 | + |
---|
| 1603 | + status = nfsd4_cld_grace_start(nn); |
---|
| 1604 | + if (status) { |
---|
| 1605 | + if (status == -EOPNOTSUPP) |
---|
| 1606 | + pr_warn("NFSD: nfsdcld GraceStart upcall failed. Please upgrade nfsdcld.\n"); |
---|
| 1607 | + nfs4_release_reclaim(nn); |
---|
| 1608 | + goto err_remove; |
---|
| 1609 | + } else |
---|
| 1610 | + printk("NFSD: Using nfsdcld client tracking operations.\n"); |
---|
| 1611 | + return 0; |
---|
| 1612 | + |
---|
| 1613 | +err_remove: |
---|
| 1614 | + nfsd4_remove_cld_pipe(net); |
---|
| 1615 | +err_shutdown: |
---|
| 1616 | + nfs4_cld_state_shutdown(net); |
---|
| 1617 | + return status; |
---|
| 1618 | +} |
---|
| 1619 | + |
---|
| 1620 | +static void |
---|
| 1621 | +nfsd4_cld_tracking_exit(struct net *net) |
---|
| 1622 | +{ |
---|
| 1623 | + struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
---|
| 1624 | + |
---|
| 1625 | + nfs4_release_reclaim(nn); |
---|
| 1626 | + nfsd4_remove_cld_pipe(net); |
---|
| 1627 | + nfs4_cld_state_shutdown(net); |
---|
| 1628 | +} |
---|
| 1629 | + |
---|
| 1630 | +/* For older nfsdcld's */ |
---|
| 1631 | +static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v0 = { |
---|
1056 | 1632 | .init = nfsd4_init_cld_pipe, |
---|
1057 | 1633 | .exit = nfsd4_remove_cld_pipe, |
---|
1058 | 1634 | .create = nfsd4_cld_create, |
---|
1059 | 1635 | .remove = nfsd4_cld_remove, |
---|
| 1636 | + .check = nfsd4_cld_check_v0, |
---|
| 1637 | + .grace_done = nfsd4_cld_grace_done_v0, |
---|
| 1638 | + .version = 1, |
---|
| 1639 | + .msglen = sizeof(struct cld_msg), |
---|
| 1640 | +}; |
---|
| 1641 | + |
---|
| 1642 | +/* For newer nfsdcld's */ |
---|
| 1643 | +static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = { |
---|
| 1644 | + .init = nfsd4_cld_tracking_init, |
---|
| 1645 | + .exit = nfsd4_cld_tracking_exit, |
---|
| 1646 | + .create = nfsd4_cld_create, |
---|
| 1647 | + .remove = nfsd4_cld_remove, |
---|
1060 | 1648 | .check = nfsd4_cld_check, |
---|
1061 | 1649 | .grace_done = nfsd4_cld_grace_done, |
---|
| 1650 | + .version = 1, |
---|
| 1651 | + .msglen = sizeof(struct cld_msg), |
---|
| 1652 | +}; |
---|
| 1653 | + |
---|
| 1654 | +/* v2 create/check ops include the principal, if available */ |
---|
| 1655 | +static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops_v2 = { |
---|
| 1656 | + .init = nfsd4_cld_tracking_init, |
---|
| 1657 | + .exit = nfsd4_cld_tracking_exit, |
---|
| 1658 | + .create = nfsd4_cld_create_v2, |
---|
| 1659 | + .remove = nfsd4_cld_remove, |
---|
| 1660 | + .check = nfsd4_cld_check_v2, |
---|
| 1661 | + .grace_done = nfsd4_cld_grace_done, |
---|
| 1662 | + .version = 2, |
---|
| 1663 | + .msglen = sizeof(struct cld_msg_v2), |
---|
1062 | 1664 | }; |
---|
1063 | 1665 | |
---|
1064 | 1666 | /* upcall via usermodehelper */ |
---|
.. | .. |
---|
1166 | 1768 | } |
---|
1167 | 1769 | |
---|
1168 | 1770 | static char * |
---|
1169 | | -nfsd4_cltrack_grace_start(time_t grace_start) |
---|
| 1771 | +nfsd4_cltrack_grace_start(time64_t grace_start) |
---|
1170 | 1772 | { |
---|
1171 | 1773 | int copied; |
---|
1172 | 1774 | size_t len; |
---|
.. | .. |
---|
1179 | 1781 | if (!result) |
---|
1180 | 1782 | return result; |
---|
1181 | 1783 | |
---|
1182 | | - copied = snprintf(result, len, GRACE_START_ENV_PREFIX "%ld", |
---|
| 1784 | + copied = snprintf(result, len, GRACE_START_ENV_PREFIX "%lld", |
---|
1183 | 1785 | grace_start); |
---|
1184 | 1786 | if (copied >= len) { |
---|
1185 | 1787 | /* just return nothing if output was truncated */ |
---|
.. | .. |
---|
1236 | 1838 | static char * |
---|
1237 | 1839 | bin_to_hex_dup(const unsigned char *src, int srclen) |
---|
1238 | 1840 | { |
---|
1239 | | - int i; |
---|
1240 | | - char *buf, *hex; |
---|
| 1841 | + char *buf; |
---|
1241 | 1842 | |
---|
1242 | 1843 | /* +1 for terminating NULL */ |
---|
1243 | | - buf = kmalloc((srclen * 2) + 1, GFP_KERNEL); |
---|
| 1844 | + buf = kzalloc((srclen * 2) + 1, GFP_KERNEL); |
---|
1244 | 1845 | if (!buf) |
---|
1245 | 1846 | return buf; |
---|
1246 | 1847 | |
---|
1247 | | - hex = buf; |
---|
1248 | | - for (i = 0; i < srclen; i++) { |
---|
1249 | | - sprintf(hex, "%2.2x", *src++); |
---|
1250 | | - hex += 2; |
---|
1251 | | - } |
---|
| 1848 | + bin2hex(buf, src, srclen); |
---|
1252 | 1849 | return buf; |
---|
1253 | 1850 | } |
---|
1254 | 1851 | |
---|
.. | .. |
---|
1268 | 1865 | |
---|
1269 | 1866 | ret = nfsd4_umh_cltrack_upcall("init", NULL, grace_start, NULL); |
---|
1270 | 1867 | kfree(grace_start); |
---|
| 1868 | + if (!ret) |
---|
| 1869 | + printk("NFSD: Using UMH upcall client tracking operations.\n"); |
---|
1271 | 1870 | return ret; |
---|
1272 | 1871 | } |
---|
1273 | 1872 | |
---|
.. | .. |
---|
1391 | 1990 | char *legacy; |
---|
1392 | 1991 | char timestr[22]; /* FIXME: better way to determine max size? */ |
---|
1393 | 1992 | |
---|
1394 | | - sprintf(timestr, "%ld", nn->boot_time); |
---|
| 1993 | + sprintf(timestr, "%lld", nn->boot_time); |
---|
1395 | 1994 | legacy = nfsd4_cltrack_legacy_topdir(); |
---|
1396 | 1995 | nfsd4_umh_cltrack_upcall("gracedone", timestr, legacy, NULL); |
---|
1397 | 1996 | kfree(legacy); |
---|
.. | .. |
---|
1404 | 2003 | .remove = nfsd4_umh_cltrack_remove, |
---|
1405 | 2004 | .check = nfsd4_umh_cltrack_check, |
---|
1406 | 2005 | .grace_done = nfsd4_umh_cltrack_grace_done, |
---|
| 2006 | + .version = 1, |
---|
| 2007 | + .msglen = 0, |
---|
1407 | 2008 | }; |
---|
1408 | 2009 | |
---|
1409 | 2010 | int |
---|
.. | .. |
---|
1417 | 2018 | if (nn->client_tracking_ops) |
---|
1418 | 2019 | goto do_init; |
---|
1419 | 2020 | |
---|
| 2021 | + /* First, try to use nfsdcld */ |
---|
| 2022 | + nn->client_tracking_ops = &nfsd4_cld_tracking_ops; |
---|
| 2023 | + status = nn->client_tracking_ops->init(net); |
---|
| 2024 | + if (!status) |
---|
| 2025 | + return status; |
---|
| 2026 | + if (status != -ETIMEDOUT) { |
---|
| 2027 | + nn->client_tracking_ops = &nfsd4_cld_tracking_ops_v0; |
---|
| 2028 | + status = nn->client_tracking_ops->init(net); |
---|
| 2029 | + if (!status) |
---|
| 2030 | + return status; |
---|
| 2031 | + } |
---|
| 2032 | + |
---|
1420 | 2033 | /* |
---|
1421 | | - * First, try a UMH upcall. It should succeed or fail quickly, so |
---|
1422 | | - * there's little harm in trying that first. |
---|
| 2034 | + * Next, try the UMH upcall. |
---|
1423 | 2035 | */ |
---|
1424 | 2036 | nn->client_tracking_ops = &nfsd4_umh_tracking_ops; |
---|
1425 | 2037 | status = nn->client_tracking_ops->init(net); |
---|
.. | .. |
---|
1427 | 2039 | return status; |
---|
1428 | 2040 | |
---|
1429 | 2041 | /* |
---|
1430 | | - * See if the recoverydir exists and is a directory. If it is, |
---|
1431 | | - * then use the legacy ops. |
---|
| 2042 | + * Finally, See if the recoverydir exists and is a directory. |
---|
| 2043 | + * If it is, then use the legacy ops. |
---|
1432 | 2044 | */ |
---|
1433 | 2045 | nn->client_tracking_ops = &nfsd4_legacy_tracking_ops; |
---|
1434 | 2046 | status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path); |
---|
1435 | 2047 | if (!status) { |
---|
1436 | 2048 | status = d_is_dir(path.dentry); |
---|
1437 | 2049 | path_put(&path); |
---|
1438 | | - if (status) |
---|
1439 | | - goto do_init; |
---|
| 2050 | + if (!status) { |
---|
| 2051 | + status = -EINVAL; |
---|
| 2052 | + goto out; |
---|
| 2053 | + } |
---|
1440 | 2054 | } |
---|
1441 | 2055 | |
---|
1442 | | - /* Finally, try to use nfsdcld */ |
---|
1443 | | - nn->client_tracking_ops = &nfsd4_cld_tracking_ops; |
---|
1444 | | - printk(KERN_WARNING "NFSD: the nfsdcld client tracking upcall will be " |
---|
1445 | | - "removed in 3.10. Please transition to using " |
---|
1446 | | - "nfsdcltrack.\n"); |
---|
1447 | 2056 | do_init: |
---|
1448 | 2057 | status = nn->client_tracking_ops->init(net); |
---|
| 2058 | +out: |
---|
1449 | 2059 | if (status) { |
---|
1450 | 2060 | printk(KERN_WARNING "NFSD: Unable to initialize client " |
---|
1451 | 2061 | "recovery tracking! (%d)\n", status); |
---|
.. | .. |
---|
1548 | 2158 | int |
---|
1549 | 2159 | register_cld_notifier(void) |
---|
1550 | 2160 | { |
---|
| 2161 | + WARN_ON(!nfsd_net_id); |
---|
1551 | 2162 | return rpc_pipefs_notifier_register(&nfsd4_cld_block); |
---|
1552 | 2163 | } |
---|
1553 | 2164 | |
---|