]> granicus.if.org Git - zfs/commitdiff
Disable FS reclaim when allocating new slabs
authorBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 27 Nov 2012 00:52:28 +0000 (16:52 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 27 Nov 2012 21:43:27 +0000 (13:43 -0800)
Allowing the spl_cache_grow_work() function to reclaim inodes
allows for two unlikely deadlocks.  Therefore, we clear __GFP_FS
for these allocations.  The two deadlocks are:

* While holding the ZFS_OBJ_HOLD_ENTER(zsb, obj1) lock a function
  calls kmem_cache_alloc() which happens to need to allocate a
  new slab.  To allocate the new slab we enter FS level reclaim
  and attempt to evict several inodes.  To evict these inodes we
  need to take the ZFS_OBJ_HOLD_ENTER(zsb, obj2) lock and it
  just happens that obj1 and obj2 use the same hashed lock.

* Similar to the first case however instead of getting blocked
  on the hash lock we block in txg_wait_open() which is waiting
  for the next txg which isn't coming because the txg_sync
  thread is blocked in kmem_cache_alloc().

Note this isn't a 100% fix because vmalloc() won't strictly
honor __GFP_FS.  However, it practice this is sufficient because
several very unlikely things must all occur concurrently.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Issue zfsonlinux/zfs#1101

module/spl/spl-kmem.c

index f3113e0f49a36a5a0abe46917c6fc2bdd332b0ae..b171d446ae8259580a9993b4cabdd55f877fdd51 100644 (file)
@@ -1773,7 +1773,7 @@ spl_cache_grow(spl_kmem_cache_t *skc, int flags, void **obj)
 
                atomic_inc(&skc->skc_ref);
                ska->ska_cache = skc;
-               ska->ska_flags = flags;
+               ska->ska_flags = flags & ~__GFP_FS;
                spl_init_delayed_work(&ska->ska_work, spl_cache_grow_work, ska);
                schedule_delayed_work(&ska->ska_work, 0);
        }