[PATCH 4/7] f2fs: change atomic and volatile write policies

2014-12-14 Thread Jaegeuk Kim
This patch adds two new ioctls to release inmemory pages grabbed by atomic
writes.
 o f2fs_ioc_abort_volatile_write
  - If transaction was failed, all the grabbed pages and data should be written.
 o f2fs_ioc_release_volatile_write
  - This is to enhance the performance of PERSIST mode in sqlite.

In order to avoid huge memory consumption which causes OOM, this patch changes
volatile writes to use normal dirty pages, instead blocked flushing to the disk
as long as system does not suffer from memory pressure.

Signed-off-by: Jaegeuk Kim 
---
 fs/f2fs/data.c|  9 +--
 fs/f2fs/f2fs.h|  8 ++
 fs/f2fs/file.c| 77 +++
 fs/f2fs/inode.c   |  2 +-
 fs/f2fs/node.c|  3 +++
 fs/f2fs/node.h|  1 +
 fs/f2fs/segment.c |  2 +-
 7 files changed, 88 insertions(+), 14 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 7ec697b..32264e3 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -814,6 +814,11 @@ static int f2fs_write_data_page(struct page *page,
 write:
if (unlikely(sbi->por_doing))
goto redirty_out;
+   if (f2fs_is_drop_cache(inode))
+   goto out;
+   if (f2fs_is_volatile_file(inode) && !wbc->for_reclaim &&
+   available_free_memory(sbi, BASE_CHECK))
+   goto redirty_out;
 
/* Dentry blocks are controlled by checkpoint */
if (S_ISDIR(inode->i_mode)) {
@@ -1109,7 +1114,7 @@ static void f2fs_invalidate_data_page(struct page *page, 
unsigned int offset,
if (offset % PAGE_CACHE_SIZE || length != PAGE_CACHE_SIZE)
return;
 
-   if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode))
+   if (f2fs_is_atomic_file(inode))
invalidate_inmem_page(inode, page);
 
if (PageDirty(page))
@@ -1132,7 +1137,7 @@ static int f2fs_set_data_page_dirty(struct page *page)
 
SetPageUptodate(page);
 
-   if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) {
+   if (f2fs_is_atomic_file(inode)) {
register_inmem_page(inode, page);
return 1;
}
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index ec58bb2..8c9bf3d 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -201,6 +201,8 @@ static inline bool __has_cursum_space(struct 
f2fs_summary_block *sum, int size,
 #define F2FS_IOC_START_ATOMIC_WRITE_IO(F2FS_IOCTL_MAGIC, 1)
 #define F2FS_IOC_COMMIT_ATOMIC_WRITE   _IO(F2FS_IOCTL_MAGIC, 2)
 #define F2FS_IOC_START_VOLATILE_WRITE  _IO(F2FS_IOCTL_MAGIC, 3)
+#define F2FS_IOC_RELEASE_VOLATILE_WRITE_IO(F2FS_IOCTL_MAGIC, 4)
+#define F2FS_IOC_ABORT_VOLATILE_WRITE  _IO(F2FS_IOCTL_MAGIC, 5)
 
 #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
 /*
@@ -1113,6 +1115,7 @@ enum {
FI_NEED_IPU,/* used for ipu per file */
FI_ATOMIC_FILE, /* indicate atomic file */
FI_VOLATILE_FILE,   /* indicate volatile file */
+   FI_DROP_CACHE,  /* drop dirty page cache */
FI_DATA_EXIST,  /* indicate data exists */
 };
 
@@ -1220,6 +1223,11 @@ static inline bool f2fs_is_volatile_file(struct inode 
*inode)
return is_inode_flag_set(F2FS_I(inode), FI_VOLATILE_FILE);
 }
 
