From: Mike Snitzer Subject: dm thin: commit before gathering status BZ 882426 This RHEL6 port was done with care to not to break kABI: - Add .status_with_flags to at end of the target_type structure via __GENKSYMS__; the old .status is left untouched . Add DM_TARGET_STATUS_WITH_FLAGS feature flag and set it in the thin-pool target's .features; this allows DM core to know it can safely dereference ->status_with_flags . Add note about non-RHEL DM target .status_with_flags considerations to include/linux/device-mapper.h This patch is required to successfully validate RHEL6's thimp discard support using the thinp-test-suite's various automated discard tests (those tests require precise accounting of the thin-pool's used blocks) Upstream commit 1f4e0ff07980820977f45d6a5dbc81d3bb9ce4d3 Author: Alasdair G Kergon Date: Fri Jul 27 15:08:16 2012 +0100 dm thin: commit before gathering status Commit outstanding metadata before returning the status for a dm thin pool so that the numbers reported are as up-to-date as possible. The commit is not performed if the device is suspended or if the DM_NOFLUSH_FLAG is supplied by userspace and passed to the target through a new 'status_flags' parameter in the target's dm_status_fn. The userspace dmsetup tool will support the --noflush flag with the 'dmsetup status' and 'dmsetup wait' commands from version 1.02.76 onwards. Tested-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-ioctl.c | 16 +++++++++++++++- drivers/md/dm-thin.c | 13 +++++++++---- drivers/md/dm.h | 5 +++++ include/linux/device-mapper.h | 23 +++++++++++++++++++++++ include/linux/dm-ioctl.h | 8 +++++--- 5 files changed, 57 insertions(+), 8 deletions(-) Index: linux-rhel6/drivers/md/dm-ioctl.c =================================================================== --- linux-rhel6.orig/drivers/md/dm-ioctl.c +++ linux-rhel6/drivers/md/dm-ioctl.c @@ -1054,6 +1054,7 @@ static void retrieve_status(struct dm_ta char *outbuf, *outptr; status_type_t type; size_t remaining, len, used = 0; + unsigned status_flags = 0; outptr = outbuf = get_result_buffer(param, param_size, &len); @@ -1089,7 +1090,20 @@ static void retrieve_status(struct dm_ta } /* Get the status/table string from the target driver */ - if (ti->type->status) { + if (dm_target_provides_status_with_flags(ti->type) && + ti->type->status_with_flags) { + /* + * Use the RHEL-specific hook for getting status with flags + * - for more details see the comment in device-mapper.h + */ + if (param->flags & DM_NOFLUSH_FLAG) + status_flags |= DM_STATUS_NOFLUSH_FLAG; + if (ti->type->status_with_flags(ti, type, status_flags, + outptr, remaining)) { + param->flags |= DM_BUFFER_FULL_FLAG; + break; + } + } else if (ti->type->status) { if (ti->type->status(ti, type, outptr, remaining)) { param->flags |= DM_BUFFER_FULL_FLAG; break; Index: linux-rhel6/drivers/md/dm-thin.c =================================================================== --- linux-rhel6.orig/drivers/md/dm-thin.c +++ linux-rhel6/drivers/md/dm-thin.c @@ -5,6 +5,7 @@ */ #include "dm-thin-metadata.h" +#include "dm.h" #include #include @@ -2645,7 +2646,7 @@ static void emit_flags(struct pool_featu * / */ static int pool_status(struct dm_target *ti, status_type_t type, - char *result, unsigned maxlen) + unsigned status_flags, char *result, unsigned maxlen) { int r; unsigned sz = 0; @@ -2667,6 +2668,10 @@ static int pool_status(struct dm_target break; } + /* Commit to ensure statistics aren't out-of-date */ + if (!(status_flags & DM_STATUS_NOFLUSH_FLAG) && !dm_suspended(ti)) + (void) commit_or_fallback(pool); + r = dm_pool_get_metadata_transaction_id(pool->pmd, &transaction_id); if (r) @@ -2807,8 +2812,8 @@ static void pool_io_hints(struct dm_targ static struct target_type pool_target = { .name = "thin-pool", .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE | - DM_TARGET_IMMUTABLE, - .version = {1, 5, 0}, + DM_TARGET_IMMUTABLE | DM_TARGET_STATUS_WITH_FLAGS, + .version = {1, 5, 1}, .module = THIS_MODULE, .ctr = pool_ctr, .dtr = pool_dtr, @@ -2817,7 +2822,7 @@ static struct target_type pool_target = .preresume = pool_preresume, .resume = pool_resume, .message = pool_message, - .status = pool_status, + .status_with_flags = pool_status, .merge = pool_merge, .iterate_devices = pool_iterate_devices, .io_hints = pool_io_hints, Index: linux-rhel6/drivers/md/dm.h =================================================================== --- linux-rhel6.orig/drivers/md/dm.h +++ linux-rhel6/drivers/md/dm.h @@ -23,6 +23,11 @@ #define DM_SUSPEND_NOFLUSH_FLAG (1 << 1) /* + * Status feature flags + */ +#define DM_STATUS_NOFLUSH_FLAG (1 << 0) + +/* * Type of table and mapped_device's mempool */ #define DM_TYPE_NONE 0 Index: linux-rhel6/include/linux/device-mapper.h =================================================================== --- linux-rhel6.orig/include/linux/device-mapper.h +++ linux-rhel6/include/linux/device-mapper.h @@ -75,6 +75,18 @@ typedef void (*dm_resume_fn) (struct dm_ typedef int (*dm_status_fn) (struct dm_target *ti, status_type_t status_type, char *result, unsigned int maxlen); +/* + * DM targets that would like to work with old RHEL kernels but also take + * advantage of the ability to pass status flags to the status method in + * new kernels must implement both .status and .status_with_flags + * - care must also be taken to set DM_TARGET_STATUS_WITH_FLAGS in the + * target's .features + */ +typedef int (*dm_status_with_flags_fn) (struct dm_target *ti, + status_type_t status_type, + unsigned status_flags, char *result, + unsigned maxlen); + typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv); typedef int (*dm_ioctl_fn) (struct dm_target *ti, unsigned int cmd, @@ -158,6 +170,10 @@ struct target_type { /* For internal device-mapper use. */ struct list_head list; + +#ifndef __GENKSYMS__ + dm_status_with_flags_fn status_with_flags; +#endif }; /* @@ -181,6 +197,13 @@ struct target_type { #define DM_TARGET_IMMUTABLE 0x00000004 #define dm_target_is_immutable(type) ((type)->features & DM_TARGET_IMMUTABLE) +/* + * Target provides the .status_with_flags method (which is RHEL-specific) + */ +#define DM_TARGET_STATUS_WITH_FLAGS 0x00000008 +#define dm_target_provides_status_with_flags(type) \ + ((type)->features & DM_TARGET_STATUS_WITH_FLAGS) + struct dm_target { uint64_t features; /* 3rd party driver must initialize to zero */ struct dm_table *table; Index: linux-rhel6/include/linux/dm-ioctl.h =================================================================== --- linux-rhel6.orig/include/linux/dm-ioctl.h +++ linux-rhel6/include/linux/dm-ioctl.h @@ -266,9 +266,9 @@ enum { #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) #define DM_VERSION_MAJOR 4 -#define DM_VERSION_MINOR 22 -#define DM_VERSION_PATCHLEVEL 7 -#define DM_VERSION_EXTRA "-ioctl (2012-06-01)" +#define DM_VERSION_MINOR 23 +#define DM_VERSION_PATCHLEVEL 6 +#define DM_VERSION_EXTRA "-ioctl (2012-07-25)" /* Status bits */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */ @@ -306,6 +306,8 @@ enum { /* * Set this to suspend without flushing queued ios. + * Also disables flushing uncommitted changes in the thin target before + * generating statistics for DM_TABLE_STATUS and DM_DEV_WAIT. */ #define DM_NOFLUSH_FLAG (1 << 11) /* In */