Skip to content

Commit 1e84371

Browse files
author
Jaegeuk Kim
committed
f2fs: change atomic and volatile write policies
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 <jaegeuk@kernel.org>
1 parent 70c640b commit 1e84371

File tree

7 files changed

+88
-14
lines changed

7 files changed

+88
-14
lines changed

fs/f2fs/data.c

+7-2
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,11 @@ static int f2fs_write_data_page(struct page *page,
814814
write:
815815
if (unlikely(sbi->por_doing))
816816
goto redirty_out;
817+
if (f2fs_is_drop_cache(inode))
818+
goto out;
819+
if (f2fs_is_volatile_file(inode) && !wbc->for_reclaim &&
820+
available_free_memory(sbi, BASE_CHECK))
821+
goto redirty_out;
817822

818823
/* Dentry blocks are controlled by checkpoint */
819824
if (S_ISDIR(inode->i_mode)) {
@@ -1109,7 +1114,7 @@ static void f2fs_invalidate_data_page(struct page *page, unsigned int offset,
11091114
if (offset % PAGE_CACHE_SIZE || length != PAGE_CACHE_SIZE)
11101115
return;
11111116

1112-
if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode))
1117+
if (f2fs_is_atomic_file(inode))
11131118
invalidate_inmem_page(inode, page);
11141119

11151120
if (PageDirty(page))
@@ -1132,7 +1137,7 @@ static int f2fs_set_data_page_dirty(struct page *page)
11321137

11331138
SetPageUptodate(page);
11341139

1135-
if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) {
1140+
if (f2fs_is_atomic_file(inode)) {
11361141
register_inmem_page(inode, page);
11371142
return 1;
11381143
}

fs/f2fs/f2fs.h

+8
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size,
201201
#define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1)
202202
#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2)
203203
#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3)
204+
#define F2FS_IOC_RELEASE_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 4)
205+
#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5)
204206

205207
#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
206208
/*
@@ -1113,6 +1115,7 @@ enum {
11131115
FI_NEED_IPU, /* used for ipu per file */
11141116
FI_ATOMIC_FILE, /* indicate atomic file */
11151117
FI_VOLATILE_FILE, /* indicate volatile file */
1118+
FI_DROP_CACHE, /* drop dirty page cache */
11161119
FI_DATA_EXIST, /* indicate data exists */
11171120
};
11181121

@@ -1220,6 +1223,11 @@ static inline bool f2fs_is_volatile_file(struct inode *inode)
12201223
return is_inode_flag_set(F2FS_I(inode), FI_VOLATILE_FILE);
12211224
}
12221225

1226+
static inline bool f2fs_is_drop_cache(struct inode *inode)
1227+
{
1228+
return is_inode_flag_set(F2FS_I(inode), FI_DROP_CACHE);
1229+
}
1230+
12231231
static inline void *inline_data_addr(struct page *page)
12241232
{
12251233
struct f2fs_inode *ri = F2FS_INODE(page);

fs/f2fs/file.c

+67-10
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,19 @@ static long f2fs_fallocate(struct file *file, int mode,
836836
return ret;
837837
}
838838

839+
static int f2fs_release_file(struct inode *inode, struct file *filp)
840+
{
841+
/* some remained atomic pages should discarded */
842+
if (f2fs_is_atomic_file(inode))
843+
commit_inmem_pages(inode, true);
844+
if (f2fs_is_volatile_file(inode)) {
845+
set_inode_flag(F2FS_I(inode), FI_DROP_CACHE);
846+
filemap_fdatawrite(inode->i_mapping);
847+
clear_inode_flag(F2FS_I(inode), FI_DROP_CACHE);
848+
}
849+
return 0;
850+
}
851+
839852
#define F2FS_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
840853
#define F2FS_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL)
841854

@@ -909,26 +922,20 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg)
909922
static int f2fs_ioc_start_atomic_write(struct file *filp)
910923
{
911924
struct inode *inode = file_inode(filp);
912-
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
913925

914926
if (!inode_owner_or_capable(inode))
915927
return -EACCES;
916928

917-
f2fs_balance_fs(sbi);
929+
f2fs_balance_fs(F2FS_I_SB(inode));
930+
931+
if (f2fs_is_atomic_file(inode))
932+
return 0;
918933

919934
set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
920935

921936
return f2fs_convert_inline_inode(inode);
922937
}
923938

