From 49b200682486e8726a6854f446202fabf27e47fc Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Tue, 27 Nov 2007 20:57:05 +0000 Subject: [PATCH] add read_ahead functions to library and dmsetup --readahead (Not live yet.) --- WHATS_NEW_DM | 5 +++-- libdm/.exported_symbols | 3 +++ libdm/ioctl/libdm-iface.c | 17 +++++++++++++++++ libdm/ioctl/libdm-targets.h | 2 ++ libdm/libdevmapper.h | 24 +++++++++++++++++++----- libdm/libdm-common.c | 2 ++ libdm/libdm-deptree.c | 25 +++++++++++++++++++++++-- man/dmsetup.8.in | 3 +++ tools/dmsetup.c | 36 +++++++++++++++++++++++++++++++++++- 9 files changed, 107 insertions(+), 10 deletions(-) diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM index a64f419d3..8541bde94 100644 --- a/WHATS_NEW_DM +++ b/WHATS_NEW_DM @@ -1,7 +1,8 @@ Version 1.02.23 - ================================== - Fix possible double-free in libdevmapper-event. - Define DM_READ_AHEAD_* values and flags. + Add --readahead to dmsetup. + Add external read_ahead library functions and DM_READ_AHEAD_* definitions. + Fix double free in a libdevmapper-event error path. Fix configure --with-dmeventd-path substitution. Allow $DM_DEV_DIR envvar to override default of "/dev". Create e.g., libdevmapper.so.1.02, in build dir alongside the .so file. diff --git a/libdm/.exported_symbols b/libdm/.exported_symbols index 84db9f448..da932b390 100644 --- a/libdm/.exported_symbols +++ b/libdm/.exported_symbols @@ -18,6 +18,7 @@ dm_task_get_name dm_task_get_names dm_task_get_versions dm_task_get_uuid +dm_task_get_read_ahead dm_task_set_ro dm_task_set_newname dm_task_set_event_nr @@ -28,6 +29,7 @@ dm_task_set_message dm_task_set_uid dm_task_set_gid dm_task_set_mode +dm_task_set_read_ahead dm_task_suppress_identical_reload dm_task_add_target dm_task_no_flush @@ -67,6 +69,7 @@ dm_tree_node_add_striped_target dm_tree_node_add_mirror_target dm_tree_node_add_mirror_target_log dm_tree_node_add_target_area +dm_tree_node_set_read_ahead dm_tree_skip_lockfs dm_tree_use_no_flush_suspend dm_is_dm_major diff --git a/libdm/ioctl/libdm-iface.c b/libdm/ioctl/libdm-iface.c index 3de9ee4c4..392ed8a87 100644 --- a/libdm/ioctl/libdm-iface.c +++ b/libdm/ioctl/libdm-iface.c @@ -920,6 +920,14 @@ int dm_task_get_info(struct dm_task *dmt, struct dm_info *info) return 1; } +uint32_t dm_task_get_read_ahead(const struct dm_task *dmt) +{ + uint32_t read_ahead = 0; //FIXME default? How cope with failure below? + // FIXME (void) dm_blockdev_get_read_ahead(dmt->dev_name, &read_ahead); + + return read_ahead; +} + const char *dm_task_get_name(const struct dm_task *dmt) { #ifdef DM_COMPAT @@ -974,6 +982,15 @@ int dm_task_set_ro(struct dm_task *dmt) return 1; } +int dm_task_set_read_ahead(struct dm_task *dmt, uint32_t read_ahead, + uint32_t read_ahead_flags) +{ + dmt->read_ahead = read_ahead; + dmt->read_ahead_flags = read_ahead_flags; + + return 1; +} + int dm_task_suppress_identical_reload(struct dm_task *dmt) { dmt->suppress_identical_reload = 1; diff --git a/libdm/ioctl/libdm-targets.h b/libdm/ioctl/libdm-targets.h index 5b037303f..3caa8dd6a 100644 --- a/libdm/ioctl/libdm-targets.h +++ b/libdm/ioctl/libdm-targets.h @@ -44,6 +44,8 @@ struct dm_task { uid_t uid; gid_t gid; mode_t mode; + uint32_t read_ahead; + uint32_t read_ahead_flags; union { struct dm_ioctl *v4; struct dm_ioctl_v1 *v1; diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h index 3d6f7577a..b3d2b0778 100644 --- a/libdm/libdevmapper.h +++ b/libdm/libdevmapper.h @@ -141,11 +141,6 @@ struct dm_deps *dm_task_get_deps(struct dm_task *dmt); struct dm_names *dm_task_get_names(struct dm_task *dmt); struct dm_versions *dm_task_get_versions(struct dm_task *dmt); -#define DM_READ_AHEAD_AUTO UINT32_MAX /* Use kernel default readahead */ -#define DM_READ_AHEAD_NONE 0 /* Disable readahead */ - -#define DM_READ_AHEAD_MINIMUM_FLAG 0x1 /* Value supplied is minimum */ - int dm_task_set_ro(struct dm_task *dmt); int dm_task_set_newname(struct dm_task *dmt, const char *newname); int dm_task_set_minor(struct dm_task *dmt, int minor); @@ -162,6 +157,18 @@ int dm_task_no_open_count(struct dm_task *dmt); int dm_task_skip_lockfs(struct dm_task *dmt); int dm_task_suppress_identical_reload(struct dm_task *dmt); +/* + * Control read_ahead. + */ +#define DM_READ_AHEAD_AUTO UINT32_MAX /* Use kernel default readahead */ +#define DM_READ_AHEAD_NONE 0 /* Disable readahead */ + +#define DM_READ_AHEAD_MINIMUM_FLAG 0x1 /* Value supplied is minimum */ + +int dm_task_set_read_ahead(struct dm_task *dmt, uint32_t read_ahead, + uint32_t read_ahead_flags); +uint32_t dm_task_get_read_ahead(const struct dm_task *dmt); + /* * Use these to prepare for a create or reload. */ @@ -381,6 +388,13 @@ int dm_tree_node_add_target_area(struct dm_tree_node *node, const char *dlid, uint64_t offset); +/* + * Set readahead (in sectors) after loading the node. + */ +void dm_tree_node_set_read_ahead(struct dm_tree_node *dnode, + uint32_t read_ahead, + uint32_t read_ahead_flags); + /***************************************************************************** * Library functions *****************************************************************************/ diff --git a/libdm/libdm-common.c b/libdm/libdm-common.c index d2e212aa7..f521db174 100644 --- a/libdm/libdm-common.c +++ b/libdm/libdm-common.c @@ -118,6 +118,8 @@ struct dm_task *dm_task_create(int type) dmt->gid = DEVICE_GID; dmt->mode = DEVICE_MODE; dmt->no_open_count = 0; + dmt->read_ahead = DM_READ_AHEAD_AUTO; + dmt->read_ahead_flags = 0; return dmt; } diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c index f0c9de29c..19c2037ea 100644 --- a/libdm/libdm-deptree.c +++ b/libdm/libdm-deptree.c @@ -95,6 +95,9 @@ struct load_properties { uint32_t major; uint32_t minor; + uint32_t read_ahead; + uint32_t read_ahead_flags; + unsigned segment_count; struct list segs; @@ -609,6 +612,8 @@ struct dm_tree_node *dm_tree_add_new_dev(struct dm_tree *dtree, } dnode->props.read_only = read_only ? 1 : 0; + dnode->props.read_ahead = DM_READ_AHEAD_AUTO; + dnode->props.read_ahead_flags = 0; if (clear_inactive && !_node_clear_table(dnode)) return_NULL; @@ -618,6 +623,14 @@ struct dm_tree_node *dm_tree_add_new_dev(struct dm_tree *dtree, return dnode; } +void dm_tree_node_set_read_ahead(struct dm_tree_node *dnode, + uint32_t read_ahead, + uint32_t read_ahead_flags) +{ + dnode->props.read_ahead = read_ahead; + dnode->props.read_ahead_flags = read_ahead_flags; +} + int dm_tree_add_dev(struct dm_tree *dtree, uint32_t major, uint32_t minor) { return _add_dev(dtree, &dtree->root, major, minor) ? 1 : 0; @@ -875,6 +888,7 @@ out: /* FIXME Merge with _suspend_node? */ static int _resume_node(const char *name, uint32_t major, uint32_t minor, + uint32_t read_ahead, uint32_t read_ahead_flags, struct dm_info *newinfo) { struct dm_task *dmt; @@ -896,6 +910,9 @@ static int _resume_node(const char *name, uint32_t major, uint32_t minor, if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count"); + if (!dm_task_set_read_ahead(dmt, read_ahead, read_ahead_flags)) + log_error("Failed to set read ahead"); + if ((r = dm_task_run(dmt))) r = dm_task_get_info(dmt, newinfo); @@ -1136,7 +1153,9 @@ int dm_tree_activate_children(struct dm_tree_node *dnode, if (!child->info.inactive_table && !child->info.suspended) continue; - if (!_resume_node(name, child->info.major, child->info.minor, &newinfo)) { + if (!_resume_node(name, child->info.major, child->info.minor, + child->props.read_ahead, + child->props.read_ahead_flags, &newinfo)) { log_error("Unable to resume %s (%" PRIu32 ":%" PRIu32 ")", name, child->info.major, child->info.minor); @@ -1527,7 +1546,9 @@ int dm_tree_preload_children(struct dm_tree_node *dnode, if (!child->info.inactive_table && !child->info.suspended) continue; - if (!_resume_node(name, child->info.major, child->info.minor, &newinfo)) { + if (!_resume_node(name, child->info.major, child->info.minor, + child->props.read_ahead, + child->props.read_ahead_flags, &newinfo)) { log_error("Unable to resume %s (%" PRIu32 ":%" PRIu32 ")", name, child->info.major, child->info.minor); diff --git a/man/dmsetup.8.in b/man/dmsetup.8.in index 5e5debe17..1b7424643 100644 --- a/man/dmsetup.8.in +++ b/man/dmsetup.8.in @@ -114,6 +114,9 @@ Specify which fields to display. .IP \fB-r|--readonly .br Set the table being loaded read-only. +.IP \fB--readahead\ +.br +Specify read ahead size in units of sectors. .IP \fB--table\ .br Specify a one-line table directly on the command line. diff --git a/tools/dmsetup.c b/tools/dmsetup.c index 7adaf0d8e..43f4f08d7 100644 --- a/tools/dmsetup.c +++ b/tools/dmsetup.c @@ -120,6 +120,7 @@ enum { NOOPENCOUNT_ARG, NOTABLE_ARG, OPTIONS_ARG, + READAHEAD_ARG, SEPARATOR_ARG, SHOWKEYS_ARG, SORT_ARG, @@ -336,6 +337,8 @@ static void _display_info_long(struct dm_task *dmt, struct dm_info *info) info->suspended ? "SUSPENDED" : "ACTIVE", info->read_only ? " (READ-ONLY)" : ""); + printf("Read Ahead: %d\n", (int) dm_task_get_read_ahead(dmt)); + if (!info->live_table && !info->inactive_table) printf("Tables present: None\n"); else @@ -494,6 +497,11 @@ static int _create(int argc, char **argv, void *data __attribute((unused))) if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) goto out; + /* FIXME Provide way to set read_ahead_flags */ + if (_switches[READAHEAD_ARG] && + !dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG], 0)) + goto out; + if (!dm_task_run(dmt)) goto out; @@ -673,6 +681,11 @@ static int _simple(int task, const char *name, uint32_t event_nr, int display) if (_switches[NOLOCKFS_ARG] && !dm_task_skip_lockfs(dmt)) goto out; + /* FIXME Provide way to set read_ahead_flags */ + if (_switches[READAHEAD_ARG] && + !dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG], 0)) + goto out; + r = dm_task_run(dmt); if (r && display && _switches[VERBOSE_ARG]) @@ -1594,6 +1607,16 @@ static int _dm_uuid_disp(struct dm_report *rh, return dm_report_field_string(rh, field, &uuid); } +static int _dm_read_ahead_disp(struct dm_report *rh, + struct dm_pool *mem __attribute((unused)), + struct dm_report_field *field, const void *data, + void *private __attribute((unused))) +{ + int32_t value = (int32_t) dm_task_get_read_ahead((const struct dm_task *) data); + + return dm_report_field_int32(rh, field, &value); +} + static int _dm_info_status_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), struct dm_report_field *field, const void *data, @@ -1849,6 +1872,10 @@ static const struct dm_report_field_type _report_fields[] = { /* *INDENT-OFF* */ FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.") FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.") + +/* FIXME Next one should be INFO */ +FIELD_F(TASK, NUM, "RAhead", 6, dm_read_ahead, "readahead", "Read ahead in sectors.") + FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.") FIELD_F(INFO, STR, "DevNo", 5, dm_info_devno, "devno", "Device major and minor numbers") FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major", "Block device major number.") @@ -2010,7 +2037,8 @@ static void _usage(FILE *out) fprintf(out, "Usage:\n\n"); fprintf(out, "dmsetup [--version] [-v|--verbose [-v|--verbose ...]]\n" - " [-r|--readonly] [--noopencount] [--nolockfs]\n" + " [-r|--readonly] [--noopencount] [--nolockfs] " + "[--readahead ]\n" " [-c|-C|--columns] [-o ] [-O|--sort ]\n" " [--noheadings] [--separator ]\n\n"); for (i = 0; _commands[i].name; i++) @@ -2374,6 +2402,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) {"noopencount", 0, &ind, NOOPENCOUNT_ARG}, {"notable", 0, &ind, NOTABLE_ARG}, {"options", 1, &ind, OPTIONS_ARG}, + {"readahead", 1, &ind, READAHEAD_ARG}, {"separator", 1, &ind, SEPARATOR_ARG}, {"showkeys", 0, &ind, SHOWKEYS_ARG}, {"sort", 1, &ind, SORT_ARG}, @@ -2506,6 +2535,11 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir) _switches[NOLOCKFS_ARG]++; if ((ind == NOOPENCOUNT_ARG)) _switches[NOOPENCOUNT_ARG]++; + /* FIXME Accept auto/none & set read_ahead_flags too */ + if ((ind == READAHEAD_ARG)) { + _switches[READAHEAD_ARG]++; + _int_args[READAHEAD_ARG] = atoi(optarg); + } if ((ind == SHOWKEYS_ARG)) _switches[SHOWKEYS_ARG]++; if ((ind == TABLE_ARG)) {