diff options
Diffstat (limited to 'fs/nfs/pagelist.c')
-rw-r--r-- | fs/nfs/pagelist.c | 86 |
1 files changed, 56 insertions, 30 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 356a33bb38a6..d53857b148e2 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -177,36 +177,6 @@ nfs_release_request(struct nfs_page *req) | |||
177 | nfs_page_free(req); | 177 | nfs_page_free(req); |
178 | } | 178 | } |
179 | 179 | ||
180 | /** | ||
181 | * nfs_list_add_request - Insert a request into a sorted list | ||
182 | * @req: request | ||
183 | * @head: head of list into which to insert the request. | ||
184 | * | ||
185 | * Note that the wb_list is sorted by page index in order to facilitate | ||
186 | * coalescing of requests. | ||
187 | * We use an insertion sort that is optimized for the case of appended | ||
188 | * writes. | ||
189 | */ | ||
190 | void | ||
191 | nfs_list_add_request(struct nfs_page *req, struct list_head *head) | ||
192 | { | ||
193 | struct list_head *pos; | ||
194 | |||
195 | #ifdef NFS_PARANOIA | ||
196 | if (!list_empty(&req->wb_list)) { | ||
197 | printk(KERN_ERR "NFS: Add to list failed!\n"); | ||
198 | BUG(); | ||
199 | } | ||
200 | #endif | ||
201 | list_for_each_prev(pos, head) { | ||
202 | struct nfs_page *p = nfs_list_entry(pos); | ||
203 | if (p->wb_index < req->wb_index) | ||
204 | break; | ||
205 | } | ||
206 | list_add(&req->wb_list, pos); | ||
207 | req->wb_list_head = head; | ||
208 | } | ||
209 | |||
210 | static int nfs_wait_bit_interruptible(void *word) | 180 | static int nfs_wait_bit_interruptible(void *word) |
211 | { | 181 | { |
212 | int ret = 0; | 182 | int ret = 0; |
@@ -291,6 +261,62 @@ nfs_coalesce_requests(struct list_head *head, struct list_head *dst, | |||
291 | return npages; | 261 | return npages; |
292 | } | 262 | } |
293 | 263 | ||
264 | #define NFS_SCAN_MAXENTRIES 16 | ||
265 | /** | ||
266 | * nfs_scan_lock_dirty - Scan the radix tree for dirty requests | ||
267 | * @nfsi: NFS inode | ||
268 | * @dst: Destination list | ||
269 | * @idx_start: lower bound of page->index to scan | ||
270 | * @npages: idx_start + npages sets the upper bound to scan. | ||
271 | * | ||
272 | * Moves elements from one of the inode request lists. | ||
273 | * If the number of requests is set to 0, the entire address_space | ||
274 | * starting at index idx_start, is scanned. | ||
275 | * The requests are *not* checked to ensure that they form a contiguous set. | ||
276 | * You must be holding the inode's req_lock when calling this function | ||
277 | */ | ||
278 | int | ||
279 | nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst, | ||
280 | unsigned long idx_start, unsigned int npages) | ||
281 | { | ||
282 | struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES]; | ||
283 | struct nfs_page *req; | ||
284 | unsigned long idx_end; | ||
285 | int found, i; | ||
286 | int res; | ||
287 | |||
288 | res = 0; | ||
289 | if (npages == 0) | ||
290 | idx_end = ~0; | ||
291 | else | ||
292 | idx_end = idx_start + npages - 1; | ||
293 | |||
294 | for (;;) { | ||
295 | found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, | ||
296 | (void **)&pgvec[0], idx_start, NFS_SCAN_MAXENTRIES, | ||
297 | NFS_PAGE_TAG_DIRTY); | ||
298 | if (found <= 0) | ||
299 | break; | ||
300 | for (i = 0; i < found; i++) { | ||
301 | req = pgvec[i]; | ||
302 | if (req->wb_index > idx_end) | ||
303 | goto out; | ||
304 | |||
305 | idx_start = req->wb_index + 1; | ||
306 | |||
307 | if (nfs_set_page_writeback_locked(req)) { | ||
308 | radix_tree_tag_clear(&nfsi->nfs_page_tree, | ||
309 | req->wb_index, NFS_PAGE_TAG_DIRTY); | ||
310 | nfs_list_remove_request(req); | ||
311 | nfs_list_add_request(req, dst); | ||
312 | res++; | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | out: | ||
317 | return res; | ||
318 | } | ||
319 | |||
294 | /** | 320 | /** |
295 | * nfs_scan_list - Scan a list for matching requests | 321 | * nfs_scan_list - Scan a list for matching requests |
296 | * @head: One of the NFS inode request lists | 322 | * @head: One of the NFS inode request lists |