Commit f9d7562fdb9dc0ada3a7aba5dbbe9d965e2a105d

Authored by J. Bruce Fields
Committed by J. Bruce Fields
1 parent 0292191417

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>

Showing 3 changed files with 221 additions and 123 deletions Side-by-side Diff

... ... @@ -162,6 +162,28 @@
162 162 static struct list_head file_hashtbl[FILE_HASH_SIZE];
163 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 187 static struct nfs4_delegation *
166 188 alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
167 189 {
168 190  
... ... @@ -191,9 +213,8 @@
191 213 dp->dl_client = clp;
192 214 get_nfs4_file(fp);
193 215 dp->dl_file = fp;
  216 + nfs4_file_get_access(fp, O_RDONLY);
194 217 dp->dl_flock = NULL;
195   - get_file(stp->st_vfs_file);
196   - dp->dl_vfs_file = stp->st_vfs_file;
197 218 dp->dl_type = type;
198 219 dp->dl_ident = cb->cb_ident;
199 220 dp->dl_stateid.si_boot = boot_time;
200 221  
201 222  
... ... @@ -228,15 +249,12 @@
228 249 static void
229 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 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 255 if (dp->dl_flock)
238 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 260 /* Called under the state lock. */
243 261  
... ... @@ -308,8 +326,12 @@
308 326  
309 327 static void release_lock_stateid(struct nfs4_stateid *stp)
310 328 {
  329 + struct file *file;
  330 +
311 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 335 free_generic_stateid(stp);
314 336 }
315 337  
316 338  
317 339  
... ... @@ -347,11 +369,85 @@
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 444 static void release_open_stateid(struct nfs4_stateid *stp)
351 445 {
  446 + int oflag = nfs4_access_bmap_to_omode(stp);
  447 +
352 448 unhash_generic_stateid(stp);
353 449 release_stateid_lockowners(stp);
354   - nfsd_close(stp->st_vfs_file);
  450 + nfs4_file_put_access(stp->st_file, oflag);
355 451 free_generic_stateid(stp);
356 452 }
357 453  
... ... @@ -1763,6 +1859,8 @@
1763 1859 fp->fi_inode = igrab(ino);
1764 1860 fp->fi_id = current_fileid++;
1765 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 1864 spin_lock(&recall_lock);
1767 1865 list_add(&fp->fi_hash, &file_hashtbl[hashval]);
1768 1866 spin_unlock(&recall_lock);
... ... @@ -1974,57 +2072,6 @@
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 2075 * Called to check deny when READ with all zero stateid or
2029 2076 * WRITE with all zero or all one stateid
2030 2077 */
2031 2078  
... ... @@ -2055,14 +2102,12 @@
2055 2102 }
2056 2103  
2057 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) {
2061   - drop_file_write_access(filp);
2062   - spin_lock(&filp->f_lock);
2063   - filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE;
2064   - spin_unlock(&filp->f_lock);
2065   - }
  2107 + if (share_access & NFS4_SHARE_ACCESS_WRITE)
  2108 + nfs4_file_put_access(fp, O_WRONLY);
  2109 + if (share_access & NFS4_SHARE_ACCESS_READ)
  2110 + nfs4_file_put_access(fp, O_RDONLY);
