825 lines · 19.3 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/*****************************************************************************************************************************************************************  Copyright (C) 2005-2009 Red Hat, Inc.  All rights reserved.*****************************************************************************************************************************************************************/ #include <linux/pagemap.h>#include <linux/seq_file.h>#include <linux/init.h>#include <linux/ctype.h>#include <linux/debugfs.h>#include <linux/slab.h> #include "dlm_internal.h"#include "midcomms.h"#include "lock.h"#include "ast.h" #define DLM_DEBUG_BUF_LEN 4096static char debug_buf[DLM_DEBUG_BUF_LEN];static struct mutex debug_buf_lock; static struct dentry *dlm_root;static struct dentry *dlm_comms; static char *print_lockmode(int mode){	switch (mode) {	case DLM_LOCK_IV:		return "--";	case DLM_LOCK_NL:		return "NL";	case DLM_LOCK_CR:		return "CR";	case DLM_LOCK_CW:		return "CW";	case DLM_LOCK_PR:		return "PR";	case DLM_LOCK_PW:		return "PW";	case DLM_LOCK_EX:		return "EX";	default:		return "??";	}} static void print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb,			       struct dlm_rsb *res){	seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode)); 	if (lkb->lkb_status == DLM_LKSTS_CONVERT ||	    lkb->lkb_status == DLM_LKSTS_WAITING)		seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode)); 	if (lkb->lkb_nodeid) {		if (lkb->lkb_nodeid != res->res_nodeid)			seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid,				   lkb->lkb_remid);		else			seq_printf(s, " Master:     %08x", lkb->lkb_remid);	} 	if (lkb->lkb_wait_type)		seq_printf(s, " wait_type: %d", lkb->lkb_wait_type); 	seq_putc(s, '\n');} static void print_format1(struct dlm_rsb *res, struct seq_file *s){	struct dlm_lkb *lkb;	int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list; 	lock_rsb(res); 	seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length); 	for (i = 0; i < res->res_length; i++) {		if (isprint(res->res_name[i]))			seq_printf(s, "%c", res->res_name[i]);		else			seq_printf(s, "%c", '.');	} 	if (res->res_nodeid > 0)		seq_printf(s, "\"\nLocal Copy, Master is node %d\n",			   res->res_nodeid);	else if (res->res_nodeid == 0)		seq_puts(s, "\"\nMaster Copy\n");	else if (res->res_nodeid == -1)		seq_printf(s, "\"\nLooking up master (lkid %x)\n",			   res->res_first_lkid);	else		seq_printf(s, "\"\nInvalid master %d\n", res->res_nodeid);	if (seq_has_overflowed(s))		goto out; 	/* Print the LVB: */	if (res->res_lvbptr) {		seq_puts(s, "LVB: ");		for (i = 0; i < lvblen; i++) {			if (i == lvblen / 2)				seq_puts(s, "\n     ");			seq_printf(s, "%02x ",				   (unsigned char) res->res_lvbptr[i]);		}		if (rsb_flag(res, RSB_VALNOTVALID))			seq_puts(s, " (INVALID)");		seq_putc(s, '\n');		if (seq_has_overflowed(s))			goto out;	} 	root_list = !list_empty(&res->res_root_list);	recover_list = !list_empty(&res->res_recover_list); 	if (root_list || recover_list) {		seq_printf(s, "Recovery: root %d recover %d flags %lx count %d\n",			   root_list, recover_list,			   res->res_flags, res->res_recover_locks_count);	} 	/* Print the locks attached to this resource */	seq_puts(s, "Granted Queue\n");	list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) {		print_format1_lock(s, lkb, res);		if (seq_has_overflowed(s))			goto out;	} 	seq_puts(s, "Conversion Queue\n");	list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) {		print_format1_lock(s, lkb, res);		if (seq_has_overflowed(s))			goto out;	} 	seq_puts(s, "Waiting Queue\n");	list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) {		print_format1_lock(s, lkb, res);		if (seq_has_overflowed(s))			goto out;	} 	if (list_empty(&res->res_lookup))		goto out; 	seq_puts(s, "Lookup Queue\n");	list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) {		seq_printf(s, "%08x %s",			   lkb->lkb_id, print_lockmode(lkb->lkb_rqmode));		if (lkb->lkb_wait_type)			seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);		seq_putc(s, '\n');		if (seq_has_overflowed(s))			goto out;	} out:	unlock_rsb(res);} static void print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb,			       struct dlm_rsb *r){	u64 xid = 0;	u64 us; 	if (test_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags)) {		if (lkb->lkb_ua)			xid = lkb->lkb_ua->xid;	} 	/* microseconds since lkb was added to current queue */	us = ktime_to_us(ktime_sub(ktime_get(), lkb->lkb_timestamp)); 	/* id nodeid remid pid xid exflags flags sts grmode rqmode time_us	   r_nodeid r_len r_name */ 	seq_printf(s, "%x %d %x %u %llu %x %x %d %d %d %llu %u %d \"%s\"\n",		   lkb->lkb_id,		   lkb->lkb_nodeid,		   lkb->lkb_remid,		   lkb->lkb_ownpid,		   (unsigned long long)xid,		   lkb->lkb_exflags,		   dlm_iflags_val(lkb),		   lkb->lkb_status,		   lkb->lkb_grmode,		   lkb->lkb_rqmode,		   (unsigned long long)us,		   r->res_nodeid,		   r->res_length,		   r->res_name);} static void print_format2(struct dlm_rsb *r, struct seq_file *s){	struct dlm_lkb *lkb; 	lock_rsb(r); 	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {		print_format2_lock(s, lkb, r);		if (seq_has_overflowed(s))			goto out;	} 	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {		print_format2_lock(s, lkb, r);		if (seq_has_overflowed(s))			goto out;	} 	list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) {		print_format2_lock(s, lkb, r);		if (seq_has_overflowed(s))			goto out;	} out:	unlock_rsb(r);} static void print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb,			      int rsb_lookup){	u64 xid = 0; 	if (test_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags)) {		if (lkb->lkb_ua)			xid = lkb->lkb_ua->xid;	} 	seq_printf(s, "lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n",		   lkb->lkb_id,		   lkb->lkb_nodeid,		   lkb->lkb_remid,		   lkb->lkb_ownpid,		   (unsigned long long)xid,		   lkb->lkb_exflags,		   dlm_iflags_val(lkb),		   lkb->lkb_status,		   lkb->lkb_grmode,		   lkb->lkb_rqmode,		   lkb->lkb_last_bast_cb_mode,		   rsb_lookup,		   lkb->lkb_wait_type,		   lkb->lkb_lvbseq,		   (unsigned long long)ktime_to_ns(lkb->lkb_timestamp),		   (unsigned long long)ktime_to_ns(lkb->lkb_last_bast_time));} static void print_format3(struct dlm_rsb *r, struct seq_file *s){	struct dlm_lkb *lkb;	int i, lvblen = r->res_ls->ls_lvblen;	int print_name = 1; 	lock_rsb(r); 	seq_printf(s, "rsb %p %d %x %lx %d %d %u %d ",		   r,		   r->res_nodeid,		   r->res_first_lkid,		   r->res_flags,		   !list_empty(&r->res_root_list),		   !list_empty(&r->res_recover_list),		   r->res_recover_locks_count,		   r->res_length);	if (seq_has_overflowed(s))		goto out; 	for (i = 0; i < r->res_length; i++) {		if (!isascii(r->res_name[i]) || !isprint(r->res_name[i]))			print_name = 0;	} 	seq_puts(s, print_name ? "str " : "hex"); 	for (i = 0; i < r->res_length; i++) {		if (print_name)			seq_printf(s, "%c", r->res_name[i]);		else			seq_printf(s, " %02x", (unsigned char)r->res_name[i]);	}	seq_putc(s, '\n');	if (seq_has_overflowed(s))		goto out; 	if (!r->res_lvbptr)		goto do_locks; 	seq_printf(s, "lvb %u %d", r->res_lvbseq, lvblen); 	for (i = 0; i < lvblen; i++)		seq_printf(s, " %02x", (unsigned char)r->res_lvbptr[i]);	seq_putc(s, '\n');	if (seq_has_overflowed(s))		goto out;  do_locks:	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {		print_format3_lock(s, lkb, 0);		if (seq_has_overflowed(s))			goto out;	} 	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {		print_format3_lock(s, lkb, 0);		if (seq_has_overflowed(s))			goto out;	} 	list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) {		print_format3_lock(s, lkb, 0);		if (seq_has_overflowed(s))			goto out;	} 	list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) {		print_format3_lock(s, lkb, 1);		if (seq_has_overflowed(s))			goto out;	} out:	unlock_rsb(r);} static void print_format4(struct dlm_rsb *r, struct seq_file *s){	int our_nodeid = dlm_our_nodeid();	int print_name = 1;	int i; 	lock_rsb(r); 	seq_printf(s, "rsb %p %d %d %d %d %lu %lx %d ",		   r,		   r->res_nodeid,		   r->res_master_nodeid,		   r->res_dir_nodeid,		   our_nodeid,		   r->res_toss_time,		   r->res_flags,		   r->res_length); 	for (i = 0; i < r->res_length; i++) {		if (!isascii(r->res_name[i]) || !isprint(r->res_name[i]))			print_name = 0;	} 	seq_puts(s, print_name ? "str " : "hex"); 	for (i = 0; i < r->res_length; i++) {		if (print_name)			seq_printf(s, "%c", r->res_name[i]);		else			seq_printf(s, " %02x", (unsigned char)r->res_name[i]);	}	seq_putc(s, '\n');	unlock_rsb(r);} static const struct seq_operations format1_seq_ops;static const struct seq_operations format2_seq_ops;static const struct seq_operations format3_seq_ops;static const struct seq_operations format4_seq_ops; /* * If the buffer is full, seq_printf can be called again, but it * does nothing.  So, the these printing routines periodically check * seq_has_overflowed to avoid wasting too much time trying to print to * a full buffer. */ static int table_seq_show(struct seq_file *seq, void *iter_ptr){	struct dlm_rsb *rsb = list_entry(iter_ptr, struct dlm_rsb, res_slow_list); 	if (seq->op == &format1_seq_ops)		print_format1(rsb, seq);	else if (seq->op == &format2_seq_ops)		print_format2(rsb, seq);	else if (seq->op == &format3_seq_ops)		print_format3(rsb, seq);	else if (seq->op == &format4_seq_ops)		print_format4(rsb, seq); 	return 0;} static void *table_seq_start(struct seq_file *seq, loff_t *pos){	struct dlm_ls *ls = seq->private;	struct list_head *list; 	if (!*pos) {		if (seq->op == &format2_seq_ops)			seq_puts(seq, "id nodeid remid pid xid exflags flags sts grmode rqmode time_ms r_nodeid r_len r_name\n");		else if (seq->op == &format3_seq_ops)			seq_puts(seq, "rsb ptr nodeid first_lkid flags !root_list_empty !recover_list_empty recover_locks_count len\n");		else if (seq->op == &format4_seq_ops)			seq_puts(seq, "rsb ptr nodeid master_nodeid dir_nodeid our_nodeid toss_time flags len str|hex name\n");	} 	if (seq->op == &format4_seq_ops)		list = &ls->ls_slow_inactive;	else		list = &ls->ls_slow_active; 	read_lock_bh(&ls->ls_rsbtbl_lock);	return seq_list_start(list, *pos);} static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos){	struct dlm_ls *ls = seq->private;	struct list_head *list; 	if (seq->op == &format4_seq_ops)		list = &ls->ls_slow_inactive;	else		list = &ls->ls_slow_active; 	return seq_list_next(iter_ptr, list, pos);} static void table_seq_stop(struct seq_file *seq, void *iter_ptr){	struct dlm_ls *ls = seq->private; 	read_unlock_bh(&ls->ls_rsbtbl_lock);} static const struct seq_operations format1_seq_ops = {	.start = table_seq_start,	.next  = table_seq_next,	.stop  = table_seq_stop,	.show  = table_seq_show,}; static const struct seq_operations format2_seq_ops = {	.start = table_seq_start,	.next  = table_seq_next,	.stop  = table_seq_stop,	.show  = table_seq_show,}; static const struct seq_operations format3_seq_ops = {	.start = table_seq_start,	.next  = table_seq_next,	.stop  = table_seq_stop,	.show  = table_seq_show,}; static const struct seq_operations format4_seq_ops = {	.start = table_seq_start,	.next  = table_seq_next,	.stop  = table_seq_stop,	.show  = table_seq_show,}; static const struct file_operations format1_fops;static const struct file_operations format2_fops;static const struct file_operations format3_fops;static const struct file_operations format4_fops; static int table_open1(struct inode *inode, struct file *file){	struct seq_file *seq;	int ret; 	ret = seq_open(file, &format1_seq_ops);	if (ret)		return ret; 	seq = file->private_data;	seq->private = inode->i_private; /* the dlm_ls */	return 0;} static int table_open2(struct inode *inode, struct file *file){	struct seq_file *seq;	int ret; 	ret = seq_open(file, &format2_seq_ops);	if (ret)		return ret; 	seq = file->private_data;	seq->private = inode->i_private; /* the dlm_ls */	return 0;} 

Lines 1–500 of 825.