Re: [f2fs-dev] [PATCH V2 4/6] f2fs: Key functions to handle inline data

2013-11-20 Thread Huajun Li
On Fri, Nov 15, 2013 at 3:49 PM, Jaegeuk Kim  wrote:
> Hi Huajun,
>
> [snip]
>
>> +static int __f2fs_convert_inline_data(struct inode *inode, struct page 
>> *page)
>> +{
>> + int err;
>> + struct page *ipage;
>> + struct dnode_of_data dn;
>> + void *src_addr, *dst_addr;
>> + block_t old_blk_addr, new_blk_addr;
>> + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
>> +
>> + f2fs_lock_op(sbi);
>> + ipage = get_node_page(sbi, inode->i_ino);
>> + if (IS_ERR(ipage))
>> + return PTR_ERR(ipage);
>> +
>> + /*
>> +  * i_addr[0] is not used for inline data,
>> +  * so reserving new block will not destroy inline data
>> +  */
>> + set_new_dnode(&dn, inode, ipage, ipage, 0);
>> + err = f2fs_reserve_block(&dn, 0);
>> + if (err) {
>> + f2fs_put_page(ipage, 1);
>> + f2fs_unlock_op(sbi);
>> + return err;
>> + }
>> +
>> + src_addr = inline_data_addr(ipage);
>> + dst_addr = page_address(page);
>> + zero_user_segment(page, 0, PAGE_CACHE_SIZE);
>> +
>> + /* Copy the whole inline data block */
>> + memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
>> +
>> + /* write data page to try to make data consistent */
>> + old_blk_addr = dn.data_blkaddr;
>> + set_page_writeback(page);
>> + write_data_page(inode, page, &dn,
>> + old_blk_addr, &new_blk_addr);
>> + update_extent_cache(new_blk_addr, &dn);
>> + f2fs_wait_on_page_writeback(page, DATA, true);
>> +
>> + /* clear inline data and flag after data writeback */
>> + zero_user_segment(ipage, INLINE_DATA_OFFSET,
>> +  INLINE_DATA_OFFSET + MAX_INLINE_DATA);
>> + clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
>> +
>> + sync_inode_page(&dn);
>> + f2fs_put_page(ipage, 1);
>
> Again, it seems that you missed what I mentioned.
> If we write the inlined data block only, we cannot recover the data
> block after SPO.
> In order to avoid that, we should write its dnode block too by
> triggering sync_node_pages(ino) at this point as similar as fsync
> routine.
>
> Thanks,
>
> --
> Jaegeuk Kim
> Samsung
>

Hi Jaegeuk,
Previously, I refactored f2fs_sync_file() and tried to call it while
converting inline data, but find it is easily dead lock, so just write
data block here.
Then, how about following enhancement to this patch ?  it only copies
some codes to the end of  __f2fs_convert_inline_data(),  and keeps
others same as before.

-
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index e9b33d7..6ceb2e6 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -10,6 +10,8 @@

 #include 
 #include 
+#include 
+#include 

 #include "f2fs.h"

@@ -71,6 +73,11 @@ static int __f2fs_convert_inline_data(struct inode
*inode, struct page *page)
 void *src_addr, *dst_addr;
 block_t old_blk_addr, new_blk_addr;
 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+struct writeback_control wbc = {
+.sync_mode = WB_SYNC_ALL,
+.nr_to_write = LONG_MAX,
+.for_reclaim = 0,
+};

 f2fs_lock_op(sbi);
 ipage = get_node_page(sbi, inode->i_ino);
@@ -108,9 +115,20 @@ static int __f2fs_convert_inline_data(struct
inode *inode, struct page *page)
 zero_user_segment(ipage, INLINE_DATA_OFFSET,
  INLINE_DATA_OFFSET + MAX_INLINE_DATA);
 clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
-
 sync_inode_page(&dn);
 f2fs_put_page(ipage, 1);
+
+while (!sync_node_pages(sbi, inode->i_ino, &wbc)) {
+mark_inode_dirty_sync(inode);
+err = f2fs_write_inode(inode, NULL);
+if (err)
+goto out;
+}
+err = wait_on_node_pages_writeback(sbi, inode->i_ino);
+if (err)
+goto out;
+err = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
+
+out:
 f2fs_unlock_op(sbi);

 return err;

--
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
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


Re: [f2fs-dev] [PATCH 1/1] No need to do recovery if there is no available CP

2013-11-10 Thread Huajun Li
On Mon, Nov 11, 2013 at 12:33 PM, Jaegeuk Kim  wrote:
> Hi Huajun,
>
> 2013-11-05 (화), 21:28 +0800, Huajun Li:
>> Hi Jaegeuk,
>>
>> Got it, and nice to fix it in mkfs.f2fs.
>>
>> Thanks,
>> --Huajun
>> On Tue, Nov 5, 2013 at 12:48 PM, Jaegeuk Kim  wrote:
>> > Hi Huajun,
>> >
>> > 2013-11-04 (월), 23:40 +0800, Huajun Li:
>> >> Hi Jaegeuk,
>> >>
>> >> On Mon, Nov 4, 2013 at 9:24 AM, Jaegeuk Kim  
>> >> wrote:
>> >> > 2013-11-03 (일), 23:08 +0800, Huajun Li:
>> >> >> From: Huajun Li 
>> >> >>
>> >> >> Normally we expect an empty partition after formatting by
>> >> >> mkfs.f2fs. But in this case, when we format a dirty partition and mount
>> >> >> it again. The former file will be recovered and available again! and
>> >> >> kernel log shows a recovery procedure is evoked.
>> >> >> This patch adds a new flag CP_EXIST_FLAG to indicate whether is a
>> >> >> available CP, and do recovery only when this flag is set.
>> >> >
>> >> > IMO, mkfs.f2fs should do the right thing to avoid this.
>> >> > If storage does not support discard, mkfs.f2fs can simply address the
>> >> > problem by writing one node block with zeros to prevent this.
>> >> >
>
> WRT the below issue, I made a patch for mkfs.f2fs.
> If possible, could you test and write a valid patch?
> Thanks,
>
Hi Jaegeuk,

Test your following fix just now on the same test machine, it can work fine.
This is new implementation to fix the issue, maybe you can
submit/integrate your patch directly.   ;)

> ---
>  mkfs/f2fs_format.c | 7 ++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c
> index 8234b00..18ded79 100644
> --- a/mkfs/f2fs_format.c
> +++ b/mkfs/f2fs_format.c
> @@ -788,7 +788,12 @@ static int f2fs_write_root_inode(void)
>
> memset(raw_node, 0xff, sizeof(struct f2fs_node));
>
> -   main_area_node_seg_blk_offset += F2FS_BLKSIZE;
> +   /* avoid power-off-recovery based on roll-forward policy */
> +   main_area_node_seg_blk_offset = le32_to_cpu(super_block.main_blkaddr);
> +   main_area_node_seg_blk_offset += config.cur_seg[CURSEG_WARM_NODE] *
> +   config.blks_per_seg;
> +main_area_node_seg_blk_offset *= blk_size_bytes;
> +
> if (dev_write(raw_node, main_area_node_seg_blk_offset, F2FS_BLKSIZE))
> {
> MSG(1, "\tError: While writing the raw_node to disk!!!\n");
> return -1;
> --
> 1.8.4.474.g128a96c
>
>
> --
> Jaegeuk Kim
> Samsung
>

--
November Webinars for C, C++, Fortran Developers
Accelerate application performance with scalable programming models. Explore
techniques for threading, error checking, porting, and tuning. Get the most 
from the latest Intel processors and coprocessors. See abstracts and register
http://pubads.g.doubleclick.net/gampad/clk?id=60136231&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH V2 5/6] f2fs: Handle inline data operations

2013-11-10 Thread Huajun Li
From: Huajun Li 

Hook inline data read/write, truncate, fallocate, setattr, etc.

Files need meet following 2 requirement to inline:
 1) file size is not greater than MAX_INLINE_DATA;
 2) file doesn't pre-allocate data blocks by fallocate().

FI_INLINE_DATA will not be set while creating a new regular inode because
most of the files are bigger than ~3.4K. Set FI_INLINE_DATA only when
data is submitted to block layer, ranther than set it while creating a new
inode, this also avoids converting data from inline to normal data block
and vice versa.

While writting inline data to inode block, the first data block should be
released if the file has a block indexed by i_addr[0].

On the other hand, when a file operation is appied to a file with inline
data, we need to test if this file can remain inline by doing this
operation, otherwise it should be convert into normal file by reserving
a new data block, copying inline data to this new block and clear
FI_INLINE_DATA flag. Because reserve a new data block here will make use
of i_addr[0], if we save inline data in i_addr[0..872], then the first
4 bytes would be overwriten. This problem can be avoided simply by
not using i_addr[0] for inline data.

Signed-off-by: Huajun Li 
Signed-off-by: Haicheng Li 
Signed-off-by: Weihong Xu 
---
 fs/f2fs/data.c |   49 -
 fs/f2fs/file.c |   43 ---
 2 files changed, 84 insertions(+), 8 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 92d0724..2e72260 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -471,13 +471,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(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);
 }
 
@@ -528,7 +543,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;
 
@@ -562,7 +577,14 @@ write:
err = do_write_data_page(page);
} else {
f2fs_lock_op(sbi);
-   err = do_write_data_page(page);
+   if (f2fs_has_inline_data(inode) || f2fs_may_inline(inode)) {
+   err = f2fs_write_inline_data(inode, page, offset);
+   f2fs_unlock_op(sbi);
+   goto out;
+   } else {
+   err = do_write_data_page(page);
+   }
+
f2fs_unlock_op(sbi);
need_balance_fs = true;
}
@@ -650,6 +672,15 @@ repeat:
return -ENOMEM;
*pagep = page;
 
+   if ((pos + len) < MAX_INLINE_DATA) {
+   if (f2fs_has_inline_data(inode))
+   goto inline_data;
+   } else if (f2fs_has_inline_data(inode)) {
+   err = f2fs_convert_inline_data(inode, page, flags);
+   if (err)
+   return err;
+   }
+
f2fs_lock_op(sbi);
set_new_dnode(&dn, inode, NULL, NULL, 0);
err = f2fs_reserve_block(&dn, index);
@@ -659,7 +690,7 @@ repeat:
f2fs_put_page(page, 1);
return err;
}
-
+inline_data:
if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
return 0;
 
