]> sourceware.org Git - lvm2.git/commitdiff
device: Suppress repeated reads of the same data.
authorAlasdair G Kergon <agk@redhat.com>
Wed, 10 Jan 2018 13:19:12 +0000 (13:19 +0000)
committerAlasdair G Kergon <agk@redhat.com>
Wed, 10 Jan 2018 15:52:03 +0000 (15:52 +0000)
If the data being requested is present in last_[extra_]devbuf,
return that directly instead of reading it from disk again.

Typical LVM2 access patterns request data within two adjacent 4k blocks
so we eliminate some read() system calls by always reading at least 8k.

WHATS_NEW
lib/device/dev-io.c

index 897576c6946515d71df888d61fd43bcdb2ff32e4..489c31530fa8588591fdc518bd612adefc64c06c 100644 (file)
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
 Version 2.02.178 - 
 =====================================
+  Suppress some repeated reads of the same disk data at the device layer.
   Avoid exceeding array bounds in allocation tag processing.
   Refactor metadata reading code to use callback functions.
   Move memory allocation for the key dev_reads into the device layer.
index 30e4235aa02a4976948b968cfa1ab0147be4e098..bacc7deffd5f169b4810fad4f213f33da896c701 100644 (file)
 #  endif
 #endif
 
+/*
+ * Always read at least 8k from disk.
+ * This seems to be a good compromise for the existing LVM2 metadata layout.
+ */
+#define MIN_READ_SIZE (8 * 1024)
+
 static DM_LIST_INIT(_open_devices);
 static unsigned _dev_size_seqno = 1;
 
@@ -273,6 +279,11 @@ static int _aligned_io(struct device_area *where, char *buffer,
 
        if (!block_size)
                block_size = lvm_getpagesize();
+
+       /* Apply minimum read size */
+       if (!should_write && block_size < MIN_READ_SIZE)
+               block_size = MIN_READ_SIZE;
+
        mask = block_size - 1;
 
        _widen_region(block_size, where, &widened);
@@ -785,14 +796,32 @@ static void _dev_inc_error_count(struct device *dev)
 static int _dev_read(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason)
 {
        struct device_area where;
+       struct device_buffer *devbuf;
+       uint64_t buf_end;
        int ret;
 
-       if (!dev->open_count)
-               return_0;
+       if (!dev->open_count) {
+               log_error(INTERNAL_ERROR "Attempt to access device %s while closed.", dev_name(dev));
+               return 0;
+       }
 
        if (!_dev_is_valid(dev))
                return 0;
 
+       /*
+        * Can we satisfy this from data we stored last time we read?
+        */
+       if ((devbuf = DEV_DEVBUF(dev, reason)) && devbuf->malloc_address) {
+               buf_end = devbuf->where.start + devbuf->where.size - 1;
+               if (offset >= devbuf->where.start && offset <= buf_end && offset + len - 1 <= buf_end) {
+                       /* Reuse this buffer */
+                       devbuf->data = (char *) devbuf->buf + (offset - devbuf->where.start);
+                       log_debug_io("Cached read for %" PRIu64 " bytes at %" PRIu64 " on %s (for %s)",
+                                    len, (uint64_t) offset, dev_name(dev), _reason_text(reason));
+                       return 1;
+               }
+       }
+
        where.dev = dev;
        where.start = offset;
        where.size = len;
This page took 0.04902 seconds and 5 git commands to generate.