git: a11d132f6c62 - main - devstat: Provide 32-bit compatibility

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Mon, 26 Jan 2026 12:02:02 UTC
The branch main has been updated by des:

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

commit a11d132f6c62f32abe44b19f7527d97ddc239058
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2026-01-26 12:01:39 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2026-01-26 12:01:59 +0000

    devstat: Provide 32-bit compatibility
    
    If a 32-bit process running on a 64-bit kernel requests kern.devstat.all,
    translate each struct devstat to its 32-bit equivalent before copying it
    out.
    
    Also fix a bug where an early error would be ignored if there were no
    devices to report.
    
    MFC after:      1 week
    Reviewed by:    kib
    Differential Revision:  https://reviews.freebsd.org/D54591
---
 sys/compat/freebsd32/freebsd32.h | 27 +++++++++++++++++++
 sys/kern/subr_devstat.c          | 56 +++++++++++++++++++++++++++++++++++-----
 2 files changed, 76 insertions(+), 7 deletions(-)

diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h
index 7d21a5be5570..a8d54290980d 100644
--- a/sys/compat/freebsd32/freebsd32.h
+++ b/sys/compat/freebsd32/freebsd32.h
@@ -29,7 +29,10 @@
 #ifndef _COMPAT_FREEBSD32_FREEBSD32_H_
 #define _COMPAT_FREEBSD32_FREEBSD32_H_
 
+#include <sys/cdefs.h>
 #include <sys/abi_compat.h>
+#include <sys/devicestat.h>
+#include <sys/mount.h>
 #include <sys/procfs.h>
 #include <sys/socket.h>
 #include <sys/user.h>
@@ -540,4 +543,28 @@ struct ptrace_sc_remote32 {
 	uint32_t	pscr_args;
 };
 
+struct devstat32 {
+	u_int			sequence0;
+	int			allocated;
+	u_int			start_count;
+	u_int			end_count;
+	struct bintime32	busy_from;
+	struct { u_int32_t stqe_next; } dev_links;
+	u_int32_t		device_number;
+	char			device_name[DEVSTAT_NAME_LEN];
+	int			unit_number;
+	freebsd32_uint64_t	bytes[DEVSTAT_N_TRANS_FLAGS];
+	freebsd32_uint64_t	operations[DEVSTAT_N_TRANS_FLAGS];
+	struct bintime32	duration[DEVSTAT_N_TRANS_FLAGS];
+	struct bintime32	busy_time;
+	struct bintime32        creation_time;
+	u_int32_t		block_size;
+	freebsd32_uint64_t	tag_types[3];
+	devstat_support_flags	flags;
+	devstat_type_flags	device_type;
+	devstat_priority	priority;
+	u_int32_t		id;
+	u_int			sequence1;
+};
+
 #endif /* !_COMPAT_FREEBSD32_FREEBSD32_H_ */
diff --git a/sys/kern/subr_devstat.c b/sys/kern/subr_devstat.c
index c4d0223d484f..c62df0e210e1 100644
--- a/sys/kern/subr_devstat.c
+++ b/sys/kern/subr_devstat.c
@@ -43,6 +43,10 @@
 #include <vm/vm.h>
 #include <vm/pmap.h>
 
+#ifdef COMPAT_FREEBSD32
+#include <compat/freebsd32/freebsd32.h>
+#endif
+
 #include <machine/atomic.h>
 
 SDT_PROVIDER_DEFINE(io);
@@ -398,25 +402,63 @@ sysctl_devstat(SYSCTL_HANDLER_ARGS)
 	 */
 	mygen = devstat_generation;
 
-	error = SYSCTL_OUT(req, &mygen, sizeof(mygen));
-
-	if (devstat_num_devs == 0)
-		return(0);
+#ifdef COMPAT_FREEBSD32
+	if ((req->flags & SCTL_MASK32) != 0) {
+		int32_t mygen32 = (int32_t)mygen;
 
+		error = SYSCTL_OUT(req, &mygen32, sizeof(mygen32));
+	} else
+#endif /* COMPAT_FREEBSD32 */
+		error = SYSCTL_OUT(req, &mygen, sizeof(mygen));
 	if (error != 0)
 		return (error);
 
+	if (devstat_num_devs == 0)
+		return(0);
+
 	mtx_lock(&devstat_mutex);
 	nds = STAILQ_FIRST(&device_statq); 
 	if (mygen != devstat_generation)
 		error = EBUSY;
 	mtx_unlock(&devstat_mutex);
-
 	if (error != 0)
 		return (error);
 
 	while (nds != NULL) {
-		error = SYSCTL_OUT(req, nds, sizeof(struct devstat));
+#ifdef COMPAT_FREEBSD32
+		if ((req->flags & SCTL_MASK32) != 0) {
+			struct devstat32 ds32;
+			unsigned int i;
+
+			CP(*nds, ds32, sequence0);
+			CP(*nds, ds32, allocated);
+			CP(*nds, ds32, start_count);
+			CP(*nds, ds32, end_count);
+			BT_CP(*nds, ds32, busy_from);
+			PTROUT_CP(*nds, ds32, dev_links.stqe_next);
+			CP(*nds, ds32, device_number);
+			strcpy(ds32.device_name, nds->device_name);
+			CP(*nds, ds32, unit_number);
+			for (i = 0; i < DEVSTAT_N_TRANS_FLAGS; i++) {
+				FU64_CP(*nds, ds32, bytes[i]);
+				FU64_CP(*nds, ds32, operations[i]);
+				BT_CP(*nds, ds32, duration[i]);
+			}
+			BT_CP(*nds, ds32, busy_time);
+			BT_CP(*nds, ds32, creation_time);
+			CP(*nds, ds32, block_size);
+			for (i = 0; i < nitems(ds32.tag_types); i++) {
+				FU64_CP(*nds, ds32, tag_types[i]);
+			}
+			CP(*nds, ds32, flags);
+			CP(*nds, ds32, device_type);
+			CP(*nds, ds32, priority);
+			PTROUT_CP(*nds, ds32, id);
+			CP(*nds, ds32, sequence1);
+			error = SYSCTL_OUT(req, &ds32, sizeof(ds32));
+		} else
+#endif /* COMPAT_FREEBSD32 */
+			error = SYSCTL_OUT(req, nds, sizeof(*nds));
 		if (error != 0)
 			return (error);
 		mtx_lock(&devstat_mutex);
@@ -428,7 +470,7 @@ sysctl_devstat(SYSCTL_HANDLER_ARGS)
 		if (error != 0)
 			return (error);
 	}
-	return(error);
+	return (error);
 }
 
 /*