Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

cdrom, scsi: sr: propagate read-only status to block layer via set_disk_ro()

The cdrom core never calls set_disk_ro() for a registered device, so
BLKROGET on a CD-ROM device always returns 0 (writable), even when the
drive has no write capabilities and writes will inevitably fail. This
causes problems for userspace that relies on BLKROGET to determine
whether a block device is read-only. For example, systemd's loop device
setup uses BLKROGET to decide whether to create a loop device with
LO_FLAGS_READ_ONLY. Without the read-only flag, writes pass through the
loop device to the CD-ROM and fail with I/O errors. systemd-fsck
similarly checks BLKROGET to decide whether to run fsck in no-repair
mode (-n).

The write-capability bits in cdi->mask come from two different sources:
CDC_DVD_RAM and CDC_CD_RW are populated by the driver from the MODE
SENSE capabilities page (page 0x2A) before register_cdrom() is called,
while CDC_MRW_W and CDC_RAM require the MMC GET CONFIGURATION command
and were only probed by cdrom_open_write() at device open time. This
meant that any attempt to compute the writable state from the full
mask at probe time was incorrect, because the GET CONFIGURATION bits
were still unset (and cdi->mask is initialized such that capabilities
are assumed present).

Fix this by factoring the GET CONFIGURATION probing out of
cdrom_open_write() into a new exported helper,
cdrom_probe_write_features(), and having sr call it from sr_probe()
right after get_capabilities() has populated the MODE SENSE bits.
register_cdrom() then calls set_disk_ro() based on the full
write-capability mask (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)
so the block layer reflects the drive's actual write support. The
feature queries used (CDF_MRW and CDF_RWRT via GET CONFIGURATION with
RT=00) report drive-level capabilities that are persistent across
media, so a single probe before register_cdrom() is sufficient and the
redundant probe at open time is dropped.

With set_disk_ro() now accurate, the long-vestigial cd->writeable flag
in sr can go: get_capabilities() used to set cd->writeable based on
the same four mask bits, but because CDC_MRW_W and CDC_RAM default to
"capability present" in cdi->mask and aren't touched by MODE SENSE,
the condition that gated cd->writeable was always true, making it
unconditionally 1. Replace the corresponding gate in sr_init_command()
with get_disk_ro(cd->disk), which turns a previously no-op check into
a real one and also catches kernel-internal bio writers that bypass
blkdev_write_iter()'s bdev_read_only() check.

The sd driver (SCSI disks) does not have this problem because it
checks the MODE SENSE Write Protect bit and calls set_disk_ro()
accordingly. The sr driver cannot use the same approach because the
MMC specification does not define the WP bit in the MODE SENSE
device-specific parameter byte for CD-ROM devices.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Daan De Meyer <daan@amutable.com>
Reviewed-by: Phillip Potter <phil@philpotter.co.uk>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Phillip Potter <phil@philpotter.co.uk>
Link: https://patch.msgid.link/20260427210139.1400-2-phil@philpotter.co.uk
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Daan De Meyer and committed by
Jens Axboe
0898a817 aa03cfe9

