Index | Thread | Search

From:
Crystal Kolipe <kolipe.c@exoticsilicon.com>
Subject:
[patch] fix softraid on read-only host volumes
To:
tech@openbsd.org
Date:
Wed, 21 Jan 2026 20:57:38 +0000

Download raw body.

Thread
  • Crystal Kolipe:

    [patch] fix softraid on read-only host volumes

Another patch that we've been using locally for almost a year, this fixes
attaching softraid volumes stored on underlying read-only media.

Updated to -current, it's actually quite trivial:

* Retry the initial VOP_OPEN() with O_RDONLY if O_RDWR fails.

* Set a new flag bit, SR_CAP_READONLY, if the VOP_OPEN() with O_RDONLY
  succeeds.

* Respond to MODE_SENSE requests so that the scsi disk driver can see that the
  new sd device is indeed read-only.

* Update bioctl to open devices O_RDONLY when performing BIOC_DELETERAID or
  BIOC_INQ.

Extensively tested here, and I also got some positive responses off-list after
my write-up about it was published on undeadly.

--- sbin/bioctl/bioctl.c
+++ sbin/bioctl/bioctl.c
@@ -230,7 +230,8 @@
 	if (devicename == NULL)
 		errx(1, "need device");
 
-	devh = opendev(devicename, O_RDWR, OPENDEV_PART, &realname);
+	devh = opendev(devicename, (func == BIOC_DELETERAID ||
+	    func == BIOC_INQ ? O_RDONLY : O_RDWR), OPENDEV_PART, &realname);
 	if (devh == -1) {
 		devh = open("/dev/bio", O_RDWR);
 		if (devh == -1)
--- sys/dev/softraid.c
+++ sys/dev/softraid.c
@@ -334,6 +334,10 @@
 			 * and figure out the open/close dance for unwind.
 			 */
 			error = VOP_OPEN(vn, FREAD | FWRITE, NOCRED, curproc);
+			if (error == EACCES || error == EROFS) {
+				sd->sd_capabilities |= SR_CAP_READONLY;
+				error = VOP_OPEN(vn, FREAD, NOCRED, curproc);
+				}
 			if (error) {
 				DNPRINTF(SR_D_META,"%s: sr_meta_probe can't "
 				    "open %s\n", DEVNAME(sc), devname);
@@ -2328,6 +2332,7 @@
 	struct sr_softc		*sc = link->bus->sb_adapter_softc;
 	struct sr_workunit	*wu = xs->io;
 	struct sr_discipline	*sd;
+	unsigned char		mode_sense_header[4];
 
 	DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd target %d xs %p flags %#x\n",
 	    DEVNAME(sc), link->target, xs, xs->flags);
@@ -2403,6 +2408,20 @@
 		if (sd->sd_scsi_req_sense(wu))
 			goto stuffup;
 		goto complete;
+
+	case MODE_SENSE:
+		if ((xs->cmd.bytes[1] & 0x3f) != 0 &&
+		    (xs->cmd.bytes[1] & 0x3f) != 0x3f) {
+			goto stuffup;
+			}
+		bzero (&mode_sense_header, 4);
+		mode_sense_header[0] = 0x03;
+		if (sd->sd_capabilities & SR_CAP_READONLY) {
+			mode_sense_header[2] = 0x80;
+			}
+		scsi_copy_internal_data(xs, &mode_sense_header, 4);
+		xs->datalen = 4;
+ 		goto complete;
 
 	default:
 		DNPRINTF(SR_D_CMD, "%s: unsupported scsi command %x\n",
--- sys/dev/softraidvar.h
+++ sys/dev/softraidvar.h
@@ -535,6 +535,7 @@
 #define SR_CAP_REBUILD		0x00000004	/* Supports rebuild. */
 #define SR_CAP_NON_COERCED	0x00000008	/* Uses non-coerced size. */
 #define SR_CAP_REDUNDANT	0x00000010	/* Redundant copies of data. */
+#define SR_CAP_READONLY		0x00000020	/* Read-only. */
 
 	union {
 	    struct sr_raid0	mdd_raid0;