diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 303 |
1 files changed, 182 insertions, 121 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b996a4badeb8..7ab572f9f388 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -162,6 +162,28 @@ static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; | |||
162 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; | 162 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; |
163 | static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; | 163 | static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; |
164 | 164 | ||
165 | static inline 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 inline void nfs4_file_put_fd(struct nfs4_file *fp, int oflag) | ||
172 | { | ||
173 | if (fp->fi_fds[oflag]) { | ||
174 | fput(fp->fi_fds[oflag]); | ||
175 | fp->fi_fds[oflag] = NULL; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | static inline void nfs4_file_put_access(struct nfs4_file *fp, int oflag) | ||
180 | { | ||
181 | if (atomic_dec_and_test(&fp->fi_access[oflag])) { | ||
182 | nfs4_file_put_fd(fp, O_RDWR); | ||
183 | nfs4_file_put_fd(fp, oflag); | ||
184 | } | ||
185 | } | ||
186 | |||
165 | static struct nfs4_delegation * | 187 | static struct nfs4_delegation * |
166 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) | 188 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) |
167 | { | 189 | { |
@@ -191,9 +213,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
191 | dp->dl_client = clp; | 213 | dp->dl_client = clp; |
192 | get_nfs4_file(fp); | 214 | get_nfs4_file(fp); |
193 | dp->dl_file = fp; | 215 | dp->dl_file = fp; |
216 | nfs4_file_get_access(fp, O_RDONLY); | ||
194 | dp->dl_flock = NULL; | 217 | dp->dl_flock = NULL; |
195 | get_file(stp->st_vfs_file); | ||
196 | dp->dl_vfs_file = stp->st_vfs_file; | ||
197 | dp->dl_type = type; | 218 | dp->dl_type = type; |
198 | dp->dl_ident = cb->cb_ident; | 219 | dp->dl_ident = cb->cb_ident; |
199 | dp->dl_stateid.si_boot = boot_time; | 220 | dp->dl_stateid.si_boot = boot_time; |
@@ -228,15 +249,12 @@ nfs4_put_delegation(struct nfs4_delegation *dp) | |||
228 | static void | 249 | static void |
229 | nfs4_close_delegation(struct nfs4_delegation *dp) | 250 | nfs4_close_delegation(struct nfs4_delegation *dp) |
230 | { | 251 | { |
231 | struct file *filp = dp->dl_vfs_file; | 252 | struct file *filp = find_readable_file(dp->dl_file); |
232 | 253 | ||
233 | dprintk("NFSD: close_delegation dp %p\n",dp); | 254 | dprintk("NFSD: close_delegation dp %p\n",dp); |
234 | dp->dl_vfs_file = NULL; | ||
235 | /* The following nfsd_close may not actually close the file, | ||
236 | * but we want to remove the lease in any case. */ | ||
237 | if (dp->dl_flock) | 255 | if (dp->dl_flock) |
238 | vfs_setlease(filp, F_UNLCK, &dp->dl_flock); | 256 | vfs_setlease(filp, F_UNLCK, &dp->dl_flock); |
239 | nfsd_close(filp); | 257 | nfs4_file_put_access(dp->dl_file, O_RDONLY); |
240 | } | 258 | } |
241 | 259 | ||
242 | /* Called under the state lock. */ | 260 | /* Called under the state lock. */ |
@@ -308,8 +326,12 @@ static void free_generic_stateid(struct nfs4_stateid *stp) | |||
308 | 326 | ||
309 | static void release_lock_stateid(struct nfs4_stateid *stp) | 327 | static void release_lock_stateid(struct nfs4_stateid *stp) |
310 | { | 328 | { |
329 | struct file *file; | ||
330 | |||
311 | unhash_generic_stateid(stp); | 331 | unhash_generic_stateid(stp); |
312 | locks_remove_posix(stp->st_vfs_file, (fl_owner_t)stp->st_stateowner); | 332 | file = find_any_file(stp->st_file); |
333 | if (file) | ||
334 | locks_remove_posix(file, (fl_owner_t)stp->st_stateowner); | ||
313 | free_generic_stateid(stp); | 335 | free_generic_stateid(stp); |
314 | } | 336 | } |
315 | 337 | ||
@@ -347,11 +369,85 @@ release_stateid_lockowners(struct nfs4_stateid *open_stp) | |||
347 | } | 369 | } |
348 | } | 370 | } |
349 | 371 | ||
372 | /* | ||
373 | * We store the NONE, READ, WRITE, and BOTH bits separately in the | ||
374 | * st_{access,deny}_bmap field of the stateid, in order to track not | ||
375 | * only what share bits are currently in force, but also what | ||
376 | * combinations of share bits previous opens have used. This allows us | ||
377 | * to enforce the recommendation of rfc 3530 14.2.19 that the server | ||
378 | * return an error if the client attempt to downgrade to a combination | ||
379 | * of share bits not explicable by closing some of its previous opens. | ||
380 | * | ||
381 | * XXX: This enforcement is actually incomplete, since we don't keep | ||
382 | * track of access/deny bit combinations; so, e.g., we allow: | ||
383 | * | ||
384 | * OPEN allow read, deny write | ||
385 | * OPEN allow both, deny none | ||
386 | * DOWNGRADE allow read, deny none | ||
387 | * | ||
388 | * which we should reject. | ||
389 | */ | ||
390 | static void | ||
391 | set_access(unsigned int *access, unsigned long bmap) { | ||
392 | int i; | ||
393 | |||
394 | *access = 0; | ||
395 | for (i = 1; i < 4; i++) { | ||
396 | if (test_bit(i, &bmap)) | ||
397 | *access |= i; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | static void | ||
402 | set_deny(unsigned int *deny, unsigned long bmap) { | ||
403 | int i; | ||
404 | |||
405 | *deny = 0; | ||
406 | for (i = 0; i < 4; i++) { | ||
407 | if (test_bit(i, &bmap)) | ||
408 | *deny |= i ; | ||
409 | } | ||
410 | } | ||
411 | |||
412 | static int | ||
413 | test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { | ||
414 | unsigned int access, deny; | ||
415 | |||
416 | set_access(&access, stp->st_access_bmap); | ||
417 | set_deny(&deny, stp->st_deny_bmap); | ||
418 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) | ||
419 | return 0; | ||
420 | return 1; | ||
421 | } | ||
422 | |||
423 | static int nfs4_access_to_omode(u32 access) | ||
424 | { | ||
425 | switch (access) { | ||
426 | case NFS4_SHARE_ACCESS_READ: | ||
427 | return O_RDONLY; | ||
428 | case NFS4_SHARE_ACCESS_WRITE: | ||
429 | return O_WRONLY; | ||
430 | case NFS4_SHARE_ACCESS_BOTH: | ||
431 | return O_RDWR; | ||
432 | } | ||
433 | BUG(); | ||
434 | } | ||
435 | |||
436 | static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp) | ||
437 | { | ||
438 | unsigned int access; | ||
439 | |||
440 | set_access(&access, stp->st_access_bmap); | ||
441 | return nfs4_access_to_omode(access); | ||
442 | } | ||
443 | |||
350 | static void release_open_stateid(struct nfs4_stateid *stp) | 444 | static void release_open_stateid(struct nfs4_stateid *stp) |
351 | { | 445 | { |
446 | int oflag = nfs4_access_bmap_to_omode(stp); | ||
447 | |||
352 | unhash_generic_stateid(stp); | 448 | unhash_generic_stateid(stp); |
353 | release_stateid_lockowners(stp); | 449 | release_stateid_lockowners(stp); |
354 | nfsd_close(stp->st_vfs_file); | 450 | nfs4_file_put_access(stp->st_file, oflag); |
355 | free_generic_stateid(stp); | 451 | free_generic_stateid(stp); |
356 | } | 452 | } |
357 | 453 | ||
@@ -1763,6 +1859,8 @@ alloc_init_file(struct inode *ino) | |||
1763 | fp->fi_inode = igrab(ino); | 1859 | fp->fi_inode = igrab(ino); |
1764 | fp->fi_id = current_fileid++; | 1860 | fp->fi_id = current_fileid++; |
1765 | fp->fi_had_conflict = false; | 1861 | fp->fi_had_conflict = false; |
1862 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); | ||
1863 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); | ||
1766 | spin_lock(&recall_lock); | 1864 | spin_lock(&recall_lock); |
1767 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | 1865 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); |
1768 | spin_unlock(&recall_lock); | 1866 | spin_unlock(&recall_lock); |
@@ -1974,57 +2072,6 @@ static inline int deny_valid(u32 x) | |||
1974 | } | 2072 | } |
1975 | 2073 | ||
1976 | /* | 2074 | /* |
1977 | * We store the NONE, READ, WRITE, and BOTH bits separately in the | ||
1978 | * st_{access,deny}_bmap field of the stateid, in order to track not | ||
1979 | * only what share bits are currently in force, but also what | ||
1980 | * combinations of share bits previous opens have used. This allows us | ||
1981 | * to enforce the recommendation of rfc 3530 14.2.19 that the server | ||
1982 | * return an error if the client attempt to downgrade to a combination | ||
1983 | * of share bits not explicable by closing some of its previous opens. | ||
1984 | * | ||
1985 | * XXX: This enforcement is actually incomplete, since we don't keep | ||
1986 | * track of access/deny bit combinations; so, e.g., we allow: | ||
1987 | * | ||
1988 | * OPEN allow read, deny write | ||
1989 | * OPEN allow both, deny none | ||
1990 | * DOWNGRADE allow read, deny none | ||
1991 | * | ||
1992 | * which we should reject. | ||
1993 | */ | ||
1994 | static void | ||
1995 | set_access(unsigned int *access, unsigned long bmap) { | ||
1996 | int i; | ||
1997 | |||
1998 | *access = 0; | ||
1999 | for (i = 1; i < 4; i++) { | ||
2000 | if (test_bit(i, &bmap)) | ||
2001 | *access |= i; | ||
2002 | } | ||
2003 | } | ||
2004 | |||
2005 | static void | ||
2006 | set_deny(unsigned int *deny, unsigned long bmap) { | ||
2007 | int i; | ||
2008 | |||
2009 | *deny = 0; | ||
2010 | for (i = 0; i < 4; i++) { | ||
2011 | if (test_bit(i, &bmap)) | ||
2012 | *deny |= i ; | ||
2013 | } | ||
2014 | } | ||
2015 | |||
2016 | static int | ||
2017 | test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { | ||
2018 | unsigned int access, deny; | ||
2019 | |||
2020 | set_access(&access, stp->st_access_bmap); | ||
2021 | set_deny(&deny, stp->st_deny_bmap); | ||
2022 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) | ||
2023 | return 0; | ||
2024 | return 1; | ||
2025 | } | ||
2026 | |||
2027 | /* | ||
2028 | * Called to check deny when READ with all zero stateid or | 2075 | * Called to check deny when READ with all zero stateid or |
2029 | * WRITE with all zero or all one stateid | 2076 | * WRITE with all zero or all one stateid |
2030 | */ | 2077 | */ |
@@ -2055,14 +2102,12 @@ out: | |||
2055 | } | 2102 | } |
2056 | 2103 | ||
2057 | static inline void | 2104 | static inline void |
2058 | nfs4_file_downgrade(struct file *filp, unsigned int share_access) | 2105 | nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access) |
2059 | { | 2106 | { |
2060 | if (share_access & NFS4_SHARE_ACCESS_WRITE) { | 2107 | if (share_access & NFS4_SHARE_ACCESS_WRITE) |
2061 | drop_file_write_access(filp); | 2108 | nfs4_file_put_access(fp, O_WRONLY); |
2062 | spin_lock(&filp->f_lock); | 2109 | if (share_access & NFS4_SHARE_ACCESS_READ) |
2063 | filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE; | 2110 | nfs4_file_put_access(fp, O_RDONLY); |
2064 | spin_unlock(&filp->f_lock); | ||
2065 | } | ||
2066 | } | 2111 | } |
2067 | 2112 | ||
2068 | /* | 2113 | /* |
@@ -2328,32 +2373,42 @@ static inline int nfs4_access_to_access(u32 nfs4_access) | |||
2328 | return flags; | 2373 | return flags; |
2329 | } | 2374 | } |
2330 | 2375 | ||
2376 | static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file | ||
2377 | *fp, struct svc_fh *cur_fh, u32 nfs4_access) | ||
2378 | { | ||
2379 | __be32 status; | ||
2380 | int oflag = nfs4_access_to_omode(nfs4_access); | ||
2381 | int access = nfs4_access_to_access(nfs4_access); | ||
2382 | |||
2383 | if (!fp->fi_fds[oflag]) { | ||
2384 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, | ||
2385 | &fp->fi_fds[oflag]); | ||
2386 | if (status == nfserr_dropit) | ||
2387 | status = nfserr_jukebox; | ||
2388 | if (status) | ||
2389 | return status; | ||
2390 | } | ||
2391 | nfs4_file_get_access(fp, oflag); | ||
2392 | |||
2393 | return nfs_ok; | ||
2394 | } | ||
2395 | |||
2331 | static __be32 | 2396 | static __be32 |
2332 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, | 2397 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, |
2333 | struct nfs4_delegation *dp, | 2398 | struct nfs4_file *fp, struct svc_fh *cur_fh, |
2334 | struct svc_fh *cur_fh, struct nfsd4_open *open) | 2399 | struct nfsd4_open *open) |
2335 | { | 2400 | { |
2336 | struct nfs4_stateid *stp; | 2401 | struct nfs4_stateid *stp; |
2402 | __be32 status; | ||
2337 | 2403 | ||
2338 | stp = nfs4_alloc_stateid(); | 2404 | stp = nfs4_alloc_stateid(); |
2339 | if (stp == NULL) | 2405 | if (stp == NULL) |
2340 | return nfserr_resource; | 2406 | return nfserr_resource; |
2341 | 2407 | ||
2342 | if (dp) { | 2408 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open->op_share_access); |
2343 | get_file(dp->dl_vfs_file); | 2409 | if (status) { |
2344 | stp->st_vfs_file = dp->dl_vfs_file; | 2410 | kmem_cache_free(stateid_slab, stp); |
2345 | } else { | 2411 | return status; |
2346 | __be32 status; | ||
2347 | int access = nfs4_access_to_access(open->op_share_access); | ||
2348 | |||
2349 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, | ||
2350 | &stp->st_vfs_file); | ||
2351 | if (status) { | ||
2352 | if (status == nfserr_dropit) | ||
2353 | status = nfserr_jukebox; | ||
2354 | kmem_cache_free(stateid_slab, stp); | ||
2355 | return status; | ||
2356 | } | ||
2357 | } | 2412 | } |
2358 | *stpp = stp; | 2413 | *stpp = stp; |
2359 | return 0; | 2414 | return 0; |
@@ -2375,36 +2430,29 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, | |||
2375 | } | 2430 | } |
2376 | 2431 | ||
2377 | static __be32 | 2432 | static __be32 |
2378 | nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) | 2433 | nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) |
2379 | { | 2434 | { |
2380 | struct file *filp = stp->st_vfs_file; | 2435 | u32 op_share_access, new_access; |
2381 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
2382 | unsigned int share_access, new_writer; | ||
2383 | u32 op_share_access; | ||
2384 | __be32 status; | 2436 | __be32 status; |
2385 | 2437 | ||
2386 | set_access(&share_access, stp->st_access_bmap); | 2438 | set_access(&new_access, stp->st_access_bmap); |
2387 | new_writer = (~share_access) & open->op_share_access | 2439 | new_access = (~new_access) & open->op_share_access & ~NFS4_SHARE_WANT_MASK; |
2388 | & NFS4_SHARE_ACCESS_WRITE; | 2440 | |
2389 | 2441 | if (new_access) { | |
2390 | if (new_writer) { | 2442 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, new_access); |
2391 | int err = get_write_access(inode); | 2443 | if (status) |
2392 | if (err) | 2444 | return status; |
2393 | return nfserrno(err); | ||
2394 | err = mnt_want_write(cur_fh->fh_export->ex_path.mnt); | ||
2395 | if (err) | ||
2396 | return nfserrno(err); | ||
2397 | file_take_write(filp); | ||
2398 | } | 2445 | } |
2399 | status = nfsd4_truncate(rqstp, cur_fh, open); | 2446 | status = nfsd4_truncate(rqstp, cur_fh, open); |
2400 | if (status) { | 2447 | if (status) { |
2401 | if (new_writer) | 2448 | if (new_access) { |
2402 | put_write_access(inode); | 2449 | int oflag = nfs4_access_to_omode(new_access); |
2450 | nfs4_file_put_access(fp, oflag); | ||
2451 | } | ||
2403 | return status; | 2452 | return status; |
2404 | } | 2453 | } |
2405 | /* remember the open */ | 2454 | /* remember the open */ |
2406 | op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK; | 2455 | op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK; |
2407 | filp->f_mode |= op_share_access; | ||
2408 | __set_bit(op_share_access, &stp->st_access_bmap); | 2456 | __set_bit(op_share_access, &stp->st_access_bmap); |
2409 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 2457 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); |
2410 | 2458 | ||
@@ -2468,13 +2516,14 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2468 | fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; | 2516 | fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; |
2469 | fl.fl_end = OFFSET_MAX; | 2517 | fl.fl_end = OFFSET_MAX; |
2470 | fl.fl_owner = (fl_owner_t)dp; | 2518 | fl.fl_owner = (fl_owner_t)dp; |
2471 | fl.fl_file = stp->st_vfs_file; | 2519 | fl.fl_file = find_readable_file(stp->st_file); |
2520 | BUG_ON(!fl.fl_file); | ||
2472 | fl.fl_pid = current->tgid; | 2521 | fl.fl_pid = current->tgid; |
2473 | 2522 | ||
2474 | /* vfs_setlease checks to see if delegation should be handed out. | 2523 | /* vfs_setlease checks to see if delegation should be handed out. |
2475 | * the lock_manager callbacks fl_mylease and fl_change are used | 2524 | * the lock_manager callbacks fl_mylease and fl_change are used |
2476 | */ | 2525 | */ |
2477 | if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) { | 2526 | if ((status = vfs_setlease(fl.fl_file, fl.fl_type, &flp))) { |
2478 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); | 2527 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); |
2479 | unhash_delegation(dp); | 2528 | unhash_delegation(dp); |
2480 | flag = NFS4_OPEN_DELEGATE_NONE; | 2529 | flag = NFS4_OPEN_DELEGATE_NONE; |
@@ -2538,13 +2587,12 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
2538 | */ | 2587 | */ |
2539 | if (stp) { | 2588 | if (stp) { |
2540 | /* Stateid was found, this is an OPEN upgrade */ | 2589 | /* Stateid was found, this is an OPEN upgrade */ |
2541 | status = nfs4_upgrade_open(rqstp, current_fh, stp, open); | 2590 | status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); |
2542 | if (status) | 2591 | if (status) |
2543 | goto out; | 2592 | goto out; |
2544 | update_stateid(&stp->st_stateid); | 2593 | update_stateid(&stp->st_stateid); |
2545 | } else { | 2594 | } else { |
2546 | /* Stateid was not found, this is a new OPEN */ | 2595 | status = nfs4_new_open(rqstp, &stp, fp, current_fh, open); |
2547 | status = nfs4_new_open(rqstp, &stp, dp, current_fh, open); | ||
2548 | if (status) | 2596 | if (status) |
2549 | goto out; | 2597 | goto out; |
2550 | init_stateid(stp, fp, open); | 2598 | init_stateid(stp, fp, open); |
@@ -2746,7 +2794,7 @@ search_close_lru(u32 st_id, int flags) | |||
2746 | static inline int | 2794 | static inline int |
2747 | nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) | 2795 | nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) |
2748 | { | 2796 | { |
2749 | return fhp->fh_dentry->d_inode != stp->st_vfs_file->f_path.dentry->d_inode; | 2797 | return fhp->fh_dentry->d_inode != stp->st_file->fi_inode; |
2750 | } | 2798 | } |
2751 | 2799 | ||
2752 | static int | 2800 | static int |
@@ -2894,7 +2942,8 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2894 | goto out; | 2942 | goto out; |
2895 | renew_client(dp->dl_client); | 2943 | renew_client(dp->dl_client); |
2896 | if (filpp) | 2944 | if (filpp) |
2897 | *filpp = dp->dl_vfs_file; | 2945 | *filpp = find_readable_file(dp->dl_file); |
2946 | BUG_ON(!*filpp); | ||
2898 | } else { /* open or lock stateid */ | 2947 | } else { /* open or lock stateid */ |
2899 | stp = find_stateid(stateid, flags); | 2948 | stp = find_stateid(stateid, flags); |
2900 | if (!stp) | 2949 | if (!stp) |
@@ -2911,8 +2960,13 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2911 | if (status) | 2960 | if (status) |
2912 | goto out; | 2961 | goto out; |
2913 | renew_client(stp->st_stateowner->so_client); | 2962 | renew_client(stp->st_stateowner->so_client); |
2914 | if (filpp) | 2963 | if (filpp) { |
2915 | *filpp = stp->st_vfs_file; | 2964 | if (flags & RD_STATE) |
2965 | *filpp = find_readable_file(stp->st_file); | ||
2966 | else | ||
2967 | *filpp = find_writeable_file(stp->st_file); | ||
2968 | BUG_ON(!*filpp); /* assured by check_openmode */ | ||
2969 | } | ||
2916 | } | 2970 | } |
2917 | status = nfs_ok; | 2971 | status = nfs_ok; |
2918 | out: | 2972 | out: |
@@ -3148,8 +3202,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3148 | goto out; | 3202 | goto out; |
3149 | } | 3203 | } |
3150 | set_access(&share_access, stp->st_access_bmap); | 3204 | set_access(&share_access, stp->st_access_bmap); |
3151 | nfs4_file_downgrade(stp->st_vfs_file, | 3205 | nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access); |
3152 | share_access & ~od->od_share_access); | ||
3153 | 3206 | ||
3154 | reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap); | 3207 | reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap); |
3155 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); | 3208 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); |
@@ -3468,7 +3521,6 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
3468 | stp->st_stateid.si_stateownerid = sop->so_id; | 3521 | stp->st_stateid.si_stateownerid = sop->so_id; |
3469 | stp->st_stateid.si_fileid = fp->fi_id; | 3522 | stp->st_stateid.si_fileid = fp->fi_id; |
3470 | stp->st_stateid.si_generation = 0; | 3523 | stp->st_stateid.si_generation = 0; |
3471 | stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */ | ||
3472 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 3524 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
3473 | stp->st_openstp = open_stp; | 3525 | stp->st_openstp = open_stp; |
3474 | 3526 | ||
@@ -3568,7 +3620,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3568 | lock_sop = lock->lk_replay_owner; | 3620 | lock_sop = lock->lk_replay_owner; |
3569 | } | 3621 | } |
3570 | /* lock->lk_replay_owner and lock_stp have been created or found */ | 3622 | /* lock->lk_replay_owner and lock_stp have been created or found */ |
3571 | filp = lock_stp->st_vfs_file; | ||
3572 | 3623 | ||
3573 | status = nfserr_grace; | 3624 | status = nfserr_grace; |
3574 | if (locks_in_grace() && !lock->lk_reclaim) | 3625 | if (locks_in_grace() && !lock->lk_reclaim) |
@@ -3581,11 +3632,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3581 | switch (lock->lk_type) { | 3632 | switch (lock->lk_type) { |
3582 | case NFS4_READ_LT: | 3633 | case NFS4_READ_LT: |
3583 | case NFS4_READW_LT: | 3634 | case NFS4_READW_LT: |
3635 | filp = find_readable_file(lock_stp->st_file); | ||
3584 | file_lock.fl_type = F_RDLCK; | 3636 | file_lock.fl_type = F_RDLCK; |
3585 | cmd = F_SETLK; | 3637 | cmd = F_SETLK; |
3586 | break; | 3638 | break; |
3587 | case NFS4_WRITE_LT: | 3639 | case NFS4_WRITE_LT: |
3588 | case NFS4_WRITEW_LT: | 3640 | case NFS4_WRITEW_LT: |
3641 | filp = find_writeable_file(lock_stp->st_file); | ||
3589 | file_lock.fl_type = F_WRLCK; | 3642 | file_lock.fl_type = F_WRLCK; |
3590 | cmd = F_SETLK; | 3643 | cmd = F_SETLK; |
3591 | break; | 3644 | break; |
@@ -3593,6 +3646,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3593 | status = nfserr_inval; | 3646 | status = nfserr_inval; |
3594 | goto out; | 3647 | goto out; |
3595 | } | 3648 | } |
3649 | if (!filp) { | ||
3650 | status = nfserr_openmode; | ||
3651 | goto out; | ||
3652 | } | ||
3596 | file_lock.fl_owner = (fl_owner_t)lock_sop; | 3653 | file_lock.fl_owner = (fl_owner_t)lock_sop; |
3597 | file_lock.fl_pid = current->tgid; | 3654 | file_lock.fl_pid = current->tgid; |
3598 | file_lock.fl_file = filp; | 3655 | file_lock.fl_file = filp; |
@@ -3761,7 +3818,11 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3761 | &locku->lu_stateowner, &stp, NULL))) | 3818 | &locku->lu_stateowner, &stp, NULL))) |
3762 | goto out; | 3819 | goto out; |
3763 | 3820 | ||
3764 | filp = stp->st_vfs_file; | 3821 | filp = find_any_file(stp->st_file); |
3822 | if (!filp) { | ||
3823 | status = nfserr_lock_range; | ||
3824 | goto out; | ||
3825 | } | ||
3765 | BUG_ON(!filp); | 3826 | BUG_ON(!filp); |
3766 | locks_init_lock(&file_lock); | 3827 | locks_init_lock(&file_lock); |
3767 | file_lock.fl_type = F_UNLCK; | 3828 | file_lock.fl_type = F_UNLCK; |
@@ -3808,10 +3869,10 @@ out_nfserr: | |||
3808 | * 0: no locks held by lockowner | 3869 | * 0: no locks held by lockowner |
3809 | */ | 3870 | */ |
3810 | static int | 3871 | static int |
3811 | check_for_locks(struct file *filp, struct nfs4_stateowner *lowner) | 3872 | check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner) |
3812 | { | 3873 | { |
3813 | struct file_lock **flpp; | 3874 | struct file_lock **flpp; |
3814 | struct inode *inode = filp->f_path.dentry->d_inode; | 3875 | struct inode *inode = filp->fi_inode; |
3815 | int status = 0; | 3876 | int status = 0; |
3816 | 3877 | ||
3817 | lock_kernel(); | 3878 | lock_kernel(); |
@@ -3862,7 +3923,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
3862 | continue; | 3923 | continue; |
3863 | list_for_each_entry(stp, &sop->so_stateids, | 3924 | list_for_each_entry(stp, &sop->so_stateids, |
3864 | st_perstateowner) { | 3925 | st_perstateowner) { |
3865 | if (check_for_locks(stp->st_vfs_file, sop)) | 3926 | if (check_for_locks(stp->st_file, sop)) |
3866 | goto out; | 3927 | goto out; |
3867 | /* Note: so_perclient unused for lockowners, | 3928 | /* Note: so_perclient unused for lockowners, |
3868 | * so it's OK to fool with here. */ | 3929 | * so it's OK to fool with here. */ |