diff options
author | David Teigland <teigland@redhat.com> | 2018-10-29 16:53:17 -0500 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2018-10-29 16:53:17 -0500 |
commit | aecf542126640faa17c240afbb1ea61f11355c39 (patch) | |
tree | d0a0d88a4ebb0ae92a76f9147c66d81d418601a7 /lib/label/label.c | |
parent | 8df2dd66ce53817b250f5dd6bd05fda3a38ac26e (diff) | |
download | lvm2-aecf542126640faa17c240afbb1ea61f11355c39.tar.gz |
metadata: prevent writing beyond metadata area
lvm uses a bcache block size of 128K. A bcache block
at the end of the metadata area will overlap the PEs
from which LVs are allocated. How much depends on
alignments. When lvm reads and writes one of these
bcache blocks to update VG metadata, it can also be
reading and writing PEs that belong to an LV.
If these overlapping PEs are being written to by the
LV user (e.g. filesystem) at the same time that lvm
is modifying VG metadata in the overlapping bcache
block, then the user's updates to the PEs can be lost.
This patch is a quick hack to prevent lvm from writing
past the end of the metadata area.
Diffstat (limited to 'lib/label/label.c')
-rw-r--r-- | lib/label/label.c | 35 |
1 files changed, 34 insertions, 1 deletions
diff --git a/lib/label/label.c b/lib/label/label.c index 22b6bc218..c92d2cf8d 100644 --- a/lib/label/label.c +++ b/lib/label/label.c @@ -174,6 +174,7 @@ int label_write(struct device *dev, struct label *label) { char buf[LABEL_SIZE] __attribute__((aligned(8))); struct label_header *lh = (struct label_header *) buf; + uint64_t offset; int r = 1; if (!label->labeller->ops->write) { @@ -208,11 +209,17 @@ int label_write(struct device *dev, struct label *label) return 0; } - if (!dev_write_bytes(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) { + offset = label->sector << SECTOR_SHIFT; + + dev_set_last_byte(dev, offset + LABEL_SIZE); + + if (!dev_write_bytes(dev, offset, LABEL_SIZE, buf)) { log_debug_devs("Failed to write label to %s", dev_name(dev)); r = 0; } + dev_unset_last_byte(dev); + return r; } @@ -1256,9 +1263,12 @@ bool dev_write_zeros(struct device *dev, uint64_t start, size_t len) } } + dev_set_last_byte(dev, start + len); + if (!bcache_zero_bytes(scan_bcache, dev->bcache_fd, start, len)) { log_error("Error writing device %s at %llu length %u.", dev_name(dev), (unsigned long long)start, (uint32_t)len); + dev_unset_last_byte(dev); label_scan_invalidate(dev); return false; } @@ -1266,9 +1276,11 @@ bool dev_write_zeros(struct device *dev, uint64_t start, size_t len) if (!bcache_flush(scan_bcache)) { log_error("Error writing device %s at %llu length %u.", dev_name(dev), (unsigned long long)start, (uint32_t)len); + dev_unset_last_byte(dev); label_scan_invalidate(dev); return false; } + dev_unset_last_byte(dev); return true; } @@ -1302,9 +1314,12 @@ bool dev_set_bytes(struct device *dev, uint64_t start, size_t len, uint8_t val) } } + dev_set_last_byte(dev, start + len); + if (!bcache_set_bytes(scan_bcache, dev->bcache_fd, start, len, val)) { log_error("Error writing device %s at %llu length %u.", dev_name(dev), (unsigned long long)start, (uint32_t)len); + dev_unset_last_byte(dev); label_scan_invalidate(dev); return false; } @@ -1312,9 +1327,27 @@ bool dev_set_bytes(struct device *dev, uint64_t start, size_t len, uint8_t val) if (!bcache_flush(scan_bcache)) { log_error("Error writing device %s at %llu length %u.", dev_name(dev), (unsigned long long)start, (uint32_t)len); + dev_unset_last_byte(dev); label_scan_invalidate(dev); return false; } + + dev_unset_last_byte(dev); return true; } +void dev_set_last_byte(struct device *dev, uint64_t offset) +{ + unsigned int phys_block_size = 0; + unsigned int block_size = 0; + + dev_get_block_size(dev, &phys_block_size, &block_size); + + bcache_set_last_byte(scan_bcache, dev->bcache_fd, offset, phys_block_size); +} + +void dev_unset_last_byte(struct device *dev) +{ + bcache_unset_last_byte(scan_bcache, dev->bcache_fd); +} + |