Commit 4a378d8a authored by Al Viro's avatar Al Viro
Browse files

gfs2: be careful with inode refresh



1) gfs2_dinode_in() should *not* touch ->i_rdev on live inodes; even
"zero and immediately reread the same value from dinode" is broken -
have it overlap with ->release() of char device and you can get all
kinds of bogus behaviour.

2) mismatch on inode type on live inodes should be treated as fs
corruption rather than blindly setting ->i_mode.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 60606eca
Loading
Loading
Loading
Loading
+14 −8
Original line number Diff line number Diff line
@@ -394,19 +394,25 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
	const struct gfs2_dinode *str = buf;
	struct timespec64 atime;
	u16 height, depth;
	umode_t mode = be32_to_cpu(str->di_mode);
	bool is_new = ip->i_inode.i_flags & I_NEW;

	if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)))
		goto corrupt;
	if (unlikely(!is_new && inode_wrong_type(&ip->i_inode, mode)))
		goto corrupt;
	ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino);
	ip->i_inode.i_mode = be32_to_cpu(str->di_mode);
	ip->i_inode.i_mode = mode;
	if (is_new) {
		ip->i_inode.i_rdev = 0;
	switch (ip->i_inode.i_mode & S_IFMT) {
		switch (mode & S_IFMT) {
		case S_IFBLK:
		case S_IFCHR:
			ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major),
						   be32_to_cpu(str->di_minor));
			break;
		}
	}

	i_uid_write(&ip->i_inode, be32_to_cpu(str->di_uid));
	i_gid_write(&ip->i_inode, be32_to_cpu(str->di_gid));