If serialisation (aka "marshalling") is considered, how about making it text based? Then you can use simple shell tools to talk to it.
On 27 March 2015 at 22:34, Elazar Leibovich <elaz...@gmail.com> wrote: > IMHO, C structs are no way near as usable as proper serialization > format. For example, what about optional fields? What about variable > length array? What about binary backwards compatibility? What about > supporting other languages? It's not trivial to take a C struct and > generate the proper struct.unpack string for it. > > Look at the complexity in perf_event_open(2), just parsing the event > stream takes a good chunk of code[0], with many potential bugs. > Parsing it with protobuf (or one of the other serialization formats) > would take three lines or so, would be more efficient, and would be > easier to program against, and less prone to bugs, etc. > > [0] Here is my take, and it's not even complete > https://gist.github.com/elazarl/c8404686e71ef0b36cc7 > > On Fri, Mar 27, 2015 at 12:26 PM, guy keren <guy.choo.ke...@gmail.com> > wrote: > > > > i imagine, if you use the proper 'packing' pragmas, you can simply mempcy > > structures, without really writing serialization code (there's no > endianess > > issues, with both sides running on the same host, by definition). > > > > --guy > > > > > > On 03/27/2015 10:03 AM, Elazar Leibovich wrote: > >> > >> Thanks, didn't know netlink. > >> > >> You still need a solution to parse the sent message, where protocol > >> buffers etc, can help. (e.g., binary data into struct > >> mymodule_request). > >> > >> Or am I missing something? > >> > >> On Fri, Mar 27, 2015 at 3:33 AM, guy keren <guy.choo.ke...@gmail.com> > >> wrote: > >>> > >>> > >>> take a look at this: > >>> > >>> > >>> > http://www.linuxfoundation.org/collaborate/workgroups/networking/generic_netlink_howto > >>> > >>> (link got broken - place it all on a single line) > >>> > >>> --guy > >>> > >>> > >>> On 03/26/2015 11:36 PM, Elazar Leibovich wrote: > >>>> > >>>> > >>>> Hi, > >>>> > >>>> I'm writing a kernel module, and I want to expose some debug > >>>> information about it. > >>>> > >>>> The debug information is often of the form of request-response. > >>>> > >>>> For example: > >>>> > >>>> - Hey module, what's up with data at 0xffffe8ff0040c000? > >>>> - Cached, populated two hours ago. > >>>> > >>>> - Hey module, please invalidate data at 0xffffe8ff0002cb00 > >>>> - Sure thing. > >>>> > >>>> - Hey module, please record all accesses to 0xffffe8ff0006bbf0. > >>>> - OK, ask me again for stats-5 > >>>> ... > >>>> - Hey module, what's in stats-5? > >>>> - So far, 41 accesses by 22 users. > >>>> > >>>> Now, the question is, what is a good design to expose this > information. > >>>> > >>>> I think that the most reasonable way to interact with userspace is > >>>> through a debugfs file. > >>>> > >>>> The user would open the debugfs file in read+write mode, would write a > >>>> request, and accept a response from it. > >>>> > >>>> As I see it, there are two fundamental problems needs to be solved: > >>>> > >>>> - Parsing the request from the client. > >>>> - Writing the response in a recognizeable format. > >>>> > >>>> A simple solution I first came up with, is to use a ad-hoc > >>>> request-response format. In my case, request and response are line > >>>> delimited, request is a hex address, and response is a translated hex > >>>> address. > >>>> > >>>> Here is the relevant snippet. > >>>> > >>>> struct pipe { > >>>> DECLARE_KFIFO(fifo, T, (1<<4)); > >>>> wait_queue_head_t queue; > >>>> char buf[100]; > >>>> int buflen; > >>>> char resp[100]; > >>>> int resp_len; > >>>> }; > >>>> static DEFINE_MUTEX(mutex); > >>>> static int open(struct inode *inode, struct file *file) > >>>> { > >>>> struct pipe *pipe; > >>>> if (!(file->f_mode & FMODE_READ) || !(file->f_mode & > FMODE_READ)) > >>>> { > >>>> pr_warn("must open with O_RDWR\n"); > >>>> return -EINVAL; > >>>> } > >>>> mutex_lock(&mutex); > >>>> pipe = kzalloc(sizeof(*pipe), GFP_KERNEL); > >>>> INIT_KFIFO(pipe->fifo); > >>>> init_waitqueue_head(&pipe->queue); > >>>> file->private = pipe; > >>>> } > >>>> > >>>> static int write(struct file *file, const char __user *ubuf, size_t > >>>> count, loff_t *ppos) > >>>> { > >>>> char *eol; > >>>> size_t n = min_t(size_t, count, sizeof(pipe->buf)); > >>>> struct pipe *pipe = file->private_data; > >>>> if (copy_from_user(&pipe->buf[pipe->buflen], ubuf, n) > >>>> return -EFAULT; > >>>> eol = memchr(buf, '\n', n); > >>>> if (eol == NULL) > >>>> return count; > >>>> *eol = '\0'; > >>>> // TODO: wait when queue full > >>>> if (!kfifo_in(&pipe->fifo, processLine(buf), 1) > >>>> return -EFAULT; > >>>> wake_up_interruptible(&pipe->queue); > >>>> memmove(&pipe->buf[0], &pipe->buf[n], pipe->buflen-n); > >>>> } > >>>> > >>>> static int read(struct file *file, const char __user *ubuf, size_t > >>>> count, loff_t *ppos) > >>>> { > >>>> struct pipe *pipe = file->private_data; > >>>> T req; > >>>> wait_event_interruptible(pipe->queue, kfifo_out(&pipe->fifo, > &req, > >>>> 1)); > >>>> process_request(req, &pipe->resp, &pipe->resp_len); > >>>> if (count < pipe->resp_len) > >>>> return -EFAULT; // TODO: handle copy to client in parts > >>>> if (copy_to_user(userbuf, buf, pipe->resp_len)) > >>>> return -EFAULT; > >>>> } > >>>> > >>>> Usage is: > >>>> > >>>> fd = io.FileIO("/debug/mymodule/file", "r+") > >>>> fd.write('req...') > >>>> print fd.read(100) > >>>> > >>>> This is not so robust, for many reasons (look how many bugs are in > >>>> this small and simple snippet), and some parts need to be repeated for > >>>> each input type. > >>>> > >>>> What I've had in mind, in similar fashion to grpc.io, have the user > >>>> write a size prefixed protocol buffer object to the file, and > >>>> similarly read it as a response. > >>>> > >>>> Something like: > >>>> > >>>> fd = io.FileIO("/debug/mymodule/file", "r+") > >>>> fd.write(myReq.SerializeToString()) > >>>> len = struct.unpack("<i", fd.read(4)) > >>>> Resp.ParseFromString(fd.read(len)) > >>>> > >>>> I believe it is not hard to create a kernel compatible protocol buffer > >>>> code generator. > >>>> > >>>> When you have this in place, you have to write a very simple logic to > >>>> add a new functionality to the debugfs file. Handler would essentially > >>>> get pointers to a request struct, and a response struct, and would > >>>> need to fill out the response struct. > >>>> > >>>> Are there similar solutions? > >>>> What problems might my approach cause? > >>>> Is there a better idea for this problem altogether? > >>>> > >>>> Thanks, > >>>> > >>>> _______________________________________________ > >>>> Linux-il mailing list > >>>> Linux-il@cs.huji.ac.il > >>>> http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il > >>>> > >>> > >>> > >>> _______________________________________________ > >>> Linux-il mailing list > >>> Linux-il@cs.huji.ac.il > >>> http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il > > > > > > _______________________________________________ > Linux-il mailing list > Linux-il@cs.huji.ac.il > http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il > -- <http://au.linkedin.com/in/gliderflyer>
_______________________________________________ Linux-il mailing list Linux-il@cs.huji.ac.il http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il