@@ -675,7 +706,11 @@ repeat:
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 (f2fs_has_inline_data(inode))
+   err = f2fs_read_inline_data(inode, page);
+   else
+   err = f2fs_readpage(sbi, page,
+   dn.data_blkaddr, READ_SYNC);
if (err)
return err;
lock_page(page);
@@ -724,6 +759,10 @@ static ssize_t f2fs_direct_IO(int rw, 

[f2fs-dev] [PATCH V2 6/6] f2fs: update f2fs Documentation

2013-11-10 Thread Huajun Li
From: Huajun Li 

This patch describes the inline_data support in f2fs document.

Signed-off-by: Huajun Li 
---
 Documentation/filesystems/f2fs.txt |2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/filesystems/f2fs.txt 
b/Documentation/filesystems/f2fs.txt
index a3fe811..9849372 100644
--- a/Documentation/filesystems/f2fs.txt
+++ b/Documentation/filesystems/f2fs.txt
@@ -120,6 +120,8 @@ active_logs=%u Support configuring the number of 
active logs. In the
 disable_ext_identify   Disable the extension list configured by mkfs, so f2fs
does not aware of cold files such as media files.
 inline_xattr   Enable the inline xattrs feature.
+inline_dataEnable the inline data feature: New created 
small(<~3.4k)
+   files can be written into inode block.
 
 

 DEBUGFS ENTRIES
-- 
1.7.9.5


--
November Webinars for C, C++, Fortran Developers
Accelerate application performance with scalable programming models. Explore
techniques for threading, error checking, porting, and tuning. Get the most 
from the latest Intel processors and coprocessors. See abstracts and register
http://pubads.g.doubleclick.net/gampad/clk?id=60136231&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH V2 4/6] f2fs: Key functions to handle inline data

2013-11-10 Thread Huajun Li
From: Huajun Li 

Functions to implement inline data read/write, and move inline data to
normal data block when file size exceeds inline data limitation.

Signed-off-by: Huajun Li 
Signed-off-by: Haicheng Li 
Signed-off-by: Weihong Xu 
---
 fs/f2fs/Makefile |2 +-
 fs/f2fs/f2fs.h   |8 +++
 fs/f2fs/inline.c |  172 ++
 3 files changed, 181 insertions(+), 1 deletion(-)
 create mode 100644 fs/f2fs/inline.c

diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile
index 27a0820..2e35da1 100644
--- a/fs/f2fs/Makefile
+++ b/fs/f2fs/Makefile
@@ -1,6 +1,6 @@
 obj-$(CONFIG_F2FS_FS) += f2fs.o
 
-f2fs-y := dir.o file.o inode.o namei.o hash.o super.o
+f2fs-y := dir.o file.o inode.o namei.o hash.o super.o inline.o
 f2fs-y += checkpoint.o gc.o data.o node.o segment.o recovery.o
 f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o
 f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index de84f52..5f78c9c 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1253,4 +1253,12 @@ extern const struct inode_operations 
f2fs_dir_inode_operations;
 extern const struct inode_operations f2fs_symlink_inode_operations;
 extern const struct inode_operations f2fs_special_inode_operations;
 
+/*
+ * inline.c
+ */
+inline int f2fs_has_inline_data(struct inode *);
+bool f2fs_may_inline(struct inode *);
+int f2fs_read_inline_data(struct inode *, struct page *);
+int f2fs_convert_inline_data(struct inode *, struct page *, unsigned);
+int f2fs_write_inline_data(struct inode *, struct page *, unsigned int);
 #endif
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
new file mode 100644
index 000..e9b33d7
--- /dev/null
+++ b/fs/f2fs/inline.c
@@ -0,0 +1,172 @@
+/*
+ * fs/f2fs/inline.c
+ * Copyright (c) 2013, Intel Corporation
+ * Authors: Huajun Li 
+ *  Haicheng Li 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include 
+#include 
+
+#include "f2fs.h"
+
+inline int f2fs_has_inline_data(struct inode *inode)
+{
+   return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DATA);
+}
+
+bool f2fs_may_inline(struct inode *inode)
+{
+   struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+   block_t nr_blocks;
+   loff_t i_size;
+
+   if (!test_opt(sbi, INLINE_DATA))
+   return false;
+
+   nr_blocks = F2FS_I(inode)->i_xattr_nid ? 3 : 2;
+   if (inode->i_blocks > nr_blocks)
+   return false;
+
+   i_size = i_size_read(inode);
+   if (i_size > MAX_INLINE_DATA)
+   return false;
+
+   return true;
+}
+
+int f2fs_read_inline_data(struct inode *inode, struct page *page)
+{
+   struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+   struct page *ipage;
+   void *src_addr, *dst_addr;
+
+   ipage = get_node_page(sbi, inode->i_ino);
+   if (IS_ERR(ipage))
+   return PTR_ERR(ipage);
+
+   src_addr = inline_data_addr(ipage);
+   dst_addr = page_address(page);
+
+   zero_user_segment(page, INLINE_DATA_OFFSET,
+   INLINE_DATA_OFFSET + MAX_INLINE_DATA);
+   /* Copy the whole inline data block */
+   memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
+   f2fs_put_page(ipage, 1);
+
+   SetPageUptodate(page);
+   unlock_page(page);
+
+   return 0;
+}
+
+static int __f2fs_convert_inline_data(struct inode *inode, struct page *page)
+{
+   int err;
+   struct page *ipage;
+   struct dnode_of_data dn;
+   void *src_addr, *dst_addr;
+   block_t old_blk_addr, new_blk_addr;
+   struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+
+   f2fs_lock_op(sbi);
+   ipage = get_node_page(sbi, inode->i_ino);
+   if (IS_ERR(ipage))
+   return PTR_ERR(ipage);
+
+   /*
+* i_addr[0] is not used for inline data,
+* so reserving new block will not destroy inline data
+*/
+   set_new_dnode(&dn, inode, ipage, ipage, 0);
+   err = f2fs_reserve_block(&dn, 0);
+   if (err) {
+   f2fs_put_page(ipage, 1);
+   f2fs_unlock_op(sbi);
+   return err;
+   }
+
+   src_addr = inline_data_addr(ipage);
+   dst_addr = page_address(page);
+   zero_user_segment(page, 0, PAGE_CACHE_SIZE);
+
+   /* Copy the whole inline data block */
+   memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
+
+   /* write data page to try to make data consistent */
+   old_blk_addr = dn.data_blkaddr;
+   set_page_writeback(page);
+   write_data_page(inode, page, &dn,
+   old_blk_addr, &new_blk_addr);
+   update_extent_cache(new_blk_addr, &dn);
+   f2fs_wait_on_page_writeback(page, DATA, true);
+
+   /* clear inline data and flag after data writeba

[f2fs-dev] [PATCH V2 2/6] f2fs: Add a new mount option: inline_data

2013-11-10 Thread Huajun Li
From: Huajun Li 

Add a mount option: inline_data. If the mount option is set,
data of New created small files can be stored in their inode.

Signed-off-by: Huajun Li 
Signed-off-by: Haicheng Li 
Signed-off-by: Weihong Xu 
---
 fs/f2fs/super.c |8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index bafff72..12e89ac 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -50,6 +50,7 @@ enum {
Opt_active_logs,
Opt_disable_ext_identify,
Opt_inline_xattr,
+   Opt_inline_data,
Opt_err,
 };
 
@@ -65,6 +66,7 @@ static match_table_t f2fs_tokens = {
{Opt_active_logs, "active_logs=%u"},
{Opt_disable_ext_identify, "disable_ext_identify"},
{Opt_inline_xattr, "inline_xattr"},
+   {Opt_inline_data, "inline_data"},
{Opt_err, NULL},
 };
 
@@ -311,6 +313,9 @@ static int parse_options(struct super_block *sb, char 
*options)
case Opt_disable_ext_identify:
set_opt(sbi, DISABLE_EXT_IDENTIFY);
break;
+   case Opt_inline_data:
+   set_opt(sbi, INLINE_DATA);
+   break;
default:
f2fs_msg(sb, KERN_ERR,
"Unrecognized mount option \"%s\" or missing 
value",
@@ -508,7 +513,8 @@ static int f2fs_show_options(struct seq_file *seq, struct 
dentry *root)
 #endif
if (test_opt(sbi, DISABLE_EXT_IDENTIFY))
seq_puts(seq, ",disable_ext_identify");
-
+   if (test_opt(sbi, INLINE_DATA))
+   seq_puts(seq, ",inline_data");
seq_printf(seq, ",active_logs=%u", sbi->active_logs);
 
return 0;
-- 
1.7.9.5


--
November Webinars for C, C++, Fortran Developers
Accelerate application performance with scalable programming models. Explore
techniques for threading, error checking, porting, and tuning. Get the most 
from the latest Intel processors and coprocessors. See abstracts and register
http://pubads.g.doubleclick.net/gampad/clk?id=60136231&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH V2 1/6] f2fs: Add flags and helpers to support inline data

2013-11-10 Thread Huajun Li
From: Huajun Li 

Add new inode flags F2FS_INLINE_DATA and FI_INLINE_DATA to indicate
whether the inode has inline data.

Inline data makes use of inode block's data indices region to save small
file. Currently there are 923 data indices in an inode block. Since
inline xattr has made use of the last 50 indices to save its data, there
are 873 indices left which can be used for inline data. When
FI_INLINE_DATA is set, the layout of inode block's indices region is
like below:

+-+
| | Reserved. reserve_new_block() will make use of
| i_addr[0]   | i_addr[0] when we need to reserve a new data block
| | to convert inline data into regular one's.
|-|
| | Used by inline data. A file whose size is less than
| i_addr[1~872]   | 3488 bytes(~3.4k) and doesn't reserve extra
| | blocks by fallocate() can be saved here.
|-|
| |
| i_addr[873~922] | Reserved for inline xattr
| |
+-+

Signed-off-by: Haicheng Li 
Signed-off-by: Huajun Li 
Signed-off-by: Weihong Xu 
---
 fs/f2fs/f2fs.h  |   14 ++
 include/linux/f2fs_fs.h |8 
 2 files changed, 22 insertions(+)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 89dc750..cd7d2f9 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -37,6 +37,7 @@
 #define F2FS_MOUNT_POSIX_ACL   0x0020
 #define F2FS_MOUNT_DISABLE_EXT_IDENTIFY0x0040
 #define F2FS_MOUNT_INLINE_XATTR0x0080
+#define F2FS_MOUNT_INLINE_DATA 0x0100
 
 #define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option)
 #define set_opt(sbi, option)   (sbi->mount_opt.opt |= F2FS_MOUNT_##option)
@@ -877,6 +878,7 @@ enum {
FI_UPDATE_DIR,  /* should update inode block for consistency */
FI_DELAY_IPUT,  /* used for the recovery */
FI_INLINE_XATTR,/* used for inline xattr */
+   FI_INLINE_DATA, /* used for inline data*/
 };
 
 static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag)
@@ -914,6 +916,8 @@ static inline void get_inline_info(struct f2fs_inode_info 
*fi,
 {
if (ri->i_inline & F2FS_INLINE_XATTR)
set_inode_flag(fi, FI_INLINE_XATTR);
+   if (ri->i_inline & F2FS_INLINE_DATA)
+   set_inode_flag(fi, FI_INLINE_DATA);
 }
 
 static inline void set_raw_inline(struct f2fs_inode_info *fi,
@@ -923,6 +927,8 @@ static inline void set_raw_inline(struct f2fs_inode_info 
*fi,
 
if (is_inode_flag_set(fi, FI_INLINE_XATTR))
ri->i_inline |= F2FS_INLINE_XATTR;
+   if (is_inode_flag_set(fi, FI_INLINE_DATA))
+   ri->i_inline |= F2FS_INLINE_DATA;
 }
 
 static inline unsigned int addrs_per_inode(struct f2fs_inode_info *fi)
@@ -948,6 +954,13 @@ static inline int inline_xattr_size(struct inode *inode)
return 0;
 }
 
+static inline void *inline_data_addr(struct page *page)
+{
+   struct f2fs_inode *ri;
+   ri = (struct f2fs_inode *)page_address(page);
+   return (void *)&(ri->i_addr[1]);
+}
+
 static inline int f2fs_readonly(struct super_block *sb)
 {
return sb->s_flags & MS_RDONLY;
@@ -1238,4 +1251,5 @@ extern const struct address_space_operations 
f2fs_meta_aops;
 extern const struct inode_operations f2fs_dir_inode_operations;
 extern const struct inode_operations f2fs_symlink_inode_operations;
 extern const struct inode_operations f2fs_special_inode_operations;
+
 #endif
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index bb942f6..aea5eed 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -153,6 +153,14 @@ struct f2fs_extent {
 #defineNODE_DIND_BLOCK (DEF_ADDRS_PER_INODE + 5)
 
 #define F2FS_INLINE_XATTR  0x01/* file inline xattr flag */
+#define F2FS_INLINE_DATA   0x02/* file inline data flag */
+
+
+#define MAX_INLINE_DATA(sizeof(__le32) * (DEF_ADDRS_PER_INODE 
- \
+   F2FS_INLINE_XATTR_ADDRS - 1))
+
+#define INLINE_DATA_OFFSET (PAGE_CACHE_SIZE - sizeof(struct node_footer) \
+   - sizeof(__le32)*(DEF_ADDRS_PER_INODE + 5 - 1))
 
 struct f2fs_inode {
__le16 i_mode;  /* file mode */
-- 
1.7.9.5


--
November Webinars for C, C++, Fortran Developers
Accelerate application performance with scalable programming models. Explore
techniques for threading, error checking, porting, and tuning. Get the most 
from the latest Intel processors and coprocessors. See abstracts and register
http://pubads.g.doubleclick.net/gampad/clk?id=60136231&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH V2 3/6] f2fs: Add a new function: f2fs_reserve_block()

2013-11-10 Thread Huajun Li
From: Huajun Li 

Add the function f2fs_reserve_block() to easily reserve new blocks, and
use it to clean up more codes.

Signed-off-by: Huajun Li 
Signed-off-by: Haicheng Li 
Signed-off-by: Weihong Xu 
---
 fs/f2fs/data.c |   50 +++---
 fs/f2fs/f2fs.h |1 +
 fs/f2fs/file.c |   38 ++
 3 files changed, 30 insertions(+), 59 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index aa3438c..92d0724 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -64,6 +64,22 @@ int reserve_new_block(struct dnode_of_data *dn)
return 0;
 }
 
+int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index)
+{
+   bool need_put = dn->inode_page ? false : true;
+   int err;
+
+   err = get_dnode_of_data(dn, index, ALLOC_NODE);
+   if (err)
+   return err;
+   if (dn->data_blkaddr == NULL_ADDR)
+   err = reserve_new_block(dn);
+
+   if (need_put)
+   f2fs_put_dnode(dn);
+   return err;
+}
+
 static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
struct buffer_head *bh_result)
 {
@@ -300,19 +316,10 @@ struct page *get_new_data_page(struct inode *inode,
int err;
 
set_new_dnode(&dn, inode, npage, npage, 0);
-   err = get_dnode_of_data(&dn, index, ALLOC_NODE);
+   err = f2fs_reserve_block(&dn, index);
if (err)
return ERR_PTR(err);
 
-   if (dn.data_blkaddr == NULL_ADDR) {
-   if (reserve_new_block(&dn)) {
-   if (!npage)
-   f2fs_put_dnode(&dn);
-   return ERR_PTR(-ENOSPC);
-   }
-   }
-   if (!npage)
-   f2fs_put_dnode(&dn);
 repeat:
page = grab_cache_page(mapping, index);
if (!page)
@@ -644,21 +651,15 @@ repeat:
*pagep = page;
 
f2fs_lock_op(sbi);
-
set_new_dnode(&dn, inode, NULL, NULL, 0);
-   err = get_dnode_of_data(&dn, index, ALLOC_NODE);
-   if (err)
-   goto err;
-
-   if (dn.data_blkaddr == NULL_ADDR)
-   err = reserve_new_block(&dn);
-
-   f2fs_put_dnode(&dn);
-   if (err)
-   goto err;
-
+   err = f2fs_reserve_block(&dn, index);
f2fs_unlock_op(sbi);
 
+   if (err) {
+   f2fs_put_page(page, 1);
+   return err;
+   }
+
if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
return 0;
 
@@ -691,11 +692,6 @@ out:
SetPageUptodate(page);
clear_cold_data(page);
return 0;
-
-err:
-   f2fs_unlock_op(sbi);
-   f2fs_put_page(page, 1);
-   return err;
 }
 
 static int f2fs_write_end(struct file *file,
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index cd7d2f9..de84f52 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1119,6 +1119,7 @@ void destroy_checkpoint_caches(void);
  * data.c
  */
 int reserve_new_block(struct dnode_of_data *);
+int f2fs_reserve_block(struct dnode_of_data *, pgoff_t);
 void update_extent_cache(block_t, struct dnode_of_data *);
 struct page *find_data_page(struct inode *, pgoff_t, bool);
 struct page *get_lock_data_page(struct inode *, pgoff_t);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 7d714f4..1cd8e44 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -33,7 +33,6 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
struct page *page = vmf->page;
struct inode *inode = file_inode(vma->vm_file);
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-   block_t old_blk_addr;
struct dnode_of_data dn;
int err;
 
@@ -44,24 +43,10 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
/* block allocation */
f2fs_lock_op(sbi);
set_new_dnode(&dn, inode, NULL, NULL, 0);
-   err = get_dnode_of_data(&dn, page->index, ALLOC_NODE);
-   if (err) {
-   f2fs_unlock_op(sbi);
-   goto out;
-   }
-
-   old_blk_addr = dn.data_blkaddr;
-
-   if (old_blk_addr == NULL_ADDR) {
-   err = reserve_new_block(&dn);
-   if (err) {
-   f2fs_put_dnode(&dn);
-   f2fs_unlock_op(sbi);
-   goto out;
-   }
-   }
-   f2fs_put_dnode(&dn);
+   err = f2fs_reserve_block(&dn, page->index);
f2fs_unlock_op(sbi);
+   if (err)
+   goto out;
 
file_update_time(vma->vm_file);
lock_page(page);
@@ -532,22 +517,11 @@ static int expand_inode_data(struct inode *inode, loff_t 
offset,
 
f2fs_lock_op(sbi);
set_new_dnode(&dn, inode, NULL, NULL, 0);
-   ret = get_dnode_of_data(&dn, index, ALLOC_NODE);
-   if (ret) {
-   f2fs_unlock_op(sbi);
+

[f2fs-dev] [PATCH V2 0/6] f2fs: Enable f2fs support inline data

2013-11-10 Thread Huajun Li
From: Huajun Li 

f2fs inode is so large, so small files can be stored directly in the inode,
rather than just storing a single block address and storing the data elsewhere.

This patch set makes files less than ~3.4K store directly in inode block.
a) space saving
   Test with kernel src(without repo data), it can save about 10% space
   with this patch set;
b) performance
   Test this patch set with iozone, there is no obvious performance difference
   with the results of disabling this feature.


V2: - Update f2fs_reserve_block() according to comments on V1
- Add function f2fs_may_inline() to check whether the file meet 
  inline requirements
- Try to write inline data to normal data block before clearing it
  from inode block 
- Change lock scope while converting inline data
- Add inline_data description to f2fs documentation

Huajun Li (6):
  f2fs: Add flags and helpers to support inline data
  f2fs: Add a new mount option: inline_data
  f2fs: Add a new function: f2fs_reserve_block()
  f2fs: Key functions to handle inline data
  f2fs: Handle inline data operations
  f2fs: update f2fs Documentation

 Documentation/filesystems/f2fs.txt |2 +
 fs/f2fs/Makefile   |2 +-
 fs/f2fs/data.c |   97 +---
 fs/f2fs/f2fs.h |   23 +
 fs/f2fs/file.c |   81 +
 fs/f2fs/inline.c   |  172 
 fs/f2fs/super.c|8 +-
 include/linux/f2fs_fs.h|8 ++
 8 files changed, 325 insertions(+), 68 deletions(-)
 create mode 100644 fs/f2fs/inline.c

-- 
1.7.9.5


--
November Webinars for C, C++, Fortran Developers
Accelerate application performance with scalable programming models. Explore
techniques for threading, error checking, porting, and tuning. Get the most 
from the latest Intel processors and coprocessors. See abstracts and register
http://pubads.g.doubleclick.net/gampad/clk?id=60136231&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


Re: [f2fs-dev] [PATCH 1/1] No need to do recovery if there is no available CP

2013-11-05 Thread Huajun Li
Hi Jaegeuk,

Got it, and nice to fix it in mkfs.f2fs.

Thanks,
--Huajun
On Tue, Nov 5, 2013 at 12:48 PM, Jaegeuk Kim  wrote:
> Hi Huajun,
>
> 2013-11-04 (월), 23:40 +0800, Huajun Li:
>> Hi Jaegeuk,
>>
>> On Mon, Nov 4, 2013 at 9:24 AM, Jaegeuk Kim  wrote:
>> > 2013-11-03 (일), 23:08 +0800, Huajun Li:
>> >> From: Huajun Li 
>> >>
>> >> Normally we expect an empty partition after formatting by
>> >> mkfs.f2fs. But in this case, when we format a dirty partition and mount
>> >> it again. The former file will be recovered and available again! and
>> >> kernel log shows a recovery procedure is evoked.
>> >> This patch adds a new flag CP_EXIST_FLAG to indicate whether is a
>> >> available CP, and do recovery only when this flag is set.
>> >
>> > IMO, mkfs.f2fs should do the right thing to avoid this.
>> > If storage does not support discard, mkfs.f2fs can simply address the
>> > problem by writing one node block with zeros to prevent this.
>> >
>> Yes, mkfs.f2fs should do this definitely. :)
>>
>> > And, if you introduce a new flag, mkfs.f2fs should do the same thing,
>> > which means that mkfs.f2fs also needs to set the CP_EXIST_FLAG.
>> > So then, it could not fix the bug.
>> >
>> > How do you think?
>>
>> IMO, mkfs.f2fs doesn't need to set CP_EXIST_FLAG. This flag indicates
>> there exists an available CP, so an new formatted partition don't need
>> set the flag since there is no CP on it yet.
>
>
> Ah, what I concern is that mkfs.f2fs writes a valid CP so that it should
> set the flag.
>
>
>> On the other hand, while mounting a partition, we need to do recovery
>> only if there is CP on the partition. So this flag may be helpful,
>> right?
>
> If there is no valid CP, f2fs never goes to recover path.
> So, I doubt the necessity of that flag. :)
>
> Thanks,
>
> --
> Jaegeuk Kim
> Samsung
>

--
November Webinars for C, C++, Fortran Developers
Accelerate application performance with scalable programming models. Explore
techniques for threading, error checking, porting, and tuning. Get the most 
from the latest Intel processors and coprocessors. See abstracts and register
http://pubads.g.doubleclick.net/gampad/clk?id=60136231&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


Re: [f2fs-dev] [PATCH 1/1] No need to do recovery if there is no available CP

2013-11-04 Thread Huajun Li
Hi Jaegeuk,

On Mon, Nov 4, 2013 at 9:24 AM, Jaegeuk Kim  wrote:
> 2013-11-03 (일), 23:08 +0800, Huajun Li:
>> From: Huajun Li 
>>
>> Normally we expect an empty partition after formatting by
>> mkfs.f2fs. But in this case, when we format a dirty partition and mount
>> it again. The former file will be recovered and available again! and
>> kernel log shows a recovery procedure is evoked.
>> This patch adds a new flag CP_EXIST_FLAG to indicate whether is a
>> available CP, and do recovery only when this flag is set.
>
> IMO, mkfs.f2fs should do the right thing to avoid this.
> If storage does not support discard, mkfs.f2fs can simply address the
> problem by writing one node block with zeros to prevent this.
>
Yes, mkfs.f2fs should do this definitely. :)

> And, if you introduce a new flag, mkfs.f2fs should do the same thing,
> which means that mkfs.f2fs also needs to set the CP_EXIST_FLAG.
> So then, it could not fix the bug.
>
> How do you think?

IMO, mkfs.f2fs doesn't need to set CP_EXIST_FLAG. This flag indicates
there exists an available CP, so an new formatted partition don't need
set the flag since there is no CP on it yet.

On the other hand, while mounting a partition, we need to do recovery
only if there is CP on the partition. So this flag may be helpful,
right?

>
> --
> Jaegeuk Kim
> Samsung
>

--
Android is increasing in popularity, but the open development platform that
developers love is also attractive to malware creators. Download this white
paper to learn more about secure code signing practices that can help keep
Android apps secure.
http://pubads.g.doubleclick.net/gampad/clk?id=65839951&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 1/1] No need to do recovery if there is no available CP

2013-11-03 Thread Huajun Li
From: Huajun Li 

Normally we expect an empty partition after formatting by
mkfs.f2fs. But in this case, when we format a dirty partition and mount
it again. The former file will be recovered and available again! and
kernel log shows a recovery procedure is evoked.
This patch adds a new flag CP_EXIST_FLAG to indicate whether is a
available CP, and do recovery only when this flag is set.

You can reproduce the bug by following script:
===
TEST_DEV=/dev/sdb1
umount $TEST_DEV
mkfs.f2fs $TEST_DEV > /dev/null
mount -t f2fs $TEST_DEV /mnt
dmesg -c > /dev/null

echo
echo "Small Vector Sync"
echo "abcdefghijklmnopqrstuvwxyz" > /mnt/small_vector_async

xfs_io -F -f -s -c "pread -v 0 1"\
-c "pwrite -S 0x61 4090 1"\
/mnt/small_vector_async

umount $TEST_DEV

mkfs.f2fs $TEST_DEV
#After we format a partition, there should be nothing but root in it.
#But in this case, when we format a used partition and mount it again,
#the former created file small_vector_async will be recover!

mount -t f2fs $TEST_DEV /mnt
#We expect nothing after mkfs, but in this case small_vector_async will
#be recovered when we mount the partition.

    ls /mnt
dmesg


Signed-off-by: Huajun Li 
Reported-and-tested-by: Weihong Xu 
---
 fs/f2fs/checkpoint.c|2 ++
 fs/f2fs/super.c |3 ++-
 include/linux/f2fs_fs.h |1 +
 3 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index d430157..22b3972 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -767,6 +767,8 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool 