+static inline bool f2fs_is_drop_cache(struct inode *inode)
+{
+   return is_inode_flag_set(F2FS_I(inode), FI_DROP_CACHE);
+}
+
 static inline void *inline_data_addr(struct page *page)
 {
struct f2fs_inode *ri = F2FS_INODE(page);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 3c27e0e..5139f90 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -836,6 +836,19 @@ static long f2fs_fallocate(struct file *file, int mode,
return ret;
 }
 
+static int f2fs_release_file(struct inode *inode, struct file *filp)
+{
+   /* some remained atomic pages should discarded */
+   if (f2fs_is_atomic_file(inode))
+   commit_inmem_pages(inode, true);
+   if (f2fs_is_volatile_file(inode)) {
+   set_inode_flag(F2FS_I(inode), FI_DROP_CACHE);
+   filemap_fdatawrite(inode->i_mapping);
+   clear_inode_flag(F2FS_I(inode), FI_DROP_CACHE);
+   }
+   return 0;
+}
+
 #define F2FS_REG_FLMASK(~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
 #define F2FS_OTHER_FLMASK  (FS_NODUMP_FL | FS_NOATIME_FL)
 
@@ -909,26 +922,20 @@ out:
 static int f2fs_ioc_start_atomic_write(struct file *filp)
 {
struct inode *inode = file_inode(filp);
-   struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 
if (!inode_owner_or_capable(inode))
return -EACCES;
 
-   f2fs_balance_fs(sbi);
+   f2fs_balance_fs(F2FS_I_SB(inode));
+
+   if (f2fs_is_atomic_file(inode))
+   return 0;
 
set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
 
return f2fs_convert_inline_inode(inode);
 }
 
-static int f2fs_release_file(struct inode *inode, struct file *filp)
-{
-   /* some remained atomic pages should discarded */
-   if 

[PATCH 4/7] f2fs: change atomic and volatile write policies

2014-12-14 Thread Jaegeuk Kim
This patch adds two new ioctls to release inmemory pages grabbed by atomic
writes.
 o f2fs_ioc_abort_volatile_write
  - If transaction was failed, all the grabbed pages and data should be written.
 o f2fs_ioc_release_volatile_write
  - This is to enhance the performance of PERSIST mode in sqlite.

In order to avoid huge memory consumption which causes OOM, this patch changes
volatile writes to use normal dirty pages, instead blocked flushing to the disk
as long as system does not suffer from memory pressure.

Signed-off-by: Jaegeuk Kim jaeg...@kernel.org
---
 fs/f2fs/data.c|  9 +--
 fs/f2fs/f2fs.h|  8 ++
 fs/f2fs/file.c| 77 +++
 fs/f2fs/inode.c   |  2 +-
 fs/f2fs/node.c|  3 +++
 fs/f2fs/node.h|  1 +
 fs/f2fs/segment.c |  2 +-
 7 files changed, 88 insertions(+), 14 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 7ec697b..32264e3 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -814,6 +814,11 @@ static int f2fs_write_data_page(struct page *page,
 write:
if (unlikely(sbi-por_doing))
goto redirty_out;
+   if (f2fs_is_drop_cache(inode))
+   goto out;
+   if (f2fs_is_volatile_file(inode)  !wbc-for_reclaim 
+   available_free_memory(sbi, BASE_CHECK))
+   goto redirty_out;
 
/* Dentry blocks are controlled by checkpoint */
if (S_ISDIR(inode-i_mode)) {
@@ -1109,7 +1114,7 @@ static void f2fs_invalidate_data_page(struct page *page, 
unsigned int offset,
if (offset % PAGE_CACHE_SIZE || length != PAGE_CACHE_SIZE)
return;
 
-   if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode))
+   if (f2fs_is_atomic_file(inode))
invalidate_inmem_page(inode, page);
 
if (PageDirty(page))
@@ -1132,7 +1137,7 @@ static int f2fs_set_data_page_dirty(struct page *page)
 
SetPageUptodate(page);
 
-   if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) {
+   if (f2fs_is_atomic_file(inode)) {
register_inmem_page(inode, page);
return 1;
}
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index ec58bb2..8c9bf3d 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -201,6 +201,8 @@ static inline bool __has_cursum_space(struct 
f2fs_summary_block *sum, int size,
 #define F2FS_IOC_START_ATOMIC_WRITE_IO(F2FS_IOCTL_MAGIC, 1)
 #define F2FS_IOC_COMMIT_ATOMIC_WRITE   _IO(F2FS_IOCTL_MAGIC, 2)
 #define F2FS_IOC_START_VOLATILE_WRITE  _IO(F2FS_IOCTL_MAGIC, 3)
+#define F2FS_IOC_RELEASE_VOLATILE_WRITE_IO(F2FS_IOCTL_MAGIC, 4)
+#define F2FS_IOC_ABORT_VOLATILE_WRITE  _IO(F2FS_IOCTL_MAGIC, 5)
 
 #if defined(__KERNEL__)  defined(CONFIG_COMPAT)
 /*
@@ -1113,6 +1115,7 @@ enum {
FI_NEED_IPU,/* used for ipu per file */
FI_ATOMIC_FILE, /* indicate atomic file */
FI_VOLATILE_FILE,   /* indicate volatile file */
+   FI_DROP_CACHE,  /* drop dirty page cache */
FI_DATA_EXIST,  /* indicate data exists */
 };
 
@@ -1220,6 +1223,11 @@ static inline bool f2fs_is_volatile_file(struct inode 
*inode)
return is_inode_flag_set(F2FS_I(inode), FI_VOLATILE_FILE);
 }
 
+static inline bool f2fs_is_drop_cache(struct inode *inode)
+{
+   return is_inode_flag_set(F2FS_I(inode), FI_DROP_CACHE);
+}
+
 static inline void *inline_data_addr(struct page *page)
 {
struct f2fs_inode *ri = F2FS_INODE(page);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 3c27e0e..5139f90 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -836,6 +836,19 @@ static long f2fs_fallocate(struct file *file, int mode,
return ret;
 }
 
+static int f2fs_release_file(struct inode *inode, struct file *filp)
+{
+   /* some remained atomic pages should discarded */
+   if (f2fs_is_atomic_file(inode))
+   commit_inmem_pages(inode, true);
+   if (f2fs_is_volatile_file(inode)) {
+   set_inode_flag(F2FS_I(inode), FI_DROP_CACHE);
+   filemap_fdatawrite(inode-i_mapping);
+   clear_inode_flag(F2FS_I(inode), FI_DROP_CACHE);
+   }
+   return 0;
+}
+
 #define F2FS_REG_FLMASK(~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
 #define F2FS_OTHER_FLMASK  (FS_NODUMP_FL | FS_NOATIME_FL)
 
@@ -909,26 +922,20 @@ out:
 static int f2fs_ioc_start_atomic_write(struct file *filp)
 {
struct inode *inode = file_inode(filp);
-   struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 
if (!inode_owner_or_capable(inode))
return -EACCES;
 
-   f2fs_balance_fs(sbi);
+   f2fs_balance_fs(F2FS_I_SB(inode));
+
+   if (f2fs_is_atomic_file(inode))
+   return 0;
 
set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
 
return f2fs_convert_inline_inode(inode);
 }
 
-static int f2fs_release_file(struct inode *inode, struct file *filp)
-{
-   /* some remained atomic pages should discarded */
-   if