blob: 9b120c3d97036562a0f02eed7c50db42c6440786 [file] [log] [blame]
Lars Ellenberg4d3d5aa2014-05-02 13:19:51 +02001#define pr_fmt(fmt) "drbd debugfs: " fmt
2#include <linux/kernel.h>
3#include <linux/module.h>
4#include <linux/debugfs.h>
5#include <linux/stat.h>
6#include <linux/list.h>
7
8#include "drbd_int.h"
9#include "drbd_req.h"
10#include "drbd_debugfs.h"
11
12static struct dentry *drbd_debugfs_root;
13static struct dentry *drbd_debugfs_resources;
14static struct dentry *drbd_debugfs_minors;
15
16void drbd_debugfs_resource_add(struct drbd_resource *resource)
17{
18 struct dentry *dentry;
19 if (!drbd_debugfs_resources)
20 return;
21
22 dentry = debugfs_create_dir(resource->name, drbd_debugfs_resources);
23 if (IS_ERR_OR_NULL(dentry))
24 goto fail;
25 resource->debugfs_res = dentry;
26
27 dentry = debugfs_create_dir("volumes", resource->debugfs_res);
28 if (IS_ERR_OR_NULL(dentry))
29 goto fail;
30 resource->debugfs_res_volumes = dentry;
31
32 dentry = debugfs_create_dir("connections", resource->debugfs_res);
33 if (IS_ERR_OR_NULL(dentry))
34 goto fail;
35 resource->debugfs_res_connections = dentry;
36
37 return;
38
39fail:
40 drbd_debugfs_resource_cleanup(resource);
41 drbd_err(resource, "failed to create debugfs dentry\n");
42}
43
44static void drbd_debugfs_remove(struct dentry **dp)
45{
46 debugfs_remove(*dp);
47 *dp = NULL;
48}
49
50void drbd_debugfs_resource_cleanup(struct drbd_resource *resource)
51{
52 /* it is ok to call debugfs_remove(NULL) */
53 drbd_debugfs_remove(&resource->debugfs_res_in_flight_summary);
54 drbd_debugfs_remove(&resource->debugfs_res_connections);
55 drbd_debugfs_remove(&resource->debugfs_res_volumes);
56 drbd_debugfs_remove(&resource->debugfs_res);
57}
58
59void drbd_debugfs_connection_add(struct drbd_connection *connection)
60{
61 struct dentry *conns_dir = connection->resource->debugfs_res_connections;
62 struct dentry *dentry;
63 if (!conns_dir)
64 return;
65
66 /* Once we enable mutliple peers,
67 * these connections will have descriptive names.
68 * For now, it is just the one connection to the (only) "peer". */
69 dentry = debugfs_create_dir("peer", conns_dir);
70 if (IS_ERR_OR_NULL(dentry))
71 goto fail;
72 connection->debugfs_conn = dentry;
73 return;
74
75fail:
76 drbd_debugfs_connection_cleanup(connection);
77 drbd_err(connection, "failed to create debugfs dentry\n");
78}
79
80void drbd_debugfs_connection_cleanup(struct drbd_connection *connection)
81{
82 drbd_debugfs_remove(&connection->debugfs_conn_callback_history);
83 drbd_debugfs_remove(&connection->debugfs_conn_oldest_requests);
84 drbd_debugfs_remove(&connection->debugfs_conn);
85}
86
87void drbd_debugfs_device_add(struct drbd_device *device)
88{
89 struct dentry *vols_dir = device->resource->debugfs_res_volumes;
90 char minor_buf[8]; /* MINORMASK, MINORBITS == 20; */
91 char vnr_buf[8]; /* volume number vnr is even 16 bit only; */
92 char *slink_name = NULL;
93
94 struct dentry *dentry;
95 if (!vols_dir || !drbd_debugfs_minors)
96 return;
97
98 snprintf(vnr_buf, sizeof(vnr_buf), "%u", device->vnr);
99 dentry = debugfs_create_dir(vnr_buf, vols_dir);
100 if (IS_ERR_OR_NULL(dentry))
101 goto fail;
102 device->debugfs_vol = dentry;
103
104 snprintf(minor_buf, sizeof(minor_buf), "%u", device->minor);
105 slink_name = kasprintf(GFP_KERNEL, "../resources/%s/volumes/%u",
106 device->resource->name, device->vnr);
107 if (!slink_name)
108 goto fail;
109 dentry = debugfs_create_symlink(minor_buf, drbd_debugfs_minors, slink_name);
110 if (IS_ERR_OR_NULL(dentry))
111 goto fail;
112 device->debugfs_minor = dentry;
113 kfree(slink_name);
114
115fail:
116 drbd_debugfs_device_cleanup(device);
117 drbd_err(device, "failed to create debugfs entries\n");
118}
119
120void drbd_debugfs_device_cleanup(struct drbd_device *device)
121{
122 drbd_debugfs_remove(&device->debugfs_minor);
123 drbd_debugfs_remove(&device->debugfs_vol_oldest_requests);
124 drbd_debugfs_remove(&device->debugfs_vol_act_log_extents);
125 drbd_debugfs_remove(&device->debugfs_vol_resync_extents);
126 drbd_debugfs_remove(&device->debugfs_vol_data_gen_id);
127 drbd_debugfs_remove(&device->debugfs_vol);
128}
129
130void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device)
131{
132 struct dentry *conn_dir = peer_device->connection->debugfs_conn;
133 struct dentry *dentry;
134 char vnr_buf[8];
135
136 if (!conn_dir)
137 return;
138
139 snprintf(vnr_buf, sizeof(vnr_buf), "%u", peer_device->device->vnr);
140 dentry = debugfs_create_dir(vnr_buf, conn_dir);
141 if (IS_ERR_OR_NULL(dentry))
142 goto fail;
143 peer_device->debugfs_peer_dev = dentry;
144 return;
145
146fail:
147 drbd_debugfs_peer_device_cleanup(peer_device);
148 drbd_err(peer_device, "failed to create debugfs entries\n");
149}
150
151void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device)
152{
153 drbd_debugfs_remove(&peer_device->debugfs_peer_dev);
154}
155
156/* not __exit, may be indirectly called
157 * from the module-load-failure path as well. */
158void drbd_debugfs_cleanup(void)
159{
160 drbd_debugfs_remove(&drbd_debugfs_resources);
161 drbd_debugfs_remove(&drbd_debugfs_minors);
162 drbd_debugfs_remove(&drbd_debugfs_root);
163}
164
165int __init drbd_debugfs_init(void)
166{
167 struct dentry *dentry;
168
169 dentry = debugfs_create_dir("drbd", NULL);
170 if (IS_ERR_OR_NULL(dentry))
171 goto fail;
172 drbd_debugfs_root = dentry;
173
174 dentry = debugfs_create_dir("resources", drbd_debugfs_root);
175 if (IS_ERR_OR_NULL(dentry))
176 goto fail;
177 drbd_debugfs_resources = dentry;
178
179 dentry = debugfs_create_dir("minors", drbd_debugfs_root);
180 if (IS_ERR_OR_NULL(dentry))
181 goto fail;
182 drbd_debugfs_minors = dentry;
183 return 0;
184
185fail:
186 drbd_debugfs_cleanup();
187 if (dentry)
188 return PTR_ERR(dentry);
189 else
190 return -EINVAL;
191}