# HG changeset patch # User Neil Perrin # Date 1239296984 21600 # Node ID dca349c475c1fa890c298aba0d9259b918bebf35 # Parent b37ff50885bc1112e9eb08554605e966193d45e6 6591646 Hang while trying to enter a txg while holding a txg open 6825232 zil_clean should use task_func_t cast in taskq_dispatch 6827943 zil_clean should dispatch zil_itx_clean with TQ_SLEEP diff -r b37ff50885bc -r dca349c475c1 usr/src/uts/common/fs/vnode.c --- a/usr/src/uts/common/fs/vnode.c Thu Apr 09 09:49:49 2009 -0700 +++ b/usr/src/uts/common/fs/vnode.c Thu Apr 09 11:09:44 2009 -0600 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -36,8 +36,6 @@ * contributors. */ - -#pragma ident "%Z%%M% %I% %E% SMI" #include #include @@ -66,6 +64,7 @@ #include #include #include +#include /* Determine if this vnode is a file that is read-only */ #define ISROFILE(vp) \ @@ -869,6 +868,37 @@ vn_rele_stream(vnode_t *vp) mutex_exit(&vp->v_lock); } +static void +vn_rele_inactive(vnode_t *vp) +{ + VOP_INACTIVE(vp, CRED(), NULL); +} + +/* + * Like vn_rele() except if we are going to call VOP_INACTIVE() then do it + * asynchronously using a taskq. This can avoid deadlocks caused by re-entering + * the file system as a result of releasing the vnode. Note, file systems + * already have to handle the race where the vnode is incremented before the + * inactive routine is called and does its locking. + * + * Warning: Excessive use of this routine can lead to performance problems. + * This is because taskqs throttle back allocation if too many are created. + */ +void +vn_rele_async(vnode_t *vp, taskq_t *taskq) +{ + VERIFY(vp->v_count > 0); + mutex_enter(&vp->v_lock); + if (vp->v_count == 1) { + mutex_exit(&vp->v_lock); + VERIFY(taskq_dispatch(taskq, (task_func_t *)vn_rele_inactive, + vp, TQ_SLEEP) != NULL); + return; + } + vp->v_count--; + mutex_exit(&vp->v_lock); +} + int vn_open( char *pnamep, diff -r b37ff50885bc -r dca349c475c1 usr/src/uts/common/fs/zfs/dsl_pool.c --- a/usr/src/uts/common/fs/zfs/dsl_pool.c Thu Apr 09 09:49:49 2009 -0700 +++ b/usr/src/uts/common/fs/zfs/dsl_pool.c Thu Apr 09 11:09:44 2009 -0600 @@ -90,6 +90,9 @@ dsl_pool_open_impl(spa_t *spa, uint64_t mutex_init(&dp->dp_lock, NULL, MUTEX_DEFAULT, NULL); mutex_init(&dp->dp_scrub_cancel_lock, NULL, MUTEX_DEFAULT, NULL); + dp->dp_vnrele_taskq = taskq_create("zfs_vn_rele_taskq", 1, minclsyspri, + 1, 4, 0); + return (dp); } @@ -227,6 +230,7 @@ dsl_pool_close(dsl_pool_t *dp) rw_destroy(&dp->dp_config_rwlock); mutex_destroy(&dp->dp_lock); mutex_destroy(&dp->dp_scrub_cancel_lock); + taskq_destroy(dp->dp_vnrele_taskq); if (dp->dp_blkstats) kmem_free(dp->dp_blkstats, sizeof (zfs_all_blkstats_t)); kmem_free(dp, sizeof (dsl_pool_t)); @@ -612,3 +616,9 @@ dsl_pool_create_origin(dsl_pool_t *dp, d dsl_dataset_rele(ds, FTAG); rw_exit(&dp->dp_config_rwlock); } + +taskq_t * +dsl_pool_vnrele_taskq(dsl_pool_t *dp) +{ + return (dp->dp_vnrele_taskq); +} diff -r b37ff50885bc -r dca349c475c1 usr/src/uts/common/fs/zfs/sys/dsl_pool.h --- a/usr/src/uts/common/fs/zfs/sys/dsl_pool.h Thu Apr 09 09:49:49 2009 -0700 +++ b/usr/src/uts/common/fs/zfs/sys/dsl_pool.h Thu Apr 09 11:09:44 2009 -0600 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -77,6 +77,7 @@ typedef struct dsl_pool { struct dsl_dir *dp_mos_dir; struct dsl_dataset *dp_origin_snap; uint64_t dp_root_dir_obj; + struct taskq *dp_vnrele_taskq; /* No lock needed - sync context only */ blkptr_t dp_meta_rootbp; @@ -143,6 +144,8 @@ void dsl_pool_scrub_sync(dsl_pool_t *dp, void dsl_pool_scrub_sync(dsl_pool_t *dp, dmu_tx_t *tx); void dsl_pool_scrub_restart(dsl_pool_t *dp); +taskq_t *dsl_pool_vnrele_taskq(dsl_pool_t *dp); + #ifdef __cplusplus } #endif diff -r b37ff50885bc -r dca349c475c1 usr/src/uts/common/fs/zfs/zfs_vnops.c --- a/usr/src/uts/common/fs/zfs/zfs_vnops.c Thu Apr 09 09:49:49 2009 -0700 +++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c Thu Apr 09 11:09:44 2009 -0600 @@ -101,6 +101,7 @@ * pushing cached pages (which acquires range locks) and syncing out * cached atime changes. Third, zfs_zinactive() may require a new tx, * which could deadlock the system if you were already holding one. + * If you must call VN_RELE() within a tx then use VN_RELE_ASYNC(). * * (3) All range locks must be grabbed before calling dmu_tx_assign(), * as they can span dmu_tx_assign() calls. @@ -791,10 +792,15 @@ zfs_get_done(dmu_buf_t *db, void *vzgd) zgd_t *zgd = (zgd_t *)vzgd; rl_t *rl = zgd->zgd_rl; vnode_t *vp = ZTOV(rl->r_zp); + objset_t *os = rl->r_zp->z_zfsvfs->z_os; dmu_buf_rele(db, vzgd); zfs_range_unlock(rl); - VN_RELE(vp); + /* + * Release the vnode asynchronously as we currently have the + * txg stopped from syncing. + */ + VN_RELE_ASYNC(vp, dsl_pool_vnrele_taskq(dmu_objset_pool(os))); zil_add_block(zgd->zgd_zilog, zgd->zgd_bp); kmem_free(zgd, sizeof (zgd_t)); } @@ -824,7 +830,12 @@ zfs_get_data(void *arg, lr_write_t *lr, if (zfs_zget(zfsvfs, lr->lr_foid, &zp) != 0) return (ENOENT); if (zp->z_unlinked) { - VN_RELE(ZTOV(zp)); + /* + * Release the vnode asynchronously as we currently have the + * txg stopped from syncing. + */ + VN_RELE_ASYNC(ZTOV(zp), + dsl_pool_vnrele_taskq(dmu_objset_pool(os))); return (ENOENT); } @@ -896,7 +907,11 @@ zfs_get_data(void *arg, lr_write_t *lr, } out: zfs_range_unlock(rl); - VN_RELE(ZTOV(zp)); + /* + * Release the vnode asynchronously as we currently have the + * txg stopped from syncing. + */ + VN_RELE_ASYNC(ZTOV(zp), dsl_pool_vnrele_taskq(dmu_objset_pool(os))); return (error); } diff -r b37ff50885bc -r dca349c475c1 usr/src/uts/common/fs/zfs/zil.c --- a/usr/src/uts/common/fs/zfs/zil.c Thu Apr 09 09:49:49 2009 -0700 +++ b/usr/src/uts/common/fs/zfs/zil.c Thu Apr 09 11:09:44 2009 -0600 @@ -1043,7 +1043,7 @@ zil_clean(zilog_t *zilog) if ((itx != NULL) && (itx->itx_lr.lrc_txg <= spa_last_synced_txg(zilog->zl_spa))) { (void) taskq_dispatch(zilog->zl_clean_taskq, - (void (*)(void *))zil_itx_clean, zilog, TQ_NOSLEEP); + (task_func_t *)zil_itx_clean, zilog, TQ_SLEEP); } mutex_exit(&zilog->zl_lock); } diff -r b37ff50885bc -r dca349c475c1 usr/src/uts/common/sys/vnode.h --- a/usr/src/uts/common/sys/vnode.h Thu Apr 09 09:49:49 2009 -0700 +++ b/usr/src/uts/common/sys/vnode.h Thu Apr 09 11:09:44 2009 -0600 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -778,6 +778,7 @@ struct seg; struct seg; struct as; struct pollhead; +struct taskq; #ifdef _KERNEL @@ -1206,6 +1207,7 @@ int vn_rdwr(enum uio_rw rw, struct vnode offset_t offset, enum uio_seg seg, int ioflag, rlim64_t ulimit, cred_t *cr, ssize_t *residp); void vn_rele(struct vnode *vp); +void vn_rele_async(struct vnode *vp, struct taskq *taskq); void vn_rele_dnlc(struct vnode *vp); void vn_rele_stream(struct vnode *vp); int vn_link(char *from, char *to, enum uio_seg seg); @@ -1284,6 +1286,10 @@ extern uint_t pvn_vmodsort_supported; vn_rele(vp); \ } +#define VN_RELE_ASYNC(vp, taskq) { \ + vn_rele_async(vp, taskq); \ +} + #define VN_SET_VFS_TYPE_DEV(vp, vfsp, type, dev) { \ (vp)->v_vfsp = (vfsp); \ (vp)->v_type = (type); \