procobjecttree.c revision 927c7927eee73e195afc5b76ffb91bd72e3cb03d
1/* procobjecttree.c 2 * 3 * Copyright � 2010 - 2013 UNISYS CORPORATION 4 * All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or (at 9 * your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 14 * NON INFRINGEMENT. See the GNU General Public License for more 15 * details. 16 */ 17 18#include "procobjecttree.h" 19 20#define MYDRVNAME "procobjecttree" 21 22 23 24/** This is context info that we stash in each /proc file entry, which we 25 * need in order to call the callback function that supplies the /proc read 26 * info for that file. 27 */ 28typedef struct { 29 void (*show_property)(struct seq_file *, void *, int); 30 MYPROCOBJECT *procObject; 31 int propertyIndex; 32 33} PROCDIRENTRYCONTEXT; 34 35/** This describes the attributes of a tree rooted at 36 * <procDirRoot>/<name[0]>/<name[1]>/... 37 * Properties for each object of this type will be located under 38 * <procDirRoot>/<name[0]>/<name[1]>/.../<objectName>/<propertyName>. 39 */ 40struct MYPROCTYPE_Tag { 41 const char **name; /**< node names for this type, ending with NULL */ 42 int nNames; /**< num of node names in <name> */ 43 44 /** root dir for this type tree in /proc */ 45 struct proc_dir_entry *procDirRoot; 46 47 struct proc_dir_entry **procDirs; /**< for each node in <name> */ 48 49 /** bottom dir where objects will be rooted; i.e., this is 50 * <procDirRoot>/<name[0]>/<name[1]>/.../, which is the same as the 51 * last entry in the <procDirs> array. */ 52 struct proc_dir_entry *procDir; 53 54 /** name for each property that objects of this type can have */ 55 const char **propertyNames; 56 57 int nProperties; /**< num of names in <propertyNames> */ 58 59 /** Call this, passing MYPROCOBJECT.context and the property index 60 * whenever someone reads the proc entry */ 61 void (*show_property)(struct seq_file *, void *, int); 62}; 63 64 65 66struct MYPROCOBJECT_Tag { 67 MYPROCTYPE *type; 68 69 /** This is the name of the dir node in /proc under which the 70 * properties of this object will appear as files. */ 71 char *name; 72 73 int namesize; /**< number of bytes allocated for name */ 74 void *context; /**< passed to MYPROCTYPE.show_property */ 75 76 /** <type.procDirRoot>/<type.name[0]>/<type.name[1]>/.../<name> */ 77 struct proc_dir_entry *procDir; 78 79 /** a proc dir entry for each of the properties of the object; 80 * properties are identified in MYPROCTYPE.propertyNames, so each of 81 * the <procDirProperties> describes a single file like 82 * <type.procDirRoot>/<type.name[0]>/<type.name[1]>/... 83 * /<name>/<propertyName> 84 */ 85 struct proc_dir_entry **procDirProperties; 86 87 /** this is a holding area for the context information that is needed 88 * to run the /proc callback function */ 89 PROCDIRENTRYCONTEXT *procDirPropertyContexts; 90}; 91 92 93 94static struct proc_dir_entry * 95createProcDir(const char *name, struct proc_dir_entry *parent) 96{ 97 struct proc_dir_entry *p = proc_mkdir_mode(name, S_IFDIR, parent); 98 if (p == NULL) 99 ERRDRV("failed to create /proc directory %s", name); 100 return p; 101} 102 103static struct proc_dir_entry * 104createProcFile(const char *name, struct proc_dir_entry *parent, 105 const struct file_operations *fops, void *data) 106{ 107 struct proc_dir_entry *p = proc_create_data(name, 0, parent, 108 fops, data); 109 if (p == NULL) 110 ERRDRV("failed to create /proc file %s", name); 111 return p; 112} 113 114static int seq_show(struct seq_file *seq, void *offset); 115static int proc_open(struct inode *inode, struct file *file) 116{ 117 return single_open(file, seq_show, PDE_DATA(inode)); 118} 119 120static const struct file_operations proc_fops = { 121 .open = proc_open, 122 .read = seq_read, 123 .llseek = seq_lseek, 124 .release = single_release, 125}; 126 127 128 129MYPROCTYPE *visor_proc_CreateType(struct proc_dir_entry *procDirRoot, 130 const char **name, 131 const char **propertyNames, 132 void (*show_property)(struct seq_file *, 133 void *, int)) 134{ 135 int i = 0; 136 MYPROCTYPE *rc = NULL, *type = NULL; 137 struct proc_dir_entry *parent = NULL; 138 139 if (procDirRoot == NULL) 140 FAIL("procDirRoot cannot be NULL!", 0); 141 if (name == NULL || name[0] == NULL) 142 FAIL("name must contain at least 1 node name!", 0); 143 type = kmalloc(sizeof(MYPROCTYPE), GFP_KERNEL|__GFP_NORETRY); 144 if (type == NULL) 145 FAIL("out of memory", 0); 146 memset(type, 0, sizeof(MYPROCTYPE)); 147 type->name = name; 148 type->propertyNames = propertyNames; 149 type->nProperties = 0; 150 type->nNames = 0; 151 type->show_property = show_property; 152 type->procDirRoot = procDirRoot; 153 if (type->propertyNames != 0) 154 while (type->propertyNames[type->nProperties] != NULL) 155 type->nProperties++; 156 while (type->name[type->nNames] != NULL) 157 type->nNames++; 158 type->procDirs = kmalloc((type->nNames+1)* 159 sizeof(struct proc_dir_entry *), 160 GFP_KERNEL|__GFP_NORETRY); 161 if (type->procDirs == NULL) 162 FAIL("out of memory", 0); 163 memset(type->procDirs, 0, (type->nNames + 1) * 164 sizeof(struct proc_dir_entry *)); 165 parent = procDirRoot; 166 for (i = 0; i < type->nNames; i++) { 167 type->procDirs[i] = createProcDir(type->name[i], parent); 168 if (type->procDirs[i] == NULL) 169 RETPTR(NULL); 170 parent = type->procDirs[i]; 171 } 172 type->procDir = type->procDirs[type->nNames-1]; 173 RETPTR(type); 174Away: 175 if (rc == NULL) { 176 if (type != NULL) { 177 visor_proc_DestroyType(type); 178 type = NULL; 179 } 180 } 181 return rc; 182} 183EXPORT_SYMBOL_GPL(visor_proc_CreateType); 184 185 186 187void visor_proc_DestroyType(MYPROCTYPE *type) 188{ 189 if (type == NULL) 190 return; 191 if (type->procDirs != NULL) { 192 int i = type->nNames-1; 193 while (i >= 0) { 194 if (type->procDirs[i] != NULL) { 195 struct proc_dir_entry *parent = NULL; 196 if (i == 0) 197 parent = type->procDirRoot; 198 else 199 parent = type->procDirs[i-1]; 200 remove_proc_entry(type->name[i], parent); 201 } 202 i--; 203 } 204 kfree(type->procDirs); 205 type->procDirs = NULL; 206 } 207 kfree(type); 208} 209EXPORT_SYMBOL_GPL(visor_proc_DestroyType); 210 211 212 213MYPROCOBJECT *visor_proc_CreateObject(MYPROCTYPE *type, 214 const char *name, void *context) 215{ 216 MYPROCOBJECT *obj = NULL, *rc = NULL; 217 int i = 0; 218 219 if (type == NULL) 220 FAIL("type cannot be NULL", 0); 221 obj = kmalloc(sizeof(MYPROCOBJECT), GFP_KERNEL | __GFP_NORETRY); 222 if (obj == NULL) 223 FAIL("out of memory", 0); 224 memset(obj, 0, sizeof(MYPROCOBJECT)); 225 obj->type = type; 226 obj->context = context; 227 if (name == NULL) { 228 obj->name = NULL; 229 obj->procDir = type->procDir; 230 } else { 231 obj->namesize = strlen(name)+1; 232 obj->name = kmalloc(obj->namesize, GFP_KERNEL | __GFP_NORETRY); 233 if (obj->name == NULL) { 234 obj->namesize = 0; 235 FAIL("out of memory", 0); 236 } 237 strcpy(obj->name, name); 238 obj->procDir = createProcDir(obj->name, type->procDir); 239 if (obj->procDir == NULL) 240 RETPTR(NULL); 241 } 242 obj->procDirPropertyContexts = 243 kmalloc((type->nProperties+1)*sizeof(PROCDIRENTRYCONTEXT), 244 GFP_KERNEL|__GFP_NORETRY); 245 if (obj->procDirPropertyContexts == NULL) 246 FAIL("out of memory", 0); 247 memset(obj->procDirPropertyContexts, 0, 248 (type->nProperties+1)*sizeof(PROCDIRENTRYCONTEXT)); 249 obj->procDirProperties = 250 kmalloc((type->nProperties+1) * sizeof(struct proc_dir_entry *), 251 GFP_KERNEL|__GFP_NORETRY); 252 if (obj->procDirProperties == NULL) 253 FAIL("out of memory", 0); 254 memset(obj->procDirProperties, 0, 255 (type->nProperties+1) * sizeof(struct proc_dir_entry *)); 256 for (i = 0; i < type->nProperties; i++) { 257 obj->procDirPropertyContexts[i].procObject = obj; 258 obj->procDirPropertyContexts[i].propertyIndex = i; 259 obj->procDirPropertyContexts[i].show_property = 260 type->show_property; 261 if (type->propertyNames[i][0] != '\0') { 262 /* only create properties that have names */ 263 obj->procDirProperties[i] = 264 createProcFile(type->propertyNames[i], 265 obj->procDir, &proc_fops, 266 &obj->procDirPropertyContexts[i]); 267 if (obj->procDirProperties[i] == NULL) 268 RETPTR(NULL); 269 } 270 } 271 RETPTR(obj); 272Away: 273 if (rc == NULL) { 274 if (obj != NULL) { 275 visor_proc_DestroyObject(obj); 276 obj = NULL; 277 } 278 } 279 return rc; 280} 281EXPORT_SYMBOL_GPL(visor_proc_CreateObject); 282 283 284 285void visor_proc_DestroyObject(MYPROCOBJECT *obj) 286{ 287 MYPROCTYPE *type = NULL; 288 if (obj == NULL) 289 return; 290 type = obj->type; 291 if (type == NULL) 292 return; 293 if (obj->procDirProperties != NULL) { 294 int i = 0; 295 for (i = 0; i < type->nProperties; i++) { 296 if (obj->procDirProperties[i] != NULL) { 297 remove_proc_entry(type->propertyNames[i], 298 obj->procDir); 299 obj->procDirProperties[i] = NULL; 300 } 301 } 302 kfree(obj->procDirProperties); 303 obj->procDirProperties = NULL; 304 } 305 if (obj->procDirPropertyContexts != NULL) { 306 kfree(obj->procDirPropertyContexts); 307 obj->procDirPropertyContexts = NULL; 308 } 309 if (obj->procDir != NULL) { 310 if (obj->name != NULL) 311 remove_proc_entry(obj->name, type->procDir); 312 obj->procDir = NULL; 313 } 314 if (obj->name != NULL) { 315 kfree(obj->name); 316 obj->name = NULL; 317 } 318 kfree(obj); 319} 320EXPORT_SYMBOL_GPL(visor_proc_DestroyObject); 321 322 323 324static int seq_show(struct seq_file *seq, void *offset) 325{ 326 PROCDIRENTRYCONTEXT *ctx = (PROCDIRENTRYCONTEXT *)(seq->private); 327 if (ctx == NULL) { 328 ERRDRV("I don't have a freakin' clue..."); 329 return 0; 330 } 331 (*ctx->show_property)(seq, ctx->procObject->context, 332 ctx->propertyIndex); 333 return 0; 334} 335