aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/auth.c46
-rw-r--r--fs/nfsd/export.c3
-rw-r--r--fs/nfsd/nfs3proc.c2
-rw-r--r--fs/nfsd/nfs4acl.c8
-rw-r--r--fs/nfsd/nfs4callback.c6
-rw-r--r--fs/nfsd/nfs4proc.c4
-rw-r--r--fs/nfsd/nfs4state.c150
-rw-r--r--fs/nfsd/nfs4xdr.c62
-rw-r--r--fs/nfsd/nfsproc.c2
-rw-r--r--fs/nfsd/vfs.c6
10 files changed, 136 insertions, 153 deletions
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index cfe9ce881613..6e92b0fe5323 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -14,46 +14,46 @@
14 14
15int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) 15int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
16{ 16{
17 struct svc_cred *cred = &rqstp->rq_cred; 17 struct svc_cred cred = rqstp->rq_cred;
18 int i; 18 int i;
19 int ret; 19 int ret;
20 20
21 if (exp->ex_flags & NFSEXP_ALLSQUASH) { 21 if (exp->ex_flags & NFSEXP_ALLSQUASH) {
22 cred->cr_uid = exp->ex_anon_uid; 22 cred.cr_uid = exp->ex_anon_uid;
23 cred->cr_gid = exp->ex_anon_gid; 23 cred.cr_gid = exp->ex_anon_gid;
24 put_group_info(cred->cr_group_info); 24 cred.cr_group_info = groups_alloc(0);
25 cred->cr_group_info = groups_alloc(0);
26 } else if (exp->ex_flags & NFSEXP_ROOTSQUASH) { 25 } else if (exp->ex_flags & NFSEXP_ROOTSQUASH) {
27 struct group_info *gi; 26 struct group_info *gi;
28 if (!cred->cr_uid) 27 if (!cred.cr_uid)
29 cred->cr_uid = exp->ex_anon_uid; 28 cred.cr_uid = exp->ex_anon_uid;
30 if (!cred->cr_gid) 29 if (!cred.cr_gid)
31 cred->cr_gid = exp->ex_anon_gid; 30 cred.cr_gid = exp->ex_anon_gid;
32 gi = groups_alloc(cred->cr_group_info->ngroups); 31 gi = groups_alloc(cred.cr_group_info->ngroups);
33 if (gi) 32 if (gi)
34 for (i = 0; i < cred->cr_group_info->ngroups; i++) { 33 for (i = 0; i < cred.cr_group_info->ngroups; i++) {
35 if (!GROUP_AT(cred->cr_group_info, i)) 34 if (!GROUP_AT(cred.cr_group_info, i))
36 GROUP_AT(gi, i) = exp->ex_anon_gid; 35 GROUP_AT(gi, i) = exp->ex_anon_gid;
37 else 36 else
38 GROUP_AT(gi, i) = GROUP_AT(cred->cr_group_info, i); 37 GROUP_AT(gi, i) = GROUP_AT(cred.cr_group_info, i);
39 } 38 }
40 put_group_info(cred->cr_group_info); 39 cred.cr_group_info = gi;
41 cred->cr_group_info = gi; 40 } else
42 } 41 get_group_info(cred.cr_group_info);
43 42
44 if (cred->cr_uid != (uid_t) -1) 43 if (cred.cr_uid != (uid_t) -1)
45 current->fsuid = cred->cr_uid; 44 current->fsuid = cred.cr_uid;
46 else 45 else
47 current->fsuid = exp->ex_anon_uid; 46 current->fsuid = exp->ex_anon_uid;
48 if (cred->cr_gid != (gid_t) -1) 47 if (cred.cr_gid != (gid_t) -1)
49 current->fsgid = cred->cr_gid; 48 current->fsgid = cred.cr_gid;
50 else 49 else
51 current->fsgid = exp->ex_anon_gid; 50 current->fsgid = exp->ex_anon_gid;
52 51
53 if (!cred->cr_group_info) 52 if (!cred.cr_group_info)
54 return -ENOMEM; 53 return -ENOMEM;
55 ret = set_current_groups(cred->cr_group_info); 54 ret = set_current_groups(cred.cr_group_info);
56 if ((cred->cr_uid)) { 55 put_group_info(cred.cr_group_info);
56 if ((cred.cr_uid)) {
57 cap_t(current->cap_effective) &= ~CAP_NFSD_MASK; 57 cap_t(current->cap_effective) &= ~CAP_NFSD_MASK;
58 } else { 58 } else {
59 cap_t(current->cap_effective) |= (CAP_NFSD_MASK & 59 cap_t(current->cap_effective) |= (CAP_NFSD_MASK &
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index c340be0a3f59..4e0578121d9a 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -422,7 +422,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
422 if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) 422 if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
423 goto out; 423 goto out;
424 err = path_lookup(buf, 0, &nd); 424 err = path_lookup(buf, 0, &nd);
425 if (err) goto out; 425 if (err) goto out_no_path;
426 426
427 exp.h.flags = 0; 427 exp.h.flags = 0;
428 exp.ex_client = dom; 428 exp.ex_client = dom;
@@ -475,6 +475,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
475 out: 475 out:
476 if (nd.dentry) 476 if (nd.dentry)
477 path_release(&nd); 477 path_release(&nd);
478 out_no_path:
478 if (dom) 479 if (dom)
479 auth_domain_put(dom); 480 auth_domain_put(dom);
480 kfree(buf); 481 kfree(buf);
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 6d2dfed1de08..f61142afea44 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -682,7 +682,7 @@ static struct svc_procedure nfsd_procedures3[22] = {
682 PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE, ST+FH+pAT+pAT), 682 PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE, ST+FH+pAT+pAT),
683 PROC(access, access, access, fhandle, RC_NOCACHE, ST+pAT+1), 683 PROC(access, access, access, fhandle, RC_NOCACHE, ST+pAT+1),
684 PROC(readlink, readlink, readlink, fhandle, RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4), 684 PROC(readlink, readlink, readlink, fhandle, RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4),
685 PROC(read, read, read, fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE), 685 PROC(read, read, read, fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE/4),
686 PROC(write, write, write, fhandle, RC_REPLBUFF, ST+WC+4), 686 PROC(write, write, write, fhandle, RC_REPLBUFF, ST+WC+4),
687 PROC(create, create, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), 687 PROC(create, create, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
688 PROC(mkdir, mkdir, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), 688 PROC(mkdir, mkdir, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index 7391f4aabedb..edb107e61b91 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -710,9 +710,9 @@ calculate_posix_ace_count(struct nfs4_acl *n4acl)
710 /* Also, the remaining entries are for named users and 710 /* Also, the remaining entries are for named users and
711 * groups, and come in threes (mask, allow, deny): */ 711 * groups, and come in threes (mask, allow, deny): */
712 if (n4acl->naces < 7) 712 if (n4acl->naces < 7)
713 return -1; 713 return -EINVAL;
714 if ((n4acl->naces - 7) % 3) 714 if ((n4acl->naces - 7) % 3)
715 return -1; 715 return -EINVAL;
716 return 4 + (n4acl->naces - 7)/3; 716 return 4 + (n4acl->naces - 7)/3;
717 } 717 }
718} 718}
@@ -790,7 +790,7 @@ nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl)
790 continue; 790 continue;
791 791
792 error = nfs4_acl_add_ace(dacl, ace->type, ace->flag, 792 error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
793 ace->access_mask, ace->whotype, ace->who) == -1; 793 ace->access_mask, ace->whotype, ace->who);
794 if (error < 0) 794 if (error < 0)
795 goto out; 795 goto out;
796 796
@@ -866,7 +866,7 @@ nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask,
866 struct nfs4_ace *ace; 866 struct nfs4_ace *ace;
867 867
868 if ((ace = kmalloc(sizeof(*ace), GFP_KERNEL)) == NULL) 868 if ((ace = kmalloc(sizeof(*ace), GFP_KERNEL)) == NULL)
869 return -1; 869 return -ENOMEM;
870 870
871 ace->type = type; 871 ace->type = type;
872 ace->flag = flag; 872 ace->flag = flag;
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index c872bd07fc10..dbaf3f93f328 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -441,8 +441,9 @@ nfsd4_probe_callback(struct nfs4_client *clp)
441 goto out_clnt; 441 goto out_clnt;
442 } 442 }
443 443
444 /* the task holds a reference to the nfs4_client struct */
445 cb->cb_client = clnt; 444 cb->cb_client = clnt;
445
446 /* the task holds a reference to the nfs4_client struct */
446 atomic_inc(&clp->cl_count); 447 atomic_inc(&clp->cl_count);
447 448
448 msg.rpc_cred = nfsd4_lookupcred(clp,0); 449 msg.rpc_cred = nfsd4_lookupcred(clp,0);
@@ -460,13 +461,12 @@ nfsd4_probe_callback(struct nfs4_client *clp)
460out_rpciod: 461out_rpciod:
461 atomic_dec(&clp->cl_count); 462 atomic_dec(&clp->cl_count);
462 rpciod_down(); 463 rpciod_down();
464 cb->cb_client = NULL;
463out_clnt: 465out_clnt:
464 rpc_shutdown_client(clnt); 466 rpc_shutdown_client(clnt);
465 goto out_err;
466out_err: 467out_err:
467 dprintk("NFSD: warning: no callback path to client %.*s\n", 468 dprintk("NFSD: warning: no callback path to client %.*s\n",
468 (int)clp->cl_name.len, clp->cl_name.data); 469 (int)clp->cl_name.len, clp->cl_name.data);
469 cb->cb_client = NULL;
470} 470}
471 471
472static void 472static void
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 6d63f1d9e5f5..b0e095ea0c03 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -288,8 +288,6 @@ nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh)
288 fh_put(current_fh); 288 fh_put(current_fh);
289 status = exp_pseudoroot(rqstp->rq_client, current_fh, 289 status = exp_pseudoroot(rqstp->rq_client, current_fh,
290 &rqstp->rq_chandle); 290 &rqstp->rq_chandle);
291 if (!status)
292 status = nfserrno(nfsd_setuser(rqstp, current_fh->fh_export));
293 return status; 291 return status;
294} 292}
295 293
@@ -975,7 +973,7 @@ struct nfsd4_voidargs { int dummy; };
975 */ 973 */
976static struct svc_procedure nfsd_procedures4[2] = { 974static struct svc_procedure nfsd_procedures4[2] = {
977 PROC(null, void, void, void, RC_NOCACHE, 1), 975 PROC(null, void, void, void, RC_NOCACHE, 1),
978 PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE) 976 PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE/4)
979}; 977};
980 978
981struct svc_version nfsd_version4 = { 979struct svc_version nfsd_version4 = {
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 47ec112b266c..96c7578cbe1e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -147,6 +147,42 @@ get_nfs4_file(struct nfs4_file *fi)
147 kref_get(&fi->fi_ref); 147 kref_get(&fi->fi_ref);
148} 148}
149 149
150static int num_delegations;
151
152/*
153 * Open owner state (share locks)
154 */
155
156/* hash tables for nfs4_stateowner */
157#define OWNER_HASH_BITS 8
158#define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS)
159#define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)
160
161#define ownerid_hashval(id) \
162 ((id) & OWNER_HASH_MASK)
163#define ownerstr_hashval(clientid, ownername) \
164 (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)
165
166static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE];
167static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
168
169/* hash table for nfs4_file */
170#define FILE_HASH_BITS 8
171#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
172#define FILE_HASH_MASK (FILE_HASH_SIZE - 1)
173/* hash table for (open)nfs4_stateid */
174#define STATEID_HASH_BITS 10
175#define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS)
176#define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1)
177
178#define file_hashval(x) \
179 hash_ptr(x, FILE_HASH_BITS)
180#define stateid_hashval(owner_id, file_id) \
181 (((owner_id) + (file_id)) & STATEID_HASH_MASK)
182
183static struct list_head file_hashtbl[FILE_HASH_SIZE];
184static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
185
150static struct nfs4_delegation * 186static struct nfs4_delegation *
151alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) 187alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
152{ 188{
@@ -155,9 +191,12 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
155 struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; 191 struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback;
156 192
157 dprintk("NFSD alloc_init_deleg\n"); 193 dprintk("NFSD alloc_init_deleg\n");
194 if (num_delegations > STATEID_HASH_SIZE * 4)
195 return NULL;
158 dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL); 196 dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
159 if (dp == NULL) 197 if (dp == NULL)
160 return dp; 198 return dp;
199 num_delegations++;
161 INIT_LIST_HEAD(&dp->dl_perfile); 200 INIT_LIST_HEAD(&dp->dl_perfile);
162 INIT_LIST_HEAD(&dp->dl_perclnt); 201 INIT_LIST_HEAD(&dp->dl_perclnt);
163 INIT_LIST_HEAD(&dp->dl_recall_lru); 202 INIT_LIST_HEAD(&dp->dl_recall_lru);
@@ -192,6 +231,7 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
192 dprintk("NFSD: freeing dp %p\n",dp); 231 dprintk("NFSD: freeing dp %p\n",dp);
193 put_nfs4_file(dp->dl_file); 232 put_nfs4_file(dp->dl_file);
194 kmem_cache_free(deleg_slab, dp); 233 kmem_cache_free(deleg_slab, dp);
234 num_delegations--;
195 } 235 }
196} 236}
197 237
@@ -330,22 +370,29 @@ put_nfs4_client(struct nfs4_client *clp)
330} 370}
331 371
332static void 372static void
373shutdown_callback_client(struct nfs4_client *clp)
374{
375 struct rpc_clnt *clnt = clp->cl_callback.cb_client;
376
377 /* shutdown rpc client, ending any outstanding recall rpcs */
378 if (clnt) {
379 clp->cl_callback.cb_client = NULL;
380 rpc_shutdown_client(clnt);
381 rpciod_down();
382 }
383}
384
385static void
333expire_client(struct nfs4_client *clp) 386expire_client(struct nfs4_client *clp)
334{ 387{
335 struct nfs4_stateowner *sop; 388 struct nfs4_stateowner *sop;
336 struct nfs4_delegation *dp; 389 struct nfs4_delegation *dp;
337 struct nfs4_callback *cb = &clp->cl_callback;
338 struct rpc_clnt *clnt = clp->cl_callback.cb_client;
339 struct list_head reaplist; 390 struct list_head reaplist;
340 391
341 dprintk("NFSD: expire_client cl_count %d\n", 392 dprintk("NFSD: expire_client cl_count %d\n",
342 atomic_read(&clp->cl_count)); 393 atomic_read(&clp->cl_count));
343 394
344 /* shutdown rpc client, ending any outstanding recall rpcs */ 395 shutdown_callback_client(clp);
345 if (atomic_read(&cb->cb_set) == 1 && clnt) {
346 rpc_shutdown_client(clnt);
347 clnt = clp->cl_callback.cb_client = NULL;
348 }
349 396
350 INIT_LIST_HEAD(&reaplist); 397 INIT_LIST_HEAD(&reaplist);
351 spin_lock(&recall_lock); 398 spin_lock(&recall_lock);
@@ -936,40 +983,6 @@ out:
936 return status; 983 return status;
937} 984}
938 985
939/*
940 * Open owner state (share locks)
941 */
942
943/* hash tables for nfs4_stateowner */
944#define OWNER_HASH_BITS 8
945#define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS)
946#define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)
947
948#define ownerid_hashval(id) \
949 ((id) & OWNER_HASH_MASK)
950#define ownerstr_hashval(clientid, ownername) \
951 (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)
952
953static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE];
954static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
955
956/* hash table for nfs4_file */
957#define FILE_HASH_BITS 8
958#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
959#define FILE_HASH_MASK (FILE_HASH_SIZE - 1)
960/* hash table for (open)nfs4_stateid */
961#define STATEID_HASH_BITS 10
962#define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS)
963#define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1)
964
965#define file_hashval(x) \
966 hash_ptr(x, FILE_HASH_BITS)
967#define stateid_hashval(owner_id, file_id) \
968 (((owner_id) + (file_id)) & STATEID_HASH_MASK)
969
970static struct list_head file_hashtbl[FILE_HASH_SIZE];
971static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
972
973/* OPEN Share state helper functions */ 986/* OPEN Share state helper functions */
974static inline struct nfs4_file * 987static inline struct nfs4_file *
975alloc_init_file(struct inode *ino) 988alloc_init_file(struct inode *ino)
@@ -1186,8 +1199,7 @@ move_to_close_lru(struct nfs4_stateowner *sop)
1186{ 1199{
1187 dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop); 1200 dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop);
1188 1201
1189 unhash_stateowner(sop); 1202 list_move_tail(&sop->so_close_lru, &close_lru);
1190 list_add_tail(&sop->so_close_lru, &close_lru);
1191 sop->so_time = get_seconds(); 1203 sop->so_time = get_seconds();
1192} 1204}
1193 1205
@@ -1916,8 +1928,7 @@ nfs4_laundromat(void)
1916 } 1928 }
1917 dprintk("NFSD: purging unused open stateowner (so_id %d)\n", 1929 dprintk("NFSD: purging unused open stateowner (so_id %d)\n",
1918 sop->so_id); 1930 sop->so_id);
1919 list_del(&sop->so_close_lru); 1931 release_stateowner(sop);
1920 nfs4_put_stateowner(sop);
1921 } 1932 }
1922 if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT) 1933 if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
1923 clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT; 1934 clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;
@@ -2495,36 +2506,27 @@ nfs4_transform_lock_offset(struct file_lock *lock)
2495 lock->fl_end = OFFSET_MAX; 2506 lock->fl_end = OFFSET_MAX;
2496} 2507}
2497 2508
2498static int 2509/* Hack!: For now, we're defining this just so we can use a pointer to it
2499nfs4_verify_lock_stateowner(struct nfs4_stateowner *sop, unsigned int hashval) 2510 * as a unique cookie to identify our (NFSv4's) posix locks. */
2500{ 2511static struct lock_manager_operations nfsd_posix_mng_ops = {
2501 struct nfs4_stateowner *local = NULL; 2512};
2502 int status = 0;
2503
2504 if (hashval >= LOCK_HASH_SIZE)
2505 goto out;
2506 list_for_each_entry(local, &lock_ownerid_hashtbl[hashval], so_idhash) {
2507 if (local == sop) {
2508 status = 1;
2509 goto out;
2510 }
2511 }
2512out:
2513 return status;
2514}
2515
2516 2513
2517static inline void 2514static inline void
2518nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 2515nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
2519{ 2516{
2520 struct nfs4_stateowner *sop = (struct nfs4_stateowner *) fl->fl_owner; 2517 struct nfs4_stateowner *sop;
2521 unsigned int hval = lockownerid_hashval(sop->so_id); 2518 unsigned int hval;
2522 2519
2523 deny->ld_sop = NULL; 2520 if (fl->fl_lmops == &nfsd_posix_mng_ops) {
2524 if (nfs4_verify_lock_stateowner(sop, hval)) { 2521 sop = (struct nfs4_stateowner *) fl->fl_owner;
2522 hval = lockownerid_hashval(sop->so_id);
2525 kref_get(&sop->so_ref); 2523 kref_get(&sop->so_ref);
2526 deny->ld_sop = sop; 2524 deny->ld_sop = sop;
2527 deny->ld_clientid = sop->so_client->cl_clientid; 2525 deny->ld_clientid = sop->so_client->cl_clientid;
2526 } else {
2527 deny->ld_sop = NULL;
2528 deny->ld_clientid.cl_boot = 0;
2529 deny->ld_clientid.cl_id = 0;
2528 } 2530 }
2529 deny->ld_start = fl->fl_start; 2531 deny->ld_start = fl->fl_start;
2530 deny->ld_length = ~(u64)0; 2532 deny->ld_length = ~(u64)0;
@@ -2736,6 +2738,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
2736 file_lock.fl_pid = current->tgid; 2738 file_lock.fl_pid = current->tgid;
2737 file_lock.fl_file = filp; 2739 file_lock.fl_file = filp;
2738 file_lock.fl_flags = FL_POSIX; 2740 file_lock.fl_flags = FL_POSIX;
2741 file_lock.fl_lmops = &nfsd_posix_mng_ops;
2739 2742
2740 file_lock.fl_start = lock->lk_offset; 2743 file_lock.fl_start = lock->lk_offset;
2741 if ((lock->lk_length == ~(u64)0) || 2744 if ((lock->lk_length == ~(u64)0) ||
@@ -2841,6 +2844,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
2841 file_lock.fl_owner = (fl_owner_t)lockt->lt_stateowner; 2844 file_lock.fl_owner = (fl_owner_t)lockt->lt_stateowner;
2842 file_lock.fl_pid = current->tgid; 2845 file_lock.fl_pid = current->tgid;
2843 file_lock.fl_flags = FL_POSIX; 2846 file_lock.fl_flags = FL_POSIX;
2847 file_lock.fl_lmops = &nfsd_posix_mng_ops;
2844 2848
2845 file_lock.fl_start = lockt->lt_offset; 2849 file_lock.fl_start = lockt->lt_offset;
2846 if ((lockt->lt_length == ~(u64)0) || LOFF_OVERFLOW(lockt->lt_offset, lockt->lt_length)) 2850 if ((lockt->lt_length == ~(u64)0) || LOFF_OVERFLOW(lockt->lt_offset, lockt->lt_length))
@@ -2900,6 +2904,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
2900 file_lock.fl_pid = current->tgid; 2904 file_lock.fl_pid = current->tgid;
2901 file_lock.fl_file = filp; 2905 file_lock.fl_file = filp;
2902 file_lock.fl_flags = FL_POSIX; 2906 file_lock.fl_flags = FL_POSIX;
2907 file_lock.fl_lmops = &nfsd_posix_mng_ops;
2903 file_lock.fl_start = locku->lu_offset; 2908 file_lock.fl_start = locku->lu_offset;
2904 2909
2905 if ((locku->lu_length == ~(u64)0) || LOFF_OVERFLOW(locku->lu_offset, locku->lu_length)) 2910 if ((locku->lu_length == ~(u64)0) || LOFF_OVERFLOW(locku->lu_offset, locku->lu_length))
@@ -3211,15 +3216,8 @@ __nfs4_state_shutdown(void)
3211 int i; 3216 int i;
3212 struct nfs4_client *clp = NULL; 3217 struct nfs4_client *clp = NULL;
3213 struct nfs4_delegation *dp = NULL; 3218 struct nfs4_delegation *dp = NULL;
3214 struct nfs4_stateowner *sop = NULL;
3215 struct list_head *pos, *next, reaplist; 3219 struct list_head *pos, *next, reaplist;
3216 3220
3217 list_for_each_safe(pos, next, &close_lru) {
3218 sop = list_entry(pos, struct nfs4_stateowner, so_close_lru);
3219 list_del(&sop->so_close_lru);
3220 nfs4_put_stateowner(sop);
3221 }
3222
3223 for (i = 0; i < CLIENT_HASH_SIZE; i++) { 3221 for (i = 0; i < CLIENT_HASH_SIZE; i++) {
3224 while (!list_empty(&conf_id_hashtbl[i])) { 3222 while (!list_empty(&conf_id_hashtbl[i])) {
3225 clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 3223 clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
@@ -3244,8 +3242,6 @@ __nfs4_state_shutdown(void)
3244 } 3242 }
3245 3243
3246 cancel_delayed_work(&laundromat_work); 3244 cancel_delayed_work(&laundromat_work);
3247 flush_workqueue(laundry_wq);
3248 destroy_workqueue(laundry_wq);
3249 nfsd4_shutdown_recdir(); 3245 nfsd4_shutdown_recdir();
3250 nfs4_init = 0; 3246 nfs4_init = 0;
3251} 3247}
@@ -3253,6 +3249,8 @@ __nfs4_state_shutdown(void)
3253void 3249void
3254nfs4_state_shutdown(void) 3250nfs4_state_shutdown(void)
3255{ 3251{
3252 cancel_rearming_delayed_workqueue(laundry_wq, &laundromat_work);
3253 destroy_workqueue(laundry_wq);
3256 nfs4_lock_state(); 3254 nfs4_lock_state();
3257 nfs4_release_reclaim(); 3255 nfs4_release_reclaim();
3258 __nfs4_state_shutdown(); 3256 __nfs4_state_shutdown();
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 03857fd81126..de3998f15f10 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -299,11 +299,10 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
299 buf, dummy32, &ace.who); 299 buf, dummy32, &ace.who);
300 if (status) 300 if (status)
301 goto out_nfserr; 301 goto out_nfserr;
302 if (nfs4_acl_add_ace(*acl, ace.type, ace.flag, 302 status = nfs4_acl_add_ace(*acl, ace.type, ace.flag,
303 ace.access_mask, ace.whotype, ace.who) != 0) { 303 ace.access_mask, ace.whotype, ace.who);
304 status = -ENOMEM; 304 if (status)
305 goto out_nfserr; 305 goto out_nfserr;
306 }
307 } 306 }
308 } else 307 } else
309 *acl = NULL; 308 *acl = NULL;
@@ -2085,27 +2084,20 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read
2085 WRITE32(eof); 2084 WRITE32(eof);
2086 WRITE32(maxcount); 2085 WRITE32(maxcount);
2087 ADJUST_ARGS(); 2086 ADJUST_ARGS();
2088 resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base; 2087 resp->xbuf->head[0].iov_len = (char*)p
2089 2088 - (char*)resp->xbuf->head[0].iov_base;
2090 resp->xbuf->page_len = maxcount; 2089 resp->xbuf->page_len = maxcount;
2091 2090
2092 /* read zero bytes -> don't set up tail */ 2091 /* Use rest of head for padding and remaining ops: */
2093 if(!maxcount) 2092 resp->rqstp->rq_restailpage = 0;
2094 return 0; 2093 resp->xbuf->tail[0].iov_base = p;
2095
2096 /* set up page for remaining responses */
2097 svc_take_page(resp->rqstp);
2098 resp->xbuf->tail[0].iov_base =
2099 page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
2100 resp->rqstp->rq_restailpage = resp->rqstp->rq_resused-1;
2101 resp->xbuf->tail[0].iov_len = 0; 2094 resp->xbuf->tail[0].iov_len = 0;
2102 resp->p = resp->xbuf->tail[0].iov_base;
2103 resp->end = resp->p + PAGE_SIZE/4;
2104
2105 if (maxcount&3) { 2095 if (maxcount&3) {
2106 *(resp->p)++ = 0; 2096 RESERVE_SPACE(4);
2097 WRITE32(0);
2107 resp->xbuf->tail[0].iov_base += maxcount&3; 2098 resp->xbuf->tail[0].iov_base += maxcount&3;
2108 resp->xbuf->tail[0].iov_len = 4 - (maxcount&3); 2099 resp->xbuf->tail[0].iov_len = 4 - (maxcount&3);
2100 ADJUST_ARGS();
2109 } 2101 }
2110 return 0; 2102 return 0;
2111} 2103}
@@ -2142,21 +2134,20 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r
2142 2134
2143 WRITE32(maxcount); 2135 WRITE32(maxcount);
2144 ADJUST_ARGS(); 2136 ADJUST_ARGS();
2145 resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base; 2137 resp->xbuf->head[0].iov_len = (char*)p
2138 - (char*)resp->xbuf->head[0].iov_base;
2139 resp->xbuf->page_len = maxcount;
2146 2140
2147 svc_take_page(resp->rqstp); 2141 /* Use rest of head for padding and remaining ops: */
2148 resp->xbuf->tail[0].iov_base = 2142 resp->rqstp->rq_restailpage = 0;
2149 page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); 2143 resp->xbuf->tail[0].iov_base = p;
2150 resp->rqstp->rq_restailpage = resp->rqstp->rq_resused-1;
2151 resp->xbuf->tail[0].iov_len = 0; 2144 resp->xbuf->tail[0].iov_len = 0;
2152 resp->p = resp->xbuf->tail[0].iov_base;
2153 resp->end = resp->p + PAGE_SIZE/4;
2154
2155 resp->xbuf->page_len = maxcount;
2156 if (maxcount&3) { 2145 if (maxcount&3) {
2157 *(resp->p)++ = 0; 2146 RESERVE_SPACE(4);
2147 WRITE32(0);
2158 resp->xbuf->tail[0].iov_base += maxcount&3; 2148 resp->xbuf->tail[0].iov_base += maxcount&3;
2159 resp->xbuf->tail[0].iov_len = 4 - (maxcount&3); 2149 resp->xbuf->tail[0].iov_len = 4 - (maxcount&3);
2150 ADJUST_ARGS();
2160 } 2151 }
2161 return 0; 2152 return 0;
2162} 2153}
@@ -2166,7 +2157,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re
2166{ 2157{
2167 int maxcount; 2158 int maxcount;
2168 loff_t offset; 2159 loff_t offset;
2169 u32 *page, *savep; 2160 u32 *page, *savep, *tailbase;
2170 ENCODE_HEAD; 2161 ENCODE_HEAD;
2171 2162
2172 if (nfserr) 2163 if (nfserr)
@@ -2182,6 +2173,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re
2182 WRITE32(0); 2173 WRITE32(0);
2183 ADJUST_ARGS(); 2174 ADJUST_ARGS();
2184 resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base; 2175 resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base;
2176 tailbase = p;
2185 2177
2186 maxcount = PAGE_SIZE; 2178 maxcount = PAGE_SIZE;
2187 if (maxcount > readdir->rd_maxcount) 2179 if (maxcount > readdir->rd_maxcount)
@@ -2226,14 +2218,12 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re
2226 *p++ = htonl(readdir->common.err == nfserr_eof); 2218 *p++ = htonl(readdir->common.err == nfserr_eof);
2227 resp->xbuf->page_len = ((char*)p) - (char*)page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); 2219 resp->xbuf->page_len = ((char*)p) - (char*)page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
2228 2220
2229 /* allocate a page for the tail */ 2221 /* Use rest of head for padding and remaining ops: */
2230 svc_take_page(resp->rqstp); 2222 resp->rqstp->rq_restailpage = 0;
2231 resp->xbuf->tail[0].iov_base = 2223 resp->xbuf->tail[0].iov_base = tailbase;
2232 page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
2233 resp->rqstp->rq_restailpage = resp->rqstp->rq_resused-1;
2234 resp->xbuf->tail[0].iov_len = 0; 2224 resp->xbuf->tail[0].iov_len = 0;
2235 resp->p = resp->xbuf->tail[0].iov_base; 2225 resp->p = resp->xbuf->tail[0].iov_base;
2236 resp->end = resp->p + PAGE_SIZE/4; 2226 resp->end = resp->p + (PAGE_SIZE - resp->xbuf->head[0].iov_len)/4;
2237 2227
2238 return 0; 2228 return 0;
2239err_no_verf: 2229err_no_verf:
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 3e6b75cd90fd..06cd0db0f32b 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -553,7 +553,7 @@ static struct svc_procedure nfsd_procedures2[18] = {
553 PROC(none, void, void, none, RC_NOCACHE, ST), 553 PROC(none, void, void, none, RC_NOCACHE, ST),
554 PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE, ST+FH+AT), 554 PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE, ST+FH+AT),
555 PROC(readlink, readlinkargs, readlinkres, none, RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4), 555 PROC(readlink, readlinkargs, readlinkres, none, RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4),
556 PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE), 556 PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE/4),
557 PROC(none, void, void, none, RC_NOCACHE, ST), 557 PROC(none, void, void, none, RC_NOCACHE, ST),
558 PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF, ST+AT), 558 PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF, ST+AT),
559 PROC(create, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT), 559 PROC(create, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT),
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 31018333dc38..6aa92d0e6876 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -371,7 +371,6 @@ out_nfserr:
371static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf) 371static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
372{ 372{
373 ssize_t buflen; 373 ssize_t buflen;
374 int error;
375 374
376 buflen = vfs_getxattr(dentry, key, NULL, 0); 375 buflen = vfs_getxattr(dentry, key, NULL, 0);
377 if (buflen <= 0) 376 if (buflen <= 0)
@@ -381,10 +380,7 @@ static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
381 if (!*buf) 380 if (!*buf)
382 return -ENOMEM; 381 return -ENOMEM;
383 382
384 error = vfs_getxattr(dentry, key, *buf, buflen); 383 return vfs_getxattr(dentry, key, *buf, buflen);
385 if (error < 0)
386 return error;
387 return buflen;
388} 384}
389#endif 385#endif
390 386