* [PATCH] f2fs: reduce unncessary locking pages during read
@ 2013-03-18 5:50 Jaegeuk Kim
2013-03-19 4:54 ` Namjae Jeon
0 siblings, 1 reply; 4+ messages in thread
From: Jaegeuk Kim @ 2013-03-18 5:50 UTC (permalink / raw)
Cc: Jaegeuk Kim, linux-fsdevel, linux-kernel, linux-f2fs-devel,
Changman Lee
This patch reduces redundant locking and unlocking pages during read operations.
In f2fs_readpage, let's use wait_on_page_locked() instead of lock_page.
And then, when we need to modify any data finally, let's lock the page so that
we can avoid lock contention.
[readpage rule]
- The f2fs_readpage returns unlocked page, or released page too in error cases.
- Its caller should handle read error, -EIO, after locking the page, which
indicates read completion.
- Its caller should check PageUptodate after grab_cache_page.
Signed-off-by: Changman Lee <cm224.lee@samsung.com>
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
---
fs/f2fs/checkpoint.c | 12 ++++++-----
fs/f2fs/data.c | 58 ++++++++++++++++++++++++++--------------------------
fs/f2fs/node.c | 58 +++++++++++++++++++++++++++++++---------------------
fs/f2fs/recovery.c | 31 +++++++++++++++++-----------
4 files changed, 90 insertions(+), 69 deletions(-)
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 2b6fc13..d947e66 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -57,13 +57,15 @@ repeat:
cond_resched();
goto repeat;
}
- if (f2fs_readpage(sbi, page, index, READ_SYNC)) {
- f2fs_put_page(page, 1);
+ if (PageUptodate(page))
+ goto out;
+
+ if (f2fs_readpage(sbi, page, index, READ_SYNC))
goto repeat;
- }
- mark_page_accessed(page);
- /* We do not allow returning an errorneous page */
+ lock_page(page);
+out:
+ mark_page_accessed(page);
return page;
}
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 277966a..6616137 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -199,12 +199,15 @@ struct page *find_data_page(struct inode *inode, pgoff_t index)
if (!page)
return ERR_PTR(-ENOMEM);
- err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
- if (err) {
- f2fs_put_page(page, 1);
- return ERR_PTR(err);
+ if (PageUptodate(page)) {
+ unlock_page(page);
+ return page;
}
- unlock_page(page);
+
+ err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
+ wait_on_page_locked(page);
+ if (!PageUptodate(page))
+ return ERR_PTR(-EIO);
return page;
}
@@ -241,9 +244,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 +290,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 +335,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 +356,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 +632,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;
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index a3cb1ff..9e6ed67 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -100,10 +100,13 @@ static void ra_nat_pages(struct f2fs_sb_info *sbi, int nid)
page = grab_cache_page(mapping, index);
if (!page)
continue;
- if (f2fs_readpage(sbi, page, index, READ)) {
+ if (PageUptodate(page)) {
f2fs_put_page(page, 1);
continue;
}
+ if (f2fs_readpage(sbi, page, index, READ))
+ continue;
+
f2fs_put_page(page, 0);
}
}
@@ -851,8 +854,16 @@ static int read_node_page(struct page *page, int type)
get_node_info(sbi, page->index, &ni);
- if (ni.blk_addr == NULL_ADDR)
+ if (ni.blk_addr == NULL_ADDR) {
+ f2fs_put_page(page, 1);
return -ENOENT;
+ }
+
+ if (PageUptodate(page)) {
+ unlock_page(page);
+ return 0;
+ }
+
return f2fs_readpage(sbi, page, ni.blk_addr, type);
}
@@ -865,19 +876,18 @@ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
struct page *apage;
apage = find_get_page(mapping, nid);
- if (apage && PageUptodate(apage))
- goto release_out;
+ if (apage && PageUptodate(apage)) {
+ f2fs_put_page(apage, 0);
+ return;
+ }
f2fs_put_page(apage, 0);
apage = grab_cache_page(mapping, nid);
if (!apage)
return;
- if (read_node_page(apage, READA))
- unlock_page(apage);
-
-release_out:
- f2fs_put_page(apage, 0);
+ if (read_node_page(apage, READA) == 0)
+ f2fs_put_page(apage, 0);
return;
}
@@ -892,11 +902,14 @@ struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
return ERR_PTR(-ENOMEM);
err = read_node_page(page, 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);
+ }
BUG_ON(nid != nid_of_node(page));
mark_page_accessed(page);
return page;
@@ -928,11 +941,8 @@ repeat:
goto page_hit;
err = read_node_page(page, READ_SYNC);
- unlock_page(page);
- if (err) {
- f2fs_put_page(page, 0);
+ if (err)
return ERR_PTR(err);
- }
/* Then, try readahead for siblings of the desired node */
end = start + MAX_RA_NODE;
@@ -957,6 +967,7 @@ page_hit:
f2fs_put_page(page, 1);
goto repeat;
}
+ mark_page_accessed(page);
return page;
}
@@ -1473,23 +1484,24 @@ int restore_node_summary(struct f2fs_sb_info *sbi,
sum_entry = &sum->entries[0];
for (i = 0; i < last_offset; i++, sum_entry++) {
+ /*
+ * In order to read next node page,
+ * we must clear PageUptodate flag.
+ */
+ ClearPageUptodate(page);
+
if (f2fs_readpage(sbi, page, addr, READ_SYNC))
goto out;
+ lock_page(page);
rn = (struct f2fs_node *)page_address(page);
sum_entry->nid = rn->footer.nid;
sum_entry->version = 0;
sum_entry->ofs_in_node = 0;
addr++;
-
- /*
- * In order to read next node page,
- * we must clear PageUptodate flag.
- */
- ClearPageUptodate(page);
}
-out:
unlock_page(page);
+out:
__free_pages(page, 0);
return 0;
}
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index 6b82e20..5c792b7 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -112,11 +112,17 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
while (1) {
struct fsync_inode_entry *entry;
- if (f2fs_readpage(sbi, page, blkaddr, READ_SYNC))
+ ClearPageUptodate(page);
+ err = f2fs_readpage(sbi, page, blkaddr, READ_SYNC);
+ if (err)
goto out;
- if (cp_ver != cpver_of_node(page))
- goto out;
+ lock_page(page);
+
+ if (cp_ver != cpver_of_node(page)) {
+ err = -EINVAL;
+ goto unlock_out;
+ }
if (!is_fsync_dnode(page))
goto next;
@@ -131,7 +137,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
if (IS_INODE(page) && is_dent_dnode(page)) {
if (recover_inode_page(sbi, page)) {
err = -ENOMEM;
- goto out;
+ goto unlock_out;
}
}
@@ -139,14 +145,14 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
entry = kmem_cache_alloc(fsync_entry_slab, GFP_NOFS);
if (!entry) {
err = -ENOMEM;
- goto out;
+ goto unlock_out;
}
entry->inode = f2fs_iget(sbi->sb, ino_of_node(page));
if (IS_ERR(entry->inode)) {
err = PTR_ERR(entry->inode);
kmem_cache_free(fsync_entry_slab, entry);
- goto out;
+ goto unlock_out;
}
list_add_tail(&entry->list, head);
@@ -155,15 +161,15 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
if (IS_INODE(page)) {
err = recover_inode(entry->inode, page);
if (err)
- goto out;
+ goto unlock_out;
}
next:
/* check next segment */
blkaddr = next_blkaddr_of_node(page);
- ClearPageUptodate(page);
}
-out:
+unlock_out:
unlock_page(page);
+out:
__free_pages(page, 0);
return err;
}
@@ -316,11 +322,12 @@ static void recover_data(struct f2fs_sb_info *sbi,
while (1) {
struct fsync_inode_entry *entry;
+ ClearPageUptodate(page);
if (f2fs_readpage(sbi, page, blkaddr, READ_SYNC))
goto out;
if (cp_ver != cpver_of_node(page))
- goto out;
+ goto unlock_out;
entry = get_fsync_inode(head, ino_of_node(page));
if (!entry)
@@ -336,10 +343,10 @@ static void recover_data(struct f2fs_sb_info *sbi,
next:
/* check next segment */
blkaddr = next_blkaddr_of_node(page);
- ClearPageUptodate(page);
}
-out:
+unlock_out:
unlock_page(page);
+out:
__free_pages(page, 0);
allocate_new_segments(sbi);
--
1.8.1.3.566.gaa39828
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] f2fs: reduce unncessary locking pages during read
2013-03-18 5:50 [PATCH] f2fs: reduce unncessary locking pages during read Jaegeuk Kim
@ 2013-03-19 4:54 ` Namjae Jeon
2013-03-19 7:04 ` Jaegeuk Kim
0 siblings, 1 reply; 4+ messages in thread
From: Namjae Jeon @ 2013-03-19 4:54 UTC (permalink / raw)
To: Jaegeuk Kim; +Cc: linux-fsdevel, linux-kernel, linux-f2fs-devel, Changman Lee
>
> - err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
> - if (err) {
> - f2fs_put_page(page, 1);
> - return ERR_PTR(err);
> + if (PageUptodate(page)) {
> + unlock_page(page);
> + return page;
> }
> - unlock_page(page);
Hi Jaegeuk.
> +
> + err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
> + wait_on_page_locked(page);
> + if (!PageUptodate(page))
> + return ERR_PTR(-EIO);
We don't need to release page before returning EIO ?
> return page;
> }
>
> @@ -241,9 +244,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);
Here is also same. We don't need to release page in case of err ?
Thanks.
> +
> + lock_page(page);
> + if (!PageUptodate(page)) {
> + f2fs_put_page(page, 1);
> + return ERR_PTR(-EIO);
> }
> return page;
> }
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] f2fs: reduce unncessary locking pages during read
2013-03-19 4:54 ` Namjae Jeon
@ 2013-03-19 7:04 ` Jaegeuk Kim
2013-03-19 8:17 ` Namjae Jeon
0 siblings, 1 reply; 4+ messages in thread
From: Jaegeuk Kim @ 2013-03-19 7:04 UTC (permalink / raw)
To: Namjae Jeon; +Cc: linux-fsdevel, linux-kernel, linux-f2fs-devel, Changman Lee
[-- Attachment #1: Type: text/plain, Size: 1549 bytes --]
2013-03-19 (화), 13:54 +0900, Namjae Jeon:
> >
> > - err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
> > - if (err) {
> > - f2fs_put_page(page, 1);
> > - return ERR_PTR(err);
> > + if (PageUptodate(page)) {
> > + unlock_page(page);
> > + return page;
> > }
> > - unlock_page(page);
> Hi Jaegeuk.
> > +
> > + err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
> > + wait_on_page_locked(page);
> > + if (!PageUptodate(page))
> > + return ERR_PTR(-EIO);
> We don't need to release page before returning EIO ?
Good catch! :)
>
> > return page;
> > }
> >
> > @@ -241,9 +244,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);
> Here is also same. We don't need to release page in case of err ?
It's different.
The f2fs_readpage() releases the page if error is occurred.
Thanks,
>
> Thanks.
> > +
> > + lock_page(page);
> > + if (!PageUptodate(page)) {
> > + f2fs_put_page(page, 1);
> > + return ERR_PTR(-EIO);
> > }
> > return page;
> > }
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
Jaegeuk Kim
Samsung
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] f2fs: reduce unncessary locking pages during read
2013-03-19 7:04 ` Jaegeuk Kim
@ 2013-03-19 8:17 ` Namjae Jeon
0 siblings, 0 replies; 4+ messages in thread
From: Namjae Jeon @ 2013-03-19 8:17 UTC (permalink / raw)
To: jaegeuk.kim; +Cc: linux-fsdevel, linux-kernel, linux-f2fs-devel, Changman Lee
2013/3/19, Jaegeuk Kim <jaegeuk.kim@samsung.com>:
> 2013-03-19 (화), 13:54 +0900, Namjae Jeon:
>> >
>> > - err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
>> > - if (err) {
>> > - f2fs_put_page(page, 1);
>> > - return ERR_PTR(err);
>> > + if (PageUptodate(page)) {
>> > + unlock_page(page);
>> > + return page;
>> > }
>> > - unlock_page(page);
>> Hi Jaegeuk.
>> > +
>> > + err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
>> > + wait_on_page_locked(page);
>> > + if (!PageUptodate(page))
>> > + return ERR_PTR(-EIO);
>> We don't need to release page before returning EIO ?
>
> Good catch! :)
>
>>
>> > return page;
>> > }
>> >
>> > @@ -241,9 +244,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);
>> Here is also same. We don't need to release page in case of err ?
>
> It's different.
> The f2fs_readpage() releases the page if error is occurred.
> Thanks,
Right~. you can add
Reviewed-by: Namjae Jeon <namjae.jeon@samsung.com>
Thanks.
>
>>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-03-19 8:17 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-03-18 5:50 [PATCH] f2fs: reduce unncessary locking pages during read Jaegeuk Kim
2013-03-19 4:54 ` Namjae Jeon
2013-03-19 7:04 ` Jaegeuk Kim
2013-03-19 8:17 ` Namjae Jeon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).