Skip to content

Commit 4a378d8

Browse files
author
Al Viro
committed
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: Al Viro <viro@zeniv.linux.org.uk>
1 parent 60606ec commit 4a378d8

1 file changed

Lines changed: 14 additions & 8 deletions

File tree

fs/gfs2/glops.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -394,18 +394,24 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
394394
const struct gfs2_dinode *str = buf;
395395
struct timespec64 atime;
396396
u16 height, depth;
397+
umode_t mode = be32_to_cpu(str->di_mode);
398+
bool is_new = ip->i_inode.i_flags & I_NEW;
397399

398400
if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)))
399401
goto corrupt;
402+
if (unlikely(!is_new && inode_wrong_type(&ip->i_inode, mode)))
403+
goto corrupt;
400404
ip->i_no_formal_ino = be64_to_cpu(str->di_num.no_formal_ino);
401-
ip->i_inode.i_mode = be32_to_cpu(str->di_mode);
402-
ip->i_inode.i_rdev = 0;
403-
switch (ip->i_inode.i_mode & S_IFMT) {
404-
case S_IFBLK:
405-
case S_IFCHR:
406-
ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major),
407-
be32_to_cpu(str->di_minor));
408-
break;
405+
ip->i_inode.i_mode = mode;
406+
if (is_new) {
407+
ip->i_inode.i_rdev = 0;
408+
switch (mode & S_IFMT) {
409+
case S_IFBLK:
410+
case S_IFCHR:
411+
ip->i_inode.i_rdev = MKDEV(be32_to_cpu(str->di_major),
412+
be32_to_cpu(str->di_minor));
413+
break;
414+
}
409415
}
410416

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

0 commit comments

Comments
 (0)