mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
Fix automatic text metadata buffer expansion (using macro). [stdarg usage bug]
Cache formatted text metadata buffer between metadata area writes. [improves write performance when lots of metadata area clones]
This commit is contained in:
parent
31b5c6e65c
commit
78aa12e1dc
@ -1,5 +1,7 @@
|
|||||||
Version 2.02.00 -
|
Version 2.02.00 -
|
||||||
===================================
|
===================================
|
||||||
|
Fix automatic text metadata buffer expansion (using macro).
|
||||||
|
Cache formatted text metadata buffer between metadata area writes.
|
||||||
Add pe_start field to pvs.
|
Add pe_start field to pvs.
|
||||||
Add 'LVM-' prefix to uuids.
|
Add 'LVM-' prefix to uuids.
|
||||||
Split lv_segment_area from lv_segment to permit extension.
|
Split lv_segment_area from lv_segment to permit extension.
|
||||||
|
@ -29,6 +29,19 @@ struct formatter;
|
|||||||
typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
|
typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
|
||||||
const char *fmt, va_list ap);
|
const char *fmt, va_list ap);
|
||||||
typedef int (*nl_fn) (struct formatter * f);
|
typedef int (*nl_fn) (struct formatter * f);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macro for formatted output.
|
||||||
|
* out_with_comment_fn returns -1 if data didn't fit and buffer was expanded.
|
||||||
|
* Then argument list is reset and out_with_comment_fn is called again.
|
||||||
|
*/
|
||||||
|
#define _out_with_comment(f, buffer, fmt, ap) \
|
||||||
|
do { \
|
||||||
|
va_start(ap, fmt); \
|
||||||
|
r = f->out_with_comment(f, buffer, fmt, ap); \
|
||||||
|
va_end(ap); \
|
||||||
|
} while (r == -1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The first half of this file deals with
|
* The first half of this file deals with
|
||||||
* exporting the vg, ie. writing it to a file.
|
* exporting the vg, ie. writing it to a file.
|
||||||
@ -100,19 +113,30 @@ static int _nl_file(struct formatter *f)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _nl_raw(struct formatter *f)
|
static int _extend_buffer(struct formatter *f)
|
||||||
{
|
{
|
||||||
char *newbuf;
|
char *newbuf;
|
||||||
|
|
||||||
/* If metadata doesn't fit, double the buffer size */
|
log_debug("Doubling metadata output buffer to %" PRIu32,
|
||||||
if (f->data.buf.used + 2 > f->data.buf.size) {
|
f->data.buf.size * 2);
|
||||||
if (!(newbuf = dm_realloc(f->data.buf.start,
|
if (!(newbuf = dm_realloc(f->data.buf.start,
|
||||||
f->data.buf.size * 2))) {
|
f->data.buf.size * 2))) {
|
||||||
stack;
|
log_error("Buffer reallocation failed.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
f->data.buf.start = newbuf;
|
f->data.buf.start = newbuf;
|
||||||
f->data.buf.size *= 2;
|
f->data.buf.size *= 2;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _nl_raw(struct formatter *f)
|
||||||
|
{
|
||||||
|
/* If metadata doesn't fit, extend buffer */
|
||||||
|
if ((f->data.buf.used + 2 > f->data.buf.size) &&
|
||||||
|
(!_extend_buffer(f))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*(f->data.buf.start + f->data.buf.used) = '\n';
|
*(f->data.buf.start + f->data.buf.used) = '\n';
|
||||||
@ -163,22 +187,17 @@ static int _out_with_comment_raw(struct formatter *f, const char *comment,
|
|||||||
const char *fmt, va_list ap)
|
const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
char *newbuf;
|
|
||||||
|
|
||||||
retry:
|
|
||||||
n = vsnprintf(f->data.buf.start + f->data.buf.used,
|
n = vsnprintf(f->data.buf.start + f->data.buf.used,
|
||||||
f->data.buf.size - f->data.buf.used, fmt, ap);
|
f->data.buf.size - f->data.buf.used, fmt, ap);
|
||||||
|
|
||||||
/* If metadata doesn't fit, double the buffer size */
|
/* If metadata doesn't fit, extend buffer */
|
||||||
if (n < 0 || (n + f->data.buf.used + 2 > f->data.buf.size)) {
|
if (n < 0 || (n + f->data.buf.used + 2 > f->data.buf.size)) {
|
||||||
if (!(newbuf = dm_realloc(f->data.buf.start,
|
if (!_extend_buffer(f)) {
|
||||||
f->data.buf.size * 2))) {
|
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
f->data.buf.start = newbuf;
|
return -1; /* Retry */
|
||||||
f->data.buf.size *= 2;
|
|
||||||
goto retry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f->data.buf.used += n;
|
f->data.buf.used += n;
|
||||||
@ -229,9 +248,7 @@ int out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
|||||||
if (!_sectors_to_units(size, buffer, sizeof(buffer)))
|
if (!_sectors_to_units(size, buffer, sizeof(buffer)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
_out_with_comment(f, buffer, fmt, ap);
|
||||||
r = f->out_with_comment(f, buffer, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -245,9 +262,7 @@ int out_hint(struct formatter *f, const char *fmt, ...)
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
_out_with_comment(f, "# Hint only", fmt, ap);
|
||||||
r = f->out_with_comment(f, "# Hint only", fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -260,9 +275,7 @@ int out_text(struct formatter *f, const char *fmt, ...)
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
_out_with_comment(f, NULL, fmt, ap);
|
||||||
r = f->out_with_comment(f, NULL, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,11 @@ static struct format_instance *_create_text_instance(const struct format_type
|
|||||||
*fmt, const char *vgname,
|
*fmt, const char *vgname,
|
||||||
void *context);
|
void *context);
|
||||||
|
|
||||||
|
struct text_fid_context {
|
||||||
|
char *raw_metadata_buf;
|
||||||
|
uint32_t raw_metadata_buf_size;
|
||||||
|
};
|
||||||
|
|
||||||
struct dir_list {
|
struct dir_list {
|
||||||
struct list list;
|
struct list list;
|
||||||
char dir[0];
|
char dir[0];
|
||||||
@ -337,12 +342,12 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
|||||||
struct metadata_area *mda)
|
struct metadata_area *mda)
|
||||||
{
|
{
|
||||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||||
|
struct text_fid_context *fidtc = (struct text_fid_context *) fid->private;
|
||||||
struct raw_locn *rlocn;
|
struct raw_locn *rlocn;
|
||||||
struct mda_header *mdah;
|
struct mda_header *mdah;
|
||||||
struct pv_list *pvl;
|
struct pv_list *pvl;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
uint32_t new_wrap = 0, old_wrap = 0;
|
uint32_t new_wrap = 0, old_wrap = 0;
|
||||||
char *buf = NULL;
|
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
|
||||||
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
|
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
|
||||||
@ -369,11 +374,15 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
|||||||
rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0);
|
rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0);
|
||||||
mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah);
|
mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah);
|
||||||
|
|
||||||
if (!(mdac->rlocn.size = text_vg_export_raw(vg, "", &buf))) {
|
if (!fidtc->raw_metadata_buf &&
|
||||||
|
!(fidtc->raw_metadata_buf_size =
|
||||||
|
text_vg_export_raw(vg, "", &fidtc->raw_metadata_buf))) {
|
||||||
log_error("VG %s metadata writing failed", vg->name);
|
log_error("VG %s metadata writing failed", vg->name);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mdac->rlocn.size = fidtc->raw_metadata_buf_size;
|
||||||
|
|
||||||
if (mdac->rlocn.offset + mdac->rlocn.size > mdah->size)
|
if (mdac->rlocn.offset + mdac->rlocn.size > mdah->size)
|
||||||
new_wrap = (mdac->rlocn.offset + mdac->rlocn.size) - mdah->size;
|
new_wrap = (mdac->rlocn.offset + mdac->rlocn.size) - mdah->size;
|
||||||
|
|
||||||
@ -396,7 +405,8 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
|||||||
|
|
||||||
/* Write text out, circularly */
|
/* Write text out, circularly */
|
||||||
if (!dev_write(mdac->area.dev, mdac->area.start + mdac->rlocn.offset,
|
if (!dev_write(mdac->area.dev, mdac->area.start + mdac->rlocn.offset,
|
||||||
(size_t) (mdac->rlocn.size - new_wrap), buf)) {
|
(size_t) (mdac->rlocn.size - new_wrap),
|
||||||
|
fidtc->raw_metadata_buf)) {
|
||||||
stack;
|
stack;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -409,18 +419,20 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
|||||||
if (!dev_write(mdac->area.dev,
|
if (!dev_write(mdac->area.dev,
|
||||||
mdac->area.start + MDA_HEADER_SIZE,
|
mdac->area.start + MDA_HEADER_SIZE,
|
||||||
(size_t) new_wrap,
|
(size_t) new_wrap,
|
||||||
buf + mdac->rlocn.size - new_wrap)) {
|
fidtc->raw_metadata_buf +
|
||||||
|
mdac->rlocn.size - new_wrap)) {
|
||||||
stack;
|
stack;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mdac->rlocn.checksum = calc_crc(INITIAL_CRC, buf,
|
mdac->rlocn.checksum = calc_crc(INITIAL_CRC, fidtc->raw_metadata_buf,
|
||||||
(uint32_t) (mdac->rlocn.size -
|
(uint32_t) (mdac->rlocn.size -
|
||||||
new_wrap));
|
new_wrap));
|
||||||
if (new_wrap)
|
if (new_wrap)
|
||||||
mdac->rlocn.checksum = calc_crc(mdac->rlocn.checksum,
|
mdac->rlocn.checksum = calc_crc(mdac->rlocn.checksum,
|
||||||
buf + mdac->rlocn.size -
|
fidtc->raw_metadata_buf +
|
||||||
|
mdac->rlocn.size -
|
||||||
new_wrap, new_wrap);
|
new_wrap, new_wrap);
|
||||||
|
|
||||||
r = 1;
|
r = 1;
|
||||||
@ -429,8 +441,6 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
|||||||
if (!r && !dev_close(mdac->area.dev))
|
if (!r && !dev_close(mdac->area.dev))
|
||||||
stack;
|
stack;
|
||||||
|
|
||||||
if (buf)
|
|
||||||
dm_free(buf);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,6 +450,7 @@ static int _vg_commit_raw_rlocn(struct format_instance *fid,
|
|||||||
int precommit)
|
int precommit)
|
||||||
{
|
{
|
||||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||||
|
struct text_fid_context *fidtc = (struct text_fid_context *) fid->private;
|
||||||
struct mda_header *mdah;
|
struct mda_header *mdah;
|
||||||
struct raw_locn *rlocn;
|
struct raw_locn *rlocn;
|
||||||
struct pv_list *pvl;
|
struct pv_list *pvl;
|
||||||
@ -488,8 +499,14 @@ static int _vg_commit_raw_rlocn(struct format_instance *fid,
|
|||||||
r = 1;
|
r = 1;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (!precommit && !dev_close(mdac->area.dev))
|
if (!precommit) {
|
||||||
stack;
|
if (!dev_close(mdac->area.dev))
|
||||||
|
stack;
|
||||||
|
if (fidtc->raw_metadata_buf) {
|
||||||
|
dm_free(fidtc->raw_metadata_buf);
|
||||||
|
fidtc->raw_metadata_buf = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -512,6 +529,7 @@ static int _vg_revert_raw(struct format_instance *fid, struct volume_group *vg,
|
|||||||
struct metadata_area *mda)
|
struct metadata_area *mda)
|
||||||
{
|
{
|
||||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||||
|
struct text_fid_context *fidtc = (struct text_fid_context *) fid->private;
|
||||||
struct pv_list *pvl;
|
struct pv_list *pvl;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
|
||||||
@ -529,6 +547,11 @@ static int _vg_revert_raw(struct format_instance *fid, struct volume_group *vg,
|
|||||||
if (!dev_close(mdac->area.dev))
|
if (!dev_close(mdac->area.dev))
|
||||||
stack;
|
stack;
|
||||||
|
|
||||||
|
if (fidtc->raw_metadata_buf) {
|
||||||
|
dm_free(fidtc->raw_metadata_buf);
|
||||||
|
fidtc->raw_metadata_buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1401,6 +1424,7 @@ static struct format_instance *_create_text_instance(const struct format_type
|
|||||||
void *context)
|
void *context)
|
||||||
{
|
{
|
||||||
struct format_instance *fid;
|
struct format_instance *fid;
|
||||||
|
struct text_fid_context *fidtc;
|
||||||
struct metadata_area *mda, *mda_new;
|
struct metadata_area *mda, *mda_new;
|
||||||
struct mda_context *mdac, *mdac_new;
|
struct mda_context *mdac, *mdac_new;
|
||||||
struct dir_list *dl;
|
struct dir_list *dl;
|
||||||
@ -1415,8 +1439,16 @@ static struct format_instance *_create_text_instance(const struct format_type
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
fid->fmt = fmt;
|
if (!(fidtc = (struct text_fid_context *)
|
||||||
|
dm_pool_zalloc(fmt->cmd->mem,sizeof(*fidtc)))) {
|
||||||
|
log_error("Couldn't allocate text_fid_context.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fidtc->raw_metadata_buf = NULL;
|
||||||
|
fid->private = (void *) fidtc;
|
||||||
|
|
||||||
|
fid->fmt = fmt;
|
||||||
list_init(&fid->metadata_areas);
|
list_init(&fid->metadata_areas);
|
||||||
|
|
||||||
if (!vgname) {
|
if (!vgname) {
|
||||||
|
@ -181,6 +181,7 @@ struct metadata_area {
|
|||||||
struct format_instance {
|
struct format_instance {
|
||||||
const struct format_type *fmt;
|
const struct format_type *fmt;
|
||||||
struct list metadata_areas; /* e.g. metadata locations */
|
struct list metadata_areas; /* e.g. metadata locations */
|
||||||
|
void *private;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct volume_group {
|
struct volume_group {
|
||||||
|
Loading…
Reference in New Issue
Block a user