summaryrefslogtreecommitdiffstats
path: root/fs/nilfs2/page.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nilfs2/page.c')
-rw-r--r--fs/nilfs2/page.c97
1 files changed, 84 insertions, 13 deletions
diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c
index a6c3c2e817f8..a585b35fd6bc 100644
--- a/fs/nilfs2/page.c
+++ b/fs/nilfs2/page.c
@@ -491,19 +491,6 @@ unsigned nilfs_page_count_clean_buffers(struct page *page,
}
return nc;
}
-
-void nilfs_mapping_init_once(struct address_space *mapping)
-{
- memset(mapping, 0, sizeof(*mapping));
- INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC);
- spin_lock_init(&mapping->tree_lock);
- INIT_LIST_HEAD(&mapping->private_list);
- spin_lock_init(&mapping->private_lock);
-
- spin_lock_init(&mapping->i_mmap_lock);
- INIT_RAW_PRIO_TREE_ROOT(&mapping->i_mmap);
- INIT_LIST_HEAD(&mapping->i_mmap_nonlinear);
-}
void nilfs_mapping_init(struct address_space *mapping,
struct backing_dev_info *bdi,
@@ -546,3 +533,87 @@ int __nilfs_clear_page_dirty(struct page *page)
}
return TestClearPageDirty(page);
}
+
+/**
+ * nilfs_find_uncommitted_extent - find extent of uncommitted data
+ * @inode: inode
+ * @start_blk: start block offset (in)
+ * @blkoff: start offset of the found extent (out)
+ *
+ * This function searches an extent of buffers marked "delayed" which
+ * starts from a block offset equal to or larger than @start_blk. If
+ * such an extent was found, this will store the start offset in
+ * @blkoff and return its length in blocks. Otherwise, zero is
+ * returned.
+ */
+unsigned long nilfs_find_uncommitted_extent(struct inode *inode,
+ sector_t start_blk,
+ sector_t *blkoff)
+{
+ unsigned int i;
+ pgoff_t index;
+ unsigned int nblocks_in_page;
+ unsigned long length = 0;
+ sector_t b;
+ struct pagevec pvec;
+ struct page *page;
+
+ if (inode->i_mapping->nrpages == 0)
+ return 0;
+
+ index = start_blk >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
+ nblocks_in_page = 1U << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+
+ pagevec_init(&pvec, 0);
+
+repeat:
+ pvec.nr = find_get_pages_contig(inode->i_mapping, index, PAGEVEC_SIZE,
+ pvec.pages);
+ if (pvec.nr == 0)
+ return length;
+
+ if (length > 0 && pvec.pages[0]->index > index)
+ goto out;
+
+ b = pvec.pages[0]->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+ i = 0;
+ do {
+ page = pvec.pages[i];
+
+ lock_page(page);
+ if (page_has_buffers(page)) {
+ struct buffer_head *bh, *head;
+
+ bh = head = page_buffers(page);
+ do {
+ if (b < start_blk)
+ continue;
+ if (buffer_delay(bh)) {
+ if (length == 0)
+ *blkoff = b;
+ length++;
+ } else if (length > 0) {
+ goto out_locked;
+ }
+ } while (++b, bh = bh->b_this_page, bh != head);
+ } else {
+ if (length > 0)
+ goto out_locked;
+
+ b += nblocks_in_page;
+ }
+ unlock_page(page);
+
+ } while (++i < pagevec_count(&pvec));
+
+ index = page->index + 1;
+ pagevec_release(&pvec);
+ cond_resched();
+ goto repeat;
+
+out_locked:
+ unlock_page(page);
+out:
+ pagevec_release(&pvec);
+ return length;
+}