19d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox/* procobjecttree.c
29d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox *
3f6d0c1e62b111bef3be279e4bf1bc2a6d560e205Benjamin Romer * Copyright (C) 2010 - 2013 UNISYS CORPORATION
49d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox * All rights reserved.
59d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox *
69d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox * This program is free software; you can redistribute it and/or modify
79d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox * it under the terms of the GNU General Public License as published by
89d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox * the Free Software Foundation; either version 2 of the License, or (at
99d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox * your option) any later version.
109d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox *
119d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox * This program is distributed in the hope that it will be useful, but
129d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox * WITHOUT ANY WARRANTY; without even the implied warranty of
139d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
149d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox * NON INFRINGEMENT.  See the GNU General Public License for more
159d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox * details.
169d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox */
179d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
189d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox#include "procobjecttree.h"
199d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
209d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox#define MYDRVNAME "procobjecttree"
219d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
229d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
239d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
249d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox/** This is context info that we stash in each /proc file entry, which we
259d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox *  need in order to call the callback function that supplies the /proc read
269d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox *  info for that file.
279d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox */
289d9baadd4069c77a97bf530abad9ddb74875fe76Ken Coxtypedef struct {
299d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	void (*show_property)(struct seq_file *, void *, int);
309d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	MYPROCOBJECT *procObject;
319d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	int propertyIndex;
329d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
339d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox} PROCDIRENTRYCONTEXT;
349d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
359d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox/** This describes the attributes of a tree rooted at
369d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox *  <procDirRoot>/<name[0]>/<name[1]>/...
379d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox *  Properties for each object of this type will be located under
389d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox *  <procDirRoot>/<name[0]>/<name[1]>/.../<objectName>/<propertyName>.
399d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox */
409d9baadd4069c77a97bf530abad9ddb74875fe76Ken Coxstruct MYPROCTYPE_Tag {
419d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	const char **name;  /**< node names for this type, ending with NULL */
429d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	int nNames;         /**< num of node names in <name> */
439d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
449d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	/** root dir for this type tree in /proc */
459d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	struct proc_dir_entry *procDirRoot;
469d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
479d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	struct proc_dir_entry **procDirs;  /**< for each node in <name> */
489d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
499d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	/** bottom dir where objects will be rooted; i.e., this is
509d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	 *  <procDirRoot>/<name[0]>/<name[1]>/.../, which is the same as the
519d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	 *  last entry in the <procDirs> array. */
529d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	struct proc_dir_entry *procDir;
539d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
549d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	/** name for each property that objects of this type can have */
559d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	const char **propertyNames;
569d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
579d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	int nProperties;       /**< num of names in <propertyNames> */
589d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
599d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	/** Call this, passing MYPROCOBJECT.context and the property index
609d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	 *  whenever someone reads the proc entry */
619d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	void (*show_property)(struct seq_file *, void *, int);
629d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox};
639d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
649d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
659d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
669d9baadd4069c77a97bf530abad9ddb74875fe76Ken Coxstruct MYPROCOBJECT_Tag {
679d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	MYPROCTYPE *type;
689d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
699d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	/** This is the name of the dir node in /proc under which the
709d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	 *  properties of this object will appear as files. */
719d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	char *name;
729d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
739d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	int namesize;   /**< number of bytes allocated for name */
749d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	void *context;  /**< passed to MYPROCTYPE.show_property */
759d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
769d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	/** <type.procDirRoot>/<type.name[0]>/<type.name[1]>/.../<name> */
779d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	struct proc_dir_entry *procDir;
789d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
799d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	/** a proc dir entry for each of the properties of the object;
809d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	 *  properties are identified in MYPROCTYPE.propertyNames, so each of
819d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	 *  the <procDirProperties> describes a single file like
829d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	 *  <type.procDirRoot>/<type.name[0]>/<type.name[1]>/...
839d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	 *           /<name>/<propertyName>
849d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	 */
859d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	struct proc_dir_entry **procDirProperties;
869d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
879d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	/** this is a holding area for the context information that is needed
889d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	 *  to run the /proc callback function */
899d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	PROCDIRENTRYCONTEXT *procDirPropertyContexts;
909d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox};
919d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
929d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
939d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
949d9baadd4069c77a97bf530abad9ddb74875fe76Ken Coxstatic struct proc_dir_entry *
959d9baadd4069c77a97bf530abad9ddb74875fe76Ken CoxcreateProcDir(const char *name, struct proc_dir_entry *parent)
969d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox{
979d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	struct proc_dir_entry *p = proc_mkdir_mode(name, S_IFDIR, parent);
98e03e1e39b6d66c11d71c91a080b479fb432e3674Masaru Nomura
999d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	if (p == NULL)
1009d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		ERRDRV("failed to create /proc directory %s", name);
1019d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	return p;
1029d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox}
1039d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
1049d9baadd4069c77a97bf530abad9ddb74875fe76Ken Coxstatic struct proc_dir_entry *
1059d9baadd4069c77a97bf530abad9ddb74875fe76Ken CoxcreateProcFile(const char *name, struct proc_dir_entry *parent,
1069d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	       const struct file_operations *fops, void *data)
1079d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox{
1089d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	struct proc_dir_entry *p = proc_create_data(name, 0, parent,
1099d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox						    fops, data);
1109d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	if (p == NULL)
1119d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		ERRDRV("failed to create /proc file %s", name);
1129d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	return p;
1139d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox}
1149d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
1159d9baadd4069c77a97bf530abad9ddb74875fe76Ken Coxstatic int seq_show(struct seq_file *seq, void *offset);
1169d9baadd4069c77a97bf530abad9ddb74875fe76Ken Coxstatic int proc_open(struct inode *inode, struct file *file)
1179d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox{
1189d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	return single_open(file, seq_show, PDE_DATA(inode));
1199d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox}
1209d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
1219d9baadd4069c77a97bf530abad9ddb74875fe76Ken Coxstatic const struct file_operations proc_fops = {
1229d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	.open = proc_open,
1239d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	.read = seq_read,
1249d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	.llseek = seq_lseek,
1259d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	.release = single_release,
1269d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox};
1279d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
1289d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
1299d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
130927c7927eee73e195afc5b76ffb91bd72e3cb03dKen CoxMYPROCTYPE *visor_proc_CreateType(struct proc_dir_entry *procDirRoot,
131927c7927eee73e195afc5b76ffb91bd72e3cb03dKen Cox				  const char **name,
132927c7927eee73e195afc5b76ffb91bd72e3cb03dKen Cox				  const char **propertyNames,
133927c7927eee73e195afc5b76ffb91bd72e3cb03dKen Cox				  void (*show_property)(struct seq_file *,
134927c7927eee73e195afc5b76ffb91bd72e3cb03dKen Cox							void *, int))
1359d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox{
1369d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	int i = 0;
1379d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	MYPROCTYPE *rc = NULL, *type = NULL;
1389d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	struct proc_dir_entry *parent = NULL;
1399d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
1405e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	if (procDirRoot == NULL) {
1415e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		ERRDRV("procDirRoot cannot be NULL!\n");
1425e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		goto Away;
1435e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	}
1445e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	if (name == NULL || name[0] == NULL) {
1455e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		ERRDRV("name must contain at least 1 node name!\n");
1465e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		goto Away;
1475e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	}
14856116b2b09092565d140c0e72596d67a29dcf89cIulia Manda	type = kzalloc(sizeof(MYPROCTYPE), GFP_KERNEL | __GFP_NORETRY);
1495e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	if (type == NULL) {
1505e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		ERRDRV("out of memory\n");
1515e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		goto Away;
1525e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	}
1539d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	type->name = name;
1549d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	type->propertyNames = propertyNames;
1559d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	type->nProperties = 0;
1569d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	type->nNames = 0;
1579d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	type->show_property = show_property;
1589d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	type->procDirRoot = procDirRoot;
159a7710336596ecf49b3c1572dd40f4ecfefc6c9abKen Cox	if (type->propertyNames != NULL)
1609d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		while (type->propertyNames[type->nProperties] != NULL)
1619d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox			type->nProperties++;
1629d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	while (type->name[type->nNames] != NULL)
1639d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		type->nNames++;
16456116b2b09092565d140c0e72596d67a29dcf89cIulia Manda	type->procDirs = kzalloc((type->nNames + 1) *
1659d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox				 sizeof(struct proc_dir_entry *),
16656116b2b09092565d140c0e72596d67a29dcf89cIulia Manda				 GFP_KERNEL | __GFP_NORETRY);
1675e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	if (type->procDirs == NULL) {
1685e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		ERRDRV("out of memory\n");
1695e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		goto Away;
1705e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	}
1719d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	parent = procDirRoot;
1729d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	for (i = 0; i < type->nNames; i++) {
1739d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		type->procDirs[i] = createProcDir(type->name[i], parent);
174d9355f8934a4c54d81a29ae7bd5ae4329c02aa48Ken Cox		if (type->procDirs[i] == NULL) {
175d9355f8934a4c54d81a29ae7bd5ae4329c02aa48Ken Cox			rc = NULL;
176d9355f8934a4c54d81a29ae7bd5ae4329c02aa48Ken Cox			goto Away;
177d9355f8934a4c54d81a29ae7bd5ae4329c02aa48Ken Cox		}
1789d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		parent = type->procDirs[i];
1799d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	}
1809d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	type->procDir = type->procDirs[type->nNames-1];
181d9355f8934a4c54d81a29ae7bd5ae4329c02aa48Ken Cox	rc = type;
1829d9baadd4069c77a97bf530abad9ddb74875fe76Ken CoxAway:
1839d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	if (rc == NULL) {
1849d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		if (type != NULL) {
185927c7927eee73e195afc5b76ffb91bd72e3cb03dKen Cox			visor_proc_DestroyType(type);
1869d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox			type = NULL;
1879d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		}
1889d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	}
1899d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	return rc;
1909d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox}
191927c7927eee73e195afc5b76ffb91bd72e3cb03dKen CoxEXPORT_SYMBOL_GPL(visor_proc_CreateType);
1929d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
1939d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
1949d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
195927c7927eee73e195afc5b76ffb91bd72e3cb03dKen Coxvoid visor_proc_DestroyType(MYPROCTYPE *type)
1969d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox{
1979d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	if (type == NULL)
1989d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		return;
1999d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	if (type->procDirs != NULL) {
2009d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		int i = type->nNames-1;
201e03e1e39b6d66c11d71c91a080b479fb432e3674Masaru Nomura
2029d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		while (i >= 0) {
2039d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox			if (type->procDirs[i] != NULL) {
2049d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox				struct proc_dir_entry *parent = NULL;
205e03e1e39b6d66c11d71c91a080b479fb432e3674Masaru Nomura
2069d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox				if (i == 0)
2079d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox					parent = type->procDirRoot;
2089d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox				else
2099d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox					parent = type->procDirs[i-1];
2109d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox				remove_proc_entry(type->name[i], parent);
2119d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox			}
2129d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox			i--;
2139d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		}
2149d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		kfree(type->procDirs);
2159d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		type->procDirs = NULL;
2169d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	}
2179d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	kfree(type);
2189d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox}
219927c7927eee73e195afc5b76ffb91bd72e3cb03dKen CoxEXPORT_SYMBOL_GPL(visor_proc_DestroyType);
2209d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
2219d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
2229d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
223927c7927eee73e195afc5b76ffb91bd72e3cb03dKen CoxMYPROCOBJECT *visor_proc_CreateObject(MYPROCTYPE *type,
224927c7927eee73e195afc5b76ffb91bd72e3cb03dKen Cox				      const char *name, void *context)
2259d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox{
2269d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	MYPROCOBJECT *obj = NULL, *rc = NULL;
2279d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	int i = 0;
2289d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
2295e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	if (type == NULL) {
2305e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		ERRDRV("type cannot be NULL\n");
2315e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		goto Away;
2325e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	}
23356116b2b09092565d140c0e72596d67a29dcf89cIulia Manda	obj = kzalloc(sizeof(MYPROCOBJECT), GFP_KERNEL | __GFP_NORETRY);
2345e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	if (obj == NULL) {
2355e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		ERRDRV("out of memory\n");
2365e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		goto Away;
2375e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	}
2389d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	obj->type = type;
2399d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	obj->context = context;
2409d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	if (name == NULL) {
2419d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		obj->name = NULL;
2429d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		obj->procDir = type->procDir;
2439d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	} else {
2449d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		obj->namesize = strlen(name)+1;
2459d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		obj->name = kmalloc(obj->namesize, GFP_KERNEL | __GFP_NORETRY);
2469d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		if (obj->name == NULL) {
2479d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox			obj->namesize = 0;
2485e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox			ERRDRV("out of memory\n");
2495e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox			goto Away;
2509d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		}
2519d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		strcpy(obj->name, name);
2529d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		obj->procDir = createProcDir(obj->name, type->procDir);
2536905cae3a86f6411b62fda0c7a8e1c0d04eaef88Catalina Mocanu		if (obj->procDir == NULL)
254d9355f8934a4c54d81a29ae7bd5ae4329c02aa48Ken Cox			goto Away;
2559d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	}
2569d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	obj->procDirPropertyContexts =
25756116b2b09092565d140c0e72596d67a29dcf89cIulia Manda		kzalloc((type->nProperties + 1) * sizeof(PROCDIRENTRYCONTEXT),
25856116b2b09092565d140c0e72596d67a29dcf89cIulia Manda			GFP_KERNEL | __GFP_NORETRY);
2595e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	if (obj->procDirPropertyContexts == NULL) {
2605e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		ERRDRV("out of memory\n");
2615e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		goto Away;
2625e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	}
2639d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	obj->procDirProperties =
26456116b2b09092565d140c0e72596d67a29dcf89cIulia Manda		kzalloc((type->nProperties + 1) * sizeof(struct proc_dir_entry *),
26556116b2b09092565d140c0e72596d67a29dcf89cIulia Manda			GFP_KERNEL | __GFP_NORETRY);
2665e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	if (obj->procDirProperties == NULL) {
2675e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		ERRDRV("out of memory\n");
2685e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox		goto Away;
2695e54c97dab0298cf5479bc1f2d3f42ef5605ce6eKen Cox	}
2709d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	for (i = 0; i < type->nProperties; i++) {
2719d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		obj->procDirPropertyContexts[i].procObject = obj;
2729d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		obj->procDirPropertyContexts[i].propertyIndex = i;
2739d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		obj->procDirPropertyContexts[i].show_property =
2749d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox			type->show_property;
2759d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		if (type->propertyNames[i][0] != '\0') {
2769d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox			/* only create properties that have names */
2779d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox			obj->procDirProperties[i] =
2789d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox				createProcFile(type->propertyNames[i],
2799d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox					       obj->procDir, &proc_fops,
2809d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox					       &obj->procDirPropertyContexts[i]);
281d9355f8934a4c54d81a29ae7bd5ae4329c02aa48Ken Cox			if (obj->procDirProperties[i] == NULL) {
282d9355f8934a4c54d81a29ae7bd5ae4329c02aa48Ken Cox				rc = NULL;
283d9355f8934a4c54d81a29ae7bd5ae4329c02aa48Ken Cox				goto Away;
284d9355f8934a4c54d81a29ae7bd5ae4329c02aa48Ken Cox			}
2859d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		}
2869d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	}
287d9355f8934a4c54d81a29ae7bd5ae4329c02aa48Ken Cox	rc = obj;
2889d9baadd4069c77a97bf530abad9ddb74875fe76Ken CoxAway:
2899d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	if (rc == NULL) {
2909d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		if (obj != NULL) {
291927c7927eee73e195afc5b76ffb91bd72e3cb03dKen Cox			visor_proc_DestroyObject(obj);
2929d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox			obj = NULL;
2939d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		}
2949d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	}
2959d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	return rc;
2969d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox}
297927c7927eee73e195afc5b76ffb91bd72e3cb03dKen CoxEXPORT_SYMBOL_GPL(visor_proc_CreateObject);
2989d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
2999d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
3009d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
301927c7927eee73e195afc5b76ffb91bd72e3cb03dKen Coxvoid visor_proc_DestroyObject(MYPROCOBJECT *obj)
3029d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox{
3039d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	MYPROCTYPE *type = NULL;
304e03e1e39b6d66c11d71c91a080b479fb432e3674Masaru Nomura
3059d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	if (obj == NULL)
3069d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		return;
3079d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	type = obj->type;
3089d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	if (type == NULL)
3099d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		return;
3109d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	if (obj->procDirProperties != NULL) {
3119d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		int i = 0;
312e03e1e39b6d66c11d71c91a080b479fb432e3674Masaru Nomura
3139d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		for (i = 0; i < type->nProperties; i++) {
3149d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox			if (obj->procDirProperties[i] != NULL) {
3159d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox				remove_proc_entry(type->propertyNames[i],
3169d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox						  obj->procDir);
3179d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox				obj->procDirProperties[i] = NULL;
3189d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox			}
3199d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		}
3209d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		kfree(obj->procDirProperties);
3219d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		obj->procDirProperties = NULL;
3229d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	}
3239d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	if (obj->procDirPropertyContexts != NULL) {
3249d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		kfree(obj->procDirPropertyContexts);
3259d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		obj->procDirPropertyContexts = NULL;
3269d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	}
3279d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	if (obj->procDir != NULL) {
3289d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		if (obj->name != NULL)
3299d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox			remove_proc_entry(obj->name, type->procDir);
3309d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		obj->procDir = NULL;
3319d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	}
3329d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	if (obj->name != NULL) {
3339d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		kfree(obj->name);
3349d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		obj->name = NULL;
3359d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	}
3369d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	kfree(obj);
3379d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox}
338927c7927eee73e195afc5b76ffb91bd72e3cb03dKen CoxEXPORT_SYMBOL_GPL(visor_proc_DestroyObject);
3399d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
3409d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
3419d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox
3429d9baadd4069c77a97bf530abad9ddb74875fe76Ken Coxstatic int seq_show(struct seq_file *seq, void *offset)
3439d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox{
3449d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	PROCDIRENTRYCONTEXT *ctx = (PROCDIRENTRYCONTEXT *)(seq->private);
345e03e1e39b6d66c11d71c91a080b479fb432e3674Masaru Nomura
3469d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	if (ctx == NULL) {
3479d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		ERRDRV("I don't have a freakin' clue...");
3489d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox		return 0;
3499d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	}
3509d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	(*ctx->show_property)(seq, ctx->procObject->context,
3519d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox			      ctx->propertyIndex);
3529d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox	return 0;
3539d9baadd4069c77a97bf530abad9ddb74875fe76Ken Cox}
354