Merge branch 'vhost' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[pandora-kernel.git] / fs / ceph / debugfs.c
1 #include "ceph_debug.h"
2
3 #include <linux/device.h>
4 #include <linux/module.h>
5 #include <linux/ctype.h>
6 #include <linux/debugfs.h>
7 #include <linux/seq_file.h>
8
9 #include "super.h"
10 #include "mds_client.h"
11 #include "mon_client.h"
12 #include "auth.h"
13
14 #ifdef CONFIG_DEBUG_FS
15
16 /*
17  * Implement /sys/kernel/debug/ceph fun
18  *
19  * /sys/kernel/debug/ceph/client*  - an instance of the ceph client
20  *      .../osdmap      - current osdmap
21  *      .../mdsmap      - current mdsmap
22  *      .../monmap      - current monmap
23  *      .../osdc        - active osd requests
24  *      .../mdsc        - active mds requests
25  *      .../monc        - mon client state
26  *      .../dentry_lru  - dump contents of dentry lru
27  *      .../caps        - expose cap (reservation) stats
28  *      .../bdi         - symlink to ../../bdi/something
29  */
30
31 static struct dentry *ceph_debugfs_dir;
32
33 static int monmap_show(struct seq_file *s, void *p)
34 {
35         int i;
36         struct ceph_client *client = s->private;
37
38         if (client->monc.monmap == NULL)
39                 return 0;
40
41         seq_printf(s, "epoch %d\n", client->monc.monmap->epoch);
42         for (i = 0; i < client->monc.monmap->num_mon; i++) {
43                 struct ceph_entity_inst *inst =
44                         &client->monc.monmap->mon_inst[i];
45
46                 seq_printf(s, "\t%s%lld\t%s\n",
47                            ENTITY_NAME(inst->name),
48                            pr_addr(&inst->addr.in_addr));
49         }
50         return 0;
51 }
52
53 static int mdsmap_show(struct seq_file *s, void *p)
54 {
55         int i;
56         struct ceph_client *client = s->private;
57
58         if (client->mdsc.mdsmap == NULL)
59                 return 0;
60         seq_printf(s, "epoch %d\n", client->mdsc.mdsmap->m_epoch);
61         seq_printf(s, "root %d\n", client->mdsc.mdsmap->m_root);
62         seq_printf(s, "session_timeout %d\n",
63                        client->mdsc.mdsmap->m_session_timeout);
64         seq_printf(s, "session_autoclose %d\n",
65                        client->mdsc.mdsmap->m_session_autoclose);
66         for (i = 0; i < client->mdsc.mdsmap->m_max_mds; i++) {
67                 struct ceph_entity_addr *addr =
68                         &client->mdsc.mdsmap->m_info[i].addr;
69                 int state = client->mdsc.mdsmap->m_info[i].state;
70
71                 seq_printf(s, "\tmds%d\t%s\t(%s)\n", i, pr_addr(&addr->in_addr),
72                                ceph_mds_state_name(state));
73         }
74         return 0;
75 }
76
77 static int osdmap_show(struct seq_file *s, void *p)
78 {
79         int i;
80         struct ceph_client *client = s->private;
81         struct rb_node *n;
82
83         if (client->osdc.osdmap == NULL)
84                 return 0;
85         seq_printf(s, "epoch %d\n", client->osdc.osdmap->epoch);
86         seq_printf(s, "flags%s%s\n",
87                    (client->osdc.osdmap->flags & CEPH_OSDMAP_NEARFULL) ?
88                    " NEARFULL" : "",
89                    (client->osdc.osdmap->flags & CEPH_OSDMAP_FULL) ?
90                    " FULL" : "");
91         for (n = rb_first(&client->osdc.osdmap->pg_pools); n; n = rb_next(n)) {
92                 struct ceph_pg_pool_info *pool =
93                         rb_entry(n, struct ceph_pg_pool_info, node);
94                 seq_printf(s, "pg_pool %d pg_num %d / %d, lpg_num %d / %d\n",
95                            pool->id, pool->v.pg_num, pool->pg_num_mask,
96                            pool->v.lpg_num, pool->lpg_num_mask);
97         }
98         for (i = 0; i < client->osdc.osdmap->max_osd; i++) {
99                 struct ceph_entity_addr *addr =
100                         &client->osdc.osdmap->osd_addr[i];
101                 int state = client->osdc.osdmap->osd_state[i];
102                 char sb[64];
103
104                 seq_printf(s, "\tosd%d\t%s\t%3d%%\t(%s)\n",
105                            i, pr_addr(&addr->in_addr),
106                            ((client->osdc.osdmap->osd_weight[i]*100) >> 16),
107                            ceph_osdmap_state_str(sb, sizeof(sb), state));
108         }
109         return 0;
110 }
111
112 static int monc_show(struct seq_file *s, void *p)
113 {
114         struct ceph_client *client = s->private;
115         struct ceph_mon_statfs_request *req;
116         struct ceph_mon_client *monc = &client->monc;
117         struct rb_node *rp;
118
119         mutex_lock(&monc->mutex);
120
121         if (monc->have_mdsmap)
122                 seq_printf(s, "have mdsmap %u\n", (unsigned)monc->have_mdsmap);
123         if (monc->have_osdmap)
124                 seq_printf(s, "have osdmap %u\n", (unsigned)monc->have_osdmap);
125         if (monc->want_next_osdmap)
126                 seq_printf(s, "want next osdmap\n");
127
128         for (rp = rb_first(&monc->statfs_request_tree); rp; rp = rb_next(rp)) {
129                 req = rb_entry(rp, struct ceph_mon_statfs_request, node);
130                 seq_printf(s, "%lld statfs\n", req->tid);
131         }
132
133         mutex_unlock(&monc->mutex);
134         return 0;
135 }
136
137 static int mdsc_show(struct seq_file *s, void *p)
138 {
139         struct ceph_client *client = s->private;
140         struct ceph_mds_client *mdsc = &client->mdsc;
141         struct ceph_mds_request *req;
142         struct rb_node *rp;
143         int pathlen;
144         u64 pathbase;
145         char *path;
146
147         mutex_lock(&mdsc->mutex);
148         for (rp = rb_first(&mdsc->request_tree); rp; rp = rb_next(rp)) {
149                 req = rb_entry(rp, struct ceph_mds_request, r_node);
150
151                 if (req->r_request)
152                         seq_printf(s, "%lld\tmds%d\t", req->r_tid, req->r_mds);
153                 else
154                         seq_printf(s, "%lld\t(no request)\t", req->r_tid);
155
156                 seq_printf(s, "%s", ceph_mds_op_name(req->r_op));
157
158                 if (req->r_got_unsafe)
159                         seq_printf(s, "\t(unsafe)");
160                 else
161                         seq_printf(s, "\t");
162
163                 if (req->r_inode) {
164                         seq_printf(s, " #%llx", ceph_ino(req->r_inode));
165                 } else if (req->r_dentry) {
166                         path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
167                                                     &pathbase, 0);
168                         spin_lock(&req->r_dentry->d_lock);
169                         seq_printf(s, " #%llx/%.*s (%s)",
170                                    ceph_ino(req->r_dentry->d_parent->d_inode),
171                                    req->r_dentry->d_name.len,
172                                    req->r_dentry->d_name.name,
173                                    path ? path : "");
174                         spin_unlock(&req->r_dentry->d_lock);
175                         kfree(path);
176                 } else if (req->r_path1) {
177                         seq_printf(s, " #%llx/%s", req->r_ino1.ino,
178                                    req->r_path1);
179                 }
180
181                 if (req->r_old_dentry) {
182                         path = ceph_mdsc_build_path(req->r_old_dentry, &pathlen,
183                                                     &pathbase, 0);
184                         spin_lock(&req->r_old_dentry->d_lock);
185                         seq_printf(s, " #%llx/%.*s (%s)",
186                            ceph_ino(req->r_old_dentry->d_parent->d_inode),
187                                    req->r_old_dentry->d_name.len,
188                                    req->r_old_dentry->d_name.name,
189                                    path ? path : "");
190                         spin_unlock(&req->r_old_dentry->d_lock);
191                         kfree(path);
192                 } else if (req->r_path2) {
193                         if (req->r_ino2.ino)
194                                 seq_printf(s, " #%llx/%s", req->r_ino2.ino,
195                                            req->r_path2);
196                         else
197                                 seq_printf(s, " %s", req->r_path2);
198                 }
199
200                 seq_printf(s, "\n");
201         }
202         mutex_unlock(&mdsc->mutex);
203
204         return 0;
205 }
206
207 static int osdc_show(struct seq_file *s, void *pp)
208 {
209         struct ceph_client *client = s->private;
210         struct ceph_osd_client *osdc = &client->osdc;
211         struct rb_node *p;
212
213         mutex_lock(&osdc->request_mutex);
214         for (p = rb_first(&osdc->requests); p; p = rb_next(p)) {
215                 struct ceph_osd_request *req;
216                 struct ceph_osd_request_head *head;
217                 struct ceph_osd_op *op;
218                 int num_ops;
219                 int opcode, olen;
220                 int i;
221
222                 req = rb_entry(p, struct ceph_osd_request, r_node);
223
224                 seq_printf(s, "%lld\tosd%d\t%d.%x\t", req->r_tid,
225                            req->r_osd ? req->r_osd->o_osd : -1,
226                            le32_to_cpu(req->r_pgid.pool),
227                            le16_to_cpu(req->r_pgid.ps));
228
229                 head = req->r_request->front.iov_base;
230                 op = (void *)(head + 1);
231
232                 num_ops = le16_to_cpu(head->num_ops);
233                 olen = le32_to_cpu(head->object_len);
234                 seq_printf(s, "%.*s", olen,
235                            (const char *)(head->ops + num_ops));
236
237                 if (req->r_reassert_version.epoch)
238                         seq_printf(s, "\t%u'%llu",
239                            (unsigned)le32_to_cpu(req->r_reassert_version.epoch),
240                            le64_to_cpu(req->r_reassert_version.version));
241                 else
242                         seq_printf(s, "\t");
243
244                 for (i = 0; i < num_ops; i++) {
245                         opcode = le16_to_cpu(op->op);
246                         seq_printf(s, "\t%s", ceph_osd_op_name(opcode));
247                         op++;
248                 }
249
250                 seq_printf(s, "\n");
251         }
252         mutex_unlock(&osdc->request_mutex);
253         return 0;
254 }
255
256 static int caps_show(struct seq_file *s, void *p)
257 {
258         struct ceph_client *client = p;
259         int total, avail, used, reserved, min;
260
261         ceph_reservation_status(client, &total, &avail, &used, &reserved, &min);
262         seq_printf(s, "total\t\t%d\n"
263                    "avail\t\t%d\n"
264                    "used\t\t%d\n"
265                    "reserved\t%d\n"
266                    "min\t%d\n",
267                    total, avail, used, reserved, min);
268         return 0;
269 }
270
271 static int dentry_lru_show(struct seq_file *s, void *ptr)
272 {
273         struct ceph_client *client = s->private;
274         struct ceph_mds_client *mdsc = &client->mdsc;
275         struct ceph_dentry_info *di;
276
277         spin_lock(&mdsc->dentry_lru_lock);
278         list_for_each_entry(di, &mdsc->dentry_lru, lru) {
279                 struct dentry *dentry = di->dentry;
280                 seq_printf(s, "%p %p\t%.*s\n",
281                            di, dentry, dentry->d_name.len, dentry->d_name.name);
282         }
283         spin_unlock(&mdsc->dentry_lru_lock);
284
285         return 0;
286 }
287
288 #define DEFINE_SHOW_FUNC(name)                                          \
289 static int name##_open(struct inode *inode, struct file *file)          \
290 {                                                                       \
291         struct seq_file *sf;                                            \
292         int ret;                                                        \
293                                                                         \
294         ret = single_open(file, name, NULL);                            \
295         sf = file->private_data;                                        \
296         sf->private = inode->i_private;                                 \
297         return ret;                                                     \
298 }                                                                       \
299                                                                         \
300 static const struct file_operations name##_fops = {                     \
301         .open           = name##_open,                                  \
302         .read           = seq_read,                                     \
303         .llseek         = seq_lseek,                                    \
304         .release        = single_release,                               \
305 };
306
307 DEFINE_SHOW_FUNC(monmap_show)
308 DEFINE_SHOW_FUNC(mdsmap_show)
309 DEFINE_SHOW_FUNC(osdmap_show)
310 DEFINE_SHOW_FUNC(monc_show)
311 DEFINE_SHOW_FUNC(mdsc_show)
312 DEFINE_SHOW_FUNC(osdc_show)
313 DEFINE_SHOW_FUNC(dentry_lru_show)
314 DEFINE_SHOW_FUNC(caps_show)
315
316 static int congestion_kb_set(void *data, u64 val)
317 {
318         struct ceph_client *client = (struct ceph_client *)data;
319
320         if (client)
321                 client->mount_args->congestion_kb = (int)val;
322
323         return 0;
324 }
325
326 static int congestion_kb_get(void *data, u64 *val)
327 {
328         struct ceph_client *client = (struct ceph_client *)data;
329
330         if (client)
331                 *val = (u64)client->mount_args->congestion_kb;
332
333         return 0;
334 }
335
336
337 DEFINE_SIMPLE_ATTRIBUTE(congestion_kb_fops, congestion_kb_get,
338                         congestion_kb_set, "%llu\n");
339
340 int __init ceph_debugfs_init(void)
341 {
342         ceph_debugfs_dir = debugfs_create_dir("ceph", NULL);
343         if (!ceph_debugfs_dir)
344                 return -ENOMEM;
345         return 0;
346 }
347
348 void ceph_debugfs_cleanup(void)
349 {
350         debugfs_remove(ceph_debugfs_dir);
351 }
352
353 int ceph_debugfs_client_init(struct ceph_client *client)
354 {
355         int ret = 0;
356         char name[80];
357
358         snprintf(name, sizeof(name), FSID_FORMAT ".client%lld",
359                  PR_FSID(&client->fsid), client->monc.auth->global_id);
360
361         client->debugfs_dir = debugfs_create_dir(name, ceph_debugfs_dir);
362         if (!client->debugfs_dir)
363                 goto out;
364
365         client->monc.debugfs_file = debugfs_create_file("monc",
366                                                       0600,
367                                                       client->debugfs_dir,
368                                                       client,
369                                                       &monc_show_fops);
370         if (!client->monc.debugfs_file)
371                 goto out;
372
373         client->mdsc.debugfs_file = debugfs_create_file("mdsc",
374                                                       0600,
375                                                       client->debugfs_dir,
376                                                       client,
377                                                       &mdsc_show_fops);
378         if (!client->mdsc.debugfs_file)
379                 goto out;
380
381         client->osdc.debugfs_file = debugfs_create_file("osdc",
382                                                       0600,
383                                                       client->debugfs_dir,
384                                                       client,
385                                                       &osdc_show_fops);
386         if (!client->osdc.debugfs_file)
387                 goto out;
388
389         client->debugfs_monmap = debugfs_create_file("monmap",
390                                         0600,
391                                         client->debugfs_dir,
392                                         client,
393                                         &monmap_show_fops);
394         if (!client->debugfs_monmap)
395                 goto out;
396
397         client->debugfs_mdsmap = debugfs_create_file("mdsmap",
398                                         0600,
399                                         client->debugfs_dir,
400                                         client,
401                                         &mdsmap_show_fops);
402         if (!client->debugfs_mdsmap)
403                 goto out;
404
405         client->debugfs_osdmap = debugfs_create_file("osdmap",
406                                         0600,
407                                         client->debugfs_dir,
408                                         client,
409                                         &osdmap_show_fops);
410         if (!client->debugfs_osdmap)
411                 goto out;
412
413         client->debugfs_dentry_lru = debugfs_create_file("dentry_lru",
414                                         0600,
415                                         client->debugfs_dir,
416                                         client,
417                                         &dentry_lru_show_fops);
418         if (!client->debugfs_dentry_lru)
419                 goto out;
420
421         client->debugfs_caps = debugfs_create_file("caps",
422                                                    0400,
423                                                    client->debugfs_dir,
424                                                    client,
425                                                    &caps_show_fops);
426         if (!client->debugfs_caps)
427                 goto out;
428
429         client->debugfs_congestion_kb = debugfs_create_file("writeback_congestion_kb",
430                                                    0600,
431                                                    client->debugfs_dir,
432                                                    client,
433                                                    &congestion_kb_fops);
434         if (!client->debugfs_congestion_kb)
435                 goto out;
436
437         sprintf(name, "../../bdi/%s", dev_name(client->sb->s_bdi->dev));
438         client->debugfs_bdi = debugfs_create_symlink("bdi", client->debugfs_dir,
439                                                      name);
440
441         return 0;
442
443 out:
444         ceph_debugfs_client_cleanup(client);
445         return ret;
446 }
447
448 void ceph_debugfs_client_cleanup(struct ceph_client *client)
449 {
450         debugfs_remove(client->debugfs_bdi);
451         debugfs_remove(client->debugfs_caps);
452         debugfs_remove(client->debugfs_dentry_lru);
453         debugfs_remove(client->debugfs_osdmap);
454         debugfs_remove(client->debugfs_mdsmap);
455         debugfs_remove(client->debugfs_monmap);
456         debugfs_remove(client->osdc.debugfs_file);
457         debugfs_remove(client->mdsc.debugfs_file);
458         debugfs_remove(client->monc.debugfs_file);
459         debugfs_remove(client->debugfs_congestion_kb);
460         debugfs_remove(client->debugfs_dir);
461 }
462
463 #else  // CONFIG_DEBUG_FS
464
465 int __init ceph_debugfs_init(void)
466 {
467         return 0;
468 }
469
470 void ceph_debugfs_cleanup(void)
471 {
472 }
473
474 int ceph_debugfs_client_init(struct ceph_client *client)
475 {
476         return 0;
477 }
478
479 void ceph_debugfs_client_cleanup(struct ceph_client *client)
480 {
481 }
482
483 #endif  // CONFIG_DEBUG_FS