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 */
5371struct 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
112136static 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
860925err_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+
9441027static 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
9481033static 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
11451238err_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