1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-03 05:18:29 +03:00

Some more sync ups

o Error file routines (initial idea)
 o Various fixes for bugs
 o Tidy a few things
 o Added a bit of debugging code ready for when this gets tested
 o get_exclusive_write_access() function which will get moved into namei.c
   I hope (and rewritten accordingly), should this become the final version
   used.

Still a few more areas need thinking about, but in general much closer now I
think. Last area to sort out before testing is the symlink code which is
pretty close now... just a few more checks needed and the actual calls to
the core code.
This commit is contained in:
Steven Whitehouse 2001-10-11 20:29:00 +00:00
parent 7f64636f5f
commit c4bf9638e3
4 changed files with 121 additions and 32 deletions

View File

@ -20,33 +20,102 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/list.h>
#include <linux/fs.h> #include <linux/fs.h>
#include "dm.h" #include "dm.h"
struct dmfs_error {
struct list_head list;
unsigned len;
char *msg;
};
void dmfs_add_error(struct dm_table *t, unsigned num, char *str) void dmfs_add_error(struct dm_table *t, unsigned num, char *str)
{ {
int len = strlen(str) + sizeof(dmfs_error) + 12;
struct dmfs_error *e = kmalloc(len, GFP_KERNEL);
if (e) {
e->msg = (char *)(e + 1);
e->len = sprintf(e->msg, "%8u: %s\n", num, str);
list_add(&e->list, &t->errors);
}
} }
/* void dmfs_zap_errors(struct dm_table *t)
* Assuming that we allow modules to call this rather than passing the message {
* back. Not sure which approach to take yet. struct dmfs_error *e;
*/
EXPORT_SYMBOL(dmfs_add_error); while(!list_empty(&t->errors)) {
e = list_entry(t->errors.next, struct dmfs_error, list);
kfree(e);
}
}
static struct dmfs_error find_initial_message(struct dn_table *t, loff_t *pos)
{
struct dmfs_error *e;
struct list_head *tmp, *head;
tmp = head = &t->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;
}
return NULL;
}
static int copy_sequence(struct dm_table *t, struct dmfs_error *e, char *buf,
size_t size, loff_t offset)
{
char *from;
int amount;
int copied = 0;
do {
from = e->msg + offset;
amount = e->len - offset;
if (copy_to_user(buf, from, amount))
return -EFAULT;
buf += amount;
copied += amount;
size -= amount;
offset = 0;
if (e->list.next == &t->errors)
break;
e = list_entry(e->list.next, struct dmfs_error, list);
} while(size > 0);
return amount;
}
static ssize_t dmfs_error_read(struct file *file, char *buf, size_t size, loff_t *pos) static ssize_t dmfs_error_read(struct file *file, char *buf, size_t size, loff_t *pos)
{ {
struct dmfs_i *dmi = DMFS_I(file->f_dentry->d_parent->d_inode); struct dmfs_i *dmi = DMFS_I(file->f_dentry->d_parent->d_inode);
struct dm_table *t = dmi->table; struct dm_table *t = dmi->table;
int copied = 0; int copied = 0;
loff_t offset = *pos;
if (!access_ok(VERIFY_WRITE, buf, count)) if (!access_ok(VERIFY_WRITE, buf, count))
return -EFAULT; return -EFAULT;
down(&dmi->sem); down(&dmi->sem);
if (dmi->table) { if (dmi->table) {
struct dmfs_error *e = find_initial_message(t, &offset);
if (e) {
copied = copy_sequence(t, e, buf, size, offset);
if (copied > 0)
(*pos) += copied;
}
} }
up(&dmi->sem); up(&dmi->sem);
return copied; return copied;

View File

@ -95,13 +95,17 @@ static int dmfs_lv_symlink(struct inode *dir, struct dentry *dentry,
int rv; int rv;
int l; int l;
if (dentry->d_name.len != 6 || memcmp(dentry->d_name, "ACTIVE", 6) != 0)
return -EINVAL;
de = dmfs_verify_name(dir, symname); de = dmfs_verify_name(dir, symname);
if (IS_ERR(de)) if (IS_ERR(de))
return PTR_ERR(de); return PTR_ERR(de);
dput(de);
inode = dmfs_create_symlink(dir, S_IRWXUGO); inode = dmfs_create_symlink(dir, S_IRWXUGO);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
kfree(realname);
return PTR_ERR(inode); return PTR_ERR(inode);
} }
@ -145,19 +149,12 @@ static int dmfs_lv_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (dentry->d_name[0] == '.') if (dentry->d_name[0] == '.')
return -EINVAL; return -EINVAL;
inode = dmfs_create_lv(dir, dentry, mode); inode = dmfs_create_tdir(dir, mode);
if (!IS_ERR(inode)) { if (!IS_ERR(inode)) {
md = dm_create(name, -1);
if (!IS_ERR(md)) {
inode->u.generic_ip = md;
md->inode = inode;
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
dget(dentry); dget(dentry);
return 0; return 0;
} }
iput(inode);
return PTR_ERR(md);
}
return PTR_ERR(inode); return PTR_ERR(inode);
} }
@ -231,13 +228,21 @@ static struct dm_root_inode_operations = {
rmdir: dmfs_lv_rmdir, rmdir: dmfs_lv_rmdir,
}; };
struct inode *dmfs_create_lv(struct super_block *sb, int mode) 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_inode(sb, mode | S_IFDIR);
struct mapped_device *md;
char *name = dentry->d_name.name;
if (inode) { if (inode) {
inode->i_fop = &dmfs_lv_file_operations; inode->i_fop = &dmfs_lv_file_operations;
inode->i_op = &dmfs_lv_dir_operations; inode->i_op = &dmfs_lv_dir_operations;
md = dm_create(name, -1);
if (md == NULL) {
iput(inode);
return NULL;
}
DMFS_I(inode)->md = md;
} }
return inode; return inode;

