📄 dm-mpath.c
字号:
return 0;}struct arg_set { unsigned argc; char **argv;};static char *shift(struct arg_set *as){ char *r; if (as->argc) { as->argc--; r = *as->argv; as->argv++; return r; } return NULL;}static void consume(struct arg_set *as, unsigned n){ BUG_ON (as->argc < n); as->argc -= n; as->argv += n;}static int parse_path_selector(struct arg_set *as, struct priority_group *pg, struct dm_target *ti){ int r; struct path_selector_type *pst; unsigned ps_argc; static struct param _params[] = { {0, 1024, "invalid number of path selector args"}, }; pst = dm_get_path_selector(shift(as)); if (!pst) { ti->error = "unknown path selector type"; return -EINVAL; } r = read_param(_params, shift(as), &ps_argc, &ti->error); if (r) return -EINVAL; r = pst->create(&pg->ps, ps_argc, as->argv); if (r) { dm_put_path_selector(pst); ti->error = "path selector constructor failed"; return r; } pg->ps.type = pst; consume(as, ps_argc); return 0;}static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps, struct dm_target *ti){ int r; struct pgpath *p; /* we need at least a path arg */ if (as->argc < 1) { ti->error = "no device given"; return NULL; } p = alloc_pgpath(); if (!p) return NULL; r = dm_get_device(ti, shift(as), ti->begin, ti->len, dm_table_get_mode(ti->table), &p->path.dev); if (r) { ti->error = "error getting device"; goto bad; } r = ps->type->add_path(ps, &p->path, as->argc, as->argv, &ti->error); if (r) { dm_put_device(ti, p->path.dev); goto bad; } return p; bad: free_pgpath(p); return NULL;}static struct priority_group *parse_priority_group(struct arg_set *as, struct multipath *m){ static struct param _params[] = { {1, 1024, "invalid number of paths"}, {0, 1024, "invalid number of selector args"} }; int r; unsigned i, nr_selector_args, nr_params; struct priority_group *pg; struct dm_target *ti = m->ti; if (as->argc < 2) { as->argc = 0; ti->error = "not enough priority group aruments"; return NULL; } pg = alloc_priority_group(); if (!pg) { ti->error = "couldn't allocate priority group"; return NULL; } pg->m = m; r = parse_path_selector(as, pg, ti); if (r) goto bad; /* * read the paths */ r = read_param(_params, shift(as), &pg->nr_pgpaths, &ti->error); if (r) goto bad; r = read_param(_params + 1, shift(as), &nr_selector_args, &ti->error); if (r) goto bad; nr_params = 1 + nr_selector_args; for (i = 0; i < pg->nr_pgpaths; i++) { struct pgpath *pgpath; struct arg_set path_args; if (as->argc < nr_params) goto bad; path_args.argc = nr_params; path_args.argv = as->argv; pgpath = parse_path(&path_args, &pg->ps, ti); if (!pgpath) goto bad; pgpath->pg = pg; list_add_tail(&pgpath->list, &pg->pgpaths); consume(as, nr_params); } return pg; bad: free_priority_group(pg, ti); return NULL;}static int parse_hw_handler(struct arg_set *as, struct multipath *m){ int r; struct hw_handler_type *hwht; unsigned hw_argc; struct dm_target *ti = m->ti; static struct param _params[] = { {0, 1024, "invalid number of hardware handler args"}, }; r = read_param(_params, shift(as), &hw_argc, &ti->error); if (r) return -EINVAL; if (!hw_argc) return 0; hwht = dm_get_hw_handler(shift(as)); if (!hwht) { ti->error = "unknown hardware handler type"; return -EINVAL; } m->hw_handler.md = dm_table_get_md(ti->table); dm_put(m->hw_handler.md); r = hwht->create(&m->hw_handler, hw_argc - 1, as->argv); if (r) { dm_put_hw_handler(hwht); ti->error = "hardware handler constructor failed"; return r; } m->hw_handler.type = hwht; consume(as, hw_argc - 1); return 0;}static int parse_features(struct arg_set *as, struct multipath *m){ int r; unsigned argc; struct dm_target *ti = m->ti; const char *param_name; static struct param _params[] = { {0, 3, "invalid number of feature args"}, {1, 50, "pg_init_retries must be between 1 and 50"}, }; r = read_param(_params, shift(as), &argc, &ti->error); if (r) return -EINVAL; if (!argc) return 0; do { param_name = shift(as); argc--; if (!strnicmp(param_name, MESG_STR("queue_if_no_path"))) { r = queue_if_no_path(m, 1, 0); continue; } if (!strnicmp(param_name, MESG_STR("pg_init_retries")) && (argc >= 1)) { r = read_param(_params + 1, shift(as), &m->pg_init_retries, &ti->error); argc--; continue; } ti->error = "Unrecognised multipath feature request"; r = -EINVAL; } while (argc && !r); return r;}static int multipath_ctr(struct dm_target *ti, unsigned int argc, char **argv){ /* target parameters */ static struct param _params[] = { {1, 1024, "invalid number of priority groups"}, {1, 1024, "invalid initial priority group number"}, }; int r; struct multipath *m; struct arg_set as; unsigned pg_count = 0; unsigned next_pg_num; as.argc = argc; as.argv = argv; m = alloc_multipath(ti); if (!m) { ti->error = "can't allocate multipath"; return -EINVAL; } r = parse_features(&as, m); if (r) goto bad; r = parse_hw_handler(&as, m); if (r) goto bad; r = read_param(_params, shift(&as), &m->nr_priority_groups, &ti->error); if (r) goto bad; r = read_param(_params + 1, shift(&as), &next_pg_num, &ti->error); if (r) goto bad; /* parse the priority groups */ while (as.argc) { struct priority_group *pg; pg = parse_priority_group(&as, m); if (!pg) { r = -EINVAL; goto bad; } m->nr_valid_paths += pg->nr_pgpaths; list_add_tail(&pg->list, &m->priority_groups); pg_count++; pg->pg_num = pg_count; if (!--next_pg_num) m->next_pg = pg; } if (pg_count != m->nr_priority_groups) { ti->error = "priority group count mismatch"; r = -EINVAL; goto bad; } return 0; bad: free_multipath(m); return r;}static void multipath_dtr(struct dm_target *ti){ struct multipath *m = (struct multipath *) ti->private; flush_workqueue(kmultipathd); free_multipath(m);}/* * Map bios, recording original fields for later in case we have to resubmit */static int multipath_map(struct dm_target *ti, struct bio *bio, union map_info *map_context){ int r; struct dm_mpath_io *mpio; struct multipath *m = (struct multipath *) ti->private; mpio = mempool_alloc(m->mpio_pool, GFP_NOIO); dm_bio_record(&mpio->details, bio); map_context->ptr = mpio; bio->bi_rw |= (1 << BIO_RW_FAILFAST); r = map_io(m, bio, mpio, 0); if (r < 0 || r == DM_MAPIO_REQUEUE) mempool_free(mpio, m->mpio_pool); return r;}/* * Take a path out of use. */static int fail_path(struct pgpath *pgpath){ unsigned long flags; struct multipath *m = pgpath->pg->m; spin_lock_irqsave(&m->lock, flags); if (!pgpath->path.is_active) goto out; DMWARN("Failing path %s.", pgpath->path.dev->name); pgpath->pg->ps.type->fail_path(&pgpath->pg->ps, &pgpath->path); pgpath->path.is_active = 0; pgpath->fail_count++; m->nr_valid_paths--; if (pgpath == m->current_pgpath) m->current_pgpath = NULL; dm_path_uevent(DM_UEVENT_PATH_FAILED, m->ti, pgpath->path.dev->name, m->nr_valid_paths); queue_work(kmultipathd, &m->trigger_event);out: spin_unlock_irqrestore(&m->lock, flags); return 0;}/* * Reinstate a previously-failed path */static int reinstate_path(struct pgpath *pgpath){ int r = 0; unsigned long flags; struct multipath *m = pgpath->pg->m; spin_lock_irqsave(&m->lock, flags); if (pgpath->path.is_active) goto out; if (!pgpath->pg->ps.type) { DMWARN("Reinstate path not supported by path selector %s", pgpath->pg->ps.type->name); r = -EINVAL; goto out; } r = pgpath->pg->ps.type->reinstate_path(&pgpath->pg->ps, &pgpath->path); if (r) goto out; pgpath->path.is_active = 1; m->current_pgpath = NULL; if (!m->nr_valid_paths++ && m->queue_size) queue_work(kmultipathd, &m->process_queued_ios); dm_path_uevent(DM_UEVENT_PATH_REINSTATED, m->ti, pgpath->path.dev->name, m->nr_valid_paths); queue_work(kmultipathd, &m->trigger_event);out: spin_unlock_irqrestore(&m->lock, flags); return r;}/* * Fail or reinstate all paths that match the provided struct dm_dev. */static int action_dev(struct multipath *m, struct dm_dev *dev, action_fn action){ int r = 0; struct pgpath *pgpath; struct priority_group *pg; list_for_each_entry(pg, &m->priority_groups, list) { list_for_each_entry(pgpath, &pg->pgpaths, list) { if (pgpath->path.dev == dev) r = action(pgpath); } } return r;}/* * Temporarily try to avoid having to use the specified PG */static void bypass_pg(struct multipath *m, struct priority_group *pg, int bypassed){ unsigned long flags; spin_lock_irqsave(&m->lock, flags); pg->bypassed = bypassed; m->current_pgpath = NULL; m->current_pg = NULL; spin_unlock_irqrestore(&m->lock, flags); queue_work(kmultipathd, &m->trigger_event);}/* * Switch to using the specified PG from the next I/O that gets mapped */static int switch_pg_num(struct multipath *m, const char *pgstr){ struct priority_group *pg; unsigned pgnum; unsigned long flags; if (!pgstr || (sscanf(pgstr, "%u", &pgnum) != 1) || !pgnum || (pgnum > m->nr_priority_groups)) { DMWARN("invalid PG number supplied to switch_pg_num"); return -EINVAL; } spin_lock_irqsave(&m->lock, flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -