aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@citi.umich.edu>2010-07-08 11:02:09 -0400
committerJ. Bruce Fields <bfields@redhat.com>2010-07-29 18:19:23 -0400
commitf9d7562fdb9dc0ada3a7aba5dbbe9d965e2a105d (patch)
treebbeb32b2cc49b6c6dafae57331a680b906017b6e
parent02921914170e3b7fea1cd82dac9713685d2de5e2 (diff)
nfsd4: share file descriptors between stateid's
The vfs doesn't really allow us to "upgrade" a file descriptor from read-only to read-write, and our attempt to do so in nfs4_upgrade_open is ugly and incomplete. Move to a different scheme where we keep multiple opens, shared between open stateid's, in the nfs4_file struct. Each file will be opened at most 3 times (for read, write, and read-write), and those opens will be shared between all clients and openers. On upgrade we will do another open if necessary instead of attempting to upgrade an existing open. We keep count of the number of readers and writers so we know when to close the shared files. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
-rw-r--r--fs/nfsd/nfs4state.c303
-rw-r--r--fs/nfsd/nfsd.h1
-rw-r--r--fs/nfsd/state.h40
3 files changed, 221 insertions, 123 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];
162static struct list_head file_hashtbl[FILE_HASH_SIZE]; 162static struct list_head file_hashtbl[FILE_HASH_SIZE];
163static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; 163static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
164 164
165static 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
171static 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
179static 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
165static struct nfs4_delegation * 187static struct nfs4_delegation *
166alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) 188alloc_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)
228static void 249static void
229nfs4_close_delegation(struct nfs4_delegation *dp) 250nfs4_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
309static void release_lock_stateid(struct nfs4_stateid *stp) 327static 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 */
390static void
391set_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
401static void
402set_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
412static int
413test_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
423static 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
436static 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
350static void release_open_stateid(struct nfs4_stateid *stp) 444static 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 */
1994static void
1995set_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
2005static void
2006set_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
2016static int
2017test_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
2057static inline void 2104static inline void
2058nfs4_file_downgrade(struct file *filp, unsigned int share_access) 2105nfs4_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
2376static __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
2331static __be32 2396static __be32
2332nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, 2397nfs4_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
2377static __be32 2432static __be32
2378nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) 2433nfs4_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)
2746static inline int 2794static inline int
2747nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) 2795nfs4_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
2752static int 2800static 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;
2918out: 2972out:
@@ -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 */
3810static int 3871static int
3811check_for_locks(struct file *filp, struct nfs4_stateowner *lowner) 3872check_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. */
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 72377761270e..b76ac3a82e39 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -153,6 +153,7 @@ void nfsd_lockd_shutdown(void);
153#define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID) 153#define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID)
154#define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK) 154#define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK)
155#define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME) 155#define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME)
156#define nfserr_lock_range cpu_to_be32(NFSERR_LOCK_RANGE)
156#define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH) 157#define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH)
157#define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP) 158#define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP)
158#define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR) 159#define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR)
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 006c84230c7c..7731a75971dd 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -88,7 +88,6 @@ struct nfs4_delegation {
88 struct nfs4_client *dl_client; 88 struct nfs4_client *dl_client;
89 struct nfs4_file *dl_file; 89 struct nfs4_file *dl_file;
90 struct file_lock *dl_flock; 90 struct file_lock *dl_flock;
91 struct file *dl_vfs_file;
92 u32 dl_type; 91 u32 dl_type;
93 time_t dl_time; 92 time_t dl_time;
94/* For recall: */ 93/* For recall: */
@@ -342,12 +341,50 @@ struct nfs4_file {
342 struct list_head fi_hash; /* hash by "struct inode *" */ 341 struct list_head fi_hash; /* hash by "struct inode *" */
343 struct list_head fi_stateids; 342 struct list_head fi_stateids;
344 struct list_head fi_delegations; 343 struct list_head fi_delegations;
344 /* One each for O_RDONLY, O_WRONLY, O_RDWR: */
345 struct file * fi_fds[3];
346 /* One each for O_RDONLY, O_WRONLY: */
347 atomic_t fi_access[2];
348 /*
349 * Each open stateid contributes 1 to either fi_readers or
350 * fi_writers, or both, depending on the open mode. A
351 * delegation also takes an fi_readers reference. Lock
352 * stateid's take none.
353 */
354 atomic_t fi_readers;
355 atomic_t fi_writers;
345 struct inode *fi_inode; 356 struct inode *fi_inode;
346 u32 fi_id; /* used with stateowner->so_id 357 u32 fi_id; /* used with stateowner->so_id
347 * for stateid_hashtbl hash */ 358 * for stateid_hashtbl hash */
348 bool fi_had_conflict; 359 bool fi_had_conflict;
349}; 360};
350 361
362/* XXX: for first cut may fall back on returning file that doesn't work
363 * at all? */
364static inline struct file *find_writeable_file(struct nfs4_file *f)
365{
366 if (f->fi_fds[O_RDWR])
367 return f->fi_fds[O_RDWR];
368 return f->fi_fds[O_WRONLY];
369}
370
371static inline struct file *find_readable_file(struct nfs4_file *f)
372{
373 if (f->fi_fds[O_RDWR])
374 return f->fi_fds[O_RDWR];
375 return f->fi_fds[O_RDONLY];
376}
377
378static inline struct file *find_any_file(struct nfs4_file *f)
379{
380 if (f->fi_fds[O_RDWR])
381 return f->fi_fds[O_RDWR];
382 else if (f->fi_fds[O_RDWR])
383 return f->fi_fds[O_WRONLY];
384 else
385 return f->fi_fds[O_RDONLY];
386}
387
351/* 388/*
352* nfs4_stateid can either be an open stateid or (eventually) a lock stateid 389* nfs4_stateid can either be an open stateid or (eventually) a lock stateid
353* 390*
@@ -373,7 +410,6 @@ struct nfs4_stateid {
373 struct nfs4_stateowner * st_stateowner; 410 struct nfs4_stateowner * st_stateowner;
374 struct nfs4_file * st_file; 411 struct nfs4_file * st_file;
375 stateid_t st_stateid; 412 stateid_t st_stateid;
376 struct file * st_vfs_file;
377 unsigned long st_access_bmap; 413 unsigned long st_access_bmap;
378 unsigned long st_deny_bmap; 414 unsigned long st_deny_bmap;
379 struct nfs4_stateid * st_openstp; 415 struct nfs4_stateid * st_openstp;