Commit 8f494a80 authored by Alasdair G. Kergon's avatar Alasdair G. Kergon Committed by Linus Torvalds

[PATCH] device-mapper: multipath

The core device-mapper multipath and path-selector code.

Paths are grouped into an ordered list of Priority Groups.  Each Priority
Group has a Path Selector which chooses which of the Priority Group's paths is
to be used for each bio e.g.  according to some load-balancing algorithm.  If
a bio generates an error, the path that it used gets disabled and an
alternative path is tried.  If all the paths in a Priority Group fail, another
Priority Group is selected.

There are management commands fail_path and reinstate_path.  A path tester
(currently implemented in userspace) is responsible for monitoring paths that
have failed and reinstating them should they come back.

Other management commands can be use to switch immediately to a specified
Priority Group or to disable a particular Priority Group so it will only be
tried after there are no more left.

As a last resort there is an option to 'queue_if_no_path' which queues I/O if
all paths have failed e.g.  temporarily during a firmware update or if the
userspace daemon is slow reinstating paths.

The userspace multipath tools are available at:
  http://christophe.varoqui.free.fr/
macroflux.png is a diagram of the current architecture.

From: Alasdair G Kergon <agk@redhat.com>

  Don't requeue I/O repeatedly if there are no paths left and the device is
  in the process of being suspended, or else the suspend can never complete.
