diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 291 |
1 files changed, 241 insertions, 50 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e98f3c2e949..6f8bcc733f7 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <linux/namei.h> | 38 | #include <linux/namei.h> |
39 | #include <linux/swap.h> | 39 | #include <linux/swap.h> |
40 | #include <linux/pagemap.h> | ||
40 | #include <linux/sunrpc/svcauth_gss.h> | 41 | #include <linux/sunrpc/svcauth_gss.h> |
41 | #include <linux/sunrpc/clnt.h> | 42 | #include <linux/sunrpc/clnt.h> |
42 | #include "xdr4.h" | 43 | #include "xdr4.h" |
@@ -60,9 +61,12 @@ static u64 current_sessionid = 1; | |||
60 | 61 | ||
61 | /* forward declarations */ | 62 | /* forward declarations */ |
62 | static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); | 63 | static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); |
64 | static struct nfs4_stateid * search_for_stateid(stateid_t *stid); | ||
65 | static struct nfs4_delegation * search_for_delegation(stateid_t *stid); | ||
63 | static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); | 66 | static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); |
64 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; | 67 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; |
65 | static void nfs4_set_recdir(char *recdir); | 68 | static void nfs4_set_recdir(char *recdir); |
69 | static int check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner); | ||
66 | 70 | ||
67 | /* Locking: */ | 71 | /* Locking: */ |
68 | 72 | ||
@@ -188,8 +192,15 @@ static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag) | |||
188 | static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) | 192 | static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) |
189 | { | 193 | { |
190 | if (atomic_dec_and_test(&fp->fi_access[oflag])) { | 194 | if (atomic_dec_and_test(&fp->fi_access[oflag])) { |
191 | nfs4_file_put_fd(fp, O_RDWR); | ||
192 | nfs4_file_put_fd(fp, oflag); | 195 | nfs4_file_put_fd(fp, oflag); |
196 | /* | ||
197 | * It's also safe to get rid of the RDWR open *if* | ||
198 | * we no longer have need of the other kind of access | ||
199 | * or if we already have the other kind of open: | ||
200 | */ | ||
201 | if (fp->fi_fds[1-oflag] | ||
202 | || atomic_read(&fp->fi_access[1 - oflag]) == 0) | ||
203 | nfs4_file_put_fd(fp, O_RDWR); | ||
193 | } | 204 | } |
194 | } | 205 | } |
195 | 206 | ||
@@ -381,14 +392,6 @@ static int nfs4_access_to_omode(u32 access) | |||
381 | BUG(); | 392 | BUG(); |
382 | } | 393 | } |
383 | 394 | ||
384 | static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp) | ||
385 | { | ||
386 | unsigned int access; | ||
387 | |||
388 | set_access(&access, stp->st_access_bmap); | ||
389 | return nfs4_access_to_omode(access); | ||
390 | } | ||
391 | |||
392 | static void unhash_generic_stateid(struct nfs4_stateid *stp) | 395 | static void unhash_generic_stateid(struct nfs4_stateid *stp) |
393 | { | 396 | { |
394 | list_del(&stp->st_hash); | 397 | list_del(&stp->st_hash); |
@@ -398,11 +401,14 @@ static void unhash_generic_stateid(struct nfs4_stateid *stp) | |||
398 | 401 | ||
399 | static void free_generic_stateid(struct nfs4_stateid *stp) | 402 | static void free_generic_stateid(struct nfs4_stateid *stp) |
400 | { | 403 | { |
401 | int oflag; | 404 | int i; |
402 | 405 | ||
403 | if (stp->st_access_bmap) { | 406 | if (stp->st_access_bmap) { |
404 | oflag = nfs4_access_bmap_to_omode(stp); | 407 | for (i = 1; i < 4; i++) { |
405 | nfs4_file_put_access(stp->st_file, oflag); | 408 | if (test_bit(i, &stp->st_access_bmap)) |
409 | nfs4_file_put_access(stp->st_file, | ||
410 | nfs4_access_to_omode(i)); | ||
411 | } | ||
406 | } | 412 | } |
407 | put_nfs4_file(stp->st_file); | 413 | put_nfs4_file(stp->st_file); |
408 | kmem_cache_free(stateid_slab, stp); | 414 | kmem_cache_free(stateid_slab, stp); |
@@ -1507,6 +1513,29 @@ nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, | |||
1507 | return slot->sl_status; | 1513 | return slot->sl_status; |
1508 | } | 1514 | } |
1509 | 1515 | ||
1516 | #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ | ||
1517 | 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ | ||
1518 | 1 + /* MIN tag is length with zero, only length */ \ | ||
1519 | 3 + /* version, opcount, opcode */ \ | ||
1520 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ | ||
1521 | /* seqid, slotID, slotID, cache */ \ | ||
1522 | 4 ) * sizeof(__be32)) | ||
1523 | |||
1524 | #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ | ||
1525 | 2 + /* verifier: AUTH_NULL, length 0 */\ | ||
1526 | 1 + /* status */ \ | ||
1527 | 1 + /* MIN tag is length with zero, only length */ \ | ||
1528 | 3 + /* opcount, opcode, opstatus*/ \ | ||
1529 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ | ||
1530 | /* seqid, slotID, slotID, slotID, status */ \ | ||
1531 | 5 ) * sizeof(__be32)) | ||
1532 | |||
1533 | static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs fchannel) | ||
1534 | { | ||
1535 | return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ | ||
1536 | || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ; | ||
1537 | } | ||
1538 | |||
1510 | __be32 | 1539 | __be32 |
1511 | nfsd4_create_session(struct svc_rqst *rqstp, | 1540 | nfsd4_create_session(struct svc_rqst *rqstp, |
1512 | struct nfsd4_compound_state *cstate, | 1541 | struct nfsd4_compound_state *cstate, |
@@ -1575,6 +1604,10 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1575 | cr_ses->flags &= ~SESSION4_PERSIST; | 1604 | cr_ses->flags &= ~SESSION4_PERSIST; |
1576 | cr_ses->flags &= ~SESSION4_RDMA; | 1605 | cr_ses->flags &= ~SESSION4_RDMA; |
1577 | 1606 | ||
1607 | status = nfserr_toosmall; | ||
1608 | if (check_forechannel_attrs(cr_ses->fore_channel)) | ||
1609 | goto out; | ||
1610 | |||
1578 | status = nfserr_jukebox; | 1611 | status = nfserr_jukebox; |
1579 | new = alloc_init_session(rqstp, conf, cr_ses); | 1612 | new = alloc_init_session(rqstp, conf, cr_ses); |
1580 | if (!new) | 1613 | if (!new) |
@@ -1736,6 +1769,14 @@ static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_sess | |||
1736 | return args->opcnt > session->se_fchannel.maxops; | 1769 | return args->opcnt > session->se_fchannel.maxops; |
1737 | } | 1770 | } |
1738 | 1771 | ||
1772 | static bool nfsd4_request_too_big(struct svc_rqst *rqstp, | ||
1773 | struct nfsd4_session *session) | ||
1774 | { | ||
1775 | struct xdr_buf *xb = &rqstp->rq_arg; | ||
1776 | |||
1777 | return xb->len > session->se_fchannel.maxreq_sz; | ||
1778 | } | ||
1779 | |||
1739 | __be32 | 1780 | __be32 |
1740 | nfsd4_sequence(struct svc_rqst *rqstp, | 1781 | nfsd4_sequence(struct svc_rqst *rqstp, |
1741 | struct nfsd4_compound_state *cstate, | 1782 | struct nfsd4_compound_state *cstate, |
@@ -1768,6 +1809,10 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1768 | if (nfsd4_session_too_many_ops(rqstp, session)) | 1809 | if (nfsd4_session_too_many_ops(rqstp, session)) |
1769 | goto out; | 1810 | goto out; |
1770 | 1811 | ||
1812 | status = nfserr_req_too_big; | ||
1813 | if (nfsd4_request_too_big(rqstp, session)) | ||
1814 | goto out; | ||
1815 | |||
1771 | status = nfserr_badslot; | 1816 | status = nfserr_badslot; |
1772 | if (seq->slotid >= session->se_fchannel.maxreqs) | 1817 | if (seq->slotid >= session->se_fchannel.maxreqs) |
1773 | goto out; | 1818 | goto out; |
@@ -1908,7 +1953,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1908 | * of 5 bullet points, labeled as CASE0 - CASE4 below. | 1953 | * of 5 bullet points, labeled as CASE0 - CASE4 below. |
1909 | */ | 1954 | */ |
1910 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 1955 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
1911 | status = nfserr_resource; | 1956 | status = nfserr_jukebox; |
1912 | if (!conf) { | 1957 | if (!conf) { |
1913 | /* | 1958 | /* |
1914 | * RFC 3530 14.2.33 CASE 4: | 1959 | * RFC 3530 14.2.33 CASE 4: |
@@ -2337,15 +2382,6 @@ out: | |||
2337 | return ret; | 2382 | return ret; |
2338 | } | 2383 | } |
2339 | 2384 | ||
2340 | static inline void | ||
2341 | nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access) | ||
2342 | { | ||
2343 | if (share_access & NFS4_SHARE_ACCESS_WRITE) | ||
2344 | nfs4_file_put_access(fp, O_WRONLY); | ||
2345 | if (share_access & NFS4_SHARE_ACCESS_READ) | ||
2346 | nfs4_file_put_access(fp, O_RDONLY); | ||
2347 | } | ||
2348 | |||
2349 | static void nfsd_break_one_deleg(struct nfs4_delegation *dp) | 2385 | static void nfsd_break_one_deleg(struct nfs4_delegation *dp) |
2350 | { | 2386 | { |
2351 | /* We're assuming the state code never drops its reference | 2387 | /* We're assuming the state code never drops its reference |
@@ -2396,8 +2432,8 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) | |||
2396 | } | 2432 | } |
2397 | 2433 | ||
2398 | static const struct lock_manager_operations nfsd_lease_mng_ops = { | 2434 | static const struct lock_manager_operations nfsd_lease_mng_ops = { |
2399 | .fl_break = nfsd_break_deleg_cb, | 2435 | .lm_break = nfsd_break_deleg_cb, |
2400 | .fl_change = nfsd_change_deleg_cb, | 2436 | .lm_change = nfsd_change_deleg_cb, |
2401 | }; | 2437 | }; |
2402 | 2438 | ||
2403 | 2439 | ||
@@ -2454,7 +2490,7 @@ renew: | |||
2454 | if (open->op_stateowner == NULL) { | 2490 | if (open->op_stateowner == NULL) { |
2455 | sop = alloc_init_open_stateowner(strhashval, clp, open); | 2491 | sop = alloc_init_open_stateowner(strhashval, clp, open); |
2456 | if (sop == NULL) | 2492 | if (sop == NULL) |
2457 | return nfserr_resource; | 2493 | return nfserr_jukebox; |
2458 | open->op_stateowner = sop; | 2494 | open->op_stateowner = sop; |
2459 | } | 2495 | } |
2460 | list_del_init(&sop->so_close_lru); | 2496 | list_del_init(&sop->so_close_lru); |
@@ -2556,12 +2592,18 @@ static inline int nfs4_access_to_access(u32 nfs4_access) | |||
2556 | return flags; | 2592 | return flags; |
2557 | } | 2593 | } |
2558 | 2594 | ||
2559 | static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file | 2595 | static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, |
2560 | *fp, struct svc_fh *cur_fh, u32 nfs4_access) | 2596 | struct svc_fh *cur_fh, struct nfsd4_open *open) |
2561 | { | 2597 | { |
2562 | __be32 status; | 2598 | __be32 status; |
2563 | int oflag = nfs4_access_to_omode(nfs4_access); | 2599 | int oflag = nfs4_access_to_omode(open->op_share_access); |
2564 | int access = nfs4_access_to_access(nfs4_access); | 2600 | int access = nfs4_access_to_access(open->op_share_access); |
2601 | |||
2602 | /* CLAIM_DELEGATE_CUR is used in response to a broken lease; | ||
2603 | * allowing it to break the lease and return EAGAIN leaves the | ||
2604 | * client unable to make progress in returning the delegation */ | ||
2605 | if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) | ||
2606 | access |= NFSD_MAY_NOT_BREAK_LEASE; | ||
2565 | 2607 | ||
2566 | if (!fp->fi_fds[oflag]) { | 2608 | if (!fp->fi_fds[oflag]) { |
2567 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, | 2609 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, |
@@ -2584,9 +2626,9 @@ nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, | |||
2584 | 2626 | ||
2585 | stp = nfs4_alloc_stateid(); | 2627 | stp = nfs4_alloc_stateid(); |
2586 | if (stp == NULL) | 2628 | if (stp == NULL) |
2587 | return nfserr_resource; | 2629 | return nfserr_jukebox; |
2588 | 2630 | ||
2589 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open->op_share_access); | 2631 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); |
2590 | if (status) { | 2632 | if (status) { |
2591 | kmem_cache_free(stateid_slab, stp); | 2633 | kmem_cache_free(stateid_slab, stp); |
2592 | return status; | 2634 | return status; |
@@ -2619,14 +2661,14 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c | |||
2619 | 2661 | ||
2620 | new_access = !test_bit(op_share_access, &stp->st_access_bmap); | 2662 | new_access = !test_bit(op_share_access, &stp->st_access_bmap); |
2621 | if (new_access) { | 2663 | if (new_access) { |
2622 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, op_share_access); | 2664 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); |
2623 | if (status) | 2665 | if (status) |
2624 | return status; | 2666 | return status; |
2625 | } | 2667 | } |
2626 | status = nfsd4_truncate(rqstp, cur_fh, open); | 2668 | status = nfsd4_truncate(rqstp, cur_fh, open); |
2627 | if (status) { | 2669 | if (status) { |
2628 | if (new_access) { | 2670 | if (new_access) { |
2629 | int oflag = nfs4_access_to_omode(new_access); | 2671 | int oflag = nfs4_access_to_omode(op_share_access); |
2630 | nfs4_file_put_access(fp, oflag); | 2672 | nfs4_file_put_access(fp, oflag); |
2631 | } | 2673 | } |
2632 | return status; | 2674 | return status; |
@@ -2815,7 +2857,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
2815 | status = nfserr_bad_stateid; | 2857 | status = nfserr_bad_stateid; |
2816 | if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) | 2858 | if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) |
2817 | goto out; | 2859 | goto out; |
2818 | status = nfserr_resource; | 2860 | status = nfserr_jukebox; |
2819 | fp = alloc_init_file(ino); | 2861 | fp = alloc_init_file(ino); |
2820 | if (fp == NULL) | 2862 | if (fp == NULL) |
2821 | goto out; | 2863 | goto out; |
@@ -3137,6 +3179,37 @@ static int is_delegation_stateid(stateid_t *stateid) | |||
3137 | return stateid->si_fileid == 0; | 3179 | return stateid->si_fileid == 0; |
3138 | } | 3180 | } |
3139 | 3181 | ||
3182 | static int is_open_stateid(struct nfs4_stateid *stateid) | ||
3183 | { | ||
3184 | return stateid->st_openstp == NULL; | ||
3185 | } | ||
3186 | |||
3187 | __be32 nfs4_validate_stateid(stateid_t *stateid, int flags) | ||
3188 | { | ||
3189 | struct nfs4_stateid *stp = NULL; | ||
3190 | __be32 status = nfserr_stale_stateid; | ||
3191 | |||
3192 | if (STALE_STATEID(stateid)) | ||
3193 | goto out; | ||
3194 | |||
3195 | status = nfserr_expired; | ||
3196 | stp = search_for_stateid(stateid); | ||
3197 | if (!stp) | ||
3198 | goto out; | ||
3199 | status = nfserr_bad_stateid; | ||
3200 | |||
3201 | if (!stp->st_stateowner->so_confirmed) | ||
3202 | goto out; | ||
3203 | |||
3204 | status = check_stateid_generation(stateid, &stp->st_stateid, flags); | ||
3205 | if (status) | ||
3206 | goto out; | ||
3207 | |||
3208 | status = nfs_ok; | ||
3209 | out: | ||
3210 | return status; | ||
3211 | } | ||
3212 | |||
3140 | /* | 3213 | /* |
3141 | * Checks for stateid operations | 3214 | * Checks for stateid operations |
3142 | */ | 3215 | */ |
@@ -3216,6 +3289,81 @@ out: | |||
3216 | return status; | 3289 | return status; |
3217 | } | 3290 | } |
3218 | 3291 | ||
3292 | static __be32 | ||
3293 | nfsd4_free_delegation_stateid(stateid_t *stateid) | ||
3294 | { | ||
3295 | struct nfs4_delegation *dp = search_for_delegation(stateid); | ||
3296 | if (dp) | ||
3297 | return nfserr_locks_held; | ||
3298 | return nfserr_bad_stateid; | ||
3299 | } | ||
3300 | |||
3301 | static __be32 | ||
3302 | nfsd4_free_lock_stateid(struct nfs4_stateid *stp) | ||
3303 | { | ||
3304 | if (check_for_locks(stp->st_file, stp->st_stateowner)) | ||
3305 | return nfserr_locks_held; | ||
3306 | release_lock_stateid(stp); | ||
3307 | return nfs_ok; | ||
3308 | } | ||
3309 | |||
3310 | /* | ||
3311 | * Test if the stateid is valid | ||
3312 | */ | ||
3313 | __be32 | ||
3314 | nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
3315 | struct nfsd4_test_stateid *test_stateid) | ||
3316 | { | ||
3317 | test_stateid->ts_has_session = nfsd4_has_session(cstate); | ||
3318 | return nfs_ok; | ||
3319 | } | ||
3320 | |||
3321 | /* | ||
3322 | * Free a state id | ||
3323 | */ | ||
3324 | __be32 | ||
3325 | nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
3326 | struct nfsd4_free_stateid *free_stateid) | ||
3327 | { | ||
3328 | stateid_t *stateid = &free_stateid->fr_stateid; | ||
3329 | struct nfs4_stateid *stp; | ||
3330 | __be32 ret; | ||
3331 | |||
3332 | nfs4_lock_state(); | ||
3333 | if (is_delegation_stateid(stateid)) { | ||
3334 | ret = nfsd4_free_delegation_stateid(stateid); | ||
3335 | goto out; | ||
3336 | } | ||
3337 | |||
3338 | stp = search_for_stateid(stateid); | ||
3339 | if (!stp) { | ||
3340 | ret = nfserr_bad_stateid; | ||
3341 | goto out; | ||
3342 | } | ||
3343 | if (stateid->si_generation != 0) { | ||
3344 | if (stateid->si_generation < stp->st_stateid.si_generation) { | ||
3345 | ret = nfserr_old_stateid; | ||
3346 | goto out; | ||
3347 | } | ||
3348 | if (stateid->si_generation > stp->st_stateid.si_generation) { | ||
3349 | ret = nfserr_bad_stateid; | ||
3350 | goto out; | ||
3351 | } | ||
3352 | } | ||
3353 | |||
3354 | if (is_open_stateid(stp)) { | ||
3355 | ret = nfserr_locks_held; | ||
3356 | goto out; | ||
3357 | } else { | ||
3358 | ret = nfsd4_free_lock_stateid(stp); | ||
3359 | goto out; | ||
3360 | } | ||
3361 | |||
3362 | out: | ||
3363 | nfs4_unlock_state(); | ||
3364 | return ret; | ||
3365 | } | ||
3366 | |||
3219 | static inline int | 3367 | static inline int |
3220 | setlkflg (int type) | 3368 | setlkflg (int type) |
3221 | { | 3369 | { |
@@ -3384,18 +3532,16 @@ out: | |||
3384 | return status; | 3532 | return status; |
3385 | } | 3533 | } |
3386 | 3534 | ||
3387 | 3535 | static inline void nfs4_file_downgrade(struct nfs4_stateid *stp, unsigned int to_access) | |
3388 | /* | ||
3389 | * unset all bits in union bitmap (bmap) that | ||
3390 | * do not exist in share (from successful OPEN_DOWNGRADE) | ||
3391 | */ | ||
3392 | static void | ||
3393 | reset_union_bmap_access(unsigned long access, unsigned long *bmap) | ||
3394 | { | 3536 | { |
3395 | int i; | 3537 | int i; |
3538 | |||
3396 | for (i = 1; i < 4; i++) { | 3539 | for (i = 1; i < 4; i++) { |
3397 | if ((i & access) != i) | 3540 | if (test_bit(i, &stp->st_access_bmap) |
3398 | __clear_bit(i, bmap); | 3541 | && ((i & to_access) != i)) { |
3542 | nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(i)); | ||
3543 | __clear_bit(i, &stp->st_access_bmap); | ||
3544 | } | ||
3399 | } | 3545 | } |
3400 | } | 3546 | } |
3401 | 3547 | ||
@@ -3416,7 +3562,6 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3416 | { | 3562 | { |
3417 | __be32 status; | 3563 | __be32 status; |
3418 | struct nfs4_stateid *stp; | 3564 | struct nfs4_stateid *stp; |
3419 | unsigned int share_access; | ||
3420 | 3565 | ||
3421 | dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", | 3566 | dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", |
3422 | (int)cstate->current_fh.fh_dentry->d_name.len, | 3567 | (int)cstate->current_fh.fh_dentry->d_name.len, |
@@ -3425,6 +3570,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3425 | if (!access_valid(od->od_share_access, cstate->minorversion) | 3570 | if (!access_valid(od->od_share_access, cstate->minorversion) |
3426 | || !deny_valid(od->od_share_deny)) | 3571 | || !deny_valid(od->od_share_deny)) |
3427 | return nfserr_inval; | 3572 | return nfserr_inval; |
3573 | /* We don't yet support WANT bits: */ | ||
3574 | od->od_share_access &= NFS4_SHARE_ACCESS_MASK; | ||
3428 | 3575 | ||
3429 | nfs4_lock_state(); | 3576 | nfs4_lock_state(); |
3430 | if ((status = nfs4_preprocess_seqid_op(cstate, | 3577 | if ((status = nfs4_preprocess_seqid_op(cstate, |
@@ -3445,10 +3592,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3445 | stp->st_deny_bmap, od->od_share_deny); | 3592 | stp->st_deny_bmap, od->od_share_deny); |
3446 | goto out; | 3593 | goto out; |
3447 | } | 3594 | } |
3448 | set_access(&share_access, stp->st_access_bmap); | 3595 | nfs4_file_downgrade(stp, od->od_share_access); |
3449 | nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access); | ||
3450 | 3596 | ||
3451 | reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap); | ||
3452 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); | 3597 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); |
3453 | 3598 | ||
3454 | update_stateid(&stp->st_stateid); | 3599 | update_stateid(&stp->st_stateid); |
@@ -3594,6 +3739,14 @@ static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE]; | |||
3594 | static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; | 3739 | static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; |
3595 | static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE]; | 3740 | static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE]; |
3596 | 3741 | ||
3742 | static int | ||
3743 | same_stateid(stateid_t *id_one, stateid_t *id_two) | ||
3744 | { | ||
3745 | if (id_one->si_stateownerid != id_two->si_stateownerid) | ||
3746 | return 0; | ||
3747 | return id_one->si_fileid == id_two->si_fileid; | ||
3748 | } | ||
3749 | |||
3597 | static struct nfs4_stateid * | 3750 | static struct nfs4_stateid * |
3598 | find_stateid(stateid_t *stid, int flags) | 3751 | find_stateid(stateid_t *stid, int flags) |
3599 | { | 3752 | { |
@@ -3623,6 +3776,44 @@ find_stateid(stateid_t *stid, int flags) | |||
3623 | return NULL; | 3776 | return NULL; |
3624 | } | 3777 | } |
3625 | 3778 | ||
3779 | static struct nfs4_stateid * | ||
3780 | search_for_stateid(stateid_t *stid) | ||
3781 | { | ||
3782 | struct nfs4_stateid *local; | ||
3783 | unsigned int hashval = stateid_hashval(stid->si_stateownerid, stid->si_fileid); | ||
3784 | |||
3785 | list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) { | ||
3786 | if (same_stateid(&local->st_stateid, stid)) | ||
3787 | return local; | ||
3788 | } | ||
3789 | |||
3790 | list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) { | ||
3791 | if (same_stateid(&local->st_stateid, stid)) | ||
3792 | return local; | ||
3793 | } | ||
3794 | return NULL; | ||
3795 | } | ||
3796 | |||
3797 | static struct nfs4_delegation * | ||
3798 | search_for_delegation(stateid_t *stid) | ||
3799 | { | ||
3800 | struct nfs4_file *fp; | ||
3801 | struct nfs4_delegation *dp; | ||
3802 | struct list_head *pos; | ||
3803 | int i; | ||
3804 | |||
3805 | for (i = 0; i < FILE_HASH_SIZE; i++) { | ||
3806 | list_for_each_entry(fp, &file_hashtbl[i], fi_hash) { | ||
3807 | list_for_each(pos, &fp->fi_delegations) { | ||
3808 | dp = list_entry(pos, struct nfs4_delegation, dl_perfile); | ||
3809 | if (same_stateid(&dp->dl_stateid, stid)) | ||
3810 | return dp; | ||
3811 | } | ||
3812 | } | ||
3813 | } | ||
3814 | return NULL; | ||
3815 | } | ||
3816 | |||
3626 | static struct nfs4_delegation * | 3817 | static struct nfs4_delegation * |
3627 | find_delegation_stateid(struct inode *ino, stateid_t *stid) | 3818 | find_delegation_stateid(struct inode *ino, stateid_t *stid) |
3628 | { | 3819 | { |
@@ -3854,7 +4045,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3854 | /* XXX: Do we need to check for duplicate stateowners on | 4045 | /* XXX: Do we need to check for duplicate stateowners on |
3855 | * the same file, or should they just be allowed (and | 4046 | * the same file, or should they just be allowed (and |
3856 | * create new stateids)? */ | 4047 | * create new stateids)? */ |
3857 | status = nfserr_resource; | 4048 | status = nfserr_jukebox; |
3858 | lock_sop = alloc_init_lock_stateowner(strhashval, | 4049 | lock_sop = alloc_init_lock_stateowner(strhashval, |
3859 | open_sop->so_client, open_stp, lock); | 4050 | open_sop->so_client, open_stp, lock); |
3860 | if (lock_sop == NULL) | 4051 | if (lock_sop == NULL) |
@@ -3938,9 +4129,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3938 | case (EDEADLK): | 4129 | case (EDEADLK): |
3939 | status = nfserr_deadlock; | 4130 | status = nfserr_deadlock; |
3940 | break; | 4131 | break; |
3941 | default: | 4132 | default: |
3942 | dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); | 4133 | dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); |
3943 | status = nfserr_resource; | 4134 | status = nfserrno(err); |
3944 | break; | 4135 | break; |
3945 | } | 4136 | } |
3946 | out: | 4137 | out: |