aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/file.c6
-rw-r--r--fs/nfs/pagelist.c47
-rw-r--r--fs/nfs/write.c27
-rw-r--r--include/linux/nfs_fs.h1
-rw-r--r--include/linux/nfs_page.h4
5 files changed, 60 insertions, 25 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 63154070145a..106ef0dec04d 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -303,7 +303,11 @@ static int nfs_commit_write(struct file *file, struct page *page, unsigned offse
303 303
304static void nfs_invalidate_page(struct page *page, unsigned long offset) 304static void nfs_invalidate_page(struct page *page, unsigned long offset)
305{ 305{
306 /* FIXME: we really should cancel any unstarted writes on this page */ 306 struct inode *inode = page->mapping->host;
307
308 /* Cancel any unstarted writes on this page */
309 if (offset == 0)
310 nfs_sync_inode_wait(inode, page->index, 1, FLUSH_INVALIDATE);
307} 311}
308 312
309static int nfs_release_page(struct page *page, gfp_t gfp) 313static int nfs_release_page(struct page *page, gfp_t gfp)
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 106aca388ebc..656481c0daa3 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -325,6 +325,7 @@ out:
325 325
326/** 326/**
327 * nfs_scan_list - Scan a list for matching requests 327 * nfs_scan_list - Scan a list for matching requests
328 * @nfsi: NFS inode
328 * @head: One of the NFS inode request lists 329 * @head: One of the NFS inode request lists
329 * @dst: Destination list 330 * @dst: Destination list
330 * @idx_start: lower bound of page->index to scan 331 * @idx_start: lower bound of page->index to scan
@@ -336,14 +337,15 @@ out:
336 * The requests are *not* checked to ensure that they form a contiguous set. 337 * The requests are *not* checked to ensure that they form a contiguous set.
337 * You must be holding the inode's req_lock when calling this function 338 * You must be holding the inode's req_lock when calling this function
338 */ 339 */
339int 340int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head,
340nfs_scan_list(struct list_head *head, struct list_head *dst, 341 struct list_head *dst, unsigned long idx_start,
341 unsigned long idx_start, unsigned int npages) 342 unsigned int npages)
342{ 343{
343 struct list_head *pos, *tmp; 344 struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
344 struct nfs_page *req; 345 struct nfs_page *req;
345 unsigned long idx_end; 346 unsigned long idx_end;
346 int res; 347 int found, i;
348 int res;
347 349
348 res = 0; 350 res = 0;
349 if (npages == 0) 351 if (npages == 0)
@@ -351,21 +353,28 @@ nfs_scan_list(struct list_head *head, struct list_head *dst,
351 else 353 else
352 idx_end = idx_start + npages - 1; 354 idx_end = idx_start + npages - 1;
353 355
354 list_for_each_safe(pos, tmp, head) { 356 for (;;) {
355 357 found = radix_tree_gang_lookup(&nfsi->nfs_page_tree,
356 req = nfs_list_entry(pos); 358 (void **)&pgvec[0], idx_start,
357 359 NFS_SCAN_MAXENTRIES);
358 if (req->wb_index < idx_start) 360 if (found <= 0)
359 continue;
360 if (req->wb_index > idx_end)
361 break; 361 break;
362 for (i = 0; i < found; i++) {
363 req = pgvec[i];
364 if (req->wb_index > idx_end)
365 goto out;
366 idx_start = req->wb_index + 1;
367 if (req->wb_list_head != head)
368 continue;
369 if (nfs_set_page_writeback_locked(req)) {
370 nfs_list_remove_request(req);
371 nfs_list_add_request(req, dst);
372 res++;
373 }
374 }
362 375
363 if (!nfs_set_page_writeback_locked(req))
364 continue;
365 nfs_list_remove_request(req);
366 nfs_list_add_request(req, dst);
367 res++;
368 } 376 }
377out:
369 return res; 378 return res;
370} 379}
371 380
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index a515ec714bb6..e03abbd8302e 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -579,6 +579,17 @@ static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, un
579 return ret; 579 return ret;
580} 580}
581 581
582static void nfs_cancel_requests(struct list_head *head)
583{
584 struct nfs_page *req;
585 while(!list_empty(head)) {
586 req = nfs_list_entry(head->next);
587 nfs_list_remove_request(req);
588 nfs_inode_remove_request(req);
589 nfs_clear_page_writeback(req);
590 }
591}
592
582/* 593/*
583 * nfs_scan_dirty - Scan an inode for dirty requests 594 * nfs_scan_dirty - Scan an inode for dirty requests
584 * @inode: NFS inode to scan 595 * @inode: NFS inode to scan
@@ -623,7 +634,7 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_st
623 int res = 0; 634 int res = 0;
624 635
625 if (nfsi->ncommit != 0) { 636 if (nfsi->ncommit != 0) {
626 res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages); 637 res = nfs_scan_list(nfsi, &nfsi->commit, dst, idx_start, npages);
627 nfsi->ncommit -= res; 638 nfsi->ncommit -= res;
628 if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) 639 if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))
629 printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); 640 printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
@@ -1491,15 +1502,25 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
1491 pages = nfs_scan_dirty(inode, &head, idx_start, npages); 1502 pages = nfs_scan_dirty(inode, &head, idx_start, npages);
1492 if (pages != 0) { 1503 if (pages != 0) {
1493 spin_unlock(&nfsi->req_lock); 1504 spin_unlock(&nfsi->req_lock);
1494 ret = nfs_flush_list(inode, &head, pages, how); 1505 if (how & FLUSH_INVALIDATE)
1506 nfs_cancel_requests(&head);
1507 else
1508 ret = nfs_flush_list(inode, &head, pages, how);
1495 spin_lock(&nfsi->req_lock); 1509 spin_lock(&nfsi->req_lock);
1496 continue; 1510 continue;
1497 } 1511 }
1498 if (nocommit) 1512 if (nocommit)
1499 break; 1513 break;
1500 pages = nfs_scan_commit(inode, &head, 0, 0); 1514 pages = nfs_scan_commit(inode, &head, idx_start, npages);
1501 if (pages == 0) 1515 if (pages == 0)
1502 break; 1516 break;
1517 if (how & FLUSH_INVALIDATE) {
1518 spin_unlock(&nfsi->req_lock);
1519 nfs_cancel_requests(&head);
1520 spin_lock(&nfsi->req_lock);
1521 continue;
1522 }
1523 pages += nfs_scan_commit(inode, &head, 0, 0);
1503 spin_unlock(&nfsi->req_lock); 1524 spin_unlock(&nfsi->req_lock);
1504 ret = nfs_commit_list(inode, &head, how); 1525 ret = nfs_commit_list(inode, &head, how);
1505 spin_lock(&nfsi->req_lock); 1526 spin_lock(&nfsi->req_lock);
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 1b524b9f982a..fc48135621ed 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -61,6 +61,7 @@
61#define FLUSH_LOWPRI 8 /* low priority background flush */ 61#define FLUSH_LOWPRI 8 /* low priority background flush */
62#define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */ 62#define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */
63#define FLUSH_NOCOMMIT 32 /* Don't send the NFSv3/v4 COMMIT */ 63#define FLUSH_NOCOMMIT 32 /* Don't send the NFSv3/v4 COMMIT */
64#define FLUSH_INVALIDATE 64 /* Invalidate the page cache */
64 65
65#ifdef __KERNEL__ 66#ifdef __KERNEL__
66 67
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index 66e2ed658527..8cadb0a77a7a 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -63,8 +63,8 @@ extern void nfs_release_request(struct nfs_page *req);
63 63
64extern int nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst, 64extern int nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst,
65 unsigned long idx_start, unsigned int npages); 65 unsigned long idx_start, unsigned int npages);
66extern int nfs_scan_list(struct list_head *, struct list_head *, 66extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, struct list_head *dst,
67 unsigned long, unsigned int); 67 unsigned long idx_start, unsigned int npages);
68extern int nfs_coalesce_requests(struct list_head *, struct list_head *, 68extern int nfs_coalesce_requests(struct list_head *, struct list_head *,
69 unsigned int); 69 unsigned int);
70extern int nfs_wait_on_request(struct nfs_page *); 70extern int nfs_wait_on_request(struct nfs_page *);