diff options
Diffstat (limited to 'fs/nfs/pagelist.c')
-rw-r--r-- | fs/nfs/pagelist.c | 60 |
1 files changed, 33 insertions, 27 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index c5bb51a29e80..f56dae5216f4 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -85,9 +85,8 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, | |||
85 | req->wb_offset = offset; | 85 | req->wb_offset = offset; |
86 | req->wb_pgbase = offset; | 86 | req->wb_pgbase = offset; |
87 | req->wb_bytes = count; | 87 | req->wb_bytes = count; |
88 | atomic_set(&req->wb_count, 1); | ||
89 | req->wb_context = get_nfs_open_context(ctx); | 88 | req->wb_context = get_nfs_open_context(ctx); |
90 | 89 | kref_init(&req->wb_kref); | |
91 | return req; | 90 | return req; |
92 | } | 91 | } |
93 | 92 | ||
@@ -109,30 +108,31 @@ void nfs_unlock_request(struct nfs_page *req) | |||
109 | } | 108 | } |
110 | 109 | ||
111 | /** | 110 | /** |
112 | * nfs_set_page_writeback_locked - Lock a request for writeback | 111 | * nfs_set_page_tag_locked - Tag a request as locked |
113 | * @req: | 112 | * @req: |
114 | */ | 113 | */ |
115 | int nfs_set_page_writeback_locked(struct nfs_page *req) | 114 | static int nfs_set_page_tag_locked(struct nfs_page *req) |
116 | { | 115 | { |
117 | struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | 116 | struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode); |
118 | 117 | ||
119 | if (!nfs_lock_request(req)) | 118 | if (!nfs_lock_request(req)) |
120 | return 0; | 119 | return 0; |
121 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); | 120 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); |
122 | return 1; | 121 | return 1; |
123 | } | 122 | } |
124 | 123 | ||
125 | /** | 124 | /** |
126 | * nfs_clear_page_writeback - Unlock request and wake up sleepers | 125 | * nfs_clear_page_tag_locked - Clear request tag and wake up sleepers |
127 | */ | 126 | */ |
128 | void nfs_clear_page_writeback(struct nfs_page *req) | 127 | void nfs_clear_page_tag_locked(struct nfs_page *req) |
129 | { | 128 | { |
130 | struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | 129 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
130 | struct nfs_inode *nfsi = NFS_I(inode); | ||
131 | 131 | ||
132 | if (req->wb_page != NULL) { | 132 | if (req->wb_page != NULL) { |
133 | spin_lock(&nfsi->req_lock); | 133 | spin_lock(&inode->i_lock); |
134 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); | 134 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); |
135 | spin_unlock(&nfsi->req_lock); | 135 | spin_unlock(&inode->i_lock); |
136 | } | 136 | } |
137 | nfs_unlock_request(req); | 137 | nfs_unlock_request(req); |
138 | } | 138 | } |
@@ -160,11 +160,9 @@ void nfs_clear_request(struct nfs_page *req) | |||
160 | * | 160 | * |
161 | * Note: Should never be called with the spinlock held! | 161 | * Note: Should never be called with the spinlock held! |
162 | */ | 162 | */ |
163 | void | 163 | static void nfs_free_request(struct kref *kref) |
164 | nfs_release_request(struct nfs_page *req) | ||
165 | { | 164 | { |
166 | if (!atomic_dec_and_test(&req->wb_count)) | 165 | struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref); |
167 | return; | ||
168 | 166 | ||
169 | /* Release struct file or cached credential */ | 167 | /* Release struct file or cached credential */ |
170 | nfs_clear_request(req); | 168 | nfs_clear_request(req); |
@@ -172,6 +170,11 @@ nfs_release_request(struct nfs_page *req) | |||
172 | nfs_page_free(req); | 170 | nfs_page_free(req); |
173 | } | 171 | } |
174 | 172 | ||
173 | void nfs_release_request(struct nfs_page *req) | ||
174 | { | ||
175 | kref_put(&req->wb_kref, nfs_free_request); | ||
176 | } | ||
177 | |||
175 | static int nfs_wait_bit_interruptible(void *word) | 178 | static int nfs_wait_bit_interruptible(void *word) |
176 | { | 179 | { |
177 | int ret = 0; | 180 | int ret = 0; |
@@ -193,7 +196,7 @@ static int nfs_wait_bit_interruptible(void *word) | |||
193 | int | 196 | int |
194 | nfs_wait_on_request(struct nfs_page *req) | 197 | nfs_wait_on_request(struct nfs_page *req) |
195 | { | 198 | { |
196 | struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->dentry->d_inode); | 199 | struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->path.dentry->d_inode); |
197 | sigset_t oldmask; | 200 | sigset_t oldmask; |
198 | int ret = 0; | 201 | int ret = 0; |
199 | 202 | ||
@@ -379,20 +382,20 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) | |||
379 | /** | 382 | /** |
380 | * nfs_scan_list - Scan a list for matching requests | 383 | * nfs_scan_list - Scan a list for matching requests |
381 | * @nfsi: NFS inode | 384 | * @nfsi: NFS inode |
382 | * @head: One of the NFS inode request lists | ||
383 | * @dst: Destination list | 385 | * @dst: Destination list |
384 | * @idx_start: lower bound of page->index to scan | 386 | * @idx_start: lower bound of page->index to scan |
385 | * @npages: idx_start + npages sets the upper bound to scan. | 387 | * @npages: idx_start + npages sets the upper bound to scan. |
388 | * @tag: tag to scan for | ||
386 | * | 389 | * |
387 | * Moves elements from one of the inode request lists. | 390 | * Moves elements from one of the inode request lists. |
388 | * If the number of requests is set to 0, the entire address_space | 391 | * If the number of requests is set to 0, the entire address_space |
389 | * starting at index idx_start, is scanned. | 392 | * starting at index idx_start, is scanned. |
390 | * The requests are *not* checked to ensure that they form a contiguous set. | 393 | * The requests are *not* checked to ensure that they form a contiguous set. |
391 | * You must be holding the inode's req_lock when calling this function | 394 | * You must be holding the inode's i_lock when calling this function |
392 | */ | 395 | */ |
393 | int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, | 396 | int nfs_scan_list(struct nfs_inode *nfsi, |
394 | struct list_head *dst, pgoff_t idx_start, | 397 | struct list_head *dst, pgoff_t idx_start, |
395 | unsigned int npages) | 398 | unsigned int npages, int tag) |
396 | { | 399 | { |
397 | struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES]; | 400 | struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES]; |
398 | struct nfs_page *req; | 401 | struct nfs_page *req; |
@@ -407,9 +410,9 @@ int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, | |||
407 | idx_end = idx_start + npages - 1; | 410 | idx_end = idx_start + npages - 1; |
408 | 411 | ||
409 | for (;;) { | 412 | for (;;) { |
410 | found = radix_tree_gang_lookup(&nfsi->nfs_page_tree, | 413 | found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, |
411 | (void **)&pgvec[0], idx_start, | 414 | (void **)&pgvec[0], idx_start, |
412 | NFS_SCAN_MAXENTRIES); | 415 | NFS_SCAN_MAXENTRIES, tag); |
413 | if (found <= 0) | 416 | if (found <= 0) |
414 | break; | 417 | break; |
415 | for (i = 0; i < found; i++) { | 418 | for (i = 0; i < found; i++) { |
@@ -417,15 +420,18 @@ int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, | |||
417 | if (req->wb_index > idx_end) | 420 | if (req->wb_index > idx_end) |
418 | goto out; | 421 | goto out; |
419 | idx_start = req->wb_index + 1; | 422 | idx_start = req->wb_index + 1; |
420 | if (req->wb_list_head != head) | 423 | if (nfs_set_page_tag_locked(req)) { |
421 | continue; | ||
422 | if (nfs_set_page_writeback_locked(req)) { | ||
423 | nfs_list_remove_request(req); | 424 | nfs_list_remove_request(req); |
425 | radix_tree_tag_clear(&nfsi->nfs_page_tree, | ||
426 | req->wb_index, tag); | ||
424 | nfs_list_add_request(req, dst); | 427 | nfs_list_add_request(req, dst); |
425 | res++; | 428 | res++; |
429 | if (res == INT_MAX) | ||
430 | goto out; | ||
426 | } | 431 | } |
427 | } | 432 | } |
428 | 433 | /* for latency reduction */ | |
434 | cond_resched_lock(&nfsi->vfs_inode.i_lock); | ||
429 | } | 435 | } |
430 | out: | 436 | out: |
431 | return res; | 437 | return res; |