2066 2111 }
2067 2112  
2068 2113 /*
2069 2114  
2070 2115  
2071 2116  
... ... @@ -2328,32 +2373,42 @@
2328 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 2396 static __be32
2332 2397 nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
2333   - struct nfs4_delegation *dp,
2334   - struct svc_fh *cur_fh, struct nfsd4_open *open)
  2398 + struct nfs4_file *fp, struct svc_fh *cur_fh,
  2399 + struct nfsd4_open *open)
2335 2400 {
2336 2401 struct nfs4_stateid *stp;
  2402 + __be32 status;
2337 2403  
2338 2404 stp = nfs4_alloc_stateid();
2339 2405 if (stp == NULL)
2340 2406 return nfserr_resource;
2341 2407  
2342   - if (dp) {
2343   - get_file(dp->dl_vfs_file);
2344   - stp->st_vfs_file = dp->dl_vfs_file;
2345   - } else {
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   - }
  2408 + status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open->op_share_access);
  2409 + if (status) {
  2410 + kmem_cache_free(stateid_slab, stp);
  2411 + return status;
2357 2412 }
2358 2413 *stpp = stp;
2359 2414 return 0;
2360 2415  
2361 2416  
2362 2417  
2363 2418  
2364 2419  
... ... @@ -2375,36 +2430,29 @@
2375 2430 }
2376 2431  
2377 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;
2381   - struct inode *inode = filp->f_path.dentry->d_inode;
2382   - unsigned int share_access, new_writer;
2383   - u32 op_share_access;
  2435 + u32 op_share_access, new_access;
2384 2436 __be32 status;
2385 2437  
2386   - set_access(&share_access, stp->st_access_bmap);
2387   - new_writer = (~share_access) & open->op_share_access
2388   - & NFS4_SHARE_ACCESS_WRITE;
  2438 + set_access(&new_access, stp->st_access_bmap);
  2439 + new_access = (~new_access) & open->op_share_access & ~NFS4_SHARE_WANT_MASK;
2389 2440  
2390   - if (new_writer) {
2391   - int err = get_write_access(inode);
2392   - if (err)
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);
  2441 + if (new_access) {
  2442 + status = nfs4_get_vfs_file(rqstp, fp, cur_fh, new_access);
  2443 + if (status)
  2444 + return status;
2398 2445 }
2399 2446 status = nfsd4_truncate(rqstp, cur_fh, open);
2400 2447 if (status) {
2401   - if (new_writer)
2402   - put_write_access(inode);
  2448 + if (new_access) {
  2449 + int oflag = nfs4_access_to_omode(new_access);
  2450 + nfs4_file_put_access(fp, oflag);
  2451 + }
2403 2452 return status;
2404 2453 }
2405 2454 /* remember the open */
2406 2455 op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK;
2407   - filp->f_mode |= op_share_access;
2408 2456 __set_bit(op_share_access, &stp->st_access_bmap);
2409 2457 __set_bit(open->op_share_deny, &stp->st_deny_bmap);
2410 2458  
2411 2459  
... ... @@ -2468,13 +2516,14 @@
2468 2516 fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
2469 2517 fl.fl_end = OFFSET_MAX;
2470 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 2521 fl.fl_pid = current->tgid;
2473 2522  
2474 2523 /* vfs_setlease checks to see if delegation should be handed out.
2475 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 2527 dprintk("NFSD: setlease failed [%d], no delegation\n", status);
2479 2528 unhash_delegation(dp);
2480 2529 flag = NFS4_OPEN_DELEGATE_NONE;
2481 2530  
... ... @@ -2538,13 +2587,12 @@
2538 2587 */
2539 2588 if (stp) {
2540 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 2591 if (status)
2543 2592 goto out;
2544 2593 update_stateid(&stp->st_stateid);
2545 2594 } else {
2546   - /* Stateid was not found, this is a new OPEN */
2547   - status = nfs4_new_open(rqstp, &stp, dp, current_fh, open);
  2595 + status = nfs4_new_open(rqstp, &stp, fp, current_fh, open);
2548 2596 if (status)
2549 2597 goto out;
2550 2598 init_stateid(stp, fp, open);
... ... @@ -2746,7 +2794,7 @@
2746 2794 static inline int
2747 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 2800 static int
... ... @@ -2894,7 +2942,8 @@
2894 2942 goto out;
2895 2943 renew_client(dp->dl_client);
2896 2944 if (filpp)
2897   - *filpp = dp->dl_vfs_file;
  2945 + *filpp = find_readable_file(dp->dl_file);
  2946 + BUG_ON(!*filpp);
2898 2947 } else { /* open or lock stateid */
2899 2948 stp = find_stateid(stateid, flags);
2900 2949 if (!stp)
... ... @@ -2911,8 +2960,13 @@
2911 2960 if (status)
2912 2961 goto out;
2913 2962 renew_client(stp->st_stateowner->so_client);
2914   - if (filpp)
2915   - *filpp = stp->st_vfs_file;
  2963 + if (filpp) {
  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 2971 status = nfs_ok;
2918 2972 out:
... ... @@ -3148,8 +3202,7 @@
3148 3202 goto out;
3149 3203 }
3150 3204 set_access(&share_access, stp->st_access_bmap);
3151   - nfs4_file_downgrade(stp->st_vfs_file,
3152   - share_access & ~od->od_share_access);
  3205 + nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access);
