svn commit: r327996 - in head/sys: cam/scsi geom

Andriy Gapon avg at FreeBSD.org
Mon Jan 15 11:20:02 UTC 2018


Author: avg
Date: Mon Jan 15 11:20:00 2018
New Revision: 327996
URL: https://svnweb.freebsd.org/changeset/base/327996

Log:
  geom_disk / scsi_da: deny opening write-protected disks for writing
  
  Ths change consists of two parts.
  
  geom_disk: deny opening a disk for writing if it's marked as
  write-protected.  A new disk(9) flag is added to mark write protected
  disks.  A possible alternative could be to add another parameter to d_open,
  so that the open mode could be passed to it and the disk drivers could
  make the decision internally, but the flag required less churn.
  
  scsi_da: add a new phase of disk probing to query the all pages mode
  sense page.  We can determine if the disk is write protected using bit 7
  of the device specific field in the mode parameter header returned by
  MODE SENSE.
  
  PR:		224037
  Reviewed by:	mav
  MFC after:	4 weeks
  Differential Revision: https://reviews.freebsd.org/D13360

Modified:
  head/sys/cam/scsi/scsi_da.c
  head/sys/geom/geom_disk.c
  head/sys/geom/geom_disk.h

Modified: head/sys/cam/scsi/scsi_da.c
==============================================================================
--- head/sys/cam/scsi/scsi_da.c	Mon Jan 15 10:59:04 2018	(r327995)
+++ head/sys/cam/scsi/scsi_da.c	Mon Jan 15 11:20:00 2018	(r327996)
@@ -81,6 +81,7 @@ __FBSDID("$FreeBSD$");
  *    ATA -> LOGDIR -> IDDIR -> SUP -> ATA_ZONE
  */
 typedef enum {
+	DA_STATE_PROBE_WP,
 	DA_STATE_PROBE_RC,
 	DA_STATE_PROBE_RC16,
 	DA_STATE_PROBE_LBP,
@@ -157,6 +158,7 @@ typedef enum {
 	DA_CCB_PROBE_ATA_IDDIR	= 0x0F,
 	DA_CCB_PROBE_ATA_SUP	= 0x10,
 	DA_CCB_PROBE_ATA_ZONE	= 0x11,
+	DA_CCB_PROBE_WP		= 0x12,
 	DA_CCB_TYPE_MASK	= 0x1F,
 	DA_CCB_RETRY_UA		= 0x20
 } da_ccb_state;
@@ -2427,7 +2429,7 @@ daregister(struct cam_periph *periph, void *arg)
 	}
 	
 	LIST_INIT(&softc->pending_ccbs);
-	softc->state = DA_STATE_PROBE_RC;
+	softc->state = DA_STATE_PROBE_WP;
 	bioq_init(&softc->delete_run_queue);
 	if (SID_IS_REMOVABLE(&cgd->inq_data))
 		softc->flags |= DA_FLAG_PACK_REMOVABLE;
@@ -2526,7 +2528,6 @@ daregister(struct cam_periph *periph, void *arg)
 	if (SID_ANSI_REV(&cgd->inq_data) >= SCSI_REV_SPC3 &&
 	    (softc->quirks & DA_Q_NO_RC16) == 0) {
 		softc->flags |= DA_FLAG_CAN_RC16;
-		softc->state = DA_STATE_PROBE_RC16;
 	}
 
 	/*
@@ -3095,6 +3096,36 @@ out:
 		daschedule(periph);
 		break;
 	}
+	case DA_STATE_PROBE_WP:
+	{
+		void  *mode_buf;
+		int    mode_buf_len;
+
+		mode_buf_len = 192;
+		mode_buf = malloc(mode_buf_len, M_SCSIDA, M_NOWAIT);
+		if (mode_buf == NULL) {
+			xpt_print(periph->path, "Unable to send mode sense - "
+			    "malloc failure\n");
+			softc->state = DA_STATE_PROBE_RC;
+			goto skipstate;
+		}
+		scsi_mode_sense_len(&start_ccb->csio,
+				    /*retries*/ da_retry_count,
+				    /*cbfcnp*/ dadone,
+				    /*tag_action*/ MSG_SIMPLE_Q_TAG,
+				    /*dbd*/ FALSE,
+				    /*pc*/ SMS_PAGE_CTRL_CURRENT,
+				    /*page*/ SMS_ALL_PAGES_PAGE,
+				    /*param_buf*/ mode_buf,
+				    /*param_len*/ mode_buf_len,
+				    /*minimum_cmd_size*/ softc->minimum_cmd_size,
+				    /*sense_len*/ SSD_FULL_SIZE,
+				    /*timeout*/ da_default_timeout * 1000);
+		start_ccb->ccb_h.ccb_bp = NULL;
+		start_ccb->ccb_h.ccb_state = DA_CCB_PROBE_WP;
+		xpt_action(start_ccb);
+		break;
+	}
 	case DA_STATE_PROBE_RC:
 	{
 		struct scsi_read_capacity_data *rcap;
@@ -4255,6 +4286,52 @@ dadone(struct cam_periph *periph, union ccb *done_ccb)
 			biodone(bp);
 		return;
 	}
