diff options
Diffstat (limited to 'fs/nilfs2/page.c')
-rw-r--r-- | fs/nilfs2/page.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c index a6c3c2e817f8..48a775ec1d2a 100644 --- a/fs/nilfs2/page.c +++ b/fs/nilfs2/page.c | |||
@@ -546,3 +546,87 @@ int __nilfs_clear_page_dirty(struct page *page) | |||
546 | } | 546 | } |
547 | return TestClearPageDirty(page); | 547 | return TestClearPageDirty(page); |
548 | } | 548 | } |
549 | |||
550 | /** | ||
551 | * nilfs_find_uncommitted_extent - find extent of uncommitted data | ||
552 | * @inode: inode | ||
553 | * @start_blk: start block offset (in) | ||
554 | * @blkoff: start offset of the found extent (out) | ||
555 | * | ||
556 | * This function searches an extent of buffers marked "delayed" which | ||
557 | * starts from a block offset equal to or larger than @start_blk. If | ||
558 | * such an extent was found, this will store the start offset in | ||
559 | * @blkoff and return its length in blocks. Otherwise, zero is | ||
560 | * returned. | ||
561 | */ | ||
562 | unsigned long nilfs_find_uncommitted_extent(struct inode *inode, | ||
563 | sector_t start_blk, | ||
564 | sector_t *blkoff) | ||
565 | { | ||
566 | unsigned int i; | ||
567 | pgoff_t index; | ||
568 | unsigned int nblocks_in_page; | ||
569 | unsigned long length = 0; | ||
570 | sector_t b; | ||
571 | struct pagevec pvec; | ||
572 | struct page *page; | ||
573 | |||
574 | if (inode->i_mapping->nrpages == 0) | ||
575 | return 0; | ||
576 | |||
577 | index = start_blk >> (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
578 | nblocks_in_page = 1U << (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
579 | |||
580 | pagevec_init(&pvec, 0); | ||
581 | |||
582 | repeat: | ||
583 | pvec.nr = find_get_pages_contig(inode->i_mapping, index, PAGEVEC_SIZE, | ||
584 | pvec.pages); | ||
585 | if (pvec.nr == 0) | ||
586 | return length; | ||
587 | |||
588 | if (length > 0 && pvec.pages[0]->index > index) | ||
589 | goto out; | ||
590 | |||
591 | b = pvec.pages[0]->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
592 | i = 0; | ||
593 | do { | ||
594 | page = pvec.pages[i]; | ||
595 | |||
596 | lock_page(page); | ||
597 | if (page_has_buffers(page)) { | ||
598 | struct buffer_head *bh, *head; | ||
599 | |||
600 | bh = head = page_buffers(page); | ||
601 | do { | ||
602 | if (b < start_blk) | ||
603 | continue; | ||
604 | if (buffer_delay(bh)) { | ||
605 | if (length == 0) | ||
606 | *blkoff = b; | ||
607 | length++; | ||
608 | } else if (length > 0) { | ||
609 | goto out_locked; | ||
610 | } | ||
611 | } while (++b, bh = bh->b_this_page, bh != head); | ||
612 | } else { | ||
613 | if (length > 0) | ||
614 | goto out_locked; | ||
615 | |||
616 | b += nblocks_in_page; | ||
617 | } | ||
618 | unlock_page(page); | ||
619 | |||
620 | } while (++i < pagevec_count(&pvec)); | ||
621 | |||
622 | index = page->index + 1; | ||
623 | pagevec_release(&pvec); | ||
624 | cond_resched(); | ||
625 | goto repeat; | ||
626 | |||
627 | out_locked: | ||
628 | unlock_page(page); | ||
629 | out: | ||
630 | pagevec_release(&pvec); | ||
631 | return length; | ||
632 | } | ||