Skip to content

Commit

Permalink
Fix zil_commit() NULL dereference
Browse files Browse the repository at this point in the history
Update the current code to ensure inodes are never dirtied if they are
part of a read-only file system or snapshot.  If they do somehow get
dirtied an attempt will make made to write them to disk.  In the case
of snapshots, which don't have a ZIL, this will result in a NULL
dereference in zil_commit().

Signed-off-by: Richard Yao <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Closes #2405
  • Loading branch information
behlendorf committed Oct 9, 2014
1 parent 46bf86a commit 908a0c2
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 6 deletions.
1 change: 1 addition & 0 deletions include/sys/zfs_znode.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ extern void zfs_znode_dmu_fini(znode_t *);
extern int zfs_inode_alloc(struct super_block *, struct inode **ip);
extern void zfs_inode_destroy(struct inode *);
extern void zfs_inode_update(znode_t *);
extern void zfs_mark_inode_dirty(struct inode *);

extern void zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
znode_t *dzp, znode_t *zp, char *name, vsecattr_t *, zfs_fuid_info_t *,
Expand Down
3 changes: 2 additions & 1 deletion module/zfs/zfs_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -3965,7 +3965,8 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc)
* writepages() normally handles the entire commit for
* performance reasons.
*/
zil_commit(zsb->z_log, zp->z_id);
if (zsb->z_log != NULL)
zil_commit(zsb->z_log, zp->z_id);
}

ZFS_EXIT(zsb);
Expand Down
15 changes: 15 additions & 0 deletions module/zfs/zfs_znode.c
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,21 @@ zfs_inode_update(znode_t *zp)
spin_unlock(&ip->i_lock);
}

/*
* Safely mark an inode dirty. Inodes which are part of a read-only
* file system or snapshot may not be dirtied.
*/
void
zfs_mark_inode_dirty(struct inode *ip)
{
zfs_sb_t *zsb = ITOZSB(ip);

if (zfs_is_readonly(zsb) || dmu_objset_is_snapshot(zsb->z_os))
return;

mark_inode_dirty(ip);
}

static uint64_t empty_xattr;
static uint64_t pad[4];
static zfs_acl_phys_t acl_phys;
Expand Down
5 changes: 3 additions & 2 deletions module/zfs/zpl_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ zpl_release(struct inode *ip, struct file *filp)
int error;

if (ITOZ(ip)->z_atime_dirty)
mark_inode_dirty(ip);
zfs_mark_inode_dirty(ip);

crhold(cr);
error = -zfs_close(ip, filp->f_flags, cr);
Expand Down Expand Up @@ -445,7 +445,8 @@ zpl_writepages(struct address_space *mapping, struct writeback_control *wbc)
if (sync_mode != wbc->sync_mode) {
ZFS_ENTER(zsb);
ZFS_VERIFY_ZP(zp);
zil_commit(zsb->z_log, zp->z_id);
if (zsb->z_log != NULL)
zil_commit(zsb->z_log, zp->z_id);
ZFS_EXIT(zsb);

/*
Expand Down
6 changes: 3 additions & 3 deletions module/zfs/zpl_xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@ zpl_set_acl(struct inode *ip, int type, struct posix_acl *acl)
if (ip->i_mode != mode) {
ip->i_mode = mode;
ip->i_ctime = current_fs_time(sb);
mark_inode_dirty(ip);
zfs_mark_inode_dirty(ip);
}

if (error == 0)
Expand Down Expand Up @@ -909,7 +909,7 @@ zpl_init_acl(struct inode *ip, struct inode *dir)
if (!acl) {
ip->i_mode &= ~current_umask();
ip->i_ctime = current_fs_time(ITOZSB(ip)->z_sb);
mark_inode_dirty(ip);
zfs_mark_inode_dirty(ip);
return (0);
}
}
Expand All @@ -927,7 +927,7 @@ zpl_init_acl(struct inode *ip, struct inode *dir)
error = __posix_acl_create(&acl, GFP_KERNEL, &mode);
if (error >= 0) {
ip->i_mode = mode;
mark_inode_dirty(ip);
zfs_mark_inode_dirty(ip);
if (error > 0)
error = zpl_set_acl(ip, ACL_TYPE_ACCESS, acl);
}
Expand Down

0 comments on commit 908a0c2

Please sign in to comment.