is_umount)
clear_prefree_segments(sbi);
F2FS_RESET_SB_DIRT(sbi);
}
+   if (!is_set_ckpt_flags(ckpt, CP_EXIST_FLAG))
+   set_ckpt_flags(ckpt, CP_EXIST_FLAG);
 }
 
 /*
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index e42351c..963da7d 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -959,7 +959,8 @@ static int f2fs_fill_super(struct super_block *sb, void 
*data, int silent)
}
 
/* recover fsynced data */
-   if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
+   if (!test_opt(sbi, DISABLE_ROLL_FORWARD) &&
+   is_set_ckpt_flags(F2FS_CKPT(sbi), CP_EXIST_FLAG)) {
err = recover_fsync_data(sbi);
if (err)
f2fs_msg(sb, KERN_ERR,
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index bb942f6..6e48f22 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -80,6 +80,7 @@ struct f2fs_super_block {
 /*
  * For checkpoint
  */
+#define CP_EXIST_FLAG  0x0010
 #define CP_ERROR_FLAG  0x0008
 #define CP_COMPACT_SUM_FLAG0x0004
 #define CP_ORPHAN_PRESENT_FLAG 0x0002
-- 
1.7.9.5


--
Android is increasing in popularity, but the open development platform that
developers love is also attractive to malware creators. Download this white
paper to learn more about secure code signing practices that can help keep
Android apps secure.
http://pubads.g.doubleclick.net/gampad/clk?id=65839951&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


Re: [f2fs-dev] [f2fs-dev 4/5] f2fs: Key functions to handle inline data

2013-10-29 Thread Huajun Li
Yes, will think over these cases carefully, and send out new version. thanks.

On Tue, Oct 29, 2013 at 9:06 AM, Jaegeuk Kim  wrote:
> Hi,
>
> 2013-10-29 (화), 01:20 +0800, Huajun Li:
>> On Mon, Oct 28, 2013 at 8:43 PM, Jaegeuk Kim  wrote:
>> > Hi,
>> >
>> > 2013-10-26 (토), 00:01 +0800, Huajun Li:
>> >> From: Huajun Li 
>> >>
>> >> Functions to implement inline data read/write, and move inline data to
>> >> normal data block when file size exceeds inline data limitation.
>> >>
>> >> Signed-off-by: Huajun Li 
>> >> Signed-off-by: Haicheng Li 
>> >> Signed-off-by: Weihong Xu 
>> >> ---
>> >>  fs/f2fs/Makefile |2 +-
>> >>  fs/f2fs/f2fs.h   |7 +++
>> >>  fs/f2fs/inline.c |  144 
>> >> ++
>> >>  3 files changed, 152 insertions(+), 1 deletion(-)
>> >>  create mode 100644 fs/f2fs/inline.c
>> >>
>> >
>> > [snip]
>> >
>> >> +static int __f2fs_convert_inline_data(struct inode *inode, struct page 
>> >> *page)
>> >> +{
>> >> + int err;
>> >> + struct page *ipage;
>> >> + struct dnode_of_data dn;
>> >> + void *src_addr, *dst_addr;
>> >> + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
>> >> +
>> >
>> > Here..  f2fs_lock_op(sbi);
>> >
>> >> + ipage = get_node_page(sbi, inode->i_ino);
>> >> + if (IS_ERR(ipage))
>> >> + return PTR_ERR(ipage);
>> >> +
>> >
>> > Need to move f2fs_lock_op prior to get_node_page.
>> >
>> >> + /* i_addr[0] is not used for inline data,
>> >
>> > Coding style.
>> >  /*
>> >   * ...
>> >   */
>> >
>> >> +  * so reserving new block will not destroy inline data */
>> >> + err = f2fs_reserve_block(inode, &dn, 0);
>> >> + if (err) {
>> >> + f2fs_put_page(ipage, 1);
>> >> + f2fs_unlock_op(sbi);
>> >> + return err;
>> >> + }
>> >
>> > Need to move this too.
>> >
>> >> +
>> >> + src_addr = inline_data_addr(ipage);
>> >> + dst_addr = page_address(page);
>> >> + zero_user_segment(page, 0, PAGE_CACHE_SIZE);
>> >
>> > + space for readability.
>> >
>> >> + /* Copy the whole inline data block */
>> >> + memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
>> >> + zero_user_segment(ipage, INLINE_DATA_OFFSET,
>> >> +  INLINE_DATA_OFFSET + MAX_INLINE_DATA);
>> >> + clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
>> >> + set_raw_inline(F2FS_I(inode),
>> >> + (struct f2fs_inode *)page_address(ipage));
>>
>> Thanks for your comments, I will update them according to above comments.
>>
>> >
>> >--> sync_inode_page()?
>> >
>> IMO, we just handle file data, so do we still need call sync_inode_page() ?
>
> I think sync_inode_page() is more suitable, since we need to sync
> between i_size, i_blocks and its i_flag, inline_data, at this moment.
>
>>
>> >> +
>> >> + set_page_dirty(ipage);
>
> Need to consider skipping set_page_dirty(ipage).
>
>> >> + f2fs_put_page(ipage, 1);
>> >> + set_page_dirty(page);
>> >
>> > Here... f2fs_unlock_op(sbi);
>> >
>> > Here, we need to consider data consistency.
>> > Let's think about the below scenario.
>> > 1. inline_data was written.
>> > 2. sync_fs is done.
>> > 3. additional data were written.
>> >   : this triggers f2fs_convert_inline_data(), produces a page, and then
>> > unsets the inline flag.
>> > 4. checkpoint was done with updated inode page. Note that, checkpoint
>> > doesn't guarantee any user data.
>> > 5. sudden power-off is occurred.
>> >   -> Once power-off-recovery is done, we loose the inline_data which was
>> > written successfully at step #2.
>> >
>> > So, I think we need to do f2fs_sync_file() procedure at this moment.
>> > Any idea?
>> >
>>
>> Yes, need consider this case carefully, thanks for your reminder.
>>
>> Considering sudden power-off may happen before f2fs_s

Re: [f2fs-dev] [f2fs-dev 3/5] f2fs: Add a new function: f2fs_reserve_block()

2013-10-29 Thread Huajun Li
On Tue, Oct 29, 2013 at 8:56 AM, Jaegeuk Kim  wrote:
> Hi Huajun,
>
> 2013-10-29 (화), 00:53 +0800, Huajun Li:
>> Hi Jaegeuk,
>>
>> Thanks for your kindly review and comments.
>>
>> On Mon, Oct 28, 2013 at 8:28 PM, Jaegeuk Kim  wrote:
>> > 2013-10-28 (월), 21:16 +0900, Jaegeuk Kim:
>> > Hi,
>> >
>> >>
>> >> 2013-10-26 (토), 00:01 +0800, Huajun Li:
>> >> > From: Huajun Li 
>> >> >
>> >> > Add the function f2fs_reserve_block() to easily reserve new blocks.
>> >> >
>> >> > Signed-off-by: Huajun Li 
>> >> > Signed-off-by: Haicheng Li 
>> >> > Signed-off-by: Weihong Xu 
>> >> > ---
>> >> >  fs/f2fs/data.c |   29 ++---
>> >> >  fs/f2fs/f2fs.h |1 +
>> >> >  2 files changed, 19 insertions(+), 11 deletions(-)
>> >> >
>> >> > diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
>> >> > index c8887d8..7b31911 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,
>> >> > +  struct dnode_of_data *dn, pgoff_t index)
>> >>
>> >
>> > We don't need to get dnode_of_data from parameters, since it is
>> > used by this function only.
>>
>> After calling f2fs_reserve_block(), we need dn.data_blkaddr to check
>> whether it is NEW_ADDR. So IMO, it's nice to keep this parameter.
>>
>
> Ah, got it.
> BTW, I found another flows we can clean up wrt this issue.
> How about this?
>

This can clean up more codes, thanks a lot.

> ---
>  fs/f2fs/data.c | 51 +++
>  fs/f2fs/f2fs.h |  1 +
>  fs/f2fs/file.c | 39 ++-
>  3 files changed, 30 insertions(+), 61 deletions(-)
>
> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> index c8887d8..b8c4f76d 100644
> --- a/fs/f2fs/data.c
> +++ b/fs/f2fs/data.c
> @@ -64,6 +64,22 @@ int reserve_new_block(struct dnode_of_data *dn)
> return 0;
>  }
>
> +int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index)
> +{
> +   bool need_put = dn->inode_page ? false : true;
> +   int err;
> +
> +   err = get_dnode_of_data(dn, index, ALLOC_NODE);
> +   if (err)
> +   return err;
> +   if (dn->data_blkaddr == NULL_ADDR)
> +   err = reserve_new_block(dn);
> +
> +   if (need_put)
> +   f2fs_put_dnode(dn);
> +   return err;
> +}
> +
>  static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
> struct buffer_head *bh_result)
>  {
> @@ -300,19 +316,9 @@ struct page *get_new_data_page(struct inode *inode,
> int err;
>
> set_new_dnode(&dn, inode, npage, npage, 0);
> -   err = get_dnode_of_data(&dn, index, ALLOC_NODE);
> +   err = f2fs_reserve_block(&dn, index);
> if (err)
> return ERR_PTR(err);
> -
> -   if (dn.data_blkaddr == NULL_ADDR) {
> -   if (reserve_new_block(&dn)) {
> -   if (!npage)
> -   f2fs_put_dnode(&dn);
> -   return ERR_PTR(-ENOSPC);
> -   }
> -   }
> -   if (!npage)
> -   f2fs_put_dnode(&dn);
>  repeat:
> page = grab_cache_page(mapping, index);
> if (!page)
> @@ -644,21 +650,15 @@ repeat:
> *pagep = page;
>
> f2fs_lock_op(sbi);
> -
> set_new_dnode(&dn, inode, NULL, NULL, 0);
> -   err = get_dnode_of_data(&dn, index, ALLOC_NODE);
> -   if (err)
> -   goto err;
> -
> -   if (dn.data_blkaddr == NULL_ADDR)
> -   err = reserve_new_block(&dn);
> -
> -   f2fs_put_dnode(&dn);
> -   if (err)
> -   goto err;
> -
> +   err = f2fs_reserve_block(&dn, index);
> f2fs_unlock_op(sbi);
>
> +   if (err) {
> +   f2fs_put_page(page, 1);
> +   return err;
> +   }
> +
> if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
> return 0;
>
> @@ -691,11 +691,6 @@ out:
> SetPageUptodate(page);
> clear_cold_data(page);
> return 0;
> -
> -err:
> -   f2fs_unlock_op(

Re: [f2fs-dev] [f2fs-dev 4/5] f2fs: Key functions to handle inline data

2013-10-28 Thread Huajun Li
On Mon, Oct 28, 2013 at 8:43 PM, Jaegeuk Kim  wrote:
> Hi,
>
> 2013-10-26 (토), 00:01 +0800, Huajun Li:
>> From: Huajun Li 
>>
>> Functions to implement inline data read/write, and move inline data to
>> normal data block when file size exceeds inline data limitation.
>>
>> Signed-off-by: Huajun Li 
>> Signed-off-by: Haicheng Li 
>> Signed-off-by: Weihong Xu 
>> ---
>>  fs/f2fs/Makefile |2 +-
>>  fs/f2fs/f2fs.h   |7 +++
>>  fs/f2fs/inline.c |  144 
>> ++
>>  3 files changed, 152 insertions(+), 1 deletion(-)
>>  create mode 100644 fs/f2fs/inline.c
>>
>
> [snip]
>
>> +static int __f2fs_convert_inline_data(struct inode *inode, struct page 
>> *page)
>> +{
>> + int err;
>> + struct page *ipage;
>> + struct dnode_of_data dn;
>> + void *src_addr, *dst_addr;
>> + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
>> +
>
> Here..  f2fs_lock_op(sbi);
>
>> + ipage = get_node_page(sbi, inode->i_ino);
>> + if (IS_ERR(ipage))
>> + return PTR_ERR(ipage);
>> +
>
> Need to move f2fs_lock_op prior to get_node_page.
>
>> + /* i_addr[0] is not used for inline data,
>
> Coding style.
>  /*
>   * ...
>   */
>
>> +  * so reserving new block will not destroy inline data */
>> + err = f2fs_reserve_block(inode, &dn, 0);
>> + if (err) {
>> + f2fs_put_page(ipage, 1);
>> + f2fs_unlock_op(sbi);
>> + return err;
>> + }
>
> Need to move this too.
>
>> +
>> + src_addr = inline_data_addr(ipage);
>> + dst_addr = page_address(page);
>> + zero_user_segment(page, 0, PAGE_CACHE_SIZE);
>
> + space for readability.
>
>> + /* Copy the whole inline data block */
>> + memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
>> + zero_user_segment(ipage, INLINE_DATA_OFFSET,
>> +  INLINE_DATA_OFFSET + MAX_INLINE_DATA);
>> + clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
>> + set_raw_inline(F2FS_I(inode),
>> + (struct f2fs_inode *)page_address(ipage));

Thanks for your comments, I will update them according to above comments.

>
>--> sync_inode_page()?
>
IMO, we just handle file data, so do we still need call sync_inode_page() ?

>> +
>> + set_page_dirty(ipage);
>> + f2fs_put_page(ipage, 1);
>> + set_page_dirty(page);
>
> Here... f2fs_unlock_op(sbi);
>
> Here, we need to consider data consistency.
> Let's think about the below scenario.
> 1. inline_data was written.
> 2. sync_fs is done.
> 3. additional data were written.
>   : this triggers f2fs_convert_inline_data(), produces a page, and then
> unsets the inline flag.
> 4. checkpoint was done with updated inode page. Note that, checkpoint
> doesn't guarantee any user data.
> 5. sudden power-off is occurred.
>   -> Once power-off-recovery is done, we loose the inline_data which was
> written successfully at step #2.
>
> So, I think we need to do f2fs_sync_file() procedure at this moment.
> Any idea?
>

Yes, need consider this case carefully, thanks for your reminder.

Considering sudden power-off may happen before f2fs_sync_file() is
called, so how about following solutions:
 ...
 /* Copy the whole inline data block */
 memcpy(dst_addr, src_addr, MAX_INLINE_DATA);

do f2fs_sync_file() procedure ( Or  do write_data_page() procedure ? )

 zero_user_segment(ipage, INLINE_DATA_OFFSET, INLINE_DATA_OFFSET +
MAX_INLINE_DATA);
 clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
 set_raw_inline(F2FS_I(inode), (struct f2fs_inode *)page_address(ipage));
 ...

>> +
>> + return 0;
>> +}
>> +
>> +int f2fs_convert_inline_data(struct inode *inode,
>> +  struct page *p, unsigned flags)
>> +{
>> + int err;
>> + struct page *page;
>> +
>> + if (p && !p->index) {
>> + page = p;
>> + } else {
>> + page = grab_cache_page_write_begin(inode->i_mapping, 0, flags);
>> + if (IS_ERR(page))
>> + return PTR_ERR(page);
>> + }
>> +
>> + err = __f2fs_convert_inline_data(inode, page);
>> +
>> + if (p && !p->index)
>> + f2fs_put_page(page, 1);
>> +
>> + return err;
>> +}
>> +
>> +int f2fs_write_inline_data(struct inode *inode,
>> +   

Re: [f2fs-dev] [f2fs-dev 5/5] f2fs: Handle inline data operations

2013-10-28 Thread Huajun Li
On Mon, Oct 28, 2013 at 8:44 PM, Jaegeuk Kim  wrote:
> Hi,
>
> 2013-10-26 (토), 00:01 +0800, Huajun Li:
>> From: Huajun Li 
>>
>
> [snip]
>
>>
>> @@ -538,7 +553,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;
>>
>> @@ -572,7 +587,14 @@ write:
>>   err = do_write_data_page(page);
>>   } else {
>>   f2fs_lock_op(sbi);
>> - err = do_write_data_page(page);
>> + if (test_opt(sbi, INLINE_DATA) && (i_size <= MAX_INLINE_DATA)) 
>> {
>> + err = f2fs_write_inline_data(inode, page, offset);
>> + ClearPageDirty(page);
>
> Don't need to call ClearPageDirty(page).
>

Yes. I will remove it in next version, thanks.

>> + f2fs_unlock_op(sbi);
>> + goto out;
>> + } else {
>> + err = do_write_data_page(page);
>> + }
>>   f2fs_unlock_op(sbi);
>>   need_balance_fs = true;
>>
> --
> Jaegeuk Kim
> Samsung
>

--
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60135991&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


Re: [f2fs-dev] [f2fs-dev 3/5] f2fs: Add a new function: f2fs_reserve_block()

2013-10-28 Thread Huajun Li
Hi Jaegeuk,

Thanks for your kindly review and comments.

On Mon, Oct 28, 2013 at 8:28 PM, Jaegeuk Kim  wrote:
> 2013-10-28 (월), 21:16 +0900, Jaegeuk Kim:
> Hi,
>
>>
>> 2013-10-26 (토), 00:01 +0800, Huajun Li:
>> > From: Huajun Li 
>> >
>> > Add the function f2fs_reserve_block() to easily reserve new blocks.
>> >
>> > Signed-off-by: Huajun Li 
>> > Signed-off-by: Haicheng Li 
>> > Signed-off-by: Weihong Xu 
>> > ---
>> >  fs/f2fs/data.c |   29 ++---
>> >  fs/f2fs/f2fs.h |1 +
>> >  2 files changed, 19 insertions(+), 11 deletions(-)
>> >
>> > diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
>> > index c8887d8..7b31911 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,
>> > +  struct dnode_of_data *dn, pgoff_t index)
>>
>
> We don't need to get dnode_of_data from parameters, since it is
> used by this function only.

After calling f2fs_reserve_block(), we need dn.data_blkaddr to check
whether it is NEW_ADDR. So IMO, it's nice to keep this parameter.

>
>>
>> > +{
>> > +   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;
>> > +}
>> > +
>>
>
> --
> Jaegeuk Kim
> Samsung
>

--
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60135991&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [f2fs-dev 2/5] f2fs: Add a new mount option: inline_data

2013-10-25 Thread Huajun Li
From: Huajun Li 

Add a mount option: inline_data. If the mount option is set,
data of New created small files can be stored in their inode.

Signed-off-by: Huajun Li 
Signed-off-by: Haicheng Li 
Signed-off-by: Weihong Xu 
---
 fs/f2fs/super.c |8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index e42351c..e8ad7f2 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -50,6 +50,7 @@ enum {
Opt_active_logs,
Opt_disable_ext_identify,
Opt_inline_xattr,
+   Opt_inline_data,
Opt_err,
 };
 
@@ -65,6 +66,7 @@ static match_table_t f2fs_tokens = {
{Opt_active_logs, "active_logs=%u"},
{Opt_disable_ext_identify, "disable_ext_identify"},
{Opt_inline_xattr, "inline_xattr"},
+   {Opt_inline_data, "inline_data"},
{Opt_err, NULL},
 };
 
@@ -311,6 +313,9 @@ static int parse_options(struct super_block *sb, char 
*options)
case Opt_disable_ext_identify:
set_opt(sbi, DISABLE_EXT_IDENTIFY);
break;
+   case Opt_inline_data:
+   set_opt(sbi, INLINE_DATA);
+   break;
default:
f2fs_msg(sb, KERN_ERR,
"Unrecognized mount option \"%s\" or missing 
value",
@@ -508,7 +513,8 @@ static int f2fs_show_options(struct seq_file *seq, struct 
dentry *root)
 #endif
if (test_opt(sbi, DISABLE_EXT_IDENTIFY))
seq_puts(seq, ",disable_ext_identify");
-
+   if (test_opt(sbi, INLINE_DATA))
+   seq_puts(seq, ",inline_data");
seq_printf(seq, ",active_logs=%u", sbi->active_logs);
 
return 0;
-- 
1.7.9.5


--
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60135991&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [f2fs-dev 0/5] f2fs: Enable f2fs support inline data

2013-10-25 Thread Huajun Li
From: Huajun Li 

f2fs inode is so large, so small files can be stored directly in the inode,
rather than just storing a single block address and storing the data elsewhere.

This patch set makes files less than ~3.4K store directly in inode block.
a) space saving
   Test with kernel src(without repo data), it can save about 10% space
   with this patch set;
b) performance
   Test this patch set with iozone, there is no obvious performance difference
   with the results of disabling this feature.

Huajun Li (5):
  f2fs: Add flags and helpers to support inline data
  f2fs: Add a new mount option: inline_data
  f2fs: Add a new function: f2fs_reserve_block()
  f2fs: Key functions to handle inline data
  f2fs: Handle inline data read and write

 fs/f2fs/Makefile|2 +-
 fs/f2fs/data.c  |   77 -
 fs/f2fs/f2fs.h  |   22 
 fs/f2fs/file.c  |   42 +-
 fs/f2fs/inline.c|  144 +++
 fs/f2fs/super.c |8 ++-
 include/linux/f2fs_fs.h |8 +++
 7 files changed, 283 insertions(+), 20 deletions(-)
 create mode 100644 fs/f2fs/inline.c

-- 
1.7.9.5


--
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60135991&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [f2fs-dev 1/5] f2fs: Add flags and helpers to support inline data

2013-10-25 Thread Huajun Li
From: Huajun Li 

Add new inode flags F2FS_INLINE_DATA and FI_INLINE_DATA to indicate
whether the inode has inline data.

Inline data makes use of inode block's data indices region to save small
file. Currently there are 923 data indices in an inode block. Since
inline xattr has made use of the last 50 indices to save its data, there
are 873 indices left which can be used for inline data. When
FI_INLINE_DATA is set, the layout of inode block's indices region is
like below:
+-+
| | Reserved. reserve_new_block() will make use of
| i_addr[0]   | i_addr[0] when we need to reserve a new data block
| | to convert inline data into regular one's.
|-|
| | Used by inline data. A file whose size is less than
| i_addr[1..872]  | 3488 bytes(~3.4k) and doesn't reserve extra
| | blocks by fallocate() can be saved here.
|-|
| i_addr[873-922] | Reserved for inline xattr
+-+

Signed-off-by: Haicheng Li 
Signed-off-by: Huajun Li 
Signed-off-by: Weihong Xu 
---
 fs/f2fs/f2fs.h  |   14 ++
 include/linux/f2fs_fs.h |8 
 2 files changed, 22 insertions(+)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index a61cc5f..e50a8b0 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -31,6 +31,7 @@
 #define F2FS_MOUNT_POSIX_ACL   0x0020
 #define F2FS_MOUNT_DISABLE_EXT_IDENTIFY0x0040
 #define F2FS_MOUNT_INLINE_XATTR0x0080
+#define F2FS_MOUNT_INLINE_DATA 0x0100
 
 #define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option)
 #define set_opt(sbi, option)   (sbi->mount_opt.opt |= F2FS_MOUNT_##option)
@@ -871,6 +872,7 @@ enum {
FI_UPDATE_DIR,  /* should update inode block for consistency */
FI_DELAY_IPUT,  /* used for the recovery */
FI_INLINE_XATTR,/* used for inline xattr */
+   FI_INLINE_DATA, /* used for inline data*/
 };
 
 static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag)
@@ -908,6 +910,8 @@ static inline void get_inline_info(struct f2fs_inode_info 
*fi,
 {
if (ri->i_inline & F2FS_INLINE_XATTR)
set_inode_flag(fi, FI_INLINE_XATTR);
+   if (ri->i_inline & F2FS_INLINE_DATA)
+   set_inode_flag(fi, FI_INLINE_DATA);
 }
 
 static inline void set_raw_inline(struct f2fs_inode_info *fi,
@@ -917,6 +921,8 @@ static inline void set_raw_inline(struct f2fs_inode_info 
*fi,
 
if (is_inode_flag_set(fi, FI_INLINE_XATTR))
ri->i_inline |= F2FS_INLINE_XATTR;
+   if (is_inode_flag_set(fi, FI_INLINE_DATA))
+   ri->i_inline |= F2FS_INLINE_DATA;
 }
 
 static inline unsigned int addrs_per_inode(struct f2fs_inode_info *fi)
@@ -942,6 +948,13 @@ static inline int inline_xattr_size(struct inode *inode)
return 0;
 }
 
+static inline void *inline_data_addr(struct page *page)
+{
+   struct f2fs_inode *ri;
+   ri = (struct f2fs_inode *)page_address(page);
+   return (void *)&(ri->i_addr[1]);
+}
+
 static inline int f2fs_readonly(struct super_block *sb)
 {
return sb->s_flags & MS_RDONLY;
@@ -1231,4 +1244,5 @@ extern const struct address_space_operations 
f2fs_meta_aops;
 extern const struct inode_operations f2fs_dir_inode_operations;
 extern const struct inode_operations f2fs_symlink_inode_operations;
 extern const struct inode_operations f2fs_special_inode_operations;
+
 #endif
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index bb942f6..aea5eed 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -153,6 +153,14 @@ struct f2fs_extent {
 #defineNODE_DIND_BLOCK (DEF_ADDRS_PER_INODE + 5)
 
 #define F2FS_INLINE_XATTR  0x01/* file inline xattr flag */
+#define F2FS_INLINE_DATA   0x02/* file inline data flag */
+
+
+#define MAX_INLINE_DATA(sizeof(__le32) * (DEF_ADDRS_PER_INODE 
- \
+   F2FS_INLINE_XATTR_ADDRS - 1))
+
+#define INLINE_DATA_OFFSET (PAGE_CACHE_SIZE - sizeof(struct node_footer) \
+   - sizeof(__le32)*(DEF_ADDRS_PER_INODE + 5 - 1))
 
 struct f2fs_inode {
__le16 i_mode;  /* file mode */
-- 
1.7.9.5


--
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60135991&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [f2fs-dev 3/5] f2fs: Add a new function: f2fs_reserve_block()

2013-10-25 Thread Huajun Li
From: Huajun Li 

Add the function f2fs_reserve_block() to easily reserve new blocks.

Signed-off-by: Huajun Li 
Signed-off-by: Haicheng Li 
Signed-off-by: Weihong Xu 
---
 fs/f2fs/data.c |   29 ++---
 fs/f2fs/f2fs.h |1 +
 2 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index c8887d8..7b31911 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,
+  struct dnode_of_data *dn, pgoff_t index)
+{
+   int err;
+
+   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)
 {
@@ -644,19 +661,9 @@ repeat:
*pagep = page;
 
f2fs_lock_op(sbi);
-
-   set_new_dnode(&dn, inode, NULL, NULL, 0);
-   err = get_dnode_of_data(&dn, index, ALLOC_NODE);
-   if (err)
-   goto err;
-
-   if (dn.data_blkaddr == NULL_ADDR)
-   err = reserve_new_block(&dn);
-
-   f2fs_put_dnode(&dn);
+   err = f2fs_reserve_block(inode, &dn, index);
if (err)
goto err;
-
f2fs_unlock_op(sbi);
 
if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index e50a8b0..4f34330 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1112,6 +1112,7 @@ void destroy_checkpoint_caches(void);
  * data.c
  */
 int reserve_new_block(struct dnode_of_data *);
+int f2fs_reserve_block(struct inode *, struct dnode_of_data *, pgoff_t);
 void update_extent_cache(block_t, struct dnode_of_data *);
 struct page *find_data_page(struct inode *, pgoff_t, bool);
 struct page *get_lock_data_page(struct inode *, pgoff_t);
-- 
1.7.9.5


--
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60135991&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [f2fs-dev 4/5] f2fs: Key functions to handle inline data

2013-10-25 Thread Huajun Li
From: Huajun Li 

Functions to implement inline data read/write, and move inline data to
normal data block when file size exceeds inline data limitation.

Signed-off-by: Huajun Li 
Signed-off-by: Haicheng Li 
Signed-off-by: Weihong Xu 
---
 fs/f2fs/Makefile |2 +-
 fs/f2fs/f2fs.h   |7 +++
 fs/f2fs/inline.c |  144 ++
 3 files changed, 152 insertions(+), 1 deletion(-)
 create mode 100644 fs/f2fs/inline.c

diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile
index 27a0820..2e35da1 100644
--- a/fs/f2fs/Makefile
+++ b/fs/f2fs/Makefile
@@ -1,6 +1,6 @@
 obj-$(CONFIG_F2FS_FS) += f2fs.o
 
-f2fs-y := dir.o file.o inode.o namei.o hash.o super.o
+f2fs-y := dir.o file.o inode.o namei.o hash.o super.o inline.o
 f2fs-y += checkpoint.o gc.o data.o node.o segment.o recovery.o
 f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o
 f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 4f34330..904ae3d 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1246,4 +1246,11 @@ extern const struct inode_operations 
f2fs_dir_inode_operations;
 extern const struct inode_operations f2fs_symlink_inode_operations;
 extern const struct inode_operations f2fs_special_inode_operations;
 
+/*
+ * inline.c
+ */
+inline int f2fs_has_inline_data(struct inode *);
+int f2fs_read_inline_data(struct inode *, struct page *);
+int f2fs_convert_inline_data(struct inode *, struct page *, unsigned);
+int f2fs_write_inline_data(struct inode *, struct page *, unsigned int);
 #endif
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
new file mode 100644
index 000..ec0d00c
--- /dev/null
+++ b/fs/f2fs/inline.c
@@ -0,0 +1,144 @@
+/*
+ * fs/f2fs/inline.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include 
+#include 
+
+#include "f2fs.h"
+
+inline int f2fs_has_inline_data(struct inode *inode)
+{
+   return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DATA);
+}
+
+int f2fs_read_inline_data(struct inode *inode, struct page *page)
+{
+   struct page *ipage;
+   void *src_addr, *dst_addr;
+
+   BUG_ON(page->index);
+   ipage = get_node_page(F2FS_SB(inode->i_sb), inode->i_ino);
+   if (IS_ERR(ipage))
+   return PTR_ERR(ipage);
+
+   src_addr = inline_data_addr(ipage);
+   dst_addr = page_address(page);
+
+   zero_user_segment(page, INLINE_DATA_OFFSET,
+   INLINE_DATA_OFFSET + MAX_INLINE_DATA);
+   /* Copy the whole inline data block */
+   memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
+   f2fs_put_page(ipage, 1);
+
+   SetPageUptodate(page);
+   unlock_page(page);
+
+   return 0;
+}
+
+static int __f2fs_convert_inline_data(struct inode *inode, struct page *page)
+{
+   int err;
+   struct page *ipage;
+   struct dnode_of_data dn;
+   void *src_addr, *dst_addr;
+   struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+
+   ipage = get_node_page(sbi, inode->i_ino);
+   if (IS_ERR(ipage))
+   return PTR_ERR(ipage);
+
+   f2fs_lock_op(sbi);
+   /* i_addr[0] is not used for inline data,
+* so reserving new block will not destroy inline data */
+   err = f2fs_reserve_block(inode, &dn, 0);
+   if (err) {
+   f2fs_put_page(ipage, 1);
+   f2fs_unlock_op(sbi);
+   return err;
+   }
+   f2fs_unlock_op(sbi);
+
+   src_addr = inline_data_addr(ipage);
+   dst_addr = page_address(page);
+   zero_user_segment(page, 0, PAGE_CACHE_SIZE);
+   /* Copy the whole inline data block */
+   memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
+   zero_user_segment(ipage, INLINE_DATA_OFFSET,
+INLINE_DATA_OFFSET + MAX_INLINE_DATA);
+   clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
+   set_raw_inline(F2FS_I(inode),
+   (struct f2fs_inode *)page_address(ipage));
+
+   set_page_dirty(ipage);
+   f2fs_put_page(ipage, 1);
+   set_page_dirty(page);
+
+   return 0;
+}
+
+int f2fs_convert_inline_data(struct inode *inode,
+struct page *p, unsigned flags)
+{
+   int err;
+   struct page *page;
+
+   if (p && !p->index) {
+   page = p;
+   } else {
+   page = grab_cache_page_write_begin(inode->i_mapping, 0, flags);
+   if (IS_ERR(page))
+   return PTR_ERR(page);
+   }
+
+   err = __f2fs_convert_inline_data(inode, page);
+
+   if (p && !p->index)
+   f2fs_put_page(page, 1);
+
+   return err;
+}
+
+int f2fs_write_inline_data(struct inode *inode,
+  struct page *page, unsigned size)
+{
+   void *src_addr, *dst_addr;
+   struct page *i

[f2fs-dev] [f2fs-dev 5/5] f2fs: Handle inline data operations

2013-10-25 Thread Huajun Li
From: Huajun Li 

Hook inline data read/write, truncate, fallocate, setattr, etc.

Files need meet following 2 requirement to inline:
 1) file size is not greater than MAX_INLINE_DATA;
 2) file doesn't pre-allocate data blocks by fallocate().

