~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to kernel/rcutree_trace.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Read-Copy Update tracing for classic implementation
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
17
 *
 
18
 * Copyright IBM Corporation, 2008
 
19
 *
 
20
 * Papers:  http://www.rdrop.com/users/paulmck/RCU
 
21
 *
 
22
 * For detailed explanation of Read-Copy Update mechanism see -
 
23
 *              Documentation/RCU
 
24
 *
 
25
 */
 
26
#include <linux/types.h>
 
27
#include <linux/kernel.h>
 
28
#include <linux/init.h>
 
29
#include <linux/spinlock.h>
 
30
#include <linux/smp.h>
 
31
#include <linux/rcupdate.h>
 
32
#include <linux/interrupt.h>
 
33
#include <linux/sched.h>
 
34
#include <linux/atomic.h>
 
35
#include <linux/bitops.h>
 
36
#include <linux/module.h>
 
37
#include <linux/completion.h>
 
38
#include <linux/moduleparam.h>
 
39
#include <linux/percpu.h>
 
40
#include <linux/notifier.h>
 
41
#include <linux/cpu.h>
 
42
#include <linux/mutex.h>
 
43
#include <linux/debugfs.h>
 
44
#include <linux/seq_file.h>
 
45
 
 
46
#define RCU_TREE_NONCORE
 
47
#include "rcutree.h"
 
48
 
 
49
#ifdef CONFIG_RCU_BOOST
 
50
 
 
51
static char convert_kthread_status(unsigned int kthread_status)
 
52
{
 
53
        if (kthread_status > RCU_KTHREAD_MAX)
 
54
                return '?';
 
55
        return "SRWOY"[kthread_status];
 
56
}
 
57
 
 
58
#endif /* #ifdef CONFIG_RCU_BOOST */
 
59
 
 
60
static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
 
61
{
 
62
        if (!rdp->beenonline)
 
63
                return;
 
64
        seq_printf(m, "%3d%cc=%lu g=%lu pq=%d pgp=%lu qp=%d",
 
65
                   rdp->cpu,
 
66
                   cpu_is_offline(rdp->cpu) ? '!' : ' ',
 
67
                   rdp->completed, rdp->gpnum,
 
68
                   rdp->passed_quiesce, rdp->passed_quiesce_gpnum,
 
69
                   rdp->qs_pending);
 
70
#ifdef CONFIG_NO_HZ
 
71
        seq_printf(m, " dt=%d/%d/%d df=%lu",
 
72
                   atomic_read(&rdp->dynticks->dynticks),
 
73
                   rdp->dynticks->dynticks_nesting,
 
74
                   rdp->dynticks->dynticks_nmi_nesting,
 
75
                   rdp->dynticks_fqs);
 
76
#endif /* #ifdef CONFIG_NO_HZ */
 
77
        seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi);
 
78
        seq_printf(m, " ql=%ld qs=%c%c%c%c",
 
79
                   rdp->qlen,
 
80
                   ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] !=
 
81
                        rdp->nxttail[RCU_NEXT_TAIL]],
 
82
                   ".R"[rdp->nxttail[RCU_WAIT_TAIL] !=
 
83
                        rdp->nxttail[RCU_NEXT_READY_TAIL]],
 
84
                   ".W"[rdp->nxttail[RCU_DONE_TAIL] !=
 
85
                        rdp->nxttail[RCU_WAIT_TAIL]],
 
86
                   ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]]);
 
87
#ifdef CONFIG_RCU_BOOST
 
88
        seq_printf(m, " kt=%d/%c/%d ktl=%x",
 
89
                   per_cpu(rcu_cpu_has_work, rdp->cpu),
 
90
                   convert_kthread_status(per_cpu(rcu_cpu_kthread_status,
 
91
                                          rdp->cpu)),
 
92
                   per_cpu(rcu_cpu_kthread_cpu, rdp->cpu),
 
93
                   per_cpu(rcu_cpu_kthread_loops, rdp->cpu) & 0xffff);
 
