]> sourceware.org Git - lvm2.git/commitdiff
Sysfs block device filtering option for 2.6.
authorAlasdair Kergon <agk@redhat.com>
Fri, 13 Feb 2004 14:46:04 +0000 (14:46 +0000)
committerAlasdair Kergon <agk@redhat.com>
Fri, 13 Feb 2004 14:46:04 +0000 (14:46 +0000)
doc/example.conf
include/.symlinks
lib/Makefile.in
lib/commands/toolcontext.c
lib/config/defaults.h
lib/filters/filter-composite.c
lib/filters/filter-composite.h
lib/filters/filter-sysfs.c [new file with mode: 0644]
lib/filters/filter-sysfs.h [new file with mode: 0644]

index 1db94a858e826d0a09c902c0b6450d0a1ca652ab..9e832ab96c0dc5c72d305b80cc86064c5d00b06f 100644 (file)
@@ -61,6 +61,10 @@ devices {
     # List of pairs of additional acceptable block device types found 
     # in /proc/devices with maximum (non-zero) number of partitions.
     # types = [ "fd", 16 ]
+
+    # If sysfs is mounted (2.6 kernels) restrict device scanning to 
+    # the block devices it believes are valid.
+    sysfs_scan = 1     
 }
 
 # This section that allows you to configure the nature of the
index 9a5335cb5f106eeeda4d0695140c7683f1807783..51faa27599f236ba345a1a505d3f1c63bbabc4cc 100644 (file)
@@ -16,6 +16,7 @@
 ../lib/filters/filter-composite.h
 ../lib/filters/filter-persistent.h
 ../lib/filters/filter-regex.h
+../lib/filters/filter-sysfs.h
 ../lib/filters/filter.h
 ../lib/format1/format1.h
 ../lib/format_text/format-text.h
index 355950bf1024d0562c1a322602ee0d3cd2ebc60d..cbe6c96acd4f34c9f1dd4f353d3006ecc98c1553 100644 (file)
@@ -28,6 +28,7 @@ SOURCES=\
        filters/filter-composite.c \
        filters/filter-persistent.c \
        filters/filter-regex.c \
+       filters/filter-sysfs.c \
        filters/filter.c \
        format_text/archive.c \
        format_text/export.c \
index 496ac61605da8248384debbd6c26184ddaaf8956..ed81cf88e704f865b768e41b6ea25086a2500347 100644 (file)
@@ -16,6 +16,7 @@
 #include "filter-composite.h"
 #include "filter-persistent.h"
 #include "filter-regex.h"
+#include "filter-sysfs.h"
 #include "label.h"
 #include "lvm-file.h"
 #include "format-text.h"
@@ -261,33 +262,43 @@ static int _init_dev_cache(struct cmd_context *cmd)
        return 1;
 }
 
