MFC r196307:

Manage asynchronous vnode release just like Solaris.

Discussed with:	kmacy
Approved by:	re (kib)
This commit is contained in:
pjd 2009-08-17 09:55:58 +00:00
parent 6c0762f5df
commit 5fbdccb6fe
7 changed files with 50 additions and 132 deletions

View File

@ -75,7 +75,6 @@ vn_is_readonly(vnode_t *vp)
#define VN_HOLD(v) vref(v)
#define VN_RELE(v) vrele(v)
#define VN_URELE(v) vput(v)
#define VN_RELE_ASYNC(v, tq) vn_rele_async(v, tq);
#define VOP_REALVP(vp, vpp, ct) (*(vpp) = (vp), 0)

View File

@ -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,12 +36,10 @@
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/taskq.h>
#include <sys/vnode.h>
/* Extensible attribute (xva) routines. */
@ -74,15 +72,12 @@ xva_getxoptattr(xvattr_t *xvap)
return (xoap);
}
static STAILQ_HEAD(, vnode) vn_rele_async_list;
static struct mtx vn_rele_async_lock;
static struct cv vn_rele_async_cv;
static int vn_rele_list_length;
static int vn_rele_async_thread_exit;
static void
vn_rele_inactive(vnode_t *vp)
{
typedef struct {
struct vnode *stqe_next;
} vnode_link_t;
vrele(vp);
}
/*
* Like vn_rele() except if we are going to call VOP_INACTIVE() then do it
@ -95,117 +90,16 @@ typedef struct {
* This is because taskqs throttle back allocation if too many are created.
*/
void
vn_rele_async(vnode_t *vp, taskq_t *taskq /* unused */)
vn_rele_async(vnode_t *vp, taskq_t *taskq)
{
KASSERT(vp != NULL, ("vrele: null vp"));
VFS_ASSERT_GIANT(vp->v_mount);
VERIFY(vp->v_count > 0);
VI_LOCK(vp);
if (vp->v_usecount > 1 || ((vp->v_iflag & VI_DOINGINACT) &&
vp->v_usecount == 1)) {
if (vp->v_count == 1 && !(vp->v_iflag & VI_DOINGINACT)) {
VI_UNLOCK(vp);
VERIFY(taskq_dispatch((taskq_t *)taskq,
(task_func_t *)vn_rele_inactive, vp, TQ_SLEEP) != 0);
return;
}
vp->v_usecount--;
vdropl(vp);
return;
}
if (vp->v_usecount != 1) {
#ifdef DIAGNOSTIC
vprint("vrele: negative ref count", vp);
#endif
VI_UNLOCK(vp);
panic("vrele: negative ref cnt");
}
/*
* We are exiting
*/
if (vn_rele_async_thread_exit != 0) {
vrele(vp);
return;
}
mtx_lock(&vn_rele_async_lock);
/* STAILQ_INSERT_TAIL */
(*(vnode_link_t *)&vp->v_cstart).stqe_next = NULL;
*vn_rele_async_list.stqh_last = vp;
vn_rele_async_list.stqh_last =
&((vnode_link_t *)&vp->v_cstart)->stqe_next;
/****************************************/
vn_rele_list_length++;
if ((vn_rele_list_length % 100) == 0)
cv_signal(&vn_rele_async_cv);
mtx_unlock(&vn_rele_async_lock);
VI_UNLOCK(vp);
}
static void
vn_rele_async_init(void *arg)
{
mtx_init(&vn_rele_async_lock, "valock", NULL, MTX_DEF);
STAILQ_INIT(&vn_rele_async_list);
/* cv_init(&vn_rele_async_cv, "vacv"); */
vn_rele_async_cv.cv_description = "vacv";
vn_rele_async_cv.cv_waiters = 0;
}
void
vn_rele_async_fini(void)
{
mtx_lock(&vn_rele_async_lock);
vn_rele_async_thread_exit = 1;
cv_signal(&vn_rele_async_cv);
while (vn_rele_async_thread_exit != 0)
cv_wait(&vn_rele_async_cv, &vn_rele_async_lock);
mtx_unlock(&vn_rele_async_lock);
mtx_destroy(&vn_rele_async_lock);
}
static void
vn_rele_async_cleaner(void)
{
STAILQ_HEAD(, vnode) vn_tmp_list;
struct vnode *curvnode;
STAILQ_INIT(&vn_tmp_list);
mtx_lock(&vn_rele_async_lock);
while (vn_rele_async_thread_exit == 0) {
STAILQ_CONCAT(&vn_tmp_list, &vn_rele_async_list);
vn_rele_list_length = 0;
mtx_unlock(&vn_rele_async_lock);
while (!STAILQ_EMPTY(&vn_tmp_list)) {
curvnode = STAILQ_FIRST(&vn_tmp_list);
/* STAILQ_REMOVE_HEAD */
STAILQ_FIRST(&vn_tmp_list) =
((vnode_link_t *)&curvnode->v_cstart)->stqe_next;
if (STAILQ_FIRST(&vn_tmp_list) == NULL)
vn_tmp_list.stqh_last = &STAILQ_FIRST(&vn_tmp_list);
/***********************/
vrele(curvnode);
}
mtx_lock(&vn_rele_async_lock);
if (vn_rele_list_length == 0)
cv_timedwait(&vn_rele_async_cv, &vn_rele_async_lock,
hz/10);
}
vn_rele_async_thread_exit = 0;
cv_broadcast(&vn_rele_async_cv);
mtx_unlock(&vn_rele_async_lock);
thread_exit();
}
static struct proc *vn_rele_async_proc;
static struct kproc_desc up_kp = {
"vaclean",
vn_rele_async_cleaner,
&vn_rele_async_proc
};
SYSINIT(vaclean, SI_SUB_KTHREAD_UPDATE, SI_ORDER_FIRST, kproc_start, &up_kp);
SYSINIT(vn_rele_async_setup, SI_SUB_VFS, SI_ORDER_FIRST, vn_rele_async_init, NULL);

