aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGabriel Somlo <somlo@cmu.edu>2016-01-28 09:23:13 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-02-09 20:37:39 -0500
commit246c46ebaeaef17814dc5a8830d16e7f1b01116b (patch)
tree0a55991f6e99de4f2895b7921569a55a3b8d5837
parent75f3e8e47f381074801d0034874d20c638d9e3d9 (diff)
firmware: create directory hierarchy for sysfs fw_cfg entries
Each fw_cfg entry of type "file" has an associated 56-char, nul-terminated ASCII string which represents its name. While the fw_cfg device doesn't itself impose any specific naming convention, QEMU developers have traditionally used path name semantics (i.e. "etc/acpi/rsdp") to descriptively name the various fw_cfg "blobs" passed into the guest. This patch attempts, on a best effort basis, to create a directory hierarchy representing the content of fw_cfg file names, under /sys/firmware/qemu_fw_cfg/by_name. Upon successful creation of all directories representing the "dirname" portion of a fw_cfg file, a symlink will be created to represent the "basename", pointing at the appropriate /sys/firmware/qemu_fw_cfg/by_key entry. If a file name is not suitable for this procedure (e.g., if its basename or dirname components collide with an already existing dirname component or basename, respectively) the corresponding fw_cfg blob is skipped and will remain available in sysfs only by its selector key value. Signed-off-by: Gabriel Somlo <somlo@cmu.edu> Cc: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-qemu_fw_cfg42
-rw-r--r--drivers/firmware/qemu_fw_cfg.c109
2 files changed, 148 insertions, 3 deletions
diff --git a/Documentation/ABI/testing/sysfs-firmware-qemu_fw_cfg b/Documentation/ABI/testing/sysfs-firmware-qemu_fw_cfg
index e9e58d4ea60a..011dda4f8e8a 100644
--- a/Documentation/ABI/testing/sysfs-firmware-qemu_fw_cfg
+++ b/Documentation/ABI/testing/sysfs-firmware-qemu_fw_cfg
@@ -56,3 +56,45 @@ Description:
56 entry via the control register, and reading a number 56 entry via the control register, and reading a number
57 of bytes equal to the blob size from the data 57 of bytes equal to the blob size from the data
58 register. 58 register.
59
60 --- Listing fw_cfg blobs by file name ---
61
62 While the fw_cfg device does not impose any specific naming
63 convention on the blobs registered in the file directory,
64 QEMU developers have traditionally used path name semantics
65 to give each blob a descriptive name. For example:
66
67 "bootorder"
68 "genroms/kvmvapic.bin"
69 "etc/e820"
70 "etc/boot-fail-wait"
71 "etc/system-states"
72 "etc/table-loader"
73 "etc/acpi/rsdp"
74 "etc/acpi/tables"
75 "etc/smbios/smbios-tables"
76 "etc/smbios/smbios-anchor"
77 ...
78
79 In addition to the listing by unique selector key described
80 above, the fw_cfg sysfs driver also attempts to build a tree
81 of directories matching the path name components of fw_cfg
82 blob names, ending in symlinks to the by_key entry for each
83 "basename", as illustrated below (assume current directory is
84 /sys/firmware):
85
86 qemu_fw_cfg/by_name/bootorder -> ../by_key/38
87 qemu_fw_cfg/by_name/etc/e820 -> ../../by_key/35
88 qemu_fw_cfg/by_name/etc/acpi/rsdp -> ../../../by_key/41
89 ...
90
91 Construction of the directory tree and symlinks is done on a
92 "best-effort" basis, as there is no guarantee that components
93 of fw_cfg blob names are always "well behaved". I.e., there is
94 the possibility that a symlink (basename) will conflict with
95 a dirname component of another fw_cfg blob, in which case the
96 creation of the offending /sys/firmware/qemu_fw_cfg/by_name
97 entry will be skipped.
98
99 The authoritative list of entries will continue to be found
100 under the /sys/firmware/qemu_fw_cfg/by_key directory.
diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 83e8a5c8f887..19f6851be87f 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -334,9 +334,103 @@ static struct bin_attribute fw_cfg_sysfs_attr_raw = {
334 .read = fw_cfg_sysfs_read_raw, 334 .read = fw_cfg_sysfs_read_raw,
335}; 335};
336 336
337/* kobjects representing top-level and by_key folders */ 337/*
338 * Create a kset subdirectory matching each '/' delimited dirname token
339 * in 'name', starting with sysfs kset/folder 'dir'; At the end, create
340 * a symlink directed at the given 'target'.
341 * NOTE: We do this on a best-effort basis, since 'name' is not guaranteed
342 * to be a well-behaved path name. Whenever a symlink vs. kset directory
343 * name collision occurs, the kernel will issue big scary warnings while
344 * refusing to add the offending link or directory. We follow up with our
345 * own, slightly less scary error messages explaining the situation :)
346 */
347static int fw_cfg_build_symlink(struct kset *dir,
348 struct kobject *target, const char *name)
349{
350 int ret;
351 struct kset *subdir;
352 struct kobject *ko;
353 char *name_copy, *p, *tok;
354
355 if (!dir || !target || !name || !*name)
356 return -EINVAL;
357
358 /* clone a copy of name for parsing */
359 name_copy = p = kstrdup(name, GFP_KERNEL);
360 if (!name_copy)
361 return -ENOMEM;
362
363 /* create folders for each dirname token, then symlink for basename */
364 while ((tok = strsep(&p, "/")) && *tok) {
365
366 /* last (basename) token? If so, add symlink here */
367 if (!p || !*p) {
368 ret = sysfs_create_link(&dir->kobj, target, tok);
369 break;
370 }
371
372 /* does the current dir contain an item named after tok ? */
373 ko = kset_find_obj(dir, tok);
374 if (ko) {
375 /* drop reference added by kset_find_obj */
376 kobject_put(ko);
377
378 /* ko MUST be a kset - we're about to use it as one ! */
379 if (ko->ktype != dir->kobj.ktype) {
380 ret = -EINVAL;
381 break;
382 }
383
384 /* descend into already existing subdirectory */
385 dir = to_kset(ko);
386 } else {
387 /* create new subdirectory kset */
388 subdir = kzalloc(sizeof(struct kset), GFP_KERNEL);
389 if (!subdir) {
390 ret = -ENOMEM;
391 break;
392 }
393 subdir->kobj.kset = dir;
394 subdir->kobj.ktype = dir->kobj.ktype;
395 ret = kobject_set_name(&subdir->kobj, "%s", tok);
396 if (ret) {
397 kfree(subdir);
398 break;
399 }
400 ret = kset_register(subdir);
401 if (ret) {
402 kfree(subdir);
403 break;
404 }
405
406 /* descend into newly created subdirectory */
407 dir = subdir;
408 }
409 }
410
411 /* we're done with cloned copy of name */
412 kfree(name_copy);
413 return ret;
414}
415
416/* recursively unregister fw_cfg/by_name/ kset directory tree */
417static void fw_cfg_kset_unregister_recursive(struct kset *kset)
418{
419 struct kobject *k, *next;
420
421 list_for_each_entry_safe(k, next, &kset->list, entry)
422 /* all set members are ksets too, but check just in case... */
423 if (k->ktype == kset->kobj.ktype)
424 fw_cfg_kset_unregister_recursive(to_kset(k));
425
426 /* symlinks are cleanly and automatically removed with the directory */
427 kset_unregister(kset);
428}
429
430/* kobjects & kset representing top-level, by_key, and by_name folders */
338static struct kobject *fw_cfg_top_ko; 431static struct kobject *fw_cfg_top_ko;
339static struct kobject *fw_cfg_sel_ko; 432static struct kobject *fw_cfg_sel_ko;
433static struct kset *fw_cfg_fname_kset;
340 434
341/* register an individual fw_cfg file */ 435/* register an individual fw_cfg file */
342static int fw_cfg_register_file(const struct fw_cfg_file *f) 436static int fw_cfg_register_file(const struct fw_cfg_file *f)
@@ -363,6 +457,9 @@ static int fw_cfg_register_file(const struct fw_cfg_file *f)
363 if (err) 457 if (err)
364 goto err_add_raw; 458 goto err_add_raw;
365 459
460 /* try adding "/sys/firmware/qemu_fw_cfg/by_name/" symlink */
461 fw_cfg_build_symlink(fw_cfg_fname_kset, &entry->kobj, entry->f.name);
462
366 /* success, add entry to global cache */ 463 /* success, add entry to global cache */
367 fw_cfg_sysfs_cache_enlist(entry); 464 fw_cfg_sysfs_cache_enlist(entry);
368 return 0; 465 return 0;
@@ -417,18 +514,21 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)
417 514
418 /* NOTE: If we supported multiple fw_cfg devices, we'd first create 515 /* NOTE: If we supported multiple fw_cfg devices, we'd first create
419 * a subdirectory named after e.g. pdev->id, then hang per-device 516 * a subdirectory named after e.g. pdev->id, then hang per-device
420 * by_key subdirectories underneath it. However, only 517 * by_key (and by_name) subdirectories underneath it. However, only
421 * one fw_cfg device exist system-wide, so if one was already found 518 * one fw_cfg device exist system-wide, so if one was already found
422 * earlier, we might as well stop here. 519 * earlier, we might as well stop here.
423 */ 520 */
424 if (fw_cfg_sel_ko) 521 if (fw_cfg_sel_ko)
425 return -EBUSY; 522 return -EBUSY;
426 523
427 /* create by_key subdirectory of /sys/firmware/qemu_fw_cfg/ */ 524 /* create by_key and by_name subdirs of /sys/firmware/qemu_fw_cfg/ */
428 err = -ENOMEM; 525 err = -ENOMEM;
429 fw_cfg_sel_ko = kobject_create_and_add("by_key", fw_cfg_top_ko); 526 fw_cfg_sel_ko = kobject_create_and_add("by_key", fw_cfg_top_ko);
430 if (!fw_cfg_sel_ko) 527 if (!fw_cfg_sel_ko)
431 goto err_sel; 528 goto err_sel;
529 fw_cfg_fname_kset = kset_create_and_add("by_name", NULL, fw_cfg_top_ko);
530 if (!fw_cfg_fname_kset)
531 goto err_name;
432 532
433 /* initialize fw_cfg device i/o from platform data */ 533 /* initialize fw_cfg device i/o from platform data */
434 err = fw_cfg_do_platform_probe(pdev); 534 err = fw_cfg_do_platform_probe(pdev);
@@ -457,6 +557,8 @@ err_dir:
457err_rev: 557err_rev:
458 fw_cfg_io_cleanup(); 558 fw_cfg_io_cleanup();
459err_probe: 559err_probe:
560 fw_cfg_kset_unregister_recursive(fw_cfg_fname_kset);
561err_name:
460 fw_cfg_kobj_cleanup(fw_cfg_sel_ko); 562 fw_cfg_kobj_cleanup(fw_cfg_sel_ko);
461err_sel: 563err_sel:
462 return err; 564 return err;
@@ -466,6 +568,7 @@ static int fw_cfg_sysfs_remove(struct platform_device *pdev)
466{ 568{
467 pr_debug("fw_cfg: unloading.\n"); 569 pr_debug("fw_cfg: unloading.\n");
468 fw_cfg_sysfs_cache_cleanup(); 570 fw_cfg_sysfs_cache_cleanup();
571 fw_cfg_kset_unregister_recursive(fw_cfg_fname_kset);
469 fw_cfg_kobj_cleanup(fw_cfg_sel_ko); 572 fw_cfg_kobj_cleanup(fw_cfg_sel_ko);
470 fw_cfg_io_cleanup(); 573 fw_cfg_io_cleanup();
471 return 0; 574 return 0;