|
@@ -984,9 +984,25 @@ static loff_t max_file_blocks(void)
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int __f2fs_commit_super(struct buffer_head *bh,
|
|
|
|
+ struct f2fs_super_block *super)
|
|
|
|
+{
|
|
|
|
+ lock_buffer(bh);
|
|
|
|
+ if (super)
|
|
|
|
+ memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super));
|
|
|
|
+ set_buffer_uptodate(bh);
|
|
|
|
+ set_buffer_dirty(bh);
|
|
|
|
+ unlock_buffer(bh);
|
|
|
|
+
|
|
|
|
+ /* it's rare case, we can do fua all the time */
|
|
|
|
+ return __sync_dirty_buffer(bh, WRITE_FLUSH_FUA);
|
|
|
|
+}
|
|
|
|
+
|
|
static inline bool sanity_check_area_boundary(struct super_block *sb,
|
|
static inline bool sanity_check_area_boundary(struct super_block *sb,
|
|
- struct f2fs_super_block *raw_super)
|
|
|
|
|
|
+ struct buffer_head *bh)
|
|
{
|
|
{
|
|
|
|
+ struct f2fs_super_block *raw_super = (struct f2fs_super_block *)
|
|
|
|
+ (bh->b_data + F2FS_SUPER_OFFSET);
|
|
u32 segment0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr);
|
|
u32 segment0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr);
|
|
u32 cp_blkaddr = le32_to_cpu(raw_super->cp_blkaddr);
|
|
u32 cp_blkaddr = le32_to_cpu(raw_super->cp_blkaddr);
|
|
u32 sit_blkaddr = le32_to_cpu(raw_super->sit_blkaddr);
|
|
u32 sit_blkaddr = le32_to_cpu(raw_super->sit_blkaddr);
|
|
@@ -1000,6 +1016,10 @@ static inline bool sanity_check_area_boundary(struct super_block *sb,
|
|
u32 segment_count_main = le32_to_cpu(raw_super->segment_count_main);
|
|
u32 segment_count_main = le32_to_cpu(raw_super->segment_count_main);
|
|
u32 segment_count = le32_to_cpu(raw_super->segment_count);
|
|
u32 segment_count = le32_to_cpu(raw_super->segment_count);
|
|
u32 log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
|
|
u32 log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
|
|
|
|
+ u64 main_end_blkaddr = main_blkaddr +
|
|
|
|
+ (segment_count_main << log_blocks_per_seg);
|
|
|
|
+ u64 seg_end_blkaddr = segment0_blkaddr +
|
|
|
|
+ (segment_count << log_blocks_per_seg);
|
|
|
|
|
|
if (segment0_blkaddr != cp_blkaddr) {
|
|
if (segment0_blkaddr != cp_blkaddr) {
|
|
f2fs_msg(sb, KERN_INFO,
|
|
f2fs_msg(sb, KERN_INFO,
|
|
@@ -1044,22 +1064,45 @@ static inline bool sanity_check_area_boundary(struct super_block *sb,
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
- if (main_blkaddr + (segment_count_main << log_blocks_per_seg) !=
|
|
|
|
- segment0_blkaddr + (segment_count << log_blocks_per_seg)) {
|
|
|
|
|
|
+ if (main_end_blkaddr > seg_end_blkaddr) {
|
|
f2fs_msg(sb, KERN_INFO,
|
|
f2fs_msg(sb, KERN_INFO,
|
|
- "Wrong MAIN_AREA boundary, start(%u) end(%u) blocks(%u)",
|
|
|
|
|
|
+ "Wrong MAIN_AREA boundary, start(%u) end(%u) block(%u)",
|
|
main_blkaddr,
|
|
main_blkaddr,
|
|
- segment0_blkaddr + (segment_count << log_blocks_per_seg),
|
|
|
|
|
|
+ segment0_blkaddr +
|
|
|
|
+ (segment_count << log_blocks_per_seg),
|
|
segment_count_main << log_blocks_per_seg);
|
|
segment_count_main << log_blocks_per_seg);
|
|
return true;
|
|
return true;
|
|
|
|
+ } else if (main_end_blkaddr < seg_end_blkaddr) {
|
|
|
|
+ int err = 0;
|
|
|
|
+ char *res;
|
|
|
|
+
|
|
|
|
+ /* fix in-memory information all the time */
|
|
|
|
+ raw_super->segment_count = cpu_to_le32((main_end_blkaddr -
|
|
|
|
+ segment0_blkaddr) >> log_blocks_per_seg);
|
|
|
|
+
|
|
|
|
+ if (f2fs_readonly(sb) || bdev_read_only(sb->s_bdev)) {
|
|
|
|
+ res = "internally";
|
|
|
|
+ } else {
|
|
|
|
+ err = __f2fs_commit_super(bh, NULL);
|
|
|
|
+ res = err ? "failed" : "done";
|
|
|
|
+ }
|
|
|
|
+ f2fs_msg(sb, KERN_INFO,
|
|
|
|
+ "Fix alignment : %s, start(%u) end(%u) block(%u)",
|
|
|
|
+ res, main_blkaddr,
|
|
|
|
+ segment0_blkaddr +
|
|
|
|
+ (segment_count << log_blocks_per_seg),
|
|
|
|
+ segment_count_main << log_blocks_per_seg);
|
|
|
|
+ if (err)
|
|
|
|
+ return true;
|
|
}
|
|
}
|
|
-
|
|
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
static int sanity_check_raw_super(struct super_block *sb,
|
|
static int sanity_check_raw_super(struct super_block *sb,
|
|
- struct f2fs_super_block *raw_super)
|
|
|
|
|
|
+ struct buffer_head *bh)
|
|
{
|
|
{
|
|
|
|
+ struct f2fs_super_block *raw_super = (struct f2fs_super_block *)
|
|
|
|
+ (bh->b_data + F2FS_SUPER_OFFSET);
|
|
unsigned int blocksize;
|
|
unsigned int blocksize;
|
|
|
|
|
|
if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) {
|
|
if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) {
|
|
@@ -1126,7 +1169,7 @@ static int sanity_check_raw_super(struct super_block *sb,
|
|
}
|
|
}
|
|
|
|
|
|
/* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */
|
|
/* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */
|
|
- if (sanity_check_area_boundary(sb, raw_super))
|
|
|
|
|
|
+ if (sanity_check_area_boundary(sb, bh))
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -1202,7 +1245,7 @@ static int read_raw_super_block(struct super_block *sb,
|
|
{
|
|
{
|
|
int block;
|
|
int block;
|
|
struct buffer_head *bh;
|
|
struct buffer_head *bh;
|
|
- struct f2fs_super_block *super, *buf;
|
|
|
|
|
|
+ struct f2fs_super_block *super;
|
|
int err = 0;
|
|
int err = 0;
|
|
|
|
|
|
super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL);
|
|
super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL);
|
|
@@ -1218,11 +1261,8 @@ static int read_raw_super_block(struct super_block *sb,
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
- buf = (struct f2fs_super_block *)
|
|
|
|
- (bh->b_data + F2FS_SUPER_OFFSET);
|
|
|
|
-
|
|
|
|
/* sanity checking of raw super */
|
|
/* sanity checking of raw super */
|
|
- if (sanity_check_raw_super(sb, buf)) {
|
|
|
|
|
|
+ if (sanity_check_raw_super(sb, bh)) {
|
|
f2fs_msg(sb, KERN_ERR,
|
|
f2fs_msg(sb, KERN_ERR,
|
|
"Can't find valid F2FS filesystem in %dth superblock",
|
|
"Can't find valid F2FS filesystem in %dth superblock",
|
|
block + 1);
|
|
block + 1);
|
|
@@ -1232,7 +1272,8 @@ static int read_raw_super_block(struct super_block *sb,
|
|
}
|
|
}
|
|
|
|
|
|
if (!*raw_super) {
|
|
if (!*raw_super) {
|
|
- memcpy(super, buf, sizeof(*super));
|
|
|
|
|
|
+ memcpy(super, bh->b_data + F2FS_SUPER_OFFSET,
|
|
|
|
+ sizeof(*super));
|
|
*valid_super_block = block;
|
|
*valid_super_block = block;
|
|
*raw_super = super;
|
|
*raw_super = super;
|
|
}
|
|
}
|
|
@@ -1252,42 +1293,29 @@ static int read_raw_super_block(struct super_block *sb,
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
-static int __f2fs_commit_super(struct f2fs_sb_info *sbi, int block)
|
|
|
|
|
|
+int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover)
|
|
{
|
|
{
|
|
- struct f2fs_super_block *super = F2FS_RAW_SUPER(sbi);
|
|
|
|
struct buffer_head *bh;
|
|
struct buffer_head *bh;
|
|
int err;
|
|
int err;
|
|
|
|
|
|
- bh = sb_getblk(sbi->sb, block);
|
|
|
|
|
|
+ /* write back-up superblock first */
|
|
|
|
+ bh = sb_getblk(sbi->sb, sbi->valid_super_block ? 0: 1);
|
|
if (!bh)
|
|
if (!bh)
|
|
return -EIO;
|
|
return -EIO;
|
|
-
|
|
|
|
- lock_buffer(bh);
|
|
|
|
- memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super));
|
|
|
|
- set_buffer_uptodate(bh);
|
|
|
|
- set_buffer_dirty(bh);
|
|
|
|
- unlock_buffer(bh);
|
|
|
|
-
|
|
|
|
- /* it's rare case, we can do fua all the time */
|
|
|
|
- err = __sync_dirty_buffer(bh, WRITE_FLUSH_FUA);
|
|
|
|
|
|
+ err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi));
|
|
brelse(bh);
|
|
brelse(bh);
|
|
|
|
|
|
- return err;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover)
|
|
|
|
-{
|
|
|
|
- int err;
|
|
|
|
-
|
|
|
|
- /* write back-up superblock first */
|
|
|
|
- err = __f2fs_commit_super(sbi, sbi->valid_super_block ? 0 : 1);
|
|
|
|
-
|
|
|
|
/* if we are in recovery path, skip writing valid superblock */
|
|
/* if we are in recovery path, skip writing valid superblock */
|
|
if (recover || err)
|
|
if (recover || err)
|
|
return err;
|
|
return err;
|
|
|
|
|
|
/* write current valid superblock */
|
|
/* write current valid superblock */
|
|
- return __f2fs_commit_super(sbi, sbi->valid_super_block);
|
|
|
|
|
|
+ bh = sb_getblk(sbi->sb, sbi->valid_super_block);
|
|
|
|
+ if (!bh)
|
|
|
|
+ return -EIO;
|
|
|
|
+ err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi));
|
|
|
|
+ brelse(bh);
|
|
|
|
+ return err;
|
|
}
|
|
}
|
|
|
|
|
|
static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
|
static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
|
@@ -1442,7 +1470,7 @@ try_onemore:
|
|
seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE);
|
|
seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE);
|
|
if (__exist_node_summaries(sbi))
|
|
if (__exist_node_summaries(sbi))
|
|
sbi->kbytes_written =
|
|
sbi->kbytes_written =
|
|
- le64_to_cpu(seg_i->sum_blk->journal.info.kbytes_written);
|
|
|
|
|
|
+ le64_to_cpu(seg_i->journal->info.kbytes_written);
|
|
|
|
|
|
build_gc_manager(sbi);
|
|
build_gc_manager(sbi);
|
|
|
|
|