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

Reply via email to