[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




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]