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-all
mailing list