FI_INLINE_DATA will not be set while creating a new regular inode because
most of the files are bigger than ~3.4K. Set FI_INLINE_DATA only when
data is submitted to block layer, ranther than set it while creating a new
inode, this also avoids converting data from inline to normal data block
and vice versa.

While writting inline data to inode block, the first data block should be
released if the file has a block indexed by i_addr[0].

On the other hand, when a file operation is appied to a file with inline
data, we need to test if this file can remain inline by doing this
operation, otherwise it should be convert into normal file by reserving
a new data block, copying inline data to this new block and clear
FI_INLINE_DATA flag. Because reserve a new data block here will make use
of i_addr[0], if we save inline data in i_addr[0..822], then the first
4 bytes would be overwriten. This problem can be avoided simply by
not using i_addr[0] for inline data.

Signed-off-by: Huajun Li 
Signed-off-by: Haicheng Li 
Signed-off-by: Weihong Xu 
---
 fs/f2fs/data.c |   48 
 fs/f2fs/file.c |   42 +++---
 2 files changed, 83 insertions(+), 7 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 7b31911..73ef248 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -481,13 +481,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(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);
 }
 
@@ -538,7 +553,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;
 
@@ -572,7 +587,14 @@ write:
err = do_write_data_page(page);
} else {
f2fs_lock_op(sbi);
-   err = do_write_data_page(page);
+   if (test_opt(sbi, INLINE_DATA) && (i_size <= MAX_INLINE_DATA)) {
+   err = f2fs_write_inline_data(inode, page, offset);
+   ClearPageDirty(page);
+   f2fs_unlock_op(sbi);
+   goto out;
+   } else {
+   err = do_write_data_page(page);
+   }
f2fs_unlock_op(sbi);
need_balance_fs = true;
}
@@ -660,12 +682,22 @@ repeat:
return -ENOMEM;
*pagep = page;
 
