162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* inode.c: /proc/openprom handling routines 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com) 562306a36Sopenharmony_ci * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/types.h> 1062306a36Sopenharmony_ci#include <linux/string.h> 1162306a36Sopenharmony_ci#include <linux/fs.h> 1262306a36Sopenharmony_ci#include <linux/fs_context.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/seq_file.h> 1662306a36Sopenharmony_ci#include <linux/magic.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <asm/openprom.h> 1962306a36Sopenharmony_ci#include <asm/oplib.h> 2062306a36Sopenharmony_ci#include <asm/prom.h> 2162306a36Sopenharmony_ci#include <linux/uaccess.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic DEFINE_MUTEX(op_mutex); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define OPENPROM_ROOT_INO 0 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cienum op_inode_type { 2862306a36Sopenharmony_ci op_inode_node, 2962306a36Sopenharmony_ci op_inode_prop, 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ciunion op_inode_data { 3362306a36Sopenharmony_ci struct device_node *node; 3462306a36Sopenharmony_ci struct property *prop; 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistruct op_inode_info { 3862306a36Sopenharmony_ci struct inode vfs_inode; 3962306a36Sopenharmony_ci enum op_inode_type type; 4062306a36Sopenharmony_ci union op_inode_data u; 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic struct inode *openprom_iget(struct super_block *sb, ino_t ino); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic inline struct op_inode_info *OP_I(struct inode *inode) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci return container_of(inode, struct op_inode_info, vfs_inode); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int is_string(unsigned char *p, int len) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci int i; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci for (i = 0; i < len; i++) { 5562306a36Sopenharmony_ci unsigned char val = p[i]; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if ((i && !val) || 5862306a36Sopenharmony_ci (val >= ' ' && val <= '~')) 5962306a36Sopenharmony_ci continue; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return 0; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci return 1; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int property_show(struct seq_file *f, void *v) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci struct property *prop = f->private; 7062306a36Sopenharmony_ci void *pval; 7162306a36Sopenharmony_ci int len; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci len = prop->length; 7462306a36Sopenharmony_ci pval = prop->value; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (is_string(pval, len)) { 7762306a36Sopenharmony_ci while (len > 0) { 7862306a36Sopenharmony_ci int n = strlen(pval); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci seq_printf(f, "%s", (char *) pval); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* Skip over the NULL byte too. */ 8362306a36Sopenharmony_ci pval += n + 1; 8462306a36Sopenharmony_ci len -= n + 1; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (len > 0) 8762306a36Sopenharmony_ci seq_printf(f, " + "); 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci } else { 9062306a36Sopenharmony_ci if (len & 3) { 9162306a36Sopenharmony_ci while (len) { 9262306a36Sopenharmony_ci len--; 9362306a36Sopenharmony_ci if (len) 9462306a36Sopenharmony_ci seq_printf(f, "%02x.", 9562306a36Sopenharmony_ci *(unsigned char *) pval); 9662306a36Sopenharmony_ci else 9762306a36Sopenharmony_ci seq_printf(f, "%02x", 9862306a36Sopenharmony_ci *(unsigned char *) pval); 9962306a36Sopenharmony_ci pval++; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci } else { 10262306a36Sopenharmony_ci while (len >= 4) { 10362306a36Sopenharmony_ci len -= 4; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (len) 10662306a36Sopenharmony_ci seq_printf(f, "%08x.", 10762306a36Sopenharmony_ci *(unsigned int *) pval); 10862306a36Sopenharmony_ci else 10962306a36Sopenharmony_ci seq_printf(f, "%08x", 11062306a36Sopenharmony_ci *(unsigned int *) pval); 11162306a36Sopenharmony_ci pval += 4; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci seq_printf(f, "\n"); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic void *property_start(struct seq_file *f, loff_t *pos) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci if (*pos == 0) 12362306a36Sopenharmony_ci return pos; 12462306a36Sopenharmony_ci return NULL; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic void *property_next(struct seq_file *f, void *v, loff_t *pos) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci (*pos)++; 13062306a36Sopenharmony_ci return NULL; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic void property_stop(struct seq_file *f, void *v) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci /* Nothing to do */ 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic const struct seq_operations property_op = { 13962306a36Sopenharmony_ci .start = property_start, 14062306a36Sopenharmony_ci .next = property_next, 14162306a36Sopenharmony_ci .stop = property_stop, 14262306a36Sopenharmony_ci .show = property_show 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int property_open(struct inode *inode, struct file *file) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct op_inode_info *oi = OP_I(inode); 14862306a36Sopenharmony_ci int ret; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci BUG_ON(oi->type != op_inode_prop); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci ret = seq_open(file, &property_op); 15362306a36Sopenharmony_ci if (!ret) { 15462306a36Sopenharmony_ci struct seq_file *m = file->private_data; 15562306a36Sopenharmony_ci m->private = oi->u.prop; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci return ret; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic const struct file_operations openpromfs_prop_ops = { 16162306a36Sopenharmony_ci .open = property_open, 16262306a36Sopenharmony_ci .read = seq_read, 16362306a36Sopenharmony_ci .llseek = seq_lseek, 16462306a36Sopenharmony_ci .release = seq_release, 16562306a36Sopenharmony_ci}; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic int openpromfs_readdir(struct file *, struct dir_context *); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic const struct file_operations openprom_operations = { 17062306a36Sopenharmony_ci .read = generic_read_dir, 17162306a36Sopenharmony_ci .iterate_shared = openpromfs_readdir, 17262306a36Sopenharmony_ci .llseek = generic_file_llseek, 17362306a36Sopenharmony_ci}; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic struct dentry *openpromfs_lookup(struct inode *, struct dentry *, unsigned int); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic const struct inode_operations openprom_inode_operations = { 17862306a36Sopenharmony_ci .lookup = openpromfs_lookup, 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct op_inode_info *ent_oi, *oi = OP_I(dir); 18462306a36Sopenharmony_ci struct device_node *dp, *child; 18562306a36Sopenharmony_ci struct property *prop; 18662306a36Sopenharmony_ci enum op_inode_type ent_type; 18762306a36Sopenharmony_ci union op_inode_data ent_data; 18862306a36Sopenharmony_ci const char *name; 18962306a36Sopenharmony_ci struct inode *inode; 19062306a36Sopenharmony_ci unsigned int ino; 19162306a36Sopenharmony_ci int len; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci BUG_ON(oi->type != op_inode_node); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci dp = oi->u.node; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci name = dentry->d_name.name; 19862306a36Sopenharmony_ci len = dentry->d_name.len; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci mutex_lock(&op_mutex); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci child = dp->child; 20362306a36Sopenharmony_ci while (child) { 20462306a36Sopenharmony_ci const char *node_name = kbasename(child->full_name); 20562306a36Sopenharmony_ci int n = strlen(node_name); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (len == n && 20862306a36Sopenharmony_ci !strncmp(node_name, name, len)) { 20962306a36Sopenharmony_ci ent_type = op_inode_node; 21062306a36Sopenharmony_ci ent_data.node = child; 21162306a36Sopenharmony_ci ino = child->unique_id; 21262306a36Sopenharmony_ci goto found; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci child = child->sibling; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci prop = dp->properties; 21862306a36Sopenharmony_ci while (prop) { 21962306a36Sopenharmony_ci int n = strlen(prop->name); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (len == n && !strncmp(prop->name, name, len)) { 22262306a36Sopenharmony_ci ent_type = op_inode_prop; 22362306a36Sopenharmony_ci ent_data.prop = prop; 22462306a36Sopenharmony_ci ino = prop->unique_id; 22562306a36Sopenharmony_ci goto found; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci prop = prop->next; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci mutex_unlock(&op_mutex); 23262306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cifound: 23562306a36Sopenharmony_ci inode = openprom_iget(dir->i_sb, ino); 23662306a36Sopenharmony_ci mutex_unlock(&op_mutex); 23762306a36Sopenharmony_ci if (IS_ERR(inode)) 23862306a36Sopenharmony_ci return ERR_CAST(inode); 23962306a36Sopenharmony_ci if (inode->i_state & I_NEW) { 24062306a36Sopenharmony_ci inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode); 24162306a36Sopenharmony_ci ent_oi = OP_I(inode); 24262306a36Sopenharmony_ci ent_oi->type = ent_type; 24362306a36Sopenharmony_ci ent_oi->u = ent_data; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci switch (ent_type) { 24662306a36Sopenharmony_ci case op_inode_node: 24762306a36Sopenharmony_ci inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 24862306a36Sopenharmony_ci inode->i_op = &openprom_inode_operations; 24962306a36Sopenharmony_ci inode->i_fop = &openprom_operations; 25062306a36Sopenharmony_ci set_nlink(inode, 2); 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci case op_inode_prop: 25362306a36Sopenharmony_ci if (of_node_name_eq(dp, "options") && (len == 17) && 25462306a36Sopenharmony_ci !strncmp (name, "security-password", 17)) 25562306a36Sopenharmony_ci inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; 25662306a36Sopenharmony_ci else 25762306a36Sopenharmony_ci inode->i_mode = S_IFREG | S_IRUGO; 25862306a36Sopenharmony_ci inode->i_fop = &openpromfs_prop_ops; 25962306a36Sopenharmony_ci set_nlink(inode, 1); 26062306a36Sopenharmony_ci inode->i_size = ent_oi->u.prop->length; 26162306a36Sopenharmony_ci break; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci unlock_new_inode(inode); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci return d_splice_alias(inode, dentry); 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic int openpromfs_readdir(struct file *file, struct dir_context *ctx) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci struct inode *inode = file_inode(file); 27262306a36Sopenharmony_ci struct op_inode_info *oi = OP_I(inode); 27362306a36Sopenharmony_ci struct device_node *dp = oi->u.node; 27462306a36Sopenharmony_ci struct device_node *child; 27562306a36Sopenharmony_ci struct property *prop; 27662306a36Sopenharmony_ci int i; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci mutex_lock(&op_mutex); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (ctx->pos == 0) { 28162306a36Sopenharmony_ci if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR)) 28262306a36Sopenharmony_ci goto out; 28362306a36Sopenharmony_ci ctx->pos = 1; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci if (ctx->pos == 1) { 28662306a36Sopenharmony_ci if (!dir_emit(ctx, "..", 2, 28762306a36Sopenharmony_ci (dp->parent == NULL ? 28862306a36Sopenharmony_ci OPENPROM_ROOT_INO : 28962306a36Sopenharmony_ci dp->parent->unique_id), DT_DIR)) 29062306a36Sopenharmony_ci goto out; 29162306a36Sopenharmony_ci ctx->pos = 2; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci i = ctx->pos - 2; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* First, the children nodes as directories. */ 29662306a36Sopenharmony_ci child = dp->child; 29762306a36Sopenharmony_ci while (i && child) { 29862306a36Sopenharmony_ci child = child->sibling; 29962306a36Sopenharmony_ci i--; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci while (child) { 30262306a36Sopenharmony_ci if (!dir_emit(ctx, 30362306a36Sopenharmony_ci kbasename(child->full_name), 30462306a36Sopenharmony_ci strlen(kbasename(child->full_name)), 30562306a36Sopenharmony_ci child->unique_id, DT_DIR)) 30662306a36Sopenharmony_ci goto out; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci ctx->pos++; 30962306a36Sopenharmony_ci child = child->sibling; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* Next, the properties as files. */ 31362306a36Sopenharmony_ci prop = dp->properties; 31462306a36Sopenharmony_ci while (i && prop) { 31562306a36Sopenharmony_ci prop = prop->next; 31662306a36Sopenharmony_ci i--; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci while (prop) { 31962306a36Sopenharmony_ci if (!dir_emit(ctx, prop->name, strlen(prop->name), 32062306a36Sopenharmony_ci prop->unique_id, DT_REG)) 32162306a36Sopenharmony_ci goto out; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci ctx->pos++; 32462306a36Sopenharmony_ci prop = prop->next; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ciout: 32862306a36Sopenharmony_ci mutex_unlock(&op_mutex); 32962306a36Sopenharmony_ci return 0; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic struct kmem_cache *op_inode_cachep; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic struct inode *openprom_alloc_inode(struct super_block *sb) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct op_inode_info *oi; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci oi = alloc_inode_sb(sb, op_inode_cachep, GFP_KERNEL); 33962306a36Sopenharmony_ci if (!oi) 34062306a36Sopenharmony_ci return NULL; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci return &oi->vfs_inode; 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic void openprom_free_inode(struct inode *inode) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci kmem_cache_free(op_inode_cachep, OP_I(inode)); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic struct inode *openprom_iget(struct super_block *sb, ino_t ino) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct inode *inode = iget_locked(sb, ino); 35362306a36Sopenharmony_ci if (!inode) 35462306a36Sopenharmony_ci inode = ERR_PTR(-ENOMEM); 35562306a36Sopenharmony_ci return inode; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int openprom_remount(struct super_block *sb, int *flags, char *data) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci sync_filesystem(sb); 36162306a36Sopenharmony_ci *flags |= SB_NOATIME; 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic const struct super_operations openprom_sops = { 36662306a36Sopenharmony_ci .alloc_inode = openprom_alloc_inode, 36762306a36Sopenharmony_ci .free_inode = openprom_free_inode, 36862306a36Sopenharmony_ci .statfs = simple_statfs, 36962306a36Sopenharmony_ci .remount_fs = openprom_remount, 37062306a36Sopenharmony_ci}; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic int openprom_fill_super(struct super_block *s, struct fs_context *fc) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct inode *root_inode; 37562306a36Sopenharmony_ci struct op_inode_info *oi; 37662306a36Sopenharmony_ci int ret; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci s->s_flags |= SB_NOATIME; 37962306a36Sopenharmony_ci s->s_blocksize = 1024; 38062306a36Sopenharmony_ci s->s_blocksize_bits = 10; 38162306a36Sopenharmony_ci s->s_magic = OPENPROM_SUPER_MAGIC; 38262306a36Sopenharmony_ci s->s_op = &openprom_sops; 38362306a36Sopenharmony_ci s->s_time_gran = 1; 38462306a36Sopenharmony_ci root_inode = openprom_iget(s, OPENPROM_ROOT_INO); 38562306a36Sopenharmony_ci if (IS_ERR(root_inode)) { 38662306a36Sopenharmony_ci ret = PTR_ERR(root_inode); 38762306a36Sopenharmony_ci goto out_no_root; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci root_inode->i_mtime = root_inode->i_atime = inode_set_ctime_current(root_inode); 39162306a36Sopenharmony_ci root_inode->i_op = &openprom_inode_operations; 39262306a36Sopenharmony_ci root_inode->i_fop = &openprom_operations; 39362306a36Sopenharmony_ci root_inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 39462306a36Sopenharmony_ci oi = OP_I(root_inode); 39562306a36Sopenharmony_ci oi->type = op_inode_node; 39662306a36Sopenharmony_ci oi->u.node = of_find_node_by_path("/"); 39762306a36Sopenharmony_ci unlock_new_inode(root_inode); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci s->s_root = d_make_root(root_inode); 40062306a36Sopenharmony_ci if (!s->s_root) 40162306a36Sopenharmony_ci goto out_no_root_dentry; 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ciout_no_root_dentry: 40562306a36Sopenharmony_ci ret = -ENOMEM; 40662306a36Sopenharmony_ciout_no_root: 40762306a36Sopenharmony_ci printk("openprom_fill_super: get root inode failed\n"); 40862306a36Sopenharmony_ci return ret; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic int openpromfs_get_tree(struct fs_context *fc) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci return get_tree_single(fc, openprom_fill_super); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic const struct fs_context_operations openpromfs_context_ops = { 41762306a36Sopenharmony_ci .get_tree = openpromfs_get_tree, 41862306a36Sopenharmony_ci}; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic int openpromfs_init_fs_context(struct fs_context *fc) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci fc->ops = &openpromfs_context_ops; 42362306a36Sopenharmony_ci return 0; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic struct file_system_type openprom_fs_type = { 42762306a36Sopenharmony_ci .owner = THIS_MODULE, 42862306a36Sopenharmony_ci .name = "openpromfs", 42962306a36Sopenharmony_ci .init_fs_context = openpromfs_init_fs_context, 43062306a36Sopenharmony_ci .kill_sb = kill_anon_super, 43162306a36Sopenharmony_ci}; 43262306a36Sopenharmony_ciMODULE_ALIAS_FS("openpromfs"); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic void op_inode_init_once(void *data) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci struct op_inode_info *oi = (struct op_inode_info *) data; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci inode_init_once(&oi->vfs_inode); 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic int __init init_openprom_fs(void) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci int err; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci op_inode_cachep = kmem_cache_create("op_inode_cache", 44662306a36Sopenharmony_ci sizeof(struct op_inode_info), 44762306a36Sopenharmony_ci 0, 44862306a36Sopenharmony_ci (SLAB_RECLAIM_ACCOUNT | 44962306a36Sopenharmony_ci SLAB_MEM_SPREAD | SLAB_ACCOUNT), 45062306a36Sopenharmony_ci op_inode_init_once); 45162306a36Sopenharmony_ci if (!op_inode_cachep) 45262306a36Sopenharmony_ci return -ENOMEM; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci err = register_filesystem(&openprom_fs_type); 45562306a36Sopenharmony_ci if (err) 45662306a36Sopenharmony_ci kmem_cache_destroy(op_inode_cachep); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return err; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic void __exit exit_openprom_fs(void) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci unregister_filesystem(&openprom_fs_type); 46462306a36Sopenharmony_ci /* 46562306a36Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 46662306a36Sopenharmony_ci * destroy cache. 46762306a36Sopenharmony_ci */ 46862306a36Sopenharmony_ci rcu_barrier(); 46962306a36Sopenharmony_ci kmem_cache_destroy(op_inode_cachep); 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cimodule_init(init_openprom_fs) 47362306a36Sopenharmony_cimodule_exit(exit_openprom_fs) 47462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 475