diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-10-18 18:03:27 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-10-19 17:19:25 -0400 |
| commit | a49c3c7736a2e77931dabc5bc4a83fb4b2da013e (patch) | |
| tree | 1921900be210540ee53a4011c9e8f781deb0367e | |
| parent | 565277f63c616e11c37309a1e98c052d18ebbb55 (diff) | |
NFSv4: Ensure that we wait for the CLOSE request to complete
Otherwise, we do end up breaking close-to-open semantics. We also end up
breaking some of the silly-rename tests in Connectathon on some setups.
Please refer to the bug-report at
http://bugzilla.linux-nfs.org/show_bug.cgi?id=150
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
| -rw-r--r-- | fs/nfs/file.c | 2 | ||||
| -rw-r--r-- | fs/nfs/inode.c | 22 | ||||
| -rw-r--r-- | fs/nfs/nfs4_fs.h | 3 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 13 | ||||
| -rw-r--r-- | fs/nfs/nfs4state.c | 14 |
5 files changed, 41 insertions, 13 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index d29f90d00aa2..b3bb89f7d5d2 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
| @@ -131,7 +131,7 @@ nfs_file_release(struct inode *inode, struct file *filp) | |||
| 131 | { | 131 | { |
| 132 | /* Ensure that dirty pages are flushed out with the right creds */ | 132 | /* Ensure that dirty pages are flushed out with the right creds */ |
| 133 | if (filp->f_mode & FMODE_WRITE) | 133 | if (filp->f_mode & FMODE_WRITE) |
| 134 | filemap_fdatawrite(filp->f_mapping); | 134 | nfs_wb_all(filp->f_path.dentry->d_inode); |
| 135 | nfs_inc_stats(inode, NFSIOS_VFSRELEASE); | 135 | nfs_inc_stats(inode, NFSIOS_VFSRELEASE); |
| 136 | return NFS_PROTO(inode)->file_release(inode, filp); | 136 | return NFS_PROTO(inode)->file_release(inode, filp); |
| 137 | } | 137 | } |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 173e294dffc5..db5d96dc6107 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -514,7 +514,7 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) | |||
| 514 | return ctx; | 514 | return ctx; |
| 515 | } | 515 | } |
| 516 | 516 | ||
| 517 | void put_nfs_open_context(struct nfs_open_context *ctx) | 517 | static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait) |
| 518 | { | 518 | { |
| 519 | struct inode *inode = ctx->path.dentry->d_inode; | 519 | struct inode *inode = ctx->path.dentry->d_inode; |
| 520 | 520 | ||
| @@ -522,8 +522,12 @@ void put_nfs_open_context(struct nfs_open_context *ctx) | |||
| 522 | return; | 522 | return; |
| 523 | list_del(&ctx->list); | 523 | list_del(&ctx->list); |
| 524 | spin_unlock(&inode->i_lock); | 524 | spin_unlock(&inode->i_lock); |
| 525 | if (ctx->state != NULL) | 525 | if (ctx->state != NULL) { |
| 526 | nfs4_close_state(&ctx->path, ctx->state, ctx->mode); | 526 | if (wait) |
| 527 | nfs4_close_sync(&ctx->path, ctx->state, ctx->mode); | ||
| 528 | else | ||
| 529 | nfs4_close_state(&ctx->path, ctx->state, ctx->mode); | ||
| 530 | } | ||
| 527 | if (ctx->cred != NULL) | 531 | if (ctx->cred != NULL) |
| 528 | put_rpccred(ctx->cred); | 532 | put_rpccred(ctx->cred); |
| 529 | dput(ctx->path.dentry); | 533 | dput(ctx->path.dentry); |
| @@ -531,6 +535,16 @@ void put_nfs_open_context(struct nfs_open_context *ctx) | |||
| 531 | kfree(ctx); | 535 | kfree(ctx); |
| 532 | } | 536 | } |
| 533 | 537 | ||
| 538 | void put_nfs_open_context(struct nfs_open_context *ctx) | ||
| 539 | { | ||
| 540 | __put_nfs_open_context(ctx, 0); | ||
| 541 | } | ||
| 542 | |||
| 543 | static void put_nfs_open_context_sync(struct nfs_open_context *ctx) | ||
| 544 | { | ||
| 545 | __put_nfs_open_context(ctx, 1); | ||
| 546 | } | ||
| 547 | |||
| 534 | /* | 548 | /* |
| 535 | * Ensure that mmap has a recent RPC credential for use when writing out | 549 | * Ensure that mmap has a recent RPC credential for use when writing out |
| 536 | * shared pages | 550 | * shared pages |
| @@ -577,7 +591,7 @@ static void nfs_file_clear_open_context(struct file *filp) | |||
| 577 | spin_lock(&inode->i_lock); | 591 | spin_lock(&inode->i_lock); |
| 578 | list_move_tail(&ctx->list, &NFS_I(inode)->open_files); | 592 | list_move_tail(&ctx->list, &NFS_I(inode)->open_files); |
| 579 | spin_unlock(&inode->i_lock); | 593 | spin_unlock(&inode->i_lock); |
| 580 | put_nfs_open_context(ctx); | 594 | put_nfs_open_context_sync(ctx); |
| 581 | } | 595 | } |
| 582 | } | 596 | } |
| 583 | 597 | ||
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index d2802b1ca3b9..a4e3b961b63b 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
| @@ -178,7 +178,7 @@ extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struc | |||
| 178 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); | 178 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); |
| 179 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); | 179 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); |
| 180 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); | 180 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); |
| 181 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state); | 181 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); |
| 182 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | 182 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); |
| 183 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); | 183 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); |
| 184 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); | 184 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); |
| @@ -209,6 +209,7 @@ extern void nfs4_drop_state_owner(struct nfs4_state_owner *); | |||
| 209 | extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); | 209 | extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); |
| 210 | extern void nfs4_put_open_state(struct nfs4_state *); | 210 | extern void nfs4_put_open_state(struct nfs4_state *); |
| 211 | extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t); | 211 | extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t); |
| 212 | extern void nfs4_close_sync(struct path *, struct nfs4_state *, mode_t); | ||
| 212 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); | 213 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); |
| 213 | extern void nfs4_schedule_state_recovery(struct nfs_client *); | 214 | extern void nfs4_schedule_state_recovery(struct nfs_client *); |
| 214 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 215 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 2cb3b8b71ee7..f03d9d5f5ba4 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -1305,7 +1305,7 @@ static const struct rpc_call_ops nfs4_close_ops = { | |||
| 1305 | * | 1305 | * |
| 1306 | * NOTE: Caller must be holding the sp->so_owner semaphore! | 1306 | * NOTE: Caller must be holding the sp->so_owner semaphore! |
| 1307 | */ | 1307 | */ |
| 1308 | int nfs4_do_close(struct path *path, struct nfs4_state *state) | 1308 | int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) |
| 1309 | { | 1309 | { |
| 1310 | struct nfs_server *server = NFS_SERVER(state->inode); | 1310 | struct nfs_server *server = NFS_SERVER(state->inode); |
| 1311 | struct nfs4_closedata *calldata; | 1311 | struct nfs4_closedata *calldata; |
| @@ -1333,8 +1333,11 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state) | |||
| 1333 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_close_ops, calldata); | 1333 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_close_ops, calldata); |
| 1334 | if (IS_ERR(task)) | 1334 | if (IS_ERR(task)) |
| 1335 | return PTR_ERR(task); | 1335 | return PTR_ERR(task); |
| 1336 | status = 0; | ||
| 1337 | if (wait) | ||
| 1338 | status = rpc_wait_for_completion_task(task); | ||
| 1336 | rpc_put_task(task); | 1339 | rpc_put_task(task); |
| 1337 | return 0; | 1340 | return status; |
| 1338 | out_free_calldata: | 1341 | out_free_calldata: |
| 1339 | kfree(calldata); | 1342 | kfree(calldata); |
| 1340 | out: | 1343 | out: |
| @@ -1365,7 +1368,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct | |||
| 1365 | } | 1368 | } |
| 1366 | ret = PTR_ERR(filp); | 1369 | ret = PTR_ERR(filp); |
| 1367 | out_close: | 1370 | out_close: |
| 1368 | nfs4_close_state(path, state, nd->intent.open.flags); | 1371 | nfs4_close_sync(path, state, nd->intent.open.flags); |
| 1369 | return ret; | 1372 | return ret; |
| 1370 | } | 1373 | } |
| 1371 | 1374 | ||
| @@ -1450,7 +1453,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
| 1450 | nfs4_intent_set_file(nd, &path, state); | 1453 | nfs4_intent_set_file(nd, &path, state); |
| 1451 | return 1; | 1454 | return 1; |
| 1452 | } | 1455 | } |
| 1453 | nfs4_close_state(&path, state, openflags); | 1456 | nfs4_close_sync(&path, state, openflags); |
| 1454 | out_drop: | 1457 | out_drop: |
| 1455 | d_drop(dentry); | 1458 | d_drop(dentry); |
| 1456 | return 0; | 1459 | return 0; |
| @@ -1904,7 +1907,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
| 1904 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) | 1907 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) |
| 1905 | status = nfs4_intent_set_file(nd, &path, state); | 1908 | status = nfs4_intent_set_file(nd, &path, state); |
| 1906 | else | 1909 | else |
| 1907 | nfs4_close_state(&path, state, flags); | 1910 | nfs4_close_sync(&path, state, flags); |
| 1908 | out: | 1911 | out: |
| 1909 | return status; | 1912 | return status; |
| 1910 | } | 1913 | } |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index bfb36261cecb..23a9a36556bf 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
| @@ -425,7 +425,7 @@ void nfs4_put_open_state(struct nfs4_state *state) | |||
| 425 | /* | 425 | /* |
| 426 | * Close the current file. | 426 | * Close the current file. |
| 427 | */ | 427 | */ |
| 428 | void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) | 428 | static void __nfs4_close(struct path *path, struct nfs4_state *state, mode_t mode, int wait) |
| 429 | { | 429 | { |
| 430 | struct nfs4_state_owner *owner = state->owner; | 430 | struct nfs4_state_owner *owner = state->owner; |
| 431 | int call_close = 0; | 431 | int call_close = 0; |
| @@ -466,7 +466,17 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) | |||
| 466 | nfs4_put_open_state(state); | 466 | nfs4_put_open_state(state); |
| 467 | nfs4_put_state_owner(owner); | 467 | nfs4_put_state_owner(owner); |
| 468 | } else | 468 | } else |
| 469 | nfs4_do_close(path, state); | 469 | nfs4_do_close(path, state, wait); |
| 470 | } | ||
| 471 | |||
| 472 | void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) | ||
| 473 | { | ||
| 474 | __nfs4_close(path, state, mode, 0); | ||
| 475 | } | ||
| 476 | |||
| 477 | void nfs4_close_sync(struct path *path, struct nfs4_state *state, mode_t mode) | ||
| 478 | { | ||
| 479 | __nfs4_close(path, state, mode, 1); | ||
| 470 | } | 480 | } |
| 471 | 481 | ||
| 472 | /* | 482 | /* |
