aboutsummaryrefslogtreecommitdiffstats
path: root/main/util-linux/libblkid-reduce-probing-area-for-crazy-CDROMs.patch
blob: 66d50082c008a08907b72e75d67039d26572afbc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
From bfebe74e3babe8c188a51269acc2673f1aea283f Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@redhat.com>
Date: Tue, 19 Apr 2016 12:39:05 +0200
Subject: [PATCH] libblkid: reduce probing area for crazy CDROMs

Linux kernel reports devices greater than area readable by read(2).
The readable area is usually 2-3 CD blocks smaller (CD block is
2048-bytes) than size returned by BLKGETSIZE. This patch checks for
this issues to avoid I/O errors in probing functions.

Reported-by: Thomas Schmitt <scdbackup@gmx.net>
Signed-off-by: Karel Zak <kzak@redhat.com>
---
 libblkid/src/probe.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/libblkid/src/probe.c b/libblkid/src/probe.c
index 0c8625c..0455c37 100644
--- a/libblkid/src/probe.c
+++ b/libblkid/src/probe.c
@@ -752,6 +752,51 @@ int blkid_probe_is_cdrom(blkid_probe pr)
 	return pr && (pr->flags & BLKID_FL_CDROM_DEV);
 }
 
+static int is_sector_readable(int fd, uint64_t sector)
+{
+	char buf[512];
+	ssize_t sz;
+
+	if (blkid_llseek(fd, sector * 512, SEEK_SET) < 0)
+		goto failed;
+
+	sz = read(fd, buf, sizeof(buf));
+	if (sz != (ssize_t) sizeof(buf))
+		goto failed;
+
+	return 1;
+failed:
+	DBG(LOWPROBE, ul_debug("CDROM: read sector %ju failed %m", sector));
+	errno = 0;
+	return 0;
+}
+
+/*
+ * 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;
+
+	for (n = nsectors - 12; n < nsectors; n++) {
+		if (!is_sector_readable(pr->fd, n))
+			goto failed;
+	}
+
+	DBG(LOWPROBE, ul_debug("CDROM: full size available"));
+	return;
+failed:
+	/* 'n' is the failed sector, reduce device size to n-1; */
+	DBG(LOWPROBE, ul_debug("CDROM: reduce size from %ju to %ju.",
+				(uintmax_t) pr->size,
+				(uintmax_t) (n - 1) << 9));
+	pr->size = n << 9;
+}
+
 /**
  * blkid_probe_set_device:
  * @pr: probe
@@ -844,8 +889,11 @@ int blkid_probe_set_device(blkid_probe pr, int fd,
 	else if (S_ISBLK(sb.st_mode) &&
 	    !blkid_probe_is_tiny(pr) &&
 	    blkid_probe_is_wholedisk(pr) &&
-	    ioctl(fd, CDROM_GET_CAPABILITY, NULL) >= 0)
+	    ioctl(fd, CDROM_GET_CAPABILITY, NULL) >= 0) {
+
 		pr->flags |= BLKID_FL_CDROM_DEV;
+		cdrom_size_correction(pr);
+	}
 #endif
 
 	DBG(LOWPROBE, ul_debug("ready for low-probing, offset=%"PRIu64", size=%"PRIu64"",