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 /fs | |
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>
Diffstat (limited to 'fs')
-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 | /* |