summaryrefslogtreecommitdiff
path: root/lib/device
diff options
context:
space:
mode:
Diffstat (limited to 'lib/device')
-rw-r--r--lib/device/dev-cache.c291
-rw-r--r--lib/device/dev-cache.h8
-rw-r--r--lib/device/dev-io.c114
-rw-r--r--lib/device/dev-luks.c2
-rw-r--r--lib/device/dev-md.c16
-rw-r--r--lib/device/dev-swap.c7
-rw-r--r--lib/device/device.c36
-rw-r--r--lib/device/device.h14
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