Sorry to be blunt, Chris.  But I think you're headed down a useless rat hole.

I agree that the usage of /proc you've described is a bad interface.
I am slightly mystified as to how that came to be what you settled on.
I don't think it's worthwhile to hash over that.  Let's move on.

Please forget ptrace.  Please forget about adding syscalls.  At this
point I think I just need you to give me the benefit of the doubt when
I tell you I am sure this is not the way, and even dabbling sidetracks
us from really useful progress.  Let's move on.

To reiterate: transport is boring.  This is not where the there is.
We need to focus on what we're providing that anyone could care to
have a means to communicate with!

I'm pretty sure what most people had in mind when saying "fd-based" is
approximately this: you do one open call, that fd is your handle on
one session with the interface.  You can write/ioctl to send it
commands, and you can read (and perhaps ioctl) on it to receive either
information replies or event notifications.  You can use poll/select
et al for efficient wakeup when there is something the interface wants
to tell you.  As with all fds, sudden death of the holder of the fd
implicitly closes it and that triggers cleanup of the session on the
kernel side.  There are more possibilities with multiple fds used
together as one "session with the interface", but this is the basic
one.  Let's start with that focus and move on.

Below is a trivial example I whipped up.  This uses debugfs.  There
are myriad ways to do the same thing; this one is simple and handy.
I hope it illustrates how a magic file can set up per-open data
structures for its operations to use, and tear them down gracefully
and automatically on close.  It should be clear how to add .write,
.poll, .unlocked_ioctl, etc. functions to build a full transport
this way without much hair.  This method is the easy path to start
with, and we can worry more about transport later.  Let's move on.

The way to find the easy route is to ask for directions.  When it
seems like there ought to be a more natural way to do something, there
might well be some ways.  When you post here about what you're up
against, people here can give you pointers to what might help.  It's
not like posting on LKML and braving the flames.  Noone here is going
to give you a hard time (not worse than this, anyway).  We need your
participation to be able to share what we know.  Let's move on together.

I'm sorry I've been remiss in writing up everything I've promised
about what I think we do need to focus on.  It hasn't helped to get
sidetracked on what I say is the boring stuff.  But I recognize that
my disorganization makes it difficult on your end.


Thanks,
Roland


-----
/*
 * Compile the module and insmod it.
 * Be sure to have done "mount -t debugfs debugfs /sys/kernel/debug"
 * (systemtap or something else might already have done it for you).
 * Look at /sys/kernel/debug/foo for example behavior.
 */

#include <linux/sched.h>
#include <linux/module.h>
#include <linux/debugfs.h>
#include <asm/atomic.h>

MODULE_DESCRIPTION("example using debugfs");
MODULE_LICENSE("GPL");

static atomic_t next = ATOMIC_INIT(0);

static int example_open(struct inode *inode, struct file *file)
{
        /*
         * The 'struct file' describes what the user's file descriptor
         * from this one open points to.  It's shared by dup and fd
         * inheritance, but not by an independent open call.  We can
         * stash here some data specific to just this one open file
         * description.
         */
        file->private_data = (void *) (unsigned long) atomic_inc_return(&next);
        return 0;
}

static ssize_t example_read(struct file *file, char __user *buf,
                            size_t count, loff_t *ppos)
{
        unsigned long n = (unsigned long) file->private_data;
        char string[128];
        int size = snprintf(string, sizeof string, "you are number %lu\n", n);

        return simple_read_from_buffer(buf, count, ppos, string, size);
}

static int example_release(struct inode *inode, struct file *file)
{
        unsigned long n = (unsigned long) file->private_data;
        printk(KERN_NOTICE "bye bye number %lu\n", n);
        return 0;
}

static const struct file_operations example_fops = {
        .owner = THIS_MODULE,
        .open = example_open,
        .release = example_release,
        .read = example_read
};

static struct dentry *top_dentry;

static int __init init_example(void)
{
        struct dentry *d = debugfs_create_file("foo", 0666, NULL,
                                               NULL, &example_fops);
        if (!d)
                return -EROFS;
        if (IS_ERR(d))
                return PTR_ERR(d);
        top_dentry = d;
        return 0;
}

static void __exit exit_example(void)
{
        debugfs_remove(top_dentry);
}

module_init(init_example);
module_exit(exit_example);

Reply via email to