+   if ((pos + len) < MAX_INLINE_DATA) {
+   if (f2fs_has_inline_data(inode))
+   goto inline_data;
+   } else if (f2fs_has_inline_data(inode)) {
+   err = f2fs_convert_inline_data(inode, page, flags);
+   if (err)
+   return err;
+   }
+
f2fs_lock_op(sbi);
err = f2fs_reserve_block(inode, &dn, index);
if (err)
goto err;
f2fs_unlock_op(sbi);
 
+inline_data:
if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
return 0;
 
@@ -681,7 +713,11 @@ repeat:
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 (f2fs_has_inline_data(inode))
+   err = f2fs_read_inline_data(inode, page);
+   else
+   err = f2fs_readpage(sbi, page,
+   dn.data_blkaddr, READ_SYNC);
if (err)
return err;
lock_page(page);
@@ -735,6 +771,10 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
  

[f2fs-dev] [f2fs-dev 1/1] f2fs-tools: add inline data check

2013-10-25 Thread Huajun Li
From: Huajun Li 

Add inline data check

Signed-off-by: Weihong Xu 
Signed-off-by: Huajun Li 
Signed-off-by: Haicheng Li 
---
 fsck/fsck.c   |4 
 include/f2fs_fs.h |5 +
 2 files changed, 9 insertions(+)