+#define MAX_FILTERS 3
+
 static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
 {
+       unsigned nr_filt = 0;
        struct config_node *cn;
-       struct dev_filter *f1, *f2, *f3;
+       struct dev_filter *filters[MAX_FILTERS];
 
-       cn = find_config_node(cmd->cf->root, "devices/types", '/');
+       memset(filters, 0, sizeof(filters));
 
-       if (!(f2 = lvm_type_filter_create(cmd->proc_dir, cn)))
-               return NULL;
+       /* sysfs filter */
+       if (find_config_bool(cmd->cf->root, "devices/sysfs_scan", '/',
+                            DEFAULT_SYSFS_SCAN)) {
+               if ((filters[nr_filt] = sysfs_filter_create(cmd->proc_dir)))
+                       nr_filt++;
+       }
 
-       if (!(cn = find_config_node(cmd->cf->root, "devices/filter", '/'))) {
+       /* regex filter */
+       if (!(cn = find_config_node(cmd->cf->root, "devices/filter", '/')))
                log_debug("devices/filter not found in config file: no regex "
                          "filter installed");
-               return f2;
-       }
 
-       if (!(f1 = regex_filter_create(cn->v))) {
+       else if (!(filters[nr_filt++] = regex_filter_create(cn->v))) {
                log_error("Failed to create regex device filter");
                return NULL;
        }
 
-       if (!(f3 = composite_filter_create(2, f1, f2))) {
-               log_error("Failed to create composite device filter");
+       /* device type filter */
+       cn = find_config_node(cmd->cf->root, "devices/types", '/');
+       if (!(filters[nr_filt++] = lvm_type_filter_create(cmd->proc_dir, cn))) {
+               log_error("Failed to create lvm type filter");
                return NULL;
        }
 
-       return f3;
+       /* only build a composite filter if we really need it */
+       return (nr_filt == 1) ?
+           filters[0] : composite_filter_create(nr_filt, filters);
 }
 
 static int _init_filters(struct cmd_context *cmd)
index bcebfa04fbcb4716d520f5662cda92d2b67993f6..b85b3d5d189760c614f72231e53e108c6d757970 100644 (file)
@@ -19,6 +19,7 @@
 #define DEFAULT_SYS_DIR "/etc/lvm"
 #define DEFAULT_DEV_DIR "/dev"
 #define DEFAULT_PROC_DIR "/proc"
+#define DEFAULT_SYSFS_SCAN 1
 
 #define DEFAULT_LOCK_DIR "/var/lock/lvm"
 #define DEFAULT_LOCKING_LIB "lvm2_locking.so"
index 78e41dc8c68bddef62deaa5317415f980a594653..a167abb0aca5e218d35c57f8939654d36897c109 100644 (file)
@@ -37,35 +37,32 @@ static void _destroy(struct dev_filter *f)
        dbg_free(f);
 }
 
-struct dev_filter *composite_filter_create(int n, ...)
+struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
 {
-       struct dev_filter **filters = dbg_malloc(sizeof(*filters) * (n + 1));
-       struct dev_filter *cf;
-       va_list ap;
-       int i;
+       struct dev_filter **filters_copy, *cf;
 
        if (!filters) {
                stack;
                return NULL;
        }
 
-       if (!(cf = dbg_malloc(sizeof(*cf)))) {
-               stack;
-               dbg_free(filters);
+       if (!(filters_copy = dbg_malloc(sizeof(*filters) * (n + 1)))) {
+               log_error("composite filters allocation failed");
                return NULL;
        }
 
-       va_start(ap, n);
-       for (i = 0; i < n; i++) {
-               struct dev_filter *f = va_arg(ap, struct dev_filter *);
-               filters[i] = f;
+       memcpy(filters_copy, filters, sizeof(*filters) * n);
+       filters_copy[n] = NULL;
+
+       if (!(cf = dbg_malloc(sizeof(*cf)))) {
+               log_error("compsoite filters allocation failed");
+               dbg_free(filters_copy);
+               return NULL;
        }
-       filters[i] = NULL;
-       va_end(ap);
 
        cf->passes_filter = _and_p;
        cf->destroy = _destroy;
-       cf->private = filters;
+       cf->private = filters_copy;
 
        return cf;
 }
index 7462e4e22764637b125eb16a5f66e17c86ed044a..b269381fc08acadf1b9dbe376e349031f7942a05 100644 (file)
@@ -9,6 +9,6 @@
 
 #include "dev-cache.h"
 
-struct dev_filter *composite_filter_create(int n, ...);
+struct dev_filter *composite_filter_create(int n, struct dev_filter **filters);
 
 #endif
diff --git a/lib/filters/filter-sysfs.c b/lib/filters/filter-sysfs.c
new file mode 100644 (file)
index 0000000..c04bb9d
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2004 Red Hat Inc
+ *
+ * This file is released under the GPL.
+ */
+
+#include "lib.h"
+#include "filter-sysfs.h"
+#include "lvm-string.h"
+#include "pool.h"
+
+#include <sys/sysmacros.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+static int _locate_sysfs_blocks(const char *proc, char *path, size_t len)
+{
+       char proc_mounts[PATH_MAX];
+       int r = 0;
+       FILE *fp;
+       char *split[2], buffer[PATH_MAX + 16];
+
+       if (!*proc) {
+               log_verbose("No proc filesystem found: skipping sysfs filter");
+               return 0;
+       }
+               
+       if (lvm_snprintf(proc_mounts, sizeof(proc_mounts),
+                        "%s/mounts", proc) < 0) {
+               log_error("Failed to create /proc/mounts string");
+               return 0;
+       }
+
+       if (!(fp = fopen(proc_mounts, "r"))) {
+               log_sys_error("fopen %s", proc_mounts);
+               return 0;
+       }
+
+       while (fgets(buffer, sizeof(buffer), fp)) {
+               if (split_words(buffer, 2, split) == 2 &&
+                   !strcmp(split[0], "sysfs")) {
+                       if (lvm_snprintf(path, len, "%s/%s", split[1],
+                                        "block") >= 0) {
+                               r = 1;
+                       }
+                       break;
+               }
+       }
+
+       fclose(fp);
+       return r;
+}
+
+/*----------------------------------------------------------------
+ * We need to store a set of dev_t.
+ *--------------------------------------------------------------*/
+struct entry {
+       struct entry *next;
+       dev_t dev;
+};
+
+#define SET_BUCKETS 64
+struct dev_set {
+       struct pool *mem;
+       const char *sys_block;
+       int initialised;
+       struct entry *slots[SET_BUCKETS];
+};
+
+static struct dev_set *_dev_set_create(struct pool *mem, const char *sys_block)
+{
+       struct dev_set *ds;
+
+       if (!(ds = pool_zalloc(mem, sizeof(*ds))))
+               return NULL;
+
+       ds->mem = mem;
+       ds->sys_block = pool_strdup(mem, sys_block);
+       ds->initialised = 0;
+
+       return ds;
+}
+
+static inline unsigned _hash_dev(dev_t dev)
+{
+       return (major(dev) ^ minor(dev)) & (SET_BUCKETS - 1);
+}
+
+/*
+ * Doesn't check that the set already contains dev.
+ */
+static int _set_insert(struct dev_set *ds, dev_t dev)
+{
+       struct entry *e;
+       unsigned h = _hash_dev(dev);
+
+       if (!(e = pool_alloc(ds->mem, sizeof(*e))))
+               return 0;
+
+       e->next = ds->slots[h];
+       e->dev = dev;
+       ds->slots[h] = e;
+
+       return 1;
+}
+
+static int _set_lookup(struct dev_set *ds, dev_t dev)
+{
+       unsigned h = _hash_dev(dev);
+       struct entry *e;
+
+       for (e = ds->slots[h]; e; e = e->next)
+               if (e->dev == dev)
+                       return 1;
+
+       return 0;
+}
+
+/*----------------------------------------------------------------
+ * filter methods
+ *--------------------------------------------------------------*/
+static int _parse_dev(const char *file, FILE *fp, dev_t *result)
+{
+       unsigned major, minor;
+       char buffer[64];
+
+       if (!fgets(buffer, sizeof(buffer), fp)) {
+               log_error("Empty sysfs device file: %s", file);
+               return 0;
+       }
+
+       if (sscanf(buffer, "%u:%u", &major, &minor) != 2) {
+               log_info("sysfs device file not correct format");
+               return 0;
+       }
+
+       *result = makedev(major, minor);
+       return 1;
+}
+
+static int _read_dev(const char *file, dev_t *result)
+{
+       int r;
+       FILE *fp;
+
+       if (!(fp = fopen(file, "r"))) {
+               log_sys_error("fopen", file);
+               return 0;
+       }
+
+       r = _parse_dev(file, fp, result);
+       fclose(fp);
+
+       return r;
+}
+
+/*
+ * Recurse through sysfs directories, inserting any devs found.
+ */
+static int _read_devs(struct dev_set *ds, const char *dir)
+{
+        struct dirent *d;
+        DIR *dr;
+       char path[PATH_MAX];
+       dev_t dev;
+       int r = 1;
+
+        if (!(dr = opendir(dir))) {
+                log_sys_error("opendir", dir);
+                return 0;
+        }
+
+        while ((d = readdir(dr))) {
+                if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+                       continue;
+
+               if (lvm_snprintf(path, sizeof(path), "%s/%s", dir,
+                                d->d_name) < 0) {
+                       log_error("sysfs path name too long: %s in %s",
+                                 d->d_name, dir);
+                       continue;
+               }
+
+               if (d->d_type == DT_DIR) {
+                       if (!_read_devs(ds, path)) {
+                               r = 0;
+                               break;
+                       }
+               }
+
+               if ((d->d_type == DT_REG && !strcmp(d->d_name, "dev")))
+                       if (!_read_dev(path, &dev) || !_set_insert(ds, dev)) {
+                               r = 0;
+                               break;
+                       }
+
+       }
+
+        if (closedir(dr))
+                log_sys_error("closedir", dir);
+
+       return r;
+}
+
+static int _init_devs(struct dev_set *ds)
+{
+       if (!_read_devs(ds, ds->sys_block)) {
+               ds->initialised = -1;
+               return 0;
+       }
+
+       ds->initialised = 1;
+
+       return 1;
+}
+
+
+static int _accept_p(struct dev_filter *f, struct device *dev)
+{
+       struct dev_set *ds = (struct dev_set *) f->private;
+
+       if (!ds->initialised)
+               _init_devs(ds);
+
+       /* Pass through if initialisation failed */
+       if (ds->initialised != 1)
+               return 1;
+
+       return _set_lookup(ds, dev->dev);
+}
+
+static void _destroy(struct dev_filter *f)
+{
+       struct dev_set *ds = (struct dev_set *) f->private;
+       pool_destroy(ds->mem);
+}
+
+struct dev_filter *sysfs_filter_create(const char *proc)
+{
+       char sys_block[PATH_MAX];
+       struct pool *mem;
+       struct dev_set *ds;
+       struct dev_filter *f;
+
+       if (!_locate_sysfs_blocks(proc, sys_block, sizeof(sys_block)))
+               return NULL;
+
+       if (!(mem = pool_create(256))) {
+               log_error("sysfs pool creation failed");
+               return NULL;
+       }
+
+       if (!(ds = _dev_set_create(mem, sys_block))) {
+               log_error("sysfs dev_set creation failed");
+               goto bad;
+       }
+
+       if (!(f = pool_zalloc(mem, sizeof(*f)))) {
+               stack;
+               goto bad;
+       }
+
+       f->passes_filter = _accept_p;
+       f->destroy = _destroy;
+       f->private = ds;
+       return f;
+
+ bad:
+       pool_destroy(mem);
+       return NULL;
+}
+
diff --git a/lib/filters/filter-sysfs.h b/lib/filters/filter-sysfs.h
new file mode 100644 (file)
index 0000000..2c6f750
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2004 Red Hat Inc
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef _LVM_FILTER_SYSFS_H
+#define _LVM_FILTER_SYSFS_H
+
+#include "config.h"
+#include "dev-cache.h"
+
+struct dev_filter *sysfs_filter_create(const char *proc);
+
+#endif
This page took 0.052122 seconds and 5 git commands to generate.