1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-03-08 08:58:50 +03:00

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
This commit is contained in:
Steven Whitehouse 2001-11-07 12:12:56 +00:00
parent 37ed70b9ea
commit 01c4ac1315
17 changed files with 448 additions and 911 deletions

View File

@ -1,552 +0,0 @@
/*
* *very* heavily based on ramfs
*
* Copyright (C) 2001 Sistina Software
*
* This file is released under the GPL.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/locks.h>
#include <linux/file.h>
#include <asm/uaccess.h>
#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);
}

View File

@ -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:
* <sector start> <length (sectors)> <target type> <args...>
*/
/* 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);

View File

@ -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)
/*

View File

@ -22,8 +22,10 @@
#include <linux/config.h>
#include <linux/list.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
#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);
return amount;
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);
}
static ssize_t dmfs_error_read(struct file *file, char *buf, size_t size, loff_t *pos)
static void e_stop(void *context, 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;
if (!access_ok(VERIFY_WRITE, buf, size))
return -EFAULT;
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;
}
}
struct dmfs_i *dmi = context;
up(&dmi->sem);
return copied;
}
static int show_error(struct seq_file *e, void *v)
{
struct dmfs_error *d = v;
seq_puts(e, d->msg);
return 0;
}
static struct seq_operations error_op = {
start: e_start,
next: e_next,
stop: e_stop,
show: show_error,
};
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;
}

View File

@ -26,6 +26,7 @@
#include <linux/fs.h>
#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];

View File

@ -26,6 +26,7 @@
#include <linux/fs.h>
#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;
}

View File

@ -23,6 +23,7 @@
#include <linux/fs.h>
#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;
}

View File

@ -21,7 +21,9 @@
#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
#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;
}

View File

@ -24,6 +24,7 @@
#include <linux/mm.h>
#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;

View File

@ -25,6 +25,7 @@
#include <linux/fs.h>
#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;

View File

@ -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 */

View File

@ -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

View File

@ -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);

View File

@ -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)
+

View File

@ -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.

View File

@ -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 <linux/malloc.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
/**
* 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;
}

View File

@ -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