diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-22 15:55:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-22 15:55:50 -0400 |
commit | 7e0338c0de18c50f09aea1fbef45110cf7d64a3c (patch) | |
tree | 30a935c1f6eee7125a9fbb802a33292b1f7268fa /fs | |
parent | df36b439c5fedefe013d4449cb6a50d15e2f4d70 (diff) | |
parent | 47fcb03fefee2501e79176932a4184fc24d6f8ec (diff) |
Merge branch 'for-2.6.31' of git://fieldses.org/git/linux-nfsd
* 'for-2.6.31' of git://fieldses.org/git/linux-nfsd: (60 commits)
SUNRPC: Fix the TCP server's send buffer accounting
nfsd41: Backchannel: minorversion support for the back channel
nfsd41: Backchannel: cleanup nfs4.0 callback encode routines
nfsd41: Remove ip address collision detection case
nfsd: optimise the starting of zero threads when none are running.
nfsd: don't take nfsd_mutex twice when setting number of threads.
nfsd41: sanity check client drc maxreqs
nfsd41: move channel attributes from nfsd4_session to a nfsd4_channel_attr struct
NFS: kill off complicated macro 'PROC'
sunrpc: potential memory leak in function rdma_read_xdr
nfsd: minor nfsd_vfs_write cleanup
nfsd: Pull write-gathering code out of nfsd_vfs_write
nfsd: track last inode only in use_wgather case
sunrpc: align cache_clean work's timer
nfsd: Use write gathering only with NFSv2
NFSv4: kill off complicated macro 'PROC'
NFSv4: do exact check about attribute specified
knfsd: remove unreported filehandle stats counters
knfsd: fix reply cache memory corruption
knfsd: reply cache cleanups
...
Diffstat (limited to 'fs')
-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 |
17 files changed, 1142 insertions, 597 deletions
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; |