View File

@ -52,19 +52,12 @@ static int dmfs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (dentry->d_name[0] == '.') if (dentry->d_name[0] == '.')
return -EINVAL; return -EINVAL;
inode = dmfs_create_lv(dir, dentry, mode); inode = dmfs_create_lv(dir, mode, dentry);
if (!IS_ERR(inode)) { if (!IS_ERR(inode)) {
md = dm_create(name, -1);
if (!IS_ERR(md)) {
inode->u.generic_ip = md;
md->inode = inode;
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
dget(dentry); dget(dentry);
return 0; return 0;
} }
iput(inode);
return PTR_ERR(md);
}
return PTR_ERR(inode); return PTR_ERR(inode);
} }

View File

@ -81,7 +81,11 @@ static void dmfs_parse_line(struct dmfs_table *t, unsigned num, char *str)
if (ttype) { if (ttype) {
msg = "This message should never appear (constructor error)"; msg = "This message should never appear (constructor error)";
rv = ttype->ctr(t, start, size, p, &context); rv = ttype->ctr(t, start, size, p, &context);
msg = context;
if (rv == 0)) { if (rv == 0)) {
printk(KERN_DEBUG "%ul %ul %s %s", start, size,
ttype->name,
ttype->print(context));
msg = "Error adding target to table"; msg = "Error adding target to table";
high = start + (size - 1); high = start + (size - 1);
if (dm_table_add_target(t, high, ttype, context) == 0) if (dm_table_add_target(t, high, ttype, context) == 0)
@ -285,13 +289,31 @@ static int dmfs_commit_write(struct file *file, struct page *page,
return 0; return 0;
} }
/*
* There is a small race here in that two processes might call this at
* the same time and both fail. So its a fail safe race :-) This should
* move into namei.c (and thus use the spinlock and do this properly)
* at some stage if we continue to use this set of functions for ensuring
* exclusive write access to the file
*/
static int get_exclusive_write_access(struct inode *inode)
{
if (get_write_access(inode))
return -1;
if (atomic_read(&inode->i_writecount) != 1) {
put_write_access(inode);
return -1;
}
return 0;
}
static int dmfs_table_open(struct inode *inode, struct file *file) static int dmfs_table_open(struct inode *inode, struct file *file)
{ {
struct dentry *dentry = file->f_dentry; struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_parent->d_inode; struct inode *inode = dentry->d_parent->d_inode;
if (file->f_mode & FMODE_WRITE) { if (file->f_mode & FMODE_WRITE) {
if (get_write_access(inode)) if (get_exclusive_write_access(inode))
return -EPERM; return -EPERM;
} }