[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
[dm-devel] [PATCH RFC 7/5] add support for manual failover devices
- From: Mike Christie <michaelc cs wisc edu>
- To: dm-devel redhat com, Joe Thornber <thornber redhat com>
- Cc:
- Subject: [dm-devel] [PATCH RFC 7/5] add support for manual failover devices
- Date: Tue, 06 Apr 2004 03:22:44 -0700
rdac-test-support.patch - this is just an example of what needs to
be done by the ps to send a failover command to the device. This
example is just sending a TUR, and I just bascially ripped off the
rr ps's other functions.
diff -Naurp linux-2.6.5-rc1-udm1-orig/drivers/md/Kconfig linux-2.6.5-rc1-udm1-work/drivers/md/Kconfig
--- linux-2.6.5-rc1-udm1-orig/drivers/md/Kconfig 2004-04-02 01:24:19.000000000 -0800
+++ linux-2.6.5-rc1-udm1-work/drivers/md/Kconfig 2004-04-04 12:23:56.607842249 -0700
@@ -186,6 +186,12 @@ config DM_MULTIPATH
---help---
Allow volume managers to support multipath hardware.
+config DM_RDAC
+ tristate "IBM FAStT RDAC/AVT (EXPERIMENTAL)"
+ depends on BLK_DEV_DM && DM_MULTIPATH && EXPERIMENTAL
+ ---help---
+ IBM FAStT RDAC/AVT support for DM Multipath.
+
config DM_SNAPSHOT
tristate "Snapshot target (EXPERIMENTAL)"
depends on BLK_DEV_DM && EXPERIMENTAL
diff -Naurp linux-2.6.5-rc1-udm1-orig/drivers/md/Makefile linux-2.6.5-rc1-udm1-work/drivers/md/Makefile
--- linux-2.6.5-rc1-udm1-orig/drivers/md/Makefile 2004-04-02 01:24:19.000000000 -0800
+++ linux-2.6.5-rc1-udm1-work/drivers/md/Makefile 2004-04-04 12:23:51.382707192 -0700
@@ -28,6 +28,7 @@ obj-$(CONFIG_BLK_DEV_MD) += md.o
obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o
obj-$(CONFIG_DM_CRYPT) += dm-crypt.o
obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o
+obj-$(CONFIG_DM_RDAC) += rdac.o
obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o
obj-$(CONFIG_DM_MIRROR) += dm-mirror.o
obj-$(CONFIG_DM_ZERO) += dm-zero.o
diff -Naurp linux-2.6.5-rc1-udm1-orig/drivers/md/rdac.c linux-2.6.5-rc1-udm1-work/drivers/md/rdac.c
--- linux-2.6.5-rc1-udm1-orig/drivers/md/rdac.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.5-rc1-udm1-work/drivers/md/rdac.c 2004-04-04 12:23:43.496010731 -0700
@@ -0,0 +1,292 @@
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "dm.h"
+#include "dm-path-selector.h"
+
+struct path_info {
+ struct list_head list;
+ struct path *path;
+
+ unsigned fail_count;
+};
+
+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;
+}
+
+/* FIXME: get rid of this */
+#define MPATH_FAIL_COUNT 1
+
+/* Failover modes */
+enum {
+ NONE,
+ AVT,
+ RDAC,
+};
+
+struct selector {
+ spinlock_t path_lock;
+
+ struct list_head active_paths;
+ struct list_head failed_paths;
+
+ int failover;
+};
+
+static struct selector *alloc_selector(void)
+{
+ struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+ if (s) {
+ INIT_LIST_HEAD(&s->active_paths);
+ INIT_LIST_HEAD(&s->failed_paths);
+ s->path_lock = SPIN_LOCK_UNLOCKED;
+ /*
+ * TODO modify arg passing.
+ */
+ s->failover = RDAC;
+ }
+
+ return s;
+}
+
+static int rdac_ctr(struct path_selector *ps)
+{
+ struct selector *s;
+
+ s = alloc_selector();
+ if (!s)
+ return -ENOMEM;
+
+ ps->context = s;
+ 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 rdac_dtr(struct path_selector *ps)
+{
+ struct selector *s = (struct selector *) ps->context;
+ free_paths(&s->active_paths);
+ free_paths(&s->failed_paths);
+ kfree(s);
+}
+
+static int send_failover_cmd(struct block_device *bdev)
+{
+ struct request *rq;
+ request_queue_t *q = bdev_get_queue(bdev);
+ struct gendisk *bd_disk = bdev->bd_contains->bd_disk;
+ int err;
+ /* tmp test */
+ char sense[SCSI_SENSE_BUFFERSIZE];
+ static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
+
+ printk (KERN_ERR "get_request\n");
+
+ if (!q)
+ return -EPERM;
+
+ rq = blk_get_request(q, READ, __GFP_WAIT);
+
+ printk (KERN_ERR "got it\n");
+
+
+ memcpy(rq->cmd, tur_command, sizeof(tur_command));
+ rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
+
+ memset(sense, 0, sizeof(sense));
+ rq->sense = sense;
+ rq->sense_len = 0;
+
+ rq->data = NULL;
+ rq->data_len = 0;
+
+// rq->data = buffer;
+// rq->data_len = bytes;
+ rq->flags |= REQ_BLOCK_PC;
+
+ printk (KERN_ERR "sending\n");
+
+ err = blk_execute_rq(q, bd_disk, rq);
+ if (rq->errors)
+ printk(KERN_ERR "send_failover_cmd failed\n");
+ else
+ printk(KERN_ERR "send_failover_cmd succeeded\n");
+ blk_put_request(rq);
+
+ return err;
+}
+
+static int rdac_init(struct path_selector *ps)
+{
+ struct selector *s = (struct selector *) ps->context;
+ struct path_info *pi;
+
+ if (s->failover != RDAC)
+ return 0;
+
+ /*
+ * This is called before any IO has been sent to
+ * these paths and after all paths have been added,
+ * so we do not need to hold the path lock.
+ */
+ while (!list_empty(&s->active_paths)) {
+ pi = list_entry(s->active_paths.next, struct path_info, list);
+
+ if (!send_failover_cmd(dm_path_to_bdev(pi->path)))
+ return 0;
+ else
+ list_move(&pi->list, &s->failed_paths);
+ }
+
+ return -EPERM;
+}
+
+static int rdac_add_path(struct path_selector *ps, struct path *path,
+ int argc, char **argv, char **error)
+{
+ struct selector *s = (struct selector *) ps->context;
+ struct path_info *pi;
+
+ /* parse the path arguments */
+ if (argc != 0) {
+ *error = "rdac ps: incorrect number of arguments";
+ return -EINVAL;
+ }
+
+ /* allocate the path */
+ pi = kmalloc(sizeof(*pi), GFP_KERNEL);
+ if (!pi) {
+ *error = "rdac ps: Error allocating path context";
+ return -ENOMEM;
+ }
+
+ pi->fail_count = MPATH_FAIL_COUNT;
+ pi->path = path;
+
+ spin_lock(&s->path_lock);
+ list_add(&pi->list, &s->active_paths);
+ spin_unlock(&s->path_lock);
+
+ return 0;
+}
+
+static void rdac_update_path(struct path_selector *ps, struct path *p,
+ int error)
+{
+ unsigned long flags;
+ struct selector *s = (struct selector *) ps->context;
+ struct path_info *pi;
+
+ /*
+ * This function will be called infrequently so we don't
+ * mind the expense of these searches.
+ */
+ spin_lock_irqsave(&s->path_lock, flags);
+
+ pi = path_lookup(&s->active_paths, p);
+ if (pi && !--pi->fail_count)
+ list_move(&pi->list, &s->failed_paths);
+
+ spin_unlock_irqrestore(&s->path_lock, flags);
+}
+
+static struct path *rdac_select_path(struct path_selector *ps)
+{
+ unsigned long flags;
+ struct selector *s = (struct selector *) ps->context;
+ struct path_info *pi = NULL;
+
+ spin_lock_irqsave(&s->path_lock, flags);
+ if (!list_empty(&s->active_paths)) {
+ pi = list_entry(s->active_paths.next, struct path_info, list);
+ list_move_tail(&pi->list, &s->active_paths);
+ }
+ spin_unlock_irqrestore(&s->path_lock, flags);
+
+ return pi ? pi->path : NULL;
+}
+
+static int rdac_status(struct path_selector *ps, struct path *path,
+ status_type_t type, char *result, unsigned int maxlen)
+{
+ unsigned long flags;
+ struct path_info *pi;
+ int failed = 0;
+ struct selector *s = (struct selector *) ps->context;
+ int sz = 0;
+
+ if (type == STATUSTYPE_TABLE)
+ return 0;
+
+ spin_lock_irqsave(&s->path_lock, flags);
+
+ /*
+ * Is status called often for testing or something?
+ * If so maybe a ps's info should be allocated w/ path
+ * so a simple container_of can be used.
+ */
+ pi = path_lookup(&s->active_paths, path);
+ if (!pi) {
+ failed = 1;
+ pi = path_lookup(&s->failed_paths, path);
+ }
+
+ sz = scnprintf(result, maxlen, "%s %u ", failed ? "F" : "A",
+ pi->fail_count);
+
+ spin_unlock_irqrestore(&s->path_lock, flags);
+
+ return sz;
+}
+
+static struct path_selector_type rdac_ps = {
+ .name = "rdac",
+ .ctr = rdac_ctr,
+ .init = rdac_init,
+ .dtr = rdac_dtr,
+ .add_path = rdac_add_path,
+ .update_path = rdac_update_path,
+ .select_path = rdac_select_path,
+ .status = rdac_status,
+};
+
+int __init init_rdac(void)
+{
+ return dm_register_path_selector(&rdac_ps);
+}
+
+void __exit exit_rdac(void)
+{
+ dm_unregister_path_selector(&rdac_ps);
+}
+
+module_init(init_rdac);
+module_exit(exit_rdac);
+
+MODULE_DESCRIPTION("RDAC/AVT Path Selector");
+MODULE_AUTHOR("Mike Christie");
+MODULE_LICENSE("GPL");
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]