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 21 static DEFINE_MUTEX(op_mutex); 22 23 #define OPENPROM_ROOT_INO 0 24 25 enum op_inode_type { 26 op_inode_node, 27 op_inode_prop, 28 }; 29 30 union op_inode_data { 31 struct device_node *node; 32 struct property *prop; 33 }; 34 35 struct op_inode_info { 36 struct inode vfs_inode; 37 enum op_inode_type type; 38 union op_inode_data u; 39 }; 40 41 static struct inode *openprom_iget(struct super_block *sb, ino_t ino); 42 43 static inline struct op_inode_info *OP_I(struct inode *inode) 44 { 45 return container_of(inode, struct op_inode_info, vfs_inode); 46 } 47 48 static 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 65 static 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 118 static void *property_start(struct seq_file *f, loff_t *pos) 119 { 120 if (*pos == 0) 121 return pos; 122 return NULL; 123 } 124 125 static void *property_next(struct seq_file *f, void *v, loff_t *pos) 126 { 127 (*pos)++; 128 return NULL; 129 } 130 131 static void property_stop(struct seq_file *f, void *v) 132 { 133 /* Nothing to do */ 134 } 135 136 static const struct seq_operations property_op = { 137 .start = property_start, 138 .next = property_next, 139 .stop = property_stop, 140 .show = property_show 141 }; 142 143 static 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 158 static 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 165 static int openpromfs_readdir(struct file *, struct dir_context *); 166 167 static const struct file_operations openprom_operations = { 168 .read = generic_read_dir, 169 .iterate = openpromfs_readdir, 170 .llseek = generic_file_llseek, 171 }; 172 173 static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, unsigned int); 174 175 static const struct inode_operations openprom_inode_operations = { 176 .lookup = openpromfs_lookup, 177 }; 178 179 static 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 231 found: 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 263 static 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 321 out: 322 mutex_unlock(&op_mutex); 323 return 0; 324 } 325 326 static struct kmem_cache *op_inode_cachep; 327 328 static 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 339 static 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 345 static void openprom_destroy_inode(struct inode *inode) 346 { 347 call_rcu(&inode->i_rcu, openprom_i_callback); 348 } 349 350 static 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 369 static int openprom_remount(struct super_block *sb, int *flags, char *data) 370 { 371 *flags |= MS_NOATIME; 372 return 0; 373 } 374 375 static const struct super_operations openprom_sops = { 376 .alloc_inode = openprom_alloc_inode, 377 .destroy_inode = openprom_destroy_inode, 378 .statfs = simple_statfs, 379 .remount_fs = openprom_remount, 380 }; 381 382 static int openprom_fill_super(struct super_block *s, void *data, int silent) 383 { 384 struct inode *root_inode; 385 struct op_inode_info *oi; 386 int ret; 387 388 s->s_flags |= MS_NOATIME; 389 s->s_blocksize = 1024; 390 s->s_blocksize_bits = 10; 391 s->s_magic = OPENPROM_SUPER_MAGIC; 392 s->s_op = &openprom_sops; 393 s->s_time_gran = 1; 394 root_inode = openprom_iget(s, OPENPROM_ROOT_INO); 395 if (IS_ERR(root_inode)) { 396 ret = PTR_ERR(root_inode); 397 goto out_no_root; 398 } 399 400 oi = OP_I(root_inode); 401 oi->type = op_inode_node; 402 oi->u.node = of_find_node_by_path("/"); 403 404 s->s_root = d_make_root(root_inode); 405 if (!s->s_root) 406 goto out_no_root_dentry; 407 return 0; 408 409 out_no_root_dentry: 410 ret = -ENOMEM; 411 out_no_root: 412 printk("openprom_fill_super: get root inode failed\n"); 413 return ret; 414 } 415 416 static struct dentry *openprom_mount(struct file_system_type *fs_type, 417 int flags, const char *dev_name, void *data) 418 { 419 return mount_single(fs_type, flags, data, openprom_fill_super); 420 } 421 422 static struct file_system_type openprom_fs_type = { 423 .owner = THIS_MODULE, 424 .name = "openpromfs", 425 .mount = openprom_mount, 426 .kill_sb = kill_anon_super, 427 }; 428 MODULE_ALIAS_FS("openpromfs"); 429 430 static void op_inode_init_once(void *data) 431 { 432 struct op_inode_info *oi = (struct op_inode_info *) data; 433 434 inode_init_once(&oi->vfs_inode); 435 } 436 437 static int __init init_openprom_fs(void) 438 { 439 int err; 440 441 op_inode_cachep = kmem_cache_create("op_inode_cache", 442 sizeof(struct op_inode_info), 443 0, 444 (SLAB_RECLAIM_ACCOUNT | 445 SLAB_MEM_SPREAD), 446 op_inode_init_once); 447 if (!op_inode_cachep) 448 return -ENOMEM; 449 450 err = register_filesystem(&openprom_fs_type); 451 if (err) 452 kmem_cache_destroy(op_inode_cachep); 453 454 return err; 455 } 456 457 static void __exit exit_openprom_fs(void) 458 { 459 unregister_filesystem(&openprom_fs_type); 460 /* 461 * Make sure all delayed rcu free inodes are flushed before we 462 * destroy cache. 463 */ 464 rcu_barrier(); 465 kmem_cache_destroy(op_inode_cachep); 466 } 467 468 module_init(init_openprom_fs) 469 module_exit(exit_openprom_fs) 470 MODULE_LICENSE("GPL"); 471