[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
[dm-devel] [PATCH RFC 3/3] make priority groups modular and rm ps's HW knowledge
- From: Mike Christie <michaelc cs wisc edu>
- To: device-mapper development <dm-devel redhat com>
- Subject: [dm-devel] [PATCH RFC 3/3] make priority groups modular and rm ps's HW knowledge
- Date: Fri, 04 Jun 2004 04:33:59 -0700
03-add-modular-pg.patch - a place to put vendor specific junk. I will resend my
FAStT code ported to a priority-group, and seperate new group that should do the
failover for HP-storage-works.
Makefile | 2
dm-priority-group.c | 354 ++++++++++++++++++++++++++++++++++++++++++++++++++++
dm-priority-group.h | 123 ++++++++++++++++++
3 files changed, 478 insertions(+), 1 deletion(-)
diff -Naurp linux-2.6.7-rc2/drivers/md/dm-priority-group.c linux-2.6.7-rc2-pg/drivers/md/dm-priority-group.c
--- linux-2.6.7-rc2/drivers/md/dm-priority-group.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.7-rc2-pg/drivers/md/dm-priority-group.c 2004-06-04 03:37:39.938958278 -0700
@@ -0,0 +1,354 @@
+/*
+ * dm-priority-group.c - DM-mpath Priority Group - Priority Groups
+ * are generic way to group your paths together. PGs should init
+ * the paths if needed (implement ->init function to send a
+ * failover command) and decide when to fail a path (how to decode
+ * and/or pass dm-mpath vendor specific sense is unfinished).
+ *
+ * Copyright (C) IBM Corporation, 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111s-1307, USA.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/list.h>
+
+#include "dm.h"
+#include "dm-priority-group.h"
+
+
+/*
+ * code to handle refcounting priority_group_type modules
+ */
+struct pg_internal {
+ struct priority_group_type pgt;
+
+ struct list_head list;
+ long use;
+};
+
+#define pgt_to_pgi(__pgt) container_of((__pgt), struct pg_internal, pgt)
+
+static LIST_HEAD(priority_groups);
+static DECLARE_MUTEX(priority_groups_lock);
+
+struct priority_group_type *__find_priority_group_type(const char *name)
+{
+ struct pg_internal *pgi;
+
+ list_for_each_entry (pgi, &priority_groups, list) {
+ if (!strcmp(name, pgi->pgt.name))
+ return &pgi->pgt;
+ }
+
+ return NULL;
+}
+
+struct priority_group_type *dm_get_priority_group(const char *name)
+{
+ struct priority_group_type *pgt;
+
+ if (!name)
+ return NULL;
+
+ down(&priority_groups_lock);
+ pgt = __find_priority_group_type(name);
+ if (pgt) {
+ struct pg_internal *pgi = pgt_to_pgi(pgt);
+
+ if (pgi->use == 0 && !try_module_get(pgt->module))
+ pgi = NULL;
+ else
+ pgi->use++;
+ }
+ up(&priority_groups_lock);
+
+ return pgt;
+}
+
+void dm_put_priority_group(struct priority_group_type *pgt)
+{
+ struct pg_internal *pgi;
+
+ down(&priority_groups_lock);
+ pgt = __find_priority_group_type(pgt->name);
+ if (!pgt)
+ return;
+
+ pgi = pgt_to_pgi(pgt);
+ if (--pgi->use == 0)
+ module_put(pgi->pgt.module);
+
+ if (pgi->use < 0)
+ BUG();
+ up(&priority_groups_lock);
+}
+
+static struct pg_internal *_alloc_priority_group(struct priority_group_type *pt)
+{
+ struct pg_internal *pgi = kmalloc(sizeof(*pgi), GFP_KERNEL);
+
+ if (pgi) {
+ memset(pgi, 0, sizeof(*pgi));
+ memcpy(&pgi->pgt, pt, sizeof(*pt));
+ }
+
+ return pgi;
+}
+
+int dm_register_priority_group(struct priority_group_type *pgt)
+{
+ int r = 0;
+ struct pg_internal *pgi = _alloc_priority_group(pgt);
+
+ if (!pgi)
+ return -ENOMEM;
+
+ down(&priority_groups_lock);
+ if (__find_priority_group_type(pgt->name)) {
+ kfree(pgi);
+ r = -EEXIST;
+ } else
+ list_add(&pgi->list, &priority_groups);
+
+ up(&priority_groups_lock);
+
+ return r;
+}
+
+EXPORT_SYMBOL(dm_register_priority_group);
+
+int dm_unregister_priority_group(struct priority_group_type *pgt)
+{
+ struct pg_internal *pgi;
+
+ down(&priority_groups_lock);
+ pgt = __find_priority_group_type(pgt->name);
+ if (!pgt) {
+ up(&priority_groups_lock);
+ return -EINVAL;
+ }
+
+ pgi = pgt_to_pgi(pgt);
+ if (pgi->use) {
+ up(&priority_groups_lock);
+ return -ETXTBSY;
+ }
+
+ list_del(&pgi->list);
+ up(&priority_groups_lock);
+
+ kfree(pgi);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(dm_unregister_priority_group);
+
+
+/*
+ * Generic Priority Group - This handles basic HW or cases where we do
+ * not have any specs/info so we cannot support the devices special
+ * features.
+ */
+
+/* FIXME: get rid of this */
+#define PG_FAIL_COUNT 1
+
+struct path_info {
+ struct list_head list;
+ struct path *path;
+ unsigned fail_count;
+};
+
+/*
+ * bleh - we do not need this. put some sort of private memeber on the
+ * path struct along with nice accessor fns. This is only used in
+ * non critical code paths though.
+ */
+static struct path_info *path_lookup(struct list_head *head, struct path *p)
+{
+ struct path_info *pi;
+
+ list_for_each_entry (pi, head, list)
+ if (pi->path == p)
+ return pi;
+
+ return NULL;
+}
+
+struct pgroup {
+ spinlock_t path_lock;
+
+ struct list_head valid_paths;
+ struct list_head invalid_paths;
+};
+
+static struct pgroup *alloc_pgroup(void)
+{
+ struct pgroup *pgroup = kmalloc(sizeof(*pgroup), GFP_KERNEL);
+
+ if (pgroup) {
+ memset(pgroup, 0, sizeof(*pgroup));
+ INIT_LIST_HEAD(&pgroup->valid_paths);
+ INIT_LIST_HEAD(&pgroup->invalid_paths);
+ pgroup->path_lock = SPIN_LOCK_UNLOCKED;
+ }
+
+ return pgroup;
+}
+
+static int generic_group_ctr(struct priority_group *pg)
+{
+ struct pgroup *pgroup;
+
+ pgroup = alloc_pgroup();
+ if (!pgroup)
+ return -ENOMEM;
+
+ pg->context = pgroup;
+ return 0;
+}
+
+static void free_paths(struct list_head *paths)
+{
+ struct path_info *pi, *next;
+
+ list_for_each_entry_safe (pi, next, paths, list) {
+ list_del(&pi->list);
+ kfree(pi);
+ }
+}
+
+static void generic_group_dtr(struct priority_group *pg)
+{
+ struct pgroup *pgroup = (struct pgroup *)pg->context;
+ free_paths(&pgroup->valid_paths);
+ free_paths(&pgroup->invalid_paths);
+ kfree(pgroup);
+}
+
+static int generic_group_add_path(struct priority_group *pg, struct path *path,
+ int argc, char **argv, char **error)
+{
+ struct pgroup *pgroup= (struct pgroup *) pg->context;
+ struct path_info *pi;
+
+ if (argc != 0) {
+ *error = "generic-pg: incorrect number of arguments";
+ return -EINVAL;
+ }
+
+ pi = kmalloc(sizeof(*pi), GFP_KERNEL);
+ if (!pi) {
+ *error = "generic-pg: Error allocating path context";
+ return -ENOMEM;
+ }
+
+ pi->fail_count = 0;
+ pi->path = path;
+
+ spin_lock(&pgroup->path_lock);
+ list_add_tail(&pi->list, &pgroup->valid_paths);
+ spin_unlock(&pgroup->path_lock);
+
+ return 0;
+}
+
+static int generic_group_update_path(struct priority_group *pg,
+ struct path *path, int status)
+{
+ unsigned long flags;
+ int r = 0;
+ struct path_info *pi;
+ struct pgroup *pgroup = (struct pgroup *) pg->context;
+
+ spin_lock_irqsave(&pgroup->path_lock, flags);
+
+ if (status) {
+ pi = path_lookup(&pgroup->valid_paths, path);
+ if (!pi)
+ goto done;
+
+ if (++pi->fail_count == PG_FAIL_COUNT) {
+ list_move(&pi->list, &pgroup->invalid_paths);
+
+ r = 1;
+ }
+ } else {
+ pi = path_lookup(&pgroup->invalid_paths, path);
+ if (!pi)
+ goto done;
+
+ list_move(&pi->list, &pgroup->valid_paths);
+ }
+
+ done:
+ spin_unlock_irqrestore(&pgroup->path_lock, flags);
+
+ return r;
+}
+
+
+static int generic_group_status(struct priority_group *pg, struct path *path,
+ status_type_t type, char *result,
+ unsigned int maxlen)
+{
+ unsigned long flags;
+ int failed = 0;
+ struct path_info *pi;
+ int sz = 0;
+ struct pgroup *pgroup = (struct pgroup *) pg->context;
+
+ if (type == STATUSTYPE_TABLE)
+ return 0;
+
+ spin_lock_irqsave(&pgroup->path_lock, flags);
+
+ pi = path_lookup(&pgroup->valid_paths, path);
+ if (!pi) {
+ failed = 1;
+ pi = path_lookup(&pgroup->invalid_paths, path);
+ }
+
+ sz = scnprintf(result, maxlen, "%s %u ", failed ? "F" : "A",
+ pi->fail_count);
+
+ spin_unlock_irqrestore(&pgroup->path_lock, flags);
+
+ return sz;
+}
+
+static struct priority_group_type gen_pg = {
+ .name = "generic",
+ .module = THIS_MODULE,
+
+ .ctr = generic_group_ctr,
+ .dtr = generic_group_dtr,
+ .add_path = generic_group_add_path,
+ .update_path = generic_group_update_path,
+ .status = generic_group_status,
+};
+
+int __init dm_register_generic_group(void)
+{
+ return dm_register_priority_group(&gen_pg);
+}
+
+void __exit dm_unregister_generic_group(void)
+{
+ dm_unregister_priority_group(&gen_pg);
+}
diff -Naurp linux-2.6.7-rc2/drivers/md/dm-priority-group.h linux-2.6.7-rc2-pg/drivers/md/dm-priority-group.h
--- linux-2.6.7-rc2/drivers/md/dm-priority-group.h 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.7-rc2-pg/drivers/md/dm-priority-group.h 2004-06-04 01:55:44.000000000 -0700
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) IBM Corporation, 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111s-1307, USA.
+ *
+ */
+
+#ifndef DM_PRIORITY_GROUP_H
+#define DM_PRIORITY_GROUP_H
+
+#include "dm-path-selector.h"
+
+struct path;
+
+struct block_device *dm_path_to_bdev(struct path *path);
+
+struct multipath;
+struct priority_group_type;
+
+/* Priority Group */
+struct priority_group {
+ /*
+ * This can be set by priority_groups to store
+ * some private data.
+ */
+ void *context;
+
+ /*
+ * These should be considered private to
+ * dm-mpath.c
+ */
+ struct priority_group_type *type;
+ struct path_selector ps;
+ struct multipath *m;
+
+ unsigned nr_paths;
+ struct list_head paths;
+
+ struct list_head list;
+};
+
+/*
+ * Constructs a priority group object, takes custom arguments
+ */
+typedef int (*pg_ctr_fn) (struct priority_group *pg);
+typedef void (*pg_dtr_fn) (struct priority_group *pg);
+
+/*
+ * Allows the pg to initialize itself. It should return one
+ * of the following return values. If DM_PG_INITIALIZING is
+ * returned the priority_group must call dm_pg_init_complete
+ * when the initializtion has completed.
+ */
+enum {
+ DM_PG_SUCCESS,
+ DM_PG_FAILED,
+ DM_PG_INITIALIZING,
+};
+
+void dm_pg_init_complete(struct priority_group *pg);
+
+typedef int (*pg_init_fn) (struct priority_group *pg);
+
+/*
+ * Add a path object, along with some path args.
+ */
+typedef int (*pg_add_path_fn) (struct priority_group *pg, struct path *path,
+ int argc, char **argv, char **error);
+/*
+ * Notify the pg that path status has changes.
+ * status should be an -Exxx value to indicate an error,
+ * 0 to indicatate reactivation.
+ * returns 1 if it determined the path should be
+ * marked as failed else 0.
+ */
+typedef int (*pg_update_path_fn) (struct priority_group *pg,
+ struct path *path, int status);
+
+/*
+ * Table content based on parameters added in pg_add_path_fn
+ * or path selector status
+ */
+typedef int (*pg_status_fn) (struct priority_group *pg, struct path *path,
+ status_type_t type, char *result,
+ unsigned int maxlen);
+
+/* Information about a priority group type */
+struct priority_group_type {
+ char *name;
+ struct module *module;
+
+ unsigned int table_args;
+ unsigned int info_args;
+ pg_ctr_fn ctr;
+ pg_dtr_fn dtr;
+ pg_init_fn init;
+ pg_add_path_fn add_path;
+ pg_update_path_fn update_path;
+ pg_status_fn status;
+};
+
+
+int dm_unregister_priority_group(struct priority_group_type *pgt);
+int dm_register_priority_group(struct priority_group_type *pgt);
+void dm_put_priority_group(struct priority_group_type *pgt);
+struct priority_group_type *dm_get_priority_group(const char *name);
+
+int dm_register_generic_group(void);
+void dm_unregister_generic_group(void);
+
+#endif
diff -Naurp linux-2.6.7-rc2/drivers/md/Makefile linux-2.6.7-rc2-pg/drivers/md/Makefile
--- linux-2.6.7-rc2/drivers/md/Makefile 2004-06-04 03:52:23.168748837 -0700
+++ linux-2.6.7-rc2-pg/drivers/md/Makefile 2004-06-04 03:59:16.659899173 -0700
@@ -4,7 +4,7 @@
dm-mod-objs := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
dm-ioctl.o dm-io.o kcopyd.o
-dm-multipath-objs := dm-path-selector.o dm-mpath.o
+dm-multipath-objs := dm-path-selector.o dm-priority-group.o dm-mpath.o
dm-snapshot-objs := dm-snap.o dm-exception-store.o
dm-mirror-objs := dm-log.o dm-raid1.o
raid6-objs := raid6main.o raid6algos.o raid6recov.o raid6tables.o \
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]