OGAWA Hirofumi <hirof...@mail.parknet.co.jp> writes: > Daniel Phillips <phill...@phunq.net> writes: > >> Here is my original ddlink writeup, posted a year ago: >> >> "An alternative interface to device mapper" >> http://lwn.net/Articles/271805/ > > I converted the fd allocation code to anon_inode_getfd(). It may clear > the point of ddlink. Well, anyway, the patches is the following.
FWIW, this is one patch version.
DESC (undescribed patch) EDESC DESC (undescribed patch) EDESC diff -puN user/kernel/Makefile~tux3.ddlink user/kernel/Makefile --- tux3/user/kernel/Makefile~tux3.ddlink 2009-02-26 19:26:40.000000000 +0900 +++ tux3-hirofumi/user/kernel/Makefile 2009-02-26 19:26:40.000000000 +0900 @@ -7,7 +7,7 @@ clean: make -C $(LINUX) M=`pwd` CONFIG_TUX3=m clean else obj-$(CONFIG_TUX3) += tux3.o -tux3-objs += balloc.o btree.o dir.o dleaf.o filemap.o iattr.o \ +tux3-objs += ddlink.o balloc.o btree.o dir.o dleaf.o filemap.o iattr.o \ ileaf.o namei.o inode.o super.o xattr.o log.o commit.o utility.o EXTRA_CFLAGS += -Werror -std=gnu99 -Wno-declaration-after-statement endif diff -puN /dev/null user/kernel/ddlink.c --- /dev/null 2009-02-23 19:28:52.553000910 +0900 +++ tux3-hirofumi/user/kernel/ddlink.c 2009-02-26 19:27:09.000000000 +0900 @@ -0,0 +1,248 @@ +#include <linux/file.h> +#include <linux/poll.h> +#include <linux/mount.h> +#include <linux/module.h> +#include <linux/anon_inodes.h> +#include "ddlink.h" + +/* + * ddlink: Device Driver link. A userspace to kernel device control interface + * useful for kernel/userspace interfaces. + * + * (c) 2007-2009, Daniel Phillips <phill...@phunq.net> + */ + +// To do: +// * need spinlocks on push, pop, queue, ready and ??? + +int ddlink_ready(struct ddctl *dd) +{ + return !list_empty(&dd->list); +} +EXPORT_SYMBOL_GPL(ddlink_ready); + +struct dditem *ddlink_pop(struct ddctl *dd) +{ + struct dditem *item; + BUG_ON(!ddlink_ready(dd)); + item = list_entry(dd->list.next, struct dditem, link); + list_del(&item->link); + return item; +} +EXPORT_SYMBOL_GPL(ddlink_pop); + +void ddlink_clear(struct ddctl *dd) +{ + while (ddlink_ready(dd)) + dd->destroy_item(ddlink_pop(dd)); +} +EXPORT_SYMBOL_GPL(ddlink_clear); + +static struct ddctl *ddlink_alloc_ddctl(void) +{ + struct ddctl *dd = kmalloc(sizeof(struct ddctl), GFP_KERNEL); + if (!dd) + return NULL; + *dd = (typeof(*dd)){ + .wait = __WAIT_QUEUE_HEAD_INITIALIZER(dd->wait), + .list = LIST_HEAD_INIT(dd->list) }; + return dd; +} + +static void ddlink_free_ddctl(struct ddctl *dd) +{ + ddlink_clear(dd); + if (ddinfo(dd)) + dd->destroy_info(ddinfo(dd)); + kfree(dd); +} + +int ddlink_file_release(struct inode *inode, struct file *filp) +{ + ddlink_free_ddctl(ddctl(filp)); + return 0; +} +EXPORT_SYMBOL_GPL(ddlink_file_release); + +int ddlink(const struct file_operations *fops, void *(*create)(struct ddctl *dd, void *info), void *info) +{ + struct ddctl *dd; + void *private = NULL; + int err; + + BUG_ON(!fops->release); + + dd = ddlink_alloc_ddctl(); + if (!dd) + return -ENOMEM; + dd->destroy_info = kfree; + dd->create_item = kmalloc; + dd->destroy_item = kfree; + + if (create && IS_ERR(private = create(dd, info))) { + err = PTR_ERR(private); + goto error; + } + dd->private = private; + + err = anon_inode_getfd("[ddlink]", fops, dd, 0); + if (err < 0) + goto error; + return err; + +error: + ddlink_free_ddctl(dd); + return err; +} +EXPORT_SYMBOL_GPL(ddlink); + +/* library methods */ + +void ddlink_push(struct ddctl *dd, struct dditem *item) +{ + list_add(&item->link, &dd->list); + wake_up_interruptible(&dd->wait); +} +EXPORT_SYMBOL_GPL(ddlink_push); + +void ddlink_queue(struct ddctl *dd, struct dditem *item) +{ + list_add_tail(&item->link, &dd->list); + wake_up_interruptible(&dd->wait); +} +EXPORT_SYMBOL_GPL(ddlink_queue); + +struct dditem *dditem_new(struct ddctl *dd, size_t size) +{ + struct dditem *item; + if (!(item = dd->create_item(sizeof(*item) + size, __GFP_NOFAIL))) // NOFAIL?? + return NULL; + *item = (typeof(*item)){ .size = size }; + return item; +} +EXPORT_SYMBOL_GPL(dditem_new); + +struct dditem *dditem_in(struct ddctl *dd, const void *buf, size_t len, int z) +{ + struct dditem *item = dditem_new(dd, len + z); + + if (!item) + return ERR_PTR(-ENOMEM); + if (copy_from_user(item->data, buf, len)) { + dd->destroy_item(item); + return ERR_PTR(-EFAULT); + } + if (z) { + item->size -= z; + item->data[len] = 0; + } + return item; +} +EXPORT_SYMBOL_GPL(dditem_in); + +int dditem_out(struct ddctl *dd, void *buf, size_t len, struct dditem *item) // !!! not tested +{ + if (len < item->size) + return -EINVAL; + if (copy_to_user(buf, item->data, len = item->size)) + return -EFAULT; + dd->destroy_item(item); + return len; +} +EXPORT_SYMBOL_GPL(dditem_out); + +int ddlink_post(struct ddctl *dd, void *data, unsigned len) +{ + struct dditem *item = dditem_new(dd, len); + if (!item) + return -ENOMEM; + memcpy(item->data, data, len); + ddlink_push(dd, item); + return 0; +} +EXPORT_SYMBOL_GPL(ddlink_post); + +int ddlink_error(struct ddctl *dd, int err, const char *fmt, ...) +{ + int size = 200; /* enough for any error? */ + struct dditem *item, *work; + va_list args; + if (err >= 0) + return err; + if (!(work = dditem_new(dd, size))) + return -ENOMEM; + va_start(args, fmt); + size = vsnprintf(work->data, size, fmt, args); + va_end(args); + if (!(item = dditem_new(dd, size))) { + err = -ENOMEM; + goto fail; + } + memcpy(item->data, work->data, size); + ddlink_push(dd, item); +fail: + dd->destroy_item(work); + return err; +} +EXPORT_SYMBOL_GPL(ddlink_error); + +unsigned ddlink_poll(struct file *file, poll_table *table) +{ + struct ddctl *dd = ddctl(file); + poll_wait(file, &dd->wait, table); + return ddlink_ready(dd) ? POLLIN : 0; +} +EXPORT_SYMBOL_GPL(ddlink_poll); + +#if 0 +/* ddlink example */ + +#include "ddlink.h" + +static int ddlink_example_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long ptr) +{ + struct ddctl *dd = ddctl(file); + printk("ddlink_ioctl %i (%lx) on %p\n", cmd, ptr, dd); + return 0; +} + +static ssize_t ddlink_example_write(struct file *file, const char *buf, size_t len, loff_t *offset) +{ + struct ddctl *dd = ddctl(file); + struct dditem *item = dditem_in(dd, buf, len, 1); + if (IS_ERR(item)) + return PTR_ERR(item); + ddlink_queue(dd, item); + return len; +} + +static ssize_t ddlink_example_read(struct file *file, char *buf, size_t len, loff_t *offset) +{ + struct ddctl *dd = ddctl(file); + if (list_empty(&dd->list)) + return EFAULT; + return dditem_out(dd, buf, len, ddlink_pop(dd)); +} + +static const struct file_operations ddlink_example_fops = { + .read = ddlink_example_read, + .write = ddlink_example_write, + .ioctl = ddlink_example_ioctl, + .poll = ddlink_poll, + .release = ddlink_file_release, +}; + +void *ddlink_example_create(struct ddctl *dd, void *info) +{ + return NULL; +} + +long example_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case DDLINK: + return ddlink(&ddlink_example_fops, ddlink_example_create, NULL); + } + return -ENOTTY; +} +#endif diff -puN /dev/null user/kernel/ddlink.h --- /dev/null 2009-02-23 19:28:52.553000910 +0900 +++ tux3-hirofumi/user/kernel/ddlink.h 2009-02-26 19:27:09.000000000 +0900 @@ -0,0 +1,45 @@ +#include <linux/poll.h> +#include <linux/list.h> + +#define DDLINK _IO(0, 0xdd) + +struct dditem { + struct list_head link; + unsigned type; // not actually used + unsigned size; + unsigned char data[]; +}; + +struct ddctl { + struct list_head list; + wait_queue_head_t wait; + typeof(kmalloc) *create_item; + typeof(kfree) *destroy_item; + typeof(kfree) *destroy_info; + void *private; +}; + +static inline struct ddctl *ddctl(struct file *file) +{ + return file->private_data; +} + +static inline void *ddinfo(struct ddctl *dd) +{ + return dd->private; +} + +int ddlink_file_release(struct inode *inode, struct file *filp); +int ddlink(const struct file_operations *fops, void *(*create)(struct ddctl *dd, void *info), void *info); +void ddlink_queue(struct ddctl *dd, struct dditem *item); +void ddlink_push(struct ddctl *dd, struct dditem *item); +struct dditem *ddlink_pop(struct ddctl *dd); +struct dditem *dditem_new(struct ddctl *dd, size_t size); +void ddlink_clear(struct ddctl *dd); +int ddlink_ready(struct ddctl *dd); + +struct dditem *dditem_in(struct ddctl *dd, const void *buf, size_t len, int z); +int dditem_out(struct ddctl *dd, void *buf, size_t len, struct dditem *item); +int ddlink_post(struct ddctl *dd, void *data, unsigned len); +unsigned ddlink_poll(struct file *file, poll_table *table); +int ddlink_error(struct ddctl *dd, int err, const char *fmt, ...); diff -puN user/kernel/inode.c~tux3.ddlink user/kernel/inode.c --- tux3/user/kernel/inode.c~tux3.ddlink 2009-02-26 19:26:40.000000000 +0900 +++ tux3-hirofumi/user/kernel/inode.c 2009-02-26 19:27:09.000000000 +0900 @@ -372,13 +372,57 @@ int tux3_setattr(struct dentry *dentry, return inode_setattr(inode, iattr); } +/* ddlink example */ + +#include "ddlink.h" + +static int ddlink_example_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long ptr) +{ + struct ddctl *dd = ddctl(file); + printk("ddlink_ioctl %i (%lx) on %p\n", cmd, ptr, dd); + return 0; +} + +static ssize_t ddlink_example_write(struct file *file, const char *buf, size_t len, loff_t *offset) +{ + struct ddctl *dd = ddctl(file); + struct dditem *item = dditem_in(dd, buf, len, 1); + if (IS_ERR(item)) + return PTR_ERR(item); + ddlink_queue(dd, item); + return len; +} + +static ssize_t ddlink_example_read(struct file *file, char *buf, size_t len, loff_t *offset) +{ + struct ddctl *dd = ddctl(file); + if (list_empty(&dd->list)) + return EFAULT; + return dditem_out(dd, buf, len, ddlink_pop(dd)); +} + +static const struct file_operations ddlink_example_fops = { + .read = ddlink_example_read, + .write = ddlink_example_write, + .ioctl = ddlink_example_ioctl, + .poll = ddlink_poll, + .release = ddlink_file_release, +}; + +long tux3_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + if (cmd == DDLINK) + return ddlink(&ddlink_example_fops, NULL, NULL); + return -ENOTTY; +} + static const struct file_operations tux_file_fops = { .llseek = generic_file_llseek, .read = do_sync_read, .write = do_sync_write, .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, -// .unlocked_ioctl = fat_generic_ioctl, + .unlocked_ioctl = tux3_ioctl, #ifdef CONFIG_COMPAT // .compat_ioctl = fat_compat_dir_ioctl, #endif diff -puN user/kernel/namei.c~tux3.ddlink user/kernel/namei.c --- tux3/user/kernel/namei.c~tux3.ddlink 2009-02-26 19:26:40.000000000 +0900 +++ tux3-hirofumi/user/kernel/namei.c 2009-02-26 19:26:40.000000000 +0900 @@ -253,7 +253,10 @@ error: return err; } +long tux3_ioctl(struct file *file, unsigned int cmd, unsigned long arg); + const struct file_operations tux_dir_fops = { + .unlocked_ioctl = tux3_ioctl, .llseek = generic_file_llseek, .read = generic_read_dir, .readdir = tux_readdir, _
-- OGAWA Hirofumi <hirof...@mail.parknet.co.jp>
_______________________________________________ Tux3 mailing list Tux3@tux3.org http://mailman.tux3.org/cgi-bin/mailman/listinfo/tux3