aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Motin <[email protected]>2024-05-16 20:56:55 -0400
committerGitHub <[email protected]>2024-05-16 17:56:55 -0700
commitefbef9e6cc1e14cc19a24b76175f7ec86610161a (patch)
tree2ebe4dce4c48af9c3fc04910865e7865e41412a7
parentfec16b93c46d80ae60a4f20632932601030b6fc0 (diff)
FreeBSD: Add zfs_link_create() error handling
Originally Solaris didn't expect errors there, but they may happen if we fail to add entry into ZAP. Linux fixed it in #7421, but it was never fully ported to FreeBSD. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Alexander Motin <[email protected]> Sponsored-By: iXsystems, Inc. Closes #13215 Closes #16138
-rw-r--r--module/os/freebsd/zfs/zfs_dir.c1
-rw-r--r--module/os/freebsd/zfs/zfs_vnops_os.c54
-rw-r--r--module/os/freebsd/zfs/zfs_znode.c1
-rwxr-xr-xtests/test-runner/bin/zts-report.py.in1
4 files changed, 43 insertions, 14 deletions
diff --git a/module/os/freebsd/zfs/zfs_dir.c b/module/os/freebsd/zfs/zfs_dir.c
index 948df8e50..3cdb94d6c 100644
--- a/module/os/freebsd/zfs/zfs_dir.c
+++ b/module/os/freebsd/zfs/zfs_dir.c
@@ -543,6 +543,7 @@ zfs_rmnode(znode_t *zp)
dataset_kstats_update_nunlinked_kstat(&zfsvfs->z_kstat, 1);
zfs_znode_delete(zp, tx);
+ zfs_znode_free(zp);
dmu_tx_commit(tx);
diff --git a/module/os/freebsd/zfs/zfs_vnops_os.c b/module/os/freebsd/zfs/zfs_vnops_os.c
index d9a8c8a0d..b9b332434 100644
--- a/module/os/freebsd/zfs/zfs_vnops_os.c
+++ b/module/os/freebsd/zfs/zfs_vnops_os.c
@@ -1175,10 +1175,25 @@ zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode,
return (error);
}
zfs_mknode(dzp, vap, tx, cr, 0, &zp, &acl_ids);
+
+ error = zfs_link_create(dzp, name, zp, tx, ZNEW);
+ if (error != 0) {
+ /*
+ * Since, we failed to add the directory entry for it,
+ * delete the newly created dnode.
+ */
+ zfs_znode_delete(zp, tx);
+ VOP_UNLOCK1(ZTOV(zp));
+ zrele(zp);
+ zfs_acl_ids_free(&acl_ids);
+ dmu_tx_commit(tx);
+ getnewvnode_drop_reserve();
+ goto out;
+ }
+
if (fuid_dirtied)
zfs_fuid_sync(zfsvfs, tx);
- (void) zfs_link_create(dzp, name, zp, tx, ZNEW);
txtype = zfs_log_create_txtype(Z_FILE, vsecp, vap);
zfs_log_create(zilog, tx, txtype, dzp, zp, name,
vsecp, acl_ids.z_fuidp, vap);
@@ -1526,13 +1541,19 @@ zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, znode_t **zpp,
*/
zfs_mknode(dzp, vap, tx, cr, 0, &zp, &acl_ids);
- if (fuid_dirtied)
- zfs_fuid_sync(zfsvfs, tx);
-
/*
* Now put new name in parent dir.
*/
- (void) zfs_link_create(dzp, dirname, zp, tx, ZNEW);
+ error = zfs_link_create(dzp, dirname, zp, tx, ZNEW);
+ if (error != 0) {
+ zfs_znode_delete(zp, tx);
+ VOP_UNLOCK1(ZTOV(zp));
+ zrele(zp);
+ goto out;
+ }
+
+ if (fuid_dirtied)
+ zfs_fuid_sync(zfsvfs, tx);
*zpp = zp;
@@ -1540,6 +1561,7 @@ zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, znode_t **zpp,
zfs_log_create(zilog, tx, txtype, dzp, zp, dirname, NULL,
acl_ids.z_fuidp, vap);
+out:
zfs_acl_ids_free(&acl_ids);
dmu_tx_commit(tx);
@@ -1550,7 +1572,7 @@ zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, znode_t **zpp,
zil_commit(zilog, 0);
zfs_exit(zfsvfs, FTAG);
- return (0);
+ return (error);
}
#if __FreeBSD_version < 1300124
@@ -3586,10 +3608,14 @@ zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap,
/*
* Insert the new object into the directory.
*/
- (void) zfs_link_create(dzp, name, zp, tx, ZNEW);
-
- zfs_log_symlink(zilog, tx, txtype, dzp, zp, name, link);
- *zpp = zp;
+ error = zfs_link_create(dzp, name, zp, tx, ZNEW);
+ if (error != 0) {
+ zfs_znode_delete(zp, tx);
+ VOP_UNLOCK1(ZTOV(zp));
+ zrele(zp);
+ } else {
+ zfs_log_symlink(zilog, tx, txtype, dzp, zp, name, link);
+ }
zfs_acl_ids_free(&acl_ids);
@@ -3597,8 +3623,12 @@ zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap,
getnewvnode_drop_reserve();
- if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
- zil_commit(zilog, 0);
+ if (error == 0) {
+ *zpp = zp;
+
+ if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
+ zil_commit(zilog, 0);
+ }
zfs_exit(zfsvfs, FTAG);
return (error);
diff --git a/module/os/freebsd/zfs/zfs_znode.c b/module/os/freebsd/zfs/zfs_znode.c
index 0d4c94555..0eea2a849 100644
--- a/module/os/freebsd/zfs/zfs_znode.c
+++ b/module/os/freebsd/zfs/zfs_znode.c
@@ -1234,7 +1234,6 @@ zfs_znode_delete(znode_t *zp, dmu_tx_t *tx)
VERIFY0(dmu_object_free(os, obj, tx));
zfs_znode_dmu_fini(zp);
ZFS_OBJ_HOLD_EXIT(zfsvfs, obj);
- zfs_znode_free(zp);
}
void
diff --git a/tests/test-runner/bin/zts-report.py.in b/tests/test-runner/bin/zts-report.py.in
index ecc50f487..5ca130931 100755
--- a/tests/test-runner/bin/zts-report.py.in
+++ b/tests/test-runner/bin/zts-report.py.in
@@ -182,7 +182,6 @@ if sys.platform.startswith('freebsd'):
'cli_root/zfs_unshare/zfs_unshare_008_pos': ['SKIP', na_reason],
'cp_files/cp_files_002_pos': ['SKIP', na_reason],
'link_count/link_count_001': ['SKIP', na_reason],
- 'casenorm/mixed_create_failure': ['FAIL', 13215],
'mmap/mmap_sync_001_pos': ['SKIP', na_reason],
'rsend/send_raw_ashift': ['SKIP', 14961],
})