Page MenuHomeFreeBSD

Add invariants that check validity of alignment, boundary parameters
ClosedPublic

Authored by dougm on Jan 2 2022, 11:56 PM.

Details

Summary

With INVARIANTS defined, have the functions that check address alignment and boundaries panic when those arguments are not powers of two (where 0 is a power of two).

Diff Detail

Repository
rG FreeBSD src repository
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

dougm requested review of this revision.Jan 2 2022, 11:56 PM
dougm created this revision.

Why not use powerof2() macro from sys/param.h?

In D33725#762451, @kib wrote:

Why not use powerof2() macro from sys/param.h?

I am not confident that wherever this header is included, sys/param.h will have been included before it. Maybe you can reassure me of that.

Lately, I've found that the advice I get on header files sometimes leads me to commit things that don't compile on some architectures, because something that is included where I build isn't included for others. I don't want to repeat that mistake with this.

In D33725#762451, @kib wrote:

Why not use powerof2() macro from sys/param.h?

I am not confident that wherever this header is included, sys/param.h will have been included before it. Maybe you can reassure me of that.

Lately, I've found that the advice I get on header files sometimes leads me to commit things that don't compile on some architectures, because something that is included where I build isn't included for others. I don't want to repeat that mistake with this.

IMO not using sys/param.h macros would reinforce the behavior you fixed with vm_addr*() inlines, but for different case. You hand-expanded the code.

If you want, I can run make tinderbox for your patch with powerof2.

sys/vm/vm_extern.h
161

There is no alignment argument for the function, it is boundary. And boundary has vm_paddr_t type, which makes it fail on most of 32bit arches. You need to use uintmax_t cast and %jx for format. BTW, it is better to use %#jx instead of manually adding 0x.

Fix a bunch of mistakes I should not have made, and use "%#" for the first time.

Fix a bunch of mistakes I should not have made, and use "%#" for the first time.

It is almost fine except that ';' are missed at the end of panic() calls. Below is the verbatim patch that passed tinderbox:

diff --git a/sys/vm/vm_extern.h b/sys/vm/vm_extern.h
index 4e03bba66ee..9fac3403f78 100644
--- a/sys/vm/vm_extern.h
+++ b/sys/vm/vm_extern.h
@@ -140,6 +140,11 @@ u_int vm_wait_count(void);
 static inline bool
 vm_addr_align_ok(vm_paddr_t pa, u_long alignment)
 {
+#ifdef INVARIANTS
+	if (!powerof2(alignment))
+		panic("%s: alignment is not a power of 2: %#lx",
+		    __func__, alignment);
+#endif
 	return ((pa & (alignment - 1)) == 0);
 }
 
@@ -150,6 +155,11 @@ vm_addr_align_ok(vm_paddr_t pa, u_long alignment)
 static inline bool
 vm_addr_bound_ok(vm_paddr_t pa, vm_paddr_t size, vm_paddr_t boundary)
 {
+#ifdef INVARIANTS
+	if (!powerof2(boundary))
+		panic("%s: boundary is not a power of 2: %#jx",
+		    __func__, (uintmax_t)boundary);
+#endif
 	return (((pa ^ (pa + size - 1)) & -boundary) == 0);
 }

Add semicolons.

You could argue that I should write the alignment test as
return (pa == roundup2(pa));

and the boundary test as
return (roundup2(pa, boundary) >= pa + size);

if you want the implementation to rely on sys/param.h for all its bit-trickery.

Nevermind. The boundary rewrite would break the boundary == 0 case.

dougm edited reviewers, added: alc; removed: se.Jan 5 2022, 7:21 PM

Make tinderbox completed with just these errors:
powerpc.powerpc64: make[6]: "/freebsd/dougm/base/src/stand/kboot/Makefile" line 27: Cannot open /fr
eebsd/dougm/base/src/stand/kboot/arch/powerpc/Makefile.inc

i386 LINT-NOIP:
ld: error: undefined symbol: tcp_lro_flush_all

referenced by lio_droq.c

lio_droq.o:(lio_droq_process_packets)

ld: error: undefined symbol: tcp_lro_rx

referenced by lio_core.c

lio_core.o:(lio_push_packet)

ld: error: undefined symbol: tcp_lro_init

referenced by lio_main.c

lio_main.o:(lio_attach)

ld: error: undefined symbol: tcp_lro_free

referenced by lio_main.c

lio_main.o:(lio_attach)

referenced by lio_main.c

lio_main.o:(lio_destroy_nic_device)

I don't think either of these problems is associated with my changes.

I plan to either commit or discard this change within a couple of days. Please let me know how to proceed.

sys/vm/vm_extern.h
148

For what it's worth, this could be written as
return (pa == rounddown2(pa, alignment));

163

For what it's worth, this could be written as

return (rounddown2(pa + size - 1, boundary) <= pa);

alc added inline comments.
sys/vm/vm_extern.h
148

I don't see how that makes anything clearer. On the other hand, using powerof2() provides clarity.

This revision is now accepted and ready to land.Jan 9 2022, 10:20 PM
This revision was automatically updated to reflect the committed changes.