* [PATCH 1/4] f2fs: check the use of macros on block counts and addresses
@ 2014-09-26 4:54 Jaegeuk Kim
2014-09-26 4:54 ` [PATCH 2/4] f2fs: support atomic_write feature for database Jaegeuk Kim
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Jaegeuk Kim @ 2014-09-26 4:54 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, linux-f2fs-devel; +Cc: Jaegeuk Kim
This patch cleans up the existing and new macros for readability.
Rule is like this.
,-----------------------------------------> MAX_BLKADDR -,
| ,------------- TOTAL_BLKS ----------------------------,
| | |
| ,- seg0_blkaddr ,----- sit/nat/ssa/main blkaddress |
block | | (SEG0_BLKADDR) | | | | (e.g., MAIN_BLKADDR) |
address 0..x................ a b c d .............................
| |
global seg# 0...................... m .............................
| | |
| `------- MAIN_SEGS -----------'
`-------------- TOTAL_SEGS ---------------------------'
| |
seg# 0..........xx..................
= Note =
o GET_SEGNO_FROM_SEG0 : blk address -> global segno
o GET_SEGNO : blk address -> segno
o START_BLOCK : segno -> starting block address
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
fs/f2fs/checkpoint.c | 5 ++--
fs/f2fs/debug.c | 20 ++++++-------
fs/f2fs/gc.c | 7 ++---
fs/f2fs/recovery.c | 8 ++---
fs/f2fs/segment.c | 85 +++++++++++++++++++++++-----------------------------
fs/f2fs/segment.h | 44 +++++++++++++--------------
6 files changed, 77 insertions(+), 92 deletions(-)
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 4abf0ba..dd10a03 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -98,7 +98,7 @@ static inline block_t get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
case META_CP:
return 0;
case META_POR:
- return SM_I(sbi)->seg0_blkaddr + TOTAL_BLKS(sbi);
+ return MAX_BLKADDR(sbi);
default:
BUG();
}
@@ -113,7 +113,6 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type
struct page *page;
block_t blkno = start;
block_t max_blks = get_max_meta_blks(sbi, type);
- block_t min_blks = SM_I(sbi)->seg0_blkaddr;
struct f2fs_io_info fio = {
.type = META,
@@ -146,7 +145,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type
case META_POR:
if (unlikely(blkno >= max_blks))
goto out;
- if (unlikely(blkno < min_blks))
+ if (unlikely(blkno < SEG0_BLKADDR(sbi)))
goto out;
blk_addr = blkno;
break;
diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
index fecebdb..0a91ab8 100644
--- a/fs/f2fs/debug.c
+++ b/fs/f2fs/debug.c
@@ -93,7 +93,7 @@ static void update_sit_info(struct f2fs_sb_info *sbi)
total_vblocks = 0;
blks_per_sec = sbi->segs_per_sec * (1 << sbi->log_blocks_per_seg);
hblks_per_sec = blks_per_sec / 2;
- for (segno = 0; segno < TOTAL_SEGS(sbi); segno += sbi->segs_per_sec) {
+ for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec);
dist = abs(vblocks - hblks_per_sec);
bimodal += dist * dist;
@@ -103,7 +103,7 @@ static void update_sit_info(struct f2fs_sb_info *sbi)
ndirty++;
}
}
- dist = TOTAL_SECS(sbi) * hblks_per_sec * hblks_per_sec / 100;
+ dist = MAIN_SECS(sbi) * hblks_per_sec * hblks_per_sec / 100;
si->bimodal = bimodal / dist;
if (si->dirty_count)
si->avg_vblocks = total_vblocks / ndirty;
@@ -131,17 +131,17 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
/* build sit */
si->base_mem += sizeof(struct sit_info);
- si->base_mem += TOTAL_SEGS(sbi) * sizeof(struct seg_entry);
- si->base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi));
- si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * TOTAL_SEGS(sbi);
+ si->base_mem += MAIN_SEGS(sbi) * sizeof(struct seg_entry);
+ si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi));
+ si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
if (sbi->segs_per_sec > 1)
- si->base_mem += TOTAL_SECS(sbi) * sizeof(struct sec_entry);
+ si->base_mem += MAIN_SECS(sbi) * sizeof(struct sec_entry);
si->base_mem += __bitmap_size(sbi, SIT_BITMAP);
/* build free segmap */
si->base_mem += sizeof(struct free_segmap_info);
- si->base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi));
- si->base_mem += f2fs_bitmap_size(TOTAL_SECS(sbi));
+ si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi));
+ si->base_mem += f2fs_bitmap_size(MAIN_SECS(sbi));
/* build curseg */
si->base_mem += sizeof(struct curseg_info) * NR_CURSEG_TYPE;
@@ -149,8 +149,8 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
/* build dirty segmap */
si->base_mem += sizeof(struct dirty_seglist_info);
- si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(TOTAL_SEGS(sbi));
- si->base_mem += f2fs_bitmap_size(TOTAL_SECS(sbi));
+ si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(MAIN_SEGS(sbi));
+ si->base_mem += f2fs_bitmap_size(MAIN_SECS(sbi));
/* build nm */
si->base_mem += sizeof(struct f2fs_nm_info);
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index e88fcf6..2a8f4ac 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -193,7 +193,7 @@ static unsigned int check_bg_victims(struct f2fs_sb_info *sbi)
* selected by background GC before.
* Those segments guarantee they have small valid blocks.
*/
- for_each_set_bit(secno, dirty_i->victim_secmap, TOTAL_SECS(sbi)) {
+ for_each_set_bit(secno, dirty_i->victim_secmap, MAIN_SECS(sbi)) {
if (sec_usage_check(sbi, secno))
continue;
clear_bit(secno, dirty_i->victim_secmap);
@@ -281,9 +281,8 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
unsigned long cost;
unsigned int segno;
- segno = find_next_bit(p.dirty_segmap,
- TOTAL_SEGS(sbi), p.offset);
- if (segno >= TOTAL_SEGS(sbi)) {
+ segno = find_next_bit(p.dirty_segmap, MAIN_SEGS(sbi), p.offset);
+ if (segno >= MAIN_SEGS(sbi)) {
if (sbi->last_victim[p.gc_mode]) {
sbi->last_victim[p.gc_mode] = 0;
p.offset = 0;
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index 947b922..ebd0132 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -173,8 +173,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
while (1) {
struct fsync_inode_entry *entry;
- if (blkaddr < SM_I(sbi)->main_blkaddr ||
- blkaddr >= (SM_I(sbi)->seg0_blkaddr + TOTAL_BLKS(sbi)))
+ if (blkaddr < MAIN_BLKADDR(sbi) || blkaddr >= MAX_BLKADDR(sbi))
return 0;
page = get_meta_page_ra(sbi, blkaddr);
@@ -434,8 +433,7 @@ static int recover_data(struct f2fs_sb_info *sbi,
while (1) {
struct fsync_inode_entry *entry;
- if (blkaddr < SM_I(sbi)->main_blkaddr ||
- blkaddr >= (SM_I(sbi)->seg0_blkaddr + TOTAL_BLKS(sbi)))
+ if (blkaddr < MAIN_BLKADDR(sbi) || blkaddr >= MAX_BLKADDR(sbi))
break;
page = get_meta_page_ra(sbi, blkaddr);
@@ -525,7 +523,7 @@ out:
/* truncate meta pages to be used by the recovery */
truncate_inode_pages_range(META_MAPPING(sbi),
- SM_I(sbi)->main_blkaddr << PAGE_CACHE_SHIFT, -1);
+ MAIN_BLKADDR(sbi) << PAGE_CACHE_SHIFT, -1);
if (err) {
truncate_inode_pages_final(NODE_MAPPING(sbi));
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index f602fa9..d30cd16 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -481,10 +481,9 @@ static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi)
{
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
unsigned int segno;
- unsigned int total_segs = TOTAL_SEGS(sbi);
mutex_lock(&dirty_i->seglist_lock);
- for_each_set_bit(segno, dirty_i->dirty_segmap[PRE], total_segs)
+ for_each_set_bit(segno, dirty_i->dirty_segmap[PRE], MAIN_SEGS(sbi))
__set_test_and_free(sbi, segno);
mutex_unlock(&dirty_i->seglist_lock);
}
@@ -495,17 +494,17 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi)
struct discard_entry *entry, *this;
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
unsigned long *prefree_map = dirty_i->dirty_segmap[PRE];
- unsigned int total_segs = TOTAL_SEGS(sbi);
unsigned int start = 0, end = -1;
mutex_lock(&dirty_i->seglist_lock);
while (1) {
int i;
- start = find_next_bit(prefree_map, total_segs, end + 1);
- if (start >= total_segs)
+ start = find_next_bit(prefree_map, MAIN_SEGS(sbi), end + 1);
+ if (start >= MAIN_SEGS(sbi))
break;
- end = find_next_zero_bit(prefree_map, total_segs, start + 1);
+ end = find_next_zero_bit(prefree_map, MAIN_SEGS(sbi),
+ start + 1);
for (i = start; i < end; i++)
clear_bit(i, prefree_map);
@@ -680,7 +679,7 @@ static int is_next_segment_free(struct f2fs_sb_info *sbi, int type)
unsigned int segno = curseg->segno + 1;
struct free_segmap_info *free_i = FREE_I(sbi);
- if (segno < TOTAL_SEGS(sbi) && segno % sbi->segs_per_sec)
+ if (segno < MAIN_SEGS(sbi) && segno % sbi->segs_per_sec)
return !test_bit(segno, free_i->free_segmap);
return 0;
}
@@ -694,7 +693,7 @@ static void get_new_segment(struct f2fs_sb_info *sbi,
{
struct free_segmap_info *free_i = FREE_I(sbi);
unsigned int segno, secno, zoneno;
- unsigned int total_zones = TOTAL_SECS(sbi) / sbi->secs_per_zone;
+ unsigned int total_zones = MAIN_SECS(sbi) / sbi->secs_per_zone;
unsigned int hint = *newseg / sbi->segs_per_sec;
unsigned int old_zoneno = GET_ZONENO_FROM_SEGNO(sbi, *newseg);
unsigned int left_start = hint;
@@ -706,18 +705,18 @@ static void get_new_segment(struct f2fs_sb_info *sbi,
if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) {
segno = find_next_zero_bit(free_i->free_segmap,
- TOTAL_SEGS(sbi), *newseg + 1);
+ MAIN_SEGS(sbi), *newseg + 1);
if (segno - *newseg < sbi->segs_per_sec -
(*newseg % sbi->segs_per_sec))
goto got_it;
}
find_other_zone:
- secno = find_next_zero_bit(free_i->free_secmap, TOTAL_SECS(sbi), hint);
- if (secno >= TOTAL_SECS(sbi)) {
+ secno = find_next_zero_bit(free_i->free_secmap, MAIN_SECS(sbi), hint);
+ if (secno >= MAIN_SECS(sbi)) {
if (dir == ALLOC_RIGHT) {
secno = find_next_zero_bit(free_i->free_secmap,
- TOTAL_SECS(sbi), 0);
- f2fs_bug_on(sbi, secno >= TOTAL_SECS(sbi));
+ MAIN_SECS(sbi), 0);
+ f2fs_bug_on(sbi, secno >= MAIN_SECS(sbi));
} else {
go_left = 1;
left_start = hint - 1;
@@ -732,8 +731,8 @@ find_other_zone:
continue;
}
left_start = find_next_zero_bit(free_i->free_secmap,
- TOTAL_SECS(sbi), 0);
- f2fs_bug_on(sbi, left_start >= TOTAL_SECS(sbi));
+ MAIN_SECS(sbi), 0);
+ f2fs_bug_on(sbi, left_start >= MAIN_SECS(sbi));
break;
}
secno = left_start;
@@ -946,26 +945,22 @@ static const struct segment_allocation default_salloc_ops = {
int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
{
- block_t start_addr = SM_I(sbi)->main_blkaddr;
__u64 start = range->start >> sbi->log_blocksize;
__u64 end = start + (range->len >> sbi->log_blocksize) - 1;
- __u64 segment = 1 << (sbi->log_blocksize + sbi->log_blocks_per_seg);
unsigned int start_segno, end_segno;
struct cp_control cpc;
- if (range->minlen > segment ||
- start >= SM_I(sbi)->seg0_blkaddr + TOTAL_BLKS(sbi) ||
- range->len < sbi->blocksize)
+ if (range->minlen > SEGMENT_SIZE(sbi) || start >= MAX_BLKADDR(sbi) ||
+ range->len < sbi->blocksize)
return -EINVAL;
- if (end <= start_addr)
+ if (end <= MAIN_BLKADDR(sbi))
goto out;
/* start/end segment number in main_area */
- start_segno = (start <= start_addr) ? 0 : GET_SEGNO(sbi, start);
- end_segno = (end >= SM_I(sbi)->seg0_blkaddr + TOTAL_BLKS(sbi)) ?
- TOTAL_SEGS(sbi) - 1 : GET_SEGNO(sbi, end);
-
+ start_segno = (start <= MAIN_BLKADDR(sbi)) ? 0 : GET_SEGNO(sbi, start);
+ end_segno = (end >= MAX_BLKADDR(sbi)) ? MAIN_SEGS(sbi) - 1 :
+ GET_SEGNO(sbi, end);
cpc.reason = CP_DISCARD;
cpc.trim_start = start_segno;
cpc.trim_end = end_segno;
@@ -1576,10 +1571,9 @@ static void add_sits_in_set(struct f2fs_sb_info *sbi)
struct f2fs_sm_info *sm_info = SM_I(sbi);
struct list_head *set_list = &sm_info->sit_entry_set;
unsigned long *bitmap = SIT_I(sbi)->dirty_sentries_bitmap;
- unsigned long nsegs = TOTAL_SEGS(sbi);
unsigned int segno;
- for_each_set_bit(segno, bitmap, nsegs)
+ for_each_set_bit(segno, bitmap, MAIN_SEGS(sbi))
add_sit_entry(segno, set_list);
}
@@ -1614,7 +1608,6 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
struct f2fs_summary_block *sum = curseg->sum_blk;
struct sit_entry_set *ses, *tmp;
struct list_head *head = &SM_I(sbi)->sit_entry_set;
- unsigned long nsegs = TOTAL_SEGS(sbi);
bool to_journal = true;
struct seg_entry *se;
@@ -1648,7 +1641,7 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
struct f2fs_sit_block *raw_sit = NULL;
unsigned int start_segno = ses->start_segno;
unsigned int end = min(start_segno + SIT_ENTRY_PER_BLOCK,
- nsegs);
+ (unsigned long)MAIN_SEGS(sbi));
unsigned int segno = start_segno;
if (to_journal &&
@@ -1727,16 +1720,16 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
SM_I(sbi)->sit_info = sit_i;
- sit_i->sentries = vzalloc(TOTAL_SEGS(sbi) * sizeof(struct seg_entry));
+ sit_i->sentries = vzalloc(MAIN_SEGS(sbi) * sizeof(struct seg_entry));
if (!sit_i->sentries)
return -ENOMEM;
- bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi));
+ bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
sit_i->dirty_sentries_bitmap = kzalloc(bitmap_size, GFP_KERNEL);
if (!sit_i->dirty_sentries_bitmap)
return -ENOMEM;
- for (start = 0; start < TOTAL_SEGS(sbi); start++) {
+ for (start = 0; start < MAIN_SEGS(sbi); start++) {
sit_i->sentries[start].cur_valid_map
= kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
sit_i->sentries[start].ckpt_valid_map
@@ -1747,7 +1740,7 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
}
if (sbi->segs_per_sec > 1) {
- sit_i->sec_entries = vzalloc(TOTAL_SECS(sbi) *
+ sit_i->sec_entries = vzalloc(MAIN_SECS(sbi) *
sizeof(struct sec_entry));
if (!sit_i->sec_entries)
return -ENOMEM;
@@ -1782,7 +1775,6 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
static int build_free_segmap(struct f2fs_sb_info *sbi)
{
- struct f2fs_sm_info *sm_info = SM_I(sbi);
struct free_segmap_info *free_i;
unsigned int bitmap_size, sec_bitmap_size;
@@ -1793,12 +1785,12 @@ static int build_free_segmap(struct f2fs_sb_info *sbi)
SM_I(sbi)->free_info = free_i;
- bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi));
+ bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
free_i->free_segmap = kmalloc(bitmap_size, GFP_KERNEL);
if (!free_i->free_segmap)
return -ENOMEM;
- sec_bitmap_size = f2fs_bitmap_size(TOTAL_SECS(sbi));
+ sec_bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi));
free_i->free_secmap = kmalloc(sec_bitmap_size, GFP_KERNEL);
if (!free_i->free_secmap)
return -ENOMEM;
@@ -1808,8 +1800,7 @@ static int build_free_segmap(struct f2fs_sb_info *sbi)
memset(free_i->free_secmap, 0xff, sec_bitmap_size);
/* init free segmap information */
- free_i->start_segno =
- (unsigned int) GET_SEGNO_FROM_SEG0(sbi, sm_info->main_blkaddr);
+ free_i->start_segno = GET_SEGNO_FROM_SEG0(sbi, MAIN_BLKADDR(sbi));
free_i->free_segments = 0;
free_i->free_sections = 0;
rwlock_init(&free_i->segmap_lock);
@@ -1854,7 +1845,7 @@ static void build_sit_entries(struct f2fs_sb_info *sbi)
start = start_blk * sit_i->sents_per_block;
end = (start_blk + readed) * sit_i->sents_per_block;
- for (; start < end && start < TOTAL_SEGS(sbi); start++) {
+ for (; start < end && start < MAIN_SEGS(sbi); start++) {
struct seg_entry *se = &sit_i->sentries[start];
struct f2fs_sit_block *sit_blk;
struct f2fs_sit_entry sit;
@@ -1892,7 +1883,7 @@ static void init_free_segmap(struct f2fs_sb_info *sbi)
unsigned int start;
int type;
- for (start = 0; start < TOTAL_SEGS(sbi); start++) {
+ for (start = 0; start < MAIN_SEGS(sbi); start++) {
struct seg_entry *sentry = get_seg_entry(sbi, start);
if (!sentry->valid_blocks)
__set_free(sbi, start);
@@ -1909,13 +1900,13 @@ static void init_dirty_segmap(struct f2fs_sb_info *sbi)
{
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
struct free_segmap_info *free_i = FREE_I(sbi);
- unsigned int segno = 0, offset = 0, total_segs = TOTAL_SEGS(sbi);
+ unsigned int segno = 0, offset = 0;
unsigned short valid_blocks;
while (1) {
/* find dirty segment based on free segmap */
- segno = find_next_inuse(free_i, total_segs, offset);
- if (segno >= total_segs)
+ segno = find_next_inuse(free_i, MAIN_SEGS(sbi), offset);
+ if (segno >= MAIN_SEGS(sbi))
break;
offset = segno + 1;
valid_blocks = get_valid_blocks(sbi, segno, 0);
@@ -1934,7 +1925,7 @@ static void init_dirty_segmap(struct f2fs_sb_info *sbi)
static int init_victim_secmap(struct f2fs_sb_info *sbi)
{
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
- unsigned int bitmap_size = f2fs_bitmap_size(TOTAL_SECS(sbi));
+ unsigned int bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi));
dirty_i->victim_secmap = kzalloc(bitmap_size, GFP_KERNEL);
if (!dirty_i->victim_secmap)
@@ -1955,7 +1946,7 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi)
SM_I(sbi)->dirty_info = dirty_i;
mutex_init(&dirty_i->seglist_lock);
- bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi));
+ bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
for (i = 0; i < NR_DIRTY_TYPE; i++) {
dirty_i->dirty_segmap[i] = kzalloc(bitmap_size, GFP_KERNEL);
@@ -1979,7 +1970,7 @@ static void init_min_max_mtime(struct f2fs_sb_info *sbi)
sit_i->min_mtime = LLONG_MAX;
- for (segno = 0; segno < TOTAL_SEGS(sbi); segno += sbi->segs_per_sec) {
+ for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
unsigned int i;
unsigned long long mtime = 0;
@@ -2122,7 +2113,7 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi)
return;
if (sit_i->sentries) {
- for (start = 0; start < TOTAL_SEGS(sbi); start++) {
+ for (start = 0; start < MAIN_SEGS(sbi); start++) {
kfree(sit_i->sentries[start].cur_valid_map);
kfree(sit_i->sentries[start].ckpt_valid_map);
}
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index 4588545..d080f55 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -45,16 +45,26 @@
(secno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \
sbi->segs_per_sec)) \
-#define START_BLOCK(sbi, segno) \
- (SM_I(sbi)->seg0_blkaddr + \
+#define MAIN_BLKADDR(sbi) (SM_I(sbi)->main_blkaddr)
+#define SEG0_BLKADDR(sbi) (SM_I(sbi)->seg0_blkaddr)
+
+#define MAIN_SEGS(sbi) (SM_I(sbi)->main_segments)
+#define MAIN_SECS(sbi) (sbi->total_sections)
+
+#define TOTAL_SEGS(sbi) (SM_I(sbi)->segment_count)
+#define TOTAL_BLKS(sbi) (TOTAL_SEGS(sbi) << sbi->log_blocks_per_seg)
+
+#define MAX_BLKADDR(sbi) (SEG0_BLKADDR(sbi) + TOTAL_BLKS(sbi))
+#define SEGMENT_SIZE(sbi) (1 << (sbi->log_blocksize + \
+ sbi->log_blocks_per_seg))
+
+#define START_BLOCK(sbi, segno) (SEG0_BLKADDR(sbi) + \
(GET_R2L_SEGNO(FREE_I(sbi), segno) << sbi->log_blocks_per_seg))
+
#define NEXT_FREE_BLKADDR(sbi, curseg) \
(START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff)
-#define MAIN_BASE_BLOCK(sbi) (SM_I(sbi)->main_blkaddr)
-
-#define GET_SEGOFF_FROM_SEG0(sbi, blk_addr) \
- ((blk_addr) - SM_I(sbi)->seg0_blkaddr)
+#define GET_SEGOFF_FROM_SEG0(sbi, blk_addr) ((blk_addr) - SEG0_BLKADDR(sbi))
#define GET_SEGNO_FROM_SEG0(sbi, blk_addr) \
(GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> sbi->log_blocks_per_seg)
#define GET_BLKOFF_FROM_SEG0(sbi, blk_addr) \
@@ -82,12 +92,9 @@
#define START_SEGNO(segno) \
(SIT_BLOCK_OFFSET(segno) * SIT_ENTRY_PER_BLOCK)
#define SIT_BLK_CNT(sbi) \
- ((TOTAL_SEGS(sbi) + SIT_ENTRY_PER_BLOCK - 1) / SIT_ENTRY_PER_BLOCK)
+ ((MAIN_SEGS(sbi) + SIT_ENTRY_PER_BLOCK - 1) / SIT_ENTRY_PER_BLOCK)
#define f2fs_bitmap_size(nr) \
(BITS_TO_LONGS(nr) * sizeof(unsigned long))
-#define TOTAL_SEGS(sbi) (SM_I(sbi)->main_segments)
-#define TOTAL_SECS(sbi) (sbi->total_sections)
-#define TOTAL_BLKS(sbi) (SM_I(sbi)->segment_count << sbi->log_blocks_per_seg)
#define SECTOR_FROM_BLOCK(blk_addr) \
(((sector_t)blk_addr) << F2FS_LOG_SECTORS_PER_BLOCK)
@@ -323,7 +330,7 @@ static inline void __set_free(struct f2fs_sb_info *sbi, unsigned int segno)
clear_bit(segno, free_i->free_segmap);
free_i->free_segments++;
- next = find_next_bit(free_i->free_segmap, TOTAL_SEGS(sbi), start_segno);
+ next = find_next_bit(free_i->free_segmap, MAIN_SEGS(sbi), start_segno);
if (next >= start_segno + sbi->segs_per_sec) {
clear_bit(secno, free_i->free_secmap);
free_i->free_sections++;
@@ -548,12 +555,8 @@ static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
{
- struct f2fs_sm_info *sm_info = SM_I(sbi);
- block_t total_blks = TOTAL_BLKS(sbi);
- block_t start_addr = sm_info->seg0_blkaddr;
- block_t end_addr = start_addr + total_blks - 1;
- BUG_ON(blk_addr < start_addr);
- BUG_ON(blk_addr > end_addr);
+ BUG_ON(blk_addr < SEG0_BLKADDR(sbi));
+ BUG_ON(blk_addr >= MAX_BLKADDR(sbi));
}
/*
@@ -601,12 +604,7 @@ static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
{
- struct f2fs_sm_info *sm_info = SM_I(sbi);
- block_t total_blks = TOTAL_BLKS(sbi);
- block_t start_addr = sm_info->seg0_blkaddr;
- block_t end_addr = start_addr + total_blks - 1;
-
- if (blk_addr < start_addr || blk_addr > end_addr)
+ if (blk_addr < SEG0_BLKADDR(sbi) || blk_addr >= MAX_BLKADDR(sbi))
sbi->need_fsck = true;
}
--
1.9.3 (Apple Git-50)
------------------------------------------------------------------------------
Meet PCI DSS 3.0 Compliance Requirements with EventLog Analyzer
Achieve PCI DSS 3.0 Compliant Status with Out-of-the-box PCI DSS Reports
Are you Audit-Ready for PCI DSS 3.0 Compliance? Download White paper
Comply to PCI DSS 3.0 Requirement 10 and 11.5 with EventLog Analyzer
http://pubads.g.doubleclick.net/gampad/clk?id=154622311&iu=/4140/ostg.clktrk
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/4] f2fs: support atomic_write feature for database
2014-09-26 4:54 [PATCH 1/4] f2fs: check the use of macros on block counts and addresses Jaegeuk Kim
@ 2014-09-26 4:54 ` Jaegeuk Kim
2014-09-30 6:19 ` [PATCH 2/4 v2] " Jaegeuk Kim
2014-09-26 4:54 ` [PATCH 3/4] f2fs: clean up f2fs_ioctl functions Jaegeuk Kim
` (2 subsequent siblings)
3 siblings, 1 reply; 7+ messages in thread
From: Jaegeuk Kim @ 2014-09-26 4:54 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, linux-f2fs-devel; +Cc: Jaegeuk Kim
This patch introduces a very limited functionality for atomic write support.
In order to support atomic write, this patch adds two ioctls:
o F2FS_IOC_ATOMIC_WRITE
o F2FS_IOC_ATOMIC_COMMIT
For F2FS_IOC_ATOMIC_WRITE, this patch introduces a data structure to communicate
with applications.
struct atmoic_w {
u64 aid; /* atomic write id */
const char __user *buf; /* user data */
u64 count; /* size to update */
u64 pos; /* file offset */
};
This is almost same as write() system call, and application can easily submit
any atomic data by calling
f2fs_ioctl(fd, F2FS_IOC_ATOMIC_WRITE, struct atomic_w *);
Then, data's page indices are recorded in the linked list, atomic_range list.
Later, f2fs_ioctl(fd, F2FS_IOC_ATOMIC_COMMIT, aid) trigger will flush all the
previous atomic data to the storage, which will be shown all or nothing by
f2fs recovery procedure.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
fs/f2fs/data.c | 7 ++++--
fs/f2fs/f2fs.h | 23 +++++++++++++++---
fs/f2fs/file.c | 55 ++++++++++++++++++++++++++++++++++++++++++
fs/f2fs/gc.c | 2 +-
fs/f2fs/inode.c | 4 ++++
fs/f2fs/segment.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/f2fs/segment.h | 12 ++++++++--
fs/f2fs/super.c | 1 +
8 files changed, 167 insertions(+), 8 deletions(-)
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 13ab7208..369f887 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -14,6 +14,7 @@
#include <linux/mpage.h>
#include <linux/aio.h>
#include <linux/writeback.h>
+#include <linux/mount.h>
#include <linux/backing-dev.h>
#include <linux/blkdev.h>
#include <linux/bio.h>
@@ -934,7 +935,6 @@ skip_write:
wbc->pages_skipped += get_dirty_pages(inode);
return 0;
}
-
static void f2fs_write_failed(struct address_space *mapping, loff_t to)
{
struct inode *inode = mapping->host;
@@ -1052,7 +1052,10 @@ static int f2fs_write_end(struct file *file,
trace_f2fs_write_end(inode, pos, len, copied);
- set_page_dirty(page);
+ if (is_inode_flag_set(F2FS_I(inode), FI_ATOMIC_FILE))
+ get_page(page);
+ else
+ set_page_dirty(page);
if (pos + copied > i_size_read(inode)) {
i_size_write(inode, pos + copied);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 94cfdc4..802ebf3 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -192,8 +192,19 @@ static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size,
/*
* ioctl commands
*/
-#define F2FS_IOC_GETFLAGS FS_IOC_GETFLAGS
-#define F2FS_IOC_SETFLAGS FS_IOC_SETFLAGS
+#define F2FS_IOC_GETFLAGS FS_IOC_GETFLAGS
+#define F2FS_IOC_SETFLAGS FS_IOC_SETFLAGS
+
+#define F2FS_IOCTL_MAGIC 0xf5
+#define F2FS_IOC_ATOMIC_WRITE _IOW(F2FS_IOCTL_MAGIC, 1, struct atomic_w)
+#define F2FS_IOC_ATOMIC_COMMIT _IOW(F2FS_IOCTL_MAGIC, 2, u64)
+
+struct atomic_w {
+ u64 aid; /* atomic write id */
+ const char __user *buf; /* user data */
+ u64 count; /* size to update */
+ u64 pos; /* file offset */
+};
#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
/*
@@ -263,6 +274,8 @@ struct f2fs_inode_info {
unsigned long long xattr_ver; /* cp version of xattr modification */
struct extent_info ext; /* in-memory extent cache entry */
struct dir_inode_entry *dirty_dir; /* the pointer of dirty dir */
+
+ struct list_head atomic_pages; /* atomic page indexes */
};
static inline void get_extent_info(struct extent_info *ext,
@@ -1051,7 +1064,8 @@ enum {
FI_INLINE_DATA, /* used for inline data*/
FI_APPEND_WRITE, /* inode has appended data */
FI_UPDATE_WRITE, /* inode has in-place-update data */
- FI_NEED_IPU, /* used fo ipu for fdatasync */
+ FI_NEED_IPU, /* used for ipu for fdatasync */
+ FI_ATOMIC_FILE, /* used for atomic writes support */
};
static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag)
@@ -1274,6 +1288,8 @@ void destroy_node_manager_caches(void);
/*
* segment.c
*/
+void prepare_atomic_pages(struct inode *, struct atomic_w *);
+void commit_atomic_pages(struct inode *, u64, bool);
void f2fs_balance_fs(struct f2fs_sb_info *);
void f2fs_balance_fs_bg(struct f2fs_sb_info *);
int f2fs_issue_flush(struct f2fs_sb_info *);
@@ -1355,6 +1371,7 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *, u64, u64);
/*
* gc.c
*/
+void move_data_page(struct inode *, struct page *, int);
int start_gc_thread(struct f2fs_sb_info *);
void stop_gc_thread(struct f2fs_sb_info *);
block_t start_bidx_of_node(unsigned int, struct f2fs_inode_info *);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 1184207..d7528c4 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -805,6 +805,57 @@ static inline __u32 f2fs_mask_flags(umode_t mode, __u32 flags)
return flags & F2FS_OTHER_FLMASK;
}
+static int f2fs_ioc_atomic_write(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ struct atomic_w aw;
+ loff_t pos;
+ int ret;
+
+ if (!inode_owner_or_capable(inode))
+ return -EACCES;
+
+ if (copy_from_user(&aw, (struct atomic_w __user *)arg, sizeof(aw)))
+ return -EFAULT;
+
+ ret = mnt_want_write_file(filp);
+ if (ret)
+ return ret;
+
+ pos = aw.pos;
+ set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
+ ret = vfs_write(filp, aw.buf, aw.count, &pos);
+ if (ret >= 0)
+ prepare_atomic_pages(inode, &aw);
+ else
+ clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
+
+ mnt_drop_write_file(filp);
+ return ret;
+}
+
+static int f2fs_ioc_atomic_commit(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ int ret;
+ u64 aid;
+
+ if (!inode_owner_or_capable(inode))
+ return -EACCES;
+
+ if (copy_from_user(&aid, (u64 __user *)arg, sizeof(u64)))
+ return -EFAULT;
+
+ ret = mnt_want_write_file(filp);
+ if (ret)
+ return ret;
+
+ commit_atomic_pages(inode, aid, false);
+ ret = f2fs_sync_file(filp, 0, LONG_MAX, 0);
+ mnt_drop_write_file(filp);
+ return ret;
+}
+
long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct inode *inode = file_inode(filp);
@@ -860,6 +911,10 @@ out:
mnt_drop_write_file(filp);
return ret;
}
+ case F2FS_IOC_ATOMIC_WRITE:
+ return f2fs_ioc_atomic_write(filp, arg);
+ case F2FS_IOC_ATOMIC_COMMIT:
+ return f2fs_ioc_atomic_commit(filp, arg);
case FITRIM:
{
struct super_block *sb = inode->i_sb;
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 2a8f4ac..1ce6e6c 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -520,7 +520,7 @@ static int check_dnode(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
return 1;
}
-static void move_data_page(struct inode *inode, struct page *page, int gc_type)
+void move_data_page(struct inode *inode, struct page *page, int gc_type)
{
struct f2fs_io_info fio = {
.type = DATA,
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index ff95547..62c5284 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -269,6 +269,10 @@ void f2fs_evict_inode(struct inode *inode)
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+ /* some remained atomic pages should discarded */
+ if (is_inode_flag_set(F2FS_I(inode), FI_ATOMIC_FILE))
+ commit_atomic_pages(inode, 0, true);
+
trace_f2fs_evict_inode(inode);
truncate_inode_pages_final(&inode->i_data);
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index d30cd16..6e3a405 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -26,6 +26,7 @@
static struct kmem_cache *discard_entry_slab;
static struct kmem_cache *sit_entry_set_slab;
+static struct kmem_cache *aw_entry_slab;
/*
* __reverse_ffs is copied from include/asm-generic/bitops/__ffs.h since
@@ -173,6 +174,70 @@ found_middle:
return result + __reverse_ffz(tmp);
}
+/* For atomic write support */
+void prepare_atomic_pages(struct inode *inode, struct atomic_w *aw)
+{
+ pgoff_t start = aw->pos >> PAGE_CACHE_SHIFT;
+ pgoff_t end = (aw->pos + aw->count + PAGE_CACHE_SIZE - 1) >>
+ PAGE_CACHE_SHIFT;
+ struct atomic_range *new;
+
+ new = f2fs_kmem_cache_alloc(aw_entry_slab, GFP_NOFS);
+
+ /* add atomic page indices to the list */
+ new->aid = aw->aid;
+ new->start = start;
+ new->end = end;
+ INIT_LIST_HEAD(&new->list);
+ list_add_tail(&new->list, &F2FS_I(inode)->atomic_pages);
+}
+
+void commit_atomic_pages(struct inode *inode, u64 aid, bool abort)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct atomic_range *cur, *tmp;
+ u64 start;
+ struct page *page;
+
+ if (abort)
+ goto release;
+
+ f2fs_balance_fs(sbi);
+ mutex_lock(&sbi->cp_mutex);
+
+ /* Step #1: write all the pages */
+ list_for_each_entry(cur, &F2FS_I(inode)->atomic_pages, list) {
+ if (cur->aid != aid)
+ continue;
+
+ for (start = cur->start; start < cur->end; start++) {
+ page = grab_cache_page(inode->i_mapping, start);
+ WARN_ON(!page);
+ move_data_page(inode, page, FG_GC);
+ }
+ }
+ f2fs_submit_merged_bio(sbi, DATA, WRITE);
+ mutex_unlock(&sbi->cp_mutex);
+release:
+ /* Step #2: wait for writeback */
+ list_for_each_entry_safe(cur, tmp, &F2FS_I(inode)->atomic_pages, list) {
+ if (cur->aid != aid && !abort)
+ continue;
+
+ for (start = cur->start; start < cur->end; start++) {
+ page = find_get_page(inode->i_mapping, start);
+ WARN_ON(!page);
+ wait_on_page_writeback(page);
+ f2fs_put_page(page, 0);
+
+ /* release reference got by atomic_write operation */
+ f2fs_put_page(page, 0);
+ }
+ list_del(&cur->list);
+ kmem_cache_free(aw_entry_slab, cur);
+ }
+}
+
/*
* This function balances dirty node and dentry pages.
* In addition, it controls garbage collection.
@@ -2153,8 +2218,14 @@ int __init create_segment_manager_caches(void)
sizeof(struct nat_entry_set));
if (!sit_entry_set_slab)
goto destory_discard_entry;
+ aw_entry_slab = f2fs_kmem_cache_create("atomic_entry",
+ sizeof(struct atomic_range));
+ if (!aw_entry_slab)
+ goto destroy_sit_entry_set;
return 0;
+destroy_sit_entry_set:
+ kmem_cache_destroy(sit_entry_set_slab);
destory_discard_entry:
kmem_cache_destroy(discard_entry_slab);
fail:
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index d080f55..393af7b 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -175,6 +175,13 @@ struct segment_allocation {
void (*allocate_segment)(struct f2fs_sb_info *, int, bool);
};
+struct atomic_range {
+ struct list_head list;
+ u64 aid;
+ pgoff_t start;
+ pgoff_t end;
+};
+
struct sit_info {
const struct segment_allocation *s_ops;
@@ -502,9 +509,10 @@ static inline bool need_inplace_update(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
unsigned int policy = SM_I(sbi)->ipu_policy;
+ struct f2fs_inode_info *fi = F2FS_I(inode);
/* IPU can be done only for the user data */
- if (S_ISDIR(inode->i_mode))
+ if (S_ISDIR(inode->i_mode) || is_inode_flag_set(fi, FI_ATOMIC_FILE))
return false;
if (policy & (0x1 << F2FS_IPU_FORCE))
@@ -520,7 +528,7 @@ static inline bool need_inplace_update(struct inode *inode)
/* this is only set during fdatasync */
if (policy & (0x1 << F2FS_IPU_FSYNC) &&
- is_inode_flag_set(F2FS_I(inode), FI_NEED_IPU))
+ is_inode_flag_set(fi, FI_NEED_IPU))
return true;
return false;
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index bb6b568..8915c77 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -373,6 +373,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
fi->i_advise = 0;
rwlock_init(&fi->ext.ext_lock);
init_rwsem(&fi->i_sem);
+ INIT_LIST_HEAD(&fi->atomic_pages);
set_inode_flag(fi, FI_NEW_INODE);
--
1.9.3 (Apple Git-50)
------------------------------------------------------------------------------
Meet PCI DSS 3.0 Compliance Requirements with EventLog Analyzer
Achieve PCI DSS 3.0 Compliant Status with Out-of-the-box PCI DSS Reports
Are you Audit-Ready for PCI DSS 3.0 Compliance? Download White paper
Comply to PCI DSS 3.0 Requirement 10 and 11.5 with EventLog Analyzer
http://pubads.g.doubleclick.net/gampad/clk?id=154622311&iu=/4140/ostg.clktrk
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/4 v2] f2fs: support atomic_write feature for database
2014-09-26 4:54 ` [PATCH 2/4] f2fs: support atomic_write feature for database Jaegeuk Kim
@ 2014-09-30 6:19 ` Jaegeuk Kim
2014-10-04 7:04 ` [f2fs-dev] " Jaegeuk Kim
0 siblings, 1 reply; 7+ messages in thread
From: Jaegeuk Kim @ 2014-09-30 6:19 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, linux-f2fs-devel
Change log from v1:
o change data structures to fix race conditions
This patch introduces a very limited functionality for atomic write support.
In order to support atomic write, this patch adds two ioctls:
o F2FS_IOC_ATOMIC_WRITE
o F2FS_IOC_ATOMIC_COMMIT
For F2FS_IOC_ATOMIC_WRITE, this patch introduces a data structure to communicate
with applications.
struct atmoic_w {
u64 aid; /* atomic write id */
const char __user *buf; /* user data */
u64 count; /* size to update */
u64 pos; /* file offset */
};
This is almost same as write() system call, and application can easily submit
any atomic data by calling
f2fs_ioctl(fd, F2FS_IOC_ATOMIC_WRITE, struct atomic_w *);
Then, data's page indices are recorded in the linked list, atomic_range list.
Later, f2fs_ioctl(fd, F2FS_IOC_ATOMIC_COMMIT, aid) trigger will flush all the
previous atomic data to the storage, which will be shown all or nothing by
f2fs recovery procedure.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
fs/f2fs/data.c | 6 +++-
fs/f2fs/f2fs.h | 25 +++++++++++--
fs/f2fs/file.c | 55 ++++++++++++++++++++++++++++
fs/f2fs/inode.c | 4 +++
fs/f2fs/segment.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/f2fs/segment.h | 11 ++++--
fs/f2fs/super.c | 3 ++
7 files changed, 204 insertions(+), 6 deletions(-)
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 13ab7208..c4f1f93 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -14,6 +14,7 @@
#include <linux/mpage.h>
#include <linux/aio.h>
#include <linux/writeback.h>
+#include <linux/mount.h>
#include <linux/backing-dev.h>
#include <linux/blkdev.h>
#include <linux/bio.h>
@@ -1052,7 +1053,10 @@ static int f2fs_write_end(struct file *file,
trace_f2fs_write_end(inode, pos, len, copied);
- set_page_dirty(page);
+ if (is_inode_flag_set(F2FS_I(inode), FI_ATOMIC_FILE))
+ prepare_atomic_page(inode, page);
+ else
+ set_page_dirty(page);
if (pos + copied > i_size_read(inode)) {
i_size_write(inode, pos + copied);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index a397f7a..ca8aa76 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -192,8 +192,19 @@ static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size,
/*
* ioctl commands
*/
-#define F2FS_IOC_GETFLAGS FS_IOC_GETFLAGS
-#define F2FS_IOC_SETFLAGS FS_IOC_SETFLAGS
+#define F2FS_IOC_GETFLAGS FS_IOC_GETFLAGS
+#define F2FS_IOC_SETFLAGS FS_IOC_SETFLAGS
+
+#define F2FS_IOCTL_MAGIC 0xf5
+#define F2FS_IOC_ATOMIC_WRITE _IOW(F2FS_IOCTL_MAGIC, 1, struct atomic_w)
+#define F2FS_IOC_ATOMIC_COMMIT _IOW(F2FS_IOCTL_MAGIC, 2, u64)
+
+struct atomic_w {
+ u64 aid; /* atomic write id */
+ const char __user *buf; /* user data */
+ u64 count; /* size to update */
+ u64 pos; /* file offset */
+};
#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
/*
@@ -263,6 +274,10 @@ struct f2fs_inode_info {
unsigned long long xattr_ver; /* cp version of xattr modification */
struct extent_info ext; /* in-memory extent cache entry */
struct dir_inode_entry *dirty_dir; /* the pointer of dirty dir */
+
+ struct list_head atomic_pages; /* atomic page indexes */
+ spinlock_t atomic_lock; /* lock for atomic pages */
+ struct radix_tree_root atomic_root; /* root of the atomic pages */
};
static inline void get_extent_info(struct extent_info *ext,
@@ -1051,7 +1066,8 @@ enum {
FI_INLINE_DATA, /* used for inline data*/
FI_APPEND_WRITE, /* inode has appended data */
FI_UPDATE_WRITE, /* inode has in-place-update data */
- FI_NEED_IPU, /* used fo ipu for fdatasync */
+ FI_NEED_IPU, /* used for ipu for fdatasync */
+ FI_ATOMIC_FILE, /* used for atomic writes support */
};
static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag)
@@ -1275,6 +1291,9 @@ void destroy_node_manager_caches(void);
/*
* segment.c
*/
+void register_atomic_pages(struct inode *, struct atomic_w *);
+void prepare_atomic_page(struct inode *, struct page *);
+void commit_atomic_pages(struct inode *, u64, bool);
void f2fs_balance_fs(struct f2fs_sb_info *);
void f2fs_balance_fs_bg(struct f2fs_sb_info *);
int f2fs_issue_flush(struct f2fs_sb_info *);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 735e9a2..a5a0bc7 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -862,6 +862,57 @@ out:
return ret;
}
+static int f2fs_ioc_atomic_write(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ struct atomic_w aw;
+ loff_t pos;
+ int ret;
+
+ if (!inode_owner_or_capable(inode))
+ return -EACCES;
+
+ if (copy_from_user(&aw, (struct atomic_w __user *)arg, sizeof(aw)))
+ return -EFAULT;
+
+ ret = mnt_want_write_file(filp);
+ if (ret)
+ return ret;
+
+ pos = aw.pos;
+ set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
+ ret = vfs_write(filp, aw.buf, aw.count, &pos);
+ if (ret >= 0)
+ register_atomic_pages(inode, &aw);
+ else
+ clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
+
+ mnt_drop_write_file(filp);
+ return ret;
+}
+
+static int f2fs_ioc_atomic_commit(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ int ret;
+ u64 aid;
+
+ if (!inode_owner_or_capable(inode))
+ return -EACCES;
+
+ if (copy_from_user(&aid, (u64 __user *)arg, sizeof(u64)))
+ return -EFAULT;
+
+ ret = mnt_want_write_file(filp);
+ if (ret)
+ return ret;
+
+ commit_atomic_pages(inode, aid, false);
+ ret = f2fs_sync_file(filp, 0, LONG_MAX, 0);
+ mnt_drop_write_file(filp);
+ return ret;
+}
+
static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
{
struct inode *inode = file_inode(filp);
@@ -899,6 +950,10 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return f2fs_ioc_getflags(filp, arg);
case F2FS_IOC_SETFLAGS:
return f2fs_ioc_setflags(filp, arg);
+ case F2FS_IOC_ATOMIC_WRITE:
+ return f2fs_ioc_atomic_write(filp, arg);
+ case F2FS_IOC_ATOMIC_COMMIT:
+ return f2fs_ioc_atomic_commit(filp, arg);
case FITRIM:
return f2fs_ioc_fitrim(filp, arg);
default:
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 63923ee..002036b 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -269,6 +269,10 @@ void f2fs_evict_inode(struct inode *inode)
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+ /* some remained atomic pages should discarded */
+ if (is_inode_flag_set(F2FS_I(inode), FI_ATOMIC_FILE))
+ commit_atomic_pages(inode, 0, true);
+
trace_f2fs_evict_inode(inode);
truncate_inode_pages_final(&inode->i_data);
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index d30cd16..a7cc250 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -26,6 +26,7 @@
static struct kmem_cache *discard_entry_slab;
static struct kmem_cache *sit_entry_set_slab;
+static struct kmem_cache *aw_entry_slab;
/*
* __reverse_ffs is copied from include/asm-generic/bitops/__ffs.h since
@@ -173,6 +174,104 @@ found_middle:
return result + __reverse_ffz(tmp);
}
+/* For atomic write support */
+void register_atomic_pages(struct inode *inode, struct atomic_w *aw)
+{
+ pgoff_t start = aw->pos >> PAGE_CACHE_SHIFT;
+ pgoff_t end = (aw->pos + aw->count + PAGE_CACHE_SIZE - 1) >>
+ PAGE_CACHE_SHIFT;
+ struct atomic_pages *cur;
+
+ spin_lock(&F2FS_I(inode)->atomic_lock);
+ list_for_each_entry(cur, &F2FS_I(inode)->atomic_pages, list)
+ if (cur->aid == (u64)current->pid &&
+ start <= cur->page->index &&
+ cur->page->index < end)
+ cur->aid = aw->aid;
+ spin_unlock(&F2FS_I(inode)->atomic_lock);
+}
+
+void prepare_atomic_page(struct inode *inode, struct page *page)
+{
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ struct atomic_pages *new;
+ int err;
+retry:
+ new = f2fs_kmem_cache_alloc(aw_entry_slab, GFP_NOFS);
+
+ /* add atomic page indices to the list */
+ new->aid = (u64)current->pid;
+ new->page = page;
+ get_page(page);
+ INIT_LIST_HEAD(&new->list);
+
+ /* increase reference count with clean state */
+ spin_lock(&fi->atomic_lock);
+ err = radix_tree_insert(&fi->atomic_root, page->index, new);
+ if (err == -EEXIST) {
+ f2fs_put_page(page, 0);
+ spin_unlock(&fi->atomic_lock);
+ kmem_cache_free(aw_entry_slab, new);
+ return;
+ } else if (err) {
+ spin_unlock(&fi->atomic_lock);
+ kmem_cache_free(aw_entry_slab, new);
+ goto retry;
+ }
+ list_add_tail(&new->list, &fi->atomic_pages);
+ spin_unlock(&fi->atomic_lock);
+}
+
+void commit_atomic_pages(struct inode *inode, u64 aid, bool abort)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ struct atomic_pages *cur, *tmp;
+ LIST_HEAD(target);
+ struct f2fs_io_info fio = {
+ .type = DATA,
+ .rw = WRITE_SYNC,
+ };
+
+ /* Step #1: move the pages to a temp list */
+ spin_lock(&fi->atomic_lock);
+ list_for_each_entry_safe(cur, tmp, &fi->atomic_pages, list) {
+ if (!abort && cur->aid != aid)
+ continue;
+ radix_tree_delete(&fi->atomic_root, cur->page->index);
+ list_move_tail(&cur->list, &target);
+ }
+ spin_unlock(&fi->atomic_lock);
+
+ if (abort)
+ goto release;
+
+ f2fs_balance_fs(sbi);
+ f2fs_lock_op(sbi);
+
+ /* Step #2: write all the pages */
+ list_for_each_entry(cur, &target, list) {
+ lock_page(cur->page);
+ f2fs_wait_on_page_writeback(cur->page, DATA);
+ if (clear_page_dirty_for_io(cur->page))
+ inode_dec_dirty_pages(inode);
+ do_write_data_page(cur->page, &fio);
+ unlock_page(cur->page);
+ }
+ f2fs_submit_merged_bio(sbi, DATA, WRITE);
+ f2fs_unlock_op(sbi);
+release:
+ /* Step #3: wait for writeback */
+ list_for_each_entry_safe(cur, tmp, &target, list) {
+ wait_on_page_writeback(cur->page);
+
+ /* release reference got by atomic_write operation */
+ f2fs_put_page(cur->page, 0);
+ list_del(&cur->list);
+ kmem_cache_free(aw_entry_slab, cur);
+ }
+}
+
/*
* This function balances dirty node and dentry pages.
* In addition, it controls garbage collection.
@@ -2153,8 +2252,14 @@ int __init create_segment_manager_caches(void)
sizeof(struct nat_entry_set));
if (!sit_entry_set_slab)
goto destory_discard_entry;
+ aw_entry_slab = f2fs_kmem_cache_create("atomic_entry",
+ sizeof(struct atomic_pages));
+ if (!aw_entry_slab)
+ goto destroy_sit_entry_set;
return 0;
+destroy_sit_entry_set:
+ kmem_cache_destroy(sit_entry_set_slab);
destory_discard_entry:
kmem_cache_destroy(discard_entry_slab);
fail:
@@ -2165,4 +2270,5 @@ void destroy_segment_manager_caches(void)
{
kmem_cache_destroy(sit_entry_set_slab);
kmem_cache_destroy(discard_entry_slab);
+ kmem_cache_destroy(aw_entry_slab);
}
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index d372dbf..5b68810 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -175,6 +175,12 @@ struct segment_allocation {
void (*allocate_segment)(struct f2fs_sb_info *, int, bool);
};
+struct atomic_pages {
+ struct list_head list;
+ u64 aid;
+ struct page *page;
+};
+
struct sit_info {
const struct segment_allocation *s_ops;
@@ -502,9 +508,10 @@ static inline bool need_inplace_update(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
unsigned int policy = SM_I(sbi)->ipu_policy;
+ struct f2fs_inode_info *fi = F2FS_I(inode);
/* IPU can be done only for the user data */
- if (S_ISDIR(inode->i_mode))
+ if (S_ISDIR(inode->i_mode) || is_inode_flag_set(fi, FI_ATOMIC_FILE))
return false;
if (policy & (0x1 << F2FS_IPU_FORCE))
@@ -520,7 +527,7 @@ static inline bool need_inplace_update(struct inode *inode)
/* this is only set during fdatasync */
if (policy & (0x1 << F2FS_IPU_FSYNC) &&
- is_inode_flag_set(F2FS_I(inode), FI_NEED_IPU))
+ is_inode_flag_set(fi, FI_NEED_IPU))
return true;
return false;
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index bb6b568..dbadfd2 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -373,6 +373,9 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
fi->i_advise = 0;
rwlock_init(&fi->ext.ext_lock);
init_rwsem(&fi->i_sem);
+ INIT_LIST_HEAD(&fi->atomic_pages);
+ spin_lock_init(&fi->atomic_lock);
+ INIT_RADIX_TREE(&fi->atomic_root, GFP_ATOMIC);
set_inode_flag(fi, FI_NEW_INODE);
--
2.1.1
------------------------------------------------------------------------------
Meet PCI DSS 3.0 Compliance Requirements with EventLog Analyzer
Achieve PCI DSS 3.0 Compliant Status with Out-of-the-box PCI DSS Reports
Are you Audit-Ready for PCI DSS 3.0 Compliance? Download White paper
Comply to PCI DSS 3.0 Requirement 10 and 11.5 with EventLog Analyzer
http://pubads.g.doubleclick.net/gampad/clk?id=154622311&iu=/4140/ostg.clktrk
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [f2fs-dev] [PATCH 2/4 v2] f2fs: support atomic_write feature for database
2014-09-30 6:19 ` [PATCH 2/4 v2] " Jaegeuk Kim
@ 2014-10-04 7:04 ` Jaegeuk Kim
0 siblings, 0 replies; 7+ messages in thread
From: Jaegeuk Kim @ 2014-10-04 7:04 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, linux-f2fs-devel
Change log from v2:
o change naming and add one more api
>From 148ec45e541b2d2b37b90f27286a3ee484866679 Mon Sep 17 00:00:00 2001
From: Jaegeuk Kim <jaegeuk@kernel.org>
Date: Thu, 25 Sep 2014 21:54:45 -0700
Subject: [PATCH] f2fs: support atomic operations for database
This patch introduces a very limited functionality for atomic write support.
In order to support atomic write, this patch adds two ioctls:
o F2FS_IOC_DB_OPEN
o F2FS_IOC_COMMIT
The database engine should be aware of the following sequence.
1. open
-> ioctl(F2FS_IOC_DB_OPEN);
2. writes
: all the written data will be treated as atomic pages.
3. commit
-> ioctl(F2FS_IOC_COMMIT);
: this flushes all the data blocks to the disk, which will be shown all or
nothing by f2fs recovery procedure.
The IO pattens should be:
CP | D D D D D D | FSYNC | D D D D | FSYNC ...
While supporting atomic writes for main database file, we can keep its journal
data temporarily in the page cache by the following sequence.
1. open
-> ioctl(F2FS_IOC_JOURNAL_OPEN);
2. writes
: keep all the data in the page cache.
3. flush to the database file with atomic writes
a. ioctl(F2FS_IOC_DB_OPEN);
b. writes
c. ioctl(F2FS_IOC_COMMIT);
4. close
-> drop the cached data
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
fs/f2fs/data.c | 9 ++++++-
fs/f2fs/f2fs.h | 27 ++++++++++++++++---
fs/f2fs/file.c | 55 ++++++++++++++++++++++++++++++++++++++
fs/f2fs/inline.c | 3 +++
fs/f2fs/inode.c | 4 +++
fs/f2fs/segment.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/f2fs/segment.h | 10 +++++--
fs/f2fs/super.c | 2 ++
8 files changed, 183 insertions(+), 6 deletions(-)
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 13ab7208..5869cfc 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -14,6 +14,7 @@
#include <linux/mpage.h>
#include <linux/aio.h>
#include <linux/writeback.h>
+#include <linux/mount.h>
#include <linux/backing-dev.h>
#include <linux/blkdev.h>
#include <linux/bio.h>
@@ -1052,7 +1053,10 @@ static int f2fs_write_end(struct file *file,
trace_f2fs_write_end(inode, pos, len, copied);
- set_page_dirty(page);
+ if (f2fs_is_db_file(inode))
+ register_db_page(inode, page);
+ else
+ set_page_dirty(page);
if (pos + copied > i_size_read(inode)) {
i_size_write(inode, pos + copied);
@@ -1116,6 +1120,9 @@ 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_db_file(inode))
+ invalidate_db_page(inode, page);
+
if (PageDirty(page))
inode_dec_dirty_pages(inode);
ClearPagePrivate(page);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index a397f7a..f424ae7 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -192,8 +192,13 @@ static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size,
/*
* ioctl commands
*/
-#define F2FS_IOC_GETFLAGS FS_IOC_GETFLAGS
-#define F2FS_IOC_SETFLAGS FS_IOC_SETFLAGS
+#define F2FS_IOC_GETFLAGS FS_IOC_GETFLAGS
+#define F2FS_IOC_SETFLAGS FS_IOC_SETFLAGS
+
+#define F2FS_IOCTL_MAGIC 0xf5
+#define F2FS_IOC_DB_OPEN _IO(F2FS_IOCTL_MAGIC, 1)
+#define F2FS_IOC_JOURNAL_OPEN _IO(F2FS_IOCTL_MAGIC, 2)
+#define F2FS_IOC_COMMIT _IO(F2FS_IOCTL_MAGIC, 3)
#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
/*
@@ -263,6 +268,9 @@ struct f2fs_inode_info {
unsigned long long xattr_ver; /* cp version of xattr modification */
struct extent_info ext; /* in-memory extent cache entry */
struct dir_inode_entry *dirty_dir; /* the pointer of dirty dir */
+
+ struct list_head db_pages; /* atomic page indexes */
+ struct mutex db_lock; /* lock for atomic pages */
};
static inline void get_extent_info(struct extent_info *ext,
@@ -1051,7 +1059,9 @@ enum {
FI_INLINE_DATA, /* used for inline data*/
FI_APPEND_WRITE, /* inode has appended data */
FI_UPDATE_WRITE, /* inode has in-place-update data */
- FI_NEED_IPU, /* used fo ipu for fdatasync */
+ FI_NEED_IPU, /* used for ipu for fdatasync */
+ FI_DB_FILE, /* indicate database file */
+ FI_JOURNAL_FILE, /* indicate journal file */
};
static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag)
@@ -1111,6 +1121,14 @@ static inline int f2fs_has_inline_xattr(struct inode *inode)
return is_inode_flag_set(F2FS_I(inode), FI_INLINE_XATTR);
}
+static inline bool f2fs_is_db_file(struct inode *inode)
+{
+ if (is_inode_flag_set(F2FS_I(inode), FI_DB_FILE) ||
+ is_inode_flag_set(F2FS_I(inode), FI_JOURNAL_FILE))
+ return true;
+ return false;
+}
+
static inline unsigned int addrs_per_inode(struct f2fs_inode_info *fi)
{
if (f2fs_has_inline_xattr(&fi->vfs_inode))
@@ -1275,6 +1293,9 @@ void destroy_node_manager_caches(void);
/*
* segment.c
*/
+void register_db_page(struct inode *, struct page *);
+void invalidate_db_page(struct inode *, struct page *);
+void commit_db_pages(struct inode *, bool);
void f2fs_balance_fs(struct f2fs_sb_info *);
void f2fs_balance_fs_bg(struct f2fs_sb_info *);
int f2fs_issue_flush(struct f2fs_sb_info *);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 735e9a2..de486ad 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -862,6 +862,55 @@ out:
return ret;
}
+static int f2fs_ioc_open_db_file(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);
+
+ set_inode_flag(F2FS_I(inode), FI_DB_FILE);
+
+ return f2fs_convert_inline_data(inode, MAX_INLINE_DATA + 1, NULL);
+}
+
+static int f2fs_ioc_open_journal_file(struct file *filp)
+{
+ struct inode *inode = file_inode(filp);
+
+ if (!inode_owner_or_capable(inode))
+ return -EACCES;
+
+ set_inode_flag(F2FS_I(inode), FI_JOURNAL_FILE);
+ return 0;
+}
+
+static int f2fs_ioc_commit(struct file *filp)
+{
+ struct inode *inode = file_inode(filp);
+ int ret;
+
+ if (!inode_owner_or_capable(inode))
+ return -EACCES;
+
+ if (is_inode_flag_set(F2FS_I(inode), FI_JOURNAL_FILE))
+ return 0;
+
+ ret = mnt_want_write_file(filp);
+ if (ret)
+ return ret;
+
+ if (is_inode_flag_set(F2FS_I(inode), FI_DB_FILE))
+ commit_db_pages(inode, false);
+
+ ret = f2fs_sync_file(filp, 0, LONG_MAX, 0);
+ mnt_drop_write_file(filp);
+ return ret;
+}
+
static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
{
struct inode *inode = file_inode(filp);
@@ -899,6 +948,12 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return f2fs_ioc_getflags(filp, arg);
case F2FS_IOC_SETFLAGS:
return f2fs_ioc_setflags(filp, arg);
+ case F2FS_IOC_DB_OPEN:
+ return f2fs_ioc_open_db_file(filp);
+ case F2FS_IOC_JOURNAL_OPEN:
+ return f2fs_ioc_open_journal_file(filp);
+ case F2FS_IOC_COMMIT:
+ return f2fs_ioc_commit(filp);
case FITRIM:
return f2fs_ioc_fitrim(filp, arg);
default:
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 6aef11d..b47377b 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -21,6 +21,9 @@ bool f2fs_may_inline(struct inode *inode)
if (!test_opt(F2FS_I_SB(inode), INLINE_DATA))
return false;
+ if (is_inode_flag_set(F2FS_I(inode), FI_DB_FILE))
+ return false;
+
nr_blocks = F2FS_I(inode)->i_xattr_nid ? 3 : 2;
if (inode->i_blocks > nr_blocks)
return false;
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 63923ee..23f718e 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -269,6 +269,10 @@ void f2fs_evict_inode(struct inode *inode)
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+ /* some remained atomic pages should discarded */
+ if (f2fs_is_db_file(inode))
+ commit_db_pages(inode, true);
+
trace_f2fs_evict_inode(inode);
truncate_inode_pages_final(&inode->i_data);
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 4d1c49a..b70e2ac 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -26,6 +26,7 @@
static struct kmem_cache *discard_entry_slab;
static struct kmem_cache *sit_entry_set_slab;
+static struct kmem_cache *aw_entry_slab;
/*
* __reverse_ffs is copied from include/asm-generic/bitops/__ffs.h since
@@ -173,6 +174,77 @@ found_middle:
return result + __reverse_ffz(tmp);
}
+/* For atomic write support */
+void register_db_page(struct inode *inode, struct page *page)
+{
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ struct db_pages *new;
+
+ new = f2fs_kmem_cache_alloc(aw_entry_slab, GFP_NOFS);
+
+ /* add atomic page indices to the list */
+ new->page = page;
+ INIT_LIST_HEAD(&new->list);
+
+ /* increase reference count with clean state */
+ mutex_lock(&fi->db_lock);
+ get_page(page);
+ list_add_tail(&new->list, &fi->db_pages);
+ mutex_unlock(&fi->db_lock);
+}
+
+void invalidate_db_page(struct inode *inode, struct page *page)
+{
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ struct db_pages *cur, *tmp;
+
+ mutex_lock(&fi->db_lock);
+ list_for_each_entry_safe(cur, tmp, &fi->db_pages, list) {
+ if (cur->page == page) {
+ put_page(page);
+ list_del(&cur->list);
+ kmem_cache_free(aw_entry_slab, cur);
+ }
+ }
+ mutex_unlock(&fi->db_lock);
+}
+
+void commit_db_pages(struct inode *inode, bool abort)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ struct db_pages *cur, *tmp;
+ bool submit_bio = false;
+ struct f2fs_io_info fio = {
+ .type = DATA,
+ .rw = WRITE_SYNC,
+ };
+
+ f2fs_balance_fs(sbi);
+ f2fs_lock_op(sbi);
+
+ mutex_lock(&fi->db_lock);
+ list_for_each_entry_safe(cur, tmp, &fi->db_pages, list) {
+ lock_page(cur->page);
+ if (!abort && cur->page->mapping == inode->i_mapping) {
+ f2fs_wait_on_page_writeback(cur->page, DATA);
+ if (clear_page_dirty_for_io(cur->page))
+ inode_dec_dirty_pages(inode);
+ do_write_data_page(cur->page, &fio);
+ submit_bio = true;
+ }
+ f2fs_put_page(cur->page, 1);
+ list_del(&cur->list);
+ kmem_cache_free(aw_entry_slab, cur);
+ }
+ if (submit_bio)
+ f2fs_submit_merged_bio(sbi, DATA, WRITE);
+ mutex_unlock(&fi->db_lock);
+
+ filemap_fdatawait_range(inode->i_mapping, 0, LLONG_MAX);
+ f2fs_unlock_op(sbi);
+}
+
/*
* This function balances dirty node and dentry pages.
* In addition, it controls garbage collection.
@@ -2148,8 +2220,14 @@ int __init create_segment_manager_caches(void)
sizeof(struct nat_entry_set));
if (!sit_entry_set_slab)
goto destory_discard_entry;
+ aw_entry_slab = f2fs_kmem_cache_create("db_page_entry",
+ sizeof(struct db_pages));
+ if (!aw_entry_slab)
+ goto destroy_sit_entry_set;
return 0;
+destroy_sit_entry_set:
+ kmem_cache_destroy(sit_entry_set_slab);
destory_discard_entry:
kmem_cache_destroy(discard_entry_slab);
fail:
@@ -2160,4 +2238,5 @@ void destroy_segment_manager_caches(void)
{
kmem_cache_destroy(sit_entry_set_slab);
kmem_cache_destroy(discard_entry_slab);
+ kmem_cache_destroy(aw_entry_slab);
}
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index afb7362..45583a9 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -175,6 +175,11 @@ struct segment_allocation {
void (*allocate_segment)(struct f2fs_sb_info *, int, bool);
};
+struct db_pages {
+ struct list_head list;
+ struct page *page;
+};
+
struct sit_info {
const struct segment_allocation *s_ops;
@@ -502,9 +507,10 @@ static inline bool need_inplace_update(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
unsigned int policy = SM_I(sbi)->ipu_policy;
+ struct f2fs_inode_info *fi = F2FS_I(inode);
/* IPU can be done only for the user data */
- if (S_ISDIR(inode->i_mode))
+ if (S_ISDIR(inode->i_mode) || is_inode_flag_set(fi, FI_DB_FILE))
return false;
if (policy & (0x1 << F2FS_IPU_FORCE))
@@ -520,7 +526,7 @@ static inline bool need_inplace_update(struct inode *inode)
/* this is only set during fdatasync */
if (policy & (0x1 << F2FS_IPU_FSYNC) &&
- is_inode_flag_set(F2FS_I(inode), FI_NEED_IPU))
+ is_inode_flag_set(fi, FI_NEED_IPU))
return true;
return false;
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index bb6b568..68a5047 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -373,6 +373,8 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
fi->i_advise = 0;
rwlock_init(&fi->ext.ext_lock);
init_rwsem(&fi->i_sem);
+ INIT_LIST_HEAD(&fi->db_pages);
+ mutex_init(&fi->db_lock);
set_inode_flag(fi, FI_NEW_INODE);
--
2.1.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/4] f2fs: clean up f2fs_ioctl functions
2014-09-26 4:54 [PATCH 1/4] f2fs: check the use of macros on block counts and addresses Jaegeuk Kim
2014-09-26 4:54 ` [PATCH 2/4] f2fs: support atomic_write feature for database Jaegeuk Kim
@ 2014-09-26 4:54 ` Jaegeuk Kim
2014-09-26 4:54 ` [PATCH 4/4] f2fs: call f2fs_unlock_op after error was handled Jaegeuk Kim
2014-09-30 6:19 ` [f2fs-dev] [PATCH 1/4] f2fs: check the use of macros on block counts and addresses Chao Yu
3 siblings, 0 replies; 7+ messages in thread
From: Jaegeuk Kim @ 2014-09-26 4:54 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, linux-f2fs-devel; +Cc: Jaegeuk Kim
This patch cleans up f2fs_ioctl functions for better readability.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
fs/f2fs/file.c | 168 ++++++++++++++++++++++++++++++---------------------------
1 file changed, 90 insertions(+), 78 deletions(-)
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index d7528c4..d203668 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -805,6 +805,93 @@ static inline __u32 f2fs_mask_flags(umode_t mode, __u32 flags)
return flags & F2FS_OTHER_FLMASK;
}
+static int f2fs_ioc_getflags(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ unsigned int flags = fi->i_flags & FS_FL_USER_VISIBLE;
+ return put_user(flags, (int __user *)arg);
+}
+
+static int f2fs_ioc_setflags(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ unsigned int flags = fi->i_flags & FS_FL_USER_VISIBLE;
+ unsigned int oldflags;
+ int ret;
+
+ ret = mnt_want_write_file(filp);
+ if (ret)
+ return ret;
+
+ if (!inode_owner_or_capable(inode)) {
+ ret = -EACCES;
+ goto out;
+ }
+
+ if (get_user(flags, (int __user *)arg)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ flags = f2fs_mask_flags(inode->i_mode, flags);
+
+ mutex_lock(&inode->i_mutex);
+
+ oldflags = fi->i_flags;
+
+ if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
+ if (!capable(CAP_LINUX_IMMUTABLE)) {
+ mutex_unlock(&inode->i_mutex);
+ ret = -EPERM;
+ goto out;
+ }
+ }
+
+ flags = flags & FS_FL_USER_MODIFIABLE;
+ flags |= oldflags & ~FS_FL_USER_MODIFIABLE;
+ fi->i_flags = flags;
+ mutex_unlock(&inode->i_mutex);
+
+ f2fs_set_inode_flags(inode);
+ inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+out:
+ mnt_drop_write_file(filp);
+ return ret;
+}
+
+static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ struct super_block *sb = inode->i_sb;
+ struct request_queue *q = bdev_get_queue(sb->s_bdev);
+ struct fstrim_range range;
+ int ret;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (!blk_queue_discard(q))
+ return -EOPNOTSUPP;
+
+ if (copy_from_user(&range, (struct fstrim_range __user *)arg,
+ sizeof(range)))
+ return -EFAULT;
+
+ range.minlen = max((unsigned int)range.minlen,
+ q->limits.discard_granularity);
+ ret = f2fs_trim_fs(F2FS_SB(sb), &range);
+ if (ret < 0)
+ return ret;
+
+ if (copy_to_user((struct fstrim_range __user *)arg, &range,
+ sizeof(range)))
+ return -EFAULT;
+ return 0;
+}
+
static int f2fs_ioc_atomic_write(struct file *filp, unsigned long arg)
{
struct inode *inode = file_inode(filp);
@@ -858,92 +945,17 @@ static int f2fs_ioc_atomic_commit(struct file *filp, unsigned long arg)
long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file_inode(filp);
- struct f2fs_inode_info *fi = F2FS_I(inode);
- unsigned int flags;
- int ret;
-
switch (cmd) {
case F2FS_IOC_GETFLAGS:
- flags = fi->i_flags & FS_FL_USER_VISIBLE;
- return put_user(flags, (int __user *) arg);
+ return f2fs_ioc_getflags(filp, arg);
case F2FS_IOC_SETFLAGS:
- {
- unsigned int oldflags;
-
- ret = mnt_want_write_file(filp);
- if (ret)
- return ret;
-
- if (!inode_owner_or_capable(inode)) {
- ret = -EACCES;
- goto out;
- }
-
- if (get_user(flags, (int __user *) arg)) {
- ret = -EFAULT;
- goto out;
- }
-
- flags = f2fs_mask_flags(inode->i_mode, flags);
-
- mutex_lock(&inode->i_mutex);
-
- oldflags = fi->i_flags;
-
- if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
- if (!capable(CAP_LINUX_IMMUTABLE)) {
- mutex_unlock(&inode->i_mutex);
- ret = -EPERM;
- goto out;
- }
- }
-
- flags = flags & FS_FL_USER_MODIFIABLE;
- flags |= oldflags & ~FS_FL_USER_MODIFIABLE;
- fi->i_flags = flags;
- mutex_unlock(&inode->i_mutex);
-
- f2fs_set_inode_flags(inode);
- inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty(inode);
-out:
- mnt_drop_write_file(filp);
- return ret;
- }
+ return f2fs_ioc_setflags(filp, arg);
case F2FS_IOC_ATOMIC_WRITE:
return f2fs_ioc_atomic_write(filp, arg);
case F2FS_IOC_ATOMIC_COMMIT:
return f2fs_ioc_atomic_commit(filp, arg);
case FITRIM:
- {
- struct super_block *sb = inode->i_sb;
- struct request_queue *q = bdev_get_queue(sb->s_bdev);
- struct fstrim_range range;
- int ret = 0;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if (!blk_queue_discard(q))
- return -EOPNOTSUPP;
-
- if (copy_from_user(&range, (struct fstrim_range __user *)arg,
- sizeof(range)))
- return -EFAULT;
-
- range.minlen = max((unsigned int)range.minlen,
- q->limits.discard_granularity);
- ret = f2fs_trim_fs(F2FS_SB(sb), &range);
- if (ret < 0)
- return ret;
-
- if (copy_to_user((struct fstrim_range __user *)arg, &range,
- sizeof(range)))
- return -EFAULT;
-
- return 0;
- }
+ return f2fs_ioc_fitrim(filp, arg);
default:
return -ENOTTY;
}
--
1.9.3 (Apple Git-50)
------------------------------------------------------------------------------
Meet PCI DSS 3.0 Compliance Requirements with EventLog Analyzer
Achieve PCI DSS 3.0 Compliant Status with Out-of-the-box PCI DSS Reports
Are you Audit-Ready for PCI DSS 3.0 Compliance? Download White paper
Comply to PCI DSS 3.0 Requirement 10 and 11.5 with EventLog Analyzer
http://pubads.g.doubleclick.net/gampad/clk?id=154622311&iu=/4140/ostg.clktrk
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/4] f2fs: call f2fs_unlock_op after error was handled
2014-09-26 4:54 [PATCH 1/4] f2fs: check the use of macros on block counts and addresses Jaegeuk Kim
2014-09-26 4:54 ` [PATCH 2/4] f2fs: support atomic_write feature for database Jaegeuk Kim
2014-09-26 4:54 ` [PATCH 3/4] f2fs: clean up f2fs_ioctl functions Jaegeuk Kim
@ 2014-09-26 4:54 ` Jaegeuk Kim
2014-09-30 6:19 ` [f2fs-dev] [PATCH 1/4] f2fs: check the use of macros on block counts and addresses Chao Yu
3 siblings, 0 replies; 7+ messages in thread
From: Jaegeuk Kim @ 2014-09-26 4:54 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, linux-f2fs-devel; +Cc: Jaegeuk Kim
This patch relocates f2fs_unlock_op in every directory operations to be called
after any error was processed.
Otherwise, the checkpoint can be entered with valid node ids without its
dentry when -ENOSPC is occurred.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
fs/f2fs/f2fs.h | 1 +
fs/f2fs/inode.c | 23 +++++++++++++++++++++++
fs/f2fs/namei.c | 32 +++++++++++---------------------
3 files changed, 35 insertions(+), 21 deletions(-)
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 802ebf3..fc66d1b 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1208,6 +1208,7 @@ void update_inode(struct inode *, struct page *);
void update_inode_page(struct inode *);
int f2fs_write_inode(struct inode *, struct writeback_control *);
void f2fs_evict_inode(struct inode *);
+void handle_failed_inode(struct inode *);
/*
* namei.c
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 62c5284..002036b 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -310,3 +310,26 @@ no_delete:
out_clear:
clear_inode(inode);
}
+
+/* caller should call f2fs_lock_op() */
+void handle_failed_inode(struct inode *inode)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
+ clear_nlink(inode);
+ make_bad_inode(inode);
+ unlock_new_inode(inode);
+
+ i_size_write(inode, 0);
+ if (F2FS_HAS_BLOCKS(inode))
+ f2fs_truncate(inode);
+
+ remove_inode_page(inode);
+ stat_dec_inline_inode(inode);
+
+ alloc_nid_failed(sbi, inode->i_ino);
+ f2fs_unlock_op(sbi);
+
+ /* iput will drop the inode object */
+ iput(inode);
+}
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index ba0779d..0d2526e 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -123,9 +123,9 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode);
- f2fs_unlock_op(sbi);
if (err)
goto out;
+ f2fs_unlock_op(sbi);
alloc_nid_done(sbi, ino);
@@ -133,9 +133,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
unlock_new_inode(inode);
return 0;
out:
- clear_nlink(inode);
- iget_failed(inode);
- alloc_nid_failed(sbi, ino);
+ handle_failed_inode(inode);
return err;
}
@@ -154,15 +152,16 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
set_inode_flag(F2FS_I(inode), FI_INC_LINK);
f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode);
- f2fs_unlock_op(sbi);
if (err)
goto out;
+ f2fs_unlock_op(sbi);
d_instantiate(dentry, inode);
return 0;
out:
clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
iput(inode);
+ f2fs_unlock_op(sbi);
return err;
}
@@ -253,9 +252,9 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode);
- f2fs_unlock_op(sbi);
if (err)
goto out;
+ f2fs_unlock_op(sbi);
err = page_symlink(inode, symname, symlen);
alloc_nid_done(sbi, inode->i_ino);
@@ -264,9 +263,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
unlock_new_inode(inode);
return err;
out:
- clear_nlink(inode);
- iget_failed(inode);
- alloc_nid_failed(sbi, inode->i_ino);
+ handle_failed_inode(inode);
return err;
}
@@ -290,9 +287,9 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
set_inode_flag(F2FS_I(inode), FI_INC_LINK);
f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode);
- f2fs_unlock_op(sbi);
if (err)
goto out_fail;
+ f2fs_unlock_op(sbi);
alloc_nid_done(sbi, inode->i_ino);
@@ -303,9 +300,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
out_fail:
clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
- clear_nlink(inode);
- iget_failed(inode);
- alloc_nid_failed(sbi, inode->i_ino);
+ handle_failed_inode(inode);
return err;
}
@@ -338,18 +333,16 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode);
- f2fs_unlock_op(sbi);
if (err)
goto out;
+ f2fs_unlock_op(sbi);
alloc_nid_done(sbi, inode->i_ino);
d_instantiate(dentry, inode);
unlock_new_inode(inode);
return 0;
out:
- clear_nlink(inode);
- iget_failed(inode);
- alloc_nid_failed(sbi, inode->i_ino);
+ handle_failed_inode(inode);
return err;
}
@@ -677,10 +670,7 @@ static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
release_out:
release_orphan_inode(sbi);
out:
- f2fs_unlock_op(sbi);
- clear_nlink(inode);
- iget_failed(inode);
- alloc_nid_failed(sbi, inode->i_ino);
+ handle_failed_inode(inode);
return err;
}
--
1.9.3 (Apple Git-50)
------------------------------------------------------------------------------
Meet PCI DSS 3.0 Compliance Requirements with EventLog Analyzer
Achieve PCI DSS 3.0 Compliant Status with Out-of-the-box PCI DSS Reports
Are you Audit-Ready for PCI DSS 3.0 Compliance? Download White paper
Comply to PCI DSS 3.0 Requirement 10 and 11.5 with EventLog Analyzer
http://pubads.g.doubleclick.net/gampad/clk?id=154622311&iu=/4140/ostg.clktrk
^ permalink raw reply related [flat|nested] 7+ messages in thread
* RE: [f2fs-dev] [PATCH 1/4] f2fs: check the use of macros on block counts and addresses
2014-09-26 4:54 [PATCH 1/4] f2fs: check the use of macros on block counts and addresses Jaegeuk Kim
` (2 preceding siblings ...)
2014-09-26 4:54 ` [PATCH 4/4] f2fs: call f2fs_unlock_op after error was handled Jaegeuk Kim
@ 2014-09-30 6:19 ` Chao Yu
3 siblings, 0 replies; 7+ messages in thread
From: Chao Yu @ 2014-09-30 6:19 UTC (permalink / raw)
To: 'Jaegeuk Kim'; +Cc: linux-kernel, linux-f2fs-devel
Hi Jaegeuk,
> -----Original Message-----
> From: Jaegeuk Kim [mailto:jaegeuk@kernel.org]
> Sent: Friday, September 26, 2014 12:55 PM
> To: linux-kernel@vger.kernel.org; linux-fsdevel@vger.kernel.org;
> linux-f2fs-devel@lists.sourceforge.net
> Cc: Jaegeuk Kim
> Subject: [f2fs-dev] [PATCH 1/4] f2fs: check the use of macros on block counts and addresses
>
> This patch cleans up the existing and new macros for readability.
>
> Rule is like this.
>
> ,-----------------------------------------> MAX_BLKADDR -,
> | ,------------- TOTAL_BLKS ----------------------------,
> | | |
> | ,- seg0_blkaddr ,----- sit/nat/ssa/main blkaddress |
> block | | (SEG0_BLKADDR) | | | | (e.g., MAIN_BLKADDR) |
> address 0..x................ a b c d .............................
> | |
> global seg# 0...................... m .............................
> | | |
> | `------- MAIN_SEGS -----------'
> `-------------- TOTAL_SEGS ---------------------------'
> | |
> seg# 0..........xx..................
>
> = Note =
> o GET_SEGNO_FROM_SEG0 : blk address -> global segno
> o GET_SEGNO : blk address -> segno
> o START_BLOCK : segno -> starting block address
>
> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Looks good!
Reviewed-by: Chao Yu <chao2.yu@samsung.com>
I see SM_I(sbi)->segment_count in check_seg_range/check_block_count still
not be instead with TOTAL_SEGS(sbi), how about insteading these together?
Regards,
Yu
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2014-10-04 7:04 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-09-26 4:54 [PATCH 1/4] f2fs: check the use of macros on block counts and addresses Jaegeuk Kim
2014-09-26 4:54 ` [PATCH 2/4] f2fs: support atomic_write feature for database Jaegeuk Kim
2014-09-30 6:19 ` [PATCH 2/4 v2] " Jaegeuk Kim
2014-10-04 7:04 ` [f2fs-dev] " Jaegeuk Kim
2014-09-26 4:54 ` [PATCH 3/4] f2fs: clean up f2fs_ioctl functions Jaegeuk Kim
2014-09-26 4:54 ` [PATCH 4/4] f2fs: call f2fs_unlock_op after error was handled Jaegeuk Kim
2014-09-30 6:19 ` [f2fs-dev] [PATCH 1/4] f2fs: check the use of macros on block counts and addresses Chao Yu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).