Skip to content

Commit 035d110

Browse files
pantoniouDa Xue
authored andcommitted
of: overlay: Add per overlay sysfs attributes
* A per overlay can_remove sysfs attribute that reports whether the overlay can be removed or not due to another overlapping overlay. * A target sysfs attribute listing the target of each fragment, in a group named after the name of the fragment. Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com> [geert: Setup ovinfo[cnt].info for symbols] [geert: Spelling s/changset/changeset/] [geert: Rebase to v4.15-rc1] [geert: Rebase on top of commit 39a751a ("of: change overlay apply input data from unflattened to FDT") in v4.17-rc1] [geert: Use "%pOF" instead of of_node_full_name()] [geert: Rebase on top of commit cdb4f26 ("kobject: kobj_type: remove default_attrs") in v5.18-rc2] [geert: Rebase on top of commit 067c098 ("of: overlay: rework overlay apply and remove kfree()s") in v5.19-rc1] [geert: Remove unused fragment.ovcs] [geert: Add kerneldoc for new fragment/overlay_changeset fields] Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
1 parent a28f116 commit 035d110

File tree

1 file changed

+99
-3
lines changed

1 file changed

+99
-3
lines changed

drivers/of/overlay.c

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,20 @@
2525

2626
#include "of_private.h"
2727

28+
/* fwd. decl */
29+
struct overlay_changeset;
30+
struct fragment;
31+
32+
/* an attribute for each fragment */
33+
struct fragment_attribute {
34+
struct attribute attr;
35+
ssize_t (*show)(struct kobject *kobj, struct fragment_attribute *fattr,
36+
char *buf);
37+
ssize_t (*store)(struct kobject *kobj, struct fragment_attribute *fattr,
38+
const char *buf, size_t count);
39+
struct fragment *fragment;
40+
};
41+
2842
/**
2943
* struct target - info about current target node as recursing through overlay
3044
* @np: node where current level of overlay will be applied
@@ -47,12 +61,20 @@ struct target {
4761

4862
/**
4963
* struct fragment - info about fragment nodes in overlay expanded device tree
50-
* @overlay: pointer to the __overlay__ node
51-
* @target: target of the overlay operation
64+
* @overlay: pointer to the __overlay__ node
65+
* @target: target of the overlay operation
66+
* @info: info node that contains the target and overlay
67+
* @attr_group: attribute group for the fragment
68+
* @attrs: list of attributes for the fragment
69+
* @target_attr: attribute for the fragment
5270
*/
5371
struct fragment {
5472
struct device_node *overlay;
5573
struct device_node *target;
74+
struct device_node *info;
75+
struct attribute_group attr_group;
76+
struct attribute *attrs[2];
77+
struct fragment_attribute target_attr;
5678
};
5779

5880
/**
@@ -65,6 +87,7 @@ struct fragment {
6587
* @notify_state: most recent notify action used on overlay
6688
* @count: count of fragment structures
6789
* @fragments: fragment nodes in the overlay expanded device tree
90+
* @attr_groups: list of attribute groups for all fragments
6891
* @symbols_fragment: last element of @fragments[] is the __symbols__ node
6992
* @cset: changeset to apply fragments to live device tree
7093
* @kobj: kernel object handle
@@ -78,6 +101,7 @@ struct overlay_changeset {
78101
enum of_overlay_notify_action notify_state;
79102
int count;
80103
struct fragment *fragments;
104+
const struct attribute_group **attr_groups;
81105
bool symbols_fragment;
82106
struct of_changeset cset;
83107
struct kobject kobj;
@@ -111,6 +135,7 @@ static int devicetree_corrupt(void)
111135

112136
static int build_changeset_next_level(struct overlay_changeset *ovcs,
113137
struct target *target, const struct device_node *overlay_node);
138+
static int overlay_removal_is_ok(struct overlay_changeset *ovcs);
114139

115140
/*
116141
* of_resolve_phandles() finds the largest phandle in the live tree.
@@ -741,6 +766,16 @@ static struct device_node *find_target(struct device_node *info_node,
741766
return NULL;
742767
}
743768

769+
static ssize_t target_show(struct kobject *kobj,
770+
struct fragment_attribute *fattr, char *buf)
771+
{
772+
struct fragment *fragment = fattr->fragment;
773+
774+
return snprintf(buf, PAGE_SIZE, "%pOF\n", fragment->target);
775+
}
776+
777+
static const struct fragment_attribute target_template_attr = __ATTR_RO(target);
778+
744779
/**
745780
* init_overlay_changeset() - initialize overlay changeset from overlay tree
746781
* @ovcs: Overlay changeset to build
@@ -761,7 +796,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
761796
struct device_node *node, *overlay_node;
762797
struct fragment *fragment;
763798
struct fragment *fragments;
764-
int cnt, ret;
799+
int cnt, i, ret;
765800

766801
/*
767802
* None of the resources allocated by this function will be freed in
@@ -823,6 +858,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
823858
goto err_out;
824859
}
825860

861+
fragment->info = of_node_get(node);
826862
cnt++;
827863
}
828864

@@ -844,6 +880,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
844880
goto err_out;
845881
}
846882

883+
fragment->info = of_node_get(node);
847884
cnt++;
848885
}
849886

@@ -855,6 +892,34 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
855892

856893
ovcs->count = cnt;
857894

895+
ovcs->attr_groups = kcalloc(cnt + 1, sizeof(struct attribute_group *),
896+
GFP_KERNEL);
897+
if (ovcs->attr_groups == NULL) {
898+
ret = -ENOMEM;
899+
goto err_out;
900+
}
901+
902+
for (i = 0; i < cnt; i++) {
903+
fragment = &ovcs->fragments[i];
904+
905+
ovcs->attr_groups[i] = &fragment->attr_group;
906+
907+
fragment->target_attr = target_template_attr;
908+
/* make lockdep happy */
909+
sysfs_attr_init(&fragment->target_attr.attr);
910+
fragment->target_attr.fragment = fragment;
911+
912+
fragment->attrs[0] = &fragment->target_attr.attr;
913+
fragment->attrs[1] = NULL;
914+
915+
/* NOTE: direct reference to the full_name */
916+
fragment->attr_group.name =
917+
kbasename(fragment->info->full_name);
918+
fragment->attr_group.attrs = fragment->attrs;
919+
920+
}
921+
ovcs->attr_groups[i] = NULL;
922+
858923
return 0;
859924

