diff --git a/include/os/linux/zfs/sys/zfs_znode_impl.h b/include/os/linux/zfs/sys/zfs_znode_impl.h index cc8e5150eaf..0a9f92152e8 100644 --- a/include/os/linux/zfs/sys/zfs_znode_impl.h +++ b/include/os/linux/zfs/sys/zfs_znode_impl.h @@ -48,6 +48,7 @@ extern "C" { #endif #define ZNODE_OS_FIELDS \ + boolean_t z_is_tmpfile; /* file is a tmpfile */ \ inode_timespec_t z_btime; /* creation/birth time (cached) */ \ struct inode z_inode; diff --git a/include/sys/zfs_znode.h b/include/sys/zfs_znode.h index 040bfbdac83..bed3e1aa5b4 100644 --- a/include/sys/zfs_znode.h +++ b/include/sys/zfs_znode.h @@ -192,7 +192,6 @@ typedef struct znode { boolean_t z_zn_prefetch; /* Prefetch znodes? */ boolean_t z_is_sa; /* are we native sa? */ boolean_t z_is_ctldir; /* are we .zfs entry */ - boolean_t z_suspended; /* extra ref from a suspend? */ uint_t z_blksz; /* block size in bytes */ uint_t z_seq; /* modification sequence number */ uint64_t z_mapcnt; /* number of pages mapped to file */ @@ -280,6 +279,7 @@ extern int zfs_zget(zfsvfs_t *, uint64_t, znode_t **); extern int zfs_rezget(znode_t *); extern void zfs_zinactive(znode_t *); extern void zfs_znode_delete(znode_t *, dmu_tx_t *); +extern void zfs_znode_delete_held(znode_t *, dmu_tx_t *); extern void zfs_remove_op_tables(void); extern int zfs_create_op_tables(void); extern dev_t zfs_cmpldev(uint64_t); diff --git a/module/os/linux/zfs/zfs_dir.c b/module/os/linux/zfs/zfs_dir.c index 564e89b37d1..5c2e9f63b22 100644 --- a/module/os/linux/zfs/zfs_dir.c +++ b/module/os/linux/zfs/zfs_dir.c @@ -654,8 +654,6 @@ zfs_rmnode(znode_t *zp) objset_t *os = zfsvfs->z_os; znode_t *xzp = NULL; dmu_tx_t *tx; - znode_hold_t *zh; - uint64_t z_id = zp->z_id; uint64_t acl_obj; uint64_t xattr_obj; uint64_t links; @@ -673,9 +671,7 @@ zfs_rmnode(znode_t *zp) * Not enough space to delete some xattrs. * Leave it in the unlinked set. */ - zh = zfs_znode_hold_enter(zfsvfs, z_id); zfs_znode_dmu_fini(zp); - zfs_znode_hold_exit(zfsvfs, zh); return; } } @@ -694,9 +690,7 @@ zfs_rmnode(znode_t *zp) * Not enough space or we were interrupted by unmount. * Leave the file in the unlinked set. */ - zh = zfs_znode_hold_enter(zfsvfs, z_id); zfs_znode_dmu_fini(zp); - zfs_znode_hold_exit(zfsvfs, zh); return; } } @@ -736,9 +730,7 @@ zfs_rmnode(znode_t *zp) * which point we'll call zfs_unlinked_drain() to process it). */ dmu_tx_abort(tx); - zh = zfs_znode_hold_enter(zfsvfs, z_id); zfs_znode_dmu_fini(zp); - zfs_znode_hold_exit(zfsvfs, zh); goto out; } @@ -775,7 +767,7 @@ zfs_rmnode(znode_t *zp) dataset_kstats_update_nunlinked_kstat(&zfsvfs->z_kstat, 1); - zfs_znode_delete(zp, tx); + zfs_znode_delete_held(zp, tx); dmu_tx_commit(tx); out: @@ -816,7 +808,8 @@ zfs_link_create(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag) mutex_enter(&zp->z_lock); if (!(flag & ZRENAMING)) { - if (zp->z_unlinked) { /* no new links to unlinked zp */ + if (zp->z_unlinked && !zp->z_is_tmpfile) { + /* no new links to unlinked zp */ ASSERT(!(flag & (ZNEW | ZEXISTS))); mutex_exit(&zp->z_lock); return (SET_ERROR(ENOENT)); diff --git a/module/os/linux/zfs/zfs_vfsops.c b/module/os/linux/zfs/zfs_vfsops.c index 3c53a8a315c..1e142c63232 100644 --- a/module/os/linux/zfs/zfs_vfsops.c +++ b/module/os/linux/zfs/zfs_vfsops.c @@ -1326,29 +1326,19 @@ zfsvfs_teardown(zfsvfs_t *zfsvfs, boolean_t unmounting) } /* - * At this point there are no VFS ops active, and any new VFS ops - * will fail with EIO since we have z_teardown_lock for writer (only + * At this point there are no vops active, and any new vops will + * fail with EIO since we have z_teardown_lock for writer (only * relevant for forced unmount). * - * Release all holds on dbufs. We also grab an extra reference to all - * the remaining inodes so that the kernel does not attempt to free - * any inodes of a suspended fs. This can cause deadlocks since the - * zfs_resume_fs() process may involve starting threads, which might - * attempt to free unreferenced inodes to free up memory for the new - * thread. + * Release all holds on dbufs. */ - if (!unmounting) { - mutex_enter(&zfsvfs->z_znodes_lock); - for (zp = list_head(&zfsvfs->z_all_znodes); zp != NULL; - zp = list_next(&zfsvfs->z_all_znodes, zp)) { - if (zp->z_sa_hdl) - zfs_znode_dmu_fini(zp); - if (igrab(ZTOI(zp)) != NULL) - zp->z_suspended = B_TRUE; - - } - mutex_exit(&zfsvfs->z_znodes_lock); + mutex_enter(&zfsvfs->z_znodes_lock); + for (zp = list_head(&zfsvfs->z_all_znodes); zp != NULL; + zp = list_next(&zfsvfs->z_all_znodes, zp)) { + if (zp->z_sa_hdl) + zfs_znode_dmu_fini(zp); } + mutex_exit(&zfsvfs->z_znodes_lock); /* * If we are unmounting, set the unmounted flag and let new VFS ops @@ -1717,7 +1707,7 @@ zfs_vget(struct super_block *sb, struct inode **ipp, fid_t *fidp) * Must have an existing ref, so igrab() * cannot return NULL */ - VERIFY3P(igrab(*ipp), !=, NULL); + zhold(ITOZ(*ipp)); } zfs_exit(zfsvfs, FTAG); return (0); @@ -1790,7 +1780,7 @@ zfs_suspend_fs(zfsvfs_t *zfsvfs) int zfs_resume_fs(zfsvfs_t *zfsvfs, dsl_dataset_t *ds) { - int err, err2; + int err; znode_t *zp; ASSERT(ZFS_TEARDOWN_WRITE_HELD(zfsvfs)); @@ -1827,20 +1817,11 @@ zfs_resume_fs(zfsvfs_t *zfsvfs, dsl_dataset_t *ds) * VFS prunes the dentry holding the remaining references * on the stale inode. */ + pr_info("Resuming file system: rezget\n"); mutex_enter(&zfsvfs->z_znodes_lock); for (zp = list_head(&zfsvfs->z_all_znodes); zp; zp = list_next(&zfsvfs->z_all_znodes, zp)) { - err2 = zfs_rezget(zp); - if (err2) { - zpl_d_drop_aliases(ZTOI(zp)); - remove_inode_hash(ZTOI(zp)); - } - - /* see comment in zfs_suspend_fs() */ - if (zp->z_suspended) { - zfs_zrele_async(zp); - zp->z_suspended = B_FALSE; - } + (void) zfs_rezget(zp); } mutex_exit(&zfsvfs->z_znodes_lock); diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c index 46919722085..35e5a79577a 100644 --- a/module/os/linux/zfs/zfs_vnops_os.c +++ b/module/os/linux/zfs/zfs_vnops_os.c @@ -768,7 +768,6 @@ zfs_create(znode_t *dzp, char *name, vattr_t *vap, int excl, * delete the newly created dnode. */ zfs_znode_delete(zp, tx); - remove_inode_hash(ZTOI(zp)); zfs_acl_ids_free(&acl_ids); dmu_tx_commit(tx); goto out; @@ -954,9 +953,6 @@ zfs_tmpfile(struct inode *dip, vattr_t *vap, int excl, if (fuid_dirtied) zfs_fuid_sync(zfsvfs, tx); - /* Add to unlinked set */ - zp->z_unlinked = B_TRUE; - zfs_unlinked_add(zp, tx); zfs_acl_ids_free(&acl_ids); dmu_tx_commit(tx); out: @@ -1372,7 +1368,6 @@ zfs_mkdir(znode_t *dzp, char *dirname, vattr_t *vap, znode_t **zpp, error = zfs_link_create(dl, zp, tx, ZNEW); if (error != 0) { zfs_znode_delete(zp, tx); - remove_inode_hash(ZTOI(zp)); goto out; } @@ -3177,10 +3172,12 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, zfs_mknode(sdzp, wo_vap, tx, cr, 0, &wzp, &acl_ids); error = zfs_link_create(sdl, wzp, tx, ZNEW); if (error) { + unlock_new_inode(ZTOI(wzp)); zfs_znode_delete(wzp, tx); - remove_inode_hash(ZTOI(wzp)); goto commit_unlink_td_szp; } + VERIFY0(insert_inode_locked(ZTOI(wzp))); + unlock_new_inode(ZTOI(wzp)); break; } @@ -3415,7 +3412,6 @@ zfs_symlink(znode_t *dzp, char *name, vattr_t *vap, char *link, error = zfs_link_create(dl, zp, tx, ZNEW); if (error != 0) { zfs_znode_delete(zp, tx); - remove_inode_hash(ZTOI(zp)); } else { if (flags & FIGNORECASE) txtype |= TX_CI; @@ -3512,11 +3508,8 @@ zfs_link(znode_t *tdzp, znode_t *szp, char *name, cred_t *cr, uint64_t parent; uid_t owner; boolean_t waited = B_FALSE; - boolean_t is_tmpfile = 0; uint64_t txg; - is_tmpfile = (sip->i_nlink == 0 && (sip->i_state & I_LINKABLE)); - ASSERT(S_ISDIR(ZTOI(tdzp)->i_mode)); if (name == NULL) @@ -3619,7 +3612,7 @@ zfs_link(znode_t *tdzp, znode_t *szp, char *name, cred_t *cr, tx = dmu_tx_create(zfsvfs->z_os); dmu_tx_hold_sa(tx, szp->z_sa_hdl, B_FALSE); dmu_tx_hold_zap(tx, tdzp->z_id, TRUE, name); - if (is_tmpfile) + if (szp->z_is_tmpfile && szp->z_unlinked) dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL); zfs_sa_upgrade_txholds(tx, szp); @@ -3637,41 +3630,43 @@ zfs_link(znode_t *tdzp, znode_t *szp, char *name, cred_t *cr, zfs_exit(zfsvfs, FTAG); return (error); } - /* unmark z_unlinked so zfs_link_create will not reject */ - if (is_tmpfile) - szp->z_unlinked = B_FALSE; error = zfs_link_create(dl, szp, tx, 0); if (error == 0) { uint64_t txtype = TX_LINK; /* - * tmpfile is created to be in z_unlinkedobj, so remove it. - * Also, we don't log in ZIL, because all previous file + * We don't log tmpfile in ZIL, because all previous file * operation on the tmpfile are ignored by ZIL. Instead we * always wait for txg to sync to make sure all previous * operation are sync safe. */ - if (is_tmpfile) { - VERIFY(zap_remove_int(zfsvfs->z_os, - zfsvfs->z_unlinkedobj, szp->z_id, tx) == 0); - } else { + if (!szp->z_is_tmpfile || !szp->z_unlinked) { if (flags & FIGNORECASE) txtype |= TX_CI; zfs_log_link(zilog, tx, txtype, tdzp, szp, name); } - } else if (is_tmpfile) { - /* restore z_unlinked since when linking failed */ - szp->z_unlinked = B_TRUE; + if (szp->z_is_tmpfile) { + mutex_enter(&szp->z_lock); + if (szp->z_unlinked) { + szp->z_unlinked = B_FALSE; + VERIFY0(zap_remove_int(zfsvfs->z_os, + zfsvfs->z_unlinkedobj, + szp->z_id, tx)); + } + mutex_exit(&szp->z_lock); + } } txg = dmu_tx_get_txg(tx); dmu_tx_commit(tx); zfs_dirent_unlock(dl); - if (!is_tmpfile && zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) + if ((!szp->z_is_tmpfile || !szp->z_unlinked) && + zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) zil_commit(zilog, 0); - if (is_tmpfile && zfsvfs->z_os->os_sync != ZFS_SYNC_DISABLED) + if (szp->z_is_tmpfile && szp->z_unlinked && + (zfsvfs->z_os->os_sync != ZFS_SYNC_DISABLED)) txg_wait_synced(dmu_objset_pool(zfsvfs->z_os), txg); zfs_znode_update_vfs(tdzp); @@ -4024,6 +4019,10 @@ zfs_inactive(struct inode *ip) need_unlock = 1; rw_enter(&zfsvfs->z_teardown_inactive_lock, RW_READER); } + + truncate_setsize(ip, 0); + clear_inode(ip); + if (zp->z_sa_hdl == NULL) { if (need_unlock) rw_exit(&zfsvfs->z_teardown_inactive_lock); diff --git a/module/os/linux/zfs/zfs_znode_os.c b/module/os/linux/zfs/zfs_znode_os.c index 631fa134c30..1a9aea5225c 100644 --- a/module/os/linux/zfs/zfs_znode_os.c +++ b/module/os/linux/zfs/zfs_znode_os.c @@ -379,6 +379,7 @@ zfs_inode_destroy(struct inode *ip) znode_t *zp = ITOZ(ip); zfsvfs_t *zfsvfs = ZTOZSB(zp); + VERIFY0(atomic_read(&ip->i_count)); mutex_enter(&zfsvfs->z_znodes_lock); if (list_link_active(&zp->z_link_node)) { list_remove(&zfsvfs->z_all_znodes, zp); @@ -525,9 +526,9 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, ASSERT3P(zp->z_acl_cached, ==, NULL); ASSERT3P(zp->z_xattr_cached, ==, NULL); zp->z_unlinked = B_FALSE; + zp->z_is_tmpfile = B_FALSE; zp->z_atime_dirty = B_FALSE; zp->z_is_ctldir = B_FALSE; - zp->z_suspended = B_FALSE; zp->z_sa_hdl = NULL; zp->z_mapcnt = 0; zp->z_id = db->db_object; @@ -569,6 +570,7 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, zp->z_mode = ip->i_mode = mode; ip->i_generation = (uint32_t)tmp_gen; ip->i_blkbits = SPA_MINBLOCKSHIFT; + atomic_set(&ip->i_count, 1); set_nlink(ip, (uint32_t)links); zfs_uid_write(ip, z_uid); zfs_gid_write(ip, z_gid); @@ -590,28 +592,10 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, zfs_znode_update_vfs(zp); zfs_inode_set_ops(zfsvfs, ip); - /* - * The only way insert_inode_locked() can fail is if the ip->i_ino - * number is already hashed for this super block. This can never - * happen because the inode numbers map 1:1 with the object numbers. - * - * Exceptions include rolling back a mounted file system, either - * from the zfs rollback or zfs recv command. - * - * Active inodes are unhashed during the rollback, but since zrele - * can happen asynchronously, we can't guarantee they've been - * unhashed. This can cause hash collisions in unlinked drain - * processing so do not hash unlinked znodes. - */ - if (links > 0) - VERIFY3S(insert_inode_locked(ip), ==, 0); - mutex_enter(&zfsvfs->z_znodes_lock); list_insert_tail(&zfsvfs->z_all_znodes, zp); mutex_exit(&zfsvfs->z_znodes_lock); - if (links > 0) - unlock_new_inode(ip); return (zp); error: @@ -916,6 +900,7 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr, * passed in is the znode for the root. */ *zpp = dzp; + zhold(*zpp); (*zpp)->z_sa_hdl = sa_hdl; } @@ -924,6 +909,12 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr, (*zpp)->z_mode = ZTOI(*zpp)->i_mode = mode; (*zpp)->z_dnodesize = dnodesize; (*zpp)->z_projid = projid; + if (flag & IS_TMPFILE) { + (*zpp)->z_is_tmpfile = B_TRUE; + /* Add to unlinked set */ + (*zpp)->z_unlinked = B_TRUE; + zfs_unlinked_add((*zpp), tx); + } if (obj_type == DMU_OT_ZNODE || acl_ids->z_aclp->z_version < ZFS_ACL_VERSION_FUID) { @@ -1106,7 +1097,7 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp) * the VFS that this inode should not be evicted. */ if (igrab(ZTOI(zp)) == NULL) { - if (zp->z_unlinked) + if (!zp->z_is_tmpfile && zp->z_unlinked) err = SET_ERROR(ENOENT); else err = SET_ERROR(EAGAIN); @@ -1143,6 +1134,8 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp) err = SET_ERROR(ENOENT); } else { *zpp = zp; + VERIFY0(insert_inode_locked(ZTOI(zp))); + unlock_new_inode(ZTOI(zp)); } zfs_znode_hold_exit(zfsvfs, zh); return (err); @@ -1195,10 +1188,8 @@ zfs_rezget(znode_t *zp) ASSERT(zp->z_sa_hdl == NULL); err = sa_buf_hold(zfsvfs->z_os, obj_num, NULL, &db); - if (err) { - zfs_znode_hold_exit(zfsvfs, zh); - return (err); - } + if (err) + goto error; dmu_object_info_from_db(db, &doi); if (doi.doi_bonus_type != DMU_OT_SA && @@ -1206,8 +1197,8 @@ zfs_rezget(znode_t *zp) (doi.doi_bonus_type == DMU_OT_ZNODE && doi.doi_bonus_size < sizeof (znode_phys_t)))) { sa_buf_rele(db, NULL); - zfs_znode_hold_exit(zfsvfs, zh); - return (SET_ERROR(EINVAL)); + err = SET_ERROR(EINVAL); + goto error; } zfs_znode_sa_init(zfsvfs, zp, db, doi.doi_bonus_type, NULL); @@ -1237,8 +1228,8 @@ zfs_rezget(znode_t *zp) if (sa_bulk_lookup(zp->z_sa_hdl, bulk, count)) { zfs_znode_dmu_fini(zp); - zfs_znode_hold_exit(zfsvfs, zh); - return (SET_ERROR(EIO)); + err = SET_ERROR(EIO); + goto error; } if (dmu_objset_projectquota_enabled(zfsvfs->z_os)) { @@ -1246,8 +1237,8 @@ zfs_rezget(znode_t *zp) &projid, 8); if (err != 0 && err != ENOENT) { zfs_znode_dmu_fini(zp); - zfs_znode_hold_exit(zfsvfs, zh); - return (SET_ERROR(err)); + err = SET_ERROR(err); + goto error; } } @@ -1266,8 +1257,8 @@ zfs_rezget(znode_t *zp) if ((uint32_t)gen != ZTOI(zp)->i_generation) { zfs_znode_dmu_fini(zp); - zfs_znode_hold_exit(zfsvfs, zh); - return (SET_ERROR(EIO)); + err = SET_ERROR(EIO); + goto error; } set_nlink(ZTOI(zp), (uint32_t)links); @@ -1293,24 +1284,37 @@ zfs_rezget(znode_t *zp) zfs_znode_hold_exit(zfsvfs, zh); return (0); + +error: + zpl_d_drop_aliases(ZTOI(zp)); + remove_inode_hash(ZTOI(zp)); + zfs_znode_hold_exit(zfsvfs, zh); + return (err); } void -zfs_znode_delete(znode_t *zp, dmu_tx_t *tx) +zfs_znode_delete_held(znode_t *zp, dmu_tx_t *tx) { - zfsvfs_t *zfsvfs = ZTOZSB(zp); - objset_t *os = zfsvfs->z_os; + objset_t *os = ZTOZSB(zp)->z_os; uint64_t obj = zp->z_id; uint64_t acl_obj = zfs_external_acl(zp); - znode_hold_t *zh; - zh = zfs_znode_hold_enter(zfsvfs, obj); if (acl_obj) { VERIFY(!zp->z_is_sa); VERIFY(0 == dmu_object_free(os, acl_obj, tx)); } VERIFY(0 == dmu_object_free(os, obj, tx)); zfs_znode_dmu_fini(zp); +} + +void +zfs_znode_delete(znode_t *zp, dmu_tx_t *tx) +{ + zfsvfs_t *zfsvfs = ZTOZSB(zp); + znode_hold_t *zh; + + zh = zfs_znode_hold_enter(zfsvfs, zp->z_id); + zfs_znode_delete_held(zp, tx); zfs_znode_hold_exit(zfsvfs, zh); } @@ -1329,7 +1333,6 @@ zfs_zinactive(znode_t *zp) zh = zfs_znode_hold_enter(zfsvfs, z_id); mutex_enter(&zp->z_lock); - /* * If this was the last reference to a file with no links, remove * the file from the file system unless the file system is mounted @@ -1342,15 +1345,14 @@ zfs_zinactive(znode_t *zp) ASSERT(!zfsvfs->z_issnap); if (!zfs_is_readonly(zfsvfs) && !zfs_unlink_suspend_progress) { mutex_exit(&zp->z_lock); - zfs_znode_hold_exit(zfsvfs, zh); zfs_rmnode(zp); + zfs_znode_hold_exit(zfsvfs, zh); return; } } mutex_exit(&zp->z_lock); zfs_znode_dmu_fini(zp); - zfs_znode_hold_exit(zfsvfs, zh); } diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 29c9227e55e..b27ae5a4a04 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -199,10 +199,10 @@ zpl_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool flag) if (error) { (void) zfs_remove(ITOZ(dir), dname(dentry), cr, 0); - remove_inode_hash(ZTOI(zp)); - iput(ZTOI(zp)); } else { + VERIFY0(insert_inode_locked(ZTOI(zp))); d_instantiate(dentry, ZTOI(zp)); + unlock_new_inode(ZTOI(zp)); } } @@ -261,10 +261,10 @@ zpl_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, if (error) { (void) zfs_remove(ITOZ(dir), dname(dentry), cr, 0); - remove_inode_hash(ZTOI(zp)); - iput(ZTOI(zp)); } else { + VERIFY0(insert_inode_locked(ZTOI(zp))); d_instantiate(dentry, ZTOI(zp)); + unlock_new_inode(ZTOI(zp)); } } @@ -314,22 +314,28 @@ zpl_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) cookie = spl_fstrans_mark(); error = -zfs_tmpfile(dir, vap, 0, mode, &ip, cr, 0, NULL, userns); if (error == 0) { - /* d_tmpfile will do drop_nlink, so we should set it first */ - set_nlink(ip, 1); #ifndef HAVE_TMPFILE_DENTRY - d_tmpfile(file, ip); - error = zpl_xattr_security_init(ip, dir, &file->f_path.dentry->d_name); + if (error == 0) + error = zpl_init_acl(ip, dir); + if (error == 0) { + VERIFY0(insert_inode_locked(ip)); + inc_nlink(ip); + d_tmpfile(file, ip); + unlock_new_inode(ip); + } + error = finish_open_simple(file, error); #else - d_tmpfile(dentry, ip); - error = zpl_xattr_security_init(ip, dir, &dentry->d_name); -#endif if (error == 0) error = zpl_init_acl(ip, dir); -#ifndef HAVE_TMPFILE_DENTRY - error = finish_open_simple(file, error); + if (error == 0) { + VERIFY0(insert_inode_locked(ip)); + inc_nlink(ip); + d_tmpfile(dentry, ip); + unlock_new_inode(ip); + } #endif /* * don't need to handle error here, file is already in @@ -409,10 +415,10 @@ zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) if (error) { (void) zfs_rmdir(ITOZ(dir), dname(dentry), NULL, cr, 0); - remove_inode_hash(ZTOI(zp)); - iput(ZTOI(zp)); } else { + VERIFY0(insert_inode_locked(ZTOI(zp))); d_instantiate(dentry, ZTOI(zp)); + unlock_new_inode(ZTOI(zp)); } } @@ -679,10 +685,10 @@ zpl_symlink(struct inode *dir, struct dentry *dentry, const char *name) error = zpl_xattr_security_init(ZTOI(zp), dir, &dentry->d_name); if (error) { (void) zfs_remove(ITOZ(dir), dname(dentry), cr, 0); - remove_inode_hash(ZTOI(zp)); - iput(ZTOI(zp)); } else { + VERIFY0(insert_inode_locked(ZTOI(zp))); d_instantiate(dentry, ZTOI(zp)); + unlock_new_inode(ZTOI(zp)); } } @@ -767,7 +773,7 @@ static int zpl_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { cred_t *cr = CRED(); - struct inode *ip = old_dentry->d_inode; + znode_t *zp = ITOZ(old_dentry->d_inode); int error; fstrans_cookie_t cookie; @@ -775,22 +781,22 @@ zpl_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) return (-ENAMETOOLONG); } - if (ip->i_nlink >= ZFS_LINK_MAX) + if (ZTOI(zp)->i_nlink >= ZFS_LINK_MAX) return (-EMLINK); crhold(cr); - zpl_inode_set_ctime_to_ts(ip, current_time(ip)); + zpl_inode_set_ctime_to_ts(ZTOI(zp), current_time(ZTOI(zp))); /* Must have an existing ref, so igrab() cannot return NULL */ - VERIFY3P(igrab(ip), !=, NULL); + zhold(zp); cookie = spl_fstrans_mark(); - error = -zfs_link(ITOZ(dir), ITOZ(ip), dname(dentry), cr, 0); + error = -zfs_link(ITOZ(dir), zp, dname(dentry), cr, 0); if (error) { - iput(ip); + zrele(zp); goto out; } - d_instantiate(dentry, ip); + d_instantiate(dentry, ZTOI(zp)); out: spl_fstrans_unmark(cookie); crfree(cr); diff --git a/module/os/linux/zfs/zpl_super.c b/module/os/linux/zfs/zpl_super.c index 6536296d045..317c6874d28 100644 --- a/module/os/linux/zfs/zpl_super.c +++ b/module/os/linux/zfs/zpl_super.c @@ -86,8 +86,6 @@ zpl_evict_inode(struct inode *ip) fstrans_cookie_t cookie; cookie = spl_fstrans_mark(); - truncate_setsize(ip, 0); - clear_inode(ip); zfs_inactive(ip); spl_fstrans_unmark(cookie); }