View File

@ -1199,9 +1199,6 @@ dmu_init(void)
void
dmu_fini(void)
{
#ifdef _KERNEL
vn_rele_async_fini();
#endif
arc_fini();
dnode_fini();
dbuf_fini();

View File

@ -91,6 +91,9 @@ dsl_pool_open_impl(spa_t *spa, uint64_t txg)
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);
}
@ -228,6 +231,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);
kmem_free(dp, sizeof (dsl_pool_t));
}
@ -611,3 +615,9 @@ dsl_pool_create_origin(dsl_pool_t *dp, dmu_tx_t *tx)
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);
}

View File

@ -57,6 +57,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;
@ -119,6 +120,8 @@ int dsl_pool_scrub_clean(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

View File

@ -924,6 +924,7 @@ 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;
int vfslocked;
vfslocked = VFS_LOCK_GIANT(vp->v_vfsp);
@ -933,7 +934,7 @@ zfs_get_done(dmu_buf_t *db, void *vzgd)
* Release the vnode asynchronously as we currently have the
* txg stopped from syncing.
*/
VN_RELE_ASYNC(vp, NULL);
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));
VFS_UNLOCK_GIANT(vfslocked);
@ -968,8 +969,8 @@ zfs_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio)
* Release the vnode asynchronously as we currently have the
* txg stopped from syncing.
*/
VN_RELE_ASYNC(ZTOV(zp), NULL);
VN_RELE_ASYNC(ZTOV(zp),
dsl_pool_vnrele_taskq(dmu_objset_pool(os)));
return (ENOENT);
}
@ -1045,7 +1046,7 @@ out:
* Release the vnode asynchronously as we currently have the
* txg stopped from syncing.
*/
VN_RELE_ASYNC(ZTOV(zp), NULL);
VN_RELE_ASYNC(ZTOV(zp), dsl_pool_vnrele_taskq(dmu_objset_pool(os)));
return (error);
}

View File

@ -353,6 +353,11 @@ typedef struct caller_context {
ulong_t cc_flags;
} caller_context_t;
/*
* Structure tags for function prototypes, defined elsewhere.
*/
struct taskq;
/*
* Flags for VOP_LOOKUP
*
@ -369,6 +374,13 @@ typedef struct caller_context {
*/
#define V_RDDIR_ENTFLAGS 0x01 /* request dirent flags */
/*
* Public vnode manipulation functions.
*/
#ifdef _KERNEL
void vn_rele_async(struct vnode *vp, struct taskq *taskq);
/*
* Extensible vnode attribute (xva) routines:
* xva_init() initializes an xvattr_t (zero struct, init mapsize, set AT_XATTR)
@ -377,9 +389,11 @@ typedef struct caller_context {
void xva_init(xvattr_t *);
xoptattr_t *xva_getxoptattr(xvattr_t *); /* Get ptr to xoptattr_t */
struct taskq;
void vn_rele_async(struct vnode *vp, struct taskq *taskq);
void vn_rele_async_fini(void);
#define VN_RELE_ASYNC(vp, taskq) { \
vn_rele_async(vp, taskq); \
}
#endif /* _KERNEL */
/*
* Flags to VOP_SETATTR/VOP_GETATTR.