|
@@ -454,11 +454,18 @@ EXPORT_SYMBOL(mpage_readpage);
|
|
* written, so it can intelligently allocate a suitably-sized BIO. For now,
|
|
* written, so it can intelligently allocate a suitably-sized BIO. For now,
|
|
* just allocate full-size (16-page) BIOs.
|
|
* just allocate full-size (16-page) BIOs.
|
|
*/
|
|
*/
|
|
-static struct bio *
|
|
|
|
-__mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
|
|
|
|
- sector_t *last_block_in_bio, int *ret, struct writeback_control *wbc,
|
|
|
|
- writepage_t writepage_fn)
|
|
|
|
|
|
+struct mpage_data {
|
|
|
|
+ struct bio *bio;
|
|
|
|
+ sector_t last_block_in_bio;
|
|
|
|
+ get_block_t *get_block;
|
|
|
|
+ unsigned use_writepage;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int __mpage_writepage(struct page *page, struct writeback_control *wbc,
|
|
|
|
+ void *data)
|
|
{
|
|
{
|
|
|
|
+ struct mpage_data *mpd = data;
|
|
|
|
+ struct bio *bio = mpd->bio;
|
|
struct address_space *mapping = page->mapping;
|
|
struct address_space *mapping = page->mapping;
|
|
struct inode *inode = page->mapping->host;
|
|
struct inode *inode = page->mapping->host;
|
|
const unsigned blkbits = inode->i_blkbits;
|
|
const unsigned blkbits = inode->i_blkbits;
|
|
@@ -476,6 +483,7 @@ __mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
|
|
int length;
|
|
int length;
|
|
struct buffer_head map_bh;
|
|
struct buffer_head map_bh;
|
|
loff_t i_size = i_size_read(inode);
|
|
loff_t i_size = i_size_read(inode);
|
|
|
|
+ int ret = 0;
|
|
|
|
|
|
if (page_has_buffers(page)) {
|
|
if (page_has_buffers(page)) {
|
|
struct buffer_head *head = page_buffers(page);
|
|
struct buffer_head *head = page_buffers(page);
|
|
@@ -538,7 +546,7 @@ __mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
|
|
|
|
|
|
map_bh.b_state = 0;
|
|
map_bh.b_state = 0;
|
|
map_bh.b_size = 1 << blkbits;
|
|
map_bh.b_size = 1 << blkbits;
|
|
- if (get_block(inode, block_in_file, &map_bh, 1))
|
|
|
|
|
|
+ if (mpd->get_block(inode, block_in_file, &map_bh, 1))
|
|
goto confused;
|
|
goto confused;
|
|
if (buffer_new(&map_bh))
|
|
if (buffer_new(&map_bh))
|
|
unmap_underlying_metadata(map_bh.b_bdev,
|
|
unmap_underlying_metadata(map_bh.b_bdev,
|
|
@@ -584,7 +592,7 @@ page_is_mapped:
|
|
/*
|
|
/*
|
|
* This page will go to BIO. Do we need to send this BIO off first?
|
|
* This page will go to BIO. Do we need to send this BIO off first?
|
|
*/
|
|
*/
|
|
- if (bio && *last_block_in_bio != blocks[0] - 1)
|
|
|
|
|
|
+ if (bio && mpd->last_block_in_bio != blocks[0] - 1)
|
|
bio = mpage_bio_submit(WRITE, bio);
|
|
bio = mpage_bio_submit(WRITE, bio);
|
|
|
|
|
|
alloc_new:
|
|
alloc_new:
|
|
@@ -641,7 +649,7 @@ alloc_new:
|
|
boundary_block, 1 << blkbits);
|
|
boundary_block, 1 << blkbits);
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- *last_block_in_bio = blocks[blocks_per_page - 1];
|
|
|
|
|
|
+ mpd->last_block_in_bio = blocks[blocks_per_page - 1];
|
|
}
|
|
}
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
@@ -649,18 +657,19 @@ confused:
|
|
if (bio)
|
|
if (bio)
|
|
bio = mpage_bio_submit(WRITE, bio);
|
|
bio = mpage_bio_submit(WRITE, bio);
|
|
|
|
|
|
- if (writepage_fn) {
|
|
|
|
- *ret = (*writepage_fn)(page, wbc);
|
|
|
|
|
|
+ if (mpd->use_writepage) {
|
|
|
|
+ ret = mapping->a_ops->writepage(page, wbc);
|
|
} else {
|
|
} else {
|
|
- *ret = -EAGAIN;
|
|
|
|
|
|
+ ret = -EAGAIN;
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
/*
|
|
/*
|
|
* The caller has a ref on the inode, so *mapping is stable
|
|
* The caller has a ref on the inode, so *mapping is stable
|
|
*/
|
|
*/
|
|
- mapping_set_error(mapping, *ret);
|
|
|
|
|
|
+ mapping_set_error(mapping, ret);
|
|
out:
|
|
out:
|
|
- return bio;
|
|
|
|
|
|
+ mpd->bio = bio;
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -683,120 +692,27 @@ out:
|
|
* the call was made get new I/O started against them. If wbc->sync_mode is
|
|
* the call was made get new I/O started against them. If wbc->sync_mode is
|
|
* WB_SYNC_ALL then we were called for data integrity and we must wait for
|
|
* WB_SYNC_ALL then we were called for data integrity and we must wait for
|
|
* existing IO to complete.
|
|
* existing IO to complete.
|
|
- *
|
|
|
|
- * If you fix this you should check generic_writepages() also!
|
|
|
|
*/
|
|
*/
|
|
int
|
|
int
|
|
mpage_writepages(struct address_space *mapping,
|
|
mpage_writepages(struct address_space *mapping,
|
|
struct writeback_control *wbc, get_block_t get_block)
|
|
struct writeback_control *wbc, get_block_t get_block)
|
|
{
|
|
{
|
|
- struct backing_dev_info *bdi = mapping->backing_dev_info;
|
|
|
|
- struct bio *bio = NULL;
|
|
|
|
- sector_t last_block_in_bio = 0;
|
|
|
|
- int ret = 0;
|
|
|
|
- int done = 0;
|
|
|
|
- int (*writepage)(struct page *page, struct writeback_control *wbc);
|
|
|
|
- struct pagevec pvec;
|
|
|
|
- int nr_pages;
|
|
|
|
- pgoff_t index;
|
|
|
|
- pgoff_t end; /* Inclusive */
|
|
|
|
- int scanned = 0;
|
|
|
|
- int range_whole = 0;
|
|
|
|
-
|
|
|
|
- if (wbc->nonblocking && bdi_write_congested(bdi)) {
|
|
|
|
- wbc->encountered_congestion = 1;
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- writepage = NULL;
|
|
|
|
- if (get_block == NULL)
|
|
|
|
- writepage = mapping->a_ops->writepage;
|
|
|
|
-
|
|
|
|
- pagevec_init(&pvec, 0);
|
|
|
|
- if (wbc->range_cyclic) {
|
|
|
|
- index = mapping->writeback_index; /* Start from prev offset */
|
|
|
|
- end = -1;
|
|
|
|
- } else {
|
|
|
|
- index = wbc->range_start >> PAGE_CACHE_SHIFT;
|
|
|
|
- end = wbc->range_end >> PAGE_CACHE_SHIFT;
|
|
|
|
- if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
|
|
|
|
- range_whole = 1;
|
|
|
|
- scanned = 1;
|
|
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ if (!get_block)
|
|
|
|
+ ret = generic_writepages(mapping, wbc);
|
|
|
|
+ else {
|
|
|
|
+ struct mpage_data mpd = {
|
|
|
|
+ .bio = NULL,
|
|
|
|
+ .last_block_in_bio = 0,
|
|
|
|
+ .get_block = get_block,
|
|
|
|
+ .use_writepage = 1,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ret = write_cache_pages(mapping, wbc, __mpage_writepage, &mpd);
|
|
|
|
+ if (mpd.bio)
|
|
|
|
+ mpage_bio_submit(WRITE, mpd.bio);
|
|
}
|
|
}
|
|
-retry:
|
|
|
|
- while (!done && (index <= end) &&
|
|
|
|
- (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
|
|
|
|
- PAGECACHE_TAG_DIRTY,
|
|
|
|
- min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
|
|
|
|
- unsigned i;
|
|
|
|
-
|
|
|
|
- scanned = 1;
|
|
|
|
- for (i = 0; i < nr_pages; i++) {
|
|
|
|
- struct page *page = pvec.pages[i];
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * At this point we hold neither mapping->tree_lock nor
|
|
|
|
- * lock on the page itself: the page may be truncated or
|
|
|
|
- * invalidated (changing page->mapping to NULL), or even
|
|
|
|
- * swizzled back from swapper_space to tmpfs file
|
|
|
|
- * mapping
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
- lock_page(page);
|
|
|
|
-
|
|
|
|
- if (unlikely(page->mapping != mapping)) {
|
|
|
|
- unlock_page(page);
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!wbc->range_cyclic && page->index > end) {
|
|
|
|
- done = 1;
|
|
|
|
- unlock_page(page);
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (wbc->sync_mode != WB_SYNC_NONE)
|
|
|
|
- wait_on_page_writeback(page);
|
|
|
|
-
|
|
|
|
- if (PageWriteback(page) ||
|
|
|
|
- !clear_page_dirty_for_io(page)) {
|
|
|
|
- unlock_page(page);
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (writepage) {
|
|
|
|
- ret = (*writepage)(page, wbc);
|
|
|
|
- mapping_set_error(mapping, ret);
|
|
|
|
- } else {
|
|
|
|
- bio = __mpage_writepage(bio, page, get_block,
|
|
|
|
- &last_block_in_bio, &ret, wbc,
|
|
|
|
- page->mapping->a_ops->writepage);
|
|
|
|
- }
|
|
|
|
- if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE))
|
|
|
|
- unlock_page(page);
|
|
|
|
- if (ret || (--(wbc->nr_to_write) <= 0))
|
|
|
|
- done = 1;
|
|
|
|
- if (wbc->nonblocking && bdi_write_congested(bdi)) {
|
|
|
|
- wbc->encountered_congestion = 1;
|
|
|
|
- done = 1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- pagevec_release(&pvec);
|
|
|
|
- cond_resched();
|
|
|
|
- }
|
|
|
|
- if (!scanned && !done) {
|
|
|
|
- /*
|
|
|
|
- * We hit the last page and there is more work to be done: wrap
|
|
|
|
- * back to the start of the file
|
|
|
|
- */
|
|
|
|
- scanned = 1;
|
|
|
|
- index = 0;
|
|
|
|
- goto retry;
|
|
|
|
- }
|
|
|
|
- if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
|
|
|
|
- mapping->writeback_index = index;
|
|
|
|
- if (bio)
|
|
|
|
- mpage_bio_submit(WRITE, bio);
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(mpage_writepages);
|
|
EXPORT_SYMBOL(mpage_writepages);
|
|
@@ -804,15 +720,15 @@ EXPORT_SYMBOL(mpage_writepages);
|
|
int mpage_writepage(struct page *page, get_block_t get_block,
|
|
int mpage_writepage(struct page *page, get_block_t get_block,
|
|
struct writeback_control *wbc)
|
|
struct writeback_control *wbc)
|
|
{
|
|
{
|
|
- int ret = 0;
|
|
|
|
- struct bio *bio;
|
|
|
|
- sector_t last_block_in_bio = 0;
|
|
|
|
-
|
|
|
|
- bio = __mpage_writepage(NULL, page, get_block,
|
|
|
|
- &last_block_in_bio, &ret, wbc, NULL);
|
|
|
|
- if (bio)
|
|
|
|
- mpage_bio_submit(WRITE, bio);
|
|
|
|
-
|
|
|
|
|
|
+ struct mpage_data mpd = {
|
|
|
|
+ .bio = NULL,
|
|
|
|
+ .last_block_in_bio = 0,
|
|
|
|
+ .get_block = get_block,
|
|
|
|
+ .use_writepage = 0,
|
|
|
|
+ };
|
|
|
|
+ int ret = __mpage_writepage(page, wbc, &mpd);
|
|
|
|
+ if (mpd.bio)
|
|
|
|
+ mpage_bio_submit(WRITE, mpd.bio);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(mpage_writepage);
|
|
EXPORT_SYMBOL(mpage_writepage);
|