Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drbd: debugfs: add basic hierarchy

Add new debugfs hierarchy /sys/kernel/debug/
drbd/
resources/
$resource_name/connections/peer/$volume_number/
$resource_name/volumes/$volume_number/
minors/$minor_number -> ../resources/$resource_name/volumes/$volume_number/

Followup commits will populate this hierarchy with files containing
statistics, diagnostic information and some attribute data.

Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>

authored by

Lars Ellenberg and committed by
Philipp Reisner
4d3d5aa8 4ce49266

+278 -5
+1
drivers/block/drbd/Makefile
··· 3 3 drbd-y += drbd_main.o drbd_strings.o drbd_nl.o 4 4 drbd-y += drbd_interval.o drbd_state.o 5 5 drbd-y += drbd_nla.o 6 + drbd-$(CONFIG_DEBUG_FS) += drbd_debugfs.o 6 7 7 8 obj-$(CONFIG_BLK_DEV_DRBD) += drbd.o
+191
drivers/block/drbd/drbd_debugfs.c
··· 1 + #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 + 12 + static struct dentry *drbd_debugfs_root; 13 + static struct dentry *drbd_debugfs_resources; 14 + static struct dentry *drbd_debugfs_minors; 15 + 16 + void 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 + 39 + fail: 40 + drbd_debugfs_resource_cleanup(resource); 41 + drbd_err(resource, "failed to create debugfs dentry\n"); 42 + } 43 + 44 + static void drbd_debugfs_remove(struct dentry **dp) 45 + { 46 + debugfs_remove(*dp); 47 + *dp = NULL; 48 + } 49 + 50 + void 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 + 59 + void 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 + 75 + fail: 76 + drbd_debugfs_connection_cleanup(connection); 77 + drbd_err(connection, "failed to create debugfs dentry\n"); 78 + } 79 + 80 + void 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 + 87 + void 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 + 115 + fail: 116 + drbd_debugfs_device_cleanup(device); 117 + drbd_err(device, "failed to create debugfs entries\n"); 118 + } 119 + 120 + void 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 + 130 + void 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 + 146 + fail: 147 + drbd_debugfs_peer_device_cleanup(peer_device); 148 + drbd_err(peer_device, "failed to create debugfs entries\n"); 149 + } 150 + 151 + void 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. */ 158 + void 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 + 165 + int __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 + 185 + fail: 186 + drbd_debugfs_cleanup(); 187 + if (dentry) 188 + return PTR_ERR(dentry); 189 + else 190 + return -EINVAL; 191 + }
+39
drivers/block/drbd/drbd_debugfs.h
··· 1 + #include <linux/kernel.h> 2 + #include <linux/module.h> 3 + #include <linux/debugfs.h> 4 + 5 + #include "drbd_int.h" 6 + 7 + #ifdef CONFIG_DEBUG_FS 8 + int __init drbd_debugfs_init(void); 9 + void drbd_debugfs_cleanup(void); 10 + 11 + void drbd_debugfs_resource_add(struct drbd_resource *resource); 12 + void drbd_debugfs_resource_cleanup(struct drbd_resource *resource); 13 + 14 + void drbd_debugfs_connection_add(struct drbd_connection *connection); 15 + void drbd_debugfs_connection_cleanup(struct drbd_connection *connection); 16 + 17 + void drbd_debugfs_device_add(struct drbd_device *device); 18 + void drbd_debugfs_device_cleanup(struct drbd_device *device); 19 + 20 + void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device); 21 + void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device); 22 + #else 23 + 24 + static inline int __init drbd_debugfs_init(void) { return -ENODEV; } 25 + static inline void drbd_debugfs_cleanup(void) { } 26 + 27 + static inline void drbd_debugfs_resource_add(struct drbd_resource *resource) { } 28 + static inline void drbd_debugfs_resource_cleanup(struct drbd_resource *resource) { } 29 + 30 + static inline void drbd_debugfs_connection_add(struct drbd_connection *connection) { } 31 + static inline void drbd_debugfs_connection_cleanup(struct drbd_connection *connection) { } 32 + 33 + static inline void drbd_debugfs_device_add(struct drbd_device *device) { } 34 + static inline void drbd_debugfs_device_cleanup(struct drbd_device *device) { } 35 + 36 + static inline void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device) { } 37 + static inline void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device) { } 38 + 39 + #endif
+28 -2
drivers/block/drbd/drbd_int.h
··· 670 670 671 671 struct drbd_resource { 672 672 char *name; 673 + #ifdef CONFIG_DEBUG_FS 674 + struct dentry *debugfs_res; 675 + struct dentry *debugfs_res_volumes; 676 + struct dentry *debugfs_res_connections; 677 + struct dentry *debugfs_res_in_flight_summary; 678 + #endif 673 679 struct kref kref; 674 680 struct idr devices; /* volume number to device mapping */ 675 681 struct list_head connections; ··· 697 691 struct drbd_connection { 698 692 struct list_head connections; 699 693 struct drbd_resource *resource; 694 + #ifdef CONFIG_DEBUG_FS 695 + struct dentry *debugfs_conn; 696 + struct dentry *debugfs_conn_callback_history; 697 + struct dentry *debugfs_conn_oldest_requests; 698 + #endif 700 699 struct kref kref; 701 700 struct idr peer_devices; /* volume number to peer device mapping */ 702 701 enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */ ··· 783 772 struct list_head peer_devices; 784 773 struct drbd_device *device; 785 774 struct drbd_connection *connection; 775 + #ifdef CONFIG_DEBUG_FS 776 + struct dentry *debugfs_peer_dev; 777 + #endif 786 778 }; 787 779 788 780 struct drbd_device { 789 781 struct drbd_resource *resource; 790 782 struct list_head peer_devices; 791 783 struct list_head pending_bitmap_io; 792 - int vnr; /* volume number within the connection */ 784 + 785 + unsigned long flush_jif; 786 + #ifdef CONFIG_DEBUG_FS 787 + struct dentry *debugfs_minor; 788 + struct dentry *debugfs_vol; 789 + struct dentry *debugfs_vol_oldest_requests; 790 + struct dentry *debugfs_vol_act_log_extents; 791 + struct dentry *debugfs_vol_resync_extents; 792 + struct dentry *debugfs_vol_data_gen_id; 793 + #endif 794 + 795 + unsigned int vnr; /* volume number within the connection */ 796 + unsigned int minor; /* device minor number */ 797 + 793 798 struct kref kref; 794 799 795 800 /* things that are stored as / read from meta data on disk */ ··· 922 895 atomic_t packet_seq; 923 896 unsigned int peer_seq; 924 897 spinlock_t peer_seq_lock; 925 - unsigned int minor; 926 898 unsigned long comm_bm_set; /* communicated number of set bits. */ 927 899 struct bm_io_work bm_io_work; 928 900 u64 ed_uuid; /* UUID of the exposed data */
+19 -3
drivers/block/drbd/drbd_main.c
··· 57 57 #include "drbd_int.h" 58 58 #include "drbd_protocol.h" 59 59 #include "drbd_req.h" /* only for _req_mod in tl_release and tl_clear */ 60 - 61 60 #include "drbd_vli.h" 61 + #include "drbd_debugfs.h" 62 62 63 63 static DEFINE_MUTEX(drbd_main_mutex); 64 64 static int drbd_open(struct block_device *bdev, fmode_t mode); ··· 2308 2308 2309 2309 for_each_connection_safe(connection, tmp, resource) { 2310 2310 list_del(&connection->connections); 2311 + drbd_debugfs_connection_cleanup(connection); 2311 2312 kref_put(&connection->kref, drbd_destroy_connection); 2312 2313 } 2314 + drbd_debugfs_resource_cleanup(resource); 2313 2315 kref_put(&resource->kref, drbd_destroy_resource); 2314 2316 } 2315 2317 ··· 2336 2334 destroy_workqueue(retry.wq); 2337 2335 2338 2336 drbd_genl_unregister(); 2337 + drbd_debugfs_cleanup(); 2339 2338 2340 2339 idr_for_each_entry(&drbd_devices, device, i) 2341 2340 drbd_delete_device(device); ··· 2586 2583 mutex_init(&resource->conf_update); 2587 2584 mutex_init(&resource->adm_mutex); 2588 2585 spin_lock_init(&resource->req_lock); 2586 + drbd_debugfs_resource_add(resource); 2589 2587 return resource; 2590 2588 2591 2589 fail_free_name: ··· 2597 2593 return NULL; 2598 2594 } 2599 2595 2600 - /* caller must be under genl_lock() */ 2596 + /* caller must be under adm_mutex */ 2601 2597 struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts) 2602 2598 { 2603 2599 struct drbd_resource *resource; ··· 2655 2651 2656 2652 kref_get(&resource->kref); 2657 2653 list_add_tail_rcu(&connection->connections, &resource->connections); 2654 + drbd_debugfs_connection_add(connection); 2658 2655 return connection; 2659 2656 2660 2657 fail_resource: ··· 2834 2829 for_each_peer_device(peer_device, device) 2835 2830 drbd_connected(peer_device); 2836 2831 } 2837 - 2832 + /* move to create_peer_device() */ 2833 + for_each_peer_device(peer_device, device) 2834 + drbd_debugfs_peer_device_add(peer_device); 2835 + drbd_debugfs_device_add(device); 2838 2836 return NO_ERROR; 2839 2837 2840 2838 out_idr_remove_vol: ··· 2876 2868 { 2877 2869 struct drbd_resource *resource = device->resource; 2878 2870 struct drbd_connection *connection; 2871 + struct drbd_peer_device *peer_device; 2879 2872 int refs = 3; 2880 2873 2874 + /* move to free_peer_device() */ 2875 + for_each_peer_device(peer_device, device) 2876 + drbd_debugfs_peer_device_cleanup(peer_device); 2877 + drbd_debugfs_device_cleanup(device); 2881 2878 for_each_connection(connection, resource) { 2882 2879 idr_remove(&connection->peer_devices, device->vnr); 2883 2880 refs++; ··· 2950 2937 INIT_WORK(&retry.worker, do_retry); 2951 2938 spin_lock_init(&retry.lock); 2952 2939 INIT_LIST_HEAD(&retry.writes); 2940 + 2941 + if (drbd_debugfs_init()) 2942 + pr_notice("failed to initialize debugfs -- will not be available\n"); 2953 2943 2954 2944 pr_info("initialized. " 2955 2945 "Version: " REL_VERSION " (api:%d/proto:%d-%d)\n",