mirror of
				https://git.proxmox.com/git/mirror_zfs.git
				synced 2025-10-26 18:05:04 +03:00 
			
		
		
		
	FreeBSD: Add support for procfs_list
The procfs_list interface is required by several kstats. Implement
this functionality for FreeBSD to provide access to these kstats.
                           
Reviewed-by: Allan Jude <allan@klarasystems.com>
Reviewed-by: Ryan Moeller <ryan@ixsystems.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Matt Macy <mmacy@FreeBSD.org>
Closes #10890
			
			
This commit is contained in:
		
							parent
							
								
									3dad29fb4b
								
							
						
					
					
						commit
						7b8363d7f0
					
				| @ -83,6 +83,14 @@ typedef struct kstat_s kstat_t; | |||||||
| typedef int kid_t;				/* unique kstat id */ | typedef int kid_t;				/* unique kstat id */ | ||||||
| typedef int kstat_update_t(struct kstat_s *, int); /* dynamic update cb */ | typedef int kstat_update_t(struct kstat_s *, int); /* dynamic update cb */ | ||||||
| 
 | 
 | ||||||
|  | struct seq_file { | ||||||
|  | 	char *sf_buf; | ||||||
|  | 	size_t sf_size; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void seq_printf(struct seq_file *m, const char *fmt, ...); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| typedef struct kstat_module { | typedef struct kstat_module { | ||||||
| 	char ksm_name[KSTAT_STRLEN+1];		/* module name */ | 	char ksm_name[KSTAT_STRLEN+1];		/* module name */ | ||||||
| 	struct list_head ksm_module_list;	/* module linkage */ | 	struct list_head ksm_module_list;	/* module linkage */ | ||||||
| @ -92,6 +100,7 @@ typedef struct kstat_module { | |||||||
| 
 | 
 | ||||||
| typedef struct kstat_raw_ops { | typedef struct kstat_raw_ops { | ||||||
| 	int (*headers)(char *buf, size_t size); | 	int (*headers)(char *buf, size_t size); | ||||||
|  | 	int (*seq_headers)(struct seq_file *); | ||||||
| 	int (*data)(char *buf, size_t size, void *data); | 	int (*data)(char *buf, size_t size, void *data); | ||||||
| 	void *(*addr)(kstat_t *ksp, loff_t index); | 	void *(*addr)(kstat_t *ksp, loff_t index); | ||||||
| } kstat_raw_ops_t; | } kstat_raw_ops_t; | ||||||
| @ -112,6 +121,7 @@ struct kstat_s { | |||||||
| 	size_t		ks_data_size;		/* size of kstat data section */ | 	size_t		ks_data_size;		/* size of kstat data section */ | ||||||
| 	kstat_update_t	*ks_update;		/* dynamic updates */ | 	kstat_update_t	*ks_update;		/* dynamic updates */ | ||||||
| 	void		*ks_private;		/* private data */ | 	void		*ks_private;		/* private data */ | ||||||
|  | 	void		*ks_private1;		/* private data */ | ||||||
| 	kmutex_t	ks_private_lock;	/* kstat private data lock */ | 	kmutex_t	ks_private_lock;	/* kstat private data lock */ | ||||||
| 	kmutex_t	*ks_lock;		/* kstat data lock */ | 	kmutex_t	*ks_lock;		/* kstat data lock */ | ||||||
| 	struct list_head ks_list;		/* kstat linkage */ | 	struct list_head ks_list;		/* kstat linkage */ | ||||||
| @ -185,6 +195,12 @@ extern void __kstat_set_raw_ops(kstat_t *ksp, | |||||||
|     int (*data)(char *buf, size_t size, void *data), |     int (*data)(char *buf, size_t size, void *data), | ||||||
|     void* (*addr)(kstat_t *ksp, loff_t index)); |     void* (*addr)(kstat_t *ksp, loff_t index)); | ||||||
| 
 | 
 | ||||||
|  | extern void __kstat_set_seq_raw_ops(kstat_t *ksp, | ||||||
|  |     int (*headers)(struct seq_file *), | ||||||
|  |     int (*data)(char *buf, size_t size, void *data), | ||||||
|  |     void* (*addr)(kstat_t *ksp, loff_t index)); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| extern kstat_t *__kstat_create(const char *ks_module, int ks_instance, | extern kstat_t *__kstat_create(const char *ks_module, int ks_instance, | ||||||
|     const char *ks_name, const char *ks_class, uchar_t ks_type, |     const char *ks_name, const char *ks_class, uchar_t ks_type, | ||||||
|     uint_t ks_ndata, uchar_t ks_flags); |     uint_t ks_ndata, uchar_t ks_flags); | ||||||
| @ -196,6 +212,8 @@ extern void kstat_waitq_exit(kstat_io_t *); | |||||||
| extern void kstat_runq_enter(kstat_io_t *); | extern void kstat_runq_enter(kstat_io_t *); | ||||||
| extern void kstat_runq_exit(kstat_io_t *); | extern void kstat_runq_exit(kstat_io_t *); | ||||||
| 
 | 
 | ||||||
|  | #define	kstat_set_seq_raw_ops(k, h, d, a) \ | ||||||
|  |     __kstat_set_seq_raw_ops(k, h, d, a) | ||||||
| #define	kstat_set_raw_ops(k, h, d, a) \ | #define	kstat_set_raw_ops(k, h, d, a) \ | ||||||
|     __kstat_set_raw_ops(k, h, d, a) |     __kstat_set_raw_ops(k, h, d, a) | ||||||
| #define	kstat_create(m, i, n, c, t, s, f) \ | #define	kstat_create(m, i, n, c, t, s, f) \ | ||||||
|  | |||||||
| @ -33,16 +33,18 @@ | |||||||
|  * procfs list manipulation |  * procfs list manipulation | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| struct seq_file { }; | typedef struct procfs_list procfs_list_t; | ||||||
| void seq_printf(struct seq_file *m, const char *fmt, ...); | struct procfs_list { | ||||||
| 
 |  | ||||||
| typedef struct procfs_list { |  | ||||||
| 	void		*pl_private; | 	void		*pl_private; | ||||||
|  | 	void		*pl_next_data; | ||||||
| 	kmutex_t	pl_lock; | 	kmutex_t	pl_lock; | ||||||
| 	list_t		pl_list; | 	list_t		pl_list; | ||||||
| 	uint64_t	pl_next_id; | 	uint64_t	pl_next_id; | ||||||
|  | 	int		(*pl_show)(struct seq_file *f, void *p); | ||||||
|  | 	int		(*pl_show_header)(struct seq_file *f); | ||||||
|  | 	int		(*pl_clear)(procfs_list_t *procfs_list); | ||||||
| 	size_t		pl_node_offset; | 	size_t		pl_node_offset; | ||||||
| } procfs_list_t; | }; | ||||||
| 
 | 
 | ||||||
| typedef struct procfs_list_node { | typedef struct procfs_list_node { | ||||||
| 	list_node_t	pln_link; | 	list_node_t	pln_link; | ||||||
| @ -50,6 +52,7 @@ typedef struct procfs_list_node { | |||||||
| } procfs_list_node_t; | } procfs_list_node_t; | ||||||
| 
 | 
 | ||||||
| void procfs_list_install(const char *module, | void procfs_list_install(const char *module, | ||||||
|  |     const char *submodule, | ||||||
|     const char *name, |     const char *name, | ||||||
|     mode_t mode, |     mode_t mode, | ||||||
|     procfs_list_t *procfs_list, |     procfs_list_t *procfs_list, | ||||||
|  | |||||||
| @ -57,6 +57,7 @@ typedef struct procfs_list_node { | |||||||
| } procfs_list_node_t; | } procfs_list_node_t; | ||||||
| 
 | 
 | ||||||
| void procfs_list_install(const char *module, | void procfs_list_install(const char *module, | ||||||
|  |     const char *submodule, | ||||||
|     const char *name, |     const char *name, | ||||||
|     mode_t mode, |     mode_t mode, | ||||||
|     procfs_list_t *procfs_list, |     procfs_list_t *procfs_list, | ||||||
|  | |||||||
| @ -386,6 +386,7 @@ typedef struct procfs_list_node { | |||||||
| } procfs_list_node_t; | } procfs_list_node_t; | ||||||
| 
 | 
 | ||||||
| void procfs_list_install(const char *module, | void procfs_list_install(const char *module, | ||||||
|  |     const char *submodule, | ||||||
|     const char *name, |     const char *name, | ||||||
|     mode_t mode, |     mode_t mode, | ||||||
|     procfs_list_t *procfs_list, |     procfs_list_t *procfs_list, | ||||||
|  | |||||||
| @ -444,6 +444,7 @@ seq_printf(struct seq_file *m, const char *fmt, ...) | |||||||
| 
 | 
 | ||||||
| void | void | ||||||
| procfs_list_install(const char *module, | procfs_list_install(const char *module, | ||||||
|  |     const char *submodule, | ||||||
|     const char *name, |     const char *name, | ||||||
|     mode_t mode, |     mode_t mode, | ||||||
|     procfs_list_t *procfs_list, |     procfs_list_t *procfs_list, | ||||||
|  | |||||||
| @ -55,6 +55,17 @@ __kstat_set_raw_ops(kstat_t *ksp, | |||||||
| 	ksp->ks_raw_ops.addr    = addr; | 	ksp->ks_raw_ops.addr    = addr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void | ||||||
|  | __kstat_set_seq_raw_ops(kstat_t *ksp, | ||||||
|  |     int (*headers)(struct seq_file *f), | ||||||
|  |     int (*data)(char *buf, size_t size, void *data), | ||||||
|  |     void *(*addr)(kstat_t *ksp, loff_t index)) | ||||||
|  | { | ||||||
|  | 	ksp->ks_raw_ops.seq_headers = headers; | ||||||
|  | 	ksp->ks_raw_ops.data    = data; | ||||||
|  | 	ksp->ks_raw_ops.addr    = addr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int | static int | ||||||
| kstat_default_update(kstat_t *ksp, int rw) | kstat_default_update(kstat_t *ksp, int rw) | ||||||
| { | { | ||||||
| @ -160,7 +171,7 @@ kstat_sysctl_raw(SYSCTL_HANDLER_ARGS) | |||||||
| 	void *data; | 	void *data; | ||||||
| 	kstat_t *ksp = arg1; | 	kstat_t *ksp = arg1; | ||||||
| 	void *(*addr_op)(kstat_t *ksp, loff_t index); | 	void *(*addr_op)(kstat_t *ksp, loff_t index); | ||||||
| 	int n, rc = 0; | 	int n, has_header, rc = 0; | ||||||
| 
 | 
 | ||||||
| 	sb = sbuf_new_auto(); | 	sb = sbuf_new_auto(); | ||||||
| 	if (sb == NULL) | 	if (sb == NULL) | ||||||
| @ -180,14 +191,25 @@ kstat_sysctl_raw(SYSCTL_HANDLER_ARGS) | |||||||
| 	ksp->ks_raw_buf = malloc(PAGE_SIZE, M_TEMP, M_WAITOK); | 	ksp->ks_raw_buf = malloc(PAGE_SIZE, M_TEMP, M_WAITOK); | ||||||
| 
 | 
 | ||||||
| 	n = 0; | 	n = 0; | ||||||
|  | 	has_header = (ksp->ks_raw_ops.headers || | ||||||
|  | 	    ksp->ks_raw_ops.seq_headers); | ||||||
|  | 
 | ||||||
| restart_headers: | restart_headers: | ||||||
| 	if (ksp->ks_raw_ops.headers) { | 	if (ksp->ks_raw_ops.headers) { | ||||||
| 		rc = ksp->ks_raw_ops.headers( | 		rc = ksp->ks_raw_ops.headers( | ||||||
| 		    ksp->ks_raw_buf, ksp->ks_raw_bufsize); | 		    ksp->ks_raw_buf, ksp->ks_raw_bufsize); | ||||||
|  | 	} else if (ksp->ks_raw_ops.seq_headers) { | ||||||
|  | 		struct seq_file f; | ||||||
|  | 
 | ||||||
|  | 		f.sf_buf = ksp->ks_raw_buf; | ||||||
|  | 		f.sf_size = ksp->ks_raw_bufsize; | ||||||
|  | 		rc = ksp->ks_raw_ops.seq_headers(&f); | ||||||
|  | 	} | ||||||
|  | 	if (has_header) { | ||||||
| 		if (rc == ENOMEM && !kstat_resize_raw(ksp)) | 		if (rc == ENOMEM && !kstat_resize_raw(ksp)) | ||||||
| 			goto restart_headers; | 			goto restart_headers; | ||||||
| 		if (rc == 0) | 		if (rc == 0) | ||||||
| 			sbuf_printf(sb, "%s", ksp->ks_raw_buf); | 			sbuf_printf(sb, "\n%s", ksp->ks_raw_buf); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	while ((data = addr_op(ksp, n)) != NULL) { | 	while ((data = addr_op(ksp, n)) != NULL) { | ||||||
| @ -220,16 +242,21 @@ kstat_t * | |||||||
| __kstat_create(const char *module, int instance, const char *name, | __kstat_create(const char *module, int instance, const char *name, | ||||||
|     const char *class, uchar_t ks_type, uint_t ks_ndata, uchar_t flags) |     const char *class, uchar_t ks_type, uint_t ks_ndata, uchar_t flags) | ||||||
| { | { | ||||||
|  | 	char buf[KSTAT_STRLEN]; | ||||||
| 	struct sysctl_oid *root; | 	struct sysctl_oid *root; | ||||||
| 	kstat_t *ksp; | 	kstat_t *ksp; | ||||||
|  | 	char *pool; | ||||||
| 
 | 
 | ||||||
| 	KASSERT(instance == 0, ("instance=%d", instance)); | 	KASSERT(instance == 0, ("instance=%d", instance)); | ||||||
| 	if ((ks_type == KSTAT_TYPE_INTR) || (ks_type == KSTAT_TYPE_IO)) | 	if ((ks_type == KSTAT_TYPE_INTR) || (ks_type == KSTAT_TYPE_IO)) | ||||||
| 		ASSERT(ks_ndata == 1); | 		ASSERT(ks_ndata == 1); | ||||||
| 
 | 
 | ||||||
|  | 	if (class == NULL) | ||||||
|  | 		class = "misc"; | ||||||
|  | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Allocate the main structure. We don't need to copy module/class/name | 	 * Allocate the main structure. We don't need to keep a copy of | ||||||
| 	 * stuff in here, because it is only used for sysctl node creation | 	 * module in here, because it is only used for sysctl node creation | ||||||
| 	 * done in this function. | 	 * done in this function. | ||||||
| 	 */ | 	 */ | ||||||
| 	ksp = malloc(sizeof (*ksp), M_KSTAT, M_WAITOK|M_ZERO); | 	ksp = malloc(sizeof (*ksp), M_KSTAT, M_WAITOK|M_ZERO); | ||||||
| @ -237,8 +264,8 @@ __kstat_create(const char *module, int instance, const char *name, | |||||||
| 	ksp->ks_crtime = gethrtime(); | 	ksp->ks_crtime = gethrtime(); | ||||||
| 	ksp->ks_snaptime = ksp->ks_crtime; | 	ksp->ks_snaptime = ksp->ks_crtime; | ||||||
| 	ksp->ks_instance = instance; | 	ksp->ks_instance = instance; | ||||||
| 	strncpy(ksp->ks_name, name, KSTAT_STRLEN); | 	(void) strlcpy(ksp->ks_name, name, KSTAT_STRLEN); | ||||||
| 	strncpy(ksp->ks_class, class, KSTAT_STRLEN); | 	(void) strlcpy(ksp->ks_class, class, KSTAT_STRLEN); | ||||||
| 	ksp->ks_type = ks_type; | 	ksp->ks_type = ks_type; | ||||||
| 	ksp->ks_flags = flags; | 	ksp->ks_flags = flags; | ||||||
| 	ksp->ks_update = kstat_default_update; | 	ksp->ks_update = kstat_default_update; | ||||||
| @ -280,10 +307,22 @@ __kstat_create(const char *module, int instance, const char *name, | |||||||
| 			ksp = NULL; | 			ksp = NULL; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Some kstats use a module name like "zfs/poolname" to distinguish a | ||||||
|  | 	 * set of kstats belonging to a specific pool.  Split on '/' to add an | ||||||
|  | 	 * extra node for the pool name if needed. | ||||||
|  | 	 */ | ||||||
|  | 	(void) strlcpy(buf, module, KSTAT_STRLEN); | ||||||
|  | 	module = buf; | ||||||
|  | 	pool = strchr(module, '/'); | ||||||
|  | 	if (pool != NULL) | ||||||
|  | 		*pool++ = '\0'; | ||||||
|  | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Create sysctl tree for those statistics: | 	 * Create sysctl tree for those statistics: | ||||||
| 	 * | 	 * | ||||||
| 	 *	kstat.<module>.<class>.<name>. | 	 *	kstat.<module>[.<pool>].<class>.<name> | ||||||
| 	 */ | 	 */ | ||||||
| 	sysctl_ctx_init(&ksp->ks_sysctl_ctx); | 	sysctl_ctx_init(&ksp->ks_sysctl_ctx); | ||||||
| 	root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, | 	root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, | ||||||
| @ -295,11 +334,26 @@ __kstat_create(const char *module, int instance, const char *name, | |||||||
| 		free(ksp, M_KSTAT); | 		free(ksp, M_KSTAT); | ||||||
| 		return (NULL); | 		return (NULL); | ||||||
| 	} | 	} | ||||||
|  | 	if (pool != NULL) { | ||||||
|  | 		root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, | ||||||
|  | 		    SYSCTL_CHILDREN(root), OID_AUTO, pool, CTLFLAG_RW, 0, ""); | ||||||
|  | 		if (root == NULL) { | ||||||
|  | 			printf("%s: Cannot create kstat.%s.%s tree!\n", | ||||||
|  | 			    __func__, module, pool); | ||||||
|  | 			sysctl_ctx_free(&ksp->ks_sysctl_ctx); | ||||||
|  | 			free(ksp, M_KSTAT); | ||||||
|  | 			return (NULL); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, SYSCTL_CHILDREN(root), | 	root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, SYSCTL_CHILDREN(root), | ||||||
| 	    OID_AUTO, class, CTLFLAG_RW, 0, ""); | 	    OID_AUTO, class, CTLFLAG_RW, 0, ""); | ||||||
| 	if (root == NULL) { | 	if (root == NULL) { | ||||||
| 		printf("%s: Cannot create kstat.%s.%s tree!\n", __func__, | 		if (pool != NULL) | ||||||
| 		    module, class); | 			printf("%s: Cannot create kstat.%s.%s.%s tree!\n", | ||||||
|  | 			    __func__, module, pool, class); | ||||||
|  | 		else | ||||||
|  | 			printf("%s: Cannot create kstat.%s.%s tree!\n", | ||||||
|  | 			    __func__, module, class); | ||||||
| 		sysctl_ctx_free(&ksp->ks_sysctl_ctx); | 		sysctl_ctx_free(&ksp->ks_sysctl_ctx); | ||||||
| 		free(ksp, M_KSTAT); | 		free(ksp, M_KSTAT); | ||||||
| 		return (NULL); | 		return (NULL); | ||||||
| @ -309,8 +363,13 @@ __kstat_create(const char *module, int instance, const char *name, | |||||||
| 		    SYSCTL_CHILDREN(root), | 		    SYSCTL_CHILDREN(root), | ||||||
| 		    OID_AUTO, name, CTLFLAG_RW, 0, ""); | 		    OID_AUTO, name, CTLFLAG_RW, 0, ""); | ||||||
| 		if (root == NULL) { | 		if (root == NULL) { | ||||||
| 			printf("%s: Cannot create kstat.%s.%s.%s tree!\n", | 			if (pool != NULL) | ||||||
| 			    __func__, module, class, name); | 				printf("%s: Cannot create kstat.%s.%s.%s.%s " | ||||||
|  | 				    "tree!\n", __func__, module, pool, class, | ||||||
|  | 				    name); | ||||||
|  | 			else | ||||||
|  | 				printf("%s: Cannot create kstat.%s.%s.%s " | ||||||
|  | 				    "tree!\n", __func__, module, class, name); | ||||||
| 			sysctl_ctx_free(&ksp->ks_sysctl_ctx); | 			sysctl_ctx_free(&ksp->ks_sysctl_ctx); | ||||||
| 			free(ksp, M_KSTAT); | 			free(ksp, M_KSTAT); | ||||||
| 			return (NULL); | 			return (NULL); | ||||||
| @ -411,7 +470,6 @@ kstat_install(kstat_t *ksp) | |||||||
| 	switch (ksp->ks_type) { | 	switch (ksp->ks_type) { | ||||||
| 	case KSTAT_TYPE_NAMED: | 	case KSTAT_TYPE_NAMED: | ||||||
| 		return (kstat_install_named(ksp)); | 		return (kstat_install_named(ksp)); | ||||||
| 		break; |  | ||||||
| 	case KSTAT_TYPE_RAW: | 	case KSTAT_TYPE_RAW: | ||||||
| 		if (ksp->ks_raw_ops.data) { | 		if (ksp->ks_raw_ops.data) { | ||||||
| 			root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, | 			root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, | ||||||
| @ -426,7 +484,6 @@ kstat_install(kstat_t *ksp) | |||||||
| 			    CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, | 			    CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, | ||||||
| 			    ksp, 0, kstat_sysctl_raw, "", ksp->ks_name); | 			    ksp, 0, kstat_sysctl_raw, "", ksp->ks_name); | ||||||
| 		} | 		} | ||||||
| 		VERIFY(root != NULL); |  | ||||||
| 		break; | 		break; | ||||||
| 	case KSTAT_TYPE_IO: | 	case KSTAT_TYPE_IO: | ||||||
| 		root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, | 		root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, | ||||||
| @ -440,6 +497,7 @@ kstat_install(kstat_t *ksp) | |||||||
| 	default: | 	default: | ||||||
| 		panic("unsupported kstat type %d\n", ksp->ks_type); | 		panic("unsupported kstat type %d\n", ksp->ks_type); | ||||||
| 	} | 	} | ||||||
|  | 	VERIFY(root != NULL); | ||||||
| 	ksp->ks_sysctl_root = root; | 	ksp->ks_sysctl_root = root; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -32,12 +32,74 @@ __FBSDID("$FreeBSD$"); | |||||||
| #include <sys/mutex.h> | #include <sys/mutex.h> | ||||||
| #include <sys/procfs_list.h> | #include <sys/procfs_list.h> | ||||||
| 
 | 
 | ||||||
|  | typedef struct procfs_list_iter { | ||||||
|  | 	procfs_list_t *pli_pl; | ||||||
|  | 	void *pli_elt; | ||||||
|  | } pli_t; | ||||||
|  | 
 | ||||||
| void | void | ||||||
| seq_printf(struct seq_file *m, const char *fmt, ...) | seq_printf(struct seq_file *f, const char *fmt, ...) | ||||||
| {} | { | ||||||
|  | 	va_list adx; | ||||||
|  | 
 | ||||||
|  | 	va_start(adx, fmt); | ||||||
|  | 	(void) vsnprintf(f->sf_buf, f->sf_size, fmt, adx); | ||||||
|  | 	va_end(adx); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int | ||||||
|  | procfs_list_update(kstat_t *ksp, int rw) | ||||||
|  | { | ||||||
|  | 	procfs_list_t *pl = ksp->ks_private; | ||||||
|  | 
 | ||||||
|  | 	if (rw == KSTAT_WRITE) | ||||||
|  | 		pl->pl_clear(pl); | ||||||
|  | 
 | ||||||
|  | 	return (0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int | ||||||
|  | procfs_list_data(char *buf, size_t size, void *data) | ||||||
|  | { | ||||||
|  | 	pli_t *p; | ||||||
|  | 	void *elt; | ||||||
|  | 	procfs_list_t *pl; | ||||||
|  | 	struct seq_file f; | ||||||
|  | 
 | ||||||
|  | 	p = data; | ||||||
|  | 	pl = p->pli_pl; | ||||||
|  | 	elt = p->pli_elt; | ||||||
|  | 	free(p, M_TEMP); | ||||||
|  | 	f.sf_buf = buf; | ||||||
|  | 	f.sf_size = size; | ||||||
|  | 	return (pl->pl_show(&f, elt)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void * | ||||||
|  | procfs_list_addr(kstat_t *ksp, loff_t n) | ||||||
|  | { | ||||||
|  | 	procfs_list_t *pl = ksp->ks_private; | ||||||
|  | 	void *elt = ksp->ks_private1; | ||||||
|  | 	pli_t *p = NULL; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	if (n == 0) | ||||||
|  | 		ksp->ks_private1 = list_head(&pl->pl_list); | ||||||
|  | 	else if (elt) | ||||||
|  | 		ksp->ks_private1 = list_next(&pl->pl_list, elt); | ||||||
|  | 
 | ||||||
|  | 	if (ksp->ks_private1) { | ||||||
|  | 		p = malloc(sizeof (*p), M_TEMP, M_WAITOK); | ||||||
|  | 		p->pli_pl = pl; | ||||||
|  | 		p->pli_elt = ksp->ks_private1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return (p); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
| procfs_list_install(const char *module, | procfs_list_install(const char *module, | ||||||
|  |     const char *submodule, | ||||||
|     const char *name, |     const char *name, | ||||||
|     mode_t mode, |     mode_t mode, | ||||||
|     procfs_list_t *procfs_list, |     procfs_list_t *procfs_list, | ||||||
| @ -46,12 +108,31 @@ procfs_list_install(const char *module, | |||||||
|     int (*clear)(procfs_list_t *procfs_list), |     int (*clear)(procfs_list_t *procfs_list), | ||||||
|     size_t procfs_list_node_off) |     size_t procfs_list_node_off) | ||||||
| { | { | ||||||
|  | 	kstat_t *procfs_kstat; | ||||||
|  | 
 | ||||||
| 	mutex_init(&procfs_list->pl_lock, NULL, MUTEX_DEFAULT, NULL); | 	mutex_init(&procfs_list->pl_lock, NULL, MUTEX_DEFAULT, NULL); | ||||||
| 	list_create(&procfs_list->pl_list, | 	list_create(&procfs_list->pl_list, | ||||||
| 	    procfs_list_node_off + sizeof (procfs_list_node_t), | 	    procfs_list_node_off + sizeof (procfs_list_node_t), | ||||||
| 	    procfs_list_node_off + offsetof(procfs_list_node_t, pln_link)); | 	    procfs_list_node_off + offsetof(procfs_list_node_t, pln_link)); | ||||||
|  | 	procfs_list->pl_show = show; | ||||||
|  | 	procfs_list->pl_show_header = show_header; | ||||||
|  | 	procfs_list->pl_clear = clear; | ||||||
| 	procfs_list->pl_next_id = 1; | 	procfs_list->pl_next_id = 1; | ||||||
| 	procfs_list->pl_node_offset = procfs_list_node_off; | 	procfs_list->pl_node_offset = procfs_list_node_off; | ||||||
|  | 
 | ||||||
|  | 	procfs_kstat =  kstat_create(module, 0, name, submodule, | ||||||
|  | 	    KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL); | ||||||
|  | 
 | ||||||
|  | 	if (procfs_kstat) { | ||||||
|  | 		procfs_kstat->ks_lock = &procfs_list->pl_lock; | ||||||
|  | 		procfs_kstat->ks_ndata = UINT32_MAX; | ||||||
|  | 		procfs_kstat->ks_private = procfs_list; | ||||||
|  | 		procfs_kstat->ks_update = procfs_list_update; | ||||||
|  | 		kstat_set_seq_raw_ops(procfs_kstat, show_header, | ||||||
|  | 		    procfs_list_data, procfs_list_addr); | ||||||
|  | 		kstat_install(procfs_kstat); | ||||||
|  | 		procfs_list->pl_private = procfs_kstat; | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
| @ -62,6 +143,7 @@ void | |||||||
| procfs_list_destroy(procfs_list_t *procfs_list) | procfs_list_destroy(procfs_list_t *procfs_list) | ||||||
| { | { | ||||||
| 	ASSERT(list_is_empty(&procfs_list->pl_list)); | 	ASSERT(list_is_empty(&procfs_list->pl_list)); | ||||||
|  | 	kstat_delete(procfs_list->pl_private); | ||||||
| 	list_destroy(&procfs_list->pl_list); | 	list_destroy(&procfs_list->pl_list); | ||||||
| 	mutex_destroy(&procfs_list->pl_lock); | 	mutex_destroy(&procfs_list->pl_lock); | ||||||
| } | } | ||||||
|  | |||||||
| @ -207,6 +207,7 @@ static const kstat_proc_op_t procfs_list_operations = { | |||||||
|  */ |  */ | ||||||
| void | void | ||||||
| procfs_list_install(const char *module, | procfs_list_install(const char *module, | ||||||
|  |     const char *submodule, | ||||||
|     const char *name, |     const char *name, | ||||||
|     mode_t mode, |     mode_t mode, | ||||||
|     procfs_list_t *procfs_list, |     procfs_list_t *procfs_list, | ||||||
| @ -215,6 +216,12 @@ procfs_list_install(const char *module, | |||||||
|     int (*clear)(procfs_list_t *procfs_list), |     int (*clear)(procfs_list_t *procfs_list), | ||||||
|     size_t procfs_list_node_off) |     size_t procfs_list_node_off) | ||||||
| { | { | ||||||
|  | 	char *modulestr; | ||||||
|  | 
 | ||||||
|  | 	if (submodule != NULL) | ||||||
|  | 		modulestr = kmem_asprintf("%s/%s", module, submodule); | ||||||
|  | 	else | ||||||
|  | 		modulestr = kmem_asprintf("%s", module); | ||||||
| 	mutex_init(&procfs_list->pl_lock, NULL, MUTEX_DEFAULT, NULL); | 	mutex_init(&procfs_list->pl_lock, NULL, MUTEX_DEFAULT, NULL); | ||||||
| 	list_create(&procfs_list->pl_list, | 	list_create(&procfs_list->pl_list, | ||||||
| 	    procfs_list_node_off + sizeof (procfs_list_node_t), | 	    procfs_list_node_off + sizeof (procfs_list_node_t), | ||||||
| @ -225,9 +232,10 @@ procfs_list_install(const char *module, | |||||||
| 	procfs_list->pl_clear = clear; | 	procfs_list->pl_clear = clear; | ||||||
| 	procfs_list->pl_node_offset = procfs_list_node_off; | 	procfs_list->pl_node_offset = procfs_list_node_off; | ||||||
| 
 | 
 | ||||||
| 	kstat_proc_entry_init(&procfs_list->pl_kstat_entry, module, name); | 	kstat_proc_entry_init(&procfs_list->pl_kstat_entry, modulestr, name); | ||||||
| 	kstat_proc_entry_install(&procfs_list->pl_kstat_entry, mode, | 	kstat_proc_entry_install(&procfs_list->pl_kstat_entry, mode, | ||||||
| 	    &procfs_list_operations, procfs_list); | 	    &procfs_list_operations, procfs_list); | ||||||
|  | 	kmem_strfree(modulestr); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(procfs_list_install); | EXPORT_SYMBOL(procfs_list_install); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -94,6 +94,7 @@ void | |||||||
| zfs_dbgmsg_init(void) | zfs_dbgmsg_init(void) | ||||||
| { | { | ||||||
| 	procfs_list_install("zfs", | 	procfs_list_install("zfs", | ||||||
|  | 	    NULL, | ||||||
| 	    "dbgmsg", | 	    "dbgmsg", | ||||||
| 	    0600, | 	    0600, | ||||||
| 	    &zfs_dbgmsgs, | 	    &zfs_dbgmsgs, | ||||||
|  | |||||||
| @ -2169,6 +2169,7 @@ spa_import_progress_init(void) | |||||||
| 	    spa_import_progress_list; | 	    spa_import_progress_list; | ||||||
| 
 | 
 | ||||||
| 	procfs_list_install("zfs", | 	procfs_list_install("zfs", | ||||||
|  | 	    NULL, | ||||||
| 	    "import_progress", | 	    "import_progress", | ||||||
| 	    0644, | 	    0644, | ||||||
| 	    &spa_import_progress_list->procfs_list, | 	    &spa_import_progress_list->procfs_list, | ||||||
|  | |||||||
| @ -122,14 +122,11 @@ static void | |||||||
| spa_read_history_init(spa_t *spa) | spa_read_history_init(spa_t *spa) | ||||||
| { | { | ||||||
| 	spa_history_list_t *shl = &spa->spa_stats.read_history; | 	spa_history_list_t *shl = &spa->spa_stats.read_history; | ||||||
| 	char *module; |  | ||||||
| 
 | 
 | ||||||
| 	shl->size = 0; | 	shl->size = 0; | ||||||
| 
 |  | ||||||
| 	module = kmem_asprintf("zfs/%s", spa_name(spa)); |  | ||||||
| 
 |  | ||||||
| 	shl->procfs_list.pl_private = shl; | 	shl->procfs_list.pl_private = shl; | ||||||
| 	procfs_list_install(module, | 	procfs_list_install("zfs", | ||||||
|  | 	    spa_name(spa), | ||||||
| 	    "reads", | 	    "reads", | ||||||
| 	    0600, | 	    0600, | ||||||
| 	    &shl->procfs_list, | 	    &shl->procfs_list, | ||||||
| @ -137,8 +134,6 @@ spa_read_history_init(spa_t *spa) | |||||||
| 	    spa_read_history_show_header, | 	    spa_read_history_show_header, | ||||||
| 	    spa_read_history_clear, | 	    spa_read_history_clear, | ||||||
| 	    offsetof(spa_read_history_t, srh_node)); | 	    offsetof(spa_read_history_t, srh_node)); | ||||||
| 
 |  | ||||||
| 	kmem_strfree(module); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| @ -293,14 +288,11 @@ static void | |||||||
| spa_txg_history_init(spa_t *spa) | spa_txg_history_init(spa_t *spa) | ||||||
| { | { | ||||||
| 	spa_history_list_t *shl = &spa->spa_stats.txg_history; | 	spa_history_list_t *shl = &spa->spa_stats.txg_history; | ||||||
| 	char *module; |  | ||||||
| 
 | 
 | ||||||
| 	shl->size = 0; | 	shl->size = 0; | ||||||
| 
 |  | ||||||
| 	module = kmem_asprintf("zfs/%s", spa_name(spa)); |  | ||||||
| 
 |  | ||||||
| 	shl->procfs_list.pl_private = shl; | 	shl->procfs_list.pl_private = shl; | ||||||
| 	procfs_list_install(module, | 	procfs_list_install("zfs", | ||||||
|  | 	    spa_name(spa), | ||||||
| 	    "txgs", | 	    "txgs", | ||||||
| 	    0644, | 	    0644, | ||||||
| 	    &shl->procfs_list, | 	    &shl->procfs_list, | ||||||
| @ -308,8 +300,6 @@ spa_txg_history_init(spa_t *spa) | |||||||
| 	    spa_txg_history_show_header, | 	    spa_txg_history_show_header, | ||||||
| 	    spa_txg_history_clear, | 	    spa_txg_history_clear, | ||||||
| 	    offsetof(spa_txg_history_t, sth_node)); | 	    offsetof(spa_txg_history_t, sth_node)); | ||||||
| 
 |  | ||||||
| 	kmem_strfree(module); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| @ -699,14 +689,12 @@ static void | |||||||
| spa_mmp_history_init(spa_t *spa) | spa_mmp_history_init(spa_t *spa) | ||||||
| { | { | ||||||
| 	spa_history_list_t *shl = &spa->spa_stats.mmp_history; | 	spa_history_list_t *shl = &spa->spa_stats.mmp_history; | ||||||
| 	char *module; |  | ||||||
| 
 | 
 | ||||||
| 	shl->size = 0; | 	shl->size = 0; | ||||||
| 
 | 
 | ||||||
| 	module = kmem_asprintf("zfs/%s", spa_name(spa)); |  | ||||||
| 
 |  | ||||||
| 	shl->procfs_list.pl_private = shl; | 	shl->procfs_list.pl_private = shl; | ||||||
| 	procfs_list_install(module, | 	procfs_list_install("zfs", | ||||||
|  | 	    spa_name(spa), | ||||||
| 	    "multihost", | 	    "multihost", | ||||||
| 	    0644, | 	    0644, | ||||||
| 	    &shl->procfs_list, | 	    &shl->procfs_list, | ||||||
| @ -714,8 +702,6 @@ spa_mmp_history_init(spa_t *spa) | |||||||
| 	    spa_mmp_history_show_header, | 	    spa_mmp_history_show_header, | ||||||
| 	    spa_mmp_history_clear, | 	    spa_mmp_history_clear, | ||||||
| 	    offsetof(spa_mmp_history_t, smh_node)); | 	    offsetof(spa_mmp_history_t, smh_node)); | ||||||
| 
 |  | ||||||
| 	kmem_strfree(module); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Matthew Macy
						Matthew Macy