typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
const char *fmt, va_list ap);
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
* exporting the vg, ie. writing it to a file.
return 1;
}
-static int _nl_raw(struct formatter *f)
+static int _extend_buffer(struct formatter *f)
{
char *newbuf;
- /* If metadata doesn't fit, double the buffer size */
- if (f->data.buf.used + 2 > f->data.buf.size) {
- if (!(newbuf = dm_realloc(f->data.buf.start,
- f->data.buf.size * 2))) {
- stack;
- return 0;
- }
- f->data.buf.start = newbuf;
- f->data.buf.size *= 2;
+ log_debug("Doubling metadata output buffer to %" PRIu32,
+ f->data.buf.size * 2);
+ if (!(newbuf = dm_realloc(f->data.buf.start,
+ f->data.buf.size * 2))) {
+ log_error("Buffer reallocation failed.");
+ return 0;
+ }
+ f->data.buf.start = newbuf;
+ 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';
const char *fmt, va_list ap)
{
int n;
- char *newbuf;
- retry:
n = vsnprintf(f->data.buf.start + f->data.buf.used,
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 (!(newbuf = dm_realloc(f->data.buf.start,
- f->data.buf.size * 2))) {
+ if (!_extend_buffer(f)) {
stack;
return 0;
}
- f->data.buf.start = newbuf;
- f->data.buf.size *= 2;
- goto retry;
+ return -1; /* Retry */
}
f->data.buf.used += n;
if (!_sectors_to_units(size, buffer, sizeof(buffer)))
return 0;
- va_start(ap, fmt);
- r = f->out_with_comment(f, buffer, fmt, ap);
- va_end(ap);
+ _out_with_comment(f, buffer, fmt, ap);
return r;
}
va_list ap;
int r;
- va_start(ap, fmt);
- r = f->out_with_comment(f, "# Hint only", fmt, ap);
- va_end(ap);
+ _out_with_comment(f, "# Hint only", fmt, ap);
return r;
}
va_list ap;
int r;
- va_start(ap, fmt);
- r = f->out_with_comment(f, NULL, fmt, ap);
- va_end(ap);
+ _out_with_comment(f, NULL, fmt, ap);
return r;
}
*fmt, const char *vgname,
void *context);
+struct text_fid_context {
+ char *raw_metadata_buf;
+ uint32_t raw_metadata_buf_size;
+};
+
struct dir_list {
struct list list;
char dir[0];
struct metadata_area *mda)
{
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 mda_header *mdah;
struct pv_list *pvl;
int r = 0;
uint32_t new_wrap = 0, old_wrap = 0;
- char *buf = NULL;
int found = 0;
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0);
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);
goto out;
}
+ mdac->rlocn.size = fidtc->raw_metadata_buf_size;
+
if (mdac->rlocn.offset + mdac->rlocn.size > mdah->size)
new_wrap = (mdac->rlocn.offset + mdac->rlocn.size) - mdah->size;
/* Write text out, circularly */
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;
goto out;
}
if (!dev_write(mdac->area.dev,
mdac->area.start + MDA_HEADER_SIZE,
(size_t) new_wrap,
- buf + mdac->rlocn.size - new_wrap)) {
+ fidtc->raw_metadata_buf +
+ mdac->rlocn.size - new_wrap)) {
stack;
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 -
new_wrap));
if (new_wrap)
mdac->rlocn.checksum = calc_crc(mdac->rlocn.checksum,
- buf + mdac->rlocn.size -
+ fidtc->raw_metadata_buf +
+ mdac->rlocn.size -
new_wrap, new_wrap);
r = 1;
if (!r && !dev_close(mdac->area.dev))
stack;
- if (buf)
- dm_free(buf);
return r;
}
int precommit)
{
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 raw_locn *rlocn;
struct pv_list *pvl;
r = 1;
out:
- if (!precommit && !dev_close(mdac->area.dev))
- stack;
+ if (!precommit) {
+ 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;
}
struct metadata_area *mda)
{
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;
int found = 0;
if (!dev_close(mdac->area.dev))
stack;
+ if (fidtc->raw_metadata_buf) {
+ dm_free(fidtc->raw_metadata_buf);
+ fidtc->raw_metadata_buf = NULL;
+ }
+
return 1;
}
void *context)
{
struct format_instance *fid;
+ struct text_fid_context *fidtc;
struct metadata_area *mda, *mda_new;
struct mda_context *mdac, *mdac_new;
struct dir_list *dl;
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);
if (!vgname) {