* [PATCH 1/6] libf2fs: enhance the bit operations
@ 2015-12-12 0:00 Jaegeuk Kim
2015-12-12 0:00 ` [PATCH 2/6] fsck.f2fs: sanity_check for extent_cache entry Jaegeuk Kim
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Jaegeuk Kim @ 2015-12-12 0:00 UTC (permalink / raw)
To: linux-f2fs-devel; +Cc: Jaegeuk Kim
This patch modifies the existing bit operations.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
fsck/fsck.c | 12 +++----
include/f2fs_fs.h | 23 ++++++++++--
lib/libf2fs.c | 104 ++++++++++++++++++++++++------------------------------
3 files changed, 73 insertions(+), 66 deletions(-)
diff --git a/fsck/fsck.c b/fsck/fsck.c
index c71f225..c81dde9 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -820,7 +820,7 @@ static void convert_encrypted_name(unsigned char *name, int len,
}
static void print_dentry(__u32 depth, __u8 *name,
- unsigned long *bitmap,
+ unsigned char *bitmap,
struct f2fs_dir_entry *dentry,
int max, int idx, int last_blk, int encrypted)
{
@@ -837,7 +837,7 @@ static void print_dentry(__u32 depth, __u8 *name,
name_len = le16_to_cpu(dentry[idx].name_len);
next_idx = idx + (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN;
- bit_offset = find_next_bit(bitmap, max, next_idx);
+ bit_offset = find_next_bit_le(bitmap, max, next_idx);
if (bit_offset >= max && last_blk)
last_de = 1;
@@ -889,7 +889,7 @@ static int f2fs_check_hash_code(struct f2fs_dir_entry *dentry,
}
static int __chk_dentries(struct f2fs_sb_info *sbi, struct child_info *child,
- unsigned long *bitmap,
+ unsigned char *bitmap,
struct f2fs_dir_entry *dentry,
__u8 (*filenames)[F2FS_SLOT_LEN],
int max, int last_blk, int encrypted)
@@ -946,7 +946,7 @@ static int __chk_dentries(struct f2fs_sb_info *sbi, struct child_info *child,
ftype = dentry[i].file_type;
if ((ftype <= F2FS_FT_UNKNOWN || ftype > F2FS_FT_LAST_FILE_TYPE)) {
- ASSERT_MSG("Bad dentry 0x%x with unexpected ftype 0x%x", i, ftype);
+ ASSERT_MSG("Bad dentry 0x%x with unexpected ftype 0x%x", ino, ftype);
if (config.fix_on) {
FIX_MSG("Clear bad dentry 0x%x with bad ftype 0x%x",
i, ftype);
@@ -1036,7 +1036,7 @@ int fsck_chk_inline_dentries(struct f2fs_sb_info *sbi,
fsck->dentry_depth++;
dentries = __chk_dentries(sbi, child,
- (unsigned long *)de_blk->dentry_bitmap,
+ de_blk->dentry_bitmap,
de_blk->dentry, de_blk->filename,
NR_INLINE_DENTRY, 1,
file_is_encrypt(node_blk->i.i_advise));
@@ -1068,7 +1068,7 @@ int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
fsck->dentry_depth++;
dentries = __chk_dentries(sbi, child,
- (unsigned long *)de_blk->dentry_bitmap,
+ de_blk->dentry_bitmap,
de_blk->dentry, de_blk->filename,
NR_DENTRY_IN_BLOCK, last_blk, encrypted);
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index a448d61..6fd4c80 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -320,6 +320,23 @@ struct f2fs_configuration {
})
/*
+ * Copied from include/linux/kernel.h
+ */
+#define __round_mask(x, y) ((__typeof__(x))((y)-1))
+#define round_down(x, y) ((x) & ~__round_mask(x, y))
+#define min(x, y) ({ \
+ typeof(x) _min1 = (x); \
+ typeof(y) _min2 = (y); \
+ (void) (&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
+
+#define max(x, y) ({ \
+ typeof(x) _max1 = (x); \
+ typeof(y) _max2 = (y); \
+ (void) (&_max1 == &_max2); \
+ _max1 > _max2 ? _max1 : _max2; })
+
+/*
* Copied from fs/f2fs/f2fs.h
*/
#define NR_CURSEG_DATA_TYPE (3)
@@ -834,8 +851,10 @@ extern int test_bit(unsigned int nr, const void * addr);
extern int f2fs_test_bit(unsigned int, const char *);
extern int f2fs_set_bit(unsigned int, char *);
extern int f2fs_clear_bit(unsigned int, char *);
-extern unsigned long find_next_bit(const unsigned long *,
- unsigned long, unsigned long);
+extern unsigned long find_next_bit_le(const unsigned char *, unsigned long,
+ unsigned long);
+extern unsigned long find_next_zero_bit_le(const unsigned char *, unsigned long,
+ unsigned long);
extern u_int32_t f2fs_cal_crc32(u_int32_t, void *, int);
extern int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len);
diff --git a/lib/libf2fs.c b/lib/libf2fs.c
index 0ac9994..307ad56 100644
--- a/lib/libf2fs.c
+++ b/lib/libf2fs.c
@@ -75,10 +75,10 @@ int get_bits_in_byte(unsigned char n)
return bits_in_byte[n];
}
-int set_bit(unsigned int nr,void * addr)
+int set_bit(unsigned int nr, void *addr)
{
- int mask, retval;
- unsigned char *ADDR = (unsigned char *) addr;
+ int mask, retval;
+ unsigned char *ADDR = (unsigned char *)addr;
ADDR += nr >> 3;
mask = 1 << ((nr & 0x07));
@@ -87,10 +87,10 @@ int set_bit(unsigned int nr,void * addr)
return retval;
}
-int clear_bit(unsigned int nr, void * addr)
+int clear_bit(unsigned int nr, void *addr)
{
- int mask, retval;
- unsigned char *ADDR = (unsigned char *) addr;
+ int mask, retval;
+ unsigned char *ADDR = (unsigned char *)addr;
ADDR += nr >> 3;
mask = 1 << ((nr & 0x07));
@@ -99,7 +99,7 @@ int clear_bit(unsigned int nr, void * addr)
return retval;
}
-int test_bit(unsigned int nr, const void * addr)
+int test_bit(unsigned int nr, const void *addr)
{
const __u32 *p = (const __u32 *)addr;
@@ -142,24 +142,10 @@ int f2fs_clear_bit(unsigned int nr, char *addr)
return ret;
}
-static inline unsigned long __ffs(unsigned long word)
+static inline unsigned long __ffs(unsigned char word)
{
int num = 0;
-#if BITS_PER_LONG == 64
- if ((word & 0xffffffff) == 0) {
- num += 32;
- word >>= 32;
- }
-#endif
- if ((word & 0xffff) == 0) {
- num += 16;
- word >>= 16;
- }
- if ((word & 0xff) == 0) {
- num += 8;
- word >>= 8;
- }
if ((word & 0xf) == 0) {
num += 4;
word >>= 4;
@@ -173,43 +159,45 @@ static inline unsigned long __ffs(unsigned long word)
return num;
}
-unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
- unsigned long offset)
+/* Copied from linux/lib/find_bit.c */
+#define BITMAP_FIRST_BYTE_MASK(start) (0xff << ((start) & (BITS_PER_BYTE - 1)))
+
+static unsigned long _find_next_bit_le(const unsigned char *addr,
+ unsigned long nbits, unsigned long start, char invert)
+{
+ unsigned char tmp;
+
+ if (!nbits || start >= nbits)
+ return nbits;
+
+ tmp = addr[start / BITS_PER_BYTE] ^ invert;
+
+ /* Handle 1st word. */
+ tmp &= BITMAP_FIRST_BYTE_MASK(start);
+ start = round_down(start, BITS_PER_BYTE);
+
+ while (!tmp) {
+ start += BITS_PER_BYTE;
+ if (start >= nbits)
+ return nbits;
+
+ tmp = addr[start / BITS_PER_BYTE] ^ invert;
+ }
+
+ return min(start + __ffs(tmp), nbits);
+}
+
+unsigned long find_next_bit_le(const unsigned char *addr, unsigned long size,
+ unsigned long offset)
+{
+ return _find_next_bit_le(addr, size, offset, 0);
+}
+
+
+unsigned long find_next_zero_bit_le(const unsigned char *addr,
+ unsigned long size, unsigned long offset)
{
- const unsigned long *p = addr + BIT_WORD(offset);
- unsigned long result = offset & ~(BITS_PER_LONG-1);
- unsigned long tmp;
-
- if (offset >= size)
- return size;
- size -= result;
- offset %= BITS_PER_LONG;
- if (offset) {
- tmp = *(p++);
- tmp &= (~0UL << offset);
- if (size < BITS_PER_LONG)
- goto found_first;
- if (tmp)
- goto found_middle;
- size -= BITS_PER_LONG;
- result += BITS_PER_LONG;
- }
- while (size & ~(BITS_PER_LONG-1)) {
- if ((tmp = *(p++)))
- goto found_middle;
- result += BITS_PER_LONG;
- size -= BITS_PER_LONG;
- }
- if (!size)
- return result;
- tmp = *p;
-
-found_first:
- tmp &= (~0UL >> (BITS_PER_LONG - size));
- if (tmp == 0UL) /* Are any bits set? */
- return result + size; /* Nope. */
-found_middle:
- return result + __ffs(tmp);
+ return _find_next_bit_le(addr, size, offset, 0xff);
}
/*
--
2.5.4 (Apple Git-61)
------------------------------------------------------------------------------
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/6] fsck.f2fs: sanity_check for extent_cache entry
2015-12-12 0:00 [PATCH 1/6] libf2fs: enhance the bit operations Jaegeuk Kim
@ 2015-12-12 0:00 ` Jaegeuk Kim
2015-12-12 0:00 ` [PATCH 3/6] mkfs.f2fs: export get_best_overprovision Jaegeuk Kim
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Jaegeuk Kim @ 2015-12-12 0:00 UTC (permalink / raw)
To: linux-f2fs-devel; +Cc: Jaegeuk Kim
This patch adds to check the stored extent_cache entry is consistent or not.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
fsck/fsck.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++--------------
fsck/fsck.h | 17 +++++++++---
fsck/main.c | 2 +-
3 files changed, 82 insertions(+), 24 deletions(-)
diff --git a/fsck/fsck.c b/fsck/fsck.c
index c81dde9..adc61d2 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -468,7 +468,8 @@ out:
int fsck_chk_node_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
u32 nid, u8 *name, enum FILE_TYPE ftype, enum NODE_TYPE ntype,
- u32 *blk_cnt, struct child_info *child)
+ u32 *blk_cnt, struct child_info *child,
+ struct extent_info *i_ext)
{
struct node_info ni;
struct f2fs_node *node_blk = NULL;
@@ -487,19 +488,19 @@ int fsck_chk_node_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
f2fs_set_main_bitmap(sbi, ni.blk_addr,
CURSEG_WARM_NODE);
fsck_chk_dnode_blk(sbi, inode, nid, ftype, node_blk,
- blk_cnt, child, &ni);
+ blk_cnt, child, &ni, i_ext);
break;
case TYPE_INDIRECT_NODE:
f2fs_set_main_bitmap(sbi, ni.blk_addr,
CURSEG_COLD_NODE);
fsck_chk_idnode_blk(sbi, inode, ftype, node_blk,
- blk_cnt, child);
+ blk_cnt, child, i_ext);
break;
case TYPE_DOUBLE_INDIRECT_NODE:
f2fs_set_main_bitmap(sbi, ni.blk_addr,
CURSEG_COLD_NODE);
fsck_chk_didnode_blk(sbi, inode, ftype, node_blk,
- blk_cnt, child);
+ blk_cnt, child, i_ext);
break;
default:
ASSERT(0);
@@ -512,6 +513,26 @@ err:
return -EINVAL;
}
+static void update_i_extent(struct extent_info *i_ext, block_t blkaddr)
+{
+ block_t end_addr;
+
+ if (!i_ext)
+ return;
+
+ end_addr = i_ext->ext.blk_addr + i_ext->ext.len;
+
+ /* TODO: check its file offset later */
+ if (blkaddr >= i_ext->ext.blk_addr && blkaddr < end_addr) {
+ unsigned int offset = blkaddr - i_ext->ext.blk_addr;
+
+ if (f2fs_set_bit(offset, i_ext->map))
+ i_ext->fail = 1;
+ else
+ i_ext->len--;
+ }
+}
+
/* start with valid nid and blkaddr */
void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
enum FILE_TYPE ftype, struct f2fs_node *node_blk,
@@ -522,6 +543,7 @@ void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
enum NODE_TYPE ntype;
u32 i_links = le32_to_cpu(node_blk->i.i_links);
u64 i_blocks = le64_to_cpu(node_blk->i.i_blocks);
+ struct extent_info i_extent;
unsigned int idx = 0;
int need_fix = 0;
int ret;
@@ -619,16 +641,28 @@ void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
}
}
+ i_extent.ext = node_blk->i.i_ext;
+ i_extent.len = le32_to_cpu(i_extent.ext.len);
+ i_extent.fail = 0;
+ if (i_extent.len) {
+ /* max 126KB */
+ i_extent.map = calloc(i_extent.len, 1);
+ ASSERT(i_extent.map != NULL);
+ }
+
/* check data blocks in inode */
for (idx = 0; idx < ADDRS_PER_INODE(&node_blk->i); idx++) {
- if (le32_to_cpu(node_blk->i.i_addr[idx]) != 0) {
+ block_t blkaddr = le32_to_cpu(node_blk->i.i_addr[idx]);
+
+ if (blkaddr != 0) {
ret = fsck_chk_data_blk(sbi,
- le32_to_cpu(node_blk->i.i_addr[idx]),
+ blkaddr,
&child, (i_blocks == *blk_cnt),
ftype, nid, idx, ni->version,
file_is_encrypt(node_blk->i.i_advise));
if (!ret) {
*blk_cnt = *blk_cnt + 1;
+ update_i_extent(&i_extent, blkaddr);
} else if (config.fix_on) {
node_blk->i.i_addr[idx] = 0;
need_fix = 1;
@@ -639,6 +673,8 @@ void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
/* check node blocks in inode */
for (idx = 0; idx < 5; idx++) {
+ block_t blkaddr = le32_to_cpu(node_blk->i.i_nid[idx]);
+
if (idx == 0 || idx == 1)
ntype = TYPE_DIRECT_NODE;
else if (idx == 2 || idx == 3)
@@ -648,10 +684,11 @@ void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
else
ASSERT(0);
- if (le32_to_cpu(node_blk->i.i_nid[idx]) != 0) {
+ if (blkaddr != 0) {
ret = fsck_chk_node_blk(sbi, &node_blk->i,
- le32_to_cpu(node_blk->i.i_nid[idx]),
- NULL, ftype, ntype, blk_cnt, &child);
+ blkaddr,
+ NULL, ftype, ntype, blk_cnt, &child,
+ &i_extent);
if (!ret) {
*blk_cnt = *blk_cnt + 1;
} else if (config.fix_on) {
@@ -661,6 +698,12 @@ void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
}
}
}
+ if (i_extent.len || i_extent.fail) {
+ ASSERT_MSG("ino: 0x%x has wrong ext: untouched=%d, overlap=%d",
+ nid, i_extent.len, i_extent.fail);
+ if (config.fix_on)
+ need_fix = 1;
+ }
check:
if (i_blocks != *blk_cnt) {
ASSERT_MSG("ino: 0x%x has i_blocks: %08"PRIx64", "
@@ -729,21 +772,25 @@ skip_blkcnt_fix:
int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk,
- u32 *blk_cnt, struct child_info *child, struct node_info *ni)
+ u32 *blk_cnt, struct child_info *child, struct node_info *ni,
+ struct extent_info *i_ext)
{
int idx, ret;
int need_fix = 0;
for (idx = 0; idx < ADDRS_PER_BLOCK; idx++) {
- if (le32_to_cpu(node_blk->dn.addr[idx]) == 0x0)
+ block_t blkaddr = le32_to_cpu(node_blk->dn.addr[idx]);
+
+ if (blkaddr == 0x0)
continue;
ret = fsck_chk_data_blk(sbi,
- le32_to_cpu(node_blk->dn.addr[idx]),
- child, le64_to_cpu(inode->i_blocks) == *blk_cnt, ftype,
+ blkaddr, child,
+ le64_to_cpu(inode->i_blocks) == *blk_cnt, ftype,
nid, idx, ni->version,
file_is_encrypt(inode->i_advise));
if (!ret) {
*blk_cnt = *blk_cnt + 1;
+ update_i_extent(i_ext, blkaddr);
} else if (config.fix_on) {
node_blk->dn.addr[idx] = 0;
need_fix = 1;
@@ -759,7 +806,7 @@ int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt,
- struct child_info *child)
+ struct child_info *child, struct extent_info *i_ext)
{
int ret;
int i = 0;
@@ -769,7 +816,8 @@ int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
continue;
ret = fsck_chk_node_blk(sbi, inode,
le32_to_cpu(node_blk->in.nid[i]), NULL,
- ftype, TYPE_DIRECT_NODE, blk_cnt, child);
+ ftype, TYPE_DIRECT_NODE, blk_cnt, child,
+ i_ext);
if (!ret)
*blk_cnt = *blk_cnt + 1;
else if (ret == -EINVAL)
@@ -780,7 +828,7 @@ int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt,
- struct child_info *child)
+ struct child_info *child, struct extent_info *i_ext)
{
int i = 0;
int ret = 0;
@@ -790,7 +838,8 @@ int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
continue;
ret = fsck_chk_node_blk(sbi, inode,
le32_to_cpu(node_blk->in.nid[i]), NULL,
- ftype, TYPE_INDIRECT_NODE, blk_cnt, child);
+ ftype, TYPE_INDIRECT_NODE, blk_cnt, child,
+ i_ext);
if (!ret)
*blk_cnt = *blk_cnt + 1;
else if (ret == -EINVAL)
@@ -999,7 +1048,7 @@ static int __chk_dentries(struct f2fs_sb_info *sbi, struct child_info *child,
blk_cnt = 1;
ret = fsck_chk_node_blk(sbi,
NULL, le32_to_cpu(dentry[i].ino), name,
- ftype, TYPE_INODE, &blk_cnt, NULL);
+ ftype, TYPE_INODE, &blk_cnt, NULL, NULL);
if (ret && config.fix_on) {
int j;
@@ -1165,7 +1214,7 @@ void fsck_chk_orphan_node(struct f2fs_sb_info *sbi)
blk_cnt = 1;
ret = fsck_chk_node_blk(sbi, NULL, ino, NULL,
F2FS_FT_ORPHAN, TYPE_INODE, &blk_cnt,
- NULL);
+ NULL, NULL);
if (!ret)
new_blk->ino[new_entry_count++] =
orphan_blk->ino[j];
diff --git a/fsck/fsck.h b/fsck/fsck.h
index 37a25ba..20dfe6b 100644
--- a/fsck/fsck.h
+++ b/fsck/fsck.h
@@ -25,6 +25,13 @@ struct child_info {
u8 dots;
};
+struct extent_info {
+ struct f2fs_extent ext;
+ char *map;
+ int len;
+ int fail;
+};
+
struct f2fs_fsck {
struct f2fs_sb_info sbi;
@@ -88,16 +95,18 @@ enum seg_type {
extern void fsck_chk_orphan_node(struct f2fs_sb_info *);
extern int fsck_chk_node_blk(struct f2fs_sb_info *, struct f2fs_inode *, u32,
u8 *, enum FILE_TYPE, enum NODE_TYPE, u32 *,
- struct child_info *);
+ struct child_info *, struct extent_info *);
extern void fsck_chk_inode_blk(struct f2fs_sb_info *, u32, enum FILE_TYPE,
struct f2fs_node *, u32 *, struct node_info *);
extern int fsck_chk_dnode_blk(struct f2fs_sb_info *, struct f2fs_inode *,
u32, enum FILE_TYPE, struct f2fs_node *, u32 *,
- struct child_info *, struct node_info *);
+ struct child_info *, struct node_info *, struct extent_info *);
extern int fsck_chk_idnode_blk(struct f2fs_sb_info *, struct f2fs_inode *,
- enum FILE_TYPE, struct f2fs_node *, u32 *, struct child_info *);
+ enum FILE_TYPE, struct f2fs_node *, u32 *, struct child_info *,
+ struct extent_info *);
extern int fsck_chk_didnode_blk(struct f2fs_sb_info *, struct f2fs_inode *,
- enum FILE_TYPE, struct f2fs_node *, u32 *, struct child_info *);
+ enum FILE_TYPE, struct f2fs_node *, u32 *, struct child_info *,
+ struct extent_info *);
extern int fsck_chk_data_blk(struct f2fs_sb_info *sbi, u32, struct child_info *,
int, enum FILE_TYPE, u32, u16, u8, int);
extern int fsck_chk_dentry_blk(struct f2fs_sb_info *, u32, struct child_info *,
diff --git a/fsck/main.c b/fsck/main.c
index 3db4a44..6b0d97e 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -155,7 +155,7 @@ static void do_fsck(struct f2fs_sb_info *sbi)
/* Traverse all block recursively from root inode */
blk_cnt = 1;
fsck_chk_node_blk(sbi, NULL, sbi->root_ino_num, (u8 *)"/",
- F2FS_FT_DIR, TYPE_INODE, &blk_cnt, NULL);
+ F2FS_FT_DIR, TYPE_INODE, &blk_cnt, NULL, NULL);
fsck_verify(sbi);
fsck_free(sbi);
}
--
2.5.4 (Apple Git-61)
------------------------------------------------------------------------------
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/6] mkfs.f2fs: export get_best_overprovision
2015-12-12 0:00 [PATCH 1/6] libf2fs: enhance the bit operations Jaegeuk Kim
2015-12-12 0:00 ` [PATCH 2/6] fsck.f2fs: sanity_check for extent_cache entry Jaegeuk Kim
@ 2015-12-12 0:00 ` Jaegeuk Kim
2015-12-12 0:00 ` [PATCH 4/6] f2fs-tools: export print_raw_sb_info Jaegeuk Kim
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Jaegeuk Kim @ 2015-12-12 0:00 UTC (permalink / raw)
To: linux-f2fs-devel; +Cc: Jaegeuk Kim
This patch exports get_best_overprovision() function.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
include/f2fs_fs.h | 28 ++++++++++++++++++++++++++++
mkfs/f2fs_format.c | 30 +-----------------------------
2 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index 6fd4c80..bbdeb51 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -886,4 +886,32 @@ extern struct f2fs_configuration config;
#define ZONE_ALIGN(blks) ALIGN(blks, config.blks_per_seg * \
config.segs_per_zone)
+static inline double get_best_overprovision(struct f2fs_super_block *sb)
+{
+ double reserved, ovp, candidate, end, diff, space;
+ double max_ovp = 0, max_space = 0;
+
+ if (get_sb(segment_count_main) < 256) {
+ candidate = 10;
+ end = 95;
+ diff = 5;
+ } else {
+ candidate = 0.01;
+ end = 10;
+ diff = 0.01;
+ }
+
+ for (; candidate <= end; candidate += diff) {
+ reserved = (2 * (100 / candidate + 1) + 6) *
+ get_sb(segs_per_sec);
+ ovp = (get_sb(segment_count_main) - reserved) * candidate / 100;
+ space = get_sb(segment_count_main) - reserved - ovp;
+ if (max_space < space) {
+ max_space = space;
+ max_ovp = candidate;
+ }
+ }
+ return max_ovp;
+}
+
#endif /*__F2FS_FS_H */
diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c
index b0c12f2..c4b17de 100644
--- a/mkfs/f2fs_format.c
+++ b/mkfs/f2fs_format.c
@@ -117,34 +117,6 @@ next:
free(config.extension_list);
}
-static double get_best_overprovision(void)
-{
- double reserved, ovp, candidate, end, diff, space;
- double max_ovp = 0, max_space = 0;
-
- if (get_sb(segment_count_main) < 256) {
- candidate = 10;
- end = 95;
- diff = 5;
- } else {
- candidate = 0.01;
- end = 10;
- diff = 0.01;
- }
-
- for (; candidate <= end; candidate += diff) {
- reserved = (2 * (100 / candidate + 1) + 6) *
- get_sb(segs_per_sec);
- ovp = (get_sb(segment_count_main) - reserved) * candidate / 100;
- space = get_sb(segment_count_main) - reserved - ovp;
- if (max_space < space) {
- max_space = space;
- max_ovp = candidate;
- }
- }
- return max_ovp;
-}
-
static int f2fs_prepare_super_block(void)
{
u_int32_t blk_size_bytes;
@@ -302,7 +274,7 @@ static int f2fs_prepare_super_block(void)
/* Let's determine the best reserved and overprovisioned space */
if (config.overprovision == 0)
- config.overprovision = get_best_overprovision();
+ config.overprovision = get_best_overprovision(sb);
config.reserved_segments =
(2 * (100 / config.overprovision + 1) + 6)
--
2.5.4 (Apple Git-61)
------------------------------------------------------------------------------
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 4/6] f2fs-tools: export print_raw_sb_info
2015-12-12 0:00 [PATCH 1/6] libf2fs: enhance the bit operations Jaegeuk Kim
2015-12-12 0:00 ` [PATCH 2/6] fsck.f2fs: sanity_check for extent_cache entry Jaegeuk Kim
2015-12-12 0:00 ` [PATCH 3/6] mkfs.f2fs: export get_best_overprovision Jaegeuk Kim
@ 2015-12-12 0:00 ` Jaegeuk Kim
2015-12-12 0:00 ` [PATCH 5/6] fsck.f2fs: LFS alloc_type must have free segment after blkoff Jaegeuk Kim
2015-12-12 0:00 ` [PATCH 6/6] defrag.f2fs: introduce defragmentation tool Jaegeuk Kim
4 siblings, 0 replies; 6+ messages in thread
From: Jaegeuk Kim @ 2015-12-12 0:00 UTC (permalink / raw)
To: linux-f2fs-devel; +Cc: Jaegeuk Kim
This patch exports print_raw_sb_info().
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
fsck/fsck.h | 2 ++
fsck/mount.c | 6 ++----
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/fsck/fsck.h b/fsck/fsck.h
index 20dfe6b..f6b8c53 100644
--- a/fsck/fsck.h
+++ b/fsck/fsck.h
@@ -132,6 +132,8 @@ extern void fsck_free(struct f2fs_sb_info *);
extern int f2fs_do_mount(struct f2fs_sb_info *);
extern void f2fs_do_umount(struct f2fs_sb_info *);
+extern void print_raw_sb_info(struct f2fs_super_block *);
+
/* dump.c */
struct dump_option {
nid_t nid;
diff --git a/fsck/mount.c b/fsck/mount.c
index 9431cd0..99e2439 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -99,10 +99,8 @@ void print_node_info(struct f2fs_node *node_block)
}
}
-void print_raw_sb_info(struct f2fs_sb_info *sbi)
+void print_raw_sb_info(struct f2fs_super_block *sb)
{
- struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
-
if (!config.dbg_lv)
return;
@@ -1292,7 +1290,7 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi)
return -1;
}
- print_raw_sb_info(sbi);
+ print_raw_sb_info(F2FS_RAW_SUPER(sbi));
init_sb_info(sbi);
--
2.5.4 (Apple Git-61)
------------------------------------------------------------------------------
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 5/6] fsck.f2fs: LFS alloc_type must have free segment after blkoff
2015-12-12 0:00 [PATCH 1/6] libf2fs: enhance the bit operations Jaegeuk Kim
` (2 preceding siblings ...)
2015-12-12 0:00 ` [PATCH 4/6] f2fs-tools: export print_raw_sb_info Jaegeuk Kim
@ 2015-12-12 0:00 ` Jaegeuk Kim
2015-12-12 0:00 ` [PATCH 6/6] defrag.f2fs: introduce defragmentation tool Jaegeuk Kim
4 siblings, 0 replies; 6+ messages in thread
From: Jaegeuk Kim @ 2015-12-12 0:00 UTC (permalink / raw)
To: linux-f2fs-devel; +Cc: Jaegeuk Kim
This patch checks alloc_type of current segment type.
If it is LFS, the last of segment should have no valid block.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
fsck/f2fs.h | 16 ++++++++++
fsck/fsck.c | 15 +++++++++-
fsck/fsck.h | 4 +++
fsck/mount.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 131 insertions(+), 1 deletion(-)
diff --git a/fsck/f2fs.h b/fsck/f2fs.h
index 100854e..03a0646 100644
--- a/fsck/f2fs.h
+++ b/fsck/f2fs.h
@@ -354,6 +354,22 @@ static inline bool IS_VALID_BLK_ADDR(struct f2fs_sb_info *sbi, u32 addr)
return 1;
}
+static inline int IS_CUR_SEGNO(struct f2fs_sb_info *sbi, u32 segno, int type)
+{
+ int i;
+
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
+
+ if (type == i)
+ continue;
+
+ if (segno == curseg->segno)
+ return 1;
+ }
+ return 0;
+}
+
static inline u64 BLKOFF_FROM_MAIN(struct f2fs_sb_info *sbi, u64 blk_addr)
{
ASSERT(blk_addr >= SM_I(sbi)->main_blkaddr);
diff --git a/fsck/fsck.c b/fsck/fsck.c
index adc61d2..1b55c30 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -1368,13 +1368,24 @@ int check_curseg_offset(struct f2fs_sb_info *sbi)
for (i = 0; i < NO_CHECK_TYPE; i++) {
struct curseg_info *curseg = CURSEG_I(sbi, i);
struct seg_entry *se;
+ int j, nblocks;
se = get_seg_entry(sbi, curseg->segno);
if (f2fs_test_bit(curseg->next_blkoff,
- (const char *)se->cur_valid_map) == 1) {
+ (const char *)se->cur_valid_map)) {
ASSERT_MSG("Next block offset is not free, type:%d", i);
return -EINVAL;
}
+ if (curseg->alloc_type == SSR)
+ return 0;
+
+ nblocks = sbi->blocks_per_seg;
+ for (j = curseg->next_blkoff + 1; j < nblocks; j++) {
+ if (f2fs_test_bit(j, (const char *)se->cur_valid_map)) {
+ ASSERT_MSG("LFS must have free section:%d", i);
+ return -EINVAL;
+ }
+ }
}
return 0;
}
@@ -1528,6 +1539,8 @@ int fsck_verify(struct f2fs_sb_info *sbi)
if (force || (config.bug_on && config.fix_on && !config.ro)) {
fix_hard_links(sbi);
fix_nat_entries(sbi);
+ move_curseg_info(sbi, SM_I(sbi)->main_blkaddr);
+ write_curseg_info(sbi);
rewrite_sit_area_bitmap(sbi);
fix_checkpoint(sbi);
}
diff --git a/fsck/fsck.h b/fsck/fsck.h
index f6b8c53..4876914 100644
--- a/fsck/fsck.h
+++ b/fsck/fsck.h
@@ -132,6 +132,10 @@ extern void fsck_free(struct f2fs_sb_info *);
extern int f2fs_do_mount(struct f2fs_sb_info *);
extern void f2fs_do_umount(struct f2fs_sb_info *);
+extern void move_curseg_info(struct f2fs_sb_info *, u64);
+extern void write_curseg_info(struct f2fs_sb_info *);
+extern int find_next_free_block(struct f2fs_sb_info *, u64 *, int, int);
+
extern void print_raw_sb_info(struct f2fs_super_block *);
/* dump.c */
diff --git a/fsck/mount.c b/fsck/mount.c
index 99e2439..970b159 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -1133,6 +1133,103 @@ void rewrite_sit_area_bitmap(struct f2fs_sb_info *sbi)
}
}
+int find_next_free_block(struct f2fs_sb_info *sbi, u64 *to, int left, int type)
+{
+ struct seg_entry *se;
+ u32 segno;
+ u64 offset;
+
+ while (*to >= SM_I(sbi)->main_blkaddr &&
+ *to < F2FS_RAW_SUPER(sbi)->block_count) {
+ segno = GET_SEGNO(sbi, *to);
+ offset = OFFSET_IN_SEG(sbi, *to);
+
+ se = get_seg_entry(sbi, segno);
+
+ if (se->valid_blocks == sbi->blocks_per_seg)
+ goto next;
+
+ if (se->valid_blocks == 0 && !(segno % sbi->segs_per_sec) &&
+ !IS_CUR_SEGNO(sbi, segno, type)) {
+ struct seg_entry *se2;
+ int i;
+
+ for (i = 0; i < sbi->segs_per_sec; i++) {
+ se2 = get_seg_entry(sbi, segno + i);
+ if (se2->valid_blocks)
+ break;
+ }
+ if (i == sbi->segs_per_sec)
+ return 0;
+ }
+
+ if (se->type == type &&
+ !f2fs_test_bit(offset, (const char *)se->cur_valid_map))
+ return 0;
+next:
+ *to = left ? *to - 1: *to + 1;
+ }
+ return -1;
+}
+
+void move_curseg_info(struct f2fs_sb_info *sbi, u64 from)
+{
+ int i, ret;
+
+ /* update summary blocks having nullified journal entries */
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
+ u32 old_segno;
+ u64 ssa_blk, to;
+
+ /* update original SSA too */
+ ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno);
+ ret = dev_write_block(curseg->sum_blk, ssa_blk);
+ ASSERT(ret >= 0);
+
+ to = from;
+ ret = find_next_free_block(sbi, &to, 0, i);
+ ASSERT(ret == 0);
+
+ old_segno = curseg->segno;
+ curseg->segno = GET_SEGNO(sbi, to);
+ curseg->next_blkoff = OFFSET_IN_SEG(sbi, to);
+ curseg->alloc_type = SSR;
+
+ /* update new segno */
+ ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno);
+ ret = dev_read_block(curseg->sum_blk, ssa_blk);
+ ASSERT(ret >= 0);
+
+ /* update se->types */
+ reset_curseg(sbi, i);
+
+ DBG(0, "Move curseg[%d] %x -> %x after %"PRIx64"\n",
+ i, old_segno, curseg->segno, from);
+ }
+}
+
+void write_curseg_info(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_checkpoint *cp = F2FS_CKPT(sbi);
+ int i;
+
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ cp->alloc_type[i] = CURSEG_I(sbi, i)->alloc_type;
+ if (i < CURSEG_HOT_NODE) {
+ set_cp(cur_data_segno[i], CURSEG_I(sbi, i)->segno);
+ set_cp(cur_data_blkoff[i],
+ CURSEG_I(sbi, i)->next_blkoff);
+ } else {
+ int n = i - CURSEG_HOT_NODE;
+
+ set_cp(cur_node_segno[n], CURSEG_I(sbi, i)->segno);
+ set_cp(cur_node_blkoff[n],
+ CURSEG_I(sbi, i)->next_blkoff);
+ }
+ }
+}
+
int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid,
struct f2fs_nat_entry *raw_nat)
{
--
2.5.4 (Apple Git-61)
------------------------------------------------------------------------------
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 6/6] defrag.f2fs: introduce defragmentation tool
2015-12-12 0:00 [PATCH 1/6] libf2fs: enhance the bit operations Jaegeuk Kim
` (3 preceding siblings ...)
2015-12-12 0:00 ` [PATCH 5/6] fsck.f2fs: LFS alloc_type must have free segment after blkoff Jaegeuk Kim
@ 2015-12-12 0:00 ` Jaegeuk Kim
4 siblings, 0 replies; 6+ messages in thread
From: Jaegeuk Kim @ 2015-12-12 0:00 UTC (permalink / raw)
To: linux-f2fs-devel; +Cc: Jaegeuk Kim
This tool tries to move the valid blocks ranging from blkaddr to blkaddr + len
to targeted blkaddr with a direction like expand or shrink.
The option includes:
-d debug level [default:0]
-s start block address [default: main_blkaddr]
-l length [default:512 (2MB)]
-t target block address [default: main_blkaddr + 2MB]
-i set direction as shrink [default: expand]
For example,
# defrag.f2fs -s 0x100 -l 0x10 -t 0x4000 /dev/sdb1
This will move data blocks between 0x100 and 0x110 to the right side of
0x4000 space.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
---
autogen.sh | 0
fsck/Makefile.am | 3 +-
fsck/defrag.c | 101 +++++++++++++++++++
fsck/f2fs.h | 1 +
fsck/fsck.h | 10 ++
fsck/main.c | 135 +++++++++++++++++++++++--
fsck/mount.c | 290 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/f2fs_fs.h | 7 ++
8 files changed, 538 insertions(+), 9 deletions(-)
mode change 100644 => 100755 autogen.sh
create mode 100644 fsck/defrag.c
diff --git a/autogen.sh b/autogen.sh
old mode 100644
new mode 100755
diff --git a/fsck/Makefile.am b/fsck/Makefile.am
index 6c19e11..73df884 100644
--- a/fsck/Makefile.am
+++ b/fsck/Makefile.am
@@ -3,8 +3,9 @@
AM_CPPFLAGS = ${libuuid_CFLAGS} -I$(top_srcdir)/include
AM_CFLAGS = -Wall
sbin_PROGRAMS = fsck.f2fs
-fsck_f2fs_SOURCES = main.c fsck.c dump.c mount.c f2fs.h fsck.h $(top_srcdir)/include/f2fs_fs.h
+fsck_f2fs_SOURCES = main.c fsck.c dump.c mount.c defrag.c f2fs.h fsck.h $(top_srcdir)/include/f2fs_fs.h
fsck_f2fs_LDADD = ${libuuid_LIBS} $(top_builddir)/lib/libf2fs.la
install-data-hook:
ln -sf fsck.f2fs $(DESTDIR)/$(sbindir)/dump.f2fs
+ ln -sf fsck.f2fs $(DESTDIR)/$(sbindir)/defrag.f2fs
diff --git a/fsck/defrag.c b/fsck/defrag.c
new file mode 100644
index 0000000..7ca7260
--- /dev/null
+++ b/fsck/defrag.c
@@ -0,0 +1,101 @@
+/**
+ * defrag.c
+ *
+ * Copyright (c) 2015 Jaegeuk Kim <jaegeuk@kernel.org>
+ *
+ * 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 "fsck.h"
+
+static int migrate_block(struct f2fs_sb_info *sbi, u64 from, u64 to)
+{
+ void *raw = calloc(BLOCK_SZ, 1);
+ struct seg_entry *se;
+ struct f2fs_summary sum;
+ u64 offset;
+ int ret, type;
+
+ ASSERT(raw != NULL);
+
+ /* read from */
+ ret = dev_read_block(raw, from);
+ ASSERT(ret >= 0);
+
+ /* write to */
+ ret = dev_write_block(raw, to);
+ ASSERT(ret >= 0);
+
+ /* update sit bitmap & valid_blocks && se->type */
+ se = get_seg_entry(sbi, GET_SEGNO(sbi, from));
+ offset = OFFSET_IN_SEG(sbi, from);
+ type = se->type;
+ se->valid_blocks--;
+ f2fs_clear_bit(offset, (char *)se->cur_valid_map);
+ se->dirty = 1;
+
+ se = get_seg_entry(sbi, GET_SEGNO(sbi, to));
+ offset = OFFSET_IN_SEG(sbi, to);
+ se->type = type;
+ se->valid_blocks++;
+ f2fs_set_bit(offset, (char *)se->cur_valid_map);
+ se->dirty = 1;
+
+ /* read/write SSA */
+ get_sum_entry(sbi, from, &sum);
+ update_sum_entry(sbi, to, &sum);
+
+ /* if data block, read node and update node block */
+ if (IS_DATASEG(type))
+ update_data_blkaddr(sbi, le32_to_cpu(sum.nid),
+ le16_to_cpu(sum.ofs_in_node), to);
+ else
+ update_nat_blkaddr(sbi, le32_to_cpu(sum.nid), to);
+
+ DBG(0, "Migrate %s block %"PRIx64" -> %"PRIx64"\n",
+ IS_DATASEG(type) ? "data" : "node",
+ from, to);
+ free(raw);
+ return 0;
+}
+
+int f2fs_defragment(struct f2fs_sb_info *sbi, u64 from, u64 len, u64 to, int left)
+{
+ struct seg_entry *se;
+ u64 idx, offset;
+
+ /* flush NAT/SIT journal entries */
+ flush_journal_entries(sbi);
+
+ for (idx = from; idx < from + len; idx++) {
+ u64 target = to;
+
+ se = get_seg_entry(sbi, GET_SEGNO(sbi, idx));
+ offset = OFFSET_IN_SEG(sbi, idx);
+
+ if (!f2fs_test_bit(offset, (const char *)se->cur_valid_map))
+ continue;
+
+ if (find_next_free_block(sbi, &target, left, se->type)) {
+ ASSERT_MSG("Not enough space to migrate blocks");
+ break;
+ }
+
+ if (migrate_block(sbi, idx, target)) {
+ ASSERT_MSG("Found inconsistency: please run FSCK");
+ return -1;
+ }
+ }
+
+ /* update curseg info; can update sit->types */
+ move_curseg_info(sbi, to);
+ write_curseg_info(sbi);
+
+ /* flush dirty sit entries */
+ flush_sit_entries(sbi);
+
+ write_checkpoint(sbi);
+
+ return 0;
+}
diff --git a/fsck/f2fs.h b/fsck/f2fs.h
index 03a0646..af5cc40 100644
--- a/fsck/f2fs.h
+++ b/fsck/f2fs.h
@@ -74,6 +74,7 @@ struct seg_entry {
unsigned char type; /* segment type like CURSEG_XXX_TYPE */
unsigned char orig_type; /* segment type like CURSEG_XXX_TYPE */
unsigned long long mtime; /* modification time of the segment */
+ int dirty;
};
struct sec_entry {
diff --git a/fsck/fsck.h b/fsck/fsck.h
index 4876914..1464146 100644
--- a/fsck/fsck.h
+++ b/fsck/fsck.h
@@ -121,6 +121,8 @@ extern struct seg_entry *get_seg_entry(struct f2fs_sb_info *, unsigned int);
extern struct f2fs_summary_block *get_sum_block(struct f2fs_sb_info *,
unsigned int, int *);
extern int get_sum_entry(struct f2fs_sb_info *, u32, struct f2fs_summary *);
+extern void update_sum_entry(struct f2fs_sb_info *, block_t,
+ struct f2fs_summary *);
extern void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
extern void nullify_nat_entry(struct f2fs_sb_info *, u32);
extern void rewrite_sit_area_bitmap(struct f2fs_sb_info *);
@@ -132,9 +134,14 @@ extern void fsck_free(struct f2fs_sb_info *);
extern int f2fs_do_mount(struct f2fs_sb_info *);
extern void f2fs_do_umount(struct f2fs_sb_info *);
+extern void flush_journal_entries(struct f2fs_sb_info *);
+extern void flush_sit_entries(struct f2fs_sb_info *);
extern void move_curseg_info(struct f2fs_sb_info *, u64);
extern void write_curseg_info(struct f2fs_sb_info *);
extern int find_next_free_block(struct f2fs_sb_info *, u64 *, int, int);
+extern void write_checkpoint(struct f2fs_sb_info *);
+extern void update_data_blkaddr(struct f2fs_sb_info *, nid_t, u16, block_t);
+extern void update_nat_blkaddr(struct f2fs_sb_info *, nid_t, block_t);
extern void print_raw_sb_info(struct f2fs_super_block *);
@@ -153,4 +160,7 @@ extern void ssa_dump(struct f2fs_sb_info *, int, int);
extern void dump_node(struct f2fs_sb_info *, nid_t);
extern int dump_info_from_blkaddr(struct f2fs_sb_info *, u32);
+/* defrag.c */
+int f2fs_defragment(struct f2fs_sb_info *, u64, u64, u64, int);
+
#endif /* _FSCK_H_ */
diff --git a/fsck/main.c b/fsck/main.c
index 6b0d97e..d70b9ed 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -3,6 +3,8 @@
*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
+ * Copyright (c) 2015 Jaegeuk Kim <jaegeuk@kernel.org>
+ * : implement defrag.f2fs
*
* 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
@@ -38,6 +40,18 @@ void dump_usage()
exit(1);
}
+void defrag_usage()
+{
+ MSG(0, "\nUsage: defrag.f2fs [options] device\n");
+ MSG(0, "[options]:\n");
+ MSG(0, " -d debug level [default:0]\n");
+ MSG(0, " -s start block address [default: main_blkaddr]\n");
+ MSG(0, " -l length [default:512 (2MB)]\n");
+ MSG(0, " -t target block address [default: main_blkaddr + 2MB]\n");
+ MSG(0, " -i set direction as shrink [default: expand]\n");
+ exit(1);
+}
+
void f2fs_parse_options(int argc, char *argv[])
{
int option = 0;
@@ -128,6 +142,53 @@ void f2fs_parse_options(int argc, char *argv[])
}
config.private = &dump_opt;
+ } else if (!strcmp("defrag.f2fs", prog)) {
+ const char *option_string = "d:s:l:t:i";
+
+ config.func = DEFRAG;
+ while ((option = getopt(argc, argv, option_string)) != EOF) {
+ int ret = 0;
+
+ switch (option) {
+ case 'd':
+ config.dbg_lv = atoi(optarg);
+ MSG(0, "Info: Debug level = %d\n",
+ config.dbg_lv);
+ break;
+ case 's':
+ if (strncmp(optarg, "0x", 2))
+ ret = sscanf(optarg, "%"PRIu64"",
+ &config.defrag_start);
+ else
+ ret = sscanf(optarg, "%"PRIx64"",
+ &config.defrag_start);
+ break;
+ case 'l':
+ if (strncmp(optarg, "0x", 2))
+ ret = sscanf(optarg, "%"PRIu64"",
+ &config.defrag_len);
+ else
+ ret = sscanf(optarg, "%"PRIx64"",
+ &config.defrag_len);
+ break;
+ case 't':
+ if (strncmp(optarg, "0x", 2))
+ ret = sscanf(optarg, "%"PRIu64"",
+ &config.defrag_target);
+ else
+ ret = sscanf(optarg, "%"PRIx64"",
+ &config.defrag_target);
+ break;
+ case 'i':
+ config.defrag_shrink = 1;
+ break;
+ default:
+ MSG(0, "\tError: Unknown option %c\n", option);
+ defrag_usage();
+ break;
+ }
+ ASSERT(ret >= 0);
+ }
}
if ((optind + 1) != argc) {
@@ -136,6 +197,8 @@ void f2fs_parse_options(int argc, char *argv[])
fsck_usage();
else if (config.func == DUMP)
dump_usage();
+ else if (config.func == DEFRAG)
+ defrag_usage();
}
config.device_name = argv[optind];
}
@@ -188,6 +251,55 @@ cleanup:
fsck_free(sbi);
}
+static int do_defrag(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
+
+ if (config.defrag_start > get_sb(block_count))
+ goto out_range;
+ if (config.defrag_start < SM_I(sbi)->main_blkaddr)
+ config.defrag_start = SM_I(sbi)->main_blkaddr;
+
+ if (config.defrag_len == 0)
+ config.defrag_len = sbi->blocks_per_seg;
+
+ if (config.defrag_start + config.defrag_len > get_sb(block_count))
+ config.defrag_len = get_sb(block_count) - config.defrag_start;
+
+ if (config.defrag_target == 0) {
+ config.defrag_target = config.defrag_start - 1;
+ if (!config.defrag_shrink)
+ config.defrag_target += config.defrag_len + 1;
+ }
+
+ if (config.defrag_target < SM_I(sbi)->main_blkaddr ||
+ config.defrag_target > get_sb(block_count))
+ goto out_range;
+ if (config.defrag_target >= config.defrag_start &&
+ config.defrag_target < config.defrag_start + config.defrag_len)
+ goto out_range;
+
+ if (config.defrag_start > config.defrag_target)
+ MSG(0, "Info: Move 0x%"PRIx64" <- [0x%"PRIx64"-0x%"PRIx64"]\n",
+ config.defrag_target,
+ config.defrag_start,
+ config.defrag_start + config.defrag_len - 1);
+ else
+ MSG(0, "Info: Move [0x%"PRIx64"-0x%"PRIx64"] -> 0x%"PRIx64"\n",
+ config.defrag_start,
+ config.defrag_start + config.defrag_len - 1,
+ config.defrag_target);
+
+ return f2fs_defragment(sbi, config.defrag_start, config.defrag_len,
+ config.defrag_target, config.defrag_shrink);
+out_range:
+ ASSERT_MSG("Out-of-range [0x%"PRIx64" ~ 0x%"PRIx64"] to 0x%"PRIx64"",
+ config.defrag_start,
+ config.defrag_start + config.defrag_len - 1,
+ config.defrag_target);
+ return -1;
+}
+
int main(int argc, char **argv)
{
struct f2fs_sb_info *sbi;
@@ -198,7 +310,7 @@ int main(int argc, char **argv)
f2fs_parse_options(argc, argv);
if (f2fs_dev_is_umounted(&config) < 0) {
- if (!config.ro) {
+ if (!config.ro || config.func == DEFRAG) {
MSG(0, "\tError: Not available on mounted device!\n");
return -1;
}
@@ -218,12 +330,8 @@ fsck_again:
sbi = &gfsck.sbi;
ret = f2fs_do_mount(sbi);
- if (ret == 1) {
- free(sbi->ckpt);
- free(sbi->raw_super);
- goto out;
- } else if (ret < 0)
- return -1;
+ if (ret != 0)
+ goto out_err;
switch (config.func) {
case FSCK:
@@ -232,10 +340,14 @@ fsck_again:
case DUMP:
do_dump(sbi);
break;
+ case DEFRAG:
+ if (do_defrag(sbi))
+ goto out_err;
+ break;
}
f2fs_do_umount(sbi);
-out:
+
if (config.func == FSCK && config.bug_on) {
if (!config.ro && config.fix_on == 0 && config.auto_fix == 0) {
char ans[255] = {0};
@@ -258,4 +370,11 @@ retry:
printf("\nDone.\n");
return 0;
+
+out_err:
+ if (sbi->ckpt)
+ free(sbi->ckpt);
+ if (sbi->raw_super)
+ free(sbi->raw_super);
+ return -1;
}
diff --git a/fsck/mount.c b/fsck/mount.c
index 970b159..e773471 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -718,6 +718,33 @@ static void read_normal_summaries(struct f2fs_sb_info *sbi, int type)
free(sum_blk);
}
+void update_sum_entry(struct f2fs_sb_info *sbi, block_t blk_addr,
+ struct f2fs_summary *sum)
+{
+ struct f2fs_summary_block *sum_blk;
+ u32 segno, offset;
+ int type, ret;
+ struct seg_entry *se;
+
+ segno = GET_SEGNO(sbi, blk_addr);
+ offset = OFFSET_IN_SEG(sbi, blk_addr);
+
+ se = get_seg_entry(sbi, segno);
+
+ sum_blk = get_sum_block(sbi, segno, &type);
+ memcpy(&sum_blk->entries[offset], sum, sizeof(*sum));
+ sum_blk->footer.entry_type = IS_NODESEG(se->type) ? SUM_TYPE_NODE :
+ SUM_TYPE_DATA;
+
+ if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA ||
+ type == SEG_TYPE_MAX) {
+ u64 ssa_blk = GET_SUM_BLKADDR(sbi, segno);
+ ret = dev_write_block(sum_blk, ssa_blk);
+ ASSERT(ret >= 0);
+ free(sum_blk);
+ }
+}
+
static void restore_curseg_summaries(struct f2fs_sb_info *sbi)
{
int type = CURSEG_HOT_DATA;
@@ -965,6 +992,88 @@ static void get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid,
free(nat_block);
}
+void update_data_blkaddr(struct f2fs_sb_info *sbi, nid_t nid,
+ u16 ofs_in_node, block_t newaddr)
+{
+ struct f2fs_node *node_blk = NULL;
+ struct node_info ni;
+ block_t oldaddr, startaddr, endaddr;
+ int ret;
+
+ node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
+ ASSERT(node_blk != NULL);
+
+ get_node_info(sbi, nid, &ni);
+
+ /* read node_block */
+ ret = dev_read_block(node_blk, ni.blk_addr);
+ ASSERT(ret >= 0);
+
+ /* check its block address */
+ if (node_blk->footer.nid == node_blk->footer.ino) {
+ oldaddr = le32_to_cpu(node_blk->i.i_addr[ofs_in_node]);
+ node_blk->i.i_addr[ofs_in_node] = cpu_to_le32(newaddr);
+ } else {
+ oldaddr = le32_to_cpu(node_blk->dn.addr[ofs_in_node]);
+ node_blk->dn.addr[ofs_in_node] = cpu_to_le32(newaddr);
+ }
+
+ ret = dev_write_block(node_blk, ni.blk_addr);
+ ASSERT(ret >= 0);
+
+ /* check extent cache entry */
+ if (node_blk->footer.nid != node_blk->footer.ino) {
+ get_node_info(sbi, le32_to_cpu(node_blk->footer.ino), &ni);
+
+ /* read inode block */
+ ret = dev_read_block(node_blk, ni.blk_addr);
+ ASSERT(ret >= 0);
+ }
+
+ startaddr = le32_to_cpu(node_blk->i.i_ext.blk_addr);
+ endaddr = startaddr + le32_to_cpu(node_blk->i.i_ext.len);
+ if (oldaddr >= startaddr && oldaddr < endaddr) {
+ node_blk->i.i_ext.len = 0;
+
+ /* update inode block */
+ ret = dev_write_block(node_blk, ni.blk_addr);
+ ASSERT(ret >= 0);
+ }
+ free(node_blk);
+}
+
+void update_nat_blkaddr(struct f2fs_sb_info *sbi, nid_t nid, block_t newaddr)
+{
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+ struct f2fs_nat_block *nat_block;
+ pgoff_t block_off;
+ pgoff_t block_addr;
+ int seg_off, entry_off;
+ int ret;
+
+ nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
+
+ block_off = nid / NAT_ENTRY_PER_BLOCK;
+ entry_off = nid % NAT_ENTRY_PER_BLOCK;
+
+ seg_off = block_off >> sbi->log_blocks_per_seg;
+ block_addr = (pgoff_t)(nm_i->nat_blkaddr +
+ (seg_off << sbi->log_blocks_per_seg << 1) +
+ (block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
+
+ if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
+ block_addr += sbi->blocks_per_seg;
+
+ ret = dev_read_block(nat_block, block_addr);
+ ASSERT(ret >= 0);
+
+ nat_block->entries[entry_off].block_addr = cpu_to_le32(newaddr);
+
+ ret = dev_write_block(nat_block, block_addr);
+ ASSERT(ret >= 0);
+ free(nat_block);
+}
+
void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
{
struct f2fs_nat_entry raw_nat;
@@ -1133,6 +1242,123 @@ void rewrite_sit_area_bitmap(struct f2fs_sb_info *sbi)
}
}
+static void flush_sit_journal_entries(struct f2fs_sb_info *sbi)
+{
+ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
+ struct f2fs_summary_block *sum = curseg->sum_blk;
+ struct sit_info *sit_i = SIT_I(sbi);
+ unsigned int segno;
+ int i;
+
+ for (i = 0; i < sits_in_cursum(sum); i++) {
+ struct f2fs_sit_block *sit_blk;
+ struct f2fs_sit_entry *sit;
+ struct seg_entry *se;
+
+ segno = segno_in_journal(sum, i);
+ se = get_seg_entry(sbi, segno);
+
+ sit_blk = get_current_sit_page(sbi, segno);
+ sit = &sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, segno)];
+
+ memcpy(sit->valid_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE);
+ sit->vblocks = cpu_to_le16((se->type << SIT_VBLOCKS_SHIFT) |
+ se->valid_blocks);
+ sit->mtime = cpu_to_le64(se->mtime);
+
+ rewrite_current_sit_page(sbi, segno, sit_blk);
+ free(sit_blk);
+ }
+ sum->n_sits = 0;
+}
+
+static void flush_nat_journal_entries(struct f2fs_sb_info *sbi)
+{
+ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
+ struct f2fs_summary_block *sum = curseg->sum_blk;
+ struct f2fs_nm_info *nm_i = NM_I(sbi);
+ struct f2fs_nat_block *nat_block;
+ pgoff_t block_off;
+ pgoff_t block_addr;
+ int seg_off, entry_off;
+ nid_t nid;
+ int ret;
+ int i = 0;
+
+next:
+ if (i >= nats_in_cursum(sum)) {
+ sum->n_nats = 0;
+ return;
+ }
+
+ nid = le32_to_cpu(nid_in_journal(sum, i));
+ nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
+
+ block_off = nid / NAT_ENTRY_PER_BLOCK;
+ entry_off = nid % NAT_ENTRY_PER_BLOCK;
+
+ seg_off = block_off >> sbi->log_blocks_per_seg;
+ block_addr = (pgoff_t)(nm_i->nat_blkaddr +
+ (seg_off << sbi->log_blocks_per_seg << 1) +
+ (block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
+
+ if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
+ block_addr += sbi->blocks_per_seg;
+
+ ret = dev_read_block(nat_block, block_addr);
+ ASSERT(ret >= 0);
+
+ memcpy(&nat_block->entries[entry_off], &nat_in_journal(sum, i),
+ sizeof(struct f2fs_nat_entry));
+
+ ret = dev_write_block(nat_block, block_addr);
+ ASSERT(ret >= 0);
+ free(nat_block);
+ i++;
+ goto next;
+}
+
+void flush_journal_entries(struct f2fs_sb_info *sbi)
+{
+ flush_nat_journal_entries(sbi);
+ flush_sit_journal_entries(sbi);
+ write_checkpoint(sbi);
+}
+
+void flush_sit_entries(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_checkpoint *cp = F2FS_CKPT(sbi);
+ struct sit_info *sit_i = SIT_I(sbi);
+ unsigned int segno = 0;
+ u32 free_segs = 0;
+
+ /* update free segments */
+ for (segno = 0; segno < TOTAL_SEGS(sbi); segno++) {
+ struct f2fs_sit_block *sit_blk;
+ struct f2fs_sit_entry *sit;
+ struct seg_entry *se;
+
+ se = get_seg_entry(sbi, segno);
+
+ if (!se->dirty)
+ continue;
+
+ sit_blk = get_current_sit_page(sbi, segno);
+ sit = &sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, segno)];
+ memcpy(sit->valid_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE);
+ sit->vblocks = cpu_to_le16((se->type << SIT_VBLOCKS_SHIFT) |
+ se->valid_blocks);
+ rewrite_current_sit_page(sbi, segno, sit_blk);
+ free(sit_blk);
+
+ if (se->valid_blocks == 0x0 &&
+ !IS_CUR_SEGNO(sbi, segno, NO_CHECK_TYPE))
+ free_segs++;
+ }
+
+ set_cp(free_segment_count, free_segs);
+}
+
int find_next_free_block(struct f2fs_sb_info *sbi, u64 *to, int left, int type)
{
struct seg_entry *se;
@@ -1293,6 +1519,70 @@ void nullify_nat_entry(struct f2fs_sb_info *sbi, u32 nid)
free(nat_block);
}
+void write_checkpoint(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_checkpoint *cp = F2FS_CKPT(sbi);
+ struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
+ block_t orphan_blks = 0;
+ u32 free_segs = 0;
+ unsigned long long cp_blk_no;
+ u32 flags = CP_UMOUNT_FLAG;
+ unsigned int segno;
+ int i, ret;
+ u_int32_t crc = 0;
+
+ if (is_set_ckpt_flags(cp, CP_ORPHAN_PRESENT_FLAG)) {
+ orphan_blks = __start_sum_addr(sbi) - 1;
+ flags |= CP_ORPHAN_PRESENT_FLAG;
+ }
+
+ set_cp(ckpt_flags, flags);
+
+ for (segno = 0; segno < TOTAL_SEGS(sbi); segno++) {
+ struct seg_entry *se = get_seg_entry(sbi, segno);
+
+ if (se->valid_blocks == 0x0 &&
+ !IS_CUR_SEGNO(sbi, segno, NO_CHECK_TYPE))
+ free_segs++;
+ }
+ set_cp(free_segment_count, free_segs);
+ set_cp(cp_pack_total_block_count, 8 + orphan_blks + get_sb(cp_payload));
+
+ crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, cp, CHECKSUM_OFFSET);
+ *((__le32 *)((unsigned char *)cp + CHECKSUM_OFFSET)) = cpu_to_le32(crc);
+
+ cp_blk_no = get_sb(cp_blkaddr);
+ if (sbi->cur_cp == 2)
+ cp_blk_no += 1 << get_sb(log_blocks_per_seg);
+
+ /* write the first cp */
+ ret = dev_write_block(cp, cp_blk_no++);
+ ASSERT(ret >= 0);
+
+ /* skip payload */
+ cp_blk_no += get_sb(cp_payload);
+ /* skip orphan blocks */
+ cp_blk_no += orphan_blks;
+
+ /* update summary blocks having nullified journal entries */
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
+ u64 ssa_blk;
+
+ ret = dev_write_block(curseg->sum_blk, cp_blk_no++);
+ ASSERT(ret >= 0);
+
+ /* update original SSA too */
+ ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno);
+ ret = dev_write_block(curseg->sum_blk, ssa_blk);
+ ASSERT(ret >= 0);
+ }
+
+ /* write the last cp */
+ ret = dev_write_block(cp, cp_blk_no++);
+ ASSERT(ret >= 0);
+}
+
void build_nat_area_bitmap(struct f2fs_sb_info *sbi)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index bbdeb51..29ff9fe 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -220,6 +220,7 @@ static inline uint64_t bswap_64(uint64_t val)
enum f2fs_config_func {
FSCK,
DUMP,
+ DEFRAG,
};
struct f2fs_configuration {
@@ -252,6 +253,12 @@ struct f2fs_configuration {
int auto_fix;
int ro;
__le32 feature; /* defined features */
+
+ /* defragmentation parameters */
+ int defrag_shrink;
+ u_int64_t defrag_start;
+ u_int64_t defrag_len;
+ u_int64_t defrag_target;
} __attribute__((packed));
#ifdef CONFIG_64BIT
--
2.5.4 (Apple Git-61)
------------------------------------------------------------------------------
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2015-12-12 0:00 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-12-12 0:00 [PATCH 1/6] libf2fs: enhance the bit operations Jaegeuk Kim
2015-12-12 0:00 ` [PATCH 2/6] fsck.f2fs: sanity_check for extent_cache entry Jaegeuk Kim
2015-12-12 0:00 ` [PATCH 3/6] mkfs.f2fs: export get_best_overprovision Jaegeuk Kim
2015-12-12 0:00 ` [PATCH 4/6] f2fs-tools: export print_raw_sb_info Jaegeuk Kim
2015-12-12 0:00 ` [PATCH 5/6] fsck.f2fs: LFS alloc_type must have free segment after blkoff Jaegeuk Kim
2015-12-12 0:00 ` [PATCH 6/6] defrag.f2fs: introduce defragmentation tool Jaegeuk Kim
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).