Module Name: src Committed By: hannken Date: Tue Jan 1 10:08:01 UTC 2019
Modified Files: src/external/cddl/osnet/dist/uts/common/fs/zfs: zfs_ioctl.c zfs_vfsops.c zfs_znode.c src/external/cddl/osnet/dist/uts/common/fs/zfs/sys: zfs_znode.h Log Message: Cannot hold zfs object across call to vcache_get() as it might deadlock with another reclaim. Add vfs operation zfs_newvnode() to create a new zfs node and hold the zfs object in zfs_loadvnode() and zfs_newvnode() only. To generate a diff of this commit: cvs rdiff -u -r1.13 -r1.14 \ src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ioctl.c cvs rdiff -u -r1.17 -r1.18 \ src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c cvs rdiff -u -r1.23 -r1.24 \ src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_znode.c cvs rdiff -u -r1.8 -r1.9 \ src/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_znode.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ioctl.c diff -u src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ioctl.c:1.13 src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ioctl.c:1.14 --- src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ioctl.c:1.13 Mon Aug 20 06:47:16 2018 +++ src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_ioctl.c Tue Jan 1 10:08:01 2019 @@ -7120,7 +7120,6 @@ zfs_modcmd(modcmd_t cmd, void *arg) uint64_t availrmem; extern struct vfsops zfs_vfsops; - extern uint_t zfs_loadvnode_key; extern uint_t zfs_putpage_key; switch (cmd) { @@ -7144,7 +7143,6 @@ zfs_modcmd(modcmd_t cmd, void *arg) tsd_create(&zfs_fsyncer_key, NULL); tsd_create(&rrw_tsd_key, rrw_tsd_destroy); tsd_create(&zfs_allow_log_key, zfs_allow_log_destroy); - tsd_create(&zfs_loadvnode_key, zfs_loadvnode_destroy); tsd_create(&zfs_putpage_key, NULL); spa_init(FREAD | FWRITE); @@ -7179,7 +7177,6 @@ attacherr: spa_fini(); tsd_destroy(&zfs_putpage_key); - tsd_destroy(&zfs_loadvnode_key); tsd_destroy(&zfs_fsyncer_key); tsd_destroy(&rrw_tsd_key); tsd_destroy(&zfs_allow_log_key); Index: src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c diff -u src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c:1.17 src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c:1.18 --- src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c:1.17 Sun Sep 16 06:09:01 2018 +++ src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c Tue Jan 1 10:08:01 2019 @@ -163,6 +163,7 @@ struct vfsops zfs_vfsops = { .vfs_sync = zfs_netbsd_sync, .vfs_vget = zfs_vget, .vfs_loadvnode = zfs_loadvnode, + .vfs_newvnode = zfs_newvnode, .vfs_init = zfs_init, .vfs_done = zfs_fini, .vfs_start = (void *)nullop, Index: src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_znode.c diff -u src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_znode.c:1.23 src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_znode.c:1.24 --- src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_znode.c:1.23 Thu Dec 6 09:58:52 2018 +++ src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_znode.c Tue Jan 1 10:08:01 2019 @@ -60,15 +60,6 @@ extern int (**zfs_vnodeop_p)(void *); extern int (**zfs_fifoop_p)(void *); extern int (**zfs_specop_p)(void *); -struct zfs_loadvnode_args { - dmu_buf_t *db; - int blksz; - dmu_object_type_t obj_type; - void *sa_hdl; -}; - -uint_t zfs_loadvnode_key; - #endif #endif /* _KERNEL */ @@ -621,6 +612,7 @@ zfs_vnode_forget(vnode_t *vp) vgone(vp); vput(vp); } +#endif /* __FreeBSD__ */ /* * Construct a new znode/vnode and intialize. @@ -630,11 +622,18 @@ zfs_vnode_forget(vnode_t *vp) * return the znode */ static znode_t * +#ifdef __NetBSD__ +zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, + dmu_object_type_t obj_type, sa_handle_t *hdl, vnode_t *vp) +#else zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, dmu_object_type_t obj_type, sa_handle_t *hdl) +#endif { znode_t *zp; +#ifndef __NetBSD__ vnode_t *vp; +#endif uint64_t mode; uint64_t parent; sa_bulk_attr_t bulk[9]; @@ -643,6 +642,7 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_bu zp = kmem_cache_alloc(znode_cache, KM_SLEEP); +#ifndef __NetBSD__ KASSERT(curthread->td_vp_reserv > 0, ("zfs_znode_alloc: getnewvnode without any vnodes reserved")); error = getnewvnode("zfs", zfsvfs->z_parent->z_vfs, &zfs_vnodeops, &vp); @@ -650,6 +650,7 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_bu kmem_cache_free(znode_cache, zp); return (NULL); } +#endif zp->z_vnode = vp; vp->v_data = zp; @@ -669,6 +670,12 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_bu zp->z_seq = 0x7A4653; zp->z_sync_cnt = 0; +#ifdef __NetBSD__ + vp->v_op = zfs_vnodeop_p; + vp->v_tag = VT_ZFS; + zp->z_lockf = NULL; +#endif + vp = ZTOV(zp); zfs_znode_sa_init(zfsvfs, zp, db, obj_type, hdl); @@ -692,7 +699,9 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_bu if (sa_bulk_lookup(zp->z_sa_hdl, bulk, count) != 0 || zp->z_gen == 0) { if (hdl == NULL) sa_handle_destroy(zp->z_sa_hdl); +#ifndef __NetBSD__ zfs_vnode_forget(vp); +#endif zp->z_vnode = NULL; kmem_cache_free(znode_cache, zp); return (NULL); @@ -706,7 +715,7 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_bu case VDIR: zp->z_zn_prefetch = B_TRUE; /* z_prefetch default is enabled */ break; -#ifdef illumos +#if defined(illumos) || defined(__NetBSD__) case VBLK: case VCHR: { @@ -714,11 +723,19 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_bu VERIFY(sa_lookup(zp->z_sa_hdl, SA_ZPL_RDEV(zfsvfs), &rdev, sizeof (rdev)) == 0); +#ifdef illumos vp->v_rdev = zfs_cmpldev(rdev); +#else + spec_node_init(vp, zfs_cmpldev(rdev)); +#endif } break; #endif case VFIFO: +#ifdef __NetBSD__ + /* XXX NetBSD vp->v_op = zfs_fifoop_p; */ + break; +#else /* __NetBSD__ */ #ifdef illumos case VSOCK: case VDOOR: @@ -739,8 +756,15 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_bu vn_setops(vp, zfs_evnodeops); break; #endif +#endif /* __NetBSD__ */ } +#ifdef __NetBSD__ + extern const struct genfs_ops zfs_genfsops; + genfs_node_init(vp, &zfs_genfsops); + uvm_vnp_setsize(vp, zp->z_size); +#endif + mutex_enter(&zfsvfs->z_znodes_lock); list_insert_tail(&zfsvfs->z_all_znodes, zp); membar_producer(); @@ -751,6 +775,7 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_bu zp->z_zfsvfs = zfsvfs; mutex_exit(&zfsvfs->z_znodes_lock); +#ifndef __NetBSD__ /* * Acquire vnode lock before making it available to the world. */ @@ -758,13 +783,13 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_bu VN_LOCK_AREC(vp); if (vp->v_type != VFIFO) VN_LOCK_ASHARE(vp); +#endif -#ifdef illumos +#if defined(illumos) || defined(__NetBSD__) VFS_HOLD(zfsvfs->z_vfs); #endif return (zp); } -#endif /* __FreeBSD__ */ static uint64_t empty_xattr; static uint64_t pad[4]; @@ -786,10 +811,119 @@ static zfs_acl_phys_t acl_phys; * OUT: zpp - allocated znode * */ +#ifdef __NetBSD__ +struct zfs_newvnode_args { + dmu_tx_t *tx; + uint_t flag; + zfs_acl_ids_t *acl_ids; +}; + +static void +zfs_mknode1(znode_t *, vattr_t *, dmu_tx_t *, cred_t *, + uint_t, znode_t **, zfs_acl_ids_t *, vnode_t *); + +int +zfs_loadvnode(struct mount *mp, struct vnode *vp, + const void *key, size_t key_len, const void **new_key) +{ + int err, blksz; + uint64_t obj_num; + zfsvfs_t *zfsvfs; + dmu_buf_t *db; + dmu_object_info_t doi; + dmu_object_type_t obj_type; + sa_handle_t *hdl; + znode_t *zp; + + KASSERT(key_len == sizeof(obj_num)); + memcpy(&obj_num, key, key_len); + + zfsvfs = mp->mnt_data; + + ZFS_OBJ_HOLD_ENTER(zfsvfs, obj_num); + + err = sa_buf_hold(zfsvfs->z_os, obj_num, NULL, &db); + if (err) { + ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num); + return (SET_ERROR(err)); + } + + dmu_object_info_from_db(db, &doi); + if (doi.doi_bonus_type != DMU_OT_SA && + (doi.doi_bonus_type != DMU_OT_ZNODE || + (doi.doi_bonus_type == DMU_OT_ZNODE && + doi.doi_bonus_size < sizeof (znode_phys_t)))) { + sa_buf_rele(db, NULL); + ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num); + return (SET_ERROR(EINVAL)); + } + blksz = doi.doi_data_block_size; + obj_type = doi.doi_bonus_type; + hdl = dmu_buf_get_user(db); + + if (hdl != NULL) { + sa_buf_rele(db, NULL); + ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num); + return (SET_ERROR(ENOENT)); + } + + zp = zfs_znode_alloc(zfsvfs, db, blksz, obj_type, hdl, vp); + if (zp == NULL) { + ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num); + return (SET_ERROR(ENOENT)); + } + ASSERT(zp == VTOZ(vp)); + + ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num); + + *new_key = &zp->z_id; + + return 0; +} + +int +zfs_newvnode(struct mount *mp, vnode_t *dvp, vnode_t *vp, vattr_t *vap, + cred_t *cr, void *extra, size_t *key_len, const void **new_key) +{ + struct zfs_newvnode_args *args = extra; + znode_t *zp, *dzp = VTOZ(dvp); + dmu_tx_t *tx = args->tx; + uint_t flag = args->flag; + zfs_acl_ids_t *acl_ids = args->acl_ids; + + zfs_mknode1(dzp, vap, tx, cr, flag, &zp, acl_ids, vp); + ASSERT(zp == VTOZ(vp)); + *key_len = sizeof(zp->z_id); + *new_key = &zp->z_id; + + return 0; +} + void zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr, uint_t flag, znode_t **zpp, zfs_acl_ids_t *acl_ids) { + vnode_t *vp, *dvp = ZTOV(dzp); + zfsvfs_t *zfsvfs = dzp->z_zfsvfs; + struct zfs_newvnode_args args = { tx, flag, acl_ids }; + + if (flag & IS_ROOT_NODE) + return zfs_mknode1(dzp, vap, tx, cr, flag, zpp, acl_ids, NULL); + + VERIFY(vcache_new(zfsvfs->z_vfs, dvp, vap, cr, &args, &vp) == 0); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + *zpp = VTOZ(vp); +} + +static void +zfs_mknode1(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr, + uint_t flag, znode_t **zpp, zfs_acl_ids_t *acl_ids, vnode_t *vp) +#else +void +zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr, + uint_t flag, znode_t **zpp, zfs_acl_ids_t *acl_ids) +#endif +{ uint64_t crtime[2], atime[2], mtime[2], ctime[2]; uint64_t mode, size, links, parent, pflags; uint64_t dzp_pflags = 0; @@ -1007,16 +1141,7 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, d if (!(flag & IS_ROOT_NODE)) { #ifdef __NetBSD__ - vnode_t *vp; - struct zfs_loadvnode_args args = { db, 0, obj_type, sa_hdl }; - - tsd_set(zfs_loadvnode_key, &args); - err = vcache_get(zfsvfs->z_vfs, &obj, sizeof(obj), &vp); - tsd_set(zfs_loadvnode_key, NULL); - - ASSERT3U(err, ==, 0); - *zpp = VTOZ(vp); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + *zpp = zfs_znode_alloc(zfsvfs, db, 0, obj_type, sa_hdl, vp); #else *zpp = zfs_znode_alloc(zfsvfs, db, 0, obj_type, sa_hdl); #endif @@ -1152,31 +1277,17 @@ zfs_xvattr_set(znode_t *zp, xvattr_t *xv #ifdef __NetBSD__ -static inline int -zfs_do_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp, - int (*get)(struct mount *, const void *, size_t, struct vnode **)) -{ - struct vnode *vp; - int err; - - ZFS_OBJ_HOLD_ENTER(zfsvfs, obj_num); - - err = (*get)(zfsvfs->z_vfs, &obj_num, sizeof(obj_num), &vp); - if (err) - *zpp = NULL; - else - *zpp = VTOZ(vp); - - ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num); - - return (err); -} - int zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp) { + int error; + vnode_t *vp; + + error = vcache_get(zfsvfs->z_vfs, &obj_num, sizeof(obj_num), &vp); + if (error == 0) + *zpp = VTOZ(vp); - return zfs_do_zget(zfsvfs, obj_num, zpp, vcache_get); + return error; } int @@ -1215,176 +1326,6 @@ zfs_zget_cleaner(zfsvfs_t *zfsvfs, uint6 return (0); } -/* - * Callback from vcache to set up the znode. - * This is largely copied from zfs_znode_alloc(). - */ - -int -zfs_loadvnode(struct mount *mp, struct vnode *vp, - const void *key, size_t key_len, const void **new_key) -{ - znode_t *zp; - uint64_t mode; - uint64_t parent; - sa_bulk_attr_t bulk[9]; - int count = 0; - int err; - - uint64_t obj_num, rdev; - zfsvfs_t *zfsvfs; - dmu_object_info_t doi; - - /* args to zfs_zvnode_alloc() */ - struct zfs_loadvnode_args *args; - dmu_buf_t *db; - int blksz; - dmu_object_type_t obj_type; - sa_handle_t *hdl; - - KASSERT(key_len == sizeof(obj_num)); - memcpy(&obj_num, key, key_len); - - zfsvfs = mp->mnt_data; - - args = tsd_get(zfs_loadvnode_key); - if (args) { - db = args->db; - blksz = args->blksz; - obj_type = args->obj_type; - hdl = args->sa_hdl; - goto skip_lookup; - } - - err = sa_buf_hold(zfsvfs->z_os, obj_num, NULL, &db); - if (err) { - return (SET_ERROR(err)); - } - - dmu_object_info_from_db(db, &doi); - if (doi.doi_bonus_type != DMU_OT_SA && - (doi.doi_bonus_type != DMU_OT_ZNODE || - (doi.doi_bonus_type == DMU_OT_ZNODE && - doi.doi_bonus_size < sizeof (znode_phys_t)))) { - sa_buf_rele(db, NULL); - return (SET_ERROR(EINVAL)); - } - blksz = doi.doi_data_block_size; - obj_type = doi.doi_bonus_type; - hdl = dmu_buf_get_user(db); - - if (hdl != NULL) { - zp = sa_get_userdata(hdl); - - /* - * Since "SA" does immediate eviction we - * should never find a sa handle that doesn't - * know about the znode. - */ - ASSERT3P(zp, !=, NULL); - ASSERT3U(zp->z_id, ==, obj_num); - - sa_buf_rele(db, NULL); - VFS_HOLD(zfsvfs->z_vfs); - *new_key = &zp->z_id; - return (0); - } - -skip_lookup: - vp->v_op = zfs_vnodeop_p; - vp->v_tag = VT_ZFS; - - zp = kmem_cache_alloc(znode_cache, KM_SLEEP); - zp->z_vnode = vp; - vp->v_data = zp; - - extern const struct genfs_ops zfs_genfsops; - genfs_node_init(vp, &zfs_genfsops); - - ASSERT(!POINTER_IS_VALID(zp->z_zfsvfs)); - zp->z_moved = 0; - - /* - * Defer setting z_zfsvfs until the znode is ready to be a candidate for - * the zfs_znode_move() callback. - */ - zp->z_sa_hdl = NULL; - zp->z_unlinked = 0; - zp->z_atime_dirty = 0; - zp->z_mapcnt = 0; - zp->z_id = db->db_object; - zp->z_blksz = blksz; - zp->z_seq = 0x7A4653; - zp->z_sync_cnt = 0; - zp->z_lockf = NULL; - - zfs_znode_sa_init(zfsvfs, zp, db, obj_type, hdl); - - SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL, &mode, 8); - SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GEN(zfsvfs), NULL, &zp->z_gen, 8); - SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_SIZE(zfsvfs), NULL, - &zp->z_size, 8); - SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zfsvfs), NULL, - &zp->z_links, 8); - SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL, - &zp->z_pflags, 8); - SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_PARENT(zfsvfs), NULL, &parent, 8); - SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ATIME(zfsvfs), NULL, - &zp->z_atime, 16); - SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_UID(zfsvfs), NULL, - &zp->z_uid, 8); - SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GID(zfsvfs), NULL, - &zp->z_gid, 8); - - if (sa_bulk_lookup(zp->z_sa_hdl, bulk, count) != 0 || zp->z_gen == 0) { - if (hdl == NULL) - sa_handle_destroy(zp->z_sa_hdl); - zp->z_vnode = NULL; - kmem_cache_free(znode_cache, zp); - sa_buf_rele(db, NULL); - return (SET_ERROR(ENOENT)); - } - - zp->z_mode = mode; - - vp->v_type = IFTOVT((mode_t)zp->z_mode); - - switch (vp->v_type) { - case VDIR: - zp->z_zn_prefetch = B_TRUE; /* z_prefetch default is enabled */ - break; - case VBLK: - case VCHR: - /* XXX NetBSD vp->v_op = zfs_specop_p; */ - (void) sa_lookup(hdl, SA_ZPL_RDEV(zfsvfs), &rdev, - sizeof (rdev)); - spec_node_init(vp, zfs_cmpldev(rdev)); - break; - case VFIFO: - /* XXX NetBSD vp->v_op = zfs_fifoop_p; */ - break; - } - - uvm_vnp_setsize(vp, zp->z_size); - dprintf("zfs_loadvnode znode %p -- vnode %p\n", zp, vp); - dprintf("zfs_loadvnode z_id %ld\n", zp->z_id); - - mutex_enter(&zfsvfs->z_znodes_lock); - list_insert_tail(&zfsvfs->z_all_znodes, zp); - membar_producer(); - - /* - * Everything else must be valid before assigning z_zfsvfs makes the - * znode eligible for zfs_znode_move(). - */ - zp->z_zfsvfs = zfsvfs; - mutex_exit(&zfsvfs->z_znodes_lock); - - VFS_HOLD(zfsvfs->z_vfs); - *new_key = &zp->z_id; - return (0); -} - #else /* __NetBSD__ */ int Index: src/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_znode.h diff -u src/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_znode.h:1.8 src/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_znode.h:1.9 --- src/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_znode.h:1.8 Mon May 28 21:05:07 2018 +++ src/external/cddl/osnet/dist/uts/common/fs/zfs/sys/zfs_znode.h Tue Jan 1 10:08:00 2019 @@ -334,6 +334,8 @@ extern void zfs_znode_fini(void); #ifdef __NetBSD__ extern int zfs_loadvnode(struct mount *, struct vnode *, const void *, size_t, const void **); +extern int zfs_newvnode(struct mount *, struct vnode *, struct vnode *, + struct vattr *, kauth_cred_t, void *, size_t *, const void **); extern int zfs_zget_cleaner(zfsvfs_t *, uint64_t, znode_t **); #endif extern int zfs_zget(zfsvfs_t *, uint64_t, znode_t **);