924-
static int f2fs_release_file(struct inode *inode, struct file *filp)
925-
{
926-
/* some remained atomic pages should discarded */
927-
if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode))
928-
commit_inmem_pages(inode, true);
929-
return 0;
930-
}
931-
932939
static int f2fs_ioc_commit_atomic_write(struct file *filp)
933940
{
934941
struct inode *inode = file_inode(filp);
@@ -949,6 +956,7 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
949956

950957
ret = f2fs_sync_file(filp, 0, LONG_MAX, 0);
951958
mnt_drop_write_file(filp);
959+
clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
952960
return ret;
953961
}
954962

@@ -959,11 +967,56 @@ static int f2fs_ioc_start_volatile_write(struct file *filp)
959967
if (!inode_owner_or_capable(inode))
960968
return -EACCES;
961969

970+
if (f2fs_is_volatile_file(inode))
971+
return 0;
972+
962973
set_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
963974

964975
return f2fs_convert_inline_inode(inode);
965976
}
966977

978+
static int f2fs_ioc_release_volatile_write(struct file *filp)
979+
{
980+
struct inode *inode = file_inode(filp);
981+
982+
if (!inode_owner_or_capable(inode))
983+
return -EACCES;
984+
985+
if (!f2fs_is_volatile_file(inode))
986+
return 0;
987+
988+
punch_hole(inode, 0, F2FS_BLKSIZE);
989+
return 0;
990+
}
991+
992+
static int f2fs_ioc_abort_volatile_write(struct file *filp)
993+
{
994+
struct inode *inode = file_inode(filp);
995+
int ret;
996+
997+
if (!inode_owner_or_capable(inode))
998+
return -EACCES;
999+
1000+
ret = mnt_want_write_file(filp);
1001+
if (ret)
1002+
return ret;
1003+
1004+
f2fs_balance_fs(F2FS_I_SB(inode));
1005+
1006+
if (f2fs_is_atomic_file(inode)) {
1007+
commit_inmem_pages(inode, false);
1008+
clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
1009+
}
1010+
1011+
if (f2fs_is_volatile_file(inode)) {
1012+
clear_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
1013+
filemap_fdatawrite(inode->i_mapping);
1014+
set_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
1015+
}
1016+
mnt_drop_write_file(filp);
1017+
return ret;
1018+
}
1019+
9671020
static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
9681021
{
9691022
struct inode *inode = file_inode(filp);
@@ -1007,6 +1060,10 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
10071060
return f2fs_ioc_commit_atomic_write(filp);
10081061
case F2FS_IOC_START_VOLATILE_WRITE:
10091062
return f2fs_ioc_start_volatile_write(filp);
1063+
case F2FS_IOC_RELEASE_VOLATILE_WRITE:
1064+
return f2fs_ioc_release_volatile_write(filp);
1065+
case F2FS_IOC_ABORT_VOLATILE_WRITE:
1066+
return f2fs_ioc_abort_volatile_write(filp);
10101067
case FITRIM:
10111068
return f2fs_ioc_fitrim(filp, arg);
10121069
default:

fs/f2fs/inode.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ void f2fs_evict_inode(struct inode *inode)
304304
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
305305

306306
/* some remained atomic pages should discarded */
307-
if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode))
307+
if (f2fs_is_atomic_file(inode))
308308
commit_inmem_pages(inode, true);
309309

310310
trace_f2fs_evict_inode(inode);

fs/f2fs/node.c

+3
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ bool available_free_memory(struct f2fs_sb_info *sbi, int type)
6161
mem_size += (sbi->im[i].ino_num *
6262
sizeof(struct ino_entry)) >> PAGE_CACHE_SHIFT;
6363
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);
64+
} else {
65+
if (sbi->sb->s_bdi->dirty_exceeded)
66+
return false;
6467
}
6568
return res;
6669
}

fs/f2fs/node.h

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ enum mem_type {
108108
NAT_ENTRIES, /* indicates the cached nat entry */
109109
DIRTY_DENTS, /* indicates dirty dentry pages */
110110
INO_ENTRIES, /* indicates inode entries */
111+
BASE_CHECK, /* check kernel status */
111112
};
112113

113114
struct nat_entry_set {

fs/f2fs/segment.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ void commit_inmem_pages(struct inode *inode, bool abort)
230230
bool submit_bio = false;
231231
struct f2fs_io_info fio = {
232232
.type = DATA,
233-
.rw = WRITE_SYNC,
233+
.rw = WRITE_SYNC | REQ_PRIO,
234234
};
235235

236236
/*

0 commit comments

Comments
 (0)