aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/proc_devtree.c
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2006-03-26 22:26:26 -0500
committerPaul Mackerras <paulus@samba.org>2006-03-28 00:45:23 -0500
commit5149fa47ec90eb5e79e28f3a7fbcf29421524817 (patch)
treec22023d68bbe23d273311185e284ead4c45d5edc /fs/proc/proc_devtree.c
parentd0160bf0b3e87032be8e85f80ddd2f18e107b86f (diff)
[PATCH] powerpc: Cope with duplicate node & property names in /proc/device-tree
Various dodgy firmware might give us nodes and/or properties in the device tree with conflicting names. That's generally ok, except for when we export the device tree via /proc, so check when we're creating the proc device tree and munge names accordingly. Tested on a faked device tree with kexec, would be good if someone with actual bogus firmware could try it, but just for completeness. Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'fs/proc/proc_devtree.c')
-rw-r--r--fs/proc/proc_devtree.c103
1 files changed, 80 insertions, 23 deletions
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
index 596b4b4f1cc8..abdf068bc27f 100644
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -52,7 +52,8 @@ static int property_read_proc(char *page, char **start, off_t off,
52 * Add a property to a node 52 * Add a property to a node
53 */ 53 */
54static struct proc_dir_entry * 54static struct proc_dir_entry *
55__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp) 55__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp,
56 const char *name)
56{ 57{
57 struct proc_dir_entry *ent; 58 struct proc_dir_entry *ent;
58 59
@@ -60,14 +61,14 @@ __proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp)
60 * Unfortunately proc_register puts each new entry 61 * Unfortunately proc_register puts each new entry
61 * at the beginning of the list. So we rearrange them. 62 * at the beginning of the list. So we rearrange them.
62 */ 63 */
63 ent = create_proc_read_entry(pp->name, 64 ent = create_proc_read_entry(name,
64 strncmp(pp->name, "security-", 9) 65 strncmp(name, "security-", 9)
65 ? S_IRUGO : S_IRUSR, de, 66 ? S_IRUGO : S_IRUSR, de,
66 property_read_proc, pp); 67 property_read_proc, pp);
67 if (ent == NULL) 68 if (ent == NULL)
68 return NULL; 69 return NULL;
69 70
70 if (!strncmp(pp->name, "security-", 9)) 71 if (!strncmp(name, "security-", 9))
71 ent->size = 0; /* don't leak number of password chars */ 72 ent->size = 0; /* don't leak number of password chars */
72 else 73 else
73 ent->size = pp->length; 74 ent->size = pp->length;
@@ -78,7 +79,7 @@ __proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp)
78 79
79void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop) 80void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop)
80{ 81{
81 __proc_device_tree_add_prop(pde, prop); 82 __proc_device_tree_add_prop(pde, prop, prop->name);
82} 83}
83 84
84void proc_device_tree_remove_prop(struct proc_dir_entry *pde, 85void proc_device_tree_remove_prop(struct proc_dir_entry *pde,
@@ -106,6 +107,69 @@ void proc_device_tree_update_prop(struct proc_dir_entry *pde,
106} 107}
107 108
108/* 109/*
110 * Various dodgy firmware might give us nodes and/or properties with
111 * conflicting names. That's generally ok, except for exporting via /proc,
112 * so munge names here to ensure they're unique.
113 */
114
115static int duplicate_name(struct proc_dir_entry *de, const char *name)
116{
117 struct proc_dir_entry *ent;
118 int found = 0;
119
120 spin_lock(&proc_subdir_lock);
121
122 for (ent = de->subdir; ent != NULL; ent = ent->next) {
123 if (strcmp(ent->name, name) == 0) {
124 found = 1;
125 break;
126 }
127 }
128
129 spin_unlock(&proc_subdir_lock);
130
131 return found;
132}
133
134static const char *fixup_name(struct device_node *np, struct proc_dir_entry *de,
135 const char *name)
136{
137 char *fixed_name;
138 int fixup_len = strlen(name) + 2 + 1; /* name + #x + \0 */
139 int i = 1, size;
140
141realloc:
142 fixed_name = kmalloc(fixup_len, GFP_KERNEL);
143 if (fixed_name == NULL) {
144 printk(KERN_ERR "device-tree: Out of memory trying to fixup "
145 "name \"%s\"\n", name);
146 return name;
147 }
148
149retry:
150 size = snprintf(fixed_name, fixup_len, "%s#%d", name, i);
151 size++; /* account for NULL */
152
153 if (size > fixup_len) {
154 /* We ran out of space, free and reallocate. */
155 kfree(fixed_name);
156 fixup_len = size;
157 goto realloc;
158 }
159
160 if (duplicate_name(de, fixed_name)) {
161 /* Multiple duplicates. Retry with a different offset. */
162 i++;
163 goto retry;
164 }
165
166 printk(KERN_WARNING "device-tree: Duplicate name in %s, "
167 "renamed to \"%s\"\n", np->full_name, fixed_name);
168
169 return fixed_name;
170}
171
172/*
109 * Process a node, adding entries for its children and its properties. 173 * Process a node, adding entries for its children and its properties.
110 */ 174 */
111void proc_device_tree_add_node(struct device_node *np, 175void proc_device_tree_add_node(struct device_node *np,
@@ -118,37 +182,30 @@ void proc_device_tree_add_node(struct device_node *np,
118 182
119 set_node_proc_entry(np, de); 183 set_node_proc_entry(np, de);
120 for (child = NULL; (child = of_get_next_child(np, child));) { 184 for (child = NULL; (child = of_get_next_child(np, child));) {
185 /* Use everything after the last slash, or the full name */
121 p = strrchr(child->full_name, '/'); 186 p = strrchr(child->full_name, '/');
122 if (!p) 187 if (!p)
123 p = child->full_name; 188 p = child->full_name;
124 else 189 else
125 ++p; 190 ++p;
191
192 if (duplicate_name(de, p))
193 p = fixup_name(np, de, p);
194
126 ent = proc_mkdir(p, de); 195 ent = proc_mkdir(p, de);
127 if (ent == 0) 196 if (ent == 0)
128 break; 197 break;
129 proc_device_tree_add_node(child, ent); 198 proc_device_tree_add_node(child, ent);
130 } 199 }
131 of_node_put(child); 200 of_node_put(child);
201
132 for (pp = np->properties; pp != 0; pp = pp->next) { 202 for (pp = np->properties; pp != 0; pp = pp->next) {
133 /* 203 p = pp->name;
134 * Yet another Apple device-tree bogosity: on some machines, 204
135 * they have properties & nodes with the same name. Those 205 if (duplicate_name(de, p))
136 * properties are quite unimportant for us though, thus we 206 p = fixup_name(np, de, p);
137 * simply "skip" them here, but we do have to check.
138 */
139 spin_lock(&proc_subdir_lock);
140 for (ent = de->subdir; ent != NULL; ent = ent->next)
141 if (!strcmp(ent->name, pp->name))
142 break;
143 spin_unlock(&proc_subdir_lock);
144 if (ent != NULL) {
145 printk(KERN_WARNING "device-tree: property \"%s\" name"
146 " conflicts with node in %s\n", pp->name,
147 np->full_name);
148 continue;
149 }
150 207
151 ent = __proc_device_tree_add_prop(de, pp); 208 ent = __proc_device_tree_add_prop(de, pp, p);
152 if (ent == 0) 209 if (ent == 0)
153 break; 210 break;
154 } 211 }