860925
err_out:
@@ -876,10 +941,12 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs)
876941
ovcs->id = 0;
877942
}
878943

944+
kfree(ovcs->attr_groups);
879945

880946
for (i = 0; i < ovcs->count; i++) {
881947
of_node_put(ovcs->fragments[i].target);
882948
of_node_put(ovcs->fragments[i].overlay);
949+
of_node_put(ovcs->fragments[i].info);
883950
}
884951
kfree(ovcs->fragments);
885952
kobject_put(&ovcs->kobj);
@@ -941,8 +1008,26 @@ static const struct attribute *overlay_global_attrs[] = {
9411008
NULL
9421009
};
9431010

1011+
static ssize_t can_remove_show(struct kobject *kobj,
1012+
struct kobj_attribute *attr, char *buf)
1013+
{
1014+
struct overlay_changeset *ovcs = kobj_to_ovcs(kobj);
1015+
1016+
return snprintf(buf, PAGE_SIZE, "%d\n", overlay_removal_is_ok(ovcs));
1017+
}
1018+
1019+
static struct kobj_attribute can_remove_attr = __ATTR_RO(can_remove);
1020+
1021+
static struct attribute *overlay_changeset_attrs[] = {
1022+
&can_remove_attr.attr,
1023+
NULL
1024+
};
1025+
ATTRIBUTE_GROUPS(overlay_changeset);
1026+
9441027
static struct kobj_type overlay_changeset_ktype = {
9451028
.release = overlay_changeset_release,
1029+
.sysfs_ops = &kobj_sysfs_ops, /* default kobj sysfs ops */
1030+
.default_groups = overlay_changeset_groups,
9461031
};
9471032

9481033
static struct kset *ov_kset;
@@ -1139,7 +1224,15 @@ int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
11391224
if (ret) {
11401225
pr_err("%s: kobject_add() failed for tree@%s\n", __func__,
11411226
ovcs->overlay_root->full_name);
1227+
goto out_unlock;
11421228
}
1229+
1230+
ret = sysfs_create_groups(&ovcs->kobj, ovcs->attr_groups);
1231+
if (ret) {
1232+
pr_err("%s: sysfs_create_groups() failed for tree@%s\n",
1233+
__func__, ovcs->overlay_root->full_name);
1234+
}
1235+
11431236
goto out_unlock;
11441237

11451238
err_free_ovcs:
@@ -1300,6 +1393,9 @@ int of_overlay_remove(int *ovcs_id)
13001393
if (ret)
13011394
goto err_unlock;
13021395

1396+
if (ovcs->kobj.state_in_sysfs)
1397+
sysfs_remove_groups(&ovcs->kobj, ovcs->attr_groups);
1398+
13031399
ret_apply = 0;
13041400
ret = __of_changeset_revert_entries(&ovcs->cset, &ret_apply);
13051401
if (ret) {

0 commit comments

Comments
 (0)