MFC r196307:
Manage asynchronous vnode release just like Solaris. Discussed with: kmacy Approved by: re (kib)
This commit is contained in:
parent
6c0762f5df
commit
5fbdccb6fe
@ -75,7 +75,6 @@ vn_is_readonly(vnode_t *vp)
|
|||||||
#define VN_HOLD(v) vref(v)
|
#define VN_HOLD(v) vref(v)
|
||||||
#define VN_RELE(v) vrele(v)
|
#define VN_RELE(v) vrele(v)
|
||||||
#define VN_URELE(v) vput(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)
|
#define VOP_REALVP(vp, vpp, ct) (*(vpp) = (vp), 0)
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
* CDDL HEADER END
|
* 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.
|
* Use is subject to license terms.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -36,12 +36,10 @@
|
|||||||
* contributors.
|
* contributors.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#pragma ident "%Z%%M% %I% %E% SMI"
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/proc.h>
|
#include <sys/proc.h>
|
||||||
|
#include <sys/taskq.h>
|
||||||
#include <sys/vnode.h>
|
#include <sys/vnode.h>
|
||||||
|
|
||||||
/* Extensible attribute (xva) routines. */
|
/* Extensible attribute (xva) routines. */
|
||||||
@ -74,15 +72,12 @@ xva_getxoptattr(xvattr_t *xvap)
|
|||||||
return (xoap);
|
return (xoap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static STAILQ_HEAD(, vnode) vn_rele_async_list;
|
static void
|
||||||
static struct mtx vn_rele_async_lock;
|
vn_rele_inactive(vnode_t *vp)
|
||||||
static struct cv vn_rele_async_cv;
|
{
|
||||||
static int vn_rele_list_length;
|
|
||||||
static int vn_rele_async_thread_exit;
|
|
||||||
|
|
||||||
typedef struct {
|
vrele(vp);
|
||||||
struct vnode *stqe_next;
|
}
|
||||||
} vnode_link_t;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Like vn_rele() except if we are going to call VOP_INACTIVE() then do it
|
* 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.
|
* This is because taskqs throttle back allocation if too many are created.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
vn_rele_async(vnode_t *vp, taskq_t *taskq /* unused */)
|
vn_rele_async(vnode_t *vp, taskq_t *taskq)
|
||||||
{
|
{
|
||||||
|
VERIFY(vp->v_count > 0);
|
||||||
KASSERT(vp != NULL, ("vrele: null vp"));
|
|
||||||
VFS_ASSERT_GIANT(vp->v_mount);
|
|
||||||
VI_LOCK(vp);
|
VI_LOCK(vp);
|
||||||
|
if (vp->v_count == 1 && !(vp->v_iflag & VI_DOINGINACT)) {
|
||||||
if (vp->v_usecount > 1 || ((vp->v_iflag & VI_DOINGINACT) &&
|
|
||||||
vp->v_usecount == 1)) {
|
|
||||||
vp->v_usecount--;
|
|
||||||
vdropl(vp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (vp->v_usecount != 1) {
|
|
||||||
#ifdef DIAGNOSTIC
|
|
||||||
vprint("vrele: negative ref count", vp);
|
|
||||||
#endif
|
|
||||||
VI_UNLOCK(vp);
|
VI_UNLOCK(vp);
|
||||||
panic("vrele: negative ref cnt");
|
VERIFY(taskq_dispatch((taskq_t *)taskq,
|
||||||
}
|
(task_func_t *)vn_rele_inactive, vp, TQ_SLEEP) != 0);
|
||||||
/*
|
|
||||||
* We are exiting
|
|
||||||
*/
|
|
||||||
if (vn_rele_async_thread_exit != 0) {
|
|
||||||
vrele(vp);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
vp->v_usecount--;
|
||||||
mtx_lock(&vn_rele_async_lock);
|
vdropl(vp);
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
@ -1199,9 +1199,6 @@ dmu_init(void)
|
|||||||
void
|
void
|
||||||
dmu_fini(void)
|
dmu_fini(void)
|
||||||
{
|
{
|
||||||
#ifdef _KERNEL
|
|
||||||
vn_rele_async_fini();
|
|
||||||
#endif
|
|
||||||
arc_fini();
|
arc_fini();
|
||||||
dnode_fini();
|
dnode_fini();
|
||||||
dbuf_fini();
|
dbuf_fini();
|
||||||
|
@ -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_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||||
mutex_init(&dp->dp_scrub_cancel_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);
|
return (dp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,6 +231,7 @@ dsl_pool_close(dsl_pool_t *dp)
|
|||||||
rw_destroy(&dp->dp_config_rwlock);
|
rw_destroy(&dp->dp_config_rwlock);
|
||||||
mutex_destroy(&dp->dp_lock);
|
mutex_destroy(&dp->dp_lock);
|
||||||
mutex_destroy(&dp->dp_scrub_cancel_lock);
|
mutex_destroy(&dp->dp_scrub_cancel_lock);
|
||||||
|
taskq_destroy(dp->dp_vnrele_taskq);
|
||||||
kmem_free(dp, sizeof (dsl_pool_t));
|
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);
|
dsl_dataset_rele(ds, FTAG);
|
||||||
rw_exit(&dp->dp_config_rwlock);
|
rw_exit(&dp->dp_config_rwlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
taskq_t *
|
||||||
|
dsl_pool_vnrele_taskq(dsl_pool_t *dp)
|
||||||
|
{
|
||||||
|
return (dp->dp_vnrele_taskq);
|
||||||
|
}
|
||||||
|
@ -57,6 +57,7 @@ typedef struct dsl_pool {
|
|||||||
struct dsl_dir *dp_mos_dir;
|
struct dsl_dir *dp_mos_dir;
|
||||||
struct dsl_dataset *dp_origin_snap;
|
struct dsl_dataset *dp_origin_snap;
|
||||||
uint64_t dp_root_dir_obj;
|
uint64_t dp_root_dir_obj;
|
||||||
|
struct taskq *dp_vnrele_taskq;
|
||||||
|
|
||||||
/* No lock needed - sync context only */
|
/* No lock needed - sync context only */
|
||||||
blkptr_t dp_meta_rootbp;
|
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_sync(dsl_pool_t *dp, dmu_tx_t *tx);
|
||||||
void dsl_pool_scrub_restart(dsl_pool_t *dp);
|
void dsl_pool_scrub_restart(dsl_pool_t *dp);
|
||||||
|
|
||||||
|
taskq_t *dsl_pool_vnrele_taskq(dsl_pool_t *dp);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -924,6 +924,7 @@ zfs_get_done(dmu_buf_t *db, void *vzgd)
|
|||||||
zgd_t *zgd = (zgd_t *)vzgd;
|
zgd_t *zgd = (zgd_t *)vzgd;
|
||||||
rl_t *rl = zgd->zgd_rl;
|
rl_t *rl = zgd->zgd_rl;
|
||||||
vnode_t *vp = ZTOV(rl->r_zp);
|
vnode_t *vp = ZTOV(rl->r_zp);
|
||||||
|
objset_t *os = rl->r_zp->z_zfsvfs->z_os;
|
||||||
int vfslocked;
|
int vfslocked;
|
||||||
|
|
||||||
vfslocked = VFS_LOCK_GIANT(vp->v_vfsp);
|
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
|
* Release the vnode asynchronously as we currently have the
|
||||||
* txg stopped from syncing.
|
* 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);
|
zil_add_block(zgd->zgd_zilog, zgd->zgd_bp);
|
||||||
kmem_free(zgd, sizeof (zgd_t));
|
kmem_free(zgd, sizeof (zgd_t));
|
||||||
VFS_UNLOCK_GIANT(vfslocked);
|
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
|
* Release the vnode asynchronously as we currently have the
|
||||||
* txg stopped from syncing.
|
* 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);
|
return (ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1045,7 +1046,7 @@ out:
|
|||||||
* Release the vnode asynchronously as we currently have the
|
* Release the vnode asynchronously as we currently have the
|
||||||
* txg stopped from syncing.
|
* 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);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,6 +353,11 @@ typedef struct caller_context {
|
|||||||
ulong_t cc_flags;
|
ulong_t cc_flags;
|
||||||
} caller_context_t;
|
} caller_context_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure tags for function prototypes, defined elsewhere.
|
||||||
|
*/
|
||||||
|
struct taskq;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags for VOP_LOOKUP
|
* Flags for VOP_LOOKUP
|
||||||
*
|
*
|
||||||
@ -369,6 +374,13 @@ typedef struct caller_context {
|
|||||||
*/
|
*/
|
||||||
#define V_RDDIR_ENTFLAGS 0x01 /* request dirent flags */
|
#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:
|
* Extensible vnode attribute (xva) routines:
|
||||||
* xva_init() initializes an xvattr_t (zero struct, init mapsize, set AT_XATTR)
|
* xva_init() initializes an xvattr_t (zero struct, init mapsize, set AT_XATTR)
|
||||||
@ -377,10 +389,12 @@ typedef struct caller_context {
|
|||||||
void xva_init(xvattr_t *);
|
void xva_init(xvattr_t *);
|
||||||
xoptattr_t *xva_getxoptattr(xvattr_t *); /* Get ptr to xoptattr_t */
|
xoptattr_t *xva_getxoptattr(xvattr_t *); /* Get ptr to xoptattr_t */
|
||||||
|
|
||||||
struct taskq;
|
#define VN_RELE_ASYNC(vp, taskq) { \
|
||||||
void vn_rele_async(struct vnode *vp, struct taskq *taskq);
|
vn_rele_async(vp, taskq); \
|
||||||
void vn_rele_async_fini(void);
|
}
|
||||||
|
|
||||||
|
#endif /* _KERNEL */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags to VOP_SETATTR/VOP_GETATTR.
|
* Flags to VOP_SETATTR/VOP_GETATTR.
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user