+	case DA_CCB_PROBE_WP:
+	{
+		struct scsi_mode_header_6 *mode_hdr6;
+		struct scsi_mode_header_10 *mode_hdr10;
+		uint8_t dev_spec;
+
+		if (softc->minimum_cmd_size > 6) {
+			mode_hdr10 = (struct scsi_mode_header_10 *)csio->data_ptr;
+			dev_spec = mode_hdr10->dev_spec;
+		} else {
+			mode_hdr6 = (struct scsi_mode_header_6 *)csio->data_ptr;
+			dev_spec = mode_hdr6->dev_spec;
+		}
+		if (cam_ccb_status(done_ccb) == CAM_REQ_CMP) {
+			if ((dev_spec & 0x80) != 0)
+				softc->disk->d_flags |= DISKFLAG_WRITE_PROTECT;
+			else
+				softc->disk->d_flags &= ~DISKFLAG_WRITE_PROTECT;
+		} else {
+			int error;
+
+			error = daerror(done_ccb, CAM_RETRY_SELTO,
+					SF_RETRY_UA|SF_NO_PRINT);
+			if (error == ERESTART)
+				return;
+			else if (error != 0) {
+				if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
+					/* Don't wedge this device's queue */
+					cam_release_devq(done_ccb->ccb_h.path,
+							 /*relsim_flags*/0,
+							 /*reduction*/0,
+							 /*timeout*/0,
+							 /*getcount_only*/0);
+				}
+			}
+		}
+
+		free(csio->data_ptr, M_SCSIDA);
+		xpt_release_ccb(done_ccb);
+		if ((softc->flags & DA_FLAG_CAN_RC16) != 0)
+			softc->state = DA_STATE_PROBE_RC16;
+		else
+			softc->state = DA_STATE_PROBE_RC;
+		xpt_schedule(periph, priority);
+		return;
+	}
 	case DA_CCB_PROBE_RC:
 	case DA_CCB_PROBE_RC16:
 	{
@@ -5340,11 +5417,7 @@ dareprobe(struct cam_periph *periph)
 	KASSERT(status == CAM_REQ_CMP,
 	    ("dareprobe: cam_periph_acquire failed"));
 
-	if (softc->flags & DA_FLAG_CAN_RC16)
-		softc->state = DA_STATE_PROBE_RC16;
-	else
-		softc->state = DA_STATE_PROBE_RC;
-
+	softc->state = DA_STATE_PROBE_WP;
 	xpt_schedule(periph, CAM_PRIORITY_DEV);
 }
 

Modified: head/sys/geom/geom_disk.c
==============================================================================
--- head/sys/geom/geom_disk.c	Mon Jan 15 10:59:04 2018	(r327995)
+++ head/sys/geom/geom_disk.c	Mon Jan 15 11:20:00 2018	(r327996)
@@ -122,14 +122,18 @@ g_disk_access(struct g_provider *pp, int r, int w, int
 	e += pp->ace;
 	error = 0;
 	if ((pp->acr + pp->acw + pp->ace) == 0 && (r + w + e) > 0) {
-		if (dp->d_open != NULL) {
+		/*
+		 * It would be better to defer this decision to d_open if
+		 * it was able to take flags.
+		 */
+		if (w > 0 && (dp->d_flags & DISKFLAG_WRITE_PROTECT) != 0)
+			error = EROFS;
+		if (error == 0 && dp->d_open != NULL)
 			error = dp->d_open(dp);
-			if (bootverbose && error != 0)
-				printf("Opened disk %s -> %d\n",
-				    pp->name, error);
-			if (error != 0)
-				return (error);
-		}
+		if (bootverbose && error != 0)
+			printf("Opened disk %s -> %d\n", pp->name, error);
+		if (error != 0)
+			return (error);
 		pp->sectorsize = dp->d_sectorsize;
 		if (dp->d_maxsize == 0) {
 			printf("WARNING: Disk drive %s%d has no d_maxsize\n",
@@ -1043,7 +1047,8 @@ g_disk_sysctl_flags(SYSCTL_HANDLER_ARGS)
 		"\4CANFLUSHCACHE"
 		"\5UNMAPPEDBIO"
 		"\6DIRECTCOMPLETION"
-		"\10CANZONE");
+		"\10CANZONE"
+		"\11WRITEPROTECT");
 
 	sbuf_finish(sb);
 	error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);

Modified: head/sys/geom/geom_disk.h
==============================================================================
--- head/sys/geom/geom_disk.h	Mon Jan 15 10:59:04 2018	(r327995)
+++ head/sys/geom/geom_disk.h	Mon Jan 15 11:20:00 2018	(r327996)
@@ -126,13 +126,14 @@ struct disk {
 	LIST_HEAD(,disk_alias)	d_aliases;
 };
 
-#define DISKFLAG_RESERVED	0x1	/* Was NEEDSGIANT */
-#define DISKFLAG_OPEN		0x2
-#define DISKFLAG_CANDELETE	0x4
-#define DISKFLAG_CANFLUSHCACHE	0x8
-#define	DISKFLAG_UNMAPPED_BIO	0x10
-#define	DISKFLAG_DIRECT_COMPLETION	0x20
-#define	DISKFLAG_CANZONE	0x80
+#define	DISKFLAG_RESERVED		0x0001	/* Was NEEDSGIANT */
+#define	DISKFLAG_OPEN			0x0002
+#define	DISKFLAG_CANDELETE		0x0004
+#define	DISKFLAG_CANFLUSHCACHE		0x0008
+#define	DISKFLAG_UNMAPPED_BIO		0x0010
+#define	DISKFLAG_DIRECT_COMPLETION	0x0020
+#define	DISKFLAG_CANZONE		0x0080
+#define	DISKFLAG_WRITE_PROTECT		0x0100
 
 struct disk *disk_alloc(void);
 void disk_create(struct disk *disk, int version);


More information about the svn-src-head mailing list