aboutsummaryrefslogtreecommitdiffstats
path: root/module/os/freebsd/zfs/zfs_vnops_os.c
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 /module/os/freebsd/zfs/zfs_vnops_os.c
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
Diffstat (limited to 'module/os/freebsd/zfs/zfs_vnops_os.c')
-rw-r--r--module/os/freebsd/zfs/zfs_vnops_os.c54
1 files changed, 42 insertions, 12 deletions
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);