[RFC 2/5] f2fs: Handle inline data read and write

From: Huajun Li
Date: Mon Jun 03 2013 - 06:06:10 EST


Hook inline data read/write in address space operations.

Signed-off-by: Huajun Li <huajun.li@xxxxxxxxx>
Signed-off-by: Haicheng Li <haicheng.li@xxxxxxxxxxxxxxx>
---
fs/f2fs/data.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
fs/f2fs/file.c | 9 +++++--
2 files changed, 83 insertions(+), 4 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 93917e3..bac25f3 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -64,6 +64,23 @@ int reserve_new_block(struct dnode_of_data *dn)
return 0;
}

+int f2fs_reserve_block(struct inode *inode, pgoff_t index)
+{
+ int err;
+ struct dnode_of_data dn;
+
+ set_new_dnode(&dn, inode, NULL, NULL, 0);
+ err = get_dnode_of_data(&dn, index, ALLOC_NODE);
+ if (err)
+ return err;
+ if (dn.data_blkaddr == NULL_ADDR)
+ err = reserve_new_block(&dn);
+
+ f2fs_put_dnode(&dn);
+
+ return err;
+}
+
static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
struct buffer_head *bh_result)
{
@@ -461,13 +478,28 @@ static int get_data_block_ro(struct inode *inode, sector_t iblock,

static int f2fs_read_data_page(struct file *file, struct page *page)
{
- return mpage_readpage(page, get_data_block_ro);
+ int ret;
+ struct inode *inode = file->f_mapping->host;
+
+ /* If the file has inline data, try to read it directlly */
+ if (f2fs_has_inline_data(inode))
+ ret = f2fs_read_inline_data_page(inode, page);
+ else
+ ret = mpage_readpage(page, get_data_block_ro);
+
+ return ret;
}

static int f2fs_read_data_pages(struct file *file,
struct address_space *mapping,
struct list_head *pages, unsigned nr_pages)
{
+ struct inode *inode = file->f_mapping->host;
+
+ /* If the file has inline data, skip readpages */
+ if (f2fs_has_inline_data(inode))
+ return 0;
+
return mpage_readpages(mapping, pages, nr_pages, get_data_block_ro);
}

@@ -517,7 +549,7 @@ static int f2fs_write_data_page(struct page *page,
loff_t i_size = i_size_read(inode);
const pgoff_t end_index = ((unsigned long long) i_size)
>> PAGE_CACHE_SHIFT;
- unsigned offset;
+ unsigned offset = 0;
bool need_balance_fs = false;
int err = 0;

@@ -551,7 +583,16 @@ write:
err = do_write_data_page(page);
} else {
int ilock = mutex_lock_op(sbi);
+
+#ifdef CONFIG_F2FS_INLINE_DATA
+ if (i_size <= MAX_INLINE_DATA)
+ err = f2fs_write_inline_data(inode, page, offset);
+ else
+ err = do_write_data_page(page);
+#else
err = do_write_data_page(page);
+#endif
+
mutex_unlock_op(sbi, ilock);
need_balance_fs = true;
}
@@ -643,6 +684,25 @@ repeat:
return -ENOMEM;
*pagep = page;

+#ifdef CONFIG_F2FS_INLINE_DATA
+ if ((pos + len) <= MAX_INLINE_DATA) {
+ set_inode_dyn_flag(F2FS_I(inode), F2FS_INLINE_DATA_ATTEMPT);
+ goto inline_data;
+ } else if (f2fs_has_inline_data(inode)) {
+ err = f2fs_convert_inline_data(page, inode, flags);
+ if (err)
+ return err;
+ } else if (f2fs_inline_data_attempt(inode)) {
+ clear_inode_dyn_flag(F2FS_I(inode), F2FS_INLINE_DATA_ATTEMPT);
+
+ ilock = mutex_lock_op(sbi);
+ err = f2fs_reserve_block(inode, 0);
+ if (err)
+ goto err;
+ mutex_unlock_op(sbi, ilock);
+ }
+#endif
+
ilock = mutex_lock_op(sbi);

set_new_dnode(&dn, inode, NULL, NULL, 0);
@@ -659,6 +719,7 @@ repeat:

mutex_unlock_op(sbi, ilock);

+inline_data:
if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
return 0;

@@ -674,7 +735,16 @@ repeat:
if (dn.data_blkaddr == NEW_ADDR) {
zero_user_segment(page, 0, PAGE_CACHE_SIZE);
} else {
+#ifdef CONFIG_F2FS_INLINE_DATA
+ if ((pos + len) <= MAX_INLINE_DATA)
+ err = f2fs_read_inline_data_page(inode, page);
+ else
+ err = f2fs_readpage(sbi, page,
+ dn.data_blkaddr, READ_SYNC);
+#else
err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
+#endif
+
if (err)
return err;
lock_page(page);
@@ -707,6 +777,10 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
if (rw == WRITE)
return 0;

+ /* Let buffer I/O handle the inline data case. */
+ if (f2fs_has_inline_data(inode))
+ return 0;
+
/* Needs synchronization with the cleaner */
return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
get_data_block_ro);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index deefd25..03b13b3 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -178,6 +178,9 @@ int truncate_data_blocks_range(struct dnode_of_data *dn, int count)
raw_node = page_address(dn->node_page);
addr = blkaddr_in_node(raw_node) + ofs;

+ if (f2fs_has_inline_data(dn->inode))
+ return nr_free;
+
for ( ; count > 0; count--, addr++, dn->ofs_in_node++) {
block_t blkaddr = le32_to_cpu(*addr);
if (blkaddr == NULL_ADDR)
@@ -267,11 +270,13 @@ static int truncate_blocks(struct inode *inode, u64 from)

f2fs_put_dnode(&dn);
free_next:
- err = truncate_inode_blocks(inode, free_from);
+ if (!f2fs_has_inline_data(inode))
+ err = truncate_inode_blocks(inode, free_from);
mutex_unlock_op(sbi, ilock);

/* lastly zero out the first data page */
- truncate_partial_data_page(inode, from);
+ if (!f2fs_has_inline_data(inode))
+ truncate_partial_data_page(inode, from);

trace_f2fs_truncate_blocks_exit(inode, err);
return err;
--
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/