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; |
