|
@@ -199,12 +199,17 @@ struct page *find_data_page(struct inode *inode, pgoff_t index)
|
|
if (!page)
|
|
if (!page)
|
|
return ERR_PTR(-ENOMEM);
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
+ if (PageUptodate(page)) {
|
|
|
|
+ unlock_page(page);
|
|
|
|
+ return page;
|
|
|
|
+ }
|
|
|
|
+
|
|
err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
|
|
err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
|
|
- if (err) {
|
|
|
|
- f2fs_put_page(page, 1);
|
|
|
|
- return ERR_PTR(err);
|
|
|
|
|
|
+ wait_on_page_locked(page);
|
|
|
|
+ if (!PageUptodate(page)) {
|
|
|
|
+ f2fs_put_page(page, 0);
|
|
|
|
+ return ERR_PTR(-EIO);
|
|
}
|
|
}
|
|
- unlock_page(page);
|
|
|
|
return page;
|
|
return page;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -241,9 +246,13 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
|
|
BUG_ON(dn.data_blkaddr == NULL_ADDR);
|
|
BUG_ON(dn.data_blkaddr == NULL_ADDR);
|
|
|
|
|
|
err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
|
|
err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
|
|
- if (err) {
|
|
|
|
- f2fs_put_page(page, 1);
|
|
|
|
|
|
+ if (err)
|
|
return ERR_PTR(err);
|
|
return ERR_PTR(err);
|
|
|
|
+
|
|
|
|
+ lock_page(page);
|
|
|
|
+ if (!PageUptodate(page)) {
|
|
|
|
+ f2fs_put_page(page, 1);
|
|
|
|
+ return ERR_PTR(-EIO);
|
|
}
|
|
}
|
|
return page;
|
|
return page;
|
|
}
|
|
}
|
|
@@ -283,14 +292,17 @@ struct page *get_new_data_page(struct inode *inode, pgoff_t index,
|
|
|
|
|
|
if (dn.data_blkaddr == NEW_ADDR) {
|
|
if (dn.data_blkaddr == NEW_ADDR) {
|
|
zero_user_segment(page, 0, PAGE_CACHE_SIZE);
|
|
zero_user_segment(page, 0, PAGE_CACHE_SIZE);
|
|
|
|
+ SetPageUptodate(page);
|
|
} else {
|
|
} else {
|
|
err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
|
|
err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
|
|
- if (err) {
|
|
|
|
- f2fs_put_page(page, 1);
|
|
|
|
|
|
+ if (err)
|
|
return ERR_PTR(err);
|
|
return ERR_PTR(err);
|
|
|
|
+ lock_page(page);
|
|
|
|
+ if (!PageUptodate(page)) {
|
|
|
|
+ f2fs_put_page(page, 1);
|
|
|
|
+ return ERR_PTR(-EIO);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- SetPageUptodate(page);
|
|
|
|
|
|
|
|
if (new_i_size &&
|
|
if (new_i_size &&
|
|
i_size_read(inode) < ((index + 1) << PAGE_CACHE_SHIFT)) {
|
|
i_size_read(inode) < ((index + 1) << PAGE_CACHE_SHIFT)) {
|
|
@@ -325,22 +337,14 @@ static void read_end_io(struct bio *bio, int err)
|
|
|
|
|
|
/*
|
|
/*
|
|
* Fill the locked page with data located in the block address.
|
|
* Fill the locked page with data located in the block address.
|
|
- * Read operation is synchronous, and caller must unlock the page.
|
|
|
|
|
|
+ * Return unlocked page.
|
|
*/
|
|
*/
|
|
int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page,
|
|
int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page,
|
|
block_t blk_addr, int type)
|
|
block_t blk_addr, int type)
|
|
{
|
|
{
|
|
struct block_device *bdev = sbi->sb->s_bdev;
|
|
struct block_device *bdev = sbi->sb->s_bdev;
|
|
- bool sync = (type == READ_SYNC);
|
|
|
|
struct bio *bio;
|
|
struct bio *bio;
|
|
|
|
|
|
- /* This page can be already read by other threads */
|
|
|
|
- if (PageUptodate(page)) {
|
|
|
|
- if (!sync)
|
|
|
|
- unlock_page(page);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
down_read(&sbi->bio_sem);
|
|
down_read(&sbi->bio_sem);
|
|
|
|
|
|
/* Allocate a new bio */
|
|
/* Allocate a new bio */
|
|
@@ -354,18 +358,12 @@ int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page,
|
|
kfree(bio->bi_private);
|
|
kfree(bio->bi_private);
|
|
bio_put(bio);
|
|
bio_put(bio);
|
|
up_read(&sbi->bio_sem);
|
|
up_read(&sbi->bio_sem);
|
|
|
|
+ f2fs_put_page(page, 1);
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
|
|
|
|
submit_bio(type, bio);
|
|
submit_bio(type, bio);
|
|
up_read(&sbi->bio_sem);
|
|
up_read(&sbi->bio_sem);
|
|
-
|
|
|
|
- /* wait for read completion if sync */
|
|
|
|
- if (sync) {
|
|
|
|
- lock_page(page);
|
|
|
|
- if (PageError(page))
|
|
|
|
- return -EIO;
|
|
|
|
- }
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -636,18 +634,22 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
|
|
|
|
|
|
/* Reading beyond i_size is simple: memset to zero */
|
|
/* Reading beyond i_size is simple: memset to zero */
|
|
zero_user_segments(page, 0, start, end, PAGE_CACHE_SIZE);
|
|
zero_user_segments(page, 0, start, end, PAGE_CACHE_SIZE);
|
|
- return 0;
|
|
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
if (dn.data_blkaddr == NEW_ADDR) {
|
|
if (dn.data_blkaddr == NEW_ADDR) {
|
|
zero_user_segment(page, 0, PAGE_CACHE_SIZE);
|
|
zero_user_segment(page, 0, PAGE_CACHE_SIZE);
|
|
} else {
|
|
} else {
|
|
err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
|
|
err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
|
|
- if (err) {
|
|
|
|
- f2fs_put_page(page, 1);
|
|
|
|
|
|
+ if (err)
|
|
return err;
|
|
return err;
|
|
|
|
+ lock_page(page);
|
|
|
|
+ if (!PageUptodate(page)) {
|
|
|
|
+ f2fs_put_page(page, 1);
|
|
|
|
+ return -EIO;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+out:
|
|
SetPageUptodate(page);
|
|
SetPageUptodate(page);
|
|
clear_cold_data(page);
|
|
clear_cold_data(page);
|
|
return 0;
|
|
return 0;
|