diff options
-rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.c | 144 |
1 files changed, 88 insertions, 56 deletions
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index e99d04d3fe82..e998009c0f52 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "xfs_rw.h" | 40 | #include "xfs_rw.h" |
41 | #include "xfs_iomap.h" | 41 | #include "xfs_iomap.h" |
42 | #include <linux/mpage.h> | 42 | #include <linux/mpage.h> |
43 | #include <linux/pagevec.h> | ||
43 | #include <linux/writeback.h> | 44 | #include <linux/writeback.h> |
44 | 45 | ||
45 | STATIC void xfs_count_page_state(struct page *, int *, int *, int *); | 46 | STATIC void xfs_count_page_state(struct page *, int *, int *, int *); |
@@ -501,18 +502,13 @@ xfs_map_at_offset( | |||
501 | */ | 502 | */ |
502 | STATIC unsigned int | 503 | STATIC unsigned int |
503 | xfs_probe_unmapped_page( | 504 | xfs_probe_unmapped_page( |
504 | struct address_space *mapping, | 505 | struct page *page, |
505 | pgoff_t index, | ||
506 | unsigned int pg_offset) | 506 | unsigned int pg_offset) |
507 | { | 507 | { |
508 | struct page *page; | ||
509 | int ret = 0; | 508 | int ret = 0; |
510 | 509 | ||
511 | page = find_trylock_page(mapping, index); | ||
512 | if (!page) | ||
513 | return 0; | ||
514 | if (PageWriteback(page)) | 510 | if (PageWriteback(page)) |
515 | goto out; | 511 | return 0; |
516 | 512 | ||
517 | if (page->mapping && PageDirty(page)) { | 513 | if (page->mapping && PageDirty(page)) { |
518 | if (page_has_buffers(page)) { | 514 | if (page_has_buffers(page)) { |
@@ -530,8 +526,6 @@ xfs_probe_unmapped_page( | |||
530 | ret = PAGE_CACHE_SIZE; | 526 | ret = PAGE_CACHE_SIZE; |
531 | } | 527 | } |
532 | 528 | ||
533 | out: | ||
534 | unlock_page(page); | ||
535 | return ret; | 529 | return ret; |
536 | } | 530 | } |
537 | 531 | ||
@@ -542,59 +536,75 @@ xfs_probe_unmapped_cluster( | |||
542 | struct buffer_head *bh, | 536 | struct buffer_head *bh, |
543 | struct buffer_head *head) | 537 | struct buffer_head *head) |
544 | { | 538 | { |
545 | size_t len, total = 0; | 539 | struct pagevec pvec; |
546 | pgoff_t tindex, tlast, tloff; | 540 | pgoff_t tindex, tlast, tloff; |
547 | unsigned int pg_offset; | 541 | size_t total = 0; |
548 | struct address_space *mapping = inode->i_mapping; | 542 | int done = 0, i; |
549 | 543 | ||
550 | /* First sum forwards in this page */ | 544 | /* First sum forwards in this page */ |
551 | do { | 545 | do { |
552 | if (buffer_mapped(bh)) | 546 | if (buffer_mapped(bh)) |
553 | break; | 547 | return total; |
554 | total += bh->b_size; | 548 | total += bh->b_size; |
555 | } while ((bh = bh->b_this_page) != head); | 549 | } while ((bh = bh->b_this_page) != head); |
556 | 550 | ||
557 | /* If we reached the end of the page, sum forwards in | 551 | /* if we reached the end of the page, sum forwards in following pages */ |
558 | * following pages. | 552 | tlast = i_size_read(inode) >> PAGE_CACHE_SHIFT; |
559 | */ | 553 | tindex = startpage->index + 1; |
560 | if (bh == head) { | 554 | |
561 | tlast = i_size_read(inode) >> PAGE_CACHE_SHIFT; | 555 | /* Prune this back to avoid pathological behavior */ |
562 | /* Prune this back to avoid pathological behavior */ | 556 | tloff = min(tlast, startpage->index + 64); |
563 | tloff = min(tlast, startpage->index + 64); | 557 | |
564 | for (tindex = startpage->index + 1; tindex < tloff; tindex++) { | 558 | pagevec_init(&pvec, 0); |
565 | len = xfs_probe_unmapped_page(mapping, tindex, | 559 | while (!done && tindex <= tloff) { |
566 | PAGE_CACHE_SIZE); | 560 | unsigned len = min_t(pgoff_t, PAGEVEC_SIZE, tlast - tindex + 1); |
567 | if (!len) | 561 | |
568 | return total; | 562 | if (!pagevec_lookup(&pvec, inode->i_mapping, tindex, len)) |
563 | break; | ||
564 | |||
565 | for (i = 0; i < pagevec_count(&pvec); i++) { | ||
566 | struct page *page = pvec.pages[i]; | ||
567 | size_t pg_offset, len = 0; | ||
568 | |||
569 | if (tindex == tlast) { | ||
570 | pg_offset = | ||
571 | i_size_read(inode) & (PAGE_CACHE_SIZE - 1); | ||
572 | if (!pg_offset) | ||
573 | break; | ||
574 | } else | ||
575 | pg_offset = PAGE_CACHE_SIZE; | ||
576 | |||
577 | if (page->index == tindex && !TestSetPageLocked(page)) { | ||
578 | len = xfs_probe_unmapped_page(page, pg_offset); | ||
579 | unlock_page(page); | ||
580 | } | ||
581 | |||
582 | if (!len) { | ||
583 | done = 1; | ||
584 | break; | ||
585 | } | ||
586 | |||
569 | total += len; | 587 | total += len; |
570 | } | 588 | } |
571 | if (tindex == tlast && | 589 | |
572 | (pg_offset = i_size_read(inode) & (PAGE_CACHE_SIZE - 1))) { | 590 | pagevec_release(&pvec); |
573 | total += xfs_probe_unmapped_page(mapping, | 591 | cond_resched(); |
574 | tindex, pg_offset); | ||
575 | } | ||
576 | } | 592 | } |
593 | |||
577 | return total; | 594 | return total; |
578 | } | 595 | } |
579 | 596 | ||
580 | /* | 597 | /* |
581 | * Probe for a given page (index) in the inode and test if it is suitable | 598 | * Test if a given page is suitable for writing as part of an unwritten |
582 | * for writing as part of an unwritten or delayed allocate extent. | 599 | * or delayed allocate extent. |
583 | * Returns page locked and with an extra reference count if so, else NULL. | ||
584 | */ | 600 | */ |
585 | STATIC struct page * | 601 | STATIC int |
586 | xfs_probe_delayed_page( | 602 | xfs_is_delayed_page( |
587 | struct inode *inode, | 603 | struct page *page, |
588 | pgoff_t index, | ||
589 | unsigned int type) | 604 | unsigned int type) |
590 | { | 605 | { |
591 | struct page *page; | ||
592 | |||
593 | page = find_trylock_page(inode->i_mapping, index); | ||
594 | if (!page) | ||
595 | return NULL; | ||
596 | if (PageWriteback(page)) | 606 | if (PageWriteback(page)) |
597 | goto out; | 607 | return 0; |
598 | 608 | ||
599 | if (page->mapping && page_has_buffers(page)) { | 609 | if (page->mapping && page_has_buffers(page)) { |
600 | struct buffer_head *bh, *head; | 610 | struct buffer_head *bh, *head; |
@@ -611,12 +621,10 @@ xfs_probe_delayed_page( | |||
611 | } while ((bh = bh->b_this_page) != head); | 621 | } while ((bh = bh->b_this_page) != head); |
612 | 622 | ||
613 | if (acceptable) | 623 | if (acceptable) |
614 | return page; | 624 | return 1; |
615 | } | 625 | } |
616 | 626 | ||
617 | out: | 627 | return 0; |
618 | unlock_page(page); | ||
619 | return NULL; | ||
620 | } | 628 | } |
621 | 629 | ||
622 | /* | 630 | /* |
@@ -629,10 +637,10 @@ STATIC int | |||
629 | xfs_convert_page( | 637 | xfs_convert_page( |
630 | struct inode *inode, | 638 | struct inode *inode, |
631 | struct page *page, | 639 | struct page *page, |
640 | loff_t tindex, | ||
632 | xfs_iomap_t *iomapp, | 641 | xfs_iomap_t *iomapp, |
633 | xfs_ioend_t **ioendp, | 642 | xfs_ioend_t **ioendp, |
634 | struct writeback_control *wbc, | 643 | struct writeback_control *wbc, |
635 | void *private, | ||
636 | int startio, | 644 | int startio, |
637 | int all_bh) | 645 | int all_bh) |
638 | { | 646 | { |
@@ -644,6 +652,17 @@ xfs_convert_page( | |||
644 | int len, page_dirty; | 652 | int len, page_dirty; |
645 | int count = 0, done = 0, uptodate = 1; | 653 | int count = 0, done = 0, uptodate = 1; |
646 | 654 | ||
655 | if (page->index != tindex) | ||
656 | goto fail; | ||
657 | if (TestSetPageLocked(page)) | ||
658 | goto fail; | ||
659 | if (PageWriteback(page)) | ||
660 | goto fail_unlock_page; | ||
661 | if (page->mapping != inode->i_mapping) | ||
662 | goto fail_unlock_page; | ||
663 | if (!xfs_is_delayed_page(page, (*ioendp)->io_type)) | ||
664 | goto fail_unlock_page; | ||
665 | |||
647 | end_offset = (i_size_read(inode) & (PAGE_CACHE_SIZE - 1)); | 666 | end_offset = (i_size_read(inode) & (PAGE_CACHE_SIZE - 1)); |
648 | 667 | ||
649 | /* | 668 | /* |
@@ -715,6 +734,10 @@ xfs_convert_page( | |||
715 | } | 734 | } |
716 | 735 | ||
717 | return done; | 736 | return done; |
737 | fail_unlock_page: | ||
738 | unlock_page(page); | ||
739 | fail: | ||
740 | return 1; | ||
718 | } | 741 | } |
719 | 742 | ||
720 | /* | 743 | /* |
@@ -732,16 +755,25 @@ xfs_cluster_write( | |||
732 | int all_bh, | 755 | int all_bh, |
733 | pgoff_t tlast) | 756 | pgoff_t tlast) |
734 | { | 757 | { |
735 | struct page *page; | 758 | struct pagevec pvec; |
736 | unsigned int type = (*ioendp)->io_type; | 759 | int done = 0, i; |
737 | int done; | ||
738 | 760 | ||
739 | for (done = 0; tindex <= tlast && !done; tindex++) { | 761 | pagevec_init(&pvec, 0); |
740 | page = xfs_probe_delayed_page(inode, tindex, type); | 762 | while (!done && tindex <= tlast) { |
741 | if (!page) | 763 | unsigned len = min_t(pgoff_t, PAGEVEC_SIZE, tlast - tindex + 1); |
764 | |||
765 | if (!pagevec_lookup(&pvec, inode->i_mapping, tindex, len)) | ||
742 | break; | 766 | break; |
743 | done = xfs_convert_page(inode, page, iomapp, ioendp, | 767 | |
744 | wbc, NULL, startio, all_bh); | 768 | for (i = 0; i < pagevec_count(&pvec); i++) { |
769 | done = xfs_convert_page(inode, pvec.pages[i], tindex++, | ||
770 | iomapp, ioendp, wbc, startio, all_bh); | ||
771 | if (done) | ||
772 | break; | ||
773 | } | ||
774 | |||
775 | pagevec_release(&pvec); | ||
776 | cond_resched(); | ||
745 | } | 777 | } |
746 | } | 778 | } |
747 | 779 | ||