From a14cc9a5046bc4954b4110323c83599f90f9f35e Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 27 Apr 2016 14:18:41 +0200 Subject: [PATCH] libblkid: check for multi-session CDROMs .. and read last session if probing offset is not specified. udev uses cdrom_id to get last session offset, so people don't see a problem with hybrid media (audio+data), but if you execute blkid on command line (without -O ) then you get I/O errors. It seems that we can use the same way as kernel filesystem iso9960 driver when session= mount option is not specified ... just use CDROMMULTISESSION ioctl to get last session offset and probe this last session rather than all medium. Signed-off-by: Karel Zak --- libblkid/src/probe.c | 51 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/libblkid/src/probe.c b/libblkid/src/probe.c index 63baed33e1..e46615702a 100644 --- a/libblkid/src/probe.c +++ b/libblkid/src/probe.c @@ -772,15 +772,54 @@ failed: } /* - * Linux kernel reports (BLKGETSIZE) cdrom device size greater than area - * readable by read(2). We have to reduce the probing area to avoid unwanted - * I/O errors in probing functions. It seems that unreadable are always last 2 - * or 3 CD blocks (CD block size is 2048 bytes, it means 12 in 512-byte - * sectors). + * Issue #1: + * + * On hybrid mutil-session media (audio+data) we get I/O errors almost + * everywhere. The solution is to specify probing offset to the wanted + * session. Udev uses this way when it calls libblkid (the proper data session + * offset is based on ID_CDROM_MEDIA_SESSION_LAST_OFFSET from by udev cdrom_id + * tool). + * + * Unfortunately, it means that blkid will be blind when executed without a + * probing offset, to avoid this problem we use CDROMMULTISESSION ioctl to get + * last session offset. This way also uses iso9660 fyslesystem kernel driver + * when you mount mutil-session CD without a sesssion= mount option. + * + * Issue #2: + * + * Linux kernel reports (BLKGETSIZE) cdrom device size greater than area + * readable by read(2). We have to reduce the probing area to avoid unwanted + * I/O errors in probing functions. It seems that unreadable are always last 2 + * or 3 CD blocks (CD block size is 2048 bytes, it means 12 in 512-byte + * sectors). */ static void cdrom_size_correction(blkid_probe pr) { - uint64_t n, nsectors = pr->size >> 9; + uint64_t size, n, nsectors; + + /* move offset */ +#ifdef CDROMMULTISESSION + if (pr->off == 0) { + struct cdrom_multisession ms_info = { 0 }; + int i; + + ms_info.addr_format = CDROM_LBA; + i = ioctl(pr->fd, CDROMMULTISESSION, (unsigned long) &ms_info); + if (i == 0 && ms_info.xa_flag) { + DBG(LOWPROBE, ul_debug("CDROM: multisession last session start: %u (CD sectors)", ms_info.addr.lba)); + + pr->off = (uint64_t) ms_info.addr.lba * 2048; + DBG(LOWPROBE, ul_debug("CDROM: moving probing offset from 0 to %ju", pr->off)); + + size = pr->size - pr->off; + DBG(LOWPROBE, ul_debug("CDROM: reduce probing size from %ju to %ju", pr->size, size)); + pr->size = size; + } + } +#endif + + /* reduce size */ + nsectors = pr->size >> 9; for (n = nsectors - 12; n < nsectors; n++) { if (!is_sector_readable(pr->fd, n)) -- 2.47.2