diff options
Diffstat (limited to 'lib/device/dev-cache.c')
-rw-r--r-- | lib/device/dev-cache.c | 218 |
1 files changed, 214 insertions, 4 deletions
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c index c3f7c49be..be5fde6e7 100644 --- a/lib/device/dev-cache.c +++ b/lib/device/dev-cache.c @@ -16,6 +16,7 @@ #include "base/memory/zalloc.h" #include "lib/misc/lib.h" #include "lib/device/dev-type.h" +#include "lib/device/device_id.h" #include "lib/datastruct/btree.h" #include "lib/config/config.h" #include "lib/commands/toolcontext.h" @@ -67,11 +68,13 @@ static void _dev_init(struct device *dev) dev->fd = -1; dev->bcache_fd = -1; dev->read_ahead = -1; + dev->part = -1; dev->ext.enabled = 0; dev->ext.src = DEV_EXT_NONE; dm_list_init(&dev->aliases); + dm_list_init(&dev->ids); } void dev_destroy_file(struct device *dev) @@ -351,7 +354,7 @@ static int _add_alias(struct device *dev, const char *path) return 1; } -static int _get_sysfs_value(const char *path, char *buf, size_t buf_size, int error_if_no_value) +int get_sysfs_value(const char *path, char *buf, size_t buf_size, int error_if_no_value) { FILE *fp; size_t len; @@ -392,7 +395,7 @@ static int _get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int mi return 0; } - return _get_sysfs_value(path, buf, buf_size, 0); + return get_sysfs_value(path, buf, buf_size, 0); } static struct dm_list *_get_or_add_list_by_index_key(struct dm_hash_table *idx, const char *key) @@ -473,7 +476,7 @@ static struct device *_get_device_for_sysfs_dev_name_using_devno(const char *dev return NULL; } - if (!_get_sysfs_value(path, buf, sizeof(buf), 1)) + if (!get_sysfs_value(path, buf, sizeof(buf), 1)) return_NULL; if (sscanf(buf, "%d:%d", &major, &minor) != 2) { @@ -971,7 +974,7 @@ static int _dev_cache_iterate_sysfs_for_index(const char *path) return r; } -int dev_cache_index_devs(void) +static int dev_cache_index_devs(void) { static int sysfs_has_dev_block = -1; char path[PATH_MAX]; @@ -1320,12 +1323,19 @@ int dev_cache_check_for_open_devices(void) int dev_cache_exit(void) { + struct device *dev; + struct dm_hash_node *n; int num_open = 0; if (_cache.names) if ((num_open = _check_for_open_devices(1)) > 0) log_error(INTERNAL_ERROR "%d device(s) were left open and have been closed.", num_open); + dm_hash_iterate(n, _cache.names) { + dev = (struct device *) dm_hash_get_data(_cache.names, n); + free_dids(&dev->ids); + } + if (_cache.mem) dm_pool_destroy(_cache.mem); @@ -1657,3 +1667,203 @@ bool dev_cache_has_md_with_end_superblock(struct dev_types *dt) return false; } +int setup_devices_file(struct cmd_context *cmd) +{ + const char *filename = NULL; + + if (cmd->devicesfile) { + /* --devicesfile <filename> or "" has been set which overrides + lvm.conf settings use_devicesfile and devicesfile. */ + if (!strlen(cmd->devicesfile)) + cmd->enable_devices_file = 0; + else { + cmd->enable_devices_file = 1; + filename = cmd->devicesfile; + } + } else { + if (!find_config_tree_bool(cmd, devices_use_devicesfile_CFG, NULL)) + cmd->enable_devices_file = 0; + else { + cmd->enable_devices_file = 1; + filename = find_config_tree_str(cmd, devices_devicesfile_CFG, NULL); + if (!validate_name(filename)) { + log_error("Invalid devices file name from config setting \"%s\".", filename); + return 0; + } + } + } + + if (!cmd->enable_devices_file) + return 1; + + if (dm_snprintf(cmd->devices_file_path, sizeof(cmd->devices_file_path), + "%s/devices/%s", cmd->system_dir, filename) < 0) { + log_error("Failed to copy devices file path"); + return 0; + } + return 1; +} + +/* + * Add all system devices to dev-cache, and attempt to + * match all devices_file entries to dev-cache entries. + */ +int setup_devices(struct cmd_context *cmd) +{ + int file_exists; + int lock_mode = 0; + + if (!setup_devices_file(cmd)) + return_0; + + if (!cmd->enable_devices_file) + goto scan; + + file_exists = devices_file_exists(cmd); + + /* + * Removing the devices file is another way of disabling the use of + * a devices file, unless the command creates the devices file. + */ + if (!file_exists && !cmd->create_edit_devices_file) { + log_print("Devices file not found, ignoring."); + cmd->enable_devices_file = 0; + goto scan; + } + + if (!file_exists) { + /* pvcreate/vgcreate/vgimportdevices/lvmdevices-add + create a new devices file here if it doesn't exist. + They have the create_edit_devices_file flag set. + First they create/lock-ex the devices file lockfile. + Other commands will not use a devices file if none exists. */ + + lock_mode = LOCK_EX; + + if (!lock_devices_file(cmd, lock_mode)) { + log_error("Failed to lock the devices file to create."); + return 0; + } + if (!devices_file_touch(cmd)) { + log_error("Failed to create the devices file."); + return 0; + } + } else { + /* Commands that intend to edit the devices file have + edit_devices_file or create_edit_devices_file set (create if + they can also create a new devices file) and lock it ex + here prior to reading. Other commands that intend to just + read the devices file lock sh. */ + + lock_mode = (cmd->create_edit_devices_file || cmd->edit_devices_file) ? LOCK_EX : LOCK_SH; + + if (!lock_devices_file(cmd, lock_mode)) { + log_error("Failed to lock the devices file."); + return 0; + } + } + + /* + * Read the list of device ids that lvm can use. + * Adds a struct dev_id to cmd->use_device_ids for each one. + */ + if (!device_ids_read(cmd)) { + log_error("Failed to read the devices file."); + return 0; + } + + /* + * When the command is editing the devices file, it acquires + * the ex lock above, will later call device_ids_write(), and + * then unlock the lock after writing the file. + * When the command is just reading the devices file, it's + * locked sh above just before reading the file, and unlocked + * here after reading. + */ + if (lock_mode && (lock_mode == LOCK_SH)) + unlock_devices_file(cmd); + + scan: + /* + * Add a 'struct device' to dev-cache for each device available on the system. + * This will not open or read any devices, but may look at sysfs properties. + * This list of devs comes from looking /dev entries, or from asking libudev. + * TODO: or from /proc/partitions? + * + * TODO: dev_cache_scan() optimization: start by looking only at + * devnames listed in the devices_file, and if the device_ids for + * those all match we won't need any others. + * Exceptions: the command wants a new device for pvcreate, or + * device_ids don't match the devnames. + */ + dev_cache_scan(); + + /* + * Match entries from cmd->use_device_ids with device structs in dev-cache. + */ + device_ids_match(cmd); + + return 1; +} + +/* + * The alternative to setup_devices() when the command is interested + * in using only one PV. + * + * Add one system device to dev-cache, and attempt to + * match its dev-cache entry to a devices_file entry. + */ +int setup_device(struct cmd_context *cmd, const char *devname) +{ + struct stat buf; + struct device *dev; + + if (!setup_devices_file(cmd)) + return_0; + + if (!cmd->enable_devices_file) + goto scan; + + if (!devices_file_exists(cmd)) { + log_print("Devices file not found, ignoring."); + cmd->enable_devices_file = 0; + goto scan; + } + + if (!lock_devices_file(cmd, LOCK_SH)) { + log_error("Failed to lock the devices file to read."); + return 0; + } + + if (!device_ids_read(cmd)) { + log_error("Failed to read the devices file."); + return 0; + } + + unlock_devices_file(cmd); + + scan: + if (stat(devname, &buf) < 0) { + log_error("Cannot access device %s.", devname); + return 0; + } + + if (!S_ISBLK(buf.st_mode)) { + log_error("Invaild device type %s.", devname); + return 0; + } + + if (!_insert_dev(devname, buf.st_rdev)) + return_0; + + if (!(dev = (struct device *) dm_hash_lookup(_cache.names, devname))) + return_0; + + /* Match this device to an entry in devices_file so it will not + be rejected by filter-deviceid. */ + if (cmd->enable_devices_file) + device_ids_match_dev(cmd, dev); + + return 1; +} + |