* [PATCH 0/13] liblvm initialization, attribute, and object handling @ 2009-02-02 20:49 Dave Wysochanski 2009-02-02 20:49 ` [PATCH 01/13] Add system_dir to create_toolcontext() Dave Wysochanski 0 siblings, 1 reply; 29+ messages in thread From: Dave Wysochanski @ 2009-02-02 20:49 UTC (permalink / raw) To: lvm-devel This is the latest in a series of liblvm patches involving the init code cleanup as well as attribute and object handling code. Patches are being developed and reviewed by Thomas Woerner and myself. I've begun to incorporate the latest vg_read() patches from Petr. Note the "vg_open()" / "vg_close()" patches, which is a possible way we might simplify some of those flags on vg_read() (an open/read/close sequence). Patches are incomplete though I thought I'd throw it out for discussion. ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 01/13] Add system_dir to create_toolcontext(). 2009-02-02 20:49 [PATCH 0/13] liblvm initialization, attribute, and object handling Dave Wysochanski @ 2009-02-02 20:49 ` Dave Wysochanski 2009-02-02 20:49 ` [PATCH 02/13] Add lvm_create, lvm_destroy, lvm_reload_config() APIs Dave Wysochanski 0 siblings, 1 reply; 29+ messages in thread From: Dave Wysochanski @ 2009-02-02 20:49 UTC (permalink / raw) To: lvm-devel Signed-off-by: Thomas Woerner <twoerner@redhat.com> Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- daemons/clvmd/lvm-functions.c | 2 +- lib/commands/toolcontext.c | 6 +++++- lib/commands/toolcontext.h | 2 +- tools/lvmcmdline.c | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/daemons/clvmd/lvm-functions.c b/daemons/clvmd/lvm-functions.c index 5cf7eff..3db2756 100644 --- a/daemons/clvmd/lvm-functions.c +++ b/daemons/clvmd/lvm-functions.c @@ -724,7 +724,7 @@ void lvm_do_backup(const char *vgname) /* Called to initialise the LVM context of the daemon */ int init_lvm(int using_gulm) { - if (!(cmd = create_toolcontext(1))) { + if (!(cmd = create_toolcontext(1, NULL))) { log_error("Failed to allocate command context"); return 0; } diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c index 0a98325..c481a2b 100644 --- a/lib/commands/toolcontext.c +++ b/lib/commands/toolcontext.c @@ -998,7 +998,8 @@ static void _init_globals(struct cmd_context *cmd) } /* Entry point */ -struct cmd_context *create_toolcontext(unsigned is_long_lived) +struct cmd_context *create_toolcontext(unsigned is_long_lived, + const char *system_dir) { struct cmd_context *cmd; @@ -1030,6 +1031,9 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived) strcpy(cmd->sys_dir, DEFAULT_SYS_DIR); + if (system_dir) + strncpy(cmd->sys_dir, system_dir, PATH_MAX); + if (!_get_env_vars(cmd)) goto error; diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h index 7d2aef9..ba6f1ed 100644 --- a/lib/commands/toolcontext.h +++ b/lib/commands/toolcontext.h @@ -94,7 +94,7 @@ struct cmd_context { char sysfs_dir[PATH_MAX]; }; -struct cmd_context *create_toolcontext(unsigned is_long_lived); +struct cmd_context *create_toolcontext(unsigned is_long_lived, const char *system_dir); void destroy_toolcontext(struct cmd_context *cmd); int refresh_toolcontext(struct cmd_context *cmd); int config_files_changed(struct cmd_context *cmd); diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index 0b12750..2dabe64 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -1159,7 +1159,7 @@ struct cmd_context *init_lvm(void) _cmdline.the_args = &_the_args[0]; - if (!(cmd = create_toolcontext(0))) + if (!(cmd = create_toolcontext(0, NULL))) return_NULL; return cmd; -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 02/13] Add lvm_create, lvm_destroy, lvm_reload_config() APIs. 2009-02-02 20:49 ` [PATCH 01/13] Add system_dir to create_toolcontext() Dave Wysochanski @ 2009-02-02 20:49 ` Dave Wysochanski 2009-02-02 20:49 ` [PATCH 03/13] Move vg_t, lv_t, and pv_t from metadata-exported.h into lvm2.h Dave Wysochanski 2009-02-02 23:22 ` [PATCH 02/13] Add lvm_create, lvm_destroy, lvm_reload_config() APIs Petr Rockai 0 siblings, 2 replies; 29+ messages in thread From: Dave Wysochanski @ 2009-02-02 20:49 UTC (permalink / raw) To: lvm-devel Add lvm2.c file. Update test code. Signed-off-by: Thomas Woerner <twoerner@redhat.com> Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- lib/Makefile.in | 3 +- lib/lvm2.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/lvm2.h | 44 +++++++++++++++++++++------------- test/api/test.c | 13 ++++----- 4 files changed, 105 insertions(+), 25 deletions(-) create mode 100644 lib/lvm2.c diff --git a/lib/Makefile.in b/lib/Makefile.in index 54092cd..c0b58b9 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -86,7 +86,8 @@ SOURCES =\ report/report.c \ striped/striped.c \ uuid/uuid.c \ - zero/zero.c + zero/zero.c \ + lvm2.c ifeq ("@LVM1@", "internal") SOURCES +=\ diff --git a/lib/lvm2.c b/lib/lvm2.c new file mode 100644 index 0000000..bb8f295 --- /dev/null +++ b/lib/lvm2.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License v.2.1. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "lvm2.h" +#include "lib.h" +#include "toolcontext.h" +#include "locking.h" +#include "metadata-exported.h" +#include "report.h" + + +lvm_handle_t lvm_create(const char *system_dir) +{ + struct cmd_context *cmd; + + /* To be done: + * logging bound to handle + */ + + /* create context */ + cmd = create_toolcontext(1, system_dir); + + /* initilize remaining */ + if (cmd) { + int locking_type; + + /* initilization from lvm_run_command */ + init_error_message_produced(0); + sigint_clear(); + + /* get locking type from config tree */ + /* FIXME: config option needed? */ + locking_type = find_config_tree_int(cmd, "global/locking_type", + 1); + + /* initialize locking */ + if (! init_locking(locking_type, cmd)) { + printf("Locking type %d initialisation failed.", + locking_type); + lvm_destroy((lvm_handle_t) cmd); + return NULL; + } + } + + return (lvm_handle_t) cmd; +} + + +void lvm_destroy(lvm_handle_t libh) +{ + destroy_toolcontext((struct cmd_context *)libh); + /* no error handling here */ +} + + +int lvm_reload_config(lvm_handle_t libh) +{ + return refresh_toolcontext((struct cmd_context *)libh); +} diff --git a/lib/lvm2.h b/lib/lvm2.h index b18cead..f348035 100644 --- a/lib/lvm2.h +++ b/lib/lvm2.h @@ -18,36 +18,46 @@ #include <stdint.h> /* - * Library Initialisation - * FIXME: For now just #define lvm2_create() and lvm2_destroy() to - * create_toolcontext() and destroy_toolcontext() + * lvm_handle_t */ -struct arg; -struct cmd_context; -struct cmd_context *create_toolcontext(unsigned is_long_lived); -void destroy_toolcontext(struct cmd_context *cmd); +struct lib_context; /* internal context data */ +typedef struct lib_context *lvm_handle_t; +#ifdef FUTURE_FEATURE /* - * lvm2_create -lvm_handle_t lvm2_create(void); + * lvm_config_t + */ +struct lvm_config { + const char *system_dir; + unsigned is_long_lived; +}; +#endif /* FUTURE_FEATURE */ + +/* + * lvm_create * - * Description: Create an LVM2 handle used in many other APIs. + * Description: Create an LVM handle used in many other APIs. * * Returns: * NULL: Fail - unable to initialise handle. - * non-NULL: Success - valid LVM2 handle returned + * non-NULL: Success - valid LVM handle returned */ -#define lvm2_create(X) create_toolcontext(1) +lvm_handle_t lvm_create(const char *system_dir); /* - * lvm2_destroy -void lvm2_destroy(lvm_handle_t h); + * lvm_destroy * - * Description: Destroy an LVM2 handle allocated with lvm2_create + * Description: Destroy an LVM handle allocated with lvm_create * * Parameters: - * - h (IN): handle obtained from lvm2_create + * - h (IN): handle obtained from lvm_create + */ +void lvm_destroy(lvm_handle_t libh); + +/* + * lvm_reload_config + * Reload configuration files */ -#define lvm2_destroy(X) destroy_toolcontext(X) +int lvm_reload_config(lvm_handle_t libh); #endif diff --git a/test/api/test.c b/test/api/test.c index de53c46..9411663 100644 --- a/test/api/test.c +++ b/test/api/test.c @@ -48,7 +48,7 @@ static int lvm_split(char *str, int *argc, char **argv, int max) return *argc; } -static int lvmapi_test_shell(void *h) +static int lvmapi_test_shell(lvm_handle_t libh) { int argc, i; char *input = NULL, *args[MAX_ARGS], **argv; @@ -99,18 +99,17 @@ static int lvmapi_test_shell(void *h) int main (int argc, char *argv[]) { - void *h; + lvm_handle_t libh; - h = lvm2_create(); - if (!h) { + libh = lvm_create(NULL); + if (!libh) { printf("Unable to open lvm library instance\n"); return 1; } - lvmapi_test_shell(h); + lvmapi_test_shell(libh); - if (h) - lvm2_destroy(h); + lvm_destroy(libh); return 0; } -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 03/13] Move vg_t, lv_t, and pv_t from metadata-exported.h into lvm2.h 2009-02-02 20:49 ` [PATCH 02/13] Add lvm_create, lvm_destroy, lvm_reload_config() APIs Dave Wysochanski @ 2009-02-02 20:49 ` Dave Wysochanski 2009-02-02 20:50 ` [PATCH 04/13] Add lvm_pv_name, lvm_vg_name, and lvm_lv_name accessors Dave Wysochanski 2009-02-02 23:25 ` [PATCH 03/13] Move vg_t, lv_t, and pv_t from metadata-exported.h into lvm2.h Petr Rockai 2009-02-02 23:22 ` [PATCH 02/13] Add lvm_create, lvm_destroy, lvm_reload_config() APIs Petr Rockai 1 sibling, 2 replies; 29+ messages in thread From: Dave Wysochanski @ 2009-02-02 20:49 UTC (permalink / raw) To: lvm-devel Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- lib/lvm2.h | 9 +++++++++ lib/metadata/metadata-exported.h | 8 +------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/lvm2.h b/lib/lvm2.h index f348035..bfa1852 100644 --- a/lib/lvm2.h +++ b/lib/lvm2.h @@ -60,4 +60,13 @@ void lvm_destroy(lvm_handle_t libh); */ int lvm_reload_config(lvm_handle_t libh); +struct volume_group; +typedef struct volume_group vg_t; + +struct physical_volume; +typedef struct physical_volume pv_t; + +struct logical_volume; +typedef struct logical_volume lv_t; + #endif diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h index a1c45ce..257bf91 100644 --- a/lib/metadata/metadata-exported.h +++ b/lib/metadata/metadata-exported.h @@ -22,13 +22,7 @@ #define _LVM_METADATA_EXPORTED_H #include "uuid.h" - -struct physical_volume; -typedef struct physical_volume pv_t; -struct volume_group; -typedef struct volume_group vg_t; - -struct logical_volume; +#include "lvm2.h" struct lv_segment; struct pv_segment; -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 04/13] Add lvm_pv_name, lvm_vg_name, and lvm_lv_name accessors. 2009-02-02 20:49 ` [PATCH 03/13] Move vg_t, lv_t, and pv_t from metadata-exported.h into lvm2.h Dave Wysochanski @ 2009-02-02 20:50 ` Dave Wysochanski 2009-02-02 20:50 ` [PATCH 05/13] Add lvm_vg_open() Dave Wysochanski 2009-02-02 23:25 ` [PATCH 03/13] Move vg_t, lv_t, and pv_t from metadata-exported.h into lvm2.h Petr Rockai 1 sibling, 1 reply; 29+ messages in thread From: Dave Wysochanski @ 2009-02-02 20:50 UTC (permalink / raw) To: lvm-devel RFC - liblvm could provide accessor functions such as these along with the generic attribute functions. These specific accessor functions will make application code simpler and more readable and may be desired by application programmers over the generic attribute functions for single attributes. Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- lib/lvm2.h | 7 +++++++ lib/metadata/metadata.c | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 0 deletions(-) diff --git a/lib/lvm2.h b/lib/lvm2.h index bfa1852..5f44614 100644 --- a/lib/lvm2.h +++ b/lib/lvm2.h @@ -69,4 +69,11 @@ typedef struct physical_volume pv_t; struct logical_volume; typedef struct logical_volume lv_t; +/* + * PV, VG, and LV object attribute functions. + */ +const char *lvm_pv_name(const pv_t *pv); +const char *lvm_vg_name(const vg_t *vg); +const char *lvm_lv_name(const lv_t *lv); + #endif diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index a2b5f2f..4c9f939 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -2673,6 +2673,21 @@ vg_t *vg_read_for_update(struct cmd_context *cmd, const char *vg_name, return vg_read(cmd, vg_name, vgid, flags | READ_FOR_UPDATE); } +const char *lvm_pv_name(const pv_t *pv) +{ + return dev_name(pv->dev); +} + +const char *lvm_vg_name(const vg_t *vg) +{ + return vg->name; +} + +const char *lvm_lv_name(const lv_t *lv) +{ + return lv->name; +} + /* * Test the validity of a VG handle returned by vg_read() or vg_read_for_update(). * -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 05/13] Add lvm_vg_open(). 2009-02-02 20:50 ` [PATCH 04/13] Add lvm_pv_name, lvm_vg_name, and lvm_lv_name accessors Dave Wysochanski @ 2009-02-02 20:50 ` Dave Wysochanski 2009-02-02 20:50 ` [PATCH 06/13] Add lvm_vg_close() Dave Wysochanski 2009-02-02 23:28 ` [PATCH 05/13] Add lvm_vg_open() Petr Rockai 0 siblings, 2 replies; 29+ messages in thread From: Dave Wysochanski @ 2009-02-02 20:50 UTC (permalink / raw) To: lvm-devel RFC - lvm_vg_open(). The new vg_read() function is a step in the right direction but still contains a lot of new options / flags that will be new to people and we can hopefully simplify. lvm_vg_open() was modelled after 'open' which gives us a potential model that others are familiar with. Can we use the modes and flags of 'open' in a similar way or do we need to introduce new flags/concepts to people? For example, can we use a some of the open flags such as O_CREAT and O_EXCL to implement READ_CHECK_EXISTENCE? Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- lib/lvm2.h | 2 ++ lib/metadata/metadata.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 0 deletions(-) diff --git a/lib/lvm2.h b/lib/lvm2.h index 5f44614..20c8ce0 100644 --- a/lib/lvm2.h +++ b/lib/lvm2.h @@ -16,6 +16,7 @@ #define _LIB_LVM2_H #include <stdint.h> +#include <fcntl.h> /* * lvm_handle_t @@ -76,4 +77,5 @@ const char *lvm_pv_name(const pv_t *pv); const char *lvm_vg_name(const vg_t *vg); const char *lvm_lv_name(const lv_t *lv); +vg_t *lvm_vg_open(lvm_handle_t libh, const char *vg_name, mode_t mode); #endif diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 4c9f939..38b6e09 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -2472,6 +2472,20 @@ vg_t *vg_lock_and_read(struct cmd_context *cmd, const char *vg_name, } /* + * Open / read a VG. + * FIXME: Only read access allowed. + */ +vg_t *lvm_vg_open(lvm_handle_t libh, const char *vg_name, mode_t mode) +{ + if ((mode & O_ACCMODE) != O_RDONLY) { + log_error("Invalid access mode 0x%x for lvm_vg_read()\n", + mode); + return NULL; + } + return vg_read((struct cmd_context *)libh, vg_name, NULL, 0); +} + +/* * Create a (vg_t) volume group handle from a struct volume_group pointer and a * possible failure code or zero for success. */ -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 06/13] Add lvm_vg_close(). 2009-02-02 20:50 ` [PATCH 05/13] Add lvm_vg_open() Dave Wysochanski @ 2009-02-02 20:50 ` Dave Wysochanski 2009-02-02 20:50 ` [PATCH 07/13] Add lvm_vg_get_attr_list() libLVM API to return a list of VG attribute names Dave Wysochanski 2009-02-02 23:45 ` [PATCH 06/13] Add lvm_vg_close() Petr Rockai 2009-02-02 23:28 ` [PATCH 05/13] Add lvm_vg_open() Petr Rockai 1 sibling, 2 replies; 29+ messages in thread From: Dave Wysochanski @ 2009-02-02 20:50 UTC (permalink / raw) To: lvm-devel For now we cannot free the handle but just check to see if we should unlock it. Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- lib/lvm2.h | 1 + lib/metadata/metadata.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 0 deletions(-) diff --git a/lib/lvm2.h b/lib/lvm2.h index 20c8ce0..85014f5 100644 --- a/lib/lvm2.h +++ b/lib/lvm2.h @@ -78,4 +78,5 @@ const char *lvm_vg_name(const vg_t *vg); const char *lvm_lv_name(const lv_t *lv); vg_t *lvm_vg_open(lvm_handle_t libh, const char *vg_name, mode_t mode); +void lvm_vg_close(vg_t *vg); #endif diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 38b6e09..0fa5db4 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -2486,6 +2486,17 @@ vg_t *lvm_vg_open(lvm_handle_t libh, const char *vg_name, mode_t mode) } /* + * Close a VG handle. + * If lock is still held, unlock the VG. + * FIXME: We cannot free the memory as it's tied to the cmd->mem pool. + */ +void lvm_vg_close(vg_t *vg) +{ + if (vgname_is_locked(vg->name)) + unlock_vg(vg->cmd, vg->name); +} + +/* * Create a (vg_t) volume group handle from a struct volume_group pointer and a * possible failure code or zero for success. */ -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 07/13] Add lvm_vg_get_attr_list() libLVM API to return a list of VG attribute names. 2009-02-02 20:50 ` [PATCH 06/13] Add lvm_vg_close() Dave Wysochanski @ 2009-02-02 20:50 ` Dave Wysochanski 2009-02-02 20:50 ` [PATCH 08/13] Add lvm_vg_get_attr_value() libLVM API to query to value of a VG attribute Dave Wysochanski 2009-02-02 23:45 ` [PATCH 06/13] Add lvm_vg_close() Petr Rockai 1 sibling, 1 reply; 29+ messages in thread From: Dave Wysochanski @ 2009-02-02 20:50 UTC (permalink / raw) To: lvm-devel This API returns a list of attribute names for a VG. A later API will allow the values of the attributes to be queried. The API implementation relies on adding an exported call to libdevmapper, dm_report_get_field_ids(), which is the interface into dm's reporting infrastructure to retrieve the attribute/field names/ids. Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- lib/lvm2.h | 3 +++ lib/report/report.c | 28 ++++++++++++++++++++++++++++ libdm/.exported_symbols | 1 + libdm/libdevmapper.h | 12 ++++++++++++ libdm/libdm-report.c | 27 +++++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 0 deletions(-) diff --git a/lib/lvm2.h b/lib/lvm2.h index 85014f5..57e8b6c 100644 --- a/lib/lvm2.h +++ b/lib/lvm2.h @@ -17,6 +17,7 @@ #include <stdint.h> #include <fcntl.h> +#include "libdevmapper.h" /* * lvm_handle_t @@ -77,6 +78,8 @@ const char *lvm_pv_name(const pv_t *pv); const char *lvm_vg_name(const vg_t *vg); const char *lvm_lv_name(const lv_t *lv); +int lvm_vg_get_attr_list(vg_t *vg, struct dm_list *list); + vg_t *lvm_vg_open(lvm_handle_t libh, const char *vg_name, mode_t mode); void lvm_vg_close(vg_t *vg); #endif diff --git a/lib/report/report.c b/lib/report/report.c index 8439b2b..8e733d8 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -1191,3 +1191,31 @@ int report_object(void *handle, struct volume_group *vg, return dm_report_object(handle, &obj); } + +/* + * Get a list of attributes for a vg + */ +int lvm_vg_get_attr_list(vg_t *vg, struct dm_list *list) +{ + void *rh; + report_type_t report_type = VGS; + + dm_list_init(list); + + /* + * Create a report so we can return the headings. + */ + if (!(rh = report_init(vg->cmd, "all", "", &report_type, + " ", 1, 1, 1, 0, 0, 0))) { + stack; + return 0; + } + + if (!dm_report_get_field_ids(rh, report_type, list)) { + dm_report_free(rh); + return 0; + } + + dm_report_free(rh); + return 1; +} diff --git a/libdm/.exported_symbols b/libdm/.exported_symbols index a6e04f8..aa70f29 100644 --- a/libdm/.exported_symbols +++ b/libdm/.exported_symbols @@ -132,6 +132,7 @@ dm_report_field_int32 dm_report_field_uint32 dm_report_field_uint64 dm_report_field_set_value +dm_report_get_field_ids dm_report_set_output_field_name_prefix dm_regex_create dm_regex_match diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h index 93aecbb..cc8302a 100644 --- a/libdm/libdevmapper.h +++ b/libdm/libdevmapper.h @@ -924,6 +924,17 @@ struct dm_report_field_type { const char *desc; /* description of the field */ }; +struct dm_report_field_ids_type { + struct dm_list list; + const char *id; +}; + +/* + * Returns a list of all field ids for a specific report type. + */ +int dm_report_get_field_ids(struct dm_report *rh, uint32_t type, + struct dm_list *list); + /* * dm_report_init output_flags */ @@ -947,6 +958,7 @@ int dm_report_object(struct dm_report *rh, void *object); int dm_report_output(struct dm_report *rh); void dm_report_free(struct dm_report *rh); + /* * Prefix added to each field name with DM_REPORT_OUTPUT_FIELD_NAME_PREFIX */ diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c index 0c5ee6d..a9db211 100644 --- a/libdm/libdm-report.c +++ b/libdm/libdm-report.c @@ -1076,3 +1076,30 @@ int dm_report_output(struct dm_report *rh) else return _output_as_columns(rh); } + +/* + * Return a list of field IDs (names) for a specified report type. + */ +int dm_report_get_field_ids(struct dm_report *rh, uint32_t type, + struct dm_list *list) +{ + uint32_t f; + struct dm_report_field_ids_type *field_id; + + for (f = 0; rh->fields[f].report_fn; f++) { + if (rh->fields[f].type != type) + continue; + + if (!(field_id = dm_pool_zalloc(rh->mem, sizeof(*field_id)))) { + log_error("dm_report_get_field_ids: struct " + "dm_report_field_ids_type allocation failed"); + return 0; + } + if (!(field_id->id = dm_pool_strdup(rh->mem, rh->fields[f].id))) { + log_error("dm_report_get_field_ids: dm_pool_strdup failed"); + return 0; + } + dm_list_add(list, &field_id->list); + } + return 1; +} -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 08/13] Add lvm_vg_get_attr_value() libLVM API to query to value of a VG attribute. 2009-02-02 20:50 ` [PATCH 07/13] Add lvm_vg_get_attr_list() libLVM API to return a list of VG attribute names Dave Wysochanski @ 2009-02-02 20:50 ` Dave Wysochanski 2009-02-02 20:50 ` [PATCH 09/13] Add lvm_lvs_in_vg() API Dave Wysochanski 2009-02-02 23:47 ` [PATCH 08/13] Add lvm_vg_get_attr_value() libLVM API to query to value of a VG attribute Petr Rockai 0 siblings, 2 replies; 29+ messages in thread From: Dave Wysochanski @ 2009-02-02 20:50 UTC (permalink / raw) To: lvm-devel This API may be used independently to query the value of a VG attribute, provided the name of the attribute is known. If the name of the attribute(s) are unknown, the previous API, vg_get_attr_list(), may be used. Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- lib/lvm2.h | 2 ++ lib/report/report.c | 28 ++++++++++++++++++++++++++++ libdm/.exported_symbols | 1 + libdm/libdevmapper.h | 12 ++++++++++++ libdm/libdm-report.c | 29 +++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 0 deletions(-) diff --git a/lib/lvm2.h b/lib/lvm2.h index 57e8b6c..b274762 100644 --- a/lib/lvm2.h +++ b/lib/lvm2.h @@ -79,6 +79,8 @@ const char *lvm_vg_name(const vg_t *vg); const char *lvm_lv_name(const lv_t *lv); int lvm_vg_get_attr_list(vg_t *vg, struct dm_list *list); +int lvm_vg_get_attr_value(vg_t *vg, const char *attr_name, + struct dm_report_field_value_type *value); vg_t *lvm_vg_open(lvm_handle_t libh, const char *vg_name, mode_t mode); void lvm_vg_close(vg_t *vg); diff --git a/lib/report/report.c b/lib/report/report.c index 8e733d8..1216fff 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -1219,3 +1219,31 @@ int lvm_vg_get_attr_list(vg_t *vg, struct dm_list *list) dm_report_free(rh); return 1; } + +/* + * Get the value of the VG attribute 'attr_name'. + */ +int lvm_vg_get_attr_value(vg_t *vg, const char *attr_name, + struct dm_report_field_value_type *value) +{ + void *rh; + report_type_t report_type = VGS; + + if (!(rh = report_init(vg->cmd, attr_name, "", &report_type, + " ", 1, 1, 1, 0, 0, 0))) { + stack; + return 0; + } + + if (!report_object(rh, vg, NULL, NULL, NULL, NULL)) { + stack; + return 0; + } + + if (!dm_report_get_field_value(rh, value)) { + stack; + return 0; + } + dm_report_free(rh); + return 1; +} diff --git a/libdm/.exported_symbols b/libdm/.exported_symbols index aa70f29..e7a4906 100644 --- a/libdm/.exported_symbols +++ b/libdm/.exported_symbols @@ -133,6 +133,7 @@ dm_report_field_uint32 dm_report_field_uint64 dm_report_field_set_value dm_report_get_field_ids +dm_report_get_field_value dm_report_set_output_field_name_prefix dm_regex_create dm_regex_match diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h index cc8302a..d6cb7cf 100644 --- a/libdm/libdevmapper.h +++ b/libdm/libdevmapper.h @@ -927,6 +927,15 @@ struct dm_report_field_type { struct dm_report_field_ids_type { struct dm_list list; const char *id; + uint32_t type; /* FIXME: unnecessary ?*/ +}; + +struct dm_report_field_value_type { + unsigned is_string; + union { + char *s_val; + uint64_t n_val; + } u; }; /* @@ -935,6 +944,9 @@ struct dm_report_field_ids_type { int dm_report_get_field_ids(struct dm_report *rh, uint32_t type, struct dm_list *list); +int dm_report_get_field_value(struct dm_report *rh, + struct dm_report_field_value_type *value); + /* * dm_report_init output_flags */ diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c index a9db211..625e212 100644 --- a/libdm/libdm-report.c +++ b/libdm/libdm-report.c @@ -1099,7 +1099,36 @@ int dm_report_get_field_ids(struct dm_report *rh, uint32_t type, log_error("dm_report_get_field_ids: dm_pool_strdup failed"); return 0; } + field_id->type = type; dm_list_add(list, &field_id->list); } return 1; } + + +int dm_report_get_field_value(struct dm_report *rh, + struct dm_report_field_value_type *value) +{ + struct dm_report_field *field; + struct row *row; + + dm_list_iterate_items(row, &rh->rows) { + if ((field = dm_list_item(dm_list_first(&row->fields), + struct dm_report_field))) { + if ((field->props->flags & DM_REPORT_FIELD_TYPE_MASK) == + DM_REPORT_FIELD_TYPE_STRING) { + value->is_string = 1; + value->u.s_val = dm_pool_strdup(rh->mem, + field->sort_value); + } else { + value->is_string = 0; + value->u.n_val = *(const uint64_t *)field->sort_value; + } + dm_list_del(&field->list); + } + + } + + return 1; + +} -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 09/13] Add lvm_lvs_in_vg() API. 2009-02-02 20:50 ` [PATCH 08/13] Add lvm_vg_get_attr_value() libLVM API to query to value of a VG attribute Dave Wysochanski @ 2009-02-02 20:50 ` Dave Wysochanski 2009-02-02 20:50 ` [PATCH 10/13] Add lvm_pvs_in_vg() Dave Wysochanski 2009-02-02 23:47 ` [PATCH 08/13] Add lvm_vg_get_attr_value() libLVM API to query to value of a VG attribute Petr Rockai 1 sibling, 1 reply; 29+ messages in thread From: Dave Wysochanski @ 2009-02-02 20:50 UTC (permalink / raw) To: lvm-devel Add exported lvm_lv_list structure along with the API. Note that this struct is very similar to struct lv_list. Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- lib/lvm2.h | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/lib/lvm2.h b/lib/lvm2.h index b274762..4d25d25 100644 --- a/lib/lvm2.h +++ b/lib/lvm2.h @@ -84,4 +84,11 @@ int lvm_vg_get_attr_value(vg_t *vg, const char *attr_name, vg_t *lvm_vg_open(lvm_handle_t libh, const char *vg_name, mode_t mode); void lvm_vg_close(vg_t *vg); + +struct lvm_lv_list { + struct dm_list list; + lv_t *lv; +}; +struct dm_list *lvm_lvs_in_vg(vg_t *vg); + #endif -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 10/13] Add lvm_pvs_in_vg(). 2009-02-02 20:50 ` [PATCH 09/13] Add lvm_lvs_in_vg() API Dave Wysochanski @ 2009-02-02 20:50 ` Dave Wysochanski 2009-02-02 20:50 ` [PATCH 11/13] Add lvm_lv_get_attr_list() and lvm_lv_get_attr_value() Dave Wysochanski 0 siblings, 1 reply; 29+ messages in thread From: Dave Wysochanski @ 2009-02-02 20:50 UTC (permalink / raw) To: lvm-devel NOTE: struct lvm_pv_list should not be necessary but I did not like exposing struct pv_list and attempts to clean up struct pv_list to contain only struct dm_list and pv_t members were unsuccessful. Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- lib/lvm2.h | 10 ++++++++++ lib/metadata/metadata.c | 10 ++++++++++ 2 files changed, 20 insertions(+), 0 deletions(-) diff --git a/lib/lvm2.h b/lib/lvm2.h index 4d25d25..25ce12d 100644 --- a/lib/lvm2.h +++ b/lib/lvm2.h @@ -91,4 +91,14 @@ struct lvm_lv_list { }; struct dm_list *lvm_lvs_in_vg(vg_t *vg); +/* + * FIXME: struct lvm_pv_list is not equivalent to struct pv_list, which + * is used in lvm_pvs_in_vg(). Ideally we should not need a new structure. + */ +struct lvm_pv_list { + struct dm_list list; + pv_t *pv; +}; +struct dm_list *lvm_pvs_in_vg(vg_t *vg); + #endif diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 0fa5db4..450e781 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -2496,6 +2496,16 @@ void lvm_vg_close(vg_t *vg) unlock_vg(vg->cmd, vg->name); } +struct dm_list *lvm_lvs_in_vg(vg_t *vg) +{ + return (&vg->lvs); +} + +struct dm_list *lvm_pvs_in_vg(vg_t *vg) +{ + return (&vg->pvs); +} + /* * Create a (vg_t) volume group handle from a struct volume_group pointer and a * possible failure code or zero for success. -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 11/13] Add lvm_lv_get_attr_list() and lvm_lv_get_attr_value(). 2009-02-02 20:50 ` [PATCH 10/13] Add lvm_pvs_in_vg() Dave Wysochanski @ 2009-02-02 20:50 ` Dave Wysochanski 2009-02-02 20:50 ` [PATCH 12/13] First cut at adding pv_obj_* APIs Dave Wysochanski 0 siblings, 1 reply; 29+ messages in thread From: Dave Wysochanski @ 2009-02-02 20:50 UTC (permalink / raw) To: lvm-devel Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- lib/lvm2.h | 3 ++ lib/report/report.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 0 deletions(-) diff --git a/lib/lvm2.h b/lib/lvm2.h index 25ce12d..2a5dd9e 100644 --- a/lib/lvm2.h +++ b/lib/lvm2.h @@ -91,6 +91,9 @@ struct lvm_lv_list { }; struct dm_list *lvm_lvs_in_vg(vg_t *vg); +int lvm_lv_get_attr_list(lv_t *lv, struct dm_list *list); +int lvm_lv_get_attr_value(lv_t *lv, const char *attr_name, + struct dm_report_field_value_type *value); /* * FIXME: struct lvm_pv_list is not equivalent to struct pv_list, which * is used in lvm_pvs_in_vg(). Ideally we should not need a new structure. diff --git a/lib/report/report.c b/lib/report/report.c index 1216fff..70bc3bd 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -1247,3 +1247,60 @@ int lvm_vg_get_attr_value(vg_t *vg, const char *attr_name, dm_report_free(rh); return 1; } + + +/* + * Get a list of attributes for a LV + */ +int lvm_lv_get_attr_list(lv_t *lv, struct dm_list *list) +{ + void *rh; + report_type_t report_type = LVS; + + dm_list_init(list); + + /* + * Create a report so we can return the headings. + */ + if (!(rh = report_init(lv->vg->cmd, "all", "", &report_type, + " ", 1, 1, 1, 0, 0, 0))) { + stack; + return 0; + } + + if (!dm_report_get_field_ids(rh, report_type, list)) { + dm_report_free(rh); + return 0; + } + + dm_report_free(rh); + return 1; +} + +/* + * Get the value of the LV attribute 'attr_name'. + */ +int lvm_lv_get_attr_value(lv_t *lv, const char *attr_name, + struct dm_report_field_value_type *value) +{ + void *rh; + report_type_t report_type = LVS; + + if (!(rh = report_init(lv->vg->cmd, attr_name, "", &report_type, + " ", 1, 1, 1, 0, 0, 0))) { + stack; + return 0; + } + + if (!report_object(rh, NULL, lv, NULL, NULL, NULL)) { + stack; + return 0; + } + + if (!dm_report_get_field_value(rh, value)) { + stack; + return 0; + } + dm_report_free(rh); + return 1; +} -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 12/13] First cut at adding pv_obj_* APIs. 2009-02-02 20:50 ` [PATCH 11/13] Add lvm_lv_get_attr_list() and lvm_lv_get_attr_value() Dave Wysochanski @ 2009-02-02 20:50 ` Dave Wysochanski 2009-02-02 20:50 ` [PATCH 13/13] Add test code Dave Wysochanski 2009-02-02 23:58 ` [PATCH 12/13] First cut at adding pv_obj_* APIs Petr Rockai 0 siblings, 2 replies; 29+ messages in thread From: Dave Wysochanski @ 2009-02-02 20:50 UTC (permalink / raw) To: lvm-devel Impelemnt pv_obj_get(), pv_obj_get_list(), pv_obj_get_attr_list() and pv_obj_get_attr_value(). This is a first attempt at adding pv_obj_* APIs as outlined by http://fedoraproject.org/wiki/LVM/liblvm/api Why add another structure when we could use struct physical_volume and other internal structs? At this point it is not clear but would provide us with the ability to more easily allocate and free handles, and would allow places to store things like the access mode and API errors without polluting the internal structures. Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- lib/lvm2.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/lvm2.h | 36 ++++++++++++++++++ 2 files changed, 157 insertions(+), 0 deletions(-) diff --git a/lib/lvm2.c b/lib/lvm2.c index bb8f295..4108321 100644 --- a/lib/lvm2.c +++ b/lib/lvm2.c @@ -68,3 +68,124 @@ int lvm_reload_config(lvm_handle_t libh) { return refresh_toolcontext((struct cmd_context *)libh); } + + +struct lvm_pv_obj { + char mode; + struct physical_volume *pv; +}; + + +/* + * Gets object for a physical volume by volume path + * Retuns lvm_pv_obj_t on success, otherwide NULL. errno is used to indicate + * the error. + * mode: "r" or "w" + */ +lvm_pv_obj_t *lvm_pv_obj_get(lvm_handle_t libh, const char* phys_vol, + const char *mode) +{ + struct cmd_context *cmd = (struct cmd_context *)libh; + lvm_pv_obj_t *pv_obj; + struct physical_volume *pv; + struct dm_list mdas; + uint64_t label_sector; + + dm_list_init(&mdas); + pv = pv_read(cmd, phys_vol, &mdas, &label_sector, 0); + if (!pv) + return NULL; + + pv_obj = dm_pool_alloc(cmd->mem, sizeof(*pv_obj)); + if (!pv_obj) + return NULL; + + pv_obj->pv = pv; + pv_obj->mode = mode[0]; + + return pv_obj; +} + + +lvm_pv_obj_list_t *lvm_pv_obj_list(lvm_handle_t libh) +{ + struct dm_list *pvs; + struct pv_list *pvl; + lvm_pv_obj_list_t *head = NULL, *elem; + struct cmd_context *cmd = (struct cmd_context *)libh; + + pvs = get_pvs(cmd); + + if (dm_list_empty(pvs)) + return NULL; + + dm_list_iterate_items(pvl, pvs) { + elem = dm_pool_alloc(cmd->mem, sizeof(*elem)); + if (!elem) + return NULL; + elem->obj = lvm_pv_obj_get(libh, lvm_pv_name(pvl->pv), "r"); + if (!head) + head = elem; + dm_list_add(&head->list, &elem->list); + } + return head; +} + + +/* + * Get a list of attributes for a vg + */ +int lvm_pv_obj_get_attr_list(lvm_pv_obj_t *obj, struct dm_list *list) +{ + void *rh; + report_type_t report_type = PVS; + + dm_list_init(list); + + /* + * Create a report so we can return the headings. + */ + if (!(rh = report_init(obj->pv->fmt->cmd, "all", "", &report_type, + " ", 1, 1, 1, 0, 0, 0))) { + stack; + return 0; + } + + if (!dm_report_get_field_ids(rh, report_type, list)) { + dm_report_free(rh); + return 0; + } + + dm_report_free(rh); + return 1; +} + +/* + * Get the value of the VG attribute 'attr_name'. + */ +int lvm_pv_obj_get_attr_value(lvm_pv_obj_t *obj, const char *attr_name, + struct dm_report_field_value_type *value) +{ + void *rh; + report_type_t report_type = PVS; + + if (!(rh = report_init(obj->pv->fmt->cmd, attr_name, "", &report_type, + " ", 1, 1, 1, 0, 0, 0))) { + stack; + return 0; + } + + if (!report_object(rh, NULL, NULL, obj->pv, NULL, NULL)) { + stack; + return 0; + } + + if (!dm_report_get_field_value(rh, value)) { + stack; + return 0; + } + dm_report_free(rh); + return 1; +} + + diff --git a/lib/lvm2.h b/lib/lvm2.h index 2a5dd9e..a47c0a5 100644 --- a/lib/lvm2.h +++ b/lib/lvm2.h @@ -104,4 +104,40 @@ struct lvm_pv_list { }; struct dm_list *lvm_pvs_in_vg(vg_t *vg); +/* + * The lvm physical volume object. + */ +struct lvm_pv_obj; +typedef struct lvm_pv_obj lvm_pv_obj_t; /* with mode inside (r/rw) */ + +/* + * The lvm physical volume object list. + */ +typedef struct lvm_pv_obj_list { + struct dm_list list; + lvm_pv_obj_t *obj; +} lvm_pv_obj_list_t; + +/* + * Gets object for a physical volume by volume path + * Retuns lvm_pv_obj_t on success, otherwide NULL. errno is used to indicate + * the error. + * mode: "r" or "rw" + */ +lvm_pv_obj_t *lvm_pv_obj_get(lvm_handle_t libh, const char* phys_vol, + const char *mode); + + +/* + * Returns list of physical volumes. + * Retuns lvm_pv_obj_list_t on success, otherwide NULL. errno is used to + * indicate the error. The objects are read only. + */ +lvm_pv_obj_list_t *lvm_pv_obj_list(lvm_handle_t libh); + +int lvm_pv_obj_get_attr_list(lvm_pv_obj_t *obj, struct dm_list *list); +int lvm_pv_obj_get_attr_value(lvm_pv_obj_t *obj, const char *attr_name, + struct dm_report_field_value_type *value); + + #endif -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 13/13] Add test code. 2009-02-02 20:50 ` [PATCH 12/13] First cut at adding pv_obj_* APIs Dave Wysochanski @ 2009-02-02 20:50 ` Dave Wysochanski 2009-02-02 23:58 ` [PATCH 12/13] First cut at adding pv_obj_* APIs Petr Rockai 1 sibling, 0 replies; 29+ messages in thread From: Dave Wysochanski @ 2009-02-02 20:50 UTC (permalink / raw) To: lvm-devel Test lvm_pv_list, lvm_lv_get_attr_list, lvm_lv_get_attr_value(). pv_obj_get(), pv_obj_get_attr_list(), pv_obj_get_attr_value, vg_get_attr_list and vg_get_attr_value, lv_get_attr_list and lv_get_attr_value, lvs_in_vg(), pvs_in_vg() lvm_vg_open, lvm_vg_close(). Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- test/api/test.c | 322 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 317 insertions(+), 5 deletions(-) diff --git a/test/api/test.c b/test/api/test.c index 9411663..b996770 100644 --- a/test/api/test.c +++ b/test/api/test.c @@ -48,10 +48,299 @@ static int lvm_split(char *str, int *argc, char **argv, int max) return *argc; } +static void _show_help(void) +{ + printf("'pv_obj_get pvname': Issue a lvm_pv_obj_get() API call on PV 'pvname'\n"); + printf("'pv_obj_get_attr_list': Issue lvm_pv_obj_get_attr_list() API; must follow pv_obj_get\n"); + printf("'pv_obj_get_attr_value [attr_name]': Issue lvm_pv_obj_get_attr_value() API; must follow pv_obj_get\n"); + printf("'vg_open vgname': Issue a lvm_vg_open() API call on VG 'vgname'\n"); + printf("'vg_close vgname': Issue a lvm_vg_close() API call on VG 'vgname'\n"); + printf("'vg_get_attr_list': Issue lvm_vg_get_attr_list() API; must follow vg_open\n"); + printf("'vg_get_attr_value [attr_name]': Issue lvm_vg_get_attr_value() API; must follow vg_open\n"); + printf("'pvs_in_vg': Issue lvm_pvs_in_vg() API; must follow vg_open\n"); + printf("'lv_get_attr_list': Issue lvm_lv_get_attr_list() API; must follow vg_open\n"); + printf("'lv_get_attr_value [attr_name]': Issue lvm_lv_get_attr_value() API; must follow vg_open\n"); + printf("'quit': exit the program\n"); +} + +static void _print_attr(const char *name, + struct dm_report_field_value_type value) +{ + if (value.is_string) + printf("%s = %s\n", name, value.u.s_val); + else + printf("%s = %llu\n", name, (unsigned long long)value.u.n_val); +} + +static void get_and_print_vg_attr(vg_t *vg, const char *name) +{ + struct dm_report_field_value_type value; + + if (!lvm_vg_get_attr_value(vg, name, &value)) { + printf("Error reading vg attribute %s value \n", + name); + return; + } + _print_attr(name, value); +} + +static void get_and_print_lv_attr(lv_t *lv, const char *name) +{ + struct dm_report_field_value_type value; + + if (!lvm_lv_get_attr_value(lv, name, &value)) { + printf("Error reading lv attribute %s value \n", + name); + return; + } + _print_attr(name, value); +} + +static void get_and_print_pv_attr(lvm_pv_obj_t *pv, const char *name) +{ + struct dm_report_field_value_type value; + + if (!lvm_pv_obj_get_attr_value(pv, name, &value)) { + printf("Error reading pv attribute %s value \n", + name); + return; + } + _print_attr(name, value); +} + +static void _vg_open(char **argv, int argc, vg_t **vgp, void *h) +{ + if (argc < 2) { + printf ("Please enter vg_name\n"); + return; + } + *vgp = lvm_vg_open(h, argv[1], O_RDONLY); + if (vg_read_error(*vgp)) + printf("Error opening vg %s\n", argv[1]); + else + printf("Success opening vg %s\n", argv[1]); +} + +static void _pv_obj_get(char **argv, int argc, lvm_pv_obj_t **pvp, void *h) +{ + if (argc < 2) { + printf ("Please enter pv_name\n"); + return; + } + if (!(*pvp = lvm_pv_obj_get(h, argv[1], "r"))) + printf("Error opening PV %s\n", argv[1]); + else + printf("Success opening PV %s\n", argv[1]); +} + +static void _pv_obj_get_attr_list(lvm_pv_obj_t *pv, void *h) +{ + struct dm_report_field_ids_type *field; + struct dm_list fields; + + if (!pv) { + printf("Run pv_obj_get first\n"); + return; + } + if (!lvm_pv_obj_get_attr_list(pv, &fields)) { + printf("Error reading pv attribute list\n"); + return; + } + printf("PV attribute names:\n"); + dm_list_iterate_items(field, &fields) { + printf("%s\n", field->id); + } +} + +static void _pv_obj_get_attr_value(char **argv, int argc, + lvm_pv_obj_t *pv) +{ + struct dm_report_field_ids_type *field; + struct dm_list fields; + int i; + + if (!pv) { + printf("Run pv_obj_get first\n"); + return; + } + if (argc > 1) { + for (i=1; i<argc; i++) + get_and_print_pv_attr(pv, argv[i]); + return; + } + if (!lvm_pv_obj_get_attr_list(pv, &fields)) { + printf("Error reading pv attribute list\n"); + return; + } + dm_list_iterate_items(field, &fields) { + get_and_print_pv_attr(pv, field->id); + } +} + +static void _vg_get_attr_list(vg_t *vg) +{ + struct dm_report_field_ids_type *field; + struct dm_list fields; + + if (vg_read_error(vg)) { + printf("Run vg_open first\n"); + return; + } + if (!lvm_vg_get_attr_list(vg, &fields)) { + printf("Error reading vg attribute list\n"); + return; + } + printf("VG attribute names:\n"); + dm_list_iterate_items(field, &fields) { + printf("%s\n", field->id); + } +} + +static void _lvs_in_vg(vg_t *vg) +{ + struct dm_list *lvs; + struct lvm_lv_list *lvl; + + if (vg_read_error(vg)) { + printf("Run vg_open first\n"); + return; + } + lvs = lvm_lvs_in_vg(vg); + if (dm_list_empty(lvs)) { + printf("No LVs in VG %s\n", lvm_vg_name(vg)); + return; + } + printf("LVs in VG %s:\n", lvm_vg_name(vg)); + dm_list_iterate_items(lvl, lvs) { + printf("%s\n", lvm_lv_name(lvl->lv)); + } +} + +static void _pvs_in_vg(vg_t *vg) +{ + struct dm_list *pvs; + struct lvm_pv_list *pvl; + + if (vg_read_error(vg)) { + printf("Run vg_open first\n"); + return; + } + pvs = lvm_pvs_in_vg(vg); + if (dm_list_empty(pvs)) { + printf("No PVs in VG %s\n", lvm_vg_name(vg)); + return; + } + printf("PVs in VG %s:\n", lvm_vg_name(vg)); + dm_list_iterate_items(pvl, pvs) { + printf("%s\n", lvm_pv_name(pvl->pv)); + } +} + +static void _vg_get_attr_value(char **argv, int argc, vg_t *vg) +{ + struct dm_list fields; + struct dm_report_field_ids_type *field; + int i; + + if (vg_read_error(vg)) { + printf("Run vg_open first\n"); + return; + } + if (argc > 1) { + for (i=1; i<argc; i++) + get_and_print_vg_attr(vg, argv[i]); + return; + } + if (!lvm_vg_get_attr_list(vg, &fields)) { + printf("Error reading vg attribute list\n"); + return; + } + dm_list_iterate_items(field, &fields) { + get_and_print_vg_attr(vg, field->id); + } +} + +static void _lv_get_attr_list(vg_t *vg) +{ + struct dm_list *lvs; + struct lvm_lv_list *lvl; + struct dm_list fields; + struct dm_report_field_ids_type *field; + + if (vg_read_error(vg)) { + printf("Run vg_open first\n"); + return; + } + lvs = lvm_lvs_in_vg(vg); + lvl = (struct lvm_lv_list *) dm_list_first(lvs); + if (!lvl) { + printf("No LVs in VG %s\n", + lvm_vg_name(vg)); + return; + } + if (!lvm_lv_get_attr_list(lvl->lv, &fields)) { + printf("Error reading lv attribute list\n"); + return; + } + printf("LV attribute names:\n"); + dm_list_iterate_items(field, &fields) { + printf("%s\n", field->id); + } +} + +static void _lv_get_attr_value(char **argv, int argc, vg_t *vg) +{ + struct dm_list *lvs; + struct lvm_lv_list *lvl; + struct dm_list fields; + struct dm_report_field_ids_type *field; + int i; + + if (vg_read_error(vg)) { + printf("Run vg_open first\n"); + return; + } + lvs = lvm_lvs_in_vg(vg); + lvl = (struct lvm_lv_list *) dm_list_first(lvs); + if (!lvl) { + printf("No LVs in VG %s\n", + lvm_vg_name(vg)); + return; + } + if (!lvm_lv_get_attr_list(lvl->lv, &fields)) { + printf("Error reading lv attribute list\n"); + return; + } + if (argc > 1) { + for (i=1; i<argc; i++) + get_and_print_lv_attr(lvl->lv,argv[i]); + return; + } + dm_list_iterate_items(field, &fields) { + get_and_print_lv_attr(lvl->lv, field->id); + } +} + +static void _vg_close(char **argv, int argc, vg_t **vgp) +{ + if (argc < 2) { + printf ("Please enter vg_name\n"); + return; + } + if (!*vgp || (strcmp(argv[1], lvm_vg_name(*vgp)))) { + printf ("Run vg_open first\n"); + return; + } + lvm_vg_close(*vgp); + *vgp = NULL; +} + static int lvmapi_test_shell(lvm_handle_t libh) { - int argc, i; + int argc; char *input = NULL, *args[MAX_ARGS], **argv; + vg_t *vg = NULL; + lvm_pv_obj_t *pv = NULL; while (1) { free(input); @@ -86,12 +375,35 @@ static int lvmapi_test_shell(lvm_handle_t libh) printf("Exiting.\n"); break; } else if (!strcmp(argv[0], "?") || !strcmp(argv[0], "help")) { - printf("No commands defined\n"); - } else if (!strcmp(argv[0], "scan")) { - for (i=1; i < argc; i++) - printf("Scan a path!\n"); + _show_help(); + } else if (!strcmp(argv[0], "vg_open")) { + _vg_open(argv, argc, &vg, libh); + } else if (!strcmp(argv[0], "vg_close")) { + _vg_close(argv, argc, &vg); + } else if (!strcmp(argv[0], "vg_get_attr_list")) { + _vg_get_attr_list(vg); + } else if (!strcmp(argv[0], "vg_get_attr_value")) { + _vg_get_attr_value(argv, argc, vg); + } else if (!strcmp(argv[0], "pvs_in_vg")) { + _pvs_in_vg(vg); + } else if (!strcmp(argv[0], "pv_obj_get")) { + _pv_obj_get(argv, argc, &pv, libh); + } else if (!strcmp(argv[0], "pv_obj_get_attr_list")) { + _pv_obj_get_attr_list(pv, libh); + } else if (!strcmp(argv[0], "pv_obj_get_attr_value")) { + _pv_obj_get_attr_value(argv, argc, pv); + } else if (!strcmp(argv[0], "lvs_in_vg")) { + _lvs_in_vg(vg); + } else if (!strcmp(argv[0], "lv_get_attr_list")) { + _lv_get_attr_list(vg); + } else if (!strcmp(argv[0], "lv_get_attr_value")) { + _lv_get_attr_value(argv, argc, vg); + } else { + printf ("Unrecognized command %s\n", argv[0]); } } + if (!vg_read_error(vg)) + lvm_vg_close(vg); free(input); return 0; -- 1.5.5.1 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 12/13] First cut at adding pv_obj_* APIs. 2009-02-02 20:50 ` [PATCH 12/13] First cut at adding pv_obj_* APIs Dave Wysochanski 2009-02-02 20:50 ` [PATCH 13/13] Add test code Dave Wysochanski @ 2009-02-02 23:58 ` Petr Rockai 2009-02-13 11:23 ` Dave Wysochanski 1 sibling, 1 reply; 29+ messages in thread From: Petr Rockai @ 2009-02-02 23:58 UTC (permalink / raw) To: lvm-devel Hi, Dave Wysochanski <dwysocha@redhat.com> writes: > Impelemnt pv_obj_get(), pv_obj_get_list(), pv_obj_get_attr_list() and > pv_obj_get_attr_value(). > > This is a first attempt at adding pv_obj_* APIs as outlined by > http://fedoraproject.org/wiki/LVM/liblvm/api > > Why add another structure when we could use struct physical_volume > and other internal structs? At this point it is not clear but would > provide us with the ability to more easily allocate and free handles, > and would allow places to store things like the access mode and API > errors without polluting the internal structures. I don't say this is completely wrong, but the naming seems very baroque to me, and not at all clear what it means, in relation to pv_t, lv_t and such. Also, how does this relate to the idea that we want to push back the concept of a PV as away from users as possible? I think Alasdair mentioned that on several occasions -- PVs should become implicit, as opposed to explicit. Although it might be a stretch for library. Not sure. What do you think? As for internal structures, I suppose the major hurdle is the way we allocate those in the toolcontext pool (and then maybe their complex interlinked nature). I wouldn't say that another layer of, especially heap-or-pool-allocated indirection will do any good. I think we already have more than is good for us: the lvmcache is keeping a shadow copy of everything already in an incompatible format from the struct volume_group and friends. This happens to be the on-disk text format in a string buffer. I believe this is also due to allocation and linking issues of the current struct volume_group representation. So improving the situation with the struct volume_group etc. would probably help the lvmcache, as well as the lvmlib API. Maybe that would be a worthy investment then, instead of building up another incompatible shadow structure? Also, the patch seems to be duplicating a lot of code from previous patches? Or were those for different kind of object (listing and checking attributes, eg.)? [snip patch] Yours, Petr. -- Peter Rockai | me()mornfall!net | prockai()redhat!com http://blog.mornfall.net | http://web.mornfall.net "In My Egotistical Opinion, most people's C programs should be indented six feet downward and covered with dirt." -- Blair P. Houghton on the subject of C program indentation ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 12/13] First cut at adding pv_obj_* APIs. 2009-02-02 23:58 ` [PATCH 12/13] First cut at adding pv_obj_* APIs Petr Rockai @ 2009-02-13 11:23 ` Dave Wysochanski 0 siblings, 0 replies; 29+ messages in thread From: Dave Wysochanski @ 2009-02-13 11:23 UTC (permalink / raw) To: lvm-devel On Tue, 2009-02-03 at 00:58 +0100, Petr Rockai wrote: > Hi, > > Dave Wysochanski <dwysocha@redhat.com> writes: > > Impelemnt pv_obj_get(), pv_obj_get_list(), pv_obj_get_attr_list() and > > pv_obj_get_attr_value(). > > > > This is a first attempt at adding pv_obj_* APIs as outlined by > > http://fedoraproject.org/wiki/LVM/liblvm/api > > > > Why add another structure when we could use struct physical_volume > > and other internal structs? At this point it is not clear but would > > provide us with the ability to more easily allocate and free handles, > > and would allow places to store things like the access mode and API > > errors without polluting the internal structures. > I don't say this is completely wrong, but the naming seems very baroque to me, > and not at all clear what it means, in relation to pv_t, lv_t and such. Also, > how does this relate to the idea that we want to push back the concept of a PV > as away from users as possible? I think Alasdair mentioned that on several > occasions -- PVs should become implicit, as opposed to explicit. Although it > might be a stretch for library. Not sure. What do you think? > We discussed removing the PV concept from the API earlier this week on a concall. From my notes/recollection, here is what we concluded: 1. We should aim to ensure a PV is always in a VG, even if it is just the orphan VG. 2. To obtain a PV object, you must first obtain a VG object. 3. If you want to change a PV attribute, you must first do a vg_read/vg_open and obtain WRITE permission. Thomas is going to update the API document. I agree it is not desirable to introduce another set of structures unless there is good reason for it. It was an initial implementation and something Thomas and I were discussing. The reason we were leaning towards a new structure was we needed a place to store the options for the create functions (e.g. pvcreate, vgcreate, lvcreate). In some cases these are attributes of the actual PV, VG, or LV. But in other cases they are options to control the create behavior. We should probably think about each of the options specifically and see what the best way to handle them. I know this wasn't apparent from my patchset here but as I recall this is why we were adding a new structure. > As for internal structures, I suppose the major hurdle is the way we allocate > those in the toolcontext pool (and then maybe their complex interlinked > nature). I wouldn't say that another layer of, especially > heap-or-pool-allocated indirection will do any good. I think we already have > more than is good for us: the lvmcache is keeping a shadow copy of everything > already in an incompatible format from the struct volume_group and > friends. This happens to be the on-disk text format in a string buffer. I > believe this is also due to allocation and linking issues of the current struct > volume_group representation. So improving the situation with the struct > volume_group etc. would probably help the lvmcache, as well as the lvmlib > API. Maybe that would be a worthy investment then, instead of building up > another incompatible shadow structure? > Agreed the internal structures are a bit confusing with various partially done abstractions, etc. If we can clean them up it would be great. > Also, the patch seems to be duplicating a lot of code from previous patches? Or > were those for different kind of object (listing and checking attributes, eg.)? > Probably so - patches were just a first stab. Thanks for the comments. ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 08/13] Add lvm_vg_get_attr_value() libLVM API to query to value of a VG attribute. 2009-02-02 20:50 ` [PATCH 08/13] Add lvm_vg_get_attr_value() libLVM API to query to value of a VG attribute Dave Wysochanski 2009-02-02 20:50 ` [PATCH 09/13] Add lvm_lvs_in_vg() API Dave Wysochanski @ 2009-02-02 23:47 ` Petr Rockai 2009-02-13 11:30 ` Dave Wysochanski 1 sibling, 1 reply; 29+ messages in thread From: Petr Rockai @ 2009-02-02 23:47 UTC (permalink / raw) To: lvm-devel Dave Wysochanski <dwysocha@redhat.com> writes: > This API may be used independently to query the value of a VG attribute, > provided the name of the attribute is known. If the name of the attribute(s) > are unknown, the previous API, vg_get_attr_list(), may be used. I suppose this makes the field names part of the API. Nothing wrong with that, they are already exported into the command-level interface, just wanted to make that fact explicit. -- Peter Rockai | me()mornfall!net | prockai()redhat!com http://blog.mornfall.net | http://web.mornfall.net "In My Egotistical Opinion, most people's C programs should be indented six feet downward and covered with dirt." -- Blair P. Houghton on the subject of C program indentation ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 08/13] Add lvm_vg_get_attr_value() libLVM API to query to value of a VG attribute. 2009-02-02 23:47 ` [PATCH 08/13] Add lvm_vg_get_attr_value() libLVM API to query to value of a VG attribute Petr Rockai @ 2009-02-13 11:30 ` Dave Wysochanski 0 siblings, 0 replies; 29+ messages in thread From: Dave Wysochanski @ 2009-02-13 11:30 UTC (permalink / raw) To: lvm-devel On Tue, 2009-02-03 at 00:47 +0100, Petr Rockai wrote: > Dave Wysochanski <dwysocha@redhat.com> writes: > > This API may be used independently to query the value of a VG attribute, > > provided the name of the attribute is known. If the name of the attribute(s) > > are unknown, the previous API, vg_get_attr_list(), may be used. > I suppose this makes the field names part of the API. Nothing wrong with that, > they are already exported into the command-level interface, just wanted to make > that fact explicit. > Yes. The field names will be the same as in the reporting commands of the tools so in theory, these should be well-known names and should not change. Note that this implementation of lvm_vg_get_attr_value() and lvm_vg_get_attr_list() is deprecated by my latest attempt at attributes based on the dm_report_output_attributes() function. My second attempt was meant to address the following 2 shortcomings: 1. The report handle must be kept alive as long as the attributes are used. To accomplish this, I allocate the report handle inside vg_open() and deallocate inside vg_close() 2. There was no good way to match up a field name with a value other than repeatedly calling lvm_vg_get_attr_value(). To solve this I decided a better approach was to define a attribute structure, which contained the name and the value. This will also allow me to add an access mode for the attribute (read-only or read/write). ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 06/13] Add lvm_vg_close(). 2009-02-02 20:50 ` [PATCH 06/13] Add lvm_vg_close() Dave Wysochanski 2009-02-02 20:50 ` [PATCH 07/13] Add lvm_vg_get_attr_list() libLVM API to return a list of VG attribute names Dave Wysochanski @ 2009-02-02 23:45 ` Petr Rockai 2009-02-04 17:11 ` Dave Wysochanski 1 sibling, 1 reply; 29+ messages in thread From: Petr Rockai @ 2009-02-02 23:45 UTC (permalink / raw) To: lvm-devel Dave Wysochanski <dwysocha@redhat.com> writes: > +void lvm_vg_close(vg_t *vg) > +{ > + if (vgname_is_locked(vg->name)) > + unlock_vg(vg->cmd, vg->name); > +} Do we want to do reference counting in here? Might be moot if we don't allow multiple opens. But contrary to what I said on IRC last time, it might be worth to have proper lock upgrading procedure, and it would be sort of nice if that could be achieved (for the user) by just calling the open function again on the same VG, with write permission request. One use case is automated recovery, which could be probably reformulated elegantly in terms of a lock upgrade. Another is the one you have mentioned, "read in the vg, wibble around a little and then decide you want to change it". The solution I proposed back then, to close and open for writing again, is inherently race-prone, so you would need to do all your wibbling again. Of course, the lock upgrade might fail, in which case, you will have to anyway, but maybe it still makes the API a little more friendly and less tempting to do the wrong thing. However, now I think about it, even that probably doesn't need refcounting if we structure the lock upgrade API accordingly. Ok, clear. I'm getting pretty tangential now, but another thought: should be the locking state encapsulated in the library handle, as opposed to process-global? This probably depends whether the locks can actually prevent the same process (in say different thread) from acquiring the lock second time (ie. whether they are effective in preventing unintended concurrent accesses from same process). If they are, it wouldn't be so hard to make the proposed lvmlib API thread-safe, by requiring that each thread owns its own library handle. This might be of direct benefit to eg. dmeventd, which currently has a fairly ugly mutex hack instead. Sorry for the tangential reply... Petr. -- Peter Rockai | me()mornfall!net | prockai()redhat!com http://blog.mornfall.net | http://web.mornfall.net "In My Egotistical Opinion, most people's C programs should be indented six feet downward and covered with dirt." -- Blair P. Houghton on the subject of C program indentation ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 06/13] Add lvm_vg_close(). 2009-02-02 23:45 ` [PATCH 06/13] Add lvm_vg_close() Petr Rockai @ 2009-02-04 17:11 ` Dave Wysochanski 2009-02-04 20:27 ` Dave Wysochanski 0 siblings, 1 reply; 29+ messages in thread From: Dave Wysochanski @ 2009-02-04 17:11 UTC (permalink / raw) To: lvm-devel On Tue, 2009-02-03 at 00:45 +0100, Petr Rockai wrote: > Dave Wysochanski <dwysocha@redhat.com> writes: > > +void lvm_vg_close(vg_t *vg) > > +{ > > + if (vgname_is_locked(vg->name)) > > + unlock_vg(vg->cmd, vg->name); > > +} > Do we want to do reference counting in here? Might be moot if we don't allow > multiple opens. But contrary to what I said on IRC last time, it might be worth > to have proper lock upgrading procedure, and it would be sort of nice if that > could be achieved (for the user) by just calling the open function again on the > same VG, with write permission request. One use case is automated recovery, > which could be probably reformulated elegantly in terms of a lock upgrade. > Well, calling the open function again on the same VG would be a new interface that we'd have to explain so I'd lean against it. Is there an example elsewhere we could point at? If we went this route we'd need to keep a list of handles internally (we may end up needing this anyway for true handle validation) and then just pass back the same one. Also I think Thomas was opposed to the lock upgrading. > Another is the one you have mentioned, "read in the vg, wibble around a little > and then decide you want to change it". The solution I proposed back then, to > close and open for writing again, is inherently race-prone, so you would need > to do all your wibbling again. Of course, the lock upgrade might fail, in which > case, you will have to anyway, but maybe it still makes the API a little more > friendly and less tempting to do the wrong thing. > Right - we'll need to weigh pros and cons. Might need to prototype each approach and see what we find. > However, now I think about it, even that probably doesn't need refcounting if > we structure the lock upgrade API accordingly. Ok, clear. > > I'm getting pretty tangential now, but another thought: should be the locking > state encapsulated in the library handle, as opposed to process-global? This > probably depends whether the locks can actually prevent the same process (in > say different thread) from acquiring the lock second time (ie. whether they are > effective in preventing unintended concurrent accesses from same process). If > they are, it wouldn't be so hard to make the proposed lvmlib API thread-safe, > by requiring that each thread owns its own library handle. This might be of > direct benefit to eg. dmeventd, which currently has a fairly ugly mutex hack > instead. > By lock state, do you mean the type of locking, the locks on the open/reads, or both? The open/read mode we'd of course have to tie to the vg handles. Does it makes sense to allow 2 threads to call init_locking() with different lock types? Like other areas the locking code needs work if we're serious about thread safety. ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 06/13] Add lvm_vg_close(). 2009-02-04 17:11 ` Dave Wysochanski @ 2009-02-04 20:27 ` Dave Wysochanski 0 siblings, 0 replies; 29+ messages in thread From: Dave Wysochanski @ 2009-02-04 20:27 UTC (permalink / raw) To: lvm-devel On Wed, 2009-02-04 at 12:11 -0500, Dave Wysochanski wrote: > On Tue, 2009-02-03 at 00:45 +0100, Petr Rockai wrote: > > Dave Wysochanski <dwysocha@redhat.com> writes: > > > +void lvm_vg_close(vg_t *vg) > > > +{ > > > + if (vgname_is_locked(vg->name)) > > > + unlock_vg(vg->cmd, vg->name); > > > +} > > Do we want to do reference counting in here? Might be moot if we don't allow > > multiple opens. But contrary to what I said on IRC last time, it might be worth > > to have proper lock upgrading procedure, and it would be sort of nice if that > > could be achieved (for the user) by just calling the open function again on the > > same VG, with write permission request. One use case is automated recovery, > > which could be probably reformulated elegantly in terms of a lock upgrade. > > > > Well, calling the open function again on the same VG would be a new > interface that we'd have to explain so I'd lean against it. Is there an > example elsewhere we could point at? If we went this route we'd need to > keep a list of handles internally (we may end up needing this anyway for > true handle validation) and then just pass back the same one. > > Also I think Thomas was opposed to the lock upgrading. > There are plenty of examples of lock upgrading though normally it's on some sort of lock call, not an open. I know we said we wanted to hide the locking - maybe still possible. But if we need lock upgrading it might be clearer if we exposed a lock API directly. *gasp* ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 05/13] Add lvm_vg_open(). 2009-02-02 20:50 ` [PATCH 05/13] Add lvm_vg_open() Dave Wysochanski 2009-02-02 20:50 ` [PATCH 06/13] Add lvm_vg_close() Dave Wysochanski @ 2009-02-02 23:28 ` Petr Rockai 2009-02-04 15:01 ` Dave Wysochanski 1 sibling, 1 reply; 29+ messages in thread From: Petr Rockai @ 2009-02-02 23:28 UTC (permalink / raw) To: lvm-devel Dave Wysochanski <dwysocha@redhat.com> writes: > RFC - lvm_vg_open(). The new vg_read() function is a step in the right > direction but still contains a lot of new options / flags that will > be new to people and we can hopefully simplify. lvm_vg_open() was > modelled after 'open' which gives us a potential model that others are > familiar with. Can we use the modes and flags of 'open' in a similar way > or do we need to introduce new flags/concepts to people? For example, > can we use a some of the open flags such as O_CREAT and O_EXCL to > implement READ_CHECK_EXISTENCE? I am currently leaning towards using a completely separate entrypoint for the existence check function. It might have been a one bit too much flag abuse, that one. Count it as laziness on my part. I am not entirely convinced about the open metaphor. For one, the locking semantics don't go well with that -- files are racy by default and need to be quite carefully locked to prevent awful things from happening. We don't want to make that implication. Maybe working a little on the vg_read interface would make it acceptable to a newcomer, without causing too much confusion? Yours, Petr. -- Peter Rockai | me()mornfall!net | prockai()redhat!com http://blog.mornfall.net | http://web.mornfall.net "In My Egotistical Opinion, most people's C programs should be indented six feet downward and covered with dirt." -- Blair P. Houghton on the subject of C program indentation ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 05/13] Add lvm_vg_open(). 2009-02-02 23:28 ` [PATCH 05/13] Add lvm_vg_open() Petr Rockai @ 2009-02-04 15:01 ` Dave Wysochanski 0 siblings, 0 replies; 29+ messages in thread From: Dave Wysochanski @ 2009-02-04 15:01 UTC (permalink / raw) To: lvm-devel On Tue, 2009-02-03 at 00:28 +0100, Petr Rockai wrote: > Dave Wysochanski <dwysocha@redhat.com> writes: > > RFC - lvm_vg_open(). The new vg_read() function is a step in the right > > direction but still contains a lot of new options / flags that will > > be new to people and we can hopefully simplify. lvm_vg_open() was > > modelled after 'open' which gives us a potential model that others are > > familiar with. Can we use the modes and flags of 'open' in a similar way > > or do we need to introduce new flags/concepts to people? For example, > > can we use a some of the open flags such as O_CREAT and O_EXCL to > > implement READ_CHECK_EXISTENCE? > I am currently leaning towards using a completely separate entrypoint for the > existence check function. It might have been a one bit too much flag abuse, > that one. Count it as laziness on my part. > > I am not entirely convinced about the open metaphor. For one, the locking > semantics don't go well with that -- files are racy by default and need to be > quite carefully locked to prevent awful things from happening. We don't want to > make that implication. Maybe working a little on the vg_read interface would > make it acceptable to a newcomer, without causing too much confusion? > Well, I'm not convinced of either direction really. At this point I think I will continue down the open path and see where I get stuck. Refining your vg_read() patches is good - both efforts should lead to a better interface in the long run, whatever we choose. ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 03/13] Move vg_t, lv_t, and pv_t from metadata-exported.h into lvm2.h 2009-02-02 20:49 ` [PATCH 03/13] Move vg_t, lv_t, and pv_t from metadata-exported.h into lvm2.h Dave Wysochanski 2009-02-02 20:50 ` [PATCH 04/13] Add lvm_pv_name, lvm_vg_name, and lvm_lv_name accessors Dave Wysochanski @ 2009-02-02 23:25 ` Petr Rockai 2009-02-04 14:57 ` Dave Wysochanski 1 sibling, 1 reply; 29+ messages in thread From: Petr Rockai @ 2009-02-02 23:25 UTC (permalink / raw) To: lvm-devel Dave Wysochanski <dwysocha@redhat.com> writes: > Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> > --- > lib/lvm2.h | 9 +++++++++ > lib/metadata/metadata-exported.h | 8 +------- > 2 files changed, 10 insertions(+), 7 deletions(-) > > diff --git a/lib/lvm2.h b/lib/lvm2.h > index f348035..bfa1852 100644 > --- a/lib/lvm2.h > +++ b/lib/lvm2.h > @@ -60,4 +60,13 @@ void lvm_destroy(lvm_handle_t libh); > */ > int lvm_reload_config(lvm_handle_t libh); > > +struct volume_group; > +typedef struct volume_group vg_t; > + > +struct physical_volume; > +typedef struct physical_volume pv_t; > + > +struct logical_volume; > +typedef struct logical_volume lv_t; Did you mean to make all of those pointers? Or is the plan to expose the actual structures instead of just handles? (I don't know, I'm just asking.) I see you use vg_t * later on. Maybe thats' because we want to make the fact that these are pointers explicit? Just thinking aloud... Yours, Petr. -- Peter Rockai | me()mornfall!net | prockai()redhat!com http://blog.mornfall.net | http://web.mornfall.net "In My Egotistical Opinion, most people's C programs should be indented six feet downward and covered with dirt." -- Blair P. Houghton on the subject of C program indentation ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 03/13] Move vg_t, lv_t, and pv_t from metadata-exported.h into lvm2.h 2009-02-02 23:25 ` [PATCH 03/13] Move vg_t, lv_t, and pv_t from metadata-exported.h into lvm2.h Petr Rockai @ 2009-02-04 14:57 ` Dave Wysochanski 0 siblings, 0 replies; 29+ messages in thread From: Dave Wysochanski @ 2009-02-04 14:57 UTC (permalink / raw) To: lvm-devel On Tue, 2009-02-03 at 00:25 +0100, Petr Rockai wrote: > Dave Wysochanski <dwysocha@redhat.com> writes: > > > Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> > > --- > > lib/lvm2.h | 9 +++++++++ > > lib/metadata/metadata-exported.h | 8 +------- > > 2 files changed, 10 insertions(+), 7 deletions(-) > > > > diff --git a/lib/lvm2.h b/lib/lvm2.h > > index f348035..bfa1852 100644 > > --- a/lib/lvm2.h > > +++ b/lib/lvm2.h > > @@ -60,4 +60,13 @@ void lvm_destroy(lvm_handle_t libh); > > */ > > int lvm_reload_config(lvm_handle_t libh); > > > > +struct volume_group; > > +typedef struct volume_group vg_t; > > + > > +struct physical_volume; > > +typedef struct physical_volume pv_t; > > + > > +struct logical_volume; > > +typedef struct logical_volume lv_t; > Did you mean to make all of those pointers? Or is the plan to expose the actual > structures instead of just handles? (I don't know, I'm just asking.) > > I see you use vg_t * later on. Maybe thats' because we want to make the fact > that these are pointers explicit? Just thinking aloud... > The plan is not to expose the structs, just needed to declare the handles. ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 02/13] Add lvm_create, lvm_destroy, lvm_reload_config() APIs. 2009-02-02 20:49 ` [PATCH 02/13] Add lvm_create, lvm_destroy, lvm_reload_config() APIs Dave Wysochanski 2009-02-02 20:49 ` [PATCH 03/13] Move vg_t, lv_t, and pv_t from metadata-exported.h into lvm2.h Dave Wysochanski @ 2009-02-02 23:22 ` Petr Rockai 2009-02-03 0:44 ` [PATCH] Move locking_type reading inside init_locking() Dave Wysochanski 2009-02-13 11:42 ` [PATCH 02/13] " Dave Wysochanski 1 sibling, 2 replies; 29+ messages in thread From: Petr Rockai @ 2009-02-02 23:22 UTC (permalink / raw) To: lvm-devel Hi, see comments inline. Dave Wysochanski <dwysocha@redhat.com> writes: > +++ b/lib/lvm2.c > @@ -0,0 +1,70 @@ > +/* > + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. > + * > + * This file is part of LVM2. > + * > + * This copyrighted material is made available to anyone wishing to use, > + * modify, copy, or redistribute it subject to the terms and conditions > + * of the GNU Lesser General Public License v.2.1. > + * > + * You should have received a copy of the GNU Lesser General Public License > + * along with this program; if not, write to the Free Software Foundation, > + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + */ > + > +#include "lvm2.h" > +#include "lib.h" > +#include "toolcontext.h" > +#include "locking.h" > +#include "metadata-exported.h" > +#include "report.h" > + > + > +lvm_handle_t lvm_create(const char *system_dir) > +{ > + struct cmd_context *cmd; > + > + /* To be done: > + * logging bound to handle > + */ > + > + /* create context */ > + cmd = create_toolcontext(1, system_dir); > + > + /* initilize remaining */ > + if (cmd) { > + int locking_type; > + > + /* initilization from lvm_run_command */ > + init_error_message_produced(0); > + sigint_clear(); > + > + /* get locking type from config tree */ > + /* FIXME: config option needed? */ > + locking_type = find_config_tree_int(cmd, "global/locking_type", > + 1); I'm wondering if it would make sense to unify the code reading the default locking type and the code reading the fallback options and such. As things are, half of the configuration processing is done here and the other half inside init_locking called below (cf lib/locking/locking.c, init_locking). > + > + /* initialize locking */ > + if (! init_locking(locking_type, cmd)) { > + printf("Locking type %d initialisation failed.", > + locking_type); > + lvm_destroy((lvm_handle_t) cmd); > + return NULL; > + } > + } > + > + return (lvm_handle_t) cmd; I'm also wondering if the explicit cast is such a great idea afterall. (I know this has been brought up before with my patches.) I would probably prefer to see a comment saying /* lvm_handle_t is an alias for struct cmd_context * */ -- that way, when that fact changes, we will hopefully get a warning from the compiler on all the places this is assumed (which might be suppressed by the explicit cast). Or am I wrong on that count? > +} > + > + > +void lvm_destroy(lvm_handle_t libh) > +{ > + destroy_toolcontext((struct cmd_context *)libh); > + /* no error handling here */ > +} > + > + > +int lvm_reload_config(lvm_handle_t libh) > +{ > + return refresh_toolcontext((struct cmd_context *)libh); > +} Should this also cater for locking re-initialisation? I suppose if configuration changed, so might have locking. [snip lvm2.h changes, no comments] [snip test.c changes, no comment either] Yours, Petr. -- Peter Rockai | me()mornfall!net | prockai()redhat!com http://blog.mornfall.net | http://web.mornfall.net "In My Egotistical Opinion, most people's C programs should be indented six feet downward and covered with dirt." -- Blair P. Houghton on the subject of C program indentation ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH] Move locking_type reading inside init_locking(). 2009-02-02 23:22 ` [PATCH 02/13] Add lvm_create, lvm_destroy, lvm_reload_config() APIs Petr Rockai @ 2009-02-03 0:44 ` Dave Wysochanski 2009-02-03 1:12 ` [PATCH take2] Add lvm_create, lvm_destroy, lvm_reload_config() APIs Dave Wysochanski 2009-02-13 11:42 ` [PATCH 02/13] " Dave Wysochanski 1 sibling, 1 reply; 29+ messages in thread From: Dave Wysochanski @ 2009-02-03 0:44 UTC (permalink / raw) To: lvm-devel No functional change. Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- lib/locking/locking.c | 5 +++++ tools/lvmcmdline.c | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/locking/locking.c b/lib/locking/locking.c index b5871ae..bf28d9a 100644 --- a/lib/locking/locking.c +++ b/lib/locking/locking.c @@ -208,11 +208,16 @@ static void _update_vg_lock_count(uint32_t flags) /* * Select a locking type + * type: locking type; if < 0, then read config tree value */ int init_locking(int type, struct cmd_context *cmd) { init_lockingfailed(0); + if (type < 0) + type = find_config_tree_int(cmd, "global/locking_type", 1); + + switch (type) { case 0: init_no_locking(&_locking, cmd); diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index 2dabe64..bafc6a5 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -995,8 +995,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv) if (arg_count(cmd, nolocking_ARG)) locking_type = 0; else - locking_type = find_config_tree_int(cmd, - "global/locking_type", 1); + locking_type = -1; if (!init_locking(locking_type, cmd)) { log_error("Locking type %d initialisation failed.", -- 1.6.0.5 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH take2] Add lvm_create, lvm_destroy, lvm_reload_config() APIs. 2009-02-03 0:44 ` [PATCH] Move locking_type reading inside init_locking() Dave Wysochanski @ 2009-02-03 1:12 ` Dave Wysochanski 0 siblings, 0 replies; 29+ messages in thread From: Dave Wysochanski @ 2009-02-03 1:12 UTC (permalink / raw) To: lvm-devel Add lvm2.c file. Update test code. Call init_locking() with locking_type = -1 to read config file value. Signed-off-by: Thomas Woerner <twoerner@redhat.com> Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> --- lib/Makefile.in | 3 +- lib/lvm2.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/lvm2.h | 44 +++++++++++++++++++++++-------------- test/api/test.c | 13 +++++------ 4 files changed, 99 insertions(+), 25 deletions(-) create mode 100644 lib/lvm2.c diff --git a/lib/Makefile.in b/lib/Makefile.in index 54092cd..c0b58b9 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -86,7 +86,8 @@ SOURCES =\ report/report.c \ striped/striped.c \ uuid/uuid.c \ - zero/zero.c + zero/zero.c \ + lvm2.c ifeq ("@LVM1@", "internal") SOURCES +=\ diff --git a/lib/lvm2.c b/lib/lvm2.c new file mode 100644 index 0000000..ef1ef21 --- /dev/null +++ b/lib/lvm2.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License v.2.1. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "lvm2.h" +#include "lib.h" +#include "toolcontext.h" +#include "locking.h" +#include "metadata-exported.h" +#include "report.h" + + +lvm_handle_t lvm_create(const char *system_dir) +{ + struct cmd_context *cmd; + + /* To be done: + * logging bound to handle + */ + + /* create context */ + cmd = create_toolcontext(1, system_dir); + + /* initilize remaining */ + if (cmd) { + /* initilization from lvm_run_command */ + init_error_message_produced(0); + sigint_clear(); + + /* FIXME: locking_type config option needed? */ + /* initialize locking */ + if (! init_locking(-1, cmd)) { + printf("Locking type %d initialisation failed.", + locking_type); + lvm_destroy((lvm_handle_t) cmd); + return NULL; + } + } + + return (lvm_handle_t) cmd; +} + + +void lvm_destroy(lvm_handle_t libh) +{ + destroy_toolcontext((struct cmd_context *)libh); + /* no error handling here */ +} + + +int lvm_reload_config(lvm_handle_t libh) +{ + return refresh_toolcontext((struct cmd_context *)libh); +} diff --git a/lib/lvm2.h b/lib/lvm2.h index b18cead..f348035 100644 --- a/lib/lvm2.h +++ b/lib/lvm2.h @@ -18,36 +18,46 @@ #include <stdint.h> /* - * Library Initialisation - * FIXME: For now just #define lvm2_create() and lvm2_destroy() to - * create_toolcontext() and destroy_toolcontext() + * lvm_handle_t */ -struct arg; -struct cmd_context; -struct cmd_context *create_toolcontext(unsigned is_long_lived); -void destroy_toolcontext(struct cmd_context *cmd); +struct lib_context; /* internal context data */ +typedef struct lib_context *lvm_handle_t; +#ifdef FUTURE_FEATURE /* - * lvm2_create -lvm_handle_t lvm2_create(void); + * lvm_config_t + */ +struct lvm_config { + const char *system_dir; + unsigned is_long_lived; +}; +#endif /* FUTURE_FEATURE */ + +/* + * lvm_create * - * Description: Create an LVM2 handle used in many other APIs. + * Description: Create an LVM handle used in many other APIs. * * Returns: * NULL: Fail - unable to initialise handle. - * non-NULL: Success - valid LVM2 handle returned + * non-NULL: Success - valid LVM handle returned */ -#define lvm2_create(X) create_toolcontext(1) +lvm_handle_t lvm_create(const char *system_dir); /* - * lvm2_destroy -void lvm2_destroy(lvm_handle_t h); + * lvm_destroy * - * Description: Destroy an LVM2 handle allocated with lvm2_create + * Description: Destroy an LVM handle allocated with lvm_create * * Parameters: - * - h (IN): handle obtained from lvm2_create + * - h (IN): handle obtained from lvm_create + */ +void lvm_destroy(lvm_handle_t libh); + +/* + * lvm_reload_config + * Reload configuration files */ -#define lvm2_destroy(X) destroy_toolcontext(X) +int lvm_reload_config(lvm_handle_t libh); #endif diff --git a/test/api/test.c b/test/api/test.c index de53c46..9411663 100644 --- a/test/api/test.c +++ b/test/api/test.c @@ -48,7 +48,7 @@ static int lvm_split(char *str, int *argc, char **argv, int max) return *argc; } -static int lvmapi_test_shell(void *h) +static int lvmapi_test_shell(lvm_handle_t libh) { int argc, i; char *input = NULL, *args[MAX_ARGS], **argv; @@ -99,18 +99,17 @@ static int lvmapi_test_shell(void *h) int main (int argc, char *argv[]) { - void *h; + lvm_handle_t libh; - h = lvm2_create(); - if (!h) { + libh = lvm_create(NULL); + if (!libh) { printf("Unable to open lvm library instance\n"); return 1; } - lvmapi_test_shell(h); + lvmapi_test_shell(libh); - if (h) - lvm2_destroy(h); + lvm_destroy(libh); return 0; } -- 1.6.0.5 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 02/13] Add lvm_create, lvm_destroy, lvm_reload_config() APIs. 2009-02-02 23:22 ` [PATCH 02/13] Add lvm_create, lvm_destroy, lvm_reload_config() APIs Petr Rockai 2009-02-03 0:44 ` [PATCH] Move locking_type reading inside init_locking() Dave Wysochanski @ 2009-02-13 11:42 ` Dave Wysochanski 1 sibling, 0 replies; 29+ messages in thread From: Dave Wysochanski @ 2009-02-13 11:42 UTC (permalink / raw) To: lvm-devel On Tue, 2009-02-03 at 00:22 +0100, Petr Rockai wrote: > Hi, > > see comments inline. > > Dave Wysochanski <dwysocha@redhat.com> writes: > > +++ b/lib/lvm2.c > > @@ -0,0 +1,70 @@ > > +/* > > + * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. > > + * > > + * This file is part of LVM2. > > + * > > + * This copyrighted material is made available to anyone wishing to use, > > + * modify, copy, or redistribute it subject to the terms and conditions > > + * of the GNU Lesser General Public License v.2.1. > > + * > > + * You should have received a copy of the GNU Lesser General Public License > > + * along with this program; if not, write to the Free Software Foundation, > > + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > > + */ > > + > > +#include "lvm2.h" > > +#include "lib.h" > > +#include "toolcontext.h" > > +#include "locking.h" > > +#include "metadata-exported.h" > > +#include "report.h" > > + > > + > > +lvm_handle_t lvm_create(const char *system_dir) > > +{ > > + struct cmd_context *cmd; > > + > > + /* To be done: > > + * logging bound to handle > > + */ > > + > > + /* create context */ > > + cmd = create_toolcontext(1, system_dir); > > + > > + /* initilize remaining */ > > + if (cmd) { > > + int locking_type; > > + > > + /* initilization from lvm_run_command */ > > + init_error_message_produced(0); > > + sigint_clear(); > > + > > + /* get locking type from config tree */ > > + /* FIXME: config option needed? */ > > + locking_type = find_config_tree_int(cmd, "global/locking_type", > > + 1); > I'm wondering if it would make sense to unify the code reading the default > locking type and the code reading the fallback options and such. As things are, > half of the configuration processing is done here and the other half inside > init_locking called below (cf lib/locking/locking.c, init_locking). > I did submit a patch I thought was a simple cleanup but more work is needed to clean up locking. Ideally I'd like to place init_locking inside create_toolcontext and just make this the initialization function. I ran into a problem with clvmd though being a "locking implementor" or "locking backend". Alasdair spent some time with me brainstorming how we might solve this - splitting the API into different portions: 1. Calls ok for a locking back-end 2. Calls ok for a locking front-end 3. Calls ok for both I have temporarily put this on the back-burner while I try to solve some other things but should make another attempt at cleanup soon. > > + > > +void lvm_destroy(lvm_handle_t libh) > > +{ > > + destroy_toolcontext((struct cmd_context *)libh); > > + /* no error handling here */ > > +} > > + > > + > > +int lvm_reload_config(lvm_handle_t libh) > > +{ > > + return refresh_toolcontext((struct cmd_context *)libh); > > +} > Should this also cater for locking re-initialisation? I suppose if > configuration changed, so might have locking. > Indeed - thanks. ^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2009-02-13 11:42 UTC | newest] Thread overview: 29+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-02-02 20:49 [PATCH 0/13] liblvm initialization, attribute, and object handling Dave Wysochanski 2009-02-02 20:49 ` [PATCH 01/13] Add system_dir to create_toolcontext() Dave Wysochanski 2009-02-02 20:49 ` [PATCH 02/13] Add lvm_create, lvm_destroy, lvm_reload_config() APIs Dave Wysochanski 2009-02-02 20:49 ` [PATCH 03/13] Move vg_t, lv_t, and pv_t from metadata-exported.h into lvm2.h Dave Wysochanski 2009-02-02 20:50 ` [PATCH 04/13] Add lvm_pv_name, lvm_vg_name, and lvm_lv_name accessors Dave Wysochanski 2009-02-02 20:50 ` [PATCH 05/13] Add lvm_vg_open() Dave Wysochanski 2009-02-02 20:50 ` [PATCH 06/13] Add lvm_vg_close() Dave Wysochanski 2009-02-02 20:50 ` [PATCH 07/13] Add lvm_vg_get_attr_list() libLVM API to return a list of VG attribute names Dave Wysochanski 2009-02-02 20:50 ` [PATCH 08/13] Add lvm_vg_get_attr_value() libLVM API to query to value of a VG attribute Dave Wysochanski 2009-02-02 20:50 ` [PATCH 09/13] Add lvm_lvs_in_vg() API Dave Wysochanski 2009-02-02 20:50 ` [PATCH 10/13] Add lvm_pvs_in_vg() Dave Wysochanski 2009-02-02 20:50 ` [PATCH 11/13] Add lvm_lv_get_attr_list() and lvm_lv_get_attr_value() Dave Wysochanski 2009-02-02 20:50 ` [PATCH 12/13] First cut at adding pv_obj_* APIs Dave Wysochanski 2009-02-02 20:50 ` [PATCH 13/13] Add test code Dave Wysochanski 2009-02-02 23:58 ` [PATCH 12/13] First cut at adding pv_obj_* APIs Petr Rockai 2009-02-13 11:23 ` Dave Wysochanski 2009-02-02 23:47 ` [PATCH 08/13] Add lvm_vg_get_attr_value() libLVM API to query to value of a VG attribute Petr Rockai 2009-02-13 11:30 ` Dave Wysochanski 2009-02-02 23:45 ` [PATCH 06/13] Add lvm_vg_close() Petr Rockai 2009-02-04 17:11 ` Dave Wysochanski 2009-02-04 20:27 ` Dave Wysochanski 2009-02-02 23:28 ` [PATCH 05/13] Add lvm_vg_open() Petr Rockai 2009-02-04 15:01 ` Dave Wysochanski 2009-02-02 23:25 ` [PATCH 03/13] Move vg_t, lv_t, and pv_t from metadata-exported.h into lvm2.h Petr Rockai 2009-02-04 14:57 ` Dave Wysochanski 2009-02-02 23:22 ` [PATCH 02/13] Add lvm_create, lvm_destroy, lvm_reload_config() APIs Petr Rockai 2009-02-03 0:44 ` [PATCH] Move locking_type reading inside init_locking() Dave Wysochanski 2009-02-03 1:12 ` [PATCH take2] Add lvm_create, lvm_destroy, lvm_reload_config() APIs Dave Wysochanski 2009-02-13 11:42 ` [PATCH 02/13] " Dave Wysochanski
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.