From: Serge E. Hallyn <serue@xxxxxxxxxx> ckpt_generate_fmt() now places the format in ctx->fmt_buf. ckpt_fill_err_string() calls ckpt_generate_fmt() under ctx->fmt_buf_lock, and writes its own error (under ctx->err_string_lock) to ctx->err_string. Signed-off-by: Serge E. Hallyn <serue@xxxxxxxxxx> --- checkpoint/checkpoint.c | 76 ++++++++++++++++++++++++++++++-------------- checkpoint/sys.c | 16 ++------- include/linux/checkpoint.h | 3 +- 3 files changed, 58 insertions(+), 37 deletions(-) diff --git a/checkpoint/checkpoint.c b/checkpoint/checkpoint.c index d0ffd0d..49f6e9d 100644 --- a/checkpoint/checkpoint.c +++ b/checkpoint/checkpoint.c @@ -96,36 +96,52 @@ int ckpt_write_string(struct ckpt_ctx *ctx, char *str, int len) return ckpt_write_obj_type(ctx, str, len, CKPT_HDR_STRING); } -/* see _ckpt_generate_fmt for information on @fmt0 */ -static void __ckpt_generate_err(struct ckpt_ctx *ctx, char *fmt0, +static void ckpt_fill_err_string(struct ckpt_ctx *ctx, char *fmt0, char *fmt, va_list ap) { va_list aq; - char *format; - char *str; int len; + unsigned long flags; - format = ckpt_generate_fmt(ctx, fmt0, fmt); + spin_lock_irqsave(&ctx->err_string_lock, flags); + spin_lock(&ctx->fmt_buf_lock); + ckpt_generate_fmt(ctx, fmt0, fmt); va_copy(aq, ap); + if (ctx->err_string_len == CKPT_MSG_BUFSZ) + goto out_unlock; + /* * prefix the error string with a '\0' to facilitate easy * backtrace to the beginning of the error message without * needing to parse the entire checkpoint image. */ - ctx->err_string[0] = '\0'; - str = &ctx->err_string[1]; - len = vsnprintf(str, 255, format ? : fmt, ap) + 2; + if (ctx->err_string_len == 0) { + ctx->err_string[0] = '\0'; + ctx->err_string_len = 1; + } - if (len > 256) { + len = vsnprintf(ctx->err_string + ctx->err_string_len, + CKPT_MSG_BUFSZ - ctx->err_string_len, + ctx->fmt_buf, ap); + + if (len >= CKPT_MSG_BUFSZ - ctx->err_string_len) { printk(KERN_NOTICE "c/r: error string truncated: "); vprintk(fmt, aq); - } + ctx->err_string[CKPT_MSG_BUFSZ-1] = '\0'; + ctx->err_string_len = CKPT_MSG_BUFSZ; + } else + /* vscnprintf did add a \0 but didn't count + * it toward the len. We want it to count + * toward the len so we keep a \0 between each + * error msg */ + ctx->err_string_len += len + 1; va_end(aq); - kfree(format); - ckpt_debug("c/r: checkpoint error: %s\n", str); +out_unlock: + spin_unlock(&ctx->fmt_buf_lock); + spin_unlock_irqrestore(&ctx->err_string_lock, flags); } /** @@ -143,7 +159,7 @@ void __ckpt_write_err(struct ckpt_ctx *ctx, char *fmt0, char *fmt, ...) va_list ap; va_start(ap, fmt); - __ckpt_generate_err(ctx, fmt0, fmt, ap); + ckpt_fill_err_string(ctx, fmt, ap); va_end(ap); } @@ -160,29 +176,41 @@ void __ckpt_write_err(struct ckpt_ctx *ctx, char *fmt0, char *fmt, ...) int ckpt_write_err(struct ckpt_ctx *ctx, char *fmt0, char *fmt, ...) { va_list ap; - char *str; - int len, ret = 0; + int i, len, ret = 0; if (fmt) { va_start(ap, fmt); - __ckpt_generate_err(ctx, fmt0, fmt, ap); + ckpt_fill_err_string(ctx, fmt, ap); va_end(ap); } - str = ctx->err_string; - len = strlen(str + 1); - if (len == 0) /* empty error string */ - return 0; + mutex_lock(&ctx->msg_buf_mutex); + spin_lock(&ctx->err_string_lock); + len = ctx->err_string_len; + memcpy(ctx->msg_buf, ctx->err_string, len); + ctx->err_string_len = 0; + spin_unlock(&ctx->err_string_lock); + + if (len == 0) + goto out_unlock; - len += 2; /* leading and trailing '\0' */ + ctx->msg_buf_len = len; + /* write to the checkpoint image */ ret = ckpt_write_obj_type(ctx, NULL, 0, CKPT_HDR_ERROR); if (!ret) - ret = ckpt_write_string(ctx, str, len); + ret = ckpt_write_string(ctx, ctx->msg_buf, ctx->msg_buf_len); if (ret < 0) printk(KERN_NOTICE "c/r: error string unsaved (%d): %s\n", - ret, str + 1); + ret, ctx->msg_buf); + + /* duplicate to user log file and syslog */ + for (i = 0; i < len-1; i++) + if (ctx->msg_buf[i] == '\0') + ctx->msg_buf[i] = '\n'; + ckpt_do_write_msg(ctx); - str[1] = '\0'; +out_unlock: + mutex_unlock(&ctx->msg_buf_mutex); return ret; } diff --git a/checkpoint/sys.c b/checkpoint/sys.c index 0a486f0..8810576 100644 --- a/checkpoint/sys.c +++ b/checkpoint/sys.c @@ -375,12 +375,13 @@ int walk_task_subtree(struct task_struct *root, * * Here, T is simply passed, E expects an integer (err), O expects an * integer (objref), and the last argument matches the format string. + * + * Must be called with ctx->fmt_buf_lock held. The expanded format + * will be placed in ctx->fmt_buf. */ char *ckpt_generate_fmt(struct ckpt_ctx *ctx, char *fmt0, char *fmt) { - static int warn_notask = 0; - static int warn_prefmt = 0; - char *format; + char *format = ctx->fmt_buf; int i, j, len = 0; static struct { @@ -395,15 +396,6 @@ char *ckpt_generate_fmt(struct ckpt_ctx *ctx, char *fmt0, char *fmt) { 0, "??? %pS" }, }; - /* - * 17 for "pid %d" (plus space) - * 21 for "tsk %s" (tsk->comm) - * up to 8 per varfmt entry - */ - format = kzalloc(37 + 8 * strlen(fmt0) + strlen(fmt), GFP_KERNEL); - if (!format) - return NULL; - format[len++] = '['; if (fmt0[0] == 'T') { diff --git a/include/linux/checkpoint.h b/include/linux/checkpoint.h index 541bfa8..4cfd44b 100644 --- a/include/linux/checkpoint.h +++ b/include/linux/checkpoint.h @@ -370,7 +370,8 @@ static inline void restore_debug_free(struct ckpt_ctx *ctx) {} #endif /* CONFIG_CHECKPOINT_DEBUG */ -extern char *ckpt_generate_fmt(struct ckpt_ctx *ctx, char *fmt0, char *fmt); +extern void ckpt_generate_fmt(struct ckpt_ctx *ctx, char *fmt0, char *fmt); +static inline void ckpt_do_write_msg(struct ckpt_ctx *ctx) { } #endif /* CONFIG_CHECKPOINT */ #endif /* __KERNEL__ */ -- 1.6.1 _______________________________________________ Containers mailing list Containers@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/containers