|
@@ -460,6 +460,43 @@ nfs_mark_request_commit(struct nfs_page *req)
|
|
|
inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
|
|
|
__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
|
|
|
}
|
|
|
+
|
|
|
+static inline
|
|
|
+int nfs_write_need_commit(struct nfs_write_data *data)
|
|
|
+{
|
|
|
+ return data->verf.committed != NFS_FILE_SYNC;
|
|
|
+}
|
|
|
+
|
|
|
+static inline
|
|
|
+int nfs_reschedule_unstable_write(struct nfs_page *req)
|
|
|
+{
|
|
|
+ if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) {
|
|
|
+ nfs_mark_request_commit(req);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) {
|
|
|
+ nfs_redirty_request(req);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#else
|
|
|
+static inline void
|
|
|
+nfs_mark_request_commit(struct nfs_page *req)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+static inline
|
|
|
+int nfs_write_need_commit(struct nfs_write_data *data)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static inline
|
|
|
+int nfs_reschedule_unstable_write(struct nfs_page *req)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
@@ -746,26 +783,12 @@ int nfs_updatepage(struct file *file, struct page *page,
|
|
|
|
|
|
static void nfs_writepage_release(struct nfs_page *req)
|
|
|
{
|
|
|
- nfs_end_page_writeback(req->wb_page);
|
|
|
|
|
|
-#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
|
|
|
- if (!PageError(req->wb_page)) {
|
|
|
- if (NFS_NEED_RESCHED(req)) {
|
|
|
- nfs_redirty_request(req);
|
|
|
- goto out;
|
|
|
- } else if (NFS_NEED_COMMIT(req)) {
|
|
|
- nfs_mark_request_commit(req);
|
|
|
- goto out;
|
|
|
- }
|
|
|
- }
|
|
|
- nfs_inode_remove_request(req);
|
|
|
-
|
|
|
-out:
|
|
|
- nfs_clear_commit(req);
|
|
|
- nfs_clear_reschedule(req);
|
|
|
-#else
|
|
|
- nfs_inode_remove_request(req);
|
|
|
-#endif
|
|
|
+ if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) {
|
|
|
+ nfs_end_page_writeback(req->wb_page);
|
|
|
+ nfs_inode_remove_request(req);
|
|
|
+ } else
|
|
|
+ nfs_end_page_writeback(req->wb_page);
|
|
|
nfs_clear_page_writeback(req);
|
|
|
}
|
|
|
|
|
@@ -1008,22 +1031,28 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
|
|
|
nfs_set_pageerror(page);
|
|
|
req->wb_context->error = task->tk_status;
|
|
|
dprintk(", error = %d\n", task->tk_status);
|
|
|
- } else {
|
|
|
-#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
|
|
|
- if (data->verf.committed < NFS_FILE_SYNC) {
|
|
|
- if (!NFS_NEED_COMMIT(req)) {
|
|
|
- nfs_defer_commit(req);
|
|
|
- memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
|
|
|
- dprintk(" defer commit\n");
|
|
|
- } else if (memcmp(&req->wb_verf, &data->verf, sizeof(req->wb_verf))) {
|
|
|
- nfs_defer_reschedule(req);
|
|
|
- dprintk(" server reboot detected\n");
|
|
|
- }
|
|
|
- } else
|
|
|
-#endif
|
|
|
- dprintk(" OK\n");
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
+ if (nfs_write_need_commit(data)) {
|
|
|
+ spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock;
|
|
|
+
|
|
|
+ spin_lock(req_lock);
|
|
|
+ if (test_bit(PG_NEED_RESCHED, &req->wb_flags)) {
|
|
|
+ /* Do nothing we need to resend the writes */
|
|
|
+ } else if (!test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags)) {
|
|
|
+ memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
|
|
|
+ dprintk(" defer commit\n");
|
|
|
+ } else if (memcmp(&req->wb_verf, &data->verf, sizeof(req->wb_verf))) {
|
|
|
+ set_bit(PG_NEED_RESCHED, &req->wb_flags);
|
|
|
+ clear_bit(PG_NEED_COMMIT, &req->wb_flags);
|
|
|
+ dprintk(" server reboot detected\n");
|
|
|
+ }
|
|
|
+ spin_unlock(req_lock);
|
|
|
+ } else
|
|
|
+ dprintk(" OK\n");
|
|
|
+
|
|
|
+out:
|
|
|
if (atomic_dec_and_test(&req->wb_complete))
|
|
|
nfs_writepage_release(req);
|
|
|
}
|
|
@@ -1064,25 +1093,21 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata)
|
|
|
if (task->tk_status < 0) {
|
|
|
nfs_set_pageerror(page);
|
|
|
req->wb_context->error = task->tk_status;
|
|
|
- nfs_end_page_writeback(page);
|
|
|
- nfs_inode_remove_request(req);
|
|
|
dprintk(", error = %d\n", task->tk_status);
|
|
|
- goto next;
|
|
|
+ goto remove_request;
|
|
|
}
|
|
|
- nfs_end_page_writeback(page);
|
|
|
|
|
|
-#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
|
|
|
- if (data->args.stable != NFS_UNSTABLE || data->verf.committed == NFS_FILE_SYNC) {
|
|
|
- nfs_inode_remove_request(req);
|
|
|
- dprintk(" OK\n");
|
|
|
+ if (nfs_write_need_commit(data)) {
|
|
|
+ memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
|
|
|
+ nfs_mark_request_commit(req);
|
|
|
+ nfs_end_page_writeback(page);
|
|
|
+ dprintk(" marked for commit\n");
|
|
|
goto next;
|
|
|
}
|
|
|
- memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
|
|
|
- nfs_mark_request_commit(req);
|
|
|
- dprintk(" marked for commit\n");
|
|
|
-#else
|
|
|
+ dprintk(" OK\n");
|
|
|
+remove_request:
|
|
|
+ nfs_end_page_writeback(page);
|
|
|
nfs_inode_remove_request(req);
|
|
|
-#endif
|
|
|
next:
|
|
|
nfs_clear_page_writeback(req);
|
|
|
}
|