]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Fix zil_commit() NULL dereference
authorBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 15 Jul 2014 20:29:57 +0000 (13:29 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 17 Jul 2014 22:15:07 +0000 (15:15 -0700)
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

include/sys/zfs_znode.h
module/zfs/zfs_vnops.c
module/zfs/zfs_znode.c
module/zfs/zpl_file.c
module/zfs/zpl_xattr.c

index a0200684e3460ac133ec1ded275b99c0d5a42f51..4bb8a77617f973ccd3d539e2cc6a2f61e8839bc7 100644 (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 *,
index 91f743aaa9300f608bcc626f33e9abcecc35b276..4f531733e42f9300cd591ee6dbd7ad309151f529 100644 (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);
index 8cd0d8379af2435cda01092b0a0fc56a28602b9d..23e090712c3fdf65f669e6d9ba37b8e7085826be 100644 (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;
index 2a7bcb9b0a694b034d104806d74d4a0bb14a8191..d37cf07f9b7105210e1aa150ca618c2a7190d527 100644 (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);
 
                /*
index c5c15a2ddb871715dee09715ea3fe0223e574f03..107b803009c105591b3f211b71871253aedfb22d 100644 (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);
                }