[BACK]Return to blktrace.c CVS log [TXT][DIR] Up to [Development] / linux-2.6-xfs / drivers / block

File: [Development] / linux-2.6-xfs / drivers / block / Attic / blktrace.c (download)

Revision 1.1, Mon Aug 29 15:19:41 2005 UTC (12 years, 1 month ago) by nathans.longdrop.melbourne.sgi.com
Branch: MAIN

Merge relayfs and the initial block device tracing patch from Jens.
Merge of 2.6.x-xfs-melb:linux:23656a by kenmcd.

#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 & (1 << BIO_RW_BARRIER))
		what |= BLK_TC_ACT(BLK_TC_BARRIER);
	if (rw & (1 << BIO_RW_SYNC))
		what |= BLK_TC_ACT(BLK_TC_SYNC);

	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();
	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;
}