free(e);
}
+static int _last_byte_fd;
+static uint64_t _last_byte_offset;
+static int _last_byte_sector_size;
+
static bool _async_issue(struct io_engine *ioe, enum dir d, int fd,
sector_t sb, sector_t se, void *data, void *context)
{
struct iocb *cb_array[1];
struct control_block *cb;
struct async_engine *e = _to_async(ioe);
+ sector_t offset;
+ sector_t nbytes;
+ sector_t limit_nbytes;
+ sector_t extra_nbytes = 0;
if (((uintptr_t) data) & e->page_mask) {
log_warn("misaligned data buffer");
return false;
}
+ offset = sb << SECTOR_SHIFT;
+ nbytes = (se - sb) << SECTOR_SHIFT;
+
+ /*
+ * If bcache block goes past where lvm wants to write, then clamp it.
+ */
+ if ((d == DIR_WRITE) && _last_byte_offset && (fd == _last_byte_fd)) {
+ if (offset > _last_byte_offset) {
+ log_error("Limit write at %llu len %llu beyond last byte %llu",
+ (unsigned long long)offset,
+ (unsigned long long)nbytes,
+ (unsigned long long)_last_byte_offset);
+ return false;
+ }
+
+ if (offset + nbytes > _last_byte_offset) {
+ limit_nbytes = _last_byte_offset - offset;
+ if (limit_nbytes % _last_byte_sector_size)
+ extra_nbytes = _last_byte_sector_size - (limit_nbytes % _last_byte_sector_size);
+
+ if (extra_nbytes) {
+ log_debug("Limit write at %llu len %llu to len %llu rounded to %llu",
+ (unsigned long long)offset,
+ (unsigned long long)nbytes,
+ (unsigned long long)limit_nbytes,
+ (unsigned long long)(limit_nbytes + extra_nbytes));
+ nbytes = limit_nbytes + extra_nbytes;
+ } else {
+ log_debug("Limit write at %llu len %llu to len %llu",
+ (unsigned long long)offset,
+ (unsigned long long)nbytes,
+ (unsigned long long)limit_nbytes);
+ nbytes = limit_nbytes;
+ }
+ }
+ }
+
cb = _cb_alloc(e->cbs, context);
if (!cb) {
log_warn("couldn't allocate control block");
cb->cb.aio_fildes = (int) fd;
cb->cb.u.c.buf = data;
- cb->cb.u.c.offset = sb << SECTOR_SHIFT;
- cb->cb.u.c.nbytes = (se - sb) << SECTOR_SHIFT;
+ cb->cb.u.c.offset = offset;
+ cb->cb.u.c.nbytes = nbytes;
cb->cb.aio_lio_opcode = (d == DIR_READ) ? IO_CMD_PREAD : IO_CMD_PWRITE;
+#if 0
+ if (d == DIR_READ) {
+ log_debug("io R off %llu bytes %llu",
+ (unsigned long long)cb->cb.u.c.offset,
+ (unsigned long long)cb->cb.u.c.nbytes);
+ } else {
+ log_debug("io W off %llu bytes %llu",
+ (unsigned long long)cb->cb.u.c.offset,
+ (unsigned long long)cb->cb.u.c.nbytes);
+ }
+#endif
+
cb_array[0] = &cb->cb;
do {
r = io_submit(e->aio_context, 1, cb_array);
//----------------------------------------------------------------
+void bcache_set_last_byte(struct bcache *cache, int fd, uint64_t offset, int sector_size)
+{
+ _last_byte_fd = fd;
+ _last_byte_offset = offset;
+ _last_byte_sector_size = sector_size;
+ if (!sector_size)
+ _last_byte_sector_size = 512;
+}
+
+void bcache_unset_last_byte(struct bcache *cache, int fd)
+{
+ if (_last_byte_fd == fd) {
+ _last_byte_fd = 0;
+ _last_byte_offset = 0;
+ _last_byte_sector_size = 0;
+ }
+}
+
bool bcache_zero_bytes(struct bcache *cache, int fd, uint64_t start, size_t len);
bool bcache_set_bytes(struct bcache *cache, int fd, uint64_t start, size_t len, uint8_t val);
+void bcache_set_last_byte(struct bcache *cache, int fd, uint64_t offset, int sector_size);
+void bcache_unset_last_byte(struct bcache *cache, int fd);
+
//----------------------------------------------------------------
#endif
MDA_HEADER_SIZE -
sizeof(mdah->checksum_xl)));
+ dev_set_last_byte(dev, start_byte + MDA_HEADER_SIZE);
+
if (!dev_write_bytes(dev, start_byte, MDA_HEADER_SIZE, mdah)) {
+ dev_unset_last_byte(dev);
log_error("Failed to write mda header to %s fd %d", dev_name(dev), dev->bcache_fd);
return 0;
}
+ dev_unset_last_byte(dev);
return 1;
}
(unsigned long long)(rlocn_new->size - new_wrap),
(unsigned long long)new_wrap);
+ dev_set_last_byte(mdac->area.dev, mdac->area.start + mdah->size);
+
if (!dev_write_bytes(mdac->area.dev, mdac->area.start + rlocn_new->offset,
(size_t) (rlocn_new->size - new_wrap), new_buf)) {
log_error("Failed to write metadata to %s fd %d", dev_name(mdac->area.dev), mdac->area.dev->bcache_fd);
+ dev_unset_last_byte(mdac->area.dev);
goto out;
}
if (!dev_write_bytes(mdac->area.dev, mdac->area.start + MDA_HEADER_SIZE,
(size_t) new_wrap, new_buf + rlocn_new->size - new_wrap)) {
log_error("Failed to write metadata wrap to %s fd %d", dev_name(mdac->area.dev), mdac->area.dev->bcache_fd);
+ dev_unset_last_byte(mdac->area.dev);
goto out;
}
}
+ dev_unset_last_byte(mdac->area.dev);
+
rlocn_new->checksum = calc_crc(INITIAL_CRC,
(uint8_t *)new_buf,
(uint32_t)(rlocn_new->size - new_wrap));
{
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) {
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;
}
}
}
+ 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;
}
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;
}
}
}
+ 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;
}
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);
+}
+
bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data);
bool dev_write_zeros(struct device *dev, uint64_t start, size_t len);
bool dev_set_bytes(struct device *dev, uint64_t start, size_t len, uint8_t val);
+void dev_set_last_byte(struct device *dev, uint64_t offset);
+void dev_unset_last_byte(struct device *dev);
#endif
return 0;
}
+ dev_set_last_byte(dev, sizeof(log_header));
+
if (!dev_write_bytes(dev, UINT64_C(0), sizeof(log_header), &log_header)) {
+ dev_unset_last_byte(dev);
log_error("Failed to write log header to %s.", name);
return 0;
}
+ dev_unset_last_byte(dev);
label_scan_invalidate(dev);