diff options
author | Li Zefan <lizf@cn.fujitsu.com> | 2009-03-24 05:43:30 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-03-24 08:09:00 -0400 |
commit | 093419971e03362a00f499960557c119982ea09f (patch) | |
tree | f355954c6282bc6ee3d67f7ae374408821a216ef | |
parent | e0dc81bec0927fa0c8aabc521793161909eef7a5 (diff) |
blktrace: print human-readable act_mask
Impact: new feature, allow symbolic values in /debug/tracing/act_mask
Print stringified act_mask instead of hex value:
# cat act_mask
read,write,barrier,sync,queue,requeue,issue,complete,fs,pc,ahead,meta,
discard,drv_data
# echo "meta,write" > act_mask
# cat act_mask
write,meta
Also:
- make act_mask accept "ahead", "meta", "discard" and "drv_data"
- use strsep() instead of strchr() to parse user input
- return -EINVAL if a token is not found in the mask map
- fix a bug that 'value' is unsigned, so it can < 0
- propagate error value of blk_trace_mask2str() to userspace, but not
always return -ENXIO.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Acked-by: Jens Axboe <jens.axboe@oracle.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <49C8AB42.1000802@cn.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | kernel/trace/blktrace.c | 103 |
1 files changed, 65 insertions, 38 deletions
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index f69f8bd8bef9..6fb274f5f34e 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c | |||
@@ -1316,53 +1316,77 @@ struct attribute_group blk_trace_attr_group = { | |||
1316 | .attrs = blk_trace_attrs, | 1316 | .attrs = blk_trace_attrs, |
1317 | }; | 1317 | }; |
1318 | 1318 | ||
1319 | static int blk_str2act_mask(const char *str) | 1319 | static const struct { |
1320 | int mask; | ||
1321 | const char *str; | ||
1322 | } mask_maps[] = { | ||
1323 | { BLK_TC_READ, "read" }, | ||
1324 | { BLK_TC_WRITE, "write" }, | ||
1325 | { BLK_TC_BARRIER, "barrier" }, | ||
1326 | { BLK_TC_SYNC, "sync" }, | ||
1327 | { BLK_TC_QUEUE, "queue" }, | ||
1328 | { BLK_TC_REQUEUE, "requeue" }, | ||
1329 | { BLK_TC_ISSUE, "issue" }, | ||
1330 | { BLK_TC_COMPLETE, "complete" }, | ||
1331 | { BLK_TC_FS, "fs" }, | ||
1332 | { BLK_TC_PC, "pc" }, | ||
1333 | { BLK_TC_AHEAD, "ahead" }, | ||
1334 | { BLK_TC_META, "meta" }, | ||
1335 | { BLK_TC_DISCARD, "discard" }, | ||
1336 | { BLK_TC_DRV_DATA, "drv_data" }, | ||
1337 | }; | ||
1338 | |||
1339 | static int blk_trace_str2mask(const char *str) | ||
1320 | { | 1340 | { |
1341 | int i; | ||
1321 | int mask = 0; | 1342 | int mask = 0; |
1322 | char *copy = kstrdup(str, GFP_KERNEL), *s; | 1343 | char *s, *token; |
1323 | 1344 | ||
1324 | if (copy == NULL) | 1345 | s = kstrdup(str, GFP_KERNEL); |
1346 | if (s == NULL) | ||
1325 | return -ENOMEM; | 1347 | return -ENOMEM; |
1326 | 1348 | s = strstrip(s); | |
1327 | s = strstrip(copy); | ||
1328 | 1349 | ||
1329 | while (1) { | 1350 | while (1) { |
1330 | char *sep = strchr(s, ','); | 1351 | token = strsep(&s, ","); |
1331 | 1352 | if (token == NULL) | |
1332 | if (sep != NULL) | ||
1333 | *sep = '\0'; | ||
1334 | |||
1335 | if (strcasecmp(s, "barrier") == 0) | ||
1336 | mask |= BLK_TC_BARRIER; | ||
1337 | else if (strcasecmp(s, "complete") == 0) | ||
1338 | mask |= BLK_TC_COMPLETE; | ||
1339 | else if (strcasecmp(s, "fs") == 0) | ||
1340 | mask |= BLK_TC_FS; | ||
1341 | else if (strcasecmp(s, "issue") == 0) | ||
1342 | mask |= BLK_TC_ISSUE; | ||
1343 | else if (strcasecmp(s, "pc") == 0) | ||
1344 | mask |= BLK_TC_PC; | ||
1345 | else if (strcasecmp(s, "queue") == 0) | ||
1346 | mask |= BLK_TC_QUEUE; | ||
1347 | else if (strcasecmp(s, "read") == 0) | ||
1348 | mask |= BLK_TC_READ; | ||
1349 | else if (strcasecmp(s, "requeue") == 0) | ||
1350 | mask |= BLK_TC_REQUEUE; | ||
1351 | else if (strcasecmp(s, "sync") == 0) | ||
1352 | mask |= BLK_TC_SYNC; | ||
1353 | else if (strcasecmp(s, "write") == 0) | ||
1354 | mask |= BLK_TC_WRITE; | ||
1355 | |||
1356 | if (sep == NULL) | ||
1357 | break; | 1353 | break; |
1358 | 1354 | ||
1359 | s = sep + 1; | 1355 | if (*token == '\0') |
1356 | continue; | ||
1357 | |||
1358 | for (i = 0; i < ARRAY_SIZE(mask_maps); i++) { | ||
1359 | if (strcasecmp(token, mask_maps[i].str) == 0) { | ||
1360 | mask |= mask_maps[i].mask; | ||
1361 | break; | ||
1362 | } | ||
1363 | } | ||
1364 | if (i == ARRAY_SIZE(mask_maps)) { | ||
1365 | mask = -EINVAL; | ||
1366 | break; | ||
1367 | } | ||
1360 | } | 1368 | } |
1361 | kfree(copy); | 1369 | kfree(s); |
1362 | 1370 | ||
1363 | return mask; | 1371 | return mask; |
1364 | } | 1372 | } |
1365 | 1373 | ||
1374 | static ssize_t blk_trace_mask2str(char *buf, int mask) | ||
1375 | { | ||
1376 | int i; | ||
1377 | char *p = buf; | ||
1378 | |||
1379 | for (i = 0; i < ARRAY_SIZE(mask_maps); i++) { | ||
1380 | if (mask & mask_maps[i].mask) { | ||
1381 | p += sprintf(p, "%s%s", | ||
1382 | (p == buf) ? "" : ",", mask_maps[i].str); | ||
1383 | } | ||
1384 | } | ||
1385 | *p++ = '\n'; | ||
1386 | |||
1387 | return p - buf; | ||
1388 | } | ||
1389 | |||
1366 | static struct request_queue *blk_trace_get_queue(struct block_device *bdev) | 1390 | static struct request_queue *blk_trace_get_queue(struct block_device *bdev) |
1367 | { | 1391 | { |
1368 | if (bdev->bd_disk == NULL) | 1392 | if (bdev->bd_disk == NULL) |
@@ -1399,7 +1423,7 @@ static ssize_t sysfs_blk_trace_attr_show(struct device *dev, | |||
1399 | if (q->blk_trace == NULL) | 1423 | if (q->blk_trace == NULL) |
1400 | ret = sprintf(buf, "disabled\n"); | 1424 | ret = sprintf(buf, "disabled\n"); |
1401 | else if (attr == &dev_attr_act_mask) | 1425 | else if (attr == &dev_attr_act_mask) |
1402 | ret = sprintf(buf, "%#x\n", q->blk_trace->act_mask); | 1426 | ret = blk_trace_mask2str(buf, q->blk_trace->act_mask); |
1403 | else if (attr == &dev_attr_pid) | 1427 | else if (attr == &dev_attr_pid) |
1404 | ret = sprintf(buf, "%u\n", q->blk_trace->pid); | 1428 | ret = sprintf(buf, "%u\n", q->blk_trace->pid); |
1405 | else if (attr == &dev_attr_start_lba) | 1429 | else if (attr == &dev_attr_start_lba) |
@@ -1424,7 +1448,7 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev, | |||
1424 | struct request_queue *q; | 1448 | struct request_queue *q; |
1425 | struct hd_struct *p; | 1449 | struct hd_struct *p; |
1426 | u64 value; | 1450 | u64 value; |
1427 | ssize_t ret = -ENXIO; | 1451 | ssize_t ret = -EINVAL; |
1428 | 1452 | ||
1429 | if (count == 0) | 1453 | if (count == 0) |
1430 | goto out; | 1454 | goto out; |
@@ -1432,13 +1456,16 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev, | |||
1432 | if (attr == &dev_attr_act_mask) { | 1456 | if (attr == &dev_attr_act_mask) { |
1433 | if (sscanf(buf, "%llx", &value) != 1) { | 1457 | if (sscanf(buf, "%llx", &value) != 1) { |
1434 | /* Assume it is a list of trace category names */ | 1458 | /* Assume it is a list of trace category names */ |
1435 | value = blk_str2act_mask(buf); | 1459 | ret = blk_trace_str2mask(buf); |
1436 | if (value < 0) | 1460 | if (ret < 0) |
1437 | goto out; | 1461 | goto out; |
1462 | value = ret; | ||
1438 | } | 1463 | } |
1439 | } else if (sscanf(buf, "%llu", &value) != 1) | 1464 | } else if (sscanf(buf, "%llu", &value) != 1) |
1440 | goto out; | 1465 | goto out; |
1441 | 1466 | ||
1467 | ret = -ENXIO; | ||
1468 | |||
1442 | lock_kernel(); | 1469 | lock_kernel(); |
1443 | p = dev_to_part(dev); | 1470 | p = dev_to_part(dev); |
1444 | bdev = bdget(part_devt(p)); | 1471 | bdev = bdget(part_devt(p)); |