Commit c7e82c64 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'f2fs-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs

Pull f2fs fixes from Jaegeuk Kim.

* tag 'f2fs-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs:
  f2fs: retrieve IO write stat from the right place
  f2fs crypto: fix corrupted symlink in encrypted case
  f2fs: cover large section in sanity check of super
parents 166c5a6e b2dde6fc
...@@ -1027,12 +1027,6 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry, ...@@ -1027,12 +1027,6 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
goto errout; goto errout;
} }
/* this is broken symlink case */
if (unlikely(cstr.name[0] == 0)) {
res = -ENOENT;
goto errout;
}
if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) { if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) {
/* Symlink data on the disk is corrupted */ /* Symlink data on the disk is corrupted */
res = -EIO; res = -EIO;
...@@ -1046,6 +1040,12 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry, ...@@ -1046,6 +1040,12 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
if (res < 0) if (res < 0)
goto errout; goto errout;
/* this is broken symlink case */
if (unlikely(pstr.name[0] == 0)) {
res = -ENOENT;
goto errout;
}
paddr = pstr.name; paddr = pstr.name;
/* Null-terminate the name */ /* Null-terminate the name */
......
...@@ -984,9 +984,25 @@ static loff_t max_file_blocks(void) ...@@ -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, ...@@ -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, ...@@ -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) != if (main_end_blkaddr > seg_end_blkaddr) {
segment0_blkaddr + (segment_count << log_blocks_per_seg)) {
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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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;
err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi));
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);
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 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1442,7 +1470,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment