📄 dm-ioctl.c
字号:
{ if (strchr(name, '/')) { DMWARN("invalid device name"); return -EINVAL; } return 0;}/* * Fills in a dm_ioctl structure, ready for sending back to * userland. */static int __dev_status(struct mapped_device *md, struct dm_ioctl *param){ struct gendisk *disk = dm_disk(md); struct dm_table *table; param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG | DM_ACTIVE_PRESENT_FLAG); if (dm_suspended(md)) param->flags |= DM_SUSPEND_FLAG; param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor)); /* * Yes, this will be out of date by the time it gets back * to userland, but it is still very useful for * debugging. */ param->open_count = dm_open_count(md); if (disk->policy) param->flags |= DM_READONLY_FLAG; param->event_nr = dm_get_event_nr(md); table = dm_get_table(md); if (table) { param->flags |= DM_ACTIVE_PRESENT_FLAG; param->target_count = dm_table_get_num_targets(table); dm_table_put(table); } else param->target_count = 0; return 0;}static int dev_create(struct dm_ioctl *param, size_t param_size){ int r, m = DM_ANY_MINOR; struct mapped_device *md; r = check_name(param->name); if (r) return r; if (param->flags & DM_PERSISTENT_DEV_FLAG) m = MINOR(huge_decode_dev(param->dev)); r = dm_create(m, &md); if (r) return r; r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); if (r) { dm_put(md); return r; } param->flags &= ~DM_INACTIVE_PRESENT_FLAG; r = __dev_status(md, param); dm_put(md); return r;}/* * Always use UUID for lookups if it's present, otherwise use name or dev. */static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param){ struct mapped_device *md; void *mdptr = NULL; if (*param->uuid) return __get_uuid_cell(param->uuid); if (*param->name) return __get_name_cell(param->name); md = dm_get_md(huge_decode_dev(param->dev)); if (!md) goto out; mdptr = dm_get_mdptr(md); if (!mdptr) dm_put(md);out: return mdptr;}static struct mapped_device *find_device(struct dm_ioctl *param){ struct hash_cell *hc; struct mapped_device *md = NULL; down_read(&_hash_lock); hc = __find_device_hash_cell(param); if (hc) { md = hc->md; /* * Sneakily write in both the name and the uuid * while we have the cell. */ strncpy(param->name, hc->name, sizeof(param->name)); if (hc->uuid) strncpy(param->uuid, hc->uuid, sizeof(param->uuid)-1); else param->uuid[0] = '\0'; if (hc->new_map) param->flags |= DM_INACTIVE_PRESENT_FLAG; else param->flags &= ~DM_INACTIVE_PRESENT_FLAG; } up_read(&_hash_lock); return md;}static int dev_remove(struct dm_ioctl *param, size_t param_size){ struct hash_cell *hc; struct mapped_device *md; int r; down_write(&_hash_lock); hc = __find_device_hash_cell(param); if (!hc) { DMWARN("device doesn't appear to be in the dev hash table."); up_write(&_hash_lock); return -ENXIO; } md = hc->md; /* * Ensure the device is not open and nothing further can open it. */ r = dm_lock_for_deletion(md); if (r) { DMWARN("unable to remove open device %s", hc->name); up_write(&_hash_lock); dm_put(md); return r; } __hash_remove(hc); up_write(&_hash_lock); dm_put(md); param->data_size = 0; return 0;}/* * Check a string doesn't overrun the chunk of * memory we copied from userland. */static int invalid_str(char *str, void *end){ while ((void *) str < end) if (!*str++) return 0; return -EINVAL;}static int dev_rename(struct dm_ioctl *param, size_t param_size){ int r; char *new_name = (char *) param + param->data_start; if (new_name < (char *) param->data || invalid_str(new_name, (void *) param + param_size)) { DMWARN("Invalid new logical volume name supplied."); return -EINVAL; } r = check_name(new_name); if (r) return r; param->data_size = 0; return dm_hash_rename(param->name, new_name);}static int dev_set_geometry(struct dm_ioctl *param, size_t param_size){ int r = -EINVAL, x; struct mapped_device *md; struct hd_geometry geometry; unsigned long indata[4]; char *geostr = (char *) param + param->data_start; md = find_device(param); if (!md) return -ENXIO; if (geostr < (char *) param->data || invalid_str(geostr, (void *) param + param_size)) { DMWARN("Invalid geometry supplied."); goto out; } x = sscanf(geostr, "%lu %lu %lu %lu", indata, indata + 1, indata + 2, indata + 3); if (x != 4) { DMWARN("Unable to interpret geometry settings."); goto out; } if (indata[0] > 65535 || indata[1] > 255 || indata[2] > 255 || indata[3] > ULONG_MAX) { DMWARN("Geometry exceeds range limits."); goto out; } geometry.cylinders = indata[0]; geometry.heads = indata[1]; geometry.sectors = indata[2]; geometry.start = indata[3]; r = dm_set_geometry(md, &geometry); if (!r) r = __dev_status(md, param); param->data_size = 0;out: dm_put(md); return r;}static int do_suspend(struct dm_ioctl *param){ int r = 0; unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG; struct mapped_device *md; md = find_device(param); if (!md) return -ENXIO; if (param->flags & DM_SKIP_LOCKFS_FLAG) suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG; if (param->flags & DM_NOFLUSH_FLAG) suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG; if (!dm_suspended(md)) r = dm_suspend(md, suspend_flags); if (!r) r = __dev_status(md, param); dm_put(md); return r;}static int do_resume(struct dm_ioctl *param){ int r = 0; unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG; struct hash_cell *hc; struct mapped_device *md; struct dm_table *new_map; down_write(&_hash_lock); hc = __find_device_hash_cell(param); if (!hc) { DMWARN("device doesn't appear to be in the dev hash table."); up_write(&_hash_lock); return -ENXIO; } md = hc->md; new_map = hc->new_map; hc->new_map = NULL; param->flags &= ~DM_INACTIVE_PRESENT_FLAG; up_write(&_hash_lock); /* Do we need to load a new map ? */ if (new_map) { /* Suspend if it isn't already suspended */ if (param->flags & DM_SKIP_LOCKFS_FLAG) suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG; if (param->flags & DM_NOFLUSH_FLAG) suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG; if (!dm_suspended(md)) dm_suspend(md, suspend_flags); r = dm_swap_table(md, new_map); if (r) { dm_put(md); dm_table_put(new_map); return r; } if (dm_table_get_mode(new_map) & FMODE_WRITE) set_disk_ro(dm_disk(md), 0); else set_disk_ro(dm_disk(md), 1); dm_table_put(new_map); } if (dm_suspended(md)) r = dm_resume(md); if (!r) r = __dev_status(md, param); dm_put(md); return r;}/* * Set or unset the suspension state of a device. * If the device already is in the requested state we just return its status. */static int dev_suspend(struct dm_ioctl *param, size_t param_size){ if (param->flags & DM_SUSPEND_FLAG) return do_suspend(param); return do_resume(param);}/* * Copies device info back to user space, used by * the create and info ioctls. */static int dev_status(struct dm_ioctl *param, size_t param_size){ int r; struct mapped_device *md; md = find_device(param); if (!md) return -ENXIO; r = __dev_status(md, param); dm_put(md); return r;}/* * Build up the status struct for each target */static void retrieve_status(struct dm_table *table, struct dm_ioctl *param, size_t param_size){ unsigned int i, num_targets; struct dm_target_spec *spec; char *outbuf, *outptr; status_type_t type; size_t remaining, len, used = 0; outptr = outbuf = get_result_buffer(param, param_size, &len); if (param->flags & DM_STATUS_TABLE_FLAG) type = STATUSTYPE_TABLE; else type = STATUSTYPE_INFO; /* Get all the target info */ num_targets = dm_table_get_num_targets(table); for (i = 0; i < num_targets; i++) { struct dm_target *ti = dm_table_get_target(table, i); remaining = len - (outptr - outbuf); if (remaining <= sizeof(struct dm_target_spec)) { param->flags |= DM_BUFFER_FULL_FLAG; break; } spec = (struct dm_target_spec *) outptr; spec->status = 0; spec->sector_start = ti->begin; spec->length = ti->len; strncpy(spec->target_type, ti->type->name, sizeof(spec->target_type)); outptr += sizeof(struct dm_target_spec); remaining = len - (outptr - outbuf); if (remaining <= 0) { param->flags |= DM_BUFFER_FULL_FLAG; break; } /* Get the status/table string from the target driver */ if (ti->type->status) { if (ti->type->status(ti, type, outptr, remaining)) { param->flags |= DM_BUFFER_FULL_FLAG; break; } } else outptr[0] = '\0'; outptr += strlen(outptr) + 1; used = param->data_start + (outptr - outbuf); outptr = align_ptr(outptr); spec->next = outptr - outbuf; } if (used) param->data_size = used; param->target_count = num_targets;}/* * Wait for a device to report an event */static int dev_wait(struct dm_ioctl *param, size_t param_size){ int r; struct mapped_device *md; struct dm_table *table; md = find_device(param); if (!md) return -ENXIO; /* * Wait for a notification event */ if (dm_wait_event(md, param->event_nr)) { r = -ERESTARTSYS; goto out; } /* * The userland program is going to want to know what * changed to trigger the event, so we may as well tell * him and save an ioctl. */ r = __dev_status(md, param); if (r) goto out; table = dm_get_table(md); if (table) { retrieve_status(table, param, param_size); dm_table_put(table); } out: dm_put(md); return r;}static inline int get_mode(struct dm_ioctl *param){ int mode = FMODE_READ | FMODE_WRITE; if (param->flags & DM_READONLY_FLAG) mode = FMODE_READ; return mode;}static int next_target(struct dm_target_spec *last, uint32_t next, void *end, struct dm_target_spec **spec, char **target_params){ *spec = (struct dm_target_spec *) ((unsigned char *) last + next); *target_params = (char *) (*spec + 1); if (*spec < (last + 1)) return -EINVAL; return invalid_str(*target_params, end);}static int populate_table(struct dm_table *table, struct dm_ioctl *param, size_t param_size){ int r; unsigned int i = 0; struct dm_target_spec *spec = (struct dm_target_spec *) param; uint32_t next = param->data_start; void *end = (void *) param + param_size; char *target_params; if (!param->target_count) { DMWARN("populate_table: no targets specified"); return -EINVAL; } for (i = 0; i < param->target_count; i++) { r = next_target(spec, next, end, &spec, &target_params); if (r) { DMWARN("unable to find target"); return r;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -