git: 262fa4695d90 - main - stand: Implement zfs_dnode_readlink in terms of zfs_dnode_sa_lookup

From: Warner Losh <imp_at_FreeBSD.org>
Date: Sat, 03 Oct 2026 17:34:58 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=262fa4695d90207b9080f2cc5cb01eccf07fe243

commit 262fa4695d90207b9080f2cc5cb01eccf07fe243
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2026-10-03 14:42:58 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2026-10-03 17:32:08 +0000

    stand: Implement zfs_dnode_readlink in terms of zfs_dnode_sa_lookup
    
    Get the link offset using the zfs_dnode_sa_lookup helper now.
    
    Recently, the symbolic links we rely on in the boot loader have stopped
    working.
    
    Prior to OpenZFS commit e90badec11d3 ("Inherit the project ID for every
    object type", Matt Turner, 2026-08-14), symbolic link information was
    written at a fixed offset in the SA data. Since that commit, the
    inherited PROJIDs mean that all pools with quota enabled have started
    writing symbolic links with a new, non-fixed offset. Old symbolic links
    remained unchanged, but new ones were written with a different
    offset. At work, we have all these things: rewritten BEs, quotas, and a
    dependence on symbolic links in our boot path.
    
    This came in on 2026-08-24 OpenZFS merge (22649d4dba73). This was 12
    hours after stab week for August, so we didn't hit this until the
    September stab week. Since the new kernel has to write links at the new
    offset, the initial tests worked, but the second ones didn't.
    
    Sponsored by:           Netflix
    Differential Revision:  https://reviews.freebsd.org/D60268
---
 stand/libsa/zfs/zfsimpl.c | 35 ++++-------------------------------
 1 file changed, 4 insertions(+), 31 deletions(-)

diff --git a/stand/libsa/zfs/zfsimpl.c b/stand/libsa/zfs/zfsimpl.c
index a13f8d805049..5447fd825c24 100644
--- a/stand/libsa/zfs/zfsimpl.c
+++ b/stand/libsa/zfs/zfsimpl.c
@@ -3995,38 +3995,11 @@ zfs_dnode_readlink(struct zfsmount *mount, dnode_phys_t *dn, char *path,
 	int rc = 0;
 
 	if (dn->dn_bonustype == DMU_OT_SA) {
-		sa_hdr_phys_t *sahdrp = NULL;
-		size_t size = 0;
-		void *buf = NULL;
-		int hdrsize;
-		char *p;
-
-		if (dn->dn_bonuslen != 0) {
-			sahdrp = (sa_hdr_phys_t *)DN_BONUS(dn);
-		} else {
-			blkptr_t *bp;
-
-			if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) == 0)
-				return (EIO);
-			bp = DN_SPILL_BLKPTR(dn);
+		size_t size = psize;
 
-			size = BP_GET_LSIZE(bp);
-			buf = malloc(size);
-			if (buf == NULL)
-				rc = ENOMEM;
-			else
-				rc = zio_read(mount->spa, bp, buf);
-			if (rc != 0) {
-				free(buf);
-				return (rc);
-			}
-			sahdrp = buf;
-		}
-		hdrsize = SA_HDR_SIZE(sahdrp);
-		p = (char *)((uintptr_t)sahdrp + hdrsize + SA_SYMLINK_OFFSET);
-		memcpy(path, p, psize);
-		free(buf);
-		return (0);
+		rc = zfs_dnode_sa_lookup(mount, dn, ZFS_SA_SYMLINK, path,
+		    &size);
+		return (rc != 0 ? rc : (size == psize ? 0 : EIO));
 	}
 	/*
 	 * Second test is purely to silence bogus compiler