blk queue io tracing support
Subsystems (2)
PATCH 1/1 blk queue io tracing support
Hi,
This is a little something I have played with. It allows you to see exactly what is going on in the block layer for a given queue. Currently it can logs request queueing and building, dispatches, requeues, and completions. I've uploaded a little silly app to do dumps here:
http://www.kernel.org/pub/linux/kernel/people/axboe/tools/blktrace.c
Sample output looks like this:
wiggum:~ # ./blktrace /dev/sda
relay name: /relay/sda0
0 3765 Q R 192-200
5 3765 G R
13 3765 M R [200-208]
15 3765 M R [208-216]
17 3765 M R [216-224]
18 3765 M R [224-232]
19 3765 M R [232-240]
20 3765 M R [240-248]
21 3765 M R [248-256]
154 3765 M R [256-264]
156 3765 M R [264-272]
157 3765 M R [272-280]
159 3765 M R [280-288]
160 3765 M R [288-296]
161 3765 M R [296-304]
162 3765 M R [304-312]
163 3765 M R [312-320]
164 3765 M R [320-328]
170 3765 M R [328-336]
171 3765 M R [336-344]
172 3765 M R [344-352]
173 3765 M R [352-360]
174 3765 M R [360-368]
175 3765 M R [368-376]
177 3765 M R [376-384]
178 3765 M R [384-392]
179 3765 Q R 392-400
180 3765 G R
181 3765 M R [400-408]
182 3765 M R [408-416]
183 3765 M R [416-424]
184 3765 M R [424-432]
185 3765 M R [432-440]
186 3765 M R [440-448]
187 3765 M R [448-456]
189 3765 M R [456-464]
190 3765 M R [464-472]
191 3765 M R [472-480]
193 3765 M R [480-488]
194 3765 M R [488-496]
196 3765 M R [496-504]
197 3765 M R [504-512]
228 3765 D R 192-392
245 3765 D R 392-512
14049 0 C R 192-392 [0]
14067 0 D R 392-512
14807 0 C R 392-512 [0]
Reads: Queued: 2, 160KiB
Completed: 2, 160KiB
Merges: 38
Writes: Queued: 0, 0KiB
Completed: 0, 0KiB
Merges: 0Events: 47
Missed events: 0
This is a log of a dd if=/dev/sda of=/dev/null bs=64k count=2 and it shows queueing (Q) and allocation (G) of two requests, along with the merges (M) that happens there. Finally you see dispatch (D) and completion (C) of them as well. When sigint is received, blktrace dumps stats of the current run.
It will work for scsi commands as well, so you can see what is going on when cdrecord is talking to the device (the cdb is dumped, not the data). The final integer printed in [] after a completion is the error, 0 for correct completion.
You can register interest in various events, see blktrace.c (grep for buts and BLKSTARTTRACE).
Patch is against 2.6.13-rc6-mm2. I'm attaching a relayfs update from Tom Zanussi as well, which is required to handle sub-buffer wrapping correctly. You need to apply both patches to play with this - and make sure to enable CONFIG_BLK_DEV_IO_TRACE in your .config, of course. And blktrace.c relies on relayfs being mounted on /relay, add something ala
none /relay relayfs defaults 0 0
to your /etc/fstab to accomplish that (or do it manually, only mentioning it for completeness).
Signature · 1 line
Jens Axboe
drivers/block/blktrace.c renamed from opt/kernel/linux-2.6.13-rc6-mm2/drivers/block/blktrace.c +119 -0
@@ -0,0 +1,119 @@ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/blkdev.h> +#include <linux/blktrace.h> +#include <asm/uaccess.h> + +void __blk_add_trace (struct blk_trace *bt,sector_t sector,int bytes, +int rw,u32 what,int error,int pdu_len,char *pdu_data) +{ +struct blk_io_trace t; +unsigned long flags; + +if (rw ==WRITE ) + what |=BLK_TC_ACT (BLK_TC_WRITE ); +else + what |=BLK_TC_ACT (BLK_TC_READ ); + +if (((bt->act_mask <<BLK_TC_SHIFT ) & what) ==0 ) +return ; + + t.magic =BLK_IO_TRACE_MAGIC |BLK_IO_TRACE_VERSION ; + t.sequence =atomic_add_return (1 , &bt->sequence); + t.time =sched_clock () /1000 ; + t.sector = sector; + t.bytes = bytes; + t.action = what; + t.pid = current->pid; + t.error = error; + t.pdu_len = pdu_len; + +local_irq_save (flags); +__relay_write (bt->rchan, &t,sizeof (t)); +if (pdu_len) +__relay_write (bt->rchan, pdu_data, pdu_len); +local_irq_restore (flags); +} + +int blk_stop_trace (struct block_device *bdev) +{ +request_queue_t *q =bdev_get_queue (bdev); +struct blk_trace *bt =NULL ; +int ret = -EINVAL ; + +if (!q) +return -ENXIO ; + +down (&bdev->bd_sem); + +spin_lock_irq (q->queue_lock); +if (q->blk_trace) { + bt = q->blk_trace; + q->blk_trace =NULL ; + ret =0 ; + } +spin_unlock_irq (q->queue_lock); + +up (&bdev->bd_sem); + +if (bt) { +relay_close (bt->rchan); +kfree (bt); + } + +return ret; +} + +int blk_start_trace (struct block_device *bdev,char __user *arg) +{ +request_queue_t *q =bdev_get_queue (bdev); +struct blk_user_trace_setup buts; +struct blk_trace *bt; +char b[BDEVNAME_SIZE ]; +int ret =0 ; + +if (!q) +return -ENXIO ; + +if (copy_from_user (&buts, arg,sizeof (buts))) +return -EFAULT ; + +if (!buts.buf_size || !buts.buf_nr) +return -EINVAL ; + +strcpy (buts.name,bdevname (bdev, b)); + +if (copy_to_user (arg, &buts,sizeof (buts))) +return -EFAULT ; + +down (&bdev->bd_sem); + ret = -EBUSY ; +if (q->blk_trace) + goto err; + + ret = -ENOMEM ; + bt =kmalloc (sizeof (*bt),GFP_KERNEL ); +if (!bt) + goto err; + +atomic_set (&bt->sequence,0 ); + + bt->rchan =relay_open (bdevname (bdev, b),NULL , buts.buf_size, + buts.buf_nr,NULL ); + ret = -EIO ; +if (!bt->rchan) + goto err; + + bt->act_mask = buts.act_mask; +if (!bt->act_mask) + bt->act_mask = (u16) -1 ; + +spin_lock_irq (q->queue_lock); + q->blk_trace = bt; +spin_unlock_irq (q->queue_lock); + ret =0 ; +err: +up (&bdev->bd_sem); +return ret; +} +
drivers/block/elevator.c renamed from opt/kernel/linux-2.6.13-rc6-mm2/drivers/block/elevator.c +4 -0
@@ -34,6 +34,7 @@#include <linux/slab.h> #include <linux/init.h> #include <linux/compiler.h> +#include <linux/blktrace.h> #include <asm/uaccess.h>
@@ -371,6 +372,9 @@ struct request *elv_next_request(requestint ret;while ((rq =__elv_next_request (q)) !=NULL ) { + +blk_add_trace_rq (q, rq,BLK_TA_ISSUE ); +/* * just mark as started even if we don't start it, a request * that has been delayed should not be passed by new incoming
drivers/block/ioctl.c renamed from opt/kernel/linux-2.6.13-rc6-mm2/drivers/block/ioctl.c +5 -0
@@ -4,6 +4,7 @@#include <linux/backing-dev.h> #include <linux/buffer_head.h> #include <linux/smp_lock.h> +#include <linux/blktrace.h> #include <asm/uaccess.h> static int blkpg_ioctl (struct block_device *bdev,struct blkpg_ioctl_arg __user *arg)
@@ -188,6 +189,10 @@ static int blkdev_locked_ioctl(struct fireturn put_ulong (arg, bdev->bd_inode->i_size >>9 );case BLKGETSIZE64 :return put_u64 (arg, bdev->bd_inode->i_size); +case BLKSTARTTRACE : +return blk_start_trace (bdev, (char __user *) arg); +case BLKSTOPTRACE : +return blk_stop_trace (bdev); }return -ENOIOCTLCMD ; }
drivers/block/Kconfig renamed from opt/kernel/linux-2.6.13-rc6-mm2/drivers/block/Kconfig +8 -0
@@ -419,6 +419,14 @@ config LBD your machine, or if you want to have a raid or loopback device bigger than 2TB. Otherwise say N. +config BLK_DEV_IO_TRACE + bool "Support for tracing block io actions" + select RELAYFS + help + Say Y here, if you want to be able to trace the block layer actions + on a given queue. + + config CDROM_PKTCDVD tristate "Packet writing on CD/DVD media" depends on !UML
drivers/block/ll_rw_blk.c renamed from opt/kernel/linux-2.6.13-rc6-mm2/drivers/block/ll_rw_blk.c +25 -0
@@ -29,6 +29,7 @@#include <linux/swap.h> #include <linux/writeback.h> #include <linux/blkdev.h> +#include <linux/blktrace.h> /* * for max sense size
@@ -1625,6 +1626,12 @@ void blk_cleanup_queue(request_queue_t *if (q->queue_tags)__blk_queue_free_tags (q); +if (q->blk_trace) { +relay_close (q->blk_trace->rchan); +kfree (q->blk_trace); + q->blk_trace =NULL ; + } +blk_queue_ordered (q,QUEUE_ORDERED_NONE );kmem_cache_free (requestq_cachep, q);
@@ -1971,6 +1978,8 @@ rq_starved:rq_init (q, rq); rq->rl = rl; + +blk_add_trace_generic (q, bio, rw,BLK_TA_GETRQ ); out:return rq; }
@@ -1999,6 +2008,8 @@ static struct request *get_request_wait(if (!rq) {struct io_context *ioc; +blk_add_trace_generic (q, bio, rw,BLK_TA_SLEEPRQ ); +__generic_unplug_device (q);spin_unlock_irq (q->queue_lock);io_schedule ();
@@ -2052,6 +2063,8 @@ EXPORT_SYMBOL(blk_get_request);*/ void blk_requeue_request (request_queue_t *q,struct request *rq) { +blk_add_trace_rq (q, rq,BLK_TA_REQUEUE ); +if (blk_rq_tagged (rq))blk_queue_end_tag (q, rq);
@@ -2665,6 +2678,8 @@ static int __make_request(request_queue_if (!q->back_merge_fn (q, req, bio))break ; +blk_add_trace_bio (q, bio,BLK_TA_BACKMERGE ); + req->biotail->bi_next = bio; req->biotail = bio; req->nr_sectors = req->hard_nr_sectors += nr_sectors;
@@ -2680,6 +2695,8 @@ static int __make_request(request_queue_if (!q->front_merge_fn (q, req, bio))break ; +blk_add_trace_bio (q, bio,BLK_TA_FRONTMERGE ); + bio->bi_next = req->bio; req->bio = bio;
@@ -2705,6 +2722,8 @@ static int __make_request(request_queue_ } get_rq: +blk_add_trace_bio (q, bio,BLK_TA_QUEUE ); +/* * Grab a free request. This is might sleep but can not fail. * Returns with the queue unlocked.
@@ -2981,6 +3000,10 @@ end_io:blk_partition_remap (bio); ret = q->make_request_fn (q, bio); + +if (ret) +blk_add_trace_bio (q, bio,BLK_TA_QUEUE ); + }while (ret); }
@@ -3099,6 +3122,8 @@ static int __end_that_request_first(struint total_bytes, bio_nbytes, error, next_idx =0 ;struct bio *bio; +blk_add_trace_rq (req->q, req,BLK_TA_COMPLETE ); +/* * extend uptodate bool to allow < 0 value to be direct io error */
drivers/block/Makefile renamed from opt/kernel/linux-2.6.13-rc6-mm2/drivers/block/Makefile +2 -0
@@ -45,3 +45,5 @@ obj-$(CONFIG_VIODASD) += viodasd.o obj-$(CONFIG_BLK_DEV_SX8) += sx8.o obj-$(CONFIG_BLK_DEV_UB) += ub.o +obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o +
include/linux/blkdev.h renamed from opt/kernel/linux-2.6.13-rc6-mm2/include/linux/blkdev.h +3 -0
@@ -22,6 +22,7 @@ typedef struct request_queue request_questruct elevator_queue ;typedef struct elevator_queue elevator_t ;struct request_pm_state ; +struct blk_trace ;#define BLKDEV_MIN_RQ 4#define BLKDEV_MAX_RQ 128/* Default maximum */
@@ -412,6 +413,8 @@ struct request_queue*/ struct request *flush_rq;unsigned char ordered; + +struct blk_trace *blk_trace; };enum {
include/linux/blktrace.h renamed from opt/kernel/linux-2.6.13-rc6-mm2/include/linux/blktrace.h +142 -0
142 lines not on this page · raw message
include/linux/fs.h renamed from opt/kernel/linux-2.6.13-rc6-mm2/include/linux/fs.h +2 -0
@@ -196,6 +196,8 @@ extern int dir_notify_enable;#define BLKBSZGET _IOR(0x12,112,size_t)#define BLKBSZSET _IOW(0x12,113,size_t)#define BLKGETSIZE64 _IOR(0x12,114,size_t)/* return device size in bytes (u64 *arg) */ +#define BLKSTARTTRACE _IOWR(0x12,115,struct blk_user_trace_setup) +#define BLKSTOPTRACE _IO(0x12,116)#define BMAP_IOCTL 1/* obsolete - kept for compatibility */ #define FIBMAP _IO(0x00,1)/* bmap access */
fs/relayfs/inode.c renamed from fs/relayfs/inode.c~ +64 -76
196 lines not on this page · raw message
fs/relayfs/relay.c renamed from fs/relayfs/relay.c~ +10 -1
@@ -58,6 +58,14 @@ void *prev_subbuf, size_t prev_padding) { + if (relay_buf_full(buf)) { +// if (smp_processor_id() == 0) { +// printk("buf full, cpu %u\n", smp_processor_id()); +// klog_printk("buf full, cpu %u\n", smp_processor_id()); +// } +return 0 ; + } +return 1 ; }
@@ -262,6 +270,7 @@for_each_online_cpu (i) {sprintf (tmpname,"%s%d" , base_filename, i); chan->buf[i] =relay_open_buf (chan, tmpname, parent); + chan->buf[i]->cpu = i;if (!chan->buf[i]) goto free_bufs; }
@@ -328,7 +337,7 @@return length; toobig: -printk (KERN_WARNING "relayfs: event too large (%u)\n" , length); +printk (KERN_WARNING "relayfs: event too large (%lu)\n" , length);WARN_ON (1 );return 0 ; }
include/linux/relayfs_fs.h renamed from include/linux/relayfs_fs.h~ +3 -1
@@ -22,7 +22,7 @@/* * Tracks changes to rchan_buf struct */ -#define RELAYFS_CHANNEL_VERSION 4 +#define RELAYFS_CHANNEL_VERSION 5/* * Per-cpu relay channel buffer
@@ -44,6 +44,8 @@unsigned int finalized;/* buffer has been finalized */ size_t *padding;/* padding counts per sub-buffer */ size_t prev_padding;/* temporary variable */ +size_t bytes_consumed;/* bytes consumed in cur read subbuf */ +unsigned int cpu;/* this buf's cpu */ }____cacheline_aligned ;/*
Quoted 6 lines · Jens Axboe
Hi,
This is a little something I have played with. It allows you to see exactly what is going on in the block layer for a given queue. Currently it can logs request queueing and building, dispatches, requeues, and completions.
Ah, fabulous. Thanks Jens!
drivers/block/blktrace.c line 23
Quoted 3 lines
drivers/block/blktrace.c renamed from opt/kernel/linux-2.6.13-rc6-mm2/drivers/block/blktrace.c +3
-0+ t.magic =BLK_IO_TRACE_MAGIC |BLK_IO_TRACE_VERSION ; + t.sequence =atomic_add_return (1 , &bt->sequence); + t.time =sched_clock () /1000 ;
Wouldn't it be better to pass out the highest precision available here & then do the conversion in userspace instead? I guess one might want that little bit more for a RAM disk or something ... actually, talking to one of the SGI people here with alot of experience on IRIX with a similar facility, the msec resolution there is apparently sometimes an issue already with fast storage.
cheers.
Signature · 1 line
Nathan
Quoted 10 lines · Nathan Scott
Quoted 6 lines · Jens Axboe
Hi,
This is a little something I have played with. It allows you to see exactly what is going on in the block layer for a given queue. Currently it can logs request queueing and building, dispatches, requeues, and completions.
Ah, fabulous. Thanks Jens!
Quoted 10 lines
drivers/block/blktrace.c line 23
Quoted 3 lines
drivers/block/blktrace.c renamed from opt/kernel/linux-2.6.13-rc6-mm2/drivers/block/blktrace.c +3
-0+ t.magic =BLK_IO_TRACE_MAGIC |BLK_IO_TRACE_VERSION ; + t.sequence =atomic_add_return (1 , &bt->sequence); + t.time =sched_clock () /1000 ;Wouldn't it be better to pass out the highest precision available here & then do the conversion in userspace instead? I guess one might want that little bit more for a RAM disk or something ... actually, talking to one of the SGI people here with alot of experience on IRIX with a similar facility, the msec resolution there is apparently sometimes an issue already with fast storage.
This isn't msec precision, it's usec. sched_clock() is in ns! I already decided that msec is too coarse, but usec _should_ be enough.
Signature · 1 line
Jens Axboe
Quoted 3 lines · Jens Axboe
...
This isn't msec precision, it's usec.sched_clock()is in ns! I already decided that msec is too coarse, but usec _should_ be enough.
Right you are (I was thinking m-for-micro, not m-for-milli in my head ;)
- but still, there doesn't seem to be any reason for that divide-by-1000 and reducing the precision in the kernel rather than in userspace, does there? Doing it the other way means you wont ever have to worry about whether it is/isn't sufficient precision for all possible block devices, and the precision the tool displays will just be a userspace decision.
cheers.
Signature · 1 line
Nathan
Quoted 11 lines · Nathan Scott
Quoted 3 lines · Jens Axboe
...
This isn't msec precision, it's usec.sched_clock()is in ns! I already decided that msec is too coarse, but usec _should_ be enough.Right you are (I was thinking m-for-micro, not m-for-milli in my head ;)
- but still, there doesn't seem to be any reason for that divide-by-1000 and reducing the precision in the kernel rather than in userspace, does there? Doing it the other way means you wont ever have to worry about whether it is/isn't sufficient precision for all possible block devices, and the precision the tool displays will just be a userspace decision.
I was just worried about wrapping of ->time, but I did make it a 64-bit unit. So I guess we could go to nsec granularity, there should be plenty [*] of space. I'll change that too, I'll post an update version later.
* I probably should not make such a statement :-)
Signature · 1 line
Jens Axboe
Quoted 13 lines · Jens Axboe
Quoted 11 lines · Nathan Scott
Quoted 3 lines · Jens Axboe
...
This isn't msec precision, it's usec.sched_clock()is in ns! I already decided that msec is too coarse, but usec _should_ be enough.Right you are (I was thinking m-for-micro, not m-for-milli in my head ;)
- but still, there doesn't seem to be any reason for that divide-by-1000 and reducing the precision in the kernel rather than in userspace, does there? Doing it the other way means you wont ever have to worry about whether it is/isn't sufficient precision for all possible block devices, and the precision the tool displays will just be a userspace decision.
Quoted 3 lines
I was just worried about wrapping of ->time, but I did make it a 64-bit unit. So I guess we could go to nsec granularity, there should be plenty [*] of space. I'll change that too, I'll post an update version later.
Ok, updated version. The tool at:
http://www.kernel.org/pub/linux/kernel/people/axboe/tools/blktrace.c
has been updated as well, the protocol version was increased to accomodate the trace structure changes.
Changes:
- Include full nsec resolution in ->time
- Bump ->pid to full 32-bit
- Include barrier and sync request options
- Move requeue to seperate trace category
Patch attached is against 2.6.13-rc6-mm2. Still a good idea to apply the relayfs read update from the previous mail [*] as well.
[*] http://marc.theaimsgroup.com/?l=linux-kernel&m=112480046405961&w=2
Signature · 1 line
Jens Axboe
drivers/block/Kconfig renamed from opt/kernel/linux-2.6.13-rc6-mm2/drivers/block/Kconfig +8 -0
@@ -419,6 +419,14 @@ config LBD your machine, or if you want to have a raid or loopback device bigger than 2TB. Otherwise say N. +config BLK_DEV_IO_TRACE + bool "Support for tracing block io actions" + select RELAYFS + help + Say Y here, if you want to be able to trace the block layer actions + on a given queue. + + config CDROM_PKTCDVD tristate "Packet writing on CD/DVD media" depends on !UML
drivers/block/Makefile renamed from opt/kernel/linux-2.6.13-rc6-mm2/drivers/block/Makefile +2 -0
@@ -45,3 +45,5 @@ obj-$(CONFIG_VIODASD) += viodasd.o obj-$(CONFIG_BLK_DEV_SX8) += sx8.o obj-$(CONFIG_BLK_DEV_UB) += ub.o +obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o +
drivers/block/blktrace.c renamed from opt/kernel/linux-2.6.13-rc6-mm2/drivers/block/blktrace.c +124 -0
124 lines not on this page · raw message
drivers/block/elevator.c renamed from opt/kernel/linux-2.6.13-rc6-mm2/drivers/block/elevator.c +4 -0
@@ -34,6 +34,7 @@#include <linux/slab.h> #include <linux/init.h> #include <linux/compiler.h> +#include <linux/blktrace.h> #include <asm/uaccess.h>
@@ -371,6 +372,9 @@ struct request *elv_next_request(requestint ret;while ((rq =__elv_next_request (q)) !=NULL ) { + +blk_add_trace_rq (q, rq,BLK_TA_ISSUE ); +/* * just mark as started even if we don't start it, a request * that has been delayed should not be passed by new incoming
drivers/block/ioctl.c renamed from opt/kernel/linux-2.6.13-rc6-mm2/drivers/block/ioctl.c +5 -0
@@ -4,6 +4,7 @@#include <linux/backing-dev.h> #include <linux/buffer_head.h> #include <linux/smp_lock.h> +#include <linux/blktrace.h> #include <asm/uaccess.h> static int blkpg_ioctl (struct block_device *bdev,struct blkpg_ioctl_arg __user *arg)
@@ -188,6 +189,10 @@ static int blkdev_locked_ioctl(struct fireturn put_ulong (arg, bdev->bd_inode->i_size >>9 );case BLKGETSIZE64 :return put_u64 (arg, bdev->bd_inode->i_size); +case BLKSTARTTRACE : +return blk_start_trace (bdev, (char __user *) arg); +case BLKSTOPTRACE : +return blk_stop_trace (bdev); }return -ENOIOCTLCMD ; }
drivers/block/ll_rw_blk.c renamed from opt/kernel/linux-2.6.13-rc6-mm2/drivers/block/ll_rw_blk.c +25 -0
@@ -29,6 +29,7 @@#include <linux/swap.h> #include <linux/writeback.h> #include <linux/blkdev.h> +#include <linux/blktrace.h> /* * for max sense size
@@ -1625,6 +1626,12 @@ void blk_cleanup_queue(request_queue_t *if (q->queue_tags)__blk_queue_free_tags (q); +if (q->blk_trace) { +relay_close (q->blk_trace->rchan); +kfree (q->blk_trace); + q->blk_trace =NULL ; + } +blk_queue_ordered (q,QUEUE_ORDERED_NONE );kmem_cache_free (requestq_cachep, q);
@@ -1971,6 +1978,8 @@ rq_starved:rq_init (q, rq); rq->rl = rl; + +blk_add_trace_generic (q, bio, rw,BLK_TA_GETRQ ); out:return rq; }
@@ -1999,6 +2008,8 @@ static struct request *get_request_wait(if (!rq) {struct io_context *ioc; +blk_add_trace_generic (q, bio, rw,BLK_TA_SLEEPRQ ); +__generic_unplug_device (q);spin_unlock_irq (q->queue_lock);io_schedule ();
@@ -2052,6 +2063,8 @@ EXPORT_SYMBOL(blk_get_request);*/ void blk_requeue_request (request_queue_t *q,struct request *rq) { +blk_add_trace_rq (q, rq,BLK_TA_REQUEUE ); +if (blk_rq_tagged (rq))blk_queue_end_tag (q, rq);
@@ -2665,6 +2678,8 @@ static int __make_request(request_queue_if (!q->back_merge_fn (q, req, bio))break ; +blk_add_trace_bio (q, bio,BLK_TA_BACKMERGE ); + req->biotail->bi_next = bio; req->biotail = bio; req->nr_sectors = req->hard_nr_sectors += nr_sectors;
@@ -2680,6 +2695,8 @@ static int __make_request(request_queue_if (!q->front_merge_fn (q, req, bio))break ; +blk_add_trace_bio (q, bio,BLK_TA_FRONTMERGE ); + bio->bi_next = req->bio; req->bio = bio;
@@ -2705,6 +2722,8 @@ static int __make_request(request_queue_ } get_rq: +blk_add_trace_bio (q, bio,BLK_TA_QUEUE ); +/* * Grab a free request. This is might sleep but can not fail. * Returns with the queue unlocked.
@@ -2981,6 +3000,10 @@ end_io:blk_partition_remap (bio); ret = q->make_request_fn (q, bio); + +if (ret) +blk_add_trace_bio (q, bio,BLK_TA_QUEUE ); + }while (ret); }
@@ -3099,6 +3122,8 @@ static int __end_that_request_first(struint total_bytes, bio_nbytes, error, next_idx =0 ;struct bio *bio; +blk_add_trace_rq (req->q, req,BLK_TA_COMPLETE ); +/* * extend uptodate bool to allow < 0 value to be direct io error */
include/linux/blkdev.h renamed from opt/kernel/linux-2.6.13-rc6-mm2/include/linux/blkdev.h +3 -0
@@ -22,6 +22,7 @@ typedef struct request_queue request_questruct elevator_queue ;typedef struct elevator_queue elevator_t ;struct request_pm_state ; +struct blk_trace ;#define BLKDEV_MIN_RQ 4#define BLKDEV_MAX_RQ 128/* Default maximum */
@@ -412,6 +413,8 @@ struct request_queue*/ struct request *flush_rq;unsigned char ordered; + +struct blk_trace *blk_trace; };enum {
include/linux/blktrace.h renamed from opt/kernel/linux-2.6.13-rc6-mm2/include/linux/blktrace.h +145 -0
145 lines not on this page · raw message
include/linux/fs.h renamed from opt/kernel/linux-2.6.13-rc6-mm2/include/linux/fs.h +2 -0
@@ -196,6 +196,8 @@ extern int dir_notify_enable;#define BLKBSZGET _IOR(0x12,112,size_t)#define BLKBSZSET _IOW(0x12,113,size_t)#define BLKGETSIZE64 _IOR(0x12,114,size_t)/* return device size in bytes (u64 *arg) */ +#define BLKSTARTTRACE _IOWR(0x12,115,struct blk_user_trace_setup) +#define BLKSTOPTRACE _IO(0x12,116)#define BMAP_IOCTL 1/* obsolete - kept for compatibility */ #define FIBMAP _IO(0x00,1)/* bmap access */
Quoted 3 lines · Jens Axboe
...
Patch attached is against 2.6.13-rc6-mm2. Still a good idea to apply the relayfs read update from the previous mail [*] as well.
Hi Jens,
There's a minor config botch in there, I get this:
scripts/kconfig/conf -s arch/i386/Kconfig
drivers/block/Kconfig:466:warning: 'select' used by config symbol 'BLK_DEV_IO_TRACE' refer to undefined symbol 'RELAYFS'
The patch below seems to resolve it.
cheers.
Signature · 16 lines
Nathan Index: relayfs-2.6.x-xfs/drivers/block/Kconfig =================================================================== --- relayfs-2.6.x-xfs.orig/drivers/block/Kconfig +++ relayfs-2.6.x-xfs/drivers/block/Kconfig @@ -463,7 +463,7 @@ config BLK_DEV_IO_TRACE bool "Support for tracing block io actions" - select RELAYFS + select RELAYFS_FS help Say Y here, if you want to be able to trace the block layer actions on a given queue.
Quoted 5 lines · Nathan Scott
Quoted 3 lines · Jens Axboe
...
Patch attached is against 2.6.13-rc6-mm2. Still a good idea to apply the relayfs read update from the previous mail [*] as well.
Quoted 8 lines
Hi Jens,
There's a minor config botch in there, I get this:
scripts/kconfig/conf-sarch/i386/Kconfig
drivers/block/Kconfig:466:warning: 'select' used by config symbol 'BLK_DEV_IO_TRACE' refer to undefined symbol 'RELAYFS'The patch below seems to resolve it.
Thanks, you are right, the name is indeed RELAYFS_FS.
Signature · 1 line
Jens Axboe
Hi Jens,
Quoted 2 lines · Jens Axboe
Patch attached is against 2.6.13-rc6-mm2. Still a good idea to apply the relayfs read update from the previous mail [*] as well.
There's a small memory leak there on one of the start-tracing error paths (relay_open failure)... this should plug it up.
cheers.
Signature · 34 lines
Nathan
Index: 2.6.x-xfs/drivers/block/blktrace.c
===================================================================
--- 2.6.x-xfs.orig/drivers/block/blktrace.c
+++ 2.6.x-xfs/drivers/block/blktrace.c
@@ -73,9 +73,9 @@ int blk_start_trace(struct block_device
{
request_queue_t *q = bdev_get_queue(bdev);
struct blk_user_trace_setup buts;
- struct blk_trace *bt;
+ struct blk_trace *bt = NULL;
char b[BDEVNAME_SIZE];
- int ret = 0;
+ int ret;
if (!q)
return -ENXIO;
@@ -116,9 +116,14 @@ int blk_start_trace(struct block_device
spin_lock_irq(q->queue_lock);
q->blk_trace = bt;
spin_unlock_irq(q->queue_lock);
- ret = 0;
+
+ up(&bdev->bd_sem);
+ return 0;
+
err:
up(&bdev->bd_sem);
+ if (bt)
+ kfree(bt);
return ret;
}Quoted 36 lines · Nathan Scott
Hi Jens,
Quoted 2 lines · Jens Axboe
Patch attached is against 2.6.13-rc6-mm2. Still a good idea to apply the relayfs read update from the previous mail [*] as well.
There's a small memory leak there on one of the start-tracing error paths (
relay_openfailure)... this should plug it up.cheers.
Signature · 5 lines
Nathan Index: 2.6.x-xfs/drivers/block/blktrace.c ===================================================================drivers/block/blktrace.c +2
-3@@ -73,9 +73,9 @@ int blk_start_trace(struct block_device {request_queue_t *q =bdev_get_queue (bdev);struct blk_user_trace_setup buts; -struct blk_trace *bt; +struct blk_trace *bt =NULL ;char b[BDEVNAME_SIZE ]; -int ret =0 ; +int ret;if (!q)return -ENXIO ;@@ -116,9 +116,14 @@ int blk_start_trace(struct block_devicespin_lock_irq (q->queue_lock); q->blk_trace = bt;spin_unlock_irq (q->queue_lock); - ret =0 ;
drivers/block/blktrace.c int blk_start_trace(struct block_device · line 128
Quoted 10 lines
drivers/block/blktrace.c +6
-0+ +up (&bdev->bd_sem); +return 0 ; + err:up (&bdev->bd_sem); +if (bt) +kfree (bt);return ret; }
Indeed, thanks! I've applied the patch, I'll do a new release against 2.6.14-pre/rc/git as soon as relayfs gets merged. Or 2.6.13-mm1, if that comes first.
BTW, the trace tools now live in a git repo here:
rsync://rsync.kernel.org/pub/scm/linux/kernel/git/axboe/blktrace.git
Signature · 1 line
Jens Axboe
Hi Jens,
Quoted 1 line · Jens Axboe
Ok, updated version.
One thing I found a bit awkward was the way its putting all inodes in the root of the relayfs namespace, with the cpuid tacked on the end of the bdevname - I was a bit confused at first when a trace of sdd on my 4P box spontaneously created files for "partitions" sdd0, sdd1, sdd2, and sdd3 ;).
I suppose if many more users of relayfs spring into existance, this is going to get quite ugly. Below is a patch that aligns the names to the conventions used in sysfs; so, for example, when running two traces simultaneously on /dev/sdd and /dev/sdb, instead of this:
# find /relay /relay /relay/sdd3 /relay/sdd2 /relay/sdd1 /relay/sdd0 /relay/sdb3 /relay/sdb2 /relay/sdb1 /relay/sdb0
it now uses this...
# find /relay /relay /relay/block /relay/block/sdd /relay/block/sdd/trace3 /relay/block/sdd/trace2 /relay/block/sdd/trace1 /relay/block/sdd/trace0 /relay/block/sdb /relay/block/sdb/trace3 /relay/block/sdb/trace2 /relay/block/sdb/trace1 /relay/block/sdb/trace0
and does the correct dynamic setup and teardown of the hierarchy as the userspace tool starts and stops tracing. I had to modify the relayfs rmdir code a bit to make this work properly, I'll send a separate patch for that shortly.
Quoted 4 lines
http://www.kernel.org/pub/linux/kernel/people/axboe/tools/blktrace.c
has been updated as well, the protocol version was increased to accomodate the trace structure changes.
I have the associated userspace change for this, as well as several other fixes and tweaks for your tool - if you could slap a copyright and license notice onto that source (pretty please? :) I'll send 'em right along.
cheers.
Signature · 147 lines
Nathan
Index: 2.6.x-xfs/drivers/block/blktrace.c
===================================================================
--- 2.6.x-xfs.orig/drivers/block/blktrace.c
+++ 2.6.x-xfs/drivers/block/blktrace.c
@@ -40,6 +40,50 @@ void __blk_add_trace(struct blk_trace *b
local_irq_restore(flags);
}
+static struct dentry * blk_tree_root;
+static DEFINE_SPINLOCK(blk_tree_lock);
+
+static inline void blk_remove_root(void)
+{
+ if (relayfs_remove_dir(blk_tree_root) != -ENOTEMPTY)
+ blk_tree_root = NULL;
+}
+
+static void blk_remove_tree(struct dentry *dir)
+{
+ spin_lock(&blk_tree_lock);
+ relayfs_remove_dir(dir);
+ blk_remove_root();
+ spin_unlock(&blk_tree_lock);
+}
+
+static struct dentry *blk_create_tree(const char *blk_name)
+{
+ struct dentry *dir;
+
+ spin_lock(&blk_tree_lock);
+ if (!blk_tree_root) {
+ blk_tree_root = relayfs_create_dir("block", NULL);
+ if (!blk_tree_root) {
+ spin_unlock(&blk_tree_lock);
+ return NULL;
+ }
+ }
+ dir = relayfs_create_dir(blk_name, blk_tree_root);
+ if (!dir)
+ blk_remove_root();
+ spin_unlock(&blk_tree_lock);
+
+ return dir;
+}
+
+void blk_cleanup_trace(struct blk_trace *bt)
+{
+ relay_close(bt->rchan);
+ blk_remove_tree(bt->dir);
+ kfree(bt);
+}
+
int blk_stop_trace(struct block_device *bdev)
{
request_queue_t *q = bdev_get_queue(bdev);
@@ -61,10 +105,8 @@ int blk_stop_trace(struct block_device *
up(&bdev->bd_sem);
- if (bt) {
- relay_close(bt->rchan);
- kfree(bt);
- }
+ if (bt)
+ blk_cleanup_trace(bt);
return ret;
}
@@ -74,6 +116,7 @@ int blk_start_trace(struct block_device
request_queue_t *q = bdev_get_queue(bdev);
struct blk_user_trace_setup buts;
struct blk_trace *bt = NULL;
+ struct dentry *dir = NULL;
char b[BDEVNAME_SIZE];
int ret;
@@ -101,11 +144,16 @@ int blk_start_trace(struct block_device
if (!bt)
goto err;
+ ret = -ENOENT;
+ dir = blk_create_tree(bdevname(bdev, b));
+ if (!dir)
+ goto err;
+
+ bt->dir = dir;
atomic_set(&bt->sequence, 0);
- bt->rchan = relay_open(bdevname(bdev, b), NULL, buts.buf_size,
- buts.buf_nr, NULL);
ret = -EIO;
+ bt->rchan = relay_open("trace", dir, buts.buf_size, buts.buf_nr, NULL);
if (!bt->rchan)
goto err;
@@ -122,6 +170,8 @@ int blk_start_trace(struct block_device
err:
up(&bdev->bd_sem);
+ if (dir)
+ blk_remove_tree(dir);
if (bt)
kfree(bt);
return ret;
Index: 2.6.x-xfs/include/linux/blktrace.h
===================================================================
--- 2.6.x-xfs.orig/include/linux/blktrace.h
+++ 2.6.x-xfs/include/linux/blktrace.h
@@ -71,6 +71,7 @@ struct blk_io_trace {
};
struct blk_trace {
+ struct dentry *dir;
struct rchan *rchan;
atomic_t sequence;
u16 act_mask;
@@ -89,6 +90,7 @@ struct blk_user_trace_setup {
#if defined(CONFIG_BLK_DEV_IO_TRACE)
extern int blk_start_trace(struct block_device *, char __user *);
extern int blk_stop_trace(struct block_device *);
+extern void blk_cleanup_trace(struct blk_trace *);
extern void __blk_add_trace(struct blk_trace *, sector_t, int, int, u32, int, int, char *);
static inline void blk_add_trace_rq(struct request_queue *q, struct request *rq,
@@ -137,6 +139,7 @@ static inline void blk_add_trace_generic
#else /* !CONFIG_BLK_DEV_IO_TRACE */
#define blk_start_trace(bdev, arg) (-EINVAL)
#define blk_stop_trace(bdev) (-EINVAL)
+#define blk_cleanup_trace(bt) do { } while (0)
#define blk_add_trace_rq(q, rq, what) do { } while (0)
#define blk_add_trace_bio(q, rq, what) do { } while (0)
#define blk_add_trace_generic(q, rq, rw, what) do { } while (0)
Index: 2.6.x-xfs/drivers/block/ll_rw_blk.c
===================================================================
--- 2.6.x-xfs.orig/drivers/block/ll_rw_blk.c
+++ 2.6.x-xfs/drivers/block/ll_rw_blk.c
@@ -1625,8 +1625,7 @@ void blk_cleanup_queue(request_queue_t *
__blk_queue_free_tags(q);
if (q->blk_trace) {
- relay_close(q->blk_trace->rchan);
- kfree(q->blk_trace);
+ blk_cleanup_trace(q->blk_trace);
q->blk_trace = NULL;
}Hi there,
Quoted 15 lines · Nathan Scott
...
# find /relay /relay /relay/block /relay/block/sdd /relay/block/sdd/trace3 /relay/block/sdd/trace2 /relay/block/sdd/trace1 /relay/block/sdd/trace0 /relay/block/sdb /relay/block/sdb/trace3 /relay/block/sdb/trace2 /relay/block/sdb/trace1 /relay/block/sdb/trace0
Quoted 4 lines
and does the correct dynamic setup and teardown of the hierarchy as the userspace tool starts and stops tracing. I had to modify the relayfs rmdir code a bit to make this work properly, I'll send a separate patch for that shortly.
Here it is. The problem was that relayfs is allowing a directory with children to be removed rather than returning -ENOTEMPTY. It looks like this can be resolved by splitting the shared relayfs unlink code (which is using simple_unlink) into separate file/dir variants, one using simple_unlink, the other using simple_rmdir.
cheers.
Signature · 51 lines
Nathan
Index: 2.6.x-xfs/fs/relayfs/inode.c
===================================================================
--- 2.6.x-xfs.orig/fs/relayfs/inode.c
+++ 2.6.x-xfs/fs/relayfs/inode.c
@@ -187,8 +187,8 @@ struct dentry *relayfs_create_dir(const
}
/**
- * relayfs_remove - remove a file or directory in the relay filesystem
- * @dentry: file or directory dentry
+ * relayfs_remove - remove a file in the relay filesystem
+ * @dentry: file dentry
*/
int relayfs_remove(struct dentry *dentry)
{
@@ -219,10 +219,31 @@ int relayfs_remove(struct dentry *dentry
*/
int relayfs_remove_dir(struct dentry *dentry)
{
+ struct dentry *parent;
+ int error = 0;
+
if (!dentry)
return -EINVAL;
+ parent = dentry->d_parent;
+ if (!parent)
+ return -EINVAL;
+
+ parent = dget(parent);
+ down(&parent->d_inode->i_sem);
+ if (dentry->d_inode) {
+ error = simple_rmdir(parent->d_inode, dentry);
+ if (!error)
+ d_delete(dentry);
+ }
+ if (!error)
+ dput(dentry);
+ up(&parent->d_inode->i_sem);
+ dput(parent);
+
+ if (!error)
+ simple_release_fs(&relayfs_mount, &relayfs_mount_count);
- return relayfs_remove(dentry);
+ return error;
}
/**Quoted 23 lines · Nathan Scott
Hi there,
Quoted 15 lines · Nathan Scott
...
# find /relay /relay /relay/block /relay/block/sdd /relay/block/sdd/trace3 /relay/block/sdd/trace2 /relay/block/sdd/trace1 /relay/block/sdd/trace0 /relay/block/sdb /relay/block/sdb/trace3 /relay/block/sdb/trace2 /relay/block/sdb/trace1 /relay/block/sdb/trace0Quoted 4 lines
and does the correct dynamic setup and teardown of the hierarchy as the userspace tool starts and stops tracing. I had to modify the relayfs rmdir code a bit to make this work properly, I'll send a separate patch for that shortly.
Quoted 6 lines
Here it is. The problem was that relayfs is allowing a directory with children to be removed rather than returning
-ENOTEMPTY. It looks like this can be resolved by splitting the shared relayfs unlink code (which is usingsimple_unlink) into separate file/dir variants, one usingsimple_unlink, the other usingsimple_rmdir.
Hi,
You're right, it should be using simple_rmdir rather than simple_unlink for removing directories. Thanks for sending the patch, which I've modified a bit to avoid splitting the rmdir/unlink cases into separate functions, since they're almost the same except for what they end up calling. relayfs_remove_dir now doesn't do anything but call relayfs_remove (it didn't do much more than that before anyway), but it makes sense to me to keep it, as the counterpart to relayfs_create_dir. Let me know if you see any problems with it.
Thanks,
Tom
inode.c renamed from inode.c~ +19 -9
@@ -189,26 +189,39 @@ struct dentry *relayfs_create_dir(const/** * relayfs_remove - remove a file or directory in the relay filesystem * @dentry: file or directory dentry +* +* Returns 0 if successful, negative otherwise. */ int relayfs_remove (struct dentry *dentry) { -struct dentry *parent = dentry->d_parent; +struct dentry *parent; +int error =0 ; + +if (!dentry) +return -EINVAL ; + parent = dentry->d_parent;if (!parent)return -EINVAL ; parent =dget (parent);down (&parent->d_inode->i_sem);if (dentry->d_inode) { -simple_unlink (parent->d_inode, dentry); -d_delete (dentry); +if (S_ISDIR (dentry->d_inode->i_mode)) + error =simple_rmdir (parent->d_inode, dentry); +else + error =simple_unlink (parent->d_inode, dentry); +if (!error) +d_delete (dentry); } -dput (dentry); +if (!error) +dput (dentry);up (&parent->d_inode->i_sem);dput (parent); -simple_release_fs (&relayfs_mount, &relayfs_mount_count); +if (!error) +simple_release_fs (&relayfs_mount, &relayfs_mount_count); -return 0 ; +return error; }/**
@@ -219,9 +232,6 @@ int relayfs_remove(struct dentry *dentry*/ int relayfs_remove_dir (struct dentry *dentry) { -if (!dentry) -return -EINVAL ; -return relayfs_remove (dentry); }
Hi Tom,
Quoted 2 lines · Tom Zanussi
You're right, it should be using
simple_rmdirrather thansimple_unlinkfor removing directories. Thanks for sending the patch,
No problem.
Quoted 6 lines
which I've modified a bit to avoid splitting the rmdir/unlink cases into separate functions, since they're almost the same except for what they end up calling.
relayfs_remove_dirnow doesn't do anything but callrelayfs_remove(it didn't do much more than that before anyway), but it makes sense to me to keep it, as the counterpart torelayfs_create_dir. Let me know if you see any problems with it.
Looks OK, I'll give it a spin.
On an unrelated note, are there any known issues with using epoll on relayfs file descriptors? I'm having a few troubles, and just wondering if its me doing something silly, or if its known to not work...? Symptoms of the problem are epoll continually reaching its timeout with no modified fds found (when I know the inode has modified trace buffers attached) ... and the epoll code is a bit too hairy for me to go find a quick fix - seems like it should be able to work though since relayfs has a ->poll implementation.
cheers.
Signature · 1 line
Nathan
Quoted 7 lines · Nathan Scott
...
On an unrelated note, are there any known issues with using epoll on relayfs file descriptors? I'm having a few troubles, and just wondering if its me doing something silly, or if its known to not work...? Symptoms of the problem are epoll continually reaching its timeout with no modified fds found (when I know the inode has modified trace buffers attached) ...
Actually, poll(2) seems to have the same behaviour with a simpler test case (i.e. no epoll, & with just one fd being polled) - if I read(2) from it every few thousand usec (using the blktrace tool) it sees new data, but if I poll, it never reports the descriptor as changed (this is a 2.6.13 kernel with the relayfs patches from -mm patched into it and Jens' blktrace patch generating the data that I'm attempting to poll).
cheers.
Signature · 1 line
Nathan
Quoted 17 lines · Nathan Scott
Hi Tom,
Quoted 2 lines · Tom Zanussi
You're right, it should be using
simple_rmdirrather thansimple_unlinkfor removing directories. Thanks for sending the patch,No problem.
Quoted 6 lines
which I've modified a bit to avoid splitting the rmdir/unlink cases into separate functions, since they're almost the same except for what they end up calling.
relayfs_remove_dirnow doesn't do anything but callrelayfs_remove(it didn't do much more than that before anyway), but it makes sense to me to keep it, as the counterpart torelayfs_create_dir. Let me know if you see any problems with it.Looks OK, I'll give it a spin.
Quoted 8 lines
On an unrelated note, are there any known issues with using epoll on relayfs file descriptors? I'm having a few troubles, and just wondering if its me doing something silly, or if its known to not work...? Symptoms of the problem are epoll continually reaching its timeout with no modified fds found (when I know the inode has modified trace buffers attached) ... and the epoll code is a bit too hairy for me to go find a quick fix - seems like it should be able to work though since relayfs has a ->poll implementation.
Well, the relayfs poll implementation is based on completed sub-buffers, so you can be writing events into a buffer, but until a buffer switch happens, you won't be notified that anything's changed. The reason for the sub-buffer granularity is that relayfs was originally meant for use only with mmap(), but now that there's a read(), I'll probably have to make some changes to the poll implementation as well.
Tom
Quoted 10 lines · Nathan Scott
Hi Jens,
Quoted 1 line · Jens Axboe
Ok, updated version.
One thing I found a bit awkward was the way its putting all inodes in the root of the relayfs namespace, with the cpuid tacked on the end of the bdevname - I was a bit confused at first when a trace of sdd on my 4P box spontaneously created files for "partitions" sdd0, sdd1, sdd2, and sdd3 ;).
Yeah I agree, it's not very logical.
Quoted 33 lines
I suppose if many more users of relayfs spring into existance, this is going to get quite ugly. Below is a patch that aligns the names to the conventions used in sysfs; so, for example, when running two traces simultaneously on
/dev/sddand/dev/sdb, instead of this:# find /relay /relay /relay/sdd3 /relay/sdd2 /relay/sdd1 /relay/sdd0 /relay/sdb3 /relay/sdb2 /relay/sdb1 /relay/sdb0it now uses this...
# find /relay /relay /relay/block /relay/block/sdd /relay/block/sdd/trace3 /relay/block/sdd/trace2 /relay/block/sdd/trace1 /relay/block/sdd/trace0 /relay/block/sdb /relay/block/sdb/trace3 /relay/block/sdb/trace2 /relay/block/sdb/trace1 /relay/block/sdb/trace0
Quoted 4 lines
and does the correct dynamic setup and teardown of the hierarchy as the userspace tool starts and stops tracing. I had to modify the relayfs rmdir code a bit to make this work properly, I'll send a separate patch for that shortly.
It makes sense to me, please work with the relayfs people to get this integrated. I really don't want to carry any extra stuff for relayfs around.
Quoted 9 lines
Quoted 4 lines
http://www.kernel.org/pub/linux/kernel/people/axboe/tools/blktrace.c
has been updated as well, the protocol version was increased to accomodate the trace structure changes.
I have the associated userspace change for this, as well as several other fixes and tweaks for your tool - if you could slap a copyright and license notice onto that source (pretty please? :) I'll send 'em right along.
You bet, I'll add it right away.
Signature · 1 line
Jens Axboe
Quoted 50 lines · Nathan Scott
Hi Jens,
Quoted 1 line · Jens Axboe
Ok, updated version.
One thing I found a bit awkward was the way its putting all inodes in the root of the relayfs namespace, with the cpuid tacked on the end of the bdevname - I was a bit confused at first when a trace of sdd on my 4P box spontaneously created files for "partitions" sdd0, sdd1, sdd2, and sdd3 ;).
I suppose if many more users of relayfs spring into existance, this is going to get quite ugly. Below is a patch that aligns the names to the conventions used in sysfs; so, for example, when running two traces simultaneously on
/dev/sddand/dev/sdb, instead of this:# find /relay /relay /relay/sdd3 /relay/sdd2 /relay/sdd1 /relay/sdd0 /relay/sdb3 /relay/sdb2 /relay/sdb1 /relay/sdb0it now uses this...
# find /relay /relay /relay/block /relay/block/sdd /relay/block/sdd/trace3 /relay/block/sdd/trace2 /relay/block/sdd/trace1 /relay/block/sdd/trace0 /relay/block/sdb /relay/block/sdb/trace3 /relay/block/sdb/trace2 /relay/block/sdb/trace1 /relay/block/sdb/trace0and does the correct dynamic setup and teardown of the hierarchy as the userspace tool starts and stops tracing. I had to modify the relayfs rmdir code a bit to make this work properly, I'll send a separate patch for that shortly.
Quoted 7 lines
Quoted 2 lines
has been updated as well, the protocol version was increased to accomodate the trace structure changes.
I have the associated userspace change for this, as well as several other fixes and tweaks for your tool - if you could slap a copyright and license notice onto that source (pretty please? :) I'll send 'em right along.
I've committed this patch. However, there's an issue with it:
Quoted 6 lines
(quoted diff) +6
-0+static struct dentry *blk_create_tree(const char *blk_name) +{ + struct dentry *dir; + + spin_lock(&blk_tree_lock); + if (!blk_tree_root) {
Review
Quoted 10 lines
(quoted diff) +10
-0+ blk_tree_root = relayfs_create_dir("block", NULL); + if (!blk_tree_root) { + spin_unlock(&blk_tree_lock); + return NULL; + } + } + dir = relayfs_create_dir(blk_name, blk_tree_root); + if (!dir) + blk_remove_root(); + spin_unlock(&blk_tree_lock);
That doesn't look very safe, relayfs_create_dir() could block. I've changed the blk_tree_lock to be a simple mutex instead. The patch is committed to the git repo.
Signature · 1 line
Jens Axboe
Hi Jens,
Quoted 4 lines · Jens Axboe
...
include/linux/blktrace.h renamed from opt/kernel/linux-2.6.13-rc6-mm2/include/linux/blktrace.h +2
-0+ t.pid = current->pid; +/*
include/linux/blktrace.h line 65
Quoted 10 lines
include/linux/blktrace.h renamed from opt/kernel/linux-2.6.13-rc6-mm2/include/linux/blktrace.h +10
-0+* The trace itself +*/ +struct blk_io_trace { +u32 magic;/* MAGIC << 8 | version */ +u32 sequence;/* event number */ +u64 time;/* in microseconds */ +u64 sector;/* disk offset */ +u32 bytes;/* transfer length */ +u32 action;/* what happened */ +u16 pid;/* who did it */
Also, this field (pid) should probably be a u32.
cheers.
Signature · 1 line
Nathan
Quoted 19 lines · Nathan Scott
Hi Jens,
Quoted 4 lines · Jens Axboe
...
include/linux/blktrace.h renamed from opt/kernel/linux-2.6.13-rc6-mm2/include/linux/blktrace.h +2
-0+ t.pid = current->pid; +/* include/linux/blktrace.h line 65
Quoted 10 lines
include/linux/blktrace.h renamed from opt/kernel/linux-2.6.13-rc6-mm2/include/linux/blktrace.h +10
-0+* The trace itself +*/ +struct blk_io_trace { +u32 magic;/* MAGIC << 8 | version */ +u32 sequence;/* event number */ +u64 time;/* in microseconds */ +u64 sector;/* disk offset */ +u32 bytes;/* transfer length */ +u32 action;/* what happened */ +u16 pid;/* who did it */ Also, this field (pid) should probably be a u32.
Ah yes, thanks!
Signature · 1 line
Jens Axboe