drbd: debugfs: add per volume oldest_requests
Show oldest requests * pending master bio completion and, * if different, local disk bio completion. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
This commit is contained in:
		
							parent
							
								
									944410e97c
								
							
						
					
					
						commit
						54e6fc38e8
					
				| @ -434,12 +434,10 @@ static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, vo | ||||
| 		goto out; | ||||
| 	/* serialize with d_delete() */ | ||||
| 	mutex_lock(&parent->d_inode->i_mutex); | ||||
| 	if (!debugfs_positive(file->f_dentry)) | ||||
| 		goto out_unlock; | ||||
| 	/* Make sure the object is still alive */ | ||||
| 	if (kref_get_unless_zero(kref)) | ||||
| 	if (debugfs_positive(file->f_dentry) | ||||
| 	&& kref_get_unless_zero(kref)) | ||||
| 		ret = 0; | ||||
| out_unlock: | ||||
| 	mutex_unlock(&parent->d_inode->i_mutex); | ||||
| 	if (!ret) { | ||||
| 		ret = single_open(file, show, data); | ||||
| @ -592,6 +590,53 @@ static const struct file_operations connection_callback_history_fops = { | ||||
| 	.release	= callback_history_release, | ||||
| }; | ||||
| 
 | ||||
| static int connection_oldest_requests_show(struct seq_file *m, void *ignored) | ||||
| { | ||||
| 	struct drbd_connection *connection = m->private; | ||||
| 	unsigned long now = jiffies; | ||||
| 	struct drbd_request *r1, *r2; | ||||
| 
 | ||||
| 	/* BUMP me if you change the file format/content/presentation */ | ||||
| 	seq_printf(m, "v: %u\n\n", 0); | ||||
| 
 | ||||
| 	spin_lock_irq(&connection->resource->req_lock); | ||||
| 	r1 = connection->req_next; | ||||
| 	if (r1) | ||||
| 		seq_print_minor_vnr_req(m, r1, now); | ||||
| 	r2 = connection->req_ack_pending; | ||||
| 	if (r2 && r2 != r1) { | ||||
| 		r1 = r2; | ||||
| 		seq_print_minor_vnr_req(m, r1, now); | ||||
| 	} | ||||
| 	r2 = connection->req_not_net_done; | ||||
| 	if (r2 && r2 != r1) | ||||
| 		seq_print_minor_vnr_req(m, r2, now); | ||||
| 	spin_unlock_irq(&connection->resource->req_lock); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int connection_oldest_requests_open(struct inode *inode, struct file *file) | ||||
| { | ||||
| 	struct drbd_connection *connection = inode->i_private; | ||||
| 	return drbd_single_open(file, connection_oldest_requests_show, connection, | ||||
| 				&connection->kref, drbd_destroy_connection); | ||||
| } | ||||
| 
 | ||||
| static int connection_oldest_requests_release(struct inode *inode, struct file *file) | ||||
| { | ||||
| 	struct drbd_connection *connection = inode->i_private; | ||||
| 	kref_put(&connection->kref, drbd_destroy_connection); | ||||
| 	return single_release(inode, file); | ||||
| } | ||||
| 
 | ||||
| static const struct file_operations connection_oldest_requests_fops = { | ||||
| 	.owner		= THIS_MODULE, | ||||
| 	.open		= connection_oldest_requests_open, | ||||
| 	.read		= seq_read, | ||||
| 	.llseek		= seq_lseek, | ||||
| 	.release	= connection_oldest_requests_release, | ||||
| }; | ||||
| 
 | ||||
| void drbd_debugfs_connection_add(struct drbd_connection *connection) | ||||
| { | ||||
| 	struct dentry *conns_dir = connection->resource->debugfs_res_connections; | ||||
| @ -627,6 +672,89 @@ void drbd_debugfs_connection_cleanup(struct drbd_connection *connection) | ||||
| 	drbd_debugfs_remove(&connection->debugfs_conn); | ||||
| } | ||||
| 
 | ||||
| static void resync_dump_detail(struct seq_file *m, struct lc_element *e) | ||||
| { | ||||
|        struct bm_extent *bme = lc_entry(e, struct bm_extent, lce); | ||||
| 
 | ||||
|        seq_printf(m, "%5d %s %s %s\n", bme->rs_left, | ||||
| 		  test_bit(BME_NO_WRITES, &bme->flags) ? "NO_WRITES" : "---------", | ||||
| 		  test_bit(BME_LOCKED, &bme->flags) ? "LOCKED" : "------", | ||||
| 		  test_bit(BME_PRIORITY, &bme->flags) ? "PRIORITY" : "--------" | ||||
| 		  ); | ||||
| } | ||||
| 
 | ||||
| static int device_resync_extents_show(struct seq_file *m, void *ignored) | ||||
| { | ||||
| 	struct drbd_device *device = m->private; | ||||
| 	if (get_ldev_if_state(device, D_FAILED)) { | ||||
| 		lc_seq_printf_stats(m, device->resync); | ||||
| 		lc_seq_dump_details(m, device->resync, "rs_left flags", resync_dump_detail); | ||||
| 		put_ldev(device); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int device_act_log_extents_show(struct seq_file *m, void *ignored) | ||||
| { | ||||
| 	struct drbd_device *device = m->private; | ||||
| 	if (get_ldev_if_state(device, D_FAILED)) { | ||||
| 		lc_seq_printf_stats(m, device->act_log); | ||||
| 		lc_seq_dump_details(m, device->act_log, "", NULL); | ||||
| 		put_ldev(device); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int device_oldest_requests_show(struct seq_file *m, void *ignored) | ||||
| { | ||||
| 	struct drbd_device *device = m->private; | ||||
| 	struct drbd_resource *resource = device->resource; | ||||
| 	unsigned long now = jiffies; | ||||
| 	struct drbd_request *r1, *r2; | ||||
| 	int i; | ||||
| 
 | ||||
| 	seq_puts(m, RQ_HDR); | ||||
| 	spin_lock_irq(&resource->req_lock); | ||||
| 	/* WRITE, then READ */ | ||||
| 	for (i = 1; i >= 0; --i) { | ||||
| 		r1 = list_first_entry_or_null(&device->pending_master_completion[i], | ||||
| 			struct drbd_request, req_pending_master_completion); | ||||
| 		r2 = list_first_entry_or_null(&device->pending_completion[i], | ||||
| 			struct drbd_request, req_pending_local); | ||||
| 		if (r1) | ||||
| 			seq_print_one_request(m, r1, now); | ||||
| 		if (r2 && r2 != r1) | ||||
| 			seq_print_one_request(m, r2, now); | ||||
| 	} | ||||
| 	spin_unlock_irq(&resource->req_lock); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #define drbd_debugfs_device_attr(name)						\ | ||||
| static int device_ ## name ## _open(struct inode *inode, struct file *file)	\ | ||||
| {										\ | ||||
| 	struct drbd_device *device = inode->i_private;				\ | ||||
| 	return drbd_single_open(file, device_ ## name ## _show, device,		\ | ||||
| 				&device->kref, drbd_destroy_device);		\ | ||||
| }										\ | ||||
| static int device_ ## name ## _release(struct inode *inode, struct file *file)	\ | ||||
| {										\ | ||||
| 	struct drbd_device *device = inode->i_private;				\ | ||||
| 	kref_put(&device->kref, drbd_destroy_device);				\ | ||||
| 	return single_release(inode, file);					\ | ||||
| }										\ | ||||
| static const struct file_operations device_ ## name ## _fops = {		\ | ||||
| 	.owner		= THIS_MODULE,						\ | ||||
| 	.open		= device_ ## name ## _open,				\ | ||||
| 	.read		= seq_read,						\ | ||||
| 	.llseek		= seq_lseek,						\ | ||||
| 	.release	= device_ ## name ## _release,				\ | ||||
| }; | ||||
| 
 | ||||
| drbd_debugfs_device_attr(oldest_requests) | ||||
| drbd_debugfs_device_attr(act_log_extents) | ||||
| drbd_debugfs_device_attr(resync_extents) | ||||
| 
 | ||||
| void drbd_debugfs_device_add(struct drbd_device *device) | ||||
| { | ||||
| 	struct dentry *vols_dir = device->resource->debugfs_res_volumes; | ||||
| @ -650,10 +778,25 @@ void drbd_debugfs_device_add(struct drbd_device *device) | ||||
| 	if (!slink_name) | ||||
| 		goto fail; | ||||
| 	dentry = debugfs_create_symlink(minor_buf, drbd_debugfs_minors, slink_name); | ||||
| 	kfree(slink_name); | ||||
| 	slink_name = NULL; | ||||
| 	if (IS_ERR_OR_NULL(dentry)) | ||||
| 		goto fail; | ||||
| 	device->debugfs_minor = dentry; | ||||
| 	kfree(slink_name); | ||||
| 
 | ||||
| #define DCF(name)	do {					\ | ||||
| 	dentry = debugfs_create_file(#name, S_IRUSR|S_IRGRP,	\ | ||||
| 			device->debugfs_vol, device,		\ | ||||
| 			&device_ ## name ## _fops);		\ | ||||
| 	if (IS_ERR_OR_NULL(dentry))				\ | ||||
| 		goto fail;					\ | ||||
| 	device->debugfs_vol_ ## name = dentry;			\ | ||||
| 	} while (0) | ||||
| 
 | ||||
| 	DCF(oldest_requests); | ||||
| 	DCF(act_log_extents); | ||||
| 	DCF(resync_extents); | ||||
| 	return; | ||||
| 
 | ||||
| fail: | ||||
| 	drbd_debugfs_device_cleanup(device); | ||||
|  | ||||
| @ -643,9 +643,10 @@ void lc_set(struct lru_cache *lc, unsigned int enr, int index) | ||||
|  * lc_dump - Dump a complete LRU cache to seq in textual form. | ||||
|  * @lc: the lru cache to operate on | ||||
|  * @seq: the &struct seq_file pointer to seq_printf into | ||||
|  * @utext: user supplied "heading" or other info | ||||
|  * @utext: user supplied additional "heading" or other info | ||||
|  * @detail: function pointer the user may provide to dump further details | ||||
|  * of the object the lc_element is embedded in. | ||||
|  * of the object the lc_element is embedded in. May be NULL. | ||||
|  * Note: a leading space ' ' and trailing newline '\n' is implied. | ||||
|  */ | ||||
| void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext, | ||||
| 	     void (*detail) (struct seq_file *, struct lc_element *)) | ||||
| @ -654,16 +655,18 @@ void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext | ||||
| 	struct lc_element *e; | ||||
| 	int i; | ||||
| 
 | ||||
| 	seq_printf(seq, "\tnn: lc_number refcnt %s\n ", utext); | ||||
| 	seq_printf(seq, "\tnn: lc_number (new nr) refcnt %s\n ", utext); | ||||
| 	for (i = 0; i < nr_elements; i++) { | ||||
| 		e = lc_element_by_index(lc, i); | ||||
| 		if (e->lc_number == LC_FREE) { | ||||
| 			seq_printf(seq, "\t%2d: FREE\n", i); | ||||
| 		} else { | ||||
| 			seq_printf(seq, "\t%2d: %4u %4u    ", i, | ||||
| 				   e->lc_number, e->refcnt); | ||||
| 		if (e->lc_number != e->lc_new_number) | ||||
| 			seq_printf(seq, "\t%5d: %6d %8d %6d ", | ||||
| 				i, e->lc_number, e->lc_new_number, e->refcnt); | ||||
| 		else | ||||
| 			seq_printf(seq, "\t%5d: %6d %-8s %6d ", | ||||
| 				i, e->lc_number, "-\"-", e->refcnt); | ||||
| 		if (detail) | ||||
| 			detail(seq, e); | ||||
| 		} | ||||
| 		seq_putc(seq, '\n'); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user