diff options
Diffstat (limited to 'fs/ocfs2/cluster/netdebug.c')
| -rw-r--r-- | fs/ocfs2/cluster/netdebug.c | 364 | 
1 files changed, 250 insertions, 114 deletions
diff --git a/fs/ocfs2/cluster/netdebug.c b/fs/ocfs2/cluster/netdebug.c index a3f150e52b0..73ba81928bc 100644 --- a/fs/ocfs2/cluster/netdebug.c +++ b/fs/ocfs2/cluster/netdebug.c @@ -46,10 +46,17 @@  #define O2NET_DEBUG_DIR		"o2net"  #define SC_DEBUG_NAME		"sock_containers"  #define NST_DEBUG_NAME		"send_tracking" +#define STATS_DEBUG_NAME	"stats" +#define NODES_DEBUG_NAME	"connected_nodes" + +#define SHOW_SOCK_CONTAINERS	0 +#define SHOW_SOCK_STATS		1  static struct dentry *o2net_dentry;  static struct dentry *sc_dentry;  static struct dentry *nst_dentry; +static struct dentry *stats_dentry; +static struct dentry *nodes_dentry;  static DEFINE_SPINLOCK(o2net_debug_lock); @@ -123,37 +130,42 @@ static void *nst_seq_next(struct seq_file *seq, void *v, loff_t *pos)  static int nst_seq_show(struct seq_file *seq, void *v)  {  	struct o2net_send_tracking *nst, *dummy_nst = seq->private; +	ktime_t now; +	s64 sock, send, status;  	spin_lock(&o2net_debug_lock);  	nst = next_nst(dummy_nst); +	if (!nst) +		goto out; -	if (nst != NULL) { -		/* get_task_comm isn't exported.  oh well. */ -		seq_printf(seq, "%p:\n" -			   "  pid:          %lu\n" -			   "  tgid:         %lu\n" -			   "  process name: %s\n" -			   "  node:         %u\n" -			   "  sc:           %p\n" -			   "  message id:   %d\n" -			   "  message type: %u\n" -			   "  message key:  0x%08x\n" -			   "  sock acquiry: %lu.%ld\n" -			   "  send start:   %lu.%ld\n" -			   "  wait start:   %lu.%ld\n", -			   nst, (unsigned long)nst->st_task->pid, -			   (unsigned long)nst->st_task->tgid, -			   nst->st_task->comm, nst->st_node, -			   nst->st_sc, nst->st_id, nst->st_msg_type, -			   nst->st_msg_key, -			   nst->st_sock_time.tv_sec, -			   (long)nst->st_sock_time.tv_usec, -			   nst->st_send_time.tv_sec, -			   (long)nst->st_send_time.tv_usec, -			   nst->st_status_time.tv_sec, -			   (long)nst->st_status_time.tv_usec); -	} +	now = ktime_get(); +	sock = ktime_to_us(ktime_sub(now, nst->st_sock_time)); +	send = ktime_to_us(ktime_sub(now, nst->st_send_time)); +	status = ktime_to_us(ktime_sub(now, nst->st_status_time)); + +	/* get_task_comm isn't exported.  oh well. */ +	seq_printf(seq, "%p:\n" +		   "  pid:          %lu\n" +		   "  tgid:         %lu\n" +		   "  process name: %s\n" +		   "  node:         %u\n" +		   "  sc:           %p\n" +		   "  message id:   %d\n" +		   "  message type: %u\n" +		   "  message key:  0x%08x\n" +		   "  sock acquiry: %lld usecs ago\n" +		   "  send start:   %lld usecs ago\n" +		   "  wait start:   %lld usecs ago\n", +		   nst, (unsigned long)task_pid_nr(nst->st_task), +		   (unsigned long)nst->st_task->tgid, +		   nst->st_task->comm, nst->st_node, +		   nst->st_sc, nst->st_id, nst->st_msg_type, +		   nst->st_msg_key, +		   (long long)sock, +		   (long long)send, +		   (long long)status); +out:  	spin_unlock(&o2net_debug_lock);  	return 0; @@ -228,6 +240,11 @@ void o2net_debug_del_sc(struct o2net_sock_container *sc)  	spin_unlock(&o2net_debug_lock);  } +struct o2net_sock_debug { +	int dbg_ctxt; +	struct o2net_sock_container *dbg_sock; +}; +  static struct o2net_sock_container  			*next_sc(struct o2net_sock_container *sc_start)  { @@ -253,7 +270,8 @@ static struct o2net_sock_container  static void *sc_seq_start(struct seq_file *seq, loff_t *pos)  { -	struct o2net_sock_container *sc, *dummy_sc = seq->private; +	struct o2net_sock_debug *sd = seq->private; +	struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;  	spin_lock(&o2net_debug_lock);  	sc = next_sc(dummy_sc); @@ -264,7 +282,8 @@ static void *sc_seq_start(struct seq_file *seq, loff_t *pos)  static void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos)  { -	struct o2net_sock_container *sc, *dummy_sc = seq->private; +	struct o2net_sock_debug *sd = seq->private; +	struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;  	spin_lock(&o2net_debug_lock);  	sc = next_sc(dummy_sc); @@ -276,65 +295,107 @@ static void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos)  	return sc; /* unused, just needs to be null when done */  } -#define TV_SEC_USEC(TV) TV.tv_sec, (long)TV.tv_usec +#ifdef CONFIG_OCFS2_FS_STATS +# define sc_send_count(_s)		((_s)->sc_send_count) +# define sc_recv_count(_s)		((_s)->sc_recv_count) +# define sc_tv_acquiry_total_ns(_s)	(ktime_to_ns((_s)->sc_tv_acquiry_total)) +# define sc_tv_send_total_ns(_s)	(ktime_to_ns((_s)->sc_tv_send_total)) +# define sc_tv_status_total_ns(_s)	(ktime_to_ns((_s)->sc_tv_status_total)) +# define sc_tv_process_total_ns(_s)	(ktime_to_ns((_s)->sc_tv_process_total)) +#else +# define sc_send_count(_s)		(0U) +# define sc_recv_count(_s)		(0U) +# define sc_tv_acquiry_total_ns(_s)	(0LL) +# define sc_tv_send_total_ns(_s)	(0LL) +# define sc_tv_status_total_ns(_s)	(0LL) +# define sc_tv_process_total_ns(_s)	(0LL) +#endif + +/* So that debugfs.ocfs2 can determine which format is being used */ +#define O2NET_STATS_STR_VERSION		1 +static void sc_show_sock_stats(struct seq_file *seq, +			       struct o2net_sock_container *sc) +{ +	if (!sc) +		return; + +	seq_printf(seq, "%d,%u,%lu,%lld,%lld,%lld,%lu,%lld\n", O2NET_STATS_STR_VERSION, +		   sc->sc_node->nd_num, (unsigned long)sc_send_count(sc), +		   (long long)sc_tv_acquiry_total_ns(sc), +		   (long long)sc_tv_send_total_ns(sc), +		   (long long)sc_tv_status_total_ns(sc), +		   (unsigned long)sc_recv_count(sc), +		   (long long)sc_tv_process_total_ns(sc)); +} + +static void sc_show_sock_container(struct seq_file *seq, +				   struct o2net_sock_container *sc) +{ +	struct inet_sock *inet = NULL; +	__be32 saddr = 0, daddr = 0; +	__be16 sport = 0, dport = 0; + +	if (!sc) +		return; + +	if (sc->sc_sock) { +		inet = inet_sk(sc->sc_sock->sk); +		/* the stack's structs aren't sparse endian clean */ +		saddr = (__force __be32)inet->inet_saddr; +		daddr = (__force __be32)inet->inet_daddr; +		sport = (__force __be16)inet->inet_sport; +		dport = (__force __be16)inet->inet_dport; +	} + +	/* XXX sigh, inet-> doesn't have sparse annotation so any +	 * use of it here generates a warning with -Wbitwise */ +	seq_printf(seq, "%p:\n" +		   "  krefs:           %d\n" +		   "  sock:            %pI4:%u -> " +				      "%pI4:%u\n" +		   "  remote node:     %s\n" +		   "  page off:        %zu\n" +		   "  handshake ok:    %u\n" +		   "  timer:           %lld usecs\n" +		   "  data ready:      %lld usecs\n" +		   "  advance start:   %lld usecs\n" +		   "  advance stop:    %lld usecs\n" +		   "  func start:      %lld usecs\n" +		   "  func stop:       %lld usecs\n" +		   "  func key:        0x%08x\n" +		   "  func type:       %u\n", +		   sc, +		   atomic_read(&sc->sc_kref.refcount), +		   &saddr, inet ? ntohs(sport) : 0, +		   &daddr, inet ? ntohs(dport) : 0, +		   sc->sc_node->nd_name, +		   sc->sc_page_off, +		   sc->sc_handshake_ok, +		   (long long)ktime_to_us(sc->sc_tv_timer), +		   (long long)ktime_to_us(sc->sc_tv_data_ready), +		   (long long)ktime_to_us(sc->sc_tv_advance_start), +		   (long long)ktime_to_us(sc->sc_tv_advance_stop), +		   (long long)ktime_to_us(sc->sc_tv_func_start), +		   (long long)ktime_to_us(sc->sc_tv_func_stop), +		   sc->sc_msg_key, +		   sc->sc_msg_type); +}  static int sc_seq_show(struct seq_file *seq, void *v)  { -	struct o2net_sock_container *sc, *dummy_sc = seq->private; +	struct o2net_sock_debug *sd = seq->private; +	struct o2net_sock_container *sc, *dummy_sc = sd->dbg_sock;  	spin_lock(&o2net_debug_lock);  	sc = next_sc(dummy_sc); -	if (sc != NULL) { -		struct inet_sock *inet = NULL; - -		__be32 saddr = 0, daddr = 0; -		__be16 sport = 0, dport = 0; - -		if (sc->sc_sock) { -			inet = inet_sk(sc->sc_sock->sk); -			/* the stack's structs aren't sparse endian clean */ -			saddr = (__force __be32)inet->inet_saddr; -			daddr = (__force __be32)inet->inet_daddr; -			sport = (__force __be16)inet->inet_sport; -			dport = (__force __be16)inet->inet_dport; -		} - -		/* XXX sigh, inet-> doesn't have sparse annotation so any -		 * use of it here generates a warning with -Wbitwise */ -		seq_printf(seq, "%p:\n" -			   "  krefs:           %d\n" -			   "  sock:            %pI4:%u -> " -					      "%pI4:%u\n" -			   "  remote node:     %s\n" -			   "  page off:        %zu\n" -			   "  handshake ok:    %u\n" -			   "  timer:           %lu.%ld\n" -			   "  data ready:      %lu.%ld\n" -			   "  advance start:   %lu.%ld\n" -			   "  advance stop:    %lu.%ld\n" -			   "  func start:      %lu.%ld\n" -			   "  func stop:       %lu.%ld\n" -			   "  func key:        %u\n" -			   "  func type:       %u\n", -			   sc, -			   atomic_read(&sc->sc_kref.refcount), -			   &saddr, inet ? ntohs(sport) : 0, -			   &daddr, inet ? ntohs(dport) : 0, -			   sc->sc_node->nd_name, -			   sc->sc_page_off, -			   sc->sc_handshake_ok, -			   TV_SEC_USEC(sc->sc_tv_timer), -			   TV_SEC_USEC(sc->sc_tv_data_ready), -			   TV_SEC_USEC(sc->sc_tv_advance_start), -			   TV_SEC_USEC(sc->sc_tv_advance_stop), -			   TV_SEC_USEC(sc->sc_tv_func_start), -			   TV_SEC_USEC(sc->sc_tv_func_stop), -			   sc->sc_msg_key, -			   sc->sc_msg_type); +	if (sc) { +		if (sd->dbg_ctxt == SHOW_SOCK_CONTAINERS) +			sc_show_sock_container(seq, sc); +		else +			sc_show_sock_stats(seq, sc);  	} -  	spin_unlock(&o2net_debug_lock);  	return 0; @@ -351,7 +412,7 @@ static const struct seq_operations sc_seq_ops = {  	.show = sc_seq_show,  }; -static int sc_fop_open(struct inode *inode, struct file *file) +static int sc_common_open(struct file *file, struct o2net_sock_debug *sd)  {  	struct o2net_sock_container *dummy_sc;  	struct seq_file *seq; @@ -369,7 +430,8 @@ static int sc_fop_open(struct inode *inode, struct file *file)  		goto out;  	seq = file->private_data; -	seq->private = dummy_sc; +	seq->private = sd; +	sd->dbg_sock = dummy_sc;  	o2net_debug_add_sc(dummy_sc);  	dummy_sc = NULL; @@ -382,12 +444,48 @@ out:  static int sc_fop_release(struct inode *inode, struct file *file)  {  	struct seq_file *seq = file->private_data; -	struct o2net_sock_container *dummy_sc = seq->private; +	struct o2net_sock_debug *sd = seq->private; +	struct o2net_sock_container *dummy_sc = sd->dbg_sock;  	o2net_debug_del_sc(dummy_sc);  	return seq_release_private(inode, file);  } +static int stats_fop_open(struct inode *inode, struct file *file) +{ +	struct o2net_sock_debug *sd; + +	sd = kmalloc(sizeof(struct o2net_sock_debug), GFP_KERNEL); +	if (sd == NULL) +		return -ENOMEM; + +	sd->dbg_ctxt = SHOW_SOCK_STATS; +	sd->dbg_sock = NULL; + +	return sc_common_open(file, sd); +} + +static const struct file_operations stats_seq_fops = { +	.open = stats_fop_open, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = sc_fop_release, +}; + +static int sc_fop_open(struct inode *inode, struct file *file) +{ +	struct o2net_sock_debug *sd; + +	sd = kmalloc(sizeof(struct o2net_sock_debug), GFP_KERNEL); +	if (sd == NULL) +		return -ENOMEM; + +	sd->dbg_ctxt = SHOW_SOCK_CONTAINERS; +	sd->dbg_sock = NULL; + +	return sc_common_open(file, sd); +} +  static const struct file_operations sc_seq_fops = {  	.open = sc_fop_open,  	.read = seq_read, @@ -395,49 +493,87 @@ static const struct file_operations sc_seq_fops = {  	.release = sc_fop_release,  }; -int o2net_debugfs_init(void) +static int o2net_fill_bitmap(char *buf, int len)  { -	o2net_dentry = debugfs_create_dir(O2NET_DEBUG_DIR, NULL); -	if (!o2net_dentry) { -		mlog_errno(-ENOMEM); -		goto bail; -	} +	unsigned long map[BITS_TO_LONGS(O2NM_MAX_NODES)]; +	int i = -1, out = 0; -	nst_dentry = debugfs_create_file(NST_DEBUG_NAME, S_IFREG|S_IRUSR, -					 o2net_dentry, NULL, -					 &nst_seq_fops); -	if (!nst_dentry) { -		mlog_errno(-ENOMEM); -		goto bail; -	} +	o2net_fill_node_map(map, sizeof(map)); -	sc_dentry = debugfs_create_file(SC_DEBUG_NAME, S_IFREG|S_IRUSR, -					o2net_dentry, NULL, -					&sc_seq_fops); -	if (!sc_dentry) { -		mlog_errno(-ENOMEM); -		goto bail; -	} +	while ((i = find_next_bit(map, O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES) +		out += snprintf(buf + out, PAGE_SIZE - out, "%d ", i); +	out += snprintf(buf + out, PAGE_SIZE - out, "\n"); + +	return out; +} + +static int nodes_fop_open(struct inode *inode, struct file *file) +{ +	char *buf; + +	buf = kmalloc(PAGE_SIZE, GFP_KERNEL); +	if (!buf) +		return -ENOMEM; + +	i_size_write(inode, o2net_fill_bitmap(buf, PAGE_SIZE)); + +	file->private_data = buf;  	return 0; -bail: -	if (sc_dentry) -		debugfs_remove(sc_dentry); -	if (nst_dentry) -		debugfs_remove(nst_dentry); -	if (o2net_dentry) -		debugfs_remove(o2net_dentry); -	return -ENOMEM;  } +static int o2net_debug_release(struct inode *inode, struct file *file) +{ +	kfree(file->private_data); +	return 0; +} + +static ssize_t o2net_debug_read(struct file *file, char __user *buf, +				size_t nbytes, loff_t *ppos) +{ +	return simple_read_from_buffer(buf, nbytes, ppos, file->private_data, +				       i_size_read(file->f_mapping->host)); +} + +static const struct file_operations nodes_fops = { +	.open		= nodes_fop_open, +	.release	= o2net_debug_release, +	.read		= o2net_debug_read, +	.llseek		= generic_file_llseek, +}; +  void o2net_debugfs_exit(void)  { -	if (sc_dentry) -		debugfs_remove(sc_dentry); -	if (nst_dentry) -		debugfs_remove(nst_dentry); +	debugfs_remove(nodes_dentry); +	debugfs_remove(stats_dentry); +	debugfs_remove(sc_dentry); +	debugfs_remove(nst_dentry); +	debugfs_remove(o2net_dentry); +} + +int o2net_debugfs_init(void) +{ +	umode_t mode = S_IFREG|S_IRUSR; + +	o2net_dentry = debugfs_create_dir(O2NET_DEBUG_DIR, NULL);  	if (o2net_dentry) -		debugfs_remove(o2net_dentry); +		nst_dentry = debugfs_create_file(NST_DEBUG_NAME, mode, +					o2net_dentry, NULL, &nst_seq_fops); +	if (nst_dentry) +		sc_dentry = debugfs_create_file(SC_DEBUG_NAME, mode, +					o2net_dentry, NULL, &sc_seq_fops); +	if (sc_dentry) +		stats_dentry = debugfs_create_file(STATS_DEBUG_NAME, mode, +					o2net_dentry, NULL, &stats_seq_fops); +	if (stats_dentry) +		nodes_dentry = debugfs_create_file(NODES_DEBUG_NAME, mode, +					o2net_dentry, NULL, &nodes_fops); +	if (nodes_dentry) +		return 0; + +	o2net_debugfs_exit(); +	mlog_errno(-ENOMEM); +	return -ENOMEM;  }  #endif	/* CONFIG_DEBUG_FS */  | 
