]> bbs.cooldavid.org Git - net-next-2.6.git/blob - fs/ceph/debugfs.c
ceph: writeback congestion control
[net-next-2.6.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
82         if (client->osdc.osdmap == NULL)
83                 return 0;
84         seq_printf(s, "epoch %d\n", client->osdc.osdmap->epoch);
85         seq_printf(s, "flags%s%s\n",
86                    (client->osdc.osdmap->flags & CEPH_OSDMAP_NEARFULL) ?
87                    " NEARFULL" : "",
88                    (client->osdc.osdmap->flags & CEPH_OSDMAP_FULL) ?
89                    " FULL" : "");
90         for (i = 0; i < client->osdc.osdmap->num_pools; i++) {
91                 struct ceph_pg_pool_info *pool =
92                         &client->osdc.osdmap->pg_pool[i];
93                 seq_printf(s, "pg_pool %d pg_num %d / %d, lpg_num %d / %d\n",
94                            i, pool->v.pg_num, pool->pg_num_mask,
95                            pool->v.lpg_num, pool->lpg_num_mask);
96         }
97         for (i = 0; i < client->osdc.osdmap->max_osd; i++) {
98                 struct ceph_entity_addr *addr =
99                         &client->osdc.osdmap->osd_addr[i];
100                 int state = client->osdc.osdmap->osd_state[i];
101                 char sb[64];
102
103                 seq_printf(s, "\tosd%d\t%s\t%3d%%\t(%s)\n",
104                            i, pr_addr(&addr->in_addr),
105                            ((client->osdc.osdmap->osd_weight[i]*100) >> 16),
106                            ceph_osdmap_state_str(sb, sizeof(sb), state));
107         }
108         return 0;
109 }
110
111 static int monc_show(struct seq_file *s, void *p)
112 {
113         struct ceph_client *client = s->private;
114         struct ceph_mon_statfs_request *req;
115         u64 nexttid = 0;
116         int got;
117         struct ceph_mon_client *monc = &client->monc;
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         while (nexttid < monc->last_tid) {
129                 got = radix_tree_gang_lookup(&monc->statfs_request_tree,
130                                              (void **)&req, nexttid, 1);
131                 if (got == 0)
132                         break;
133                 nexttid = req->tid + 1;
134
135                 seq_printf(s, "%lld statfs\n", req->tid);
136         }
137         mutex_unlock(&monc->mutex);
138
139         return 0;
140 }
141
142 static int mdsc_show(struct seq_file *s, void *p)
143 {
144         struct ceph_client *client = s->private;
145         struct ceph_mds_request *req;
146         u64 nexttid = 0;
147         int got;
148         struct ceph_mds_client *mdsc = &client->mdsc;
149         int pathlen;
150         u64 pathbase;
151         char *path;
152
153         mutex_lock(&mdsc->mutex);
154         while (nexttid < mdsc->last_tid) {
155                 got = radix_tree_gang_lookup(&mdsc->request_tree,
156                                              (void **)&req, nexttid, 1);
157                 if (got == 0)
158                         break;
159                 nexttid = req->r_tid + 1;
160
161                 if (req->r_request)
162                         seq_printf(s, "%lld\tmds%d\t", req->r_tid, req->r_mds);
163                 else
164                         seq_printf(s, "%lld\t(no request)\t", req->r_tid);
165
166                 seq_printf(s, "%s", ceph_mds_op_name(req->r_op));
167
168                 if (req->r_got_unsafe)
169                         seq_printf(s, "\t(unsafe)");
170                 else
171                         seq_printf(s, "\t");
172
173                 if (req->r_inode) {
174                         seq_printf(s, " #%llx", ceph_ino(req->r_inode));
175                 } else if (req->r_dentry) {
176                         path = ceph_mdsc_build_path(req->r_dentry, &pathlen,
177                                                     &pathbase, 0);
178                         spin_lock(&req->r_dentry->d_lock);
179                         seq_printf(s, " #%llx/%.*s (%s)",
180                                    ceph_ino(req->r_dentry->d_parent->d_inode),
181                                    req->r_dentry->d_name.len,
182                                    req->r_dentry->d_name.name,
183                                    path ? path : "");
184                         spin_unlock(&req->r_dentry->d_lock);
185                         kfree(path);
186                 } else if (req->r_path1) {
187                         seq_printf(s, " #%llx/%s", req->r_ino1.ino,
188                                    req->r_path1);
189                 }
190
191                 if (req->r_old_dentry) {
192                         path = ceph_mdsc_build_path(req->r_old_dentry, &pathlen,
193                                                     &pathbase, 0);
194                         spin_lock(&req->r_old_dentry->d_lock);
195                         seq_printf(s, " #%llx/%.*s (%s)",
196                            ceph_ino(req->r_old_dentry->d_parent->d_inode),
197                                    req->r_old_dentry->d_name.len,
198                                    req->r_old_dentry->d_name.name,
199                                    path ? path : "");
200                         spin_unlock(&req->r_old_dentry->d_lock);
201                         kfree(path);
202                 } else if (req->r_path2) {
203                         if (req->r_ino2.ino)
204                                 seq_printf(s, " #%llx/%s", req->r_ino2.ino,
205                                            req->r_path2);
206                         else
207                                 seq_printf(s, " %s", req->r_path2);
208                 }
209
210                 seq_printf(s, "\n");
211         }
212         mutex_unlock(&mdsc->mutex);
213
214         return 0;
215 }
216
217 static int osdc_show(struct seq_file *s, void *pp)
218 {
219         struct ceph_client *client = s->private;
220         struct ceph_osd_client *osdc = &client->osdc;
221         struct rb_node *p;
222
223         mutex_lock(&osdc->request_mutex);
224         for (p = rb_first(&osdc->requests); p; p = rb_next(p)) {
225                 struct ceph_osd_request *req;
226                 struct ceph_osd_request_head *head;
227                 struct ceph_osd_op *op;
228                 int num_ops;
229                 int opcode, olen;
230                 int i;
231
232                 req = rb_entry(p, struct ceph_osd_request, r_node);
233
234                 seq_printf(s, "%lld\tosd%d\t", req->r_tid,
235                            req->r_osd ? req->r_osd->o_osd : -1);
236
237                 head = req->r_request->front.iov_base;
238                 op = (void *)(head + 1);
239
240                 num_ops = le16_to_cpu(head->num_ops);
241                 olen = le32_to_cpu(head->object_len);
242                 seq_printf(s, "%.*s", olen,
243                            (const char *)(head->ops + num_ops));
244
245                 if (req->r_reassert_version.epoch)
246                         seq_printf(s, "\t%u'%llu",
247                            (unsigned)le32_to_cpu(req->r_reassert_version.epoch),
248                            le64_to_cpu(req->r_reassert_version.version));
249                 else
250                         seq_printf(s, "\t");
251
252                 for (i = 0; i < num_ops; i++) {
253                         opcode = le16_to_cpu(op->op);
254                         seq_printf(s, "\t%s", ceph_osd_op_name(opcode));
255                         op++;
256                 }
257
258                 seq_printf(s, "\n");
259         }
260         mutex_unlock(&osdc->request_mutex);
261         return 0;
262 }
263
264 static int caps_show(struct seq_file *s, void *p)
265 {
266         struct ceph_client *client = p;
267         int total, avail, used, reserved;
268
269         ceph_reservation_status(client, &total, &avail, &used, &reserved);
270         seq_printf(s, "total\t\t%d\n"
271                       "avail\t\t%d\n"
272                       "used\t\t%d\n"
273                       "reserved\t%d\n",
274                    total, avail, used, reserved);
275         return 0;
276 }
277
278 static int dentry_lru_show(struct seq_file *s, void *ptr)
279 {
280         struct ceph_client *client = s->private;
281         struct ceph_mds_client *mdsc = &client->mdsc;
282         struct ceph_dentry_info *di;
283
284         spin_lock(&mdsc->dentry_lru_lock);
285         list_for_each_entry(di, &mdsc->dentry_lru, lru) {
286                 struct dentry *dentry = di->dentry;
287                 seq_printf(s, "%p %p\t%.*s\n",
288                            di, dentry, dentry->d_name.len, dentry->d_name.name);
289         }
290         spin_unlock(&mdsc->dentry_lru_lock);
291
292         return 0;
293 }
294
295 #define DEFINE_SHOW_FUNC(name)                                          \
296 static int name##_open(struct inode *inode, struct file *file)          \
297 {                                                                       \
298         struct seq_file *sf;                                            \
299         int ret;                                                        \
300                                                                         \
301         ret = single_open(file, name, NULL);                            \
302         sf = file->private_data;                                        \
303         sf->private = inode->i_private;                                 \
304         return ret;                                                     \
305 }                                                                       \
306                                                                         \
307 static const struct file_operations name##_fops = {                     \
308         .open           = name##_open,                                  \
309         .read           = seq_read,                                     \
310         .llseek         = seq_lseek,                                    \
311         .release        = single_release,                               \
312 };
313
314 DEFINE_SHOW_FUNC(monmap_show)
315 DEFINE_SHOW_FUNC(mdsmap_show)
316 DEFINE_SHOW_FUNC(osdmap_show)
317 DEFINE_SHOW_FUNC(monc_show)
318 DEFINE_SHOW_FUNC(mdsc_show)
319 DEFINE_SHOW_FUNC(osdc_show)
320 DEFINE_SHOW_FUNC(dentry_lru_show)
321 DEFINE_SHOW_FUNC(caps_show)
322
323 static int congestion_kb_set(void *data, u64 val)
324 {
325         struct ceph_client *client = (struct ceph_client *)data;
326
327         if (client)
328                 client->mount_args->congestion_kb = (int)val;
329
330         return 0;
331 }
332
333 static int congestion_kb_get(void *data, u64 *val)
334 {
335         struct ceph_client *client = (struct ceph_client *)data;
336
337         if (client)
338                 *val = (u64)client->mount_args->congestion_kb;
339
340         return 0;
341 }
342
343
344 DEFINE_SIMPLE_ATTRIBUTE(congestion_kb_fops, congestion_kb_get,
345                         congestion_kb_set, "%llu\n");
346
347 int __init ceph_debugfs_init(void)
348 {
349         ceph_debugfs_dir = debugfs_create_dir("ceph", NULL);
350         if (!ceph_debugfs_dir)
351                 return -ENOMEM;
352         return 0;
353 }
354
355 void ceph_debugfs_cleanup(void)
356 {
357         debugfs_remove(ceph_debugfs_dir);
358 }
359
360 int ceph_debugfs_client_init(struct ceph_client *client)
361 {
362         int ret = 0;
363         char name[80];
364
365         snprintf(name, sizeof(name), FSID_FORMAT ".client%lld",
366                  PR_FSID(&client->fsid), client->monc.auth->global_id);
367
368         client->debugfs_dir = debugfs_create_dir(name, ceph_debugfs_dir);
369         if (!client->debugfs_dir)
370                 goto out;
371
372         client->monc.debugfs_file = debugfs_create_file("monc",
373                                                       0600,
374                                                       client->debugfs_dir,
375                                                       client,
376                                                       &monc_show_fops);
377         if (!client->monc.debugfs_file)
378                 goto out;
379
380         client->mdsc.debugfs_file = debugfs_create_file("mdsc",
381                                                       0600,
382                                                       client->debugfs_dir,
383                                                       client,
384                                                       &mdsc_show_fops);
385         if (!client->mdsc.debugfs_file)
386                 goto out;
387
388         client->osdc.debugfs_file = debugfs_create_file("osdc",
389                                                       0600,
390                                                       client->debugfs_dir,
391                                                       client,
392                                                       &osdc_show_fops);
393         if (!client->osdc.debugfs_file)
394                 goto out;
395
396         client->debugfs_monmap = debugfs_create_file("monmap",
397                                         0600,
398                                         client->debugfs_dir,
399                                         client,
400                                         &monmap_show_fops);
401         if (!client->debugfs_monmap)
402                 goto out;
403
404         client->debugfs_mdsmap = debugfs_create_file("mdsmap",
405                                         0600,
406                                         client->debugfs_dir,
407                                         client,
408                                         &mdsmap_show_fops);
409         if (!client->debugfs_mdsmap)
410                 goto out;
411
412         client->debugfs_osdmap = debugfs_create_file("osdmap",
413                                         0600,
414                                         client->debugfs_dir,
415                                         client,
416                                         &osdmap_show_fops);
417         if (!client->debugfs_osdmap)
418                 goto out;
419
420         client->debugfs_dentry_lru = debugfs_create_file("dentry_lru",
421                                         0600,
422                                         client->debugfs_dir,
423                                         client,
424                                         &dentry_lru_show_fops);
425         if (!client->debugfs_dentry_lru)
426                 goto out;
427
428         client->debugfs_caps = debugfs_create_file("caps",
429                                                    0400,
430                                                    client->debugfs_dir,
431                                                    client,
432                                                    &caps_show_fops);
433         if (!client->debugfs_caps)
434                 goto out;
435
436         client->debugfs_congestion_kb = debugfs_create_file("writeback_congestion_kb",
437                                                    0600,
438                                                    client->debugfs_dir,
439                                                    client,
440                                                    &congestion_kb_fops);
441         if (!client->debugfs_congestion_kb)
442                 goto out;
443
444         sprintf(name, "../../bdi/%s", dev_name(client->sb->s_bdi->dev));
445         client->debugfs_bdi = debugfs_create_symlink("bdi", client->debugfs_dir,
446                                                      name);
447
448         return 0;
449
450 out:
451         ceph_debugfs_client_cleanup(client);
452         return ret;
453 }
454
455 void ceph_debugfs_client_cleanup(struct ceph_client *client)
456 {
457         debugfs_remove(client->debugfs_bdi);
458         debugfs_remove(client->debugfs_caps);
459         debugfs_remove(client->debugfs_dentry_lru);
460         debugfs_remove(client->debugfs_osdmap);
461         debugfs_remove(client->debugfs_mdsmap);
462         debugfs_remove(client->debugfs_monmap);
463         debugfs_remove(client->osdc.debugfs_file);
464         debugfs_remove(client->mdsc.debugfs_file);
465         debugfs_remove(client->monc.debugfs_file);
466         debugfs_remove(client->debugfs_congestion_kb);
467         debugfs_remove(client->debugfs_dir);
468 }
469
470 #else  // CONFIG_DEBUG_FS
471
472 int __init ceph_debugfs_init(void)
473 {
474         return 0;
475 }
476
477 void ceph_debugfs_cleanup(void)
478 {
479 }
480
481 int ceph_debugfs_client_init(struct ceph_client *client)
482 {
483         return 0;
484 }
485
486 void ceph_debugfs_client_cleanup(struct ceph_client *client)
487 {
488 }
489
490 #endif  // CONFIG_DEBUG_FS