]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libblkid: (probe) read data in chunks
authorThomas Weißschuh <thomas@t-8ch.de>
Sat, 30 Sep 2023 21:59:44 +0000 (23:59 +0200)
committerThomas Weißschuh <thomas@t-8ch.de>
Wed, 4 Oct 2023 18:03:42 +0000 (20:03 +0200)
Signed-off-by: Thomas Weißschuh <thomas@t-8ch.de>
libblkid/src/blkidP.h
libblkid/src/probe.c

index a02df7eb6f6ebfe4b80b193adbcfa629a309aa9b..63d1946f9b66d6d02f7ac6fd85b742fc3a4e9eeb 100644 (file)
@@ -206,6 +206,7 @@ struct blkid_struct_probe
        int                     fd;             /* device file descriptor */
        uint64_t                off;            /* begin of data on the device */
        uint64_t                size;           /* end of data on the device */
+       uint64_t                io_size;        /* optimal size of IO */
 
        dev_t                   devno;          /* device number (st.st_rdev) */
        dev_t                   disk_devno;     /* devno of the whole-disk or 0 */
index 24cbd1761bf7595a45b7f93f58ed9eef65159244..552bed22c01cbb4562c44c3770fb3a00c16e86d8 100644 (file)
@@ -184,6 +184,7 @@ blkid_probe blkid_clone_probe(blkid_probe parent)
        pr->fd = parent->fd;
        pr->off = parent->off;
        pr->size = parent->size;
+       pr->io_size = parent->io_size;
        pr->devno = parent->devno;
        pr->disk_devno = parent->disk_devno;
        pr->blkssz = parent->blkssz;
@@ -729,13 +730,21 @@ static int hide_buffer(blkid_probe pr, uint64_t off, uint64_t len)
 const unsigned char *blkid_probe_get_buffer(blkid_probe pr, uint64_t off, uint64_t len)
 {
        struct blkid_bufinfo *bf = NULL;
-       uint64_t real_off = pr->off + off;
+       uint64_t real_off, bias;
+
+       bias = off % pr->io_size;
+       off -= bias;
+       len += bias;
+       if (len % pr->io_size)
+               len += pr->io_size - (len % pr->io_size);
+
+       real_off = pr->off + off;
 
        /*
        DBG(BUFFER, ul_debug("\t>>>> off=%ju, real-off=%ju (probe <%ju..%ju>, len=%ju",
                                off, real_off, pr->off, pr->off + pr->size, len));
        */
-       if (pr->size == 0) {
+       if (pr->size == 0 || pr->io_size == 0) {
                errno = EINVAL;
                return NULL;
        }
@@ -788,7 +797,7 @@ const unsigned char *blkid_probe_get_buffer(blkid_probe pr, uint64_t off, uint64
        assert(bf->off + bf->len >= real_off + len);
 
        errno = 0;
-       return real_off ? bf->data + (real_off - bf->off) : bf->data;
+       return real_off ? bf->data + (real_off - bf->off + bias) : bf->data + bias;
 }
 
 /**
@@ -953,6 +962,22 @@ failed:
 
 #endif
 
+static uint64_t blkid_get_io_size(int fd)
+{
+       static const int ioctls[] = { BLKIOOPT, BLKIOMIN, BLKBSZGET };
+       unsigned int s;
+       size_t i;
+       int r;
+
+       for (i = 0; i < ARRAY_SIZE(ioctls); i++) {
+               r = ioctl(fd, ioctls[i], &s);
+               if (r == 0 && is_power_of_2(s) && s >= DEFAULT_SECTOR_SIZE)
+                       return min(s, 1U << 16);
+       }
+
+       return DEFAULT_SECTOR_SIZE;
+}
+
 /**
  * blkid_probe_set_device:
  * @pr: probe
@@ -996,6 +1021,7 @@ int blkid_probe_set_device(blkid_probe pr, int fd,
        pr->fd = fd;
        pr->off = (uint64_t) off;
        pr->size = 0;
+       pr->io_size = DEFAULT_SECTOR_SIZE;
        pr->devno = 0;
        pr->disk_devno = 0;
        pr->mode = 0;
@@ -1159,8 +1185,11 @@ int blkid_probe_set_device(blkid_probe pr, int fd,
        }
 # endif
 
-       DBG(LOWPROBE, ul_debug("ready for low-probing, offset=%"PRIu64", size=%"PRIu64", zonesize=%"PRIu64,
-                               pr->off, pr->size, pr->zone_size));
+       if (S_ISBLK(sb.st_mode) && !is_floppy && !blkid_probe_is_tiny(pr))
+               pr->io_size = blkid_get_io_size(fd);
+
+       DBG(LOWPROBE, ul_debug("ready for low-probing, offset=%"PRIu64", size=%"PRIu64", zonesize=%"PRIu64", iosize=%"PRIu64,
+                               pr->off, pr->size, pr->zone_size, pr->io_size));
        DBG(LOWPROBE, ul_debug("whole-disk: %s, regfile: %s",
                blkid_probe_is_wholedisk(pr) ?"YES" : "NO",
                S_ISREG(pr->mode) ? "YES" : "NO"));