* [PATCH 1/2] f2fs: disable the extent cache ops on high fragmented files
@ 2013-11-19 7:10 Jaegeuk Kim
2013-11-19 7:10 ` [PATCH 2/2] f2fs: introduce a bio array for per-page write bios Jaegeuk Kim
2013-11-21 5:34 ` [f2fs-dev] [PATCH 1/2] f2fs: disable the extent cache ops on high fragmented files Haicheng Li
0 siblings, 2 replies; 3+ messages in thread
From: Jaegeuk Kim @ 2013-11-19 7:10 UTC (permalink / raw)
Cc: Jaegeuk Kim, linux-fsdevel, linux-kernel, linux-f2fs-devel
The f2fs manages an extent cache to search a number of consecutive data blocks
very quickly.
However it conducts unnecessary cache operations if the file is highly
fragmented with no valid extent cache.
In such the case, we don't need to handle the extent cache, but just can disable
the cache facility.
Nevertheless, this patch gives one more chance to enable the extent cache.
For example,
1. create a file
2. write data sequentially which produces a large valid extent cache
3. update some data, resulting in a fragmented extent
4. if the fragmented extent is too small, then drop extent cache
5. close the file
6. open the file again
7. give another chance to make a new extent cache
8. write data sequentially again which creates another big extent cache.
...
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
---
fs/f2fs/data.c | 22 ++++++++++++++++++----
fs/f2fs/f2fs.h | 3 +++
2 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 5920639..2e54522 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -71,6 +71,9 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
pgoff_t start_fofs, end_fofs;
block_t start_blkaddr;
+ if (is_inode_flag_set(fi, FI_NO_EXTENT))
+ return 0;
+
read_lock(&fi->ext.ext_lock);
if (fi->ext.len == 0) {
read_unlock(&fi->ext.ext_lock);
@@ -109,6 +112,7 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn)
struct f2fs_inode_info *fi = F2FS_I(dn->inode);
pgoff_t fofs, start_fofs, end_fofs;
block_t start_blkaddr, end_blkaddr;
+ int need_update = true;
f2fs_bug_on(blk_addr == NEW_ADDR);
fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) +
@@ -117,6 +121,9 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn)
/* Update the page address in the parent node */
__set_data_blkaddr(dn, blk_addr);
+ if (is_inode_flag_set(fi, FI_NO_EXTENT))
+ return;
+
write_lock(&fi->ext.ext_lock);
start_fofs = fi->ext.fofs;
@@ -163,14 +170,21 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn)
fofs - start_fofs + 1;
fi->ext.len -= fofs - start_fofs + 1;
}
- goto end_update;
+ } else {
+ need_update = false;
}
- write_unlock(&fi->ext.ext_lock);
- return;
+ /* Finally, if the extent is very fragmented, let's drop the cache. */
+ if (fi->ext.len < F2FS_MIN_EXTENT_LEN) {
+ fi->ext.len = 0;
+ set_inode_flag(fi, FI_NO_EXTENT);
+ need_update = true;
+ }
end_update:
write_unlock(&fi->ext.ext_lock);
- sync_inode_page(dn);
+ if (need_update)
+ sync_inode_page(dn);
+ return;
}
struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync)
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index c2de549..e9038bb 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -169,6 +169,8 @@ enum {
#define F2FS_LINK_MAX 32000 /* maximum link count per file */
/* for in-memory extent cache entry */
+#define F2FS_MIN_EXTENT_LEN 16 /* minimum extent length */
+
struct extent_info {
rwlock_t ext_lock; /* rwlock for consistency */
unsigned int fofs; /* start offset in a file */
@@ -889,6 +891,7 @@ enum {
FI_NO_ALLOC, /* should not allocate any blocks */
FI_UPDATE_DIR, /* should update inode block for consistency */
FI_DELAY_IPUT, /* used for the recovery */
+ FI_NO_EXTENT, /* not to use the extent cache */
FI_INLINE_XATTR, /* used for inline xattr */
};
--
1.8.4.474.g128a96c
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/2] f2fs: introduce a bio array for per-page write bios
2013-11-19 7:10 [PATCH 1/2] f2fs: disable the extent cache ops on high fragmented files Jaegeuk Kim
@ 2013-11-19 7:10 ` Jaegeuk Kim
2013-11-21 5:34 ` [f2fs-dev] [PATCH 1/2] f2fs: disable the extent cache ops on high fragmented files Haicheng Li
1 sibling, 0 replies; 3+ messages in thread
From: Jaegeuk Kim @ 2013-11-19 7:10 UTC (permalink / raw)
Cc: linux-fsdevel, linux-kernel, linux-f2fs-devel
The f2fs has three bio types, NODE, DATA, and META, and manages some data
structures per each bio types.
The codes are a little bit messy, thus, this patch introduces a bio array
which groups individual data structures as follows.
struct f2fs_bio_info {
struct bio *bio; /* bios to merge */
sector_t last_block_in_bio; /* last block number */
struct mutex io_mutex; /* mutex for bio */
};
struct f2fs_sb_info {
...
struct f2fs_bio_info write_io[NR_PAGE_TYPE]; /* for write bios */
...
};
The code changes from this new data structure are trivial.
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
---
fs/f2fs/f2fs.h | 12 +++++++++---
fs/f2fs/segment.c | 44 ++++++++++++++++++++++----------------------
fs/f2fs/super.c | 2 +-
3 files changed, 32 insertions(+), 26 deletions(-)
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index e9038bb..05f8fe1 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -361,6 +361,12 @@ enum page_type {
META_FLUSH,
};
+struct f2fs_bio_info {
+ struct bio *bio; /* bios to merge */
+ sector_t last_block_in_bio; /* last block number */
+ struct mutex io_mutex; /* mutex for bio */
+};
+
struct f2fs_sb_info {
struct super_block *sb; /* pointer to VFS super block */
struct proc_dir_entry *s_proc; /* proc entry */
@@ -374,9 +380,9 @@ struct f2fs_sb_info {
/* for segment-related operations */
struct f2fs_sm_info *sm_info; /* segment manager */
- struct bio *bio[NR_PAGE_TYPE]; /* bios to merge */
- sector_t last_block_in_bio[NR_PAGE_TYPE]; /* last block number */
- struct mutex write_mutex[NR_PAGE_TYPE]; /* mutex for writing IOs */
+
+ /* for bio operations */
+ struct f2fs_bio_info write_io[NR_PAGE_TYPE]; /* for write bios */
/* for checkpoint */
struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 119af0b..9607cc4 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -838,65 +838,65 @@ static void do_submit_bio(struct f2fs_sb_info *sbi,
{
int rw = sync ? WRITE_SYNC : WRITE;
enum page_type btype = PAGE_TYPE_OF_BIO(type);
- struct bio *bio = sbi->bio[btype];
+ struct f2fs_bio_info *io = &sbi->write_io[btype];
struct bio_private *p;
- if (!bio)
+ if (!io->bio)
return;
- sbi->bio[btype] = NULL;
-
if (type >= META_FLUSH)
rw = WRITE_FLUSH_FUA;
if (btype == META)
rw |= REQ_META;
- p = bio->bi_private;
+ p = io->bio->bi_private;
p->sbi = sbi;
- bio->bi_end_io = f2fs_end_io_write;
+ io->bio->bi_end_io = f2fs_end_io_write;
- trace_f2fs_do_submit_bio(sbi->sb, btype, sync, bio);
+ trace_f2fs_do_submit_bio(sbi->sb, btype, sync, io->bio);
if (type == META_FLUSH) {
DECLARE_COMPLETION_ONSTACK(wait);
p->is_sync = true;
p->wait = &wait;
- submit_bio(rw, bio);
+ submit_bio(rw, io->bio);
wait_for_completion(&wait);
} else {
p->is_sync = false;
- submit_bio(rw, bio);
+ submit_bio(rw, io->bio);
}
+ io->bio = NULL;
}
void f2fs_submit_bio(struct f2fs_sb_info *sbi, enum page_type type, bool sync)
{
- enum page_type btype = PAGE_TYPE_OF_BIO(type);
+ struct f2fs_bio_info *io = &sbi->write_io[PAGE_TYPE_OF_BIO(type)];
- if (!sbi->bio[btype])
+ if (!io->bio)
return;
- mutex_lock(&sbi->write_mutex[btype]);
+ mutex_lock(&io->io_mutex);
do_submit_bio(sbi, type, sync);
- mutex_unlock(&sbi->write_mutex[btype]);
+ mutex_unlock(&io->io_mutex);
}
static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page,
block_t blk_addr, enum page_type type)
{
struct block_device *bdev = sbi->sb->s_bdev;
+ struct f2fs_bio_info *io = &sbi->write_io[type];
int bio_blocks;
verify_block_addr(sbi, blk_addr);
- mutex_lock(&sbi->write_mutex[type]);
+ mutex_lock(&io->io_mutex);
inc_page_count(sbi, F2FS_WRITEBACK);
- if (sbi->bio[type] && sbi->last_block_in_bio[type] != blk_addr - 1)
+ if (io->bio && io->last_block_in_bio != blk_addr - 1)
do_submit_bio(sbi, type, false);
alloc_new:
- if (sbi->bio[type] == NULL) {
+ if (io->bio == NULL) {
struct bio_private *priv;
retry:
priv = kmalloc(sizeof(struct bio_private), GFP_NOFS);
@@ -906,9 +906,9 @@ retry:
}
bio_blocks = MAX_BIO_BLOCKS(max_hw_blocks(sbi));
- sbi->bio[type] = f2fs_bio_alloc(bdev, bio_blocks);
- sbi->bio[type]->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr);
- sbi->bio[type]->bi_private = priv;
+ io->bio = f2fs_bio_alloc(bdev, bio_blocks);
+ io->bio->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr);
+ io->bio->bi_private = priv;
/*
* The end_io will be assigned at the sumbission phase.
* Until then, let bio_add_page() merge consecutive IOs as much
@@ -916,15 +916,15 @@ retry:
*/
}
- if (bio_add_page(sbi->bio[type], page, PAGE_CACHE_SIZE, 0) <
+ if (bio_add_page(io->bio, page, PAGE_CACHE_SIZE, 0) <
PAGE_CACHE_SIZE) {
do_submit_bio(sbi, type, false);
goto alloc_new;
}
- sbi->last_block_in_bio[type] = blk_addr;
+ io->last_block_in_bio = blk_addr;
- mutex_unlock(&sbi->write_mutex[type]);
+ mutex_unlock(&io->io_mutex);
trace_f2fs_submit_write_page(page, blk_addr, type);
}
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index e194578..8c677e9 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -879,7 +879,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
spin_lock_init(&sbi->stat_lock);
for (i = 0; i < NR_PAGE_TYPE; i++)
- mutex_init(&sbi->write_mutex[i]);
+ mutex_init(&sbi->write_io[i].io_mutex);
init_rwsem(&sbi->cp_rwsem);
init_waitqueue_head(&sbi->cp_wait);
--
1.8.4.474.g128a96c
------------------------------------------------------------------------------
Shape the Mobile Experience: Free Subscription
Software experts and developers: Be at the forefront of tech innovation.
Intel(R) Software Adrenaline delivers strategic insight and game-changing
conversations that shape the rapidly evolving mobile landscape. Sign up now.
http://pubads.g.doubleclick.net/gampad/clk?id=63431311&iu=/4140/ostg.clktrk
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [f2fs-dev] [PATCH 1/2] f2fs: disable the extent cache ops on high fragmented files
2013-11-19 7:10 [PATCH 1/2] f2fs: disable the extent cache ops on high fragmented files Jaegeuk Kim
2013-11-19 7:10 ` [PATCH 2/2] f2fs: introduce a bio array for per-page write bios Jaegeuk Kim
@ 2013-11-21 5:34 ` Haicheng Li
1 sibling, 0 replies; 3+ messages in thread
From: Haicheng Li @ 2013-11-21 5:34 UTC (permalink / raw)
To: Jaegeuk Kim; +Cc: linux-fsdevel, linux-kernel, linux-f2fs-devel
> Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Function looks good to me. But some nitpicking below for code cleanup..
> @@ -71,6 +71,9 @@ static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
return value could be boolean?
> pgoff_t start_fofs, end_fofs;
> block_t start_blkaddr;
>
> + if (is_inode_flag_set(fi, FI_NO_EXTENT))
> + return 0;
> +
> read_lock(&fi->ext.ext_lock);
> if (fi->ext.len == 0) {
> read_unlock(&fi->ext.ext_lock);
> @@ -109,6 +112,7 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn)
> struct f2fs_inode_info *fi = F2FS_I(dn->inode);
> pgoff_t fofs, start_fofs, end_fofs;
> block_t start_blkaddr, end_blkaddr;
> + int need_update = true;
bool?
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2013-11-21 5:34 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-11-19 7:10 [PATCH 1/2] f2fs: disable the extent cache ops on high fragmented files Jaegeuk Kim
2013-11-19 7:10 ` [PATCH 2/2] f2fs: introduce a bio array for per-page write bios Jaegeuk Kim
2013-11-21 5:34 ` [f2fs-dev] [PATCH 1/2] f2fs: disable the extent cache ops on high fragmented files Haicheng Li
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).