diff options
| -rw-r--r-- | fs/nfsd/nfs4state.c | 303 | ||||
| -rw-r--r-- | fs/nfsd/nfsd.h | 1 | ||||
| -rw-r--r-- | fs/nfsd/state.h | 40 |
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]; | |||
| 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. */ |
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? */ | ||
| 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 | * 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; |
