This commit was manufactured by cvs2svn to create tag 'after-xenU'.
[linux-2.6.git] / fs / relayfs / klog.c
1 /*
2  * KLOG         Generic Logging facility built upon the relayfs infrastructure
3  *
4  * Authors:     Hubertus Franke  (frankeh@us.ibm.com)
5  *              Tom Zanussi  (zanussi@us.ibm.com)
6  *
7  *              Please direct all questions/comments to zanussi@us.ibm.com
8  *
9  *              Copyright (C) 2003, IBM Corp
10  *
11  *              This program is free software; you can redistribute it and/or
12  *              modify it under the terms of the GNU General Public License
13  *              as published by the Free Software Foundation; either version
14  *              2 of the License, or (at your option) any later version.
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/smp_lock.h>
19 #include <linux/console.h>
20 #include <linux/init.h>
21 #include <linux/module.h>
22 #include <linux/config.h>
23 #include <linux/delay.h>
24 #include <linux/smp.h>
25 #include <linux/sysctl.h>
26 #include <linux/relayfs_fs.h>
27 #include <linux/klog.h>
28
29 /* klog channel id */
30 static int klog_channel = -1;
31
32 /* maximum size of klog formatting buffer beyond which truncation will occur */
33 #define KLOG_BUF_SIZE (512)
34 /* per-cpu klog formatting buffer */
35 static char buf[NR_CPUS][KLOG_BUF_SIZE];
36
37 /*
38  *      klog_enabled determines whether klog()/klog_raw() actually do write
39  *      to the klog channel at any given time. If klog_enabled == 1 they do,
40  *      otherwise they don't.  Settable using sysctl fs.relayfs.klog_enabled.
41  */
42 #ifdef CONFIG_KLOG_CHANNEL_AUTOENABLE
43 static int klog_enabled = 1;
44 #else
45 static int klog_enabled = 0;
46 #endif
47
48 /**
49  *      klog - write a formatted string into the klog channel
50  *      @fmt: format string
51  *
52  *      Returns number of bytes written, negative number on failure.
53  */
54 int klog(const char *fmt, ...)
55 {
56         va_list args;
57         int len, err;
58         char *cbuf;
59         unsigned long flags;
60
61         if (!klog_enabled || klog_channel < 0) 
62                 return 0;
63
64         local_irq_save(flags);
65         cbuf = buf[smp_processor_id()];
66
67         va_start(args, fmt);
68         len = vsnprintf(cbuf, KLOG_BUF_SIZE, fmt, args);
69         va_end(args);
70         
71         err = relay_write(klog_channel, cbuf, len, -1, NULL);
72         local_irq_restore(flags);
73
74         return err;
75 }
76
77 /**
78  *      klog_raw - directly write into the klog channel
79  *      @buf: buffer containing data to write
80  *      @len: # bytes to write
81  *
82  *      Returns number of bytes written, negative number on failure.
83  */
84 int klog_raw(const char *buf,int len)
85 {
86         int err = 0;
87         
88         if (klog_enabled && klog_channel >= 0)
89                 err = relay_write(klog_channel, buf, len, -1, NULL);
90
91         return err;
92 }
93
94 /**
95  *      relayfs sysctl data
96  *
97  *      Only sys/fs/relayfs/klog_enabled for now.
98  */
99 #define CTL_ENABLE_KLOG         100
100 #define CTL_RELAYFS             100
101
102 static struct ctl_table_header *relayfs_ctl_table_header;
103
104 static struct ctl_table relayfs_table[] =
105 {
106         {
107                 .ctl_name       = CTL_ENABLE_KLOG,
108                 .procname       = "klog_enabled",
109                 .data           = &klog_enabled,
110                 .maxlen         = sizeof(int),
111                 .mode           = 0644,
112                 .proc_handler   = &proc_dointvec,
113         },
114         {
115                 0
116         }
117 };
118
119 static struct ctl_table relayfs_dir_table[] =
120 {
121         {
122                 .ctl_name       = CTL_RELAYFS,
123                 .procname       = "relayfs",
124                 .data           = NULL,
125                 .maxlen         = 0,
126                 .mode           = 0555,
127                 .child          = relayfs_table,
128         },
129         {
130                 0
131         }
132 };
133
134 static struct ctl_table relayfs_root_table[] =
135 {
136         {
137                 .ctl_name       = CTL_FS,
138                 .procname       = "fs",
139                 .data           = NULL,
140                 .maxlen         = 0,
141                 .mode           = 0555,
142                 .child          = relayfs_dir_table,
143         },
144         {
145                 0
146         }
147 };
148
149 /**
150  *      create_klog_channel - creates channel /mnt/relay/klog
151  *
152  *      Returns channel id on success, negative otherwise.
153  */
154 int 
155 create_klog_channel(void)
156 {
157         u32 bufsize, nbufs;
158         u32 channel_flags;
159
160         channel_flags = RELAY_DELIVERY_PACKET | RELAY_USAGE_GLOBAL;
161         channel_flags |= RELAY_SCHEME_ANY | RELAY_TIMESTAMP_ANY;
162
163         bufsize = 1 << (CONFIG_KLOG_CHANNEL_SHIFT - 2);
164         nbufs = 4;
165
166         klog_channel = relay_open("klog",
167                                   bufsize,
168                                   nbufs,
169                                   channel_flags,
170                                   NULL,
171                                   0,
172                                   0,
173                                   0,
174                                   0,
175                                   0,
176                                   0,
177                                   NULL,
178                                   0);
179
180         if (klog_channel < 0)
181                 printk("klog channel creation failed, errcode: %d\n", klog_channel);
182         else {
183                 printk("klog channel created (%u bytes)\n", 1 << CONFIG_KLOG_CHANNEL_SHIFT);
184                 relayfs_ctl_table_header = register_sysctl_table(relayfs_root_table, 1);
185         }
186
187         return klog_channel;
188 }
189
190 /**
191  *      remove_klog_channel - destroys channel /mnt/relay/klog
192  *
193  *      Returns 0, negative otherwise.
194  */
195 int
196 remove_klog_channel(void)
197 {
198         if (relayfs_ctl_table_header)
199                 unregister_sysctl_table(relayfs_ctl_table_header);
200         
201         return relay_close(klog_channel);
202 }
203
204 EXPORT_SYMBOL(klog);
205 EXPORT_SYMBOL(klog_raw);
206