0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/types.h>
0010 #include <linux/string.h>
0011 #include <linux/fs.h>
0012 #include <linux/fs_context.h>
0013 #include <linux/init.h>
0014 #include <linux/slab.h>
0015 #include <linux/seq_file.h>
0016 #include <linux/magic.h>
0017
0018 #include <asm/openprom.h>
0019 #include <asm/oplib.h>
0020 #include <asm/prom.h>
0021 #include <linux/uaccess.h>
0022
0023 static DEFINE_MUTEX(op_mutex);
0024
0025 #define OPENPROM_ROOT_INO 0
0026
0027 enum op_inode_type {
0028 op_inode_node,
0029 op_inode_prop,
0030 };
0031
0032 union op_inode_data {
0033 struct device_node *node;
0034 struct property *prop;
0035 };
0036
0037 struct op_inode_info {
0038 struct inode vfs_inode;
0039 enum op_inode_type type;
0040 union op_inode_data u;
0041 };
0042
0043 static struct inode *openprom_iget(struct super_block *sb, ino_t ino);
0044
0045 static inline struct op_inode_info *OP_I(struct inode *inode)
0046 {
0047 return container_of(inode, struct op_inode_info, vfs_inode);
0048 }
0049
0050 static int is_string(unsigned char *p, int len)
0051 {
0052 int i;
0053
0054 for (i = 0; i < len; i++) {
0055 unsigned char val = p[i];
0056
0057 if ((i && !val) ||
0058 (val >= ' ' && val <= '~'))
0059 continue;
0060
0061 return 0;
0062 }
0063
0064 return 1;
0065 }
0066
0067 static int property_show(struct seq_file *f, void *v)
0068 {
0069 struct property *prop = f->private;
0070 void *pval;
0071 int len;
0072
0073 len = prop->length;
0074 pval = prop->value;
0075
0076 if (is_string(pval, len)) {
0077 while (len > 0) {
0078 int n = strlen(pval);
0079
0080 seq_printf(f, "%s", (char *) pval);
0081
0082
0083 pval += n + 1;
0084 len -= n + 1;
0085
0086 if (len > 0)
0087 seq_printf(f, " + ");
0088 }
0089 } else {
0090 if (len & 3) {
0091 while (len) {
0092 len--;
0093 if (len)
0094 seq_printf(f, "%02x.",
0095 *(unsigned char *) pval);
0096 else
0097 seq_printf(f, "%02x",
0098 *(unsigned char *) pval);
0099 pval++;
0100 }
0101 } else {
0102 while (len >= 4) {
0103 len -= 4;
0104
0105 if (len)
0106 seq_printf(f, "%08x.",
0107 *(unsigned int *) pval);
0108 else
0109 seq_printf(f, "%08x",
0110 *(unsigned int *) pval);
0111 pval += 4;
0112 }
0113 }
0114 }
0115 seq_printf(f, "\n");
0116
0117 return 0;
0118 }
0119
0120 static void *property_start(struct seq_file *f, loff_t *pos)
0121 {
0122 if (*pos == 0)
0123 return pos;
0124 return NULL;
0125 }
0126
0127 static void *property_next(struct seq_file *f, void *v, loff_t *pos)
0128 {
0129 (*pos)++;
0130 return NULL;
0131 }
0132
0133 static void property_stop(struct seq_file *f, void *v)
0134 {
0135
0136 }
0137
0138 static const struct seq_operations property_op = {
0139 .start = property_start,
0140 .next = property_next,
0141 .stop = property_stop,
0142 .show = property_show
0143 };
0144
0145 static int property_open(struct inode *inode, struct file *file)
0146 {
0147 struct op_inode_info *oi = OP_I(inode);
0148 int ret;
0149
0150 BUG_ON(oi->type != op_inode_prop);
0151
0152 ret = seq_open(file, &property_op);
0153 if (!ret) {
0154 struct seq_file *m = file->private_data;
0155 m->private = oi->u.prop;
0156 }
0157 return ret;
0158 }
0159
0160 static const struct file_operations openpromfs_prop_ops = {
0161 .open = property_open,
0162 .read = seq_read,
0163 .llseek = seq_lseek,
0164 .release = seq_release,
0165 };
0166
0167 static int openpromfs_readdir(struct file *, struct dir_context *);
0168
0169 static const struct file_operations openprom_operations = {
0170 .read = generic_read_dir,
0171 .iterate_shared = openpromfs_readdir,
0172 .llseek = generic_file_llseek,
0173 };
0174
0175 static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, unsigned int);
0176
0177 static const struct inode_operations openprom_inode_operations = {
0178 .lookup = openpromfs_lookup,
0179 };
0180
0181 static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
0182 {
0183 struct op_inode_info *ent_oi, *oi = OP_I(dir);
0184 struct device_node *dp, *child;
0185 struct property *prop;
0186 enum op_inode_type ent_type;
0187 union op_inode_data ent_data;
0188 const char *name;
0189 struct inode *inode;
0190 unsigned int ino;
0191 int len;
0192
0193 BUG_ON(oi->type != op_inode_node);
0194
0195 dp = oi->u.node;
0196
0197 name = dentry->d_name.name;
0198 len = dentry->d_name.len;
0199
0200 mutex_lock(&op_mutex);
0201
0202 child = dp->child;
0203 while (child) {
0204 const char *node_name = kbasename(child->full_name);
0205 int n = strlen(node_name);
0206
0207 if (len == n &&
0208 !strncmp(node_name, name, len)) {
0209 ent_type = op_inode_node;
0210 ent_data.node = child;
0211 ino = child->unique_id;
0212 goto found;
0213 }
0214 child = child->sibling;
0215 }
0216
0217 prop = dp->properties;
0218 while (prop) {
0219 int n = strlen(prop->name);
0220
0221 if (len == n && !strncmp(prop->name, name, len)) {
0222 ent_type = op_inode_prop;
0223 ent_data.prop = prop;
0224 ino = prop->unique_id;
0225 goto found;
0226 }
0227
0228 prop = prop->next;
0229 }
0230
0231 mutex_unlock(&op_mutex);
0232 return ERR_PTR(-ENOENT);
0233
0234 found:
0235 inode = openprom_iget(dir->i_sb, ino);
0236 mutex_unlock(&op_mutex);
0237 if (IS_ERR(inode))
0238 return ERR_CAST(inode);
0239 if (inode->i_state & I_NEW) {
0240 inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
0241 ent_oi = OP_I(inode);
0242 ent_oi->type = ent_type;
0243 ent_oi->u = ent_data;
0244
0245 switch (ent_type) {
0246 case op_inode_node:
0247 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
0248 inode->i_op = &openprom_inode_operations;
0249 inode->i_fop = &openprom_operations;
0250 set_nlink(inode, 2);
0251 break;
0252 case op_inode_prop:
0253 if (of_node_name_eq(dp, "options") && (len == 17) &&
0254 !strncmp (name, "security-password", 17))
0255 inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
0256 else
0257 inode->i_mode = S_IFREG | S_IRUGO;
0258 inode->i_fop = &openpromfs_prop_ops;
0259 set_nlink(inode, 1);
0260 inode->i_size = ent_oi->u.prop->length;
0261 break;
0262 }
0263 unlock_new_inode(inode);
0264 }
0265
0266 return d_splice_alias(inode, dentry);
0267 }
0268
0269 static int openpromfs_readdir(struct file *file, struct dir_context *ctx)
0270 {
0271 struct inode *inode = file_inode(file);
0272 struct op_inode_info *oi = OP_I(inode);
0273 struct device_node *dp = oi->u.node;
0274 struct device_node *child;
0275 struct property *prop;
0276 int i;
0277
0278 mutex_lock(&op_mutex);
0279
0280 if (ctx->pos == 0) {
0281 if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR))
0282 goto out;
0283 ctx->pos = 1;
0284 }
0285 if (ctx->pos == 1) {
0286 if (!dir_emit(ctx, "..", 2,
0287 (dp->parent == NULL ?
0288 OPENPROM_ROOT_INO :
0289 dp->parent->unique_id), DT_DIR))
0290 goto out;
0291 ctx->pos = 2;
0292 }
0293 i = ctx->pos - 2;
0294
0295
0296 child = dp->child;
0297 while (i && child) {
0298 child = child->sibling;
0299 i--;
0300 }
0301 while (child) {
0302 if (!dir_emit(ctx,
0303 kbasename(child->full_name),
0304 strlen(kbasename(child->full_name)),
0305 child->unique_id, DT_DIR))
0306 goto out;
0307
0308 ctx->pos++;
0309 child = child->sibling;
0310 }
0311
0312
0313 prop = dp->properties;
0314 while (i && prop) {
0315 prop = prop->next;
0316 i--;
0317 }
0318 while (prop) {
0319 if (!dir_emit(ctx, prop->name, strlen(prop->name),
0320 prop->unique_id, DT_REG))
0321 goto out;
0322
0323 ctx->pos++;
0324 prop = prop->next;
0325 }
0326
0327 out:
0328 mutex_unlock(&op_mutex);
0329 return 0;
0330 }
0331
0332 static struct kmem_cache *op_inode_cachep;
0333
0334 static struct inode *openprom_alloc_inode(struct super_block *sb)
0335 {
0336 struct op_inode_info *oi;
0337
0338 oi = alloc_inode_sb(sb, op_inode_cachep, GFP_KERNEL);
0339 if (!oi)
0340 return NULL;
0341
0342 return &oi->vfs_inode;
0343 }
0344
0345 static void openprom_free_inode(struct inode *inode)
0346 {
0347 kmem_cache_free(op_inode_cachep, OP_I(inode));
0348 }
0349
0350 static struct inode *openprom_iget(struct super_block *sb, ino_t ino)
0351 {
0352 struct inode *inode = iget_locked(sb, ino);
0353 if (!inode)
0354 inode = ERR_PTR(-ENOMEM);
0355 return inode;
0356 }
0357
0358 static int openprom_remount(struct super_block *sb, int *flags, char *data)
0359 {
0360 sync_filesystem(sb);
0361 *flags |= SB_NOATIME;
0362 return 0;
0363 }
0364
0365 static const struct super_operations openprom_sops = {
0366 .alloc_inode = openprom_alloc_inode,
0367 .free_inode = openprom_free_inode,
0368 .statfs = simple_statfs,
0369 .remount_fs = openprom_remount,
0370 };
0371
0372 static int openprom_fill_super(struct super_block *s, struct fs_context *fc)
0373 {
0374 struct inode *root_inode;
0375 struct op_inode_info *oi;
0376 int ret;
0377
0378 s->s_flags |= SB_NOATIME;
0379 s->s_blocksize = 1024;
0380 s->s_blocksize_bits = 10;
0381 s->s_magic = OPENPROM_SUPER_MAGIC;
0382 s->s_op = &openprom_sops;
0383 s->s_time_gran = 1;
0384 root_inode = openprom_iget(s, OPENPROM_ROOT_INO);
0385 if (IS_ERR(root_inode)) {
0386 ret = PTR_ERR(root_inode);
0387 goto out_no_root;
0388 }
0389
0390 root_inode->i_mtime = root_inode->i_atime =
0391 root_inode->i_ctime = current_time(root_inode);
0392 root_inode->i_op = &openprom_inode_operations;
0393 root_inode->i_fop = &openprom_operations;
0394 root_inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
0395 oi = OP_I(root_inode);
0396 oi->type = op_inode_node;
0397 oi->u.node = of_find_node_by_path("/");
0398 unlock_new_inode(root_inode);
0399
0400 s->s_root = d_make_root(root_inode);
0401 if (!s->s_root)
0402 goto out_no_root_dentry;
0403 return 0;
0404
0405 out_no_root_dentry:
0406 ret = -ENOMEM;
0407 out_no_root:
0408 printk("openprom_fill_super: get root inode failed\n");
0409 return ret;
0410 }
0411
0412 static int openpromfs_get_tree(struct fs_context *fc)
0413 {
0414 return get_tree_single(fc, openprom_fill_super);
0415 }
0416
0417 static const struct fs_context_operations openpromfs_context_ops = {
0418 .get_tree = openpromfs_get_tree,
0419 };
0420
0421 static int openpromfs_init_fs_context(struct fs_context *fc)
0422 {
0423 fc->ops = &openpromfs_context_ops;
0424 return 0;
0425 }
0426
0427 static struct file_system_type openprom_fs_type = {
0428 .owner = THIS_MODULE,
0429 .name = "openpromfs",
0430 .init_fs_context = openpromfs_init_fs_context,
0431 .kill_sb = kill_anon_super,
0432 };
0433 MODULE_ALIAS_FS("openpromfs");
0434
0435 static void op_inode_init_once(void *data)
0436 {
0437 struct op_inode_info *oi = (struct op_inode_info *) data;
0438
0439 inode_init_once(&oi->vfs_inode);
0440 }
0441
0442 static int __init init_openprom_fs(void)
0443 {
0444 int err;
0445
0446 op_inode_cachep = kmem_cache_create("op_inode_cache",
0447 sizeof(struct op_inode_info),
0448 0,
0449 (SLAB_RECLAIM_ACCOUNT |
0450 SLAB_MEM_SPREAD | SLAB_ACCOUNT),
0451 op_inode_init_once);
0452 if (!op_inode_cachep)
0453 return -ENOMEM;
0454
0455 err = register_filesystem(&openprom_fs_type);
0456 if (err)
0457 kmem_cache_destroy(op_inode_cachep);
0458
0459 return err;
0460 }
0461
0462 static void __exit exit_openprom_fs(void)
0463 {
0464 unregister_filesystem(&openprom_fs_type);
0465
0466
0467
0468
0469 rcu_barrier();
0470 kmem_cache_destroy(op_inode_cachep);
0471 }
0472
0473 module_init(init_openprom_fs)
0474 module_exit(exit_openprom_fs)
0475 MODULE_LICENSE("GPL");