diff --git a/module/os/linux/zfs/zfs_znode_os.c b/module/os/linux/zfs/zfs_znode_os.c index bc1e17f086d..86440b06e51 100644 --- a/module/os/linux/zfs/zfs_znode_os.c +++ b/module/os/linux/zfs/zfs_znode_os.c @@ -1053,7 +1053,6 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp) *zpp = NULL; -again: zh = zfs_znode_hold_enter(zfsvfs, obj_num); err = sa_buf_hold(zfsvfs->z_os, obj_num, NULL, &db); @@ -1076,7 +1075,6 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp) if (hdl != NULL) { zp = sa_get_userdata(hdl); - /* * Since "SA" does immediate eviction we * should never find a sa handle that doesn't @@ -1084,47 +1082,13 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp) */ ASSERT3P(zp, !=, NULL); + VERIFY3P(igrab(ZTOI(zp)), !=, NULL); + *zpp = zp; - mutex_enter(&zp->z_lock); - ASSERT3U(zp->z_id, ==, obj_num); - /* - * If zp->z_unlinked is set, the znode is already marked - * for deletion and should not be discovered. Check this - * after checking igrab() due to fsetxattr() & O_TMPFILE. - * - * If igrab() returns NULL the VFS has independently - * determined the inode should be evicted and has - * called iput_final() to start the eviction process. - * The SA handle is still valid but because the VFS - * requires that the eviction succeed we must drop - * our locks and references to allow the eviction to - * complete. The zfs_zget() may then be retried. - * - * This unlikely case could be optimized by registering - * a sops->drop_inode() callback. The callback would - * need to detect the active SA hold thereby informing - * the VFS that this inode should not be evicted. - */ - if (igrab(ZTOI(zp)) == NULL) { - if (zp->z_unlinked) - err = SET_ERROR(ENOENT); - else - err = SET_ERROR(EAGAIN); - } else { - *zpp = zp; - err = 0; - } - - mutex_exit(&zp->z_lock); sa_buf_rele(db, NULL); zfs_znode_hold_exit(zfsvfs, zh); - if (err == EAGAIN) { - /* inode might need this to finish evict */ - cond_resched(); - goto again; - } - return (err); + return 0; } /* diff --git a/module/os/linux/zfs/zpl_super.c b/module/os/linux/zfs/zpl_super.c index 287f5f36f9d..39071c0a5c0 100644 --- a/module/os/linux/zfs/zpl_super.c +++ b/module/os/linux/zfs/zpl_super.c @@ -378,12 +378,30 @@ zpl_prune_sb(uint64_t nr_to_scan, void *arg) (void) -zfs_prune(sb, nr_to_scan, &objects); } +static int +zpl_drop_inode(struct inode *ip) +{ + znode_t *zp = ITOZ(ip); + dmu_buf_t *db; + int error; + + if (!zp->z_unlinked && zp->z_sa_hdl && + (db = sa_get_db(zp->z_sa_hdl)) && + dmu_buf_refcount(db)) + return (0); + + error = generic_drop_inode(ip); + + return (error); +} + const struct super_operations zpl_super_operations = { .alloc_inode = zpl_inode_alloc, .destroy_inode = zpl_inode_destroy, .dirty_inode = zpl_dirty_inode, .write_inode = NULL, .evict_inode = zpl_evict_inode, + .drop_inode = zpl_drop_inode, .put_super = zpl_put_super, .sync_fs = zpl_sync_fs, .statfs = zpl_statfs,