From 01c4ac131518d08bda8739a4f288517150899673 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 7 Nov 2001 12:12:56 +0000 Subject: [PATCH] Tidy and changes to make code smaller. o Created dmfs.h as a private header for the filesystem code o Using seq_file.[ch] written by Al Viro as a generic mechanism for /proc style files which have one record per line. We use a slight modification here, so if you are using a recent -ac kernel you'll need to replace the existing seq_file.[ch] with the ones here and do a bit of editing to make it work. I'll submit the changes to Al Viro shortly as they are very small and I think make sense generally. o Using fail_writepage() o Init code for filesystem now all in dmfs-super.c o Some common code reduction amoung the dmfs-*.c files o Auto allocation of major device number (default). You can specify a particular major by using a module argument. If built in then you don't get this option at the moment but it could be added if required. o Hotplug support o General tidying o Updated projects.txt file o Patches updated to 2.4.14 --- driver/device-mapper/dm-fs.c | 552 ----------------------- driver/device-mapper/dm-parse.c | 201 --------- driver/device-mapper/dm.h | 18 - driver/device-mapper/dmfs-error.c | 107 ++--- driver/device-mapper/dmfs-lv.c | 5 +- driver/device-mapper/dmfs-root.c | 10 +- driver/device-mapper/dmfs-status.c | 10 +- driver/device-mapper/dmfs-super.c | 45 +- driver/device-mapper/dmfs-table.c | 19 +- driver/device-mapper/dmfs-tdir.c | 3 +- driver/device-mapper/dmfs.h | 26 ++ driver/device-mapper/patches/00_config | 8 +- driver/device-mapper/patches/00_ksyms | 6 +- driver/device-mapper/patches/00_makefile | 26 +- driver/device-mapper/projects.txt | 19 - driver/device-mapper/seq_file.c | 240 ++++++++++ driver/device-mapper/seq_file.h | 60 +++ 17 files changed, 446 insertions(+), 909 deletions(-) delete mode 100644 driver/device-mapper/dm-fs.c delete mode 100644 driver/device-mapper/dm-parse.c create mode 100644 driver/device-mapper/dmfs.h create mode 100644 driver/device-mapper/seq_file.c create mode 100644 driver/device-mapper/seq_file.h diff --git a/driver/device-mapper/dm-fs.c b/driver/device-mapper/dm-fs.c deleted file mode 100644 index c39270ef8..000000000 --- a/driver/device-mapper/dm-fs.c +++ /dev/null @@ -1,552 +0,0 @@ -/* - * *very* heavily based on ramfs - * - * Copyright (C) 2001 Sistina Software - * - * This file is released under the GPL. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "dm.h" - -/* some magic number */ -#define DM_MAGIC 0x444D4653 - -static struct super_operations dm_ops; -static struct address_space_operations dm_aops; -static struct file_operations dm_dir_operations; -static struct file_operations dm_file_operations; -static struct inode_operations dm_dir_inode_operations; - -struct vfsmount *_mnt; - -static int _unlink(struct inode *dir, struct dentry *dentry); - -#define NOT_A_TABLE ((struct dm_table *) 1) - -/* - * context for the line splitter and error function. - */ -struct line_c { - unsigned int line_num; - loff_t next_read; - char data[MAX_TARGET_LINE]; - - struct file *in; - struct file *out; -}; - -static int is_identifier(const char *str, int len) -{ - if (len > DM_NAME_LEN - 1) - return 0; - - while(len--) { - if (!isalnum(*str) && *str != '_') - return 0; - str++; - } - - return 1; -} - -/* - * Grabs lines one at a time from the table file. - */ -int extract_line(struct text_region *line, void *private) -{ - struct line_c *lc = (struct line_c *) private; - struct text_region text; - ssize_t n; - loff_t off = lc->next_read; - const char *read_begin; - mm_segment_t fs; - - fs = get_fs(); - set_fs(get_ds()); - - n = lc->in->f_op->read(lc->in, lc->data, sizeof (lc->data), &off); - - set_fs(fs); - - if (n <= 0) - return 0; - - read_begin = text.b = lc->data; - text.e = lc->data + n; - - if (!dm_get_line(&text, line)) - return 0; - - lc->line_num++; - lc->next_read += line->e - read_begin; - - return 1; -} - -static struct file *open_error_file(struct file *table) -{ - struct file *f; - char *name, *buffer; - int bufsize = PATH_MAX + 1; - - if (bufsize < PAGE_SIZE) - bufsize = PAGE_SIZE; - - /* Get space to append ".err" */ - buffer = (char *) kmalloc(bufsize + 4, GFP_KERNEL); - - if (!buffer) - return 0; - - /* Get path name */ - name = d_path(table->f_dentry, table->f_vfsmnt, buffer, bufsize); - - if (!name) { - kfree(buffer); - return 0; - } - - /* Create error file */ - strcat(name, ".err"); - f = filp_open(name, O_WRONLY | O_TRUNC | O_CREAT, S_IRUGO); - - kfree(buffer); - - if (f) - f->f_dentry->d_inode->u.generic_ip = NOT_A_TABLE; - - return f; -} - -static void close_error_file(struct file *out) -{ - fput(out); -} - -static void parse_error(const char *message, void *private) -{ - struct line_c *lc = (struct line_c *) private; - char buffer[32]; - -#define emit(b, l) lc->out->f_op->write(lc->out, (b), (l), &lc->out->f_pos) - - emit(lc->in->f_dentry->d_name.name, lc->in->f_dentry->d_name.len); - sprintf(buffer, "(%d): ", lc->line_num); - emit(buffer, strlen(buffer)); - emit(message, strlen(message)); - emit("\n", 1); - -#undef emit -} - -static int _release(struct inode *inode, struct file *f) -{ - /* FIXME: we should lock the inode to - prevent someone else opening it while - we are parsing */ - struct line_c *lc; - struct dm_table *table = (struct dm_table *) inode->u.generic_ip; - - /* noop for files without tables (.err files) */ - if (table == NOT_A_TABLE) - return 0; - - /* only bother parsing if it was open for a write */ - if (!(f->f_mode & S_IWUGO)) - return 0; - - /* free off the old table */ - if (table) { - dm_table_destroy(table); - inode->u.generic_ip = 0; - } - - if (!(lc = kmalloc(sizeof (*lc), GFP_KERNEL))) - return -ENOMEM; - - memset(lc, 0, sizeof (*lc)); - lc->in = f; - - if (!(lc->out = open_error_file(lc->in))) - return -ENOMEM; - - table = dm_parse(extract_line, lc, parse_error, lc); - close_error_file(lc->out); - - kfree(lc); - inode->u.generic_ip = table; - - return 0; -} - -void _put_inode(struct inode *inode) -{ - struct mapped_device *md = - (struct mapped_device *) inode->u.generic_ip; - struct dm_table *table = (struct dm_table *) inode->u.generic_ip; - - if (inode->i_mode & S_IFDIR) { - if (md) - dm_remove(md); - - } else { - if (table) - dm_table_destroy(table); - - } - - inode->u.generic_ip = 0; - force_delete(inode); -} - -static int _statfs(struct super_block *sb, struct statfs *buf) -{ - buf->f_type = DM_MAGIC; - buf->f_bsize = PAGE_CACHE_SIZE; - buf->f_namelen = 255; - return 0; -} - -/* - * Lookup the data. This is trivial - if the dentry didn't already - * exist, we know it is negative. - */ -static struct dentry *_lookup(struct inode *dir, struct dentry *dentry) -{ - d_add(dentry, NULL); - return NULL; -} - -/* - * Read a page. Again trivial. If it didn't already exist - * in the page cache, it is zero-filled. - */ -static int _readpage(struct file *file, struct page *page) -{ - if (!Page_Uptodate(page)) { - memset(kmap(page), 0, PAGE_CACHE_SIZE); - kunmap(page); - flush_dcache_page(page); - SetPageUptodate(page); - } - UnlockPage(page); - return 0; -} - -/* - * Writing: just make sure the page gets marked dirty, so that - * the page stealer won't grab it. - */ -static int _writepage(struct page *page) -{ - SetPageDirty(page); - UnlockPage(page); - return 0; -} - -static int _prepare_write(struct file *file, struct page *page, - unsigned offset, unsigned to) -{ - void *addr = kmap(page); - if (!Page_Uptodate(page)) { - memset(addr, 0, PAGE_CACHE_SIZE); - flush_dcache_page(page); - SetPageUptodate(page); - } - SetPageDirty(page); - return 0; -} - -static int _commit_write(struct file *file, struct page *page, - unsigned offset, unsigned to) -{ - struct inode *inode = page->mapping->host; - loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + to; - - kunmap(page); - if (pos > inode->i_size) - inode->i_size = pos; - return 0; -} - -struct inode *_get_inode(struct super_block *sb, int mode, int dev) -{ - struct inode *inode = new_inode(sb); - - if (inode) { - inode->i_mode = mode; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; - inode->i_blocks = 0; - inode->i_rdev = NODEV; - inode->i_mapping->a_ops = &dm_aops; - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - switch (mode & S_IFMT) { - case S_IFBLK: - case S_IFCHR: - init_special_inode(inode, mode, dev); - break; - case S_IFREG: - inode->i_fop = &dm_file_operations; - break; - case S_IFDIR: - inode->i_op = &dm_dir_inode_operations; - inode->i_fop = &dm_dir_operations; - break; - case S_IFLNK: - inode->i_op = &page_symlink_inode_operations; - break; - default: - make_bad_inode(inode); - } - } - return inode; -} - -/* - * File creation. Allocate an inode, and we're done.. - */ -static int _mknod(struct inode *dir, struct dentry *dentry, int mode) -{ - int error = -ENOSPC; - struct inode *inode = _get_inode(dir->i_sb, mode, 0); - - if (inode) { - d_instantiate(dentry, inode); - dget(dentry); /* Extra count - pin the dentry in core */ - error = 0; - } - - return error; -} - -static int _mkdir(struct inode *dir, struct dentry *dentry, int mode) -{ - int r; - const char *name = (const char *) dentry->d_name.name; - struct mapped_device *md; - - if (!is_identifier(name, dentry->d_name.len)) - return -EPERM; /* or EINVAL ? */ - - md = dm_create(name, -1); - if (IS_ERR(md)) - return PTR_ERR(md); - - r = _mknod(dir, dentry, mode | S_IFDIR); - if (r) { - dm_remove(md); - return r; - } - - dentry->d_inode->u.generic_ip = md; - - return 0; -} - -static int _rmdir(struct inode *dir, struct dentry *dentry) -{ - int r = _unlink(dir, dentry); - return r; -} - -static int _create(struct inode *dir, struct dentry *dentry, int mode) -{ - int r; - - if ((r = _mknod(dir, dentry, mode | S_IFREG))) - return r; - - dentry->d_inode->u.generic_ip = 0; - return 0; -} - -static inline int positive(struct dentry *dentry) -{ - return dentry->d_inode && !d_unhashed(dentry); -} - -/* - * Check that a directory is empty (this works - * for regular files too, they'll just always be - * considered empty..). - * - * Note that an empty directory can still have - * children, they just all have to be negative.. - */ -static int _empty(struct dentry *dentry) -{ - struct list_head *list; - - spin_lock(&dcache_lock); - list = dentry->d_subdirs.next; - - while (list != &dentry->d_subdirs) { - struct dentry *de = list_entry(list, struct dentry, d_child); - - if (positive(de)) { - spin_unlock(&dcache_lock); - return 0; - } - list = list->next; - } - spin_unlock(&dcache_lock); - return 1; -} - -/* - * This works for both directories and regular files. - * (non-directories will always have empty subdirs) - */ -static int _unlink(struct inode *dir, struct dentry *dentry) -{ - int retval = -ENOTEMPTY; - - if (_empty(dentry)) { - struct inode *inode = dentry->d_inode; - - inode->i_nlink--; - dput(dentry); /* Undo the count from "create" - this does all the work */ - retval = 0; - } - return retval; -} - -/* - * The VFS layer already does all the dentry stuff for rename, - * we just have to decrement the usage count for the target if - * it exists so that the VFS layer correctly free's it when it - * gets overwritten. - */ -static int _rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) -{ - struct inode *inode = new_dentry->d_inode; - struct mapped_device *md = old_dir->u.generic_ip; - struct dm_table *table = old_dentry->d_inode->u.generic_ip; - - if (!md || !table) - return -EINVAL; - - if (!_empty(new_dentry)) - return -ENOTEMPTY; - - if (!strcmp(new_dentry->d_name.name, "ACTIVE")) { - /* activate the table */ - dm_activate(md, table); - - } else if (!strcmp(old_dentry->d_name.name, "ACTIVE")) { - dm_suspend(md); - - } - - if (inode) { - inode->i_nlink--; - dput(new_dentry); - } - - return 0; -} - -static int _sync_file(struct file *file, struct dentry *dentry, - int datasync) -{ - return 0; -} - -static struct address_space_operations dm_aops = { - readpage: _readpage, - writepage: _writepage, - prepare_write: _prepare_write, - commit_write: _commit_write -}; - -static struct file_operations dm_file_operations = { - read: generic_file_read, - write: generic_file_write, - fsync: _sync_file, - release: _release, -}; - -static struct file_operations dm_dir_operations = { - read: generic_read_dir, - readdir: dcache_readdir, - fsync: _sync_file, -}; - -static struct inode_operations root_dir_inode_operations = { - lookup: _lookup, - mkdir: _mkdir, - rmdir: _rmdir, - rename: _rename, -}; - -static struct inode_operations dm_dir_inode_operations = { - create: _create, - lookup: _lookup, - unlink: _unlink, - rename: _rename, -}; - -static struct super_operations dm_ops = { - statfs: _statfs, - put_inode: _put_inode, -}; - -static struct super_block *_read_super(struct super_block *sb, void *data, - int silent) -{ - struct inode *inode; - struct dentry *root; - - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = DM_MAGIC; - sb->s_op = &dm_ops; - inode = _get_inode(sb, S_IFDIR | 0755, 0); - inode->i_op = &root_dir_inode_operations; - if (!inode) - return NULL; - - root = d_alloc_root(inode); - if (!root) { - iput(inode); - return NULL; - } - sb->s_root = root; - return sb; -} - -static DECLARE_FSTYPE(_fs_type, "dmfs", _read_super, FS_SINGLE); - -int __init dm_fs_init(void) -{ - int r; - if ((r = register_filesystem(&_fs_type))) - return r; - - _mnt = kern_mount(&_fs_type); - - if (IS_ERR(_mnt)) { - unregister_filesystem(&_fs_type); - return PTR_ERR(_mnt); - } - - return 0; -} - -void __exit dm_fs_exit(void) -{ - unregister_filesystem(&_fs_type); -} diff --git a/driver/device-mapper/dm-parse.c b/driver/device-mapper/dm-parse.c deleted file mode 100644 index 689e0a425..000000000 --- a/driver/device-mapper/dm-parse.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * dm-parse.c - * - * Copyright (C) 2001 Sistina Software - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2, or (at - * your option) any later version. - * - * This software 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * 4/09/2001 - First version [Joe Thornber] - */ - -#include "dm.h" - -struct dm_table *dm_parse(extract_line_fn line_fn, void *l_private, - dm_error_fn err_fn, void *e_private) -{ - struct text_region line, word; - struct dm_table *table = dm_table_create(); - struct target_type *ttype; - offset_t start, size, high; - char target_name[64]; - void *context; - int last_line_good = 1, was_error = 0; - - if (!table) - return 0; - -#define PARSE_ERROR(msg) {\ - last_line_good = 0;\ - was_error = 1;\ - err_fn(msg, e_private);\ - continue;} - - while (line_fn(&line, l_private)) { - - /* - * each line is of the format: - * - */ - - /* the line may be blank ... */ - dm_eat_space(&line); - if (dm_empty_tok(&line) || (*line.b == '#')) - continue; - - /* sector start */ - if (!dm_get_number(&line, &start)) - PARSE_ERROR("expecting a number for sector start"); - - /* length */ - if (!dm_get_number(&line, &size)) - PARSE_ERROR("expecting a number for region length"); - - /* target type */ - if (!dm_get_word(&line, &word)) - PARSE_ERROR("target type missing"); - - /* we have to copy the target type to a C str */ - dm_txt_copy(target_name, sizeof(target_name), &word); - - /* lookup the target type */ - if (!(ttype = dm_get_target_type(target_name))) - PARSE_ERROR("unable to find target type"); - - /* check there isn't a gap, but only if the last target - parsed ok. */ - if (last_line_good && - - ((table->num_targets && - start != table->highs[table->num_targets - 1] + 1) || - (!table->num_targets && start))) - PARSE_ERROR("gap in target ranges"); - - /* build the target */ - if (ttype->ctr(table, start, size, &line, &context, - err_fn, e_private)) - PARSE_ERROR("target constructor failed"); - - /* no point registering the target - if there was an error. */ - if (was_error) { - ttype->dtr(table, context); - continue; - } - - /* add the target to the table */ - high = start + (size - 1); - if (dm_table_add_target(table, high, ttype, context)) - PARSE_ERROR("internal error adding target to table"); - } - -#undef PARSE_ERROR - - if (was_error || dm_table_complete(table)) { - dm_table_destroy(table); - return 0; - } - - return table; -} - -/* - * convert the text in txt to an unsigned int, - * returns 0 on failure. - */ -int dm_get_number(struct text_region *txt, unsigned int *n) -{ - char *ptr; - - dm_eat_space(txt); - if (dm_empty_tok(txt)) - return 0; - - *n = simple_strtoul(txt->b, &ptr, 10); - if (ptr == txt->b) - return 0; - - txt->b = ptr; - - return 1; -} - -/* - * extracts text up to the next '\n'. - */ -int dm_get_line(struct text_region *txt, struct text_region *line) -{ - const char *ptr; - - dm_eat_space(txt); - if (dm_empty_tok(txt)) - return 0; - - ptr = line->b = txt->b; - while((ptr != txt->e) && (*ptr != '\n')) - ptr++; - - txt->b = line->e = ptr; - return 1; -} - -/* - * extracts the next non-whitespace token from the file. - */ -int dm_get_word(struct text_region *txt, struct text_region *word) -{ - const char *ptr; - - dm_eat_space(txt); - - if (dm_empty_tok(txt)) - return 0; - - word->b = txt->b; - for (ptr = word->b = txt->b; - ptr != txt->e && !isspace((int) *ptr); ptr++) - ; - - word->e = txt->b = ptr; - - return 1; -} - -/* - * copy a text region into a traditional C str. - */ -void dm_txt_copy(char *dest, size_t max, struct text_region *txt) -{ - size_t len = txt->e - txt->b; - if (len > --max) - len = max; - strncpy(dest, txt->b, len); - dest[len] = '\0'; -} - -/* - * skip leading whitespace - */ -void dm_eat_space(struct text_region *txt) -{ - while(txt->b != txt->e && isspace((int) *txt->b)) - (txt->b)++; -} - - -EXPORT_SYMBOL(dm_get_number); -EXPORT_SYMBOL(dm_get_word); -EXPORT_SYMBOL(dm_txt_copy); -EXPORT_SYMBOL(dm_eat_space); diff --git a/driver/device-mapper/dm.h b/driver/device-mapper/dm.h index 5e2faa10b..d16f3ece4 100644 --- a/driver/device-mapper/dm.h +++ b/driver/device-mapper/dm.h @@ -201,16 +201,6 @@ struct mapped_device { devfs_handle_t devfs_entry; }; -struct dmfs_i { - struct semaphore sem; - struct dm_table *table; - struct mapped_device *md; - struct dentry *dentry; - struct list_head errors; -}; - -#define DMFS_I(inode) ((struct dmfs_i *)(inode)->u.generic_ip) - extern struct block_device_operations dm_blk_dops; @@ -239,14 +229,6 @@ int dm_table_add_target(struct dm_table *t, offset_t high, struct target_type *type, void *private); int dm_table_complete(struct dm_table *t); -/* dmfs-error.c */ -void dmfs_add_error(struct inode *inode, unsigned num, char *str); -void dmfs_zap_errors(struct inode *inode); - -/* dmfs-super.c */ -struct super_block *dmfs_read_super(struct super_block *, void *, int); -struct inode *dmfs_new_inode(struct super_block *sb, int mode); - #define WARN(f, x...) printk(KERN_WARNING "device-mapper: " f "\n" , ## x) /* diff --git a/driver/device-mapper/dmfs-error.c b/driver/device-mapper/dmfs-error.c index 9bfb9cbeb..97009af13 100644 --- a/driver/device-mapper/dmfs-error.c +++ b/driver/device-mapper/dmfs-error.c @@ -22,8 +22,10 @@ #include #include #include +#include #include "dm.h" +#include "dmfs.h" struct dmfs_error { struct list_head list; @@ -55,76 +57,51 @@ void dmfs_zap_errors(struct inode *inode) } } -static struct dmfs_error *find_initial_message(struct inode *inode, loff_t *pos) +static void *e_start(void *context, loff_t *pos) { - struct dmfs_error *e; - struct list_head *tmp, *head; - - tmp = head = &DMFS_I(inode)->errors; - for(;;) { - tmp = tmp->next; - if (tmp == head) - break; - e = list_entry(tmp, struct dmfs_error, list); - if (*pos < e->len) - return e; - (*pos) -= e->len; - } + struct list_head *p; + loff_t n = *pos; + struct dmfs_i *dmi = context; + down(&dmi->sem); + list_for_each(p, &dmi->errors) + if (n-- == 0) + return list_entry(p, struct dmfs_error, list); return NULL; } -static int copy_sequence(struct inode *inode, struct dmfs_error *e, char *buf, - size_t size, loff_t offset) +static void *e_next(void *context, void *v, loff_t *pos) { - char *from; - int amount; - int copied = 0; - - do { - from = e->msg + offset; - amount = e->len - offset; - - if (size < amount) - amount = size; - - if (copy_to_user(buf, from, amount)) - return -EFAULT; - - buf += amount; - copied += amount; - size -= amount; - offset = 0; - - if (e->list.next == &DMFS_I(inode)->errors) - break; - e = list_entry(e->list.next, struct dmfs_error, list); - } while(size > 0); + struct dmfs_i *dmi = context; + struct list_head *p = ((struct dmfs_error *)v)->list.next; + (*pos)++; + return (p == &dmi->errors) ? NULL + : list_entry(p, struct dmfs_error, list); +} - return amount; +static void e_stop(void *context, void *v) +{ + struct dmfs_i *dmi = context; + up(&dmi->sem); } -static ssize_t dmfs_error_read(struct file *file, char *buf, size_t size, loff_t *pos) +static int show_error(struct seq_file *e, void *v) { - struct inode *inode = file->f_dentry->d_parent->d_inode; - struct dmfs_i *dmi = DMFS_I(inode); - int copied = 0; - loff_t offset = *pos; + struct dmfs_error *d = v; + seq_puts(e, d->msg); + return 0; +} - if (!access_ok(VERIFY_WRITE, buf, size)) - return -EFAULT; +static struct seq_operations error_op = { + start: e_start, + next: e_next, + stop: e_stop, + show: show_error, +}; - down(&dmi->sem); - if (dmi->table) { - struct dmfs_error *e = find_initial_message(inode, &offset); - if (e) { - copied = copy_sequence(inode, e, buf, size, offset); - if (copied > 0) - (*pos) += copied; - } - } - up(&dmi->sem); - return copied; +static int dmfs_error_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &error_op, DMFS_I(file->f_dentry->d_parent->d_inode)); } static int dmfs_error_sync(struct file *file, struct dentry *dentry, int datasync) @@ -133,7 +110,10 @@ static int dmfs_error_sync(struct file *file, struct dentry *dentry, int datasyn } static struct file_operations dmfs_error_file_operations = { - read: dmfs_error_read, + open: dmfs_error_open, + read: seq_read, + llseek: seq_lseek, + release: seq_release, fsync: dmfs_error_sync, }; @@ -142,16 +122,9 @@ static struct inode_operations dmfs_error_inode_operations = { struct inode *dmfs_create_error(struct inode *dir, int mode) { - struct inode *inode = new_inode(dir->i_sb); + struct inode *inode = dmfs_new_inode(dir->i_sb, mode | S_IFREG); if (inode) { - inode->i_mode = mode | S_IFREG; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; - inode->i_blocks = 0; - inode->i_rdev = NODEV; - inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; inode->i_fop = &dmfs_error_file_operations; inode->i_op = &dmfs_error_inode_operations; } diff --git a/driver/device-mapper/dmfs-lv.c b/driver/device-mapper/dmfs-lv.c index c9679d468..a72782f30 100644 --- a/driver/device-mapper/dmfs-lv.c +++ b/driver/device-mapper/dmfs-lv.c @@ -26,6 +26,7 @@ #include #include "dm.h" +#include "dmfs.h" extern struct address_space_operations dmfs_address_space_operations; extern struct inode *dmfs_create_tdir(struct super_block *sb, int mode); @@ -77,7 +78,7 @@ err_out: struct inode *dmfs_create_symlink(struct inode *dir, int mode) { - struct inode *inode = dmfs_new_inode(dir->i_sb, mode | S_IFLNK); + struct inode *inode = dmfs_new_private_inode(dir->i_sb, mode | S_IFLNK); if (inode) { inode->i_mapping->a_ops = &dmfs_address_space_operations; @@ -261,7 +262,7 @@ static struct inode_operations dmfs_lv_inode_operations = { struct inode *dmfs_create_lv(struct super_block *sb, int mode, struct dentry *dentry) { - struct inode *inode = dmfs_new_inode(sb, mode | S_IFDIR); + struct inode *inode = dmfs_new_private_inode(sb, mode | S_IFDIR); struct mapped_device *md; const char *name = dentry->d_name.name; char tmp_name[DM_NAME_LEN + 1]; diff --git a/driver/device-mapper/dmfs-root.c b/driver/device-mapper/dmfs-root.c index 7fe2ab306..8345814ae 100644 --- a/driver/device-mapper/dmfs-root.c +++ b/driver/device-mapper/dmfs-root.c @@ -26,6 +26,7 @@ #include #include "dm.h" +#include "dmfs.h" extern struct inode *dmfs_create_lv(struct super_block *sb, int mode, struct dentry *dentry); @@ -144,16 +145,9 @@ static struct inode_operations dmfs_root_inode_operations = { struct inode *dmfs_create_root(struct super_block *sb, int mode) { - struct inode *inode = new_inode(sb); + struct inode *inode = dmfs_new_inode(sb, mode | S_IFDIR); if (inode) { - inode->i_mode = mode | S_IFDIR; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; - inode->i_blocks = 0; - inode->i_rdev = NODEV; - inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; inode->i_fop = &dmfs_root_file_operations; inode->i_op = &dmfs_root_inode_operations; } diff --git a/driver/device-mapper/dmfs-status.c b/driver/device-mapper/dmfs-status.c index 514e9ea0c..6886eff97 100644 --- a/driver/device-mapper/dmfs-status.c +++ b/driver/device-mapper/dmfs-status.c @@ -23,6 +23,7 @@ #include #include "dm.h" +#include "dmfs.h" static ssize_t dmfs_status_read(struct file *file, char *buf, size_t size, loff_t *pos) { @@ -44,16 +45,9 @@ static struct inode_operations dmfs_status_inode_operations = { struct inode *dmfs_create_status(struct inode *dir, int mode) { - struct inode *inode = new_inode(dir->i_sb); + struct inode *inode = dmfs_new_inode(dir->i_sb, mode | S_IFREG); if (inode) { - inode->i_mode = mode | S_IFREG; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; - inode->i_blocks = 0; - inode->i_rdev = NODEV; - inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; inode->i_fop = &dmfs_status_file_operations; inode->i_op = &dmfs_status_inode_operations; } diff --git a/driver/device-mapper/dmfs-super.c b/driver/device-mapper/dmfs-super.c index b6edcaed0..cd0e1321f 100644 --- a/driver/device-mapper/dmfs-super.c +++ b/driver/device-mapper/dmfs-super.c @@ -21,7 +21,9 @@ #include #include +#include +#include "dmfs.h" #include "dm.h" #define DMFS_MAGIC 0x444D4653 @@ -63,7 +65,7 @@ static struct super_operations dmfs_super_operations = { delete_inode: dmfs_delete_inode, }; -struct super_block *dmfs_read_super(struct super_block *sb, void *data, int silent) +static struct super_block *dmfs_read_super(struct super_block *sb, void *data, int silent) { struct inode *inode; struct dentry *root; @@ -90,7 +92,6 @@ struct super_block *dmfs_read_super(struct super_block *sb, void *data, int sile struct inode *dmfs_new_inode(struct super_block *sb, int mode) { struct inode *inode = new_inode(sb); - struct dmfs_i *dmi; if (inode) { inode->i_mode = mode; @@ -100,7 +101,17 @@ struct inode *dmfs_new_inode(struct super_block *sb, int mode) inode->i_blocks = 0; inode->i_rdev = NODEV; inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; + } + + return inode; +} + +struct inode *dmfs_new_private_inode(struct super_block *sb, int mode) +{ + struct inode *inode = dmfs_new_inode(sb, mode); + struct dmfs_i *dmi; + if (inode) { dmi = kmalloc(sizeof(struct dmfs_i), GFP_KERNEL); if (dmi == NULL) { iput(inode); @@ -113,3 +124,33 @@ struct inode *dmfs_new_inode(struct super_block *sb, int mode) } return inode; } + +static DECLARE_FSTYPE(dmfs_fstype, "dmfs", dmfs_read_super, FS_SINGLE); +static struct vfsmount *dmfs_mnt; + +int __init dmfs_init(void) +{ + int ret; + + ret = register_filesystem(&dmfs_fstype); + if (ret < 0) + goto out; + + dmfs_mnt = kern_mount(&dmfs_fstype); + if (IS_ERR(dmfs_mnt)) { + ret = PTR_ERR(dmfs_mnt); + unregister_filesystem(&dmfs_fstype); + } +out: + return ret; +} + +int __exit dmfs_exit(void) +{ + /* kern_umount(&dmfs_mnt); */ + + unregister_filesystem(&dmfs_fstype); + + return 0; +} + diff --git a/driver/device-mapper/dmfs-table.c b/driver/device-mapper/dmfs-table.c index cd0f2a297..6208a2765 100644 --- a/driver/device-mapper/dmfs-table.c +++ b/driver/device-mapper/dmfs-table.c @@ -24,6 +24,7 @@ #include #include "dm.h" +#include "dmfs.h" static offset_t start_of_next_range(struct dm_table *t) { @@ -246,13 +247,6 @@ static int dmfs_readpage(struct file *file, struct page *page) return 0; } -static int dmfs_writepage(struct page *page) -{ - SetPageDirty(page); - UnlockPage(page); - return 0; -} - static int dmfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) { @@ -325,7 +319,7 @@ static int dmfs_table_revalidate(struct dentry *dentry) struct address_space_operations dmfs_address_space_operations = { readpage: dmfs_readpage, - writepage: dmfs_writepage, + writepage: fail_writepage, prepare_write: dmfs_prepare_write, commit_write: dmfs_commit_write, }; @@ -345,16 +339,9 @@ static struct inode_operations dmfs_table_inode_operations = { struct inode *dmfs_create_table(struct inode *dir, int mode) { - struct inode *inode = new_inode(dir->i_sb); + struct inode *inode = dmfs_new_inode(dir->i_sb, mode | S_IFREG); if (inode) { - inode->i_mode = mode | S_IFREG; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; - inode->i_blocks = 0; - inode->i_rdev = NODEV; - inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; inode->i_mapping = dir->i_mapping; inode->i_mapping->a_ops = &dmfs_address_space_operations; inode->i_fop = &dmfs_table_file_operations; diff --git a/driver/device-mapper/dmfs-tdir.c b/driver/device-mapper/dmfs-tdir.c index 9eebfd3ee..5c630ff68 100644 --- a/driver/device-mapper/dmfs-tdir.c +++ b/driver/device-mapper/dmfs-tdir.c @@ -25,6 +25,7 @@ #include #include "dm.h" +#include "dmfs.h" extern struct inode *dmfs_create_error(struct inode *, int); extern struct inode *dmfs_create_table(struct inode *, int); @@ -124,7 +125,7 @@ static struct inode_operations dmfs_tdir_inode_operations = { struct inode *dmfs_create_tdir(struct super_block *sb, int mode) { - struct inode *inode = dmfs_new_inode(sb, mode | S_IFDIR); + struct inode *inode = dmfs_new_private_inode(sb, mode | S_IFDIR); if (inode) { inode->i_fop = &dmfs_tdir_file_operations; diff --git a/driver/device-mapper/dmfs.h b/driver/device-mapper/dmfs.h new file mode 100644 index 000000000..1cc0df350 --- /dev/null +++ b/driver/device-mapper/dmfs.h @@ -0,0 +1,26 @@ +#ifndef LINUX_DMFS_H +#define LINUX_DMFS_H + +struct dmfs_i { + struct semaphore sem; + struct dm_table *table; + struct mapped_device *md; + struct dentry *dentry; + struct list_head errors; +}; + +#define DMFS_I(inode) ((struct dmfs_i *)(inode)->u.generic_ip) + + +extern int dmfs_init(void) __init; +extern int dmfs_exit(void) __exit; + +struct inode *dmfs_new_inode(struct super_block *sb, int mode); +struct inode *dmfs_new_private_inode(struct super_block *sb, int mode); + +void dmfs_add_error(struct inode *inode, unsigned num, char *str); +void dmfs_zap_errors(struct inode *inode); + + + +#endif /* LINUX_DMFS_H */ diff --git a/driver/device-mapper/patches/00_config b/driver/device-mapper/patches/00_config index 0d64c4dd8..cc918029a 100644 --- a/driver/device-mapper/patches/00_config +++ b/driver/device-mapper/patches/00_config @@ -1,7 +1,7 @@ ---- linux-2.4.9-ac5/drivers/md/Config.in Sun Mar 11 13:33:24 2001 -+++ linux/drivers/md/Config.in Thu Sep 13 18:02:17 2001 -@@ -13,5 +13,7 @@ - dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD +--- linux-2.4.14/drivers/md/Config.in Mon Sep 24 16:29:14 2001 ++++ linux/drivers/md/Config.in Tue Nov 6 11:25:35 2001 +@@ -14,5 +14,7 @@ + dep_tristate ' Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD +dep_tristate ' Device mapper support' CONFIG_BLK_DEV_DM $CONFIG_MD diff --git a/driver/device-mapper/patches/00_ksyms b/driver/device-mapper/patches/00_ksyms index 468b6893c..fa62ad660 100644 --- a/driver/device-mapper/patches/00_ksyms +++ b/driver/device-mapper/patches/00_ksyms @@ -1,6 +1,6 @@ ---- linux-2.4.12/kernel/ksyms.c Wed Oct 17 13:08:17 2001 -+++ linux/kernel/ksyms.c Mon Oct 15 15:26:47 2001 -@@ -519,6 +519,7 @@ +--- linux-2.4.14/kernel/ksyms.c Tue Nov 6 11:18:14 2001 ++++ linux/kernel/ksyms.c Wed Nov 7 11:26:45 2001 +@@ -521,6 +521,7 @@ /* binfmt_aout */ EXPORT_SYMBOL(get_write_access); diff --git a/driver/device-mapper/patches/00_makefile b/driver/device-mapper/patches/00_makefile index 78942c1da..220391692 100644 --- a/driver/device-mapper/patches/00_makefile +++ b/driver/device-mapper/patches/00_makefile @@ -1,21 +1,31 @@ ---- linux/drivers/md/Makefile.old Wed Oct 24 10:41:48 2001 -+++ linux/drivers/md/Makefile Wed Oct 24 11:33:11 2001 -@@ -4,7 +4,7 @@ +--- linux-2.4.14/drivers/md/Makefile Mon Sep 24 16:29:14 2001 ++++ linux/drivers/md/Makefile Wed Nov 7 10:48:26 2001 +@@ -4,9 +4,12 @@ O_TARGET := mddev.o -export-objs := md.o xor.o -+export-objs := md.o xor.o dm-table.o dm-target.o dm-parse.o ++export-objs := md.o xor.o dm-table.o dm-target.o list-multi := lvm-mod.o lvm-mod-objs := lvm.o lvm-snap.o ++dm-mod-objs := dm.o dm-table.o dm-target.o dmfs-super.o dmfs-root.o \ ++ dmfs-tdir.o dmfs-table.o dmfs-error.o dmfs-status.o \ ++ dmfs-lv.o seq_file.o -@@ -20,7 +20,8 @@ + # Note: link order is important. All raid personalities + # and xor.o must come before md.o, as they each initialise +@@ -20,8 +23,14 @@ obj-$(CONFIG_MD_MULTIPATH) += multipath.o obj-$(CONFIG_BLK_DEV_MD) += md.o obj-$(CONFIG_BLK_DEV_LVM) += lvm-mod.o --obj-$(CONFIG_BLK_DEV_DM) += dm.o dm-table.o dm-target.o dm-fs.o dm-parse.o dm-linear.o -+obj-$(CONFIG_BLK_DEV_DM) += dm.o dm-table.o dm-target.o dm-fs.o \ -+ dm-parse.o dm-linear.o ++obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o ++obj-$(CONFIG_BLK_DEV_DM_LINEAR) += dm-linear.o include $(TOPDIR)/Rules.make + lvm-mod.o: $(lvm-mod-objs) + $(LD) -r -o $@ $(lvm-mod-objs) ++ ++dm-mod.o: $(dm-mod-objs) ++ $(LD) -r -o $@ $(dm-mod-objs) ++ diff --git a/driver/device-mapper/projects.txt b/driver/device-mapper/projects.txt index 6e543c7cb..1f73d2996 100644 --- a/driver/device-mapper/projects.txt +++ b/driver/device-mapper/projects.txt @@ -1,12 +1,6 @@ List of projects, ideas and pending bug fixes =============================================== - o Use devfs auto device allocation to get devices rather than a fixed - series of devices (which limits us to 256 volumes atm) - - - Ought to have an option of using the old version for non-devfs systems - - Would be nice if the auto device allocation was independant of devfs - o Need to work out how to make module use counts work correctly. The existing scheme does not allow us to unload the module. A reference is taken during kern_mount() which does not allow us to rmmod() so even if the right @@ -16,19 +10,6 @@ o Check tables are an integer multiple of the underlying block size at table load time. - o Use Al Viro's new code for "proc files consisting of one line per entry" - for the error and status files. [This item waiting for the patches to - reach the kernel and for their suitability to be further investigated - and checked] - o Error code (as well as error list) so that "out of memory" errors can result in messages which can be read from the error file. - o Further reduction of common code between the filesystem source files. - -[For 2.4.14-pre and upwards] - - o Use fail_writepage() in address_space_operations - o Kernel takes care of module reference count for block devices, so all we - need to do is add an owner field in the right place. - diff --git a/driver/device-mapper/seq_file.c b/driver/device-mapper/seq_file.c new file mode 100644 index 000000000..ab66e4798 --- /dev/null +++ b/driver/device-mapper/seq_file.c @@ -0,0 +1,240 @@ +/* + * linux/fs/seq_file.c + * + * helper functions for making syntetic files from sequences of records. + * initial implementation -- AV, Oct 2001. + * + * Slight modifications to the original. Will be passed on to Al Viro in + * the next few days. + */ + +#include +#include +#include +#include + +/** + * seq_open - initialize sequential file + * @file: file we initialize + * @op: method table describing the sequence + * + * seq_open() sets @file, associating it with a sequence described + * by @op. @op->start() sets the iterator up and returns the first + * element of sequence. @op->stop() shuts it down. @op->next() + * returns the next element of sequence. @op->show() prints element + * into the buffer. In case of error ->start() and ->next() return + * ERR_PTR(error). In the end of sequence they return %NULL. ->show() + * returns 0 in case of success and negative number in case of error. + */ +int seq_open(struct file *file, struct seq_operations *op, void *context) +{ + struct seq_file *p = kmalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + memset(p, 0, sizeof(*p)); + sema_init(&p->sem, 1); + p->op = op; + p->context = context; + file->private_data = p; + return 0; +} + +/** + * seq_read - ->read() method for sequential files. + * @file, @buf, @size, @ppos: see file_operations method + * + * Ready-made ->f_op->read() + */ +ssize_t seq_read(struct file *file, char *buf, size_t size, loff_t *ppos) +{ + struct seq_file *m = (struct seq_file *)file->private_data; + size_t copied = 0; + loff_t pos; + size_t n; + void *p; + int err = 0; + + if (ppos != &file->f_pos) + return -EPIPE; + + down(&m->sem); + /* grab buffer if we didn't have one */ + if (!m->buf) { + m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL); + if (!m->buf) + goto Enomem; + } + /* if not empty - flush it first */ + if (m->count) { + n = min(m->count, size); + err = copy_to_user(buf, m->buf + m->from, n); + if (err) + goto Efault; + m->count -= n; + m->from += n; + size -= n; + buf += n; + copied += n; + if (!m->count) + (*ppos)++; + if (!size) + goto Done; + } + /* we need at least one record in buffer */ + while (1) { + pos = *ppos; + p = m->op->start(m->context, &pos); + err = PTR_ERR(p); + if (!p || IS_ERR(p)) + break; + err = m->op->show(m, p); + if (err) + break; + if (m->count < m->size) + goto Fill; + m->op->stop(m->context, p); + kfree(m->buf); + m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); + if (!m->buf) + goto Enomem; + } + m->op->stop(m->context, p); + goto Done; +Fill: + /* they want more? let's try to get some more */ + while (m->count < size) { + size_t offs = m->count; + loff_t next = pos; + p = m->op->next(m->context, p, &next); + if (!p || IS_ERR(p)) { + err = PTR_ERR(p); + break; + } + err = m->op->show(m, p); + if (err || m->count == m->size) { + m->count = offs; + break; + } + pos = next; + } + m->op->stop(m->context, p); + n = min(m->count, size); + err = copy_to_user(buf, m->buf, n); + if (err) + goto Efault; + copied += n; + m->count -= n; + if (m->count) + m->from = n; + else + pos++; + *ppos = pos; +Done: + if (!copied) + copied = err; + up(&m->sem); + return copied; +Enomem: + err = -ENOMEM; + goto Done; +Efault: + err = -EFAULT; + goto Done; +} + +/** + * seq_lseek - ->llseek() method for sequential files. + * @file, @offset, @origin: see file_operations method + * + * Ready-made ->f_op->llseek() + */ +loff_t seq_lseek(struct file *file, loff_t offset, int origin) +{ + struct seq_file *m = (struct seq_file *)file->private_data; + long long retval = -EINVAL; + + down(&m->sem); + switch (origin) { + case 1: + offset += file->f_pos; + case 0: + if (offset < 0) + break; + if (offset != file->f_pos) { + file->f_pos = offset; + m->count = 0; + } + retval = offset; + } + up(&m->sem); + return retval; +} + +/** + * seq_release - free the structures associated with sequential file. + * @file: file in question + * @inode: file->f_dentry->d_inode + * + * Frees the structures associated with sequential file; can be used + * as ->f_op->release() if you don't have private data to destroy. + */ +int seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *m = (struct seq_file *)file->private_data; + kfree(m->buf); + kfree(m); + return 0; +} + +/** + * seq_escape - print string into buffer, escaping some characters + * @m: target buffer + * @s: string + * @esc: set of characters that need escaping + * + * Puts string into buffer, replacing each occurence of character from + * @esc with usual octal escape. Returns 0 in case of success, -1 - in + * case of overflow. + */ +int seq_escape(struct seq_file *m, const char *s, const char *esc) +{ + char *end = m->buf + m->size; + char *p; + char c; + + for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) { + if (!strchr(esc, c)) { + *p++ = c; + continue; + } + if (p + 3 < end) { + *p++ = '\\'; + *p++ = '0' + ((c & 0300) >> 6); + *p++ = '0' + ((c & 070) >> 3); + *p++ = '0' + (c & 07); + continue; + } + m->count = m->size; + return -1; + } + m->count = p - m->buf; + return 0; +} + +int seq_printf(struct seq_file *m, const char *f, ...) +{ + va_list args; + int len; + + if (m->count < m->size) { + va_start(args, f); + len = vsnprintf(m->buf + m->count, m->size - m->count, f, args); + va_end(args); + if (m->count + len < m->size) { + m->count += len; + return 0; + } + } + m->count = m->size; + return -1; +} diff --git a/driver/device-mapper/seq_file.h b/driver/device-mapper/seq_file.h new file mode 100644 index 000000000..cebe849ca --- /dev/null +++ b/driver/device-mapper/seq_file.h @@ -0,0 +1,60 @@ +/* + * Original file by Al Viro. This is a slight modification which I'll + * pass on to Al Viro shortly. + */ +#ifndef _LINUX_SEQ_FILE_H +#define _LINUX_SEQ_FILE_H +#ifdef __KERNEL__ + +struct seq_operations; + +struct seq_file { + char *buf; + size_t size; + size_t from; + size_t count; + loff_t index; + struct semaphore sem; + struct seq_operations *op; + void *context; +}; + +struct seq_operations { + void * (*start) (void *context, loff_t *pos); + void (*stop) (void *context, void *v); + void * (*next) (void *context, void *v, loff_t *pos); + int (*show) (struct seq_file *m, void *v); +}; + +int seq_open(struct file *, struct seq_operations *, void *context); +ssize_t seq_read(struct file *, char *, size_t, loff_t *); +loff_t seq_lseek(struct file *, loff_t, int); +int seq_release(struct inode *, struct file *); +int seq_escape(struct seq_file *, const char *, const char *); + +static inline int seq_putc(struct seq_file *m, char c) +{ + if (m->count < m->size) { + m->buf[m->count++] = c; + return 0; + } + return -1; +} + +static inline int seq_puts(struct seq_file *m, const char *s) +{ + int len = strlen(s); + if (m->count + len < m->size) { + memcpy(m->buf + m->count, s, len); + m->count += len; + return 0; + } + m->count = m->size; + return -1; +} + +int seq_printf(struct seq_file *, const char *, ...) + __attribute__ ((format (printf,2,3))); + +#endif +#endif -- 2.43.5