Merge commit 'c0053bd50af5' into omap-for-v4.8/soc
[cascardo/linux.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         debugfs_remove_recursive(debug_dir);
130 }
131
132 /* open ORANGEFS_KMOD_DEBUG_HELP_FILE */
133 static int orangefs_debug_help_open(struct inode *inode, struct file *file)
134 {
135         int rc = -ENODEV;
136         int ret;
137
138         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
139                      "orangefs_debug_help_open: start\n");
140
141         if (orangefs_debug_disabled)
142                 goto out;
143
144         ret = seq_open(file, &help_debug_ops);
145         if (ret)
146                 goto out;
147
148         ((struct seq_file *)(file->private_data))->private = inode->i_private;
149
150         rc = 0;
151
152 out:
153         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
154                      "orangefs_debug_help_open: rc:%d:\n",
155                      rc);
156         return rc;
157 }
158
159 /*
160  * I think start always gets called again after stop. Start
161  * needs to return NULL when it is done. The whole "payload"
162  * in this case is a single (long) string, so by the second
163  * time we get to start (pos = 1), we're done.
164  */
165 static void *help_start(struct seq_file *m, loff_t *pos)
166 {
167         void *payload = NULL;
168
169         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_start: start\n");
170
171         if (*pos == 0)
172                 payload = m->private;
173
174         return payload;
175 }
176
177 static void *help_next(struct seq_file *m, void *v, loff_t *pos)
178 {
179         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_next: start\n");
180
181         return NULL;
182 }
183
184 static void help_stop(struct seq_file *m, void *p)
185 {
186         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_stop: start\n");
187 }
188
189 static int help_show(struct seq_file *m, void *v)
190 {
191         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_show: start\n");
192
193         seq_puts(m, v);
194
195         return 0;
196 }
197
198 /*
199  * initialize the kernel-debug file.
200  */
201 int orangefs_kernel_debug_init(void)
202 {
203         int rc = -ENOMEM;
204         struct dentry *ret;
205         char *k_buffer = NULL;
206
207         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__);
208
209         k_buffer = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
210         if (!k_buffer)
211                 goto out;
212
213         if (strlen(kernel_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) {
214                 strcpy(k_buffer, kernel_debug_string);
215                 strcat(k_buffer, "\n");
216         } else {
217                 strcpy(k_buffer, "none\n");
218                 pr_info("%s: overflow 1!\n", __func__);
219         }
220
221         ret = debugfs_create_file(ORANGEFS_KMOD_DEBUG_FILE,
222                                   0444,
223                                   debug_dir,
224                                   k_buffer,
225                                   &kernel_debug_fops);
226         if (!ret) {
227                 pr_info("%s: failed to create %s.\n",
228                         __func__,
229                         ORANGEFS_KMOD_DEBUG_FILE);
230                 goto out;
231         }
232
233         rc = 0;
234
235 out:
236
237         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: rc:%d:\n", __func__, rc);
238         return rc;
239 }
240
241 /*
242  * initialize the client-debug file.
243  */
244 int orangefs_client_debug_init(void)
245 {
246
247         int rc = -ENOMEM;
248         char *c_buffer = NULL;
249
250         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__);
251
252         c_buffer = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
253         if (!c_buffer)
254                 goto out;
255
256         if (strlen(client_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) {
257                 strcpy(c_buffer, client_debug_string);
258                 strcat(c_buffer, "\n");
259         } else {
260                 strcpy(c_buffer, "none\n");
261                 pr_info("%s: overflow! 2\n", __func__);
262         }
263
264         client_debug_dentry = debugfs_create_file(ORANGEFS_CLIENT_DEBUG_FILE,
265                                                   0444,
266                                                   debug_dir,
267                                                   c_buffer,
268                                                   &kernel_debug_fops);
269         if (!client_debug_dentry) {
270                 pr_info("%s: failed to create updated %s.\n",
271                         __func__,
272                         ORANGEFS_CLIENT_DEBUG_FILE);
273                 goto out;
274         }
275
276         rc = 0;
277
278 out:
279
280         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: rc:%d:\n", __func__, rc);
281         return rc;
282 }
283
284 /* open ORANGEFS_KMOD_DEBUG_FILE or ORANGEFS_CLIENT_DEBUG_FILE.*/
285 int orangefs_debug_open(struct inode *inode, struct file *file)
286 {
287         int rc = -ENODEV;
288
289         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
290                      "%s: orangefs_debug_disabled: %d\n",
291                      __func__,
292                      orangefs_debug_disabled);
293
294         if (orangefs_debug_disabled)
295                 goto out;
296
297         rc = 0;
298         mutex_lock(&orangefs_debug_lock);
299         file->private_data = inode->i_private;
300         mutex_unlock(&orangefs_debug_lock);
301
302 out:
303         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
304                      "orangefs_debug_open: rc: %d\n",
305                      rc);
306         return rc;
307 }
308
309 static ssize_t orangefs_debug_read(struct file *file,
310                                  char __user *ubuf,
311                                  size_t count,
312                                  loff_t *ppos)
313 {
314         char *buf;
315         int sprintf_ret;
316         ssize_t read_ret = -ENOMEM;
317
318         gossip_debug(GOSSIP_DEBUGFS_DEBUG, "orangefs_debug_read: start\n");
319
320         buf = kmalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
321         if (!buf)
322                 goto out;
323
324         mutex_lock(&orangefs_debug_lock);
325         sprintf_ret = sprintf(buf, "%s", (char *)file->private_data);
326         mutex_unlock(&orangefs_debug_lock);
327
328         read_ret = simple_read_from_buffer(ubuf, count, ppos, buf, sprintf_ret);
329
330         kfree(buf);
331
332 out:
333         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
334                      "orangefs_debug_read: ret: %zu\n",
335                      read_ret);
336
337         return read_ret;
338 }
339
340 static ssize_t orangefs_debug_write(struct file *file,
341                                   const char __user *ubuf,
342                                   size_t count,
343                                   loff_t *ppos)
344 {
345         char *buf;
346         int rc = -EFAULT;
347         size_t silly = 0;
348         char *debug_string;
349         struct orangefs_kernel_op_s *new_op = NULL;
350         struct client_debug_mask c_mask = { NULL, 0, 0 };
351
352         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
353                 "orangefs_debug_write: %s\n",
354                 file->f_path.dentry->d_name.name);
355
356         /*
357          * Thwart users who try to jamb a ridiculous number
358          * of bytes into the debug file...
359          */
360         if (count > ORANGEFS_MAX_DEBUG_STRING_LEN + 1) {
361                 silly = count;
362                 count = ORANGEFS_MAX_DEBUG_STRING_LEN + 1;
363         }
364
365         buf = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
366         if (!buf)
367                 goto out;
368
369         if (copy_from_user(buf, ubuf, count - 1)) {
370                 gossip_debug(GOSSIP_DEBUGFS_DEBUG,
371                              "%s: copy_from_user failed!\n",
372                              __func__);
373                 goto out;
374         }
375
376         /*
377          * Map the keyword string from userspace into a valid debug mask.
378          * The mapping process involves mapping the human-inputted string
379          * into a valid mask, and then rebuilding the string from the
380          * verified valid mask.
381          *
382          * A service operation is required to set a new client-side
383          * debug mask.
384          */
385         if (!strcmp(file->f_path.dentry->d_name.name,
386                     ORANGEFS_KMOD_DEBUG_FILE)) {
387                 debug_string_to_mask(buf, &gossip_debug_mask, 0);
388                 debug_mask_to_string(&gossip_debug_mask, 0);
389                 debug_string = kernel_debug_string;
390                 gossip_debug(GOSSIP_DEBUGFS_DEBUG,
391                              "New kernel debug string is %s\n",
392                              kernel_debug_string);
393         } else {
394                 /* Can't reset client debug mask if client is not running. */
395                 if (is_daemon_in_service()) {
396                         pr_info("%s: Client not running :%d:\n",
397                                 __func__,
398                                 is_daemon_in_service());
399                         goto out;
400                 }
401
402                 debug_string_to_mask(buf, &c_mask, 1);
403                 debug_mask_to_string(&c_mask, 1);
404                 debug_string = client_debug_string;
405
406                 new_op = op_alloc(ORANGEFS_VFS_OP_PARAM);
407                 if (!new_op) {
408                         pr_info("%s: op_alloc failed!\n", __func__);
409                         goto out;
410                 }
411
412                 new_op->upcall.req.param.op =
413                         ORANGEFS_PARAM_REQUEST_OP_TWO_MASK_VALUES;
414                 new_op->upcall.req.param.type = ORANGEFS_PARAM_REQUEST_SET;
415                 memset(new_op->upcall.req.param.s_value,
416                        0,
417                        ORANGEFS_MAX_DEBUG_STRING_LEN);
418                 sprintf(new_op->upcall.req.param.s_value,
419                         "%llx %llx\n",
420                         c_mask.mask1,
421                         c_mask.mask2);
422
423                 /* service_operation returns 0 on success... */
424                 rc = service_operation(new_op,
425                                        "orangefs_param",
426                                         ORANGEFS_OP_INTERRUPTIBLE);
427
428                 if (rc)
429                         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
430                                      "%s: service_operation failed! rc:%d:\n",
431                                      __func__,
432                                      rc);
433
434                 op_release(new_op);
435         }
436
437         mutex_lock(&orangefs_debug_lock);
438         memset(file->f_inode->i_private, 0, ORANGEFS_MAX_DEBUG_STRING_LEN);
439         sprintf((char *)file->f_inode->i_private, "%s\n", debug_string);
440         mutex_unlock(&orangefs_debug_lock);
441
442         *ppos += count;
443         if (silly)
444                 rc = silly;
445         else
446                 rc = count;
447
448 out:
449         gossip_debug(GOSSIP_DEBUGFS_DEBUG,
450                      "orangefs_debug_write: rc: %d\n",
451                      rc);
452         kfree(buf);
453         return rc;
454 }