void zfs_delete_thread(void *arg) { zfsvfs_t *zfsvfs = arg; zfs_delete_t *zd = &zfsvfs->z_delete_head; znode_t *zp; callb_cpr_t cprinfo; int drained; CALLB_CPR_INIT(&cprinfo, &zd->z_mutex, callb_generic_cpr, "zfs_delete"); mutex_enter(&zd->z_mutex); if (!zd->z_drained && !zd->z_draining) { zd->z_draining = B_TRUE; mutex_exit(&zd->z_mutex); drained = zfs_drain_dq(zfsvfs); mutex_enter(&zd->z_mutex); zd->z_draining = B_FALSE; zd->z_drained = drained; cv_broadcast(&zd->z_quiesce_cv); } while (zd->z_thread_count <= zd->z_thread_target) { zp = list_head(&zd->z_znodes); if (zp == NULL) { ASSERT(zd->z_znode_count == 0); CALLB_CPR_SAFE_BEGIN(&cprinfo); cv_wait(&zd->z_cv, &zd->z_mutex); CALLB_CPR_SAFE_END(&cprinfo, &zd->z_mutex); continue; } ASSERT(zd->z_znode_count != 0); list_remove(&zd->z_znodes, zp); if (--zd->z_znode_count == 0) cv_broadcast(&zd->z_quiesce_cv); mutex_exit(&zd->z_mutex); zfs_rmnode(zp); (void) zfs_delete_thread_target(zfsvfs, -1); mutex_enter(&zd->z_mutex); } ASSERT(zd->z_thread_count != 0); if (--zd->z_thread_count == 0) cv_broadcast(&zd->z_cv); CALLB_CPR_EXIT(&cprinfo); /* NB: drops z_mutex */ thread_exit(); }
void 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. * * 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. */ if (!ZFS_OBJ_HOLD_OWNED(zsb, z_id)) { ZFS_OBJ_HOLD_ENTER(zsb, z_id); drop_mutex = 1; } mutex_enter(&zp->z_lock); /* * If this was the last reference to a file with no links, * remove the file from the file system. */ if (zp->z_unlinked) { mutex_exit(&zp->z_lock); if (drop_mutex) ZFS_OBJ_HOLD_EXIT(zsb, z_id); zfs_rmnode(zp); return; } mutex_exit(&zp->z_lock); zfs_znode_dmu_fini(zp); if (drop_mutex) ZFS_OBJ_HOLD_EXIT(zsb, z_id); }