mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +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:
parent
7f64636f5f
commit
c4bf9638e3
@ -20,33 +20,102 @@
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/fs.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)
|
||||
{
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Assuming that we allow modules to call this rather than passing the message
|
||||
* back. Not sure which approach to take yet.
|
||||
*/
|
||||
EXPORT_SYMBOL(dmfs_add_error);
|
||||
void dmfs_zap_errors(struct dm_table *t)
|
||||
{
|
||||
struct dmfs_error *e;
|
||||
|
||||
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)
|
||||
{
|
||||
struct dmfs_i *dmi = DMFS_I(file->f_dentry->d_parent->d_inode);
|
||||
struct dm_table *t = dmi->table;
|
||||
int copied = 0;
|
||||
loff_t offset = *pos;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
down(&dmi->sem);
|
||||
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);
|
||||
return copied;
|
||||
|
@ -95,13 +95,17 @@ static int dmfs_lv_symlink(struct inode *dir, struct dentry *dentry,
|
||||
int rv;
|
||||
int l;
|
||||
|
||||
if (dentry->d_name.len != 6 || memcmp(dentry->d_name, "ACTIVE", 6) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
de = dmfs_verify_name(dir, symname);
|
||||
if (IS_ERR(de))
|
||||
return PTR_ERR(de);
|
||||
|
||||
dput(de);
|
||||
|
||||
inode = dmfs_create_symlink(dir, S_IRWXUGO);
|
||||
if (IS_ERR(inode)) {
|
||||
kfree(realname);
|
||||
return PTR_ERR(inode);
|
||||
}
|
||||
|
||||
@ -145,18 +149,11 @@ static int dmfs_lv_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
||||
if (dentry->d_name[0] == '.')
|
||||
return -EINVAL;
|
||||
|
||||
inode = dmfs_create_lv(dir, dentry, mode);
|
||||
inode = dmfs_create_tdir(dir, mode);
|
||||
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);
|
||||
dget(dentry);
|
||||
return 0;
|
||||
}
|
||||
iput(inode);
|
||||
return PTR_ERR(md);
|
||||
d_instantiate(dentry, inode);
|
||||
dget(dentry);
|
||||
return 0;
|
||||
}
|
||||
return PTR_ERR(inode);
|
||||
}
|
||||
@ -231,13 +228,21 @@ static struct dm_root_inode_operations = {
|
||||
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 mapped_device *md;
|
||||
char *name = dentry->d_name.name;
|
||||
|
||||
if (inode) {
|
||||
inode->i_fop = &dmfs_lv_file_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;
|
||||
|
@ -52,18 +52,11 @@ static int dmfs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
||||
if (dentry->d_name[0] == '.')
|
||||
return -EINVAL;
|
||||
|
||||
inode = dmfs_create_lv(dir, dentry, mode);
|
||||
inode = dmfs_create_lv(dir, mode, dentry);
|
||||
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);
|
||||
dget(dentry);
|
||||
return 0;
|
||||
}
|
||||
iput(inode);
|
||||
return PTR_ERR(md);
|
||||
d_instantiate(dentry, inode);
|
||||
dget(dentry);
|
||||
return 0;
|
||||
}
|
||||
return PTR_ERR(inode);
|
||||
}
|
||||
|
@ -81,7 +81,11 @@ static void dmfs_parse_line(struct dmfs_table *t, unsigned num, char *str)
|
||||
if (ttype) {
|
||||
msg = "This message should never appear (constructor error)";
|
||||
rv = ttype->ctr(t, start, size, p, &context);
|
||||
msg = context;
|
||||
if (rv == 0)) {
|
||||
printk(KERN_DEBUG "%ul %ul %s %s", start, size,
|
||||
ttype->name,
|
||||
ttype->print(context));
|
||||
msg = "Error adding target to table";
|
||||
high = start + (size - 1);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
struct dentry *dentry = file->f_dentry;
|
||||
struct inode *inode = dentry->d_parent->d_inode;
|
||||
|
||||
if (file->f_mode & FMODE_WRITE) {
|
||||
if (get_write_access(inode))
|
||||
if (get_exclusive_write_access(inode))
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user