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