diff options
Diffstat (limited to 'lib/device')
-rw-r--r-- | lib/device/dev-cache.c | 291 | ||||
-rw-r--r-- | lib/device/dev-cache.h | 8 | ||||
-rw-r--r-- | lib/device/dev-io.c | 114 | ||||
-rw-r--r-- | lib/device/dev-luks.c | 2 | ||||
-rw-r--r-- | lib/device/dev-md.c | 16 | ||||
-rw-r--r-- | lib/device/dev-swap.c | 7 | ||||
-rw-r--r-- | lib/device/device.c | 36 | ||||
-rw-r--r-- | lib/device/device.h | 14 |
8 files changed, 366 insertions, 122 deletions
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c index 962aa1e..d08b07f 100644 --- a/lib/device/dev-cache.c +++ b/lib/device/dev-cache.c @@ -18,7 +18,6 @@ #include "lvm-types.h" #include "btree.h" #include "filter.h" -#include "filter-persistent.h" #include "toolcontext.h" #include <unistd.h> @@ -48,11 +47,23 @@ static struct { } _cache; -#define _alloc(x) dm_pool_zalloc(_cache.mem, (x)) +#define _zalloc(x) dm_pool_zalloc(_cache.mem, (x)) #define _free(x) dm_pool_free(_cache.mem, (x)) #define _strdup(x) dm_pool_strdup(_cache.mem, (x)) -static int _insert(const char *path, int rec); +static int _insert(const char *path, int rec, int check_with_udev_db); + +/* Setup non-zero members of passed zeroed 'struct device' */ +static void _dev_init(struct device *dev, int max_error_count) +{ + dev->block_size = -1; + dev->fd = -1; + dev->read_ahead = -1; + dev->max_error_count = max_error_count; + + dm_list_init(&dev->aliases); + dm_list_init(&dev->open_list); +} struct device *dev_create_file(const char *filename, struct device *dev, struct str_list *alias, int use_malloc) @@ -61,11 +72,11 @@ struct device *dev_create_file(const char *filename, struct device *dev, if (allocate) { if (use_malloc) { - if (!(dev = dm_malloc(sizeof(*dev)))) { + if (!(dev = dm_zalloc(sizeof(*dev)))) { log_error("struct device allocation failed"); return NULL; } - if (!(alias = dm_malloc(sizeof(*alias)))) { + if (!(alias = dm_zalloc(sizeof(*alias)))) { log_error("struct str_list allocation failed"); dm_free(dev); return NULL; @@ -76,13 +87,12 @@ struct device *dev_create_file(const char *filename, struct device *dev, dm_free(alias); return NULL; } - dev->flags = DEV_ALLOCED; } else { - if (!(dev = _alloc(sizeof(*dev)))) { + if (!(dev = _zalloc(sizeof(*dev)))) { log_error("struct device allocation failed"); return NULL; } - if (!(alias = _alloc(sizeof(*alias)))) { + if (!(alias = _zalloc(sizeof(*alias)))) { log_error("struct str_list allocation failed"); _free(dev); return NULL; @@ -97,19 +107,9 @@ struct device *dev_create_file(const char *filename, struct device *dev, return NULL; } - dev->flags |= DEV_REGULAR; - dm_list_init(&dev->aliases); + _dev_init(dev, NO_DEV_ERROR_COUNT_LIMIT); + dev->flags = DEV_REGULAR | ((use_malloc) ? DEV_ALLOCED : 0); dm_list_add(&dev->aliases, &alias->list); - dev->end = UINT64_C(0); - dev->dev = 0; - dev->fd = -1; - dev->open_count = 0; - dev->error_count = 0; - dev->max_error_count = NO_DEV_ERROR_COUNT_LIMIT; - dev->block_size = -1; - dev->read_ahead = -1; - memset(dev->pvid, 0, sizeof(dev->pvid)); - dm_list_init(&dev->open_list); return dev; } @@ -118,21 +118,13 @@ static struct device *_dev_create(dev_t d) { struct device *dev; - if (!(dev = _alloc(sizeof(*dev)))) { + if (!(dev = _zalloc(sizeof(*dev)))) { log_error("struct device allocation failed"); return NULL; } - dev->flags = 0; - dm_list_init(&dev->aliases); + + _dev_init(dev, dev_disable_after_error_count()); dev->dev = d; - dev->fd = -1; - dev->open_count = 0; - dev->max_error_count = dev_disable_after_error_count(); - dev->block_size = -1; - dev->read_ahead = -1; - dev->end = UINT64_C(0); - memset(dev->pvid, 0, sizeof(dev->pvid)); - dm_list_init(&dev->open_list); return dev; } @@ -261,10 +253,19 @@ static int _compare_paths(const char *path0, const char *path1) if (slash1 < slash0) return 1; - strncpy(p0, path0, PATH_MAX); - strncpy(p1, path1, PATH_MAX); - s0 = &p0[0] + 1; - s1 = &p1[0] + 1; + strncpy(p0, path0, sizeof(p0) - 1); + p0[sizeof(p0) - 1] = '\0'; + strncpy(p1, path1, sizeof(p1) - 1); + p1[sizeof(p1) - 1] = '\0'; + s0 = p0 + 1; + s1 = p1 + 1; + + /* + * If we reach here, both paths are the same length. + * Now skip past identical path components. + */ + while (*s0 && *s0 == *s1) + s0++, s1++; /* We prefer symlinks - they exist for a reason! * So we prefer a shorter path before the first symlink in the name. @@ -303,7 +304,7 @@ static int _compare_paths(const char *path0, const char *path1) static int _add_alias(struct device *dev, const char *path) { - struct str_list *sl = _alloc(sizeof(*sl)); + struct str_list *sl = _zalloc(sizeof(*sl)); struct str_list *strl; const char *oldpath; int prefer_old = 1; @@ -319,8 +320,7 @@ static int _add_alias(struct device *dev, const char *path) } } - if (!(sl->str = dm_pool_strdup(_cache.mem, path))) - return_0; + sl->str = path; if (!dm_list_empty(&dev->aliases)) { oldpath = dm_list_item(dev->aliases.n, struct str_list)->str; @@ -348,6 +348,7 @@ static int _insert_dev(const char *path, dev_t d) struct device *dev; static dev_t loopfile_count = 0; int loopfile = 0; + char *path_copy; /* Generate pretend device numbers for loopfiles */ if (!d) { @@ -374,12 +375,17 @@ static int _insert_dev(const char *path, dev_t d) } } - if (!loopfile && !_add_alias(dev, path)) { + if (!(path_copy = dm_pool_strdup(_cache.mem, path))) { + log_error("Failed to duplicate path string."); + return 0; + } + + if (!loopfile && !_add_alias(dev, path_copy)) { log_error("Couldn't add alias to dev cache."); return 0; } - if (!dm_hash_insert(_cache.names, path, dev)) { + if (!dm_hash_insert(_cache.names, path_copy, dev)) { log_error("Couldn't add name to hash in dev cache."); return 0; } @@ -437,7 +443,7 @@ static int _insert_dir(const char *dir) return_0; _collapse_slashes(path); - r &= _insert(path, 1); + r &= _insert(path, 1, 0); dm_free(path); free(dirent[n]); @@ -468,7 +474,123 @@ static int _insert_file(const char *path) return 1; } -static int _insert(const char *path, int rec) +#ifdef UDEV_SYNC_SUPPORT + +static int _device_in_udev_db(const dev_t d) +{ + struct udev *udev; + struct udev_device *udev_device; + + if (!(udev = udev_get_library_context())) + return_0; + + if ((udev_device = udev_device_new_from_devnum(udev, 'b', d))) { + udev_device_unref(udev_device); + return 1; + } + + return 0; +} + +static int _insert_udev_dir(struct udev *udev, const char *dir) +{ + struct udev_enumerate *udev_enum = NULL; + struct udev_list_entry *device_entry, *symlink_entry; + const char *entry_name, *node_name, *symlink_name; + struct udev_device *device; + int r = 1; + + if (!(udev_enum = udev_enumerate_new(udev))) + goto bad; + + if (udev_enumerate_add_match_subsystem(udev_enum, "block") || + udev_enumerate_scan_devices(udev_enum)) + goto bad; + + /* + * Report any missing information as "log_very_verbose" only, do not + * report it as a "warning" or "error" - the record could be removed + * by the time we ask for more info (node name, symlink name...). + * Whatever removes *any* block device in the system (even unrelated + * to our operation), we would have a warning/error on output then. + * That could be misleading. If there's really any problem with missing + * information from udev db, we can still have a look at the verbose log. + */ + udev_list_entry_foreach(device_entry, udev_enumerate_get_list_entry(udev_enum)) { + entry_name = udev_list_entry_get_name(device_entry); + + if (!(device = udev_device_new_from_syspath(udev, entry_name))) { + log_very_verbose("udev failed to return a device for entry %s.", + entry_name); + continue; + } + + if (!(node_name = udev_device_get_devnode(device))) + log_very_verbose("udev failed to return a device node for entry %s.", + entry_name); + else + r &= _insert(node_name, 0, 0); + + udev_list_entry_foreach(symlink_entry, udev_device_get_devlinks_list_entry(device)) { + if (!(symlink_name = udev_list_entry_get_name(symlink_entry))) + log_very_verbose("udev failed to return a symlink name for entry %s.", + entry_name); + else + r &= _insert(symlink_name, 0, 0); + } + + udev_device_unref(device); + } + + udev_enumerate_unref(udev_enum); + return r; + +bad: + log_error("Failed to enumerate udev device list."); + udev_enumerate_unref(udev_enum); + return 0; +} + +static void _insert_dirs(struct dm_list *dirs) +{ + struct dir_list *dl; + struct udev *udev; + int with_udev; + + with_udev = obtain_device_list_from_udev() && + (udev = udev_get_library_context()); + + dm_list_iterate_items(dl, &_cache.dirs) { + if (with_udev) { + if (!_insert_udev_dir(udev, dl->dir)) + log_debug("%s: Failed to insert devices from " + "udev-managed directory to device " + "cache fully", dl->dir); + } + else if (!_insert_dir(dl->dir)) + log_debug("%s: Failed to insert devices to " + "device cache fully", dl->dir); + } +} + +#else /* UDEV_SYNC_SUPPORT */ + +static int _device_in_udev_db(const dev_t d) +{ + return 0; +} + +static void _insert_dirs(struct dm_list *dirs) +{ + struct dir_list *dl; + + dm_list_iterate_items(dl, &_cache.dirs) + _insert_dir(dl->dir); +} + +#endif /* UDEV_SYNC_SUPPORT */ + +static int _insert(const char *path, int rec, int check_with_udev_db) { struct stat info; int r = 0; @@ -478,6 +600,11 @@ static int _insert(const char *path, int rec) return 0; } + if (check_with_udev_db && !_device_in_udev_db(info.st_rdev)) { + log_very_verbose("%s: Not in udev db", path); + return 0; + } + if (S_ISDIR(info.st_mode)) { /* add a directory */ /* check it's not a symbolic link */ if (lstat(path, &info) < 0) { @@ -515,8 +642,7 @@ static void _full_scan(int dev_scan) if (_cache.has_scanned && !dev_scan) return; - dm_list_iterate_items(dl, &_cache.dirs) - _insert_dir(dl->dir); + _insert_dirs(&_cache.dirs); dm_list_iterate_items(dl, &_cache.files) _insert_file(dl->dir); @@ -540,8 +666,8 @@ void dev_cache_scan(int do_scan) static int _init_preferred_names(struct cmd_context *cmd) { - const struct config_node *cn; - const struct config_value *v; + const struct dm_config_node *cn; + const struct dm_config_value *v; struct dm_pool *scratch = NULL; const char **regex; unsigned count = 0; @@ -550,14 +676,14 @@ static int _init_preferred_names(struct cmd_context *cmd) _cache.preferred_names_matcher = NULL; if (!(cn = find_config_tree_node(cmd, "devices/preferred_names")) || - cn->v->type == CFG_EMPTY_ARRAY) { + cn->v->type == DM_CFG_EMPTY_ARRAY) { log_very_verbose("devices/preferred_names not found in config file: " "using built-in preferences"); return 1; } for (v = cn->v; v; v = v->next) { - if (v->type != CFG_STRING) { + if (v->type != DM_CFG_STRING) { log_error("preferred_names patterns must be enclosed in quotes"); return 0; } @@ -684,7 +810,7 @@ int dev_cache_add_dir(const char *path) return 1; } - if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) { + if (!(dl = _zalloc(sizeof(*dl) + strlen(path) + 1))) { log_error("dir_list allocation failed"); return 0; } @@ -710,7 +836,7 @@ int dev_cache_add_loopfile(const char *path) return 1; } - if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) { + if (!(dl = _zalloc(sizeof(*dl) + strlen(path) + 1))) { log_error("dir_list allocation failed for file"); return 0; } @@ -760,7 +886,7 @@ const char *dev_name_confirmed(struct device *dev, int quiet) if (dm_list_size(&dev->aliases) > 1) { dm_list_del(dev->aliases.n); if (!r) - _insert(name, 0); + _insert(name, 0, obtain_device_list_from_udev()); continue; } @@ -788,7 +914,7 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f) } if (!d) { - _insert(name, 0); + _insert(name, 0, obtain_device_list_from_udev()); d = (struct device *) dm_hash_lookup(_cache.names, name); if (!d) { _full_scan(0); @@ -800,6 +926,39 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f) f->passes_filter(f, d))) ? d : NULL; } +static struct device *_dev_cache_seek_devt(dev_t dev) +{ + struct device *d = NULL; + struct dm_hash_node *n = dm_hash_get_first(_cache.names); + while (n) { + d = dm_hash_get_data(_cache.names, n); + if (d->dev == dev) + return d; + n = dm_hash_get_next(_cache.names, n); + } + return NULL; +} + +/* + * TODO This is very inefficient. We probably want a hash table indexed by + * major:minor for keys to speed up these lookups. + */ +struct device *dev_cache_get_by_devt(dev_t dev, struct dev_filter *f) +{ + struct device *d = _dev_cache_seek_devt(dev); + + if (d && (d->flags & DEV_REGULAR)) + return d; + + if (!d) { + _full_scan(0); + d = _dev_cache_seek_devt(dev); + } + + return (d && (!f || (d->flags & DEV_REGULAR) || + f->passes_filter(f, d))) ? d : NULL; +} + struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan) { struct dev_iter *di = dm_malloc(sizeof(*di)); @@ -811,21 +970,27 @@ struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan) if (dev_scan && !trust_cache()) { /* Flag gets reset between each command */ - if (!full_scan_done()) - persistent_filter_wipe(f); /* Calls _full_scan(1) */ + if (!full_scan_done()) { + if (f && f->wipe) + f->wipe(f); /* Calls _full_scan(1) */ + else + _full_scan(1); + } } else _full_scan(0); di->current = btree_first(_cache.devices); di->filter = f; - di->filter->use_count++; + if (di->filter) + di->filter->use_count++; return di; } void dev_iter_destroy(struct dev_iter *iter) { - iter->filter->use_count--; + if (iter->filter) + iter->filter->use_count--; dm_free(iter); } @@ -850,18 +1015,14 @@ struct device *dev_iter_get(struct dev_iter *iter) void dev_reset_error_count(struct cmd_context *cmd) { - struct dev_iter *iter; - struct device *dev; + struct dev_iter iter; - if (!(iter = dev_iter_create(cmd->filter, 0))) { - log_error("Resetting device error count failed"); + if (!_cache.devices) return; - } - - for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) - dev->error_count = 0; - dev_iter_destroy(iter); + iter.current = btree_first(_cache.devices); + while (iter.current) + _iter_next(&iter)->error_count = 0; } int dev_fd(struct device *dev) diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h index c1c86d6..3267c9d 100644 --- a/lib/device/dev-cache.h +++ b/lib/device/dev-cache.h @@ -17,6 +17,7 @@ #define _LVM_DEV_CACHE_H #include "device.h" +#include "lvm-wrappers.h" /* * predicate for devices. @@ -24,8 +25,9 @@ struct dev_filter { int (*passes_filter) (struct dev_filter * f, struct device * dev); void (*destroy) (struct dev_filter * f); - unsigned use_count; + void (*wipe) (struct dev_filter * f); void *private; + unsigned use_count; }; /* @@ -41,8 +43,12 @@ int dev_cache_has_scanned(void); int dev_cache_add_dir(const char *path); int dev_cache_add_loopfile(const char *path); +__attribute__((nonnull(1))) struct device *dev_cache_get(const char *name, struct dev_filter *f); +// TODO +struct device *dev_cache_get_by_devt(dev_t device, struct dev_filter *f); + void dev_set_preferred_name(struct str_list *sl, struct device *dev); /* diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c index eb80a89..3bb9d65 100644 --- a/lib/device/dev-io.c +++ b/lib/device/dev-io.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * @@ -36,6 +36,9 @@ # ifndef BLKGETSIZE64 /* fs.h out-of-date */ # define BLKGETSIZE64 _IOR(0x12, 114, size_t) # endif /* BLKGETSIZE64 */ +# ifndef BLKDISCARD +# define BLKDISCARD _IO(0x12,119) +# endif #else # include <sys/disk.h> # define BLKBSZGET DKIOCGETBLOCKSIZE @@ -57,7 +60,7 @@ static DM_LIST_INIT(_open_devices); * The standard io loop that keeps submitting an io until it's * all gone. *---------------------------------------------------------------*/ -static int _io(struct device_area *where, void *buffer, int should_write) +static int _io(struct device_area *where, char *buffer, int should_write) { int fd = dev_fd(where->dev); ssize_t n = 0; @@ -126,7 +129,7 @@ static int _get_block_size(struct device *dev, unsigned int *size) { const char *name = dev_name(dev); - if ((dev->block_size == -1)) { + if (dev->block_size == -1) { if (ioctl(dev_fd(dev), BLKBSZGET, &dev->block_size) < 0) { log_sys_error("ioctl BLKBSZGET", name); return 0; @@ -161,10 +164,10 @@ static void _widen_region(unsigned int block_size, struct device_area *region, result->size += block_size - delta; } -static int _aligned_io(struct device_area *where, void *buffer, +static int _aligned_io(struct device_area *where, char *buffer, int should_write) { - void *bounce, *bounce_buf; + char *bounce, *bounce_buf; unsigned int block_size = 0; uintptr_t mask; struct device_area widened; @@ -195,7 +198,7 @@ static int _aligned_io(struct device_area *where, void *buffer, * Realign start of bounce buffer (using the extra sector) */ if (((uintptr_t) bounce) & mask) - bounce = (void *) ((((uintptr_t) bounce) + mask) & ~mask); + bounce = (char *) ((((uintptr_t) bounce) + mask) & ~mask); /* channel the io through the bounce buffer */ if (!_io(&widened, bounce, 0)) { @@ -279,7 +282,7 @@ static int _dev_read_ahead_dev(struct device *dev, uint32_t *read_ahead) return 1; } - if (!dev_open(dev)) + if (!dev_open_readonly(dev)) return_0; if (ioctl(dev->fd, BLKRAGET, &read_ahead_long) < 0) { @@ -289,15 +292,42 @@ static int _dev_read_ahead_dev(struct device *dev, uint32_t *read_ahead) return 0; } - if (!dev_close(dev)) - stack; - *read_ahead = (uint32_t) read_ahead_long; dev->read_ahead = read_ahead_long; log_very_verbose("%s: read_ahead is %u sectors", dev_name(dev), *read_ahead); + if (!dev_close(dev)) + stack; + + return 1; +} + +static int _dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64_t size_bytes) +{ + uint64_t discard_range[2]; + + if (!dev_open(dev)) + return_0; + + discard_range[0] = offset_bytes; + discard_range[1] = size_bytes; + + log_debug("Discarding %" PRIu64 " bytes offset %" PRIu64 " bytes on %s.", + size_bytes, offset_bytes, dev_name(dev)); + if (ioctl(dev->fd, BLKDISCARD, &discard_range) < 0) { + log_error("%s: BLKDISCARD ioctl at offset %" PRIu64 " size %" PRIu64 " failed: %s.", + dev_name(dev), offset_bytes, size_bytes, strerror(errno)); + if (!dev_close(dev)) + stack; + /* It doesn't matter if discard failed, so return success. */ + return 1; + } + + if (!dev_close(dev)) + stack; + return 1; } @@ -329,6 +359,17 @@ int dev_get_read_ahead(struct device *dev, uint32_t *read_ahead) return _dev_read_ahead_dev(dev, read_ahead); } +int dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64_t size_bytes) +{ + if (!dev) + return 0; + + if (dev->flags & DEV_REGULAR) + return 1; + + return _dev_discard_blocks(dev, offset_bytes, size_bytes); +} + /* FIXME Unused int dev_get_sectsize(struct device *dev, uint32_t *size) { @@ -390,16 +431,15 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet) } if (dev->open_count && !need_excl) { - /* FIXME Ensure we never get here */ - log_error(INTERNAL_ERROR "%s already opened read-only", - dev_name(dev)); + log_debug("%s already opened read-only. Upgrading " + "to read-write.", dev_name(dev)); dev->open_count++; } dev_close_immediate(dev); } - if (memlock()) + if (critical_section()) /* FIXME Make this log_error */ log_verbose("dev_open(%s) called while suspended", dev_name(dev)); @@ -409,17 +449,6 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet) else if (!(name = dev_name_confirmed(dev, quiet))) return_0; - if (!(dev->flags & DEV_REGULAR)) { - if (stat(name, &buf) < 0) { - log_sys_error("%s: stat failed", name); - return 0; - } - if (buf.st_rdev != dev->dev) { - log_error("%s: device changed", name); - return 0; - } - } - #ifdef O_DIRECT_SUPPORT if (direct) { if (!(dev->flags & DEV_O_DIRECT_TESTED)) @@ -499,20 +528,27 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet) int dev_open_quiet(struct device *dev) { - int flags; - - flags = vg_write_lock_held() ? O_RDWR : O_RDONLY; - - return dev_open_flags(dev, flags, 1, 1); + return dev_open_flags(dev, O_RDWR, 1, 1); } int dev_open(struct device *dev) { - int flags; + return dev_open_flags(dev, O_RDWR, 1, 0); +} - flags = vg_write_lock_held() ? O_RDWR : O_RDONLY; +int dev_open_readonly(struct device *dev) +{ + return dev_open_flags(dev, O_RDONLY, 1, 0); +} + +int dev_open_readonly_buffered(struct device *dev) +{ + return dev_open_flags(dev, O_RDONLY, 0, 0); +} - return dev_open_flags(dev, flags, 1, 0); +int dev_open_readonly_quiet(struct device *dev) +{ + return dev_open_flags(dev, O_RDONLY, 1, 1); } int dev_test_excl(struct device *dev) @@ -550,7 +586,6 @@ static void _close(struct device *dev) static int _dev_close(struct device *dev, int immediate) { - struct lvmcache_info *info; if (dev->fd < 0) { log_error("Attempt to close device '%s' " @@ -572,10 +607,7 @@ static int _dev_close(struct device *dev, int immediate) /* Close unless device is known to belong to a locked VG */ if (immediate || - (dev->open_count < 1 && - (!(info = info_from_pvid(dev->pvid, 0)) || - !info->vginfo || - !vgname_is_locked(info->vginfo->vgname)))) + (dev->open_count < 1 && !lvmcache_pvid_is_locked(dev->pvid))) _close(dev); return 1; @@ -632,6 +664,8 @@ int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer) where.start = offset; where.size = len; + // fprintf(stderr, "READ: %s, %lld, %d\n", dev_name(dev), offset, len); + ret = _aligned_io(&where, buffer, 0); if (!ret) _dev_inc_error_count(dev); @@ -645,7 +679,7 @@ int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer) * 'buf' should be len+len2. */ int dev_read_circular(struct device *dev, uint64_t offset, size_t len, - uint64_t offset2, size_t len2, void *buf) + uint64_t offset2, size_t len2, char *buf) { if (!dev_read(dev, offset, len, buf)) { log_error("Read from %s failed", dev_name(dev)); @@ -673,7 +707,7 @@ int dev_read_circular(struct device *dev, uint64_t offset, size_t len, */ /* FIXME pre-extend the file */ -int dev_append(struct device *dev, size_t len, void *buffer) +int dev_append(struct device *dev, size_t len, char *buffer) { int r; diff --git a/lib/device/dev-luks.c b/lib/device/dev-luks.c index 6337992..10aae30 100644 --- a/lib/device/dev-luks.c +++ b/lib/device/dev-luks.c @@ -23,7 +23,7 @@ int dev_is_luks(struct device *dev, uint64_t *signature) char buf[LUKS_SIGNATURE_SIZE]; int ret = -1; - if (!dev_open(dev)) { + if (!dev_open_readonly(dev)) { stack; return -1; } diff --git a/lib/device/dev-md.c b/lib/device/dev-md.c index 89b9341..247a8ac 100644 --- a/lib/device/dev-md.c +++ b/lib/device/dev-md.c @@ -27,6 +27,7 @@ #define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512) #define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) \ - MD_RESERVED_SECTORS) +#define MD_MAX_SYSFS_SIZE 64 static int _dev_has_md_magic(struct device *dev, uint64_t sb_offset) { @@ -94,7 +95,7 @@ int dev_is_md(struct device *dev, uint64_t *sb) if (size < MD_RESERVED_SECTORS * 2) return 0; - if (!dev_open(dev)) { + if (!dev_open_readonly(dev)) { stack; return -1; } @@ -176,7 +177,7 @@ static int _md_sysfs_attribute_scanf(const char *sysfs_dir, const char *attribute_fmt, void *attribute_value) { - char path[PATH_MAX+1], buffer[64]; + char path[PATH_MAX+1], buffer[MD_MAX_SYSFS_SIZE]; FILE *fp; int ret = 0; @@ -231,15 +232,20 @@ static unsigned long dev_md_chunk_size(const char *sysfs_dir, */ static int dev_md_level(const char *sysfs_dir, struct device *dev) { + char level_string[MD_MAX_SYSFS_SIZE]; const char *attribute = "level"; int level = -1; if (_md_sysfs_attribute_scanf(sysfs_dir, dev, attribute, - "raid%d", &level) != 1) + "%s", &level_string) != 1) return -1; - log_very_verbose("Device %s %s is raid%d.", - dev_name(dev), attribute, level); + log_very_verbose("Device %s %s is %s.", + dev_name(dev), attribute, level_string); + + /* We only care about raid - ignore linear/faulty/multipath etc. */ + if (sscanf(level_string, "raid%d", &level) != 1) + return -1; return level; } diff --git a/lib/device/dev-swap.c b/lib/device/dev-swap.c index b8ebcca..346b60a 100644 --- a/lib/device/dev-swap.c +++ b/lib/device/dev-swap.c @@ -14,8 +14,6 @@ #include "lib.h" #include "metadata.h" -#include "xlate.h" -#include "filter.h" #ifdef linux @@ -42,14 +40,15 @@ int dev_is_swap(struct device *dev, uint64_t *signature) { char buf[10]; uint64_t size; - int page, ret = 0; + unsigned page; + int ret = 0; if (!dev_get_size(dev, &size)) { stack; return -1; } - if (!dev_open(dev)) { + if (!dev_open_readonly(dev)) { stack; return -1; } diff --git a/lib/device/device.c b/lib/device/device.c index 80b4479..a87ae7f 100644 --- a/lib/device/device.c +++ b/lib/device/device.c @@ -287,7 +287,7 @@ int get_primary_dev(const char *sysfs_dir, struct stat info; FILE *fp; uint32_t pri_maj, pri_min; - int ret = 0; + int size, ret = 0; /* check if dev is a partition */ if (dm_snprintf(path, PATH_MAX, "%s/dev/block/%d:%d/partition", @@ -309,11 +309,13 @@ int get_primary_dev(const char *sysfs_dir, * - basename ../../block/md0/md0 = md0 * Parent's 'dev' sysfs attribute = /sys/block/md0/dev */ - if (readlink(dirname(path), temp_path, PATH_MAX) < 0) { + if ((size = readlink(dirname(path), temp_path, PATH_MAX)) < 0) { log_sys_error("readlink", path); return ret; } + temp_path[size] = '\0'; + if (dm_snprintf(path, PATH_MAX, "%s/block/%s/dev", sysfs_dir, basename(dirname(temp_path))) < 0) { log_error("dm_snprintf dev failed"); @@ -345,7 +347,7 @@ int get_primary_dev(const char *sysfs_dir, path, buffer); goto out; } - *result = MKDEV(pri_maj, pri_min); + *result = MKDEV((dev_t)pri_maj, pri_min); ret = 1; out: @@ -359,7 +361,7 @@ static unsigned long _dev_topology_attribute(const char *attribute, const char *sysfs_dir, struct device *dev) { - const char *sysfs_fmt_str = "%s/dev/block/%d:%d/%s"; + static const char sysfs_fmt_str[] = "%s/dev/block/%d:%d/%s"; char path[PATH_MAX+1], buffer[64]; FILE *fp; struct stat info; @@ -453,6 +455,20 @@ unsigned long dev_optimal_io_size(const char *sysfs_dir, sysfs_dir, dev); } +unsigned long dev_discard_max_bytes(const char *sysfs_dir, + struct device *dev) +{ + return _dev_topology_attribute("queue/discard_max_bytes", + sysfs_dir, dev); +} + +unsigned long dev_discard_granularity(const char *sysfs_dir, + struct device *dev) +{ + return _dev_topology_attribute("queue/discard_granularity", + sysfs_dir, dev); +} + #else int get_primary_dev(const char *sysfs_dir, @@ -479,4 +495,16 @@ unsigned long dev_optimal_io_size(const char *sysfs_dir, return 0UL; } +unsigned long dev_discard_max_bytes(const char *sysfs_dir, + struct device *dev) +{ + return 0UL; +} + +unsigned long dev_discard_granularity(const char *sysfs_dir, + struct device *dev) +{ + return 0UL; +} + #endif diff --git a/lib/device/device.h b/lib/device/device.h index 694f503..8c32a03 100644 --- a/lib/device/device.h +++ b/lib/device/device.h @@ -68,11 +68,15 @@ struct device_area { int dev_get_size(const struct device *dev, uint64_t *size); int dev_get_sectsize(struct device *dev, uint32_t *size); int dev_get_read_ahead(struct device *dev, uint32_t *read_ahead); +int dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64_t size_bytes); /* Use quiet version if device number could change e.g. when opening LV */ int dev_open(struct device *dev); int dev_open_quiet(struct device *dev); int dev_open_flags(struct device *dev, int flags, int direct, int quiet); +int dev_open_readonly(struct device *dev); +int dev_open_readonly_buffered(struct device *dev); +int dev_open_readonly_quiet(struct device *dev); int dev_close(struct device *dev); int dev_close_immediate(struct device *dev); void dev_close_all(void); @@ -83,9 +87,9 @@ const char *dev_name(const struct device *dev); int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer); int dev_read_circular(struct device *dev, uint64_t offset, size_t len, - uint64_t offset2, size_t len2, void *buf); + uint64_t offset2, size_t len2, char *buf); int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer); -int dev_append(struct device *dev, size_t len, void *buffer); +int dev_append(struct device *dev, size_t len, char *buffer); int dev_set(struct device *dev, uint64_t offset, size_t len, int value); void dev_flush(struct device *dev); @@ -115,4 +119,10 @@ unsigned long dev_minimum_io_size(const char *sysfs_dir, unsigned long dev_optimal_io_size(const char *sysfs_dir, struct device *dev); +unsigned long dev_discard_max_bytes(const char *sysfs_dir, + struct device *dev); + +unsigned long dev_discard_granularity(const char *sysfs_dir, + struct device *dev); + #endif |