From: Mikulas Patocka dm-ioctl: enhanced messages This patch introduces enhanced message support that is needed for the following statistics patch. This patch allows processing of special messages in the device mapper in the function "message_for_md". If the device mapper doesn't support the message, it is passed to the target driver.. This patch allows two-way messages, that is messages that may return some data. If the message returns data, the kernel signals it with DM_MESSAGE_OUT_FLAG flag. Signed-off-by: Mikulas Patocka FIXME Why is BUFFER_FULL tested before setting size to 0? Currently BUFFER_FULL => no data. FIXME Update ioctl version FIXME Callers ignore dm_output_message_string return value? FIXME Can we dodge the separate sprintf + fn call? --- drivers/md/dm-ioctl.c | 62 +++++++++++++++++++++++++++++++++++++++++- include/uapi/linux/dm-ioctl.h | 5 +++ 2 files changed, 66 insertions(+), 1 deletion(-) Index: linux/drivers/md/dm-ioctl.c =================================================================== --- linux.orig/drivers/md/dm-ioctl.c +++ linux/drivers/md/dm-ioctl.c @@ -1455,6 +1455,59 @@ static int table_status(struct dm_ioctl return 0; } +struct dm_message_output_callback { + struct dm_ioctl *param; + size_t param_size; +}; + +// ENOBUFS instead of -1? +static int dm_output_message_string(struct dm_message_output_callback *c, + const char *string) +{ + size_t len; + char *p; + + if (c->param->flags & DM_BUFFER_FULL_FLAG) + return -1; + + if (!(c->param->flags & DM_MESSAGE_OUT_FLAG)) { + p = get_result_buffer(c->param, c->param_size, &len); + if (!len) { + c->param->flags |= DM_BUFFER_FULL_FLAG; + return -1; + } + *p = 0; + c->param->data_size = c->param->data_start + 1; + c->param->flags |= DM_MESSAGE_OUT_FLAG; + } + + p = (char *)c->param + c->param->data_size - 1; + len = strlen(string); + if (c->param->data_size + len > c->param_size) { + c->param->flags |= DM_BUFFER_FULL_FLAG; + c->param->flags &= ~DM_MESSAGE_OUT_FLAG; + return -1; + } + + c->param->data_size += len; + strcpy(p, string); + + return 0; +} + +/* + * Process device-mapper dependent messages. + * Returns a number <= 0 if message was processed by device mapper. + * Returns 1 if message should be delivered to the target. + */ +// rename this to make meaning of return status clearer +static int message_for_md(struct mapped_device *md, + struct dm_message_output_callback *c, + unsigned argc, char **argv) +{ + return 1; +} + /* * Pass a message to the target that's at the supplied device offset. */ @@ -1467,6 +1520,7 @@ static int target_message(struct dm_ioct struct dm_target *ti; struct dm_target_msg *tmsg = (void *) param + param->data_start; int srcu_idx; + struct dm_message_output_callback c = { param, param_size }; md = find_device(param); if (!md) @@ -1490,6 +1544,10 @@ static int target_message(struct dm_ioct goto out_argv; } + r = message_for_md(md, &c, argc, argv); + if (r <= 0) + goto out_argv; + table = dm_get_live_table(md, &srcu_idx); if (!table) goto out_table; @@ -1515,7 +1573,8 @@ static int target_message(struct dm_ioct out_argv: kfree(argv); out: - param->data_size = 0; + if (!(param->flags & (DM_MESSAGE_OUT_FLAG | DM_BUFFER_FULL_FLAG))) + param->data_size = 0; dm_put(md); return r; } @@ -1695,6 +1754,7 @@ static int validate_params(uint cmd, str param->flags &= ~DM_BUFFER_FULL_FLAG; param->flags &= ~DM_UEVENT_GENERATED_FLAG; param->flags &= ~DM_SECURE_DATA_FLAG; + param->flags &= ~DM_MESSAGE_OUT_FLAG; /* Ignores parameters */ if (cmd == DM_REMOVE_ALL_CMD || Index: linux/include/uapi/linux/dm-ioctl.h =================================================================== --- linux.orig/include/uapi/linux/dm-ioctl.h +++ linux/include/uapi/linux/dm-ioctl.h @@ -336,4 +336,9 @@ enum { */ #define DM_SECURE_DATA_FLAG (1 << 15) /* In */ +/* + * If set, message generated output. + */ +#define DM_MESSAGE_OUT_FLAG (1 << 16) /* Out */ + #endif /* _LINUX_DM_IOCTL_H */