Reported-By: default avatar"goggin, edward" <egoggin@emc.com>
Signed-Off-By: default avatarAlasdair G Kergon <agk@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 0296e494
......@@ -227,5 +227,11 @@ config DM_ZERO
A target that discards writes, and returns all zeroes for
reads. Useful in some recovery situations.
config DM_MULTIPATH
tristate "Multipath target (EXPERIMENTAL)"
depends on BLK_DEV_DM && EXPERIMENTAL
---help---
Allow volume managers to support multipath hardware.
endmenu
......@@ -4,6 +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-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 \
......@@ -30,6 +31,7 @@ obj-$(CONFIG_MD_FAULTY) += faulty.o
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_SNAPSHOT) += dm-snapshot.o
obj-$(CONFIG_DM_MIRROR) += dm-mirror.o
obj-$(CONFIG_DM_ZERO) += dm-zero.o
......
This diff is collapsed.
/*
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is released under the GPL.
*
* Multipath.
*/
#ifndef DM_MPATH_H
#define DM_MPATH_H
#include <linux/device-mapper.h>
struct path {
struct dm_dev *dev; /* Read-only */
unsigned is_active; /* Read-only */
void *pscontext; /* For path-selector use */
};
#endif
/*
* Copyright (C) 2003 Sistina Software.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* Module Author: Heinz Mauelshagen
*
* This file is released under the GPL.
*
* Path selector registration.
*/
#include "dm.h"
#include "dm-path-selector.h"
#include <linux/slab.h>
struct ps_internal {
struct path_selector_type pst;
struct list_head list;
long use;
};
#define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst)
static LIST_HEAD(_path_selectors);
static DECLARE_RWSEM(_ps_lock);
struct ps_internal *__find_path_selector_type(const char *name)
{
struct ps_internal *psi;
list_for_each_entry (psi, &_path_selectors, list) {
if (!strcmp(name, psi->pst.name))
return psi;
}
return NULL;
}
static struct ps_internal *get_path_selector(const char *name)
{
struct ps_internal *psi;
down_read(&_ps_lock);
psi = __find_path_selector_type(name);
if (psi) {
if ((psi->use == 0) && !try_module_get(psi->pst.module))
psi = NULL;
else
psi->use++;
}
up_read(&_ps_lock);
return psi;
}
struct path_selector_type *dm_get_path_selector(const char *name)
{
struct ps_internal *psi;
if (!name)
return NULL;
psi = get_path_selector(name);
if (!psi) {
request_module("dm-%s", name);
psi = get_path_selector(name);
}
return psi ? &psi->pst : NULL;
}
void dm_put_path_selector(struct path_selector_type *pst)
{
struct ps_internal *psi;
if (!pst)
return;
down_read(&_ps_lock);
psi = __find_path_selector_type(pst->name);
if (!psi)
goto out;
if (--psi->use == 0)
module_put(psi->pst.module);
if (psi->use < 0)
BUG();
out:
up_read(&_ps_lock);
}
static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst)
{
struct ps_internal *psi = kmalloc(sizeof(*psi), GFP_KERNEL);
if (psi) {
memset(psi, 0, sizeof(*psi));
psi->pst = *pst;
}
return psi;
}
int dm_register_path_selector(struct path_selector_type *pst)
{
int r = 0;
struct ps_internal *psi = _alloc_path_selector(pst);
if (!psi)
return -ENOMEM;
down_write(&_ps_lock);
if (__find_path_selector_type(pst->name)) {
kfree(psi);
r = -EEXIST;
} else
list_add(&psi->list, &_path_selectors);
up_write(&_ps_lock);
return r;
}
int dm_unregister_path_selector(struct path_selector_type *pst)
{
struct ps_internal *psi;
down_write(&_ps_lock);
psi = __find_path_selector_type(pst->name);
if (!psi) {
up_write(&_ps_lock);
return -EINVAL;
}
if (psi->use) {
up_write(&_ps_lock);
return -ETXTBSY;
}
list_del(&psi->list);
up_write(&_ps_lock);
kfree(psi);
return 0;
}
EXPORT_SYMBOL(dm_register_path_selector);
EXPORT_SYMBOL(dm_unregister_path_selector);
/*
* Copyright (C) 2003 Sistina Software.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* Module Author: Heinz Mauelshagen
*
* This file is released under the GPL.
*
* Path-Selector registration.
*/
#ifndef DM_PATH_SELECTOR_H
#define DM_PATH_SELECTOR_H
#include <linux/device-mapper.h>
#include "dm-mpath.h"
/*
* We provide an abstraction for the code that chooses which path
* to send some io down.
*/
struct path_selector_type;
struct path_selector {
struct path_selector_type *type;
void *context;
};
/*
* Constructs a path selector object, takes custom arguments
*/
typedef int (*ps_ctr_fn) (struct path_selector *ps, unsigned argc, char **argv);
typedef void (*ps_dtr_fn) (struct path_selector *ps);
/*
* Add an opaque path object, along with some selector specific
* path args (eg, path priority).
*/
typedef int (*ps_add_path_fn) (struct path_selector *ps, struct path *path,
int argc, char **argv, char **error);
/*
* Chooses a path for this io, if no paths are available then
* NULL will be returned.
*
* repeat_count is the number of times to use the path before
* calling the function again. 0 means don't call it again unless
* the path fails.
*/
typedef struct path *(*ps_select_path_fn) (struct path_selector *ps,
unsigned *repeat_count);
/*
* Notify the selector that a path has failed.
*/
typedef void (*ps_fail_path_fn) (struct path_selector *ps,
struct path *p);
/*
* Ask selector to reinstate a path.
*/
typedef int (*ps_reinstate_path_fn) (struct path_selector *ps,
struct path *p);
/*
* Table content based on parameters added in ps_add_path_fn
* or path selector status
*/
typedef int (*ps_status_fn) (struct path_selector *ps,
struct path *path,
status_type_t type,
char *result, unsigned int maxlen);
typedef int (*ps_end_io_fn) (struct path_selector *ps, struct path *path);
/* Information about a path selector type */
struct path_selector_type {
char *name;
struct module *module;
unsigned int table_args;
unsigned int info_args;
ps_ctr_fn ctr;
ps_dtr_fn dtr;
ps_add_path_fn add_path;
ps_fail_path_fn fail_path;
ps_reinstate_path_fn reinstate_path;
ps_select_path_fn select_path;
ps_status_fn status;
ps_end_io_fn end_io;
};
/* Register a path selector */
int dm_register_path_selector(struct path_selector_type *type);
/* Unregister a path selector */
int dm_unregister_path_selector(struct path_selector_type *type);
/* Returns a registered path selector type */
struct path_selector_type *dm_get_path_selector(const char *name);
/* Releases a path selector */
void dm_put_path_selector(struct path_selector_type *pst);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment