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:
parent
37ed70b9ea
commit
01c4ac1315
@ -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);
|
||||
}
|
@ -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);
|
@ -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)
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
26
driver/device-mapper/dmfs.h
Normal file
26
driver/device-mapper/dmfs.h
Normal 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 */
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
+
|
||||
|
@ -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.
|
||||
|
||||
|
240
driver/device-mapper/seq_file.c
Normal file
240
driver/device-mapper/seq_file.c
Normal 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;
|
||||
}
|
60
driver/device-mapper/seq_file.h
Normal file
60
driver/device-mapper/seq_file.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user