diff options
author | Chuck Lever <cel@netapp.com> | 2006-06-20 12:55:45 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-06-24 13:11:38 -0400 |
commit | fedb595c66e1fbd5acafe0d43b7e95c13c936d61 (patch) | |
tree | e865ecc2399c09b7164c2f2c13a2c5c10c8d4de1 /fs/nfs | |
parent | b1c5921c5b715c207d7fe77cd7aaafbb322f09f5 (diff) |
NFS: "open code" the NFS direct write rescheduler
An NFSv3/v4 client must reschedule on-the-wire writes if the writes are
UNSTABLE, and the server reboots before the client can complete a
subsequent COMMIT request.
To support direct asynchronous scatter-gather writes, the write
rescheduler in fs/nfs/direct.c must not depend on the I/O parameters
in the controlling nfs_direct_req structure. iovecs can be somewhat
arbitrarily complex, so there could be an unbounded amount of information
to save for a rarely encountered requirement.
Refactor the direct write rescheduler so it uses information from each
nfs_write_data structure to reschedule writes, instead of caching that
information in the controlling nfs_direct_req structure.
Signed-off-by: Chuck Lever <cel@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/direct.c | 51 |
1 files changed, 43 insertions, 8 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index d78c61a41ec3..7101405713e1 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -94,8 +94,8 @@ struct nfs_direct_req { | |||
94 | struct nfs_writeverf verf; /* unstable write verifier */ | 94 | struct nfs_writeverf verf; /* unstable write verifier */ |
95 | }; | 95 | }; |
96 | 96 | ||
97 | static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync); | ||
98 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode); | 97 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode); |
98 | static const struct rpc_call_ops nfs_write_direct_ops; | ||
99 | 99 | ||
100 | static inline void get_dreq(struct nfs_direct_req *dreq) | 100 | static inline void get_dreq(struct nfs_direct_req *dreq) |
101 | { | 101 | { |
@@ -435,14 +435,51 @@ static void nfs_direct_free_writedata(struct nfs_direct_req *dreq) | |||
435 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 435 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
436 | static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | 436 | static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) |
437 | { | 437 | { |
438 | struct list_head *pos; | 438 | struct inode *inode = dreq->inode; |
439 | struct list_head *p; | ||
440 | struct nfs_write_data *data; | ||
439 | 441 | ||
440 | list_splice_init(&dreq->rewrite_list, &dreq->list); | ||
441 | list_for_each(pos, &dreq->list) | ||
442 | get_dreq(dreq); | ||
443 | dreq->count = 0; | 442 | dreq->count = 0; |
443 | get_dreq(dreq); | ||
444 | |||
445 | list_for_each(p, &dreq->rewrite_list) { | ||
446 | data = list_entry(p, struct nfs_write_data, pages); | ||
447 | |||
448 | get_dreq(dreq); | ||
449 | |||
450 | /* | ||
451 | * Reset data->res. | ||
452 | */ | ||
453 | nfs_fattr_init(&data->fattr); | ||
454 | data->res.count = data->args.count; | ||
455 | memset(&data->verf, 0, sizeof(data->verf)); | ||
456 | |||
457 | /* | ||
458 | * Reuse data->task; data->args should not have changed | ||
459 | * since the original request was sent. | ||
460 | */ | ||
461 | rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, | ||
462 | &nfs_write_direct_ops, data); | ||
463 | NFS_PROTO(inode)->write_setup(data, FLUSH_STABLE); | ||
464 | |||
465 | data->task.tk_priority = RPC_PRIORITY_NORMAL; | ||
466 | data->task.tk_cookie = (unsigned long) inode; | ||
467 | |||
468 | /* | ||
469 | * We're called via an RPC callback, so BKL is already held. | ||
470 | */ | ||
471 | rpc_execute(&data->task); | ||
472 | |||
473 | dprintk("NFS: %5u rescheduled direct write call (req %s/%Ld, %u bytes @ offset %Lu)\n", | ||
474 | data->task.tk_pid, | ||
475 | inode->i_sb->s_id, | ||
476 | (long long)NFS_FILEID(inode), | ||
477 | data->args.count, | ||
478 | (unsigned long long)data->args.offset); | ||
479 | } | ||
444 | 480 | ||
445 | nfs_direct_write_schedule(dreq, FLUSH_STABLE); | 481 | if (put_dreq(dreq)) |
482 | nfs_direct_write_complete(dreq, inode); | ||
446 | } | 483 | } |
447 | 484 | ||
448 | static void nfs_direct_commit_result(struct rpc_task *task, void *calldata) | 485 | static void nfs_direct_commit_result(struct rpc_task *task, void *calldata) |
@@ -612,8 +649,6 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata) | |||
612 | } | 649 | } |
613 | } | 650 | } |
614 | } | 651 | } |
615 | /* In case we have to resend */ | ||
616 | data->args.stable = NFS_FILE_SYNC; | ||
617 | 652 | ||
618 | spin_unlock(&dreq->lock); | 653 | spin_unlock(&dreq->lock); |
619 | } | 654 | } |