Call udevadm trigger more safely
[zfs.git] / module / zfs / zfs_znode.c
index 0bb9c09..1fe8849 100644 (file)
@@ -174,7 +174,7 @@ zfs_create_share_dir(zfs_sb_t *zsb, dmu_tx_t *tx)
        vattr.va_uid = crgetuid(kcred);
        vattr.va_gid = crgetgid(kcred);
 
-       sharezp = kmem_cache_alloc(znode_cache, KM_SLEEP);
+       sharezp = kmem_cache_alloc(znode_cache, KM_PUSHPAGE);
        sharezp->z_moved = 0;
        sharezp->z_unlinked = 0;
        sharezp->z_atime_dirty = 0;
@@ -248,7 +248,7 @@ zfs_inode_alloc(struct super_block *sb, struct inode **ip)
 {
        znode_t *zp;
 
-       zp = kmem_cache_alloc(znode_cache, KM_SLEEP);
+       zp = kmem_cache_alloc(znode_cache, KM_PUSHPAGE);
        *ip = ZTOI(zp);
 
        return (0);
@@ -347,6 +347,7 @@ zfs_znode_alloc(zfs_sb_t *zsb, dmu_buf_t *db, int blksz,
        zp->z_blksz = blksz;
        zp->z_seq = 0x7A4653;
        zp->z_sync_cnt = 0;
+       zp->z_is_zvol = 0;
 
        zfs_znode_sa_init(zsb, zp, db, obj_type, hdl);
 
@@ -979,13 +980,24 @@ zfs_zinactive(znode_t *zp)
 {
        zfs_sb_t *zsb = ZTOZSB(zp);
        uint64_t z_id = zp->z_id;
+       boolean_t drop_mutex = 0;
 
        ASSERT(zp->z_sa_hdl);
 
        /*
-        * Don't allow a zfs_zget() while were trying to release this znode
+        * Don't allow a zfs_zget() while were trying to release this znode.
+        *
+        * Linux allows direct memory reclaim which means that any KM_SLEEP
+        * allocation may trigger inode eviction.  This can lead to a deadlock
+        * through the ->shrink_icache_memory()->evict()->zfs_inactive()->
+        * zfs_zinactive() call path.  To avoid this deadlock the process
+        * must not reacquire the mutex when it is already holding it.
         */
-       ZFS_OBJ_HOLD_ENTER(zsb, z_id);
+       if (!ZFS_OBJ_HOLD_OWNED(zsb, z_id)) {
+               ZFS_OBJ_HOLD_ENTER(zsb, z_id);
+               drop_mutex = 1;
+       }
+
        mutex_enter(&zp->z_lock);
 
        /*
@@ -994,14 +1006,19 @@ zfs_zinactive(znode_t *zp)
         */
        if (zp->z_unlinked) {
                mutex_exit(&zp->z_lock);
-               ZFS_OBJ_HOLD_EXIT(zsb, z_id);
+
+               if (drop_mutex)
+                       ZFS_OBJ_HOLD_EXIT(zsb, z_id);
+
                zfs_rmnode(zp);
                return;
        }
 
        mutex_exit(&zp->z_lock);
        zfs_znode_dmu_fini(zp);
-       ZFS_OBJ_HOLD_EXIT(zsb, z_id);
+
+       if (drop_mutex)
+               ZFS_OBJ_HOLD_EXIT(zsb, z_id);
 }
 
 void