relay revamp v8
cover relay revamp v8
Here's version 8 of the 'relay revamp' patchset.
The difference between this version and version 7 is a set of small changes needed to make kvm_trace work properly (details below).
I've tested this version with both kvm_trace and blktrace and both seemed to perform well and without any problems.
At this point, I think the patchset is mergeable - I would have liked to have had more time for testing, but wanted to post it for consideration anyway before the 2.6.28 merge window closed; I have the funny feeling that if it doesn't make it into 2.6.28, it (or the current relay) won't survive to see 2.6.29.
As I've mentioned previously, I think the end result of all these changes is really a much nicer, simpler and more powerful design (and implementation) and for that reason alone, I think it's worthwhile to consider merging.
But probably the more important reason I'd like to see it in 2.6.28 is that despite the fact that I turned relay maintainership over two years ago, I'm still the only one banging my head against the wall when problems come up, and I just don't want to have to do it any more; even if I'm not the one maintaining it, it's now much easier for anyone else to understand what's going on. A major part of the headaches had to do with padding and sub-buffers, which are now either gone or handled in a sane way - over the past several months, I've spent a lot of late nights digging into a couple of bugs directly related to those 'features' of the current relay. Actually, those features made some sense when the target users were supposed to be using mmap, which is what relay was originally designed for (splice didn't even exist then), but they really got in the way of a sane read(2) implementation, which was basically bolted on as an afterthought. As it turned out, once it was added, read(2) ended up being used pretty much exclusively, which in reality hasn't been a problem from the user's perspective - it's proven to be very high-performing and robust - there's really only been one bug reported and fixed against it, and that basically amounted to a corner case. Nonetheless, from a maintenance perspective, it wasn't fun to dig up the cause and fix it. With the new patchset, that should no longer be the case.
Finally, the fact that the current relay isn't really broken and actually performs well means that even if the new changes turn out to be fatally flawed in some way, they can just be reverted and the current relay will still be there and will still work the same as before.
Rather than posting all the individual patches again, I'm just posting the squashed version. The description for that patch contains the overview and API description; if it gets merged, I'll convert all that to Documentation later.
I'm also appending the end-result relay and relay_pagewriter at the end of this mail since it may be hard to see the result through all the individual changes.
Here's the description of the additional patch beyond the previous 23 (rolled into the full patch, and not posted separately):
-- Fixes to make kvm_trace work properly with new relay.
kvm_trace uses the new_page() callback to write a magic number at the beginning of the first page, but the logic added in an earlier patch to do that was erroneously using a per-channel flag for that; what's really needed is a per-buffer flag. Added a private_data field to pagewriter_buf for this purpose. Also discovered that the first page was being switched twice at the beginning of a trace, so removed the extra initial page_switch and added it to __pagewriter_reset().
Below is the current relay/relay_pagewriter code after applying all patches in the patchset, for convenience.
Tom
linux/relay.h new file +176 -0
@@ -0,0 +1,176 @@ +/* +* linux/include/linux/relay.h +* +* Copyright (C) 2002, 2003 - Tom Zanussi ([email protected]), IBM Corp +* Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour ([email protected]) +* Copyright (C) 2008 - Tom Zanussi ([email protected]) +* +* CONFIG_RELAY definitions and declarations +*/ + +#ifndef _LINUX_RELAY_H +#define _LINUX_RELAY_H + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/wait.h> +#include <linux/list.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/kref.h> +#include <linux/pagevec.h> + +/* +* relay channel flags +*/ +#define RCHAN_GLOBAL_BUFFER 0x00000001/* not using per-cpu */ + +/* +* For page lists +*/ +struct relay_page { +struct page *page; +size_t len; +struct list_head list; +struct relay_page_callbacks *cb; +void *private_data; +}; + +/* +* Per-cpu relay channel buffer +*/ +struct rchan_buf { +struct rchan *chan;/* associated channel */ +wait_queue_head_t read_wait;/* reader wait queue */ +struct timer_list timer;/* reader wake-up timer */ +struct dentry *dentry;/* channel file dentry */ +struct kref kref;/* channel buffer refcount */ +struct list_head pages;/* current set of unconsumed pages */ +size_t nr_pages;/* number of unconsumed pages */ +spinlock_t lock;/* protect pages list */ +size_t consumed_offset;/* bytes consumed in cur page */ +unsigned int finalized;/* buffer has been finalized */ +unsigned int cpu;/* this buf's cpu */ +}____cacheline_aligned ; + +/* +* Relay channel data structure +*/ +struct rchan +{ +size_t n_pages_wakeup;/* wake up readers after filling n */ +struct rchan_callbacks *cb;/* client callbacks */ +struct kref kref;/* channel refcount */ +void *private_data;/* for user-defined data */ +struct rchan_buf *buf[NR_CPUS ];/* per-cpu channel buffers */ +struct list_head list;/* for channel list */ +struct dentry *parent;/* parent dentry passed to open */ +char base_filename[NAME_MAX ];/* saved base filename */ +unsigned long flags;/* relay flags for this channel */ +}; + +/* +* Relay channel client callbacks +*/ +struct rchan_callbacks +{ +/* +* create_buf_file - create file to represent a relay channel buffer +* @filename: the name of the file to create +* @parent: the parent of the file to create +* @mode: the mode of the file to create +* @buf: the channel buffer +* +* Called during relay_open(), once for each per-cpu buffer, +* to allow the client to create a file to be used to +* represent the corresponding channel buffer. If the file is +* created outside of relay, the parent must also exist in +* that filesystem. +* +* The callback should return the dentry of the file created +* to represent the relay buffer. +* +* See Documentation/filesystems/relayfs.txt for more info. +*/ +struct dentry *(*create_buf_file)(const char *filename, +struct dentry *parent, +int mode, +struct rchan_buf *buf); + +/* +* remove_buf_file - remove file representing a relay channel buffer +* @dentry: the dentry of the file to remove +* +* Called during relay_close(), once for each per-cpu buffer, +* to allow the client to remove a file used to represent a +* channel buffer. +* +* The callback should return 0 if successful, negative if not. +*/ +int (*remove_buf_file)(struct dentry *dentry); +}; + +/* +* Relay page callbacks +*/ +struct relay_page_callbacks +{ +/* +* page_released - notification that a page is ready for re-use +* @page: the released page +* @private_data: user-defined data associated with the page +* +* This callback is a notification that a given page has been +* read by userspace and can be re-used. Always called in +* user context. +*/ +void (*page_released) (struct page *page,void *private_data); + +/* +* page_released - notification that a page has been stolen +* @page: the stolen page +* @private_data: user-defined data associated with the page +* +* This callback is a notification that a given page has been +* stolen by userspace. The owner may wish to replace it; +* this gives it the opportunity to do so. Always called in +* user context. +*/ +void (*page_stolen) (struct page *page,void *private_data); +}; + +/* +* CONFIG_RELAY kernel API, kernel/relay.c +*/ + +extern struct rchan *relay_open (const char *base_filename, +struct dentry *parent, +size_t n_pages_wakeup, +struct rchan_callbacks *cb, +void *private_data, +unsigned long rchan_flags); +extern void relay_add_partial_page (struct rchan *chan, +struct page *page, +size_t len, +struct relay_page_callbacks *cb, +void *private_data); +extern void relay_add_page (struct rchan *chan, +struct page *page, +struct relay_page_callbacks *cb, +void *private_data); +extern void relay_add_pages (struct rchan *chan, +struct pagevec *pages, +struct relay_page_callbacks *cb, +void *private_data); +extern void relay_flush (struct rchan *chan); +extern void relay_close (struct rchan *chan); +extern void relay_reset (struct rchan *chan); + +/* +* exported relay file operations, kernel/relay.c +*/ +extern const struct file_operations relay_file_operations; + +#endif /* _LINUX_RELAY_H */ +
relay.c new file +1015 -0
1,015 lines not on this page · raw message
linux/relay_pagewriter.h new file +295 -0
295 lines not on this page · raw message
relay_pagewriter.c new file +860 -0
860 lines not on this page · raw message