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