94
#endif /* #ifdef CONFIG_RCU_BOOST */
 
95
        seq_printf(m, " b=%ld", rdp->blimit);
 
96
        seq_printf(m, " ci=%lu co=%lu ca=%lu\n",
 
97
                   rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
 
98
}
 
99
 
 
100
#define PRINT_RCU_DATA(name, func, m) \
 
101
        do { \
 
102
                int _p_r_d_i; \
 
103
                \
 
104
                for_each_possible_cpu(_p_r_d_i) \
 
105
                        func(m, &per_cpu(name, _p_r_d_i)); \
 
106
        } while (0)
 
107
 
 
108
static int show_rcudata(struct seq_file *m, void *unused)
 
109
{
 
110
#ifdef CONFIG_TREE_PREEMPT_RCU
 
111
        seq_puts(m, "rcu_preempt:\n");
 
112
        PRINT_RCU_DATA(rcu_preempt_data, print_one_rcu_data, m);
 
113
#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 
114
        seq_puts(m, "rcu_sched:\n");
 
115
        PRINT_RCU_DATA(rcu_sched_data, print_one_rcu_data, m);
 
116
        seq_puts(m, "rcu_bh:\n");
 
117
        PRINT_RCU_DATA(rcu_bh_data, print_one_rcu_data, m);
 
118
        return 0;
 
119
}
 
120
 
 
121
static int rcudata_open(struct inode *inode, struct file *file)
 
122
{
 
123
        return single_open(file, show_rcudata, NULL);
 
124
}
 
125
 
 
126
static const struct file_operations rcudata_fops = {
 
127
        .owner = THIS_MODULE,
 
128
        .open = rcudata_open,
 
129
        .read = seq_read,
 
130
        .llseek = seq_lseek,
 
131
        .release = single_release,
 
132
};
 
133
 
 
134
static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp)
 
135
{
 
136
        if (!rdp->beenonline)
 
137
                return;
 
138
        seq_printf(m, "%d,%s,%lu,%lu,%d,%lu,%d",
 
139
                   rdp->cpu,
 
140
                   cpu_is_offline(rdp->cpu) ? "\"N\"" : "\"Y\"",
 
141
                   rdp->completed, rdp->gpnum,
 
142
                   rdp->passed_quiesce, rdp->passed_quiesce_gpnum,
 
143
                   rdp->qs_pending);
 
144
#ifdef CONFIG_NO_HZ
 
145
        seq_printf(m, ",%d,%d,%d,%lu",
 
146
                   atomic_read(&rdp->dynticks->dynticks),
 
147
                   rdp->dynticks->dynticks_nesting,
 
148
                   rdp->dynticks->dynticks_nmi_nesting,
 
149
                   rdp->dynticks_fqs);
 
150
#endif /* #ifdef CONFIG_NO_HZ */
 
151
        seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi);
 
152
        seq_printf(m, ",%ld,\"%c%c%c%c\"", rdp->qlen,
 
153
                   ".N"[rdp->nxttail[RCU_NEXT_READY_TAIL] !=
 
154
                        rdp->nxttail[RCU_NEXT_TAIL]],
 
155
                   ".R"[rdp->nxttail[RCU_WAIT_TAIL] !=
 
156
                        rdp->nxttail[RCU_NEXT_READY_TAIL]],
 
157
                   ".W"[rdp->nxttail[RCU_DONE_TAIL] !=
 
158
                        rdp->nxttail[RCU_WAIT_TAIL]],
 
159
                   ".D"[&rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]]);
 
160
#ifdef CONFIG_RCU_BOOST
 
161
        seq_printf(m, ",%d,\"%c\"",
 
162
                   per_cpu(rcu_cpu_has_work, rdp->cpu),
 
163
                   convert_kthread_status(per_cpu(rcu_cpu_kthread_status,
 
164
                                          rdp->cpu)));
 
165
#endif /* #ifdef CONFIG_RCU_BOOST */
 
166
        seq_printf(m, ",%ld", rdp->blimit);
 
167
        seq_printf(m, ",%lu,%lu,%lu\n",
 
168
                   rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
 
169
}
 
170
 
 
171
static int show_rcudata_csv(struct seq_file *m, void *unused)
 
172
{
 
173
        seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pgp\",\"pq\",");
 
174
#ifdef CONFIG_NO_HZ
 
175
        seq_puts(m, "\"dt\",\"dt nesting\",\"dt NMI nesting\",\"df\",");
 
176
#endif /* #ifdef CONFIG_NO_HZ */
 
177
        seq_puts(m, "\"of\",\"ri\",\"ql\",\"qs\"");
 
178
#ifdef CONFIG_RCU_BOOST
 
179
        seq_puts(m, "\"kt\",\"ktl\"");
 
180
#endif /* #ifdef CONFIG_RCU_BOOST */
 
181
        seq_puts(m, ",\"b\",\"ci\",\"co\",\"ca\"\n");
 
182
#ifdef CONFIG_TREE_PREEMPT_RCU
 
183
        seq_puts(m, "\"rcu_preempt:\"\n");
 
184
        PRINT_RCU_DATA(rcu_preempt_data, print_one_rcu_data_csv, m);
 
185
#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 
186
        seq_puts(m, "\"rcu_sched:\"\n");
 
187
        PRINT_RCU_DATA(rcu_sched_data, print_one_rcu_data_csv, m);
 
188
        seq_puts(m, "\"rcu_bh:\"\n");
 
189
        PRINT_RCU_DATA(rcu_bh_data, print_one_rcu_data_csv, m);
 
190
        return 0;
 
191
}
 
192
 
 
193
static int rcudata_csv_open(struct inode *inode, struct file *file)
 
194
{
 
195
        return single_open(file, show_rcudata_csv, NULL);
 
196
}
 
197
 
 
198
static const struct file_operations rcudata_csv_fops = {
 
199
        .owner = THIS_MODULE,
 
200
        .open = rcudata_csv_open,
 
201
        .read = seq_read,
 
202
        .llseek = seq_lseek,
 
203
        .release = single_release,
 
204
};
 
205
 
 
206
#ifdef CONFIG_RCU_BOOST
 
207
 
 
208
static void print_one_rcu_node_boost(struct seq_file *m, struct rcu_node *rnp)
 
209
{
 
210
        seq_printf(m,  "%d:%d tasks=%c%c%c%c kt=%c ntb=%lu neb=%lu nnb=%lu "
 
211
                   "j=%04x bt=%04x\n",
 
212
                   rnp->grplo, rnp->grphi,
 
213
                   "T."[list_empty(&rnp->blkd_tasks)],
 
214
                   "N."[!rnp->gp_tasks],
 
215
                   "E."[!rnp->exp_tasks],
 
216
                   "B."[!rnp->boost_tasks],
 
217
                   convert_kthread_status(rnp->boost_kthread_status),
 
218
                   rnp->n_tasks_boosted, rnp->n_exp_boosts,
 
219
                   rnp->n_normal_boosts,
 
220
                   (int)(jiffies & 0xffff),
 
221
                   (int)(rnp->boost_time & 0xffff));
 
222
        seq_printf(m, "%s: nt=%lu egt=%lu bt=%lu nb=%lu ny=%lu nos=%lu\n",
 
223
                   "     balk",
 
224
                   rnp->n_balk_blkd_tasks,
 
225
                   rnp->n_balk_exp_gp_tasks,
 
226
                   rnp->n_balk_boost_tasks,
 
227
                   rnp->n_balk_notblocked,
 
228
                   rnp->n_balk_notyet,
 
229
                   rnp->n_balk_nos);
 
230
}
 
231
 
 
232
static int show_rcu_node_boost(struct seq_file *m, void *unused)
 
233
{
 
234
        struct rcu_node *rnp;
 
235
 
 
236
        rcu_for_each_leaf_node(&rcu_preempt_state, rnp)
 
237
                print_one_rcu_node_boost(m, rnp);
 
238
        return 0;
 
239
}
 
240
 
 
241
static int rcu_node_boost_open(struct inode *inode, struct file *file)
 
242
{
 
243
        return single_open(file, show_rcu_node_boost, NULL);
 
244
}
 
245
 
 
246
static const struct file_operations rcu_node_boost_fops = {
 
247
        .owner = THIS_MODULE,
 
248
        .open = rcu_node_boost_open,
 
249
        .read = seq_read,
 
250
        .llseek = seq_lseek,
 
251
        .release = single_release,
 
252
};
 
253
 
 
254
/*
 
255
 * Create the rcuboost debugfs entry.  Standard error return.
 
256
 */
 
257
static int rcu_boost_trace_create_file(struct dentry *rcudir)
 
258
{
 
259
        return !debugfs_create_file("rcuboost", 0444, rcudir, NULL,
 
260
                                    &rcu_node_boost_fops);
 
261
}
 
262
 
 
263
#else /* #ifdef CONFIG_RCU_BOOST */
 
264
 
 
265
static int rcu_boost_trace_create_file(struct dentry *rcudir)
 
266
{
 
267
        return 0;  /* There cannot be an error if we didn't create it! */
 
268
}
 
269
 
 
270
#endif /* #else #ifdef CONFIG_RCU_BOOST */
 
271
 
 
272
static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
 
273
{
 
274
        unsigned long gpnum;
 
275
        int level = 0;
 
276
        struct rcu_node *rnp;
 
277
 
 
278
        gpnum = rsp->gpnum;
 
279
        seq_printf(m, "c=%lu g=%lu s=%d jfq=%ld j=%x "
 
280
                      "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu\n",
 
281
                   rsp->completed, gpnum, rsp->signaled,
 
282
                   (long)(rsp->jiffies_force_qs - jiffies),
 
283
                   (int)(jiffies & 0xffff),
 
284
                   rsp->n_force_qs, rsp->n_force_qs_ngp,
 
285
                   rsp->n_force_qs - rsp->n_force_qs_ngp,
 
286
                   rsp->n_force_qs_lh);
 
287
        for (rnp = &rsp->node[0]; rnp - &rsp->node[0] < NUM_RCU_NODES; rnp++) {
 
288
                if (rnp->level != level) {
 
289
                        seq_puts(m, "\n");
 
290
                        level = rnp->level;
 
291
                }
 
292
                seq_printf(m, "%lx/%lx %c%c>%c %d:%d ^%d    ",
 
293
                           rnp->qsmask, rnp->qsmaskinit,
 
294
                           ".G"[rnp->gp_tasks != NULL],
 
295
                           ".E"[rnp->exp_tasks != NULL],
 
296
                           ".T"[!list_empty(&rnp->blkd_tasks)],
 
297
                           rnp->grplo, rnp->grphi, rnp->grpnum);
 
298
        }
 
299
        seq_puts(m, "\n");
 
300
}
 
301
 
 
302
static int show_rcuhier(struct seq_file *m, void *unused)
 
303
{
 
304
#ifdef CONFIG_TREE_PREEMPT_RCU
 
305
        seq_puts(m, "rcu_preempt:\n");
 
306
        print_one_rcu_state(m, &rcu_preempt_state);
 
307
#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 
308
        seq_puts(m, "rcu_sched:\n");
 
309
        print_one_rcu_state(m, &rcu_sched_state);
 
310
        seq_puts(m, "rcu_bh:\n");
 
311
        print_one_rcu_state(m, &rcu_bh_state);
 
312
        return 0;
 
313
}
 
314
 
 
315
static int rcuhier_open(struct inode *inode, struct file *file)
 
316
{
 
317
        return single_open(file, show_rcuhier, NULL);
 
318
}
 
319
 
 
320
static const struct file_operations rcuhier_fops = {
 
321
        .owner = THIS_MODULE,
 
322
        .open = rcuhier_open,
 
323
        .read = seq_read,
 
324
        .llseek = seq_lseek,
 
325
        .release = single_release,
 
326
};
 
327
 
 
328
static void show_one_rcugp(struct seq_file *m, struct rcu_state *rsp)
 
329
{
 
330
        unsigned long flags;
 
331
        unsigned long completed;
 
332
        unsigned long gpnum;
 
333
        unsigned long gpage;
 
334
        unsigned long gpmax;
 
335
        struct rcu_node *rnp = &rsp->node[0];
 
336
 
 
337
        raw_spin_lock_irqsave(&rnp->lock, flags);
 
338
        completed = rsp->completed;
 
339
        gpnum = rsp->gpnum;
 
340
        if (rsp->completed == rsp->gpnum)
 
341
                gpage = 0;
 
342
        else
 
343
                gpage = jiffies - rsp->gp_start;
 
344
        gpmax = rsp->gp_max;
 
345
        raw_spin_unlock_irqrestore(&rnp->lock, flags);
 
346
        seq_printf(m, "%s: completed=%ld  gpnum=%lu  age=%ld  max=%ld\n",
 
347
                   rsp->name, completed, gpnum, gpage, gpmax);
 
348
}
 
349
 
 
350
static int show_rcugp(struct seq_file *m, void *unused)
 
351
{
 
352
#ifdef CONFIG_TREE_PREEMPT_RCU
 
353
        show_one_rcugp(m, &rcu_preempt_state);
 
354
#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 
355
        show_one_rcugp(m, &rcu_sched_state);
 
356
        show_one_rcugp(m, &rcu_bh_state);
 
357
        return 0;
 
358
}
 
359
 
 
360
static int rcugp_open(struct inode *inode, struct file *file)
 
361
{
 
362
        return single_open(file, show_rcugp, NULL);
 
363
}
 
364
 
 
365
static const struct file_operations rcugp_fops = {
 
366
        .owner = THIS_MODULE,
 
367
        .open = rcugp_open,
 
368
        .read = seq_read,
 
369
        .llseek = seq_lseek,
 
370
        .release = single_release,
 
371
};
 
372
 
 
373
static void print_one_rcu_pending(struct seq_file *m, struct rcu_data *rdp)
 
374
{
 
375
        seq_printf(m, "%3d%cnp=%ld "
 
376
                   "qsp=%ld rpq=%ld cbr=%ld cng=%ld "
 
377
                   "gpc=%ld gps=%ld nf=%ld nn=%ld\n",
 
378
                   rdp->cpu,
 
379
                   cpu_is_offline(rdp->cpu) ? '!' : ' ',
 
380
                   rdp->n_rcu_pending,
 
381
                   rdp->n_rp_qs_pending,
 
382
                   rdp->n_rp_report_qs,
 
383
                   rdp->n_rp_cb_ready,
 
384
                   rdp->n_rp_cpu_needs_gp,
 
385
                   rdp->n_rp_gp_completed,
 
386
                   rdp->n_rp_gp_started,
 
387
                   rdp->n_rp_need_fqs,
 
388
                   rdp->n_rp_need_nothing);
 
389
}
 
390
 
 
391
static void print_rcu_pendings(struct seq_file *m, struct rcu_state *rsp)
 
392
{
 
393
        int cpu;
 
394
        struct rcu_data *rdp;
 
395
 
 
396
        for_each_possible_cpu(cpu) {
 
397
                rdp = per_cpu_ptr(rsp->rda, cpu);
 
398
                if (rdp->beenonline)
 
399
                        print_one_rcu_pending(m, rdp);
 
400
        }
 
401
}
 
402
 
 
403
static int show_rcu_pending(struct seq_file *m, void *unused)
 
404
{
 
405
#ifdef CONFIG_TREE_PREEMPT_RCU
 
406
        seq_puts(m, "rcu_preempt:\n");
 
407
        print_rcu_pendings(m, &rcu_preempt_state);
 
408
#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 
409
        seq_puts(m, "rcu_sched:\n");
 
410
        print_rcu_pendings(m, &rcu_sched_state);
 
411
        seq_puts(m, "rcu_bh:\n");
 
412
        print_rcu_pendings(m, &rcu_bh_state);
 
413
        return 0;
 
414
}
 
415
 
 
416
static int rcu_pending_open(struct inode *inode, struct file *file)
 
417
{
 
418
        return single_open(file, show_rcu_pending, NULL);
 
419
}
 
420
 
 
421
static const struct file_operations rcu_pending_fops = {
 
422
        .owner = THIS_MODULE,
 
423
        .open = rcu_pending_open,
 
424
        .read = seq_read,
 
425
        .llseek = seq_lseek,
 
426
        .release = single_release,
 
427
};
 
428
 
 
429
static int show_rcutorture(struct seq_file *m, void *unused)
 
430
{
 
431
        seq_printf(m, "rcutorture test sequence: %lu %s\n",
 
432
                   rcutorture_testseq >> 1,
 
433
                   (rcutorture_testseq & 0x1) ? "(test in progress)" : "");
 
434
        seq_printf(m, "rcutorture update version number: %lu\n",
 
435
                   rcutorture_vernum);
 
436
        return 0;
 
437
}
 
438
 
 
439
static int rcutorture_open(struct inode *inode, struct file *file)
 
440
{
 
441
        return single_open(file, show_rcutorture, NULL);
 
442
}
 
443
 
 
444
static const struct file_operations rcutorture_fops = {
 
445
        .owner = THIS_MODULE,
 
446
        .open = rcutorture_open,
 
447
        .read = seq_read,
 
448
        .llseek = seq_lseek,
 
449
        .release = single_release,
 
450
};
 
451
 
 
452
static struct dentry *rcudir;
 
453
 
 
454
static int __init rcutree_trace_init(void)
 
455
{
 
456
        struct dentry *retval;
 
457
 
 
458
        rcudir = debugfs_create_dir("rcu", NULL);
 
459
        if (!rcudir)
 
460
                goto free_out;
 
461
 
 
462
        retval = debugfs_create_file("rcudata", 0444, rcudir,
 
463
                                                NULL, &rcudata_fops);
 
464
        if (!retval)
 
465
                goto free_out;
 
466
 
 
467
        retval = debugfs_create_file("rcudata.csv", 0444, rcudir,
 
468
                                                NULL, &rcudata_csv_fops);
 
469
        if (!retval)
 
470
                goto free_out;
 
471
 
 
472
        if (rcu_boost_trace_create_file(rcudir))
 
473
                goto free_out;
 
474
 
 
475
        retval = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops);
 
476
        if (!retval)
 
477
                goto free_out;
 
478
 
 
479
        retval = debugfs_create_file("rcuhier", 0444, rcudir,
 
480
                                                NULL, &rcuhier_fops);
 
481
        if (!retval)
 
482
                goto free_out;
 
483
 
 
484
        retval = debugfs_create_file("rcu_pending", 0444, rcudir,
 
485
                                                NULL, &rcu_pending_fops);
 
486
        if (!retval)
 
487
                goto free_out;
 
488
 
 
489
        retval = debugfs_create_file("rcutorture", 0444, rcudir,
 
490
                                                NULL, &rcutorture_fops);
 
491
        if (!retval)
 
492
                goto free_out;
 
493
        return 0;
 
494
free_out:
 
495
        debugfs_remove_recursive(rcudir);
 
496
        return 1;
 
497
}
 
498
 
 
499
static void __exit rcutree_trace_cleanup(void)
 
500
{
 
501
        debugfs_remove_recursive(rcudir);
 
502
}
 
503
 
 
504
 
 
505
module_init(rcutree_trace_init);
 
506
module_exit(rcutree_trace_cleanup);
 
507
 
 
508
MODULE_AUTHOR("Paul E. McKenney");
 
509
MODULE_DESCRIPTION("Read-Copy Update tracing for hierarchical implementation");
 
510
MODULE_LICENSE("GPL");