[RFC] Generic Trace Setup and Control (GTSC) kernel API (3/3)

From: David Wilder
Date: Mon Jun 18 2007 - 00:58:22 EST


Patches to convert blktrace to the new GTSC API.
Two patches are included, the first is to the kernel portion of blktrace. Apply the second patch is to the blktrace user code.

--
David Wilder
IBM Linux Technology Center
Beaverton, Oregon, USA dwilder@xxxxxxxxxx
(503)578-3789

This patch converts the blktrace facility to use the Generic Trace
Setup and Control (GTSC) API. (kernel patch)

Signed-off-by: Tom Zanussi <zanussi@xxxxxxxxxx>
Signed-off-by: David Wilder <dwilder@xxxxxxxxxx>

diff --git a/block/Kconfig b/block/Kconfig
index a50f481..9ae9a8c 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -30,7 +30,7 @@ config LBD
config BLK_DEV_IO_TRACE
bool "Support for tracing block io actions"
depends on SYSFS
- select RELAY
+ select GTSC
select DEBUG_FS
help
Say Y here, if you want to be able to trace the block layer actions
diff --git a/block/blktrace.c b/block/blktrace.c
index 3f0e7c3..b4acf89 100644
--- a/block/blktrace.c
+++ b/block/blktrace.c
@@ -36,7 +36,7 @@ static void trace_note(struct blk_trace *bt, pid_t pid, int action,
{
struct blk_io_trace *t;

- t = relay_reserve(bt->rchan, sizeof(*t) + len);
+ t = relay_reserve(bt->gtsc->rchan, sizeof(*t) + len);
if (t) {
const int cpu = smp_processor_id();

@@ -126,7 +126,7 @@ void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
pid_t pid;
int cpu;

- if (unlikely(bt->trace_state != Blktrace_running))
+ if (unlikely(!gtsc_trace_running(bt->gtsc)))
return;

what |= ddir_act[rw & WRITE];
@@ -152,7 +152,7 @@ void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
if (unlikely(tsk->btrace_seq != blktrace_seq))
trace_note_tsk(bt, tsk);

- t = relay_reserve(bt->rchan, sizeof(*t) + pdu_len);
+ t = relay_reserve(bt->gtsc->rchan, sizeof(*t) + pdu_len);
if (t) {
cpu = smp_processor_id();
sequence = per_cpu_ptr(bt->sequence, cpu);
@@ -178,55 +178,8 @@ void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,

EXPORT_SYMBOL_GPL(__blk_add_trace);

-static struct dentry *blk_tree_root;
-static struct mutex blk_tree_mutex;
-static unsigned int root_users;
-
-static inline void blk_remove_root(void)
-{
- if (blk_tree_root) {
- debugfs_remove(blk_tree_root);
- blk_tree_root = NULL;
- }
-}
-
-static void blk_remove_tree(struct dentry *dir)
-{
- mutex_lock(&blk_tree_mutex);
- debugfs_remove(dir);
- if (--root_users == 0)
- blk_remove_root();
- mutex_unlock(&blk_tree_mutex);
-}
-
-static struct dentry *blk_create_tree(const char *blk_name)
-{
- struct dentry *dir = NULL;
-
- mutex_lock(&blk_tree_mutex);
-
- if (!blk_tree_root) {
- blk_tree_root = debugfs_create_dir("block", NULL);
- if (!blk_tree_root)
- goto err;
- }
-
- dir = debugfs_create_dir(blk_name, blk_tree_root);
- if (dir)
- root_users++;
- else
- blk_remove_root();
-
-err:
- mutex_unlock(&blk_tree_mutex);
- return dir;
-}
-
static void blk_trace_cleanup(struct blk_trace *bt)
{
- relay_close(bt->rchan);
- debugfs_remove(bt->dropped_file);
- blk_remove_tree(bt->dir);
free_percpu(bt->sequence);
kfree(bt);
}
@@ -239,76 +192,14 @@ static int blk_trace_remove(request_queue_t *q)
if (!bt)
return -EINVAL;

- if (bt->trace_state == Blktrace_setup ||
- bt->trace_state == Blktrace_stopped)
+ if (!gtsc_trace_running(bt->gtsc)) {
+ gtsc_trace_cleanup(bt->gtsc);
blk_trace_cleanup(bt);
+ }

return 0;
}

-static int blk_dropped_open(struct inode *inode, struct file *filp)
-{
- filp->private_data = inode->i_private;
-
- return 0;
-}
-
-static ssize_t blk_dropped_read(struct file *filp, char __user *buffer,
- size_t count, loff_t *ppos)
-{
- struct blk_trace *bt = filp->private_data;
- char buf[16];
-
- snprintf(buf, sizeof(buf), "%u\n", atomic_read(&bt->dropped));
-
- return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
-}
-
-static const struct file_operations blk_dropped_fops = {
- .owner = THIS_MODULE,
- .open = blk_dropped_open,
- .read = blk_dropped_read,
-};
-
-/*
- * Keep track of how many times we encountered a full subbuffer, to aid
- * the user space app in telling how many lost events there were.
- */
-static int blk_subbuf_start_callback(struct rchan_buf *buf, void *subbuf,
- void *prev_subbuf, size_t prev_padding)
-{
- struct blk_trace *bt;
-
- if (!relay_buf_full(buf))
- return 1;
-
- bt = buf->chan->private_data;
- atomic_inc(&bt->dropped);
- return 0;
-}
-
-static int blk_remove_buf_file_callback(struct dentry *dentry)
-{
- debugfs_remove(dentry);
- return 0;
-}
-
-static struct dentry *blk_create_buf_file_callback(const char *filename,
- struct dentry *parent,
- int mode,
- struct rchan_buf *buf,
- int *is_global)
-{
- return debugfs_create_file(filename, mode, parent, buf,
- &relay_file_operations);
-}
-
-static struct rchan_callbacks blk_relay_callbacks = {
- .subbuf_start = blk_subbuf_start_callback,
- .create_buf_file = blk_create_buf_file_callback,
- .remove_buf_file = blk_remove_buf_file_callback,
-};
-
/*
* Setup everything required to start tracing
*/
@@ -317,25 +208,23 @@ static int blk_trace_setup(request_queue_t *q, struct block_device *bdev,
{
struct blk_user_trace_setup buts;
struct blk_trace *old_bt, *bt = NULL;
- struct dentry *dir = NULL;
char b[BDEVNAME_SIZE];
int ret, i;
+ struct gtsc_trace_setup *gts = &buts.gts;

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));
+ strcpy(gts->root, "block");
+ strcpy(gts->name, bdevname(bdev, b));

/*
* some device names have larger paths - convert the slashes
* to underscores for this to work as expected
*/
- for (i = 0; i < strlen(buts.name); i++)
- if (buts.name[i] == '/')
- buts.name[i] = '_';
+ for (i = 0; i < strlen(gts->name); i++)
+ if (gts->name[i] == '/')
+ gts->name[i] = '_';

if (copy_to_user(arg, &buts, sizeof(buts)))
return -EFAULT;
@@ -349,23 +238,12 @@ static int blk_trace_setup(request_queue_t *q, struct block_device *bdev,
if (!bt->sequence)
goto err;

- ret = -ENOENT;
- dir = blk_create_tree(buts.name);
- if (!dir)
+ bt->gtsc = gtsc_trace_setup(gts->root, gts->name, gts->buf_size,
+ gts->buf_nr, 0);
+ if (!bt->gtsc)
goto err;

- bt->dir = dir;
bt->dev = bdev->bd_dev;
- atomic_set(&bt->dropped, 0);
-
- ret = -EIO;
- bt->dropped_file = debugfs_create_file("dropped", 0444, dir, bt, &blk_dropped_fops);
- if (!bt->dropped_file)
- goto err;
-
- bt->rchan = relay_open("trace", dir, buts.buf_size, buts.buf_nr, &blk_relay_callbacks, bt);
- if (!bt->rchan)
- goto err;

bt->act_mask = buts.act_mask;
if (!bt->act_mask)
@@ -377,7 +255,6 @@ static int blk_trace_setup(request_queue_t *q, struct block_device *bdev,
bt->end_lba = -1ULL;

bt->pid = buts.pid;
- bt->trace_state = Blktrace_setup;

ret = -EBUSY;
old_bt = xchg(&q->blk_trace, bt);
@@ -388,14 +265,10 @@ static int blk_trace_setup(request_queue_t *q, struct block_device *bdev,

return 0;
err:
- if (dir)
- blk_remove_tree(dir);
if (bt) {
- if (bt->dropped_file)
- debugfs_remove(bt->dropped_file);
free_percpu(bt->sequence);
- if (bt->rchan)
- relay_close(bt->rchan);
+ if (bt->gtsc)
+ gtsc_trace_cleanup(bt->gtsc);
kfree(bt);
}
return ret;
@@ -404,33 +277,21 @@ err:
static int blk_trace_startstop(request_queue_t *q, int start)
{
struct blk_trace *bt;
- int ret;
+ int ret = 0;

if ((bt = q->blk_trace) == NULL)
return -EINVAL;

- /*
- * For starting a trace, we can transition from a setup or stopped
- * trace. For stopping a trace, the state must be running
- */
- ret = -EINVAL;
if (start) {
- if (bt->trace_state == Blktrace_setup ||
- bt->trace_state == Blktrace_stopped) {
+ if (!gtsc_trace_running(bt->gtsc)) {
blktrace_seq++;
smp_mb();
- bt->trace_state = Blktrace_running;
-
- trace_note_time(bt);
- ret = 0;
- }
- } else {
- if (bt->trace_state == Blktrace_running) {
- bt->trace_state = Blktrace_stopped;
- relay_flush(bt->rchan);
- ret = 0;
+ ret = gtsc_trace_startstop(bt->gtsc, start);
+ if (!ret)
+ trace_note_time(bt);
}
- }
+ } else
+ ret = gtsc_trace_startstop(bt->gtsc, start);

return ret;
}
@@ -551,7 +412,6 @@ static void blk_trace_set_ht_offsets(void)

static __init int blk_trace_init(void)
{
- mutex_init(&blk_tree_mutex);
on_each_cpu(blk_trace_check_cpu_time, NULL, 1, 1);
blk_trace_set_ht_offsets();

diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h
index 3680ff9..9ccb72f 100644
--- a/include/linux/blktrace_api.h
+++ b/include/linux/blktrace_api.h
@@ -2,7 +2,7 @@
#define BLKTRACE_H

#include <linux/blkdev.h>
-#include <linux/relay.h>
+#include <linux/gtsc.h>

/*
* Trace categories
@@ -109,34 +109,34 @@ struct blk_io_trace_remap {
__be64 sector;
};

-enum {
- Blktrace_setup = 1,
- Blktrace_running,
- Blktrace_stopped,
-};
-
struct blk_trace {
- int trace_state;
- struct rchan *rchan;
+ struct gtsc_trace *gtsc;
unsigned long *sequence;
u16 act_mask;
u64 start_lba;
u64 end_lba;
u32 pid;
u32 dev;
- struct dentry *dir;
- struct dentry *dropped_file;
- atomic_t dropped;
+};
+
+/*
+ * User setup structure
+ */
+struct gtsc_trace_setup
+{
+ char root[GTSC_TRACE_ROOT_NAME_SIZE];
+ char name[GTSC_TRACE_NAME_SIZE];
+ u32 buf_size;
+ u32 buf_nr;
+ u32 flags;
};

/*
* User setup structure passed with BLKTRACESTART
*/
struct blk_user_trace_setup {
- char name[BDEVNAME_SIZE]; /* output */
+ struct gtsc_trace_setup gts; /* input */
u16 act_mask; /* input */
- u32 buf_size; /* input */
- u32 buf_nr; /* input */
u64 start_lba;
u64 end_lba;
u32 pid;
This patch converts the blktrace facility to use the Generic Trace
Setup and Control (GTSC) API. (patch to blktrace user code)

Signed-off-by: Tom Zanussi <zanussi@xxxxxxxxxx>
Signed-off-by: David Wilder <dwilder@xxxxxxxxxx>

diff --git a/blktrace.c b/blktrace.c
index 2ad940d..486fdc3 100644
--- a/blktrace.c
+++ b/blktrace.c
@@ -395,8 +395,8 @@ static int start_trace(struct device_information *dip)
struct blk_user_trace_setup buts;

memset(&buts, 0, sizeof(buts));
- buts.buf_size = dip->buf_size;
- buts.buf_nr = dip->buf_nr;
+ buts.gts.buf_size = dip->buf_size;
+ buts.gts.buf_nr = dip->buf_nr;
buts.act_mask = act_mask;

if (ioctl(dip->fd, BLKTRACESETUP, &buts) < 0) {
@@ -409,7 +409,7 @@ static int start_trace(struct device_information *dip)
return 1;
}

- memcpy(dip->buts_name, buts.name, sizeof(dip->buts_name));
+ memcpy(dip->buts_name, buts.gts.name, sizeof(dip->buts_name));
dip_set_tracing(dip, 1);
return 0;
}
diff --git a/blktrace_api.h b/blktrace_api.h
index 61b405a..3ff0905 100644
--- a/blktrace_api.h
+++ b/blktrace_api.h
@@ -107,14 +107,28 @@ struct blk_io_trace_remap {
__u64 sector;
};

+#define GTSC_TRACE_ROOT_NAME_SIZE 64 /* Max root dir identifier */
+#define GTSC_TRACE_NAME_SIZE 64 /* Max trace identifier */
+
+/*
+ * User setup structure
+ */
+struct gtsc_trace_setup
+{
+ char root[GTSC_TRACE_ROOT_NAME_SIZE];
+ char name[GTSC_TRACE_NAME_SIZE];
+ __u32 buf_size;
+ __u32 buf_nr;
+ __u32 flags;
+};
+
+
/*
* User setup structure passed with BLKSTARTTRACE
*/
struct blk_user_trace_setup {
- char name[32]; /* output */
+ struct gtsc_trace_setup gts; /* input */
__u16 act_mask; /* input */
- __u32 buf_size; /* input */
- __u32 buf_nr; /* input */
__u64 start_lba;
__u64 end_lba;
__u32 pid;