mmc: s3c6410: enable ADMA feature in 6410 sdhci controller
[safe/jmp/linux-2.6] / kernel / gcov / fs.c
1 /*
2  *  This code exports profiling data as debugfs files to userspace.
3  *
4  *    Copyright IBM Corp. 2009
5  *    Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
6  *
7  *    Uses gcc-internal data definitions.
8  *    Based on the gcov-kernel patch by:
9  *               Hubertus Franke <frankeh@us.ibm.com>
10  *               Nigel Hinds <nhinds@us.ibm.com>
11  *               Rajan Ravindran <rajancr@us.ibm.com>
12  *               Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
13  *               Paul Larson
14  *               Yi CDL Yang
15  */
16
17 #define pr_fmt(fmt)     "gcov: " fmt
18
19 #include <linux/init.h>
20 #include <linux/module.h>
21 #include <linux/debugfs.h>
22 #include <linux/fs.h>
23 #include <linux/list.h>
24 #include <linux/string.h>
25 #include <linux/slab.h>
26 #include <linux/mutex.h>
27 #include <linux/seq_file.h>
28 #include "gcov.h"
29
30 /**
31  * struct gcov_node - represents a debugfs entry
32  * @list: list head for child node list
33  * @children: child nodes
34  * @all: list head for list of all nodes
35  * @parent: parent node
36  * @info: associated profiling data structure if not a directory
37  * @ghost: when an object file containing profiling data is unloaded we keep a
38  *         copy of the profiling data here to allow collecting coverage data
39  *         for cleanup code. Such a node is called a "ghost".
40  * @dentry: main debugfs entry, either a directory or data file
41  * @links: associated symbolic links
42  * @name: data file basename
43  *
44  * struct gcov_node represents an entity within the gcov/ subdirectory
45  * of debugfs. There are directory and data file nodes. The latter represent
46  * the actual synthesized data file plus any associated symbolic links which
47  * are needed by the gcov tool to work correctly.
48  */
49 struct gcov_node {
50         struct list_head list;
51         struct list_head children;
52         struct list_head all;
53         struct gcov_node *parent;
54         struct gcov_info *info;
55         struct gcov_info *ghost;
56         struct dentry *dentry;
57         struct dentry **links;
58         char name[0];
59 };
60
61 static const char objtree[] = OBJTREE;
62 static const char srctree[] = SRCTREE;
63 static struct gcov_node root_node;
64 static struct dentry *reset_dentry;
65 static LIST_HEAD(all_head);
66 static DEFINE_MUTEX(node_lock);
67
68 /* If non-zero, keep copies of profiling data for unloaded modules. */
69 static int gcov_persist = 1;
70
71 static int __init gcov_persist_setup(char *str)
72 {
73         unsigned long val;
74
75         if (strict_strtoul(str, 0, &val)) {
76                 pr_warning("invalid gcov_persist parameter '%s'\n", str);
77                 return 0;
78         }
79         gcov_persist = val;
80         pr_info("setting gcov_persist to %d\n", gcov_persist);
81
82         return 1;
83 }
84 __setup("gcov_persist=", gcov_persist_setup);
85
86 /*
87  * seq_file.start() implementation for gcov data files. Note that the
88  * gcov_iterator interface is designed to be more restrictive than seq_file
89  * (no start from arbitrary position, etc.), to simplify the iterator
90  * implementation.
91  */
92 static void *gcov_seq_start(struct seq_file *seq, loff_t *pos)
93 {
94         loff_t i;
95
96         gcov_iter_start(seq->private);
97         for (i = 0; i < *pos; i++) {
98                 if (gcov_iter_next(seq->private))
99                         return NULL;
100         }
101         return seq->private;
102 }
103
104 /* seq_file.next() implementation for gcov data files. */
105 static void *gcov_seq_next(struct seq_file *seq, void *data, loff_t *pos)
106 {
107         struct gcov_iterator *iter = data;
108
109         if (gcov_iter_next(iter))
110                 return NULL;
111         (*pos)++;
112
113         return iter;
114 }
115
116 /* seq_file.show() implementation for gcov data files. */
117 static int gcov_seq_show(struct seq_file *seq, void *data)
118 {
119         struct gcov_iterator *iter = data;
120
121         if (gcov_iter_write(iter, seq))
122                 return -EINVAL;
123         return 0;
124 }
125
126 static void gcov_seq_stop(struct seq_file *seq, void *data)
127 {
128         /* Unused. */
129 }
130
131 static const struct seq_operations gcov_seq_ops = {
132         .start  = gcov_seq_start,
133         .next   = gcov_seq_next,
134         .show   = gcov_seq_show,
135         .stop   = gcov_seq_stop,
136 };
137
138 /*
139  * Return the profiling data set for a given node. This can either be the
140  * original profiling data structure or a duplicate (also called "ghost")
141  * in case the associated object file has been unloaded.
142  */
143 static struct gcov_info *get_node_info(struct gcov_node *node)
144 {
145         if (node->info)
146                 return node->info;
147
148         return node->ghost;
149 }
150
151 /*
152  * open() implementation for gcov data files. Create a copy of the profiling
153  * data set and initialize the iterator and seq_file interface.
154  */
155 static int gcov_seq_open(struct inode *inode, struct file *file)
156 {
157         struct gcov_node *node = inode->i_private;
158         struct gcov_iterator *iter;
159         struct seq_file *seq;
160         struct gcov_info *info;
161         int rc = -ENOMEM;
162
163         mutex_lock(&node_lock);
164         /*
165          * Read from a profiling data copy to minimize reference tracking
166          * complexity and concurrent access.
167          */
168         info = gcov_info_dup(get_node_info(node));
169         if (!info)
170                 goto out_unlock;
171         iter = gcov_iter_new(info);
172         if (!iter)
173                 goto err_free_info;
174         rc = seq_open(file, &gcov_seq_ops);
175         if (rc)
176                 goto err_free_iter_info;
177         seq = file->private_data;
178         seq->private = iter;
179 out_unlock:
180         mutex_unlock(&node_lock);
181         return rc;
182
183 err_free_iter_info:
184         gcov_iter_free(iter);
185 err_free_info:
186         gcov_info_free(info);
187         goto out_unlock;
188 }
189
190 /*
191  * release() implementation for gcov data files. Release resources allocated
192  * by open().
193  */
194 static int gcov_seq_release(struct inode *inode, struct file *file)
195 {
196         struct gcov_iterator *iter;
197         struct gcov_info *info;
198         struct seq_file *seq;
199
200         seq = file->private_data;
201         iter = seq->private;
202         info = gcov_iter_get_info(iter);
203         gcov_iter_free(iter);
204         gcov_info_free(info);
205         seq_release(inode, file);
206
207         return 0;
208 }
209
210 /*
211  * Find a node by the associated data file name. Needs to be called with
212  * node_lock held.
213  */
214 static struct gcov_node *get_node_by_name(const char *name)
215 {
216         struct gcov_node *node;
217         struct gcov_info *info;
218
219         list_for_each_entry(node, &all_head, all) {
220                 info = get_node_info(node);
221                 if (info && (strcmp(info->filename, name) == 0))
222                         return node;
223         }
224
225         return NULL;
226 }
227
228 static void remove_node(struct gcov_node *node);
229
230 /*
231  * write() implementation for gcov data files. Reset profiling data for the
232  * associated file. If the object file has been unloaded (i.e. this is
233  * a "ghost" node), remove the debug fs node as well.
234  */
235 static ssize_t gcov_seq_write(struct file *file, const char __user *addr,
236                               size_t len, loff_t *pos)
237 {
238         struct seq_file *seq;
239         struct gcov_info *info;
240         struct gcov_node *node;
241
242         seq = file->private_data;
243         info = gcov_iter_get_info(seq->private);
244         mutex_lock(&node_lock);
245         node = get_node_by_name(info->filename);
246         if (node) {
247                 /* Reset counts or remove node for unloaded modules. */
248                 if (node->ghost)
249                         remove_node(node);
250                 else
251                         gcov_info_reset(node->info);
252         }
253         /* Reset counts for open file. */
254         gcov_info_reset(info);
255         mutex_unlock(&node_lock);
256
257         return len;
258 }
259
260 /*
261  * Given a string <path> representing a file path of format:
262  *   path/to/file.gcda
263  * construct and return a new string:
264  *   <dir/>path/to/file.<ext>
265  */
266 static char *link_target(const char *dir, const char *path, const char *ext)
267 {
268         char *target;
269         char *old_ext;
270         char *copy;
271
272         copy = kstrdup(path, GFP_KERNEL);
273         if (!copy)
274                 return NULL;
275         old_ext = strrchr(copy, '.');
276         if (old_ext)
277                 *old_ext = '\0';
278         if (dir)
279                 target = kasprintf(GFP_KERNEL, "%s/%s.%s", dir, copy, ext);
280         else
281                 target = kasprintf(GFP_KERNEL, "%s.%s", copy, ext);
282         kfree(copy);
283
284         return target;
285 }
286
287 /*
288  * Construct a string representing the symbolic link target for the given
289  * gcov data file name and link type. Depending on the link type and the
290  * location of the data file, the link target can either point to a
291  * subdirectory of srctree, objtree or in an external location.
292  */
293 static char *get_link_target(const char *filename, const struct gcov_link *ext)
294 {
295         const char *rel;
296         char *result;
297
298         if (strncmp(filename, objtree, strlen(objtree)) == 0) {
299                 rel = filename + strlen(objtree) + 1;
300                 if (ext->dir == SRC_TREE)
301                         result = link_target(srctree, rel, ext->ext);
302                 else
303                         result = link_target(objtree, rel, ext->ext);
304         } else {
305                 /* External compilation. */
306                 result = link_target(NULL, filename, ext->ext);
307         }
308
309         return result;
310 }
311
312 #define SKEW_PREFIX     ".tmp_"
313
314 /*
315  * For a filename .tmp_filename.ext return filename.ext. Needed to compensate
316  * for filename skewing caused by the mod-versioning mechanism.
317  */
318 static const char *deskew(const char *basename)
319 {
320         if (strncmp(basename, SKEW_PREFIX, sizeof(SKEW_PREFIX) - 1) == 0)
321                 return basename + sizeof(SKEW_PREFIX) - 1;
322         return basename;
323 }
324
325 /*
326  * Create links to additional files (usually .c and .gcno files) which the
327  * gcov tool expects to find in the same directory as the gcov data file.
328  */
329 static void add_links(struct gcov_node *node, struct dentry *parent)
330 {
331         char *basename;
332         char *target;
333         int num;
334         int i;
335
336         for (num = 0; gcov_link[num].ext; num++)
337                 /* Nothing. */;
338         node->links = kcalloc(num, sizeof(struct dentry *), GFP_KERNEL);
339         if (!node->links)
340                 return;
341         for (i = 0; i < num; i++) {
342                 target = get_link_target(get_node_info(node)->filename,
343                                          &gcov_link[i]);
344                 if (!target)
345                         goto out_err;
346                 basename = strrchr(target, '/');
347                 if (!basename)
348                         goto out_err;
349                 basename++;
350                 node->links[i] = debugfs_create_symlink(deskew(basename),
351                                                         parent, target);
352                 if (!node->links[i])
353                         goto out_err;
354                 kfree(target);
355         }
356
357         return;
358 out_err:
359         kfree(target);
360         while (i-- > 0)
361                 debugfs_remove(node->links[i]);
362         kfree(node->links);
363         node->links = NULL;
364 }
365
366 static const struct file_operations gcov_data_fops = {
367         .open           = gcov_seq_open,
368         .release        = gcov_seq_release,
369         .read           = seq_read,
370         .llseek         = seq_lseek,
371         .write          = gcov_seq_write,
372 };
373
374 /* Basic initialization of a new node. */
375 static void init_node(struct gcov_node *node, struct gcov_info *info,
376                       const char *name, struct gcov_node *parent)
377 {
378         INIT_LIST_HEAD(&node->list);
379         INIT_LIST_HEAD(&node->children);
380         INIT_LIST_HEAD(&node->all);
381         node->info = info;
382         node->parent = parent;
383         if (name)
384                 strcpy(node->name, name);
385 }
386
387 /*
388  * Create a new node and associated debugfs entry. Needs to be called with
389  * node_lock held.
390  */
391 static struct gcov_node *new_node(struct gcov_node *parent,
392                                   struct gcov_info *info, const char *name)
393 {
394         struct gcov_node *node;
395
396         node = kzalloc(sizeof(struct gcov_node) + strlen(name) + 1, GFP_KERNEL);
397         if (!node) {
398                 pr_warning("out of memory\n");
399                 return NULL;
400         }
401         init_node(node, info, name, parent);
402         /* Differentiate between gcov data file nodes and directory nodes. */
403         if (info) {
404                 node->dentry = debugfs_create_file(deskew(node->name), 0600,
405                                         parent->dentry, node, &gcov_data_fops);
406         } else
407                 node->dentry = debugfs_create_dir(node->name, parent->dentry);
408         if (!node->dentry) {
409                 pr_warning("could not create file\n");
410                 kfree(node);
411                 return NULL;
412         }
413         if (info)
414                 add_links(node, parent->dentry);
415         list_add(&node->list, &parent->children);
416         list_add(&node->all, &all_head);
417
418         return node;
419 }
420
421 /* Remove symbolic links associated with node. */
422 static void remove_links(struct gcov_node *node)
423 {
424         int i;
425
426         if (!node->links)
427                 return;
428         for (i = 0; gcov_link[i].ext; i++)
429                 debugfs_remove(node->links[i]);
430         kfree(node->links);
431         node->links = NULL;
432 }
433
434 /*
435  * Remove node from all lists and debugfs and release associated resources.
436  * Needs to be called with node_lock held.
437  */
438 static void release_node(struct gcov_node *node)
439 {
440         list_del(&node->list);
441         list_del(&node->all);
442         debugfs_remove(node->dentry);
443         remove_links(node);
444         if (node->ghost)
445                 gcov_info_free(node->ghost);
446         kfree(node);
447 }
448
449 /* Release node and empty parents. Needs to be called with node_lock held. */
450 static void remove_node(struct gcov_node *node)
451 {
452         struct gcov_node *parent;
453
454         while ((node != &root_node) && list_empty(&node->children)) {
455                 parent = node->parent;
456                 release_node(node);
457                 node = parent;
458         }
459 }
460
461 /*
462  * Find child node with given basename. Needs to be called with node_lock
463  * held.
464  */
465 static struct gcov_node *get_child_by_name(struct gcov_node *parent,
466                                            const char *name)
467 {
468         struct gcov_node *node;
469
470         list_for_each_entry(node, &parent->children, list) {
471                 if (strcmp(node->name, name) == 0)
472                         return node;
473         }
474
475         return NULL;
476 }
477
478 /*
479  * write() implementation for reset file. Reset all profiling data to zero
480  * and remove ghost nodes.
481  */
482 static ssize_t reset_write(struct file *file, const char __user *addr,
483                            size_t len, loff_t *pos)
484 {
485         struct gcov_node *node;
486
487         mutex_lock(&node_lock);
488 restart:
489         list_for_each_entry(node, &all_head, all) {
490                 if (node->info)
491                         gcov_info_reset(node->info);
492                 else if (list_empty(&node->children)) {
493                         remove_node(node);
494                         /* Several nodes may have gone - restart loop. */
495                         goto restart;
496                 }
497         }
498         mutex_unlock(&node_lock);
499
500         return len;
501 }
502
503 /* read() implementation for reset file. Unused. */
504 static ssize_t reset_read(struct file *file, char __user *addr, size_t len,
505                           loff_t *pos)
506 {
507         /* Allow read operation so that a recursive copy won't fail. */
508         return 0;
509 }
510
511 static const struct file_operations gcov_reset_fops = {
512         .write  = reset_write,
513         .read   = reset_read,
514 };
515
516 /*
517  * Create a node for a given profiling data set and add it to all lists and
518  * debugfs. Needs to be called with node_lock held.
519  */
520 static void add_node(struct gcov_info *info)
521 {
522         char *filename;
523         char *curr;
524         char *next;
525         struct gcov_node *parent;
526         struct gcov_node *node;
527
528         filename = kstrdup(info->filename, GFP_KERNEL);
529         if (!filename)
530                 return;
531         parent = &root_node;
532         /* Create directory nodes along the path. */
533         for (curr = filename; (next = strchr(curr, '/')); curr = next + 1) {
534                 if (curr == next)
535                         continue;
536                 *next = 0;
537                 if (strcmp(curr, ".") == 0)
538                         continue;
539                 if (strcmp(curr, "..") == 0) {
540                         if (!parent->parent)
541                                 goto err_remove;
542                         parent = parent->parent;
543                         continue;
544                 }
545                 node = get_child_by_name(parent, curr);
546                 if (!node) {
547                         node = new_node(parent, NULL, curr);
548                         if (!node)
549                                 goto err_remove;
550                 }
551                 parent = node;
552         }
553         /* Create file node. */
554         node = new_node(parent, info, curr);
555         if (!node)
556                 goto err_remove;
557 out:
558         kfree(filename);
559         return;
560
561 err_remove:
562         remove_node(parent);
563         goto out;
564 }
565
566 /*
567  * The profiling data set associated with this node is being unloaded. Store a
568  * copy of the profiling data and turn this node into a "ghost".
569  */
570 static int ghost_node(struct gcov_node *node)
571 {
572         node->ghost = gcov_info_dup(node->info);
573         if (!node->ghost) {
574                 pr_warning("could not save data for '%s' (out of memory)\n",
575                            node->info->filename);
576                 return -ENOMEM;
577         }
578         node->info = NULL;
579
580         return 0;
581 }
582
583 /*
584  * Profiling data for this node has been loaded again. Add profiling data
585  * from previous instantiation and turn this node into a regular node.
586  */
587 static void revive_node(struct gcov_node *node, struct gcov_info *info)
588 {
589         if (gcov_info_is_compatible(node->ghost, info))
590                 gcov_info_add(info, node->ghost);
591         else {
592                 pr_warning("discarding saved data for '%s' (version changed)\n",
593                            info->filename);
594         }
595         gcov_info_free(node->ghost);
596         node->ghost = NULL;
597         node->info = info;
598 }
599
600 /*
601  * Callback to create/remove profiling files when code compiled with
602  * -fprofile-arcs is loaded/unloaded.
603  */
604 void gcov_event(enum gcov_action action, struct gcov_info *info)
605 {
606         struct gcov_node *node;
607
608         mutex_lock(&node_lock);
609         node = get_node_by_name(info->filename);
610         switch (action) {
611         case GCOV_ADD:
612                 /* Add new node or revive ghost. */
613                 if (!node) {
614                         add_node(info);
615                         break;
616                 }
617                 if (gcov_persist)
618                         revive_node(node, info);
619                 else {
620                         pr_warning("could not add '%s' (already exists)\n",
621                                    info->filename);
622                 }
623                 break;
624         case GCOV_REMOVE:
625                 /* Remove node or turn into ghost. */
626                 if (!node) {
627                         pr_warning("could not remove '%s' (not found)\n",
628                                    info->filename);
629                         break;
630                 }
631                 if (gcov_persist) {
632                         if (!ghost_node(node))
633                                 break;
634                 }
635                 remove_node(node);
636                 break;
637         }
638         mutex_unlock(&node_lock);
639 }
640
641 /* Create debugfs entries. */
642 static __init int gcov_fs_init(void)
643 {
644         int rc = -EIO;
645
646         init_node(&root_node, NULL, NULL, NULL);
647         /*
648          * /sys/kernel/debug/gcov will be parent for the reset control file
649          * and all profiling files.
650          */
651         root_node.dentry = debugfs_create_dir("gcov", NULL);
652         if (!root_node.dentry)
653                 goto err_remove;
654         /*
655          * Create reset file which resets all profiling counts when written
656          * to.
657          */
658         reset_dentry = debugfs_create_file("reset", 0600, root_node.dentry,
659                                            NULL, &gcov_reset_fops);
660         if (!reset_dentry)
661                 goto err_remove;
662         /* Replay previous events to get our fs hierarchy up-to-date. */
663         gcov_enable_events();
664         return 0;
665
666 err_remove:
667         pr_err("init failed\n");
668         if (root_node.dentry)
669                 debugfs_remove(root_node.dentry);
670
671         return rc;
672 }
673 device_initcall(gcov_fs_init);