On Tue, Jul 01, 2008 at 01:44:17AM -0700, Roland McGrath wrote: > 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); >
Hi All, Sorry if I have missed out something I need to know before I respond to this email. But the "trace" infrastructure (lib/trace.c) already provides such a facility which more features such as per-cpu buffer for faster transmission (it is a wrapper over "relay" which sits on top of "debugfs"). The interfaces provided by "trace" are much simpler/functional than setting up a "debugfs" interface manually (see samples/trace/fork_trace.c) and the directory structure and control files setup by "trace" are already familiar to the systemtap code. Thanks, K.Prasad P.S.: "trace" is currently in -mm tree.