diff options
| -rw-r--r-- | Documentation/filesystems/00-INDEX | 4 | ||||
| -rw-r--r-- | fs/Kconfig | 2 | ||||
| -rw-r--r-- | fs/lockd/svclock.c | 2 | ||||
| -rw-r--r-- | fs/locks.c | 3 | ||||
| -rw-r--r-- | fs/nfs/Kconfig | 2 | ||||
| -rw-r--r-- | fs/nfsd/export.c | 13 | ||||
| -rw-r--r-- | fs/nfsd/nfs3proc.c | 237 | ||||
| -rw-r--r-- | fs/nfsd/nfs3xdr.c | 1 | ||||
| -rw-r--r-- | fs/nfsd/nfs4callback.c | 247 | ||||
| -rw-r--r-- | fs/nfsd/nfs4proc.c | 129 | ||||
| -rw-r--r-- | fs/nfsd/nfs4state.c | 171 | ||||
| -rw-r--r-- | fs/nfsd/nfs4xdr.c | 296 | ||||
| -rw-r--r-- | fs/nfsd/nfscache.c | 33 | ||||
| -rw-r--r-- | fs/nfsd/nfsctl.c | 294 | ||||
| -rw-r--r-- | fs/nfsd/nfsfh.c | 6 | ||||
| -rw-r--r-- | fs/nfsd/nfsproc.c | 198 | ||||
| -rw-r--r-- | fs/nfsd/nfssvc.c | 12 | ||||
| -rw-r--r-- | fs/nfsd/vfs.c | 93 | ||||
| -rw-r--r-- | include/linux/fs.h | 1 | ||||
| -rw-r--r-- | include/linux/nfsd/cache.h | 3 | ||||
| -rw-r--r-- | include/linux/nfsd/nfsfh.h | 7 | ||||
| -rw-r--r-- | include/linux/nfsd/state.h | 44 | ||||
| -rw-r--r-- | include/linux/nfsd/xdr4.h | 28 | ||||
| -rw-r--r-- | include/linux/sunrpc/svc_xprt.h | 7 | ||||
| -rw-r--r-- | include/linux/sunrpc/svcsock.h | 7 | ||||
| -rw-r--r-- | net/sunrpc/cache.c | 2 | ||||
| -rw-r--r-- | net/sunrpc/svc_xprt.c | 57 | ||||
| -rw-r--r-- | net/sunrpc/svcsock.c | 122 | ||||
| -rw-r--r-- | net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 8 |
29 files changed, 1329 insertions, 700 deletions
diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX index 8dd6db76171d..f15621ee5599 100644 --- a/Documentation/filesystems/00-INDEX +++ b/Documentation/filesystems/00-INDEX | |||
| @@ -66,6 +66,10 @@ mandatory-locking.txt | |||
| 66 | - info on the Linux implementation of Sys V mandatory file locking. | 66 | - info on the Linux implementation of Sys V mandatory file locking. |
| 67 | ncpfs.txt | 67 | ncpfs.txt |
| 68 | - info on Novell Netware(tm) filesystem using NCP protocol. | 68 | - info on Novell Netware(tm) filesystem using NCP protocol. |
| 69 | nfs41-server.txt | ||
| 70 | - info on the Linux server implementation of NFSv4 minor version 1. | ||
| 71 | nfs-rdma.txt | ||
| 72 | - how to install and setup the Linux NFS/RDMA client and server software. | ||
| 69 | nfsroot.txt | 73 | nfsroot.txt |
| 70 | - short guide on setting up a diskless box with NFS root filesystem. | 74 | - short guide on setting up a diskless box with NFS root filesystem. |
| 71 | nilfs2.txt | 75 | nilfs2.txt |
diff --git a/fs/Kconfig b/fs/Kconfig index d78e950402c1..a97263be6a91 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
| @@ -236,10 +236,12 @@ source "fs/nfsd/Kconfig" | |||
| 236 | 236 | ||
| 237 | config LOCKD | 237 | config LOCKD |
| 238 | tristate | 238 | tristate |
| 239 | depends on FILE_LOCKING | ||
| 239 | 240 | ||
| 240 | config LOCKD_V4 | 241 | config LOCKD_V4 |
| 241 | bool | 242 | bool |
| 242 | depends on NFSD_V3 || NFS_V3 | 243 | depends on NFSD_V3 || NFS_V3 |
| 244 | depends on FILE_LOCKING | ||
| 243 | default y | 245 | default y |
| 244 | 246 | ||
| 245 | config EXPORTFS | 247 | config EXPORTFS |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 83ee34203bd7..e577a78d7bac 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
| @@ -326,6 +326,8 @@ static void nlmsvc_freegrantargs(struct nlm_rqst *call) | |||
| 326 | { | 326 | { |
| 327 | if (call->a_args.lock.oh.data != call->a_owner) | 327 | if (call->a_args.lock.oh.data != call->a_owner) |
| 328 | kfree(call->a_args.lock.oh.data); | 328 | kfree(call->a_args.lock.oh.data); |
| 329 | |||
| 330 | locks_release_private(&call->a_args.lock.fl); | ||
| 329 | } | 331 | } |
| 330 | 332 | ||
| 331 | /* | 333 | /* |
diff --git a/fs/locks.c b/fs/locks.c index ec3deea29e37..b6440f52178f 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -151,7 +151,7 @@ static struct file_lock *locks_alloc_lock(void) | |||
| 151 | return kmem_cache_alloc(filelock_cache, GFP_KERNEL); | 151 | return kmem_cache_alloc(filelock_cache, GFP_KERNEL); |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | static void locks_release_private(struct file_lock *fl) | 154 | void locks_release_private(struct file_lock *fl) |
| 155 | { | 155 | { |
| 156 | if (fl->fl_ops) { | 156 | if (fl->fl_ops) { |
| 157 | if (fl->fl_ops->fl_release_private) | 157 | if (fl->fl_ops->fl_release_private) |
| @@ -165,6 +165,7 @@ static void locks_release_private(struct file_lock *fl) | |||
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | } | 167 | } |
| 168 | EXPORT_SYMBOL_GPL(locks_release_private); | ||
| 168 | 169 | ||
| 169 | /* Free a lock which is not in use. */ | 170 | /* Free a lock which is not in use. */ |
| 170 | static void locks_free_lock(struct file_lock *fl) | 171 | static void locks_free_lock(struct file_lock *fl) |
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index 5d6d6f415935..2a77bc25d5af 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | config NFS_FS | 1 | config NFS_FS |
| 2 | tristate "NFS client support" | 2 | tristate "NFS client support" |
| 3 | depends on INET | 3 | depends on INET && FILE_LOCKING |
| 4 | select LOCKD | 4 | select LOCKD |
| 5 | select SUNRPC | 5 | select SUNRPC |
| 6 | select NFS_ACL_SUPPORT if NFS_V3_ACL | 6 | select NFS_ACL_SUPPORT if NFS_V3_ACL |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 8b1f8efb4690..b92a27629fb7 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
| @@ -464,16 +464,11 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp) | |||
| 464 | if (err) | 464 | if (err) |
| 465 | return err; | 465 | return err; |
| 466 | /* | 466 | /* |
| 467 | * Just a quick sanity check; we could also try to check | 467 | * XXX: It would be nice to also check whether this |
| 468 | * whether this pseudoflavor is supported, but at worst | 468 | * pseudoflavor is supported, so we can discover the |
| 469 | * an unsupported pseudoflavor on the export would just | 469 | * problem at export time instead of when a client fails |
| 470 | * be a pseudoflavor that won't match the flavor of any | 470 | * to authenticate. |
| 471 | * authenticated request. The administrator will | ||
| 472 | * probably discover the problem when someone fails to | ||
| 473 | * authenticate. | ||
| 474 | */ | 471 | */ |
| 475 | if (f->pseudoflavor < 0) | ||
| 476 | return -EINVAL; | ||
| 477 | err = get_int(mesg, &f->flags); | 472 | err = get_int(mesg, &f->flags); |
| 478 | if (err) | 473 | if (err) |
| 479 | return err; | 474 | return err; |
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 7c9fe838f038..a713c418a922 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c | |||
| @@ -652,8 +652,6 @@ nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp, | |||
| 652 | * NFSv3 Server procedures. | 652 | * NFSv3 Server procedures. |
| 653 | * Only the results of non-idempotent operations are cached. | 653 | * Only the results of non-idempotent operations are cached. |
| 654 | */ | 654 | */ |
| 655 | #define nfs3svc_decode_voidargs NULL | ||
| 656 | #define nfs3svc_release_void NULL | ||
| 657 | #define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle | 655 | #define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle |
| 658 | #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat | 656 | #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat |
| 659 | #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat | 657 | #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat |
| @@ -686,28 +684,219 @@ struct nfsd3_voidargs { int dummy; }; | |||
| 686 | #define WC (7+pAT) /* WCC attributes */ | 684 | #define WC (7+pAT) /* WCC attributes */ |
| 687 | 685 | ||
| 688 | static struct svc_procedure nfsd_procedures3[22] = { | 686 | static struct svc_procedure nfsd_procedures3[22] = { |
| 689 | PROC(null, void, void, void, RC_NOCACHE, ST), | 687 | [NFS3PROC_NULL] = { |
| 690 | PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT), | 688 | .pc_func = (svc_procfunc) nfsd3_proc_null, |
| 691 | PROC(setattr, sattr, wccstat, fhandle, RC_REPLBUFF, ST+WC), | 689 | .pc_encode = (kxdrproc_t) nfs3svc_encode_voidres, |
| 692 | PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE, ST+FH+pAT+pAT), | 690 | .pc_argsize = sizeof(struct nfsd3_voidargs), |
| 693 | PROC(access, access, access, fhandle, RC_NOCACHE, ST+pAT+1), | 691 | .pc_ressize = sizeof(struct nfsd3_voidres), |
| 694 | PROC(readlink, readlink, readlink, fhandle, RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4), | 692 | .pc_cachetype = RC_NOCACHE, |
| 695 | PROC(read, read, read, fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE/4), | 693 | .pc_xdrressize = ST, |
| 696 | PROC(write, write, write, fhandle, RC_REPLBUFF, ST+WC+4), | 694 | }, |
| 697 | PROC(create, create, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 695 | [NFS3PROC_GETATTR] = { |
| 698 | PROC(mkdir, mkdir, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 696 | .pc_func = (svc_procfunc) nfsd3_proc_getattr, |
| 699 | PROC(symlink, symlink, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 697 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, |
| 700 | PROC(mknod, mknod, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 698 | .pc_encode = (kxdrproc_t) nfs3svc_encode_attrstatres, |
| 701 | PROC(remove, dirop, wccstat, fhandle, RC_REPLBUFF, ST+WC), | 699 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, |
| 702 | PROC(rmdir, dirop, wccstat, fhandle, RC_REPLBUFF, ST+WC), | 700 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), |
| 703 | PROC(rename, rename, rename, fhandle2, RC_REPLBUFF, ST+WC+WC), | 701 | .pc_ressize = sizeof(struct nfsd3_attrstatres), |
| 704 | PROC(link, link, link, fhandle2, RC_REPLBUFF, ST+pAT+WC), | 702 | .pc_cachetype = RC_NOCACHE, |
| 705 | PROC(readdir, readdir, readdir, fhandle, RC_NOCACHE, 0), | 703 | .pc_xdrressize = ST+AT, |
| 706 | PROC(readdirplus,readdirplus, readdir, fhandle, RC_NOCACHE, 0), | 704 | }, |
| 707 | PROC(fsstat, fhandle, fsstat, void, RC_NOCACHE, ST+pAT+2*6+1), | 705 | [NFS3PROC_SETATTR] = { |
| 708 | PROC(fsinfo, fhandle, fsinfo, void, RC_NOCACHE, ST+pAT+12), | 706 | .pc_func = (svc_procfunc) nfsd3_proc_setattr, |
| 709 | PROC(pathconf, fhandle, pathconf, void, RC_NOCACHE, ST+pAT+6), | 707 | .pc_decode = (kxdrproc_t) nfs3svc_decode_sattrargs, |
| 710 | PROC(commit, commit, commit, fhandle, RC_NOCACHE, ST+WC+2), | 708 | .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres, |
| 709 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
| 710 | .pc_argsize = sizeof(struct nfsd3_sattrargs), | ||
| 711 | .pc_ressize = sizeof(struct nfsd3_wccstatres), | ||
| 712 | .pc_cachetype = RC_REPLBUFF, | ||
| 713 | .pc_xdrressize = ST+WC, | ||
| 714 | }, | ||
| 715 | [NFS3PROC_LOOKUP] = { | ||
| 716 | .pc_func = (svc_procfunc) nfsd3_proc_lookup, | ||
| 717 | .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs, | ||
| 718 | .pc_encode = (kxdrproc_t) nfs3svc_encode_diropres, | ||
| 719 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
| 720 | .pc_argsize = sizeof(struct nfsd3_diropargs), | ||
| 721 | .pc_ressize = sizeof(struct nfsd3_diropres), | ||
| 722 | .pc_cachetype = RC_NOCACHE, | ||
| 723 | .pc_xdrressize = ST+FH+pAT+pAT, | ||
| 724 | }, | ||
| 725 | [NFS3PROC_ACCESS] = { | ||
| 726 | .pc_func = (svc_procfunc) nfsd3_proc_access, | ||
| 727 | .pc_decode = (kxdrproc_t) nfs3svc_decode_accessargs, | ||
| 728 | .pc_encode = (kxdrproc_t) nfs3svc_encode_accessres, | ||
| 729 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
| 730 | .pc_argsize = sizeof(struct nfsd3_accessargs), | ||
| 731 | .pc_ressize = sizeof(struct nfsd3_accessres), | ||
| 732 | .pc_cachetype = RC_NOCACHE, | ||
| 733 | .pc_xdrressize = ST+pAT+1, | ||
| 734 | }, | ||
| 735 | [NFS3PROC_READLINK] = { | ||
| 736 | .pc_func = (svc_procfunc) nfsd3_proc_readlink, | ||
| 737 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readlinkargs, | ||
| 738 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readlinkres, | ||
| 739 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
| 740 | .pc_argsize = sizeof(struct nfsd3_readlinkargs), | ||
| 741 | .pc_ressize = sizeof(struct nfsd3_readlinkres), | ||
| 742 | .pc_cachetype = RC_NOCACHE, | ||
| 743 | .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4, | ||
| 744 | }, | ||
| 745 | [NFS3PROC_READ] = { | ||
| 746 | .pc_func = (svc_procfunc) nfsd3_proc_read, | ||
| 747 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readargs, | ||
| 748 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readres, | ||
| 749 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
| 750 | .pc_argsize = sizeof(struct nfsd3_readargs), | ||
| 751 | .pc_ressize = sizeof(struct nfsd3_readres), | ||
| 752 | .pc_cachetype = RC_NOCACHE, | ||
| 753 | .pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4, | ||
| 754 | }, | ||
| 755 | [NFS3PROC_WRITE] = { | ||
| 756 | .pc_func = (svc_procfunc) nfsd3_proc_write, | ||
| 757 | .pc_decode = (kxdrproc_t) nfs3svc_decode_writeargs, | ||
| 758 | .pc_encode = (kxdrproc_t) nfs3svc_encode_writeres, | ||
| 759 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
| 760 | .pc_argsize = sizeof(struct nfsd3_writeargs), | ||
| 761 | .pc_ressize = sizeof(struct nfsd3_writeres), | ||
| 762 | .pc_cachetype = RC_REPLBUFF, | ||
| 763 | .pc_xdrressize = ST+WC+4, | ||
| 764 | }, | ||
| 765 | [NFS3PROC_CREATE] = { | ||
| 766 | .pc_func = (svc_procfunc) nfsd3_proc_create, | ||
| 767 | .pc_decode = (kxdrproc_t) nfs3svc_decode_createargs, | ||
| 768 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
| 769 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
| 770 | .pc_argsize = sizeof(struct nfsd3_createargs), | ||
| 771 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
| 772 | .pc_cachetype = RC_REPLBUFF, | ||
| 773 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
| 774 | }, | ||
| 775 | [NFS3PROC_MKDIR] = { | ||
| 776 | .pc_func = (svc_procfunc) nfsd3_proc_mkdir, | ||
| 777 | .pc_decode = (kxdrproc_t) nfs3svc_decode_mkdirargs, | ||
| 778 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
| 779 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
| 780 | .pc_argsize = sizeof(struct nfsd3_mkdirargs), | ||
| 781 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
| 782 | .pc_cachetype = RC_REPLBUFF, | ||
| 783 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
| 784 | }, | ||
| 785 | [NFS3PROC_SYMLINK] = { | ||
| 786 | .pc_func = (svc_procfunc) nfsd3_proc_symlink, | ||
| 787 | .pc_decode = (kxdrproc_t) nfs3svc_decode_symlinkargs, | ||
| 788 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
| 789 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
| 790 | .pc_argsize = sizeof(struct nfsd3_symlinkargs), | ||
| 791 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
| 792 | .pc_cachetype = RC_REPLBUFF, | ||
| 793 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
| 794 | }, | ||
| 795 | [NFS3PROC_MKNOD] = { | ||
| 796 | .pc_func = (svc_procfunc) nfsd3_proc_mknod, | ||
| 797 | .pc_decode = (kxdrproc_t) nfs3svc_decode_mknodargs, | ||
| 798 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
| 799 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
| 800 | .pc_argsize = sizeof(struct nfsd3_mknodargs), | ||
| 801 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
| 802 | .pc_cachetype = RC_REPLBUFF, | ||
| 803 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
| 804 | }, | ||
| 805 | [NFS3PROC_REMOVE] = { | ||
| 806 | .pc_func = (svc_procfunc) nfsd3_proc_remove, | ||
| 807 | .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs, | ||
| 808 | .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres, | ||
| 809 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
| 810 | .pc_argsize = sizeof(struct nfsd3_diropargs), | ||
| 811 | .pc_ressize = sizeof(struct nfsd3_wccstatres), | ||
| 812 | .pc_cachetype = RC_REPLBUFF, | ||
| 813 | .pc_xdrressize = ST+WC, | ||
| 814 | }, | ||
| 815 | [NFS3PROC_RMDIR] = { | ||
| 816 | .pc_func = (svc_procfunc) nfsd3_proc_rmdir, | ||
| 817 | .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs, | ||
| 818 | .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres, | ||
| 819 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
| 820 | .pc_argsize = sizeof(struct nfsd3_diropargs), | ||
| 821 | .pc_ressize = sizeof(struct nfsd3_wccstatres), | ||
| 822 | .pc_cachetype = RC_REPLBUFF, | ||
| 823 | .pc_xdrressize = ST+WC, | ||
| 824 | }, | ||
| 825 | [NFS3PROC_RENAME] = { | ||
| 826 | .pc_func = (svc_procfunc) nfsd3_proc_rename, | ||
| 827 | .pc_decode = (kxdrproc_t) nfs3svc_decode_renameargs, | ||
| 828 | .pc_encode = (kxdrproc_t) nfs3svc_encode_renameres, | ||
| 829 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
| 830 | .pc_argsize = sizeof(struct nfsd3_renameargs), | ||
| 831 | .pc_ressize = sizeof(struct nfsd3_renameres), | ||
| 832 | .pc_cachetype = RC_REPLBUFF, | ||
| 833 | .pc_xdrressize = ST+WC+WC, | ||
| 834 | }, | ||
| 835 | [NFS3PROC_LINK] = { | ||
| 836 | .pc_func = (svc_procfunc) nfsd3_proc_link, | ||
| 837 | .pc_decode = (kxdrproc_t) nfs3svc_decode_linkargs, | ||
| 838 | .pc_encode = (kxdrproc_t) nfs3svc_encode_linkres, | ||
| 839 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
| 840 | .pc_argsize = sizeof(struct nfsd3_linkargs), | ||
| 841 | .pc_ressize = sizeof(struct nfsd3_linkres), | ||
| 842 | .pc_cachetype = RC_REPLBUFF, | ||
| 843 | .pc_xdrressize = ST+pAT+WC, | ||
| 844 | }, | ||
| 845 | [NFS3PROC_READDIR] = { | ||
| 846 | .pc_func = (svc_procfunc) nfsd3_proc_readdir, | ||
| 847 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirargs, | ||
| 848 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres, | ||
| 849 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
| 850 | .pc_argsize = sizeof(struct nfsd3_readdirargs), | ||
| 851 | .pc_ressize = sizeof(struct nfsd3_readdirres), | ||
| 852 | .pc_cachetype = RC_NOCACHE, | ||
| 853 | }, | ||
| 854 | [NFS3PROC_READDIRPLUS] = { | ||
| 855 | .pc_func = (svc_procfunc) nfsd3_proc_readdirplus, | ||
| 856 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirplusargs, | ||
| 857 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres, | ||
| 858 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
| 859 | .pc_argsize = sizeof(struct nfsd3_readdirplusargs), | ||
| 860 | .pc_ressize = sizeof(struct nfsd3_readdirres), | ||
| 861 | .pc_cachetype = RC_NOCACHE, | ||
| 862 | }, | ||
| 863 | [NFS3PROC_FSSTAT] = { | ||
| 864 | .pc_func = (svc_procfunc) nfsd3_proc_fsstat, | ||
| 865 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, | ||
| 866 | .pc_encode = (kxdrproc_t) nfs3svc_encode_fsstatres, | ||
| 867 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), | ||
| 868 | .pc_ressize = sizeof(struct nfsd3_fsstatres), | ||
| 869 | .pc_cachetype = RC_NOCACHE, | ||
| 870 | .pc_xdrressize = ST+pAT+2*6+1, | ||
| 871 | }, | ||
| 872 | [NFS3PROC_FSINFO] = { | ||
| 873 | .pc_func = (svc_procfunc) nfsd3_proc_fsinfo, | ||
| 874 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, | ||
| 875 | .pc_encode = (kxdrproc_t) nfs3svc_encode_fsinfores, | ||
| 876 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), | ||
| 877 | .pc_ressize = sizeof(struct nfsd3_fsinfores), | ||
| 878 | .pc_cachetype = RC_NOCACHE, | ||
| 879 | .pc_xdrressize = ST+pAT+12, | ||
| 880 | }, | ||
| 881 | [NFS3PROC_PATHCONF] = { | ||
| 882 | .pc_func = (svc_procfunc) nfsd3_proc_pathconf, | ||
| 883 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, | ||
| 884 | .pc_encode = (kxdrproc_t) nfs3svc_encode_pathconfres, | ||
| 885 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), | ||
| 886 | .pc_ressize = sizeof(struct nfsd3_pathconfres), | ||
| 887 | .pc_cachetype = RC_NOCACHE, | ||
| 888 | .pc_xdrressize = ST+pAT+6, | ||
| 889 | }, | ||
| 890 | [NFS3PROC_COMMIT] = { | ||
| 891 | .pc_func = (svc_procfunc) nfsd3_proc_commit, | ||
| 892 | .pc_decode = (kxdrproc_t) nfs3svc_decode_commitargs, | ||
| 893 | .pc_encode = (kxdrproc_t) nfs3svc_encode_commitres, | ||
| 894 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
| 895 | .pc_argsize = sizeof(struct nfsd3_commitargs), | ||
| 896 | .pc_ressize = sizeof(struct nfsd3_commitres), | ||
| 897 | .pc_cachetype = RC_NOCACHE, | ||
| 898 | .pc_xdrressize = ST+WC+2, | ||
| 899 | }, | ||
| 711 | }; | 900 | }; |
| 712 | 901 | ||
| 713 | struct svc_version nfsd_version3 = { | 902 | struct svc_version nfsd_version3 = { |
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 17d0dd997204..01d4ec1c88e0 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
| @@ -272,6 +272,7 @@ void fill_post_wcc(struct svc_fh *fhp) | |||
| 272 | 272 | ||
| 273 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, | 273 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, |
| 274 | &fhp->fh_post_attr); | 274 | &fhp->fh_post_attr); |
| 275 | fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version; | ||
| 275 | if (err) | 276 | if (err) |
| 276 | fhp->fh_post_saved = 0; | 277 | fhp->fh_post_saved = 0; |
| 277 | else | 278 | else |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 290289bd44f7..3fd23f7aceca 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
| @@ -140,8 +140,10 @@ struct nfs4_cb_compound_hdr { | |||
| 140 | int status; | 140 | int status; |
| 141 | u32 ident; | 141 | u32 ident; |
| 142 | u32 nops; | 142 | u32 nops; |
| 143 | __be32 *nops_p; | ||
| 144 | u32 minorversion; | ||
| 143 | u32 taglen; | 145 | u32 taglen; |
| 144 | char * tag; | 146 | char *tag; |
| 145 | }; | 147 | }; |
| 146 | 148 | ||
| 147 | static struct { | 149 | static struct { |
| @@ -201,33 +203,39 @@ nfs_cb_stat_to_errno(int stat) | |||
| 201 | * XDR encode | 203 | * XDR encode |
| 202 | */ | 204 | */ |
| 203 | 205 | ||
| 204 | static int | 206 | static void |
| 205 | encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) | 207 | encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) |
| 206 | { | 208 | { |
| 207 | __be32 * p; | 209 | __be32 * p; |
| 208 | 210 | ||
| 209 | RESERVE_SPACE(16); | 211 | RESERVE_SPACE(16); |
| 210 | WRITE32(0); /* tag length is always 0 */ | 212 | WRITE32(0); /* tag length is always 0 */ |
| 211 | WRITE32(NFS4_MINOR_VERSION); | 213 | WRITE32(hdr->minorversion); |
| 212 | WRITE32(hdr->ident); | 214 | WRITE32(hdr->ident); |
| 215 | hdr->nops_p = p; | ||
| 213 | WRITE32(hdr->nops); | 216 | WRITE32(hdr->nops); |
| 214 | return 0; | ||
| 215 | } | 217 | } |
| 216 | 218 | ||
| 217 | static int | 219 | static void encode_cb_nops(struct nfs4_cb_compound_hdr *hdr) |
| 218 | encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec) | 220 | { |
| 221 | *hdr->nops_p = htonl(hdr->nops); | ||
| 222 | } | ||
| 223 | |||
| 224 | static void | ||
| 225 | encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp, | ||
| 226 | struct nfs4_cb_compound_hdr *hdr) | ||
| 219 | { | 227 | { |
| 220 | __be32 *p; | 228 | __be32 *p; |
| 221 | int len = cb_rec->cbr_fh.fh_size; | 229 | int len = dp->dl_fh.fh_size; |
| 222 | 230 | ||
| 223 | RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len); | 231 | RESERVE_SPACE(12+sizeof(dp->dl_stateid) + len); |
| 224 | WRITE32(OP_CB_RECALL); | 232 | WRITE32(OP_CB_RECALL); |
| 225 | WRITE32(cb_rec->cbr_stateid.si_generation); | 233 | WRITE32(dp->dl_stateid.si_generation); |
| 226 | WRITEMEM(&cb_rec->cbr_stateid.si_opaque, sizeof(stateid_opaque_t)); | 234 | WRITEMEM(&dp->dl_stateid.si_opaque, sizeof(stateid_opaque_t)); |
| 227 | WRITE32(cb_rec->cbr_trunc); | 235 | WRITE32(0); /* truncate optimization not implemented */ |
| 228 | WRITE32(len); | 236 | WRITE32(len); |
| 229 | WRITEMEM(&cb_rec->cbr_fh.fh_base, len); | 237 | WRITEMEM(&dp->dl_fh.fh_base, len); |
| 230 | return 0; | 238 | hdr->nops++; |
| 231 | } | 239 | } |
| 232 | 240 | ||
| 233 | static int | 241 | static int |
| @@ -241,17 +249,18 @@ nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p) | |||
| 241 | } | 249 | } |
| 242 | 250 | ||
| 243 | static int | 251 | static int |
| 244 | nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_recall *args) | 252 | nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_delegation *args) |
| 245 | { | 253 | { |
| 246 | struct xdr_stream xdr; | 254 | struct xdr_stream xdr; |
| 247 | struct nfs4_cb_compound_hdr hdr = { | 255 | struct nfs4_cb_compound_hdr hdr = { |
| 248 | .ident = args->cbr_ident, | 256 | .ident = args->dl_ident, |
| 249 | .nops = 1, | ||
| 250 | }; | 257 | }; |
| 251 | 258 | ||
| 252 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 259 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 253 | encode_cb_compound_hdr(&xdr, &hdr); | 260 | encode_cb_compound_hdr(&xdr, &hdr); |
| 254 | return (encode_cb_recall(&xdr, args)); | 261 | encode_cb_recall(&xdr, args, &hdr); |
| 262 | encode_cb_nops(&hdr); | ||
| 263 | return 0; | ||
| 255 | } | 264 | } |
| 256 | 265 | ||
| 257 | 266 | ||
| @@ -358,18 +367,21 @@ static struct rpc_program cb_program = { | |||
| 358 | .pipe_dir_name = "/nfsd4_cb", | 367 | .pipe_dir_name = "/nfsd4_cb", |
| 359 | }; | 368 | }; |
| 360 | 369 | ||
| 370 | static int max_cb_time(void) | ||
| 371 | { | ||
| 372 | return max(NFSD_LEASE_TIME/10, (time_t)1) * HZ; | ||
| 373 | } | ||
| 374 | |||
| 361 | /* Reference counting, callback cleanup, etc., all look racy as heck. | 375 | /* Reference counting, callback cleanup, etc., all look racy as heck. |
| 362 | * And why is cb_set an atomic? */ | 376 | * And why is cb_set an atomic? */ |
| 363 | 377 | ||
| 364 | static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) | 378 | int setup_callback_client(struct nfs4_client *clp) |
| 365 | { | 379 | { |
| 366 | struct sockaddr_in addr; | 380 | struct sockaddr_in addr; |
| 367 | struct nfs4_callback *cb = &clp->cl_callback; | 381 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
| 368 | struct rpc_timeout timeparms = { | 382 | struct rpc_timeout timeparms = { |
| 369 | .to_initval = (NFSD_LEASE_TIME/4) * HZ, | 383 | .to_initval = max_cb_time(), |
| 370 | .to_retries = 5, | 384 | .to_retries = 0, |
| 371 | .to_maxval = (NFSD_LEASE_TIME/2) * HZ, | ||
| 372 | .to_exponential = 1, | ||
| 373 | }; | 385 | }; |
| 374 | struct rpc_create_args args = { | 386 | struct rpc_create_args args = { |
| 375 | .protocol = IPPROTO_TCP, | 387 | .protocol = IPPROTO_TCP, |
| @@ -386,7 +398,7 @@ static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) | |||
| 386 | struct rpc_clnt *client; | 398 | struct rpc_clnt *client; |
| 387 | 399 | ||
| 388 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) | 400 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) |
| 389 | return ERR_PTR(-EINVAL); | 401 | return -EINVAL; |
| 390 | 402 | ||
| 391 | /* Initialize address */ | 403 | /* Initialize address */ |
| 392 | memset(&addr, 0, sizeof(addr)); | 404 | memset(&addr, 0, sizeof(addr)); |
| @@ -396,48 +408,77 @@ static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) | |||
| 396 | 408 | ||
| 397 | /* Create RPC client */ | 409 | /* Create RPC client */ |
| 398 | client = rpc_create(&args); | 410 | client = rpc_create(&args); |
| 399 | if (IS_ERR(client)) | 411 | if (IS_ERR(client)) { |
| 400 | dprintk("NFSD: couldn't create callback client: %ld\n", | 412 | dprintk("NFSD: couldn't create callback client: %ld\n", |
| 401 | PTR_ERR(client)); | 413 | PTR_ERR(client)); |
| 402 | return client; | 414 | return PTR_ERR(client); |
| 415 | } | ||
| 416 | cb->cb_client = client; | ||
| 417 | return 0; | ||
| 418 | |||
| 419 | } | ||
| 420 | |||
| 421 | static void warn_no_callback_path(struct nfs4_client *clp, int reason) | ||
| 422 | { | ||
| 423 | dprintk("NFSD: warning: no callback path to client %.*s: error %d\n", | ||
| 424 | (int)clp->cl_name.len, clp->cl_name.data, reason); | ||
| 425 | } | ||
| 426 | |||
| 427 | static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) | ||
| 428 | { | ||
| 429 | struct nfs4_client *clp = calldata; | ||
| 430 | |||
| 431 | if (task->tk_status) | ||
| 432 | warn_no_callback_path(clp, task->tk_status); | ||
| 433 | else | ||
| 434 | atomic_set(&clp->cl_cb_conn.cb_set, 1); | ||
| 435 | put_nfs4_client(clp); | ||
| 436 | } | ||
| 437 | |||
| 438 | static const struct rpc_call_ops nfsd4_cb_probe_ops = { | ||
| 439 | .rpc_call_done = nfsd4_cb_probe_done, | ||
| 440 | }; | ||
| 403 | 441 | ||
| 442 | static struct rpc_cred *lookup_cb_cred(struct nfs4_cb_conn *cb) | ||
| 443 | { | ||
| 444 | struct auth_cred acred = { | ||
| 445 | .machine_cred = 1 | ||
| 446 | }; | ||
| 447 | |||
| 448 | /* | ||
| 449 | * Note in the gss case this doesn't actually have to wait for a | ||
| 450 | * gss upcall (or any calls to the client); this just creates a | ||
| 451 | * non-uptodate cred which the rpc state machine will fill in with | ||
| 452 | * a refresh_upcall later. | ||
| 453 | */ | ||
| 454 | return rpcauth_lookup_credcache(cb->cb_client->cl_auth, &acred, | ||
| 455 | RPCAUTH_LOOKUP_NEW); | ||
| 404 | } | 456 | } |
| 405 | 457 | ||
| 406 | static int do_probe_callback(void *data) | 458 | void do_probe_callback(struct nfs4_client *clp) |
| 407 | { | 459 | { |
| 408 | struct nfs4_client *clp = data; | 460 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
| 409 | struct nfs4_callback *cb = &clp->cl_callback; | ||
| 410 | struct rpc_message msg = { | 461 | struct rpc_message msg = { |
| 411 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], | 462 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], |
| 412 | .rpc_argp = clp, | 463 | .rpc_argp = clp, |
| 413 | }; | 464 | }; |
| 414 | struct rpc_clnt *client; | 465 | struct rpc_cred *cred; |
| 415 | int status; | 466 | int status; |
| 416 | 467 | ||
| 417 | client = setup_callback_client(clp); | 468 | cred = lookup_cb_cred(cb); |
| 418 | if (IS_ERR(client)) { | 469 | if (IS_ERR(cred)) { |
| 419 | status = PTR_ERR(client); | 470 | status = PTR_ERR(cred); |
| 420 | dprintk("NFSD: couldn't create callback client: %d\n", | 471 | goto out; |
| 421 | status); | 472 | } |
| 422 | goto out_err; | 473 | cb->cb_cred = cred; |
| 474 | msg.rpc_cred = cb->cb_cred; | ||
| 475 | status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_SOFT, | ||
| 476 | &nfsd4_cb_probe_ops, (void *)clp); | ||
| 477 | out: | ||
| 478 | if (status) { | ||
| 479 | warn_no_callback_path(clp, status); | ||
| 480 | put_nfs4_client(clp); | ||
| 423 | } | 481 | } |
| 424 | |||
| 425 | status = rpc_call_sync(client, &msg, RPC_TASK_SOFT); | ||
| 426 | |||
| 427 | if (status) | ||
| 428 | goto out_release_client; | ||
| 429 | |||
| 430 | cb->cb_client = client; | ||
| 431 | atomic_set(&cb->cb_set, 1); | ||
| 432 | put_nfs4_client(clp); | ||
| 433 | return 0; | ||
| 434 | out_release_client: | ||
| 435 | rpc_shutdown_client(client); | ||
| 436 | out_err: | ||
| 437 | dprintk("NFSD: warning: no callback path to client %.*s: error %d\n", | ||
| 438 | (int)clp->cl_name.len, clp->cl_name.data, status); | ||
| 439 | put_nfs4_client(clp); | ||
| 440 | return 0; | ||
| 441 | } | 482 | } |
| 442 | 483 | ||
| 443 | /* | 484 | /* |
| @@ -446,21 +487,65 @@ out_err: | |||
| 446 | void | 487 | void |
| 447 | nfsd4_probe_callback(struct nfs4_client *clp) | 488 | nfsd4_probe_callback(struct nfs4_client *clp) |
| 448 | { | 489 | { |
| 449 | struct task_struct *t; | 490 | int status; |
| 450 | 491 | ||
| 451 | BUG_ON(atomic_read(&clp->cl_callback.cb_set)); | 492 | BUG_ON(atomic_read(&clp->cl_cb_conn.cb_set)); |
| 493 | |||
| 494 | status = setup_callback_client(clp); | ||
| 495 | if (status) { | ||
| 496 | warn_no_callback_path(clp, status); | ||
| 497 | return; | ||
| 498 | } | ||
| 452 | 499 | ||
| 453 | /* the task holds a reference to the nfs4_client struct */ | 500 | /* the task holds a reference to the nfs4_client struct */ |
| 454 | atomic_inc(&clp->cl_count); | 501 | atomic_inc(&clp->cl_count); |
| 455 | 502 | ||
| 456 | t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe"); | 503 | do_probe_callback(clp); |
| 504 | } | ||
| 457 | 505 | ||
| 458 | if (IS_ERR(t)) | 506 | static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) |
| 459 | atomic_dec(&clp->cl_count); | 507 | { |
| 508 | struct nfs4_delegation *dp = calldata; | ||
| 509 | struct nfs4_client *clp = dp->dl_client; | ||
| 460 | 510 | ||
| 461 | return; | 511 | switch (task->tk_status) { |
| 512 | case -EIO: | ||
| 513 | /* Network partition? */ | ||
| 514 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | ||
| 515 | warn_no_callback_path(clp, task->tk_status); | ||
| 516 | case -EBADHANDLE: | ||
| 517 | case -NFS4ERR_BAD_STATEID: | ||
| 518 | /* Race: client probably got cb_recall | ||
| 519 | * before open reply granting delegation */ | ||
| 520 | break; | ||
| 521 | default: | ||
| 522 | /* success, or error we can't handle */ | ||
| 523 | return; | ||
| 524 | } | ||
| 525 | if (dp->dl_retries--) { | ||
| 526 | rpc_delay(task, 2*HZ); | ||
| 527 | task->tk_status = 0; | ||
| 528 | rpc_restart_call(task); | ||
| 529 | } else { | ||
| 530 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | ||
| 531 | warn_no_callback_path(clp, task->tk_status); | ||
| 532 | } | ||
| 533 | } | ||
| 534 | |||
| 535 | static void nfsd4_cb_recall_release(void *calldata) | ||
| 536 | { | ||
| 537 | struct nfs4_delegation *dp = calldata; | ||
| 538 | struct nfs4_client *clp = dp->dl_client; | ||
| 539 | |||
| 540 | nfs4_put_delegation(dp); | ||
| 541 | put_nfs4_client(clp); | ||
| 462 | } | 542 | } |
| 463 | 543 | ||
| 544 | static const struct rpc_call_ops nfsd4_cb_recall_ops = { | ||
| 545 | .rpc_call_done = nfsd4_cb_recall_done, | ||
| 546 | .rpc_release = nfsd4_cb_recall_release, | ||
| 547 | }; | ||
| 548 | |||
| 464 | /* | 549 | /* |
| 465 | * called with dp->dl_count inc'ed. | 550 | * called with dp->dl_count inc'ed. |
| 466 | */ | 551 | */ |
| @@ -468,41 +553,19 @@ void | |||
| 468 | nfsd4_cb_recall(struct nfs4_delegation *dp) | 553 | nfsd4_cb_recall(struct nfs4_delegation *dp) |
| 469 | { | 554 | { |
| 470 | struct nfs4_client *clp = dp->dl_client; | 555 | struct nfs4_client *clp = dp->dl_client; |
| 471 | struct rpc_clnt *clnt = clp->cl_callback.cb_client; | 556 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; |
| 472 | struct nfs4_cb_recall *cbr = &dp->dl_recall; | ||
| 473 | struct rpc_message msg = { | 557 | struct rpc_message msg = { |
| 474 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], | 558 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], |
| 475 | .rpc_argp = cbr, | 559 | .rpc_argp = dp, |
| 560 | .rpc_cred = clp->cl_cb_conn.cb_cred | ||
| 476 | }; | 561 | }; |
| 477 | int retries = 1; | 562 | int status; |
| 478 | int status = 0; | 563 | |
| 479 | 564 | dp->dl_retries = 1; | |
| 480 | cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */ | 565 | status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, |
| 481 | cbr->cbr_dp = dp; | 566 | &nfsd4_cb_recall_ops, dp); |
| 482 | 567 | if (status) { | |
| 483 | status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); | 568 | put_nfs4_client(clp); |
| 484 | while (retries--) { | 569 | nfs4_put_delegation(dp); |
| 485 | switch (status) { | ||
| 486 | case -EIO: | ||
| 487 | /* Network partition? */ | ||
| 488 | atomic_set(&clp->cl_callback.cb_set, 0); | ||
| 489 | case -EBADHANDLE: | ||
| 490 | case -NFS4ERR_BAD_STATEID: | ||
| 491 | /* Race: client probably got cb_recall | ||
| 492 | * before open reply granting delegation */ | ||
| 493 | break; | ||
| 494 | default: | ||
| 495 | goto out_put_cred; | ||
| 496 | } | ||
| 497 | ssleep(2); | ||
| 498 | status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); | ||
| 499 | } | 570 | } |
| 500 | out_put_cred: | ||
| 501 | /* | ||
| 502 | * Success or failure, now we're either waiting for lease expiration | ||
| 503 | * or deleg_return. | ||
| 504 | */ | ||
| 505 | put_nfs4_client(clp); | ||
| 506 | nfs4_put_delegation(dp); | ||
| 507 | return; | ||
| 508 | } | 571 | } |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index b2883e9c6381..7c8801769a3c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
| @@ -51,6 +51,78 @@ | |||
| 51 | 51 | ||
| 52 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 52 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
| 53 | 53 | ||
| 54 | static u32 nfsd_attrmask[] = { | ||
| 55 | NFSD_WRITEABLE_ATTRS_WORD0, | ||
| 56 | NFSD_WRITEABLE_ATTRS_WORD1, | ||
| 57 | NFSD_WRITEABLE_ATTRS_WORD2 | ||
| 58 | }; | ||
| 59 | |||
| 60 | static u32 nfsd41_ex_attrmask[] = { | ||
| 61 | NFSD_SUPPATTR_EXCLCREAT_WORD0, | ||
| 62 | NFSD_SUPPATTR_EXCLCREAT_WORD1, | ||
| 63 | NFSD_SUPPATTR_EXCLCREAT_WORD2 | ||
| 64 | }; | ||
| 65 | |||
| 66 | static __be32 | ||
| 67 | check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
| 68 | u32 *bmval, u32 *writable) | ||
| 69 | { | ||
| 70 | struct dentry *dentry = cstate->current_fh.fh_dentry; | ||
| 71 | struct svc_export *exp = cstate->current_fh.fh_export; | ||
| 72 | |||
| 73 | /* | ||
| 74 | * Check about attributes are supported by the NFSv4 server or not. | ||
| 75 | * According to spec, unsupported attributes return ERR_ATTRNOTSUPP. | ||
| 76 | */ | ||
| 77 | if ((bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) || | ||
| 78 | (bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) || | ||
| 79 | (bmval[2] & ~nfsd_suppattrs2(cstate->minorversion))) | ||
| 80 | return nfserr_attrnotsupp; | ||
| 81 | |||
| 82 | /* | ||
| 83 | * Check FATTR4_WORD0_ACL & FATTR4_WORD0_FS_LOCATIONS can be supported | ||
| 84 | * in current environment or not. | ||
| 85 | */ | ||
| 86 | if (bmval[0] & FATTR4_WORD0_ACL) { | ||
| 87 | if (!IS_POSIXACL(dentry->d_inode)) | ||
| 88 | return nfserr_attrnotsupp; | ||
| 89 | } | ||
| 90 | if (bmval[0] & FATTR4_WORD0_FS_LOCATIONS) { | ||
| 91 | if (exp->ex_fslocs.locations == NULL) | ||
| 92 | return nfserr_attrnotsupp; | ||
| 93 | } | ||
| 94 | |||
| 95 | /* | ||
| 96 | * According to spec, read-only attributes return ERR_INVAL. | ||
| 97 | */ | ||
| 98 | if (writable) { | ||
| 99 | if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) || | ||
| 100 | (bmval[2] & ~writable[2])) | ||
| 101 | return nfserr_inval; | ||
| 102 | } | ||
| 103 | |||
| 104 | return nfs_ok; | ||
| 105 | } | ||
| 106 | |||
| 107 | static __be32 | ||
| 108 | nfsd4_check_open_attributes(struct svc_rqst *rqstp, | ||
| 109 | struct nfsd4_compound_state *cstate, struct nfsd4_open *open) | ||
| 110 | { | ||
| 111 | __be32 status = nfs_ok; | ||
| 112 | |||
| 113 | if (open->op_create == NFS4_OPEN_CREATE) { | ||
| 114 | if (open->op_createmode == NFS4_CREATE_UNCHECKED | ||
| 115 | || open->op_createmode == NFS4_CREATE_GUARDED) | ||
| 116 | status = check_attr_support(rqstp, cstate, | ||
| 117 | open->op_bmval, nfsd_attrmask); | ||
| 118 | else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1) | ||
| 119 | status = check_attr_support(rqstp, cstate, | ||
| 120 | open->op_bmval, nfsd41_ex_attrmask); | ||
| 121 | } | ||
| 122 | |||
| 123 | return status; | ||
| 124 | } | ||
| 125 | |||
| 54 | static inline void | 126 | static inline void |
| 55 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) | 127 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) |
| 56 | { | 128 | { |
| @@ -225,6 +297,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 225 | if (status) | 297 | if (status) |
| 226 | goto out; | 298 | goto out; |
| 227 | 299 | ||
| 300 | status = nfsd4_check_open_attributes(rqstp, cstate, open); | ||
| 301 | if (status) | ||
| 302 | goto out; | ||
| 303 | |||
| 228 | /* Openowner is now set, so sequence id will get bumped. Now we need | 304 | /* Openowner is now set, so sequence id will get bumped. Now we need |
| 229 | * these checks before we do any creates: */ | 305 | * these checks before we do any creates: */ |
| 230 | status = nfserr_grace; | 306 | status = nfserr_grace; |
| @@ -395,6 +471,11 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 395 | if (status) | 471 | if (status) |
| 396 | return status; | 472 | return status; |
| 397 | 473 | ||
| 474 | status = check_attr_support(rqstp, cstate, create->cr_bmval, | ||
| 475 | nfsd_attrmask); | ||
| 476 | if (status) | ||
| 477 | return status; | ||
| 478 | |||
| 398 | switch (create->cr_type) { | 479 | switch (create->cr_type) { |
| 399 | case NF4LNK: | 480 | case NF4LNK: |
| 400 | /* ugh! we have to null-terminate the linktext, or | 481 | /* ugh! we have to null-terminate the linktext, or |
| @@ -689,6 +770,12 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 689 | if (status) | 770 | if (status) |
| 690 | return status; | 771 | return status; |
| 691 | status = nfs_ok; | 772 | status = nfs_ok; |
| 773 | |||
| 774 | status = check_attr_support(rqstp, cstate, setattr->sa_bmval, | ||
| 775 | nfsd_attrmask); | ||
| 776 | if (status) | ||
| 777 | goto out; | ||
| 778 | |||
| 692 | if (setattr->sa_acl != NULL) | 779 | if (setattr->sa_acl != NULL) |
| 693 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, | 780 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, |
| 694 | setattr->sa_acl); | 781 | setattr->sa_acl); |
| @@ -763,10 +850,10 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 763 | if (status) | 850 | if (status) |
| 764 | return status; | 851 | return status; |
| 765 | 852 | ||
| 766 | if ((verify->ve_bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) | 853 | status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL); |
| 767 | || (verify->ve_bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) | 854 | if (status) |
| 768 | || (verify->ve_bmval[2] & ~nfsd_suppattrs2(cstate->minorversion))) | 855 | return status; |
| 769 | return nfserr_attrnotsupp; | 856 | |
| 770 | if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) | 857 | if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) |
| 771 | || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) | 858 | || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) |
| 772 | return nfserr_inval; | 859 | return nfserr_inval; |
| @@ -1226,24 +1313,9 @@ static const char *nfsd4_op_name(unsigned opnum) | |||
| 1226 | return "unknown_operation"; | 1313 | return "unknown_operation"; |
| 1227 | } | 1314 | } |
| 1228 | 1315 | ||
| 1229 | #define nfs4svc_decode_voidargs NULL | ||
| 1230 | #define nfs4svc_release_void NULL | ||
| 1231 | #define nfsd4_voidres nfsd4_voidargs | 1316 | #define nfsd4_voidres nfsd4_voidargs |
| 1232 | #define nfs4svc_release_compound NULL | ||
| 1233 | struct nfsd4_voidargs { int dummy; }; | 1317 | struct nfsd4_voidargs { int dummy; }; |
| 1234 | 1318 | ||
| 1235 | #define PROC(name, argt, rest, relt, cache, respsize) \ | ||
| 1236 | { (svc_procfunc) nfsd4_proc_##name, \ | ||
| 1237 | (kxdrproc_t) nfs4svc_decode_##argt##args, \ | ||
| 1238 | (kxdrproc_t) nfs4svc_encode_##rest##res, \ | ||
| 1239 | (kxdrproc_t) nfs4svc_release_##relt, \ | ||
| 1240 | sizeof(struct nfsd4_##argt##args), \ | ||
| 1241 | sizeof(struct nfsd4_##rest##res), \ | ||
| 1242 | 0, \ | ||
| 1243 | cache, \ | ||
| 1244 | respsize, \ | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | /* | 1319 | /* |
| 1248 | * TODO: At the present time, the NFSv4 server does not do XID caching | 1320 | * TODO: At the present time, the NFSv4 server does not do XID caching |
| 1249 | * of requests. Implementing XID caching would not be a serious problem, | 1321 | * of requests. Implementing XID caching would not be a serious problem, |
| @@ -1255,8 +1327,23 @@ struct nfsd4_voidargs { int dummy; }; | |||
| 1255 | * better XID's. | 1327 | * better XID's. |
| 1256 | */ | 1328 | */ |
| 1257 | static struct svc_procedure nfsd_procedures4[2] = { | 1329 | static struct svc_procedure nfsd_procedures4[2] = { |
| 1258 | PROC(null, void, void, void, RC_NOCACHE, 1), | 1330 | [NFSPROC4_NULL] = { |
| 1259 | PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE/4) | 1331 | .pc_func = (svc_procfunc) nfsd4_proc_null, |
| 1332 | .pc_encode = (kxdrproc_t) nfs4svc_encode_voidres, | ||
| 1333 | .pc_argsize = sizeof(struct nfsd4_voidargs), | ||
| 1334 | .pc_ressize = sizeof(struct nfsd4_voidres), | ||
| 1335 | .pc_cachetype = RC_NOCACHE, | ||
| 1336 | .pc_xdrressize = 1, | ||
| 1337 | }, | ||
| 1338 | [NFSPROC4_COMPOUND] = { | ||
| 1339 | .pc_func = (svc_procfunc) nfsd4_proc_compound, | ||
| 1340 | .pc_decode = (kxdrproc_t) nfs4svc_decode_compoundargs, | ||
| 1341 | .pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres, | ||
| 1342 | .pc_argsize = sizeof(struct nfsd4_compoundargs), | ||
| 1343 | .pc_ressize = sizeof(struct nfsd4_compoundres), | ||
| 1344 | .pc_cachetype = RC_NOCACHE, | ||
| 1345 | .pc_xdrressize = NFSD_BUFSIZE/4, | ||
| 1346 | }, | ||
| 1260 | }; | 1347 | }; |
| 1261 | 1348 | ||
| 1262 | struct svc_version nfsd_version4 = { | 1349 | struct svc_version nfsd_version4 = { |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3b711f5147a7..980a216a48c8 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -182,7 +182,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
| 182 | { | 182 | { |
| 183 | struct nfs4_delegation *dp; | 183 | struct nfs4_delegation *dp; |
| 184 | struct nfs4_file *fp = stp->st_file; | 184 | struct nfs4_file *fp = stp->st_file; |
| 185 | struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; | 185 | struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn; |
| 186 | 186 | ||
| 187 | dprintk("NFSD alloc_init_deleg\n"); | 187 | dprintk("NFSD alloc_init_deleg\n"); |
| 188 | if (fp->fi_had_conflict) | 188 | if (fp->fi_had_conflict) |
| @@ -203,10 +203,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
| 203 | get_file(stp->st_vfs_file); | 203 | get_file(stp->st_vfs_file); |
| 204 | dp->dl_vfs_file = stp->st_vfs_file; | 204 | dp->dl_vfs_file = stp->st_vfs_file; |
| 205 | dp->dl_type = type; | 205 | dp->dl_type = type; |
| 206 | dp->dl_recall.cbr_dp = NULL; | 206 | dp->dl_ident = cb->cb_ident; |
| 207 | dp->dl_recall.cbr_ident = cb->cb_ident; | 207 | dp->dl_stateid.si_boot = get_seconds(); |
| 208 | dp->dl_recall.cbr_trunc = 0; | ||
| 209 | dp->dl_stateid.si_boot = boot_time; | ||
| 210 | dp->dl_stateid.si_stateownerid = current_delegid++; | 208 | dp->dl_stateid.si_stateownerid = current_delegid++; |
| 211 | dp->dl_stateid.si_fileid = 0; | 209 | dp->dl_stateid.si_fileid = 0; |
| 212 | dp->dl_stateid.si_generation = 0; | 210 | dp->dl_stateid.si_generation = 0; |
| @@ -427,6 +425,11 @@ static int set_forechannel_maxreqs(struct nfsd4_channel_attrs *fchan) | |||
| 427 | { | 425 | { |
| 428 | int status = 0, np = fchan->maxreqs * NFSD_PAGES_PER_SLOT; | 426 | int status = 0, np = fchan->maxreqs * NFSD_PAGES_PER_SLOT; |
| 429 | 427 | ||
| 428 | if (fchan->maxreqs < 1) | ||
| 429 | return nfserr_inval; | ||
| 430 | else if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | ||
| 431 | fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION; | ||
| 432 | |||
| 430 | spin_lock(&nfsd_serv->sv_lock); | 433 | spin_lock(&nfsd_serv->sv_lock); |
| 431 | if (np + nfsd_serv->sv_drc_pages_used > nfsd_serv->sv_drc_max_pages) | 434 | if (np + nfsd_serv->sv_drc_pages_used > nfsd_serv->sv_drc_max_pages) |
| 432 | np = nfsd_serv->sv_drc_max_pages - nfsd_serv->sv_drc_pages_used; | 435 | np = nfsd_serv->sv_drc_max_pages - nfsd_serv->sv_drc_pages_used; |
| @@ -446,8 +449,8 @@ static int set_forechannel_maxreqs(struct nfsd4_channel_attrs *fchan) | |||
| 446 | * fchan holds the client values on input, and the server values on output | 449 | * fchan holds the client values on input, and the server values on output |
| 447 | */ | 450 | */ |
| 448 | static int init_forechannel_attrs(struct svc_rqst *rqstp, | 451 | static int init_forechannel_attrs(struct svc_rqst *rqstp, |
| 449 | struct nfsd4_session *session, | 452 | struct nfsd4_channel_attrs *session_fchan, |
| 450 | struct nfsd4_channel_attrs *fchan) | 453 | struct nfsd4_channel_attrs *fchan) |
| 451 | { | 454 | { |
| 452 | int status = 0; | 455 | int status = 0; |
| 453 | __u32 maxcount = svc_max_payload(rqstp); | 456 | __u32 maxcount = svc_max_payload(rqstp); |
| @@ -457,21 +460,21 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp, | |||
| 457 | /* Use the client's max request and max response size if possible */ | 460 | /* Use the client's max request and max response size if possible */ |
| 458 | if (fchan->maxreq_sz > maxcount) | 461 | if (fchan->maxreq_sz > maxcount) |
| 459 | fchan->maxreq_sz = maxcount; | 462 | fchan->maxreq_sz = maxcount; |
| 460 | session->se_fmaxreq_sz = fchan->maxreq_sz; | 463 | session_fchan->maxreq_sz = fchan->maxreq_sz; |
| 461 | 464 | ||
| 462 | if (fchan->maxresp_sz > maxcount) | 465 | if (fchan->maxresp_sz > maxcount) |
| 463 | fchan->maxresp_sz = maxcount; | 466 | fchan->maxresp_sz = maxcount; |
| 464 | session->se_fmaxresp_sz = fchan->maxresp_sz; | 467 | session_fchan->maxresp_sz = fchan->maxresp_sz; |
| 465 | 468 | ||
| 466 | /* Set the max response cached size our default which is | 469 | /* Set the max response cached size our default which is |
| 467 | * a multiple of PAGE_SIZE and small */ | 470 | * a multiple of PAGE_SIZE and small */ |
| 468 | session->se_fmaxresp_cached = NFSD_PAGES_PER_SLOT * PAGE_SIZE; | 471 | session_fchan->maxresp_cached = NFSD_PAGES_PER_SLOT * PAGE_SIZE; |
| 469 | fchan->maxresp_cached = session->se_fmaxresp_cached; | 472 | fchan->maxresp_cached = session_fchan->maxresp_cached; |
| 470 | 473 | ||
| 471 | /* Use the client's maxops if possible */ | 474 | /* Use the client's maxops if possible */ |
| 472 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) | 475 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) |
| 473 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; | 476 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; |
| 474 | session->se_fmaxops = fchan->maxops; | 477 | session_fchan->maxops = fchan->maxops; |
| 475 | 478 | ||
| 476 | /* try to use the client requested number of slots */ | 479 | /* try to use the client requested number of slots */ |
| 477 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | 480 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) |
| @@ -483,7 +486,7 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp, | |||
| 483 | */ | 486 | */ |
| 484 | status = set_forechannel_maxreqs(fchan); | 487 | status = set_forechannel_maxreqs(fchan); |
| 485 | 488 | ||
| 486 | session->se_fnumslots = fchan->maxreqs; | 489 | session_fchan->maxreqs = fchan->maxreqs; |
| 487 | return status; | 490 | return status; |
| 488 | } | 491 | } |
| 489 | 492 | ||
| @@ -497,12 +500,14 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | |||
| 497 | memset(&tmp, 0, sizeof(tmp)); | 500 | memset(&tmp, 0, sizeof(tmp)); |
| 498 | 501 | ||
| 499 | /* FIXME: For now, we just accept the client back channel attributes. */ | 502 | /* FIXME: For now, we just accept the client back channel attributes. */ |
| 500 | status = init_forechannel_attrs(rqstp, &tmp, &cses->fore_channel); | 503 | tmp.se_bchannel = cses->back_channel; |
| 504 | status = init_forechannel_attrs(rqstp, &tmp.se_fchannel, | ||
| 505 | &cses->fore_channel); | ||
| 501 | if (status) | 506 | if (status) |
| 502 | goto out; | 507 | goto out; |
| 503 | 508 | ||
| 504 | /* allocate struct nfsd4_session and slot table in one piece */ | 509 | /* allocate struct nfsd4_session and slot table in one piece */ |
| 505 | slotsize = tmp.se_fnumslots * sizeof(struct nfsd4_slot); | 510 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot); |
| 506 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); | 511 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); |
| 507 | if (!new) | 512 | if (!new) |
| 508 | goto out; | 513 | goto out; |
| @@ -576,7 +581,7 @@ free_session(struct kref *kref) | |||
| 576 | int i; | 581 | int i; |
| 577 | 582 | ||
| 578 | ses = container_of(kref, struct nfsd4_session, se_ref); | 583 | ses = container_of(kref, struct nfsd4_session, se_ref); |
| 579 | for (i = 0; i < ses->se_fnumslots; i++) { | 584 | for (i = 0; i < ses->se_fchannel.maxreqs; i++) { |
| 580 | struct nfsd4_cache_entry *e = &ses->se_slots[i].sl_cache_entry; | 585 | struct nfsd4_cache_entry *e = &ses->se_slots[i].sl_cache_entry; |
| 581 | nfsd4_release_respages(e->ce_respages, e->ce_resused); | 586 | nfsd4_release_respages(e->ce_respages, e->ce_resused); |
| 582 | } | 587 | } |
| @@ -632,16 +637,20 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
| 632 | static void | 637 | static void |
| 633 | shutdown_callback_client(struct nfs4_client *clp) | 638 | shutdown_callback_client(struct nfs4_client *clp) |
| 634 | { | 639 | { |
| 635 | struct rpc_clnt *clnt = clp->cl_callback.cb_client; | 640 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; |
| 636 | 641 | ||
| 637 | if (clnt) { | 642 | if (clnt) { |
| 638 | /* | 643 | /* |
| 639 | * Callback threads take a reference on the client, so there | 644 | * Callback threads take a reference on the client, so there |
| 640 | * should be no outstanding callbacks at this point. | 645 | * should be no outstanding callbacks at this point. |
| 641 | */ | 646 | */ |
| 642 | clp->cl_callback.cb_client = NULL; | 647 | clp->cl_cb_conn.cb_client = NULL; |
| 643 | rpc_shutdown_client(clnt); | 648 | rpc_shutdown_client(clnt); |
| 644 | } | 649 | } |
| 650 | if (clp->cl_cb_conn.cb_cred) { | ||
| 651 | put_rpccred(clp->cl_cb_conn.cb_cred); | ||
| 652 | clp->cl_cb_conn.cb_cred = NULL; | ||
| 653 | } | ||
| 645 | } | 654 | } |
| 646 | 655 | ||
| 647 | static inline void | 656 | static inline void |
| @@ -714,7 +723,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir) | |||
| 714 | return NULL; | 723 | return NULL; |
| 715 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 724 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
| 716 | atomic_set(&clp->cl_count, 1); | 725 | atomic_set(&clp->cl_count, 1); |
| 717 | atomic_set(&clp->cl_callback.cb_set, 0); | 726 | atomic_set(&clp->cl_cb_conn.cb_set, 0); |
| 718 | INIT_LIST_HEAD(&clp->cl_idhash); | 727 | INIT_LIST_HEAD(&clp->cl_idhash); |
| 719 | INIT_LIST_HEAD(&clp->cl_strhash); | 728 | INIT_LIST_HEAD(&clp->cl_strhash); |
| 720 | INIT_LIST_HEAD(&clp->cl_openowners); | 729 | INIT_LIST_HEAD(&clp->cl_openowners); |
| @@ -966,7 +975,7 @@ parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigne | |||
| 966 | static void | 975 | static void |
| 967 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | 976 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) |
| 968 | { | 977 | { |
| 969 | struct nfs4_callback *cb = &clp->cl_callback; | 978 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
| 970 | 979 | ||
| 971 | /* Currently, we only support tcp for the callback channel */ | 980 | /* Currently, we only support tcp for the callback channel */ |
| 972 | if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3)) | 981 | if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3)) |
| @@ -975,6 +984,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | |||
| 975 | if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val, | 984 | if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val, |
| 976 | &cb->cb_addr, &cb->cb_port))) | 985 | &cb->cb_addr, &cb->cb_port))) |
| 977 | goto out_err; | 986 | goto out_err; |
| 987 | cb->cb_minorversion = 0; | ||
| 978 | cb->cb_prog = se->se_callback_prog; | 988 | cb->cb_prog = se->se_callback_prog; |
| 979 | cb->cb_ident = se->se_callback_ident; | 989 | cb->cb_ident = se->se_callback_ident; |
| 980 | return; | 990 | return; |
| @@ -1128,7 +1138,7 @@ nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, | |||
| 1128 | * is sent (lease renewal). | 1138 | * is sent (lease renewal). |
| 1129 | */ | 1139 | */ |
| 1130 | if (seq && nfsd4_not_cached(resp)) { | 1140 | if (seq && nfsd4_not_cached(resp)) { |
| 1131 | seq->maxslots = resp->cstate.session->se_fnumslots; | 1141 | seq->maxslots = resp->cstate.session->se_fchannel.maxreqs; |
| 1132 | return nfs_ok; | 1142 | return nfs_ok; |
| 1133 | } | 1143 | } |
| 1134 | 1144 | ||
| @@ -1238,12 +1248,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
| 1238 | expire_client(conf); | 1248 | expire_client(conf); |
| 1239 | goto out_new; | 1249 | goto out_new; |
| 1240 | } | 1250 | } |
| 1241 | if (ip_addr != conf->cl_addr && | ||
| 1242 | !(exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A)) { | ||
| 1243 | /* Client collision. 18.35.4 case 3 */ | ||
| 1244 | status = nfserr_clid_inuse; | ||
| 1245 | goto out; | ||
| 1246 | } | ||
| 1247 | /* | 1251 | /* |
| 1248 | * Set bit when the owner id and verifier map to an already | 1252 | * Set bit when the owner id and verifier map to an already |
| 1249 | * confirmed client id (18.35.3). | 1253 | * confirmed client id (18.35.3). |
| @@ -1257,12 +1261,12 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
| 1257 | copy_verf(conf, &verf); | 1261 | copy_verf(conf, &verf); |
| 1258 | new = conf; | 1262 | new = conf; |
| 1259 | goto out_copy; | 1263 | goto out_copy; |
| 1260 | } else { | 1264 | } |
| 1261 | /* 18.35.4 case 7 */ | 1265 | |
| 1262 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1266 | /* 18.35.4 case 7 */ |
| 1263 | status = nfserr_noent; | 1267 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { |
| 1264 | goto out; | 1268 | status = nfserr_noent; |
| 1265 | } | 1269 | goto out; |
| 1266 | } | 1270 | } |
| 1267 | 1271 | ||
| 1268 | unconf = find_unconfirmed_client_by_str(dname, strhashval, true); | 1272 | unconf = find_unconfirmed_client_by_str(dname, strhashval, true); |
| @@ -1471,7 +1475,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
| 1471 | goto out; | 1475 | goto out; |
| 1472 | 1476 | ||
| 1473 | status = nfserr_badslot; | 1477 | status = nfserr_badslot; |
| 1474 | if (seq->slotid >= session->se_fnumslots) | 1478 | if (seq->slotid >= session->se_fchannel.maxreqs) |
| 1475 | goto out; | 1479 | goto out; |
| 1476 | 1480 | ||
| 1477 | slot = &session->se_slots[seq->slotid]; | 1481 | slot = &session->se_slots[seq->slotid]; |
| @@ -1686,9 +1690,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
| 1686 | else { | 1690 | else { |
| 1687 | /* XXX: We just turn off callbacks until we can handle | 1691 | /* XXX: We just turn off callbacks until we can handle |
| 1688 | * change request correctly. */ | 1692 | * change request correctly. */ |
| 1689 | atomic_set(&conf->cl_callback.cb_set, 0); | 1693 | atomic_set(&conf->cl_cb_conn.cb_set, 0); |
| 1690 | gen_confirm(conf); | ||
| 1691 | nfsd4_remove_clid_dir(unconf); | ||
| 1692 | expire_client(unconf); | 1694 | expire_client(unconf); |
| 1693 | status = nfs_ok; | 1695 | status = nfs_ok; |
| 1694 | 1696 | ||
| @@ -1882,7 +1884,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open * | |||
| 1882 | stp->st_stateowner = sop; | 1884 | stp->st_stateowner = sop; |
| 1883 | get_nfs4_file(fp); | 1885 | get_nfs4_file(fp); |
| 1884 | stp->st_file = fp; | 1886 | stp->st_file = fp; |
| 1885 | stp->st_stateid.si_boot = boot_time; | 1887 | stp->st_stateid.si_boot = get_seconds(); |
| 1886 | stp->st_stateid.si_stateownerid = sop->so_id; | 1888 | stp->st_stateid.si_stateownerid = sop->so_id; |
| 1887 | stp->st_stateid.si_fileid = fp->fi_id; | 1889 | stp->st_stateid.si_fileid = fp->fi_id; |
| 1888 | stp->st_stateid.si_generation = 0; | 1890 | stp->st_stateid.si_generation = 0; |
| @@ -2059,19 +2061,6 @@ nfs4_file_downgrade(struct file *filp, unsigned int share_access) | |||
| 2059 | } | 2061 | } |
| 2060 | 2062 | ||
| 2061 | /* | 2063 | /* |
| 2062 | * Recall a delegation | ||
| 2063 | */ | ||
| 2064 | static int | ||
| 2065 | do_recall(void *__dp) | ||
| 2066 | { | ||
| 2067 | struct nfs4_delegation *dp = __dp; | ||
| 2068 | |||
| 2069 | dp->dl_file->fi_had_conflict = true; | ||
| 2070 | nfsd4_cb_recall(dp); | ||
| 2071 | return 0; | ||
| 2072 | } | ||
| 2073 | |||
| 2074 | /* | ||
| 2075 | * Spawn a thread to perform a recall on the delegation represented | 2064 | * Spawn a thread to perform a recall on the delegation represented |
| 2076 | * by the lease (file_lock) | 2065 | * by the lease (file_lock) |
| 2077 | * | 2066 | * |
| @@ -2082,8 +2071,7 @@ do_recall(void *__dp) | |||
| 2082 | static | 2071 | static |
| 2083 | void nfsd_break_deleg_cb(struct file_lock *fl) | 2072 | void nfsd_break_deleg_cb(struct file_lock *fl) |
| 2084 | { | 2073 | { |
| 2085 | struct nfs4_delegation *dp= (struct nfs4_delegation *)fl->fl_owner; | 2074 | struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; |
| 2086 | struct task_struct *t; | ||
| 2087 | 2075 | ||
| 2088 | dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl); | 2076 | dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl); |
| 2089 | if (!dp) | 2077 | if (!dp) |
| @@ -2111,16 +2099,8 @@ void nfsd_break_deleg_cb(struct file_lock *fl) | |||
| 2111 | */ | 2099 | */ |
| 2112 | fl->fl_break_time = 0; | 2100 | fl->fl_break_time = 0; |
| 2113 | 2101 | ||
| 2114 | t = kthread_run(do_recall, dp, "%s", "nfs4_cb_recall"); | 2102 | dp->dl_file->fi_had_conflict = true; |
| 2115 | if (IS_ERR(t)) { | 2103 | nfsd4_cb_recall(dp); |
| 2116 | struct nfs4_client *clp = dp->dl_client; | ||
| 2117 | |||
| 2118 | printk(KERN_INFO "NFSD: Callback thread failed for " | ||
| 2119 | "for client (clientid %08x/%08x)\n", | ||
| 2120 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | ||
| 2121 | put_nfs4_client(dp->dl_client); | ||
| 2122 | nfs4_put_delegation(dp); | ||
| 2123 | } | ||
| 2124 | } | 2104 | } |
| 2125 | 2105 | ||
| 2126 | /* | 2106 | /* |
| @@ -2422,7 +2402,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
| 2422 | { | 2402 | { |
| 2423 | struct nfs4_delegation *dp; | 2403 | struct nfs4_delegation *dp; |
| 2424 | struct nfs4_stateowner *sop = stp->st_stateowner; | 2404 | struct nfs4_stateowner *sop = stp->st_stateowner; |
| 2425 | struct nfs4_callback *cb = &sop->so_client->cl_callback; | 2405 | struct nfs4_cb_conn *cb = &sop->so_client->cl_cb_conn; |
| 2426 | struct file_lock fl, *flp = &fl; | 2406 | struct file_lock fl, *flp = &fl; |
| 2427 | int status, flag = 0; | 2407 | int status, flag = 0; |
| 2428 | 2408 | ||
| @@ -2614,7 +2594,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 2614 | renew_client(clp); | 2594 | renew_client(clp); |
| 2615 | status = nfserr_cb_path_down; | 2595 | status = nfserr_cb_path_down; |
| 2616 | if (!list_empty(&clp->cl_delegations) | 2596 | if (!list_empty(&clp->cl_delegations) |
| 2617 | && !atomic_read(&clp->cl_callback.cb_set)) | 2597 | && !atomic_read(&clp->cl_cb_conn.cb_set)) |
| 2618 | goto out; | 2598 | goto out; |
| 2619 | status = nfs_ok; | 2599 | status = nfs_ok; |
| 2620 | out: | 2600 | out: |
| @@ -2738,12 +2718,42 @@ nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) | |||
| 2738 | static int | 2718 | static int |
| 2739 | STALE_STATEID(stateid_t *stateid) | 2719 | STALE_STATEID(stateid_t *stateid) |
| 2740 | { | 2720 | { |
| 2741 | if (stateid->si_boot == boot_time) | 2721 | if (time_after((unsigned long)boot_time, |
| 2742 | return 0; | 2722 | (unsigned long)stateid->si_boot)) { |
| 2743 | dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", | 2723 | dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", |
| 2744 | stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, | 2724 | stateid->si_boot, stateid->si_stateownerid, |
| 2745 | stateid->si_generation); | 2725 | stateid->si_fileid, stateid->si_generation); |
| 2746 | return 1; | 2726 | return 1; |
| 2727 | } | ||
| 2728 | return 0; | ||
| 2729 | } | ||
| 2730 | |||
| 2731 | static int | ||
| 2732 | EXPIRED_STATEID(stateid_t *stateid) | ||
| 2733 | { | ||
| 2734 | if (time_before((unsigned long)boot_time, | ||
| 2735 | ((unsigned long)stateid->si_boot)) && | ||
| 2736 | time_before((unsigned long)(stateid->si_boot + lease_time), get_seconds())) { | ||
| 2737 | dprintk("NFSD: expired stateid (%08x/%08x/%08x/%08x)!\n", | ||
| 2738 | stateid->si_boot, stateid->si_stateownerid, | ||
| 2739 | stateid->si_fileid, stateid->si_generation); | ||
| 2740 | return 1; | ||
| 2741 | } | ||
| 2742 | return 0; | ||
| 2743 | } | ||
| 2744 | |||
| 2745 | static __be32 | ||
| 2746 | stateid_error_map(stateid_t *stateid) | ||
| 2747 | { | ||
| 2748 | if (STALE_STATEID(stateid)) | ||
| 2749 | return nfserr_stale_stateid; | ||
| 2750 | if (EXPIRED_STATEID(stateid)) | ||
| 2751 | return nfserr_expired; | ||
| 2752 | |||
| 2753 | dprintk("NFSD: bad stateid (%08x/%08x/%08x/%08x)!\n", | ||
| 2754 | stateid->si_boot, stateid->si_stateownerid, | ||
| 2755 | stateid->si_fileid, stateid->si_generation); | ||
| 2756 | return nfserr_bad_stateid; | ||
| 2747 | } | 2757 | } |
| 2748 | 2758 | ||
| 2749 | static inline int | 2759 | static inline int |
| @@ -2867,8 +2877,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
| 2867 | status = nfserr_bad_stateid; | 2877 | status = nfserr_bad_stateid; |
| 2868 | if (is_delegation_stateid(stateid)) { | 2878 | if (is_delegation_stateid(stateid)) { |
| 2869 | dp = find_delegation_stateid(ino, stateid); | 2879 | dp = find_delegation_stateid(ino, stateid); |
| 2870 | if (!dp) | 2880 | if (!dp) { |
| 2881 | status = stateid_error_map(stateid); | ||
| 2871 | goto out; | 2882 | goto out; |
| 2883 | } | ||
| 2872 | status = check_stateid_generation(stateid, &dp->dl_stateid, | 2884 | status = check_stateid_generation(stateid, &dp->dl_stateid, |
| 2873 | flags); | 2885 | flags); |
| 2874 | if (status) | 2886 | if (status) |
| @@ -2881,8 +2893,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
| 2881 | *filpp = dp->dl_vfs_file; | 2893 | *filpp = dp->dl_vfs_file; |
| 2882 | } else { /* open or lock stateid */ | 2894 | } else { /* open or lock stateid */ |
| 2883 | stp = find_stateid(stateid, flags); | 2895 | stp = find_stateid(stateid, flags); |
| 2884 | if (!stp) | 2896 | if (!stp) { |
| 2897 | status = stateid_error_map(stateid); | ||
| 2885 | goto out; | 2898 | goto out; |
| 2899 | } | ||
| 2886 | if (nfs4_check_fh(current_fh, stp)) | 2900 | if (nfs4_check_fh(current_fh, stp)) |
| 2887 | goto out; | 2901 | goto out; |
| 2888 | if (!stp->st_stateowner->so_confirmed) | 2902 | if (!stp->st_stateowner->so_confirmed) |
| @@ -2956,7 +2970,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
| 2956 | */ | 2970 | */ |
| 2957 | sop = search_close_lru(stateid->si_stateownerid, flags); | 2971 | sop = search_close_lru(stateid->si_stateownerid, flags); |
| 2958 | if (sop == NULL) | 2972 | if (sop == NULL) |
| 2959 | return nfserr_bad_stateid; | 2973 | return stateid_error_map(stateid); |
| 2960 | *sopp = sop; | 2974 | *sopp = sop; |
| 2961 | goto check_replay; | 2975 | goto check_replay; |
| 2962 | } | 2976 | } |
| @@ -3227,8 +3241,10 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 3227 | if (!is_delegation_stateid(stateid)) | 3241 | if (!is_delegation_stateid(stateid)) |
| 3228 | goto out; | 3242 | goto out; |
| 3229 | dp = find_delegation_stateid(inode, stateid); | 3243 | dp = find_delegation_stateid(inode, stateid); |
| 3230 | if (!dp) | 3244 | if (!dp) { |
| 3245 | status = stateid_error_map(stateid); | ||
| 3231 | goto out; | 3246 | goto out; |
| 3247 | } | ||
| 3232 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); | 3248 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); |
| 3233 | if (status) | 3249 | if (status) |
| 3234 | goto out; | 3250 | goto out; |
| @@ -3455,7 +3471,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
| 3455 | stp->st_stateowner = sop; | 3471 | stp->st_stateowner = sop; |
| 3456 | get_nfs4_file(fp); | 3472 | get_nfs4_file(fp); |
| 3457 | stp->st_file = fp; | 3473 | stp->st_file = fp; |
| 3458 | stp->st_stateid.si_boot = boot_time; | 3474 | stp->st_stateid.si_boot = get_seconds(); |
| 3459 | stp->st_stateid.si_stateownerid = sop->so_id; | 3475 | stp->st_stateid.si_stateownerid = sop->so_id; |
| 3460 | stp->st_stateid.si_fileid = fp->fi_id; | 3476 | stp->st_stateid.si_fileid = fp->fi_id; |
| 3461 | stp->st_stateid.si_generation = 0; | 3477 | stp->st_stateid.si_generation = 0; |
| @@ -3987,6 +4003,7 @@ nfs4_state_init(void) | |||
| 3987 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); | 4003 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); |
| 3988 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); | 4004 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); |
| 3989 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); | 4005 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); |
| 4006 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); | ||
| 3990 | } | 4007 | } |
| 3991 | for (i = 0; i < SESSION_HASH_SIZE; i++) | 4008 | for (i = 0; i < SESSION_HASH_SIZE; i++) |
| 3992 | INIT_LIST_HEAD(&sessionid_hashtbl[i]); | 4009 | INIT_LIST_HEAD(&sessionid_hashtbl[i]); |
| @@ -4009,8 +4026,6 @@ nfs4_state_init(void) | |||
| 4009 | INIT_LIST_HEAD(&close_lru); | 4026 | INIT_LIST_HEAD(&close_lru); |
| 4010 | INIT_LIST_HEAD(&client_lru); | 4027 | INIT_LIST_HEAD(&client_lru); |
| 4011 | INIT_LIST_HEAD(&del_recall_lru); | 4028 | INIT_LIST_HEAD(&del_recall_lru); |
| 4012 | for (i = 0; i < CLIENT_HASH_SIZE; i++) | ||
| 4013 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); | ||
| 4014 | reclaim_str_hashtbl_size = 0; | 4029 | reclaim_str_hashtbl_size = 0; |
| 4015 | return 0; | 4030 | return 0; |
| 4016 | } | 4031 | } |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b73549d293be..2dcc7feaa6ff 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
| @@ -83,16 +83,6 @@ check_filename(char *str, int len, __be32 err) | |||
| 83 | return 0; | 83 | return 0; |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | /* | ||
| 87 | * START OF "GENERIC" DECODE ROUTINES. | ||
| 88 | * These may look a little ugly since they are imported from a "generic" | ||
| 89 | * set of XDR encode/decode routines which are intended to be shared by | ||
| 90 | * all of our NFSv4 implementations (OpenBSD, MacOS X...). | ||
| 91 | * | ||
| 92 | * If the pain of reading these is too great, it should be a straightforward | ||
| 93 | * task to translate them into Linux-specific versions which are more | ||
| 94 | * consistent with the style used in NFSv2/v3... | ||
| 95 | */ | ||
| 96 | #define DECODE_HEAD \ | 86 | #define DECODE_HEAD \ |
| 97 | __be32 *p; \ | 87 | __be32 *p; \ |
| 98 | __be32 status | 88 | __be32 status |
| @@ -254,20 +244,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) | |||
| 254 | DECODE_TAIL; | 244 | DECODE_TAIL; |
| 255 | } | 245 | } |
| 256 | 246 | ||
| 257 | static u32 nfsd_attrmask[] = { | ||
| 258 | NFSD_WRITEABLE_ATTRS_WORD0, | ||
| 259 | NFSD_WRITEABLE_ATTRS_WORD1, | ||
| 260 | NFSD_WRITEABLE_ATTRS_WORD2 | ||
| 261 | }; | ||
| 262 | |||
| 263 | static u32 nfsd41_ex_attrmask[] = { | ||
| 264 | NFSD_SUPPATTR_EXCLCREAT_WORD0, | ||
| 265 | NFSD_SUPPATTR_EXCLCREAT_WORD1, | ||
| 266 | NFSD_SUPPATTR_EXCLCREAT_WORD2 | ||
| 267 | }; | ||
| 268 | |||
| 269 | static __be32 | 247 | static __be32 |
| 270 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, | 248 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, |
| 271 | struct iattr *iattr, struct nfs4_acl **acl) | 249 | struct iattr *iattr, struct nfs4_acl **acl) |
| 272 | { | 250 | { |
| 273 | int expected_len, len = 0; | 251 | int expected_len, len = 0; |
| @@ -280,18 +258,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, | |||
| 280 | if ((status = nfsd4_decode_bitmap(argp, bmval))) | 258 | if ((status = nfsd4_decode_bitmap(argp, bmval))) |
| 281 | return status; | 259 | return status; |
| 282 | 260 | ||
| 283 | /* | ||
| 284 | * According to spec, unsupported attributes return ERR_ATTRNOTSUPP; | ||
| 285 | * read-only attributes return ERR_INVAL. | ||
| 286 | */ | ||
| 287 | if ((bmval[0] & ~nfsd_suppattrs0(argp->minorversion)) || | ||
| 288 | (bmval[1] & ~nfsd_suppattrs1(argp->minorversion)) || | ||
| 289 | (bmval[2] & ~nfsd_suppattrs2(argp->minorversion))) | ||
| 290 | return nfserr_attrnotsupp; | ||
| 291 | if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) || | ||
| 292 | (bmval[2] & ~writable[2])) | ||
| 293 | return nfserr_inval; | ||
| 294 | |||
| 295 | READ_BUF(4); | 261 | READ_BUF(4); |
| 296 | READ32(expected_len); | 262 | READ32(expected_len); |
| 297 | 263 | ||
| @@ -424,8 +390,11 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, | |||
| 424 | goto xdr_error; | 390 | goto xdr_error; |
| 425 | } | 391 | } |
| 426 | } | 392 | } |
| 427 | BUG_ON(bmval[2]); /* no such writeable attr supported yet */ | 393 | if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 |
| 428 | if (len != expected_len) | 394 | || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 |
| 395 | || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) | ||
| 396 | READ_BUF(expected_len - len); | ||
| 397 | else if (len != expected_len) | ||
| 429 | goto xdr_error; | 398 | goto xdr_error; |
| 430 | 399 | ||
| 431 | DECODE_TAIL; | 400 | DECODE_TAIL; |
| @@ -518,8 +487,8 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create | |||
| 518 | if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) | 487 | if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) |
| 519 | return status; | 488 | return status; |
| 520 | 489 | ||
| 521 | status = nfsd4_decode_fattr(argp, create->cr_bmval, nfsd_attrmask, | 490 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, |
| 522 | &create->cr_iattr, &create->cr_acl); | 491 | &create->cr_acl); |
| 523 | if (status) | 492 | if (status) |
| 524 | goto out; | 493 | goto out; |
| 525 | 494 | ||
| @@ -682,7 +651,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
| 682 | case NFS4_CREATE_UNCHECKED: | 651 | case NFS4_CREATE_UNCHECKED: |
| 683 | case NFS4_CREATE_GUARDED: | 652 | case NFS4_CREATE_GUARDED: |
| 684 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 653 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
| 685 | nfsd_attrmask, &open->op_iattr, &open->op_acl); | 654 | &open->op_iattr, &open->op_acl); |
| 686 | if (status) | 655 | if (status) |
| 687 | goto out; | 656 | goto out; |
| 688 | break; | 657 | break; |
| @@ -696,8 +665,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
| 696 | READ_BUF(8); | 665 | READ_BUF(8); |
| 697 | COPYMEM(open->op_verf.data, 8); | 666 | COPYMEM(open->op_verf.data, 8); |
| 698 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 667 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
| 699 | nfsd41_ex_attrmask, &open->op_iattr, | 668 | &open->op_iattr, &open->op_acl); |
| 700 | &open->op_acl); | ||
| 701 | if (status) | 669 | if (status) |
| 702 | goto out; | 670 | goto out; |
| 703 | break; | 671 | break; |
| @@ -893,8 +861,8 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta | |||
| 893 | status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); | 861 | status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); |
| 894 | if (status) | 862 | if (status) |
| 895 | return status; | 863 | return status; |
| 896 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, nfsd_attrmask, | 864 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, |
| 897 | &setattr->sa_iattr, &setattr->sa_acl); | 865 | &setattr->sa_acl); |
| 898 | } | 866 | } |
| 899 | 867 | ||
| 900 | static __be32 | 868 | static __be32 |
| @@ -1328,64 +1296,64 @@ static nfsd4_dec nfsd4_dec_ops[] = { | |||
| 1328 | }; | 1296 | }; |
| 1329 | 1297 | ||
| 1330 | static nfsd4_dec nfsd41_dec_ops[] = { | 1298 | static nfsd4_dec nfsd41_dec_ops[] = { |
| 1331 | [OP_ACCESS] (nfsd4_dec)nfsd4_decode_access, | 1299 | [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access, |
| 1332 | [OP_CLOSE] (nfsd4_dec)nfsd4_decode_close, | 1300 | [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close, |
| 1333 | [OP_COMMIT] (nfsd4_dec)nfsd4_decode_commit, | 1301 | [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit, |
| 1334 | [OP_CREATE] (nfsd4_dec)nfsd4_decode_create, | 1302 | [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create, |
| 1335 | [OP_DELEGPURGE] (nfsd4_dec)nfsd4_decode_notsupp, | 1303 | [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1336 | [OP_DELEGRETURN] (nfsd4_dec)nfsd4_decode_delegreturn, | 1304 | [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn, |
| 1337 | [OP_GETATTR] (nfsd4_dec)nfsd4_decode_getattr, | 1305 | [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr, |
| 1338 | [OP_GETFH] (nfsd4_dec)nfsd4_decode_noop, | 1306 | [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop, |
| 1339 | [OP_LINK] (nfsd4_dec)nfsd4_decode_link, | 1307 | [OP_LINK] = (nfsd4_dec)nfsd4_decode_link, |
| 1340 | [OP_LOCK] (nfsd4_dec)nfsd4_decode_lock, | 1308 | [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock, |
| 1341 | [OP_LOCKT] (nfsd4_dec)nfsd4_decode_lockt, | 1309 | [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt, |
| 1342 | [OP_LOCKU] (nfsd4_dec)nfsd4_decode_locku, | 1310 | [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku, |
| 1343 | [OP_LOOKUP] (nfsd4_dec)nfsd4_decode_lookup, | 1311 | [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup, |
| 1344 | [OP_LOOKUPP] (nfsd4_dec)nfsd4_decode_noop, | 1312 | [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop, |
| 1345 | [OP_NVERIFY] (nfsd4_dec)nfsd4_decode_verify, | 1313 | [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify, |
| 1346 | [OP_OPEN] (nfsd4_dec)nfsd4_decode_open, | 1314 | [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open, |
| 1347 | [OP_OPENATTR] (nfsd4_dec)nfsd4_decode_notsupp, | 1315 | [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1348 | [OP_OPEN_CONFIRM] (nfsd4_dec)nfsd4_decode_notsupp, | 1316 | [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1349 | [OP_OPEN_DOWNGRADE] (nfsd4_dec)nfsd4_decode_open_downgrade, | 1317 | [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, |
| 1350 | [OP_PUTFH] (nfsd4_dec)nfsd4_decode_putfh, | 1318 | [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, |
| 1351 | [OP_PUTPUBFH] (nfsd4_dec)nfsd4_decode_notsupp, | 1319 | [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1352 | [OP_PUTROOTFH] (nfsd4_dec)nfsd4_decode_noop, | 1320 | [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, |
| 1353 | [OP_READ] (nfsd4_dec)nfsd4_decode_read, | 1321 | [OP_READ] = (nfsd4_dec)nfsd4_decode_read, |
| 1354 | [OP_READDIR] (nfsd4_dec)nfsd4_decode_readdir, | 1322 | [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, |
| 1355 | [OP_READLINK] (nfsd4_dec)nfsd4_decode_noop, | 1323 | [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop, |
| 1356 | [OP_REMOVE] (nfsd4_dec)nfsd4_decode_remove, | 1324 | [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove, |
| 1357 | [OP_RENAME] (nfsd4_dec)nfsd4_decode_rename, | 1325 | [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename, |
| 1358 | [OP_RENEW] (nfsd4_dec)nfsd4_decode_notsupp, | 1326 | [OP_RENEW] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1359 | [OP_RESTOREFH] (nfsd4_dec)nfsd4_decode_noop, | 1327 | [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop, |
| 1360 | [OP_SAVEFH] (nfsd4_dec)nfsd4_decode_noop, | 1328 | [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop, |
| 1361 | [OP_SECINFO] (nfsd4_dec)nfsd4_decode_secinfo, | 1329 | [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo, |
| 1362 | [OP_SETATTR] (nfsd4_dec)nfsd4_decode_setattr, | 1330 | [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr, |
| 1363 | [OP_SETCLIENTID] (nfsd4_dec)nfsd4_decode_notsupp, | 1331 | [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1364 | [OP_SETCLIENTID_CONFIRM](nfsd4_dec)nfsd4_decode_notsupp, | 1332 | [OP_SETCLIENTID_CONFIRM]= (nfsd4_dec)nfsd4_decode_notsupp, |
| 1365 | [OP_VERIFY] (nfsd4_dec)nfsd4_decode_verify, | 1333 | [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, |
| 1366 | [OP_WRITE] (nfsd4_dec)nfsd4_decode_write, | 1334 | [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, |
| 1367 | [OP_RELEASE_LOCKOWNER] (nfsd4_dec)nfsd4_decode_notsupp, | 1335 | [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1368 | 1336 | ||
| 1369 | /* new operations for NFSv4.1 */ | 1337 | /* new operations for NFSv4.1 */ |
| 1370 | [OP_BACKCHANNEL_CTL] (nfsd4_dec)nfsd4_decode_notsupp, | 1338 | [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1371 | [OP_BIND_CONN_TO_SESSION](nfsd4_dec)nfsd4_decode_notsupp, | 1339 | [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_notsupp, |
| 1372 | [OP_EXCHANGE_ID] (nfsd4_dec)nfsd4_decode_exchange_id, | 1340 | [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, |
| 1373 | [OP_CREATE_SESSION] (nfsd4_dec)nfsd4_decode_create_session, | 1341 | [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, |
| 1374 | [OP_DESTROY_SESSION] (nfsd4_dec)nfsd4_decode_destroy_session, | 1342 | [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, |
| 1375 | [OP_FREE_STATEID] (nfsd4_dec)nfsd4_decode_notsupp, | 1343 | [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1376 | [OP_GET_DIR_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp, | 1344 | [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1377 | [OP_GETDEVICEINFO] (nfsd4_dec)nfsd4_decode_notsupp, | 1345 | [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1378 | [OP_GETDEVICELIST] (nfsd4_dec)nfsd4_decode_notsupp, | 1346 | [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1379 | [OP_LAYOUTCOMMIT] (nfsd4_dec)nfsd4_decode_notsupp, | 1347 | [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1380 | [OP_LAYOUTGET] (nfsd4_dec)nfsd4_decode_notsupp, | 1348 | [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1381 | [OP_LAYOUTRETURN] (nfsd4_dec)nfsd4_decode_notsupp, | 1349 | [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1382 | [OP_SECINFO_NO_NAME] (nfsd4_dec)nfsd4_decode_notsupp, | 1350 | [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1383 | [OP_SEQUENCE] (nfsd4_dec)nfsd4_decode_sequence, | 1351 | [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, |
| 1384 | [OP_SET_SSV] (nfsd4_dec)nfsd4_decode_notsupp, | 1352 | [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1385 | [OP_TEST_STATEID] (nfsd4_dec)nfsd4_decode_notsupp, | 1353 | [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1386 | [OP_WANT_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp, | 1354 | [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1387 | [OP_DESTROY_CLIENTID] (nfsd4_dec)nfsd4_decode_notsupp, | 1355 | [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1388 | [OP_RECLAIM_COMPLETE] (nfsd4_dec)nfsd4_decode_notsupp, | 1356 | [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1389 | }; | 1357 | }; |
| 1390 | 1358 | ||
| 1391 | struct nfsd4_minorversion_ops { | 1359 | struct nfsd4_minorversion_ops { |
| @@ -1489,21 +1457,6 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
| 1489 | 1457 | ||
| 1490 | DECODE_TAIL; | 1458 | DECODE_TAIL; |
| 1491 | } | 1459 | } |
| 1492 | /* | ||
| 1493 | * END OF "GENERIC" DECODE ROUTINES. | ||
| 1494 | */ | ||
| 1495 | |||
| 1496 | /* | ||
| 1497 | * START OF "GENERIC" ENCODE ROUTINES. | ||
| 1498 | * These may look a little ugly since they are imported from a "generic" | ||
| 1499 | * set of XDR encode/decode routines which are intended to be shared by | ||
| 1500 | * all of our NFSv4 implementations (OpenBSD, MacOS X...). | ||
| 1501 | * | ||
| 1502 | * If the pain of reading these is too great, it should be a straightforward | ||
| 1503 | * task to translate them into Linux-specific versions which are more | ||
| 1504 | * consistent with the style used in NFSv2/v3... | ||
| 1505 | */ | ||
| 1506 | #define ENCODE_HEAD __be32 *p | ||
| 1507 | 1460 | ||
| 1508 | #define WRITE32(n) *p++ = htonl(n) | 1461 | #define WRITE32(n) *p++ = htonl(n) |
| 1509 | #define WRITE64(n) do { \ | 1462 | #define WRITE64(n) do { \ |
| @@ -1515,13 +1468,41 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
| 1515 | memcpy(p, ptr, nbytes); \ | 1468 | memcpy(p, ptr, nbytes); \ |
| 1516 | p += XDR_QUADLEN(nbytes); \ | 1469 | p += XDR_QUADLEN(nbytes); \ |
| 1517 | }} while (0) | 1470 | }} while (0) |
| 1518 | #define WRITECINFO(c) do { \ | 1471 | |
| 1519 | *p++ = htonl(c.atomic); \ | 1472 | static void write32(__be32 **p, u32 n) |
| 1520 | *p++ = htonl(c.before_ctime_sec); \ | 1473 | { |
| 1521 | *p++ = htonl(c.before_ctime_nsec); \ | 1474 | *(*p)++ = n; |
| 1522 | *p++ = htonl(c.after_ctime_sec); \ | 1475 | } |
| 1523 | *p++ = htonl(c.after_ctime_nsec); \ | 1476 | |
| 1524 | } while (0) | 1477 | static void write64(__be32 **p, u64 n) |
| 1478 | { | ||
| 1479 | write32(p, (u32)(n >> 32)); | ||
| 1480 | write32(p, (u32)n); | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | static void write_change(__be32 **p, struct kstat *stat, struct inode *inode) | ||
| 1484 | { | ||
| 1485 | if (IS_I_VERSION(inode)) { | ||
| 1486 | write64(p, inode->i_version); | ||
| 1487 | } else { | ||
| 1488 | write32(p, stat->ctime.tv_sec); | ||
| 1489 | write32(p, stat->ctime.tv_nsec); | ||
| 1490 | } | ||
| 1491 | } | ||
| 1492 | |||
| 1493 | static void write_cinfo(__be32 **p, struct nfsd4_change_info *c) | ||
| 1494 | { | ||
| 1495 | write32(p, c->atomic); | ||
| 1496 | if (c->change_supported) { | ||
| 1497 | write64(p, c->before_change); | ||
| 1498 | write64(p, c->after_change); | ||
| 1499 | } else { | ||
| 1500 | write32(p, c->before_ctime_sec); | ||
| 1501 | write32(p, c->before_ctime_nsec); | ||
| 1502 | write32(p, c->after_ctime_sec); | ||
| 1503 | write32(p, c->after_ctime_nsec); | ||
| 1504 | } | ||
| 1505 | } | ||
| 1525 | 1506 | ||
| 1526 | #define RESERVE_SPACE(nbytes) do { \ | 1507 | #define RESERVE_SPACE(nbytes) do { \ |
| 1527 | p = resp->p; \ | 1508 | p = resp->p; \ |
| @@ -1874,16 +1855,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
| 1874 | WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME); | 1855 | WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME); |
| 1875 | } | 1856 | } |
| 1876 | if (bmval0 & FATTR4_WORD0_CHANGE) { | 1857 | if (bmval0 & FATTR4_WORD0_CHANGE) { |
| 1877 | /* | ||
| 1878 | * Note: This _must_ be consistent with the scheme for writing | ||
| 1879 | * change_info, so any changes made here must be reflected there | ||
| 1880 | * as well. (See xdr4.h:set_change_info() and the WRITECINFO() | ||
| 1881 | * macro above.) | ||
| 1882 | */ | ||
| 1883 | if ((buflen -= 8) < 0) | 1858 | if ((buflen -= 8) < 0) |
| 1884 | goto out_resource; | 1859 | goto out_resource; |
| 1885 | WRITE32(stat.ctime.tv_sec); | 1860 | write_change(&p, &stat, dentry->d_inode); |
| 1886 | WRITE32(stat.ctime.tv_nsec); | ||
| 1887 | } | 1861 | } |
| 1888 | if (bmval0 & FATTR4_WORD0_SIZE) { | 1862 | if (bmval0 & FATTR4_WORD0_SIZE) { |
| 1889 | if ((buflen -= 8) < 0) | 1863 | if ((buflen -= 8) < 0) |
| @@ -2348,7 +2322,7 @@ fail: | |||
| 2348 | static void | 2322 | static void |
| 2349 | nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) | 2323 | nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) |
| 2350 | { | 2324 | { |
| 2351 | ENCODE_HEAD; | 2325 | __be32 *p; |
| 2352 | 2326 | ||
| 2353 | RESERVE_SPACE(sizeof(stateid_t)); | 2327 | RESERVE_SPACE(sizeof(stateid_t)); |
| 2354 | WRITE32(sid->si_generation); | 2328 | WRITE32(sid->si_generation); |
| @@ -2359,7 +2333,7 @@ nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) | |||
| 2359 | static __be32 | 2333 | static __be32 |
| 2360 | nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) | 2334 | nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) |
| 2361 | { | 2335 | { |
| 2362 | ENCODE_HEAD; | 2336 | __be32 *p; |
| 2363 | 2337 | ||
| 2364 | if (!nfserr) { | 2338 | if (!nfserr) { |
| 2365 | RESERVE_SPACE(8); | 2339 | RESERVE_SPACE(8); |
| @@ -2386,7 +2360,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c | |||
| 2386 | static __be32 | 2360 | static __be32 |
| 2387 | nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) | 2361 | nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) |
| 2388 | { | 2362 | { |
| 2389 | ENCODE_HEAD; | 2363 | __be32 *p; |
| 2390 | 2364 | ||
| 2391 | if (!nfserr) { | 2365 | if (!nfserr) { |
| 2392 | RESERVE_SPACE(8); | 2366 | RESERVE_SPACE(8); |
| @@ -2399,11 +2373,11 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
| 2399 | static __be32 | 2373 | static __be32 |
| 2400 | nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) | 2374 | nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) |
| 2401 | { | 2375 | { |
| 2402 | ENCODE_HEAD; | 2376 | __be32 *p; |
| 2403 | 2377 | ||
| 2404 | if (!nfserr) { | 2378 | if (!nfserr) { |
| 2405 | RESERVE_SPACE(32); | 2379 | RESERVE_SPACE(32); |
| 2406 | WRITECINFO(create->cr_cinfo); | 2380 | write_cinfo(&p, &create->cr_cinfo); |
| 2407 | WRITE32(2); | 2381 | WRITE32(2); |
| 2408 | WRITE32(create->cr_bmval[0]); | 2382 | WRITE32(create->cr_bmval[0]); |
| 2409 | WRITE32(create->cr_bmval[1]); | 2383 | WRITE32(create->cr_bmval[1]); |
| @@ -2435,7 +2409,7 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh | |||
| 2435 | { | 2409 | { |
| 2436 | struct svc_fh *fhp = *fhpp; | 2410 | struct svc_fh *fhp = *fhpp; |
| 2437 | unsigned int len; | 2411 | unsigned int len; |
| 2438 | ENCODE_HEAD; | 2412 | __be32 *p; |
| 2439 | 2413 | ||
| 2440 | if (!nfserr) { | 2414 | if (!nfserr) { |
| 2441 | len = fhp->fh_handle.fh_size; | 2415 | len = fhp->fh_handle.fh_size; |
| @@ -2454,7 +2428,7 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh | |||
| 2454 | static void | 2428 | static void |
| 2455 | nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) | 2429 | nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) |
| 2456 | { | 2430 | { |
| 2457 | ENCODE_HEAD; | 2431 | __be32 *p; |
| 2458 | 2432 | ||
| 2459 | RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0)); | 2433 | RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0)); |
| 2460 | WRITE64(ld->ld_start); | 2434 | WRITE64(ld->ld_start); |
| @@ -2510,11 +2484,11 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l | |||
| 2510 | static __be32 | 2484 | static __be32 |
| 2511 | nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) | 2485 | nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) |
| 2512 | { | 2486 | { |
| 2513 | ENCODE_HEAD; | 2487 | __be32 *p; |
| 2514 | 2488 | ||
| 2515 | if (!nfserr) { | 2489 | if (!nfserr) { |
| 2516 | RESERVE_SPACE(20); | 2490 | RESERVE_SPACE(20); |
| 2517 | WRITECINFO(link->li_cinfo); | 2491 | write_cinfo(&p, &link->li_cinfo); |
| 2518 | ADJUST_ARGS(); | 2492 | ADJUST_ARGS(); |
| 2519 | } | 2493 | } |
| 2520 | return nfserr; | 2494 | return nfserr; |
| @@ -2524,7 +2498,7 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li | |||
| 2524 | static __be32 | 2498 | static __be32 |
| 2525 | nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) | 2499 | nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) |
| 2526 | { | 2500 | { |
| 2527 | ENCODE_HEAD; | 2501 | __be32 *p; |
| 2528 | ENCODE_SEQID_OP_HEAD; | 2502 | ENCODE_SEQID_OP_HEAD; |
| 2529 | 2503 | ||
| 2530 | if (nfserr) | 2504 | if (nfserr) |
| @@ -2532,7 +2506,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op | |||
| 2532 | 2506 | ||
| 2533 | nfsd4_encode_stateid(resp, &open->op_stateid); | 2507 | nfsd4_encode_stateid(resp, &open->op_stateid); |
| 2534 | RESERVE_SPACE(40); | 2508 | RESERVE_SPACE(40); |
| 2535 | WRITECINFO(open->op_cinfo); | 2509 | write_cinfo(&p, &open->op_cinfo); |
| 2536 | WRITE32(open->op_rflags); | 2510 | WRITE32(open->op_rflags); |
| 2537 | WRITE32(2); | 2511 | WRITE32(2); |
| 2538 | WRITE32(open->op_bmval[0]); | 2512 | WRITE32(open->op_bmval[0]); |
| @@ -2619,7 +2593,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
| 2619 | int v, pn; | 2593 | int v, pn; |
| 2620 | unsigned long maxcount; | 2594 | unsigned long maxcount; |
| 2621 | long len; | 2595 | long len; |
| 2622 | ENCODE_HEAD; | 2596 | __be32 *p; |
| 2623 | 2597 | ||
| 2624 | if (nfserr) | 2598 | if (nfserr) |
| 2625 | return nfserr; | 2599 | return nfserr; |
| @@ -2681,7 +2655,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd | |||
| 2681 | { | 2655 | { |
| 2682 | int maxcount; | 2656 | int maxcount; |
| 2683 | char *page; | 2657 | char *page; |
| 2684 | ENCODE_HEAD; | 2658 | __be32 *p; |
| 2685 | 2659 | ||
| 2686 | if (nfserr) | 2660 | if (nfserr) |
| 2687 | return nfserr; | 2661 | return nfserr; |
| @@ -2730,7 +2704,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
| 2730 | int maxcount; | 2704 | int maxcount; |
| 2731 | loff_t offset; | 2705 | loff_t offset; |
| 2732 | __be32 *page, *savep, *tailbase; | 2706 | __be32 *page, *savep, *tailbase; |
| 2733 | ENCODE_HEAD; | 2707 | __be32 *p; |
| 2734 | 2708 | ||
| 2735 | if (nfserr) | 2709 | if (nfserr) |
| 2736 | return nfserr; | 2710 | return nfserr; |
| @@ -2806,11 +2780,11 @@ err_no_verf: | |||
| 2806 | static __be32 | 2780 | static __be32 |
| 2807 | nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) | 2781 | nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) |
| 2808 | { | 2782 | { |
| 2809 | ENCODE_HEAD; | 2783 | __be32 *p; |
| 2810 | 2784 | ||
| 2811 | if (!nfserr) { | 2785 | if (!nfserr) { |
| 2812 | RESERVE_SPACE(20); | 2786 | RESERVE_SPACE(20); |
| 2813 | WRITECINFO(remove->rm_cinfo); | 2787 | write_cinfo(&p, &remove->rm_cinfo); |
| 2814 | ADJUST_ARGS(); | 2788 | ADJUST_ARGS(); |
| 2815 | } | 2789 | } |
| 2816 | return nfserr; | 2790 | return nfserr; |
| @@ -2819,12 +2793,12 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
| 2819 | static __be32 | 2793 | static __be32 |
| 2820 | nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) | 2794 | nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) |
| 2821 | { | 2795 | { |
| 2822 | ENCODE_HEAD; | 2796 | __be32 *p; |
| 2823 | 2797 | ||
| 2824 | if (!nfserr) { | 2798 | if (!nfserr) { |
| 2825 | RESERVE_SPACE(40); | 2799 | RESERVE_SPACE(40); |
| 2826 | WRITECINFO(rename->rn_sinfo); | 2800 | write_cinfo(&p, &rename->rn_sinfo); |
| 2827 | WRITECINFO(rename->rn_tinfo); | 2801 | write_cinfo(&p, &rename->rn_tinfo); |
| 2828 | ADJUST_ARGS(); | 2802 | ADJUST_ARGS(); |
| 2829 | } | 2803 | } |
| 2830 | return nfserr; | 2804 | return nfserr; |
| @@ -2839,7 +2813,7 @@ nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
| 2839 | u32 nflavs; | 2813 | u32 nflavs; |
| 2840 | struct exp_flavor_info *flavs; | 2814 | struct exp_flavor_info *flavs; |
| 2841 | struct exp_flavor_info def_flavs[2]; | 2815 | struct exp_flavor_info def_flavs[2]; |
| 2842 | ENCODE_HEAD; | 2816 | __be32 *p; |
| 2843 | 2817 | ||
| 2844 | if (nfserr) | 2818 | if (nfserr) |
| 2845 | goto out; | 2819 | goto out; |
| @@ -2904,7 +2878,7 @@ out: | |||
| 2904 | static __be32 | 2878 | static __be32 |
| 2905 | nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) | 2879 | nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) |
| 2906 | { | 2880 | { |
| 2907 | ENCODE_HEAD; | 2881 | __be32 *p; |
| 2908 | 2882 | ||
| 2909 | RESERVE_SPACE(12); | 2883 | RESERVE_SPACE(12); |
| 2910 | if (nfserr) { | 2884 | if (nfserr) { |
| @@ -2924,7 +2898,7 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
| 2924 | static __be32 | 2898 | static __be32 |
| 2925 | nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) | 2899 | nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) |
| 2926 | { | 2900 | { |
| 2927 | ENCODE_HEAD; | 2901 | __be32 *p; |
| 2928 | 2902 | ||
| 2929 | if (!nfserr) { | 2903 | if (!nfserr) { |
| 2930 | RESERVE_SPACE(8 + sizeof(nfs4_verifier)); | 2904 | RESERVE_SPACE(8 + sizeof(nfs4_verifier)); |
| @@ -2944,7 +2918,7 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n | |||
| 2944 | static __be32 | 2918 | static __be32 |
| 2945 | nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) | 2919 | nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) |
| 2946 | { | 2920 | { |
| 2947 | ENCODE_HEAD; | 2921 | __be32 *p; |
| 2948 | 2922 | ||
| 2949 | if (!nfserr) { | 2923 | if (!nfserr) { |
| 2950 | RESERVE_SPACE(16); | 2924 | RESERVE_SPACE(16); |
| @@ -2960,7 +2934,7 @@ static __be32 | |||
| 2960 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, | 2934 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, |
| 2961 | struct nfsd4_exchange_id *exid) | 2935 | struct nfsd4_exchange_id *exid) |
| 2962 | { | 2936 | { |
| 2963 | ENCODE_HEAD; | 2937 | __be32 *p; |
| 2964 | char *major_id; | 2938 | char *major_id; |
| 2965 | char *server_scope; | 2939 | char *server_scope; |
| 2966 | int major_id_sz; | 2940 | int major_id_sz; |
| @@ -3015,7 +2989,7 @@ static __be32 | |||
| 3015 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, | 2989 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, |
| 3016 | struct nfsd4_create_session *sess) | 2990 | struct nfsd4_create_session *sess) |
| 3017 | { | 2991 | { |
| 3018 | ENCODE_HEAD; | 2992 | __be32 *p; |
| 3019 | 2993 | ||
| 3020 | if (nfserr) | 2994 | if (nfserr) |
| 3021 | return nfserr; | 2995 | return nfserr; |
| @@ -3071,7 +3045,7 @@ __be32 | |||
| 3071 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | 3045 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, |
| 3072 | struct nfsd4_sequence *seq) | 3046 | struct nfsd4_sequence *seq) |
| 3073 | { | 3047 | { |
| 3074 | ENCODE_HEAD; | 3048 | __be32 *p; |
| 3075 | 3049 | ||
| 3076 | if (nfserr) | 3050 | if (nfserr) |
| 3077 | return nfserr; | 3051 | return nfserr; |
| @@ -3209,7 +3183,7 @@ static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) | |||
| 3209 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, | 3183 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, |
| 3210 | length, xb->page_len, tlen, pad); | 3184 | length, xb->page_len, tlen, pad); |
| 3211 | 3185 | ||
| 3212 | if (length <= session->se_fmaxresp_cached) | 3186 | if (length <= session->se_fchannel.maxresp_cached) |
| 3213 | return status; | 3187 | return status; |
| 3214 | else | 3188 | else |
| 3215 | return nfserr_rep_too_big_to_cache; | 3189 | return nfserr_rep_too_big_to_cache; |
| @@ -3219,7 +3193,7 @@ void | |||
| 3219 | nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | 3193 | nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) |
| 3220 | { | 3194 | { |
| 3221 | __be32 *statp; | 3195 | __be32 *statp; |
| 3222 | ENCODE_HEAD; | 3196 | __be32 *p; |
| 3223 | 3197 | ||
| 3224 | RESERVE_SPACE(8); | 3198 | RESERVE_SPACE(8); |
| 3225 | WRITE32(op->opnum); | 3199 | WRITE32(op->opnum); |
| @@ -3253,7 +3227,7 @@ status: | |||
| 3253 | void | 3227 | void |
| 3254 | nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | 3228 | nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) |
| 3255 | { | 3229 | { |
| 3256 | ENCODE_HEAD; | 3230 | __be32 *p; |
| 3257 | struct nfs4_replay *rp = op->replay; | 3231 | struct nfs4_replay *rp = op->replay; |
| 3258 | 3232 | ||
| 3259 | BUG_ON(!rp); | 3233 | BUG_ON(!rp); |
| @@ -3268,10 +3242,6 @@ nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | |||
| 3268 | ADJUST_ARGS(); | 3242 | ADJUST_ARGS(); |
| 3269 | } | 3243 | } |
| 3270 | 3244 | ||
| 3271 | /* | ||
| 3272 | * END OF "GENERIC" ENCODE ROUTINES. | ||
| 3273 | */ | ||
| 3274 | |||
| 3275 | int | 3245 | int |
| 3276 | nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) | 3246 | nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) |
| 3277 | { | 3247 | { |
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 5bfc2ac60d54..4638635c5d87 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c | |||
| @@ -29,15 +29,24 @@ | |||
| 29 | */ | 29 | */ |
| 30 | #define CACHESIZE 1024 | 30 | #define CACHESIZE 1024 |
| 31 | #define HASHSIZE 64 | 31 | #define HASHSIZE 64 |
| 32 | #define REQHASH(xid) (((((__force __u32)xid) >> 24) ^ ((__force __u32)xid)) & (HASHSIZE-1)) | ||
| 33 | 32 | ||
| 34 | static struct hlist_head * hash_list; | 33 | static struct hlist_head * cache_hash; |
| 35 | static struct list_head lru_head; | 34 | static struct list_head lru_head; |
| 36 | static int cache_disabled = 1; | 35 | static int cache_disabled = 1; |
| 37 | 36 | ||
| 37 | /* | ||
| 38 | * Calculate the hash index from an XID. | ||
| 39 | */ | ||
| 40 | static inline u32 request_hash(u32 xid) | ||
| 41 | { | ||
| 42 | u32 h = xid; | ||
| 43 | h ^= (xid >> 24); | ||
| 44 | return h & (HASHSIZE-1); | ||
| 45 | } | ||
| 46 | |||
| 38 | static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); | 47 | static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); |
| 39 | 48 | ||
| 40 | /* | 49 | /* |
| 41 | * locking for the reply cache: | 50 | * locking for the reply cache: |
| 42 | * A cache entry is "single use" if c_state == RC_INPROG | 51 | * A cache entry is "single use" if c_state == RC_INPROG |
| 43 | * Otherwise, it when accessing _prev or _next, the lock must be held. | 52 | * Otherwise, it when accessing _prev or _next, the lock must be held. |
| @@ -62,8 +71,8 @@ int nfsd_reply_cache_init(void) | |||
| 62 | i--; | 71 | i--; |
| 63 | } | 72 | } |
| 64 | 73 | ||
| 65 | hash_list = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL); | 74 | cache_hash = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL); |
| 66 | if (!hash_list) | 75 | if (!cache_hash) |
| 67 | goto out_nomem; | 76 | goto out_nomem; |
| 68 | 77 | ||
| 69 | cache_disabled = 0; | 78 | cache_disabled = 0; |
| @@ -88,8 +97,8 @@ void nfsd_reply_cache_shutdown(void) | |||
| 88 | 97 | ||
| 89 | cache_disabled = 1; | 98 | cache_disabled = 1; |
| 90 | 99 | ||
| 91 | kfree (hash_list); | 100 | kfree (cache_hash); |
| 92 | hash_list = NULL; | 101 | cache_hash = NULL; |
| 93 | } | 102 | } |
| 94 | 103 | ||
| 95 | /* | 104 | /* |
| @@ -108,7 +117,7 @@ static void | |||
| 108 | hash_refile(struct svc_cacherep *rp) | 117 | hash_refile(struct svc_cacherep *rp) |
| 109 | { | 118 | { |
| 110 | hlist_del_init(&rp->c_hash); | 119 | hlist_del_init(&rp->c_hash); |
| 111 | hlist_add_head(&rp->c_hash, hash_list + REQHASH(rp->c_xid)); | 120 | hlist_add_head(&rp->c_hash, cache_hash + request_hash(rp->c_xid)); |
| 112 | } | 121 | } |
| 113 | 122 | ||
| 114 | /* | 123 | /* |
| @@ -138,7 +147,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) | |||
| 138 | spin_lock(&cache_lock); | 147 | spin_lock(&cache_lock); |
| 139 | rtn = RC_DOIT; | 148 | rtn = RC_DOIT; |
| 140 | 149 | ||
| 141 | rh = &hash_list[REQHASH(xid)]; | 150 | rh = &cache_hash[request_hash(xid)]; |
| 142 | hlist_for_each_entry(rp, hn, rh, c_hash) { | 151 | hlist_for_each_entry(rp, hn, rh, c_hash) { |
| 143 | if (rp->c_state != RC_UNUSED && | 152 | if (rp->c_state != RC_UNUSED && |
| 144 | xid == rp->c_xid && proc == rp->c_proc && | 153 | xid == rp->c_xid && proc == rp->c_proc && |
| @@ -165,8 +174,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) | |||
| 165 | } | 174 | } |
| 166 | } | 175 | } |
| 167 | 176 | ||
| 168 | /* This should not happen */ | 177 | /* All entries on the LRU are in-progress. This should not happen */ |
| 169 | if (rp == NULL) { | 178 | if (&rp->c_lru == &lru_head) { |
| 170 | static int complaints; | 179 | static int complaints; |
| 171 | 180 | ||
| 172 | printk(KERN_WARNING "nfsd: all repcache entries locked!\n"); | 181 | printk(KERN_WARNING "nfsd: all repcache entries locked!\n"); |
| @@ -264,7 +273,7 @@ nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp) | |||
| 264 | 273 | ||
| 265 | len = resv->iov_len - ((char*)statp - (char*)resv->iov_base); | 274 | len = resv->iov_len - ((char*)statp - (char*)resv->iov_base); |
| 266 | len >>= 2; | 275 | len >>= 2; |
| 267 | 276 | ||
| 268 | /* Don't cache excessive amounts of data and XDR failures */ | 277 | /* Don't cache excessive amounts of data and XDR failures */ |
| 269 | if (!statp || len > (256 >> 2)) { | 278 | if (!statp || len > (256 >> 2)) { |
| 270 | rp->c_state = RC_UNUSED; | 279 | rp->c_state = RC_UNUSED; |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index af16849d243a..1250fb978ac1 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
| @@ -207,10 +207,14 @@ static struct file_operations pool_stats_operations = { | |||
| 207 | static ssize_t write_svc(struct file *file, char *buf, size_t size) | 207 | static ssize_t write_svc(struct file *file, char *buf, size_t size) |
| 208 | { | 208 | { |
| 209 | struct nfsctl_svc *data; | 209 | struct nfsctl_svc *data; |
| 210 | int err; | ||
| 210 | if (size < sizeof(*data)) | 211 | if (size < sizeof(*data)) |
| 211 | return -EINVAL; | 212 | return -EINVAL; |
| 212 | data = (struct nfsctl_svc*) buf; | 213 | data = (struct nfsctl_svc*) buf; |
| 213 | return nfsd_svc(data->svc_port, data->svc_nthreads); | 214 | err = nfsd_svc(data->svc_port, data->svc_nthreads); |
| 215 | if (err < 0) | ||
| 216 | return err; | ||
| 217 | return 0; | ||
| 214 | } | 218 | } |
| 215 | 219 | ||
| 216 | /** | 220 | /** |
| @@ -692,11 +696,12 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) | |||
| 692 | if (newthreads < 0) | 696 | if (newthreads < 0) |
| 693 | return -EINVAL; | 697 | return -EINVAL; |
| 694 | rv = nfsd_svc(NFS_PORT, newthreads); | 698 | rv = nfsd_svc(NFS_PORT, newthreads); |
| 695 | if (rv) | 699 | if (rv < 0) |
| 696 | return rv; | 700 | return rv; |
| 697 | } | 701 | } else |
| 698 | sprintf(buf, "%d\n", nfsd_nrthreads()); | 702 | rv = nfsd_nrthreads(); |
| 699 | return strlen(buf); | 703 | |
| 704 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv); | ||
| 700 | } | 705 | } |
| 701 | 706 | ||
| 702 | /** | 707 | /** |
| @@ -793,7 +798,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
| 793 | { | 798 | { |
| 794 | char *mesg = buf; | 799 | char *mesg = buf; |
| 795 | char *vers, *minorp, sign; | 800 | char *vers, *minorp, sign; |
| 796 | int len, num; | 801 | int len, num, remaining; |
| 797 | unsigned minor; | 802 | unsigned minor; |
| 798 | ssize_t tlen = 0; | 803 | ssize_t tlen = 0; |
| 799 | char *sep; | 804 | char *sep; |
| @@ -840,32 +845,50 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
| 840 | } | 845 | } |
| 841 | next: | 846 | next: |
| 842 | vers += len + 1; | 847 | vers += len + 1; |
| 843 | tlen += len; | ||
| 844 | } while ((len = qword_get(&mesg, vers, size)) > 0); | 848 | } while ((len = qword_get(&mesg, vers, size)) > 0); |
| 845 | /* If all get turned off, turn them back on, as | 849 | /* If all get turned off, turn them back on, as |
| 846 | * having no versions is BAD | 850 | * having no versions is BAD |
| 847 | */ | 851 | */ |
| 848 | nfsd_reset_versions(); | 852 | nfsd_reset_versions(); |
| 849 | } | 853 | } |
| 854 | |||
| 850 | /* Now write current state into reply buffer */ | 855 | /* Now write current state into reply buffer */ |
| 851 | len = 0; | 856 | len = 0; |
| 852 | sep = ""; | 857 | sep = ""; |
| 858 | remaining = SIMPLE_TRANSACTION_LIMIT; | ||
| 853 | for (num=2 ; num <= 4 ; num++) | 859 | for (num=2 ; num <= 4 ; num++) |
| 854 | if (nfsd_vers(num, NFSD_AVAIL)) { | 860 | if (nfsd_vers(num, NFSD_AVAIL)) { |
| 855 | len += sprintf(buf+len, "%s%c%d", sep, | 861 | len = snprintf(buf, remaining, "%s%c%d", sep, |
| 856 | nfsd_vers(num, NFSD_TEST)?'+':'-', | 862 | nfsd_vers(num, NFSD_TEST)?'+':'-', |
| 857 | num); | 863 | num); |
| 858 | sep = " "; | 864 | sep = " "; |
| 865 | |||
| 866 | if (len > remaining) | ||
| 867 | break; | ||
| 868 | remaining -= len; | ||
| 869 | buf += len; | ||
| 870 | tlen += len; | ||
| 859 | } | 871 | } |
| 860 | if (nfsd_vers(4, NFSD_AVAIL)) | 872 | if (nfsd_vers(4, NFSD_AVAIL)) |
| 861 | for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; minor++) | 873 | for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; |
| 862 | len += sprintf(buf+len, " %c4.%u", | 874 | minor++) { |
| 875 | len = snprintf(buf, remaining, " %c4.%u", | ||
| 863 | (nfsd_vers(4, NFSD_TEST) && | 876 | (nfsd_vers(4, NFSD_TEST) && |
| 864 | nfsd_minorversion(minor, NFSD_TEST)) ? | 877 | nfsd_minorversion(minor, NFSD_TEST)) ? |
| 865 | '+' : '-', | 878 | '+' : '-', |
| 866 | minor); | 879 | minor); |
| 867 | len += sprintf(buf+len, "\n"); | 880 | |
| 868 | return len; | 881 | if (len > remaining) |
| 882 | break; | ||
| 883 | remaining -= len; | ||
| 884 | buf += len; | ||
| 885 | tlen += len; | ||
| 886 | } | ||
| 887 | |||
| 888 | len = snprintf(buf, remaining, "\n"); | ||
| 889 | if (len > remaining) | ||
| 890 | return -EINVAL; | ||
| 891 | return tlen + len; | ||
| 869 | } | 892 | } |
| 870 | 893 | ||
| 871 | /** | 894 | /** |
| @@ -910,104 +933,143 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) | |||
| 910 | return rv; | 933 | return rv; |
| 911 | } | 934 | } |
| 912 | 935 | ||
| 913 | static ssize_t __write_ports(struct file *file, char *buf, size_t size) | 936 | /* |
| 937 | * Zero-length write. Return a list of NFSD's current listener | ||
| 938 | * transports. | ||
| 939 | */ | ||
| 940 | static ssize_t __write_ports_names(char *buf) | ||
| 914 | { | 941 | { |
| 915 | if (size == 0) { | 942 | if (nfsd_serv == NULL) |
| 916 | int len = 0; | 943 | return 0; |
| 944 | return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT); | ||
| 945 | } | ||
| 917 | 946 | ||
| 918 | if (nfsd_serv) | 947 | /* |
| 919 | len = svc_xprt_names(nfsd_serv, buf, 0); | 948 | * A single 'fd' number was written, in which case it must be for |
| 920 | return len; | 949 | * a socket of a supported family/protocol, and we use it as an |
| 921 | } | 950 | * nfsd listener. |
| 922 | /* Either a single 'fd' number is written, in which | 951 | */ |
| 923 | * case it must be for a socket of a supported family/protocol, | 952 | static ssize_t __write_ports_addfd(char *buf) |
| 924 | * and we use it as an nfsd socket, or | 953 | { |
| 925 | * A '-' followed by the 'name' of a socket in which case | 954 | char *mesg = buf; |
| 926 | * we close the socket. | 955 | int fd, err; |
| 927 | */ | 956 | |
| 928 | if (isdigit(buf[0])) { | 957 | err = get_int(&mesg, &fd); |
| 929 | char *mesg = buf; | 958 | if (err != 0 || fd < 0) |
| 930 | int fd; | 959 | return -EINVAL; |
| 931 | int err; | 960 | |
| 932 | err = get_int(&mesg, &fd); | 961 | err = nfsd_create_serv(); |
| 933 | if (err) | 962 | if (err != 0) |
| 934 | return -EINVAL; | 963 | return err; |
| 935 | if (fd < 0) | 964 | |
| 936 | return -EINVAL; | 965 | err = lockd_up(); |
| 937 | err = nfsd_create_serv(); | 966 | if (err != 0) |
| 938 | if (!err) { | 967 | goto out; |
| 939 | err = svc_addsock(nfsd_serv, fd, buf); | 968 | |
| 940 | if (err >= 0) { | 969 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); |
| 941 | err = lockd_up(); | 970 | if (err < 0) |
| 942 | if (err < 0) | 971 | lockd_down(); |
| 943 | svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf); | 972 | |
| 944 | } | 973 | out: |
| 945 | /* Decrease the count, but don't shutdown the | 974 | /* Decrease the count, but don't shut down the service */ |
| 946 | * the service | 975 | nfsd_serv->sv_nrthreads--; |
| 947 | */ | 976 | return err; |
| 948 | nfsd_serv->sv_nrthreads--; | 977 | } |
| 949 | } | 978 | |
| 950 | return err < 0 ? err : 0; | 979 | /* |
| 951 | } | 980 | * A '-' followed by the 'name' of a socket means we close the socket. |
| 952 | if (buf[0] == '-' && isdigit(buf[1])) { | 981 | */ |
| 953 | char *toclose = kstrdup(buf+1, GFP_KERNEL); | 982 | static ssize_t __write_ports_delfd(char *buf) |
| 954 | int len = 0; | 983 | { |
| 955 | if (!toclose) | 984 | char *toclose; |
| 956 | return -ENOMEM; | 985 | int len = 0; |
| 957 | if (nfsd_serv) | 986 | |
| 958 | len = svc_sock_names(buf, nfsd_serv, toclose); | 987 | toclose = kstrdup(buf + 1, GFP_KERNEL); |
| 959 | if (len >= 0) | 988 | if (toclose == NULL) |
| 960 | lockd_down(); | 989 | return -ENOMEM; |
| 961 | kfree(toclose); | 990 | |
| 962 | return len; | 991 | if (nfsd_serv != NULL) |
| 963 | } | 992 | len = svc_sock_names(nfsd_serv, buf, |
| 964 | /* | 993 | SIMPLE_TRANSACTION_LIMIT, toclose); |
| 965 | * Add a transport listener by writing it's transport name | 994 | if (len >= 0) |
| 966 | */ | 995 | lockd_down(); |
| 967 | if (isalpha(buf[0])) { | 996 | |
| 968 | int err; | 997 | kfree(toclose); |
| 969 | char transport[16]; | 998 | return len; |
| 970 | int port; | 999 | } |
| 971 | if (sscanf(buf, "%15s %4d", transport, &port) == 2) { | 1000 | |
| 972 | if (port < 1 || port > 65535) | 1001 | /* |
| 973 | return -EINVAL; | 1002 | * A transport listener is added by writing it's transport name and |
| 974 | err = nfsd_create_serv(); | 1003 | * a port number. |
| 975 | if (!err) { | 1004 | */ |
| 976 | err = svc_create_xprt(nfsd_serv, | 1005 | static ssize_t __write_ports_addxprt(char *buf) |
| 977 | transport, PF_INET, port, | 1006 | { |
| 978 | SVC_SOCK_ANONYMOUS); | 1007 | char transport[16]; |
| 979 | if (err == -ENOENT) | 1008 | int port, err; |
| 980 | /* Give a reasonable perror msg for | 1009 | |
| 981 | * bad transport string */ | 1010 | if (sscanf(buf, "%15s %4u", transport, &port) != 2) |
| 982 | err = -EPROTONOSUPPORT; | 1011 | return -EINVAL; |
| 983 | } | 1012 | |
| 984 | return err < 0 ? err : 0; | 1013 | if (port < 1 || port > USHORT_MAX) |
| 985 | } | 1014 | return -EINVAL; |
| 986 | } | 1015 | |
| 987 | /* | 1016 | err = nfsd_create_serv(); |
| 988 | * Remove a transport by writing it's transport name and port number | 1017 | if (err != 0) |
| 989 | */ | 1018 | return err; |
| 990 | if (buf[0] == '-' && isalpha(buf[1])) { | 1019 | |
| 991 | struct svc_xprt *xprt; | 1020 | err = svc_create_xprt(nfsd_serv, transport, |
| 992 | int err = -EINVAL; | 1021 | PF_INET, port, SVC_SOCK_ANONYMOUS); |
| 993 | char transport[16]; | 1022 | if (err < 0) { |
| 994 | int port; | 1023 | /* Give a reasonable perror msg for bad transport string */ |
| 995 | if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) { | 1024 | if (err == -ENOENT) |
| 996 | if (port < 1 || port > 65535) | 1025 | err = -EPROTONOSUPPORT; |
| 997 | return -EINVAL; | 1026 | return err; |
| 998 | if (nfsd_serv) { | ||
| 999 | xprt = svc_find_xprt(nfsd_serv, transport, | ||
| 1000 | AF_UNSPEC, port); | ||
| 1001 | if (xprt) { | ||
| 1002 | svc_close_xprt(xprt); | ||
| 1003 | svc_xprt_put(xprt); | ||
| 1004 | err = 0; | ||
| 1005 | } else | ||
| 1006 | err = -ENOTCONN; | ||
| 1007 | } | ||
| 1008 | return err < 0 ? err : 0; | ||
| 1009 | } | ||
| 1010 | } | 1027 | } |
| 1028 | return 0; | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | /* | ||
| 1032 | * A transport listener is removed by writing a "-", it's transport | ||
| 1033 | * name, and it's port number. | ||
| 1034 | */ | ||
| 1035 | static ssize_t __write_ports_delxprt(char *buf) | ||
| 1036 | { | ||
| 1037 | struct svc_xprt *xprt; | ||
| 1038 | char transport[16]; | ||
| 1039 | int port; | ||
| 1040 | |||
| 1041 | if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2) | ||
| 1042 | return -EINVAL; | ||
| 1043 | |||
| 1044 | if (port < 1 || port > USHORT_MAX || nfsd_serv == NULL) | ||
| 1045 | return -EINVAL; | ||
| 1046 | |||
| 1047 | xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port); | ||
| 1048 | if (xprt == NULL) | ||
| 1049 | return -ENOTCONN; | ||
| 1050 | |||
| 1051 | svc_close_xprt(xprt); | ||
| 1052 | svc_xprt_put(xprt); | ||
| 1053 | return 0; | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | static ssize_t __write_ports(struct file *file, char *buf, size_t size) | ||
| 1057 | { | ||
| 1058 | if (size == 0) | ||
| 1059 | return __write_ports_names(buf); | ||
| 1060 | |||
| 1061 | if (isdigit(buf[0])) | ||
| 1062 | return __write_ports_addfd(buf); | ||
| 1063 | |||
| 1064 | if (buf[0] == '-' && isdigit(buf[1])) | ||
| 1065 | return __write_ports_delfd(buf); | ||
| 1066 | |||
| 1067 | if (isalpha(buf[0])) | ||
| 1068 | return __write_ports_addxprt(buf); | ||
| 1069 | |||
| 1070 | if (buf[0] == '-' && isalpha(buf[1])) | ||
| 1071 | return __write_ports_delxprt(buf); | ||
| 1072 | |||
| 1011 | return -EINVAL; | 1073 | return -EINVAL; |
| 1012 | } | 1074 | } |
| 1013 | 1075 | ||
| @@ -1030,7 +1092,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) | |||
| 1030 | * buf: C string containing an unsigned | 1092 | * buf: C string containing an unsigned |
| 1031 | * integer value representing a bound | 1093 | * integer value representing a bound |
| 1032 | * but unconnected socket that is to be | 1094 | * but unconnected socket that is to be |
| 1033 | * used as an NFSD listener | 1095 | * used as an NFSD listener; listen(3) |
| 1096 | * must be called for a SOCK_STREAM | ||
| 1097 | * socket, otherwise it is ignored | ||
| 1034 | * size: non-zero length of C string in @buf | 1098 | * size: non-zero length of C string in @buf |
| 1035 | * Output: | 1099 | * Output: |
| 1036 | * On success: NFS service is started; | 1100 | * On success: NFS service is started; |
| @@ -1138,7 +1202,9 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) | |||
| 1138 | nfsd_max_blksize = bsize; | 1202 | nfsd_max_blksize = bsize; |
| 1139 | mutex_unlock(&nfsd_mutex); | 1203 | mutex_unlock(&nfsd_mutex); |
| 1140 | } | 1204 | } |
| 1141 | return sprintf(buf, "%d\n", nfsd_max_blksize); | 1205 | |
| 1206 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", | ||
| 1207 | nfsd_max_blksize); | ||
| 1142 | } | 1208 | } |
| 1143 | 1209 | ||
| 1144 | #ifdef CONFIG_NFSD_V4 | 1210 | #ifdef CONFIG_NFSD_V4 |
| @@ -1162,8 +1228,9 @@ static ssize_t __write_leasetime(struct file *file, char *buf, size_t size) | |||
| 1162 | return -EINVAL; | 1228 | return -EINVAL; |
| 1163 | nfs4_reset_lease(lease); | 1229 | nfs4_reset_lease(lease); |
| 1164 | } | 1230 | } |
| 1165 | sprintf(buf, "%ld\n", nfs4_lease_time()); | 1231 | |
| 1166 | return strlen(buf); | 1232 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", |
| 1233 | nfs4_lease_time()); | ||
| 1167 | } | 1234 | } |
| 1168 | 1235 | ||
| 1169 | /** | 1236 | /** |
| @@ -1219,8 +1286,9 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) | |||
| 1219 | 1286 | ||
| 1220 | status = nfs4_reset_recoverydir(recdir); | 1287 | status = nfs4_reset_recoverydir(recdir); |
| 1221 | } | 1288 | } |
| 1222 | sprintf(buf, "%s\n", nfs4_recoverydir()); | 1289 | |
| 1223 | return strlen(buf); | 1290 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n", |
| 1291 | nfs4_recoverydir()); | ||
| 1224 | } | 1292 | } |
| 1225 | 1293 | ||
| 1226 | /** | 1294 | /** |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 9f1ca17293d3..8847f3fbfc1e 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
| @@ -27,9 +27,6 @@ | |||
| 27 | #define NFSDDBG_FACILITY NFSDDBG_FH | 27 | #define NFSDDBG_FACILITY NFSDDBG_FH |
| 28 | 28 | ||
| 29 | 29 | ||
| 30 | static int nfsd_nr_verified; | ||
| 31 | static int nfsd_nr_put; | ||
| 32 | |||
| 33 | /* | 30 | /* |
| 34 | * our acceptability function. | 31 | * our acceptability function. |
| 35 | * if NOSUBTREECHECK, accept anything | 32 | * if NOSUBTREECHECK, accept anything |
| @@ -251,7 +248,6 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) | |||
| 251 | 248 | ||
| 252 | fhp->fh_dentry = dentry; | 249 | fhp->fh_dentry = dentry; |
| 253 | fhp->fh_export = exp; | 250 | fhp->fh_export = exp; |
| 254 | nfsd_nr_verified++; | ||
| 255 | return 0; | 251 | return 0; |
| 256 | out: | 252 | out: |
| 257 | exp_put(exp); | 253 | exp_put(exp); |
| @@ -552,7 +548,6 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | |||
| 552 | return nfserr_opnotsupp; | 548 | return nfserr_opnotsupp; |
| 553 | } | 549 | } |
| 554 | 550 | ||
| 555 | nfsd_nr_verified++; | ||
| 556 | return 0; | 551 | return 0; |
| 557 | } | 552 | } |
| 558 | 553 | ||
| @@ -609,7 +604,6 @@ fh_put(struct svc_fh *fhp) | |||
| 609 | fhp->fh_pre_saved = 0; | 604 | fhp->fh_pre_saved = 0; |
| 610 | fhp->fh_post_saved = 0; | 605 | fhp->fh_post_saved = 0; |
| 611 | #endif | 606 | #endif |
| 612 | nfsd_nr_put++; | ||
| 613 | } | 607 | } |
| 614 | if (exp) { | 608 | if (exp) { |
| 615 | cache_put(&exp->h, &svc_export_cache); | 609 | cache_put(&exp->h, &svc_export_cache); |
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index e298e260b5f1..0eb9c820b7a6 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
| @@ -533,45 +533,179 @@ nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, | |||
| 533 | * NFSv2 Server procedures. | 533 | * NFSv2 Server procedures. |
| 534 | * Only the results of non-idempotent operations are cached. | 534 | * Only the results of non-idempotent operations are cached. |
| 535 | */ | 535 | */ |
| 536 | #define nfsd_proc_none NULL | ||
| 537 | #define nfssvc_release_none NULL | ||
| 538 | struct nfsd_void { int dummy; }; | 536 | struct nfsd_void { int dummy; }; |
| 539 | 537 | ||
| 540 | #define PROC(name, argt, rest, relt, cache, respsize) \ | ||
| 541 | { (svc_procfunc) nfsd_proc_##name, \ | ||
| 542 | (kxdrproc_t) nfssvc_decode_##argt, \ | ||
| 543 | (kxdrproc_t) nfssvc_encode_##rest, \ | ||
| 544 | (kxdrproc_t) nfssvc_release_##relt, \ | ||
| 545 | sizeof(struct nfsd_##argt), \ | ||
| 546 | sizeof(struct nfsd_##rest), \ | ||
| 547 | 0, \ | ||
| 548 | cache, \ | ||
| 549 | respsize, \ | ||
| 550 | } | ||
| 551 | |||
| 552 | #define ST 1 /* status */ | 538 | #define ST 1 /* status */ |
| 553 | #define FH 8 /* filehandle */ | 539 | #define FH 8 /* filehandle */ |
| 554 | #define AT 18 /* attributes */ | 540 | #define AT 18 /* attributes */ |
| 555 | 541 | ||
| 556 | static struct svc_procedure nfsd_procedures2[18] = { | 542 | static struct svc_procedure nfsd_procedures2[18] = { |
| 557 | PROC(null, void, void, none, RC_NOCACHE, ST), | 543 | [NFSPROC_NULL] = { |
| 558 | PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT), | 544 | .pc_func = (svc_procfunc) nfsd_proc_null, |
| 559 | PROC(setattr, sattrargs, attrstat, fhandle, RC_REPLBUFF, ST+AT), | 545 | .pc_decode = (kxdrproc_t) nfssvc_decode_void, |
| 560 | PROC(none, void, void, none, RC_NOCACHE, ST), | 546 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, |
| 561 | PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE, ST+FH+AT), | 547 | .pc_argsize = sizeof(struct nfsd_void), |
| 562 | PROC(readlink, readlinkargs, readlinkres, none, RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4), | 548 | .pc_ressize = sizeof(struct nfsd_void), |
| 563 | PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4), | 549 | .pc_cachetype = RC_NOCACHE, |
| 564 | PROC(none, void, void, none, RC_NOCACHE, ST), | 550 | .pc_xdrressize = ST, |
| 565 | PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF, ST+AT), | 551 | }, |
| 566 | PROC(create, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT), | 552 | [NFSPROC_GETATTR] = { |
| 567 | PROC(remove, diropargs, void, none, RC_REPLSTAT, ST), | 553 | .pc_func = (svc_procfunc) nfsd_proc_getattr, |
| 568 | PROC(rename, renameargs, void, none, RC_REPLSTAT, ST), | 554 | .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle, |
| 569 | PROC(link, linkargs, void, none, RC_REPLSTAT, ST), | 555 | .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, |
| 570 | PROC(symlink, symlinkargs, void, none, RC_REPLSTAT, ST), | 556 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, |
| 571 | PROC(mkdir, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT), | 557 | .pc_argsize = sizeof(struct nfsd_fhandle), |
| 572 | PROC(rmdir, diropargs, void, none, RC_REPLSTAT, ST), | 558 | .pc_ressize = sizeof(struct nfsd_attrstat), |
| 573 | PROC(readdir, readdirargs, readdirres, none, RC_NOCACHE, 0), | 559 | .pc_cachetype = RC_NOCACHE, |
| 574 | PROC(statfs, fhandle, statfsres, none, RC_NOCACHE, ST+5), | 560 | .pc_xdrressize = ST+AT, |
| 561 | }, | ||
| 562 | [NFSPROC_SETATTR] = { | ||
| 563 | .pc_func = (svc_procfunc) nfsd_proc_setattr, | ||
| 564 | .pc_decode = (kxdrproc_t) nfssvc_decode_sattrargs, | ||
| 565 | .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, | ||
| 566 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
| 567 | .pc_argsize = sizeof(struct nfsd_sattrargs), | ||
| 568 | .pc_ressize = sizeof(struct nfsd_attrstat), | ||
| 569 | .pc_cachetype = RC_REPLBUFF, | ||
| 570 | .pc_xdrressize = ST+AT, | ||
| 571 | }, | ||
| 572 | [NFSPROC_ROOT] = { | ||
| 573 | .pc_decode = (kxdrproc_t) nfssvc_decode_void, | ||
| 574 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
| 575 | .pc_argsize = sizeof(struct nfsd_void), | ||
| 576 | .pc_ressize = sizeof(struct nfsd_void), | ||
| 577 | .pc_cachetype = RC_NOCACHE, | ||
| 578 | .pc_xdrressize = ST, | ||
| 579 | }, | ||
| 580 | [NFSPROC_LOOKUP] = { | ||
| 581 | .pc_func = (svc_procfunc) nfsd_proc_lookup, | ||
| 582 | .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, | ||
| 583 | .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, | ||
| 584 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
| 585 | .pc_argsize = sizeof(struct nfsd_diropargs), | ||
| 586 | .pc_ressize = sizeof(struct nfsd_diropres), | ||
| 587 | .pc_cachetype = RC_NOCACHE, | ||
| 588 | .pc_xdrressize = ST+FH+AT, | ||
| 589 | }, | ||
| 590 | [NFSPROC_READLINK] = { | ||
| 591 | .pc_func = (svc_procfunc) nfsd_proc_readlink, | ||
| 592 | .pc_decode = (kxdrproc_t) nfssvc_decode_readlinkargs, | ||
| 593 | .pc_encode = (kxdrproc_t) nfssvc_encode_readlinkres, | ||
| 594 | .pc_argsize = sizeof(struct nfsd_readlinkargs), | ||
| 595 | .pc_ressize = sizeof(struct nfsd_readlinkres), | ||
| 596 | .pc_cachetype = RC_NOCACHE, | ||
| 597 | .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4, | ||
| 598 | }, | ||
| 599 | [NFSPROC_READ] = { | ||
| 600 | .pc_func = (svc_procfunc) nfsd_proc_read, | ||
| 601 | .pc_decode = (kxdrproc_t) nfssvc_decode_readargs, | ||
| 602 | .pc_encode = (kxdrproc_t) nfssvc_encode_readres, | ||
| 603 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
| 604 | .pc_argsize = sizeof(struct nfsd_readargs), | ||
| 605 | .pc_ressize = sizeof(struct nfsd_readres), | ||
| 606 | .pc_cachetype = RC_NOCACHE, | ||
| 607 | .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4, | ||
| 608 | }, | ||
| 609 | [NFSPROC_WRITECACHE] = { | ||
| 610 | .pc_decode = (kxdrproc_t) nfssvc_decode_void, | ||
| 611 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
| 612 | .pc_argsize = sizeof(struct nfsd_void), | ||
| 613 | .pc_ressize = sizeof(struct nfsd_void), | ||
| 614 | .pc_cachetype = RC_NOCACHE, | ||
| 615 | .pc_xdrressize = ST, | ||
| 616 | }, | ||
| 617 | [NFSPROC_WRITE] = { | ||
| 618 | .pc_func = (svc_procfunc) nfsd_proc_write, | ||
| 619 | .pc_decode = (kxdrproc_t) nfssvc_decode_writeargs, | ||
| 620 | .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, | ||
| 621 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
| 622 | .pc_argsize = sizeof(struct nfsd_writeargs), | ||
| 623 | .pc_ressize = sizeof(struct nfsd_attrstat), | ||
| 624 | .pc_cachetype = RC_REPLBUFF, | ||
| 625 | .pc_xdrressize = ST+AT, | ||
| 626 | }, | ||
| 627 | [NFSPROC_CREATE] = { | ||
| 628 | .pc_func = (svc_procfunc) nfsd_proc_create, | ||
| 629 | .pc_decode = (kxdrproc_t) nfssvc_decode_createargs, | ||
| 630 | .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, | ||
| 631 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
| 632 | .pc_argsize = sizeof(struct nfsd_createargs), | ||
| 633 | .pc_ressize = sizeof(struct nfsd_diropres), | ||
| 634 | .pc_cachetype = RC_REPLBUFF, | ||
| 635 | .pc_xdrressize = ST+FH+AT, | ||
| 636 | }, | ||
| 637 | [NFSPROC_REMOVE] = { | ||
| 638 | .pc_func = (svc_procfunc) nfsd_proc_remove, | ||
| 639 | .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, | ||
| 640 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
| 641 | .pc_argsize = sizeof(struct nfsd_diropargs), | ||
| 642 | .pc_ressize = sizeof(struct nfsd_void), | ||
| 643 | .pc_cachetype = RC_REPLSTAT, | ||
| 644 | .pc_xdrressize = ST, | ||
| 645 | }, | ||
| 646 | [NFSPROC_RENAME] = { | ||
| 647 | .pc_func = (svc_procfunc) nfsd_proc_rename, | ||
| 648 | .pc_decode = (kxdrproc_t) nfssvc_decode_renameargs, | ||
| 649 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
| 650 | .pc_argsize = sizeof(struct nfsd_renameargs), | ||
| 651 | .pc_ressize = sizeof(struct nfsd_void), | ||
| 652 | .pc_cachetype = RC_REPLSTAT, | ||
| 653 | .pc_xdrressize = ST, | ||
| 654 | }, | ||
| 655 | [NFSPROC_LINK] = { | ||
| 656 | .pc_func = (svc_procfunc) nfsd_proc_link, | ||
| 657 | .pc_decode = (kxdrproc_t) nfssvc_decode_linkargs, | ||
| 658 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
| 659 | .pc_argsize = sizeof(struct nfsd_linkargs), | ||
| 660 | .pc_ressize = sizeof(struct nfsd_void), | ||
| 661 | .pc_cachetype = RC_REPLSTAT, | ||
| 662 | .pc_xdrressize = ST, | ||
| 663 | }, | ||
| 664 | [NFSPROC_SYMLINK] = { | ||
| 665 | .pc_func = (svc_procfunc) nfsd_proc_symlink, | ||
| 666 | .pc_decode = (kxdrproc_t) nfssvc_decode_symlinkargs, | ||
| 667 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
| 668 | .pc_argsize = sizeof(struct nfsd_symlinkargs), | ||
| 669 | .pc_ressize = sizeof(struct nfsd_void), | ||
| 670 | .pc_cachetype = RC_REPLSTAT, | ||
| 671 | .pc_xdrressize = ST, | ||
| 672 | }, | ||
| 673 | [NFSPROC_MKDIR] = { | ||
| 674 | .pc_func = (svc_procfunc) nfsd_proc_mkdir, | ||
| 675 | .pc_decode = (kxdrproc_t) nfssvc_decode_createargs, | ||
| 676 | .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, | ||
| 677 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
| 678 | .pc_argsize = sizeof(struct nfsd_createargs), | ||
| 679 | .pc_ressize = sizeof(struct nfsd_diropres), | ||
| 680 | .pc_cachetype = RC_REPLBUFF, | ||
| 681 | .pc_xdrressize = ST+FH+AT, | ||
| 682 | }, | ||
| 683 | [NFSPROC_RMDIR] = { | ||
| 684 | .pc_func = (svc_procfunc) nfsd_proc_rmdir, | ||
| 685 | .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, | ||
| 686 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
| 687 | .pc_argsize = sizeof(struct nfsd_diropargs), | ||
| 688 | .pc_ressize = sizeof(struct nfsd_void), | ||
| 689 | .pc_cachetype = RC_REPLSTAT, | ||
| 690 | .pc_xdrressize = ST, | ||
| 691 | }, | ||
| 692 | [NFSPROC_READDIR] = { | ||
| 693 | .pc_func = (svc_procfunc) nfsd_proc_readdir, | ||
| 694 | .pc_decode = (kxdrproc_t) nfssvc_decode_readdirargs, | ||
| 695 | .pc_encode = (kxdrproc_t) nfssvc_encode_readdirres, | ||
| 696 | .pc_argsize = sizeof(struct nfsd_readdirargs), | ||
| 697 | .pc_ressize = sizeof(struct nfsd_readdirres), | ||
| 698 | .pc_cachetype = RC_NOCACHE, | ||
| 699 | }, | ||
| 700 | [NFSPROC_STATFS] = { | ||
| 701 | .pc_func = (svc_procfunc) nfsd_proc_statfs, | ||
| 702 | .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle, | ||
| 703 | .pc_encode = (kxdrproc_t) nfssvc_encode_statfsres, | ||
| 704 | .pc_argsize = sizeof(struct nfsd_fhandle), | ||
| 705 | .pc_ressize = sizeof(struct nfsd_statfsres), | ||
| 706 | .pc_cachetype = RC_NOCACHE, | ||
| 707 | .pc_xdrressize = ST+5, | ||
| 708 | }, | ||
| 575 | }; | 709 | }; |
| 576 | 710 | ||
| 577 | 711 | ||
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index cbba4a935786..d4c9884cd54b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
| @@ -390,12 +390,14 @@ nfsd_svc(unsigned short port, int nrservs) | |||
| 390 | 390 | ||
| 391 | mutex_lock(&nfsd_mutex); | 391 | mutex_lock(&nfsd_mutex); |
| 392 | dprintk("nfsd: creating service\n"); | 392 | dprintk("nfsd: creating service\n"); |
| 393 | error = -EINVAL; | ||
| 394 | if (nrservs <= 0) | 393 | if (nrservs <= 0) |
| 395 | nrservs = 0; | 394 | nrservs = 0; |
| 396 | if (nrservs > NFSD_MAXSERVS) | 395 | if (nrservs > NFSD_MAXSERVS) |
| 397 | nrservs = NFSD_MAXSERVS; | 396 | nrservs = NFSD_MAXSERVS; |
| 398 | 397 | error = 0; | |
| 398 | if (nrservs == 0 && nfsd_serv == NULL) | ||
| 399 | goto out; | ||
| 400 | |||
| 399 | /* Readahead param cache - will no-op if it already exists */ | 401 | /* Readahead param cache - will no-op if it already exists */ |
| 400 | error = nfsd_racache_init(2*nrservs); | 402 | error = nfsd_racache_init(2*nrservs); |
| 401 | if (error<0) | 403 | if (error<0) |
| @@ -413,6 +415,12 @@ nfsd_svc(unsigned short port, int nrservs) | |||
| 413 | goto failure; | 415 | goto failure; |
| 414 | 416 | ||
| 415 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); | 417 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); |
| 418 | if (error == 0) | ||
| 419 | /* We are holding a reference to nfsd_serv which | ||
| 420 | * we don't want to count in the return value, | ||
| 421 | * so subtract 1 | ||
| 422 | */ | ||
| 423 | error = nfsd_serv->sv_nrthreads - 1; | ||
| 416 | failure: | 424 | failure: |
| 417 | svc_destroy(nfsd_serv); /* Release server */ | 425 | svc_destroy(nfsd_serv); /* Release server */ |
| 418 | out: | 426 | out: |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 99f835753596..4145083dcf88 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -966,6 +966,43 @@ static void kill_suid(struct dentry *dentry) | |||
| 966 | mutex_unlock(&dentry->d_inode->i_mutex); | 966 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 967 | } | 967 | } |
| 968 | 968 | ||
| 969 | /* | ||
| 970 | * Gathered writes: If another process is currently writing to the file, | ||
| 971 | * there's a high chance this is another nfsd (triggered by a bulk write | ||
| 972 | * from a client's biod). Rather than syncing the file with each write | ||
| 973 | * request, we sleep for 10 msec. | ||
| 974 | * | ||
| 975 | * I don't know if this roughly approximates C. Juszak's idea of | ||
| 976 | * gathered writes, but it's a nice and simple solution (IMHO), and it | ||
| 977 | * seems to work:-) | ||
| 978 | * | ||
| 979 | * Note: we do this only in the NFSv2 case, since v3 and higher have a | ||
| 980 | * better tool (separate unstable writes and commits) for solving this | ||
| 981 | * problem. | ||
| 982 | */ | ||
| 983 | static int wait_for_concurrent_writes(struct file *file) | ||
| 984 | { | ||
| 985 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 986 | static ino_t last_ino; | ||
| 987 | static dev_t last_dev; | ||
| 988 | int err = 0; | ||
| 989 | |||
| 990 | if (atomic_read(&inode->i_writecount) > 1 | ||
| 991 | || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) { | ||
| 992 | dprintk("nfsd: write defer %d\n", task_pid_nr(current)); | ||
| 993 | msleep(10); | ||
| 994 | dprintk("nfsd: write resume %d\n", task_pid_nr(current)); | ||
| 995 | } | ||
| 996 | |||
| 997 | if (inode->i_state & I_DIRTY) { | ||
| 998 | dprintk("nfsd: write sync %d\n", task_pid_nr(current)); | ||
| 999 | err = nfsd_sync(file); | ||
| 1000 | } | ||
| 1001 | last_ino = inode->i_ino; | ||
| 1002 | last_dev = inode->i_sb->s_dev; | ||
| 1003 | return err; | ||
| 1004 | } | ||
| 1005 | |||
| 969 | static __be32 | 1006 | static __be32 |
| 970 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 1007 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
| 971 | loff_t offset, struct kvec *vec, int vlen, | 1008 | loff_t offset, struct kvec *vec, int vlen, |
| @@ -978,6 +1015,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
| 978 | __be32 err = 0; | 1015 | __be32 err = 0; |
| 979 | int host_err; | 1016 | int host_err; |
| 980 | int stable = *stablep; | 1017 | int stable = *stablep; |
| 1018 | int use_wgather; | ||
| 981 | 1019 | ||
| 982 | #ifdef MSNFS | 1020 | #ifdef MSNFS |
| 983 | err = nfserr_perm; | 1021 | err = nfserr_perm; |
| @@ -996,9 +1034,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
| 996 | * - the sync export option has been set, or | 1034 | * - the sync export option has been set, or |
| 997 | * - the client requested O_SYNC behavior (NFSv3 feature). | 1035 | * - the client requested O_SYNC behavior (NFSv3 feature). |
| 998 | * - The file system doesn't support fsync(). | 1036 | * - The file system doesn't support fsync(). |
| 999 | * When gathered writes have been configured for this volume, | 1037 | * When NFSv2 gathered writes have been configured for this volume, |
| 1000 | * flushing the data to disk is handled separately below. | 1038 | * flushing the data to disk is handled separately below. |
| 1001 | */ | 1039 | */ |
| 1040 | use_wgather = (rqstp->rq_vers == 2) && EX_WGATHER(exp); | ||
| 1002 | 1041 | ||
| 1003 | if (!file->f_op->fsync) {/* COMMIT3 cannot work */ | 1042 | if (!file->f_op->fsync) {/* COMMIT3 cannot work */ |
| 1004 | stable = 2; | 1043 | stable = 2; |
| @@ -1007,7 +1046,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
| 1007 | 1046 | ||
| 1008 | if (!EX_ISSYNC(exp)) | 1047 | if (!EX_ISSYNC(exp)) |
| 1009 | stable = 0; | 1048 | stable = 0; |
| 1010 | if (stable && !EX_WGATHER(exp)) { | 1049 | if (stable && !use_wgather) { |
| 1011 | spin_lock(&file->f_lock); | 1050 | spin_lock(&file->f_lock); |
| 1012 | file->f_flags |= O_SYNC; | 1051 | file->f_flags |= O_SYNC; |
| 1013 | spin_unlock(&file->f_lock); | 1052 | spin_unlock(&file->f_lock); |
| @@ -1017,52 +1056,20 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
| 1017 | oldfs = get_fs(); set_fs(KERNEL_DS); | 1056 | oldfs = get_fs(); set_fs(KERNEL_DS); |
| 1018 | host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); | 1057 | host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); |
| 1019 | set_fs(oldfs); | 1058 | set_fs(oldfs); |
| 1020 | if (host_err >= 0) { | 1059 | if (host_err < 0) |
| 1021 | *cnt = host_err; | 1060 | goto out_nfserr; |
| 1022 | nfsdstats.io_write += host_err; | 1061 | *cnt = host_err; |
| 1023 | fsnotify_modify(file->f_path.dentry); | 1062 | nfsdstats.io_write += host_err; |
| 1024 | } | 1063 | fsnotify_modify(file->f_path.dentry); |
| 1025 | 1064 | ||
| 1026 | /* clear setuid/setgid flag after write */ | 1065 | /* clear setuid/setgid flag after write */ |
| 1027 | if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) | 1066 | if (inode->i_mode & (S_ISUID | S_ISGID)) |
| 1028 | kill_suid(dentry); | 1067 | kill_suid(dentry); |
| 1029 | 1068 | ||
| 1030 | if (host_err >= 0 && stable) { | 1069 | if (stable && use_wgather) |
| 1031 | static ino_t last_ino; | 1070 | host_err = wait_for_concurrent_writes(file); |
| 1032 | static dev_t last_dev; | ||
| 1033 | |||
| 1034 | /* | ||
| 1035 | * Gathered writes: If another process is currently | ||
| 1036 | * writing to the file, there's a high chance | ||
| 1037 | * this is another nfsd (triggered by a bulk write | ||
| 1038 | * from a client's biod). Rather than syncing the | ||
| 1039 | * file with each write request, we sleep for 10 msec. | ||
| 1040 | * | ||
| 1041 | * I don't know if this roughly approximates | ||
| 1042 | * C. Juszak's idea of gathered writes, but it's a | ||
| 1043 | * nice and simple solution (IMHO), and it seems to | ||
| 1044 | * work:-) | ||
| 1045 | */ | ||
| 1046 | if (EX_WGATHER(exp)) { | ||
| 1047 | if (atomic_read(&inode->i_writecount) > 1 | ||
| 1048 | || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) { | ||
| 1049 | dprintk("nfsd: write defer %d\n", task_pid_nr(current)); | ||
| 1050 | msleep(10); | ||
| 1051 | dprintk("nfsd: write resume %d\n", task_pid_nr(current)); | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | if (inode->i_state & I_DIRTY) { | ||
| 1055 | dprintk("nfsd: write sync %d\n", task_pid_nr(current)); | ||
| 1056 | host_err=nfsd_sync(file); | ||
| 1057 | } | ||
| 1058 | #if 0 | ||
| 1059 | wake_up(&inode->i_wait); | ||
| 1060 | #endif | ||
| 1061 | } | ||
| 1062 | last_ino = inode->i_ino; | ||
| 1063 | last_dev = inode->i_sb->s_dev; | ||
| 1064 | } | ||
| 1065 | 1071 | ||
| 1072 | out_nfserr: | ||
| 1066 | dprintk("nfsd: write complete host_err=%d\n", host_err); | 1073 | dprintk("nfsd: write complete host_err=%d\n", host_err); |
| 1067 | if (host_err >= 0) | 1074 | if (host_err >= 0) |
| 1068 | err = 0; | 1075 | err = 0; |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 74a57938c880..1ff5e4e01952 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -1107,6 +1107,7 @@ extern void locks_copy_lock(struct file_lock *, struct file_lock *); | |||
| 1107 | extern void __locks_copy_lock(struct file_lock *, const struct file_lock *); | 1107 | extern void __locks_copy_lock(struct file_lock *, const struct file_lock *); |
| 1108 | extern void locks_remove_posix(struct file *, fl_owner_t); | 1108 | extern void locks_remove_posix(struct file *, fl_owner_t); |
| 1109 | extern void locks_remove_flock(struct file *); | 1109 | extern void locks_remove_flock(struct file *); |
| 1110 | extern void locks_release_private(struct file_lock *); | ||
| 1110 | extern void posix_test_lock(struct file *, struct file_lock *); | 1111 | extern void posix_test_lock(struct file *, struct file_lock *); |
| 1111 | extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); | 1112 | extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); |
| 1112 | extern int posix_lock_file_wait(struct file *, struct file_lock *); | 1113 | extern int posix_lock_file_wait(struct file *, struct file_lock *); |
diff --git a/include/linux/nfsd/cache.h b/include/linux/nfsd/cache.h index 5bccaab81056..3a3f58934f5e 100644 --- a/include/linux/nfsd/cache.h +++ b/include/linux/nfsd/cache.h | |||
| @@ -14,8 +14,7 @@ | |||
| 14 | #include <linux/uio.h> | 14 | #include <linux/uio.h> |
| 15 | 15 | ||
| 16 | /* | 16 | /* |
| 17 | * Representation of a reply cache entry. The first two members *must* | 17 | * Representation of a reply cache entry. |
| 18 | * be hash_next and hash_prev. | ||
| 19 | */ | 18 | */ |
| 20 | struct svc_cacherep { | 19 | struct svc_cacherep { |
| 21 | struct hlist_node c_hash; | 20 | struct hlist_node c_hash; |
diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index afa19016c4a8..8f641c908450 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h | |||
| @@ -151,9 +151,15 @@ typedef struct svc_fh { | |||
| 151 | __u64 fh_pre_size; /* size before operation */ | 151 | __u64 fh_pre_size; /* size before operation */ |
| 152 | struct timespec fh_pre_mtime; /* mtime before oper */ | 152 | struct timespec fh_pre_mtime; /* mtime before oper */ |
| 153 | struct timespec fh_pre_ctime; /* ctime before oper */ | 153 | struct timespec fh_pre_ctime; /* ctime before oper */ |
| 154 | /* | ||
| 155 | * pre-op nfsv4 change attr: note must check IS_I_VERSION(inode) | ||
| 156 | * to find out if it is valid. | ||
| 157 | */ | ||
| 158 | u64 fh_pre_change; | ||
| 154 | 159 | ||
| 155 | /* Post-op attributes saved in fh_unlock */ | 160 | /* Post-op attributes saved in fh_unlock */ |
| 156 | struct kstat fh_post_attr; /* full attrs after operation */ | 161 | struct kstat fh_post_attr; /* full attrs after operation */ |
| 162 | u64 fh_post_change; /* nfsv4 change; see above */ | ||
| 157 | #endif /* CONFIG_NFSD_V3 */ | 163 | #endif /* CONFIG_NFSD_V3 */ |
| 158 | 164 | ||
| 159 | } svc_fh; | 165 | } svc_fh; |
| @@ -298,6 +304,7 @@ fill_pre_wcc(struct svc_fh *fhp) | |||
| 298 | fhp->fh_pre_mtime = inode->i_mtime; | 304 | fhp->fh_pre_mtime = inode->i_mtime; |
| 299 | fhp->fh_pre_ctime = inode->i_ctime; | 305 | fhp->fh_pre_ctime = inode->i_ctime; |
| 300 | fhp->fh_pre_size = inode->i_size; | 306 | fhp->fh_pre_size = inode->i_size; |
| 307 | fhp->fh_pre_change = inode->i_version; | ||
| 301 | fhp->fh_pre_saved = 1; | 308 | fhp->fh_pre_saved = 1; |
| 302 | } | 309 | } |
| 303 | } | 310 | } |
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 7ef4b7ad1214..57ab2ed08459 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h | |||
| @@ -60,15 +60,6 @@ typedef struct { | |||
| 60 | #define si_stateownerid si_opaque.so_stateownerid | 60 | #define si_stateownerid si_opaque.so_stateownerid |
| 61 | #define si_fileid si_opaque.so_fileid | 61 | #define si_fileid si_opaque.so_fileid |
| 62 | 62 | ||
| 63 | |||
| 64 | struct nfs4_cb_recall { | ||
| 65 | u32 cbr_ident; | ||
| 66 | int cbr_trunc; | ||
| 67 | stateid_t cbr_stateid; | ||
| 68 | struct knfsd_fh cbr_fh; | ||
| 69 | struct nfs4_delegation *cbr_dp; | ||
| 70 | }; | ||
| 71 | |||
| 72 | struct nfs4_delegation { | 63 | struct nfs4_delegation { |
| 73 | struct list_head dl_perfile; | 64 | struct list_head dl_perfile; |
| 74 | struct list_head dl_perclnt; | 65 | struct list_head dl_perclnt; |
| @@ -80,22 +71,25 @@ struct nfs4_delegation { | |||
| 80 | struct file *dl_vfs_file; | 71 | struct file *dl_vfs_file; |
| 81 | u32 dl_type; | 72 | u32 dl_type; |
| 82 | time_t dl_time; | 73 | time_t dl_time; |
| 83 | struct nfs4_cb_recall dl_recall; | 74 | /* For recall: */ |
| 75 | u32 dl_ident; | ||
| 76 | stateid_t dl_stateid; | ||
| 77 | struct knfsd_fh dl_fh; | ||
| 78 | int dl_retries; | ||
| 84 | }; | 79 | }; |
| 85 | 80 | ||
| 86 | #define dl_stateid dl_recall.cbr_stateid | ||
| 87 | #define dl_fh dl_recall.cbr_fh | ||
| 88 | |||
| 89 | /* client delegation callback info */ | 81 | /* client delegation callback info */ |
| 90 | struct nfs4_callback { | 82 | struct nfs4_cb_conn { |
| 91 | /* SETCLIENTID info */ | 83 | /* SETCLIENTID info */ |
| 92 | u32 cb_addr; | 84 | u32 cb_addr; |
| 93 | unsigned short cb_port; | 85 | unsigned short cb_port; |
| 94 | u32 cb_prog; | 86 | u32 cb_prog; |
| 95 | u32 cb_ident; | 87 | u32 cb_minorversion; |
| 88 | u32 cb_ident; /* minorversion 0 only */ | ||
| 96 | /* RPC client info */ | 89 | /* RPC client info */ |
| 97 | atomic_t cb_set; /* successful CB_NULL call */ | 90 | atomic_t cb_set; /* successful CB_NULL call */ |
| 98 | struct rpc_clnt * cb_client; | 91 | struct rpc_clnt * cb_client; |
| 92 | struct rpc_cred * cb_cred; | ||
| 99 | }; | 93 | }; |
| 100 | 94 | ||
| 101 | /* Maximum number of slots per session. 128 is useful for long haul TCP */ | 95 | /* Maximum number of slots per session. 128 is useful for long haul TCP */ |
| @@ -121,6 +115,17 @@ struct nfsd4_slot { | |||
| 121 | struct nfsd4_cache_entry sl_cache_entry; | 115 | struct nfsd4_cache_entry sl_cache_entry; |
| 122 | }; | 116 | }; |
| 123 | 117 | ||
| 118 | struct nfsd4_channel_attrs { | ||
| 119 | u32 headerpadsz; | ||
| 120 | u32 maxreq_sz; | ||
| 121 | u32 maxresp_sz; | ||
| 122 | u32 maxresp_cached; | ||
| 123 | u32 maxops; | ||
| 124 | u32 maxreqs; | ||
| 125 | u32 nr_rdma_attrs; | ||
| 126 | u32 rdma_attrs; | ||
| 127 | }; | ||
| 128 | |||
| 124 | struct nfsd4_session { | 129 | struct nfsd4_session { |
| 125 | struct kref se_ref; | 130 | struct kref se_ref; |
| 126 | struct list_head se_hash; /* hash by sessionid */ | 131 | struct list_head se_hash; /* hash by sessionid */ |
| @@ -128,11 +133,8 @@ struct nfsd4_session { | |||
| 128 | u32 se_flags; | 133 | u32 se_flags; |
| 129 | struct nfs4_client *se_client; /* for expire_client */ | 134 | struct nfs4_client *se_client; /* for expire_client */ |
| 130 | struct nfs4_sessionid se_sessionid; | 135 | struct nfs4_sessionid se_sessionid; |
| 131 | u32 se_fmaxreq_sz; | 136 | struct nfsd4_channel_attrs se_fchannel; |
| 132 | u32 se_fmaxresp_sz; | 137 | struct nfsd4_channel_attrs se_bchannel; |
| 133 | u32 se_fmaxresp_cached; | ||
| 134 | u32 se_fmaxops; | ||
| 135 | u32 se_fnumslots; | ||
| 136 | struct nfsd4_slot se_slots[]; /* forward channel slots */ | 138 | struct nfsd4_slot se_slots[]; /* forward channel slots */ |
| 137 | }; | 139 | }; |
| 138 | 140 | ||
| @@ -184,7 +186,7 @@ struct nfs4_client { | |||
| 184 | struct svc_cred cl_cred; /* setclientid principal */ | 186 | struct svc_cred cl_cred; /* setclientid principal */ |
| 185 | clientid_t cl_clientid; /* generated by server */ | 187 | clientid_t cl_clientid; /* generated by server */ |
| 186 | nfs4_verifier cl_confirm; /* generated by server */ | 188 | nfs4_verifier cl_confirm; /* generated by server */ |
| 187 | struct nfs4_callback cl_callback; /* callback info */ | 189 | struct nfs4_cb_conn cl_cb_conn; /* callback info */ |
| 188 | atomic_t cl_count; /* ref count */ | 190 | atomic_t cl_count; /* ref count */ |
| 189 | u32 cl_firststate; /* recovery dir creation */ | 191 | u32 cl_firststate; /* recovery dir creation */ |
| 190 | 192 | ||
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index f80d6013fdc3..2bacf7535069 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h | |||
| @@ -64,10 +64,13 @@ static inline bool nfsd4_has_session(struct nfsd4_compound_state *cs) | |||
| 64 | 64 | ||
| 65 | struct nfsd4_change_info { | 65 | struct nfsd4_change_info { |
| 66 | u32 atomic; | 66 | u32 atomic; |
| 67 | bool change_supported; | ||
| 67 | u32 before_ctime_sec; | 68 | u32 before_ctime_sec; |
| 68 | u32 before_ctime_nsec; | 69 | u32 before_ctime_nsec; |
| 70 | u64 before_change; | ||
| 69 | u32 after_ctime_sec; | 71 | u32 after_ctime_sec; |
| 70 | u32 after_ctime_nsec; | 72 | u32 after_ctime_nsec; |
| 73 | u64 after_change; | ||
| 71 | }; | 74 | }; |
| 72 | 75 | ||
| 73 | struct nfsd4_access { | 76 | struct nfsd4_access { |
| @@ -363,17 +366,6 @@ struct nfsd4_exchange_id { | |||
| 363 | int spa_how; | 366 | int spa_how; |
| 364 | }; | 367 | }; |
| 365 | 368 | ||
| 366 | struct nfsd4_channel_attrs { | ||
| 367 | u32 headerpadsz; | ||
| 368 | u32 maxreq_sz; | ||
| 369 | u32 maxresp_sz; | ||
| 370 | u32 maxresp_cached; | ||
| 371 | u32 maxops; | ||
| 372 | u32 maxreqs; | ||
| 373 | u32 nr_rdma_attrs; | ||
| 374 | u32 rdma_attrs; | ||
| 375 | }; | ||
| 376 | |||
| 377 | struct nfsd4_create_session { | 369 | struct nfsd4_create_session { |
| 378 | clientid_t clientid; | 370 | clientid_t clientid; |
| 379 | struct nfs4_sessionid sessionid; | 371 | struct nfs4_sessionid sessionid; |
| @@ -503,10 +495,16 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) | |||
| 503 | { | 495 | { |
| 504 | BUG_ON(!fhp->fh_pre_saved || !fhp->fh_post_saved); | 496 | BUG_ON(!fhp->fh_pre_saved || !fhp->fh_post_saved); |
| 505 | cinfo->atomic = 1; | 497 | cinfo->atomic = 1; |
| 506 | cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; | 498 | cinfo->change_supported = IS_I_VERSION(fhp->fh_dentry->d_inode); |
| 507 | cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; | 499 | if (cinfo->change_supported) { |
| 508 | cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; | 500 | cinfo->before_change = fhp->fh_pre_change; |
| 509 | cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; | 501 | cinfo->after_change = fhp->fh_post_change; |
| 502 | } else { | ||
| 503 | cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; | ||
| 504 | cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; | ||
| 505 | cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; | ||
| 506 | cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; | ||
| 507 | } | ||
| 510 | } | 508 | } |
| 511 | 509 | ||
| 512 | int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *); | 510 | int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *); |
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 0d9cb6ef28b0..2223ae0b5ed5 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h | |||
| @@ -83,7 +83,7 @@ int svc_port_is_privileged(struct sockaddr *sin); | |||
| 83 | int svc_print_xprts(char *buf, int maxlen); | 83 | int svc_print_xprts(char *buf, int maxlen); |
| 84 | struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, | 84 | struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, |
| 85 | const sa_family_t af, const unsigned short port); | 85 | const sa_family_t af, const unsigned short port); |
| 86 | int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen); | 86 | int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen); |
| 87 | 87 | ||
| 88 | static inline void svc_xprt_get(struct svc_xprt *xprt) | 88 | static inline void svc_xprt_get(struct svc_xprt *xprt) |
| 89 | { | 89 | { |
| @@ -118,7 +118,7 @@ static inline unsigned short svc_addr_port(const struct sockaddr *sa) | |||
| 118 | return 0; | 118 | return 0; |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | static inline size_t svc_addr_len(struct sockaddr *sa) | 121 | static inline size_t svc_addr_len(const struct sockaddr *sa) |
| 122 | { | 122 | { |
| 123 | switch (sa->sa_family) { | 123 | switch (sa->sa_family) { |
| 124 | case AF_INET: | 124 | case AF_INET: |
| @@ -126,7 +126,8 @@ static inline size_t svc_addr_len(struct sockaddr *sa) | |||
| 126 | case AF_INET6: | 126 | case AF_INET6: |
| 127 | return sizeof(struct sockaddr_in6); | 127 | return sizeof(struct sockaddr_in6); |
| 128 | } | 128 | } |
| 129 | return -EAFNOSUPPORT; | 129 | |
| 130 | return 0; | ||
| 130 | } | 131 | } |
| 131 | 132 | ||
| 132 | static inline unsigned short svc_xprt_local_port(const struct svc_xprt *xprt) | 133 | static inline unsigned short svc_xprt_local_port(const struct svc_xprt *xprt) |
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 6bb1ec4ae310..04dba23c59f2 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h | |||
| @@ -38,8 +38,11 @@ int svc_recv(struct svc_rqst *, long); | |||
| 38 | int svc_send(struct svc_rqst *); | 38 | int svc_send(struct svc_rqst *); |
| 39 | void svc_drop(struct svc_rqst *); | 39 | void svc_drop(struct svc_rqst *); |
| 40 | void svc_sock_update_bufs(struct svc_serv *serv); | 40 | void svc_sock_update_bufs(struct svc_serv *serv); |
| 41 | int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose); | 41 | int svc_sock_names(struct svc_serv *serv, char *buf, |
| 42 | int svc_addsock(struct svc_serv *serv, int fd, char *name_return); | 42 | const size_t buflen, |
| 43 | const char *toclose); | ||
| 44 | int svc_addsock(struct svc_serv *serv, const int fd, | ||
| 45 | char *name_return, const size_t len); | ||
| 43 | void svc_init_xprt_sock(void); | 46 | void svc_init_xprt_sock(void); |
| 44 | void svc_cleanup_xprt_sock(void); | 47 | void svc_cleanup_xprt_sock(void); |
| 45 | struct svc_xprt *svc_sock_create(struct svc_serv *serv, int prot); | 48 | struct svc_xprt *svc_sock_create(struct svc_serv *serv, int prot); |
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 20029a79a5de..ff0c23053d2f 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
| @@ -488,7 +488,7 @@ static void do_cache_clean(struct work_struct *work) | |||
| 488 | { | 488 | { |
| 489 | int delay = 5; | 489 | int delay = 5; |
| 490 | if (cache_clean() == -1) | 490 | if (cache_clean() == -1) |
| 491 | delay = 30*HZ; | 491 | delay = round_jiffies_relative(30*HZ); |
| 492 | 492 | ||
| 493 | if (list_empty(&cache_list)) | 493 | if (list_empty(&cache_list)) |
| 494 | delay = 0; | 494 | delay = 0; |
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index c200d92e57e4..6f33d33cc064 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <net/sock.h> | 11 | #include <net/sock.h> |
| 12 | #include <linux/sunrpc/stats.h> | 12 | #include <linux/sunrpc/stats.h> |
| 13 | #include <linux/sunrpc/svc_xprt.h> | 13 | #include <linux/sunrpc/svc_xprt.h> |
| 14 | #include <linux/sunrpc/svcsock.h> | ||
| 14 | 15 | ||
| 15 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT | 16 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT |
| 16 | 17 | ||
| @@ -1097,36 +1098,58 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, | |||
| 1097 | } | 1098 | } |
| 1098 | EXPORT_SYMBOL_GPL(svc_find_xprt); | 1099 | EXPORT_SYMBOL_GPL(svc_find_xprt); |
| 1099 | 1100 | ||
| 1100 | /* | 1101 | static int svc_one_xprt_name(const struct svc_xprt *xprt, |
| 1101 | * Format a buffer with a list of the active transports. A zero for | 1102 | char *pos, int remaining) |
| 1102 | * the buflen parameter disables target buffer overflow checking. | 1103 | { |
| 1104 | int len; | ||
| 1105 | |||
| 1106 | len = snprintf(pos, remaining, "%s %u\n", | ||
| 1107 | xprt->xpt_class->xcl_name, | ||
| 1108 | svc_xprt_local_port(xprt)); | ||
| 1109 | if (len >= remaining) | ||
| 1110 | return -ENAMETOOLONG; | ||
| 1111 | return len; | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | /** | ||
| 1115 | * svc_xprt_names - format a buffer with a list of transport names | ||
| 1116 | * @serv: pointer to an RPC service | ||
| 1117 | * @buf: pointer to a buffer to be filled in | ||
| 1118 | * @buflen: length of buffer to be filled in | ||
| 1119 | * | ||
| 1120 | * Fills in @buf with a string containing a list of transport names, | ||
| 1121 | * each name terminated with '\n'. | ||
| 1122 | * | ||
| 1123 | * Returns positive length of the filled-in string on success; otherwise | ||
| 1124 | * a negative errno value is returned if an error occurs. | ||
| 1103 | */ | 1125 | */ |
| 1104 | int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen) | 1126 | int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen) |
| 1105 | { | 1127 | { |
| 1106 | struct svc_xprt *xprt; | 1128 | struct svc_xprt *xprt; |
| 1107 | char xprt_str[64]; | 1129 | int len, totlen; |
| 1108 | int totlen = 0; | 1130 | char *pos; |
| 1109 | int len; | ||
| 1110 | 1131 | ||
| 1111 | /* Sanity check args */ | 1132 | /* Sanity check args */ |
| 1112 | if (!serv) | 1133 | if (!serv) |
| 1113 | return 0; | 1134 | return 0; |
| 1114 | 1135 | ||
| 1115 | spin_lock_bh(&serv->sv_lock); | 1136 | spin_lock_bh(&serv->sv_lock); |
| 1137 | |||
| 1138 | pos = buf; | ||
| 1139 | totlen = 0; | ||
| 1116 | list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) { | 1140 | list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) { |
| 1117 | len = snprintf(xprt_str, sizeof(xprt_str), | 1141 | len = svc_one_xprt_name(xprt, pos, buflen - totlen); |
| 1118 | "%s %d\n", xprt->xpt_class->xcl_name, | 1142 | if (len < 0) { |
| 1119 | svc_xprt_local_port(xprt)); | 1143 | *buf = '\0'; |
| 1120 | /* If the string was truncated, replace with error string */ | 1144 | totlen = len; |
| 1121 | if (len >= sizeof(xprt_str)) | 1145 | } |
| 1122 | strcpy(xprt_str, "name-too-long\n"); | 1146 | if (len <= 0) |
| 1123 | /* Don't overflow buffer */ | ||
| 1124 | len = strlen(xprt_str); | ||
| 1125 | if (buflen && (len + totlen >= buflen)) | ||
| 1126 | break; | 1147 | break; |
| 1127 | strcpy(buf+totlen, xprt_str); | 1148 | |
| 1149 | pos += len; | ||
| 1128 | totlen += len; | 1150 | totlen += len; |
| 1129 | } | 1151 | } |
| 1152 | |||
| 1130 | spin_unlock_bh(&serv->sv_lock); | 1153 | spin_unlock_bh(&serv->sv_lock); |
| 1131 | return totlen; | 1154 | return totlen; |
| 1132 | } | 1155 | } |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index a2a03e500533..23128ee191ae 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
| @@ -240,42 +240,76 @@ out: | |||
| 240 | /* | 240 | /* |
| 241 | * Report socket names for nfsdfs | 241 | * Report socket names for nfsdfs |
| 242 | */ | 242 | */ |
| 243 | static int one_sock_name(char *buf, struct svc_sock *svsk) | 243 | static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining) |
| 244 | { | 244 | { |
| 245 | const struct sock *sk = svsk->sk_sk; | ||
| 246 | const char *proto_name = sk->sk_protocol == IPPROTO_UDP ? | ||
| 247 | "udp" : "tcp"; | ||
| 245 | int len; | 248 | int len; |
| 246 | 249 | ||
| 247 | switch(svsk->sk_sk->sk_family) { | 250 | switch (sk->sk_family) { |
| 248 | case AF_INET: | 251 | case PF_INET: |
| 249 | len = sprintf(buf, "ipv4 %s %pI4 %d\n", | 252 | len = snprintf(buf, remaining, "ipv4 %s %pI4 %d\n", |
| 250 | svsk->sk_sk->sk_protocol == IPPROTO_UDP ? | 253 | proto_name, |
| 251 | "udp" : "tcp", | 254 | &inet_sk(sk)->rcv_saddr, |
| 252 | &inet_sk(svsk->sk_sk)->rcv_saddr, | 255 | inet_sk(sk)->num); |
| 253 | inet_sk(svsk->sk_sk)->num); | 256 | break; |
| 257 | case PF_INET6: | ||
| 258 | len = snprintf(buf, remaining, "ipv6 %s %pI6 %d\n", | ||
| 259 | proto_name, | ||
| 260 | &inet6_sk(sk)->rcv_saddr, | ||
| 261 | inet_sk(sk)->num); | ||
| 254 | break; | 262 | break; |
| 255 | default: | 263 | default: |
| 256 | len = sprintf(buf, "*unknown-%d*\n", | 264 | len = snprintf(buf, remaining, "*unknown-%d*\n", |
| 257 | svsk->sk_sk->sk_family); | 265 | sk->sk_family); |
| 266 | } | ||
| 267 | |||
| 268 | if (len >= remaining) { | ||
| 269 | *buf = '\0'; | ||
| 270 | return -ENAMETOOLONG; | ||
| 258 | } | 271 | } |
| 259 | return len; | 272 | return len; |
| 260 | } | 273 | } |
| 261 | 274 | ||
| 262 | int | 275 | /** |
| 263 | svc_sock_names(char *buf, struct svc_serv *serv, char *toclose) | 276 | * svc_sock_names - construct a list of listener names in a string |
| 277 | * @serv: pointer to RPC service | ||
| 278 | * @buf: pointer to a buffer to fill in with socket names | ||
| 279 | * @buflen: size of the buffer to be filled | ||
| 280 | * @toclose: pointer to '\0'-terminated C string containing the name | ||
| 281 | * of a listener to be closed | ||
| 282 | * | ||
| 283 | * Fills in @buf with a '\n'-separated list of names of listener | ||
| 284 | * sockets. If @toclose is not NULL, the socket named by @toclose | ||
| 285 | * is closed, and is not included in the output list. | ||
| 286 | * | ||
| 287 | * Returns positive length of the socket name string, or a negative | ||
| 288 | * errno value on error. | ||
| 289 | */ | ||
| 290 | int svc_sock_names(struct svc_serv *serv, char *buf, const size_t buflen, | ||
| 291 | const char *toclose) | ||
| 264 | { | 292 | { |
| 265 | struct svc_sock *svsk, *closesk = NULL; | 293 | struct svc_sock *svsk, *closesk = NULL; |
| 266 | int len = 0; | 294 | int len = 0; |
| 267 | 295 | ||
| 268 | if (!serv) | 296 | if (!serv) |
| 269 | return 0; | 297 | return 0; |
| 298 | |||
| 270 | spin_lock_bh(&serv->sv_lock); | 299 | spin_lock_bh(&serv->sv_lock); |
| 271 | list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) { | 300 | list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) { |
| 272 | int onelen = one_sock_name(buf+len, svsk); | 301 | int onelen = svc_one_sock_name(svsk, buf + len, buflen - len); |
| 273 | if (toclose && strcmp(toclose, buf+len) == 0) | 302 | if (onelen < 0) { |
| 303 | len = onelen; | ||
| 304 | break; | ||
| 305 | } | ||
| 306 | if (toclose && strcmp(toclose, buf + len) == 0) | ||
| 274 | closesk = svsk; | 307 | closesk = svsk; |
| 275 | else | 308 | else |
| 276 | len += onelen; | 309 | len += onelen; |
| 277 | } | 310 | } |
| 278 | spin_unlock_bh(&serv->sv_lock); | 311 | spin_unlock_bh(&serv->sv_lock); |
| 312 | |||
| 279 | if (closesk) | 313 | if (closesk) |
| 280 | /* Should unregister with portmap, but you cannot | 314 | /* Should unregister with portmap, but you cannot |
| 281 | * unregister just one protocol... | 315 | * unregister just one protocol... |
| @@ -346,6 +380,7 @@ static void svc_sock_setbufsize(struct socket *sock, unsigned int snd, | |||
| 346 | sock->sk->sk_sndbuf = snd * 2; | 380 | sock->sk->sk_sndbuf = snd * 2; |
| 347 | sock->sk->sk_rcvbuf = rcv * 2; | 381 | sock->sk->sk_rcvbuf = rcv * 2; |
| 348 | sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK; | 382 | sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK; |
| 383 | sock->sk->sk_write_space(sock->sk); | ||
| 349 | release_sock(sock->sk); | 384 | release_sock(sock->sk); |
| 350 | #endif | 385 | #endif |
| 351 | } | 386 | } |
| @@ -387,6 +422,15 @@ static void svc_write_space(struct sock *sk) | |||
| 387 | } | 422 | } |
| 388 | } | 423 | } |
| 389 | 424 | ||
| 425 | static void svc_tcp_write_space(struct sock *sk) | ||
| 426 | { | ||
| 427 | struct socket *sock = sk->sk_socket; | ||
| 428 | |||
| 429 | if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && sock) | ||
| 430 | clear_bit(SOCK_NOSPACE, &sock->flags); | ||
| 431 | svc_write_space(sk); | ||
| 432 | } | ||
| 433 | |||
| 390 | /* | 434 | /* |
| 391 | * Copy the UDP datagram's destination address to the rqstp structure. | 435 | * Copy the UDP datagram's destination address to the rqstp structure. |
| 392 | * The 'destination' address in this case is the address to which the | 436 | * The 'destination' address in this case is the address to which the |
| @@ -427,13 +471,14 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
| 427 | long all[SVC_PKTINFO_SPACE / sizeof(long)]; | 471 | long all[SVC_PKTINFO_SPACE / sizeof(long)]; |
| 428 | } buffer; | 472 | } buffer; |
| 429 | struct cmsghdr *cmh = &buffer.hdr; | 473 | struct cmsghdr *cmh = &buffer.hdr; |
| 430 | int err, len; | ||
| 431 | struct msghdr msg = { | 474 | struct msghdr msg = { |
| 432 | .msg_name = svc_addr(rqstp), | 475 | .msg_name = svc_addr(rqstp), |
| 433 | .msg_control = cmh, | 476 | .msg_control = cmh, |
| 434 | .msg_controllen = sizeof(buffer), | 477 | .msg_controllen = sizeof(buffer), |
| 435 | .msg_flags = MSG_DONTWAIT, | 478 | .msg_flags = MSG_DONTWAIT, |
| 436 | }; | 479 | }; |
| 480 | size_t len; | ||
| 481 | int err; | ||
| 437 | 482 | ||
| 438 | if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags)) | 483 | if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags)) |
| 439 | /* udp sockets need large rcvbuf as all pending | 484 | /* udp sockets need large rcvbuf as all pending |
| @@ -465,8 +510,8 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
| 465 | return -EAGAIN; | 510 | return -EAGAIN; |
| 466 | } | 511 | } |
| 467 | len = svc_addr_len(svc_addr(rqstp)); | 512 | len = svc_addr_len(svc_addr(rqstp)); |
| 468 | if (len < 0) | 513 | if (len == 0) |
| 469 | return len; | 514 | return -EAFNOSUPPORT; |
| 470 | rqstp->rq_addrlen = len; | 515 | rqstp->rq_addrlen = len; |
| 471 | if (skb->tstamp.tv64 == 0) { | 516 | if (skb->tstamp.tv64 == 0) { |
| 472 | skb->tstamp = ktime_get_real(); | 517 | skb->tstamp = ktime_get_real(); |
| @@ -980,25 +1025,16 @@ static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp) | |||
| 980 | static int svc_tcp_has_wspace(struct svc_xprt *xprt) | 1025 | static int svc_tcp_has_wspace(struct svc_xprt *xprt) |
| 981 | { | 1026 | { |
| 982 | struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); | 1027 | struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); |
| 983 | struct svc_serv *serv = svsk->sk_xprt.xpt_server; | 1028 | struct svc_serv *serv = svsk->sk_xprt.xpt_server; |
| 984 | int required; | 1029 | int required; |
| 985 | int wspace; | ||
| 986 | 1030 | ||
| 987 | /* | 1031 | if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) |
| 988 | * Set the SOCK_NOSPACE flag before checking the available | 1032 | return 1; |
| 989 | * sock space. | 1033 | required = atomic_read(&xprt->xpt_reserved) + serv->sv_max_mesg; |
| 990 | */ | 1034 | if (sk_stream_wspace(svsk->sk_sk) >= required) |
| 1035 | return 1; | ||
| 991 | set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); | 1036 | set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); |
| 992 | required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg; | 1037 | return 0; |
| 993 | wspace = sk_stream_wspace(svsk->sk_sk); | ||
| 994 | |||
| 995 | if (wspace < sk_stream_min_wspace(svsk->sk_sk)) | ||
| 996 | return 0; | ||
| 997 | if (required * 2 > wspace) | ||
| 998 | return 0; | ||
| 999 | |||
| 1000 | clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); | ||
| 1001 | return 1; | ||
| 1002 | } | 1038 | } |
| 1003 | 1039 | ||
| 1004 | static struct svc_xprt *svc_tcp_create(struct svc_serv *serv, | 1040 | static struct svc_xprt *svc_tcp_create(struct svc_serv *serv, |
| @@ -1054,7 +1090,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) | |||
| 1054 | dprintk("setting up TCP socket for reading\n"); | 1090 | dprintk("setting up TCP socket for reading\n"); |
| 1055 | sk->sk_state_change = svc_tcp_state_change; | 1091 | sk->sk_state_change = svc_tcp_state_change; |
| 1056 | sk->sk_data_ready = svc_tcp_data_ready; | 1092 | sk->sk_data_ready = svc_tcp_data_ready; |
| 1057 | sk->sk_write_space = svc_write_space; | 1093 | sk->sk_write_space = svc_tcp_write_space; |
| 1058 | 1094 | ||
| 1059 | svsk->sk_reclen = 0; | 1095 | svsk->sk_reclen = 0; |
| 1060 | svsk->sk_tcplen = 0; | 1096 | svsk->sk_tcplen = 0; |
| @@ -1148,9 +1184,19 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, | |||
| 1148 | return svsk; | 1184 | return svsk; |
| 1149 | } | 1185 | } |
| 1150 | 1186 | ||
| 1151 | int svc_addsock(struct svc_serv *serv, | 1187 | /** |
| 1152 | int fd, | 1188 | * svc_addsock - add a listener socket to an RPC service |
| 1153 | char *name_return) | 1189 | * @serv: pointer to RPC service to which to add a new listener |
| 1190 | * @fd: file descriptor of the new listener | ||
| 1191 | * @name_return: pointer to buffer to fill in with name of listener | ||
| 1192 | * @len: size of the buffer | ||
| 1193 | * | ||
| 1194 | * Fills in socket name and returns positive length of name if successful. | ||
| 1195 | * Name is terminated with '\n'. On error, returns a negative errno | ||
| 1196 | * value. | ||
| 1197 | */ | ||
| 1198 | int svc_addsock(struct svc_serv *serv, const int fd, char *name_return, | ||
| 1199 | const size_t len) | ||
| 1154 | { | 1200 | { |
| 1155 | int err = 0; | 1201 | int err = 0; |
| 1156 | struct socket *so = sockfd_lookup(fd, &err); | 1202 | struct socket *so = sockfd_lookup(fd, &err); |
| @@ -1190,7 +1236,7 @@ int svc_addsock(struct svc_serv *serv, | |||
| 1190 | sockfd_put(so); | 1236 | sockfd_put(so); |
| 1191 | return err; | 1237 | return err; |
| 1192 | } | 1238 | } |
| 1193 | return one_sock_name(name_return, svsk); | 1239 | return svc_one_sock_name(svsk, name_return, len); |
| 1194 | } | 1240 | } |
| 1195 | EXPORT_SYMBOL_GPL(svc_addsock); | 1241 | EXPORT_SYMBOL_GPL(svc_addsock); |
| 1196 | 1242 | ||
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 42a6f9f20285..9e884383134f 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | |||
| @@ -397,14 +397,14 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt, | |||
| 397 | if (!ch) | 397 | if (!ch) |
| 398 | return 0; | 398 | return 0; |
| 399 | 399 | ||
| 400 | /* Allocate temporary reply and chunk maps */ | ||
| 401 | rpl_map = svc_rdma_get_req_map(); | ||
| 402 | chl_map = svc_rdma_get_req_map(); | ||
| 403 | |||
| 404 | svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count); | 400 | svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count); |
| 405 | if (ch_count > RPCSVC_MAXPAGES) | 401 | if (ch_count > RPCSVC_MAXPAGES) |
| 406 | return -EINVAL; | 402 | return -EINVAL; |
| 407 | 403 | ||
| 404 | /* Allocate temporary reply and chunk maps */ | ||
| 405 | rpl_map = svc_rdma_get_req_map(); | ||
| 406 | chl_map = svc_rdma_get_req_map(); | ||
| 407 | |||
| 408 | if (!xprt->sc_frmr_pg_list_len) | 408 | if (!xprt->sc_frmr_pg_list_len) |
| 409 | sge_count = map_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp, | 409 | sge_count = map_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp, |
| 410 | rpl_map, chl_map, ch_count, | 410 | rpl_map, chl_map, ch_count, |
