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 <linux/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_shared = 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 const char *node_name = kbasename(child->full_name); 203 int n = strlen(node_name); 204 205 if (len == n && 206 !strncmp(node_name, name, len)) { 207 ent_type = op_inode_node; 208 ent_data.node = child; 209 ino = child->unique_id; 210 goto found; 211 } 212 child = child->sibling; 213 } 214 215 prop = dp->properties; 216 while (prop) { 217 int n = strlen(prop->name); 218 219 if (len == n && !strncmp(prop->name, name, len)) { 220 ent_type = op_inode_prop; 221 ent_data.prop = prop; 222 ino = prop->unique_id; 223 goto found; 224 } 225 226 prop = prop->next; 227 } 228 229 mutex_unlock(&op_mutex); 230 return ERR_PTR(-ENOENT); 231 232 found: 233 inode = openprom_iget(dir->i_sb, ino); 234 mutex_unlock(&op_mutex); 235 if (IS_ERR(inode)) 236 return ERR_CAST(inode); 237 ent_oi = OP_I(inode); 238 ent_oi->type = ent_type; 239 ent_oi->u = ent_data; 240 241 switch (ent_type) { 242 case op_inode_node: 243 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 244 inode->i_op = &openprom_inode_operations; 245 inode->i_fop = &openprom_operations; 246 set_nlink(inode, 2); 247 break; 248 case op_inode_prop: 249 if (of_node_name_eq(dp, "options") && (len == 17) && 250 !strncmp (name, "security-password", 17)) 251 inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; 252 else 253 inode->i_mode = S_IFREG | S_IRUGO; 254 inode->i_fop = &openpromfs_prop_ops; 255 set_nlink(inode, 1); 256 inode->i_size = ent_oi->u.prop->length; 257 break; 258 } 259 260 return d_splice_alias(inode, dentry); 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 kbasename(child->full_name), 298 strlen(kbasename(child->full_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_free_inode(struct inode *inode) 340 { 341 kmem_cache_free(op_inode_cachep, OP_I(inode)); 342 } 343 344 static struct inode *openprom_iget(struct super_block *sb, ino_t ino) 345 { 346 struct inode *inode; 347 348 inode = iget_locked(sb, ino); 349 if (!inode) 350 return ERR_PTR(-ENOMEM); 351 if (inode->i_state & I_NEW) { 352 inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 353 if (inode->i_ino == OPENPROM_ROOT_INO) { 354 inode->i_op = &openprom_inode_operations; 355 inode->i_fop = &openprom_operations; 356 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 357 } 358 unlock_new_inode(inode); 359 } 360 return inode; 361 } 362 363 static int openprom_remount(struct super_block *sb, int *flags, char *data) 364 { 365 sync_filesystem(sb); 366 *flags |= SB_NOATIME; 367 return 0; 368 } 369 370 static const struct super_operations openprom_sops = { 371 .alloc_inode = openprom_alloc_inode, 372 .free_inode = openprom_free_inode, 373 .statfs = simple_statfs, 374 .remount_fs = openprom_remount, 375 }; 376 377 static int openprom_fill_super(struct super_block *s, void *data, int silent) 378 { 379 struct inode *root_inode; 380 struct op_inode_info *oi; 381 int ret; 382 383 s->s_flags |= SB_NOATIME; 384 s->s_blocksize = 1024; 385 s->s_blocksize_bits = 10; 386 s->s_magic = OPENPROM_SUPER_MAGIC; 387 s->s_op = &openprom_sops; 388 s->s_time_gran = 1; 389 root_inode = openprom_iget(s, OPENPROM_ROOT_INO); 390 if (IS_ERR(root_inode)) { 391 ret = PTR_ERR(root_inode); 392 goto out_no_root; 393 } 394 395 oi = OP_I(root_inode); 396 oi->type = op_inode_node; 397 oi->u.node = of_find_node_by_path("/"); 398 399 s->s_root = d_make_root(root_inode); 400 if (!s->s_root) 401 goto out_no_root_dentry; 402 return 0; 403 404 out_no_root_dentry: 405 ret = -ENOMEM; 406 out_no_root: 407 printk("openprom_fill_super: get root inode failed\n"); 408 return ret; 409 } 410 411 static struct dentry *openprom_mount(struct file_system_type *fs_type, 412 int flags, const char *dev_name, void *data) 413 { 414 return mount_single(fs_type, flags, data, openprom_fill_super); 415 } 416 417 static struct file_system_type openprom_fs_type = { 418 .owner = THIS_MODULE, 419 .name = "openpromfs", 420 .mount = openprom_mount, 421 .kill_sb = kill_anon_super, 422 }; 423 MODULE_ALIAS_FS("openpromfs"); 424 425 static void op_inode_init_once(void *data) 426 { 427 struct op_inode_info *oi = (struct op_inode_info *) data; 428 429 inode_init_once(&oi->vfs_inode); 430 } 431 432 static int __init init_openprom_fs(void) 433 { 434 int err; 435 436 op_inode_cachep = kmem_cache_create("op_inode_cache", 437 sizeof(struct op_inode_info), 438 0, 439 (SLAB_RECLAIM_ACCOUNT | 440 SLAB_MEM_SPREAD | SLAB_ACCOUNT), 441 op_inode_init_once); 442 if (!op_inode_cachep) 443 return -ENOMEM; 444 445 err = register_filesystem(&openprom_fs_type); 446 if (err) 447 kmem_cache_destroy(op_inode_cachep); 448 449 return err; 450 } 451 452 static void __exit exit_openprom_fs(void) 453 { 454 unregister_filesystem(&openprom_fs_type); 455 /* 456 * Make sure all delayed rcu free inodes are flushed before we 457 * destroy cache. 458 */ 459 rcu_barrier(); 460 kmem_cache_destroy(op_inode_cachep); 461 } 462 463 module_init(init_openprom_fs) 464 module_exit(exit_openprom_fs) 465 MODULE_LICENSE("GPL"); 466