o/blockdev: add options support
Allow passing options to Open(). This resolves a TODO left from when
blockdev was initially implemented and is now needed as Linux 6.12
rejects opening mounted block devices read-write, so we needed at least
a read-only option.
I also implemented the two options mentioned in the now-removed TODO
even though we're not using them yet.
These options are implemented generically to facilitate their use in
cross-platform code. Unsupported options are rejected at runtime. This
is similar to how Go's own stdlib does this.
Change-Id: I2548cb31e59a5c1198ca04537450bdf665878ca8
Reviewed-on: https://review.monogon.dev/c/monogon/+/3985
Reviewed-by: Jan Schär <jan@monogon.tech>
Tested-by: Jenkins CI
diff --git a/osbase/blockdev/blockdev.go b/osbase/blockdev/blockdev.go
index a8d55cb..5eb7fe8 100644
--- a/osbase/blockdev/blockdev.go
+++ b/osbase/blockdev/blockdev.go
@@ -7,10 +7,57 @@
"errors"
"fmt"
"io"
+ "os"
)
var ErrNotBlockDevice = errors.New("not a block device")
+// options aggregates all open options for all platforms.
+// If these were defined per-platform selecting the right ones per platform
+// would require multiple per-platform files at each call site.
+type options struct {
+ readOnly bool
+ direct bool
+ exclusive bool
+}
+
+func (o *options) collect(opts []Option) {
+ for _, f := range opts {
+ f(o)
+ }
+}
+
+func (o *options) genericFlags() int {
+ if o.readOnly {
+ return os.O_RDONLY
+ } else {
+ return os.O_RDWR
+ }
+}
+
+type Option func(*options)
+
+// WithReadonly opens the block device read-only. Any write calls will fail.
+// Passed as an option to Open.
+func WithReadonly(o *options) {
+ o.readOnly = true
+}
+
+// WithDirect opens the block device bypassing any caching by the kernel.
+// Note that additional alignment requirements might be imposed by the
+// underlying device.
+// Unsupported on non-Linux currently, will return an error.
+func WithDirect(o *options) {
+ o.direct = true
+}
+
+// WithExclusive tries to acquire a pseudo-exclusive lock (only with other
+// exclusive FDs) over the block device.
+// Unsupported on non-Linux currently, will return an error.
+func WithExclusive(o *options) {
+ o.exclusive = true
+}
+
// BlockDev represents a generic block device made up of equally-sized blocks.
// All offsets and intervals are expressed in bytes and must be aligned to
// BlockSize and are recommended to be aligned to OptimalBlockSize if feasible.