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