/* * Setup everything required to start tracing */ static int blk_trace_setup(request_queue_t *q, struct block_device *bdev, char __user *arg) { struct blk_user_trace_setup buts; struct blk_trace *old_bt, *bt = NULL; struct dentry *dir = NULL; char b[BDEVNAME_SIZE]; int ret, i; 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)); /* * 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] = '_'; if (copy_to_user(arg, &buts, sizeof(buts))) return -EFAULT; ret = -ENOMEM; bt = kzalloc(sizeof(*bt), GFP_KERNEL); if (!bt) goto err; bt->sequence = alloc_percpu(unsigned long); if (!bt->sequence) goto err; ret = -ENOENT; dir = blk_create_tree(buts.name); if (!dir) 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); if (!bt->rchan) goto err; bt->rchan->private_data = bt; bt->act_mask = buts.act_mask; if (!bt->act_mask) bt->act_mask = (u16) -1; bt->start_lba = buts.start_lba; bt->end_lba = buts.end_lba; if (!bt->end_lba) bt->end_lba = -1ULL; bt->pid = buts.pid; bt->trace_state = Blktrace_setup; ret = -EBUSY; old_bt = xchg(&q->blk_trace, bt); if (old_bt) { (void) xchg(&q->blk_trace, old_bt); goto err; } return 0; err: if (dir) blk_remove_tree(dir); if (bt) { if (bt->dropped_file) debugfs_remove(bt->dropped_file); if (bt->sequence) free_percpu(bt->sequence); if (bt->rchan) relay_close(bt->rchan); kfree(bt); } return ret; }
/* * Setup everything required to start tracing */ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev, struct blk_user_trace_setup *buts) { struct blk_trace *old_bt, *bt = NULL; struct dentry *dir = NULL; int ret, i; if (!buts->buf_size || !buts->buf_nr) return -EINVAL; strcpy(buts->name, name); /* * 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] = '_'; ret = -ENOMEM; bt = kzalloc(sizeof(*bt), GFP_KERNEL); if (!bt) goto err; bt->sequence = alloc_percpu(unsigned long); if (!bt->sequence) goto err; ret = -ENOENT; dir = blk_create_tree(buts->name); if (!dir) goto err; bt->dir = dir; bt->dev = 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) bt->act_mask = (u16) -1; bt->start_lba = buts->start_lba; bt->end_lba = buts->end_lba; if (!bt->end_lba) bt->end_lba = -1ULL; bt->pid = buts->pid; bt->trace_state = Blktrace_setup; ret = -EBUSY; old_bt = xchg(&q->blk_trace, bt); if (old_bt) { (void) xchg(&q->blk_trace, old_bt); goto err; } 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); kfree(bt); } return ret; }