diff options
| -rw-r--r-- | fs/nfsd/nfs4state.c | 49 | ||||
| -rw-r--r-- | include/linux/nfsd/state.h | 5 |
2 files changed, 38 insertions, 16 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 59b214f01b6d..b83f8fb441e1 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -1160,6 +1160,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open * | |||
| 1160 | stp->st_deny_bmap = 0; | 1160 | stp->st_deny_bmap = 0; |
| 1161 | __set_bit(open->op_share_access, &stp->st_access_bmap); | 1161 | __set_bit(open->op_share_access, &stp->st_access_bmap); |
| 1162 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 1162 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); |
| 1163 | stp->st_openstp = NULL; | ||
| 1163 | } | 1164 | } |
| 1164 | 1165 | ||
| 1165 | static void | 1166 | static void |
| @@ -2158,12 +2159,18 @@ out: | |||
| 2158 | return status; | 2159 | return status; |
| 2159 | } | 2160 | } |
| 2160 | 2161 | ||
| 2162 | static inline int | ||
| 2163 | setlkflg (int type) | ||
| 2164 | { | ||
| 2165 | return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? | ||
| 2166 | RD_STATE : WR_STATE; | ||
| 2167 | } | ||
| 2161 | 2168 | ||
| 2162 | /* | 2169 | /* |
| 2163 | * Checks for sequence id mutating operations. | 2170 | * Checks for sequence id mutating operations. |
| 2164 | */ | 2171 | */ |
| 2165 | static int | 2172 | static int |
| 2166 | nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid) | 2173 | nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock) |
| 2167 | { | 2174 | { |
| 2168 | struct nfs4_stateid *stp; | 2175 | struct nfs4_stateid *stp; |
| 2169 | struct nfs4_stateowner *sop; | 2176 | struct nfs4_stateowner *sop; |
| @@ -2201,21 +2208,31 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
| 2201 | goto check_replay; | 2208 | goto check_replay; |
| 2202 | } | 2209 | } |
| 2203 | 2210 | ||
| 2204 | /* for new lock stateowners: | 2211 | if (lock) { |
| 2205 | * check that the lock->v.new.open_stateid | ||
| 2206 | * refers to an open stateowner | ||
| 2207 | * | ||
| 2208 | * check that the lockclid (nfs4_lock->v.new.clientid) is the same | ||
| 2209 | * as the open_stateid->st_stateowner->so_client->clientid | ||
| 2210 | */ | ||
| 2211 | if (lockclid) { | ||
| 2212 | struct nfs4_stateowner *sop = stp->st_stateowner; | 2212 | struct nfs4_stateowner *sop = stp->st_stateowner; |
| 2213 | clientid_t *lockclid = &lock->v.new.clientid; | ||
| 2213 | struct nfs4_client *clp = sop->so_client; | 2214 | struct nfs4_client *clp = sop->so_client; |
| 2215 | int lkflg = 0; | ||
| 2216 | int status; | ||
| 2217 | |||
| 2218 | lkflg = setlkflg(lock->lk_type); | ||
| 2219 | |||
| 2220 | if (lock->lk_is_new) { | ||
| 2221 | if (!sop->so_is_open_owner) | ||
| 2222 | return nfserr_bad_stateid; | ||
| 2223 | if (!cmp_clid(&clp->cl_clientid, lockclid)) | ||
| 2224 | return nfserr_bad_stateid; | ||
| 2225 | /* stp is the open stateid */ | ||
| 2226 | status = nfs4_check_openmode(stp, lkflg); | ||
| 2227 | if (status) | ||
| 2228 | return status; | ||
| 2229 | } else { | ||
| 2230 | /* stp is the lock stateid */ | ||
| 2231 | status = nfs4_check_openmode(stp->st_openstp, lkflg); | ||
| 2232 | if (status) | ||
| 2233 | return status; | ||
| 2234 | } | ||
| 2214 | 2235 | ||
| 2215 | if (!sop->so_is_open_owner) | ||
| 2216 | return nfserr_bad_stateid; | ||
| 2217 | if (!cmp_clid(&clp->cl_clientid, lockclid)) | ||
| 2218 | return nfserr_bad_stateid; | ||
| 2219 | } | 2236 | } |
| 2220 | 2237 | ||
| 2221 | if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) { | 2238 | if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) { |
| @@ -2642,6 +2659,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
| 2642 | stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */ | 2659 | stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */ |
| 2643 | stp->st_access_bmap = open_stp->st_access_bmap; | 2660 | stp->st_access_bmap = open_stp->st_access_bmap; |
| 2644 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 2661 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
| 2662 | stp->st_openstp = open_stp; | ||
| 2645 | 2663 | ||
| 2646 | out: | 2664 | out: |
| 2647 | return stp; | 2665 | return stp; |
| @@ -2697,8 +2715,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
| 2697 | lock->lk_new_open_seqid, | 2715 | lock->lk_new_open_seqid, |
| 2698 | &lock->lk_new_open_stateid, | 2716 | &lock->lk_new_open_stateid, |
| 2699 | CHECK_FH | OPEN_STATE, | 2717 | CHECK_FH | OPEN_STATE, |
| 2700 | &open_sop, &open_stp, | 2718 | &open_sop, &open_stp, lock); |
| 2701 | &lock->v.new.clientid); | ||
| 2702 | if (status) | 2719 | if (status) |
| 2703 | goto out; | 2720 | goto out; |
| 2704 | /* create lockowner and lock stateid */ | 2721 | /* create lockowner and lock stateid */ |
| @@ -2726,7 +2743,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
| 2726 | lock->lk_old_lock_seqid, | 2743 | lock->lk_old_lock_seqid, |
| 2727 | &lock->lk_old_lock_stateid, | 2744 | &lock->lk_old_lock_stateid, |
| 2728 | CHECK_FH | LOCK_STATE, | 2745 | CHECK_FH | LOCK_STATE, |
| 2729 | &lock->lk_stateowner, &lock_stp, NULL); | 2746 | &lock->lk_stateowner, &lock_stp, lock); |
| 2730 | if (status) | 2747 | if (status) |
| 2731 | goto out; | 2748 | goto out; |
| 2732 | } | 2749 | } |
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 2d19431f47ea..8bf23cf8b603 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h | |||
| @@ -237,6 +237,10 @@ struct nfs4_file { | |||
| 237 | * st_perlockowner: (open stateid) list of lock nfs4_stateowners | 237 | * st_perlockowner: (open stateid) list of lock nfs4_stateowners |
| 238 | * st_access_bmap: used only for open stateid | 238 | * st_access_bmap: used only for open stateid |
| 239 | * st_deny_bmap: used only for open stateid | 239 | * st_deny_bmap: used only for open stateid |
| 240 | * st_openstp: open stateid lock stateid was derived from | ||
| 241 | * | ||
| 242 | * XXX: open stateids and lock stateids have diverged sufficiently that | ||
| 243 | * we should consider defining separate structs for the two cases. | ||
| 240 | */ | 244 | */ |
| 241 | 245 | ||
| 242 | struct nfs4_stateid { | 246 | struct nfs4_stateid { |
| @@ -250,6 +254,7 @@ struct nfs4_stateid { | |||
| 250 | struct file * st_vfs_file; | 254 | struct file * st_vfs_file; |
| 251 | unsigned long st_access_bmap; | 255 | unsigned long st_access_bmap; |
| 252 | unsigned long st_deny_bmap; | 256 | unsigned long st_deny_bmap; |
| 257 | struct nfs4_stateid * st_openstp; | ||
| 253 | }; | 258 | }; |
| 254 | 259 | ||
| 255 | /* flags for preprocess_seqid_op() */ | 260 | /* flags for preprocess_seqid_op() */ |
