diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-04-14 19:10:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-15 00:46:48 -0400 |
commit | 5a6d41b32a17ca902ef50fdfa170d7f23264bad5 (patch) | |
tree | 1a380f2e7fe7858da3dfb53ec85e3d4b100c948f | |
parent | 60fa3f769f7651a60125a0f44e3ffe3246d7cf39 (diff) |
NFS: Ensure PG_writeback is cleared when writeback fails
If the writebacks are cancelled via nfs_cancel_dirty_list, or due to the
memory allocation failing in nfs_flush_one/nfs_flush_multi, then we must
ensure that the PG_writeback flag is cleared.
Also ensure that we actually own the PG_writeback flag whenever we
schedule a new writeback by making nfs_set_page_writeback() return the
value of test_set_page_writeback().
The PG_writeback page flag ends up replacing the functionality of the
PG_FLUSHING nfs_page flag, so we rip that out too.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/nfs/write.c | 22 | ||||
-rw-r--r-- | include/linux/nfs_page.h | 1 |
2 files changed, 15 insertions, 8 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 2867e6b7096f..e5d7cac569aa 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -218,9 +218,11 @@ int nfs_congestion_kb; | |||
218 | #define NFS_CONGESTION_OFF_THRESH \ | 218 | #define NFS_CONGESTION_OFF_THRESH \ |
219 | (NFS_CONGESTION_ON_THRESH - (NFS_CONGESTION_ON_THRESH >> 2)) | 219 | (NFS_CONGESTION_ON_THRESH - (NFS_CONGESTION_ON_THRESH >> 2)) |
220 | 220 | ||
221 | static void nfs_set_page_writeback(struct page *page) | 221 | static int nfs_set_page_writeback(struct page *page) |
222 | { | 222 | { |
223 | if (!test_set_page_writeback(page)) { | 223 | int ret = test_set_page_writeback(page); |
224 | |||
225 | if (!ret) { | ||
224 | struct inode *inode = page->mapping->host; | 226 | struct inode *inode = page->mapping->host; |
225 | struct nfs_server *nfss = NFS_SERVER(inode); | 227 | struct nfs_server *nfss = NFS_SERVER(inode); |
226 | 228 | ||
@@ -228,6 +230,7 @@ static void nfs_set_page_writeback(struct page *page) | |||
228 | NFS_CONGESTION_ON_THRESH) | 230 | NFS_CONGESTION_ON_THRESH) |
229 | set_bdi_congested(&nfss->backing_dev_info, WRITE); | 231 | set_bdi_congested(&nfss->backing_dev_info, WRITE); |
230 | } | 232 | } |
233 | return ret; | ||
231 | } | 234 | } |
232 | 235 | ||
233 | static void nfs_end_page_writeback(struct page *page) | 236 | static void nfs_end_page_writeback(struct page *page) |
@@ -277,10 +280,8 @@ static int nfs_page_mark_flush(struct page *page) | |||
277 | spin_lock(req_lock); | 280 | spin_lock(req_lock); |
278 | } | 281 | } |
279 | spin_unlock(req_lock); | 282 | spin_unlock(req_lock); |
280 | if (test_and_set_bit(PG_FLUSHING, &req->wb_flags) == 0) { | 283 | if (nfs_set_page_writeback(page) == 0) |
281 | nfs_mark_request_dirty(req); | 284 | nfs_mark_request_dirty(req); |
282 | nfs_set_page_writeback(page); | ||
283 | } | ||
284 | ret = test_bit(PG_NEED_FLUSH, &req->wb_flags); | 285 | ret = test_bit(PG_NEED_FLUSH, &req->wb_flags); |
285 | nfs_unlock_request(req); | 286 | nfs_unlock_request(req); |
286 | return ret; | 287 | return ret; |
@@ -424,7 +425,6 @@ nfs_mark_request_dirty(struct nfs_page *req) | |||
424 | static void | 425 | static void |
425 | nfs_redirty_request(struct nfs_page *req) | 426 | nfs_redirty_request(struct nfs_page *req) |
426 | { | 427 | { |
427 | clear_bit(PG_FLUSHING, &req->wb_flags); | ||
428 | __set_page_dirty_nobuffers(req->wb_page); | 428 | __set_page_dirty_nobuffers(req->wb_page); |
429 | } | 429 | } |
430 | 430 | ||
@@ -434,7 +434,11 @@ nfs_redirty_request(struct nfs_page *req) | |||
434 | static inline int | 434 | static inline int |
435 | nfs_dirty_request(struct nfs_page *req) | 435 | nfs_dirty_request(struct nfs_page *req) |
436 | { | 436 | { |
437 | return test_bit(PG_FLUSHING, &req->wb_flags) == 0; | 437 | struct page *page = req->wb_page; |
438 | |||
439 | if (page == NULL) | ||
440 | return 0; | ||
441 | return !PageWriteback(req->wb_page); | ||
438 | } | 442 | } |
439 | 443 | ||
440 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 444 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
@@ -500,6 +504,7 @@ static void nfs_cancel_dirty_list(struct list_head *head) | |||
500 | while(!list_empty(head)) { | 504 | while(!list_empty(head)) { |
501 | req = nfs_list_entry(head->next); | 505 | req = nfs_list_entry(head->next); |
502 | nfs_list_remove_request(req); | 506 | nfs_list_remove_request(req); |
507 | nfs_end_page_writeback(req->wb_page); | ||
503 | nfs_inode_remove_request(req); | 508 | nfs_inode_remove_request(req); |
504 | nfs_clear_page_writeback(req); | 509 | nfs_clear_page_writeback(req); |
505 | } | 510 | } |
@@ -890,6 +895,7 @@ out_bad: | |||
890 | list_del(&data->pages); | 895 | list_del(&data->pages); |
891 | nfs_writedata_release(data); | 896 | nfs_writedata_release(data); |
892 | } | 897 | } |
898 | nfs_end_page_writeback(req->wb_page); | ||
893 | nfs_redirty_request(req); | 899 | nfs_redirty_request(req); |
894 | nfs_clear_page_writeback(req); | 900 | nfs_clear_page_writeback(req); |
895 | return -ENOMEM; | 901 | return -ENOMEM; |
@@ -935,6 +941,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, int how) | |||
935 | while (!list_empty(head)) { | 941 | while (!list_empty(head)) { |
936 | struct nfs_page *req = nfs_list_entry(head->next); | 942 | struct nfs_page *req = nfs_list_entry(head->next); |
937 | nfs_list_remove_request(req); | 943 | nfs_list_remove_request(req); |
944 | nfs_end_page_writeback(req->wb_page); | ||
938 | nfs_redirty_request(req); | 945 | nfs_redirty_request(req); |
939 | nfs_clear_page_writeback(req); | 946 | nfs_clear_page_writeback(req); |
940 | } | 947 | } |
@@ -970,6 +977,7 @@ out_err: | |||
970 | while (!list_empty(head)) { | 977 | while (!list_empty(head)) { |
971 | req = nfs_list_entry(head->next); | 978 | req = nfs_list_entry(head->next); |
972 | nfs_list_remove_request(req); | 979 | nfs_list_remove_request(req); |
980 | nfs_end_page_writeback(req->wb_page); | ||
973 | nfs_redirty_request(req); | 981 | nfs_redirty_request(req); |
974 | nfs_clear_page_writeback(req); | 982 | nfs_clear_page_writeback(req); |
975 | } | 983 | } |
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 2e555d49c9b7..d111be639140 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h | |||
@@ -31,7 +31,6 @@ | |||
31 | #define PG_NEED_COMMIT 1 | 31 | #define PG_NEED_COMMIT 1 |
32 | #define PG_NEED_RESCHED 2 | 32 | #define PG_NEED_RESCHED 2 |
33 | #define PG_NEED_FLUSH 3 | 33 | #define PG_NEED_FLUSH 3 |
34 | #define PG_FLUSHING 4 | ||
35 | 34 | ||
36 | struct nfs_inode; | 35 | struct nfs_inode; |
37 | struct nfs_page { | 36 | struct nfs_page { |