Fix zil_commit() NULL dereference

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 <ryao@gentoo.org>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #2405
This commit is contained in:
Brian Behlendorf 2014-07-15 13:29:57 -07:00
parent a5778ea242
commit 1e8db77102
5 changed files with 24 additions and 6 deletions

View File

@ -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 *,

View File

@ -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);

View File

@ -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;

View File

@ -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);
@ -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);
/*

View File

@ -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)
@ -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);
}
}
@ -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);
}