diff --git a/fsck/fsck.c b/fsck/fsck.c
index cdf68ab..7e263ed 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -338,6 +338,10 @@ int fsck_chk_inode_blk(struct f2fs_sb_info *sbi,
if (ftype == F2FS_FT_CHRDEV || ftype == F2FS_FT_BLKDEV ||
ftype == F2FS_FT_FIFO || ftype == F2FS_FT_SOCK)
goto check;
+   if((node_blk->i.i_inline & F2FS_INLINE_DATA)){
+   DBG(3, "ino[0x%x] has inline data!\n", nid);
+   goto check;
+   }
 
/* check data blocks in inode */
for (idx = 0; idx < ADDRS_PER_INODE(&node_blk->i); idx++) {
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index fb7c94c..68f427d 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -360,6 +360,11 @@ struct f2fs_extent {
 
 #define F2FS_INLINE_XATTR  0x01/* file inline xattr flag */
 #define F2FS_INLINE_DATA   0x02/* file inline data flag */
+#define MAX_INLINE_DATA(sizeof(__le32) * (DEF_ADDRS_PER_INODE 
- \
+   F2FS_INLINE_XATTR_ADDRS - 1))
+
+#define INLINE_DATA_OFFSET (PAGE_CACHE_SIZE - sizeof(struct node_footer) \
+   - sizeof(__le32)*(DEF_ADDRS_PER_INODE + 5 - 1))
 
 struct f2fs_inode {
__le16 i_mode;  /* file mode */
-- 
1.7.9.5


--
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60135991&iu=/4140/ostg.clktrk
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


Re: [f2fs-dev] Kernel BUG when writing to f2fs drive, PowerPC, SD card, USB3

2013-06-17 Thread Huajun Li
Hi,
Is it possible caused by bitmap ? you know, bitmaps are unsigned
variable, while f2fs_{clear, set, test}_bit() parameter is signed
variable.
So, could you please try following patch, and update the same issue in
mkfs.f2fs tool.

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 3e7cb33..28d31f1 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -209,7 +209,7 @@ struct f2fs_nm_info {
 struct mutex build_lock;/* lock for build free nids */

 /* for checkpoint */
-char *nat_bitmap;/* NAT bitmap pointer */
+unsigned char *nat_bitmap;/* NAT bitmap pointer */
 int bitmap_size;/* bitmap size */
 };

@@ -820,7 +820,7 @@ static inline block_t datablock_addr(struct page *node_page,
 return le32_to_cpu(addr_array[offset]);
 }

-static inline int f2fs_test_bit(unsigned int nr, char *addr)
+static inline int f2fs_test_bit(unsigned int nr, unsigned char *addr)
 {
 int mask;

@@ -829,7 +829,7 @@ static inline int f2fs_test_bit(unsigned int nr, char *addr)
 return mask & *addr;
 }

-static inline int f2fs_set_bit(unsigned int nr, char *addr)
+static inline int f2fs_set_bit(unsigned int nr, unsigned char *addr)
 {
 int mask;
 int ret;
@@ -841,7 +841,7 @@ static inline int f2fs_set_bit(unsigned int nr, char *addr)
 return ret;
 }

-static inline int f2fs_clear_bit(unsigned int nr, char *addr)
+static inline int f2fs_clear_bit(unsigned int nr, unsigned char *addr)
 {
 int mask;
 int ret;
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index b15debc..b191449 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -1402,7 +1402,7 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
 struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
 struct sit_info *sit_i;
 unsigned int sit_segs, start;
-char *src_bitmap, *dst_bitmap;
+unsigned char *src_bitmap, *dst_bitmap;
 unsigned int bitmap_size;

 /* allocate memory for SIT information */
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index 062424a..a96f7f4 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -175,7 +175,7 @@ struct sit_info {
 block_t sit_base_addr;/* start block address of SIT area */
 block_t sit_blocks;/* # of blocks used by SIT area */
 block_t written_valid_blocks;/* # of valid blocks in main area */
-char *sit_bitmap;/* SIT bitmap pointer */
+unsigned char *sit_bitmap;/* SIT bitmap pointer */
 unsigned int bitmap_size;/* SIT bitmap size */

 unsigned long *dirty_sentries_bitmap;/* bitmap for dirty sentries */

On Sun, Jun 16, 2013 at 7:51 PM, Oded Gabbay  wrote:
> Hi,
>
> I'm working on a custom board with a PowerPC processor (Freescale P2020).
> On the board there is an SD card, which is connected to a USB3 chip (from
> TI), which is connected to the PCI-e controller of the CPU.
> I'm running with Linux kernel 3.9.6, with our custom rootFS.
>
> I formatted an SD card using the mkfs.f2fs utility (after fixing some
> Big-endian issues - sent a patch a few days ago).
> I then mounted the SD card, using "mount -o
> noatime,nodiratime,rw,nosuid,nodev,relatime,active_logs=6,uhelper=udisks2,background_gc_off
> /dev/sda /mnt/sd1"
> Then, I started a small user-space test application which opens a file on
> the mount folder and starts to do "fwrite" into the file.
> After 2-3 seconds, the kernel gives me a BUG and the system restarts.
> When the system is up and I try to re-mount the SD card, I get the following
> error message:
>
> F2FS-fs (sda): Failed to get valid F2FS checkpoint
> mount: you must specify the filesystem type
>
> Only way is to re-format the card using mkfs.f2fs
>
> I took the f2fs patch that Jaegeuk Kim sent to Linus for 3.10 (here -
> https://lkml.org/lkml/2013/5/8/122) and applied it cleanly to 3.9.6
> I repeated the procedure but got the same result.
>
> The BUG is from this line, from segment.c:
> if (!f2fs_clear_bit(offset, se->cur_valid_map))
> BUG();
>
> Additional information I can give is
>
> 1. I tried using F2FS in ArchLinux, kernel 3.9.5, on an x86 machine, with
> the same SD card and the same USB3-to-PCIe chip and it worked flawlessly
> there.
> 2. I can work with other FS on the SD card on our custom board, such as
> Ext3, Ext4 and vfat, so this is not a H/W issue.
>
> Could you please try to help me pinpoint/debug the problem ?
>
> Here is the complete kernel BUG print:
>
> kernel BUG at .../linux-3.9.6-adva/fs/f2fs/segment.c:214!
> Oops: Exception in kernel mode, sig: 5 [#1]
> PREEMPT SMP NR_CPUS=2 P2020 FSP150
> Modules linked in: mdio(O) hardware_version(PO) clipresent(PO) monotonic(O)
> restartcause(PO) panic_buffer(O)
> NIP: c026a7e0 LR: c026a660 CTR: 
> REGS: ee761a60 TRAP: 0700   Tainted: P   O
> (3.9.6-dev_ogabbay-109482*)
> MSR: 00029000   CR: 24a52588  XER: 2000
> TASK = efb444c0[1755] 'flush-8:0' THREAD: ee76 CPU: 1
> GPR00:  ee761b10 efb444c0 004c   01dc4900
> eb0fa70

Re: [f2fs-dev] [RFC 0/5] Enable f2fs support inline data

2013-06-08 Thread Huajun Li
Hi Jaegeuk,
Thanks for your suggestion.

On Wed, Jun 5, 2013 at 3:13 PM, Jaegeuk Kim  wrote:

> Hi Haicheng,
>
> 2013-06-04 (화), 14:01 +0800, Haicheng Li:
> > Hi Jaegeuk & Namjae,
> >
> > Sure, we'll address your comments. And this version is RFC, just wanna to
> > make sure this feature is meaningful for f2fs project, and there is no
> obvious
> > mistake, e.g. missing some critical path.
>
> IMO, it is worth to design and implement the inline feature though, I'd
> like to review the total design before looking at trivial mistakes.
> Since if the initial design is changed frequently, we need to review
> again and again.
>
> Agree. So let's understand/clarify your following proposal firstly.

> So, we need to decide the overall inline design.
> Currently we have to consider three data structures at a same time for
> the on-disk *inline* inode block structure, which are data, dentry, and
> xattr as well.
>
> IMO, we can give three inode flags: F2FS_INLINE_DATA, F2FS_INLINE_DENT,
> and F2FS_INLINE_XATTR.
>
> Small data and dentries can be inline.  And xattr (such as XATTR_USER,
XATTR_TRUSTED, eg. ) can be inline too, right ?
Or inline xattr is just working for inline data/dentries?


> < on-disk inode block >
>  - metadata
>  - if F2FS_INLINE_XATTR is set,
>   : use fixed 2*255 bytes to *cache* two xattrs for simplicity
>

These 2 xattrs are working for the ones storing in xattr_nid block before,
or just providing info for inline data/dent ?

 `- if F2FS_INLINE_DATA is set,
>: use the remained space varied by F2FS_INLINE_XATTR.
>  `- if F2FS_INLINE_DENT is set,
>: use variable number of dentries determined by F2FS_INLINE_XATTR.
>
Do you mean inline dent depends on inline xattr, that is, we need a
dedicated xattr entry providing info for inline denteries, right?


>  `- Otherwise, use as pointers
>
> And then, we need to define how to deal with their combinations.
>
> Operational conditions
> --
>  - use inline xattr or not, by checking other inline flags and inline
> data size.
>  - calculate inline data size and its offset according to the use of
> inline xattrs.
>  - the places of inline operaions wrt the lock consistency and coverage
>  - Power-off-recovery routine should care about the on-disk inode
> structure.
>  - unset F2FS_INLINE_DATA if i_size = 0
>  - unset F2FS_INLINE_XATTR if xattr entries = 0
>  - unset F2FS_INLINE_DENT if dentries = 0
>
>  - what else?
>
- clear these flags after the inline data/dent is moved to normal data block
- maybe we need store xattr_header while making xattr inline.


> Once we design the whole thing, we can make general functions to deal
> with them gracefully.
>
> > And if you team has some special opensource test suites used in your
> daily
> > f2fs test cycle, pls. kindly share the info with us, then we can make
> sure our
> > patchset can pass these cases before we send out next version.
>
> 1. xfstests for functionality
> 2. fsstress for deadlock/consistency check
> 3. power-off with fsstress
>
> Thanks,
>
> > BTW, test the kernel source tree or kernel build is a good suggestion.
> thanks.
> >
> > On Tue, Jun 04, 2013 at 01:23:57PM +0900, Namjae Jeon wrote:
> > > Hi. Huajun.
> > >
> > > I agree jaegeuk's opinion.
> > > Additionally, It is better that you describe the effect in change-log
> > > when this feature is added to f2fs.
> > > e.g.
> > > 1. how much space is saved when storing kernel-tree(small files) ?
> > > 2. small files creation performance test.
> > > 3. file look-up performance test.
> > > 4. other performance tools 's result.
> > >
> > > Thanks.
> > >
> > > 2013/6/4 Jaegeuk Kim :
> > > > Hi,
> > > >
> > > > This feature is one of my todo items. ;)
> > > > Thank you for the contribution.
> > > >
> > > > Before reviewing the below code intensively, we need to check the
> > > > following issues.
> > > >
> > > > - deadlock conditions
> > > > - FS consistency
> > > > - recovery routine
> > > >
> > > > Could you check one more time?
> > > > Thanks again,
> > > >
> > > > 2013-06-03 (월), 18:04 +0800, Huajun Li:
> > > >> f2fs inode is so large, small files can be stored directly in the
> inode,
> > > >> rather than just storing a single block address and storing the
> data elsewhere.
> > > >>
> > > >> This RFC patch set is just to enable f2fs su

[f2fs-dev] [RFC 5/5] f2fs: add tracepoints to debug inline data operations

2013-06-03 Thread Huajun Li
From: Haicheng Li 

Add tracepoints for: f2fs_read_inline_data(), f2fs_convert_inline_data(),
f2fs_write_inline_data().

Cc: Steven Rostedt 
Signed-off-by: Haicheng Li 
Signed-off-by: Huajun Li 
---
 fs/f2fs/inline.c|4 +++
 include/trace/events/f2fs.h |   69 +++
 2 files changed, 73 insertions(+)

diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index a2aa056..9ec66e5 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -14,6 +14,7 @@
 #include 
 
 #include "f2fs.h"
+#include 
 
 void f2fs_clear_inode_inline_flag(struct f2fs_inode *raw_inode)
 {
@@ -44,6 +45,7 @@ static int f2fs_read_inline_data(struct inode *inode, struct 
page *page)
if (IS_ERR(ipage))
return PTR_ERR(ipage);
 
+   trace_f2fs_read_inline_data(inode, page);
src_addr = page_address(ipage);
dst_addr = page_address(page);
 
@@ -107,6 +109,7 @@ int f2fs_convert_inline_data(struct page *p,
set_page_dirty(ipage);
f2fs_put_page(ipage, 1);
 
+   trace_f2fs_convert_inline_data(inode, page);
if (!p->index) {
SetPageUptodate(page);
} else {
@@ -138,6 +141,7 @@ int f2fs_write_inline_data(struct inode *inode,
if (IS_ERR(ipage))
return PTR_ERR(ipage);
 
+   trace_f2fs_write_inline_data(inode, page);
src_addr = page_address(page);
dst_addr = page_address(ipage);
 
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
index 52ae548..bc7a84e 100644
--- a/include/trace/events/f2fs.h
+++ b/include/trace/events/f2fs.h
@@ -676,6 +676,75 @@ TRACE_EVENT(f2fs_write_checkpoint,
__entry->msg)
 );
 
+TRACE_EVENT(f2fs_read_inline_data,
+
+   TP_PROTO(struct inode *inode, struct page *page),
+
+   TP_ARGS(inode, page),
+
+   TP_STRUCT__entry(
+   __field(dev_t,  dev)
+   __field(ino_t,  ino)
+   __field(pgoff_t, index)
+   ),
+
+   TP_fast_assign(
+   __entry->dev= inode->i_sb->s_dev;
+   __entry->ino= inode->i_ino;
+   __entry->index  = page->index;
+   ),
+
+   TP_printk("dev = (%d,%d), ino = %lu, index = %lu",
+   show_dev_ino(__entry),
+   (unsigned long)__entry->index)
+);
+
+TRACE_EVENT(f2fs_convert_inline_data,
+
+   TP_PROTO(struct inode *inode, struct page *page),
+
+   TP_ARGS(inode, page),
+
+   TP_STRUCT__entry(
+   __field(dev_t,  dev)
+   __field(ino_t,  ino)
+   __field(pgoff_t, index)
+   ),
+
+   TP_fast_assign(
+   __entry->dev= inode->i_sb->s_dev;
+   __entry->ino= inode->i_ino;
+   __entry->index  = page->index;
+   ),
+
+   TP_printk("dev = (%d,%d), ino = %lu, index = %lu",
+   show_dev_ino(__entry),
+   (unsigned long)__entry->index)
+);
+
+TRACE_EVENT(f2fs_write_inline_data,
+
+   TP_PROTO(struct inode *inode, struct page *page),
+
+   TP_ARGS(inode, page),
+
+   TP_STRUCT__entry(
+   __field(dev_t,  dev)
+   __field(ino_t,  ino)
+   __field(pgoff_t, index)
+   ),
+
+   TP_fast_assign(
+   __entry->dev= inode->i_sb->s_dev;
+   __entry->ino= inode->i_ino;
+   __entry->index  = page->index;
+   ),
+
+   TP_printk("dev = (%d,%d), ino = %lu, index = %lu",
+   show_dev_ino(__entry),
+   (unsigned long)__entry->index)
+);
+
 #endif /* _TRACE_F2FS_H */
 
  /* This part must be outside protection */
-- 
1.7.9.5


--
Get 100% visibility into Java/.NET code with AppDynamics Lite
It's a free troubleshooting tool designed for production
Get down to code-level detail for bottlenecks, with <2% overhead.
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap2
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [RFC 0/5] Enable f2fs support inline data

2013-06-03 Thread Huajun Li
f2fs inode is so large, small files can be stored directly in the inode,
rather than just storing a single block address and storing the data elsewhere.

This RFC patch set is just to enable f2fs support inline data: files less than
about 3.6K can be stored directly in inode block.

TODO: make small dirs inline too.


Haicheng Li (3):
  f2fs: Add helper functions and flag to support inline data
  f2fs: Add interface for inline data support
  f2fs: add tracepoints to debug inline data operations

Huajun Li (2):
  f2fs: Handle inline data read and write
  f2fs: Key functions to handle inline data

 fs/f2fs/Kconfig |   10 +++
 fs/f2fs/Makefile|1 +
 fs/f2fs/data.c  |   78 +-
 fs/f2fs/f2fs.h  |   70 +++
 fs/f2fs/file.c  |9 ++-
 fs/f2fs/inline.c|  156 +++
 fs/f2fs/inode.c |8 +++
 include/linux/f2fs_fs.h |5 ++
 include/trace/events/f2fs.h |   69 +++
 9 files changed, 402 insertions(+), 4 deletions(-)
 create mode 100644 fs/f2fs/inline.c

-- 
1.7.9.5


--
Get 100% visibility into Java/.NET code with AppDynamics Lite
It's a free troubleshooting tool designed for production
Get down to code-level detail for bottlenecks, with <2% overhead.
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap2
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [RFC 3/5] f2fs: Key functions to handle inline data

2013-06-03 Thread Huajun Li
Functions to implement inline data read/write, and move inline data to
normal data block when file size exceeds inline data limitation.

Signed-off-by: Huajun Li 
Signed-off-by: Haicheng Li 
---
 fs/f2fs/inline.c |  152 ++
 1 file changed, 152 insertions(+)
 create mode 100644 fs/f2fs/inline.c

diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
new file mode 100644
index 000..a2aa056
--- /dev/null
+++ b/fs/f2fs/inline.c
@@ -0,0 +1,152 @@
+/*
+ * fs/f2fs/inline.c
+ *
+ * Copyright (c) 2013, Intel Corporation.
+ * Authors:
+ *  Huajun Li 
+ *  Haicheng Li 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include 
+#include 
+
+#include "f2fs.h"
+
+void f2fs_clear_inode_inline_flag(struct f2fs_inode *raw_inode)
+{
+   raw_inode->i_reserved &= ~F2FS_INODE_INLINE_DATA;
+}
+
+void f2fs_set_inode_inline_flag(struct f2fs_inode *raw_inode)
+{
+   raw_inode->i_reserved |= F2FS_INODE_INLINE_DATA;
+}
+
+int f2fs_inline_data_attempt(struct inode *inode)
+{
+   return is_inode_dyn_flag_set(F2FS_I(inode), F2FS_INLINE_DATA_ATTEMPT);
+}
+
+int f2fs_has_inline_data(struct inode *inode)
+{
+   return is_inode_dyn_flag_set(F2FS_I(inode), F2FS_INLINE_DATA_FL);
+}
+
+static int f2fs_read_inline_data(struct inode *inode, struct page *page)
+{
+   void *src_addr, *dst_addr;
+   loff_t size = i_size_read(inode);
+   struct page *ipage = get_node_page(F2FS_SB(inode->i_sb), inode->i_ino);
+
+   if (IS_ERR(ipage))
+   return PTR_ERR(ipage);
+
+   src_addr = page_address(ipage);
+   dst_addr = page_address(page);
+
+   memcpy(dst_addr, src_addr + INLINE_DATA_OFFSET, size);
+   zero_user_segment(page, INLINE_DATA_OFFSET + size, PAGE_CACHE_SIZE);
+   SetPageUptodate(page);
+
+   f2fs_put_page(ipage, 1);
+
+   return 0;
+}
+
+int f2fs_read_inline_data_page(struct inode *inode, struct page *page)
+{
+   int ret = 0;
+
+   if (!page->index) {
+   ret = f2fs_read_inline_data(inode, page);
+   } else if (!PageUptodate(page)) {
+   zero_user_segment(page, 0, PAGE_CACHE_SIZE);
+   SetPageUptodate(page);
+   }
+
+   unlock_page(page);
+
+   return ret;
+}
+
+int f2fs_convert_inline_data(struct page *p,
+struct inode *inode, unsigned flags)
+{
+   int err;
+   int ilock;
+   loff_t size;
+   struct page *page, *ipage;
+   void *src_addr, *dst_addr;
+   struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+
+   if (!p->index)
+   page = p;
+   else
+   page = grab_cache_page_write_begin(inode->i_mapping, 0, flags);
+
+   if (IS_ERR(page))
+   return PTR_ERR(page);
+
+   ipage = get_node_page(sbi, inode->i_ino);
+   if (IS_ERR(ipage)) {
+   f2fs_put_page(page, 1);
+   return PTR_ERR(ipage);
+   }
+
+   src_addr = page_address(ipage);
+   dst_addr = page_address(page);
+
+   size = i_size_read(inode);
+   memcpy(dst_addr, src_addr + INLINE_DATA_OFFSET, size);
+   zero_user_segment(ipage, INLINE_DATA_OFFSET,
+ INLINE_DATA_OFFSET + MAX_INLINE_DATA);
+   clear_inode_dyn_flag(F2FS_I(inode), F2FS_INLINE_DATA_FL);
+   set_page_dirty(ipage);
+   f2fs_put_page(ipage, 1);
+
+   if (!p->index) {
+   SetPageUptodate(page);
+   } else {
+   ilock = mutex_lock_op(sbi);
+   err = f2fs_reserve_block(inode, 0);
+   if (err)
+   goto err;
+   mutex_unlock_op(sbi, ilock);
+
+   set_page_dirty(page);
+   f2fs_put_page(page, 1);
+   }
+
+   return 0;
+
+err:
+   mutex_unlock_op(sbi, ilock);
+   f2fs_put_page(page, 1);
+   return err;
+}
+
+int f2fs_write_inline_data(struct inode *inode,
+  struct page *page, unsigned size)
+{
+   void *src_addr, *dst_addr;
+   struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+   struct page *ipage = get_node_page(sbi, inode->i_ino);
+
+   if (IS_ERR(ipage))
+   return PTR_ERR(ipage);
+
+   src_addr = page_address(page);
+   dst_addr = page_address(ipage);
+
+   memcpy(dst_addr + INLINE_DATA_OFFSET, src_addr, size);
+   clear_inode_dyn_flag(F2FS_I(inode), F2FS_INLINE_DATA_ATTEMPT);
+   if (!f2fs_has_inline_data(inode))
+   set_inode_dyn_flag(F2FS_I(inode), F2FS_INLINE_DATA_FL);
+   set_page_dirty(ipage);
+   f2fs_put_page(ipage, 1);
+
+   return 0;
+}
-- 
1.7.9.5


--
Get 100% visibility into Java/.NET code with AppDynamics Lite
It's a free troubleshoot

[f2fs-dev] [RFC 1/5] f2fs: Add helper functions and flag to support inline data

2013-06-03 Thread Huajun Li
From: Haicheng Li 

Add a new flag i_dyn_flags to struct f2fs_inode_info to indicate whether
the inode has inline data, and sync the flag with raw inode while update
file.

Signed-off-by: Haicheng Li 
Signed-off-by: Huajun Li 
---
 fs/f2fs/f2fs.h  |   70 +++
 fs/f2fs/inode.c |8 ++
 include/linux/f2fs_fs.h |5 
 3 files changed, 83 insertions(+)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 40b137a..9382f76 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -162,6 +162,7 @@ struct f2fs_inode_info {
umode_t i_acl_mode; /* keep file acl mode temporarily */
 
/* Use below internally in f2fs*/
+   unsigned long i_dyn_flags;  /* use to mark dynamic features */
unsigned long flags;/* use to pass per-file flags */
atomic_t dirty_dents;   /* # of dirty dentry pages */
f2fs_hash_t chash;  /* hash value of given file name */
@@ -170,6 +171,14 @@ struct f2fs_inode_info {
struct extent_info ext; /* in-memory extent cache entry */
 };
 
+/*
+ * Flags on f2fs_inode_info.i_dyn_flags
+ *
+ * These can change much more often than i_flags.
+ */
+#define F2FS_INLINE_DATA_FL   (0x0001) /* Data stored in inode block */
+#define F2FS_INLINE_DATA_ATTEMPT  (0x0002) /* Data stored in inode block */
+
 static inline void get_extent_info(struct extent_info *ext,
struct f2fs_extent i_ext)
 {
@@ -877,6 +886,21 @@ static inline void clear_inode_flag(struct f2fs_inode_info 
*fi, int flag)
clear_bit(flag, &fi->flags);
 }
 
+static inline void set_inode_dyn_flag(struct f2fs_inode_info *fi, int flag)
+{
+   set_bit(flag, &fi->i_dyn_flags);
+}
+
+static inline int is_inode_dyn_flag_set(struct f2fs_inode_info *fi, int flag)
+{
+   return test_bit(flag, &fi->i_dyn_flags);
+}
+
+static inline void clear_inode_dyn_flag(struct f2fs_inode_info *fi, int flag)
+{
+   clear_bit(flag, &fi->i_dyn_flags);
+}
+
 static inline void set_acl_inode(struct f2fs_inode_info *fi, umode_t mode)
 {
fi->i_acl_mode = mode;
@@ -1042,6 +1066,7 @@ void destroy_checkpoint_caches(void);
  * data.c
  */
 int reserve_new_block(struct dnode_of_data *);
+int f2fs_reserve_block(struct inode *, pgoff_t);
 void update_extent_cache(block_t, struct dnode_of_data *);
 struct page *find_data_page(struct inode *, pgoff_t, bool);
 struct page *get_lock_data_page(struct inode *, pgoff_t);
@@ -1144,6 +1169,51 @@ static inline void __init f2fs_create_root_stats(void) { 
}
 static inline void f2fs_destroy_root_stats(void) { }
 #endif
 
+/*
+ * inline.c
+ */
+#ifdef CONFIG_F2FS_INLINE_DATA
+#define MAX_INLINE_DATA(sizeof(__le32) * (ADDRS_PER_INODE + 5))
+#define INLINE_DATA_OFFSET (PAGE_CACHE_SIZE - sizeof(struct node_footer)\
+   - MAX_INLINE_DATA)
+
+void f2fs_clear_inode_inline_flag(struct f2fs_inode *);
+void f2fs_set_inode_inline_flag(struct f2fs_inode *);
+int f2fs_inline_data_attempt(struct inode *);
+int f2fs_has_inline_data(struct inode *);
+int f2fs_read_inline_data_page(struct inode *, struct page *);
+int f2fs_convert_inline_data(struct page *, struct inode *, unsigned);
+int f2fs_write_inline_data(struct inode *, struct page *, unsigned int);
+#else
+static inline void
+f2fs_clear_inode_inline_flag(struct f2fs_inode *raw_inode) { }
+static inline void
+f2fs_set_inode_inline_flag(struct f2fs_inode *raw_inode) { }
+int f2fs_inline_data_attempt(struct inode *inode)
+{
+   return 0;
+}
+static inline int f2fs_has_inline_data(struct inode *inode)
+{
+   return 0;
+}
+static inline int f2fs_read_inline_data_page(struct inode *inode,
+   struct page *page)
+{
+   return 0;
+}
+static inline int f2fs_convert_inline_data(struct page *page,
+  struct inode *inode, unsigned flags)
+{
+   return 0;
+}
+static inline int f2fs_write_inline_data(struct inode *inode,
+struct page *page, unsigned size)
+{
+   return 0;
+}
+#endif
+
 extern const struct file_operations f2fs_dir_operations;
 extern const struct file_operations f2fs_file_operations;
 extern const struct inode_operations f2fs_file_inode_operations;
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index b44a4c1..1d7b0b5 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -84,6 +84,9 @@ static int do_read_inode(struct inode *inode)
fi->flags = 0;
fi->i_advise = ri->i_advise;
fi->i_pino = le32_to_cpu(ri->i_pino);
+   if (ri->i_reserved & F2FS_INODE_INLINE_DATA)
+   set_inode_dyn_flag(fi, F2FS_INLINE_DATA_FL);
+
get_extent_info(&fi->ext, ri->i_ext);
f2fs_put_page(node_page, 1);
return 0;
@@ -177,6 +180,11 @@ void update_inode(struct inode *i

[f2fs-dev] [RFC 4/5] f2fs: Add Kconfig interface for inline data support

2013-06-03 Thread Huajun Li
From: Haicheng Li 

Add Kconfig interface for inline data support, and update Makefile to
compile new added source file.

Signed-off-by: Haicheng Li 
Signed-off-by: Huajun Li 
---
 fs/f2fs/Kconfig  |   10 ++
 fs/f2fs/Makefile |1 +
 2 files changed, 11 insertions(+)

diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig
index fd27e7e..75da2e4 100644
--- a/fs/f2fs/Kconfig
+++ b/fs/f2fs/Kconfig
@@ -51,3 +51,13 @@ config F2FS_FS_POSIX_ACL
  Linux website <http://acl.bestbits.at/>.
 
  If you don't know what Access Control Lists are, say N
+
+config F2FS_INLINE_DATA
+   bool "F2FS inline data support"
+   depends on F2FS_FS
+   default y
+   help
+ Inline data support is an optimization of F2FS data space management,
+ which utilizes the unused space within f2fs inode to keep real data.
+
+ If unsure, say N.
diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile
index 27a0820..e1ff7b8 100644
--- a/fs/f2fs/Makefile
+++ b/fs/f2fs/Makefile
@@ -5,3 +5,4 @@ f2fs-y  += checkpoint.o gc.o data.o node.o segment.o 
recovery.o
 f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o
 f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o
 f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o
+f2fs-$(CONFIG_F2FS_INLINE_DATA) += inline.o
-- 
1.7.9.5


--
Get 100% visibility into Java/.NET code with AppDynamics Lite
It's a free troubleshooting tool designed for production
Get down to code-level detail for bottlenecks, with <2% overhead.
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap2
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


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

2013-06-03 Thread Huajun Li
Hook inline data read/write in address space operations.

Signed-off-by: Huajun Li 
Signed-off-by: Haicheng Li 
---
 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 syn