3153 3206  
3154 3207 reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap);
3155 3208 reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);
... ... @@ -3468,7 +3521,6 @@
3468 3521 stp->st_stateid.si_stateownerid = sop->so_id;
3469 3522 stp->st_stateid.si_fileid = fp->fi_id;
3470 3523 stp->st_stateid.si_generation = 0;
3471   - stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */
3472 3524 stp->st_deny_bmap = open_stp->st_deny_bmap;
3473 3525 stp->st_openstp = open_stp;
3474 3526  
... ... @@ -3568,7 +3620,6 @@
3568 3620 lock_sop = lock->lk_replay_owner;
3569 3621 }
3570 3622 /* lock->lk_replay_owner and lock_stp have been created or found */
3571   - filp = lock_stp->st_vfs_file;
3572 3623  
3573 3624 status = nfserr_grace;
3574 3625 if (locks_in_grace() && !lock->lk_reclaim)
3575 3626  
... ... @@ -3581,11 +3632,13 @@
3581 3632 switch (lock->lk_type) {
3582 3633 case NFS4_READ_LT:
3583 3634 case NFS4_READW_LT:
  3635 + filp = find_readable_file(lock_stp->st_file);
3584 3636 file_lock.fl_type = F_RDLCK;
3585 3637 cmd = F_SETLK;
3586 3638 break;
3587 3639 case NFS4_WRITE_LT:
3588 3640 case NFS4_WRITEW_LT:
  3641 + filp = find_writeable_file(lock_stp->st_file);
3589 3642 file_lock.fl_type = F_WRLCK;
3590 3643 cmd = F_SETLK;
3591 3644 break;
... ... @@ -3593,6 +3646,10 @@
3593 3646 status = nfserr_inval;
3594 3647 goto out;
3595 3648 }
  3649 + if (!filp) {
  3650 + status = nfserr_openmode;
  3651 + goto out;
  3652 + }
3596 3653 file_lock.fl_owner = (fl_owner_t)lock_sop;
3597 3654 file_lock.fl_pid = current->tgid;
3598 3655 file_lock.fl_file = filp;
... ... @@ -3761,7 +3818,11 @@
3761 3818 &locku->lu_stateowner, &stp, NULL)))
3762 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 3826 BUG_ON(!filp);
3766 3827 locks_init_lock(&file_lock);
3767 3828 file_lock.fl_type = F_UNLCK;
3768 3829  
... ... @@ -3808,10 +3869,10 @@
3808 3869 * 0: no locks held by lockowner
3809 3870 */
3810 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 3874 struct file_lock **flpp;
3814   - struct inode *inode = filp->f_path.dentry->d_inode;
  3875 + struct inode *inode = filp->fi_inode;
3815 3876 int status = 0;
3816 3877  
3817 3878 lock_kernel();
... ... @@ -3862,7 +3923,7 @@
3862 3923 continue;
3863 3924 list_for_each_entry(stp, &sop->so_stateids,
3864 3925 st_perstateowner) {
3865   - if (check_for_locks(stp->st_vfs_file, sop))
  3926 + if (check_for_locks(stp->st_file, sop))
3866 3927 goto out;
3867 3928 /* Note: so_perclient unused for lockowners,
3868 3929 * so it's OK to fool with here. */
... ... @@ -153,6 +153,7 @@
153 153 #define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID)
154 154 #define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK)
155 155 #define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME)
  156 +#define nfserr_lock_range cpu_to_be32(NFSERR_LOCK_RANGE)
156 157 #define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH)
157 158 #define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP)
158 159 #define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR)
... ... @@ -88,7 +88,6 @@
88 88 struct nfs4_client *dl_client;
89 89 struct nfs4_file *dl_file;
90 90 struct file_lock *dl_flock;
91   - struct file *dl_vfs_file;
92 91 u32 dl_type;
93 92 time_t dl_time;
94 93 /* For recall: */
95 94  
... ... @@ -342,12 +341,50 @@
342 341 struct list_head fi_hash; /* hash by "struct inode *" */
343 342 struct list_head fi_stateids;
344 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 356 struct inode *fi_inode;
346 357 u32 fi_id; /* used with stateowner->so_id
347 358 * for stateid_hashtbl hash */
348 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? */
  364 +static 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 +
  371 +static 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 +
  378 +static 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 389 * nfs4_stateid can either be an open stateid or (eventually) a lock stateid
353 390 *
... ... @@ -373,7 +410,6 @@
373 410 struct nfs4_stateowner * st_stateowner;
374 411 struct nfs4_file * st_file;
375 412 stateid_t st_stateid;
376   - struct file * st_vfs_file;
377 413 unsigned long st_access_bmap;
378 414 unsigned long st_deny_bmap;
379 415 struct nfs4_stateid * st_openstp;