Changeset View
Changeset View
Standalone View
Standalone View
head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
Show First 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | |||||
zfs_znode_cache_constructor(void *buf, void *arg, int kmflags) | zfs_znode_cache_constructor(void *buf, void *arg, int kmflags) | ||||
{ | { | ||||
znode_t *zp = buf; | znode_t *zp = buf; | ||||
POINTER_INVALIDATE(&zp->z_zfsvfs); | POINTER_INVALIDATE(&zp->z_zfsvfs); | ||||
list_link_init(&zp->z_link_node); | list_link_init(&zp->z_link_node); | ||||
mutex_init(&zp->z_lock, NULL, MUTEX_DEFAULT, NULL); | |||||
rw_init(&zp->z_parent_lock, NULL, RW_DEFAULT, NULL); | |||||
rw_init(&zp->z_name_lock, NULL, RW_DEFAULT, NULL); | |||||
mutex_init(&zp->z_acl_lock, NULL, MUTEX_DEFAULT, NULL); | mutex_init(&zp->z_acl_lock, NULL, MUTEX_DEFAULT, NULL); | ||||
mutex_init(&zp->z_range_lock, NULL, MUTEX_DEFAULT, NULL); | mutex_init(&zp->z_range_lock, NULL, MUTEX_DEFAULT, NULL); | ||||
avl_create(&zp->z_range_avl, zfs_range_compare, | avl_create(&zp->z_range_avl, zfs_range_compare, | ||||
sizeof (rl_t), offsetof(rl_t, r_node)); | sizeof (rl_t), offsetof(rl_t, r_node)); | ||||
zp->z_dirlocks = NULL; | |||||
zp->z_acl_cached = NULL; | zp->z_acl_cached = NULL; | ||||
zp->z_vnode = NULL; | zp->z_vnode = NULL; | ||||
zp->z_moved = 0; | zp->z_moved = 0; | ||||
return (0); | return (0); | ||||
} | } | ||||
/*ARGSUSED*/ | /*ARGSUSED*/ | ||||
static void | static void | ||||
zfs_znode_cache_destructor(void *buf, void *arg) | zfs_znode_cache_destructor(void *buf, void *arg) | ||||
{ | { | ||||
znode_t *zp = buf; | znode_t *zp = buf; | ||||
ASSERT(!POINTER_IS_VALID(zp->z_zfsvfs)); | ASSERT(!POINTER_IS_VALID(zp->z_zfsvfs)); | ||||
ASSERT(ZTOV(zp) == NULL); | ASSERT(ZTOV(zp) == NULL); | ||||
vn_free(ZTOV(zp)); | vn_free(ZTOV(zp)); | ||||
ASSERT(!list_link_active(&zp->z_link_node)); | ASSERT(!list_link_active(&zp->z_link_node)); | ||||
mutex_destroy(&zp->z_lock); | |||||
rw_destroy(&zp->z_parent_lock); | |||||
rw_destroy(&zp->z_name_lock); | |||||
mutex_destroy(&zp->z_acl_lock); | mutex_destroy(&zp->z_acl_lock); | ||||
avl_destroy(&zp->z_range_avl); | avl_destroy(&zp->z_range_avl); | ||||
mutex_destroy(&zp->z_range_lock); | mutex_destroy(&zp->z_range_lock); | ||||
ASSERT(zp->z_dirlocks == NULL); | |||||
ASSERT(zp->z_acl_cached == NULL); | ASSERT(zp->z_acl_cached == NULL); | ||||
} | } | ||||
#ifdef ZNODE_STATS | #ifdef ZNODE_STATS | ||||
static struct { | static struct { | ||||
uint64_t zms_zfsvfs_invalid; | uint64_t zms_zfsvfs_invalid; | ||||
uint64_t zms_zfsvfs_recheck1; | uint64_t zms_zfsvfs_recheck1; | ||||
uint64_t zms_zfsvfs_unmounted; | uint64_t zms_zfsvfs_unmounted; | ||||
▲ Show 20 Lines • Show All 385 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
zfs_znode_sa_init(zfsvfs_t *zfsvfs, znode_t *zp, | zfs_znode_sa_init(zfsvfs_t *zfsvfs, znode_t *zp, | ||||
dmu_buf_t *db, dmu_object_type_t obj_type, sa_handle_t *sa_hdl) | dmu_buf_t *db, dmu_object_type_t obj_type, sa_handle_t *sa_hdl) | ||||
{ | { | ||||
ASSERT(!POINTER_IS_VALID(zp->z_zfsvfs) || (zfsvfs == zp->z_zfsvfs)); | ASSERT(!POINTER_IS_VALID(zp->z_zfsvfs) || (zfsvfs == zp->z_zfsvfs)); | ||||
ASSERT(MUTEX_HELD(ZFS_OBJ_MUTEX(zfsvfs, zp->z_id))); | ASSERT(MUTEX_HELD(ZFS_OBJ_MUTEX(zfsvfs, zp->z_id))); | ||||
mutex_enter(&zp->z_lock); | |||||
ASSERT(zp->z_sa_hdl == NULL); | ASSERT(zp->z_sa_hdl == NULL); | ||||
ASSERT(zp->z_acl_cached == NULL); | ASSERT(zp->z_acl_cached == NULL); | ||||
if (sa_hdl == NULL) { | if (sa_hdl == NULL) { | ||||
VERIFY(0 == sa_handle_get_from_db(zfsvfs->z_os, db, zp, | VERIFY(0 == sa_handle_get_from_db(zfsvfs->z_os, db, zp, | ||||
SA_HDL_SHARED, &zp->z_sa_hdl)); | SA_HDL_SHARED, &zp->z_sa_hdl)); | ||||
} else { | } else { | ||||
zp->z_sa_hdl = sa_hdl; | zp->z_sa_hdl = sa_hdl; | ||||
sa_set_userp(sa_hdl, zp); | sa_set_userp(sa_hdl, zp); | ||||
} | } | ||||
zp->z_is_sa = (obj_type == DMU_OT_SA) ? B_TRUE : B_FALSE; | zp->z_is_sa = (obj_type == DMU_OT_SA) ? B_TRUE : B_FALSE; | ||||
/* | /* | ||||
* Slap on VROOT if we are the root znode unless we are the root | * Slap on VROOT if we are the root znode unless we are the root | ||||
* node of a snapshot mounted under .zfs. | * node of a snapshot mounted under .zfs. | ||||
*/ | */ | ||||
if (zp->z_id == zfsvfs->z_root && zfsvfs->z_parent == zfsvfs) | if (zp->z_id == zfsvfs->z_root && zfsvfs->z_parent == zfsvfs) | ||||
ZTOV(zp)->v_flag |= VROOT; | ZTOV(zp)->v_flag |= VROOT; | ||||
mutex_exit(&zp->z_lock); | |||||
vn_exists(ZTOV(zp)); | vn_exists(ZTOV(zp)); | ||||
} | } | ||||
void | void | ||||
zfs_znode_dmu_fini(znode_t *zp) | zfs_znode_dmu_fini(znode_t *zp) | ||||
{ | { | ||||
ASSERT(MUTEX_HELD(ZFS_OBJ_MUTEX(zp->z_zfsvfs, zp->z_id)) || | ASSERT(MUTEX_HELD(ZFS_OBJ_MUTEX(zp->z_zfsvfs, zp->z_id)) || | ||||
zp->z_unlinked || | zp->z_unlinked || | ||||
Show All 40 Lines | zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, | ||||
error = getnewvnode("zfs", zfsvfs->z_parent->z_vfs, &zfs_vnodeops, &vp); | error = getnewvnode("zfs", zfsvfs->z_parent->z_vfs, &zfs_vnodeops, &vp); | ||||
if (error != 0) { | if (error != 0) { | ||||
kmem_cache_free(znode_cache, zp); | kmem_cache_free(znode_cache, zp); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
zp->z_vnode = vp; | zp->z_vnode = vp; | ||||
vp->v_data = zp; | vp->v_data = zp; | ||||
ASSERT(zp->z_dirlocks == NULL); | |||||
ASSERT(!POINTER_IS_VALID(zp->z_zfsvfs)); | ASSERT(!POINTER_IS_VALID(zp->z_zfsvfs)); | ||||
zp->z_moved = 0; | zp->z_moved = 0; | ||||
/* | /* | ||||
* Defer setting z_zfsvfs until the znode is ready to be a candidate for | * Defer setting z_zfsvfs until the znode is ready to be a candidate for | ||||
* the zfs_znode_move() callback. | * the zfs_znode_move() callback. | ||||
*/ | */ | ||||
zp->z_sa_hdl = NULL; | zp->z_sa_hdl = NULL; | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | #endif | ||||
* znode eligible for zfs_znode_move(). | * znode eligible for zfs_znode_move(). | ||||
*/ | */ | ||||
zp->z_zfsvfs = zfsvfs; | zp->z_zfsvfs = zfsvfs; | ||||
mutex_exit(&zfsvfs->z_znodes_lock); | mutex_exit(&zfsvfs->z_znodes_lock); | ||||
/* | /* | ||||
* Acquire vnode lock before making it available to the world. | * Acquire vnode lock before making it available to the world. | ||||
*/ | */ | ||||
#ifdef DIAGNOSTIC | |||||
vop_lock1_t *orig_lock = vp->v_op->vop_lock1; | |||||
vp->v_op->vop_lock1 = vop_stdlock; | |||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | ||||
vp->v_op->vop_lock1 = orig_lock; | |||||
#else | |||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); | |||||
#endif | |||||
VN_LOCK_AREC(vp); | VN_LOCK_AREC(vp); | ||||
if (vp->v_type != VFIFO) | if (vp->v_type != VFIFO) | ||||
VN_LOCK_ASHARE(vp); | VN_LOCK_ASHARE(vp); | ||||
#ifdef illumos | #ifdef illumos | ||||
VFS_HOLD(zfsvfs->z_vfs); | VFS_HOLD(zfsvfs->z_vfs); | ||||
#endif | #endif | ||||
return (zp); | return (zp); | ||||
▲ Show 20 Lines • Show All 405 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
return (SET_ERROR(EINVAL)); | return (SET_ERROR(EINVAL)); | ||||
} | } | ||||
hdl = dmu_buf_get_user(db); | hdl = dmu_buf_get_user(db); | ||||
if (hdl != NULL) { | if (hdl != NULL) { | ||||
zp = sa_get_userdata(hdl); | zp = sa_get_userdata(hdl); | ||||
/* | /* | ||||
* Since "SA" does immediate eviction we | * Since "SA" does immediate eviction we | ||||
* should never find a sa handle that doesn't | * should never find a sa handle that doesn't | ||||
* know about the znode. | * know about the znode. | ||||
*/ | */ | ||||
ASSERT3P(zp, !=, NULL); | ASSERT3P(zp, !=, NULL); | ||||
mutex_enter(&zp->z_lock); | |||||
ASSERT3U(zp->z_id, ==, obj_num); | ASSERT3U(zp->z_id, ==, obj_num); | ||||
if (zp->z_unlinked) { | |||||
err = SET_ERROR(ENOENT); | |||||
} else { | |||||
vp = ZTOV(zp); | |||||
*zpp = zp; | *zpp = zp; | ||||
err = 0; | vp = ZTOV(zp); | ||||
} | |||||
/* Don't let the vnode disappear after ZFS_OBJ_HOLD_EXIT. */ | /* Don't let the vnode disappear after ZFS_OBJ_HOLD_EXIT. */ | ||||
if (err == 0) | |||||
VN_HOLD(vp); | VN_HOLD(vp); | ||||
mutex_exit(&zp->z_lock); | |||||
sa_buf_rele(db, NULL); | sa_buf_rele(db, NULL); | ||||
ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num); | ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num); | ||||
if (err == 0) { | |||||
locked = VOP_ISLOCKED(vp); | locked = VOP_ISLOCKED(vp); | ||||
VI_LOCK(vp); | VI_LOCK(vp); | ||||
if ((vp->v_iflag & VI_DOOMED) != 0 && | if ((vp->v_iflag & VI_DOOMED) != 0 && | ||||
locked != LK_EXCLUSIVE) { | locked != LK_EXCLUSIVE) { | ||||
/* | /* | ||||
* The vnode is doomed and this thread doesn't | * The vnode is doomed and this thread doesn't | ||||
* hold the exclusive lock on it, so the vnode | * hold the exclusive lock on it, so the vnode | ||||
* must be being reclaimed by another thread. | * must be being reclaimed by another thread. | ||||
* Otherwise the doomed vnode is being reclaimed | * Otherwise the doomed vnode is being reclaimed | ||||
* by this thread and zfs_zget is called from | * by this thread and zfs_zget is called from | ||||
* ZIL internals. | * ZIL internals. | ||||
*/ | */ | ||||
VI_UNLOCK(vp); | VI_UNLOCK(vp); | ||||
/* | |||||
* XXX vrele() locks the vnode when the last reference | |||||
* is dropped. Although in this case the vnode is | |||||
* doomed / dead and so no inactivation is required, | |||||
* the vnode lock is still acquired. That could result | |||||
* in a LOR with z_teardown_lock if another thread holds | |||||
* the vnode's lock and tries to take z_teardown_lock. | |||||
* But that is only possible if the other thread peforms | |||||
* a ZFS vnode operation on the vnode. That either | |||||
* should not happen if the vnode is dead or the thread | |||||
* should also have a refrence to the vnode and thus | |||||
* our reference is not last. | |||||
*/ | |||||
VN_RELE(vp); | VN_RELE(vp); | ||||
goto again; | goto again; | ||||
} | } | ||||
VI_UNLOCK(vp); | VI_UNLOCK(vp); | ||||
} | |||||
getnewvnode_drop_reserve(); | getnewvnode_drop_reserve(); | ||||
return (err); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Not found create new znode/vnode | * Not found create new znode/vnode | ||||
* but only if file exists. | * but only if file exists. | ||||
* | * | ||||
* There is a small window where zfs_vget() could | * There is a small window where zfs_vget() could | ||||
* find this object while a file create is still in | * find this object while a file create is still in | ||||
▲ Show 20 Lines • Show All 166 Lines • ▼ Show 20 Lines | zfs_zinactive(znode_t *zp) | ||||
ASSERT(zp->z_sa_hdl); | ASSERT(zp->z_sa_hdl); | ||||
/* | /* | ||||
* Don't allow a zfs_zget() while were trying to release this znode | * Don't allow a zfs_zget() while were trying to release this znode | ||||
*/ | */ | ||||
ZFS_OBJ_HOLD_ENTER(zfsvfs, z_id); | ZFS_OBJ_HOLD_ENTER(zfsvfs, z_id); | ||||
mutex_enter(&zp->z_lock); | |||||
/* | /* | ||||
* If this was the last reference to a file with no links, | * If this was the last reference to a file with no links, | ||||
* remove the file from the file system. | * remove the file from the file system. | ||||
*/ | */ | ||||
if (zp->z_unlinked) { | if (zp->z_unlinked) { | ||||
mutex_exit(&zp->z_lock); | |||||
ZFS_OBJ_HOLD_EXIT(zfsvfs, z_id); | ZFS_OBJ_HOLD_EXIT(zfsvfs, z_id); | ||||
zfs_rmnode(zp); | zfs_rmnode(zp); | ||||
return; | return; | ||||
} | } | ||||
mutex_exit(&zp->z_lock); | |||||
zfs_znode_dmu_fini(zp); | zfs_znode_dmu_fini(zp); | ||||
ZFS_OBJ_HOLD_EXIT(zfsvfs, z_id); | ZFS_OBJ_HOLD_EXIT(zfsvfs, z_id); | ||||
zfs_znode_free(zp); | zfs_znode_free(zp); | ||||
} | } | ||||
void | void | ||||
zfs_znode_free(znode_t *zp) | zfs_znode_free(znode_t *zp) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 787 Lines • Show Last 20 Lines |