Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 15 Feb 2018 16:31:36 +0000 (UTC)
From:      Andriy Gapon <avg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r329319 - in stable/10/sys: cam/scsi geom
Message-ID:  <201802151631.w1FGVarH023681@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avg
Date: Thu Feb 15 16:31:35 2018
New Revision: 329319
URL: https://svnweb.freebsd.org/changeset/base/329319

Log:
  MFC r327996: 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

Modified:
  stable/10/sys/cam/scsi/scsi_da.c
  stable/10/sys/geom/geom_disk.c
  stable/10/sys/geom/geom_disk.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/cam/scsi/scsi_da.c
==============================================================================
--- stable/10/sys/cam/scsi/scsi_da.c	Thu Feb 15 16:29:35 2018	(r329318)
+++ stable/10/sys/cam/scsi/scsi_da.c	Thu Feb 15 16:31:35 2018	(r329319)
@@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$");
 
 #ifdef _KERNEL
 typedef enum {
+	DA_STATE_PROBE_WP,
 	DA_STATE_PROBE_RC,
 	DA_STATE_PROBE_RC16,
 	DA_STATE_PROBE_LBP,
@@ -126,8 +127,9 @@ typedef enum {
 	DA_CCB_DUMP		= 0x0A,
 	DA_CCB_DELETE		= 0x0B,
  	DA_CCB_TUR		= 0x0C,
-	DA_CCB_TYPE_MASK	= 0x0F,
-	DA_CCB_RETRY_UA		= 0x10
+	DA_CCB_PROBE_WP		= 0x12,
+	DA_CCB_TYPE_MASK	= 0x1F,
+	DA_CCB_RETRY_UA		= 0x20
 } da_ccb_state;
 
 /*
@@ -2096,7 +2098,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->bio_queue);
 	bioq_init(&softc->delete_queue);
 	bioq_init(&softc->delete_run_queue);
@@ -2183,7 +2185,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;
 	}
 
 	/*
@@ -2415,6 +2416,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;
@@ -3095,6 +3126,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:
 	{
@@ -3612,11 +3689,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: stable/10/sys/geom/geom_disk.c
==============================================================================
--- stable/10/sys/geom/geom_disk.c	Thu Feb 15 16:29:35 2018	(r329318)
+++ stable/10/sys/geom/geom_disk.c	Thu Feb 15 16:31:35 2018	(r329319)
@@ -134,16 +134,21 @@ 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) {
 			g_disk_lock_giant(dp);
 			error = dp->d_open(dp);
-			if (bootverbose && error != 0)
-				printf("Opened disk %s -> %d\n",
-				    pp->name, error);
 			g_disk_unlock_giant(dp);
-			if (error != 0)
-				return (error);
 		}
+		if (bootverbose && error != 0)
+			printf("Opened disk %s -> %d\n", pp->name, error);
+		if (error != 0)
+			return (error);
 		pp->mediasize = dp->d_mediasize;
 		pp->sectorsize = dp->d_sectorsize;
 		if (dp->d_maxsize == 0) {

Modified: stable/10/sys/geom/geom_disk.h
==============================================================================
--- stable/10/sys/geom/geom_disk.h	Thu Feb 15 16:29:35 2018	(r329318)
+++ stable/10/sys/geom/geom_disk.h	Thu Feb 15 16:31:35 2018	(r329319)
@@ -105,13 +105,14 @@ struct disk {
 	uint16_t		d_rotation_rate;
 };
 
-#define DISKFLAG_NEEDSGIANT	0x1
-#define DISKFLAG_OPEN		0x2
-#define DISKFLAG_CANDELETE	0x4
-#define DISKFLAG_CANFLUSHCACHE	0x8
-#define	DISKFLAG_UNMAPPED_BIO	0x10
-#define	DISKFLAG_DIRECT_COMPLETION	0x20
-#define DISKFLAG_LACKS_ROTRATE	0x40
+#define	DISKFLAG_NEEDSGIANT		0x0001
+#define	DISKFLAG_OPEN			0x0002
+#define	DISKFLAG_CANDELETE		0x0004
+#define	DISKFLAG_CANFLUSHCACHE		0x0008
+#define	DISKFLAG_UNMAPPED_BIO		0x0010
+#define	DISKFLAG_DIRECT_COMPLETION	0x0020
+#define DISKFLAG_LACKS_ROTRATE		0x0040
+#define	DISKFLAG_WRITE_PROTECT		0x0100
 
 #define	DISK_RR_UNKNOWN		0
 #define	DISK_RR_NON_ROTATING	1



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201802151631.w1FGVarH023681>