1 /****************************************************************************** 2 ******************************************************************************* 3 ** 4 ** Copyright (C) 2005 Red Hat, Inc. All rights reserved. 5 ** 6 ** This copyrighted material is made available to anyone wishing to use, 7 ** modify, copy, or redistribute it subject to the terms and conditions 8 ** of the GNU General Public License v.2. 9 ** 10 ******************************************************************************* 11 ******************************************************************************/ 12 13 #include <linux/pagemap.h> 14 #include <linux/seq_file.h> 15 #include <linux/module.h> 16 #include <linux/ctype.h> 17 #include <linux/debugfs.h> 18 19 #include "dlm_internal.h" 20 21 #define DLM_DEBUG_BUF_LEN 4096 22 static char debug_buf[DLM_DEBUG_BUF_LEN]; 23 static struct mutex debug_buf_lock; 24 25 static struct dentry *dlm_root; 26 27 struct rsb_iter { 28 int entry; 29 struct dlm_ls *ls; 30 struct list_head *next; 31 struct dlm_rsb *rsb; 32 }; 33 34 /* 35 * dump all rsb's in the lockspace hash table 36 */ 37 38 static char *print_lockmode(int mode) 39 { 40 switch (mode) { 41 case DLM_LOCK_IV: 42 return "--"; 43 case DLM_LOCK_NL: 44 return "NL"; 45 case DLM_LOCK_CR: 46 return "CR"; 47 case DLM_LOCK_CW: 48 return "CW"; 49 case DLM_LOCK_PR: 50 return "PR"; 51 case DLM_LOCK_PW: 52 return "PW"; 53 case DLM_LOCK_EX: 54 return "EX"; 55 default: 56 return "??"; 57 } 58 } 59 60 static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, 61 struct dlm_rsb *res) 62 { 63 seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode)); 64 65 if (lkb->lkb_status == DLM_LKSTS_CONVERT 66 || lkb->lkb_status == DLM_LKSTS_WAITING) 67 seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode)); 68 69 if (lkb->lkb_nodeid) { 70 if (lkb->lkb_nodeid != res->res_nodeid) 71 seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid, 72 lkb->lkb_remid); 73 else 74 seq_printf(s, " Master: %08x", lkb->lkb_remid); 75 } 76 77 if (lkb->lkb_wait_type) 78 seq_printf(s, " wait_type: %d", lkb->lkb_wait_type); 79 80 seq_printf(s, "\n"); 81 } 82 83 static int print_resource(struct dlm_rsb *res, struct seq_file *s) 84 { 85 struct dlm_lkb *lkb; 86 int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list; 87 88 seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length); 89 for (i = 0; i < res->res_length; i++) { 90 if (isprint(res->res_name[i])) 91 seq_printf(s, "%c", res->res_name[i]); 92 else 93 seq_printf(s, "%c", '.'); 94 } 95 if (res->res_nodeid > 0) 96 seq_printf(s, "\" \nLocal Copy, Master is node %d\n", 97 res->res_nodeid); 98 else if (res->res_nodeid == 0) 99 seq_printf(s, "\" \nMaster Copy\n"); 100 else if (res->res_nodeid == -1) 101 seq_printf(s, "\" \nLooking up master (lkid %x)\n", 102 res->res_first_lkid); 103 else 104 seq_printf(s, "\" \nInvalid master %d\n", res->res_nodeid); 105 106 /* Print the LVB: */ 107 if (res->res_lvbptr) { 108 seq_printf(s, "LVB: "); 109 for (i = 0; i < lvblen; i++) { 110 if (i == lvblen / 2) 111 seq_printf(s, "\n "); 112 seq_printf(s, "%02x ", 113 (unsigned char) res->res_lvbptr[i]); 114 } 115 if (rsb_flag(res, RSB_VALNOTVALID)) 116 seq_printf(s, " (INVALID)"); 117 seq_printf(s, "\n"); 118 } 119 120 root_list = !list_empty(&res->res_root_list); 121 recover_list = !list_empty(&res->res_recover_list); 122 123 if (root_list || recover_list) { 124 seq_printf(s, "Recovery: root %d recover %d flags %lx " 125 "count %d\n", root_list, recover_list, 126 res->res_flags, res->res_recover_locks_count); 127 } 128 129 /* Print the locks attached to this resource */ 130 seq_printf(s, "Granted Queue\n"); 131 list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) 132 print_lock(s, lkb, res); 133 134 seq_printf(s, "Conversion Queue\n"); 135 list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) 136 print_lock(s, lkb, res); 137 138 seq_printf(s, "Waiting Queue\n"); 139 list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) 140 print_lock(s, lkb, res); 141 142 if (list_empty(&res->res_lookup)) 143 goto out; 144 145 seq_printf(s, "Lookup Queue\n"); 146 list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) { 147 seq_printf(s, "%08x %s", lkb->lkb_id, 148 print_lockmode(lkb->lkb_rqmode)); 149 if (lkb->lkb_wait_type) 150 seq_printf(s, " wait_type: %d", lkb->lkb_wait_type); 151 seq_printf(s, "\n"); 152 } 153 out: 154 return 0; 155 } 156 157 static int rsb_iter_next(struct rsb_iter *ri) 158 { 159 struct dlm_ls *ls = ri->ls; 160 int i; 161 162 if (!ri->next) { 163 top: 164 /* Find the next non-empty hash bucket */ 165 for (i = ri->entry; i < ls->ls_rsbtbl_size; i++) { 166 read_lock(&ls->ls_rsbtbl[i].lock); 167 if (!list_empty(&ls->ls_rsbtbl[i].list)) { 168 ri->next = ls->ls_rsbtbl[i].list.next; 169 read_unlock(&ls->ls_rsbtbl[i].lock); 170 break; 171 } 172 read_unlock(&ls->ls_rsbtbl[i].lock); 173 } 174 ri->entry = i; 175 176 if (ri->entry >= ls->ls_rsbtbl_size) 177 return 1; 178 } else { 179 i = ri->entry; 180 read_lock(&ls->ls_rsbtbl[i].lock); 181 ri->next = ri->next->next; 182 if (ri->next->next == ls->ls_rsbtbl[i].list.next) { 183 /* End of list - move to next bucket */ 184 ri->next = NULL; 185 ri->entry++; 186 read_unlock(&ls->ls_rsbtbl[i].lock); 187 goto top; 188 } 189 read_unlock(&ls->ls_rsbtbl[i].lock); 190 } 191 ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain); 192 193 return 0; 194 } 195 196 static void rsb_iter_free(struct rsb_iter *ri) 197 { 198 kfree(ri); 199 } 200 201 static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls) 202 { 203 struct rsb_iter *ri; 204 205 ri = kmalloc(sizeof *ri, GFP_KERNEL); 206 if (!ri) 207 return NULL; 208 209 ri->ls = ls; 210 ri->entry = 0; 211 ri->next = NULL; 212 213 if (rsb_iter_next(ri)) { 214 rsb_iter_free(ri); 215 return NULL; 216 } 217 218 return ri; 219 } 220 221 static void *rsb_seq_start(struct seq_file *file, loff_t *pos) 222 { 223 struct rsb_iter *ri; 224 loff_t n = *pos; 225 226 ri = rsb_iter_init(file->private); 227 if (!ri) 228 return NULL; 229 230 while (n--) { 231 if (rsb_iter_next(ri)) { 232 rsb_iter_free(ri); 233 return NULL; 234 } 235 } 236 237 return ri; 238 } 239 240 static void *rsb_seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos) 241 { 242 struct rsb_iter *ri = iter_ptr; 243 244 (*pos)++; 245 246 if (rsb_iter_next(ri)) { 247 rsb_iter_free(ri); 248 return NULL; 249 } 250 251 return ri; 252 } 253 254 static void rsb_seq_stop(struct seq_file *file, void *iter_ptr) 255 { 256 /* nothing for now */ 257 } 258 259 static int rsb_seq_show(struct seq_file *file, void *iter_ptr) 260 { 261 struct rsb_iter *ri = iter_ptr; 262 263 print_resource(ri->rsb, file); 264 265 return 0; 266 } 267 268 static struct seq_operations rsb_seq_ops = { 269 .start = rsb_seq_start, 270 .next = rsb_seq_next, 271 .stop = rsb_seq_stop, 272 .show = rsb_seq_show, 273 }; 274 275 static int rsb_open(struct inode *inode, struct file *file) 276 { 277 struct seq_file *seq; 278 int ret; 279 280 ret = seq_open(file, &rsb_seq_ops); 281 if (ret) 282 return ret; 283 284 seq = file->private_data; 285 seq->private = inode->i_private; 286 287 return 0; 288 } 289 290 static const struct file_operations rsb_fops = { 291 .owner = THIS_MODULE, 292 .open = rsb_open, 293 .read = seq_read, 294 .llseek = seq_lseek, 295 .release = seq_release 296 }; 297 298 /* 299 * dump lkb's on the ls_waiters list 300 */ 301 302 static int waiters_open(struct inode *inode, struct file *file) 303 { 304 file->private_data = inode->i_private; 305 return 0; 306 } 307 308 static ssize_t waiters_read(struct file *file, char __user *userbuf, 309 size_t count, loff_t *ppos) 310 { 311 struct dlm_ls *ls = file->private_data; 312 struct dlm_lkb *lkb; 313 size_t len = DLM_DEBUG_BUF_LEN, pos = 0, ret, rv; 314 315 mutex_lock(&debug_buf_lock); 316 mutex_lock(&ls->ls_waiters_mutex); 317 memset(debug_buf, 0, sizeof(debug_buf)); 318 319 list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) { 320 ret = snprintf(debug_buf + pos, len - pos, "%x %d %d %s\n", 321 lkb->lkb_id, lkb->lkb_wait_type, 322 lkb->lkb_nodeid, lkb->lkb_resource->res_name); 323 if (ret >= len - pos) 324 break; 325 pos += ret; 326 } 327 mutex_unlock(&ls->ls_waiters_mutex); 328 329 rv = simple_read_from_buffer(userbuf, count, ppos, debug_buf, pos); 330 mutex_unlock(&debug_buf_lock); 331 return rv; 332 } 333 334 static const struct file_operations waiters_fops = { 335 .owner = THIS_MODULE, 336 .open = waiters_open, 337 .read = waiters_read 338 }; 339 340 int dlm_create_debug_file(struct dlm_ls *ls) 341 { 342 char name[DLM_LOCKSPACE_LEN+8]; 343 344 ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name, 345 S_IFREG | S_IRUGO, 346 dlm_root, 347 ls, 348 &rsb_fops); 349 if (!ls->ls_debug_rsb_dentry) 350 return -ENOMEM; 351 352 memset(name, 0, sizeof(name)); 353 snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name); 354 355 ls->ls_debug_waiters_dentry = debugfs_create_file(name, 356 S_IFREG | S_IRUGO, 357 dlm_root, 358 ls, 359 &waiters_fops); 360 if (!ls->ls_debug_waiters_dentry) { 361 debugfs_remove(ls->ls_debug_rsb_dentry); 362 return -ENOMEM; 363 } 364 365 return 0; 366 } 367 368 void dlm_delete_debug_file(struct dlm_ls *ls) 369 { 370 if (ls->ls_debug_rsb_dentry) 371 debugfs_remove(ls->ls_debug_rsb_dentry); 372 if (ls->ls_debug_waiters_dentry) 373 debugfs_remove(ls->ls_debug_waiters_dentry); 374 } 375 376 int dlm_register_debugfs(void) 377 { 378 mutex_init(&debug_buf_lock); 379 dlm_root = debugfs_create_dir("dlm", NULL); 380 return dlm_root ? 0 : -ENOMEM; 381 } 382 383 void dlm_unregister_debugfs(void) 384 { 385 debugfs_remove(dlm_root); 386 } 387 388