+51 -35
+48 -25
drivers/cdrom/cdrom.c
··· 631 631 632 632 WARN_ON(!cdo->generic_packet); 633 633 634 + /* 635 + * Propagate the drive's write support to the block layer so BLKROGET 636 + * reflects actual write capability. Drivers that use GET CONFIGURATION 637 + * features (CDC_MRW_W, CDC_RAM) must have called 638 + * cdrom_probe_write_features() before register_cdrom() so the mask is 639 + * complete here. 640 + */ 641 + set_disk_ro(disk, !CDROM_CAN(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | 642 + CDC_CD_RW)); 643 + 634 644 cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); 635 645 mutex_lock(&cdrom_mutex); 636 646 list_add(&cdi->list, &cdrom_list); ··· 751 741 752 742 return 0; 753 743 } 744 + 745 + /* 746 + * Probe write-related MMC features via GET CONFIGURATION and update 747 + * cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE 748 + * capabilities page (e.g. sr) should call this after those MODE SENSE bits 749 + * have been set but before register_cdrom(), so that the full set of 750 + * write-capability bits is known by the time register_cdrom() decides on the 751 + * initial read-only state of the disk. 752 + */ 753 + void cdrom_probe_write_features(struct cdrom_device_info *cdi) 754 + { 755 + int mrw, mrw_write, ram_write; 756 + 757 + mrw = 0; 758 + if (!cdrom_is_mrw(cdi, &mrw_write)) 759 + mrw = 1; 760 + 761 + if (CDROM_CAN(CDC_MO_DRIVE)) 762 + ram_write = 1; 763 + else 764 + (void) cdrom_is_random_writable(cdi, &ram_write); 765 + 766 + if (mrw) 767 + cdi->mask &= ~CDC_MRW; 768 + else 769 + cdi->mask |= CDC_MRW; 770 + 771 + if (mrw_write) 772 + cdi->mask &= ~CDC_MRW_W; 773 + else 774 + cdi->mask |= CDC_MRW_W; 775 + 776 + if (ram_write) 777 + cdi->mask &= ~CDC_RAM; 778 + else 779 + cdi->mask |= CDC_RAM; 780 + } 781 + EXPORT_SYMBOL(cdrom_probe_write_features); 754 782 755 783 static int cdrom_media_erasable(struct cdrom_device_info *cdi) 756 784 { ··· 942 894 */ 943 895 static int cdrom_open_write(struct cdrom_device_info *cdi) 944 896 { 945 - int mrw, mrw_write, ram_write; 946 897 int ret = 1; 947 - 948 - mrw = 0; 949 - if (!cdrom_is_mrw(cdi, &mrw_write)) 950 - mrw = 1; 951 - 952 - if (CDROM_CAN(CDC_MO_DRIVE)) 953 - ram_write = 1; 954 - else 955 - (void) cdrom_is_random_writable(cdi, &ram_write); 956 - 957 - if (mrw) 958 - cdi->mask &= ~CDC_MRW; 959 - else 960 - cdi->mask |= CDC_MRW; 961 - 962 - if (mrw_write) 963 - cdi->mask &= ~CDC_MRW_W; 964 - else 965 - cdi->mask |= CDC_MRW_W; 966 - 967 - if (ram_write) 968 - cdi->mask &= ~CDC_RAM; 969 - else 970 - cdi->mask |= CDC_RAM; 971 898 972 899 if (CDROM_CAN(CDC_MRW_W)) 973 900 ret = cdrom_mrw_open_write(cdi);
+2 -9
drivers/scsi/sr.c
··· 395 395 396 396 switch (req_op(rq)) { 397 397 case REQ_OP_WRITE: 398 - if (!cd->writeable) 398 + if (get_disk_ro(cd->disk)) 399 399 goto out; 400 400 SCpnt->cmnd[0] = WRITE_10; 401 401 cd->cdi.media_written = 1; ··· 681 681 error = -ENOMEM; 682 682 if (get_capabilities(cd)) 683 683 goto fail_minor; 684 + cdrom_probe_write_features(&cd->cdi); 684 685 sr_vendor_init(cd); 685 686 686 687 set_capacity(disk, cd->capacity); ··· 899 898 cd->cdi.mask |= CDC_SELECT_DISC; 900 899 /*else I don't think it can close its tray 901 900 cd->cdi.mask |= CDC_CLOSE_TRAY; */ 902 - 903 - /* 904 - * if DVD-RAM, MRW-W or CD-RW, we are randomly writable 905 - */ 906 - if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != 907 - (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { 908 - cd->writeable = 1; 909 - } 910 901 911 902 kfree(buffer); 912 903 return 0;
-1
drivers/scsi/sr.h
··· 35 35 struct scsi_device *device; 36 36 unsigned int vendor; /* vendor code, see sr_vendor.c */ 37 37 unsigned long ms_offset; /* for reading multisession-CD's */ 38 - unsigned writeable : 1; 39 38 unsigned use:1; /* is this device still supportable */ 40 39 unsigned xa_flag:1; /* CD has XA sectors ? */ 41 40 unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */
+1
include/linux/cdrom.h
··· 108 108 extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, 109 109 unsigned int clearing); 110 110 111 + extern void cdrom_probe_write_features(struct cdrom_device_info *cdi); 111 112 extern int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi); 112 113 extern void unregister_cdrom(struct cdrom_device_info *cdi); 113 114