diff options
| -rw-r--r-- | fs/nfs/pagelist.c | 29 | ||||
| -rw-r--r-- | fs/nfs/read.c | 3 | ||||
| -rw-r--r-- | fs/nfs/write.c | 19 | ||||
| -rw-r--r-- | include/linux/nfs_page.h | 12 |
4 files changed, 45 insertions, 18 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 80777f99a58a..356a33bb38a6 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
| @@ -112,6 +112,33 @@ void nfs_unlock_request(struct nfs_page *req) | |||
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | /** | 114 | /** |
| 115 | * nfs_set_page_writeback_locked - Lock a request for writeback | ||
| 116 | * @req: | ||
| 117 | */ | ||
| 118 | int nfs_set_page_writeback_locked(struct nfs_page *req) | ||
| 119 | { | ||
| 120 | struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | ||
| 121 | |||
| 122 | if (!nfs_lock_request(req)) | ||
| 123 | return 0; | ||
| 124 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); | ||
| 125 | return 1; | ||
| 126 | } | ||
| 127 | |||
| 128 | /** | ||
| 129 | * nfs_clear_page_writeback - Unlock request and wake up sleepers | ||
| 130 | */ | ||
| 131 | void nfs_clear_page_writeback(struct nfs_page *req) | ||
| 132 | { | ||
| 133 | struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | ||
| 134 | |||
| 135 | spin_lock(&nfsi->req_lock); | ||
| 136 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); | ||
| 137 | spin_unlock(&nfsi->req_lock); | ||
| 138 | nfs_unlock_request(req); | ||
| 139 | } | ||
| 140 | |||
| 141 | /** | ||
| 115 | * nfs_clear_request - Free up all resources allocated to the request | 142 | * nfs_clear_request - Free up all resources allocated to the request |
| 116 | * @req: | 143 | * @req: |
| 117 | * | 144 | * |
| @@ -301,7 +328,7 @@ nfs_scan_list(struct list_head *head, struct list_head *dst, | |||
| 301 | if (req->wb_index > idx_end) | 328 | if (req->wb_index > idx_end) |
| 302 | break; | 329 | break; |
| 303 | 330 | ||
| 304 | if (!nfs_lock_request(req)) | 331 | if (!nfs_set_page_writeback_locked(req)) |
| 305 | continue; | 332 | continue; |
| 306 | nfs_list_remove_request(req); | 333 | nfs_list_remove_request(req); |
| 307 | nfs_list_add_request(req, dst); | 334 | nfs_list_add_request(req, dst); |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index a0042fb58634..6f866b8aa2d5 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
| @@ -173,7 +173,6 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | |||
| 173 | if (len < PAGE_CACHE_SIZE) | 173 | if (len < PAGE_CACHE_SIZE) |
| 174 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | 174 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); |
| 175 | 175 | ||
| 176 | nfs_lock_request(new); | ||
| 177 | nfs_list_add_request(new, &one_request); | 176 | nfs_list_add_request(new, &one_request); |
| 178 | nfs_pagein_one(&one_request, inode); | 177 | nfs_pagein_one(&one_request, inode); |
| 179 | return 0; | 178 | return 0; |
| @@ -185,7 +184,6 @@ static void nfs_readpage_release(struct nfs_page *req) | |||
| 185 | 184 | ||
| 186 | nfs_clear_request(req); | 185 | nfs_clear_request(req); |
| 187 | nfs_release_request(req); | 186 | nfs_release_request(req); |
| 188 | nfs_unlock_request(req); | ||
| 189 | 187 | ||
| 190 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", | 188 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", |
| 191 | req->wb_context->dentry->d_inode->i_sb->s_id, | 189 | req->wb_context->dentry->d_inode->i_sb->s_id, |
| @@ -553,7 +551,6 @@ readpage_async_filler(void *data, struct page *page) | |||
| 553 | } | 551 | } |
| 554 | if (len < PAGE_CACHE_SIZE) | 552 | if (len < PAGE_CACHE_SIZE) |
| 555 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | 553 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); |
| 556 | nfs_lock_request(new); | ||
| 557 | nfs_list_add_request(new, desc->head); | 554 | nfs_list_add_request(new, desc->head); |
| 558 | return 0; | 555 | return 0; |
| 559 | } | 556 | } |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 79b621a545b2..58a39b0486a7 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -503,13 +503,12 @@ nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int | |||
| 503 | 503 | ||
| 504 | spin_lock(&nfsi->req_lock); | 504 | spin_lock(&nfsi->req_lock); |
| 505 | next = idx_start; | 505 | next = idx_start; |
| 506 | while (radix_tree_gang_lookup(&nfsi->nfs_page_tree, (void **)&req, next, 1)) { | 506 | while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_WRITEBACK)) { |
| 507 | if (req->wb_index > idx_end) | 507 | if (req->wb_index > idx_end) |
| 508 | break; | 508 | break; |
| 509 | 509 | ||
| 510 | next = req->wb_index + 1; | 510 | next = req->wb_index + 1; |
| 511 | if (!NFS_WBACK_BUSY(req)) | 511 | BUG_ON(!NFS_WBACK_BUSY(req)); |
| 512 | continue; | ||
| 513 | 512 | ||
| 514 | atomic_inc(&req->wb_count); | 513 | atomic_inc(&req->wb_count); |
| 515 | spin_unlock(&nfsi->req_lock); | 514 | spin_unlock(&nfsi->req_lock); |
| @@ -821,7 +820,7 @@ out: | |||
| 821 | #else | 820 | #else |
| 822 | nfs_inode_remove_request(req); | 821 | nfs_inode_remove_request(req); |
| 823 | #endif | 822 | #endif |
| 824 | nfs_unlock_request(req); | 823 | nfs_clear_page_writeback(req); |
| 825 | } | 824 | } |
| 826 | 825 | ||
| 827 | static inline int flush_task_priority(int how) | 826 | static inline int flush_task_priority(int how) |
| @@ -952,7 +951,7 @@ out_bad: | |||
| 952 | nfs_writedata_free(data); | 951 | nfs_writedata_free(data); |
| 953 | } | 952 | } |
| 954 | nfs_mark_request_dirty(req); | 953 | nfs_mark_request_dirty(req); |
| 955 | nfs_unlock_request(req); | 954 | nfs_clear_page_writeback(req); |
| 956 | return -ENOMEM; | 955 | return -ENOMEM; |
| 957 | } | 956 | } |
| 958 | 957 | ||
| @@ -1002,7 +1001,7 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) | |||
| 1002 | struct nfs_page *req = nfs_list_entry(head->next); | 1001 | struct nfs_page *req = nfs_list_entry(head->next); |
| 1003 | nfs_list_remove_request(req); | 1002 | nfs_list_remove_request(req); |
| 1004 | nfs_mark_request_dirty(req); | 1003 | nfs_mark_request_dirty(req); |
| 1005 | nfs_unlock_request(req); | 1004 | nfs_clear_page_writeback(req); |
| 1006 | } | 1005 | } |
| 1007 | return -ENOMEM; | 1006 | return -ENOMEM; |
| 1008 | } | 1007 | } |
| @@ -1029,7 +1028,7 @@ nfs_flush_list(struct list_head *head, int wpages, int how) | |||
| 1029 | req = nfs_list_entry(head->next); | 1028 | req = nfs_list_entry(head->next); |
| 1030 | nfs_list_remove_request(req); | 1029 | nfs_list_remove_request(req); |
| 1031 | nfs_mark_request_dirty(req); | 1030 | nfs_mark_request_dirty(req); |
| 1032 | nfs_unlock_request(req); | 1031 | nfs_clear_page_writeback(req); |
| 1033 | } | 1032 | } |
| 1034 | return error; | 1033 | return error; |
| 1035 | } | 1034 | } |
| @@ -1121,7 +1120,7 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | |||
| 1121 | nfs_inode_remove_request(req); | 1120 | nfs_inode_remove_request(req); |
| 1122 | #endif | 1121 | #endif |
| 1123 | next: | 1122 | next: |
| 1124 | nfs_unlock_request(req); | 1123 | nfs_clear_page_writeback(req); |
| 1125 | } | 1124 | } |
| 1126 | } | 1125 | } |
| 1127 | 1126 | ||
| @@ -1278,7 +1277,7 @@ nfs_commit_list(struct list_head *head, int how) | |||
| 1278 | req = nfs_list_entry(head->next); | 1277 | req = nfs_list_entry(head->next); |
| 1279 | nfs_list_remove_request(req); | 1278 | nfs_list_remove_request(req); |
| 1280 | nfs_mark_request_commit(req); | 1279 | nfs_mark_request_commit(req); |
| 1281 | nfs_unlock_request(req); | 1280 | nfs_clear_page_writeback(req); |
| 1282 | } | 1281 | } |
| 1283 | return -ENOMEM; | 1282 | return -ENOMEM; |
| 1284 | } | 1283 | } |
| @@ -1324,7 +1323,7 @@ nfs_commit_done(struct rpc_task *task) | |||
| 1324 | dprintk(" mismatch\n"); | 1323 | dprintk(" mismatch\n"); |
| 1325 | nfs_mark_request_dirty(req); | 1324 | nfs_mark_request_dirty(req); |
| 1326 | next: | 1325 | next: |
| 1327 | nfs_unlock_request(req); | 1326 | nfs_clear_page_writeback(req); |
| 1328 | res++; | 1327 | res++; |
| 1329 | } | 1328 | } |
| 1330 | sub_page_state(nr_unstable,res); | 1329 | sub_page_state(nr_unstable,res); |
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 39e4895bcdb4..db40e4590ba2 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h | |||
| @@ -20,6 +20,11 @@ | |||
| 20 | #include <asm/atomic.h> | 20 | #include <asm/atomic.h> |
| 21 | 21 | ||
| 22 | /* | 22 | /* |
| 23 | * Valid flags for the radix tree | ||
| 24 | */ | ||
| 25 | #define NFS_PAGE_TAG_WRITEBACK 1 | ||
| 26 | |||
| 27 | /* | ||
| 23 | * Valid flags for a dirty buffer | 28 | * Valid flags for a dirty buffer |
| 24 | */ | 29 | */ |
| 25 | #define PG_BUSY 0 | 30 | #define PG_BUSY 0 |
| @@ -62,6 +67,9 @@ extern int nfs_coalesce_requests(struct list_head *, struct list_head *, | |||
| 62 | unsigned int); | 67 | unsigned int); |
| 63 | extern int nfs_wait_on_request(struct nfs_page *); | 68 | extern int nfs_wait_on_request(struct nfs_page *); |
| 64 | extern void nfs_unlock_request(struct nfs_page *req); | 69 | extern void nfs_unlock_request(struct nfs_page *req); |
| 70 | extern int nfs_set_page_writeback_locked(struct nfs_page *req); | ||
| 71 | extern void nfs_clear_page_writeback(struct nfs_page *req); | ||
| 72 | |||
| 65 | 73 | ||
| 66 | /* | 74 | /* |
| 67 | * Lock the page of an asynchronous request without incrementing the wb_count | 75 | * Lock the page of an asynchronous request without incrementing the wb_count |
| @@ -96,10 +104,6 @@ nfs_list_remove_request(struct nfs_page *req) | |||
| 96 | { | 104 | { |
| 97 | if (list_empty(&req->wb_list)) | 105 | if (list_empty(&req->wb_list)) |
| 98 | return; | 106 | return; |
| 99 | if (!NFS_WBACK_BUSY(req)) { | ||
| 100 | printk(KERN_ERR "NFS: unlocked request attempted removed from list!\n"); | ||
| 101 | BUG(); | ||
| 102 | } | ||
| 103 | list_del_init(&req->wb_list); | 107 | list_del_init(&req->wb_list); |
| 104 | req->wb_list_head = NULL; | 108 | req->wb_list_head = NULL; |
| 105 | } | 109 | } |
