1/* inode.c: /proc/openprom handling routines 2 * 3 * Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com) 4 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) 5 */ 6 7#include <linux/module.h> 8#include <linux/types.h> 9#include <linux/string.h> 10#include <linux/fs.h> 11#include <linux/init.h> 12#include <linux/slab.h> 13#include <linux/seq_file.h> 14#include <linux/magic.h> 15 16#include <asm/openprom.h> 17#include <asm/oplib.h> 18#include <asm/prom.h> 19#include <asm/uaccess.h> 20 21static DEFINE_MUTEX(op_mutex); 22 23#define OPENPROM_ROOT_INO 0 24 25enum op_inode_type { 26 op_inode_node, 27 op_inode_prop, 28}; 29 30union op_inode_data { 31 struct device_node *node; 32 struct property *prop; 33}; 34 35struct op_inode_info { 36 struct inode vfs_inode; 37 enum op_inode_type type; 38 union op_inode_data u; 39}; 40 41static struct inode *openprom_iget(struct super_block *sb, ino_t ino); 42 43static inline struct op_inode_info *OP_I(struct inode *inode) 44{ 45 return container_of(inode, struct op_inode_info, vfs_inode); 46} 47 48static int is_string(unsigned char *p, int len) 49{ 50 int i; 51 52 for (i = 0; i < len; i++) { 53 unsigned char val = p[i]; 54 55 if ((i && !val) || 56 (val >= ' ' && val <= '~')) 57 continue; 58 59 return 0; 60 } 61 62 return 1; 63} 64 65static int property_show(struct seq_file *f, void *v) 66{ 67 struct property *prop = f->private; 68 void *pval; 69 int len; 70 71 len = prop->length; 72 pval = prop->value; 73 74 if (is_string(pval, len)) { 75 while (len > 0) { 76 int n = strlen(pval); 77 78 seq_printf(f, "%s", (char *) pval); 79 80 /* Skip over the NULL byte too. */ 81 pval += n + 1; 82 len -= n + 1; 83 84 if (len > 0) 85 seq_printf(f, " + "); 86 } 87 } else { 88 if (len & 3) { 89 while (len) { 90 len--; 91 if (len) 92 seq_printf(f, "%02x.", 93 *(unsigned char *) pval); 94 else 95 seq_printf(f, "%02x", 96 *(unsigned char *) pval); 97 pval++; 98 } 99 } else { 100 while (len >= 4) { 101 len -= 4; 102 103 if (len) 104 seq_printf(f, "%08x.", 105 *(unsigned int *) pval); 106 else 107 seq_printf(f, "%08x", 108 *(unsigned int *) pval); 109 pval += 4; 110 } 111 } 112 } 113 seq_printf(f, "\n"); 114 115 return 0; 116} 117 118static void *property_start(struct seq_file *f, loff_t *pos) 119{ 120 if (*pos == 0) 121 return pos; 122 return NULL; 123} 124 125static void *property_next(struct seq_file *f, void *v, loff_t *pos) 126{ 127 (*pos)++; 128 return NULL; 129} 130 131static void property_stop(struct seq_file *f, void *v) 132{ 133 /* Nothing to do */ 134} 135 136static const struct seq_operations property_op = { 137 .start = property_start, 138 .next = property_next, 139 .stop = property_stop, 140 .show = property_show 141}; 142 143static int property_open(struct inode *inode, struct file *file) 144{ 145 struct op_inode_info *oi = OP_I(inode); 146 int ret; 147 148 BUG_ON(oi->type != op_inode_prop); 149 150 ret = seq_open(file, &property_op); 151 if (!ret) { 152 struct seq_file *m = file->private_data; 153 m->private = oi->u.prop; 154 } 155 return ret; 156} 157 158static const struct file_operations openpromfs_prop_ops = { 159 .open = property_open, 160 .read = seq_read, 161 .llseek = seq_lseek, 162 .release = seq_release, 163}; 164 165static int openpromfs_readdir(struct file *, struct dir_context *); 166 167static const struct file_operations openprom_operations = { 168 .read = generic_read_dir, 169 .iterate = openpromfs_readdir, 170 .llseek = generic_file_llseek, 171}; 172 173static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, unsigned int); 174 175static const struct inode_operations openprom_inode_operations = { 176 .lookup = openpromfs_lookup, 177}; 178 179static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 180{ 181 struct op_inode_info *ent_oi, *oi = OP_I(dir); 182 struct device_node *dp, *child; 183 struct property *prop; 184 enum op_inode_type ent_type; 185 union op_inode_data ent_data; 186 const char *name; 187 struct inode *inode; 188 unsigned int ino; 189 int len; 190 191 BUG_ON(oi->type != op_inode_node); 192 193 dp = oi->u.node; 194 195 name = dentry->d_name.name; 196 len = dentry->d_name.len; 197 198 mutex_lock(&op_mutex); 199 200 child = dp->child; 201 while (child) { 202 int n = strlen(child->path_component_name); 203 204 if (len == n && 205 !strncmp(child->path_component_name, name, len)) { 206 ent_type = op_inode_node; 207 ent_data.node = child; 208 ino = child->unique_id; 209 goto found; 210 } 211 child = child->sibling; 212 } 213 214 prop = dp->properties; 215 while (prop) { 216 int n = strlen(prop->name); 217 218 if (len == n && !strncmp(prop->name, name, len)) { 219 ent_type = op_inode_prop; 220 ent_data.prop = prop; 221 ino = prop->unique_id; 222 goto found; 223 } 224 225 prop = prop->next; 226 } 227 228 mutex_unlock(&op_mutex); 229 return ERR_PTR(-ENOENT); 230 231found: 232 inode = openprom_iget(dir->i_sb, ino); 233 mutex_unlock(&op_mutex); 234 if (IS_ERR(inode)) 235 return ERR_CAST(inode); 236 ent_oi = OP_I(inode); 237 ent_oi->type = ent_type; 238 ent_oi->u = ent_data; 239 240 switch (ent_type) { 241 case op_inode_node: 242 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 243 inode->i_op = &openprom_inode_operations; 244 inode->i_fop = &openprom_operations; 245 set_nlink(inode, 2); 246 break; 247 case op_inode_prop: 248 if (!strcmp(dp->name, "options") && (len == 17) && 249 !strncmp (name, "security-password", 17)) 250 inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; 251 else 252 inode->i_mode = S_IFREG | S_IRUGO; 253 inode->i_fop = &openpromfs_prop_ops; 254 set_nlink(inode, 1); 255 inode->i_size = ent_oi->u.prop->length; 256 break; 257 } 258 259 d_add(dentry, inode); 260 return NULL; 261} 262 263static int openpromfs_readdir(struct file *file, struct dir_context *ctx) 264{ 265 struct inode *inode = file_inode(file); 266 struct op_inode_info *oi = OP_I(inode); 267 struct device_node *dp = oi->u.node; 268 struct device_node *child; 269 struct property *prop; 270 int i; 271 272 mutex_lock(&op_mutex); 273 274 if (ctx->pos == 0) { 275 if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR)) 276 goto out; 277 ctx->pos = 1; 278 } 279 if (ctx->pos == 1) { 280 if (!dir_emit(ctx, "..", 2, 281 (dp->parent == NULL ? 282 OPENPROM_ROOT_INO : 283 dp->parent->unique_id), DT_DIR)) 284 goto out; 285 ctx->pos = 2; 286 } 287 i = ctx->pos - 2; 288 289 /* First, the children nodes as directories. */ 290 child = dp->child; 291 while (i && child) { 292 child = child->sibling; 293 i--; 294 } 295 while (child) { 296 if (!dir_emit(ctx, 297 child->path_component_name, 298 strlen(child->path_component_name), 299 child->unique_id, DT_DIR)) 300 goto out; 301 302 ctx->pos++; 303 child = child->sibling; 304 } 305 306 /* Next, the properties as files. */ 307 prop = dp->properties; 308 while (i && prop) { 309 prop = prop->next; 310 i--; 311 } 312 while (prop) { 313 if (!dir_emit(ctx, prop->name, strlen(prop->name), 314 prop->unique_id, DT_REG)) 315 goto out; 316 317 ctx->pos++; 318 prop = prop->next; 319 } 320 321out: 322 mutex_unlock(&op_mutex); 323 return 0; 324} 325 326static struct kmem_cache *op_inode_cachep; 327 328static struct inode *openprom_alloc_inode(struct super_block *sb) 329{ 330 struct op_inode_info *oi; 331 332 oi = kmem_cache_alloc(op_inode_cachep, GFP_KERNEL); 333 if (!oi) 334 return NULL; 335 336 return &oi->vfs_inode; 337} 338 339static void openprom_i_callback(struct rcu_head *head) 340{ 341 struct inode *inode = container_of(head, struct inode, i_rcu); 342 kmem_cache_free(op_inode_cachep, OP_I(inode)); 343} 344 345static void openprom_destroy_inode(struct inode *inode) 346{ 347 call_rcu(&inode->i_rcu, openprom_i_callback); 348} 349 350static struct inode *openprom_iget(struct super_block *sb, ino_t ino) 351{ 352 struct inode *inode; 353 354 inode = iget_locked(sb, ino); 355 if (!inode) 356 return ERR_PTR(-ENOMEM); 357 if (inode->i_state & I_NEW) { 358 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; 359 if (inode->i_ino == OPENPROM_ROOT_INO) { 360 inode->i_op = &openprom_inode_operations; 361 inode->i_fop = &openprom_operations; 362 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 363 } 364 unlock_new_inode(inode); 365 } 366 return inode; 367} 368 369static int openprom_remount(struct super_block *sb, int *flags, char *data) 370{ 371 sync_filesystem(sb); 372 *flags |= MS_NOATIME; 373 return 0; 374} 375 376static const struct super_operations openprom_sops = { 377 .alloc_inode = openprom_alloc_inode, 378 .destroy_inode = openprom_destroy_inode, 379 .statfs = simple_statfs, 380 .remount_fs = openprom_remount, 381}; 382 383static int openprom_fill_super(struct super_block *s, void *data, int silent) 384{ 385 struct inode *root_inode; 386 struct op_inode_info *oi; 387 int ret; 388 389 s->s_flags |= MS_NOATIME; 390 s->s_blocksize = 1024; 391 s->s_blocksize_bits = 10; 392 s->s_magic = OPENPROM_SUPER_MAGIC; 393 s->s_op = &openprom_sops; 394 s->s_time_gran = 1; 395 root_inode = openprom_iget(s, OPENPROM_ROOT_INO); 396 if (IS_ERR(root_inode)) { 397 ret = PTR_ERR(root_inode); 398 goto out_no_root; 399 } 400 401 oi = OP_I(root_inode); 402 oi->type = op_inode_node; 403 oi->u.node = of_find_node_by_path("/"); 404 405 s->s_root = d_make_root(root_inode); 406 if (!s->s_root) 407 goto out_no_root_dentry; 408 return 0; 409 410out_no_root_dentry: 411 ret = -ENOMEM; 412out_no_root: 413 printk("openprom_fill_super: get root inode failed\n"); 414 return ret; 415} 416 417static struct dentry *openprom_mount(struct file_system_type *fs_type, 418 int flags, const char *dev_name, void *data) 419{ 420 return mount_single(fs_type, flags, data, openprom_fill_super); 421} 422 423static struct file_system_type openprom_fs_type = { 424 .owner = THIS_MODULE, 425 .name = "openpromfs", 426 .mount = openprom_mount, 427 .kill_sb = kill_anon_super, 428}; 429MODULE_ALIAS_FS("openpromfs"); 430 431static void op_inode_init_once(void *data) 432{ 433 struct op_inode_info *oi = (struct op_inode_info *) data; 434 435 inode_init_once(&oi->vfs_inode); 436} 437 438static int __init init_openprom_fs(void) 439{ 440 int err; 441 442 op_inode_cachep = kmem_cache_create("op_inode_cache", 443 sizeof(struct op_inode_info), 444 0, 445 (SLAB_RECLAIM_ACCOUNT | 446 SLAB_MEM_SPREAD), 447 op_inode_init_once); 448 if (!op_inode_cachep) 449 return -ENOMEM; 450 451 err = register_filesystem(&openprom_fs_type); 452 if (err) 453 kmem_cache_destroy(op_inode_cachep); 454 455 return err; 456} 457 458static void __exit exit_openprom_fs(void) 459{ 460 unregister_filesystem(&openprom_fs_type); 461 /* 462 * Make sure all delayed rcu free inodes are flushed before we 463 * destroy cache. 464 */ 465 rcu_barrier(); 466 kmem_cache_destroy(op_inode_cachep); 467} 468 469module_init(init_openprom_fs) 470module_exit(exit_openprom_fs) 471MODULE_LICENSE("GPL"); 472