]> Pileus Git - ~andy/linux/blobdiff - fs/f2fs/data.c
f2fs: reduce unncessary locking pages during read
[~andy/linux] / fs / f2fs / data.c
index 277966a8547ad8549efdab6be61a7a87c84c17cd..c8e20b6189134fcefe60d4da4a2a0db5015dcf15 100644 (file)
@@ -199,12 +199,17 @@ struct page *find_data_page(struct inode *inode, pgoff_t index)
        if (!page)
                return ERR_PTR(-ENOMEM);
 
+       if (PageUptodate(page)) {
+               unlock_page(page);
+               return page;
+       }
+
        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;
 }
 
@@ -241,9 +246,13 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
        BUG_ON(dn.data_blkaddr == NULL_ADDR);
 
        err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
-       if (err) {
-               f2fs_put_page(page, 1);
+       if (err)
                return ERR_PTR(err);
+
+       lock_page(page);
+       if (!PageUptodate(page)) {
+               f2fs_put_page(page, 1);
+               return ERR_PTR(-EIO);
        }
        return page;
 }
@@ -283,14 +292,17 @@ struct page *get_new_data_page(struct inode *inode, pgoff_t index,
 
        if (dn.data_blkaddr == NEW_ADDR) {
                zero_user_segment(page, 0, PAGE_CACHE_SIZE);
+               SetPageUptodate(page);
        } else {
                err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
-               if (err) {
-                       f2fs_put_page(page, 1);
+               if (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 &&
                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.
- * Read operation is synchronous, and caller must unlock the page.
+ * Return unlocked page.
  */
 int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page,
                                        block_t blk_addr, int type)
 {
        struct block_device *bdev = sbi->sb->s_bdev;
-       bool sync = (type == READ_SYNC);
        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);
 
        /* Allocate a new bio */
@@ -354,18 +358,12 @@ int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page,
                kfree(bio->bi_private);
                bio_put(bio);
                up_read(&sbi->bio_sem);
+               f2fs_put_page(page, 1);
                return -EFAULT;
        }
 
        submit_bio(type, bio);
        up_read(&sbi->bio_sem);
-
-       /* wait for read completion if sync */
-       if (sync) {
-               lock_page(page);
-               if (PageError(page))
-                       return -EIO;
-       }
        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 */
                zero_user_segments(page, 0, start, end, PAGE_CACHE_SIZE);
-               return 0;
+               goto out;
        }
 
        if (dn.data_blkaddr == NEW_ADDR) {
                zero_user_segment(page, 0, PAGE_CACHE_SIZE);
        } else {
                err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
-               if (err) {
-                       f2fs_put_page(page, 1);
+               if (err)
                        return err;
+               lock_page(page);
+               if (!PageUptodate(page)) {
+                       f2fs_put_page(page, 1);
+                       return -EIO;
                }
        }
+out:
        SetPageUptodate(page);
        clear_cold_data(page);
        return 0;