From 8696e06602df6ee380d045ec763e4fed01b70932 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 3 Oct 2001 12:41:29 +0000 Subject: [PATCH] o I've moved the dev-cache and dev-io into here since this directory has a better name. dev-mgr will be removed at some point. --- lib/device/dev-cache.c | 272 +++++++++++++++++++++++++++++++++++++++++ lib/device/dev-cache.h | 41 +++++++ lib/device/dev-io.c | 42 +++++++ lib/device/device.c | 4 +- lib/device/device.h | 43 ++++--- 5 files changed, 383 insertions(+), 19 deletions(-) create mode 100644 lib/device/dev-cache.c create mode 100644 lib/device/dev-cache.h create mode 100644 lib/device/dev-io.c diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c new file mode 100644 index 000000000..fecc54a15 --- /dev/null +++ b/lib/device/dev-cache.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include "dev-cache.h" +#include "log.h" +#include "pool.h" +#include "hash.h" +#include "list.h" +#include "dbg_malloc.h" + +#include +#include +#include +#include +#include +#include + +/* + * FIXME: really need to seperate names from the devices since + * multiple names can point to the same device. + */ + +struct dev_iter { + struct hash_node *current; + struct dev_filter *filter; +}; + +struct dir_list { + struct list_head list; + char dir[0]; +}; + +static struct { + struct pool *mem; + struct hash_table *devices; + + int has_scanned; + struct list_head dirs; + +} _cache; + + +#define _alloc(x) pool_alloc(_cache.mem, (x)) +#define _free(x) pool_free(_cache.mem, (x)) + +/* + * return a new path for the destination of the path. + */ +static char *_follow_link(const char *path, struct stat *info) +{ + char buffer[PATH_MAX + 1]; + int n; + n = readlink(path, buffer, sizeof(buffer) - 1); + + if (n <= 0) + return NULL; + + buffer[n] = '\0'; + + if (stat(buffer, info) < 0) { + log_sys_err("stat"); + return NULL; + } + + return pool_strdup(_cache.mem, buffer); +} + +/* + * Get rid of extra slashes in the path string. + */ +static void _collapse_slashes(char *str) +{ + char *ptr; + int was_slash = 0; + + for (ptr = str; *ptr; ptr++) { + if (*ptr == '/') { + if (was_slash) + continue; + + was_slash = 1; + } else + was_slash = 0; + *str++ = *ptr; + } + + *str = *ptr; +} + +static struct device *_create_dev(const char *path) +{ + struct stat info; + struct device *dev; + char *name = pool_strdup(_cache.mem, path); + + if (!name) { + stack; + return NULL; + } + + _collapse_slashes(name); + + if (stat(name, &info) < 0) { + log_sys_err("stat"); + goto bad; + } + + if (S_ISLNK(info.st_mode)) { + log_debug("%s is a symbolic link, following\n", name); + if (!(name = _follow_link(name, &info))) { + stack; + goto bad; + } + } + + if (!S_ISBLK(info.st_mode)) { + log_debug("%s is not a block device\n", name); + goto bad; + } + + if (!(dev = _alloc(sizeof(*dev)))) { + stack; + goto bad; + } + + dev->name = name; + dev->dev = info.st_rdev; + return dev; + + bad: + _free(name); + return NULL; +} + +static struct device *_add(const char *dir, const char *path) +{ + struct device *d; + int len = strlen(dir) + strlen(path) + 2; + char *buffer = dbg_malloc(len); + + snprintf(buffer, len, "%s/%s", dir, path); + d = dev_cache_get(buffer, NULL); + dbg_free(buffer); + + return d; +} + +static int _dir_scan(const char *dir) +{ + int n, dirent_count; + struct dirent **dirent; + + dirent_count = scandir(dir, &dirent, NULL, alphasort); + if (dirent_count > 0) { + for (n = 0; n < dirent_count; n++) { + _add(dir, dirent[n]->d_name); + free(dirent[n]); + } + free(dirent); + } + + return 1; +} + +static void _full_scan(void) +{ + struct list_head *tmp; + + if (_cache.has_scanned) + return; + + list_for_each(tmp, &_cache.dirs) { + struct dir_list *dl = list_entry(tmp, struct dir_list, list); + _dir_scan(dl->dir); + } + + _cache.has_scanned = 1; +} + +int dev_cache_init(void) +{ + if (!(_cache.mem = pool_create(10 * 1024))) { + stack; + return 0; + } + + if (!(_cache.devices = hash_create(128))) { + stack; + pool_destroy(_cache.mem); + _cache.mem = 0; + return 0; + } + + return 1; +} + +void dev_cache_exit(void) +{ + pool_destroy(_cache.mem); + hash_destroy(_cache.devices); +} + +int dev_cache_add_dir(const char *path) +{ + struct dir_list *dl; + + if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) + return 0; + + strcpy(dl->dir, path); + list_add(&dl->list, &_cache.dirs); + return 1; +} + +struct device *_insert_new(const char *name) +{ + struct device *d = _create_dev(name); + if (!d || !hash_insert(_cache.devices, name, d)) + return NULL; + + return d; +} + +struct device *dev_cache_get(const char *name, struct dev_filter *f) +{ + struct device *d = (struct device *) hash_lookup(_cache.devices, name); + return (d && (!f || f->passes_filter(f, d))) ? d : NULL; +} + +struct dev_iter *dev_iter_create(struct dev_filter *f) +{ + struct dev_iter *di = dbg_malloc(sizeof(*di)); + + if (!di) + return NULL; + + _full_scan(); + di->current = hash_get_first(_cache.devices); + di->filter = f; + + return di; +} + +void dev_iter_destroy(struct dev_iter *iter) +{ + dbg_free(iter); +} + +static inline struct device *_iter_next(struct dev_iter *iter) +{ + struct device *d = hash_get_data(_cache.devices, iter->current); + iter->current = hash_get_next(_cache.devices, iter->current); + return d; +} + +struct device *dev_iter_get(struct dev_iter *iter) +{ + while (iter->current) { + struct device *d = _iter_next(iter); + if (!iter->filter || + iter->filter->passes_filter(iter->filter, d)) + return d; + } + + return NULL; +} + + + diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h new file mode 100644 index 000000000..defd5986e --- /dev/null +++ b/lib/device/dev-cache.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#ifndef _LVM_DEV_CACHE_H +#define _LVM_DEV_CACHE_H + +#include +#include "lvm-types.h" +#include "device.h" + +/* + * predicate for devices. + */ +struct dev_filter { + int (*passes_filter)(struct dev_filter *f, struct device *dev); + void *private; +}; + + +/* + * The global device cache. + */ +int dev_cache_init(void); +void dev_cache_exit(void); + +int dev_cache_add_dir(const char *path); +struct device *dev_cache_get(const char *name, struct dev_filter *f); + + +/* + * Object for iterating through the cache. + */ +struct dev_iter; +struct dev_iter *dev_iter_create(struct dev_filter *f); +void dev_iter_destroy(struct dev_iter *iter); +struct device *dev_iter_get(struct dev_iter *iter); + +#endif diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c new file mode 100644 index 000000000..be4f24724 --- /dev/null +++ b/lib/device/dev-io.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2001 Sistina Software + * + * This file is released under the GPL. + */ + +int dev_get_size(struct device *dev, uint64_t *size) +{ + int fd; + long s; + + log_verbose("Getting device size"); + if ((fd = open(pv, O_RDONLY)) < 0) { + log_sys_error("open"); + return 0; + } + + /* FIXME: add 64 bit ioctl */ + if (ioctl(fd, BLKGETSIZE, &s) < 0) { + log_sys_err("ioctl"); + close(fd); + return 0; + } + + close(fd); + *size = (uint64_t) s; + return 1; +} + +int64_t dev_read(struct device *dev, uint64_t offset, + int64_t len, void *buffer) +{ + // FIXME: lazy programmer + return 0; +} + +int64_t dev_write(struct device *dev, uint64_t offset, + int64_t len, void *buffer) +{ + // FIXME: lazy programmer + return 0; +} diff --git a/lib/device/device.c b/lib/device/device.c index 87ad84c4c..729e809e7 100644 --- a/lib/device/device.c +++ b/lib/device/device.c @@ -38,11 +38,11 @@ #include #include -int _get_partition_type(struct dev_mgr *dm, struct device *d); +int _get_partition_type(struct dev_filter *filter, struct device *d); #define MINOR_PART(dm, d) (MINOR((d)->dev) % dev_max_partitions(dm, (d)->dev)) -int is_whole_disk(struct dev_mgr *dm, struct device *d) +int is_whole_disk(struct dev_filter *filter, struct device *d) { return (MINOR_PART(dm, d)) ? 0 : 1; } diff --git a/lib/device/device.h b/lib/device/device.h index 4dbaf425e..ee5f3b1b0 100644 --- a/lib/device/device.h +++ b/lib/device/device.h @@ -1,27 +1,36 @@ /* - * Copyright (C) 2001 Sistina Software + * Copyright (C) 2001 Sistina Software (UK) Limited. * - * This LVM library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This LVM library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this LVM library; if not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA + * This file is released under the GPL. */ #ifndef _LVM_DEVICE_H #define _LVM_DEVICE_H -int do_ioctl(const char *file, int mode, unsigned long cmd, void *req); -int device_get_size(const char *dev_name); +#include "lvm-types.h" + +/* + * All devices in LVM will be represented by one of these. + * pointer comparisons are valid. + */ +struct device { + char *name; + dev_t dev; +}; + +/* + * All io should use these routines, rather than opening the devices + * by hand. You do not have to call an open routine. ATM all io is + * immediately flushed. + */ +int dev_get_size(struct device *dev, uint64_t *size); +int64_t dev_read(struct device *dev, + uint64_t offset, int64_t len, void *buffer); +int64_t dev_write(struct device *dev, + uint64_t offset, int64_t len, void *buffer); + +/* FIXME: Alasdair lets add more query functions here for accessing + the partition information, this can then be used by your filter. */ #endif