/* Run dm command which is descirbed in dm_task structure. */ int dm_task_run(struct dm_task *dmt) { struct dm_ioctl *dmi; unsigned command; if ((unsigned) dmt->type >= (sizeof(_cmd_data_v4) / sizeof(*_cmd_data_v4))) { log_error("Internal error: unknown device-mapper task %d", dmt->type); return 0; } command = _cmd_data_v4[dmt->type].cmd; /* Old-style creation had a table supplied */ if (dmt->type == DM_DEVICE_CREATE && dmt->head) return _create_and_load_v4(dmt); if (dmt->type == DM_DEVICE_MKNODES && !dmt->dev_name && !dmt->uuid && dmt->major <= 0) return _mknodes_v4(dmt); if ((dmt->type == DM_DEVICE_RELOAD) && dmt->suppress_identical_reload) return _reload_with_suppression_v4(dmt); if (!_open_control()) return 0; if (!(dmi = _do_dm_ioctl(dmt, command))) return 0; switch (dmt->type) { case DM_DEVICE_CREATE: add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev), dmt->uid, dmt->gid, dmt->mode, 0); break; case DM_DEVICE_REMOVE: /* FIXME Kernel needs to fill in dmi->name */ if (dmt->dev_name) rm_dev_node(dmt->dev_name, 0); break; case DM_DEVICE_RENAME: /* FIXME Kernel needs to fill in dmi->name */ if (dmt->dev_name) rename_dev_node(dmt->dev_name, dmt->newname, 0); break; case DM_DEVICE_RESUME: /* FIXME Kernel needs to fill in dmi->name */ set_dev_node_read_ahead(dmt->dev_name, dmt->read_ahead, dmt->read_ahead_flags); break; case DM_DEVICE_MKNODES: if (dmi->flags & DM_EXISTS_FLAG) add_dev_node(dmi->name, MAJOR(dmi->dev), MINOR(dmi->dev), dmt->uid, dmt->gid, dmt->mode, 0); else if (dmt->dev_name) rm_dev_node(dmt->dev_name, 0); break; case DM_DEVICE_STATUS: case DM_DEVICE_TABLE: case DM_DEVICE_WAITEVENT: if (!_unmarshal_status(dmt, dmi)) goto bad; break; } /* Was structure reused? */ if (dmt->dmi.v4) dm_free(dmt->dmi.v4); dmt->dmi.v4 = dmi; return 1; bad: dm_free(dmi); return 0; }
static int _dm_task_run_v1(struct dm_task *dmt) { struct dm_ioctl_v1 *dmi; unsigned int command; dmi = _flatten_v1(dmt); if (!dmi) { log_error("Couldn't create ioctl argument."); return 0; } if (!_open_control()) return 0; if ((unsigned) dmt->type >= (sizeof(_cmd_data_v1) / sizeof(*_cmd_data_v1))) { log_error(INTERNAL_ERROR "unknown device-mapper task %d", dmt->type); goto bad; } command = _cmd_data_v1[dmt->type].cmd; if (dmt->type == DM_DEVICE_TABLE) dmi->flags |= DM_STATUS_TABLE_FLAG; if (dmt->new_uuid) { log_error("Changing UUID is not supported by kernel."); goto bad; } log_debug("dm %s %s %s%s%s [%u]", _cmd_data_v1[dmt->type].name, dmi->name, dmi->uuid, dmt->newname ? " " : "", dmt->newname ? dmt->newname : "", dmi->data_size); if (dmt->type == DM_DEVICE_LIST) { if (!_dm_names_v1(dmi)) goto bad; } #ifdef DM_IOCTLS else if (ioctl(_control_fd, command, dmi) < 0) { if (_log_suppress) log_verbose("device-mapper: %s ioctl failed: %s", _cmd_data_v1[dmt->type].name, strerror(errno)); else log_error("device-mapper: %s ioctl failed: %s", _cmd_data_v1[dmt->type].name, strerror(errno)); goto bad; } #else /* Userspace alternative for testing */ #endif if (dmi->flags & DM_BUFFER_FULL_FLAG) /* FIXME Increase buffer size and retry operation (if query) */ log_error("WARNING: libdevmapper buffer too small for data"); switch (dmt->type) { case DM_DEVICE_CREATE: add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev), dmt->uid, dmt->gid, dmt->mode, 0); break; case DM_DEVICE_REMOVE: rm_dev_node(dmt->dev_name, 0); break; case DM_DEVICE_RENAME: rename_dev_node(dmt->dev_name, dmt->newname, 0); break; case DM_DEVICE_MKNODES: if (dmi->flags & DM_EXISTS_FLAG) add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev), dmt->uid, dmt->gid, dmt->mode, 0); else rm_dev_node(dmt->dev_name, 0); break; case DM_DEVICE_STATUS: case DM_DEVICE_TABLE: if (!_unmarshal_status_v1(dmt, dmi)) goto bad; break; case DM_DEVICE_SUSPEND: case DM_DEVICE_RESUME: dmt->type = DM_DEVICE_INFO; if (!dm_task_run(dmt)) goto bad; _dm_zfree_dmi_v1(dmi); /* We'll use what info returned */ return 1; } dmt->dmi.v1 = dmi; return 1; bad: _dm_zfree_dmi_v1(dmi); return 0; }
/* * This function is heart of NetBSD libdevmapper-> device-mapper kernel protocol * It creates proplib_dictionary from dm task structure and sends it to NetBSD * kernel driver. After succesfull ioctl it create dmi structure from returned * proplib dictionary. This way I keep number of changes in NetBSD version of * libdevmapper as small as posible. */ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command) { struct dm_ioctl *dmi; prop_dictionary_t dm_dict_in, dm_dict_out; uint32_t flags; dm_dict_in = NULL; dm_dict_in = prop_dictionary_create(); /* Dictionary send to kernel */ dm_dict_out = prop_dictionary_create(); /* Dictionary received from kernel */ /* Set command name to dictionary */ prop_dictionary_set_cstring(dm_dict_in, DM_IOCTL_COMMAND, _cmd_data_v4[dmt->type].name); /* Parse dmi from libdevmapper to dictionary */ if (_flatten(dmt, dm_dict_in) < 0) goto bad; prop_dictionary_get_uint32(dm_dict_in, DM_IOCTL_FLAGS, &flags); if (dmt->type == DM_DEVICE_TABLE) flags |= DM_STATUS_TABLE_FLAG; if (dmt->no_open_count) flags |= DM_SKIP_BDGET_FLAG; flags |= DM_EXISTS_FLAG; /* Set flags to dictionary. */ prop_dictionary_set_uint32(dm_dict_in,DM_IOCTL_FLAGS,flags); prop_dictionary_externalize_to_file(dm_dict_in,"/tmp/test_in"); log_very_verbose("Ioctl type %s --- flags %d",_cmd_data_v4[dmt->type].name,flags); //printf("name %s, major %d minor %d\n uuid %s\n", //dm_task_get_name(dmt), dmt->minor, dmt->major, dm_task_get_uuid(dmt)); /* Send dictionary to kernel and wait for reply. */ #ifdef RUMP_ACTION struct plistref prefp; int err; prop_dictionary_externalize_to_pref(dm_dict_in, &prefp); if (rump_sys_ioctl(_control_fd, NETBSD_DM_IOCTL, &prefp) != 0) { dm_dict_out = prop_dictionary_internalize(prefp.pref_plist); #else if (prop_dictionary_sendrecv_ioctl(dm_dict_in,_control_fd, NETBSD_DM_IOCTL,&dm_dict_out) != 0) { #endif if (errno == ENOENT && ((dmt->type == DM_DEVICE_INFO) || (dmt->type == DM_DEVICE_MKNODES) || (dmt->type == DM_DEVICE_STATUS))) { /* * Linux version doesn't fail when ENOENT is returned * for nonexisting device after info, deps, mknodes call. * It returns dmi sent to kernel with DM_EXISTS_FLAG = 0; */ dmi = nbsd_dm_dict_to_dmi(dm_dict_in,_cmd_data_v4[dmt->type].cmd); dmi->flags &= ~DM_EXISTS_FLAG; prop_object_release(dm_dict_in); prop_object_release(dm_dict_out); goto out; } else { log_error("ioctl %s call failed with errno %d\n", _cmd_data_v4[dmt->type].name, errno); prop_object_release(dm_dict_in); prop_object_release(dm_dict_out); goto bad; } } #ifdef RUMP_ACTION dm_dict_out = prop_dictionary_internalize(prefp.pref_plist); #endif prop_dictionary_externalize_to_file(dm_dict_out,"/tmp/test_out"); /* Parse kernel dictionary to dmi structure and return it to libdevmapper. */ dmi = nbsd_dm_dict_to_dmi(dm_dict_out,_cmd_data_v4[dmt->type].cmd); prop_object_release(dm_dict_in); prop_object_release(dm_dict_out); out: return dmi; bad: return NULL; } /* Create new edvice nodes in mapper/ dir. */ void dm_task_update_nodes(void) { update_devs(); } /* Run dm command which is descirbed in dm_task structure. */ int dm_task_run(struct dm_task *dmt) { struct dm_ioctl *dmi; unsigned command; if ((unsigned) dmt->type >= (sizeof(_cmd_data_v4) / sizeof(*_cmd_data_v4))) { log_error("Internal error: unknown device-mapper task %d", dmt->type); return 0; } command = _cmd_data_v4[dmt->type].cmd; /* Old-style creation had a table supplied */ if (dmt->type == DM_DEVICE_CREATE && dmt->head) return _create_and_load_v4(dmt); if (dmt->type == DM_DEVICE_MKNODES && !dmt->dev_name && !dmt->uuid && dmt->major <= 0) return _mknodes_v4(dmt); if ((dmt->type == DM_DEVICE_RELOAD) && dmt->suppress_identical_reload) return _reload_with_suppression_v4(dmt); if (!_open_control()) return 0; if (!(dmi = _do_dm_ioctl(dmt, command))) return 0; switch (dmt->type) { case DM_DEVICE_CREATE: add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev), dmt->uid, dmt->gid, dmt->mode, 0); break; case DM_DEVICE_REMOVE: /* FIXME Kernel needs to fill in dmi->name */ if (dmt->dev_name) rm_dev_node(dmt->dev_name, 0); break; case DM_DEVICE_RENAME: /* FIXME Kernel needs to fill in dmi->name */ if (dmt->dev_name) rename_dev_node(dmt->dev_name, dmt->newname, 0); break; case DM_DEVICE_RESUME: /* FIXME Kernel needs to fill in dmi->name */ set_dev_node_read_ahead(dmt->dev_name, dmt->read_ahead, dmt->read_ahead_flags); break; case DM_DEVICE_MKNODES: if (dmi->flags & DM_EXISTS_FLAG) add_dev_node(dmi->name, MAJOR(dmi->dev), MINOR(dmi->dev), dmt->uid, dmt->gid, dmt->mode, 0); else if (dmt->dev_name) rm_dev_node(dmt->dev_name, 0); break; case DM_DEVICE_STATUS: case DM_DEVICE_TABLE: case DM_DEVICE_WAITEVENT: if (!_unmarshal_status(dmt, dmi)) goto bad; break; } /* Was structure reused? */ if (dmt->dmi.v4) dm_free(dmt->dmi.v4); dmt->dmi.v4 = dmi; return 1; bad: dm_free(dmi); return 0; } void dm_lib_release(void) { if (_control_fd != -1) { close(_control_fd); _control_fd = -1; } update_devs(); } void dm_lib_exit(void) { dm_lib_release(); dm_dump_memory(); _version_ok = 1; _version_checked = 0; }