diff --git a/driver/device-mapper/dmfs-suspend.c b/driver/device-mapper/dmfs-suspend.c index a6c75bf94..9016db23c 100644 --- a/driver/device-mapper/dmfs-suspend.c +++ b/driver/device-mapper/dmfs-suspend.c @@ -24,16 +24,41 @@ static ssize_t dmfs_suspend_read(struct file *file, char *buf, size_t size, loff_t *pos) { - down(&inode->i_sem); + struct inode *inode = file->f_dentry->d_parent->d_inode; + struct mapped_device *md = (struct mapped_device *)inode->u.generic_ip; - up(&inode->i_sem); + char content[2] = { '0', '\n' }; + + if (size > 2) + size = 2; + + if (test_bit(DM_ACTIVE, &md->state)) + content[0] = '1'; + + if (copy_to_user(buf, content, size)) + return -EFAULT; + + return size; } static ssize_t dmfs_suspend_write(struct file *file, const char *buf, size_t size, loff_t *pos) { - down(&inode->i_sem); + struct inode *inode = file->f_dentry->d_inode; + char cmd; - up(&inode->i_sem); + if (size == 0) + return 0; + + size = 1; + if (copy_from_user(&cmd, buf, size)) + return -EFAULT; + + if (cmd != '0' && cmd != '1') + return -EINVAL; + + /* do suspend or unsuspend */ + + return size; } static int dmfs_suspend_sync(struct file *file, struct dentry *dentry, int datasync) @@ -42,10 +67,8 @@ static int dmfs_suspend_sync(struct file *file, struct dentry *dentry, int datas } static struct dm_table_file_operations = { -/* llseek: generic_file_llseek, */ read: dmfs_suspend_read, write: dmfs_suspend_write, - open: dmfs_suspend_open, fsync: dmfs_suspend_sync, }; diff --git a/driver/device-mapper/dmfs-table.c b/driver/device-mapper/dmfs-table.c index 6e3e9dbea..5c1858135 100644 --- a/driver/device-mapper/dmfs-table.c +++ b/driver/device-mapper/dmfs-table.c @@ -21,18 +21,179 @@ #include #include +#include +#include "dm.h" + + +static int dmfs_parse_line(struct dmfs_table *t, char *str) +{ + char *p = str; + const char *delim = " \t"; + const char *tok; + offset_t start, size, high; + void *context; + struct target_type *ttype; + + tok = strsep(&p, delim); + if (!tok) + return -1; + start = simple_strtoul(tok, NULL, 10); + + tok = strsep(&p, delim); + if (!tok) + return -1; + size = simple_strtoul(tok, NULL, 10); + + tok = strsep(&p, delim); + if (!tok) + return -1; + + ttype = dm_get_target_type(tok); + if (ttype) { + context = ttype->ctr(t, start, size, p); + if (!IS_ERR(context)) { + high = start + (size - 1); + if (dm_table_add_target(t, high, ttype, context) == 0) + return 0; + ttype->dtr(t, context); + } + dm_put_target_type(ttype); + } + return -1; +} + +static int dmfs_copy(char *dst, int dstlen, char *src, int srclen, int *flag) +{ + int copied = 0; + + while(dstlen && srclen) { + *dst = *src++; + copied++; + if (*dst == '\n') + goto end_of_line; + dst++; + dstlen--; + srclen--; + } +out: + return copied; +end_of_line: + *flag = 1; + *dst = 0; + goto out; +} + +static int dmfs_parse_page(struct dm_table *t, char *buf, int len, char *tmp, unsigned long *tmpl) +{ + int copied; + + do { + int flag = 0; + copied = dmfs_copy(tmp + *tmpl, PAGE_SIZE - *tmpl - 1, buf, len, &flag); + buf += copied; + len -= copied; + if (*tmpl + copied == PAGE_SIZE - 1) + return -1; + *tmpl = copied; + if (flag) { + if (dmfs_parse_line(t, tmp)) + return -1; + *tmpl = 0; + } + } while(len > 0); + return 0; +} + +static struct dm_table *dmfs_parse(struct inode *inode) +{ + struct address_space *mapping = inode->i_mapping; + unsigned long index = 0; + unsigned long offset = 0; + unsigned long end_index, end_offset; + unsigned long page; + unsigned long rem = 0; + struct dm_table *t; + struct page *pg, **hash; + + if (inode->i_size == 0) + return NULL; + + page = __get_free_page(GFP_KERNEL); + + if (!page) + return NULL; + + t = dm_create_table(); + if (!t) { + free_page(page); + return NULL; + } + + down(&inode->i_sem); + end_index = inode->i_size >> PAGE_CACHE_SIZE; + end_offset = inode->i_size & (PAGE_CAHE_SIZE - 1); + + do { + unsigned long end = (index == end_index) ? end_offset : PAGE_CACHE_SIZE; + hash = page_hash(mapping, index); + + spin_lock(&pagecache_lock); + pg = __find_page_nolock(mapping, index, *hash); + if (pg) + page_cache_get(pg); + spin_unlock(&pagecache_lock); + + if (pg) { + if (!Page_Uptodate(pg)) + goto broken; + + if (dmfs_parse_page(t, pg, end, (char *)page, &rem)) + goto parse_error; + } + + page_cache_release(pg); + index++; + } while(index != end_index); + + up(&inode->i_sem); + + free_page(page); + if (dm_table_complete(t) == 0) + return t; + + dm_put_table(t); + return NULL; + +broken: + up(&inode->i_sem); + printk(KERN_ERR "dmfs_parse: Page not uptodate\n"); + free_page(page); + dm_put_table(t); + return NULL; + +parse_error: + up(&inode->i_sem); + printk(KERN_ERR "dmfs_parse: Parse error\n"); + free_page(page); + dm_put_table(t); + return NULL; +} static int dmfs_release(struct inode *inode, struct file *f) { struct dm_table *table; - /* FIXME: we should lock the inode to - prevent someone else opening it while - we are parsing */ - if (!(f->f_mode & S_IWUGO)) return 0; + table = dmfs_parse(inode); + + if (table) { + dm_put_table((struct dm_table *)inode->u.generic_ip); + inode->u.generic_ip = table; + } + + return 0; } static int dmfs_readpage(struct file *file, struct page *page) @@ -95,7 +256,6 @@ static struct dm_table_file_operations = { llseek: generic_file_llseek, read: generic_file_read, write: generic_file_write, - mmap: generic_file_mmap, fsync: dmfs_table_sync, release: dmfs_release, };