History

vsprintf: Add %p extension "%pOF" for device tree

90% of the usage of device node's full_name is printing it out in a kernel message. However, storing the full path for every node is wasteful and redundant. With a custom format specifier, we can generate the full path at run-time and eventually remove the full path from every node. For instance typical use is: pr_info("Frobbing node %s\n", node->full_name); Which can be written now as: pr_info("Frobbing node %pOF\n", node); '%pO' is the base specifier to represent kobjects with '%pOF' representing struct device_node. Currently, struct device_node is the only supported type of kobject. More fine-grained control of formatting includes printing the name, flags, path-spec name and others, explained in the documentation entry. Originally written by Pantelis, but pretty much rewrote the core function using existing string/number functions. The 2 passes were unnecessary and have been removed. Also, updated the checkpatch.pl check. The unittest code was written by Grant Likely.

Pantelis Antoniou committed 11 years ago

Commit ce4fecf1 parent 27497e15 files · +234 −2Browse files

Unified · Split

5 files
  1. Documentation/printk-formats.txt +36 −0
  2. drivers/of/unittest-data/tests-platform.dtsi +3 −1
  3. drivers/of/unittest.c +58 −0
  4. lib/vsprintf.c +136 −0
  5. scripts/checkpatch.pl +1 −1
Documentation/printk-formats.txt+36−0
@@ -275,6 +275,42 @@ struct va_format: · 274 unmodified lines
275 275
276 Passed by reference.276 Passed by reference.
277 277
278kobjects:
279 %pO
280
281 Base specifier for kobject based structs. Must be followed with
282 character for specific type of kobject as listed below:
283
284 Device tree nodes:
285
286 %pOF[fnpPcCF]
287
288 For printing device tree nodes. The optional arguments are:
289 f device node full_name
290 n device node name
291 p device node phandle
292 P device node path spec (name + @unit)
293 F device node flags
294 c major compatible string
295 C full compatible string
296 Without any arguments prints full_name (same as %pOFf)
297 The separator when using multiple arguments is ':'
298
299 Examples:
300
301 %pOF /foo/bar@0 - Node full name
302 %pOFf /foo/bar@0 - Same as above
303 %pOFfp /foo/bar@0:10 - Node full name + phandle
304 %pOFfcF /foo/bar@0:foo,device:--P- - Node full name +
305 major compatible string +
306 node flags
307 D - dynamic
308 d - detached
309 P - Populated
310 B - Populated bus
311
312 Passed by reference.
313
278struct clk:314struct clk:
279 315
280 %pC pll1316 %pC pll1
drivers/of/unittest-data/tests-platform.dtsi+3−1
@@ -26,7 +26,9 @@ · 25 unmodified lines
26 #size-cells = <0>;26 #size-cells = <0>;
27 27
28 dev@100 {28 dev@100 {
29 compatible = "test-sub-device";29 compatible = "test-sub-device",
30 "test-compat2",
31 "test-compat3";
30 reg = <0x100>;32 reg = <0x100>;
31 };33 };
32 };34 };
drivers/of/unittest.c+58−0
@@ -239,6 +239,63 @@ static void __init of_unittest_check_tree_linkage(void) · 238 unmodified lines
239 pr_debug("allnodes list size (%i); sibling lists size (%i)\n", allnode_count, child_count);239 pr_debug("allnodes list size (%i); sibling lists size (%i)\n", allnode_count, child_count);
240}240}
241 241
242static void __init of_unittest_printf_one(struct device_node *np, const char *fmt,
243 const char *expected)
244{
245 unsigned char buf[strlen(expected)+10];
246 int size, i;
247
248 /* Baseline; check conversion with a large size limit */
249 memset(buf, 0xff, sizeof(buf));
250 size = snprintf(buf, sizeof(buf) - 2, fmt, np);
251
252 /* use strcmp() instead of strncmp() here to be absolutely sure strings match */
253 unittest((strcmp(buf, expected) == 0) && (buf[size+1] == 0xff),
254 "sprintf failed; fmt='%s' expected='%s' rslt='%s'\n",
255 fmt, expected, buf);
256
257 /* Make sure length limits work */
258 size++;
259 for (i = 0; i < 2; i++, size--) {
260 /* Clear the buffer, and make sure it works correctly still */
261 memset(buf, 0xff, sizeof(buf));
262 snprintf(buf, size+1, fmt, np);
263 unittest(strncmp(buf, expected, size) == 0 && (buf[size+1] == 0xff),
264 "snprintf failed; size=%i fmt='%s' expected='%s' rslt='%s'\n",
265 size, fmt, expected, buf);
266 }
267}
268
269static void __init of_unittest_printf(void)
270{
271 struct device_node *np;
272 const char *full_name = "/testcase-data/platform-tests/test-device@1/dev@100";
273 char phandle_str[16] = "";
274
275 np = of_find_node_by_path(full_name);
276 if (!np) {
277 unittest(np, "testcase data missing\n");
278 return;
279 }
280
281 num_to_str(phandle_str, sizeof(phandle_str), np->phandle);
282
283 of_unittest_printf_one(np, "%pOF", full_name);
284 of_unittest_printf_one(np, "%pOFf", full_name);
285 of_unittest_printf_one(np, "%pOFp", phandle_str);
286 of_unittest_printf_one(np, "%pOFP", "dev@100");
287 of_unittest_printf_one(np, "ABC %pOFP ABC", "ABC dev@100 ABC");
288 of_unittest_printf_one(np, "%10pOFP", " dev@100");
289 of_unittest_printf_one(np, "%-10pOFP", "dev@100 ");
290 of_unittest_printf_one(of_root, "%pOFP", "/");
291 of_unittest_printf_one(np, "%pOFF", "----");
292 of_unittest_printf_one(np, "%pOFPF", "dev@100:----");
293 of_unittest_printf_one(np, "%pOFPFPc", "dev@100:----:dev@100:test-sub-device");
294 of_unittest_printf_one(np, "%pOFc", "test-sub-device");
295 of_unittest_printf_one(np, "%pOFC",
296 "\"test-sub-device\",\"test-compat2\",\"test-compat3\"");
297}
298
242struct node_hash {299struct node_hash {
243 struct hlist_node node;300 struct hlist_node node;
244 struct device_node *np;301 struct device_node *np;
@@ -2269,6 +2326,7 @@ static int __init of_unittest(void) · 2024 unmodified lines
2269 of_unittest_find_node_by_name();2326 of_unittest_find_node_by_name();
2270 of_unittest_dynamic();2327 of_unittest_dynamic();
2271 of_unittest_parse_phandle_with_args();2328 of_unittest_parse_phandle_with_args();
2329 of_unittest_printf();
2272 of_unittest_property_string();2330 of_unittest_property_string();
2273 of_unittest_property_copy();2331 of_unittest_property_copy();
2274 of_unittest_changeset();2332 of_unittest_changeset();
lib/vsprintf.c+136−0
@@ -31,6 +31,7 @@ · 30 unmodified lines
31#include <linux/dcache.h>31#include <linux/dcache.h>
32#include <linux/cred.h>32#include <linux/cred.h>
33#include <linux/uuid.h>33#include <linux/uuid.h>
34#include <linux/of.h>
34#include <net/addrconf.h>35#include <net/addrconf.h>
35#ifdef CONFIG_BLOCK36#ifdef CONFIG_BLOCK
36#include <linux/blkdev.h>37#include <linux/blkdev.h>
@@ -1470,6 +1471,126 @@ char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt) · 1433 unmodified lines
1470 return format_flags(buf, end, flags, names);1471 return format_flags(buf, end, flags, names);
1471}1472}
1472 1473
1474static const char *device_node_name_for_depth(const struct device_node *np, int depth)
1475{
1476 for ( ; np && depth; depth--)
1477 np = np->parent;
1478
1479 return kbasename(np->full_name);
1480}
1481
1482static noinline_for_stack
1483char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end)
1484{
1485 int depth;
1486 const struct device_node *parent = np->parent;
1487 static const struct printf_spec strspec = {
1488 .field_width = -1,
1489 .precision = -1,
1490 };
1491
1492 /* special case for root node */
1493 if (!parent)
1494 return string(buf, end, "/", strspec);
1495
1496 for (depth = 0; parent->parent; depth++)
1497 parent = parent->parent;
1498
1499 for ( ; depth >= 0; depth--) {
1500 buf = string(buf, end, "/", strspec);
1501 buf = string(buf, end, device_node_name_for_depth(np, depth),
1502 strspec);
1503 }
1504 return buf;
1505}
1506
1507static noinline_for_stack
1508char *device_node_string(char *buf, char *end, struct device_node *dn,
1509 struct printf_spec spec, const char *fmt)
1510{
1511 char tbuf[sizeof("xxxx") + 1];
1512 const char *p;
1513 int ret;
1514 char *buf_start = buf;
1515 struct property *prop;
1516 bool has_mult, pass;
1517 static const struct printf_spec num_spec = {
1518 .flags = SMALL,
1519 .field_width = -1,
1520 .precision = -1,
1521 .base = 10,
1522 };
1523
1524 struct printf_spec str_spec = spec;
1525 str_spec.field_width = -1;
1526
1527 if (!IS_ENABLED(CONFIG_OF))
1528 return string(buf, end, "(!OF)", spec);
1529
1530 if ((unsigned long)dn < PAGE_SIZE)
1531 return string(buf, end, "(null)", spec);
1532
1533 /* simple case without anything any more format specifiers */
1534 fmt++;
1535 if (fmt[0] == '\0' || strcspn(fmt,"fnpPFcC") > 0)
1536 fmt = "f";
1537
1538 for (pass = false; strspn(fmt,"fnpPFcC"); fmt++, pass = true) {
1539 if (pass) {
1540 if (buf < end)
1541 *buf = ':';
1542 buf++;
1543 }
1544
1545 switch (*fmt) {
1546 case 'f': /* full_name */
1547 buf = device_node_gen_full_name(dn, buf, end);
1548 break;
1549 case 'n': /* name */
1550 buf = string(buf, end, dn->name, str_spec);
1551 break;
1552 case 'p': /* phandle */
1553 buf = number(buf, end, (unsigned int)dn->phandle, num_spec);
1554 break;
1555 case 'P': /* path-spec */
1556 p = kbasename(of_node_full_name(dn));
1557 if (!p[1])
1558 p = "/";
1559 buf = string(buf, end, p, str_spec);
1560 break;
1561 case 'F': /* flags */
1562 tbuf[0] = of_node_check_flag(dn, OF_DYNAMIC) ? 'D' : '-';
1563 tbuf[1] = of_node_check_flag(dn, OF_DETACHED) ? 'd' : '-';
1564 tbuf[2] = of_node_check_flag(dn, OF_POPULATED) ? 'P' : '-';
1565 tbuf[3] = of_node_check_flag(dn, OF_POPULATED_BUS) ? 'B' : '-';
1566 tbuf[4] = 0;
1567 buf = string(buf, end, tbuf, str_spec);
1568 break;
1569 case 'c': /* major compatible string */
1570 ret = of_property_read_string(dn, "compatible", &p);
1571 if (!ret)
1572 buf = string(buf, end, p, str_spec);
1573 break;
1574 case 'C': /* full compatible string */
1575 has_mult = false;
1576 of_property_for_each_string(dn, "compatible", prop, p) {
1577 if (has_mult)
1578 buf = string(buf, end, ",", str_spec);
1579 buf = string(buf, end, "\"", str_spec);
1580 buf = string(buf, end, p, str_spec);
1581 buf = string(buf, end, "\"", str_spec);
1582
1583 has_mult = true;
1584 }
1585 break;
1586 default:
1587 break;
1588 }
1589 }
1590
1591 return widen_string(buf, buf - buf_start, end, spec);
1592}
1593
1473int kptr_restrict __read_mostly;1594int kptr_restrict __read_mostly;
1474 1595
1475/*1596/*
@@ -1566,6 +1687,16 @@ int kptr_restrict __read_mostly; · 90 unmodified lines
1566 * p page flags (see struct page) given as pointer to unsigned long1687 * p page flags (see struct page) given as pointer to unsigned long
1567 * g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t1688 * g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t
1568 * v vma flags (VM_*) given as pointer to unsigned long1689 * v vma flags (VM_*) given as pointer to unsigned long
1690 * - 'O' For a kobject based struct. Must be one of the following:
1691 * - 'OF[fnpPcCF]' For a device tree object
1692 * Without any optional arguments prints the full_name
1693 * f device node full_name
1694 * n device node name
1695 * p device node phandle
1696 * P device node path spec (name + @unit)
1697 * F device node flags
1698 * c major compatible string
1699 * C full compatible string
1569 *1700 *
1570 * ** Please update also Documentation/printk-formats.txt when making changes **1701 * ** Please update also Documentation/printk-formats.txt when making changes **
1571 *1702 *
@@ -1721,6 +1852,11 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, · 149 unmodified lines
1721 1852
1722 case 'G':1853 case 'G':
1723 return flags_string(buf, end, ptr, fmt);1854 return flags_string(buf, end, ptr, fmt);
1855 case 'O':
1856 switch (fmt[1]) {
1857 case 'F':
1858 return device_node_string(buf, end, ptr, spec, fmt + 1);
1859 }
1724 }1860 }
1725 spec.flags |= SMALL;1861 spec.flags |= SMALL;
1726 if (spec.field_width == -1) {1862 if (spec.field_width == -1) {
scripts/checkpatch.pl+1−1
@@ -5709,7 +5709,7 @@ sub process { · 5708 unmodified lines
5709 for (my $count = $linenr; $count <= $lc; $count++) {5709 for (my $count = $linenr; $count <= $lc; $count++) {
5710 my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));5710 my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
5711 $fmt =~ s/%%//g;5711 $fmt =~ s/%%//g;
5712 if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGN]).)/) {5712 if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGNO]).)/) {
5713 $bad_extension = $1;5713 $bad_extension = $1;
5714 last;5714 last;
5715 }5715 }