/* * hp_sw_end_io - Completion handler for HP path activation. * @req: path activation request * @error: scsi-ml error * * Check sense data, free request structure, and notify dm that * pg initialization has completed. * * Context: scsi-ml softirq * */ static void hp_sw_end_io(struct request *req, int error) { struct dm_path *path = req->end_io_data; unsigned err_flags = 0; if (!error) { DMDEBUG("%s path activation command - success", path->dev->name); goto out; } if (hp_sw_error_is_retryable(req)) { DMDEBUG("%s path activation command - retry", path->dev->name); err_flags = MP_RETRY; goto out; } DMWARN("%s path activation fail - error=0x%x", path->dev->name, error); err_flags = MP_FAIL_PATH; out: req->end_io_data = NULL; __blk_put_request(req->q, req); dm_pg_init_complete(path, err_flags); }
static void __init dm_substitute_devices(char *str, size_t str_len) { char *candidate = str; char *candidate_end = str; char old_char; size_t len = 0; dev_t dev; if (str_len < 3) return; while (str && *str) { candidate = strchr(str, '/'); if (!candidate) break; /* Avoid embedded slashes */ if (candidate != str && *(candidate - 1) != DM_FIELD_SEP) { str = strchr(candidate, DM_FIELD_SEP); continue; } len = get_dm_option(candidate, &candidate_end, DM_FIELD_SEP); str = skip_spaces(candidate_end); if (len < 3 || len > 37) /* name_to_dev_t max; maj:mix min */ continue; /* Temporarily terminate with a nul */ candidate_end--; old_char = *candidate_end; *candidate_end = '\0'; DMDEBUG("converting candidate device '%s' to dev_t", candidate); /* Use the boot-time specific device naming */ dev = name_to_dev_t(candidate); *candidate_end = old_char; DMDEBUG(" -> %u", dev); /* No suitable replacement found */ if (!dev) continue; /* Rewrite the /dev/path as a major:minor */ len = snprintf(candidate, len, "%u:%u", MAJOR(dev), MINOR(dev)); if (!len) { DMERR("error substituting device major/minor."); break; } candidate += len; /* Pad out with spaces (fixing our nul) */ while (candidate < candidate_end) *(candidate++) = DM_FIELD_SEP; } }
/* get_boot_dev is bassed on dm_get_device_by_uuid in dm_bootcache. */ static dev_t get_boot_dev(void) { const char partuuid[] = "PARTUUID="; char uuid[2 * sizeof(partuuid) + 36]; /* Room for 2 PARTUUIDs */ char *uuid_str; dev_t devt = 0; uuid_str = get_info_from_cmdline(" kern_guid=", &uuid[sizeof(partuuid) - 1], sizeof(uuid) - sizeof(partuuid)); if (!uuid_str) { DMERR("Couldn't get uuid, try root dev"); return 0; } if (strncmp(uuid_str, partuuid, strlen(partuuid)) != 0) { /* Not prefixed with "PARTUUID=", so add it */ memcpy(uuid, partuuid, sizeof(partuuid) - 1); uuid_str = uuid; } devt = name_to_dev_t(uuid_str); if (!devt) goto found_nothing; return devt; found_nothing: DMDEBUG("No matching partition for GUID: %s", uuid_str); return 0; }
static int __init dm_setup(char *str) { dm_setup_args_init(); str = dm_setup_parse_device_args(str); if (!str) { DMDEBUG("str is NULL"); goto parse_fail; } /* Target parsing is delayed until we have dynamic memory */ dm_setup_args.targets = str; printk(KERN_INFO "dm: will configure '%s' on dm-%d\n", dm_setup_args.name, dm_setup_args.minor); dm_early_setup = 1; return 1; parse_fail: printk(KERN_WARNING "dm: Invalid arguments supplied to dm=.\n"); return 0; }
/* * hp_sw_pg_init - HP path activation implementation. * @hwh: hardware handler specific data * @bypassed: unused; is the path group bypassed? (see dm-mpath.c) * @path: path to send initialization command * * Send an HP-specific path activation command on 'path'. * Do not try to optimize in any way, just send the activation command. * More than one path activation command may be sent to the same controller. * This seems to work fine for basic failover support. * * Possible optimizations * 1. Detect an in-progress activation request and avoid submitting another one * 2. Model the controller and only send a single activation request at a time * 3. Determine the state of a path before sending an activation request * * Context: kmpathd (see process_queued_ios() in dm-mpath.c) */ static void hp_sw_pg_init(struct hw_handler *hwh, unsigned bypassed, struct dm_path *path) { struct request *req; struct hp_sw_context *h; path->hwhcontext = hwh->context; h = hwh->context; req = hp_sw_get_request(path); if (!req) { DMERR("%s path activation command - allocation fail", path->dev->name); goto retry; } DMDEBUG("%s path activation command - sent", path->dev->name); blk_execute_rq_nowait(req->q, NULL, req, 1, hp_sw_end_io); return; retry: dm_pg_init_complete(path, MP_RETRY); }
static void __init dm_setup_drive(void) { struct mapped_device *md = NULL; struct dm_table *table = NULL; struct dm_setup_target *target; char *uuid = dm_setup_args.uuid; fmode_t fmode = FMODE_READ; /* Finish parsing the targets. */ if (dm_setup_parse_targets(dm_setup_args.targets)) goto parse_fail; if (dm_create(dm_setup_args.minor, &md)) { DMDEBUG("failed to create the device"); goto dm_create_fail; } DMDEBUG("created device '%s'", dm_device_name(md)); /* In addition to flagging the table below, the disk must be * set explicitly ro/rw. */ set_disk_ro(dm_disk(md), dm_setup_args.ro); if (!dm_setup_args.ro) fmode |= FMODE_WRITE; if (dm_table_create(&table, fmode, dm_setup_args.target_count, md)) { DMDEBUG("failed to create the table"); goto dm_table_create_fail; } target = dm_setup_args.target; while (target) { DMINFO("adding target '%llu %llu %s %s'", (unsigned long long) target->begin, (unsigned long long) target->length, target->type, target->params); if (dm_table_add_target(table, target->type, target->begin, target->length, target->params)) { DMDEBUG("failed to add the target to the table"); goto add_target_fail; } target = target->next; } if (dm_table_complete(table)) { DMDEBUG("failed to complete the table"); goto table_complete_fail; } /* Suspend the device so that we can bind it to the table. */ if (dm_suspend(md, 0)) { DMDEBUG("failed to suspend the device pre-bind"); goto suspend_fail; } /* Bind the table to the device. This is the only way to associate * md->map with the table and set the disk capacity directly. */ if (dm_swap_table(md, table)) { /* should return NULL. */ DMDEBUG("failed to bind the device to the table"); goto table_bind_fail; } /* Finally, resume and the device should be ready. */ if (dm_resume(md)) { DMDEBUG("failed to resume the device"); goto resume_fail; } /* Export the dm device via the ioctl interface */ if (!strcmp(DM_NO_UUID, dm_setup_args.uuid)) uuid = NULL; if (dm_ioctl_export(md, dm_setup_args.name, uuid)) { DMDEBUG("failed to export device with given name and uuid"); goto export_fail; } printk(KERN_INFO "dm: dm-%d is ready\n", dm_setup_args.minor); dm_setup_cleanup(); return; export_fail: resume_fail: table_bind_fail: suspend_fail: table_complete_fail: add_target_fail: dm_table_put(table); dm_table_create_fail: dm_put(md); dm_create_fail: dm_setup_cleanup(); parse_fail: printk(KERN_WARNING "dm: starting dm-%d (%s) failed\n", dm_setup_args.minor, dm_setup_args.name); }
static int __init dm_setup_parse_targets(char *str) { char *next = NULL; size_t len = 0; struct dm_setup_target **target = NULL; /* Targets are defined as per the table format but with a * comma as a newline separator. */ target = &dm_setup_args.target; while (str && *str) { *target = kzalloc(sizeof(struct dm_setup_target), GFP_KERNEL); if (!*target) { DMERR("failed to allocate memory for target %d", dm_setup_args.target_count); goto parse_fail; } dm_setup_args.target_count++; (*target)->begin = simple_strtoull(str, &next, 10); if (!next || *next != DM_FIELD_SEP) { DMERR("failed to parse starting sector for target %d", dm_setup_args.target_count - 1); goto parse_fail; } str = skip_spaces(next + 1); (*target)->length = simple_strtoull(str, &next, 10); if (!next || *next != DM_FIELD_SEP) { DMERR("failed to parse length for target %d", dm_setup_args.target_count - 1); goto parse_fail; } str = skip_spaces(next + 1); len = get_dm_option(str, &next, DM_FIELD_SEP); if (!len || !((*target)->type = kstrndup(str, len, GFP_KERNEL))) { DMERR("failed to parse type for target %d", dm_setup_args.target_count - 1); goto parse_fail; } str = skip_spaces(next); len = get_dm_option(str, &next, DM_LINE_SEP); if (!len || !((*target)->params = kstrndup(str, len, GFP_KERNEL))) { DMERR("failed to parse params for target %d", dm_setup_args.target_count - 1); goto parse_fail; } str = skip_spaces(next); /* Before moving on, walk through the copied target and * attempt to replace all /dev/xxx with the major:minor number. * It may not be possible to resolve them traditionally at * boot-time. */ dm_substitute_devices((*target)->params, len); target = &((*target)->next); } DMDEBUG("parsed %d targets", dm_setup_args.target_count); return 0; parse_fail: return 1; }