Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
[linux-2.6-block.git] / fs / orangefs / orangefs-debugfs.c
1 /*
2  * What:                /sys/kernel/debug/orangefs/debug-help
3  * Date:                June 2015
4  * Contact:             Mike Marshall <hubcap@omnibond.com>
5  * Description:
6  *                      List of client and kernel debug keywords.
7  *
8  *
9  * What:                /sys/kernel/debug/orangefs/client-debug
10  * Date:                June 2015
11  * Contact:             Mike Marshall <hubcap@omnibond.com>
12  * Description:
13  *                      Debug setting for "the client", the userspace
14  *                      helper for the kernel module.
15  *
16  *
17  * What:                /sys/kernel/debug/orangefs/kernel-debug
18  * Date:                June 2015
19  * Contact:             Mike Marshall <hubcap@omnibond.com>
20  * Description:
21  *                      Debug setting for the orangefs kernel module.
22  *
23  *                      Any of the keywords, or comma-separated lists
24  *                      of keywords, from debug-help can be catted to
25  *                      client-debug or kernel-debug.
26  *
27  *                      "none", "all" and "verbose" are special keywords
28  *                      for client-debug. Setting client-debug to "all"
29  *                      is kind of like trying to drink water from a
30  *                      fire hose, "verbose" triggers most of the same
31  *                      output except for the constant flow of output
32  *                      from the main wait loop.
33  *
34  *                      "none" and "all" are similar settings for kernel-debug
35  *                      no need for a "verbose".
36  */
37 #include <linux/debugfs.h>
38 #include <linux/slab.h>
39
40 #include <linux/uaccess.h>
41
42 #include "orangefs-debugfs.h"
43 #include "protocol.h"
44 #include "orangefs-kernel.h"
45
46 static int orangefs_debug_disabled = 1;
47
48 static int orangefs_debug_help_open(struct inode *, struct file *);
49
50 const struct file_operations debug_help_fops = {
51         .open           = orangefs_debug_help_open,
52         .read           = seq_read,
53         .release        = seq_release,
54         .llseek         = seq_lseek,
55 };
56
57 static void *help_start(struct seq_file *, loff_t *);
58 static void *help_next(struct seq_file *, void *, loff_t *);
59 static void help_stop(struct seq_file *, void *);
60 static int help_show(struct seq_file *, void *);
61
62 static const struct seq_operations help_debug_ops = {
63         .start  = help_start,
64         .next   = help_next,
65         .stop   = help_stop,
66         .show   = help_show,
67 };
68
69 /*
70  * Used to protect data in ORANGEFS_KMOD_DEBUG_FILE and
71  * ORANGEFS_KMOD_DEBUG_FILE.
72  */
73 static DEFINE_MUTEX(orangefs_debug_lock);
74
75 int orangefs_debug_open(struct inode *, struct file *);
76
77 static ssize_t orangefs_debug_read(struct file *,
78                                  char __user *,
79                                  size_t,
80                                  loff_t *);
81
82 static ssize_t orangefs_debug_write(struct file *,
83                                   const char __user *,
84                                   size_t,
85                                   loff_t *);
86
87 static const struct file_operations kernel_debug_fops = {
88         .open           = orangefs_debug_open,
89         .read           = orangefs_debug_read,
90         .write          = orangefs_debug_write,
91         .llseek         = generic_file_llseek,
92 };
93
94 /*
95  * initialize kmod debug operations, create orangefs debugfs dir and
96  * ORANGEFS_KMOD_DEBUG_HELP_FILE.
97  */
98 int orangefs_debugfs_init(void)
99 {
100
101         int rc = -ENOMEM;
102
103         debug_dir = debugfs_create_dir("orangefs", NULL);
104         if (!debug_dir) {
105                 pr_info("%s: debugfs_create_dir failed.\n", __func__);
106                 goto out;
107         }
108
109         help_file_dentry = debugfs_create_file(ORANGEFS_KMOD_DEBUG_HELP_FILE,
110                                   0444,
111                                   debug_dir,
112                                   debug_help_string,
113                                   &debug_help_fops);
114         if (!help_file_dentry) {
115                 pr_info("%s: debugfs_create_file failed.\n", __func__);
116                 goto out;
117         }
118
119         orangefs_debug_disabled = 0;
120         rc = 0;
121
122 out:
123
124         return rc;
125 }
126
127 void orangefs_debugfs_cleanup(void)
128 {
129         if (debug_dir)
130                 debugfs_remove_recursive(debug_dir);
131 }
132
133 /* open ORANGEFS_KMOD_DEBUG_HELP_FILE */
134 static int orangefs_debug_help_open(struct inode *inode, struct file *file)
135 {
136         int rc = -ENODEV;
137         int ret;
138
139         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
140                      "orangefs_debug_help_open: start\n");
141
142         if (orangefs_debug_disabled)
143                 goto out;
144
145         ret = seq_open(file, &help_debug_ops);
146         if (ret)
147                 goto out;
148
149         ((struct seq_file *)(file->private_data))->private = inode->i_private;
150
151         rc = 0;
152
153 out:
154         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
155                      "orangefs_debug_help_open: rc:%d:\n",
156                      rc);
157         return rc;
158 }
159
160 /*
161  * I think start always gets called again after stop. Start
162  * needs to return NULL when it is done. The whole "payload"
163  * in this case is a single (long) string, so by the second
164  * time we get to start (pos = 1), we're done.
165  */
166 static void *help_start(struct seq_file *m, loff_t *pos)
167 {
168         void *payload = NULL;
169
170         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_start: start\n");
171
172         if (*pos == 0)
173                 payload = m->private;
174
175         return payload;
176 }
177
178 static void *help_next(struct seq_file *m, void *v, loff_t *pos)
179 {
180         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_next: start\n");
181
182         return NULL;
183 }
184
185 static void help_stop(struct seq_file *m, void *p)
186 {
187         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_stop: start\n");
188 }
189
190 static int help_show(struct seq_file *m, void *v)
191 {
192         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_show: start\n");
193
194         seq_puts(m, v);
195
196         return 0;
197 }
198
199 /*
200  * initialize the kernel-debug file.
201  */
202 int orangefs_kernel_debug_init(void)
203 {
204         int rc = -ENOMEM;
205         struct dentry *ret;
206         char *k_buffer = NULL;
207
208         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__);
209
210         k_buffer = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
211         if (!k_buffer)
212                 goto out;
213
214         if (strlen(kernel_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) {
215                 strcpy(k_buffer, kernel_debug_string);
216                 strcat(k_buffer, "\n");
217         } else {
218                 strcpy(k_buffer, "none\n");
219                 pr_info("%s: overflow 1!\n", __func__);
220         }
221
222         ret = debugfs_create_file(ORANGEFS_KMOD_DEBUG_FILE,
223                                   0444,
224                                   debug_dir,
225                                   k_buffer,
226                                   &kernel_debug_fops);
227         if (!ret) {
228                 pr_info("%s: failed to create %s.\n",
229                         __func__,
230                         ORANGEFS_KMOD_DEBUG_FILE);
231                 goto out;
232         }
233
234         rc = 0;
235
236 out:
237
238         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: rc:%d:\n", __func__, rc);
239         return rc;
240 }
241
242 /*
243  * initialize the client-debug file.
244  */
245 int orangefs_client_debug_init(void)
246 {
247
248         int rc = -ENOMEM;
249         char *c_buffer = NULL;
250
251         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__);
252
253         c_buffer = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
254         if (!c_buffer)
255                 goto out;
256
257         if (strlen(client_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) {
258                 strcpy(c_buffer, client_debug_string);
259                 strcat(c_buffer, "\n");
260         } else {
261                 strcpy(c_buffer, "none\n");
262                 pr_info("%s: overflow! 2\n", __func__);
263         }
264
265         client_debug_dentry = debugfs_create_file(ORANGEFS_CLIENT_DEBUG_FILE,
266                                                   0444,
267                                                   debug_dir,
268                                                   c_buffer,
269                                                   &kernel_debug_fops);
270         if (!client_debug_dentry) {
271                 pr_info("%s: failed to create updated %s.\n",
272                         __func__,
273                         ORANGEFS_CLIENT_DEBUG_FILE);
274                 goto out;
275         }
276
277         rc = 0;
278
279 out:
280
281         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: rc:%d:\n", __func__, rc);
282         return rc;
283 }
284
285 /* open ORANGEFS_KMOD_DEBUG_FILE or ORANGEFS_CLIENT_DEBUG_FILE.*/
286 int orangefs_debug_open(struct inode *inode, struct file *file)
287 {
288         int rc = -ENODEV;
289
290         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
291                      "%s: orangefs_debug_disabled: %d\n",
292                      __func__,
293                      orangefs_debug_disabled);
294
295         if (orangefs_debug_disabled)
296                 goto out;
297
298         rc = 0;
299         mutex_lock(&orangefs_debug_lock);
300         file->private_data = inode->i_private;
301         mutex_unlock(&orangefs_debug_lock);
302
303 out:
304         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
305                      "orangefs_debug_open: rc: %d\n",
306                      rc);
307         return rc;
308 }
309
310 static ssize_t orangefs_debug_read(struct file *file,
311                                  char __user *ubuf,
312                                  size_t count,
313                                  loff_t *ppos)
314 {
315         char *buf;
316         int sprintf_ret;
317         ssize_t read_ret = -ENOMEM;
318
319         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "orangefs_debug_read: start\n");
320
321         buf = kmalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
322         if (!buf)
323                 goto out;
324
325         mutex_lock(&orangefs_debug_lock);
326         sprintf_ret = sprintf(buf, "%s", (char *)file->private_data);
327         mutex_unlock(&orangefs_debug_lock);
328
329         read_ret = simple_read_from_buffer(ubuf, count, ppos, buf, sprintf_ret);
330
331         kfree(buf);
332
333 out:
334         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
335                      "orangefs_debug_read: ret: %zu\n",
336                      read_ret);
337
338         return read_ret;
339 }
340
341 static ssize_t orangefs_debug_write(struct file *file,
342                                   const char __user *ubuf,
343                                   size_t count,
344                                   loff_t *ppos)
345 {
346         char *buf;
347         int rc = -EFAULT;
348         size_t silly = 0;
349         char *debug_string;
350         struct orangefs_kernel_op_s *new_op = NULL;
351         struct client_debug_mask c_mask = { NULL, 0, 0 };
352
353         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
354                 "orangefs_debug_write: %s\n",
355                 file->f_path.dentry->d_name.name);
356
357         /*
358          * Thwart users who try to jamb a ridiculous number
359          * of bytes into the debug file...
360          */
361         if (count > ORANGEFS_MAX_DEBUG_STRING_LEN + 1) {
362                 silly = count;
363                 count = ORANGEFS_MAX_DEBUG_STRING_LEN + 1;
364         }
365
366         buf = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
367         if (!buf)
368                 goto out;
369
370         if (copy_from_user(buf, ubuf, count - 1)) {
371                 gossip_debug(GOSSIP_DEBUGFS_DEBUG,
372                              "%s: copy_from_user failed!\n",
373                              __func__);
374                 goto out;
375         }
376
377         /*
378          * Map the keyword string from userspace into a valid debug mask.
379          * The mapping process involves mapping the human-inputted string
380          * into a valid mask, and then rebuilding the string from the
381          * verified valid mask.
382          *
383          * A service operation is required to set a new client-side
384          * debug mask.
385          */
386         if (!strcmp(file->f_path.dentry->d_name.name,
387                     ORANGEFS_KMOD_DEBUG_FILE)) {
388                 debug_string_to_mask(buf, &gossip_debug_mask, 0);
389                 debug_mask_to_string(&gossip_debug_mask, 0);
390                 debug_string = kernel_debug_string;
391                 gossip_debug(GOSSIP_DEBUGFS_DEBUG,
392                              "New kernel debug string is %s\n",
393                              kernel_debug_string);
394         } else {
395                 /* Can't reset client debug mask if client is not running. */
396                 if (is_daemon_in_service()) {
397                         pr_info("%s: Client not running :%d:\n",
398                                 __func__,
399                                 is_daemon_in_service());
400                         goto out;
401                 }
402
403                 debug_string_to_mask(buf, &c_mask, 1);
404                 debug_mask_to_string(&c_mask, 1);
405                 debug_string = client_debug_string;
406
407                 new_op = op_alloc(ORANGEFS_VFS_OP_PARAM);
408                 if (!new_op) {
409                         pr_info("%s: op_alloc failed!\n", __func__);
410                         goto out;
411                 }
412
413                 new_op->upcall.req.param.op =
414                         ORANGEFS_PARAM_REQUEST_OP_TWO_MASK_VALUES;
415                 new_op->upcall.req.param.type = ORANGEFS_PARAM_REQUEST_SET;
416                 memset(new_op->upcall.req.param.s_value,
417                        0,
418                        ORANGEFS_MAX_DEBUG_STRING_LEN);
419                 sprintf(new_op->upcall.req.param.s_value,
420                         "%llx %llx\n",
421                         c_mask.mask1,
422                         c_mask.mask2);
423
424                 /* service_operation returns 0 on success... */
425                 rc = service_operation(new_op,
426                                        "orangefs_param",
427                                         ORANGEFS_OP_INTERRUPTIBLE);
428
429                 if (rc)
430                         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
431                                      "%s: service_operation failed! rc:%d:\n",
432                                      __func__,
433                                      rc);
434
435                 op_release(new_op);
436         }
437
438         mutex_lock(&orangefs_debug_lock);
439         memset(file->f_inode->i_private, 0, ORANGEFS_MAX_DEBUG_STRING_LEN);
440         sprintf((char *)file->f_inode->i_private, "%s\n", debug_string);
441         mutex_unlock(&orangefs_debug_lock);
442
443         *ppos += count;
444         if (silly)
445                 rc = silly;
446         else
447                 rc = count;
448
449 out:
450         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
451                      "orangefs_debug_write: rc: %d\n",
452                      rc);
453         kfree(buf);
454         return rc;
455 }