From nobody Fri Sep 11 14:09:45 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hhGdV3xV7z6sQBv for ; Fri, 11 Sep 2026 14:09:50 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hhGdV1bBTz4KNg for ; Fri, 11 Sep 2026 14:09:50 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1789135790; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=nvmHK3xUgh6shq+KxUAvXjvVuC5NoRFZs/S4RSZbevg=; b=AQBPB0LfKQ4TJd64ggXgfxw2wJ+2m4IbyHpj/18XvEqAhBZ2f9BEufRLnG5Xjfv36IDzcf flDIbZEiZB5c/Svat6ZIcwPPT/EBthG2NFC4M56LF1MgU5l9JcU4gsRSCPdMzyg35qrYab ytThO9I48g+ymTCU/ZPlLnOUYHQ19ciaz6ErhQybZvaeKfM5Db69WSJYy5YnrM8RZUgSIl iTX03T7yXMTYgdDFr7NU7f7ejpNrQxbIIBMoL/Jo8rmu6F17PrQ3V+XzuPN/nZe7ky9Z0W qY7lVc8X4UgNfcFOmH/OnicbY7/zv+piuQK1U4PKcIl9vjxN53IDvPFWkRTprQ== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1789135790; b=Ki9QL9ULs7IcLocsPqK10Yx/4fCz/CCBEp+5IoN3YR0YwvW+dLnoq254dfl6lFy1r+xXD5 AF8OS0BvUlCLAmN0Tl0ExAxJHfjpv0TGM5oMW3vKsmkhk63Ep66bctRQBg1877+k41enVF 7LK3UIth9+qTfabt2DROI4aixH8GoS6L+jDOYyLlm3cbDXvJPdbO4WbfJ7THhnSoLIGJS4 DTmTocbHW/tOo0HLJiU4XQRA2tAewmQ5lDzVujGIB5AkVSsYrp++AR1/KKr03ZZAuW/21O B3eP9B7+VM7GDhJnCyhftoecSuggmpdpARoBcBCX0X73V7fJGENbgBxegOuYwg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1789135790; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=nvmHK3xUgh6shq+KxUAvXjvVuC5NoRFZs/S4RSZbevg=; b=ZEy6yis4SWfqcFPxbkmXGbLW39I2nmkipvW2myTYtJ7tIgoxfHNGb30pCwTEDJHRkAmrON fOGJCIrMLblz1OAEKuPbdhXdB5MaaidgCK7diH0GjAXG8gXUvNvMTVjUTPrtsGQ4J9VNoK o9WltWzEc3H4a8ffX0G4G1o8eYundIpM7JpHaKj7teZB1jvnJ+C+QaYGFktg6pqruZg+PY 2w2lEfXp03whSCgsByKvyub0s/pYs1mB8kuTJDI2iaRuI21u2QWZTDVrWvcbCaXJxIhQYk u8Kpcn/meLV6DCbmNDBxwBVlFf5CpgPBts34LWz2zRHiTD0E7ff/tRhrhMLQeg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hhGdV0Jv1zGTY for ; Fri, 11 Sep 2026 14:09:50 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 2672a by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Fri, 11 Sep 2026 14:09:45 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Michal Meloun Subject: git: 477c594d9063 - main - kobj: allow multiple inheritance with per-class softc List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: mmel X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 477c594d906328e210c30cf2c21d983152f21de3 Auto-Submitted: auto-generated Date: Fri, 11 Sep 2026 14:09:45 +0000 Message-Id: <6aa40ba9.2672a.7c32cf3e@gitrepo.freebsd.org> The branch main has been updated by mmel: URL: https://cgit.FreeBSD.org/src/commit/?id=477c594d906328e210c30cf2c21d983152f21de3 commit 477c594d906328e210c30cf2c21d983152f21de3 Author: Michal Meloun AuthorDate: 2026-09-11 11:47:30 +0000 Commit: Michal Meloun CommitDate: 2026-09-11 14:09:36 +0000 kobj: allow multiple inheritance with per-class softc Add support for hierarchical softc layout so that a leaf class and each of its base classes owns a private softc region inside a single allocation. device_get_softc_class(dev, cls) returns a pointer to the softc that belongs to the requested class. The classic device_get_softc() still returns the leaf softc and remains fully compatible with existing drivers. Existing drivers are unaffected; they simply obtain a slightly larger softc block when they inherit from base classes. MFC after: 2 months Reviewed by: kib Differential Revision: https://reviews.freebsd.org/D59115 --- sys/kern/subr_bus.c | 19 ++++++++-- sys/kern/subr_kobj.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++ sys/sys/bus.h | 1 + sys/sys/kobj.h | 30 +++++++++++++--- 4 files changed, 142 insertions(+), 8 deletions(-) diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index b5c1c5b61f60..4398b3fa9e13 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -2159,6 +2159,17 @@ device_get_softc(device_t dev) return (dev->softc); } +void * +device_get_softc_class(device_t dev, kobj_class_t cls) +{ + char *ptr; + + ptr = dev->softc; + ptr += kobj_instance_offset(device_get_driver(dev), cls); + + return (ptr); +} + /** * @brief Set the device's softc field * @@ -2472,6 +2483,7 @@ device_set_driver(device_t dev, driver_t *driver) { int domain; struct domainset *policy; + size_t size; if (dev->state >= DS_ATTACHED) return (EBUSY); @@ -2488,13 +2500,14 @@ device_set_driver(device_t dev, driver_t *driver) dev->driver = driver; if (driver) { kobj_init((kobj_t) dev, (kobj_class_t) driver); - if (!(dev->flags & DF_EXTERNALSOFTC) && driver->size > 0) { + size = kobj_total_data_size(driver); + if (!(dev->flags & DF_EXTERNALSOFTC) && size > 0) { if (bus_get_domain(dev, &domain) == 0) policy = DOMAINSET_PREF(domain); else policy = DOMAINSET_RR(); - dev->softc = malloc_domainset(driver->size, M_BUS_SC, - policy, M_WAITOK | M_ZERO); + dev->softc = malloc_domainset(size, M_BUS_SC, policy, + M_WAITOK | M_ZERO); } } else { kobj_init((kobj_t) dev, &null_class); diff --git a/sys/kern/subr_kobj.c b/sys/kern/subr_kobj.c index a88639289954..0f9f7a79aaf0 100644 --- a/sys/kern/subr_kobj.c +++ b/sys/kern/subr_kobj.c @@ -94,6 +94,35 @@ kobj_error_method(void) return ENXIO; } +static inline size_t +kobj_data_size_roundup(size_t size) +{ + + return (roundup2((size), _Alignof(__max_align_t))); +} + +static void +kobj_class_init_total_size(kobj_class_t cls) +{ + kobj_class_t *bases; + size_t size; + int i; + + MPASS(!cls->total_size_inited); + bases = cls->baseclasses; + + size = kobj_data_size_roundup(cls->size); + if (bases != NULL) { + for (i = 0; bases[i] != NULL; i++) { + if (!bases[i]->total_size_inited) + kobj_class_init_total_size(bases[i]); + size += bases[i]->total_size; + } + } + cls->total_size_inited = true; + cls->total_size = size; +} + static void kobj_class_compile_common(kobj_class_t cls, kobj_ops_t ops) { @@ -121,6 +150,12 @@ kobj_class_compile_common(kobj_class_t cls, kobj_ops_t ops) ops->cache[i] = &null_method; ops->cls = cls; cls->ops = ops; + + /* + * Then compute total object data size. + */ + if (!cls->total_size_inited) + kobj_class_init_total_size(cls); } static int @@ -349,3 +384,68 @@ kobj_delete(kobj_t obj, struct malloc_type *mtype) if (mtype) free(obj, mtype); } + +static inline bool +kobj_get_instance_offset(kobj_class_t cls, kobj_class_t subclass, size_t *offs) +{ + kobj_class_t *bases; + size_t tmp; + int i; + + if (cls == subclass) + return (true); + + bases = cls->baseclasses; + *offs += kobj_data_size_roundup(cls->size); + + if (bases == NULL || bases[0] == NULL) + return (false); + + /* Try most common cases (offset of direct subclass) first. */ + tmp = *offs; + for (i = 0; bases[i] != NULL; i++) { + if (bases[i] == subclass) { + *offs = tmp; + return (true); + } + tmp += bases[i]->total_size; + } + + /* Then do recursion for nested classes. */ + for (i = 0; bases[i] != NULL; i++) { + if (kobj_get_instance_offset(bases[i], subclass, offs)) + return (true); + } + return (false); +} + +/* + * Get the data offset for the given class. + * layout is: [main | base0 | base1 | ... ] + */ +size_t +kobj_instance_offset(kobj_class_t cls, kobj_class_t subclass) +{ + size_t offs; + + if (cls == subclass) + return (0); + + offs = 0; + if (!kobj_get_instance_offset(cls, subclass, &offs)) + panic("%s: class %s not found in hierarchy of %s", __func__, + subclass->name, cls->name); + return (offs); +} + +/* + * Get the total data size of this class and all its subclasses. + */ +size_t +kobj_total_data_size(kobj_class_t cls) +{ + + MPASS(cls->total_size_inited); + + return (cls->total_size); +} diff --git a/sys/sys/bus.h b/sys/sys/bus.h index a2e315bb9dee..4ea411a4dd80 100644 --- a/sys/sys/bus.h +++ b/sys/sys/bus.h @@ -724,6 +724,7 @@ void device_set_ivars(device_t dev, void *ivars); const char *device_get_name(device_t dev); const char *device_get_nameunit(device_t dev); void *device_get_softc(device_t dev); +void *device_get_softc_class(device_t dev, kobj_class_t cls); device_state_t device_get_state(device_t dev); int device_get_unit(device_t dev); struct sysctl_ctx_list *device_get_sysctl_ctx(device_t dev); diff --git a/sys/sys/kobj.h b/sys/sys/kobj.h index 7705f609bea9..e248f9eafaf8 100644 --- a/sys/sys/kobj.h +++ b/sys/sys/kobj.h @@ -31,6 +31,11 @@ #include +/* XXX workaround for bool type for tools/build/test-includes */ +#if !defined(_KERNEL) && !defined(_STANDALONE) +#include +#endif + /* * Forward declarations */ @@ -59,7 +64,9 @@ struct kobj_method { size_t size; /* object size */ \ kobj_class_t *baseclasses; /* base classes */ \ u_int refs; /* reference count */ \ - kobj_ops_t ops /* compiled method table */ + kobj_ops_t ops; /* compiled method table */ \ + size_t total_size; /* total object size */ \ + bool total_size_inited struct kobj_class { KOBJ_CLASS_FIELDS; @@ -124,7 +131,7 @@ DEFINE_CLASS_0(name, name ## _class, methods, size) #define DEFINE_CLASS_0(name, classvar, methods, size) \ \ struct kobj_class classvar = { \ - #name, methods, size, NULL \ + #name, methods, size, NULL, 0, false \ } /* @@ -139,7 +146,8 @@ struct kobj_class classvar = { \ static kobj_class_t name ## _baseclasses[] = \ { &base1, NULL }; \ struct kobj_class classvar = { \ - #name, methods, size, name ## _baseclasses \ + #name, methods, size, name ## _baseclasses, 0, \ + false \ } /* @@ -155,7 +163,8 @@ static kobj_class_t name ## _baseclasses[] = \ { &base1, \ &base2, NULL }; \ struct kobj_class classvar = { \ - #name, methods, size, name ## _baseclasses \ + #name, methods, size, name ## _baseclasses, 0, \ + false \ } /* @@ -172,7 +181,8 @@ static kobj_class_t name ## _baseclasses[] = \ &base2, \ &base3, NULL }; \ struct kobj_class classvar = { \ - #name, methods, size, name ## _baseclasses \ + #name, methods, size, name ## _baseclasses, 0, \ + false \ } /* @@ -209,6 +219,16 @@ void kobj_init_static(kobj_t obj, kobj_class_t cls); */ void kobj_delete(kobj_t obj, struct malloc_type *mtype); +/* + * Get the data offset for the given class. + */ +size_t kobj_instance_offset(kobj_class_t cls, kobj_class_t subclass); + +/* + * Get the total data size of this class and all its subclasses. + */ +size_t kobj_total_data_size(kobj_class_t cls); + /* * Maintain stats on hits/misses in lookup caches. */