diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 381 |
1 files changed, 235 insertions, 146 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 4a2734758778..2e7357104cfd 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -51,7 +51,6 @@ static time_t boot_time; | |||
51 | static u32 current_ownerid = 1; | 51 | static u32 current_ownerid = 1; |
52 | static u32 current_fileid = 1; | 52 | static u32 current_fileid = 1; |
53 | static u32 current_delegid = 1; | 53 | static u32 current_delegid = 1; |
54 | static u32 nfs4_init; | ||
55 | static stateid_t zerostateid; /* bits all 0 */ | 54 | static stateid_t zerostateid; /* bits all 0 */ |
56 | static stateid_t onestateid; /* bits all 1 */ | 55 | static stateid_t onestateid; /* bits all 1 */ |
57 | static u64 current_sessionid = 1; | 56 | static u64 current_sessionid = 1; |
@@ -163,6 +162,46 @@ static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; | |||
163 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; | 162 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; |
164 | static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; | 163 | static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; |
165 | 164 | ||
165 | static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag) | ||
166 | { | ||
167 | BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR])); | ||
168 | atomic_inc(&fp->fi_access[oflag]); | ||
169 | } | ||
170 | |||
171 | static void nfs4_file_get_access(struct nfs4_file *fp, int oflag) | ||
172 | { | ||
173 | if (oflag == O_RDWR) { | ||
174 | __nfs4_file_get_access(fp, O_RDONLY); | ||
175 | __nfs4_file_get_access(fp, O_WRONLY); | ||
176 | } else | ||
177 | __nfs4_file_get_access(fp, oflag); | ||
178 | } | ||
179 | |||
180 | static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag) | ||
181 | { | ||
182 | if (fp->fi_fds[oflag]) { | ||
183 | fput(fp->fi_fds[oflag]); | ||
184 | fp->fi_fds[oflag] = NULL; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) | ||
189 | { | ||
190 | if (atomic_dec_and_test(&fp->fi_access[oflag])) { | ||
191 | nfs4_file_put_fd(fp, O_RDWR); | ||
192 | nfs4_file_put_fd(fp, oflag); | ||
193 | } | ||
194 | } | ||
195 | |||
196 | static void nfs4_file_put_access(struct nfs4_file *fp, int oflag) | ||
197 | { | ||
198 | if (oflag == O_RDWR) { | ||
199 | __nfs4_file_put_access(fp, O_RDONLY); | ||
200 | __nfs4_file_put_access(fp, O_WRONLY); | ||
201 | } else | ||
202 | __nfs4_file_put_access(fp, oflag); | ||
203 | } | ||
204 | |||
166 | static struct nfs4_delegation * | 205 | static struct nfs4_delegation * |
167 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) | 206 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) |
168 | { | 207 | { |
@@ -171,6 +210,13 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
171 | struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn; | 210 | struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn; |
172 | 211 | ||
173 | dprintk("NFSD alloc_init_deleg\n"); | 212 | dprintk("NFSD alloc_init_deleg\n"); |
213 | /* | ||
214 | * Major work on the lease subsystem (for example, to support | ||
215 | * calbacks on stat) will be required before we can support | ||
216 | * write delegations properly. | ||
217 | */ | ||
218 | if (type != NFS4_OPEN_DELEGATE_READ) | ||
219 | return NULL; | ||
174 | if (fp->fi_had_conflict) | 220 | if (fp->fi_had_conflict) |
175 | return NULL; | 221 | return NULL; |
176 | if (num_delegations > max_delegations) | 222 | if (num_delegations > max_delegations) |
@@ -185,9 +231,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
185 | dp->dl_client = clp; | 231 | dp->dl_client = clp; |
186 | get_nfs4_file(fp); | 232 | get_nfs4_file(fp); |
187 | dp->dl_file = fp; | 233 | dp->dl_file = fp; |
234 | nfs4_file_get_access(fp, O_RDONLY); | ||
188 | dp->dl_flock = NULL; | 235 | dp->dl_flock = NULL; |
189 | get_file(stp->st_vfs_file); | ||
190 | dp->dl_vfs_file = stp->st_vfs_file; | ||
191 | dp->dl_type = type; | 236 | dp->dl_type = type; |
192 | dp->dl_ident = cb->cb_ident; | 237 | dp->dl_ident = cb->cb_ident; |
193 | dp->dl_stateid.si_boot = boot_time; | 238 | dp->dl_stateid.si_boot = boot_time; |
@@ -222,15 +267,12 @@ nfs4_put_delegation(struct nfs4_delegation *dp) | |||
222 | static void | 267 | static void |
223 | nfs4_close_delegation(struct nfs4_delegation *dp) | 268 | nfs4_close_delegation(struct nfs4_delegation *dp) |
224 | { | 269 | { |
225 | struct file *filp = dp->dl_vfs_file; | 270 | struct file *filp = find_readable_file(dp->dl_file); |
226 | 271 | ||
227 | dprintk("NFSD: close_delegation dp %p\n",dp); | 272 | dprintk("NFSD: close_delegation dp %p\n",dp); |
228 | dp->dl_vfs_file = NULL; | ||
229 | /* The following nfsd_close may not actually close the file, | ||
230 | * but we want to remove the lease in any case. */ | ||
231 | if (dp->dl_flock) | 273 | if (dp->dl_flock) |
232 | vfs_setlease(filp, F_UNLCK, &dp->dl_flock); | 274 | vfs_setlease(filp, F_UNLCK, &dp->dl_flock); |
233 | nfsd_close(filp); | 275 | nfs4_file_put_access(dp->dl_file, O_RDONLY); |
234 | } | 276 | } |
235 | 277 | ||
236 | /* Called under the state lock. */ | 278 | /* Called under the state lock. */ |
@@ -302,8 +344,12 @@ static void free_generic_stateid(struct nfs4_stateid *stp) | |||
302 | 344 | ||
303 | static void release_lock_stateid(struct nfs4_stateid *stp) | 345 | static void release_lock_stateid(struct nfs4_stateid *stp) |
304 | { | 346 | { |
347 | struct file *file; | ||
348 | |||
305 | unhash_generic_stateid(stp); | 349 | unhash_generic_stateid(stp); |
306 | locks_remove_posix(stp->st_vfs_file, (fl_owner_t)stp->st_stateowner); | 350 | file = find_any_file(stp->st_file); |
351 | if (file) | ||
352 | locks_remove_posix(file, (fl_owner_t)stp->st_stateowner); | ||
307 | free_generic_stateid(stp); | 353 | free_generic_stateid(stp); |
308 | } | 354 | } |
309 | 355 | ||
@@ -341,11 +387,85 @@ release_stateid_lockowners(struct nfs4_stateid *open_stp) | |||
341 | } | 387 | } |
342 | } | 388 | } |
343 | 389 | ||
390 | /* | ||
391 | * We store the NONE, READ, WRITE, and BOTH bits separately in the | ||
392 | * st_{access,deny}_bmap field of the stateid, in order to track not | ||
393 | * only what share bits are currently in force, but also what | ||
394 | * combinations of share bits previous opens have used. This allows us | ||
395 | * to enforce the recommendation of rfc 3530 14.2.19 that the server | ||
396 | * return an error if the client attempt to downgrade to a combination | ||
397 | * of share bits not explicable by closing some of its previous opens. | ||
398 | * | ||
399 | * XXX: This enforcement is actually incomplete, since we don't keep | ||
400 | * track of access/deny bit combinations; so, e.g., we allow: | ||
401 | * | ||
402 | * OPEN allow read, deny write | ||
403 | * OPEN allow both, deny none | ||
404 | * DOWNGRADE allow read, deny none | ||
405 | * | ||
406 | * which we should reject. | ||
407 | */ | ||
408 | static void | ||
409 | set_access(unsigned int *access, unsigned long bmap) { | ||
410 | int i; | ||
411 | |||
412 | *access = 0; | ||
413 | for (i = 1; i < 4; i++) { | ||
414 | if (test_bit(i, &bmap)) | ||
415 | *access |= i; | ||
416 | } | ||
417 | } | ||
418 | |||
419 | static void | ||
420 | set_deny(unsigned int *deny, unsigned long bmap) { | ||
421 | int i; | ||
422 | |||
423 | *deny = 0; | ||
424 | for (i = 0; i < 4; i++) { | ||
425 | if (test_bit(i, &bmap)) | ||
426 | *deny |= i ; | ||
427 | } | ||
428 | } | ||
429 | |||
430 | static int | ||
431 | test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { | ||
432 | unsigned int access, deny; | ||
433 | |||
434 | set_access(&access, stp->st_access_bmap); | ||
435 | set_deny(&deny, stp->st_deny_bmap); | ||
436 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) | ||
437 | return 0; | ||
438 | return 1; | ||
439 | } | ||
440 | |||
441 | static int nfs4_access_to_omode(u32 access) | ||
442 | { | ||
443 | switch (access) { | ||
444 | case NFS4_SHARE_ACCESS_READ: | ||
445 | return O_RDONLY; | ||
446 | case NFS4_SHARE_ACCESS_WRITE: | ||
447 | return O_WRONLY; | ||
448 | case NFS4_SHARE_ACCESS_BOTH: | ||
449 | return O_RDWR; | ||
450 | } | ||
451 | BUG(); | ||
452 | } | ||
453 | |||
454 | static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp) | ||
455 | { | ||
456 | unsigned int access; | ||
457 | |||
458 | set_access(&access, stp->st_access_bmap); | ||
459 | return nfs4_access_to_omode(access); | ||
460 | } | ||
461 | |||
344 | static void release_open_stateid(struct nfs4_stateid *stp) | 462 | static void release_open_stateid(struct nfs4_stateid *stp) |
345 | { | 463 | { |
464 | int oflag = nfs4_access_bmap_to_omode(stp); | ||
465 | |||
346 | unhash_generic_stateid(stp); | 466 | unhash_generic_stateid(stp); |
347 | release_stateid_lockowners(stp); | 467 | release_stateid_lockowners(stp); |
348 | nfsd_close(stp->st_vfs_file); | 468 | nfs4_file_put_access(stp->st_file, oflag); |
349 | free_generic_stateid(stp); | 469 | free_generic_stateid(stp); |
350 | } | 470 | } |
351 | 471 | ||
@@ -457,7 +577,7 @@ static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan) | |||
457 | spin_unlock(&nfsd_drc_lock); | 577 | spin_unlock(&nfsd_drc_lock); |
458 | 578 | ||
459 | if (fchan->maxreqs == 0) | 579 | if (fchan->maxreqs == 0) |
460 | return nfserr_serverfault; | 580 | return nfserr_jukebox; |
461 | 581 | ||
462 | fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ; | 582 | fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ; |
463 | return 0; | 583 | return 0; |
@@ -542,7 +662,7 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | |||
542 | BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot) | 662 | BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot) |
543 | + sizeof(struct nfsd4_session) > PAGE_SIZE); | 663 | + sizeof(struct nfsd4_session) > PAGE_SIZE); |
544 | 664 | ||
545 | status = nfserr_serverfault; | 665 | status = nfserr_jukebox; |
546 | /* allocate struct nfsd4_session and slot table pointers in one piece */ | 666 | /* allocate struct nfsd4_session and slot table pointers in one piece */ |
547 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *); | 667 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *); |
548 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); | 668 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); |
@@ -591,10 +711,8 @@ find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) | |||
591 | 711 | ||
592 | dump_sessionid(__func__, sessionid); | 712 | dump_sessionid(__func__, sessionid); |
593 | idx = hash_sessionid(sessionid); | 713 | idx = hash_sessionid(sessionid); |
594 | dprintk("%s: idx is %d\n", __func__, idx); | ||
595 | /* Search in the appropriate list */ | 714 | /* Search in the appropriate list */ |
596 | list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) { | 715 | list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) { |
597 | dump_sessionid("list traversal", &elem->se_sessionid); | ||
598 | if (!memcmp(elem->se_sessionid.data, sessionid->data, | 716 | if (!memcmp(elem->se_sessionid.data, sessionid->data, |
599 | NFS4_MAX_SESSIONID_LEN)) { | 717 | NFS4_MAX_SESSIONID_LEN)) { |
600 | return elem; | 718 | return elem; |
@@ -714,7 +832,6 @@ release_session_client(struct nfsd4_session *session) | |||
714 | } else | 832 | } else |
715 | renew_client_locked(clp); | 833 | renew_client_locked(clp); |
716 | spin_unlock(&client_lock); | 834 | spin_unlock(&client_lock); |
717 | nfsd4_put_session(session); | ||
718 | } | 835 | } |
719 | 836 | ||
720 | /* must be called under the client_lock */ | 837 | /* must be called under the client_lock */ |
@@ -1220,7 +1337,7 @@ out_new: | |||
1220 | /* Normal case */ | 1337 | /* Normal case */ |
1221 | new = create_client(exid->clname, dname, rqstp, &verf); | 1338 | new = create_client(exid->clname, dname, rqstp, &verf); |
1222 | if (new == NULL) { | 1339 | if (new == NULL) { |
1223 | status = nfserr_serverfault; | 1340 | status = nfserr_jukebox; |
1224 | goto out; | 1341 | goto out; |
1225 | } | 1342 | } |
1226 | 1343 | ||
@@ -1760,6 +1877,8 @@ alloc_init_file(struct inode *ino) | |||
1760 | fp->fi_inode = igrab(ino); | 1877 | fp->fi_inode = igrab(ino); |
1761 | fp->fi_id = current_fileid++; | 1878 | fp->fi_id = current_fileid++; |
1762 | fp->fi_had_conflict = false; | 1879 | fp->fi_had_conflict = false; |
1880 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); | ||
1881 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); | ||
1763 | spin_lock(&recall_lock); | 1882 | spin_lock(&recall_lock); |
1764 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | 1883 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); |
1765 | spin_unlock(&recall_lock); | 1884 | spin_unlock(&recall_lock); |
@@ -1971,57 +2090,6 @@ static inline int deny_valid(u32 x) | |||
1971 | } | 2090 | } |
1972 | 2091 | ||
1973 | /* | 2092 | /* |
1974 | * We store the NONE, READ, WRITE, and BOTH bits separately in the | ||
1975 | * st_{access,deny}_bmap field of the stateid, in order to track not | ||
1976 | * only what share bits are currently in force, but also what | ||
1977 | * combinations of share bits previous opens have used. This allows us | ||
1978 | * to enforce the recommendation of rfc 3530 14.2.19 that the server | ||
1979 | * return an error if the client attempt to downgrade to a combination | ||
1980 | * of share bits not explicable by closing some of its previous opens. | ||
1981 | * | ||
1982 | * XXX: This enforcement is actually incomplete, since we don't keep | ||
1983 | * track of access/deny bit combinations; so, e.g., we allow: | ||
1984 | * | ||
1985 | * OPEN allow read, deny write | ||
1986 | * OPEN allow both, deny none | ||
1987 | * DOWNGRADE allow read, deny none | ||
1988 | * | ||
1989 | * which we should reject. | ||
1990 | */ | ||
1991 | static void | ||
1992 | set_access(unsigned int *access, unsigned long bmap) { | ||
1993 | int i; | ||
1994 | |||
1995 | *access = 0; | ||
1996 | for (i = 1; i < 4; i++) { | ||
1997 | if (test_bit(i, &bmap)) | ||
1998 | *access |= i; | ||
1999 | } | ||
2000 | } | ||
2001 | |||
2002 | static void | ||
2003 | set_deny(unsigned int *deny, unsigned long bmap) { | ||
2004 | int i; | ||
2005 | |||
2006 | *deny = 0; | ||
2007 | for (i = 0; i < 4; i++) { | ||
2008 | if (test_bit(i, &bmap)) | ||
2009 | *deny |= i ; | ||
2010 | } | ||
2011 | } | ||
2012 | |||
2013 | static int | ||
2014 | test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { | ||
2015 | unsigned int access, deny; | ||
2016 | |||
2017 | set_access(&access, stp->st_access_bmap); | ||
2018 | set_deny(&deny, stp->st_deny_bmap); | ||
2019 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) | ||
2020 | return 0; | ||
2021 | return 1; | ||
2022 | } | ||
2023 | |||
2024 | /* | ||
2025 | * Called to check deny when READ with all zero stateid or | 2093 | * Called to check deny when READ with all zero stateid or |
2026 | * WRITE with all zero or all one stateid | 2094 | * WRITE with all zero or all one stateid |
2027 | */ | 2095 | */ |
@@ -2052,14 +2120,12 @@ out: | |||
2052 | } | 2120 | } |
2053 | 2121 | ||
2054 | static inline void | 2122 | static inline void |
2055 | nfs4_file_downgrade(struct file *filp, unsigned int share_access) | 2123 | nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access) |
2056 | { | 2124 | { |
2057 | if (share_access & NFS4_SHARE_ACCESS_WRITE) { | 2125 | if (share_access & NFS4_SHARE_ACCESS_WRITE) |
2058 | drop_file_write_access(filp); | 2126 | nfs4_file_put_access(fp, O_WRONLY); |
2059 | spin_lock(&filp->f_lock); | 2127 | if (share_access & NFS4_SHARE_ACCESS_READ) |
2060 | filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE; | 2128 | nfs4_file_put_access(fp, O_RDONLY); |
2061 | spin_unlock(&filp->f_lock); | ||
2062 | } | ||
2063 | } | 2129 | } |
2064 | 2130 | ||
2065 | /* | 2131 | /* |
@@ -2255,6 +2321,13 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid) | |||
2255 | return NULL; | 2321 | return NULL; |
2256 | } | 2322 | } |
2257 | 2323 | ||
2324 | int share_access_to_flags(u32 share_access) | ||
2325 | { | ||
2326 | share_access &= ~NFS4_SHARE_WANT_MASK; | ||
2327 | |||
2328 | return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; | ||
2329 | } | ||
2330 | |||
2258 | static __be32 | 2331 | static __be32 |
2259 | nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, | 2332 | nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, |
2260 | struct nfs4_delegation **dp) | 2333 | struct nfs4_delegation **dp) |
@@ -2265,8 +2338,7 @@ nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, | |||
2265 | *dp = find_delegation_file(fp, &open->op_delegate_stateid); | 2338 | *dp = find_delegation_file(fp, &open->op_delegate_stateid); |
2266 | if (*dp == NULL) | 2339 | if (*dp == NULL) |
2267 | goto out; | 2340 | goto out; |
2268 | flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ? | 2341 | flags = share_access_to_flags(open->op_share_access); |
2269 | RD_STATE : WR_STATE; | ||
2270 | status = nfs4_check_delegmode(*dp, flags); | 2342 | status = nfs4_check_delegmode(*dp, flags); |
2271 | if (status) | 2343 | if (status) |
2272 | *dp = NULL; | 2344 | *dp = NULL; |
@@ -2308,30 +2380,53 @@ nfs4_alloc_stateid(void) | |||
2308 | return kmem_cache_alloc(stateid_slab, GFP_KERNEL); | 2380 | return kmem_cache_alloc(stateid_slab, GFP_KERNEL); |
2309 | } | 2381 | } |
2310 | 2382 | ||
2383 | static inline int nfs4_access_to_access(u32 nfs4_access) | ||
2384 | { | ||
2385 | int flags = 0; | ||
2386 | |||
2387 | if (nfs4_access & NFS4_SHARE_ACCESS_READ) | ||
2388 | flags |= NFSD_MAY_READ; | ||
2389 | if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) | ||
2390 | flags |= NFSD_MAY_WRITE; | ||
2391 | return flags; | ||
2392 | } | ||
2393 | |||
2394 | static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file | ||
2395 | *fp, struct svc_fh *cur_fh, u32 nfs4_access) | ||
2396 | { | ||
2397 | __be32 status; | ||
2398 | int oflag = nfs4_access_to_omode(nfs4_access); | ||
2399 | int access = nfs4_access_to_access(nfs4_access); | ||
2400 | |||
2401 | if (!fp->fi_fds[oflag]) { | ||
2402 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, | ||
2403 | &fp->fi_fds[oflag]); | ||
2404 | if (status == nfserr_dropit) | ||
2405 | status = nfserr_jukebox; | ||
2406 | if (status) | ||
2407 | return status; | ||
2408 | } | ||
2409 | nfs4_file_get_access(fp, oflag); | ||
2410 | |||
2411 | return nfs_ok; | ||
2412 | } | ||
2413 | |||
2311 | static __be32 | 2414 | static __be32 |
2312 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, | 2415 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, |
2313 | struct nfs4_delegation *dp, | 2416 | struct nfs4_file *fp, struct svc_fh *cur_fh, |
2314 | struct svc_fh *cur_fh, int flags) | 2417 | struct nfsd4_open *open) |
2315 | { | 2418 | { |
2316 | struct nfs4_stateid *stp; | 2419 | struct nfs4_stateid *stp; |
2420 | __be32 status; | ||
2317 | 2421 | ||
2318 | stp = nfs4_alloc_stateid(); | 2422 | stp = nfs4_alloc_stateid(); |
2319 | if (stp == NULL) | 2423 | if (stp == NULL) |
2320 | return nfserr_resource; | 2424 | return nfserr_resource; |
2321 | 2425 | ||
2322 | if (dp) { | 2426 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open->op_share_access); |
2323 | get_file(dp->dl_vfs_file); | 2427 | if (status) { |
2324 | stp->st_vfs_file = dp->dl_vfs_file; | 2428 | kmem_cache_free(stateid_slab, stp); |
2325 | } else { | 2429 | return status; |
2326 | __be32 status; | ||
2327 | status = nfsd_open(rqstp, cur_fh, S_IFREG, flags, | ||
2328 | &stp->st_vfs_file); | ||
2329 | if (status) { | ||
2330 | if (status == nfserr_dropit) | ||
2331 | status = nfserr_jukebox; | ||
2332 | kmem_cache_free(stateid_slab, stp); | ||
2333 | return status; | ||
2334 | } | ||
2335 | } | 2430 | } |
2336 | *stpp = stp; | 2431 | *stpp = stp; |
2337 | return 0; | 2432 | return 0; |
@@ -2353,35 +2448,30 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, | |||
2353 | } | 2448 | } |
2354 | 2449 | ||
2355 | static __be32 | 2450 | static __be32 |
2356 | nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) | 2451 | nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) |
2357 | { | 2452 | { |
2358 | struct file *filp = stp->st_vfs_file; | 2453 | u32 op_share_access, new_access; |
2359 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
2360 | unsigned int share_access, new_writer; | ||
2361 | __be32 status; | 2454 | __be32 status; |
2362 | 2455 | ||
2363 | set_access(&share_access, stp->st_access_bmap); | 2456 | set_access(&new_access, stp->st_access_bmap); |
2364 | new_writer = (~share_access) & open->op_share_access | 2457 | new_access = (~new_access) & open->op_share_access & ~NFS4_SHARE_WANT_MASK; |
2365 | & NFS4_SHARE_ACCESS_WRITE; | 2458 | |
2366 | 2459 | if (new_access) { | |
2367 | if (new_writer) { | 2460 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, new_access); |
2368 | int err = get_write_access(inode); | 2461 | if (status) |
2369 | if (err) | 2462 | return status; |
2370 | return nfserrno(err); | ||
2371 | err = mnt_want_write(cur_fh->fh_export->ex_path.mnt); | ||
2372 | if (err) | ||
2373 | return nfserrno(err); | ||
2374 | file_take_write(filp); | ||
2375 | } | 2463 | } |
2376 | status = nfsd4_truncate(rqstp, cur_fh, open); | 2464 | status = nfsd4_truncate(rqstp, cur_fh, open); |
2377 | if (status) { | 2465 | if (status) { |
2378 | if (new_writer) | 2466 | if (new_access) { |
2379 | put_write_access(inode); | 2467 | int oflag = nfs4_access_to_omode(new_access); |
2468 | nfs4_file_put_access(fp, oflag); | ||
2469 | } | ||
2380 | return status; | 2470 | return status; |
2381 | } | 2471 | } |
2382 | /* remember the open */ | 2472 | /* remember the open */ |
2383 | filp->f_mode |= open->op_share_access; | 2473 | op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK; |
2384 | __set_bit(open->op_share_access, &stp->st_access_bmap); | 2474 | __set_bit(op_share_access, &stp->st_access_bmap); |
2385 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 2475 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); |
2386 | 2476 | ||
2387 | return nfs_ok; | 2477 | return nfs_ok; |
@@ -2444,13 +2534,14 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2444 | fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; | 2534 | fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; |
2445 | fl.fl_end = OFFSET_MAX; | 2535 | fl.fl_end = OFFSET_MAX; |
2446 | fl.fl_owner = (fl_owner_t)dp; | 2536 | fl.fl_owner = (fl_owner_t)dp; |
2447 | fl.fl_file = stp->st_vfs_file; | 2537 | fl.fl_file = find_readable_file(stp->st_file); |
2538 | BUG_ON(!fl.fl_file); | ||
2448 | fl.fl_pid = current->tgid; | 2539 | fl.fl_pid = current->tgid; |
2449 | 2540 | ||
2450 | /* vfs_setlease checks to see if delegation should be handed out. | 2541 | /* vfs_setlease checks to see if delegation should be handed out. |
2451 | * the lock_manager callbacks fl_mylease and fl_change are used | 2542 | * the lock_manager callbacks fl_mylease and fl_change are used |
2452 | */ | 2543 | */ |
2453 | if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) { | 2544 | if ((status = vfs_setlease(fl.fl_file, fl.fl_type, &flp))) { |
2454 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); | 2545 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); |
2455 | unhash_delegation(dp); | 2546 | unhash_delegation(dp); |
2456 | flag = NFS4_OPEN_DELEGATE_NONE; | 2547 | flag = NFS4_OPEN_DELEGATE_NONE; |
@@ -2514,18 +2605,12 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
2514 | */ | 2605 | */ |
2515 | if (stp) { | 2606 | if (stp) { |
2516 | /* Stateid was found, this is an OPEN upgrade */ | 2607 | /* Stateid was found, this is an OPEN upgrade */ |
2517 | status = nfs4_upgrade_open(rqstp, current_fh, stp, open); | 2608 | status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); |
2518 | if (status) | 2609 | if (status) |
2519 | goto out; | 2610 | goto out; |
2520 | update_stateid(&stp->st_stateid); | 2611 | update_stateid(&stp->st_stateid); |
2521 | } else { | 2612 | } else { |
2522 | /* Stateid was not found, this is a new OPEN */ | 2613 | status = nfs4_new_open(rqstp, &stp, fp, current_fh, open); |
2523 | int flags = 0; | ||
2524 | if (open->op_share_access & NFS4_SHARE_ACCESS_READ) | ||
2525 | flags |= NFSD_MAY_READ; | ||
2526 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | ||
2527 | flags |= NFSD_MAY_WRITE; | ||
2528 | status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags); | ||
2529 | if (status) | 2614 | if (status) |
2530 | goto out; | 2615 | goto out; |
2531 | init_stateid(stp, fp, open); | 2616 | init_stateid(stp, fp, open); |
@@ -2727,7 +2812,7 @@ search_close_lru(u32 st_id, int flags) | |||
2727 | static inline int | 2812 | static inline int |
2728 | nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) | 2813 | nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) |
2729 | { | 2814 | { |
2730 | return fhp->fh_dentry->d_inode != stp->st_vfs_file->f_path.dentry->d_inode; | 2815 | return fhp->fh_dentry->d_inode != stp->st_file->fi_inode; |
2731 | } | 2816 | } |
2732 | 2817 | ||
2733 | static int | 2818 | static int |
@@ -2760,6 +2845,9 @@ __be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags) | |||
2760 | { | 2845 | { |
2761 | __be32 status = nfserr_openmode; | 2846 | __be32 status = nfserr_openmode; |
2762 | 2847 | ||
2848 | /* For lock stateid's, we test the parent open, not the lock: */ | ||
2849 | if (stp->st_openstp) | ||
2850 | stp = stp->st_openstp; | ||
2763 | if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) | 2851 | if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) |
2764 | goto out; | 2852 | goto out; |
2765 | if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap))) | 2853 | if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap))) |
@@ -2872,7 +2960,8 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2872 | goto out; | 2960 | goto out; |
2873 | renew_client(dp->dl_client); | 2961 | renew_client(dp->dl_client); |
2874 | if (filpp) | 2962 | if (filpp) |
2875 | *filpp = dp->dl_vfs_file; | 2963 | *filpp = find_readable_file(dp->dl_file); |
2964 | BUG_ON(!*filpp); | ||
2876 | } else { /* open or lock stateid */ | 2965 | } else { /* open or lock stateid */ |
2877 | stp = find_stateid(stateid, flags); | 2966 | stp = find_stateid(stateid, flags); |
2878 | if (!stp) | 2967 | if (!stp) |
@@ -2889,8 +2978,13 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2889 | if (status) | 2978 | if (status) |
2890 | goto out; | 2979 | goto out; |
2891 | renew_client(stp->st_stateowner->so_client); | 2980 | renew_client(stp->st_stateowner->so_client); |
2892 | if (filpp) | 2981 | if (filpp) { |
2893 | *filpp = stp->st_vfs_file; | 2982 | if (flags & RD_STATE) |
2983 | *filpp = find_readable_file(stp->st_file); | ||
2984 | else | ||
2985 | *filpp = find_writeable_file(stp->st_file); | ||
2986 | BUG_ON(!*filpp); /* assured by check_openmode */ | ||
2987 | } | ||
2894 | } | 2988 | } |
2895 | status = nfs_ok; | 2989 | status = nfs_ok; |
2896 | out: | 2990 | out: |
@@ -3126,8 +3220,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3126 | goto out; | 3220 | goto out; |
3127 | } | 3221 | } |
3128 | set_access(&share_access, stp->st_access_bmap); | 3222 | set_access(&share_access, stp->st_access_bmap); |
3129 | nfs4_file_downgrade(stp->st_vfs_file, | 3223 | nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access); |
3130 | share_access & ~od->od_share_access); | ||
3131 | 3224 | ||
3132 | reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap); | 3225 | reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap); |
3133 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); | 3226 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); |
@@ -3346,11 +3439,9 @@ static inline void | |||
3346 | nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) | 3439 | nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) |
3347 | { | 3440 | { |
3348 | struct nfs4_stateowner *sop; | 3441 | struct nfs4_stateowner *sop; |
3349 | unsigned int hval; | ||
3350 | 3442 | ||
3351 | if (fl->fl_lmops == &nfsd_posix_mng_ops) { | 3443 | if (fl->fl_lmops == &nfsd_posix_mng_ops) { |
3352 | sop = (struct nfs4_stateowner *) fl->fl_owner; | 3444 | sop = (struct nfs4_stateowner *) fl->fl_owner; |
3353 | hval = lockownerid_hashval(sop->so_id); | ||
3354 | kref_get(&sop->so_ref); | 3445 | kref_get(&sop->so_ref); |
3355 | deny->ld_sop = sop; | 3446 | deny->ld_sop = sop; |
3356 | deny->ld_clientid = sop->so_client->cl_clientid; | 3447 | deny->ld_clientid = sop->so_client->cl_clientid; |
@@ -3446,8 +3537,6 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
3446 | stp->st_stateid.si_stateownerid = sop->so_id; | 3537 | stp->st_stateid.si_stateownerid = sop->so_id; |
3447 | stp->st_stateid.si_fileid = fp->fi_id; | 3538 | stp->st_stateid.si_fileid = fp->fi_id; |
3448 | stp->st_stateid.si_generation = 0; | 3539 | stp->st_stateid.si_generation = 0; |
3449 | stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */ | ||
3450 | stp->st_access_bmap = open_stp->st_access_bmap; | ||
3451 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 3540 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
3452 | stp->st_openstp = open_stp; | 3541 | stp->st_openstp = open_stp; |
3453 | 3542 | ||
@@ -3547,7 +3636,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3547 | lock_sop = lock->lk_replay_owner; | 3636 | lock_sop = lock->lk_replay_owner; |
3548 | } | 3637 | } |
3549 | /* lock->lk_replay_owner and lock_stp have been created or found */ | 3638 | /* lock->lk_replay_owner and lock_stp have been created or found */ |
3550 | filp = lock_stp->st_vfs_file; | ||
3551 | 3639 | ||
3552 | status = nfserr_grace; | 3640 | status = nfserr_grace; |
3553 | if (locks_in_grace() && !lock->lk_reclaim) | 3641 | if (locks_in_grace() && !lock->lk_reclaim) |
@@ -3560,11 +3648,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3560 | switch (lock->lk_type) { | 3648 | switch (lock->lk_type) { |
3561 | case NFS4_READ_LT: | 3649 | case NFS4_READ_LT: |
3562 | case NFS4_READW_LT: | 3650 | case NFS4_READW_LT: |
3651 | filp = find_readable_file(lock_stp->st_file); | ||
3563 | file_lock.fl_type = F_RDLCK; | 3652 | file_lock.fl_type = F_RDLCK; |
3564 | cmd = F_SETLK; | 3653 | cmd = F_SETLK; |
3565 | break; | 3654 | break; |
3566 | case NFS4_WRITE_LT: | 3655 | case NFS4_WRITE_LT: |
3567 | case NFS4_WRITEW_LT: | 3656 | case NFS4_WRITEW_LT: |
3657 | filp = find_writeable_file(lock_stp->st_file); | ||
3568 | file_lock.fl_type = F_WRLCK; | 3658 | file_lock.fl_type = F_WRLCK; |
3569 | cmd = F_SETLK; | 3659 | cmd = F_SETLK; |
3570 | break; | 3660 | break; |
@@ -3572,6 +3662,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3572 | status = nfserr_inval; | 3662 | status = nfserr_inval; |
3573 | goto out; | 3663 | goto out; |
3574 | } | 3664 | } |
3665 | if (!filp) { | ||
3666 | status = nfserr_openmode; | ||
3667 | goto out; | ||
3668 | } | ||
3575 | file_lock.fl_owner = (fl_owner_t)lock_sop; | 3669 | file_lock.fl_owner = (fl_owner_t)lock_sop; |
3576 | file_lock.fl_pid = current->tgid; | 3670 | file_lock.fl_pid = current->tgid; |
3577 | file_lock.fl_file = filp; | 3671 | file_lock.fl_file = filp; |
@@ -3740,7 +3834,11 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3740 | &locku->lu_stateowner, &stp, NULL))) | 3834 | &locku->lu_stateowner, &stp, NULL))) |
3741 | goto out; | 3835 | goto out; |
3742 | 3836 | ||
3743 | filp = stp->st_vfs_file; | 3837 | filp = find_any_file(stp->st_file); |
3838 | if (!filp) { | ||
3839 | status = nfserr_lock_range; | ||
3840 | goto out; | ||
3841 | } | ||
3744 | BUG_ON(!filp); | 3842 | BUG_ON(!filp); |
3745 | locks_init_lock(&file_lock); | 3843 | locks_init_lock(&file_lock); |
3746 | file_lock.fl_type = F_UNLCK; | 3844 | file_lock.fl_type = F_UNLCK; |
@@ -3787,10 +3885,10 @@ out_nfserr: | |||
3787 | * 0: no locks held by lockowner | 3885 | * 0: no locks held by lockowner |
3788 | */ | 3886 | */ |
3789 | static int | 3887 | static int |
3790 | check_for_locks(struct file *filp, struct nfs4_stateowner *lowner) | 3888 | check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner) |
3791 | { | 3889 | { |
3792 | struct file_lock **flpp; | 3890 | struct file_lock **flpp; |
3793 | struct inode *inode = filp->f_path.dentry->d_inode; | 3891 | struct inode *inode = filp->fi_inode; |
3794 | int status = 0; | 3892 | int status = 0; |
3795 | 3893 | ||
3796 | lock_kernel(); | 3894 | lock_kernel(); |
@@ -3841,7 +3939,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
3841 | continue; | 3939 | continue; |
3842 | list_for_each_entry(stp, &sop->so_stateids, | 3940 | list_for_each_entry(stp, &sop->so_stateids, |
3843 | st_perstateowner) { | 3941 | st_perstateowner) { |
3844 | if (check_for_locks(stp->st_vfs_file, sop)) | 3942 | if (check_for_locks(stp->st_file, sop)) |
3845 | goto out; | 3943 | goto out; |
3846 | /* Note: so_perclient unused for lockowners, | 3944 | /* Note: so_perclient unused for lockowners, |
3847 | * so it's OK to fool with here. */ | 3945 | * so it's OK to fool with here. */ |
@@ -4066,16 +4164,8 @@ out_free_laundry: | |||
4066 | int | 4164 | int |
4067 | nfs4_state_start(void) | 4165 | nfs4_state_start(void) |
4068 | { | 4166 | { |
4069 | int ret; | ||
4070 | |||
4071 | if (nfs4_init) | ||
4072 | return 0; | ||
4073 | nfsd4_load_reboot_recovery_data(); | 4167 | nfsd4_load_reboot_recovery_data(); |
4074 | ret = __nfs4_state_start(); | 4168 | return __nfs4_state_start(); |
4075 | if (ret) | ||
4076 | return ret; | ||
4077 | nfs4_init = 1; | ||
4078 | return 0; | ||
4079 | } | 4169 | } |
4080 | 4170 | ||
4081 | static void | 4171 | static void |
@@ -4110,7 +4200,6 @@ __nfs4_state_shutdown(void) | |||
4110 | } | 4200 | } |
4111 | 4201 | ||
4112 | nfsd4_shutdown_recdir(); | 4202 | nfsd4_shutdown_recdir(); |
4113 | nfs4_init = 0; | ||
4114 | } | 4203 | } |
4115 | 4204 | ||
4116 | void | 4205 | void |