Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c7e82c64 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -1027,12 +1027,6 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
		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) {
		/* Symlink data on the disk is corrupted */
		res = -EIO;
@@ -1046,6 +1040,12 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
	if (res < 0)
		goto errout;

	/* this is broken symlink case */
	if (unlikely(pstr.name[0] == 0)) {
		res = -ENOENT;
		goto errout;
	}

	paddr = pstr.name;

	/* Null-terminate the name */
+66 −38
Original line number Diff line number Diff line
@@ -984,9 +984,25 @@ static loff_t max_file_blocks(void)
	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,
					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 cp_blkaddr = le32_to_cpu(raw_super->cp_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 = le32_to_cpu(raw_super->segment_count);
	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) {
		f2fs_msg(sb, KERN_INFO,
@@ -1044,22 +1064,45 @@ static inline bool sanity_check_area_boundary(struct super_block *sb,
		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,
			"Wrong MAIN_AREA boundary, start(%u) end(%u) blocks(%u)",
			"Wrong MAIN_AREA boundary, start(%u) end(%u) block(%u)",
			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);
		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;
}

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;

	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 */
	if (sanity_check_area_boundary(sb, raw_super))
	if (sanity_check_area_boundary(sb, bh))
		return 1;

	return 0;
@@ -1202,7 +1245,7 @@ static int read_raw_super_block(struct super_block *sb,
{
	int block;
	struct buffer_head *bh;
	struct f2fs_super_block *super, *buf;
	struct f2fs_super_block *super;
	int err = 0;

	super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL);
@@ -1218,11 +1261,8 @@ static int read_raw_super_block(struct super_block *sb,
			continue;
		}

		buf = (struct f2fs_super_block *)
				(bh->b_data + F2FS_SUPER_OFFSET);

		/* sanity checking of raw super */
		if (sanity_check_raw_super(sb, buf)) {
		if (sanity_check_raw_super(sb, bh)) {
			f2fs_msg(sb, KERN_ERR,
				"Can't find valid F2FS filesystem in %dth superblock",
				block + 1);
@@ -1232,7 +1272,8 @@ static int read_raw_super_block(struct super_block *sb,
		}

		if (!*raw_super) {
			memcpy(super, buf, sizeof(*super));
			memcpy(super, bh->b_data + F2FS_SUPER_OFFSET,
							sizeof(*super));
			*valid_super_block = block;
			*raw_super = super;
		}
@@ -1252,42 +1293,29 @@ static int read_raw_super_block(struct super_block *sb,
	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;
	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)
		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);

	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 (recover || err)
		return err;

	/* 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)
@@ -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);
	if (__exist_node_summaries(sbi))
		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);