diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-11-02 23:56:40 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-11-02 23:56:40 -0400 |
commit | 31cbecb4ab538f433145bc5a46f3bea9b9627031 (patch) | |
tree | d6206d42dea7298f7ef05fd1f7bf474245f0d43a /fs/nfsd | |
parent | 2b72c9ccd22c4a3299e5a358dcd639fb253730f4 (diff) | |
parent | 278c023a99b0d6b471d0f4a79835c703482e29ac (diff) |
Merge branch 'osd-devel' into nfs-for-next
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/export.c | 16 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 20 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 374 | ||||
-rw-r--r-- | fs/nfsd/nfs4recover.c | 53 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 1794 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 380 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 1 | ||||
-rw-r--r-- | fs/nfsd/nfsd.h | 33 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 39 | ||||
-rw-r--r-- | fs/nfsd/state.h | 174 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 31 | ||||
-rw-r--r-- | fs/nfsd/vfs.h | 29 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 28 |
13 files changed, 1645 insertions, 1327 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index f4cc1e2bfc54..62f3b9074e84 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/exportfs.h> | 17 | #include <linux/exportfs.h> |
18 | 18 | ||
19 | #include <linux/nfsd/syscall.h> | ||
20 | #include <net/ipv6.h> | 19 | #include <net/ipv6.h> |
21 | 20 | ||
22 | #include "nfsd.h" | 21 | #include "nfsd.h" |
@@ -318,7 +317,6 @@ static void svc_export_put(struct kref *ref) | |||
318 | struct svc_export *exp = container_of(ref, struct svc_export, h.ref); | 317 | struct svc_export *exp = container_of(ref, struct svc_export, h.ref); |
319 | path_put(&exp->ex_path); | 318 | path_put(&exp->ex_path); |
320 | auth_domain_put(exp->ex_client); | 319 | auth_domain_put(exp->ex_client); |
321 | kfree(exp->ex_pathname); | ||
322 | nfsd4_fslocs_free(&exp->ex_fslocs); | 320 | nfsd4_fslocs_free(&exp->ex_fslocs); |
323 | kfree(exp); | 321 | kfree(exp); |
324 | } | 322 | } |
@@ -528,11 +526,6 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
528 | 526 | ||
529 | exp.ex_client = dom; | 527 | exp.ex_client = dom; |
530 | 528 | ||
531 | err = -ENOMEM; | ||
532 | exp.ex_pathname = kstrdup(buf, GFP_KERNEL); | ||
533 | if (!exp.ex_pathname) | ||
534 | goto out2; | ||
535 | |||
536 | /* expiry */ | 529 | /* expiry */ |
537 | err = -EINVAL; | 530 | err = -EINVAL; |
538 | exp.h.expiry_time = get_expiry(&mesg); | 531 | exp.h.expiry_time = get_expiry(&mesg); |
@@ -613,8 +606,6 @@ out4: | |||
613 | nfsd4_fslocs_free(&exp.ex_fslocs); | 606 | nfsd4_fslocs_free(&exp.ex_fslocs); |
614 | kfree(exp.ex_uuid); | 607 | kfree(exp.ex_uuid); |
615 | out3: | 608 | out3: |
616 | kfree(exp.ex_pathname); | ||
617 | out2: | ||
618 | path_put(&exp.ex_path); | 609 | path_put(&exp.ex_path); |
619 | out1: | 610 | out1: |
620 | auth_domain_put(dom); | 611 | auth_domain_put(dom); |
@@ -678,7 +669,6 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem) | |||
678 | new->ex_client = item->ex_client; | 669 | new->ex_client = item->ex_client; |
679 | new->ex_path.dentry = dget(item->ex_path.dentry); | 670 | new->ex_path.dentry = dget(item->ex_path.dentry); |
680 | new->ex_path.mnt = mntget(item->ex_path.mnt); | 671 | new->ex_path.mnt = mntget(item->ex_path.mnt); |
681 | new->ex_pathname = NULL; | ||
682 | new->ex_fslocs.locations = NULL; | 672 | new->ex_fslocs.locations = NULL; |
683 | new->ex_fslocs.locations_count = 0; | 673 | new->ex_fslocs.locations_count = 0; |
684 | new->ex_fslocs.migrated = 0; | 674 | new->ex_fslocs.migrated = 0; |
@@ -696,8 +686,6 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) | |||
696 | new->ex_fsid = item->ex_fsid; | 686 | new->ex_fsid = item->ex_fsid; |
697 | new->ex_uuid = item->ex_uuid; | 687 | new->ex_uuid = item->ex_uuid; |
698 | item->ex_uuid = NULL; | 688 | item->ex_uuid = NULL; |
699 | new->ex_pathname = item->ex_pathname; | ||
700 | item->ex_pathname = NULL; | ||
701 | new->ex_fslocs.locations = item->ex_fslocs.locations; | 689 | new->ex_fslocs.locations = item->ex_fslocs.locations; |
702 | item->ex_fslocs.locations = NULL; | 690 | item->ex_fslocs.locations = NULL; |
703 | new->ex_fslocs.locations_count = item->ex_fslocs.locations_count; | 691 | new->ex_fslocs.locations_count = item->ex_fslocs.locations_count; |
@@ -1010,7 +998,7 @@ rqst_exp_parent(struct svc_rqst *rqstp, struct path *path) | |||
1010 | return exp; | 998 | return exp; |
1011 | } | 999 | } |
1012 | 1000 | ||
1013 | static struct svc_export *find_fsidzero_export(struct svc_rqst *rqstp) | 1001 | struct svc_export *rqst_find_fsidzero_export(struct svc_rqst *rqstp) |
1014 | { | 1002 | { |
1015 | u32 fsidv[2]; | 1003 | u32 fsidv[2]; |
1016 | 1004 | ||
@@ -1030,7 +1018,7 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp) | |||
1030 | struct svc_export *exp; | 1018 | struct svc_export *exp; |
1031 | __be32 rv; | 1019 | __be32 rv; |
1032 | 1020 | ||
1033 | exp = find_fsidzero_export(rqstp); | 1021 | exp = rqst_find_fsidzero_export(rqstp); |
1034 | if (IS_ERR(exp)) | 1022 | if (IS_ERR(exp)) |
1035 | return nfserrno(PTR_ERR(exp)); | 1023 | return nfserrno(PTR_ERR(exp)); |
1036 | rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL); | 1024 | rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL); |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 02eb4edf0ece..7748d6a18d97 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -39,6 +39,8 @@ | |||
39 | 39 | ||
40 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 40 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
41 | 41 | ||
42 | static void nfsd4_mark_cb_fault(struct nfs4_client *, int reason); | ||
43 | |||
42 | #define NFSPROC4_CB_NULL 0 | 44 | #define NFSPROC4_CB_NULL 0 |
43 | #define NFSPROC4_CB_COMPOUND 1 | 45 | #define NFSPROC4_CB_COMPOUND 1 |
44 | 46 | ||
@@ -351,7 +353,7 @@ static void encode_cb_recall4args(struct xdr_stream *xdr, | |||
351 | __be32 *p; | 353 | __be32 *p; |
352 | 354 | ||
353 | encode_nfs_cb_opnum4(xdr, OP_CB_RECALL); | 355 | encode_nfs_cb_opnum4(xdr, OP_CB_RECALL); |
354 | encode_stateid4(xdr, &dp->dl_stateid); | 356 | encode_stateid4(xdr, &dp->dl_stid.sc_stateid); |
355 | 357 | ||
356 | p = xdr_reserve_space(xdr, 4); | 358 | p = xdr_reserve_space(xdr, 4); |
357 | *p++ = xdr_zero; /* truncate */ | 359 | *p++ = xdr_zero; /* truncate */ |
@@ -460,6 +462,8 @@ static int decode_cb_sequence4resok(struct xdr_stream *xdr, | |||
460 | */ | 462 | */ |
461 | status = 0; | 463 | status = 0; |
462 | out: | 464 | out: |
465 | if (status) | ||
466 | nfsd4_mark_cb_fault(cb->cb_clp, status); | ||
463 | return status; | 467 | return status; |
464 | out_overflow: | 468 | out_overflow: |
465 | print_overflow_msg(__func__, xdr); | 469 | print_overflow_msg(__func__, xdr); |
@@ -686,6 +690,12 @@ static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason) | |||
686 | warn_no_callback_path(clp, reason); | 690 | warn_no_callback_path(clp, reason); |
687 | } | 691 | } |
688 | 692 | ||
693 | static void nfsd4_mark_cb_fault(struct nfs4_client *clp, int reason) | ||
694 | { | ||
695 | clp->cl_cb_state = NFSD4_CB_FAULT; | ||
696 | warn_no_callback_path(clp, reason); | ||
697 | } | ||
698 | |||
689 | static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) | 699 | static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) |
690 | { | 700 | { |
691 | struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null); | 701 | struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null); |
@@ -787,7 +797,7 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata) | |||
787 | { | 797 | { |
788 | struct nfsd4_callback *cb = calldata; | 798 | struct nfsd4_callback *cb = calldata; |
789 | struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); | 799 | struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); |
790 | struct nfs4_client *clp = dp->dl_client; | 800 | struct nfs4_client *clp = dp->dl_stid.sc_client; |
791 | u32 minorversion = clp->cl_minorversion; | 801 | u32 minorversion = clp->cl_minorversion; |
792 | 802 | ||
793 | cb->cb_minorversion = minorversion; | 803 | cb->cb_minorversion = minorversion; |
@@ -809,7 +819,7 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata) | |||
809 | { | 819 | { |
810 | struct nfsd4_callback *cb = calldata; | 820 | struct nfsd4_callback *cb = calldata; |
811 | struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); | 821 | struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); |
812 | struct nfs4_client *clp = dp->dl_client; | 822 | struct nfs4_client *clp = dp->dl_stid.sc_client; |
813 | 823 | ||
814 | dprintk("%s: minorversion=%d\n", __func__, | 824 | dprintk("%s: minorversion=%d\n", __func__, |
815 | clp->cl_minorversion); | 825 | clp->cl_minorversion); |
@@ -832,7 +842,7 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) | |||
832 | { | 842 | { |
833 | struct nfsd4_callback *cb = calldata; | 843 | struct nfsd4_callback *cb = calldata; |
834 | struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); | 844 | struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); |
835 | struct nfs4_client *clp = dp->dl_client; | 845 | struct nfs4_client *clp = dp->dl_stid.sc_client; |
836 | struct rpc_clnt *current_rpc_client = clp->cl_cb_client; | 846 | struct rpc_clnt *current_rpc_client = clp->cl_cb_client; |
837 | 847 | ||
838 | nfsd4_cb_done(task, calldata); | 848 | nfsd4_cb_done(task, calldata); |
@@ -1006,7 +1016,7 @@ void nfsd4_do_callback_rpc(struct work_struct *w) | |||
1006 | void nfsd4_cb_recall(struct nfs4_delegation *dp) | 1016 | void nfsd4_cb_recall(struct nfs4_delegation *dp) |
1007 | { | 1017 | { |
1008 | struct nfsd4_callback *cb = &dp->dl_recall; | 1018 | struct nfsd4_callback *cb = &dp->dl_recall; |
1009 | struct nfs4_client *clp = dp->dl_client; | 1019 | struct nfs4_client *clp = dp->dl_stid.sc_client; |
1010 | 1020 | ||
1011 | dp->dl_retries = 1; | 1021 | dp->dl_retries = 1; |
1012 | cb->cb_op = dp; | 1022 | cb->cb_op = dp; |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index e80777666618..fa383361bc61 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/file.h> | 35 | #include <linux/file.h> |
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | 37 | ||
38 | #include "idmap.h" | ||
38 | #include "cache.h" | 39 | #include "cache.h" |
39 | #include "xdr4.h" | 40 | #include "xdr4.h" |
40 | #include "vfs.h" | 41 | #include "vfs.h" |
@@ -156,6 +157,8 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs | |||
156 | !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) | 157 | !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) |
157 | return nfserr_inval; | 158 | return nfserr_inval; |
158 | 159 | ||
160 | accmode |= NFSD_MAY_READ_IF_EXEC; | ||
161 | |||
159 | if (open->op_share_access & NFS4_SHARE_ACCESS_READ) | 162 | if (open->op_share_access & NFS4_SHARE_ACCESS_READ) |
160 | accmode |= NFSD_MAY_READ; | 163 | accmode |= NFSD_MAY_READ; |
161 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | 164 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) |
@@ -168,12 +171,29 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs | |||
168 | return status; | 171 | return status; |
169 | } | 172 | } |
170 | 173 | ||
174 | static __be32 nfsd_check_obj_isreg(struct svc_fh *fh) | ||
175 | { | ||
176 | umode_t mode = fh->fh_dentry->d_inode->i_mode; | ||
177 | |||
178 | if (S_ISREG(mode)) | ||
179 | return nfs_ok; | ||
180 | if (S_ISDIR(mode)) | ||
181 | return nfserr_isdir; | ||
182 | /* | ||
183 | * Using err_symlink as our catch-all case may look odd; but | ||
184 | * there's no other obvious error for this case in 4.0, and we | ||
185 | * happen to know that it will cause the linux v4 client to do | ||
186 | * the right thing on attempts to open something other than a | ||
187 | * regular file. | ||
188 | */ | ||
189 | return nfserr_symlink; | ||
190 | } | ||
191 | |||
171 | static __be32 | 192 | static __be32 |
172 | do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) | 193 | do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) |
173 | { | 194 | { |
174 | struct svc_fh resfh; | 195 | struct svc_fh resfh; |
175 | __be32 status; | 196 | __be32 status; |
176 | int created = 0; | ||
177 | 197 | ||
178 | fh_init(&resfh, NFS4_FHSIZE); | 198 | fh_init(&resfh, NFS4_FHSIZE); |
179 | open->op_truncate = 0; | 199 | open->op_truncate = 0; |
@@ -202,7 +222,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o | |||
202 | open->op_fname.len, &open->op_iattr, | 222 | open->op_fname.len, &open->op_iattr, |
203 | &resfh, open->op_createmode, | 223 | &resfh, open->op_createmode, |
204 | (u32 *)open->op_verf.data, | 224 | (u32 *)open->op_verf.data, |
205 | &open->op_truncate, &created); | 225 | &open->op_truncate, &open->op_created); |
206 | 226 | ||
207 | /* | 227 | /* |
208 | * Following rfc 3530 14.2.16, use the returned bitmask | 228 | * Following rfc 3530 14.2.16, use the returned bitmask |
@@ -216,6 +236,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o | |||
216 | status = nfsd_lookup(rqstp, current_fh, | 236 | status = nfsd_lookup(rqstp, current_fh, |
217 | open->op_fname.data, open->op_fname.len, &resfh); | 237 | open->op_fname.data, open->op_fname.len, &resfh); |
218 | fh_unlock(current_fh); | 238 | fh_unlock(current_fh); |
239 | if (status) | ||
240 | goto out; | ||
241 | status = nfsd_check_obj_isreg(&resfh); | ||
219 | } | 242 | } |
220 | if (status) | 243 | if (status) |
221 | goto out; | 244 | goto out; |
@@ -227,9 +250,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o | |||
227 | fh_dup2(current_fh, &resfh); | 250 | fh_dup2(current_fh, &resfh); |
228 | 251 | ||
229 | /* set reply cache */ | 252 | /* set reply cache */ |
230 | fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh, | 253 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, |
231 | &resfh.fh_handle); | 254 | &resfh.fh_handle); |
232 | if (!created) | 255 | if (!open->op_created) |
233 | status = do_open_permission(rqstp, current_fh, open, | 256 | status = do_open_permission(rqstp, current_fh, open, |
234 | NFSD_MAY_NOP); | 257 | NFSD_MAY_NOP); |
235 | 258 | ||
@@ -254,7 +277,7 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ | |||
254 | memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info)); | 277 | memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info)); |
255 | 278 | ||
256 | /* set replay cache */ | 279 | /* set replay cache */ |
257 | fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh, | 280 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, |
258 | ¤t_fh->fh_handle); | 281 | ¤t_fh->fh_handle); |
259 | 282 | ||
260 | open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && | 283 | open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && |
@@ -283,14 +306,18 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
283 | __be32 status; | 306 | __be32 status; |
284 | struct nfsd4_compoundres *resp; | 307 | struct nfsd4_compoundres *resp; |
285 | 308 | ||
286 | dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", | 309 | dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n", |
287 | (int)open->op_fname.len, open->op_fname.data, | 310 | (int)open->op_fname.len, open->op_fname.data, |
288 | open->op_stateowner); | 311 | open->op_openowner); |
289 | 312 | ||
290 | /* This check required by spec. */ | 313 | /* This check required by spec. */ |
291 | if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) | 314 | if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) |
292 | return nfserr_inval; | 315 | return nfserr_inval; |
293 | 316 | ||
317 | /* We don't yet support WANT bits: */ | ||
318 | open->op_share_access &= NFS4_SHARE_ACCESS_MASK; | ||
319 | |||
320 | open->op_created = 0; | ||
294 | /* | 321 | /* |
295 | * RFC5661 18.51.3 | 322 | * RFC5661 18.51.3 |
296 | * Before RECLAIM_COMPLETE done, server should deny new lock | 323 | * Before RECLAIM_COMPLETE done, server should deny new lock |
@@ -309,7 +336,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
309 | resp = rqstp->rq_resp; | 336 | resp = rqstp->rq_resp; |
310 | status = nfsd4_process_open1(&resp->cstate, open); | 337 | status = nfsd4_process_open1(&resp->cstate, open); |
311 | if (status == nfserr_replay_me) { | 338 | if (status == nfserr_replay_me) { |
312 | struct nfs4_replay *rp = &open->op_stateowner->so_replay; | 339 | struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay; |
313 | fh_put(&cstate->current_fh); | 340 | fh_put(&cstate->current_fh); |
314 | fh_copy_shallow(&cstate->current_fh.fh_handle, | 341 | fh_copy_shallow(&cstate->current_fh.fh_handle, |
315 | &rp->rp_openfh); | 342 | &rp->rp_openfh); |
@@ -339,32 +366,23 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
339 | switch (open->op_claim_type) { | 366 | switch (open->op_claim_type) { |
340 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: | 367 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: |
341 | case NFS4_OPEN_CLAIM_NULL: | 368 | case NFS4_OPEN_CLAIM_NULL: |
342 | /* | ||
343 | * (1) set CURRENT_FH to the file being opened, | ||
344 | * creating it if necessary, (2) set open->op_cinfo, | ||
345 | * (3) set open->op_truncate if the file is to be | ||
346 | * truncated after opening, (4) do permission checking. | ||
347 | */ | ||
348 | status = do_open_lookup(rqstp, &cstate->current_fh, | 369 | status = do_open_lookup(rqstp, &cstate->current_fh, |
349 | open); | 370 | open); |
350 | if (status) | 371 | if (status) |
351 | goto out; | 372 | goto out; |
352 | break; | 373 | break; |
353 | case NFS4_OPEN_CLAIM_PREVIOUS: | 374 | case NFS4_OPEN_CLAIM_PREVIOUS: |
354 | open->op_stateowner->so_confirmed = 1; | 375 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; |
355 | /* | 376 | case NFS4_OPEN_CLAIM_FH: |
356 | * The CURRENT_FH is already set to the file being | 377 | case NFS4_OPEN_CLAIM_DELEG_CUR_FH: |
357 | * opened. (1) set open->op_cinfo, (2) set | ||
358 | * open->op_truncate if the file is to be truncated | ||
359 | * after opening, (3) do permission checking. | ||
360 | */ | ||
361 | status = do_open_fhandle(rqstp, &cstate->current_fh, | 378 | status = do_open_fhandle(rqstp, &cstate->current_fh, |
362 | open); | 379 | open); |
363 | if (status) | 380 | if (status) |
364 | goto out; | 381 | goto out; |
365 | break; | 382 | break; |
383 | case NFS4_OPEN_CLAIM_DELEG_PREV_FH: | ||
366 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: | 384 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: |
367 | open->op_stateowner->so_confirmed = 1; | 385 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; |
368 | dprintk("NFSD: unsupported OPEN claim type %d\n", | 386 | dprintk("NFSD: unsupported OPEN claim type %d\n", |
369 | open->op_claim_type); | 387 | open->op_claim_type); |
370 | status = nfserr_notsupp; | 388 | status = nfserr_notsupp; |
@@ -381,12 +399,13 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
381 | * set, (2) sets open->op_stateid, (3) sets open->op_delegation. | 399 | * set, (2) sets open->op_stateid, (3) sets open->op_delegation. |
382 | */ | 400 | */ |
383 | status = nfsd4_process_open2(rqstp, &cstate->current_fh, open); | 401 | status = nfsd4_process_open2(rqstp, &cstate->current_fh, open); |
402 | WARN_ON(status && open->op_created); | ||
384 | out: | 403 | out: |
385 | if (open->op_stateowner) { | 404 | nfsd4_cleanup_open_state(open, status); |
386 | nfs4_get_stateowner(open->op_stateowner); | 405 | if (open->op_openowner) |
387 | cstate->replay_owner = open->op_stateowner; | 406 | cstate->replay_owner = &open->op_openowner->oo_owner; |
388 | } | 407 | else |
389 | nfs4_unlock_state(); | 408 | nfs4_unlock_state(); |
390 | return status; | 409 | return status; |
391 | } | 410 | } |
392 | 411 | ||
@@ -467,17 +486,12 @@ static __be32 | |||
467 | nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 486 | nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
468 | struct nfsd4_commit *commit) | 487 | struct nfsd4_commit *commit) |
469 | { | 488 | { |
470 | __be32 status; | ||
471 | |||
472 | u32 *p = (u32 *)commit->co_verf.data; | 489 | u32 *p = (u32 *)commit->co_verf.data; |
473 | *p++ = nfssvc_boot.tv_sec; | 490 | *p++ = nfssvc_boot.tv_sec; |
474 | *p++ = nfssvc_boot.tv_usec; | 491 | *p++ = nfssvc_boot.tv_usec; |
475 | 492 | ||
476 | status = nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, | 493 | return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, |
477 | commit->co_count); | 494 | commit->co_count); |
478 | if (status == nfserr_symlink) | ||
479 | status = nfserr_inval; | ||
480 | return status; | ||
481 | } | 495 | } |
482 | 496 | ||
483 | static __be32 | 497 | static __be32 |
@@ -492,8 +506,6 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
492 | 506 | ||
493 | status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, | 507 | status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, |
494 | NFSD_MAY_CREATE); | 508 | NFSD_MAY_CREATE); |
495 | if (status == nfserr_symlink) | ||
496 | status = nfserr_notdir; | ||
497 | if (status) | 509 | if (status) |
498 | return status; | 510 | return status; |
499 | 511 | ||
@@ -691,7 +703,7 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
691 | readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion); | 703 | readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion); |
692 | readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion); | 704 | readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion); |
693 | 705 | ||
694 | if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) || | 706 | if ((cookie == 1) || (cookie == 2) || |
695 | (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE))) | 707 | (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE))) |
696 | return nfserr_bad_cookie; | 708 | return nfserr_bad_cookie; |
697 | 709 | ||
@@ -719,8 +731,6 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
719 | return nfserr_grace; | 731 | return nfserr_grace; |
720 | status = nfsd_unlink(rqstp, &cstate->current_fh, 0, | 732 | status = nfsd_unlink(rqstp, &cstate->current_fh, 0, |
721 | remove->rm_name, remove->rm_namelen); | 733 | remove->rm_name, remove->rm_namelen); |
722 | if (status == nfserr_symlink) | ||
723 | return nfserr_notdir; | ||
724 | if (!status) { | 734 | if (!status) { |
725 | fh_unlock(&cstate->current_fh); | 735 | fh_unlock(&cstate->current_fh); |
726 | set_change_info(&remove->rm_cinfo, &cstate->current_fh); | 736 | set_change_info(&remove->rm_cinfo, &cstate->current_fh); |
@@ -751,8 +761,6 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
751 | (S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) && | 761 | (S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) && |
752 | S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode))) | 762 | S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode))) |
753 | status = nfserr_exist; | 763 | status = nfserr_exist; |
754 | else if (status == nfserr_symlink) | ||
755 | status = nfserr_notdir; | ||
756 | 764 | ||
757 | if (!status) { | 765 | if (!status) { |
758 | set_change_info(&rename->rn_sinfo, &cstate->current_fh); | 766 | set_change_info(&rename->rn_sinfo, &cstate->current_fh); |
@@ -892,8 +900,6 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
892 | 900 | ||
893 | write->wr_bytes_written = cnt; | 901 | write->wr_bytes_written = cnt; |
894 | 902 | ||
895 | if (status == nfserr_symlink) | ||
896 | status = nfserr_inval; | ||
897 | return status; | 903 | return status; |
898 | } | 904 | } |
899 | 905 | ||
@@ -930,7 +936,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
930 | count = 4 + (verify->ve_attrlen >> 2); | 936 | count = 4 + (verify->ve_attrlen >> 2); |
931 | buf = kmalloc(count << 2, GFP_KERNEL); | 937 | buf = kmalloc(count << 2, GFP_KERNEL); |
932 | if (!buf) | 938 | if (!buf) |
933 | return nfserr_resource; | 939 | return nfserr_jukebox; |
934 | 940 | ||
935 | status = nfsd4_encode_fattr(&cstate->current_fh, | 941 | status = nfsd4_encode_fattr(&cstate->current_fh, |
936 | cstate->current_fh.fh_export, | 942 | cstate->current_fh.fh_export, |
@@ -994,6 +1000,8 @@ static inline void nfsd4_increment_op_stats(u32 opnum) | |||
994 | 1000 | ||
995 | typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, | 1001 | typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, |
996 | void *); | 1002 | void *); |
1003 | typedef u32(*nfsd4op_rsize)(struct svc_rqst *, struct nfsd4_op *op); | ||
1004 | |||
997 | enum nfsd4_op_flags { | 1005 | enum nfsd4_op_flags { |
998 | ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ | 1006 | ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ |
999 | ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */ | 1007 | ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */ |
@@ -1001,13 +1009,15 @@ enum nfsd4_op_flags { | |||
1001 | /* For rfc 5661 section 2.6.3.1.1: */ | 1009 | /* For rfc 5661 section 2.6.3.1.1: */ |
1002 | OP_HANDLES_WRONGSEC = 1 << 3, | 1010 | OP_HANDLES_WRONGSEC = 1 << 3, |
1003 | OP_IS_PUTFH_LIKE = 1 << 4, | 1011 | OP_IS_PUTFH_LIKE = 1 << 4, |
1004 | }; | ||
1005 | |||
1006 | struct nfsd4_operation { | ||
1007 | nfsd4op_func op_func; | ||
1008 | u32 op_flags; | ||
1009 | char *op_name; | ||
1010 | /* | 1012 | /* |
1013 | * These are the ops whose result size we estimate before | ||
1014 | * encoding, to avoid performing an op then not being able to | ||
1015 | * respond or cache a response. This includes writes and setattrs | ||
1016 | * as well as the operations usually called "nonidempotent": | ||
1017 | */ | ||
1018 | OP_MODIFIES_SOMETHING = 1 << 5, | ||
1019 | /* | ||
1020 | * Cache compounds containing these ops in the xid-based drc: | ||
1011 | * We use the DRC for compounds containing non-idempotent | 1021 | * We use the DRC for compounds containing non-idempotent |
1012 | * operations, *except* those that are 4.1-specific (since | 1022 | * operations, *except* those that are 4.1-specific (since |
1013 | * sessions provide their own EOS), and except for stateful | 1023 | * sessions provide their own EOS), and except for stateful |
@@ -1015,7 +1025,15 @@ struct nfsd4_operation { | |||
1015 | * (since sequence numbers provide EOS for open, lock, etc in | 1025 | * (since sequence numbers provide EOS for open, lock, etc in |
1016 | * the v4.0 case). | 1026 | * the v4.0 case). |
1017 | */ | 1027 | */ |
1018 | bool op_cacheresult; | 1028 | OP_CACHEME = 1 << 6, |
1029 | }; | ||
1030 | |||
1031 | struct nfsd4_operation { | ||
1032 | nfsd4op_func op_func; | ||
1033 | u32 op_flags; | ||
1034 | char *op_name; | ||
1035 | /* Try to get response size before operation */ | ||
1036 | nfsd4op_rsize op_rsize_bop; | ||
1019 | }; | 1037 | }; |
1020 | 1038 | ||
1021 | static struct nfsd4_operation nfsd4_ops[]; | 1039 | static struct nfsd4_operation nfsd4_ops[]; |
@@ -1062,7 +1080,7 @@ static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op) | |||
1062 | 1080 | ||
1063 | bool nfsd4_cache_this_op(struct nfsd4_op *op) | 1081 | bool nfsd4_cache_this_op(struct nfsd4_op *op) |
1064 | { | 1082 | { |
1065 | return OPDESC(op)->op_cacheresult; | 1083 | return OPDESC(op)->op_flags & OP_CACHEME; |
1066 | } | 1084 | } |
1067 | 1085 | ||
1068 | static bool need_wrongsec_check(struct svc_rqst *rqstp) | 1086 | static bool need_wrongsec_check(struct svc_rqst *rqstp) |
@@ -1110,6 +1128,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1110 | struct nfsd4_operation *opdesc; | 1128 | struct nfsd4_operation *opdesc; |
1111 | struct nfsd4_compound_state *cstate = &resp->cstate; | 1129 | struct nfsd4_compound_state *cstate = &resp->cstate; |
1112 | int slack_bytes; | 1130 | int slack_bytes; |
1131 | u32 plen = 0; | ||
1113 | __be32 status; | 1132 | __be32 status; |
1114 | 1133 | ||
1115 | resp->xbuf = &rqstp->rq_res; | 1134 | resp->xbuf = &rqstp->rq_res; |
@@ -1188,6 +1207,15 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1188 | goto encode_op; | 1207 | goto encode_op; |
1189 | } | 1208 | } |
1190 | 1209 | ||
1210 | /* If op is non-idempotent */ | ||
1211 | if (opdesc->op_flags & OP_MODIFIES_SOMETHING) { | ||
1212 | plen = opdesc->op_rsize_bop(rqstp, op); | ||
1213 | op->status = nfsd4_check_resp_size(resp, plen); | ||
1214 | } | ||
1215 | |||
1216 | if (op->status) | ||
1217 | goto encode_op; | ||
1218 | |||
1191 | if (opdesc->op_func) | 1219 | if (opdesc->op_func) |
1192 | op->status = opdesc->op_func(rqstp, cstate, &op->u); | 1220 | op->status = opdesc->op_func(rqstp, cstate, &op->u); |
1193 | else | 1221 | else |
@@ -1217,7 +1245,7 @@ encode_op: | |||
1217 | be32_to_cpu(status)); | 1245 | be32_to_cpu(status)); |
1218 | 1246 | ||
1219 | if (cstate->replay_owner) { | 1247 | if (cstate->replay_owner) { |
1220 | nfs4_put_stateowner(cstate->replay_owner); | 1248 | nfs4_unlock_state(); |
1221 | cstate->replay_owner = NULL; | 1249 | cstate->replay_owner = NULL; |
1222 | } | 1250 | } |
1223 | /* XXX Ugh, we need to get rid of this kind of special case: */ | 1251 | /* XXX Ugh, we need to get rid of this kind of special case: */ |
@@ -1238,6 +1266,144 @@ out: | |||
1238 | return status; | 1266 | return status; |
1239 | } | 1267 | } |
1240 | 1268 | ||
1269 | #define op_encode_hdr_size (2) | ||
1270 | #define op_encode_stateid_maxsz (XDR_QUADLEN(NFS4_STATEID_SIZE)) | ||
1271 | #define op_encode_verifier_maxsz (XDR_QUADLEN(NFS4_VERIFIER_SIZE)) | ||
1272 | #define op_encode_change_info_maxsz (5) | ||
1273 | #define nfs4_fattr_bitmap_maxsz (4) | ||
1274 | |||
1275 | #define op_encode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) | ||
1276 | #define op_encode_lock_denied_maxsz (8 + op_encode_lockowner_maxsz) | ||
1277 | |||
1278 | #define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) | ||
1279 | |||
1280 | #define op_encode_ace_maxsz (3 + nfs4_owner_maxsz) | ||
1281 | #define op_encode_delegation_maxsz (1 + op_encode_stateid_maxsz + 1 + \ | ||
1282 | op_encode_ace_maxsz) | ||
1283 | |||
1284 | #define op_encode_channel_attrs_maxsz (6 + 1 + 1) | ||
1285 | |||
1286 | static inline u32 nfsd4_only_status_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1287 | { | ||
1288 | return (op_encode_hdr_size) * sizeof(__be32); | ||
1289 | } | ||
1290 | |||
1291 | static inline u32 nfsd4_status_stateid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1292 | { | ||
1293 | return (op_encode_hdr_size + op_encode_stateid_maxsz)* sizeof(__be32); | ||
1294 | } | ||
1295 | |||
1296 | static inline u32 nfsd4_commit_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1297 | { | ||
1298 | return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32); | ||
1299 | } | ||
1300 | |||
1301 | static inline u32 nfsd4_create_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1302 | { | ||
1303 | return (op_encode_hdr_size + op_encode_change_info_maxsz | ||
1304 | + nfs4_fattr_bitmap_maxsz) * sizeof(__be32); | ||
1305 | } | ||
1306 | |||
1307 | static inline u32 nfsd4_link_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1308 | { | ||
1309 | return (op_encode_hdr_size + op_encode_change_info_maxsz) | ||
1310 | * sizeof(__be32); | ||
1311 | } | ||
1312 | |||
1313 | static inline u32 nfsd4_lock_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1314 | { | ||
1315 | return (op_encode_hdr_size + op_encode_lock_denied_maxsz) | ||
1316 | * sizeof(__be32); | ||
1317 | } | ||
1318 | |||
1319 | static inline u32 nfsd4_open_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1320 | { | ||
1321 | return (op_encode_hdr_size + op_encode_stateid_maxsz | ||
1322 | + op_encode_change_info_maxsz + 1 | ||
1323 | + nfs4_fattr_bitmap_maxsz | ||
1324 | + op_encode_delegation_maxsz) * sizeof(__be32); | ||
1325 | } | ||
1326 | |||
1327 | static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1328 | { | ||
1329 | u32 maxcount = 0, rlen = 0; | ||
1330 | |||
1331 | maxcount = svc_max_payload(rqstp); | ||
1332 | rlen = op->u.read.rd_length; | ||
1333 | |||
1334 | if (rlen > maxcount) | ||
1335 | rlen = maxcount; | ||
1336 | |||
1337 | return (op_encode_hdr_size + 2) * sizeof(__be32) + rlen; | ||
1338 | } | ||
1339 | |||
1340 | static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1341 | { | ||
1342 | u32 rlen = op->u.readdir.rd_maxcount; | ||
1343 | |||
1344 | if (rlen > PAGE_SIZE) | ||
1345 | rlen = PAGE_SIZE; | ||
1346 | |||
1347 | return (op_encode_hdr_size + op_encode_verifier_maxsz) | ||
1348 | * sizeof(__be32) + rlen; | ||
1349 | } | ||
1350 | |||
1351 | static inline u32 nfsd4_remove_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1352 | { | ||
1353 | return (op_encode_hdr_size + op_encode_change_info_maxsz) | ||
1354 | * sizeof(__be32); | ||
1355 | } | ||
1356 | |||
1357 | static inline u32 nfsd4_rename_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1358 | { | ||
1359 | return (op_encode_hdr_size + op_encode_change_info_maxsz | ||
1360 | + op_encode_change_info_maxsz) * sizeof(__be32); | ||
1361 | } | ||
1362 | |||
1363 | static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1364 | { | ||
1365 | return (op_encode_hdr_size + nfs4_fattr_bitmap_maxsz) * sizeof(__be32); | ||
1366 | } | ||
1367 | |||
1368 | static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1369 | { | ||
1370 | return (op_encode_hdr_size + 2 + 1024) * sizeof(__be32); | ||
1371 | } | ||
1372 | |||
1373 | static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1374 | { | ||
1375 | return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32); | ||
1376 | } | ||
1377 | |||
1378 | static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1379 | { | ||
1380 | return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\ | ||
1381 | 1 + 1 + 0 + /* eir_flags, spr_how, SP4_NONE (for now) */\ | ||
1382 | 2 + /*eir_server_owner.so_minor_id */\ | ||
1383 | /* eir_server_owner.so_major_id<> */\ | ||
1384 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\ | ||
1385 | /* eir_server_scope<> */\ | ||
1386 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\ | ||
1387 | 1 + /* eir_server_impl_id array length */\ | ||
1388 | 0 /* ignored eir_server_impl_id contents */) * sizeof(__be32); | ||
1389 | } | ||
1390 | |||
1391 | static inline u32 nfsd4_bind_conn_to_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1392 | { | ||
1393 | return (op_encode_hdr_size + \ | ||
1394 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* bctsr_sessid */\ | ||
1395 | 2 /* bctsr_dir, use_conn_in_rdma_mode */) * sizeof(__be32); | ||
1396 | } | ||
1397 | |||
1398 | static inline u32 nfsd4_create_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | ||
1399 | { | ||
1400 | return (op_encode_hdr_size + \ | ||
1401 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* sessionid */\ | ||
1402 | 2 + /* csr_sequence, csr_flags */\ | ||
1403 | op_encode_channel_attrs_maxsz + \ | ||
1404 | op_encode_channel_attrs_maxsz) * sizeof(__be32); | ||
1405 | } | ||
1406 | |||
1241 | static struct nfsd4_operation nfsd4_ops[] = { | 1407 | static struct nfsd4_operation nfsd4_ops[] = { |
1242 | [OP_ACCESS] = { | 1408 | [OP_ACCESS] = { |
1243 | .op_func = (nfsd4op_func)nfsd4_access, | 1409 | .op_func = (nfsd4op_func)nfsd4_access, |
@@ -1245,20 +1411,27 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1245 | }, | 1411 | }, |
1246 | [OP_CLOSE] = { | 1412 | [OP_CLOSE] = { |
1247 | .op_func = (nfsd4op_func)nfsd4_close, | 1413 | .op_func = (nfsd4op_func)nfsd4_close, |
1414 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1248 | .op_name = "OP_CLOSE", | 1415 | .op_name = "OP_CLOSE", |
1416 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | ||
1249 | }, | 1417 | }, |
1250 | [OP_COMMIT] = { | 1418 | [OP_COMMIT] = { |
1251 | .op_func = (nfsd4op_func)nfsd4_commit, | 1419 | .op_func = (nfsd4op_func)nfsd4_commit, |
1420 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1252 | .op_name = "OP_COMMIT", | 1421 | .op_name = "OP_COMMIT", |
1422 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_commit_rsize, | ||
1253 | }, | 1423 | }, |
1254 | [OP_CREATE] = { | 1424 | [OP_CREATE] = { |
1255 | .op_func = (nfsd4op_func)nfsd4_create, | 1425 | .op_func = (nfsd4op_func)nfsd4_create, |
1426 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, | ||
1256 | .op_name = "OP_CREATE", | 1427 | .op_name = "OP_CREATE", |
1257 | .op_cacheresult = true, | 1428 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_rsize, |
1258 | }, | 1429 | }, |
1259 | [OP_DELEGRETURN] = { | 1430 | [OP_DELEGRETURN] = { |
1260 | .op_func = (nfsd4op_func)nfsd4_delegreturn, | 1431 | .op_func = (nfsd4op_func)nfsd4_delegreturn, |
1432 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1261 | .op_name = "OP_DELEGRETURN", | 1433 | .op_name = "OP_DELEGRETURN", |
1434 | .op_rsize_bop = nfsd4_only_status_rsize, | ||
1262 | }, | 1435 | }, |
1263 | [OP_GETATTR] = { | 1436 | [OP_GETATTR] = { |
1264 | .op_func = (nfsd4op_func)nfsd4_getattr, | 1437 | .op_func = (nfsd4op_func)nfsd4_getattr, |
@@ -1271,12 +1444,16 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1271 | }, | 1444 | }, |
1272 | [OP_LINK] = { | 1445 | [OP_LINK] = { |
1273 | .op_func = (nfsd4op_func)nfsd4_link, | 1446 | .op_func = (nfsd4op_func)nfsd4_link, |
1447 | .op_flags = ALLOWED_ON_ABSENT_FS | OP_MODIFIES_SOMETHING | ||
1448 | | OP_CACHEME, | ||
1274 | .op_name = "OP_LINK", | 1449 | .op_name = "OP_LINK", |
1275 | .op_cacheresult = true, | 1450 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_link_rsize, |
1276 | }, | 1451 | }, |
1277 | [OP_LOCK] = { | 1452 | [OP_LOCK] = { |
1278 | .op_func = (nfsd4op_func)nfsd4_lock, | 1453 | .op_func = (nfsd4op_func)nfsd4_lock, |
1454 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1279 | .op_name = "OP_LOCK", | 1455 | .op_name = "OP_LOCK", |
1456 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_lock_rsize, | ||
1280 | }, | 1457 | }, |
1281 | [OP_LOCKT] = { | 1458 | [OP_LOCKT] = { |
1282 | .op_func = (nfsd4op_func)nfsd4_lockt, | 1459 | .op_func = (nfsd4op_func)nfsd4_lockt, |
@@ -1284,7 +1461,9 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1284 | }, | 1461 | }, |
1285 | [OP_LOCKU] = { | 1462 | [OP_LOCKU] = { |
1286 | .op_func = (nfsd4op_func)nfsd4_locku, | 1463 | .op_func = (nfsd4op_func)nfsd4_locku, |
1464 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1287 | .op_name = "OP_LOCKU", | 1465 | .op_name = "OP_LOCKU", |
1466 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | ||
1288 | }, | 1467 | }, |
1289 | [OP_LOOKUP] = { | 1468 | [OP_LOOKUP] = { |
1290 | .op_func = (nfsd4op_func)nfsd4_lookup, | 1469 | .op_func = (nfsd4op_func)nfsd4_lookup, |
@@ -1302,42 +1481,54 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1302 | }, | 1481 | }, |
1303 | [OP_OPEN] = { | 1482 | [OP_OPEN] = { |
1304 | .op_func = (nfsd4op_func)nfsd4_open, | 1483 | .op_func = (nfsd4op_func)nfsd4_open, |
1305 | .op_flags = OP_HANDLES_WRONGSEC, | 1484 | .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, |
1306 | .op_name = "OP_OPEN", | 1485 | .op_name = "OP_OPEN", |
1486 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_open_rsize, | ||
1307 | }, | 1487 | }, |
1308 | [OP_OPEN_CONFIRM] = { | 1488 | [OP_OPEN_CONFIRM] = { |
1309 | .op_func = (nfsd4op_func)nfsd4_open_confirm, | 1489 | .op_func = (nfsd4op_func)nfsd4_open_confirm, |
1490 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1310 | .op_name = "OP_OPEN_CONFIRM", | 1491 | .op_name = "OP_OPEN_CONFIRM", |
1492 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | ||
1311 | }, | 1493 | }, |
1312 | [OP_OPEN_DOWNGRADE] = { | 1494 | [OP_OPEN_DOWNGRADE] = { |
1313 | .op_func = (nfsd4op_func)nfsd4_open_downgrade, | 1495 | .op_func = (nfsd4op_func)nfsd4_open_downgrade, |
1496 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1314 | .op_name = "OP_OPEN_DOWNGRADE", | 1497 | .op_name = "OP_OPEN_DOWNGRADE", |
1498 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | ||
1315 | }, | 1499 | }, |
1316 | [OP_PUTFH] = { | 1500 | [OP_PUTFH] = { |
1317 | .op_func = (nfsd4op_func)nfsd4_putfh, | 1501 | .op_func = (nfsd4op_func)nfsd4_putfh, |
1318 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1502 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1319 | | OP_IS_PUTFH_LIKE, | 1503 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, |
1320 | .op_name = "OP_PUTFH", | 1504 | .op_name = "OP_PUTFH", |
1505 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1321 | }, | 1506 | }, |
1322 | [OP_PUTPUBFH] = { | 1507 | [OP_PUTPUBFH] = { |
1323 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | 1508 | .op_func = (nfsd4op_func)nfsd4_putrootfh, |
1324 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1509 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1325 | | OP_IS_PUTFH_LIKE, | 1510 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, |
1326 | .op_name = "OP_PUTPUBFH", | 1511 | .op_name = "OP_PUTPUBFH", |
1512 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1327 | }, | 1513 | }, |
1328 | [OP_PUTROOTFH] = { | 1514 | [OP_PUTROOTFH] = { |
1329 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | 1515 | .op_func = (nfsd4op_func)nfsd4_putrootfh, |
1330 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1516 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1331 | | OP_IS_PUTFH_LIKE, | 1517 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, |
1332 | .op_name = "OP_PUTROOTFH", | 1518 | .op_name = "OP_PUTROOTFH", |
1519 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1333 | }, | 1520 | }, |
1334 | [OP_READ] = { | 1521 | [OP_READ] = { |
1335 | .op_func = (nfsd4op_func)nfsd4_read, | 1522 | .op_func = (nfsd4op_func)nfsd4_read, |
1523 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1336 | .op_name = "OP_READ", | 1524 | .op_name = "OP_READ", |
1525 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_read_rsize, | ||
1337 | }, | 1526 | }, |
1338 | [OP_READDIR] = { | 1527 | [OP_READDIR] = { |
1339 | .op_func = (nfsd4op_func)nfsd4_readdir, | 1528 | .op_func = (nfsd4op_func)nfsd4_readdir, |
1529 | .op_flags = OP_MODIFIES_SOMETHING, | ||
1340 | .op_name = "OP_READDIR", | 1530 | .op_name = "OP_READDIR", |
1531 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_readdir_rsize, | ||
1341 | }, | 1532 | }, |
1342 | [OP_READLINK] = { | 1533 | [OP_READLINK] = { |
1343 | .op_func = (nfsd4op_func)nfsd4_readlink, | 1534 | .op_func = (nfsd4op_func)nfsd4_readlink, |
@@ -1345,29 +1536,36 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1345 | }, | 1536 | }, |
1346 | [OP_REMOVE] = { | 1537 | [OP_REMOVE] = { |
1347 | .op_func = (nfsd4op_func)nfsd4_remove, | 1538 | .op_func = (nfsd4op_func)nfsd4_remove, |
1539 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, | ||
1348 | .op_name = "OP_REMOVE", | 1540 | .op_name = "OP_REMOVE", |
1349 | .op_cacheresult = true, | 1541 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_remove_rsize, |
1350 | }, | 1542 | }, |
1351 | [OP_RENAME] = { | 1543 | [OP_RENAME] = { |
1352 | .op_name = "OP_RENAME", | ||
1353 | .op_func = (nfsd4op_func)nfsd4_rename, | 1544 | .op_func = (nfsd4op_func)nfsd4_rename, |
1354 | .op_cacheresult = true, | 1545 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, |
1546 | .op_name = "OP_RENAME", | ||
1547 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_rename_rsize, | ||
1355 | }, | 1548 | }, |
1356 | [OP_RENEW] = { | 1549 | [OP_RENEW] = { |
1357 | .op_func = (nfsd4op_func)nfsd4_renew, | 1550 | .op_func = (nfsd4op_func)nfsd4_renew, |
1358 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1551 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1552 | | OP_MODIFIES_SOMETHING, | ||
1359 | .op_name = "OP_RENEW", | 1553 | .op_name = "OP_RENEW", |
1554 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1555 | |||
1360 | }, | 1556 | }, |
1361 | [OP_RESTOREFH] = { | 1557 | [OP_RESTOREFH] = { |
1362 | .op_func = (nfsd4op_func)nfsd4_restorefh, | 1558 | .op_func = (nfsd4op_func)nfsd4_restorefh, |
1363 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1559 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1364 | | OP_IS_PUTFH_LIKE, | 1560 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, |
1365 | .op_name = "OP_RESTOREFH", | 1561 | .op_name = "OP_RESTOREFH", |
1562 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1366 | }, | 1563 | }, |
1367 | [OP_SAVEFH] = { | 1564 | [OP_SAVEFH] = { |
1368 | .op_func = (nfsd4op_func)nfsd4_savefh, | 1565 | .op_func = (nfsd4op_func)nfsd4_savefh, |
1369 | .op_flags = OP_HANDLES_WRONGSEC, | 1566 | .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, |
1370 | .op_name = "OP_SAVEFH", | 1567 | .op_name = "OP_SAVEFH", |
1568 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1371 | }, | 1569 | }, |
1372 | [OP_SECINFO] = { | 1570 | [OP_SECINFO] = { |
1373 | .op_func = (nfsd4op_func)nfsd4_secinfo, | 1571 | .op_func = (nfsd4op_func)nfsd4_secinfo, |
@@ -1377,19 +1575,22 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1377 | [OP_SETATTR] = { | 1575 | [OP_SETATTR] = { |
1378 | .op_func = (nfsd4op_func)nfsd4_setattr, | 1576 | .op_func = (nfsd4op_func)nfsd4_setattr, |
1379 | .op_name = "OP_SETATTR", | 1577 | .op_name = "OP_SETATTR", |
1380 | .op_cacheresult = true, | 1578 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, |
1579 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_setattr_rsize, | ||
1381 | }, | 1580 | }, |
1382 | [OP_SETCLIENTID] = { | 1581 | [OP_SETCLIENTID] = { |
1383 | .op_func = (nfsd4op_func)nfsd4_setclientid, | 1582 | .op_func = (nfsd4op_func)nfsd4_setclientid, |
1384 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1583 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1584 | | OP_MODIFIES_SOMETHING | OP_CACHEME, | ||
1385 | .op_name = "OP_SETCLIENTID", | 1585 | .op_name = "OP_SETCLIENTID", |
1386 | .op_cacheresult = true, | 1586 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_setclientid_rsize, |
1387 | }, | 1587 | }, |
1388 | [OP_SETCLIENTID_CONFIRM] = { | 1588 | [OP_SETCLIENTID_CONFIRM] = { |
1389 | .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, | 1589 | .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, |
1390 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1590 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1591 | | OP_MODIFIES_SOMETHING | OP_CACHEME, | ||
1391 | .op_name = "OP_SETCLIENTID_CONFIRM", | 1592 | .op_name = "OP_SETCLIENTID_CONFIRM", |
1392 | .op_cacheresult = true, | 1593 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1393 | }, | 1594 | }, |
1394 | [OP_VERIFY] = { | 1595 | [OP_VERIFY] = { |
1395 | .op_func = (nfsd4op_func)nfsd4_verify, | 1596 | .op_func = (nfsd4op_func)nfsd4_verify, |
@@ -1397,35 +1598,46 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1397 | }, | 1598 | }, |
1398 | [OP_WRITE] = { | 1599 | [OP_WRITE] = { |
1399 | .op_func = (nfsd4op_func)nfsd4_write, | 1600 | .op_func = (nfsd4op_func)nfsd4_write, |
1601 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, | ||
1400 | .op_name = "OP_WRITE", | 1602 | .op_name = "OP_WRITE", |
1401 | .op_cacheresult = true, | 1603 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize, |
1402 | }, | 1604 | }, |
1403 | [OP_RELEASE_LOCKOWNER] = { | 1605 | [OP_RELEASE_LOCKOWNER] = { |
1404 | .op_func = (nfsd4op_func)nfsd4_release_lockowner, | 1606 | .op_func = (nfsd4op_func)nfsd4_release_lockowner, |
1405 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1607 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1608 | | OP_MODIFIES_SOMETHING, | ||
1406 | .op_name = "OP_RELEASE_LOCKOWNER", | 1609 | .op_name = "OP_RELEASE_LOCKOWNER", |
1610 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1407 | }, | 1611 | }, |
1408 | 1612 | ||
1409 | /* NFSv4.1 operations */ | 1613 | /* NFSv4.1 operations */ |
1410 | [OP_EXCHANGE_ID] = { | 1614 | [OP_EXCHANGE_ID] = { |
1411 | .op_func = (nfsd4op_func)nfsd4_exchange_id, | 1615 | .op_func = (nfsd4op_func)nfsd4_exchange_id, |
1412 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1616 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1617 | | OP_MODIFIES_SOMETHING, | ||
1413 | .op_name = "OP_EXCHANGE_ID", | 1618 | .op_name = "OP_EXCHANGE_ID", |
1619 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize, | ||
1414 | }, | 1620 | }, |
1415 | [OP_BIND_CONN_TO_SESSION] = { | 1621 | [OP_BIND_CONN_TO_SESSION] = { |
1416 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, | 1622 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, |
1417 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1623 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1624 | | OP_MODIFIES_SOMETHING, | ||
1418 | .op_name = "OP_BIND_CONN_TO_SESSION", | 1625 | .op_name = "OP_BIND_CONN_TO_SESSION", |
1626 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_bind_conn_to_session_rsize, | ||
1419 | }, | 1627 | }, |
1420 | [OP_CREATE_SESSION] = { | 1628 | [OP_CREATE_SESSION] = { |
1421 | .op_func = (nfsd4op_func)nfsd4_create_session, | 1629 | .op_func = (nfsd4op_func)nfsd4_create_session, |
1422 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1630 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1631 | | OP_MODIFIES_SOMETHING, | ||
1423 | .op_name = "OP_CREATE_SESSION", | 1632 | .op_name = "OP_CREATE_SESSION", |
1633 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_session_rsize, | ||
1424 | }, | 1634 | }, |
1425 | [OP_DESTROY_SESSION] = { | 1635 | [OP_DESTROY_SESSION] = { |
1426 | .op_func = (nfsd4op_func)nfsd4_destroy_session, | 1636 | .op_func = (nfsd4op_func)nfsd4_destroy_session, |
1427 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1637 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1638 | | OP_MODIFIES_SOMETHING, | ||
1428 | .op_name = "OP_DESTROY_SESSION", | 1639 | .op_name = "OP_DESTROY_SESSION", |
1640 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1429 | }, | 1641 | }, |
1430 | [OP_SEQUENCE] = { | 1642 | [OP_SEQUENCE] = { |
1431 | .op_func = (nfsd4op_func)nfsd4_sequence, | 1643 | .op_func = (nfsd4op_func)nfsd4_sequence, |
@@ -1433,14 +1645,17 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1433 | .op_name = "OP_SEQUENCE", | 1645 | .op_name = "OP_SEQUENCE", |
1434 | }, | 1646 | }, |
1435 | [OP_DESTROY_CLIENTID] = { | 1647 | [OP_DESTROY_CLIENTID] = { |
1436 | .op_func = NULL, | 1648 | .op_func = (nfsd4op_func)nfsd4_destroy_clientid, |
1437 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1649 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1650 | | OP_MODIFIES_SOMETHING, | ||
1438 | .op_name = "OP_DESTROY_CLIENTID", | 1651 | .op_name = "OP_DESTROY_CLIENTID", |
1652 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1439 | }, | 1653 | }, |
1440 | [OP_RECLAIM_COMPLETE] = { | 1654 | [OP_RECLAIM_COMPLETE] = { |
1441 | .op_func = (nfsd4op_func)nfsd4_reclaim_complete, | 1655 | .op_func = (nfsd4op_func)nfsd4_reclaim_complete, |
1442 | .op_flags = ALLOWED_WITHOUT_FH, | 1656 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, |
1443 | .op_name = "OP_RECLAIM_COMPLETE", | 1657 | .op_name = "OP_RECLAIM_COMPLETE", |
1658 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1444 | }, | 1659 | }, |
1445 | [OP_SECINFO_NO_NAME] = { | 1660 | [OP_SECINFO_NO_NAME] = { |
1446 | .op_func = (nfsd4op_func)nfsd4_secinfo_no_name, | 1661 | .op_func = (nfsd4op_func)nfsd4_secinfo_no_name, |
@@ -1454,8 +1669,9 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1454 | }, | 1669 | }, |
1455 | [OP_FREE_STATEID] = { | 1670 | [OP_FREE_STATEID] = { |
1456 | .op_func = (nfsd4op_func)nfsd4_free_stateid, | 1671 | .op_func = (nfsd4op_func)nfsd4_free_stateid, |
1457 | .op_flags = ALLOWED_WITHOUT_FH, | 1672 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, |
1458 | .op_name = "OP_FREE_STATEID", | 1673 | .op_name = "OP_FREE_STATEID", |
1674 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1459 | }, | 1675 | }, |
1460 | }; | 1676 | }; |
1461 | 1677 | ||
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 29d77f60585b..ed083b9a731b 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -45,6 +45,7 @@ | |||
45 | 45 | ||
46 | /* Globals */ | 46 | /* Globals */ |
47 | static struct file *rec_file; | 47 | static struct file *rec_file; |
48 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; | ||
48 | 49 | ||
49 | static int | 50 | static int |
50 | nfs4_save_creds(const struct cred **original_creds) | 51 | nfs4_save_creds(const struct cred **original_creds) |
@@ -88,7 +89,7 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) | |||
88 | struct xdr_netobj cksum; | 89 | struct xdr_netobj cksum; |
89 | struct hash_desc desc; | 90 | struct hash_desc desc; |
90 | struct scatterlist sg; | 91 | struct scatterlist sg; |
91 | __be32 status = nfserr_resource; | 92 | __be32 status = nfserr_jukebox; |
92 | 93 | ||
93 | dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", | 94 | dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", |
94 | clname->len, clname->data); | 95 | clname->len, clname->data); |
@@ -129,6 +130,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) | |||
129 | if (!rec_file || clp->cl_firststate) | 130 | if (!rec_file || clp->cl_firststate) |
130 | return 0; | 131 | return 0; |
131 | 132 | ||
133 | clp->cl_firststate = 1; | ||
132 | status = nfs4_save_creds(&original_cred); | 134 | status = nfs4_save_creds(&original_cred); |
133 | if (status < 0) | 135 | if (status < 0) |
134 | return status; | 136 | return status; |
@@ -143,10 +145,8 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) | |||
143 | goto out_unlock; | 145 | goto out_unlock; |
144 | } | 146 | } |
145 | status = -EEXIST; | 147 | status = -EEXIST; |
146 | if (dentry->d_inode) { | 148 | if (dentry->d_inode) |
147 | dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n"); | ||
148 | goto out_put; | 149 | goto out_put; |
149 | } | ||
150 | status = mnt_want_write(rec_file->f_path.mnt); | 150 | status = mnt_want_write(rec_file->f_path.mnt); |
151 | if (status) | 151 | if (status) |
152 | goto out_put; | 152 | goto out_put; |
@@ -156,12 +156,14 @@ out_put: | |||
156 | dput(dentry); | 156 | dput(dentry); |
157 | out_unlock: | 157 | out_unlock: |
158 | mutex_unlock(&dir->d_inode->i_mutex); | 158 | mutex_unlock(&dir->d_inode->i_mutex); |
159 | if (status == 0) { | 159 | if (status == 0) |
160 | clp->cl_firststate = 1; | ||
161 | vfs_fsync(rec_file, 0); | 160 | vfs_fsync(rec_file, 0); |
162 | } | 161 | else |
162 | printk(KERN_ERR "NFSD: failed to write recovery record" | ||
163 | " (err %d); please check that %s exists" | ||
164 | " and is writeable", status, | ||
165 | user_recovery_dirname); | ||
163 | nfs4_reset_creds(original_cred); | 166 | nfs4_reset_creds(original_cred); |
164 | dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status); | ||
165 | return status; | 167 | return status; |
166 | } | 168 | } |
167 | 169 | ||
@@ -354,13 +356,13 @@ nfsd4_recdir_load(void) { | |||
354 | */ | 356 | */ |
355 | 357 | ||
356 | void | 358 | void |
357 | nfsd4_init_recdir(char *rec_dirname) | 359 | nfsd4_init_recdir() |
358 | { | 360 | { |
359 | const struct cred *original_cred; | 361 | const struct cred *original_cred; |
360 | int status; | 362 | int status; |
361 | 363 | ||
362 | printk("NFSD: Using %s as the NFSv4 state recovery directory\n", | 364 | printk("NFSD: Using %s as the NFSv4 state recovery directory\n", |
363 | rec_dirname); | 365 | user_recovery_dirname); |
364 | 366 | ||
365 | BUG_ON(rec_file); | 367 | BUG_ON(rec_file); |
366 | 368 | ||
@@ -372,10 +374,10 @@ nfsd4_init_recdir(char *rec_dirname) | |||
372 | return; | 374 | return; |
373 | } | 375 | } |
374 | 376 | ||
375 | rec_file = filp_open(rec_dirname, O_RDONLY | O_DIRECTORY, 0); | 377 | rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0); |
376 | if (IS_ERR(rec_file)) { | 378 | if (IS_ERR(rec_file)) { |
377 | printk("NFSD: unable to find recovery directory %s\n", | 379 | printk("NFSD: unable to find recovery directory %s\n", |
378 | rec_dirname); | 380 | user_recovery_dirname); |
379 | rec_file = NULL; | 381 | rec_file = NULL; |
380 | } | 382 | } |
381 | 383 | ||
@@ -390,3 +392,30 @@ nfsd4_shutdown_recdir(void) | |||
390 | fput(rec_file); | 392 | fput(rec_file); |
391 | rec_file = NULL; | 393 | rec_file = NULL; |
392 | } | 394 | } |
395 | |||
396 | /* | ||
397 | * Change the NFSv4 recovery directory to recdir. | ||
398 | */ | ||
399 | int | ||
400 | nfs4_reset_recoverydir(char *recdir) | ||
401 | { | ||
402 | int status; | ||
403 | struct path path; | ||
404 | |||
405 | status = kern_path(recdir, LOOKUP_FOLLOW, &path); | ||
406 | if (status) | ||
407 | return status; | ||
408 | status = -ENOTDIR; | ||
409 | if (S_ISDIR(path.dentry->d_inode->i_mode)) { | ||
410 | strcpy(user_recovery_dirname, recdir); | ||
411 | status = 0; | ||
412 | } | ||
413 | path_put(&path); | ||
414 | return status; | ||
415 | } | ||
416 | |||
417 | char * | ||
418 | nfs4_recoverydir(void) | ||
419 | { | ||
420 | return user_recovery_dirname; | ||
421 | } | ||
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3787ec117400..47e94e33a975 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -49,9 +49,6 @@ | |||
49 | time_t nfsd4_lease = 90; /* default lease time */ | 49 | time_t nfsd4_lease = 90; /* default lease time */ |
50 | time_t nfsd4_grace = 90; | 50 | time_t nfsd4_grace = 90; |
51 | static time_t boot_time; | 51 | static time_t boot_time; |
52 | static u32 current_ownerid = 1; | ||
53 | static u32 current_fileid = 1; | ||
54 | static u32 current_delegid = 1; | ||
55 | static stateid_t zerostateid; /* bits all 0 */ | 52 | static stateid_t zerostateid; /* bits all 0 */ |
56 | static stateid_t onestateid; /* bits all 1 */ | 53 | static stateid_t onestateid; /* bits all 1 */ |
57 | static u64 current_sessionid = 1; | 54 | static u64 current_sessionid = 1; |
@@ -60,13 +57,7 @@ static u64 current_sessionid = 1; | |||
60 | #define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t))) | 57 | #define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t))) |
61 | 58 | ||
62 | /* forward declarations */ | 59 | /* forward declarations */ |
63 | static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); | 60 | static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner); |
64 | static struct nfs4_stateid * search_for_stateid(stateid_t *stid); | ||
65 | static struct nfs4_delegation * search_for_delegation(stateid_t *stid); | ||
66 | static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); | ||
67 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; | ||
68 | static void nfs4_set_recdir(char *recdir); | ||
69 | static int check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner); | ||
70 | 61 | ||
71 | /* Locking: */ | 62 | /* Locking: */ |
72 | 63 | ||
@@ -80,7 +71,8 @@ static DEFINE_MUTEX(client_mutex); | |||
80 | */ | 71 | */ |
81 | static DEFINE_SPINLOCK(recall_lock); | 72 | static DEFINE_SPINLOCK(recall_lock); |
82 | 73 | ||
83 | static struct kmem_cache *stateowner_slab = NULL; | 74 | static struct kmem_cache *openowner_slab = NULL; |
75 | static struct kmem_cache *lockowner_slab = NULL; | ||
84 | static struct kmem_cache *file_slab = NULL; | 76 | static struct kmem_cache *file_slab = NULL; |
85 | static struct kmem_cache *stateid_slab = NULL; | 77 | static struct kmem_cache *stateid_slab = NULL; |
86 | static struct kmem_cache *deleg_slab = NULL; | 78 | static struct kmem_cache *deleg_slab = NULL; |
@@ -112,6 +104,11 @@ opaque_hashval(const void *ptr, int nbytes) | |||
112 | 104 | ||
113 | static struct list_head del_recall_lru; | 105 | static struct list_head del_recall_lru; |
114 | 106 | ||
107 | static void nfsd4_free_file(struct nfs4_file *f) | ||
108 | { | ||
109 | kmem_cache_free(file_slab, f); | ||
110 | } | ||
111 | |||
115 | static inline void | 112 | static inline void |
116 | put_nfs4_file(struct nfs4_file *fi) | 113 | put_nfs4_file(struct nfs4_file *fi) |
117 | { | 114 | { |
@@ -119,7 +116,7 @@ put_nfs4_file(struct nfs4_file *fi) | |||
119 | list_del(&fi->fi_hash); | 116 | list_del(&fi->fi_hash); |
120 | spin_unlock(&recall_lock); | 117 | spin_unlock(&recall_lock); |
121 | iput(fi->fi_inode); | 118 | iput(fi->fi_inode); |
122 | kmem_cache_free(file_slab, fi); | 119 | nfsd4_free_file(fi); |
123 | } | 120 | } |
124 | } | 121 | } |
125 | 122 | ||
@@ -136,35 +133,33 @@ unsigned int max_delegations; | |||
136 | * Open owner state (share locks) | 133 | * Open owner state (share locks) |
137 | */ | 134 | */ |
138 | 135 | ||
139 | /* hash tables for nfs4_stateowner */ | 136 | /* hash tables for open owners */ |
140 | #define OWNER_HASH_BITS 8 | 137 | #define OPEN_OWNER_HASH_BITS 8 |
141 | #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) | 138 | #define OPEN_OWNER_HASH_SIZE (1 << OPEN_OWNER_HASH_BITS) |
142 | #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) | 139 | #define OPEN_OWNER_HASH_MASK (OPEN_OWNER_HASH_SIZE - 1) |
143 | 140 | ||
144 | #define ownerid_hashval(id) \ | 141 | static unsigned int open_ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername) |
145 | ((id) & OWNER_HASH_MASK) | 142 | { |
146 | #define ownerstr_hashval(clientid, ownername) \ | 143 | unsigned int ret; |
147 | (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK) | ||
148 | 144 | ||
149 | static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE]; | 145 | ret = opaque_hashval(ownername->data, ownername->len); |
150 | static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; | 146 | ret += clientid; |
147 | return ret & OPEN_OWNER_HASH_MASK; | ||
148 | } | ||
149 | |||
150 | static struct list_head open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE]; | ||
151 | 151 | ||
152 | /* hash table for nfs4_file */ | 152 | /* hash table for nfs4_file */ |
153 | #define FILE_HASH_BITS 8 | 153 | #define FILE_HASH_BITS 8 |
154 | #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) | 154 | #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) |
155 | 155 | ||
156 | /* hash table for (open)nfs4_stateid */ | 156 | static unsigned int file_hashval(struct inode *ino) |
157 | #define STATEID_HASH_BITS 10 | 157 | { |
158 | #define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS) | 158 | /* XXX: why are we hashing on inode pointer, anyway? */ |
159 | #define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1) | 159 | return hash_ptr(ino, FILE_HASH_BITS); |
160 | 160 | } | |
161 | #define file_hashval(x) \ | ||
162 | hash_ptr(x, FILE_HASH_BITS) | ||
163 | #define stateid_hashval(owner_id, file_id) \ | ||
164 | (((owner_id) + (file_id)) & STATEID_HASH_MASK) | ||
165 | 161 | ||
166 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; | 162 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; |
167 | static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; | ||
168 | 163 | ||
169 | static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag) | 164 | static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag) |
170 | { | 165 | { |
@@ -192,8 +187,15 @@ static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag) | |||
192 | static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) | 187 | static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) |
193 | { | 188 | { |
194 | if (atomic_dec_and_test(&fp->fi_access[oflag])) { | 189 | if (atomic_dec_and_test(&fp->fi_access[oflag])) { |
195 | nfs4_file_put_fd(fp, O_RDWR); | ||
196 | nfs4_file_put_fd(fp, oflag); | 190 | nfs4_file_put_fd(fp, oflag); |
191 | /* | ||
192 | * It's also safe to get rid of the RDWR open *if* | ||
193 | * we no longer have need of the other kind of access | ||
194 | * or if we already have the other kind of open: | ||
195 | */ | ||
196 | if (fp->fi_fds[1-oflag] | ||
197 | || atomic_read(&fp->fi_access[1 - oflag]) == 0) | ||
198 | nfs4_file_put_fd(fp, O_RDWR); | ||
197 | } | 199 | } |
198 | } | 200 | } |
199 | 201 | ||
@@ -206,8 +208,73 @@ static void nfs4_file_put_access(struct nfs4_file *fp, int oflag) | |||
206 | __nfs4_file_put_access(fp, oflag); | 208 | __nfs4_file_put_access(fp, oflag); |
207 | } | 209 | } |
208 | 210 | ||
211 | static inline int get_new_stid(struct nfs4_stid *stid) | ||
212 | { | ||
213 | static int min_stateid = 0; | ||
214 | struct idr *stateids = &stid->sc_client->cl_stateids; | ||
215 | int new_stid; | ||
216 | int error; | ||
217 | |||
218 | error = idr_get_new_above(stateids, stid, min_stateid, &new_stid); | ||
219 | /* | ||
220 | * Note: the necessary preallocation was done in | ||
221 | * nfs4_alloc_stateid(). The idr code caps the number of | ||
222 | * preallocations that can exist at a time, but the state lock | ||
223 | * prevents anyone from using ours before we get here: | ||
224 | */ | ||
225 | BUG_ON(error); | ||
226 | /* | ||
227 | * It shouldn't be a problem to reuse an opaque stateid value. | ||
228 | * I don't think it is for 4.1. But with 4.0 I worry that, for | ||
229 | * example, a stray write retransmission could be accepted by | ||
230 | * the server when it should have been rejected. Therefore, | ||
231 | * adopt a trick from the sctp code to attempt to maximize the | ||
232 | * amount of time until an id is reused, by ensuring they always | ||
233 | * "increase" (mod INT_MAX): | ||
234 | */ | ||
235 | |||
236 | min_stateid = new_stid+1; | ||
237 | if (min_stateid == INT_MAX) | ||
238 | min_stateid = 0; | ||
239 | return new_stid; | ||
240 | } | ||
241 | |||
242 | static void init_stid(struct nfs4_stid *stid, struct nfs4_client *cl, unsigned char type) | ||
243 | { | ||
244 | stateid_t *s = &stid->sc_stateid; | ||
245 | int new_id; | ||
246 | |||
247 | stid->sc_type = type; | ||
248 | stid->sc_client = cl; | ||
249 | s->si_opaque.so_clid = cl->cl_clientid; | ||
250 | new_id = get_new_stid(stid); | ||
251 | s->si_opaque.so_id = (u32)new_id; | ||
252 | /* Will be incremented before return to client: */ | ||
253 | s->si_generation = 0; | ||
254 | } | ||
255 | |||
256 | static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab) | ||
257 | { | ||
258 | struct idr *stateids = &cl->cl_stateids; | ||
259 | |||
260 | if (!idr_pre_get(stateids, GFP_KERNEL)) | ||
261 | return NULL; | ||
262 | /* | ||
263 | * Note: if we fail here (or any time between now and the time | ||
264 | * we actually get the new idr), we won't need to undo the idr | ||
265 | * preallocation, since the idr code caps the number of | ||
266 | * preallocated entries. | ||
267 | */ | ||
268 | return kmem_cache_alloc(slab, GFP_KERNEL); | ||
269 | } | ||
270 | |||
271 | static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp) | ||
272 | { | ||
273 | return openlockstateid(nfs4_alloc_stid(clp, stateid_slab)); | ||
274 | } | ||
275 | |||
209 | static struct nfs4_delegation * | 276 | static struct nfs4_delegation * |
210 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) | 277 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type) |
211 | { | 278 | { |
212 | struct nfs4_delegation *dp; | 279 | struct nfs4_delegation *dp; |
213 | struct nfs4_file *fp = stp->st_file; | 280 | struct nfs4_file *fp = stp->st_file; |
@@ -224,21 +291,23 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
224 | return NULL; | 291 | return NULL; |
225 | if (num_delegations > max_delegations) | 292 | if (num_delegations > max_delegations) |
226 | return NULL; | 293 | return NULL; |
227 | dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL); | 294 | dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); |
228 | if (dp == NULL) | 295 | if (dp == NULL) |
229 | return dp; | 296 | return dp; |
297 | init_stid(&dp->dl_stid, clp, NFS4_DELEG_STID); | ||
298 | /* | ||
299 | * delegation seqid's are never incremented. The 4.1 special | ||
300 | * meaning of seqid 0 isn't meaningful, really, but let's avoid | ||
301 | * 0 anyway just for consistency and use 1: | ||
302 | */ | ||
303 | dp->dl_stid.sc_stateid.si_generation = 1; | ||
230 | num_delegations++; | 304 | num_delegations++; |
231 | INIT_LIST_HEAD(&dp->dl_perfile); | 305 | INIT_LIST_HEAD(&dp->dl_perfile); |
232 | INIT_LIST_HEAD(&dp->dl_perclnt); | 306 | INIT_LIST_HEAD(&dp->dl_perclnt); |
233 | INIT_LIST_HEAD(&dp->dl_recall_lru); | 307 | INIT_LIST_HEAD(&dp->dl_recall_lru); |
234 | dp->dl_client = clp; | ||
235 | get_nfs4_file(fp); | 308 | get_nfs4_file(fp); |
236 | dp->dl_file = fp; | 309 | dp->dl_file = fp; |
237 | dp->dl_type = type; | 310 | dp->dl_type = type; |
238 | dp->dl_stateid.si_boot = boot_time; | ||
239 | dp->dl_stateid.si_stateownerid = current_delegid++; | ||
240 | dp->dl_stateid.si_fileid = 0; | ||
241 | dp->dl_stateid.si_generation = 0; | ||
242 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); | 311 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); |
243 | dp->dl_time = 0; | 312 | dp->dl_time = 0; |
244 | atomic_set(&dp->dl_count, 1); | 313 | atomic_set(&dp->dl_count, 1); |
@@ -267,10 +336,18 @@ static void nfs4_put_deleg_lease(struct nfs4_file *fp) | |||
267 | } | 336 | } |
268 | } | 337 | } |
269 | 338 | ||
339 | static void unhash_stid(struct nfs4_stid *s) | ||
340 | { | ||
341 | struct idr *stateids = &s->sc_client->cl_stateids; | ||
342 | |||
343 | idr_remove(stateids, s->sc_stateid.si_opaque.so_id); | ||
344 | } | ||
345 | |||
270 | /* Called under the state lock. */ | 346 | /* Called under the state lock. */ |
271 | static void | 347 | static void |
272 | unhash_delegation(struct nfs4_delegation *dp) | 348 | unhash_delegation(struct nfs4_delegation *dp) |
273 | { | 349 | { |
350 | unhash_stid(&dp->dl_stid); | ||
274 | list_del_init(&dp->dl_perclnt); | 351 | list_del_init(&dp->dl_perclnt); |
275 | spin_lock(&recall_lock); | 352 | spin_lock(&recall_lock); |
276 | list_del_init(&dp->dl_perfile); | 353 | list_del_init(&dp->dl_perfile); |
@@ -292,10 +369,16 @@ static DEFINE_SPINLOCK(client_lock); | |||
292 | #define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS) | 369 | #define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS) |
293 | #define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1) | 370 | #define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1) |
294 | 371 | ||
295 | #define clientid_hashval(id) \ | 372 | static unsigned int clientid_hashval(u32 id) |
296 | ((id) & CLIENT_HASH_MASK) | 373 | { |
297 | #define clientstr_hashval(name) \ | 374 | return id & CLIENT_HASH_MASK; |
298 | (opaque_hashval((name), 8) & CLIENT_HASH_MASK) | 375 | } |
376 | |||
377 | static unsigned int clientstr_hashval(const char *name) | ||
378 | { | ||
379 | return opaque_hashval(name, 8) & CLIENT_HASH_MASK; | ||
380 | } | ||
381 | |||
299 | /* | 382 | /* |
300 | * reclaim_str_hashtbl[] holds known client info from previous reset/reboot | 383 | * reclaim_str_hashtbl[] holds known client info from previous reset/reboot |
301 | * used in reboot/reset lease grace period processing | 384 | * used in reboot/reset lease grace period processing |
@@ -362,7 +445,7 @@ set_deny(unsigned int *deny, unsigned long bmap) { | |||
362 | } | 445 | } |
363 | 446 | ||
364 | static int | 447 | static int |
365 | test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { | 448 | test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) { |
366 | unsigned int access, deny; | 449 | unsigned int access, deny; |
367 | 450 | ||
368 | set_access(&access, stp->st_access_bmap); | 451 | set_access(&access, stp->st_access_bmap); |
@@ -385,14 +468,13 @@ static int nfs4_access_to_omode(u32 access) | |||
385 | BUG(); | 468 | BUG(); |
386 | } | 469 | } |
387 | 470 | ||
388 | static void unhash_generic_stateid(struct nfs4_stateid *stp) | 471 | static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) |
389 | { | 472 | { |
390 | list_del(&stp->st_hash); | ||
391 | list_del(&stp->st_perfile); | 473 | list_del(&stp->st_perfile); |
392 | list_del(&stp->st_perstateowner); | 474 | list_del(&stp->st_perstateowner); |
393 | } | 475 | } |
394 | 476 | ||
395 | static void free_generic_stateid(struct nfs4_stateid *stp) | 477 | static void close_generic_stateid(struct nfs4_ol_stateid *stp) |
396 | { | 478 | { |
397 | int i; | 479 | int i; |
398 | 480 | ||
@@ -401,84 +483,106 @@ static void free_generic_stateid(struct nfs4_stateid *stp) | |||
401 | if (test_bit(i, &stp->st_access_bmap)) | 483 | if (test_bit(i, &stp->st_access_bmap)) |
402 | nfs4_file_put_access(stp->st_file, | 484 | nfs4_file_put_access(stp->st_file, |
403 | nfs4_access_to_omode(i)); | 485 | nfs4_access_to_omode(i)); |
486 | __clear_bit(i, &stp->st_access_bmap); | ||
404 | } | 487 | } |
405 | } | 488 | } |
406 | put_nfs4_file(stp->st_file); | 489 | put_nfs4_file(stp->st_file); |
490 | stp->st_file = NULL; | ||
491 | } | ||
492 | |||
493 | static void free_generic_stateid(struct nfs4_ol_stateid *stp) | ||
494 | { | ||
407 | kmem_cache_free(stateid_slab, stp); | 495 | kmem_cache_free(stateid_slab, stp); |
408 | } | 496 | } |
409 | 497 | ||
410 | static void release_lock_stateid(struct nfs4_stateid *stp) | 498 | static void release_lock_stateid(struct nfs4_ol_stateid *stp) |
411 | { | 499 | { |
412 | struct file *file; | 500 | struct file *file; |
413 | 501 | ||
414 | unhash_generic_stateid(stp); | 502 | unhash_generic_stateid(stp); |
503 | unhash_stid(&stp->st_stid); | ||
415 | file = find_any_file(stp->st_file); | 504 | file = find_any_file(stp->st_file); |
416 | if (file) | 505 | if (file) |
417 | locks_remove_posix(file, (fl_owner_t)stp->st_stateowner); | 506 | locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner)); |
507 | close_generic_stateid(stp); | ||
418 | free_generic_stateid(stp); | 508 | free_generic_stateid(stp); |
419 | } | 509 | } |
420 | 510 | ||
421 | static void unhash_lockowner(struct nfs4_stateowner *sop) | 511 | static void unhash_lockowner(struct nfs4_lockowner *lo) |
422 | { | 512 | { |
423 | struct nfs4_stateid *stp; | 513 | struct nfs4_ol_stateid *stp; |
424 | 514 | ||
425 | list_del(&sop->so_idhash); | 515 | list_del(&lo->lo_owner.so_strhash); |
426 | list_del(&sop->so_strhash); | 516 | list_del(&lo->lo_perstateid); |
427 | list_del(&sop->so_perstateid); | 517 | while (!list_empty(&lo->lo_owner.so_stateids)) { |
428 | while (!list_empty(&sop->so_stateids)) { | 518 | stp = list_first_entry(&lo->lo_owner.so_stateids, |
429 | stp = list_first_entry(&sop->so_stateids, | 519 | struct nfs4_ol_stateid, st_perstateowner); |
430 | struct nfs4_stateid, st_perstateowner); | ||
431 | release_lock_stateid(stp); | 520 | release_lock_stateid(stp); |
432 | } | 521 | } |
433 | } | 522 | } |
434 | 523 | ||
435 | static void release_lockowner(struct nfs4_stateowner *sop) | 524 | static void release_lockowner(struct nfs4_lockowner *lo) |
436 | { | 525 | { |
437 | unhash_lockowner(sop); | 526 | unhash_lockowner(lo); |
438 | nfs4_put_stateowner(sop); | 527 | nfs4_free_lockowner(lo); |
439 | } | 528 | } |
440 | 529 | ||
441 | static void | 530 | static void |
442 | release_stateid_lockowners(struct nfs4_stateid *open_stp) | 531 | release_stateid_lockowners(struct nfs4_ol_stateid *open_stp) |
443 | { | 532 | { |
444 | struct nfs4_stateowner *lock_sop; | 533 | struct nfs4_lockowner *lo; |
445 | 534 | ||
446 | while (!list_empty(&open_stp->st_lockowners)) { | 535 | while (!list_empty(&open_stp->st_lockowners)) { |
447 | lock_sop = list_entry(open_stp->st_lockowners.next, | 536 | lo = list_entry(open_stp->st_lockowners.next, |
448 | struct nfs4_stateowner, so_perstateid); | 537 | struct nfs4_lockowner, lo_perstateid); |
449 | /* list_del(&open_stp->st_lockowners); */ | 538 | release_lockowner(lo); |
450 | BUG_ON(lock_sop->so_is_open_owner); | ||
451 | release_lockowner(lock_sop); | ||
452 | } | 539 | } |
453 | } | 540 | } |
454 | 541 | ||
455 | static void release_open_stateid(struct nfs4_stateid *stp) | 542 | static void unhash_open_stateid(struct nfs4_ol_stateid *stp) |
456 | { | 543 | { |
457 | unhash_generic_stateid(stp); | 544 | unhash_generic_stateid(stp); |
458 | release_stateid_lockowners(stp); | 545 | release_stateid_lockowners(stp); |
546 | close_generic_stateid(stp); | ||
547 | } | ||
548 | |||
549 | static void release_open_stateid(struct nfs4_ol_stateid *stp) | ||
550 | { | ||
551 | unhash_open_stateid(stp); | ||
552 | unhash_stid(&stp->st_stid); | ||
459 | free_generic_stateid(stp); | 553 | free_generic_stateid(stp); |
460 | } | 554 | } |
461 | 555 | ||
462 | static void unhash_openowner(struct nfs4_stateowner *sop) | 556 | static void unhash_openowner(struct nfs4_openowner *oo) |
463 | { | 557 | { |
464 | struct nfs4_stateid *stp; | 558 | struct nfs4_ol_stateid *stp; |
465 | 559 | ||
466 | list_del(&sop->so_idhash); | 560 | list_del(&oo->oo_owner.so_strhash); |
467 | list_del(&sop->so_strhash); | 561 | list_del(&oo->oo_perclient); |
468 | list_del(&sop->so_perclient); | 562 | while (!list_empty(&oo->oo_owner.so_stateids)) { |
469 | list_del(&sop->so_perstateid); /* XXX: necessary? */ | 563 | stp = list_first_entry(&oo->oo_owner.so_stateids, |
470 | while (!list_empty(&sop->so_stateids)) { | 564 | struct nfs4_ol_stateid, st_perstateowner); |
471 | stp = list_first_entry(&sop->so_stateids, | ||
472 | struct nfs4_stateid, st_perstateowner); | ||
473 | release_open_stateid(stp); | 565 | release_open_stateid(stp); |
474 | } | 566 | } |
475 | } | 567 | } |
476 | 568 | ||
477 | static void release_openowner(struct nfs4_stateowner *sop) | 569 | static void release_last_closed_stateid(struct nfs4_openowner *oo) |
478 | { | 570 | { |
479 | unhash_openowner(sop); | 571 | struct nfs4_ol_stateid *s = oo->oo_last_closed_stid; |
480 | list_del(&sop->so_close_lru); | 572 | |
481 | nfs4_put_stateowner(sop); | 573 | if (s) { |
574 | unhash_stid(&s->st_stid); | ||
575 | free_generic_stateid(s); | ||
576 | oo->oo_last_closed_stid = NULL; | ||
577 | } | ||
578 | } | ||
579 | |||
580 | static void release_openowner(struct nfs4_openowner *oo) | ||
581 | { | ||
582 | unhash_openowner(oo); | ||
583 | list_del(&oo->oo_close_lru); | ||
584 | release_last_closed_stateid(oo); | ||
585 | nfs4_free_openowner(oo); | ||
482 | } | 586 | } |
483 | 587 | ||
484 | #define SESSION_HASH_SIZE 512 | 588 | #define SESSION_HASH_SIZE 512 |
@@ -843,9 +947,6 @@ renew_client_locked(struct nfs4_client *clp) | |||
843 | return; | 947 | return; |
844 | } | 948 | } |
845 | 949 | ||
846 | /* | ||
847 | * Move client to the end to the LRU list. | ||
848 | */ | ||
849 | dprintk("renewing client (clientid %08x/%08x)\n", | 950 | dprintk("renewing client (clientid %08x/%08x)\n", |
850 | clp->cl_clientid.cl_boot, | 951 | clp->cl_clientid.cl_boot, |
851 | clp->cl_clientid.cl_id); | 952 | clp->cl_clientid.cl_id); |
@@ -943,7 +1044,7 @@ unhash_client_locked(struct nfs4_client *clp) | |||
943 | static void | 1044 | static void |
944 | expire_client(struct nfs4_client *clp) | 1045 | expire_client(struct nfs4_client *clp) |
945 | { | 1046 | { |
946 | struct nfs4_stateowner *sop; | 1047 | struct nfs4_openowner *oo; |
947 | struct nfs4_delegation *dp; | 1048 | struct nfs4_delegation *dp; |
948 | struct list_head reaplist; | 1049 | struct list_head reaplist; |
949 | 1050 | ||
@@ -961,8 +1062,8 @@ expire_client(struct nfs4_client *clp) | |||
961 | unhash_delegation(dp); | 1062 | unhash_delegation(dp); |
962 | } | 1063 | } |
963 | while (!list_empty(&clp->cl_openowners)) { | 1064 | while (!list_empty(&clp->cl_openowners)) { |
964 | sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient); | 1065 | oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); |
965 | release_openowner(sop); | 1066 | release_openowner(oo); |
966 | } | 1067 | } |
967 | nfsd4_shutdown_callback(clp); | 1068 | nfsd4_shutdown_callback(clp); |
968 | if (clp->cl_cb_conn.cb_xprt) | 1069 | if (clp->cl_cb_conn.cb_xprt) |
@@ -1038,6 +1139,23 @@ static void gen_confirm(struct nfs4_client *clp) | |||
1038 | *p++ = i++; | 1139 | *p++ = i++; |
1039 | } | 1140 | } |
1040 | 1141 | ||
1142 | static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t) | ||
1143 | { | ||
1144 | return idr_find(&cl->cl_stateids, t->si_opaque.so_id); | ||
1145 | } | ||
1146 | |||
1147 | static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) | ||
1148 | { | ||
1149 | struct nfs4_stid *s; | ||
1150 | |||
1151 | s = find_stateid(cl, t); | ||
1152 | if (!s) | ||
1153 | return NULL; | ||
1154 | if (typemask & s->sc_type) | ||
1155 | return s; | ||
1156 | return NULL; | ||
1157 | } | ||
1158 | |||
1041 | static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | 1159 | static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, |
1042 | struct svc_rqst *rqstp, nfs4_verifier *verf) | 1160 | struct svc_rqst *rqstp, nfs4_verifier *verf) |
1043 | { | 1161 | { |
@@ -1060,6 +1178,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
1060 | } | 1178 | } |
1061 | } | 1179 | } |
1062 | 1180 | ||
1181 | idr_init(&clp->cl_stateids); | ||
1063 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 1182 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
1064 | atomic_set(&clp->cl_refcount, 0); | 1183 | atomic_set(&clp->cl_refcount, 0); |
1065 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; | 1184 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; |
@@ -1083,17 +1202,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
1083 | return clp; | 1202 | return clp; |
1084 | } | 1203 | } |
1085 | 1204 | ||
1086 | static int check_name(struct xdr_netobj name) | ||
1087 | { | ||
1088 | if (name.len == 0) | ||
1089 | return 0; | ||
1090 | if (name.len > NFS4_OPAQUE_LIMIT) { | ||
1091 | dprintk("NFSD: check_name: name too long(%d)!\n", name.len); | ||
1092 | return 0; | ||
1093 | } | ||
1094 | return 1; | ||
1095 | } | ||
1096 | |||
1097 | static void | 1205 | static void |
1098 | add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) | 1206 | add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) |
1099 | { | 1207 | { |
@@ -1125,8 +1233,10 @@ find_confirmed_client(clientid_t *clid) | |||
1125 | unsigned int idhashval = clientid_hashval(clid->cl_id); | 1233 | unsigned int idhashval = clientid_hashval(clid->cl_id); |
1126 | 1234 | ||
1127 | list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { | 1235 | list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { |
1128 | if (same_clid(&clp->cl_clientid, clid)) | 1236 | if (same_clid(&clp->cl_clientid, clid)) { |
1237 | renew_client(clp); | ||
1129 | return clp; | 1238 | return clp; |
1239 | } | ||
1130 | } | 1240 | } |
1131 | return NULL; | 1241 | return NULL; |
1132 | } | 1242 | } |
@@ -1173,20 +1283,6 @@ find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) | |||
1173 | return NULL; | 1283 | return NULL; |
1174 | } | 1284 | } |
1175 | 1285 | ||
1176 | static void rpc_svcaddr2sockaddr(struct sockaddr *sa, unsigned short family, union svc_addr_u *svcaddr) | ||
1177 | { | ||
1178 | switch (family) { | ||
1179 | case AF_INET: | ||
1180 | ((struct sockaddr_in *)sa)->sin_family = AF_INET; | ||
1181 | ((struct sockaddr_in *)sa)->sin_addr = svcaddr->addr; | ||
1182 | return; | ||
1183 | case AF_INET6: | ||
1184 | ((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6; | ||
1185 | ((struct sockaddr_in6 *)sa)->sin6_addr = svcaddr->addr6; | ||
1186 | return; | ||
1187 | } | ||
1188 | } | ||
1189 | |||
1190 | static void | 1286 | static void |
1191 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) | 1287 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) |
1192 | { | 1288 | { |
@@ -1218,7 +1314,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r | |||
1218 | 1314 | ||
1219 | conn->cb_prog = se->se_callback_prog; | 1315 | conn->cb_prog = se->se_callback_prog; |
1220 | conn->cb_ident = se->se_callback_ident; | 1316 | conn->cb_ident = se->se_callback_ident; |
1221 | rpc_svcaddr2sockaddr((struct sockaddr *)&conn->cb_saddr, expected_family, &rqstp->rq_daddr); | 1317 | memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); |
1222 | return; | 1318 | return; |
1223 | out_err: | 1319 | out_err: |
1224 | conn->cb_addr.ss_family = AF_UNSPEC; | 1320 | conn->cb_addr.ss_family = AF_UNSPEC; |
@@ -1350,7 +1446,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1350 | __func__, rqstp, exid, exid->clname.len, exid->clname.data, | 1446 | __func__, rqstp, exid, exid->clname.len, exid->clname.data, |
1351 | addr_str, exid->flags, exid->spa_how); | 1447 | addr_str, exid->flags, exid->spa_how); |
1352 | 1448 | ||
1353 | if (!check_name(exid->clname) || (exid->flags & ~EXCHGID4_FLAG_MASK_A)) | 1449 | if (exid->flags & ~EXCHGID4_FLAG_MASK_A) |
1354 | return nfserr_inval; | 1450 | return nfserr_inval; |
1355 | 1451 | ||
1356 | /* Currently only support SP4_NONE */ | 1452 | /* Currently only support SP4_NONE */ |
@@ -1849,8 +1945,16 @@ out: | |||
1849 | 1945 | ||
1850 | nfsd4_get_session(cstate->session); | 1946 | nfsd4_get_session(cstate->session); |
1851 | atomic_inc(&clp->cl_refcount); | 1947 | atomic_inc(&clp->cl_refcount); |
1852 | if (clp->cl_cb_state == NFSD4_CB_DOWN) | 1948 | switch (clp->cl_cb_state) { |
1853 | seq->status_flags |= SEQ4_STATUS_CB_PATH_DOWN; | 1949 | case NFSD4_CB_DOWN: |
1950 | seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; | ||
1951 | break; | ||
1952 | case NFSD4_CB_FAULT: | ||
1953 | seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; | ||
1954 | break; | ||
1955 | default: | ||
1956 | seq->status_flags = 0; | ||
1957 | } | ||
1854 | } | 1958 | } |
1855 | kfree(conn); | 1959 | kfree(conn); |
1856 | spin_unlock(&client_lock); | 1960 | spin_unlock(&client_lock); |
@@ -1858,6 +1962,50 @@ out: | |||
1858 | return status; | 1962 | return status; |
1859 | } | 1963 | } |
1860 | 1964 | ||
1965 | static inline bool has_resources(struct nfs4_client *clp) | ||
1966 | { | ||
1967 | return !list_empty(&clp->cl_openowners) | ||
1968 | || !list_empty(&clp->cl_delegations) | ||
1969 | || !list_empty(&clp->cl_sessions); | ||
1970 | } | ||
1971 | |||
1972 | __be32 | ||
1973 | nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) | ||
1974 | { | ||
1975 | struct nfs4_client *conf, *unconf, *clp; | ||
1976 | int status = 0; | ||
1977 | |||
1978 | nfs4_lock_state(); | ||
1979 | unconf = find_unconfirmed_client(&dc->clientid); | ||
1980 | conf = find_confirmed_client(&dc->clientid); | ||
1981 | |||
1982 | if (conf) { | ||
1983 | clp = conf; | ||
1984 | |||
1985 | if (!is_client_expired(conf) && has_resources(conf)) { | ||
1986 | status = nfserr_clientid_busy; | ||
1987 | goto out; | ||
1988 | } | ||
1989 | |||
1990 | /* rfc5661 18.50.3 */ | ||
1991 | if (cstate->session && conf == cstate->session->se_client) { | ||
1992 | status = nfserr_clientid_busy; | ||
1993 | goto out; | ||
1994 | } | ||
1995 | } else if (unconf) | ||
1996 | clp = unconf; | ||
1997 | else { | ||
1998 | status = nfserr_stale_clientid; | ||
1999 | goto out; | ||
2000 | } | ||
2001 | |||
2002 | expire_client(clp); | ||
2003 | out: | ||
2004 | nfs4_unlock_state(); | ||
2005 | dprintk("%s return %d\n", __func__, ntohl(status)); | ||
2006 | return status; | ||
2007 | } | ||
2008 | |||
1861 | __be32 | 2009 | __be32 |
1862 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) | 2010 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) |
1863 | { | 2011 | { |
@@ -1900,19 +2048,13 @@ __be32 | |||
1900 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 2048 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
1901 | struct nfsd4_setclientid *setclid) | 2049 | struct nfsd4_setclientid *setclid) |
1902 | { | 2050 | { |
1903 | struct xdr_netobj clname = { | 2051 | struct xdr_netobj clname = setclid->se_name; |
1904 | .len = setclid->se_namelen, | ||
1905 | .data = setclid->se_name, | ||
1906 | }; | ||
1907 | nfs4_verifier clverifier = setclid->se_verf; | 2052 | nfs4_verifier clverifier = setclid->se_verf; |
1908 | unsigned int strhashval; | 2053 | unsigned int strhashval; |
1909 | struct nfs4_client *conf, *unconf, *new; | 2054 | struct nfs4_client *conf, *unconf, *new; |
1910 | __be32 status; | 2055 | __be32 status; |
1911 | char dname[HEXDIR_LEN]; | 2056 | char dname[HEXDIR_LEN]; |
1912 | 2057 | ||
1913 | if (!check_name(clname)) | ||
1914 | return nfserr_inval; | ||
1915 | |||
1916 | status = nfs4_make_rec_clidname(dname, &clname); | 2058 | status = nfs4_make_rec_clidname(dname, &clname); |
1917 | if (status) | 2059 | if (status) |
1918 | return status; | 2060 | return status; |
@@ -1946,7 +2088,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1946 | * of 5 bullet points, labeled as CASE0 - CASE4 below. | 2088 | * of 5 bullet points, labeled as CASE0 - CASE4 below. |
1947 | */ | 2089 | */ |
1948 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 2090 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
1949 | status = nfserr_resource; | 2091 | status = nfserr_jukebox; |
1950 | if (!conf) { | 2092 | if (!conf) { |
1951 | /* | 2093 | /* |
1952 | * RFC 3530 14.2.33 CASE 4: | 2094 | * RFC 3530 14.2.33 CASE 4: |
@@ -2116,31 +2258,28 @@ out: | |||
2116 | return status; | 2258 | return status; |
2117 | } | 2259 | } |
2118 | 2260 | ||
2261 | static struct nfs4_file *nfsd4_alloc_file(void) | ||
2262 | { | ||
2263 | return kmem_cache_alloc(file_slab, GFP_KERNEL); | ||
2264 | } | ||
2265 | |||
2119 | /* OPEN Share state helper functions */ | 2266 | /* OPEN Share state helper functions */ |
2120 | static inline struct nfs4_file * | 2267 | static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino) |
2121 | alloc_init_file(struct inode *ino) | ||
2122 | { | 2268 | { |
2123 | struct nfs4_file *fp; | ||
2124 | unsigned int hashval = file_hashval(ino); | 2269 | unsigned int hashval = file_hashval(ino); |
2125 | 2270 | ||
2126 | fp = kmem_cache_alloc(file_slab, GFP_KERNEL); | 2271 | atomic_set(&fp->fi_ref, 1); |
2127 | if (fp) { | 2272 | INIT_LIST_HEAD(&fp->fi_hash); |
2128 | atomic_set(&fp->fi_ref, 1); | 2273 | INIT_LIST_HEAD(&fp->fi_stateids); |
2129 | INIT_LIST_HEAD(&fp->fi_hash); | 2274 | INIT_LIST_HEAD(&fp->fi_delegations); |
2130 | INIT_LIST_HEAD(&fp->fi_stateids); | 2275 | fp->fi_inode = igrab(ino); |
2131 | INIT_LIST_HEAD(&fp->fi_delegations); | 2276 | fp->fi_had_conflict = false; |
2132 | fp->fi_inode = igrab(ino); | 2277 | fp->fi_lease = NULL; |
2133 | fp->fi_id = current_fileid++; | 2278 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); |
2134 | fp->fi_had_conflict = false; | 2279 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); |
2135 | fp->fi_lease = NULL; | 2280 | spin_lock(&recall_lock); |
2136 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); | 2281 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); |
2137 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); | 2282 | spin_unlock(&recall_lock); |
2138 | spin_lock(&recall_lock); | ||
2139 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | ||
2140 | spin_unlock(&recall_lock); | ||
2141 | return fp; | ||
2142 | } | ||
2143 | return NULL; | ||
2144 | } | 2283 | } |
2145 | 2284 | ||
2146 | static void | 2285 | static void |
@@ -2155,7 +2294,8 @@ nfsd4_free_slab(struct kmem_cache **slab) | |||
2155 | void | 2294 | void |
2156 | nfsd4_free_slabs(void) | 2295 | nfsd4_free_slabs(void) |
2157 | { | 2296 | { |
2158 | nfsd4_free_slab(&stateowner_slab); | 2297 | nfsd4_free_slab(&openowner_slab); |
2298 | nfsd4_free_slab(&lockowner_slab); | ||
2159 | nfsd4_free_slab(&file_slab); | 2299 | nfsd4_free_slab(&file_slab); |
2160 | nfsd4_free_slab(&stateid_slab); | 2300 | nfsd4_free_slab(&stateid_slab); |
2161 | nfsd4_free_slab(&deleg_slab); | 2301 | nfsd4_free_slab(&deleg_slab); |
@@ -2164,16 +2304,20 @@ nfsd4_free_slabs(void) | |||
2164 | static int | 2304 | static int |
2165 | nfsd4_init_slabs(void) | 2305 | nfsd4_init_slabs(void) |
2166 | { | 2306 | { |
2167 | stateowner_slab = kmem_cache_create("nfsd4_stateowners", | 2307 | openowner_slab = kmem_cache_create("nfsd4_openowners", |
2168 | sizeof(struct nfs4_stateowner), 0, 0, NULL); | 2308 | sizeof(struct nfs4_openowner), 0, 0, NULL); |
2169 | if (stateowner_slab == NULL) | 2309 | if (openowner_slab == NULL) |
2310 | goto out_nomem; | ||
2311 | lockowner_slab = kmem_cache_create("nfsd4_lockowners", | ||
2312 | sizeof(struct nfs4_openowner), 0, 0, NULL); | ||
2313 | if (lockowner_slab == NULL) | ||
2170 | goto out_nomem; | 2314 | goto out_nomem; |
2171 | file_slab = kmem_cache_create("nfsd4_files", | 2315 | file_slab = kmem_cache_create("nfsd4_files", |
2172 | sizeof(struct nfs4_file), 0, 0, NULL); | 2316 | sizeof(struct nfs4_file), 0, 0, NULL); |
2173 | if (file_slab == NULL) | 2317 | if (file_slab == NULL) |
2174 | goto out_nomem; | 2318 | goto out_nomem; |
2175 | stateid_slab = kmem_cache_create("nfsd4_stateids", | 2319 | stateid_slab = kmem_cache_create("nfsd4_stateids", |
2176 | sizeof(struct nfs4_stateid), 0, 0, NULL); | 2320 | sizeof(struct nfs4_ol_stateid), 0, 0, NULL); |
2177 | if (stateid_slab == NULL) | 2321 | if (stateid_slab == NULL) |
2178 | goto out_nomem; | 2322 | goto out_nomem; |
2179 | deleg_slab = kmem_cache_create("nfsd4_delegations", | 2323 | deleg_slab = kmem_cache_create("nfsd4_delegations", |
@@ -2187,97 +2331,94 @@ out_nomem: | |||
2187 | return -ENOMEM; | 2331 | return -ENOMEM; |
2188 | } | 2332 | } |
2189 | 2333 | ||
2190 | void | 2334 | void nfs4_free_openowner(struct nfs4_openowner *oo) |
2191 | nfs4_free_stateowner(struct kref *kref) | ||
2192 | { | 2335 | { |
2193 | struct nfs4_stateowner *sop = | 2336 | kfree(oo->oo_owner.so_owner.data); |
2194 | container_of(kref, struct nfs4_stateowner, so_ref); | 2337 | kmem_cache_free(openowner_slab, oo); |
2195 | kfree(sop->so_owner.data); | ||
2196 | kmem_cache_free(stateowner_slab, sop); | ||
2197 | } | 2338 | } |
2198 | 2339 | ||
2199 | static inline struct nfs4_stateowner * | 2340 | void nfs4_free_lockowner(struct nfs4_lockowner *lo) |
2200 | alloc_stateowner(struct xdr_netobj *owner) | ||
2201 | { | 2341 | { |
2202 | struct nfs4_stateowner *sop; | 2342 | kfree(lo->lo_owner.so_owner.data); |
2343 | kmem_cache_free(lockowner_slab, lo); | ||
2344 | } | ||
2203 | 2345 | ||
2204 | if ((sop = kmem_cache_alloc(stateowner_slab, GFP_KERNEL))) { | 2346 | static void init_nfs4_replay(struct nfs4_replay *rp) |
2205 | if ((sop->so_owner.data = kmalloc(owner->len, GFP_KERNEL))) { | 2347 | { |
2206 | memcpy(sop->so_owner.data, owner->data, owner->len); | 2348 | rp->rp_status = nfserr_serverfault; |
2207 | sop->so_owner.len = owner->len; | 2349 | rp->rp_buflen = 0; |
2208 | kref_init(&sop->so_ref); | 2350 | rp->rp_buf = rp->rp_ibuf; |
2209 | return sop; | ||
2210 | } | ||
2211 | kmem_cache_free(stateowner_slab, sop); | ||
2212 | } | ||
2213 | return NULL; | ||
2214 | } | 2351 | } |
2215 | 2352 | ||
2216 | static struct nfs4_stateowner * | 2353 | static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) |
2217 | alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) { | 2354 | { |
2218 | struct nfs4_stateowner *sop; | 2355 | struct nfs4_stateowner *sop; |
2219 | struct nfs4_replay *rp; | ||
2220 | unsigned int idhashval; | ||
2221 | 2356 | ||
2222 | if (!(sop = alloc_stateowner(&open->op_owner))) | 2357 | sop = kmem_cache_alloc(slab, GFP_KERNEL); |
2358 | if (!sop) | ||
2359 | return NULL; | ||
2360 | |||
2361 | sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL); | ||
2362 | if (!sop->so_owner.data) { | ||
2363 | kmem_cache_free(slab, sop); | ||
2223 | return NULL; | 2364 | return NULL; |
2224 | idhashval = ownerid_hashval(current_ownerid); | 2365 | } |
2225 | INIT_LIST_HEAD(&sop->so_idhash); | 2366 | sop->so_owner.len = owner->len; |
2226 | INIT_LIST_HEAD(&sop->so_strhash); | 2367 | |
2227 | INIT_LIST_HEAD(&sop->so_perclient); | ||
2228 | INIT_LIST_HEAD(&sop->so_stateids); | 2368 | INIT_LIST_HEAD(&sop->so_stateids); |
2229 | INIT_LIST_HEAD(&sop->so_perstateid); /* not used */ | ||
2230 | INIT_LIST_HEAD(&sop->so_close_lru); | ||
2231 | sop->so_time = 0; | ||
2232 | list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]); | ||
2233 | list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]); | ||
2234 | list_add(&sop->so_perclient, &clp->cl_openowners); | ||
2235 | sop->so_is_open_owner = 1; | ||
2236 | sop->so_id = current_ownerid++; | ||
2237 | sop->so_client = clp; | 2369 | sop->so_client = clp; |
2238 | sop->so_seqid = open->op_seqid; | 2370 | init_nfs4_replay(&sop->so_replay); |
2239 | sop->so_confirmed = 0; | ||
2240 | rp = &sop->so_replay; | ||
2241 | rp->rp_status = nfserr_serverfault; | ||
2242 | rp->rp_buflen = 0; | ||
2243 | rp->rp_buf = rp->rp_ibuf; | ||
2244 | return sop; | 2371 | return sop; |
2245 | } | 2372 | } |
2246 | 2373 | ||
2247 | static inline void | 2374 | static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) |
2248 | init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) { | 2375 | { |
2249 | struct nfs4_stateowner *sop = open->op_stateowner; | 2376 | list_add(&oo->oo_owner.so_strhash, &open_ownerstr_hashtbl[strhashval]); |
2250 | unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id); | 2377 | list_add(&oo->oo_perclient, &clp->cl_openowners); |
2378 | } | ||
2251 | 2379 | ||
2252 | INIT_LIST_HEAD(&stp->st_hash); | 2380 | static struct nfs4_openowner * |
2253 | INIT_LIST_HEAD(&stp->st_perstateowner); | 2381 | alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) { |
2382 | struct nfs4_openowner *oo; | ||
2383 | |||
2384 | oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); | ||
2385 | if (!oo) | ||
2386 | return NULL; | ||
2387 | oo->oo_owner.so_is_open_owner = 1; | ||
2388 | oo->oo_owner.so_seqid = open->op_seqid; | ||
2389 | oo->oo_flags = NFS4_OO_NEW; | ||
2390 | oo->oo_time = 0; | ||
2391 | oo->oo_last_closed_stid = NULL; | ||
2392 | INIT_LIST_HEAD(&oo->oo_close_lru); | ||
2393 | hash_openowner(oo, clp, strhashval); | ||
2394 | return oo; | ||
2395 | } | ||
2396 | |||
2397 | static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) { | ||
2398 | struct nfs4_openowner *oo = open->op_openowner; | ||
2399 | struct nfs4_client *clp = oo->oo_owner.so_client; | ||
2400 | |||
2401 | init_stid(&stp->st_stid, clp, NFS4_OPEN_STID); | ||
2254 | INIT_LIST_HEAD(&stp->st_lockowners); | 2402 | INIT_LIST_HEAD(&stp->st_lockowners); |
2255 | INIT_LIST_HEAD(&stp->st_perfile); | 2403 | list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); |
2256 | list_add(&stp->st_hash, &stateid_hashtbl[hashval]); | ||
2257 | list_add(&stp->st_perstateowner, &sop->so_stateids); | ||
2258 | list_add(&stp->st_perfile, &fp->fi_stateids); | 2404 | list_add(&stp->st_perfile, &fp->fi_stateids); |
2259 | stp->st_stateowner = sop; | 2405 | stp->st_stateowner = &oo->oo_owner; |
2260 | get_nfs4_file(fp); | 2406 | get_nfs4_file(fp); |
2261 | stp->st_file = fp; | 2407 | stp->st_file = fp; |
2262 | stp->st_stateid.si_boot = boot_time; | ||
2263 | stp->st_stateid.si_stateownerid = sop->so_id; | ||
2264 | stp->st_stateid.si_fileid = fp->fi_id; | ||
2265 | stp->st_stateid.si_generation = 0; | ||
2266 | stp->st_access_bmap = 0; | 2408 | stp->st_access_bmap = 0; |
2267 | stp->st_deny_bmap = 0; | 2409 | stp->st_deny_bmap = 0; |
2268 | __set_bit(open->op_share_access & ~NFS4_SHARE_WANT_MASK, | 2410 | __set_bit(open->op_share_access, &stp->st_access_bmap); |
2269 | &stp->st_access_bmap); | ||
2270 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 2411 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); |
2271 | stp->st_openstp = NULL; | 2412 | stp->st_openstp = NULL; |
2272 | } | 2413 | } |
2273 | 2414 | ||
2274 | static void | 2415 | static void |
2275 | move_to_close_lru(struct nfs4_stateowner *sop) | 2416 | move_to_close_lru(struct nfs4_openowner *oo) |
2276 | { | 2417 | { |
2277 | dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop); | 2418 | dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); |
2278 | 2419 | ||
2279 | list_move_tail(&sop->so_close_lru, &close_lru); | 2420 | list_move_tail(&oo->oo_close_lru, &close_lru); |
2280 | sop->so_time = get_seconds(); | 2421 | oo->oo_time = get_seconds(); |
2281 | } | 2422 | } |
2282 | 2423 | ||
2283 | static int | 2424 | static int |
@@ -2289,14 +2430,18 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, | |||
2289 | (sop->so_client->cl_clientid.cl_id == clid->cl_id); | 2430 | (sop->so_client->cl_clientid.cl_id == clid->cl_id); |
2290 | } | 2431 | } |
2291 | 2432 | ||
2292 | static struct nfs4_stateowner * | 2433 | static struct nfs4_openowner * |
2293 | find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open) | 2434 | find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open) |
2294 | { | 2435 | { |
2295 | struct nfs4_stateowner *so = NULL; | 2436 | struct nfs4_stateowner *so; |
2437 | struct nfs4_openowner *oo; | ||
2296 | 2438 | ||
2297 | list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) { | 2439 | list_for_each_entry(so, &open_ownerstr_hashtbl[hashval], so_strhash) { |
2298 | if (same_owner_str(so, &open->op_owner, &open->op_clientid)) | 2440 | if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { |
2299 | return so; | 2441 | oo = openowner(so); |
2442 | renew_client(oo->oo_owner.so_client); | ||
2443 | return oo; | ||
2444 | } | ||
2300 | } | 2445 | } |
2301 | return NULL; | 2446 | return NULL; |
2302 | } | 2447 | } |
@@ -2320,31 +2465,6 @@ find_file(struct inode *ino) | |||
2320 | return NULL; | 2465 | return NULL; |
2321 | } | 2466 | } |
2322 | 2467 | ||
2323 | static inline int access_valid(u32 x, u32 minorversion) | ||
2324 | { | ||
2325 | if ((x & NFS4_SHARE_ACCESS_MASK) < NFS4_SHARE_ACCESS_READ) | ||
2326 | return 0; | ||
2327 | if ((x & NFS4_SHARE_ACCESS_MASK) > NFS4_SHARE_ACCESS_BOTH) | ||
2328 | return 0; | ||
2329 | x &= ~NFS4_SHARE_ACCESS_MASK; | ||
2330 | if (minorversion && x) { | ||
2331 | if ((x & NFS4_SHARE_WANT_MASK) > NFS4_SHARE_WANT_CANCEL) | ||
2332 | return 0; | ||
2333 | if ((x & NFS4_SHARE_WHEN_MASK) > NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED) | ||
2334 | return 0; | ||
2335 | x &= ~(NFS4_SHARE_WANT_MASK | NFS4_SHARE_WHEN_MASK); | ||
2336 | } | ||
2337 | if (x) | ||
2338 | return 0; | ||
2339 | return 1; | ||
2340 | } | ||
2341 | |||
2342 | static inline int deny_valid(u32 x) | ||
2343 | { | ||
2344 | /* Note: unlike access bits, deny bits may be zero. */ | ||
2345 | return x <= NFS4_SHARE_DENY_BOTH; | ||
2346 | } | ||
2347 | |||
2348 | /* | 2468 | /* |
2349 | * Called to check deny when READ with all zero stateid or | 2469 | * Called to check deny when READ with all zero stateid or |
2350 | * WRITE with all zero or all one stateid | 2470 | * WRITE with all zero or all one stateid |
@@ -2354,7 +2474,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) | |||
2354 | { | 2474 | { |
2355 | struct inode *ino = current_fh->fh_dentry->d_inode; | 2475 | struct inode *ino = current_fh->fh_dentry->d_inode; |
2356 | struct nfs4_file *fp; | 2476 | struct nfs4_file *fp; |
2357 | struct nfs4_stateid *stp; | 2477 | struct nfs4_ol_stateid *stp; |
2358 | __be32 ret; | 2478 | __be32 ret; |
2359 | 2479 | ||
2360 | dprintk("NFSD: nfs4_share_conflict\n"); | 2480 | dprintk("NFSD: nfs4_share_conflict\n"); |
@@ -2429,6 +2549,16 @@ static const struct lock_manager_operations nfsd_lease_mng_ops = { | |||
2429 | .lm_change = nfsd_change_deleg_cb, | 2549 | .lm_change = nfsd_change_deleg_cb, |
2430 | }; | 2550 | }; |
2431 | 2551 | ||
2552 | static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) | ||
2553 | { | ||
2554 | if (nfsd4_has_session(cstate)) | ||
2555 | return nfs_ok; | ||
2556 | if (seqid == so->so_seqid - 1) | ||
2557 | return nfserr_replay_me; | ||
2558 | if (seqid == so->so_seqid) | ||
2559 | return nfs_ok; | ||
2560 | return nfserr_bad_seqid; | ||
2561 | } | ||
2432 | 2562 | ||
2433 | __be32 | 2563 | __be32 |
2434 | nfsd4_process_open1(struct nfsd4_compound_state *cstate, | 2564 | nfsd4_process_open1(struct nfsd4_compound_state *cstate, |
@@ -2437,57 +2567,49 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, | |||
2437 | clientid_t *clientid = &open->op_clientid; | 2567 | clientid_t *clientid = &open->op_clientid; |
2438 | struct nfs4_client *clp = NULL; | 2568 | struct nfs4_client *clp = NULL; |
2439 | unsigned int strhashval; | 2569 | unsigned int strhashval; |
2440 | struct nfs4_stateowner *sop = NULL; | 2570 | struct nfs4_openowner *oo = NULL; |
2441 | 2571 | __be32 status; | |
2442 | if (!check_name(open->op_owner)) | ||
2443 | return nfserr_inval; | ||
2444 | 2572 | ||
2445 | if (STALE_CLIENTID(&open->op_clientid)) | 2573 | if (STALE_CLIENTID(&open->op_clientid)) |
2446 | return nfserr_stale_clientid; | 2574 | return nfserr_stale_clientid; |
2575 | /* | ||
2576 | * In case we need it later, after we've already created the | ||
2577 | * file and don't want to risk a further failure: | ||
2578 | */ | ||
2579 | open->op_file = nfsd4_alloc_file(); | ||
2580 | if (open->op_file == NULL) | ||
2581 | return nfserr_jukebox; | ||
2447 | 2582 | ||
2448 | strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner); | 2583 | strhashval = open_ownerstr_hashval(clientid->cl_id, &open->op_owner); |
2449 | sop = find_openstateowner_str(strhashval, open); | 2584 | oo = find_openstateowner_str(strhashval, open); |
2450 | open->op_stateowner = sop; | 2585 | open->op_openowner = oo; |
2451 | if (!sop) { | 2586 | if (!oo) { |
2452 | /* Make sure the client's lease hasn't expired. */ | ||
2453 | clp = find_confirmed_client(clientid); | 2587 | clp = find_confirmed_client(clientid); |
2454 | if (clp == NULL) | 2588 | if (clp == NULL) |
2455 | return nfserr_expired; | 2589 | return nfserr_expired; |
2456 | goto renew; | 2590 | goto new_owner; |
2457 | } | 2591 | } |
2458 | /* When sessions are used, skip open sequenceid processing */ | 2592 | if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { |
2459 | if (nfsd4_has_session(cstate)) | ||
2460 | goto renew; | ||
2461 | if (!sop->so_confirmed) { | ||
2462 | /* Replace unconfirmed owners without checking for replay. */ | 2593 | /* Replace unconfirmed owners without checking for replay. */ |
2463 | clp = sop->so_client; | 2594 | clp = oo->oo_owner.so_client; |
2464 | release_openowner(sop); | 2595 | release_openowner(oo); |
2465 | open->op_stateowner = NULL; | 2596 | open->op_openowner = NULL; |
2466 | goto renew; | 2597 | goto new_owner; |
2467 | } | ||
2468 | if (open->op_seqid == sop->so_seqid - 1) { | ||
2469 | if (sop->so_replay.rp_buflen) | ||
2470 | return nfserr_replay_me; | ||
2471 | /* The original OPEN failed so spectacularly | ||
2472 | * that we don't even have replay data saved! | ||
2473 | * Therefore, we have no choice but to continue | ||
2474 | * processing this OPEN; presumably, we'll | ||
2475 | * fail again for the same reason. | ||
2476 | */ | ||
2477 | dprintk("nfsd4_process_open1: replay with no replay cache\n"); | ||
2478 | goto renew; | ||
2479 | } | ||
2480 | if (open->op_seqid != sop->so_seqid) | ||
2481 | return nfserr_bad_seqid; | ||
2482 | renew: | ||
2483 | if (open->op_stateowner == NULL) { | ||
2484 | sop = alloc_init_open_stateowner(strhashval, clp, open); | ||
2485 | if (sop == NULL) | ||
2486 | return nfserr_resource; | ||
2487 | open->op_stateowner = sop; | ||
2488 | } | 2598 | } |
2489 | list_del_init(&sop->so_close_lru); | 2599 | status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); |
2490 | renew_client(sop->so_client); | 2600 | if (status) |
2601 | return status; | ||
2602 | clp = oo->oo_owner.so_client; | ||
2603 | goto alloc_stateid; | ||
2604 | new_owner: | ||
2605 | oo = alloc_init_open_stateowner(strhashval, clp, open); | ||
2606 | if (oo == NULL) | ||
2607 | return nfserr_jukebox; | ||
2608 | open->op_openowner = oo; | ||
2609 | alloc_stateid: | ||
2610 | open->op_stp = nfs4_alloc_stateid(clp); | ||
2611 | if (!open->op_stp) | ||
2612 | return nfserr_jukebox; | ||
2491 | return nfs_ok; | 2613 | return nfs_ok; |
2492 | } | 2614 | } |
2493 | 2615 | ||
@@ -2500,36 +2622,37 @@ nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) | |||
2500 | return nfs_ok; | 2622 | return nfs_ok; |
2501 | } | 2623 | } |
2502 | 2624 | ||
2503 | static struct nfs4_delegation * | 2625 | static int share_access_to_flags(u32 share_access) |
2504 | find_delegation_file(struct nfs4_file *fp, stateid_t *stid) | ||
2505 | { | 2626 | { |
2506 | struct nfs4_delegation *dp; | 2627 | share_access &= ~NFS4_SHARE_WANT_MASK; |
2507 | 2628 | ||
2508 | spin_lock(&recall_lock); | 2629 | return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; |
2509 | list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) | ||
2510 | if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) { | ||
2511 | spin_unlock(&recall_lock); | ||
2512 | return dp; | ||
2513 | } | ||
2514 | spin_unlock(&recall_lock); | ||
2515 | return NULL; | ||
2516 | } | 2630 | } |
2517 | 2631 | ||
2518 | static int share_access_to_flags(u32 share_access) | 2632 | static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) |
2519 | { | 2633 | { |
2520 | share_access &= ~NFS4_SHARE_WANT_MASK; | 2634 | struct nfs4_stid *ret; |
2521 | 2635 | ||
2522 | return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; | 2636 | ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID); |
2637 | if (!ret) | ||
2638 | return NULL; | ||
2639 | return delegstateid(ret); | ||
2640 | } | ||
2641 | |||
2642 | static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) | ||
2643 | { | ||
2644 | return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || | ||
2645 | open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; | ||
2523 | } | 2646 | } |
2524 | 2647 | ||
2525 | static __be32 | 2648 | static __be32 |
2526 | nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, | 2649 | nfs4_check_deleg(struct nfs4_client *cl, struct nfs4_file *fp, struct nfsd4_open *open, |
2527 | struct nfs4_delegation **dp) | 2650 | struct nfs4_delegation **dp) |
2528 | { | 2651 | { |
2529 | int flags; | 2652 | int flags; |
2530 | __be32 status = nfserr_bad_stateid; | 2653 | __be32 status = nfserr_bad_stateid; |
2531 | 2654 | ||
2532 | *dp = find_delegation_file(fp, &open->op_delegate_stateid); | 2655 | *dp = find_deleg_stateid(cl, &open->op_delegate_stateid); |
2533 | if (*dp == NULL) | 2656 | if (*dp == NULL) |
2534 | goto out; | 2657 | goto out; |
2535 | flags = share_access_to_flags(open->op_share_access); | 2658 | flags = share_access_to_flags(open->op_share_access); |
@@ -2537,41 +2660,37 @@ nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, | |||
2537 | if (status) | 2660 | if (status) |
2538 | *dp = NULL; | 2661 | *dp = NULL; |
2539 | out: | 2662 | out: |
2540 | if (open->op_claim_type != NFS4_OPEN_CLAIM_DELEGATE_CUR) | 2663 | if (!nfsd4_is_deleg_cur(open)) |
2541 | return nfs_ok; | 2664 | return nfs_ok; |
2542 | if (status) | 2665 | if (status) |
2543 | return status; | 2666 | return status; |
2544 | open->op_stateowner->so_confirmed = 1; | 2667 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; |
2545 | return nfs_ok; | 2668 | return nfs_ok; |
2546 | } | 2669 | } |
2547 | 2670 | ||
2548 | static __be32 | 2671 | static __be32 |
2549 | nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp) | 2672 | nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_stateid **stpp) |
2550 | { | 2673 | { |
2551 | struct nfs4_stateid *local; | 2674 | struct nfs4_ol_stateid *local; |
2552 | __be32 status = nfserr_share_denied; | 2675 | struct nfs4_openowner *oo = open->op_openowner; |
2553 | struct nfs4_stateowner *sop = open->op_stateowner; | ||
2554 | 2676 | ||
2555 | list_for_each_entry(local, &fp->fi_stateids, st_perfile) { | 2677 | list_for_each_entry(local, &fp->fi_stateids, st_perfile) { |
2556 | /* ignore lock owners */ | 2678 | /* ignore lock owners */ |
2557 | if (local->st_stateowner->so_is_open_owner == 0) | 2679 | if (local->st_stateowner->so_is_open_owner == 0) |
2558 | continue; | 2680 | continue; |
2559 | /* remember if we have seen this open owner */ | 2681 | /* remember if we have seen this open owner */ |
2560 | if (local->st_stateowner == sop) | 2682 | if (local->st_stateowner == &oo->oo_owner) |
2561 | *stpp = local; | 2683 | *stpp = local; |
2562 | /* check for conflicting share reservations */ | 2684 | /* check for conflicting share reservations */ |
2563 | if (!test_share(local, open)) | 2685 | if (!test_share(local, open)) |
2564 | goto out; | 2686 | return nfserr_share_denied; |
2565 | } | 2687 | } |
2566 | status = 0; | 2688 | return nfs_ok; |
2567 | out: | ||
2568 | return status; | ||
2569 | } | 2689 | } |
2570 | 2690 | ||
2571 | static inline struct nfs4_stateid * | 2691 | static void nfs4_free_stateid(struct nfs4_ol_stateid *s) |
2572 | nfs4_alloc_stateid(void) | ||
2573 | { | 2692 | { |
2574 | return kmem_cache_alloc(stateid_slab, GFP_KERNEL); | 2693 | kmem_cache_free(stateid_slab, s); |
2575 | } | 2694 | } |
2576 | 2695 | ||
2577 | static inline int nfs4_access_to_access(u32 nfs4_access) | 2696 | static inline int nfs4_access_to_access(u32 nfs4_access) |
@@ -2592,12 +2711,6 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, | |||
2592 | int oflag = nfs4_access_to_omode(open->op_share_access); | 2711 | int oflag = nfs4_access_to_omode(open->op_share_access); |
2593 | int access = nfs4_access_to_access(open->op_share_access); | 2712 | int access = nfs4_access_to_access(open->op_share_access); |
2594 | 2713 | ||
2595 | /* CLAIM_DELEGATE_CUR is used in response to a broken lease; | ||
2596 | * allowing it to break the lease and return EAGAIN leaves the | ||
2597 | * client unable to make progress in returning the delegation */ | ||
2598 | if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) | ||
2599 | access |= NFSD_MAY_NOT_BREAK_LEASE; | ||
2600 | |||
2601 | if (!fp->fi_fds[oflag]) { | 2714 | if (!fp->fi_fds[oflag]) { |
2602 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, | 2715 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, |
2603 | &fp->fi_fds[oflag]); | 2716 | &fp->fi_fds[oflag]); |
@@ -2609,27 +2722,6 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, | |||
2609 | return nfs_ok; | 2722 | return nfs_ok; |
2610 | } | 2723 | } |
2611 | 2724 | ||
2612 | static __be32 | ||
2613 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, | ||
2614 | struct nfs4_file *fp, struct svc_fh *cur_fh, | ||
2615 | struct nfsd4_open *open) | ||
2616 | { | ||
2617 | struct nfs4_stateid *stp; | ||
2618 | __be32 status; | ||
2619 | |||
2620 | stp = nfs4_alloc_stateid(); | ||
2621 | if (stp == NULL) | ||
2622 | return nfserr_resource; | ||
2623 | |||
2624 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); | ||
2625 | if (status) { | ||
2626 | kmem_cache_free(stateid_slab, stp); | ||
2627 | return status; | ||
2628 | } | ||
2629 | *stpp = stp; | ||
2630 | return 0; | ||
2631 | } | ||
2632 | |||
2633 | static inline __be32 | 2725 | static inline __be32 |
2634 | nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, | 2726 | nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, |
2635 | struct nfsd4_open *open) | 2727 | struct nfsd4_open *open) |
@@ -2646,9 +2738,9 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, | |||
2646 | } | 2738 | } |
2647 | 2739 | ||
2648 | static __be32 | 2740 | static __be32 |
2649 | nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) | 2741 | nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open) |
2650 | { | 2742 | { |
2651 | u32 op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK; | 2743 | u32 op_share_access = open->op_share_access; |
2652 | bool new_access; | 2744 | bool new_access; |
2653 | __be32 status; | 2745 | __be32 status; |
2654 | 2746 | ||
@@ -2677,8 +2769,8 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c | |||
2677 | static void | 2769 | static void |
2678 | nfs4_set_claim_prev(struct nfsd4_open *open) | 2770 | nfs4_set_claim_prev(struct nfsd4_open *open) |
2679 | { | 2771 | { |
2680 | open->op_stateowner->so_confirmed = 1; | 2772 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; |
2681 | open->op_stateowner->so_client->cl_firststate = 1; | 2773 | open->op_openowner->oo_owner.so_client->cl_firststate = 1; |
2682 | } | 2774 | } |
2683 | 2775 | ||
2684 | /* Should we give out recallable state?: */ | 2776 | /* Should we give out recallable state?: */ |
@@ -2721,7 +2813,7 @@ static int nfs4_setlease(struct nfs4_delegation *dp, int flag) | |||
2721 | if (!fl) | 2813 | if (!fl) |
2722 | return -ENOMEM; | 2814 | return -ENOMEM; |
2723 | fl->fl_file = find_readable_file(fp); | 2815 | fl->fl_file = find_readable_file(fp); |
2724 | list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations); | 2816 | list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); |
2725 | status = vfs_setlease(fl->fl_file, fl->fl_type, &fl); | 2817 | status = vfs_setlease(fl->fl_file, fl->fl_type, &fl); |
2726 | if (status) { | 2818 | if (status) { |
2727 | list_del_init(&dp->dl_perclnt); | 2819 | list_del_init(&dp->dl_perclnt); |
@@ -2750,7 +2842,7 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag) | |||
2750 | atomic_inc(&fp->fi_delegees); | 2842 | atomic_inc(&fp->fi_delegees); |
2751 | list_add(&dp->dl_perfile, &fp->fi_delegations); | 2843 | list_add(&dp->dl_perfile, &fp->fi_delegations); |
2752 | spin_unlock(&recall_lock); | 2844 | spin_unlock(&recall_lock); |
2753 | list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations); | 2845 | list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); |
2754 | return 0; | 2846 | return 0; |
2755 | } | 2847 | } |
2756 | 2848 | ||
@@ -2758,14 +2850,14 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag) | |||
2758 | * Attempt to hand out a delegation. | 2850 | * Attempt to hand out a delegation. |
2759 | */ | 2851 | */ |
2760 | static void | 2852 | static void |
2761 | nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_stateid *stp) | 2853 | nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_stateid *stp) |
2762 | { | 2854 | { |
2763 | struct nfs4_delegation *dp; | 2855 | struct nfs4_delegation *dp; |
2764 | struct nfs4_stateowner *sop = stp->st_stateowner; | 2856 | struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner); |
2765 | int cb_up; | 2857 | int cb_up; |
2766 | int status, flag = 0; | 2858 | int status, flag = 0; |
2767 | 2859 | ||
2768 | cb_up = nfsd4_cb_channel_good(sop->so_client); | 2860 | cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); |
2769 | flag = NFS4_OPEN_DELEGATE_NONE; | 2861 | flag = NFS4_OPEN_DELEGATE_NONE; |
2770 | open->op_recall = 0; | 2862 | open->op_recall = 0; |
2771 | switch (open->op_claim_type) { | 2863 | switch (open->op_claim_type) { |
@@ -2781,7 +2873,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2781 | * had the chance to reclaim theirs.... */ | 2873 | * had the chance to reclaim theirs.... */ |
2782 | if (locks_in_grace()) | 2874 | if (locks_in_grace()) |
2783 | goto out; | 2875 | goto out; |
2784 | if (!cb_up || !sop->so_confirmed) | 2876 | if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) |
2785 | goto out; | 2877 | goto out; |
2786 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | 2878 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) |
2787 | flag = NFS4_OPEN_DELEGATE_WRITE; | 2879 | flag = NFS4_OPEN_DELEGATE_WRITE; |
@@ -2792,17 +2884,17 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2792 | goto out; | 2884 | goto out; |
2793 | } | 2885 | } |
2794 | 2886 | ||
2795 | dp = alloc_init_deleg(sop->so_client, stp, fh, flag); | 2887 | dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag); |
2796 | if (dp == NULL) | 2888 | if (dp == NULL) |
2797 | goto out_no_deleg; | 2889 | goto out_no_deleg; |
2798 | status = nfs4_set_delegation(dp, flag); | 2890 | status = nfs4_set_delegation(dp, flag); |
2799 | if (status) | 2891 | if (status) |
2800 | goto out_free; | 2892 | goto out_free; |
2801 | 2893 | ||
2802 | memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid)); | 2894 | memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); |
2803 | 2895 | ||
2804 | dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", | 2896 | dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", |
2805 | STATEID_VAL(&dp->dl_stateid)); | 2897 | STATEID_VAL(&dp->dl_stid.sc_stateid)); |
2806 | out: | 2898 | out: |
2807 | if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS | 2899 | if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS |
2808 | && flag == NFS4_OPEN_DELEGATE_NONE | 2900 | && flag == NFS4_OPEN_DELEGATE_NONE |
@@ -2824,16 +2916,13 @@ __be32 | |||
2824 | nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) | 2916 | nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) |
2825 | { | 2917 | { |
2826 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | 2918 | struct nfsd4_compoundres *resp = rqstp->rq_resp; |
2919 | struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; | ||
2827 | struct nfs4_file *fp = NULL; | 2920 | struct nfs4_file *fp = NULL; |
2828 | struct inode *ino = current_fh->fh_dentry->d_inode; | 2921 | struct inode *ino = current_fh->fh_dentry->d_inode; |
2829 | struct nfs4_stateid *stp = NULL; | 2922 | struct nfs4_ol_stateid *stp = NULL; |
2830 | struct nfs4_delegation *dp = NULL; | 2923 | struct nfs4_delegation *dp = NULL; |
2831 | __be32 status; | 2924 | __be32 status; |
2832 | 2925 | ||
2833 | status = nfserr_inval; | ||
2834 | if (!access_valid(open->op_share_access, resp->cstate.minorversion) | ||
2835 | || !deny_valid(open->op_share_deny)) | ||
2836 | goto out; | ||
2837 | /* | 2926 | /* |
2838 | * Lookup file; if found, lookup stateid and check open request, | 2927 | * Lookup file; if found, lookup stateid and check open request, |
2839 | * and check for delegations in the process of being recalled. | 2928 | * and check for delegations in the process of being recalled. |
@@ -2843,17 +2932,17 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
2843 | if (fp) { | 2932 | if (fp) { |
2844 | if ((status = nfs4_check_open(fp, open, &stp))) | 2933 | if ((status = nfs4_check_open(fp, open, &stp))) |
2845 | goto out; | 2934 | goto out; |
2846 | status = nfs4_check_deleg(fp, open, &dp); | 2935 | status = nfs4_check_deleg(cl, fp, open, &dp); |
2847 | if (status) | 2936 | if (status) |
2848 | goto out; | 2937 | goto out; |
2849 | } else { | 2938 | } else { |
2850 | status = nfserr_bad_stateid; | 2939 | status = nfserr_bad_stateid; |
2851 | if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) | 2940 | if (nfsd4_is_deleg_cur(open)) |
2852 | goto out; | ||
2853 | status = nfserr_resource; | ||
2854 | fp = alloc_init_file(ino); | ||
2855 | if (fp == NULL) | ||
2856 | goto out; | 2941 | goto out; |
2942 | status = nfserr_jukebox; | ||
2943 | fp = open->op_file; | ||
2944 | open->op_file = NULL; | ||
2945 | nfsd4_init_file(fp, ino); | ||
2857 | } | 2946 | } |
2858 | 2947 | ||
2859 | /* | 2948 | /* |
@@ -2865,24 +2954,24 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
2865 | status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); | 2954 | status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); |
2866 | if (status) | 2955 | if (status) |
2867 | goto out; | 2956 | goto out; |
2868 | update_stateid(&stp->st_stateid); | ||
2869 | } else { | 2957 | } else { |
2870 | status = nfs4_new_open(rqstp, &stp, fp, current_fh, open); | 2958 | status = nfs4_get_vfs_file(rqstp, fp, current_fh, open); |
2871 | if (status) | 2959 | if (status) |
2872 | goto out; | 2960 | goto out; |
2873 | init_stateid(stp, fp, open); | 2961 | stp = open->op_stp; |
2962 | open->op_stp = NULL; | ||
2963 | init_open_stateid(stp, fp, open); | ||
2874 | status = nfsd4_truncate(rqstp, current_fh, open); | 2964 | status = nfsd4_truncate(rqstp, current_fh, open); |
2875 | if (status) { | 2965 | if (status) { |
2876 | release_open_stateid(stp); | 2966 | release_open_stateid(stp); |
2877 | goto out; | 2967 | goto out; |
2878 | } | 2968 | } |
2879 | if (nfsd4_has_session(&resp->cstate)) | ||
2880 | update_stateid(&stp->st_stateid); | ||
2881 | } | 2969 | } |
2882 | memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t)); | 2970 | update_stateid(&stp->st_stid.sc_stateid); |
2971 | memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | ||
2883 | 2972 | ||
2884 | if (nfsd4_has_session(&resp->cstate)) | 2973 | if (nfsd4_has_session(&resp->cstate)) |
2885 | open->op_stateowner->so_confirmed = 1; | 2974 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; |
2886 | 2975 | ||
2887 | /* | 2976 | /* |
2888 | * Attempt to hand out a delegation. No error return, because the | 2977 | * Attempt to hand out a delegation. No error return, because the |
@@ -2893,7 +2982,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
2893 | status = nfs_ok; | 2982 | status = nfs_ok; |
2894 | 2983 | ||
2895 | dprintk("%s: stateid=" STATEID_FMT "\n", __func__, | 2984 | dprintk("%s: stateid=" STATEID_FMT "\n", __func__, |
2896 | STATEID_VAL(&stp->st_stateid)); | 2985 | STATEID_VAL(&stp->st_stid.sc_stateid)); |
2897 | out: | 2986 | out: |
2898 | if (fp) | 2987 | if (fp) |
2899 | put_nfs4_file(fp); | 2988 | put_nfs4_file(fp); |
@@ -2903,13 +2992,34 @@ out: | |||
2903 | * To finish the open response, we just need to set the rflags. | 2992 | * To finish the open response, we just need to set the rflags. |
2904 | */ | 2993 | */ |
2905 | open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; | 2994 | open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; |
2906 | if (!open->op_stateowner->so_confirmed && | 2995 | if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) && |
2907 | !nfsd4_has_session(&resp->cstate)) | 2996 | !nfsd4_has_session(&resp->cstate)) |
2908 | open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; | 2997 | open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; |
2909 | 2998 | ||
2910 | return status; | 2999 | return status; |
2911 | } | 3000 | } |
2912 | 3001 | ||
3002 | void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status) | ||
3003 | { | ||
3004 | if (open->op_openowner) { | ||
3005 | struct nfs4_openowner *oo = open->op_openowner; | ||
3006 | |||
3007 | if (!list_empty(&oo->oo_owner.so_stateids)) | ||
3008 | list_del_init(&oo->oo_close_lru); | ||
3009 | if (oo->oo_flags & NFS4_OO_NEW) { | ||
3010 | if (status) { | ||
3011 | release_openowner(oo); | ||
3012 | open->op_openowner = NULL; | ||
3013 | } else | ||
3014 | oo->oo_flags &= ~NFS4_OO_NEW; | ||
3015 | } | ||
3016 | } | ||
3017 | if (open->op_file) | ||
3018 | nfsd4_free_file(open->op_file); | ||
3019 | if (open->op_stp) | ||
3020 | nfs4_free_stateid(open->op_stp); | ||
3021 | } | ||
3022 | |||
2913 | __be32 | 3023 | __be32 |
2914 | nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 3024 | nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
2915 | clientid_t *clid) | 3025 | clientid_t *clid) |
@@ -2930,7 +3040,6 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2930 | dprintk("nfsd4_renew: clientid not found!\n"); | 3040 | dprintk("nfsd4_renew: clientid not found!\n"); |
2931 | goto out; | 3041 | goto out; |
2932 | } | 3042 | } |
2933 | renew_client(clp); | ||
2934 | status = nfserr_cb_path_down; | 3043 | status = nfserr_cb_path_down; |
2935 | if (!list_empty(&clp->cl_delegations) | 3044 | if (!list_empty(&clp->cl_delegations) |
2936 | && clp->cl_cb_state != NFSD4_CB_UP) | 3045 | && clp->cl_cb_state != NFSD4_CB_UP) |
@@ -2962,7 +3071,7 @@ static time_t | |||
2962 | nfs4_laundromat(void) | 3071 | nfs4_laundromat(void) |
2963 | { | 3072 | { |
2964 | struct nfs4_client *clp; | 3073 | struct nfs4_client *clp; |
2965 | struct nfs4_stateowner *sop; | 3074 | struct nfs4_openowner *oo; |
2966 | struct nfs4_delegation *dp; | 3075 | struct nfs4_delegation *dp; |
2967 | struct list_head *pos, *next, reaplist; | 3076 | struct list_head *pos, *next, reaplist; |
2968 | time_t cutoff = get_seconds() - nfsd4_lease; | 3077 | time_t cutoff = get_seconds() - nfsd4_lease; |
@@ -3019,16 +3128,14 @@ nfs4_laundromat(void) | |||
3019 | } | 3128 | } |
3020 | test_val = nfsd4_lease; | 3129 | test_val = nfsd4_lease; |
3021 | list_for_each_safe(pos, next, &close_lru) { | 3130 | list_for_each_safe(pos, next, &close_lru) { |
3022 | sop = list_entry(pos, struct nfs4_stateowner, so_close_lru); | 3131 | oo = container_of(pos, struct nfs4_openowner, oo_close_lru); |
3023 | if (time_after((unsigned long)sop->so_time, (unsigned long)cutoff)) { | 3132 | if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) { |
3024 | u = sop->so_time - cutoff; | 3133 | u = oo->oo_time - cutoff; |
3025 | if (test_val > u) | 3134 | if (test_val > u) |
3026 | test_val = u; | 3135 | test_val = u; |
3027 | break; | 3136 | break; |
3028 | } | 3137 | } |
3029 | dprintk("NFSD: purging unused open stateowner (so_id %d)\n", | 3138 | release_openowner(oo); |
3030 | sop->so_id); | ||
3031 | release_openowner(sop); | ||
3032 | } | 3139 | } |
3033 | if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT) | 3140 | if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT) |
3034 | clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT; | 3141 | clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT; |
@@ -3050,30 +3157,17 @@ laundromat_main(struct work_struct *not_used) | |||
3050 | queue_delayed_work(laundry_wq, &laundromat_work, t*HZ); | 3157 | queue_delayed_work(laundry_wq, &laundromat_work, t*HZ); |
3051 | } | 3158 | } |
3052 | 3159 | ||
3053 | static struct nfs4_stateowner * | 3160 | static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp) |
3054 | search_close_lru(u32 st_id, int flags) | ||
3055 | { | 3161 | { |
3056 | struct nfs4_stateowner *local = NULL; | 3162 | if (fhp->fh_dentry->d_inode != stp->st_file->fi_inode) |
3057 | 3163 | return nfserr_bad_stateid; | |
3058 | if (flags & CLOSE_STATE) { | 3164 | return nfs_ok; |
3059 | list_for_each_entry(local, &close_lru, so_close_lru) { | ||
3060 | if (local->so_id == st_id) | ||
3061 | return local; | ||
3062 | } | ||
3063 | } | ||
3064 | return NULL; | ||
3065 | } | ||
3066 | |||
3067 | static inline int | ||
3068 | nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) | ||
3069 | { | ||
3070 | return fhp->fh_dentry->d_inode != stp->st_file->fi_inode; | ||
3071 | } | 3165 | } |
3072 | 3166 | ||
3073 | static int | 3167 | static int |
3074 | STALE_STATEID(stateid_t *stateid) | 3168 | STALE_STATEID(stateid_t *stateid) |
3075 | { | 3169 | { |
3076 | if (stateid->si_boot == boot_time) | 3170 | if (stateid->si_opaque.so_clid.cl_boot == boot_time) |
3077 | return 0; | 3171 | return 0; |
3078 | dprintk("NFSD: stale stateid " STATEID_FMT "!\n", | 3172 | dprintk("NFSD: stale stateid " STATEID_FMT "!\n", |
3079 | STATEID_VAL(stateid)); | 3173 | STATEID_VAL(stateid)); |
@@ -3096,7 +3190,7 @@ access_permit_write(unsigned long access_bmap) | |||
3096 | } | 3190 | } |
3097 | 3191 | ||
3098 | static | 3192 | static |
3099 | __be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags) | 3193 | __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) |
3100 | { | 3194 | { |
3101 | __be32 status = nfserr_openmode; | 3195 | __be32 status = nfserr_openmode; |
3102 | 3196 | ||
@@ -3139,68 +3233,80 @@ grace_disallows_io(struct inode *inode) | |||
3139 | return locks_in_grace() && mandatory_lock(inode); | 3233 | return locks_in_grace() && mandatory_lock(inode); |
3140 | } | 3234 | } |
3141 | 3235 | ||
3142 | static int check_stateid_generation(stateid_t *in, stateid_t *ref, int flags) | 3236 | /* Returns true iff a is later than b: */ |
3237 | static bool stateid_generation_after(stateid_t *a, stateid_t *b) | ||
3238 | { | ||
3239 | return (s32)a->si_generation - (s32)b->si_generation > 0; | ||
3240 | } | ||
3241 | |||
3242 | static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) | ||
3143 | { | 3243 | { |
3144 | /* | 3244 | /* |
3145 | * When sessions are used the stateid generation number is ignored | 3245 | * When sessions are used the stateid generation number is ignored |
3146 | * when it is zero. | 3246 | * when it is zero. |
3147 | */ | 3247 | */ |
3148 | if ((flags & HAS_SESSION) && in->si_generation == 0) | 3248 | if (has_session && in->si_generation == 0) |
3149 | goto out; | 3249 | return nfs_ok; |
3250 | |||
3251 | if (in->si_generation == ref->si_generation) | ||
3252 | return nfs_ok; | ||
3150 | 3253 | ||
3151 | /* If the client sends us a stateid from the future, it's buggy: */ | 3254 | /* If the client sends us a stateid from the future, it's buggy: */ |
3152 | if (in->si_generation > ref->si_generation) | 3255 | if (stateid_generation_after(in, ref)) |
3153 | return nfserr_bad_stateid; | 3256 | return nfserr_bad_stateid; |
3154 | /* | 3257 | /* |
3155 | * The following, however, can happen. For example, if the | 3258 | * However, we could see a stateid from the past, even from a |
3156 | * client sends an open and some IO at the same time, the open | 3259 | * non-buggy client. For example, if the client sends a lock |
3157 | * may bump si_generation while the IO is still in flight. | 3260 | * while some IO is outstanding, the lock may bump si_generation |
3158 | * Thanks to hard links and renames, the client never knows what | 3261 | * while the IO is still in flight. The client could avoid that |
3159 | * file an open will affect. So it could avoid that situation | 3262 | * situation by waiting for responses on all the IO requests, |
3160 | * only by serializing all opens and IO from the same open | 3263 | * but better performance may result in retrying IO that |
3161 | * owner. To recover from the old_stateid error, the client | 3264 | * receives an old_stateid error if requests are rarely |
3162 | * will just have to retry the IO: | 3265 | * reordered in flight: |
3163 | */ | 3266 | */ |
3164 | if (in->si_generation < ref->si_generation) | 3267 | return nfserr_old_stateid; |
3165 | return nfserr_old_stateid; | ||
3166 | out: | ||
3167 | return nfs_ok; | ||
3168 | } | 3268 | } |
3169 | 3269 | ||
3170 | static int is_delegation_stateid(stateid_t *stateid) | 3270 | __be32 nfs4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) |
3171 | { | 3271 | { |
3172 | return stateid->si_fileid == 0; | 3272 | struct nfs4_stid *s; |
3173 | } | 3273 | struct nfs4_ol_stateid *ols; |
3274 | __be32 status; | ||
3174 | 3275 | ||
3175 | static int is_open_stateid(struct nfs4_stateid *stateid) | 3276 | if (STALE_STATEID(stateid)) |
3176 | { | 3277 | return nfserr_stale_stateid; |
3177 | return stateid->st_openstp == NULL; | 3278 | |
3279 | s = find_stateid(cl, stateid); | ||
3280 | if (!s) | ||
3281 | return nfserr_stale_stateid; | ||
3282 | status = check_stateid_generation(stateid, &s->sc_stateid, 1); | ||
3283 | if (status) | ||
3284 | return status; | ||
3285 | if (!(s->sc_type & (NFS4_OPEN_STID | NFS4_LOCK_STID))) | ||
3286 | return nfs_ok; | ||
3287 | ols = openlockstateid(s); | ||
3288 | if (ols->st_stateowner->so_is_open_owner | ||
3289 | && !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) | ||
3290 | return nfserr_bad_stateid; | ||
3291 | return nfs_ok; | ||
3178 | } | 3292 | } |
3179 | 3293 | ||
3180 | __be32 nfs4_validate_stateid(stateid_t *stateid, int flags) | 3294 | static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s) |
3181 | { | 3295 | { |
3182 | struct nfs4_stateid *stp = NULL; | 3296 | struct nfs4_client *cl; |
3183 | __be32 status = nfserr_stale_stateid; | ||
3184 | 3297 | ||
3298 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | ||
3299 | return nfserr_bad_stateid; | ||
3185 | if (STALE_STATEID(stateid)) | 3300 | if (STALE_STATEID(stateid)) |
3186 | goto out; | 3301 | return nfserr_stale_stateid; |
3187 | 3302 | cl = find_confirmed_client(&stateid->si_opaque.so_clid); | |
3188 | status = nfserr_expired; | 3303 | if (!cl) |
3189 | stp = search_for_stateid(stateid); | 3304 | return nfserr_expired; |
3190 | if (!stp) | 3305 | *s = find_stateid_by_type(cl, stateid, typemask); |
3191 | goto out; | 3306 | if (!*s) |
3192 | status = nfserr_bad_stateid; | 3307 | return nfserr_bad_stateid; |
3193 | 3308 | return nfs_ok; | |
3194 | if (!stp->st_stateowner->so_confirmed) | ||
3195 | goto out; | ||
3196 | |||
3197 | status = check_stateid_generation(stateid, &stp->st_stateid, flags); | ||
3198 | if (status) | ||
3199 | goto out; | ||
3200 | 3309 | ||
3201 | status = nfs_ok; | ||
3202 | out: | ||
3203 | return status; | ||
3204 | } | 3310 | } |
3205 | 3311 | ||
3206 | /* | 3312 | /* |
@@ -3210,7 +3316,8 @@ __be32 | |||
3210 | nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | 3316 | nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, |
3211 | stateid_t *stateid, int flags, struct file **filpp) | 3317 | stateid_t *stateid, int flags, struct file **filpp) |
3212 | { | 3318 | { |
3213 | struct nfs4_stateid *stp = NULL; | 3319 | struct nfs4_stid *s; |
3320 | struct nfs4_ol_stateid *stp = NULL; | ||
3214 | struct nfs4_delegation *dp = NULL; | 3321 | struct nfs4_delegation *dp = NULL; |
3215 | struct svc_fh *current_fh = &cstate->current_fh; | 3322 | struct svc_fh *current_fh = &cstate->current_fh; |
3216 | struct inode *ino = current_fh->fh_dentry->d_inode; | 3323 | struct inode *ino = current_fh->fh_dentry->d_inode; |
@@ -3222,60 +3329,47 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
3222 | if (grace_disallows_io(ino)) | 3329 | if (grace_disallows_io(ino)) |
3223 | return nfserr_grace; | 3330 | return nfserr_grace; |
3224 | 3331 | ||
3225 | if (nfsd4_has_session(cstate)) | ||
3226 | flags |= HAS_SESSION; | ||
3227 | |||
3228 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 3332 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
3229 | return check_special_stateids(current_fh, stateid, flags); | 3333 | return check_special_stateids(current_fh, stateid, flags); |
3230 | 3334 | ||
3231 | status = nfserr_stale_stateid; | 3335 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s); |
3232 | if (STALE_STATEID(stateid)) | 3336 | if (status) |
3337 | return status; | ||
3338 | status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); | ||
3339 | if (status) | ||
3233 | goto out; | 3340 | goto out; |
3234 | 3341 | switch (s->sc_type) { | |
3235 | /* | 3342 | case NFS4_DELEG_STID: |
3236 | * We assume that any stateid that has the current boot time, | 3343 | dp = delegstateid(s); |
3237 | * but that we can't find, is expired: | ||
3238 | */ | ||
3239 | status = nfserr_expired; | ||
3240 | if (is_delegation_stateid(stateid)) { | ||
3241 | dp = find_delegation_stateid(ino, stateid); | ||
3242 | if (!dp) | ||
3243 | goto out; | ||
3244 | status = check_stateid_generation(stateid, &dp->dl_stateid, | ||
3245 | flags); | ||
3246 | if (status) | ||
3247 | goto out; | ||
3248 | status = nfs4_check_delegmode(dp, flags); | 3344 | status = nfs4_check_delegmode(dp, flags); |
3249 | if (status) | 3345 | if (status) |
3250 | goto out; | 3346 | goto out; |
3251 | renew_client(dp->dl_client); | ||
3252 | if (filpp) { | 3347 | if (filpp) { |
3253 | *filpp = dp->dl_file->fi_deleg_file; | 3348 | *filpp = dp->dl_file->fi_deleg_file; |
3254 | BUG_ON(!*filpp); | 3349 | BUG_ON(!*filpp); |
3255 | } | 3350 | } |
3256 | } else { /* open or lock stateid */ | 3351 | break; |
3257 | stp = find_stateid(stateid, flags); | 3352 | case NFS4_OPEN_STID: |
3258 | if (!stp) | 3353 | case NFS4_LOCK_STID: |
3259 | goto out; | 3354 | stp = openlockstateid(s); |
3260 | status = nfserr_bad_stateid; | 3355 | status = nfs4_check_fh(current_fh, stp); |
3261 | if (nfs4_check_fh(current_fh, stp)) | ||
3262 | goto out; | ||
3263 | if (!stp->st_stateowner->so_confirmed) | ||
3264 | goto out; | ||
3265 | status = check_stateid_generation(stateid, &stp->st_stateid, | ||
3266 | flags); | ||
3267 | if (status) | 3356 | if (status) |
3268 | goto out; | 3357 | goto out; |
3358 | if (stp->st_stateowner->so_is_open_owner | ||
3359 | && !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) | ||
3360 | goto out; | ||
3269 | status = nfs4_check_openmode(stp, flags); | 3361 | status = nfs4_check_openmode(stp, flags); |
3270 | if (status) | 3362 | if (status) |
3271 | goto out; | 3363 | goto out; |
3272 | renew_client(stp->st_stateowner->so_client); | ||
3273 | if (filpp) { | 3364 | if (filpp) { |
3274 | if (flags & RD_STATE) | 3365 | if (flags & RD_STATE) |
3275 | *filpp = find_readable_file(stp->st_file); | 3366 | *filpp = find_readable_file(stp->st_file); |
3276 | else | 3367 | else |
3277 | *filpp = find_writeable_file(stp->st_file); | 3368 | *filpp = find_writeable_file(stp->st_file); |
3278 | } | 3369 | } |
3370 | break; | ||
3371 | default: | ||
3372 | return nfserr_bad_stateid; | ||
3279 | } | 3373 | } |
3280 | status = nfs_ok; | 3374 | status = nfs_ok; |
3281 | out: | 3375 | out: |
@@ -3283,18 +3377,9 @@ out: | |||
3283 | } | 3377 | } |
3284 | 3378 | ||
3285 | static __be32 | 3379 | static __be32 |
3286 | nfsd4_free_delegation_stateid(stateid_t *stateid) | 3380 | nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp) |
3287 | { | 3381 | { |
3288 | struct nfs4_delegation *dp = search_for_delegation(stateid); | 3382 | if (check_for_locks(stp->st_file, lockowner(stp->st_stateowner))) |
3289 | if (dp) | ||
3290 | return nfserr_locks_held; | ||
3291 | return nfserr_bad_stateid; | ||
3292 | } | ||
3293 | |||
3294 | static __be32 | ||
3295 | nfsd4_free_lock_stateid(struct nfs4_stateid *stp) | ||
3296 | { | ||
3297 | if (check_for_locks(stp->st_file, stp->st_stateowner)) | ||
3298 | return nfserr_locks_held; | 3383 | return nfserr_locks_held; |
3299 | release_lock_stateid(stp); | 3384 | release_lock_stateid(stp); |
3300 | return nfs_ok; | 3385 | return nfs_ok; |
@@ -3307,51 +3392,40 @@ __be32 | |||
3307 | nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 3392 | nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
3308 | struct nfsd4_test_stateid *test_stateid) | 3393 | struct nfsd4_test_stateid *test_stateid) |
3309 | { | 3394 | { |
3310 | test_stateid->ts_has_session = nfsd4_has_session(cstate); | 3395 | /* real work is done during encoding */ |
3311 | return nfs_ok; | 3396 | return nfs_ok; |
3312 | } | 3397 | } |
3313 | 3398 | ||
3314 | /* | ||
3315 | * Free a state id | ||
3316 | */ | ||
3317 | __be32 | 3399 | __be32 |
3318 | nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 3400 | nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
3319 | struct nfsd4_free_stateid *free_stateid) | 3401 | struct nfsd4_free_stateid *free_stateid) |
3320 | { | 3402 | { |
3321 | stateid_t *stateid = &free_stateid->fr_stateid; | 3403 | stateid_t *stateid = &free_stateid->fr_stateid; |
3322 | struct nfs4_stateid *stp; | 3404 | struct nfs4_stid *s; |
3323 | __be32 ret; | 3405 | struct nfs4_client *cl = cstate->session->se_client; |
3406 | __be32 ret = nfserr_bad_stateid; | ||
3324 | 3407 | ||
3325 | nfs4_lock_state(); | 3408 | nfs4_lock_state(); |
3326 | if (is_delegation_stateid(stateid)) { | 3409 | s = find_stateid(cl, stateid); |
3327 | ret = nfsd4_free_delegation_stateid(stateid); | 3410 | if (!s) |
3328 | goto out; | ||
3329 | } | ||
3330 | |||
3331 | stp = search_for_stateid(stateid); | ||
3332 | if (!stp) { | ||
3333 | ret = nfserr_bad_stateid; | ||
3334 | goto out; | 3411 | goto out; |
3335 | } | 3412 | switch (s->sc_type) { |
3336 | if (stateid->si_generation != 0) { | 3413 | case NFS4_DELEG_STID: |
3337 | if (stateid->si_generation < stp->st_stateid.si_generation) { | ||
3338 | ret = nfserr_old_stateid; | ||
3339 | goto out; | ||
3340 | } | ||
3341 | if (stateid->si_generation > stp->st_stateid.si_generation) { | ||
3342 | ret = nfserr_bad_stateid; | ||
3343 | goto out; | ||
3344 | } | ||
3345 | } | ||
3346 | |||
3347 | if (is_open_stateid(stp)) { | ||
3348 | ret = nfserr_locks_held; | 3414 | ret = nfserr_locks_held; |
3349 | goto out; | 3415 | goto out; |
3350 | } else { | 3416 | case NFS4_OPEN_STID: |
3351 | ret = nfsd4_free_lock_stateid(stp); | 3417 | case NFS4_LOCK_STID: |
3352 | goto out; | 3418 | ret = check_stateid_generation(stateid, &s->sc_stateid, 1); |
3419 | if (ret) | ||
3420 | goto out; | ||
3421 | if (s->sc_type == NFS4_LOCK_STID) | ||
3422 | ret = nfsd4_free_lock_stateid(openlockstateid(s)); | ||
3423 | else | ||
3424 | ret = nfserr_locks_held; | ||
3425 | break; | ||
3426 | default: | ||
3427 | ret = nfserr_bad_stateid; | ||
3353 | } | 3428 | } |
3354 | |||
3355 | out: | 3429 | out: |
3356 | nfs4_unlock_state(); | 3430 | nfs4_unlock_state(); |
3357 | return ret; | 3431 | return ret; |
@@ -3364,124 +3438,64 @@ setlkflg (int type) | |||
3364 | RD_STATE : WR_STATE; | 3438 | RD_STATE : WR_STATE; |
3365 | } | 3439 | } |
3366 | 3440 | ||
3441 | static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) | ||
3442 | { | ||
3443 | struct svc_fh *current_fh = &cstate->current_fh; | ||
3444 | struct nfs4_stateowner *sop = stp->st_stateowner; | ||
3445 | __be32 status; | ||
3446 | |||
3447 | status = nfsd4_check_seqid(cstate, sop, seqid); | ||
3448 | if (status) | ||
3449 | return status; | ||
3450 | if (stp->st_stid.sc_type == NFS4_CLOSED_STID) | ||
3451 | /* | ||
3452 | * "Closed" stateid's exist *only* to return | ||
3453 | * nfserr_replay_me from the previous step. | ||
3454 | */ | ||
3455 | return nfserr_bad_stateid; | ||
3456 | status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); | ||
3457 | if (status) | ||
3458 | return status; | ||
3459 | return nfs4_check_fh(current_fh, stp); | ||
3460 | } | ||
3461 | |||
3367 | /* | 3462 | /* |
3368 | * Checks for sequence id mutating operations. | 3463 | * Checks for sequence id mutating operations. |
3369 | */ | 3464 | */ |
3370 | static __be32 | 3465 | static __be32 |
3371 | nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | 3466 | nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, |
3372 | stateid_t *stateid, int flags, | 3467 | stateid_t *stateid, char typemask, |
3373 | struct nfs4_stateowner **sopp, | 3468 | struct nfs4_ol_stateid **stpp) |
3374 | struct nfs4_stateid **stpp, struct nfsd4_lock *lock) | ||
3375 | { | 3469 | { |
3376 | struct nfs4_stateid *stp; | ||
3377 | struct nfs4_stateowner *sop; | ||
3378 | struct svc_fh *current_fh = &cstate->current_fh; | ||
3379 | __be32 status; | 3470 | __be32 status; |
3471 | struct nfs4_stid *s; | ||
3380 | 3472 | ||
3381 | dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__, | 3473 | dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__, |
3382 | seqid, STATEID_VAL(stateid)); | 3474 | seqid, STATEID_VAL(stateid)); |
3383 | 3475 | ||
3384 | *stpp = NULL; | 3476 | *stpp = NULL; |
3385 | *sopp = NULL; | 3477 | status = nfsd4_lookup_stateid(stateid, typemask, &s); |
3386 | 3478 | if (status) | |
3387 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { | 3479 | return status; |
3388 | dprintk("NFSD: preprocess_seqid_op: magic stateid!\n"); | 3480 | *stpp = openlockstateid(s); |
3389 | return nfserr_bad_stateid; | 3481 | cstate->replay_owner = (*stpp)->st_stateowner; |
3390 | } | ||
3391 | |||
3392 | if (STALE_STATEID(stateid)) | ||
3393 | return nfserr_stale_stateid; | ||
3394 | |||
3395 | if (nfsd4_has_session(cstate)) | ||
3396 | flags |= HAS_SESSION; | ||
3397 | |||
3398 | /* | ||
3399 | * We return BAD_STATEID if filehandle doesn't match stateid, | ||
3400 | * the confirmed flag is incorrecly set, or the generation | ||
3401 | * number is incorrect. | ||
3402 | */ | ||
3403 | stp = find_stateid(stateid, flags); | ||
3404 | if (stp == NULL) { | ||
3405 | /* | ||
3406 | * Also, we should make sure this isn't just the result of | ||
3407 | * a replayed close: | ||
3408 | */ | ||
3409 | sop = search_close_lru(stateid->si_stateownerid, flags); | ||
3410 | /* It's not stale; let's assume it's expired: */ | ||
3411 | if (sop == NULL) | ||
3412 | return nfserr_expired; | ||
3413 | *sopp = sop; | ||
3414 | goto check_replay; | ||
3415 | } | ||
3416 | |||
3417 | *stpp = stp; | ||
3418 | *sopp = sop = stp->st_stateowner; | ||
3419 | |||
3420 | if (lock) { | ||
3421 | clientid_t *lockclid = &lock->v.new.clientid; | ||
3422 | struct nfs4_client *clp = sop->so_client; | ||
3423 | int lkflg = 0; | ||
3424 | __be32 status; | ||
3425 | |||
3426 | lkflg = setlkflg(lock->lk_type); | ||
3427 | |||
3428 | if (lock->lk_is_new) { | ||
3429 | if (!sop->so_is_open_owner) | ||
3430 | return nfserr_bad_stateid; | ||
3431 | if (!(flags & HAS_SESSION) && | ||
3432 | !same_clid(&clp->cl_clientid, lockclid)) | ||
3433 | return nfserr_bad_stateid; | ||
3434 | /* stp is the open stateid */ | ||
3435 | status = nfs4_check_openmode(stp, lkflg); | ||
3436 | if (status) | ||
3437 | return status; | ||
3438 | } else { | ||
3439 | /* stp is the lock stateid */ | ||
3440 | status = nfs4_check_openmode(stp->st_openstp, lkflg); | ||
3441 | if (status) | ||
3442 | return status; | ||
3443 | } | ||
3444 | } | ||
3445 | 3482 | ||
3446 | if (nfs4_check_fh(current_fh, stp)) { | 3483 | return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp); |
3447 | dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n"); | 3484 | } |
3448 | return nfserr_bad_stateid; | ||
3449 | } | ||
3450 | 3485 | ||
3451 | /* | 3486 | static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, stateid_t *stateid, struct nfs4_ol_stateid **stpp) |
3452 | * We now validate the seqid and stateid generation numbers. | 3487 | { |
3453 | * For the moment, we ignore the possibility of | 3488 | __be32 status; |
3454 | * generation number wraparound. | 3489 | struct nfs4_openowner *oo; |
3455 | */ | ||
3456 | if (!(flags & HAS_SESSION) && seqid != sop->so_seqid) | ||
3457 | goto check_replay; | ||
3458 | 3490 | ||
3459 | if (sop->so_confirmed && flags & CONFIRM) { | 3491 | status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, |
3460 | dprintk("NFSD: preprocess_seqid_op: expected" | 3492 | NFS4_OPEN_STID, stpp); |
3461 | " unconfirmed stateowner!\n"); | ||
3462 | return nfserr_bad_stateid; | ||
3463 | } | ||
3464 | if (!sop->so_confirmed && !(flags & CONFIRM)) { | ||
3465 | dprintk("NFSD: preprocess_seqid_op: stateowner not" | ||
3466 | " confirmed yet!\n"); | ||
3467 | return nfserr_bad_stateid; | ||
3468 | } | ||
3469 | status = check_stateid_generation(stateid, &stp->st_stateid, flags); | ||
3470 | if (status) | 3493 | if (status) |
3471 | return status; | 3494 | return status; |
3472 | renew_client(sop->so_client); | 3495 | oo = openowner((*stpp)->st_stateowner); |
3496 | if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) | ||
3497 | return nfserr_bad_stateid; | ||
3473 | return nfs_ok; | 3498 | return nfs_ok; |
3474 | |||
3475 | check_replay: | ||
3476 | if (seqid == sop->so_seqid - 1) { | ||
3477 | dprintk("NFSD: preprocess_seqid_op: retransmission?\n"); | ||
3478 | /* indicate replay to calling function */ | ||
3479 | return nfserr_replay_me; | ||
3480 | } | ||
3481 | dprintk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n", | ||
3482 | sop->so_seqid, seqid); | ||
3483 | *sopp = NULL; | ||
3484 | return nfserr_bad_seqid; | ||
3485 | } | 3499 | } |
3486 | 3500 | ||
3487 | __be32 | 3501 | __be32 |
@@ -3489,8 +3503,8 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3489 | struct nfsd4_open_confirm *oc) | 3503 | struct nfsd4_open_confirm *oc) |
3490 | { | 3504 | { |
3491 | __be32 status; | 3505 | __be32 status; |
3492 | struct nfs4_stateowner *sop; | 3506 | struct nfs4_openowner *oo; |
3493 | struct nfs4_stateid *stp; | 3507 | struct nfs4_ol_stateid *stp; |
3494 | 3508 | ||
3495 | dprintk("NFSD: nfsd4_open_confirm on file %.*s\n", | 3509 | dprintk("NFSD: nfsd4_open_confirm on file %.*s\n", |
3496 | (int)cstate->current_fh.fh_dentry->d_name.len, | 3510 | (int)cstate->current_fh.fh_dentry->d_name.len, |
@@ -3502,38 +3516,52 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3502 | 3516 | ||
3503 | nfs4_lock_state(); | 3517 | nfs4_lock_state(); |
3504 | 3518 | ||
3505 | if ((status = nfs4_preprocess_seqid_op(cstate, | 3519 | status = nfs4_preprocess_seqid_op(cstate, |
3506 | oc->oc_seqid, &oc->oc_req_stateid, | 3520 | oc->oc_seqid, &oc->oc_req_stateid, |
3507 | CONFIRM | OPEN_STATE, | 3521 | NFS4_OPEN_STID, &stp); |
3508 | &oc->oc_stateowner, &stp, NULL))) | 3522 | if (status) |
3509 | goto out; | 3523 | goto out; |
3510 | 3524 | oo = openowner(stp->st_stateowner); | |
3511 | sop = oc->oc_stateowner; | 3525 | status = nfserr_bad_stateid; |
3512 | sop->so_confirmed = 1; | 3526 | if (oo->oo_flags & NFS4_OO_CONFIRMED) |
3513 | update_stateid(&stp->st_stateid); | 3527 | goto out; |
3514 | memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t)); | 3528 | oo->oo_flags |= NFS4_OO_CONFIRMED; |
3529 | update_stateid(&stp->st_stid.sc_stateid); | ||
3530 | memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | ||
3515 | dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", | 3531 | dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", |
3516 | __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stateid)); | 3532 | __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); |
3517 | 3533 | ||
3518 | nfsd4_create_clid_dir(sop->so_client); | 3534 | nfsd4_create_clid_dir(oo->oo_owner.so_client); |
3535 | status = nfs_ok; | ||
3519 | out: | 3536 | out: |
3520 | if (oc->oc_stateowner) { | 3537 | if (!cstate->replay_owner) |
3521 | nfs4_get_stateowner(oc->oc_stateowner); | 3538 | nfs4_unlock_state(); |
3522 | cstate->replay_owner = oc->oc_stateowner; | ||
3523 | } | ||
3524 | nfs4_unlock_state(); | ||
3525 | return status; | 3539 | return status; |
3526 | } | 3540 | } |
3527 | 3541 | ||
3528 | static inline void nfs4_file_downgrade(struct nfs4_stateid *stp, unsigned int to_access) | 3542 | static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) |
3529 | { | 3543 | { |
3530 | int i; | 3544 | if (!test_bit(access, &stp->st_access_bmap)) |
3545 | return; | ||
3546 | nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access)); | ||
3547 | __clear_bit(access, &stp->st_access_bmap); | ||
3548 | } | ||
3531 | 3549 | ||
3532 | for (i = 1; i < 4; i++) { | 3550 | static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) |
3533 | if (test_bit(i, &stp->st_access_bmap) && !(i & to_access)) { | 3551 | { |
3534 | nfs4_file_put_access(stp->st_file, i); | 3552 | switch (to_access) { |
3535 | __clear_bit(i, &stp->st_access_bmap); | 3553 | case NFS4_SHARE_ACCESS_READ: |
3536 | } | 3554 | nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); |
3555 | nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); | ||
3556 | break; | ||
3557 | case NFS4_SHARE_ACCESS_WRITE: | ||
3558 | nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); | ||
3559 | nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); | ||
3560 | break; | ||
3561 | case NFS4_SHARE_ACCESS_BOTH: | ||
3562 | break; | ||
3563 | default: | ||
3564 | BUG(); | ||
3537 | } | 3565 | } |
3538 | } | 3566 | } |
3539 | 3567 | ||
@@ -3553,24 +3581,20 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3553 | struct nfsd4_open_downgrade *od) | 3581 | struct nfsd4_open_downgrade *od) |
3554 | { | 3582 | { |
3555 | __be32 status; | 3583 | __be32 status; |
3556 | struct nfs4_stateid *stp; | 3584 | struct nfs4_ol_stateid *stp; |
3557 | 3585 | ||
3558 | dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", | 3586 | dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", |
3559 | (int)cstate->current_fh.fh_dentry->d_name.len, | 3587 | (int)cstate->current_fh.fh_dentry->d_name.len, |
3560 | cstate->current_fh.fh_dentry->d_name.name); | 3588 | cstate->current_fh.fh_dentry->d_name.name); |
3561 | 3589 | ||
3562 | if (!access_valid(od->od_share_access, cstate->minorversion) | 3590 | /* We don't yet support WANT bits: */ |
3563 | || !deny_valid(od->od_share_deny)) | 3591 | od->od_share_access &= NFS4_SHARE_ACCESS_MASK; |
3564 | return nfserr_inval; | ||
3565 | 3592 | ||
3566 | nfs4_lock_state(); | 3593 | nfs4_lock_state(); |
3567 | if ((status = nfs4_preprocess_seqid_op(cstate, | 3594 | status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, |
3568 | od->od_seqid, | 3595 | &od->od_stateid, &stp); |
3569 | &od->od_stateid, | 3596 | if (status) |
3570 | OPEN_STATE, | ||
3571 | &od->od_stateowner, &stp, NULL))) | ||
3572 | goto out; | 3597 | goto out; |
3573 | |||
3574 | status = nfserr_inval; | 3598 | status = nfserr_inval; |
3575 | if (!test_bit(od->od_share_access, &stp->st_access_bmap)) { | 3599 | if (!test_bit(od->od_share_access, &stp->st_access_bmap)) { |
3576 | dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n", | 3600 | dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n", |
@@ -3582,22 +3606,45 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3582 | stp->st_deny_bmap, od->od_share_deny); | 3606 | stp->st_deny_bmap, od->od_share_deny); |
3583 | goto out; | 3607 | goto out; |
3584 | } | 3608 | } |
3585 | nfs4_file_downgrade(stp, od->od_share_access); | 3609 | nfs4_stateid_downgrade(stp, od->od_share_access); |
3586 | 3610 | ||
3587 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); | 3611 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); |
3588 | 3612 | ||
3589 | update_stateid(&stp->st_stateid); | 3613 | update_stateid(&stp->st_stid.sc_stateid); |
3590 | memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t)); | 3614 | memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
3591 | status = nfs_ok; | 3615 | status = nfs_ok; |
3592 | out: | 3616 | out: |
3593 | if (od->od_stateowner) { | 3617 | if (!cstate->replay_owner) |
3594 | nfs4_get_stateowner(od->od_stateowner); | 3618 | nfs4_unlock_state(); |
3595 | cstate->replay_owner = od->od_stateowner; | ||
3596 | } | ||
3597 | nfs4_unlock_state(); | ||
3598 | return status; | 3619 | return status; |
3599 | } | 3620 | } |
3600 | 3621 | ||
3622 | void nfsd4_purge_closed_stateid(struct nfs4_stateowner *so) | ||
3623 | { | ||
3624 | struct nfs4_openowner *oo; | ||
3625 | struct nfs4_ol_stateid *s; | ||
3626 | |||
3627 | if (!so->so_is_open_owner) | ||
3628 | return; | ||
3629 | oo = openowner(so); | ||
3630 | s = oo->oo_last_closed_stid; | ||
3631 | if (!s) | ||
3632 | return; | ||
3633 | if (!(oo->oo_flags & NFS4_OO_PURGE_CLOSE)) { | ||
3634 | /* Release the last_closed_stid on the next seqid bump: */ | ||
3635 | oo->oo_flags |= NFS4_OO_PURGE_CLOSE; | ||
3636 | return; | ||
3637 | } | ||
3638 | oo->oo_flags &= ~NFS4_OO_PURGE_CLOSE; | ||
3639 | release_last_closed_stateid(oo); | ||
3640 | } | ||
3641 | |||
3642 | static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) | ||
3643 | { | ||
3644 | unhash_open_stateid(s); | ||
3645 | s->st_stid.sc_type = NFS4_CLOSED_STID; | ||
3646 | } | ||
3647 | |||
3601 | /* | 3648 | /* |
3602 | * nfs4_unlock_state() called after encode | 3649 | * nfs4_unlock_state() called after encode |
3603 | */ | 3650 | */ |
@@ -3606,39 +3653,37 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3606 | struct nfsd4_close *close) | 3653 | struct nfsd4_close *close) |
3607 | { | 3654 | { |
3608 | __be32 status; | 3655 | __be32 status; |
3609 | struct nfs4_stateid *stp; | 3656 | struct nfs4_openowner *oo; |
3657 | struct nfs4_ol_stateid *stp; | ||
3610 | 3658 | ||
3611 | dprintk("NFSD: nfsd4_close on file %.*s\n", | 3659 | dprintk("NFSD: nfsd4_close on file %.*s\n", |
3612 | (int)cstate->current_fh.fh_dentry->d_name.len, | 3660 | (int)cstate->current_fh.fh_dentry->d_name.len, |
3613 | cstate->current_fh.fh_dentry->d_name.name); | 3661 | cstate->current_fh.fh_dentry->d_name.name); |
3614 | 3662 | ||
3615 | nfs4_lock_state(); | 3663 | nfs4_lock_state(); |
3616 | /* check close_lru for replay */ | 3664 | status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, |
3617 | if ((status = nfs4_preprocess_seqid_op(cstate, | 3665 | &close->cl_stateid, |
3618 | close->cl_seqid, | 3666 | NFS4_OPEN_STID|NFS4_CLOSED_STID, |
3619 | &close->cl_stateid, | 3667 | &stp); |
3620 | OPEN_STATE | CLOSE_STATE, | 3668 | if (status) |
3621 | &close->cl_stateowner, &stp, NULL))) | ||
3622 | goto out; | 3669 | goto out; |
3670 | oo = openowner(stp->st_stateowner); | ||
3623 | status = nfs_ok; | 3671 | status = nfs_ok; |
3624 | update_stateid(&stp->st_stateid); | 3672 | update_stateid(&stp->st_stid.sc_stateid); |
3625 | memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t)); | 3673 | memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
3626 | 3674 | ||
3627 | /* release_stateid() calls nfsd_close() if needed */ | 3675 | nfsd4_close_open_stateid(stp); |
3628 | release_open_stateid(stp); | 3676 | oo->oo_last_closed_stid = stp; |
3629 | 3677 | ||
3630 | /* place unused nfs4_stateowners on so_close_lru list to be | 3678 | /* place unused nfs4_stateowners on so_close_lru list to be |
3631 | * released by the laundromat service after the lease period | 3679 | * released by the laundromat service after the lease period |
3632 | * to enable us to handle CLOSE replay | 3680 | * to enable us to handle CLOSE replay |
3633 | */ | 3681 | */ |
3634 | if (list_empty(&close->cl_stateowner->so_stateids)) | 3682 | if (list_empty(&oo->oo_owner.so_stateids)) |
3635 | move_to_close_lru(close->cl_stateowner); | 3683 | move_to_close_lru(oo); |
3636 | out: | 3684 | out: |
3637 | if (close->cl_stateowner) { | 3685 | if (!cstate->replay_owner) |
3638 | nfs4_get_stateowner(close->cl_stateowner); | 3686 | nfs4_unlock_state(); |
3639 | cstate->replay_owner = close->cl_stateowner; | ||
3640 | } | ||
3641 | nfs4_unlock_state(); | ||
3642 | return status; | 3687 | return status; |
3643 | } | 3688 | } |
3644 | 3689 | ||
@@ -3648,34 +3693,22 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3648 | { | 3693 | { |
3649 | struct nfs4_delegation *dp; | 3694 | struct nfs4_delegation *dp; |
3650 | stateid_t *stateid = &dr->dr_stateid; | 3695 | stateid_t *stateid = &dr->dr_stateid; |
3696 | struct nfs4_stid *s; | ||
3651 | struct inode *inode; | 3697 | struct inode *inode; |
3652 | __be32 status; | 3698 | __be32 status; |
3653 | int flags = 0; | ||
3654 | 3699 | ||
3655 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) | 3700 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) |
3656 | return status; | 3701 | return status; |
3657 | inode = cstate->current_fh.fh_dentry->d_inode; | 3702 | inode = cstate->current_fh.fh_dentry->d_inode; |
3658 | 3703 | ||
3659 | if (nfsd4_has_session(cstate)) | ||
3660 | flags |= HAS_SESSION; | ||
3661 | nfs4_lock_state(); | 3704 | nfs4_lock_state(); |
3662 | status = nfserr_bad_stateid; | 3705 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s); |
3663 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 3706 | if (status) |
3664 | goto out; | ||
3665 | status = nfserr_stale_stateid; | ||
3666 | if (STALE_STATEID(stateid)) | ||
3667 | goto out; | ||
3668 | status = nfserr_bad_stateid; | ||
3669 | if (!is_delegation_stateid(stateid)) | ||
3670 | goto out; | ||
3671 | status = nfserr_expired; | ||
3672 | dp = find_delegation_stateid(inode, stateid); | ||
3673 | if (!dp) | ||
3674 | goto out; | 3707 | goto out; |
3675 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); | 3708 | dp = delegstateid(s); |
3709 | status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate)); | ||
3676 | if (status) | 3710 | if (status) |
3677 | goto out; | 3711 | goto out; |
3678 | renew_client(dp->dl_client); | ||
3679 | 3712 | ||
3680 | unhash_delegation(dp); | 3713 | unhash_delegation(dp); |
3681 | out: | 3714 | out: |
@@ -3713,9 +3746,6 @@ last_byte_offset(u64 start, u64 len) | |||
3713 | return end > start ? end - 1: NFS4_MAX_UINT64; | 3746 | return end > start ? end - 1: NFS4_MAX_UINT64; |
3714 | } | 3747 | } |
3715 | 3748 | ||
3716 | #define lockownerid_hashval(id) \ | ||
3717 | ((id) & LOCK_HASH_MASK) | ||
3718 | |||
3719 | static inline unsigned int | 3749 | static inline unsigned int |
3720 | lock_ownerstr_hashval(struct inode *inode, u32 cl_id, | 3750 | lock_ownerstr_hashval(struct inode *inode, u32 cl_id, |
3721 | struct xdr_netobj *ownername) | 3751 | struct xdr_netobj *ownername) |
@@ -3725,101 +3755,7 @@ lock_ownerstr_hashval(struct inode *inode, u32 cl_id, | |||
3725 | & LOCK_HASH_MASK; | 3755 | & LOCK_HASH_MASK; |
3726 | } | 3756 | } |
3727 | 3757 | ||
3728 | static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE]; | ||
3729 | static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; | 3758 | static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; |
3730 | static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE]; | ||
3731 | |||
3732 | static int | ||
3733 | same_stateid(stateid_t *id_one, stateid_t *id_two) | ||
3734 | { | ||
3735 | if (id_one->si_stateownerid != id_two->si_stateownerid) | ||
3736 | return 0; | ||
3737 | return id_one->si_fileid == id_two->si_fileid; | ||
3738 | } | ||
3739 | |||
3740 | static struct nfs4_stateid * | ||
3741 | find_stateid(stateid_t *stid, int flags) | ||
3742 | { | ||
3743 | struct nfs4_stateid *local; | ||
3744 | u32 st_id = stid->si_stateownerid; | ||
3745 | u32 f_id = stid->si_fileid; | ||
3746 | unsigned int hashval; | ||
3747 | |||
3748 | dprintk("NFSD: find_stateid flags 0x%x\n",flags); | ||
3749 | if (flags & (LOCK_STATE | RD_STATE | WR_STATE)) { | ||
3750 | hashval = stateid_hashval(st_id, f_id); | ||
3751 | list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) { | ||
3752 | if ((local->st_stateid.si_stateownerid == st_id) && | ||
3753 | (local->st_stateid.si_fileid == f_id)) | ||
3754 | return local; | ||
3755 | } | ||
3756 | } | ||
3757 | |||
3758 | if (flags & (OPEN_STATE | RD_STATE | WR_STATE)) { | ||
3759 | hashval = stateid_hashval(st_id, f_id); | ||
3760 | list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) { | ||
3761 | if ((local->st_stateid.si_stateownerid == st_id) && | ||
3762 | (local->st_stateid.si_fileid == f_id)) | ||
3763 | return local; | ||
3764 | } | ||
3765 | } | ||
3766 | return NULL; | ||
3767 | } | ||
3768 | |||
3769 | static struct nfs4_stateid * | ||
3770 | search_for_stateid(stateid_t *stid) | ||
3771 | { | ||
3772 | struct nfs4_stateid *local; | ||
3773 | unsigned int hashval = stateid_hashval(stid->si_stateownerid, stid->si_fileid); | ||
3774 | |||
3775 | list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) { | ||
3776 | if (same_stateid(&local->st_stateid, stid)) | ||
3777 | return local; | ||
3778 | } | ||
3779 | |||
3780 | list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) { | ||
3781 | if (same_stateid(&local->st_stateid, stid)) | ||
3782 | return local; | ||
3783 | } | ||
3784 | return NULL; | ||
3785 | } | ||
3786 | |||
3787 | static struct nfs4_delegation * | ||
3788 | search_for_delegation(stateid_t *stid) | ||
3789 | { | ||
3790 | struct nfs4_file *fp; | ||
3791 | struct nfs4_delegation *dp; | ||
3792 | struct list_head *pos; | ||
3793 | int i; | ||
3794 | |||
3795 | for (i = 0; i < FILE_HASH_SIZE; i++) { | ||
3796 | list_for_each_entry(fp, &file_hashtbl[i], fi_hash) { | ||
3797 | list_for_each(pos, &fp->fi_delegations) { | ||
3798 | dp = list_entry(pos, struct nfs4_delegation, dl_perfile); | ||
3799 | if (same_stateid(&dp->dl_stateid, stid)) | ||
3800 | return dp; | ||
3801 | } | ||
3802 | } | ||
3803 | } | ||
3804 | return NULL; | ||
3805 | } | ||
3806 | |||
3807 | static struct nfs4_delegation * | ||
3808 | find_delegation_stateid(struct inode *ino, stateid_t *stid) | ||
3809 | { | ||
3810 | struct nfs4_file *fp; | ||
3811 | struct nfs4_delegation *dl; | ||
3812 | |||
3813 | dprintk("NFSD: %s: stateid=" STATEID_FMT "\n", __func__, | ||
3814 | STATEID_VAL(stid)); | ||
3815 | |||
3816 | fp = find_file(ino); | ||
3817 | if (!fp) | ||
3818 | return NULL; | ||
3819 | dl = find_delegation_file(fp, stid); | ||
3820 | put_nfs4_file(fp); | ||
3821 | return dl; | ||
3822 | } | ||
3823 | 3759 | ||
3824 | /* | 3760 | /* |
3825 | * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that | 3761 | * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that |
@@ -3846,15 +3782,21 @@ static const struct lock_manager_operations nfsd_posix_mng_ops = { | |||
3846 | static inline void | 3782 | static inline void |
3847 | nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) | 3783 | nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) |
3848 | { | 3784 | { |
3849 | struct nfs4_stateowner *sop; | 3785 | struct nfs4_lockowner *lo; |
3850 | 3786 | ||
3851 | if (fl->fl_lmops == &nfsd_posix_mng_ops) { | 3787 | if (fl->fl_lmops == &nfsd_posix_mng_ops) { |
3852 | sop = (struct nfs4_stateowner *) fl->fl_owner; | 3788 | lo = (struct nfs4_lockowner *) fl->fl_owner; |
3853 | kref_get(&sop->so_ref); | 3789 | deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data, |
3854 | deny->ld_sop = sop; | 3790 | lo->lo_owner.so_owner.len, GFP_KERNEL); |
3855 | deny->ld_clientid = sop->so_client->cl_clientid; | 3791 | if (!deny->ld_owner.data) |
3792 | /* We just don't care that much */ | ||
3793 | goto nevermind; | ||
3794 | deny->ld_owner.len = lo->lo_owner.so_owner.len; | ||
3795 | deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; | ||
3856 | } else { | 3796 | } else { |
3857 | deny->ld_sop = NULL; | 3797 | nevermind: |
3798 | deny->ld_owner.len = 0; | ||
3799 | deny->ld_owner.data = NULL; | ||
3858 | deny->ld_clientid.cl_boot = 0; | 3800 | deny->ld_clientid.cl_boot = 0; |
3859 | deny->ld_clientid.cl_id = 0; | 3801 | deny->ld_clientid.cl_id = 0; |
3860 | } | 3802 | } |
@@ -3867,8 +3809,8 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) | |||
3867 | deny->ld_type = NFS4_WRITE_LT; | 3809 | deny->ld_type = NFS4_WRITE_LT; |
3868 | } | 3810 | } |
3869 | 3811 | ||
3870 | static struct nfs4_stateowner * | 3812 | static struct nfs4_lockowner * |
3871 | find_lockstateowner_str(struct inode *inode, clientid_t *clid, | 3813 | find_lockowner_str(struct inode *inode, clientid_t *clid, |
3872 | struct xdr_netobj *owner) | 3814 | struct xdr_netobj *owner) |
3873 | { | 3815 | { |
3874 | unsigned int hashval = lock_ownerstr_hashval(inode, clid->cl_id, owner); | 3816 | unsigned int hashval = lock_ownerstr_hashval(inode, clid->cl_id, owner); |
@@ -3876,11 +3818,17 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid, | |||
3876 | 3818 | ||
3877 | list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) { | 3819 | list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) { |
3878 | if (same_owner_str(op, owner, clid)) | 3820 | if (same_owner_str(op, owner, clid)) |
3879 | return op; | 3821 | return lockowner(op); |
3880 | } | 3822 | } |
3881 | return NULL; | 3823 | return NULL; |
3882 | } | 3824 | } |
3883 | 3825 | ||
3826 | static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp) | ||
3827 | { | ||
3828 | list_add(&lo->lo_owner.so_strhash, &lock_ownerstr_hashtbl[strhashval]); | ||
3829 | list_add(&lo->lo_perstateid, &open_stp->st_lockowners); | ||
3830 | } | ||
3831 | |||
3884 | /* | 3832 | /* |
3885 | * Alloc a lock owner structure. | 3833 | * Alloc a lock owner structure. |
3886 | * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has | 3834 | * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has |
@@ -3889,67 +3837,40 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid, | |||
3889 | * strhashval = lock_ownerstr_hashval | 3837 | * strhashval = lock_ownerstr_hashval |
3890 | */ | 3838 | */ |
3891 | 3839 | ||
3892 | static struct nfs4_stateowner * | 3840 | static struct nfs4_lockowner * |
3893 | alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp, struct nfsd4_lock *lock) { | 3841 | alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp, struct nfsd4_lock *lock) { |
3894 | struct nfs4_stateowner *sop; | 3842 | struct nfs4_lockowner *lo; |
3895 | struct nfs4_replay *rp; | ||
3896 | unsigned int idhashval; | ||
3897 | 3843 | ||
3898 | if (!(sop = alloc_stateowner(&lock->lk_new_owner))) | 3844 | lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); |
3845 | if (!lo) | ||
3899 | return NULL; | 3846 | return NULL; |
3900 | idhashval = lockownerid_hashval(current_ownerid); | 3847 | INIT_LIST_HEAD(&lo->lo_owner.so_stateids); |
3901 | INIT_LIST_HEAD(&sop->so_idhash); | 3848 | lo->lo_owner.so_is_open_owner = 0; |
3902 | INIT_LIST_HEAD(&sop->so_strhash); | ||
3903 | INIT_LIST_HEAD(&sop->so_perclient); | ||
3904 | INIT_LIST_HEAD(&sop->so_stateids); | ||
3905 | INIT_LIST_HEAD(&sop->so_perstateid); | ||
3906 | INIT_LIST_HEAD(&sop->so_close_lru); /* not used */ | ||
3907 | sop->so_time = 0; | ||
3908 | list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]); | ||
3909 | list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]); | ||
3910 | list_add(&sop->so_perstateid, &open_stp->st_lockowners); | ||
3911 | sop->so_is_open_owner = 0; | ||
3912 | sop->so_id = current_ownerid++; | ||
3913 | sop->so_client = clp; | ||
3914 | /* It is the openowner seqid that will be incremented in encode in the | 3849 | /* It is the openowner seqid that will be incremented in encode in the |
3915 | * case of new lockowners; so increment the lock seqid manually: */ | 3850 | * case of new lockowners; so increment the lock seqid manually: */ |
3916 | sop->so_seqid = lock->lk_new_lock_seqid + 1; | 3851 | lo->lo_owner.so_seqid = lock->lk_new_lock_seqid + 1; |
3917 | sop->so_confirmed = 1; | 3852 | hash_lockowner(lo, strhashval, clp, open_stp); |
3918 | rp = &sop->so_replay; | 3853 | return lo; |
3919 | rp->rp_status = nfserr_serverfault; | ||
3920 | rp->rp_buflen = 0; | ||
3921 | rp->rp_buf = rp->rp_ibuf; | ||
3922 | return sop; | ||
3923 | } | 3854 | } |
3924 | 3855 | ||
3925 | static struct nfs4_stateid * | 3856 | static struct nfs4_ol_stateid * |
3926 | alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struct nfs4_stateid *open_stp) | 3857 | alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp) |
3927 | { | 3858 | { |
3928 | struct nfs4_stateid *stp; | 3859 | struct nfs4_ol_stateid *stp; |
3929 | unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id); | 3860 | struct nfs4_client *clp = lo->lo_owner.so_client; |
3930 | 3861 | ||
3931 | stp = nfs4_alloc_stateid(); | 3862 | stp = nfs4_alloc_stateid(clp); |
3932 | if (stp == NULL) | 3863 | if (stp == NULL) |
3933 | goto out; | 3864 | return NULL; |
3934 | INIT_LIST_HEAD(&stp->st_hash); | 3865 | init_stid(&stp->st_stid, clp, NFS4_LOCK_STID); |
3935 | INIT_LIST_HEAD(&stp->st_perfile); | ||
3936 | INIT_LIST_HEAD(&stp->st_perstateowner); | ||
3937 | INIT_LIST_HEAD(&stp->st_lockowners); /* not used */ | ||
3938 | list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]); | ||
3939 | list_add(&stp->st_perfile, &fp->fi_stateids); | 3866 | list_add(&stp->st_perfile, &fp->fi_stateids); |
3940 | list_add(&stp->st_perstateowner, &sop->so_stateids); | 3867 | list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); |
3941 | stp->st_stateowner = sop; | 3868 | stp->st_stateowner = &lo->lo_owner; |
3942 | get_nfs4_file(fp); | 3869 | get_nfs4_file(fp); |
3943 | stp->st_file = fp; | 3870 | stp->st_file = fp; |
3944 | stp->st_stateid.si_boot = boot_time; | ||
3945 | stp->st_stateid.si_stateownerid = sop->so_id; | ||
3946 | stp->st_stateid.si_fileid = fp->fi_id; | ||
3947 | stp->st_stateid.si_generation = 0; | ||
3948 | stp->st_access_bmap = 0; | 3871 | stp->st_access_bmap = 0; |
3949 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 3872 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
3950 | stp->st_openstp = open_stp; | 3873 | stp->st_openstp = open_stp; |
3951 | |||
3952 | out: | ||
3953 | return stp; | 3874 | return stp; |
3954 | } | 3875 | } |
3955 | 3876 | ||
@@ -3960,7 +3881,7 @@ check_lock_length(u64 offset, u64 length) | |||
3960 | LOFF_OVERFLOW(offset, length))); | 3881 | LOFF_OVERFLOW(offset, length))); |
3961 | } | 3882 | } |
3962 | 3883 | ||
3963 | static void get_lock_access(struct nfs4_stateid *lock_stp, u32 access) | 3884 | static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) |
3964 | { | 3885 | { |
3965 | struct nfs4_file *fp = lock_stp->st_file; | 3886 | struct nfs4_file *fp = lock_stp->st_file; |
3966 | int oflag = nfs4_access_to_omode(access); | 3887 | int oflag = nfs4_access_to_omode(access); |
@@ -3978,15 +3899,16 @@ __be32 | |||
3978 | nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 3899 | nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
3979 | struct nfsd4_lock *lock) | 3900 | struct nfsd4_lock *lock) |
3980 | { | 3901 | { |
3981 | struct nfs4_stateowner *open_sop = NULL; | 3902 | struct nfs4_openowner *open_sop = NULL; |
3982 | struct nfs4_stateowner *lock_sop = NULL; | 3903 | struct nfs4_lockowner *lock_sop = NULL; |
3983 | struct nfs4_stateid *lock_stp; | 3904 | struct nfs4_ol_stateid *lock_stp; |
3984 | struct nfs4_file *fp; | 3905 | struct nfs4_file *fp; |
3985 | struct file *filp = NULL; | 3906 | struct file *filp = NULL; |
3986 | struct file_lock file_lock; | 3907 | struct file_lock file_lock; |
3987 | struct file_lock conflock; | 3908 | struct file_lock conflock; |
3988 | __be32 status = 0; | 3909 | __be32 status = 0; |
3989 | unsigned int strhashval; | 3910 | unsigned int strhashval; |
3911 | int lkflg; | ||
3990 | int err; | 3912 | int err; |
3991 | 3913 | ||
3992 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", | 3914 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", |
@@ -4010,7 +3932,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4010 | * Use open owner and open stateid to create lock owner and | 3932 | * Use open owner and open stateid to create lock owner and |
4011 | * lock stateid. | 3933 | * lock stateid. |
4012 | */ | 3934 | */ |
4013 | struct nfs4_stateid *open_stp = NULL; | 3935 | struct nfs4_ol_stateid *open_stp = NULL; |
4014 | 3936 | ||
4015 | status = nfserr_stale_clientid; | 3937 | status = nfserr_stale_clientid; |
4016 | if (!nfsd4_has_session(cstate) && | 3938 | if (!nfsd4_has_session(cstate) && |
@@ -4018,26 +3940,29 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4018 | goto out; | 3940 | goto out; |
4019 | 3941 | ||
4020 | /* validate and update open stateid and open seqid */ | 3942 | /* validate and update open stateid and open seqid */ |
4021 | status = nfs4_preprocess_seqid_op(cstate, | 3943 | status = nfs4_preprocess_confirmed_seqid_op(cstate, |
4022 | lock->lk_new_open_seqid, | 3944 | lock->lk_new_open_seqid, |
4023 | &lock->lk_new_open_stateid, | 3945 | &lock->lk_new_open_stateid, |
4024 | OPEN_STATE, | 3946 | &open_stp); |
4025 | &lock->lk_replay_owner, &open_stp, | ||
4026 | lock); | ||
4027 | if (status) | 3947 | if (status) |
4028 | goto out; | 3948 | goto out; |
4029 | open_sop = lock->lk_replay_owner; | 3949 | open_sop = openowner(open_stp->st_stateowner); |
3950 | status = nfserr_bad_stateid; | ||
3951 | if (!nfsd4_has_session(cstate) && | ||
3952 | !same_clid(&open_sop->oo_owner.so_client->cl_clientid, | ||
3953 | &lock->v.new.clientid)) | ||
3954 | goto out; | ||
4030 | /* create lockowner and lock stateid */ | 3955 | /* create lockowner and lock stateid */ |
4031 | fp = open_stp->st_file; | 3956 | fp = open_stp->st_file; |
4032 | strhashval = lock_ownerstr_hashval(fp->fi_inode, | 3957 | strhashval = lock_ownerstr_hashval(fp->fi_inode, |
4033 | open_sop->so_client->cl_clientid.cl_id, | 3958 | open_sop->oo_owner.so_client->cl_clientid.cl_id, |
4034 | &lock->v.new.owner); | 3959 | &lock->v.new.owner); |
4035 | /* XXX: Do we need to check for duplicate stateowners on | 3960 | /* XXX: Do we need to check for duplicate stateowners on |
4036 | * the same file, or should they just be allowed (and | 3961 | * the same file, or should they just be allowed (and |
4037 | * create new stateids)? */ | 3962 | * create new stateids)? */ |
4038 | status = nfserr_resource; | 3963 | status = nfserr_jukebox; |
4039 | lock_sop = alloc_init_lock_stateowner(strhashval, | 3964 | lock_sop = alloc_init_lock_stateowner(strhashval, |
4040 | open_sop->so_client, open_stp, lock); | 3965 | open_sop->oo_owner.so_client, open_stp, lock); |
4041 | if (lock_sop == NULL) | 3966 | if (lock_sop == NULL) |
4042 | goto out; | 3967 | goto out; |
4043 | lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); | 3968 | lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); |
@@ -4046,16 +3971,20 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4046 | } else { | 3971 | } else { |
4047 | /* lock (lock owner + lock stateid) already exists */ | 3972 | /* lock (lock owner + lock stateid) already exists */ |
4048 | status = nfs4_preprocess_seqid_op(cstate, | 3973 | status = nfs4_preprocess_seqid_op(cstate, |
4049 | lock->lk_old_lock_seqid, | 3974 | lock->lk_old_lock_seqid, |
4050 | &lock->lk_old_lock_stateid, | 3975 | &lock->lk_old_lock_stateid, |
4051 | LOCK_STATE, | 3976 | NFS4_LOCK_STID, &lock_stp); |
4052 | &lock->lk_replay_owner, &lock_stp, lock); | ||
4053 | if (status) | 3977 | if (status) |
4054 | goto out; | 3978 | goto out; |
4055 | lock_sop = lock->lk_replay_owner; | 3979 | lock_sop = lockowner(lock_stp->st_stateowner); |
4056 | fp = lock_stp->st_file; | 3980 | fp = lock_stp->st_file; |
4057 | } | 3981 | } |
4058 | /* lock->lk_replay_owner and lock_stp have been created or found */ | 3982 | /* lock_sop and lock_stp have been created or found */ |
3983 | |||
3984 | lkflg = setlkflg(lock->lk_type); | ||
3985 | status = nfs4_check_openmode(lock_stp, lkflg); | ||
3986 | if (status) | ||
3987 | goto out; | ||
4059 | 3988 | ||
4060 | status = nfserr_grace; | 3989 | status = nfserr_grace; |
4061 | if (locks_in_grace() && !lock->lk_reclaim) | 3990 | if (locks_in_grace() && !lock->lk_reclaim) |
@@ -4106,8 +4035,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4106 | err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock); | 4035 | err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock); |
4107 | switch (-err) { | 4036 | switch (-err) { |
4108 | case 0: /* success! */ | 4037 | case 0: /* success! */ |
4109 | update_stateid(&lock_stp->st_stateid); | 4038 | update_stateid(&lock_stp->st_stid.sc_stateid); |
4110 | memcpy(&lock->lk_resp_stateid, &lock_stp->st_stateid, | 4039 | memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid, |
4111 | sizeof(stateid_t)); | 4040 | sizeof(stateid_t)); |
4112 | status = 0; | 4041 | status = 0; |
4113 | break; | 4042 | break; |
@@ -4119,19 +4048,16 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4119 | case (EDEADLK): | 4048 | case (EDEADLK): |
4120 | status = nfserr_deadlock; | 4049 | status = nfserr_deadlock; |
4121 | break; | 4050 | break; |
4122 | default: | 4051 | default: |
4123 | dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); | 4052 | dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); |
4124 | status = nfserr_resource; | 4053 | status = nfserrno(err); |
4125 | break; | 4054 | break; |
4126 | } | 4055 | } |
4127 | out: | 4056 | out: |
4128 | if (status && lock->lk_is_new && lock_sop) | 4057 | if (status && lock->lk_is_new && lock_sop) |
4129 | release_lockowner(lock_sop); | 4058 | release_lockowner(lock_sop); |
4130 | if (lock->lk_replay_owner) { | 4059 | if (!cstate->replay_owner) |
4131 | nfs4_get_stateowner(lock->lk_replay_owner); | 4060 | nfs4_unlock_state(); |
4132 | cstate->replay_owner = lock->lk_replay_owner; | ||
4133 | } | ||
4134 | nfs4_unlock_state(); | ||
4135 | return status; | 4061 | return status; |
4136 | } | 4062 | } |
4137 | 4063 | ||
@@ -4163,6 +4089,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4163 | { | 4089 | { |
4164 | struct inode *inode; | 4090 | struct inode *inode; |
4165 | struct file_lock file_lock; | 4091 | struct file_lock file_lock; |
4092 | struct nfs4_lockowner *lo; | ||
4166 | int error; | 4093 | int error; |
4167 | __be32 status; | 4094 | __be32 status; |
4168 | 4095 | ||
@@ -4172,19 +4099,14 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4172 | if (check_lock_length(lockt->lt_offset, lockt->lt_length)) | 4099 | if (check_lock_length(lockt->lt_offset, lockt->lt_length)) |
4173 | return nfserr_inval; | 4100 | return nfserr_inval; |
4174 | 4101 | ||
4175 | lockt->lt_stateowner = NULL; | ||
4176 | nfs4_lock_state(); | 4102 | nfs4_lock_state(); |
4177 | 4103 | ||
4178 | status = nfserr_stale_clientid; | 4104 | status = nfserr_stale_clientid; |
4179 | if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid)) | 4105 | if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid)) |
4180 | goto out; | 4106 | goto out; |
4181 | 4107 | ||
4182 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) { | 4108 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) |
4183 | dprintk("NFSD: nfsd4_lockt: fh_verify() failed!\n"); | ||
4184 | if (status == nfserr_symlink) | ||
4185 | status = nfserr_inval; | ||
4186 | goto out; | 4109 | goto out; |
4187 | } | ||
4188 | 4110 | ||
4189 | inode = cstate->current_fh.fh_dentry->d_inode; | 4111 | inode = cstate->current_fh.fh_dentry->d_inode; |
4190 | locks_init_lock(&file_lock); | 4112 | locks_init_lock(&file_lock); |
@@ -4203,10 +4125,9 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4203 | goto out; | 4125 | goto out; |
4204 | } | 4126 | } |
4205 | 4127 | ||
4206 | lockt->lt_stateowner = find_lockstateowner_str(inode, | 4128 | lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner); |
4207 | &lockt->lt_clientid, &lockt->lt_owner); | 4129 | if (lo) |
4208 | if (lockt->lt_stateowner) | 4130 | file_lock.fl_owner = (fl_owner_t)lo; |
4209 | file_lock.fl_owner = (fl_owner_t)lockt->lt_stateowner; | ||
4210 | file_lock.fl_pid = current->tgid; | 4131 | file_lock.fl_pid = current->tgid; |
4211 | file_lock.fl_flags = FL_POSIX; | 4132 | file_lock.fl_flags = FL_POSIX; |
4212 | 4133 | ||
@@ -4234,7 +4155,7 @@ __be32 | |||
4234 | nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 4155 | nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
4235 | struct nfsd4_locku *locku) | 4156 | struct nfsd4_locku *locku) |
4236 | { | 4157 | { |
4237 | struct nfs4_stateid *stp; | 4158 | struct nfs4_ol_stateid *stp; |
4238 | struct file *filp = NULL; | 4159 | struct file *filp = NULL; |
4239 | struct file_lock file_lock; | 4160 | struct file_lock file_lock; |
4240 | __be32 status; | 4161 | __be32 status; |
@@ -4249,13 +4170,10 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4249 | 4170 | ||
4250 | nfs4_lock_state(); | 4171 | nfs4_lock_state(); |
4251 | 4172 | ||
4252 | if ((status = nfs4_preprocess_seqid_op(cstate, | 4173 | status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, |
4253 | locku->lu_seqid, | 4174 | &locku->lu_stateid, NFS4_LOCK_STID, &stp); |
4254 | &locku->lu_stateid, | 4175 | if (status) |
4255 | LOCK_STATE, | ||
4256 | &locku->lu_stateowner, &stp, NULL))) | ||
4257 | goto out; | 4176 | goto out; |
4258 | |||
4259 | filp = find_any_file(stp->st_file); | 4177 | filp = find_any_file(stp->st_file); |
4260 | if (!filp) { | 4178 | if (!filp) { |
4261 | status = nfserr_lock_range; | 4179 | status = nfserr_lock_range; |
@@ -4264,7 +4182,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4264 | BUG_ON(!filp); | 4182 | BUG_ON(!filp); |
4265 | locks_init_lock(&file_lock); | 4183 | locks_init_lock(&file_lock); |
4266 | file_lock.fl_type = F_UNLCK; | 4184 | file_lock.fl_type = F_UNLCK; |
4267 | file_lock.fl_owner = (fl_owner_t) locku->lu_stateowner; | 4185 | file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); |
4268 | file_lock.fl_pid = current->tgid; | 4186 | file_lock.fl_pid = current->tgid; |
4269 | file_lock.fl_file = filp; | 4187 | file_lock.fl_file = filp; |
4270 | file_lock.fl_flags = FL_POSIX; | 4188 | file_lock.fl_flags = FL_POSIX; |
@@ -4285,15 +4203,12 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4285 | /* | 4203 | /* |
4286 | * OK, unlock succeeded; the only thing left to do is update the stateid. | 4204 | * OK, unlock succeeded; the only thing left to do is update the stateid. |
4287 | */ | 4205 | */ |
4288 | update_stateid(&stp->st_stateid); | 4206 | update_stateid(&stp->st_stid.sc_stateid); |
4289 | memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t)); | 4207 | memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
4290 | 4208 | ||
4291 | out: | 4209 | out: |
4292 | if (locku->lu_stateowner) { | 4210 | if (!cstate->replay_owner) |
4293 | nfs4_get_stateowner(locku->lu_stateowner); | 4211 | nfs4_unlock_state(); |
4294 | cstate->replay_owner = locku->lu_stateowner; | ||
4295 | } | ||
4296 | nfs4_unlock_state(); | ||
4297 | return status; | 4212 | return status; |
4298 | 4213 | ||
4299 | out_nfserr: | 4214 | out_nfserr: |
@@ -4307,7 +4222,7 @@ out_nfserr: | |||
4307 | * 0: no locks held by lockowner | 4222 | * 0: no locks held by lockowner |
4308 | */ | 4223 | */ |
4309 | static int | 4224 | static int |
4310 | check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner) | 4225 | check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner) |
4311 | { | 4226 | { |
4312 | struct file_lock **flpp; | 4227 | struct file_lock **flpp; |
4313 | struct inode *inode = filp->fi_inode; | 4228 | struct inode *inode = filp->fi_inode; |
@@ -4332,7 +4247,8 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
4332 | { | 4247 | { |
4333 | clientid_t *clid = &rlockowner->rl_clientid; | 4248 | clientid_t *clid = &rlockowner->rl_clientid; |
4334 | struct nfs4_stateowner *sop; | 4249 | struct nfs4_stateowner *sop; |
4335 | struct nfs4_stateid *stp; | 4250 | struct nfs4_lockowner *lo; |
4251 | struct nfs4_ol_stateid *stp; | ||
4336 | struct xdr_netobj *owner = &rlockowner->rl_owner; | 4252 | struct xdr_netobj *owner = &rlockowner->rl_owner; |
4337 | struct list_head matches; | 4253 | struct list_head matches; |
4338 | int i; | 4254 | int i; |
@@ -4356,16 +4272,15 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
4356 | * data structures. */ | 4272 | * data structures. */ |
4357 | INIT_LIST_HEAD(&matches); | 4273 | INIT_LIST_HEAD(&matches); |
4358 | for (i = 0; i < LOCK_HASH_SIZE; i++) { | 4274 | for (i = 0; i < LOCK_HASH_SIZE; i++) { |
4359 | list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) { | 4275 | list_for_each_entry(sop, &lock_ownerstr_hashtbl[i], so_strhash) { |
4360 | if (!same_owner_str(sop, owner, clid)) | 4276 | if (!same_owner_str(sop, owner, clid)) |
4361 | continue; | 4277 | continue; |
4362 | list_for_each_entry(stp, &sop->so_stateids, | 4278 | list_for_each_entry(stp, &sop->so_stateids, |
4363 | st_perstateowner) { | 4279 | st_perstateowner) { |
4364 | if (check_for_locks(stp->st_file, sop)) | 4280 | lo = lockowner(sop); |
4281 | if (check_for_locks(stp->st_file, lo)) | ||
4365 | goto out; | 4282 | goto out; |
4366 | /* Note: so_perclient unused for lockowners, | 4283 | list_add(&lo->lo_list, &matches); |
4367 | * so it's OK to fool with here. */ | ||
4368 | list_add(&sop->so_perclient, &matches); | ||
4369 | } | 4284 | } |
4370 | } | 4285 | } |
4371 | } | 4286 | } |
@@ -4374,12 +4289,12 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
4374 | * have been checked. */ | 4289 | * have been checked. */ |
4375 | status = nfs_ok; | 4290 | status = nfs_ok; |
4376 | while (!list_empty(&matches)) { | 4291 | while (!list_empty(&matches)) { |
4377 | sop = list_entry(matches.next, struct nfs4_stateowner, | 4292 | lo = list_entry(matches.next, struct nfs4_lockowner, |
4378 | so_perclient); | 4293 | lo_list); |
4379 | /* unhash_stateowner deletes so_perclient only | 4294 | /* unhash_stateowner deletes so_perclient only |
4380 | * for openowners. */ | 4295 | * for openowners. */ |
4381 | list_del(&sop->so_perclient); | 4296 | list_del(&lo->lo_list); |
4382 | release_lockowner(sop); | 4297 | release_lockowner(lo); |
4383 | } | 4298 | } |
4384 | out: | 4299 | out: |
4385 | nfs4_unlock_state(); | 4300 | nfs4_unlock_state(); |
@@ -4501,16 +4416,10 @@ nfs4_state_init(void) | |||
4501 | for (i = 0; i < FILE_HASH_SIZE; i++) { | 4416 | for (i = 0; i < FILE_HASH_SIZE; i++) { |
4502 | INIT_LIST_HEAD(&file_hashtbl[i]); | 4417 | INIT_LIST_HEAD(&file_hashtbl[i]); |
4503 | } | 4418 | } |
4504 | for (i = 0; i < OWNER_HASH_SIZE; i++) { | 4419 | for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) { |
4505 | INIT_LIST_HEAD(&ownerstr_hashtbl[i]); | 4420 | INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]); |
4506 | INIT_LIST_HEAD(&ownerid_hashtbl[i]); | ||
4507 | } | ||
4508 | for (i = 0; i < STATEID_HASH_SIZE; i++) { | ||
4509 | INIT_LIST_HEAD(&stateid_hashtbl[i]); | ||
4510 | INIT_LIST_HEAD(&lockstateid_hashtbl[i]); | ||
4511 | } | 4421 | } |
4512 | for (i = 0; i < LOCK_HASH_SIZE; i++) { | 4422 | for (i = 0; i < LOCK_HASH_SIZE; i++) { |
4513 | INIT_LIST_HEAD(&lock_ownerid_hashtbl[i]); | ||
4514 | INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]); | 4423 | INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]); |
4515 | } | 4424 | } |
4516 | memset(&onestateid, ~0, sizeof(stateid_t)); | 4425 | memset(&onestateid, ~0, sizeof(stateid_t)); |
@@ -4527,7 +4436,7 @@ nfsd4_load_reboot_recovery_data(void) | |||
4527 | int status; | 4436 | int status; |
4528 | 4437 | ||
4529 | nfs4_lock_state(); | 4438 | nfs4_lock_state(); |
4530 | nfsd4_init_recdir(user_recovery_dirname); | 4439 | nfsd4_init_recdir(); |
4531 | status = nfsd4_recdir_load(); | 4440 | status = nfsd4_recdir_load(); |
4532 | nfs4_unlock_state(); | 4441 | nfs4_unlock_state(); |
4533 | if (status) | 4442 | if (status) |
@@ -4636,40 +4545,3 @@ nfs4_state_shutdown(void) | |||
4636 | nfs4_unlock_state(); | 4545 | nfs4_unlock_state(); |
4637 | nfsd4_destroy_callback_queue(); | 4546 | nfsd4_destroy_callback_queue(); |
4638 | } | 4547 | } |
4639 | |||
4640 | /* | ||
4641 | * user_recovery_dirname is protected by the nfsd_mutex since it's only | ||
4642 | * accessed when nfsd is starting. | ||
4643 | */ | ||
4644 | static void | ||
4645 | nfs4_set_recdir(char *recdir) | ||
4646 | { | ||
4647 | strcpy(user_recovery_dirname, recdir); | ||
4648 | } | ||
4649 | |||
4650 | /* | ||
4651 | * Change the NFSv4 recovery directory to recdir. | ||
4652 | */ | ||
4653 | int | ||
4654 | nfs4_reset_recoverydir(char *recdir) | ||
4655 | { | ||
4656 | int status; | ||
4657 | struct path path; | ||
4658 | |||
4659 | status = kern_path(recdir, LOOKUP_FOLLOW, &path); | ||
4660 | if (status) | ||
4661 | return status; | ||
4662 | status = -ENOTDIR; | ||
4663 | if (S_ISDIR(path.dentry->d_inode->i_mode)) { | ||
4664 | nfs4_set_recdir(recdir); | ||
4665 | status = 0; | ||
4666 | } | ||
4667 | path_put(&path); | ||
4668 | return status; | ||
4669 | } | ||
4670 | |||
4671 | char * | ||
4672 | nfs4_recoverydir(void) | ||
4673 | { | ||
4674 | return user_recovery_dirname; | ||
4675 | } | ||
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c8bf405d19de..66d095d7955e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -456,7 +456,6 @@ nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) | |||
456 | { | 456 | { |
457 | DECODE_HEAD; | 457 | DECODE_HEAD; |
458 | 458 | ||
459 | close->cl_stateowner = NULL; | ||
460 | READ_BUF(4); | 459 | READ_BUF(4); |
461 | READ32(close->cl_seqid); | 460 | READ32(close->cl_seqid); |
462 | return nfsd4_decode_stateid(argp, &close->cl_stateid); | 461 | return nfsd4_decode_stateid(argp, &close->cl_stateid); |
@@ -551,7 +550,6 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) | |||
551 | { | 550 | { |
552 | DECODE_HEAD; | 551 | DECODE_HEAD; |
553 | 552 | ||
554 | lock->lk_replay_owner = NULL; | ||
555 | /* | 553 | /* |
556 | * type, reclaim(boolean), offset, length, new_lock_owner(boolean) | 554 | * type, reclaim(boolean), offset, length, new_lock_owner(boolean) |
557 | */ | 555 | */ |
@@ -611,7 +609,6 @@ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) | |||
611 | { | 609 | { |
612 | DECODE_HEAD; | 610 | DECODE_HEAD; |
613 | 611 | ||
614 | locku->lu_stateowner = NULL; | ||
615 | READ_BUF(8); | 612 | READ_BUF(8); |
616 | READ32(locku->lu_type); | 613 | READ32(locku->lu_type); |
617 | if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT)) | 614 | if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT)) |
@@ -642,6 +639,83 @@ nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup | |||
642 | DECODE_TAIL; | 639 | DECODE_TAIL; |
643 | } | 640 | } |
644 | 641 | ||
642 | static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *x) | ||
643 | { | ||
644 | __be32 *p; | ||
645 | u32 w; | ||
646 | |||
647 | READ_BUF(4); | ||
648 | READ32(w); | ||
649 | *x = w; | ||
650 | switch (w & NFS4_SHARE_ACCESS_MASK) { | ||
651 | case NFS4_SHARE_ACCESS_READ: | ||
652 | case NFS4_SHARE_ACCESS_WRITE: | ||
653 | case NFS4_SHARE_ACCESS_BOTH: | ||
654 | break; | ||
655 | default: | ||
656 | return nfserr_bad_xdr; | ||
657 | } | ||
658 | w &= !NFS4_SHARE_ACCESS_MASK; | ||
659 | if (!w) | ||
660 | return nfs_ok; | ||
661 | if (!argp->minorversion) | ||
662 | return nfserr_bad_xdr; | ||
663 | switch (w & NFS4_SHARE_WANT_MASK) { | ||
664 | case NFS4_SHARE_WANT_NO_PREFERENCE: | ||
665 | case NFS4_SHARE_WANT_READ_DELEG: | ||
666 | case NFS4_SHARE_WANT_WRITE_DELEG: | ||
667 | case NFS4_SHARE_WANT_ANY_DELEG: | ||
668 | case NFS4_SHARE_WANT_NO_DELEG: | ||
669 | case NFS4_SHARE_WANT_CANCEL: | ||
670 | break; | ||
671 | default: | ||
672 | return nfserr_bad_xdr; | ||
673 | } | ||
674 | w &= ~NFS4_SHARE_WANT_MASK; | ||
675 | if (!w) | ||
676 | return nfs_ok; | ||
677 | switch (w) { | ||
678 | case NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL: | ||
679 | case NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED: | ||
680 | case (NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL | | ||
681 | NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED): | ||
682 | return nfs_ok; | ||
683 | } | ||
684 | xdr_error: | ||
685 | return nfserr_bad_xdr; | ||
686 | } | ||
687 | |||
688 | static __be32 nfsd4_decode_share_deny(struct nfsd4_compoundargs *argp, u32 *x) | ||
689 | { | ||
690 | __be32 *p; | ||
691 | |||
692 | READ_BUF(4); | ||
693 | READ32(*x); | ||
694 | /* Note: unlinke access bits, deny bits may be zero. */ | ||
695 | if (*x & ~NFS4_SHARE_DENY_BOTH) | ||
696 | return nfserr_bad_xdr; | ||
697 | return nfs_ok; | ||
698 | xdr_error: | ||
699 | return nfserr_bad_xdr; | ||
700 | } | ||
701 | |||
702 | static __be32 nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o) | ||
703 | { | ||
704 | __be32 *p; | ||
705 | |||
706 | READ_BUF(4); | ||
707 | READ32(o->len); | ||
708 | |||
709 | if (o->len == 0 || o->len > NFS4_OPAQUE_LIMIT) | ||
710 | return nfserr_bad_xdr; | ||
711 | |||
712 | READ_BUF(o->len); | ||
713 | SAVEMEM(o->data, o->len); | ||
714 | return nfs_ok; | ||
715 | xdr_error: | ||
716 | return nfserr_bad_xdr; | ||
717 | } | ||
718 | |||
645 | static __be32 | 719 | static __be32 |
646 | nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | 720 | nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) |
647 | { | 721 | { |
@@ -649,19 +723,23 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
649 | 723 | ||
650 | memset(open->op_bmval, 0, sizeof(open->op_bmval)); | 724 | memset(open->op_bmval, 0, sizeof(open->op_bmval)); |
651 | open->op_iattr.ia_valid = 0; | 725 | open->op_iattr.ia_valid = 0; |
652 | open->op_stateowner = NULL; | 726 | open->op_openowner = NULL; |
653 | 727 | ||
654 | /* seqid, share_access, share_deny, clientid, ownerlen */ | 728 | /* seqid, share_access, share_deny, clientid, ownerlen */ |
655 | READ_BUF(16 + sizeof(clientid_t)); | 729 | READ_BUF(4); |
656 | READ32(open->op_seqid); | 730 | READ32(open->op_seqid); |
657 | READ32(open->op_share_access); | 731 | status = nfsd4_decode_share_access(argp, &open->op_share_access); |
658 | READ32(open->op_share_deny); | 732 | if (status) |
733 | goto xdr_error; | ||
734 | status = nfsd4_decode_share_deny(argp, &open->op_share_deny); | ||
735 | if (status) | ||
736 | goto xdr_error; | ||
737 | READ_BUF(sizeof(clientid_t)); | ||
659 | COPYMEM(&open->op_clientid, sizeof(clientid_t)); | 738 | COPYMEM(&open->op_clientid, sizeof(clientid_t)); |
660 | READ32(open->op_owner.len); | 739 | status = nfsd4_decode_opaque(argp, &open->op_owner); |
661 | 740 | if (status) | |
662 | /* owner, open_flag */ | 741 | goto xdr_error; |
663 | READ_BUF(open->op_owner.len + 4); | 742 | READ_BUF(4); |
664 | SAVEMEM(open->op_owner.data, open->op_owner.len); | ||
665 | READ32(open->op_create); | 743 | READ32(open->op_create); |
666 | switch (open->op_create) { | 744 | switch (open->op_create) { |
667 | case NFS4_OPEN_NOCREATE: | 745 | case NFS4_OPEN_NOCREATE: |
@@ -727,6 +805,19 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
727 | if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval))) | 805 | if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval))) |
728 | return status; | 806 | return status; |
729 | break; | 807 | break; |
808 | case NFS4_OPEN_CLAIM_FH: | ||
809 | case NFS4_OPEN_CLAIM_DELEG_PREV_FH: | ||
810 | if (argp->minorversion < 1) | ||
811 | goto xdr_error; | ||
812 | /* void */ | ||
813 | break; | ||
814 | case NFS4_OPEN_CLAIM_DELEG_CUR_FH: | ||
815 | if (argp->minorversion < 1) | ||
816 | goto xdr_error; | ||
817 | status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid); | ||
818 | if (status) | ||
819 | return status; | ||
820 | break; | ||
730 | default: | 821 | default: |
731 | goto xdr_error; | 822 | goto xdr_error; |
732 | } | 823 | } |
@@ -739,7 +830,6 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con | |||
739 | { | 830 | { |
740 | DECODE_HEAD; | 831 | DECODE_HEAD; |
741 | 832 | ||
742 | open_conf->oc_stateowner = NULL; | ||
743 | status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid); | 833 | status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid); |
744 | if (status) | 834 | if (status) |
745 | return status; | 835 | return status; |
@@ -754,15 +844,17 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d | |||
754 | { | 844 | { |
755 | DECODE_HEAD; | 845 | DECODE_HEAD; |
756 | 846 | ||
757 | open_down->od_stateowner = NULL; | ||
758 | status = nfsd4_decode_stateid(argp, &open_down->od_stateid); | 847 | status = nfsd4_decode_stateid(argp, &open_down->od_stateid); |
759 | if (status) | 848 | if (status) |
760 | return status; | 849 | return status; |
761 | READ_BUF(12); | 850 | READ_BUF(4); |
762 | READ32(open_down->od_seqid); | 851 | READ32(open_down->od_seqid); |
763 | READ32(open_down->od_share_access); | 852 | status = nfsd4_decode_share_access(argp, &open_down->od_share_access); |
764 | READ32(open_down->od_share_deny); | 853 | if (status) |
765 | 854 | return status; | |
855 | status = nfsd4_decode_share_deny(argp, &open_down->od_share_deny); | ||
856 | if (status) | ||
857 | return status; | ||
766 | DECODE_TAIL; | 858 | DECODE_TAIL; |
767 | } | 859 | } |
768 | 860 | ||
@@ -903,12 +995,13 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient | |||
903 | { | 995 | { |
904 | DECODE_HEAD; | 996 | DECODE_HEAD; |
905 | 997 | ||
906 | READ_BUF(12); | 998 | READ_BUF(8); |
907 | COPYMEM(setclientid->se_verf.data, 8); | 999 | COPYMEM(setclientid->se_verf.data, 8); |
908 | READ32(setclientid->se_namelen); | ||
909 | 1000 | ||
910 | READ_BUF(setclientid->se_namelen + 8); | 1001 | status = nfsd4_decode_opaque(argp, &setclientid->se_name); |
911 | SAVEMEM(setclientid->se_name, setclientid->se_namelen); | 1002 | if (status) |
1003 | return nfserr_bad_xdr; | ||
1004 | READ_BUF(8); | ||
912 | READ32(setclientid->se_callback_prog); | 1005 | READ32(setclientid->se_callback_prog); |
913 | READ32(setclientid->se_callback_netid_len); | 1006 | READ32(setclientid->se_callback_netid_len); |
914 | 1007 | ||
@@ -1051,11 +1144,9 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, | |||
1051 | READ_BUF(NFS4_VERIFIER_SIZE); | 1144 | READ_BUF(NFS4_VERIFIER_SIZE); |
1052 | COPYMEM(exid->verifier.data, NFS4_VERIFIER_SIZE); | 1145 | COPYMEM(exid->verifier.data, NFS4_VERIFIER_SIZE); |
1053 | 1146 | ||
1054 | READ_BUF(4); | 1147 | status = nfsd4_decode_opaque(argp, &exid->clname); |
1055 | READ32(exid->clname.len); | 1148 | if (status) |
1056 | 1149 | return nfserr_bad_xdr; | |
1057 | READ_BUF(exid->clname.len); | ||
1058 | SAVEMEM(exid->clname.data, exid->clname.len); | ||
1059 | 1150 | ||
1060 | READ_BUF(4); | 1151 | READ_BUF(4); |
1061 | READ32(exid->flags); | 1152 | READ32(exid->flags); |
@@ -1326,6 +1417,16 @@ xdr_error: | |||
1326 | goto out; | 1417 | goto out; |
1327 | } | 1418 | } |
1328 | 1419 | ||
1420 | static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp, struct nfsd4_destroy_clientid *dc) | ||
1421 | { | ||
1422 | DECODE_HEAD; | ||
1423 | |||
1424 | READ_BUF(8); | ||
1425 | COPYMEM(&dc->clientid, 8); | ||
1426 | |||
1427 | DECODE_TAIL; | ||
1428 | } | ||
1429 | |||
1329 | static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc) | 1430 | static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc) |
1330 | { | 1431 | { |
1331 | DECODE_HEAD; | 1432 | DECODE_HEAD; |
@@ -1447,7 +1548,7 @@ static nfsd4_dec nfsd41_dec_ops[] = { | |||
1447 | [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, | 1548 | [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, |
1448 | [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_test_stateid, | 1549 | [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_test_stateid, |
1449 | [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, | 1550 | [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, |
1450 | [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp, | 1551 | [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_destroy_clientid, |
1451 | [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete, | 1552 | [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete, |
1452 | }; | 1553 | }; |
1453 | 1554 | ||
@@ -1630,15 +1731,20 @@ static void write_cinfo(__be32 **p, struct nfsd4_change_info *c) | |||
1630 | * we know whether the error to be returned is a sequence id mutating error. | 1731 | * we know whether the error to be returned is a sequence id mutating error. |
1631 | */ | 1732 | */ |
1632 | 1733 | ||
1633 | #define ENCODE_SEQID_OP_TAIL(stateowner) do { \ | 1734 | static void encode_seqid_op_tail(struct nfsd4_compoundres *resp, __be32 *save, __be32 nfserr) |
1634 | if (seqid_mutating_err(nfserr) && stateowner) { \ | 1735 | { |
1635 | stateowner->so_seqid++; \ | 1736 | struct nfs4_stateowner *stateowner = resp->cstate.replay_owner; |
1636 | stateowner->so_replay.rp_status = nfserr; \ | 1737 | |
1637 | stateowner->so_replay.rp_buflen = \ | 1738 | if (seqid_mutating_err(ntohl(nfserr)) && stateowner) { |
1638 | (((char *)(resp)->p - (char *)save)); \ | 1739 | stateowner->so_seqid++; |
1639 | memcpy(stateowner->so_replay.rp_buf, save, \ | 1740 | stateowner->so_replay.rp_status = nfserr; |
1640 | stateowner->so_replay.rp_buflen); \ | 1741 | stateowner->so_replay.rp_buflen = |
1641 | } } while (0); | 1742 | (char *)resp->p - (char *)save; |
1743 | memcpy(stateowner->so_replay.rp_buf, save, | ||
1744 | stateowner->so_replay.rp_buflen); | ||
1745 | nfsd4_purge_closed_stateid(stateowner); | ||
1746 | } | ||
1747 | } | ||
1642 | 1748 | ||
1643 | /* Encode as an array of strings the string given with components | 1749 | /* Encode as an array of strings the string given with components |
1644 | * separated @sep. | 1750 | * separated @sep. |
@@ -1697,36 +1803,89 @@ static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, | |||
1697 | } | 1803 | } |
1698 | 1804 | ||
1699 | /* | 1805 | /* |
1700 | * Return the path to an export point in the pseudo filesystem namespace | 1806 | * Encode a path in RFC3530 'pathname4' format |
1701 | * Returned string is safe to use as long as the caller holds a reference | ||
1702 | * to @exp. | ||
1703 | */ | 1807 | */ |
1704 | static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat) | 1808 | static __be32 nfsd4_encode_path(const struct path *root, |
1809 | const struct path *path, __be32 **pp, int *buflen) | ||
1705 | { | 1810 | { |
1706 | struct svc_fh tmp_fh; | 1811 | struct path cur = { |
1707 | char *path = NULL, *rootpath; | 1812 | .mnt = path->mnt, |
1708 | size_t rootlen; | 1813 | .dentry = path->dentry, |
1814 | }; | ||
1815 | __be32 *p = *pp; | ||
1816 | struct dentry **components = NULL; | ||
1817 | unsigned int ncomponents = 0; | ||
1818 | __be32 err = nfserr_jukebox; | ||
1709 | 1819 | ||
1710 | fh_init(&tmp_fh, NFS4_FHSIZE); | 1820 | dprintk("nfsd4_encode_components("); |
1711 | *stat = exp_pseudoroot(rqstp, &tmp_fh); | ||
1712 | if (*stat) | ||
1713 | return NULL; | ||
1714 | rootpath = tmp_fh.fh_export->ex_pathname; | ||
1715 | 1821 | ||
1716 | path = exp->ex_pathname; | 1822 | path_get(&cur); |
1823 | /* First walk the path up to the nfsd root, and store the | ||
1824 | * dentries/path components in an array. | ||
1825 | */ | ||
1826 | for (;;) { | ||
1827 | if (cur.dentry == root->dentry && cur.mnt == root->mnt) | ||
1828 | break; | ||
1829 | if (cur.dentry == cur.mnt->mnt_root) { | ||
1830 | if (follow_up(&cur)) | ||
1831 | continue; | ||
1832 | goto out_free; | ||
1833 | } | ||
1834 | if ((ncomponents & 15) == 0) { | ||
1835 | struct dentry **new; | ||
1836 | new = krealloc(components, | ||
1837 | sizeof(*new) * (ncomponents + 16), | ||
1838 | GFP_KERNEL); | ||
1839 | if (!new) | ||
1840 | goto out_free; | ||
1841 | components = new; | ||
1842 | } | ||
1843 | components[ncomponents++] = cur.dentry; | ||
1844 | cur.dentry = dget_parent(cur.dentry); | ||
1845 | } | ||
1717 | 1846 | ||
1718 | rootlen = strlen(rootpath); | 1847 | *buflen -= 4; |
1719 | if (strncmp(path, rootpath, rootlen)) { | 1848 | if (*buflen < 0) |
1720 | dprintk("nfsd: fs_locations failed;" | 1849 | goto out_free; |
1721 | "%s is not contained in %s\n", path, rootpath); | 1850 | WRITE32(ncomponents); |
1722 | *stat = nfserr_notsupp; | 1851 | |
1723 | path = NULL; | 1852 | while (ncomponents) { |
1724 | goto out; | 1853 | struct dentry *dentry = components[ncomponents - 1]; |
1854 | unsigned int len = dentry->d_name.len; | ||
1855 | |||
1856 | *buflen -= 4 + (XDR_QUADLEN(len) << 2); | ||
1857 | if (*buflen < 0) | ||
1858 | goto out_free; | ||
1859 | WRITE32(len); | ||
1860 | WRITEMEM(dentry->d_name.name, len); | ||
1861 | dprintk("/%s", dentry->d_name.name); | ||
1862 | dput(dentry); | ||
1863 | ncomponents--; | ||
1725 | } | 1864 | } |
1726 | path += rootlen; | 1865 | |
1727 | out: | 1866 | *pp = p; |
1728 | fh_put(&tmp_fh); | 1867 | err = 0; |
1729 | return path; | 1868 | out_free: |
1869 | dprintk(")\n"); | ||
1870 | while (ncomponents) | ||
1871 | dput(components[--ncomponents]); | ||
1872 | kfree(components); | ||
1873 | path_put(&cur); | ||
1874 | return err; | ||
1875 | } | ||
1876 | |||
1877 | static __be32 nfsd4_encode_fsloc_fsroot(struct svc_rqst *rqstp, | ||
1878 | const struct path *path, __be32 **pp, int *buflen) | ||
1879 | { | ||
1880 | struct svc_export *exp_ps; | ||
1881 | __be32 res; | ||
1882 | |||
1883 | exp_ps = rqst_find_fsidzero_export(rqstp); | ||
1884 | if (IS_ERR(exp_ps)) | ||
1885 | return nfserrno(PTR_ERR(exp_ps)); | ||
1886 | res = nfsd4_encode_path(&exp_ps->ex_path, path, pp, buflen); | ||
1887 | exp_put(exp_ps); | ||
1888 | return res; | ||
1730 | } | 1889 | } |
1731 | 1890 | ||
1732 | /* | 1891 | /* |
@@ -1740,11 +1899,8 @@ static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp, | |||
1740 | int i; | 1899 | int i; |
1741 | __be32 *p = *pp; | 1900 | __be32 *p = *pp; |
1742 | struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; | 1901 | struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs; |
1743 | char *root = nfsd4_path(rqstp, exp, &status); | ||
1744 | 1902 | ||
1745 | if (status) | 1903 | status = nfsd4_encode_fsloc_fsroot(rqstp, &exp->ex_path, &p, buflen); |
1746 | return status; | ||
1747 | status = nfsd4_encode_components('/', root, &p, buflen); | ||
1748 | if (status) | 1904 | if (status) |
1749 | return status; | 1905 | return status; |
1750 | if ((*buflen -= 4) < 0) | 1906 | if ((*buflen -= 4) < 0) |
@@ -1760,12 +1916,19 @@ static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp, | |||
1760 | return 0; | 1916 | return 0; |
1761 | } | 1917 | } |
1762 | 1918 | ||
1763 | static u32 nfs4_ftypes[16] = { | 1919 | static u32 nfs4_file_type(umode_t mode) |
1764 | NF4BAD, NF4FIFO, NF4CHR, NF4BAD, | 1920 | { |
1765 | NF4DIR, NF4BAD, NF4BLK, NF4BAD, | 1921 | switch (mode & S_IFMT) { |
1766 | NF4REG, NF4BAD, NF4LNK, NF4BAD, | 1922 | case S_IFIFO: return NF4FIFO; |
1767 | NF4SOCK, NF4BAD, NF4LNK, NF4BAD, | 1923 | case S_IFCHR: return NF4CHR; |
1768 | }; | 1924 | case S_IFDIR: return NF4DIR; |
1925 | case S_IFBLK: return NF4BLK; | ||
1926 | case S_IFLNK: return NF4LNK; | ||
1927 | case S_IFREG: return NF4REG; | ||
1928 | case S_IFSOCK: return NF4SOCK; | ||
1929 | default: return NF4BAD; | ||
1930 | }; | ||
1931 | } | ||
1769 | 1932 | ||
1770 | static __be32 | 1933 | static __be32 |
1771 | nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, | 1934 | nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, |
@@ -1954,7 +2117,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
1954 | if (bmval0 & FATTR4_WORD0_TYPE) { | 2117 | if (bmval0 & FATTR4_WORD0_TYPE) { |
1955 | if ((buflen -= 4) < 0) | 2118 | if ((buflen -= 4) < 0) |
1956 | goto out_resource; | 2119 | goto out_resource; |
1957 | dummy = nfs4_ftypes[(stat.mode & S_IFMT) >> 12]; | 2120 | dummy = nfs4_file_type(stat.mode); |
1958 | if (dummy == NF4BAD) | 2121 | if (dummy == NF4BAD) |
1959 | goto out_serverfault; | 2122 | goto out_serverfault; |
1960 | WRITE32(dummy); | 2123 | WRITE32(dummy); |
@@ -2488,7 +2651,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c | |||
2488 | if (!nfserr) | 2651 | if (!nfserr) |
2489 | nfsd4_encode_stateid(resp, &close->cl_stateid); | 2652 | nfsd4_encode_stateid(resp, &close->cl_stateid); |
2490 | 2653 | ||
2491 | ENCODE_SEQID_OP_TAIL(close->cl_stateowner); | 2654 | encode_seqid_op_tail(resp, save, nfserr); |
2492 | return nfserr; | 2655 | return nfserr; |
2493 | } | 2656 | } |
2494 | 2657 | ||
@@ -2564,17 +2727,18 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh | |||
2564 | static void | 2727 | static void |
2565 | nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) | 2728 | nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) |
2566 | { | 2729 | { |
2730 | struct xdr_netobj *conf = &ld->ld_owner; | ||
2567 | __be32 *p; | 2731 | __be32 *p; |
2568 | 2732 | ||
2569 | RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0)); | 2733 | RESERVE_SPACE(32 + XDR_LEN(conf->len)); |
2570 | WRITE64(ld->ld_start); | 2734 | WRITE64(ld->ld_start); |
2571 | WRITE64(ld->ld_length); | 2735 | WRITE64(ld->ld_length); |
2572 | WRITE32(ld->ld_type); | 2736 | WRITE32(ld->ld_type); |
2573 | if (ld->ld_sop) { | 2737 | if (conf->len) { |
2574 | WRITEMEM(&ld->ld_clientid, 8); | 2738 | WRITEMEM(&ld->ld_clientid, 8); |
2575 | WRITE32(ld->ld_sop->so_owner.len); | 2739 | WRITE32(conf->len); |
2576 | WRITEMEM(ld->ld_sop->so_owner.data, ld->ld_sop->so_owner.len); | 2740 | WRITEMEM(conf->data, conf->len); |
2577 | kref_put(&ld->ld_sop->so_ref, nfs4_free_stateowner); | 2741 | kfree(conf->data); |
2578 | } else { /* non - nfsv4 lock in conflict, no clientid nor owner */ | 2742 | } else { /* non - nfsv4 lock in conflict, no clientid nor owner */ |
2579 | WRITE64((u64)0); /* clientid */ | 2743 | WRITE64((u64)0); /* clientid */ |
2580 | WRITE32(0); /* length of owner name */ | 2744 | WRITE32(0); /* length of owner name */ |
@@ -2592,7 +2756,7 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo | |||
2592 | else if (nfserr == nfserr_denied) | 2756 | else if (nfserr == nfserr_denied) |
2593 | nfsd4_encode_lock_denied(resp, &lock->lk_denied); | 2757 | nfsd4_encode_lock_denied(resp, &lock->lk_denied); |
2594 | 2758 | ||
2595 | ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner); | 2759 | encode_seqid_op_tail(resp, save, nfserr); |
2596 | return nfserr; | 2760 | return nfserr; |
2597 | } | 2761 | } |
2598 | 2762 | ||
@@ -2612,7 +2776,7 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l | |||
2612 | if (!nfserr) | 2776 | if (!nfserr) |
2613 | nfsd4_encode_stateid(resp, &locku->lu_stateid); | 2777 | nfsd4_encode_stateid(resp, &locku->lu_stateid); |
2614 | 2778 | ||
2615 | ENCODE_SEQID_OP_TAIL(locku->lu_stateowner); | 2779 | encode_seqid_op_tail(resp, save, nfserr); |
2616 | return nfserr; | 2780 | return nfserr; |
2617 | } | 2781 | } |
2618 | 2782 | ||
@@ -2693,7 +2857,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op | |||
2693 | } | 2857 | } |
2694 | /* XXX save filehandle here */ | 2858 | /* XXX save filehandle here */ |
2695 | out: | 2859 | out: |
2696 | ENCODE_SEQID_OP_TAIL(open->op_stateowner); | 2860 | encode_seqid_op_tail(resp, save, nfserr); |
2697 | return nfserr; | 2861 | return nfserr; |
2698 | } | 2862 | } |
2699 | 2863 | ||
@@ -2705,7 +2869,7 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct | |||
2705 | if (!nfserr) | 2869 | if (!nfserr) |
2706 | nfsd4_encode_stateid(resp, &oc->oc_resp_stateid); | 2870 | nfsd4_encode_stateid(resp, &oc->oc_resp_stateid); |
2707 | 2871 | ||
2708 | ENCODE_SEQID_OP_TAIL(oc->oc_stateowner); | 2872 | encode_seqid_op_tail(resp, save, nfserr); |
2709 | return nfserr; | 2873 | return nfserr; |
2710 | } | 2874 | } |
2711 | 2875 | ||
@@ -2717,7 +2881,7 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struc | |||
2717 | if (!nfserr) | 2881 | if (!nfserr) |
2718 | nfsd4_encode_stateid(resp, &od->od_stateid); | 2882 | nfsd4_encode_stateid(resp, &od->od_stateid); |
2719 | 2883 | ||
2720 | ENCODE_SEQID_OP_TAIL(od->od_stateowner); | 2884 | encode_seqid_op_tail(resp, save, nfserr); |
2721 | return nfserr; | 2885 | return nfserr; |
2722 | } | 2886 | } |
2723 | 2887 | ||
@@ -2759,8 +2923,6 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
2759 | read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen, | 2923 | read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen, |
2760 | &maxcount); | 2924 | &maxcount); |
2761 | 2925 | ||
2762 | if (nfserr == nfserr_symlink) | ||
2763 | nfserr = nfserr_inval; | ||
2764 | if (nfserr) | 2926 | if (nfserr) |
2765 | return nfserr; | 2927 | return nfserr; |
2766 | eof = (read->rd_offset + maxcount >= | 2928 | eof = (read->rd_offset + maxcount >= |
@@ -2886,8 +3048,6 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
2886 | readdir->common.err == nfserr_toosmall && | 3048 | readdir->common.err == nfserr_toosmall && |
2887 | readdir->buffer == page) | 3049 | readdir->buffer == page) |
2888 | nfserr = nfserr_toosmall; | 3050 | nfserr = nfserr_toosmall; |
2889 | if (nfserr == nfserr_symlink) | ||
2890 | nfserr = nfserr_notdir; | ||
2891 | if (nfserr) | 3051 | if (nfserr) |
2892 | goto err_no_verf; | 3052 | goto err_no_verf; |
2893 | 3053 | ||
@@ -3218,9 +3378,9 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | |||
3218 | WRITEMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN); | 3378 | WRITEMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN); |
3219 | WRITE32(seq->seqid); | 3379 | WRITE32(seq->seqid); |
3220 | WRITE32(seq->slotid); | 3380 | WRITE32(seq->slotid); |
3221 | WRITE32(seq->maxslots); | 3381 | /* Note slotid's are numbered from zero: */ |
3222 | /* For now: target_maxslots = maxslots */ | 3382 | WRITE32(seq->maxslots - 1); /* sr_highest_slotid */ |
3223 | WRITE32(seq->maxslots); | 3383 | WRITE32(seq->maxslots - 1); /* sr_target_highest_slotid */ |
3224 | WRITE32(seq->status_flags); | 3384 | WRITE32(seq->status_flags); |
3225 | 3385 | ||
3226 | ADJUST_ARGS(); | 3386 | ADJUST_ARGS(); |
@@ -3233,6 +3393,7 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr, | |||
3233 | struct nfsd4_test_stateid *test_stateid) | 3393 | struct nfsd4_test_stateid *test_stateid) |
3234 | { | 3394 | { |
3235 | struct nfsd4_compoundargs *argp; | 3395 | struct nfsd4_compoundargs *argp; |
3396 | struct nfs4_client *cl = resp->cstate.session->se_client; | ||
3236 | stateid_t si; | 3397 | stateid_t si; |
3237 | __be32 *p; | 3398 | __be32 *p; |
3238 | int i; | 3399 | int i; |
@@ -3248,7 +3409,7 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr, | |||
3248 | nfs4_lock_state(); | 3409 | nfs4_lock_state(); |
3249 | for (i = 0; i < test_stateid->ts_num_ids; i++) { | 3410 | for (i = 0; i < test_stateid->ts_num_ids; i++) { |
3250 | nfsd4_decode_stateid(argp, &si); | 3411 | nfsd4_decode_stateid(argp, &si); |
3251 | valid = nfs4_validate_stateid(&si, test_stateid->ts_has_session); | 3412 | valid = nfs4_validate_stateid(cl, &si); |
3252 | RESERVE_SPACE(4); | 3413 | RESERVE_SPACE(4); |
3253 | *p++ = htonl(valid); | 3414 | *p++ = htonl(valid); |
3254 | resp->p = p; | 3415 | resp->p = p; |
@@ -3334,34 +3495,29 @@ static nfsd4_enc nfsd4_enc_ops[] = { | |||
3334 | 3495 | ||
3335 | /* | 3496 | /* |
3336 | * Calculate the total amount of memory that the compound response has taken | 3497 | * Calculate the total amount of memory that the compound response has taken |
3337 | * after encoding the current operation. | 3498 | * after encoding the current operation with pad. |
3338 | * | 3499 | * |
3339 | * pad: add on 8 bytes for the next operation's op_code and status so that | 3500 | * pad: if operation is non-idempotent, pad was calculate by op_rsize_bop() |
3340 | * there is room to cache a failure on the next operation. | 3501 | * which was specified at nfsd4_operation, else pad is zero. |
3341 | * | 3502 | * |
3342 | * Compare this length to the session se_fmaxresp_cached. | 3503 | * Compare this length to the session se_fmaxresp_sz and se_fmaxresp_cached. |
3343 | * | 3504 | * |
3344 | * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so | 3505 | * Our se_fmaxresp_cached will always be a multiple of PAGE_SIZE, and so |
3345 | * will be at least a page and will therefore hold the xdr_buf head. | 3506 | * will be at least a page and will therefore hold the xdr_buf head. |
3346 | */ | 3507 | */ |
3347 | static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) | 3508 | int nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad) |
3348 | { | 3509 | { |
3349 | int status = 0; | ||
3350 | struct xdr_buf *xb = &resp->rqstp->rq_res; | 3510 | struct xdr_buf *xb = &resp->rqstp->rq_res; |
3351 | struct nfsd4_compoundargs *args = resp->rqstp->rq_argp; | ||
3352 | struct nfsd4_session *session = NULL; | 3511 | struct nfsd4_session *session = NULL; |
3353 | struct nfsd4_slot *slot = resp->cstate.slot; | 3512 | struct nfsd4_slot *slot = resp->cstate.slot; |
3354 | u32 length, tlen = 0, pad = 8; | 3513 | u32 length, tlen = 0; |
3355 | 3514 | ||
3356 | if (!nfsd4_has_session(&resp->cstate)) | 3515 | if (!nfsd4_has_session(&resp->cstate)) |
3357 | return status; | 3516 | return 0; |
3358 | 3517 | ||
3359 | session = resp->cstate.session; | 3518 | session = resp->cstate.session; |
3360 | if (session == NULL || slot->sl_cachethis == 0) | 3519 | if (session == NULL) |
3361 | return status; | 3520 | return 0; |
3362 | |||
3363 | if (resp->opcnt >= args->opcnt) | ||
3364 | pad = 0; /* this is the last operation */ | ||
3365 | 3521 | ||
3366 | if (xb->page_len == 0) { | 3522 | if (xb->page_len == 0) { |
3367 | length = (char *)resp->p - (char *)xb->head[0].iov_base + pad; | 3523 | length = (char *)resp->p - (char *)xb->head[0].iov_base + pad; |
@@ -3374,10 +3530,14 @@ static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) | |||
3374 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, | 3530 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, |
3375 | length, xb->page_len, tlen, pad); | 3531 | length, xb->page_len, tlen, pad); |
3376 | 3532 | ||
3377 | if (length <= session->se_fchannel.maxresp_cached) | 3533 | if (length > session->se_fchannel.maxresp_sz) |
3378 | return status; | 3534 | return nfserr_rep_too_big; |
3379 | else | 3535 | |
3536 | if (slot->sl_cachethis == 1 && | ||
3537 | length > session->se_fchannel.maxresp_cached) | ||
3380 | return nfserr_rep_too_big_to_cache; | 3538 | return nfserr_rep_too_big_to_cache; |
3539 | |||
3540 | return 0; | ||
3381 | } | 3541 | } |
3382 | 3542 | ||
3383 | void | 3543 | void |
@@ -3397,8 +3557,8 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | |||
3397 | !nfsd4_enc_ops[op->opnum]); | 3557 | !nfsd4_enc_ops[op->opnum]); |
3398 | op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u); | 3558 | op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u); |
3399 | /* nfsd4_check_drc_limit guarantees enough room for error status */ | 3559 | /* nfsd4_check_drc_limit guarantees enough room for error status */ |
3400 | if (!op->status && nfsd4_check_drc_limit(resp)) | 3560 | if (!op->status) |
3401 | op->status = nfserr_rep_too_big_to_cache; | 3561 | op->status = nfsd4_check_resp_size(resp, 0); |
3402 | status: | 3562 | status: |
3403 | /* | 3563 | /* |
3404 | * Note: We write the status directly, instead of using WRITE32(), | 3564 | * Note: We write the status directly, instead of using WRITE32(), |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index c7716143cbd1..db34a585e112 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <linux/ctype.h> | 9 | #include <linux/ctype.h> |
10 | 10 | ||
11 | #include <linux/sunrpc/svcsock.h> | 11 | #include <linux/sunrpc/svcsock.h> |
12 | #include <linux/nfsd/syscall.h> | ||
13 | #include <linux/lockd/lockd.h> | 12 | #include <linux/lockd/lockd.h> |
14 | #include <linux/sunrpc/clnt.h> | 13 | #include <linux/sunrpc/clnt.h> |
15 | #include <linux/sunrpc/gss_api.h> | 14 | #include <linux/sunrpc/gss_api.h> |
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 7ecfa2420307..58134a23fdfb 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h | |||
@@ -11,13 +11,39 @@ | |||
11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
12 | #include <linux/mount.h> | 12 | #include <linux/mount.h> |
13 | 13 | ||
14 | #include <linux/nfs.h> | ||
15 | #include <linux/nfs2.h> | ||
16 | #include <linux/nfs3.h> | ||
17 | #include <linux/nfs4.h> | ||
18 | #include <linux/sunrpc/msg_prot.h> | ||
19 | |||
14 | #include <linux/nfsd/debug.h> | 20 | #include <linux/nfsd/debug.h> |
15 | #include <linux/nfsd/export.h> | 21 | #include <linux/nfsd/export.h> |
16 | #include <linux/nfsd/stats.h> | 22 | #include <linux/nfsd/stats.h> |
23 | |||
17 | /* | 24 | /* |
18 | * nfsd version | 25 | * nfsd version |
19 | */ | 26 | */ |
20 | #define NFSD_SUPPORTED_MINOR_VERSION 1 | 27 | #define NFSD_SUPPORTED_MINOR_VERSION 1 |
28 | /* | ||
29 | * Maximum blocksizes supported by daemon under various circumstances. | ||
30 | */ | ||
31 | #define NFSSVC_MAXBLKSIZE RPCSVC_MAXPAYLOAD | ||
32 | /* NFSv2 is limited by the protocol specification, see RFC 1094 */ | ||
33 | #define NFSSVC_MAXBLKSIZE_V2 (8*1024) | ||
34 | |||
35 | |||
36 | /* | ||
37 | * Largest number of bytes we need to allocate for an NFS | ||
38 | * call or reply. Used to control buffer sizes. We use | ||
39 | * the length of v3 WRITE, READDIR and READDIR replies | ||
40 | * which are an RPC header, up to 26 XDR units of reply | ||
41 | * data, and some page data. | ||
42 | * | ||
43 | * Note that accuracy here doesn't matter too much as the | ||
44 | * size is rounded up to a page size when allocating space. | ||
45 | */ | ||
46 | #define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE) | ||
21 | 47 | ||
22 | struct readdir_cd { | 48 | struct readdir_cd { |
23 | __be32 err; /* 0, nfserr, or nfserr_eof */ | 49 | __be32 err; /* 0, nfserr, or nfserr_eof */ |
@@ -335,6 +361,13 @@ static inline u32 nfsd_suppattrs2(u32 minorversion) | |||
335 | #define NFSD_SUPPATTR_EXCLCREAT_WORD2 \ | 361 | #define NFSD_SUPPATTR_EXCLCREAT_WORD2 \ |
336 | NFSD_WRITEABLE_ATTRS_WORD2 | 362 | NFSD_WRITEABLE_ATTRS_WORD2 |
337 | 363 | ||
364 | extern int nfsd4_is_junction(struct dentry *dentry); | ||
365 | #else | ||
366 | static inline int nfsd4_is_junction(struct dentry *dentry) | ||
367 | { | ||
368 | return 0; | ||
369 | } | ||
370 | |||
338 | #endif /* CONFIG_NFSD_V4 */ | 371 | #endif /* CONFIG_NFSD_V4 */ |
339 | 372 | ||
340 | #endif /* LINUX_NFSD_NFSD_H */ | 373 | #endif /* LINUX_NFSD_NFSD_H */ |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 90c6aa6d5e0f..c763de5c1157 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -59,28 +59,25 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry) | |||
59 | * the write call). | 59 | * the write call). |
60 | */ | 60 | */ |
61 | static inline __be32 | 61 | static inline __be32 |
62 | nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int type) | 62 | nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int requested) |
63 | { | 63 | { |
64 | /* Type can be negative when creating hardlinks - not to a dir */ | 64 | mode &= S_IFMT; |
65 | if (type > 0 && (mode & S_IFMT) != type) { | 65 | |
66 | if (rqstp->rq_vers == 4 && (mode & S_IFMT) == S_IFLNK) | 66 | if (requested == 0) /* the caller doesn't care */ |
67 | return nfserr_symlink; | 67 | return nfs_ok; |
68 | else if (type == S_IFDIR) | 68 | if (mode == requested) |
69 | return nfserr_notdir; | 69 | return nfs_ok; |
70 | else if ((mode & S_IFMT) == S_IFDIR) | 70 | /* |
71 | return nfserr_isdir; | 71 | * v4 has an error more specific than err_notdir which we should |
72 | else | 72 | * return in preference to err_notdir: |
73 | return nfserr_inval; | 73 | */ |
74 | } | 74 | if (rqstp->rq_vers == 4 && mode == S_IFLNK) |
75 | if (type < 0 && (mode & S_IFMT) == -type) { | 75 | return nfserr_symlink; |
76 | if (rqstp->rq_vers == 4 && (mode & S_IFMT) == S_IFLNK) | 76 | if (requested == S_IFDIR) |
77 | return nfserr_symlink; | 77 | return nfserr_notdir; |
78 | else if (type == -S_IFDIR) | 78 | if (mode == S_IFDIR) |
79 | return nfserr_isdir; | 79 | return nfserr_isdir; |
80 | else | 80 | return nfserr_inval; |
81 | return nfserr_notdir; | ||
82 | } | ||
83 | return 0; | ||
84 | } | 81 | } |
85 | 82 | ||
86 | static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp, | 83 | static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp, |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 4eefaf1b42e8..a3cf38476a1b 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -35,6 +35,7 @@ | |||
35 | #ifndef _NFSD4_STATE_H | 35 | #ifndef _NFSD4_STATE_H |
36 | #define _NFSD4_STATE_H | 36 | #define _NFSD4_STATE_H |
37 | 37 | ||
38 | #include <linux/idr.h> | ||
38 | #include <linux/sunrpc/svc_xprt.h> | 39 | #include <linux/sunrpc/svc_xprt.h> |
39 | #include <linux/nfsd/nfsfh.h> | 40 | #include <linux/nfsd/nfsfh.h> |
40 | #include "nfsfh.h" | 41 | #include "nfsfh.h" |
@@ -45,24 +46,20 @@ typedef struct { | |||
45 | } clientid_t; | 46 | } clientid_t; |
46 | 47 | ||
47 | typedef struct { | 48 | typedef struct { |
48 | u32 so_boot; | 49 | clientid_t so_clid; |
49 | u32 so_stateownerid; | 50 | u32 so_id; |
50 | u32 so_fileid; | ||
51 | } stateid_opaque_t; | 51 | } stateid_opaque_t; |
52 | 52 | ||
53 | typedef struct { | 53 | typedef struct { |
54 | u32 si_generation; | 54 | u32 si_generation; |
55 | stateid_opaque_t si_opaque; | 55 | stateid_opaque_t si_opaque; |
56 | } stateid_t; | 56 | } stateid_t; |
57 | #define si_boot si_opaque.so_boot | ||
58 | #define si_stateownerid si_opaque.so_stateownerid | ||
59 | #define si_fileid si_opaque.so_fileid | ||
60 | 57 | ||
61 | #define STATEID_FMT "(%08x/%08x/%08x/%08x)" | 58 | #define STATEID_FMT "(%08x/%08x/%08x/%08x)" |
62 | #define STATEID_VAL(s) \ | 59 | #define STATEID_VAL(s) \ |
63 | (s)->si_boot, \ | 60 | (s)->si_opaque.so_clid.cl_boot, \ |
64 | (s)->si_stateownerid, \ | 61 | (s)->si_opaque.so_clid.cl_id, \ |
65 | (s)->si_fileid, \ | 62 | (s)->si_opaque.so_id, \ |
66 | (s)->si_generation | 63 | (s)->si_generation |
67 | 64 | ||
68 | struct nfsd4_callback { | 65 | struct nfsd4_callback { |
@@ -76,17 +73,27 @@ struct nfsd4_callback { | |||
76 | bool cb_done; | 73 | bool cb_done; |
77 | }; | 74 | }; |
78 | 75 | ||
76 | struct nfs4_stid { | ||
77 | #define NFS4_OPEN_STID 1 | ||
78 | #define NFS4_LOCK_STID 2 | ||
79 | #define NFS4_DELEG_STID 4 | ||
80 | /* For an open stateid kept around *only* to process close replays: */ | ||
81 | #define NFS4_CLOSED_STID 8 | ||
82 | unsigned char sc_type; | ||
83 | stateid_t sc_stateid; | ||
84 | struct nfs4_client *sc_client; | ||
85 | }; | ||
86 | |||
79 | struct nfs4_delegation { | 87 | struct nfs4_delegation { |
88 | struct nfs4_stid dl_stid; /* must be first field */ | ||
80 | struct list_head dl_perfile; | 89 | struct list_head dl_perfile; |
81 | struct list_head dl_perclnt; | 90 | struct list_head dl_perclnt; |
82 | struct list_head dl_recall_lru; /* delegation recalled */ | 91 | struct list_head dl_recall_lru; /* delegation recalled */ |
83 | atomic_t dl_count; /* ref count */ | 92 | atomic_t dl_count; /* ref count */ |
84 | struct nfs4_client *dl_client; | ||
85 | struct nfs4_file *dl_file; | 93 | struct nfs4_file *dl_file; |
86 | u32 dl_type; | 94 | u32 dl_type; |
87 | time_t dl_time; | 95 | time_t dl_time; |
88 | /* For recall: */ | 96 | /* For recall: */ |
89 | stateid_t dl_stateid; | ||
90 | struct knfsd_fh dl_fh; | 97 | struct knfsd_fh dl_fh; |
91 | int dl_retries; | 98 | int dl_retries; |
92 | struct nfsd4_callback dl_recall; | 99 | struct nfsd4_callback dl_recall; |
@@ -104,6 +111,11 @@ struct nfs4_cb_conn { | |||
104 | struct svc_xprt *cb_xprt; /* minorversion 1 only */ | 111 | struct svc_xprt *cb_xprt; /* minorversion 1 only */ |
105 | }; | 112 | }; |
106 | 113 | ||
114 | static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s) | ||
115 | { | ||
116 | return container_of(s, struct nfs4_delegation, dl_stid); | ||
117 | } | ||
118 | |||
107 | /* Maximum number of slots per session. 160 is useful for long haul TCP */ | 119 | /* Maximum number of slots per session. 160 is useful for long haul TCP */ |
108 | #define NFSD_MAX_SLOTS_PER_SESSION 160 | 120 | #define NFSD_MAX_SLOTS_PER_SESSION 160 |
109 | /* Maximum number of operations per session compound */ | 121 | /* Maximum number of operations per session compound */ |
@@ -220,6 +232,7 @@ struct nfs4_client { | |||
220 | struct list_head cl_idhash; /* hash by cl_clientid.id */ | 232 | struct list_head cl_idhash; /* hash by cl_clientid.id */ |
221 | struct list_head cl_strhash; /* hash by cl_name */ | 233 | struct list_head cl_strhash; /* hash by cl_name */ |
222 | struct list_head cl_openowners; | 234 | struct list_head cl_openowners; |
235 | struct idr cl_stateids; /* stateid lookup */ | ||
223 | struct list_head cl_delegations; | 236 | struct list_head cl_delegations; |
224 | struct list_head cl_lru; /* tail queue */ | 237 | struct list_head cl_lru; /* tail queue */ |
225 | struct xdr_netobj cl_name; /* id generated by client */ | 238 | struct xdr_netobj cl_name; /* id generated by client */ |
@@ -245,6 +258,7 @@ struct nfs4_client { | |||
245 | #define NFSD4_CB_UP 0 | 258 | #define NFSD4_CB_UP 0 |
246 | #define NFSD4_CB_UNKNOWN 1 | 259 | #define NFSD4_CB_UNKNOWN 1 |
247 | #define NFSD4_CB_DOWN 2 | 260 | #define NFSD4_CB_DOWN 2 |
261 | #define NFSD4_CB_FAULT 3 | ||
248 | int cl_cb_state; | 262 | int cl_cb_state; |
249 | struct nfsd4_callback cl_cb_null; | 263 | struct nfsd4_callback cl_cb_null; |
250 | struct nfsd4_session *cl_cb_session; | 264 | struct nfsd4_session *cl_cb_session; |
@@ -293,6 +307,9 @@ static inline void | |||
293 | update_stateid(stateid_t *stateid) | 307 | update_stateid(stateid_t *stateid) |
294 | { | 308 | { |
295 | stateid->si_generation++; | 309 | stateid->si_generation++; |
310 | /* Wraparound recommendation from 3530bis-13 9.1.3.2: */ | ||
311 | if (stateid->si_generation == 0) | ||
312 | stateid->si_generation = 1; | ||
296 | } | 313 | } |
297 | 314 | ||
298 | /* A reasonable value for REPLAY_ISIZE was estimated as follows: | 315 | /* A reasonable value for REPLAY_ISIZE was estimated as follows: |
@@ -312,49 +329,57 @@ struct nfs4_replay { | |||
312 | __be32 rp_status; | 329 | __be32 rp_status; |
313 | unsigned int rp_buflen; | 330 | unsigned int rp_buflen; |
314 | char *rp_buf; | 331 | char *rp_buf; |
315 | unsigned intrp_allocated; | ||
316 | struct knfsd_fh rp_openfh; | 332 | struct knfsd_fh rp_openfh; |
317 | char rp_ibuf[NFSD4_REPLAY_ISIZE]; | 333 | char rp_ibuf[NFSD4_REPLAY_ISIZE]; |
318 | }; | 334 | }; |
319 | 335 | ||
320 | /* | ||
321 | * nfs4_stateowner can either be an open_owner, or a lock_owner | ||
322 | * | ||
323 | * so_idhash: stateid_hashtbl[] for open owner, lockstateid_hashtbl[] | ||
324 | * for lock_owner | ||
325 | * so_strhash: ownerstr_hashtbl[] for open_owner, lock_ownerstr_hashtbl[] | ||
326 | * for lock_owner | ||
327 | * so_perclient: nfs4_client->cl_perclient entry - used when nfs4_client | ||
328 | * struct is reaped. | ||
329 | * so_perfilestate: heads the list of nfs4_stateid (either open or lock) | ||
330 | * and is used to ensure no dangling nfs4_stateid references when we | ||
331 | * release a stateowner. | ||
332 | * so_perlockowner: (open) nfs4_stateid->st_perlockowner entry - used when | ||
333 | * close is called to reap associated byte-range locks | ||
334 | * so_close_lru: (open) stateowner is placed on this list instead of being | ||
335 | * reaped (when so_perfilestate is empty) to hold the last close replay. | ||
336 | * reaped by laundramat thread after lease period. | ||
337 | */ | ||
338 | struct nfs4_stateowner { | 336 | struct nfs4_stateowner { |
339 | struct kref so_ref; | ||
340 | struct list_head so_idhash; /* hash by so_id */ | ||
341 | struct list_head so_strhash; /* hash by op_name */ | 337 | struct list_head so_strhash; /* hash by op_name */ |
342 | struct list_head so_perclient; | ||
343 | struct list_head so_stateids; | 338 | struct list_head so_stateids; |
344 | struct list_head so_perstateid; /* for lockowners only */ | ||
345 | struct list_head so_close_lru; /* tail queue */ | ||
346 | time_t so_time; /* time of placement on so_close_lru */ | ||
347 | int so_is_open_owner; /* 1=openowner,0=lockowner */ | ||
348 | u32 so_id; | ||
349 | struct nfs4_client * so_client; | 339 | struct nfs4_client * so_client; |
350 | /* after increment in ENCODE_SEQID_OP_TAIL, represents the next | 340 | /* after increment in ENCODE_SEQID_OP_TAIL, represents the next |
351 | * sequence id expected from the client: */ | 341 | * sequence id expected from the client: */ |
352 | u32 so_seqid; | 342 | u32 so_seqid; |
353 | struct xdr_netobj so_owner; /* open owner name */ | 343 | struct xdr_netobj so_owner; /* open owner name */ |
354 | int so_confirmed; /* successful OPEN_CONFIRM? */ | ||
355 | struct nfs4_replay so_replay; | 344 | struct nfs4_replay so_replay; |
345 | bool so_is_open_owner; | ||
356 | }; | 346 | }; |
357 | 347 | ||
348 | struct nfs4_openowner { | ||
349 | struct nfs4_stateowner oo_owner; /* must be first field */ | ||
350 | struct list_head oo_perclient; | ||
351 | /* | ||
352 | * We keep around openowners a little while after last close, | ||
353 | * which saves clients from having to confirm, and allows us to | ||
354 | * handle close replays if they come soon enough. The close_lru | ||
355 | * is a list of such openowners, to be reaped by the laundromat | ||
356 | * thread eventually if they remain unused: | ||
357 | */ | ||
358 | struct list_head oo_close_lru; | ||
359 | struct nfs4_ol_stateid *oo_last_closed_stid; | ||
360 | time_t oo_time; /* time of placement on so_close_lru */ | ||
361 | #define NFS4_OO_CONFIRMED 1 | ||
362 | #define NFS4_OO_PURGE_CLOSE 2 | ||
363 | #define NFS4_OO_NEW 4 | ||
364 | unsigned char oo_flags; | ||
365 | }; | ||
366 | |||
367 | struct nfs4_lockowner { | ||
368 | struct nfs4_stateowner lo_owner; /* must be first element */ | ||
369 | struct list_head lo_perstateid; /* for lockowners only */ | ||
370 | struct list_head lo_list; /* for temporary uses */ | ||
371 | }; | ||
372 | |||
373 | static inline struct nfs4_openowner * openowner(struct nfs4_stateowner *so) | ||
374 | { | ||
375 | return container_of(so, struct nfs4_openowner, oo_owner); | ||
376 | } | ||
377 | |||
378 | static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so) | ||
379 | { | ||
380 | return container_of(so, struct nfs4_lockowner, lo_owner); | ||
381 | } | ||
382 | |||
358 | /* | 383 | /* |
359 | * nfs4_file: a file opened by some number of (open) nfs4_stateowners. | 384 | * nfs4_file: a file opened by some number of (open) nfs4_stateowners. |
360 | * o fi_perfile list is used to search for conflicting | 385 | * o fi_perfile list is used to search for conflicting |
@@ -368,17 +393,17 @@ struct nfs4_file { | |||
368 | /* One each for O_RDONLY, O_WRONLY, O_RDWR: */ | 393 | /* One each for O_RDONLY, O_WRONLY, O_RDWR: */ |
369 | struct file * fi_fds[3]; | 394 | struct file * fi_fds[3]; |
370 | /* | 395 | /* |
371 | * Each open or lock stateid contributes 1 to either | 396 | * Each open or lock stateid contributes 0-4 to the counts |
372 | * fi_access[O_RDONLY], fi_access[O_WRONLY], or both, depending | 397 | * below depending on which bits are set in st_access_bitmap: |
373 | * on open or lock mode: | 398 | * 1 to fi_access[O_RDONLY] if NFS4_SHARE_ACCES_READ is set |
399 | * + 1 to fi_access[O_WRONLY] if NFS4_SHARE_ACCESS_WRITE is set | ||
400 | * + 1 to both of the above if NFS4_SHARE_ACCESS_BOTH is set. | ||
374 | */ | 401 | */ |
375 | atomic_t fi_access[2]; | 402 | atomic_t fi_access[2]; |
376 | struct file *fi_deleg_file; | 403 | struct file *fi_deleg_file; |
377 | struct file_lock *fi_lease; | 404 | struct file_lock *fi_lease; |
378 | atomic_t fi_delegees; | 405 | atomic_t fi_delegees; |
379 | struct inode *fi_inode; | 406 | struct inode *fi_inode; |
380 | u32 fi_id; /* used with stateowner->so_id | ||
381 | * for stateid_hashtbl hash */ | ||
382 | bool fi_had_conflict; | 407 | bool fi_had_conflict; |
383 | }; | 408 | }; |
384 | 409 | ||
@@ -408,50 +433,27 @@ static inline struct file *find_any_file(struct nfs4_file *f) | |||
408 | return f->fi_fds[O_RDONLY]; | 433 | return f->fi_fds[O_RDONLY]; |
409 | } | 434 | } |
410 | 435 | ||
411 | /* | 436 | /* "ol" stands for "Open or Lock". Better suggestions welcome. */ |
412 | * nfs4_stateid can either be an open stateid or (eventually) a lock stateid | 437 | struct nfs4_ol_stateid { |
413 | * | 438 | struct nfs4_stid st_stid; /* must be first field */ |
414 | * (open)nfs4_stateid: one per (open)nfs4_stateowner, nfs4_file | ||
415 | * | ||
416 | * st_hash: stateid_hashtbl[] entry or lockstateid_hashtbl entry | ||
417 | * st_perfile: file_hashtbl[] entry. | ||
418 | * st_perfile_state: nfs4_stateowner->so_perfilestate | ||
419 | * st_perlockowner: (open stateid) list of lock nfs4_stateowners | ||
420 | * st_access_bmap: used only for open stateid | ||
421 | * st_deny_bmap: used only for open stateid | ||
422 | * st_openstp: open stateid lock stateid was derived from | ||
423 | * | ||
424 | * XXX: open stateids and lock stateids have diverged sufficiently that | ||
425 | * we should consider defining separate structs for the two cases. | ||
426 | */ | ||
427 | |||
428 | struct nfs4_stateid { | ||
429 | struct list_head st_hash; | ||
430 | struct list_head st_perfile; | 439 | struct list_head st_perfile; |
431 | struct list_head st_perstateowner; | 440 | struct list_head st_perstateowner; |
432 | struct list_head st_lockowners; | 441 | struct list_head st_lockowners; |
433 | struct nfs4_stateowner * st_stateowner; | 442 | struct nfs4_stateowner * st_stateowner; |
434 | struct nfs4_file * st_file; | 443 | struct nfs4_file * st_file; |
435 | stateid_t st_stateid; | ||
436 | unsigned long st_access_bmap; | 444 | unsigned long st_access_bmap; |
437 | unsigned long st_deny_bmap; | 445 | unsigned long st_deny_bmap; |
438 | struct nfs4_stateid * st_openstp; | 446 | struct nfs4_ol_stateid * st_openstp; |
439 | }; | 447 | }; |
440 | 448 | ||
449 | static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s) | ||
450 | { | ||
451 | return container_of(s, struct nfs4_ol_stateid, st_stid); | ||
452 | } | ||
453 | |||
441 | /* flags for preprocess_seqid_op() */ | 454 | /* flags for preprocess_seqid_op() */ |
442 | #define HAS_SESSION 0x00000001 | ||
443 | #define CONFIRM 0x00000002 | ||
444 | #define OPEN_STATE 0x00000004 | ||
445 | #define LOCK_STATE 0x00000008 | ||
446 | #define RD_STATE 0x00000010 | 455 | #define RD_STATE 0x00000010 |
447 | #define WR_STATE 0x00000020 | 456 | #define WR_STATE 0x00000020 |
448 | #define CLOSE_STATE 0x00000040 | ||
449 | |||
450 | #define seqid_mutating_err(err) \ | ||
451 | (((err) != nfserr_stale_clientid) && \ | ||
452 | ((err) != nfserr_bad_seqid) && \ | ||
453 | ((err) != nfserr_stale_stateid) && \ | ||
454 | ((err) != nfserr_bad_stateid)) | ||
455 | 457 | ||
456 | struct nfsd4_compound_state; | 458 | struct nfsd4_compound_state; |
457 | 459 | ||
@@ -461,7 +463,8 @@ extern void nfs4_lock_state(void); | |||
461 | extern void nfs4_unlock_state(void); | 463 | extern void nfs4_unlock_state(void); |
462 | extern int nfs4_in_grace(void); | 464 | extern int nfs4_in_grace(void); |
463 | extern __be32 nfs4_check_open_reclaim(clientid_t *clid); | 465 | extern __be32 nfs4_check_open_reclaim(clientid_t *clid); |
464 | extern void nfs4_free_stateowner(struct kref *kref); | 466 | extern void nfs4_free_openowner(struct nfs4_openowner *); |
467 | extern void nfs4_free_lockowner(struct nfs4_lockowner *); | ||
465 | extern int set_callback_cred(void); | 468 | extern int set_callback_cred(void); |
466 | extern void nfsd4_probe_callback(struct nfs4_client *clp); | 469 | extern void nfsd4_probe_callback(struct nfs4_client *clp); |
467 | extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); | 470 | extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); |
@@ -473,7 +476,7 @@ extern void nfsd4_destroy_callback_queue(void); | |||
473 | extern void nfsd4_shutdown_callback(struct nfs4_client *); | 476 | extern void nfsd4_shutdown_callback(struct nfs4_client *); |
474 | extern void nfs4_put_delegation(struct nfs4_delegation *dp); | 477 | extern void nfs4_put_delegation(struct nfs4_delegation *dp); |
475 | extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); | 478 | extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); |
476 | extern void nfsd4_init_recdir(char *recdir_name); | 479 | extern void nfsd4_init_recdir(void); |
477 | extern int nfsd4_recdir_load(void); | 480 | extern int nfsd4_recdir_load(void); |
478 | extern void nfsd4_shutdown_recdir(void); | 481 | extern void nfsd4_shutdown_recdir(void); |
479 | extern int nfs4_client_to_reclaim(const char *name); | 482 | extern int nfs4_client_to_reclaim(const char *name); |
@@ -482,18 +485,7 @@ extern void nfsd4_recdir_purge_old(void); | |||
482 | extern int nfsd4_create_clid_dir(struct nfs4_client *clp); | 485 | extern int nfsd4_create_clid_dir(struct nfs4_client *clp); |
483 | extern void nfsd4_remove_clid_dir(struct nfs4_client *clp); | 486 | extern void nfsd4_remove_clid_dir(struct nfs4_client *clp); |
484 | extern void release_session_client(struct nfsd4_session *); | 487 | extern void release_session_client(struct nfsd4_session *); |
485 | extern __be32 nfs4_validate_stateid(stateid_t *, int); | 488 | extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *); |
486 | 489 | extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); | |
487 | static inline void | ||
488 | nfs4_put_stateowner(struct nfs4_stateowner *so) | ||
489 | { | ||
490 | kref_put(&so->so_ref, nfs4_free_stateowner); | ||
491 | } | ||
492 | |||
493 | static inline void | ||
494 | nfs4_get_stateowner(struct nfs4_stateowner *so) | ||
495 | { | ||
496 | kref_get(&so->so_ref); | ||
497 | } | ||
498 | 490 | ||
499 | #endif /* NFSD4_STATE_H */ | 491 | #endif /* NFSD4_STATE_H */ |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index fd0acca5370a..7a2e442623c8 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -168,6 +168,8 @@ int nfsd_mountpoint(struct dentry *dentry, struct svc_export *exp) | |||
168 | { | 168 | { |
169 | if (d_mountpoint(dentry)) | 169 | if (d_mountpoint(dentry)) |
170 | return 1; | 170 | return 1; |
171 | if (nfsd4_is_junction(dentry)) | ||
172 | return 1; | ||
171 | if (!(exp->ex_flags & NFSEXP_V4ROOT)) | 173 | if (!(exp->ex_flags & NFSEXP_V4ROOT)) |
172 | return 0; | 174 | return 0; |
173 | return dentry->d_inode != NULL; | 175 | return dentry->d_inode != NULL; |
@@ -502,7 +504,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
502 | unsigned int flags = 0; | 504 | unsigned int flags = 0; |
503 | 505 | ||
504 | /* Get inode */ | 506 | /* Get inode */ |
505 | error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR); | 507 | error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR); |
506 | if (error) | 508 | if (error) |
507 | return error; | 509 | return error; |
508 | 510 | ||
@@ -592,6 +594,22 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac | |||
592 | return error; | 594 | return error; |
593 | } | 595 | } |
594 | 596 | ||
597 | #define NFSD_XATTR_JUNCTION_PREFIX XATTR_TRUSTED_PREFIX "junction." | ||
598 | #define NFSD_XATTR_JUNCTION_TYPE NFSD_XATTR_JUNCTION_PREFIX "type" | ||
599 | int nfsd4_is_junction(struct dentry *dentry) | ||
600 | { | ||
601 | struct inode *inode = dentry->d_inode; | ||
602 | |||
603 | if (inode == NULL) | ||
604 | return 0; | ||
605 | if (inode->i_mode & S_IXUGO) | ||
606 | return 0; | ||
607 | if (!(inode->i_mode & S_ISVTX)) | ||
608 | return 0; | ||
609 | if (vfs_getxattr(dentry, NFSD_XATTR_JUNCTION_TYPE, NULL, 0) <= 0) | ||
610 | return 0; | ||
611 | return 1; | ||
612 | } | ||
595 | #endif /* defined(CONFIG_NFSD_V4) */ | 613 | #endif /* defined(CONFIG_NFSD_V4) */ |
596 | 614 | ||
597 | #ifdef CONFIG_NFSD_V3 | 615 | #ifdef CONFIG_NFSD_V3 |
@@ -1352,7 +1370,7 @@ __be32 | |||
1352 | do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | 1370 | do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, |
1353 | char *fname, int flen, struct iattr *iap, | 1371 | char *fname, int flen, struct iattr *iap, |
1354 | struct svc_fh *resfhp, int createmode, u32 *verifier, | 1372 | struct svc_fh *resfhp, int createmode, u32 *verifier, |
1355 | int *truncp, int *created) | 1373 | bool *truncp, bool *created) |
1356 | { | 1374 | { |
1357 | struct dentry *dentry, *dchild = NULL; | 1375 | struct dentry *dentry, *dchild = NULL; |
1358 | struct inode *dirp; | 1376 | struct inode *dirp; |
@@ -1632,10 +1650,12 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1632 | err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_CREATE); | 1650 | err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_CREATE); |
1633 | if (err) | 1651 | if (err) |
1634 | goto out; | 1652 | goto out; |
1635 | err = fh_verify(rqstp, tfhp, -S_IFDIR, NFSD_MAY_NOP); | 1653 | err = fh_verify(rqstp, tfhp, 0, NFSD_MAY_NOP); |
1636 | if (err) | 1654 | if (err) |
1637 | goto out; | 1655 | goto out; |
1638 | 1656 | err = nfserr_isdir; | |
1657 | if (S_ISDIR(tfhp->fh_dentry->d_inode->i_mode)) | ||
1658 | goto out; | ||
1639 | err = nfserr_perm; | 1659 | err = nfserr_perm; |
1640 | if (!len) | 1660 | if (!len) |
1641 | goto out; | 1661 | goto out; |
@@ -2114,7 +2134,8 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
2114 | 2134 | ||
2115 | /* Allow read access to binaries even when mode 111 */ | 2135 | /* Allow read access to binaries even when mode 111 */ |
2116 | if (err == -EACCES && S_ISREG(inode->i_mode) && | 2136 | if (err == -EACCES && S_ISREG(inode->i_mode) && |
2117 | acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) | 2137 | (acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE) || |
2138 | acc == (NFSD_MAY_READ | NFSD_MAY_READ_IF_EXEC))) | ||
2118 | err = inode_permission(inode, MAY_EXEC); | 2139 | err = inode_permission(inode, MAY_EXEC); |
2119 | 2140 | ||
2120 | return err? nfserrno(err) : 0; | 2141 | return err? nfserrno(err) : 0; |
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index e0bbac04d1dd..3f54ad03bb2b 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h | |||
@@ -10,21 +10,22 @@ | |||
10 | /* | 10 | /* |
11 | * Flags for nfsd_permission | 11 | * Flags for nfsd_permission |
12 | */ | 12 | */ |
13 | #define NFSD_MAY_NOP 0 | 13 | #define NFSD_MAY_NOP 0 |
14 | #define NFSD_MAY_EXEC 1 /* == MAY_EXEC */ | 14 | #define NFSD_MAY_EXEC 0x001 /* == MAY_EXEC */ |
15 | #define NFSD_MAY_WRITE 2 /* == MAY_WRITE */ | 15 | #define NFSD_MAY_WRITE 0x002 /* == MAY_WRITE */ |
16 | #define NFSD_MAY_READ 4 /* == MAY_READ */ | 16 | #define NFSD_MAY_READ 0x004 /* == MAY_READ */ |
17 | #define NFSD_MAY_SATTR 8 | 17 | #define NFSD_MAY_SATTR 0x008 |
18 | #define NFSD_MAY_TRUNC 16 | 18 | #define NFSD_MAY_TRUNC 0x010 |
19 | #define NFSD_MAY_LOCK 32 | 19 | #define NFSD_MAY_LOCK 0x020 |
20 | #define NFSD_MAY_MASK 63 | 20 | #define NFSD_MAY_MASK 0x03f |
21 | 21 | ||
22 | /* extra hints to permission and open routines: */ | 22 | /* extra hints to permission and open routines: */ |
23 | #define NFSD_MAY_OWNER_OVERRIDE 64 | 23 | #define NFSD_MAY_OWNER_OVERRIDE 0x040 |
24 | #define NFSD_MAY_LOCAL_ACCESS 128 /* IRIX doing local access check on device special file*/ | 24 | #define NFSD_MAY_LOCAL_ACCESS 0x080 /* for device special files */ |
25 | #define NFSD_MAY_BYPASS_GSS_ON_ROOT 256 | 25 | #define NFSD_MAY_BYPASS_GSS_ON_ROOT 0x100 |
26 | #define NFSD_MAY_NOT_BREAK_LEASE 512 | 26 | #define NFSD_MAY_NOT_BREAK_LEASE 0x200 |
27 | #define NFSD_MAY_BYPASS_GSS 1024 | 27 | #define NFSD_MAY_BYPASS_GSS 0x400 |
28 | #define NFSD_MAY_READ_IF_EXEC 0x800 | ||
28 | 29 | ||
29 | #define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE) | 30 | #define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE) |
30 | #define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC) | 31 | #define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC) |
@@ -61,7 +62,7 @@ __be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); | |||
61 | __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, | 62 | __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, |
62 | char *name, int len, struct iattr *attrs, | 63 | char *name, int len, struct iattr *attrs, |
63 | struct svc_fh *res, int createmode, | 64 | struct svc_fh *res, int createmode, |
64 | u32 *verifier, int *truncp, int *created); | 65 | u32 *verifier, bool *truncp, bool *created); |
65 | __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, | 66 | __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, |
66 | loff_t, unsigned long); | 67 | loff_t, unsigned long); |
67 | #endif /* CONFIG_NFSD_V3 */ | 68 | #endif /* CONFIG_NFSD_V3 */ |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index d2a8d04428c7..2364747ee97d 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -81,7 +81,6 @@ struct nfsd4_access { | |||
81 | struct nfsd4_close { | 81 | struct nfsd4_close { |
82 | u32 cl_seqid; /* request */ | 82 | u32 cl_seqid; /* request */ |
83 | stateid_t cl_stateid; /* request+response */ | 83 | stateid_t cl_stateid; /* request+response */ |
84 | struct nfs4_stateowner * cl_stateowner; /* response */ | ||
85 | }; | 84 | }; |
86 | 85 | ||
87 | struct nfsd4_commit { | 86 | struct nfsd4_commit { |
@@ -131,7 +130,7 @@ struct nfsd4_link { | |||
131 | 130 | ||
132 | struct nfsd4_lock_denied { | 131 | struct nfsd4_lock_denied { |
133 | clientid_t ld_clientid; | 132 | clientid_t ld_clientid; |
134 | struct nfs4_stateowner *ld_sop; | 133 | struct xdr_netobj ld_owner; |
135 | u64 ld_start; | 134 | u64 ld_start; |
136 | u64 ld_length; | 135 | u64 ld_length; |
137 | u32 ld_type; | 136 | u32 ld_type; |
@@ -165,9 +164,6 @@ struct nfsd4_lock { | |||
165 | } ok; | 164 | } ok; |
166 | struct nfsd4_lock_denied denied; | 165 | struct nfsd4_lock_denied denied; |
167 | } u; | 166 | } u; |
168 | /* The lk_replay_owner is the open owner in the open_to_lock_owner | ||
169 | * case and the lock owner otherwise: */ | ||
170 | struct nfs4_stateowner *lk_replay_owner; | ||
171 | }; | 167 | }; |
172 | #define lk_new_open_seqid v.new.open_seqid | 168 | #define lk_new_open_seqid v.new.open_seqid |
173 | #define lk_new_open_stateid v.new.open_stateid | 169 | #define lk_new_open_stateid v.new.open_stateid |
@@ -188,7 +184,6 @@ struct nfsd4_lockt { | |||
188 | struct xdr_netobj lt_owner; | 184 | struct xdr_netobj lt_owner; |
189 | u64 lt_offset; | 185 | u64 lt_offset; |
190 | u64 lt_length; | 186 | u64 lt_length; |
191 | struct nfs4_stateowner * lt_stateowner; | ||
192 | struct nfsd4_lock_denied lt_denied; | 187 | struct nfsd4_lock_denied lt_denied; |
193 | }; | 188 | }; |
194 | 189 | ||
@@ -199,7 +194,6 @@ struct nfsd4_locku { | |||
199 | stateid_t lu_stateid; | 194 | stateid_t lu_stateid; |
200 | u64 lu_offset; | 195 | u64 lu_offset; |
201 | u64 lu_length; | 196 | u64 lu_length; |
202 | struct nfs4_stateowner *lu_stateowner; | ||
203 | }; | 197 | }; |
204 | 198 | ||
205 | 199 | ||
@@ -232,8 +226,11 @@ struct nfsd4_open { | |||
232 | u32 op_recall; /* recall */ | 226 | u32 op_recall; /* recall */ |
233 | struct nfsd4_change_info op_cinfo; /* response */ | 227 | struct nfsd4_change_info op_cinfo; /* response */ |
234 | u32 op_rflags; /* response */ | 228 | u32 op_rflags; /* response */ |
235 | int op_truncate; /* used during processing */ | 229 | bool op_truncate; /* used during processing */ |
236 | struct nfs4_stateowner *op_stateowner; /* used during processing */ | 230 | bool op_created; /* used during processing */ |
231 | struct nfs4_openowner *op_openowner; /* used during processing */ | ||
232 | struct nfs4_file *op_file; /* used during processing */ | ||
233 | struct nfs4_ol_stateid *op_stp; /* used during processing */ | ||
237 | struct nfs4_acl *op_acl; | 234 | struct nfs4_acl *op_acl; |
238 | }; | 235 | }; |
239 | #define op_iattr iattr | 236 | #define op_iattr iattr |
@@ -243,7 +240,6 @@ struct nfsd4_open_confirm { | |||
243 | stateid_t oc_req_stateid /* request */; | 240 | stateid_t oc_req_stateid /* request */; |
244 | u32 oc_seqid /* request */; | 241 | u32 oc_seqid /* request */; |
245 | stateid_t oc_resp_stateid /* response */; | 242 | stateid_t oc_resp_stateid /* response */; |
246 | struct nfs4_stateowner * oc_stateowner; /* response */ | ||
247 | }; | 243 | }; |
248 | 244 | ||
249 | struct nfsd4_open_downgrade { | 245 | struct nfsd4_open_downgrade { |
@@ -251,7 +247,6 @@ struct nfsd4_open_downgrade { | |||
251 | u32 od_seqid; | 247 | u32 od_seqid; |
252 | u32 od_share_access; | 248 | u32 od_share_access; |
253 | u32 od_share_deny; | 249 | u32 od_share_deny; |
254 | struct nfs4_stateowner *od_stateowner; | ||
255 | }; | 250 | }; |
256 | 251 | ||
257 | 252 | ||
@@ -325,8 +320,7 @@ struct nfsd4_setattr { | |||
325 | 320 | ||
326 | struct nfsd4_setclientid { | 321 | struct nfsd4_setclientid { |
327 | nfs4_verifier se_verf; /* request */ | 322 | nfs4_verifier se_verf; /* request */ |
328 | u32 se_namelen; /* request */ | 323 | struct xdr_netobj se_name; |
329 | char * se_name; /* request */ | ||
330 | u32 se_callback_prog; /* request */ | 324 | u32 se_callback_prog; /* request */ |
331 | u32 se_callback_netid_len; /* request */ | 325 | u32 se_callback_netid_len; /* request */ |
332 | char * se_callback_netid_val; /* request */ | 326 | char * se_callback_netid_val; /* request */ |
@@ -351,7 +345,6 @@ struct nfsd4_saved_compoundargs { | |||
351 | 345 | ||
352 | struct nfsd4_test_stateid { | 346 | struct nfsd4_test_stateid { |
353 | __be32 ts_num_ids; | 347 | __be32 ts_num_ids; |
354 | __be32 ts_has_session; | ||
355 | struct nfsd4_compoundargs *ts_saved_args; | 348 | struct nfsd4_compoundargs *ts_saved_args; |
356 | struct nfsd4_saved_compoundargs ts_savedp; | 349 | struct nfsd4_saved_compoundargs ts_savedp; |
357 | }; | 350 | }; |
@@ -405,6 +398,10 @@ struct nfsd4_destroy_session { | |||
405 | struct nfs4_sessionid sessionid; | 398 | struct nfs4_sessionid sessionid; |
406 | }; | 399 | }; |
407 | 400 | ||
401 | struct nfsd4_destroy_clientid { | ||
402 | clientid_t clientid; | ||
403 | }; | ||
404 | |||
408 | struct nfsd4_reclaim_complete { | 405 | struct nfsd4_reclaim_complete { |
409 | u32 rca_one_fs; | 406 | u32 rca_one_fs; |
410 | }; | 407 | }; |
@@ -532,6 +529,7 @@ int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *, | |||
532 | struct nfsd4_compoundargs *); | 529 | struct nfsd4_compoundargs *); |
533 | int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, | 530 | int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *, |
534 | struct nfsd4_compoundres *); | 531 | struct nfsd4_compoundres *); |
532 | int nfsd4_check_resp_size(struct nfsd4_compoundres *, u32); | ||
535 | void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); | 533 | void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); |
536 | void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); | 534 | void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); |
537 | __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | 535 | __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, |
@@ -558,11 +556,13 @@ extern __be32 nfsd4_sequence(struct svc_rqst *, | |||
558 | extern __be32 nfsd4_destroy_session(struct svc_rqst *, | 556 | extern __be32 nfsd4_destroy_session(struct svc_rqst *, |
559 | struct nfsd4_compound_state *, | 557 | struct nfsd4_compound_state *, |
560 | struct nfsd4_destroy_session *); | 558 | struct nfsd4_destroy_session *); |
559 | extern __be32 nfsd4_destroy_clientid(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_destroy_clientid *); | ||
561 | __be32 nfsd4_reclaim_complete(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_reclaim_complete *); | 560 | __be32 nfsd4_reclaim_complete(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_reclaim_complete *); |
562 | extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *, | 561 | extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *, |
563 | struct nfsd4_open *open); | 562 | struct nfsd4_open *open); |
564 | extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp, | 563 | extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp, |
565 | struct svc_fh *current_fh, struct nfsd4_open *open); | 564 | struct svc_fh *current_fh, struct nfsd4_open *open); |
565 | extern void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status); | ||
566 | extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp, | 566 | extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp, |
567 | struct nfsd4_compound_state *, struct nfsd4_open_confirm *oc); | 567 | struct nfsd4_compound_state *, struct nfsd4_open_confirm *oc); |
568 | extern __be32 nfsd4_close(struct svc_rqst *rqstp, | 568 | extern __be32 nfsd4_close(struct svc_rqst *rqstp, |