⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dm-mpath.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (C) 2003 Sistina Software Limited. * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. * * This file is released under the GPL. */#include "dm.h"#include "dm-path-selector.h"#include "dm-hw-handler.h"#include "dm-bio-list.h"#include "dm-bio-record.h"#include "dm-uevent.h"#include <linux/ctype.h>#include <linux/init.h>#include <linux/mempool.h>#include <linux/module.h>#include <linux/pagemap.h>#include <linux/slab.h>#include <linux/time.h>#include <linux/workqueue.h>#include <asm/atomic.h>#define DM_MSG_PREFIX "multipath"#define MESG_STR(x) x, sizeof(x)/* Path properties */struct pgpath {	struct list_head list;	struct priority_group *pg;	/* Owning PG */	unsigned fail_count;		/* Cumulative failure count */	struct dm_path path;};#define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path)/* * Paths are grouped into Priority Groups and numbered from 1 upwards. * Each has a path selector which controls which path gets used. */struct priority_group {	struct list_head list;	struct multipath *m;		/* Owning multipath instance */	struct path_selector ps;	unsigned pg_num;		/* Reference number */	unsigned bypassed;		/* Temporarily bypass this PG? */	unsigned nr_pgpaths;		/* Number of paths in PG */	struct list_head pgpaths;};/* Multipath context */struct multipath {	struct list_head list;	struct dm_target *ti;	spinlock_t lock;	struct hw_handler hw_handler;	unsigned nr_priority_groups;	struct list_head priority_groups;	unsigned pg_init_required;	/* pg_init needs calling? */	unsigned pg_init_in_progress;	/* Only one pg_init allowed at once */	unsigned nr_valid_paths;	/* Total number of usable paths */	struct pgpath *current_pgpath;	struct priority_group *current_pg;	struct priority_group *next_pg;	/* Switch to this PG if set */	unsigned repeat_count;		/* I/Os left before calling PS again */	unsigned queue_io;		/* Must we queue all I/O? */	unsigned queue_if_no_path;	/* Queue I/O if last path fails? */	unsigned saved_queue_if_no_path;/* Saved state during suspension */	unsigned pg_init_retries;	/* Number of times to retry pg_init */	unsigned pg_init_count;		/* Number of times pg_init called */	struct work_struct process_queued_ios;	struct bio_list queued_ios;	unsigned queue_size;	struct work_struct trigger_event;	/*	 * We must use a mempool of dm_mpath_io structs so that we	 * can resubmit bios on error.	 */	mempool_t *mpio_pool;};/* * Context information attached to each bio we process. */struct dm_mpath_io {	struct pgpath *pgpath;	struct dm_bio_details details;};typedef int (*action_fn) (struct pgpath *pgpath);#define MIN_IOS 256	/* Mempool size */static struct kmem_cache *_mpio_cache;struct workqueue_struct *kmultipathd;static void process_queued_ios(struct work_struct *work);static void trigger_event(struct work_struct *work);/*----------------------------------------------- * Allocation routines *-----------------------------------------------*/static struct pgpath *alloc_pgpath(void){	struct pgpath *pgpath = kzalloc(sizeof(*pgpath), GFP_KERNEL);	if (pgpath)		pgpath->path.is_active = 1;	return pgpath;}static void free_pgpath(struct pgpath *pgpath){	kfree(pgpath);}static struct priority_group *alloc_priority_group(void){	struct priority_group *pg;	pg = kzalloc(sizeof(*pg), GFP_KERNEL);	if (pg)		INIT_LIST_HEAD(&pg->pgpaths);	return pg;}static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti){	struct pgpath *pgpath, *tmp;	list_for_each_entry_safe(pgpath, tmp, pgpaths, list) {		list_del(&pgpath->list);		dm_put_device(ti, pgpath->path.dev);		free_pgpath(pgpath);	}}static void free_priority_group(struct priority_group *pg,				struct dm_target *ti){	struct path_selector *ps = &pg->ps;	if (ps->type) {		ps->type->destroy(ps);		dm_put_path_selector(ps->type);	}	free_pgpaths(&pg->pgpaths, ti);	kfree(pg);}static struct multipath *alloc_multipath(struct dm_target *ti){	struct multipath *m;	m = kzalloc(sizeof(*m), GFP_KERNEL);	if (m) {		INIT_LIST_HEAD(&m->priority_groups);		spin_lock_init(&m->lock);		m->queue_io = 1;		INIT_WORK(&m->process_queued_ios, process_queued_ios);		INIT_WORK(&m->trigger_event, trigger_event);		m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache);		if (!m->mpio_pool) {			kfree(m);			return NULL;		}		m->ti = ti;		ti->private = m;	}	return m;}static void free_multipath(struct multipath *m){	struct priority_group *pg, *tmp;	struct hw_handler *hwh = &m->hw_handler;	list_for_each_entry_safe(pg, tmp, &m->priority_groups, list) {		list_del(&pg->list);		free_priority_group(pg, m->ti);	}	if (hwh->type) {		hwh->type->destroy(hwh);		dm_put_hw_handler(hwh->type);	}	mempool_destroy(m->mpio_pool);	kfree(m);}/*----------------------------------------------- * Path selection *-----------------------------------------------*/static void __switch_pg(struct multipath *m, struct pgpath *pgpath){	struct hw_handler *hwh = &m->hw_handler;	m->current_pg = pgpath->pg;	/* Must we initialise the PG first, and queue I/O till it's ready? */	if (hwh->type && hwh->type->pg_init) {		m->pg_init_required = 1;		m->queue_io = 1;	} else {		m->pg_init_required = 0;		m->queue_io = 0;	}	m->pg_init_count = 0;}static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg){	struct dm_path *path;	path = pg->ps.type->select_path(&pg->ps, &m->repeat_count);	if (!path)		return -ENXIO;	m->current_pgpath = path_to_pgpath(path);	if (m->current_pg != pg)		__switch_pg(m, m->current_pgpath);	return 0;}static void __choose_pgpath(struct multipath *m){	struct priority_group *pg;	unsigned bypassed = 1;	if (!m->nr_valid_paths)		goto failed;	/* Were we instructed to switch PG? */	if (m->next_pg) {		pg = m->next_pg;		m->next_pg = NULL;		if (!__choose_path_in_pg(m, pg))			return;	}	/* Don't change PG until it has no remaining paths */	if (m->current_pg && !__choose_path_in_pg(m, m->current_pg))		return;	/*	 * Loop through priority groups until we find a valid path.	 * First time we skip PGs marked 'bypassed'.	 * Second time we only try the ones we skipped.	 */	do {		list_for_each_entry(pg, &m->priority_groups, list) {			if (pg->bypassed == bypassed)				continue;			if (!__choose_path_in_pg(m, pg))				return;		}	} while (bypassed--);failed:	m->current_pgpath = NULL;	m->current_pg = NULL;}/* * Check whether bios must be queued in the device-mapper core rather * than here in the target. * * m->lock must be held on entry. * * If m->queue_if_no_path and m->saved_queue_if_no_path hold the * same value then we are not between multipath_presuspend() * and multipath_resume() calls and we have no need to check * for the DMF_NOFLUSH_SUSPENDING flag. */static int __must_push_back(struct multipath *m){	return (m->queue_if_no_path != m->saved_queue_if_no_path &&		dm_noflush_suspending(m->ti));}static int map_io(struct multipath *m, struct bio *bio,		  struct dm_mpath_io *mpio, unsigned was_queued){	int r = DM_MAPIO_REMAPPED;	unsigned long flags;	struct pgpath *pgpath;	spin_lock_irqsave(&m->lock, flags);	/* Do we need to select a new pgpath? */	if (!m->current_pgpath ||	    (!m->queue_io && (m->repeat_count && --m->repeat_count == 0)))		__choose_pgpath(m);	pgpath = m->current_pgpath;	if (was_queued)		m->queue_size--;	if ((pgpath && m->queue_io) ||	    (!pgpath && m->queue_if_no_path)) {		/* Queue for the daemon to resubmit */		bio_list_add(&m->queued_ios, bio);		m->queue_size++;		if ((m->pg_init_required && !m->pg_init_in_progress) ||		    !m->queue_io)			queue_work(kmultipathd, &m->process_queued_ios);		pgpath = NULL;		r = DM_MAPIO_SUBMITTED;	} else if (pgpath)		bio->bi_bdev = pgpath->path.dev->bdev;	else if (__must_push_back(m))		r = DM_MAPIO_REQUEUE;	else		r = -EIO;	/* Failed */	mpio->pgpath = pgpath;	spin_unlock_irqrestore(&m->lock, flags);	return r;}/* * If we run out of usable paths, should we queue I/O or error it? */static int queue_if_no_path(struct multipath *m, unsigned queue_if_no_path,			    unsigned save_old_value){	unsigned long flags;	spin_lock_irqsave(&m->lock, flags);	if (save_old_value)		m->saved_queue_if_no_path = m->queue_if_no_path;	else		m->saved_queue_if_no_path = queue_if_no_path;	m->queue_if_no_path = queue_if_no_path;	if (!m->queue_if_no_path && m->queue_size)		queue_work(kmultipathd, &m->process_queued_ios);	spin_unlock_irqrestore(&m->lock, flags);	return 0;}/*----------------------------------------------------------------- * The multipath daemon is responsible for resubmitting queued ios. *---------------------------------------------------------------*/static void dispatch_queued_ios(struct multipath *m){	int r;	unsigned long flags;	struct bio *bio = NULL, *next;	struct dm_mpath_io *mpio;	union map_info *info;	spin_lock_irqsave(&m->lock, flags);	bio = bio_list_get(&m->queued_ios);	spin_unlock_irqrestore(&m->lock, flags);	while (bio) {		next = bio->bi_next;		bio->bi_next = NULL;		info = dm_get_mapinfo(bio);		mpio = info->ptr;		r = map_io(m, bio, mpio, 1);		if (r < 0)			bio_endio(bio, r);		else if (r == DM_MAPIO_REMAPPED)			generic_make_request(bio);		else if (r == DM_MAPIO_REQUEUE)			bio_endio(bio, -EIO);		bio = next;	}}static void process_queued_ios(struct work_struct *work){	struct multipath *m =		container_of(work, struct multipath, process_queued_ios);	struct hw_handler *hwh = &m->hw_handler;	struct pgpath *pgpath = NULL;	unsigned init_required = 0, must_queue = 1;	unsigned long flags;	spin_lock_irqsave(&m->lock, flags);	if (!m->queue_size)		goto out;	if (!m->current_pgpath)		__choose_pgpath(m);	pgpath = m->current_pgpath;	if ((pgpath && !m->queue_io) ||	    (!pgpath && !m->queue_if_no_path))		must_queue = 0;	if (m->pg_init_required && !m->pg_init_in_progress) {		m->pg_init_count++;		m->pg_init_required = 0;		m->pg_init_in_progress = 1;		init_required = 1;	}out:	spin_unlock_irqrestore(&m->lock, flags);	if (init_required)		hwh->type->pg_init(hwh, pgpath->pg->bypassed, &pgpath->path);	if (!must_queue)		dispatch_queued_ios(m);}/* * An event is triggered whenever a path is taken out of use. * Includes path failure and PG bypass. */static void trigger_event(struct work_struct *work){	struct multipath *m =		container_of(work, struct multipath, trigger_event);	dm_table_event(m->ti->table);}/*----------------------------------------------------------------- * Constructor/argument parsing: * <#multipath feature args> [<arg>]* * <#hw_handler args> [hw_handler [<arg>]*] * <#priority groups> * <initial priority group> *     [<selector> <#selector args> [<arg>]* *      <#paths> <#per-path selector args> *         [<path> [<arg>]* ]+ ]+ *---------------------------------------------------------------*/struct param {	unsigned min;	unsigned max;	char *error;};static int read_param(struct param *param, char *str, unsigned *v, char **error){	if (!str ||	    (sscanf(str, "%u", v) != 1) ||	    (*v < param->min) ||	    (*v > param->max)) {		*error = param->error;		return -EINVAL;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -