18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* inode.c: /proc/openprom handling routines 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com) 58c2ecf20Sopenharmony_ci * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/types.h> 108c2ecf20Sopenharmony_ci#include <linux/string.h> 118c2ecf20Sopenharmony_ci#include <linux/fs.h> 128c2ecf20Sopenharmony_ci#include <linux/fs_context.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 168c2ecf20Sopenharmony_ci#include <linux/magic.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <asm/openprom.h> 198c2ecf20Sopenharmony_ci#include <asm/oplib.h> 208c2ecf20Sopenharmony_ci#include <asm/prom.h> 218c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(op_mutex); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define OPENPROM_ROOT_INO 0 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cienum op_inode_type { 288c2ecf20Sopenharmony_ci op_inode_node, 298c2ecf20Sopenharmony_ci op_inode_prop, 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ciunion op_inode_data { 338c2ecf20Sopenharmony_ci struct device_node *node; 348c2ecf20Sopenharmony_ci struct property *prop; 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistruct op_inode_info { 388c2ecf20Sopenharmony_ci struct inode vfs_inode; 398c2ecf20Sopenharmony_ci enum op_inode_type type; 408c2ecf20Sopenharmony_ci union op_inode_data u; 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic struct inode *openprom_iget(struct super_block *sb, ino_t ino); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic inline struct op_inode_info *OP_I(struct inode *inode) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci return container_of(inode, struct op_inode_info, vfs_inode); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int is_string(unsigned char *p, int len) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci int i; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 558c2ecf20Sopenharmony_ci unsigned char val = p[i]; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if ((i && !val) || 588c2ecf20Sopenharmony_ci (val >= ' ' && val <= '~')) 598c2ecf20Sopenharmony_ci continue; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return 0; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return 1; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int property_show(struct seq_file *f, void *v) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct property *prop = f->private; 708c2ecf20Sopenharmony_ci void *pval; 718c2ecf20Sopenharmony_ci int len; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci len = prop->length; 748c2ecf20Sopenharmony_ci pval = prop->value; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (is_string(pval, len)) { 778c2ecf20Sopenharmony_ci while (len > 0) { 788c2ecf20Sopenharmony_ci int n = strlen(pval); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci seq_printf(f, "%s", (char *) pval); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* Skip over the NULL byte too. */ 838c2ecf20Sopenharmony_ci pval += n + 1; 848c2ecf20Sopenharmony_ci len -= n + 1; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (len > 0) 878c2ecf20Sopenharmony_ci seq_printf(f, " + "); 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci } else { 908c2ecf20Sopenharmony_ci if (len & 3) { 918c2ecf20Sopenharmony_ci while (len) { 928c2ecf20Sopenharmony_ci len--; 938c2ecf20Sopenharmony_ci if (len) 948c2ecf20Sopenharmony_ci seq_printf(f, "%02x.", 958c2ecf20Sopenharmony_ci *(unsigned char *) pval); 968c2ecf20Sopenharmony_ci else 978c2ecf20Sopenharmony_ci seq_printf(f, "%02x", 988c2ecf20Sopenharmony_ci *(unsigned char *) pval); 998c2ecf20Sopenharmony_ci pval++; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci } else { 1028c2ecf20Sopenharmony_ci while (len >= 4) { 1038c2ecf20Sopenharmony_ci len -= 4; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (len) 1068c2ecf20Sopenharmony_ci seq_printf(f, "%08x.", 1078c2ecf20Sopenharmony_ci *(unsigned int *) pval); 1088c2ecf20Sopenharmony_ci else 1098c2ecf20Sopenharmony_ci seq_printf(f, "%08x", 1108c2ecf20Sopenharmony_ci *(unsigned int *) pval); 1118c2ecf20Sopenharmony_ci pval += 4; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci seq_printf(f, "\n"); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void *property_start(struct seq_file *f, loff_t *pos) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci if (*pos == 0) 1238c2ecf20Sopenharmony_ci return pos; 1248c2ecf20Sopenharmony_ci return NULL; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic void *property_next(struct seq_file *f, void *v, loff_t *pos) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci (*pos)++; 1308c2ecf20Sopenharmony_ci return NULL; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic void property_stop(struct seq_file *f, void *v) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci /* Nothing to do */ 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic const struct seq_operations property_op = { 1398c2ecf20Sopenharmony_ci .start = property_start, 1408c2ecf20Sopenharmony_ci .next = property_next, 1418c2ecf20Sopenharmony_ci .stop = property_stop, 1428c2ecf20Sopenharmony_ci .show = property_show 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int property_open(struct inode *inode, struct file *file) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct op_inode_info *oi = OP_I(inode); 1488c2ecf20Sopenharmony_ci int ret; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci BUG_ON(oi->type != op_inode_prop); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci ret = seq_open(file, &property_op); 1538c2ecf20Sopenharmony_ci if (!ret) { 1548c2ecf20Sopenharmony_ci struct seq_file *m = file->private_data; 1558c2ecf20Sopenharmony_ci m->private = oi->u.prop; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci return ret; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic const struct file_operations openpromfs_prop_ops = { 1618c2ecf20Sopenharmony_ci .open = property_open, 1628c2ecf20Sopenharmony_ci .read = seq_read, 1638c2ecf20Sopenharmony_ci .llseek = seq_lseek, 1648c2ecf20Sopenharmony_ci .release = seq_release, 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic int openpromfs_readdir(struct file *, struct dir_context *); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic const struct file_operations openprom_operations = { 1708c2ecf20Sopenharmony_ci .read = generic_read_dir, 1718c2ecf20Sopenharmony_ci .iterate_shared = openpromfs_readdir, 1728c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 1738c2ecf20Sopenharmony_ci}; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic struct dentry *openpromfs_lookup(struct inode *, struct dentry *, unsigned int); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic const struct inode_operations openprom_inode_operations = { 1788c2ecf20Sopenharmony_ci .lookup = openpromfs_lookup, 1798c2ecf20Sopenharmony_ci}; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct op_inode_info *ent_oi, *oi = OP_I(dir); 1848c2ecf20Sopenharmony_ci struct device_node *dp, *child; 1858c2ecf20Sopenharmony_ci struct property *prop; 1868c2ecf20Sopenharmony_ci enum op_inode_type ent_type; 1878c2ecf20Sopenharmony_ci union op_inode_data ent_data; 1888c2ecf20Sopenharmony_ci const char *name; 1898c2ecf20Sopenharmony_ci struct inode *inode; 1908c2ecf20Sopenharmony_ci unsigned int ino; 1918c2ecf20Sopenharmony_ci int len; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci BUG_ON(oi->type != op_inode_node); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci dp = oi->u.node; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci name = dentry->d_name.name; 1988c2ecf20Sopenharmony_ci len = dentry->d_name.len; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci mutex_lock(&op_mutex); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci child = dp->child; 2038c2ecf20Sopenharmony_ci while (child) { 2048c2ecf20Sopenharmony_ci const char *node_name = kbasename(child->full_name); 2058c2ecf20Sopenharmony_ci int n = strlen(node_name); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (len == n && 2088c2ecf20Sopenharmony_ci !strncmp(node_name, name, len)) { 2098c2ecf20Sopenharmony_ci ent_type = op_inode_node; 2108c2ecf20Sopenharmony_ci ent_data.node = child; 2118c2ecf20Sopenharmony_ci ino = child->unique_id; 2128c2ecf20Sopenharmony_ci goto found; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci child = child->sibling; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci prop = dp->properties; 2188c2ecf20Sopenharmony_ci while (prop) { 2198c2ecf20Sopenharmony_ci int n = strlen(prop->name); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (len == n && !strncmp(prop->name, name, len)) { 2228c2ecf20Sopenharmony_ci ent_type = op_inode_prop; 2238c2ecf20Sopenharmony_ci ent_data.prop = prop; 2248c2ecf20Sopenharmony_ci ino = prop->unique_id; 2258c2ecf20Sopenharmony_ci goto found; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci prop = prop->next; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci mutex_unlock(&op_mutex); 2328c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cifound: 2358c2ecf20Sopenharmony_ci inode = openprom_iget(dir->i_sb, ino); 2368c2ecf20Sopenharmony_ci mutex_unlock(&op_mutex); 2378c2ecf20Sopenharmony_ci if (IS_ERR(inode)) 2388c2ecf20Sopenharmony_ci return ERR_CAST(inode); 2398c2ecf20Sopenharmony_ci ent_oi = OP_I(inode); 2408c2ecf20Sopenharmony_ci ent_oi->type = ent_type; 2418c2ecf20Sopenharmony_ci ent_oi->u = ent_data; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci switch (ent_type) { 2448c2ecf20Sopenharmony_ci case op_inode_node: 2458c2ecf20Sopenharmony_ci inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 2468c2ecf20Sopenharmony_ci inode->i_op = &openprom_inode_operations; 2478c2ecf20Sopenharmony_ci inode->i_fop = &openprom_operations; 2488c2ecf20Sopenharmony_ci set_nlink(inode, 2); 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci case op_inode_prop: 2518c2ecf20Sopenharmony_ci if (of_node_name_eq(dp, "options") && (len == 17) && 2528c2ecf20Sopenharmony_ci !strncmp (name, "security-password", 17)) 2538c2ecf20Sopenharmony_ci inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; 2548c2ecf20Sopenharmony_ci else 2558c2ecf20Sopenharmony_ci inode->i_mode = S_IFREG | S_IRUGO; 2568c2ecf20Sopenharmony_ci inode->i_fop = &openpromfs_prop_ops; 2578c2ecf20Sopenharmony_ci set_nlink(inode, 1); 2588c2ecf20Sopenharmony_ci inode->i_size = ent_oi->u.prop->length; 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci return d_splice_alias(inode, dentry); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic int openpromfs_readdir(struct file *file, struct dir_context *ctx) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 2688c2ecf20Sopenharmony_ci struct op_inode_info *oi = OP_I(inode); 2698c2ecf20Sopenharmony_ci struct device_node *dp = oi->u.node; 2708c2ecf20Sopenharmony_ci struct device_node *child; 2718c2ecf20Sopenharmony_ci struct property *prop; 2728c2ecf20Sopenharmony_ci int i; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci mutex_lock(&op_mutex); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (ctx->pos == 0) { 2778c2ecf20Sopenharmony_ci if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR)) 2788c2ecf20Sopenharmony_ci goto out; 2798c2ecf20Sopenharmony_ci ctx->pos = 1; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci if (ctx->pos == 1) { 2828c2ecf20Sopenharmony_ci if (!dir_emit(ctx, "..", 2, 2838c2ecf20Sopenharmony_ci (dp->parent == NULL ? 2848c2ecf20Sopenharmony_ci OPENPROM_ROOT_INO : 2858c2ecf20Sopenharmony_ci dp->parent->unique_id), DT_DIR)) 2868c2ecf20Sopenharmony_ci goto out; 2878c2ecf20Sopenharmony_ci ctx->pos = 2; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci i = ctx->pos - 2; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* First, the children nodes as directories. */ 2928c2ecf20Sopenharmony_ci child = dp->child; 2938c2ecf20Sopenharmony_ci while (i && child) { 2948c2ecf20Sopenharmony_ci child = child->sibling; 2958c2ecf20Sopenharmony_ci i--; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci while (child) { 2988c2ecf20Sopenharmony_ci if (!dir_emit(ctx, 2998c2ecf20Sopenharmony_ci kbasename(child->full_name), 3008c2ecf20Sopenharmony_ci strlen(kbasename(child->full_name)), 3018c2ecf20Sopenharmony_ci child->unique_id, DT_DIR)) 3028c2ecf20Sopenharmony_ci goto out; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci ctx->pos++; 3058c2ecf20Sopenharmony_ci child = child->sibling; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* Next, the properties as files. */ 3098c2ecf20Sopenharmony_ci prop = dp->properties; 3108c2ecf20Sopenharmony_ci while (i && prop) { 3118c2ecf20Sopenharmony_ci prop = prop->next; 3128c2ecf20Sopenharmony_ci i--; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci while (prop) { 3158c2ecf20Sopenharmony_ci if (!dir_emit(ctx, prop->name, strlen(prop->name), 3168c2ecf20Sopenharmony_ci prop->unique_id, DT_REG)) 3178c2ecf20Sopenharmony_ci goto out; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci ctx->pos++; 3208c2ecf20Sopenharmony_ci prop = prop->next; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ciout: 3248c2ecf20Sopenharmony_ci mutex_unlock(&op_mutex); 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic struct kmem_cache *op_inode_cachep; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic struct inode *openprom_alloc_inode(struct super_block *sb) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci struct op_inode_info *oi; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci oi = kmem_cache_alloc(op_inode_cachep, GFP_KERNEL); 3358c2ecf20Sopenharmony_ci if (!oi) 3368c2ecf20Sopenharmony_ci return NULL; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return &oi->vfs_inode; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic void openprom_free_inode(struct inode *inode) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci kmem_cache_free(op_inode_cachep, OP_I(inode)); 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic struct inode *openprom_iget(struct super_block *sb, ino_t ino) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct inode *inode; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci inode = iget_locked(sb, ino); 3518c2ecf20Sopenharmony_ci if (!inode) 3528c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3538c2ecf20Sopenharmony_ci if (inode->i_state & I_NEW) { 3548c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 3558c2ecf20Sopenharmony_ci if (inode->i_ino == OPENPROM_ROOT_INO) { 3568c2ecf20Sopenharmony_ci inode->i_op = &openprom_inode_operations; 3578c2ecf20Sopenharmony_ci inode->i_fop = &openprom_operations; 3588c2ecf20Sopenharmony_ci inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci unlock_new_inode(inode); 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci return inode; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int openprom_remount(struct super_block *sb, int *flags, char *data) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci sync_filesystem(sb); 3688c2ecf20Sopenharmony_ci *flags |= SB_NOATIME; 3698c2ecf20Sopenharmony_ci return 0; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic const struct super_operations openprom_sops = { 3738c2ecf20Sopenharmony_ci .alloc_inode = openprom_alloc_inode, 3748c2ecf20Sopenharmony_ci .free_inode = openprom_free_inode, 3758c2ecf20Sopenharmony_ci .statfs = simple_statfs, 3768c2ecf20Sopenharmony_ci .remount_fs = openprom_remount, 3778c2ecf20Sopenharmony_ci}; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int openprom_fill_super(struct super_block *s, struct fs_context *fc) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct inode *root_inode; 3828c2ecf20Sopenharmony_ci struct op_inode_info *oi; 3838c2ecf20Sopenharmony_ci int ret; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci s->s_flags |= SB_NOATIME; 3868c2ecf20Sopenharmony_ci s->s_blocksize = 1024; 3878c2ecf20Sopenharmony_ci s->s_blocksize_bits = 10; 3888c2ecf20Sopenharmony_ci s->s_magic = OPENPROM_SUPER_MAGIC; 3898c2ecf20Sopenharmony_ci s->s_op = &openprom_sops; 3908c2ecf20Sopenharmony_ci s->s_time_gran = 1; 3918c2ecf20Sopenharmony_ci root_inode = openprom_iget(s, OPENPROM_ROOT_INO); 3928c2ecf20Sopenharmony_ci if (IS_ERR(root_inode)) { 3938c2ecf20Sopenharmony_ci ret = PTR_ERR(root_inode); 3948c2ecf20Sopenharmony_ci goto out_no_root; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci oi = OP_I(root_inode); 3988c2ecf20Sopenharmony_ci oi->type = op_inode_node; 3998c2ecf20Sopenharmony_ci oi->u.node = of_find_node_by_path("/"); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci s->s_root = d_make_root(root_inode); 4028c2ecf20Sopenharmony_ci if (!s->s_root) 4038c2ecf20Sopenharmony_ci goto out_no_root_dentry; 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ciout_no_root_dentry: 4078c2ecf20Sopenharmony_ci ret = -ENOMEM; 4088c2ecf20Sopenharmony_ciout_no_root: 4098c2ecf20Sopenharmony_ci printk("openprom_fill_super: get root inode failed\n"); 4108c2ecf20Sopenharmony_ci return ret; 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic int openpromfs_get_tree(struct fs_context *fc) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci return get_tree_single(fc, openprom_fill_super); 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic const struct fs_context_operations openpromfs_context_ops = { 4198c2ecf20Sopenharmony_ci .get_tree = openpromfs_get_tree, 4208c2ecf20Sopenharmony_ci}; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic int openpromfs_init_fs_context(struct fs_context *fc) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci fc->ops = &openpromfs_context_ops; 4258c2ecf20Sopenharmony_ci return 0; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic struct file_system_type openprom_fs_type = { 4298c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4308c2ecf20Sopenharmony_ci .name = "openpromfs", 4318c2ecf20Sopenharmony_ci .init_fs_context = openpromfs_init_fs_context, 4328c2ecf20Sopenharmony_ci .kill_sb = kill_anon_super, 4338c2ecf20Sopenharmony_ci}; 4348c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("openpromfs"); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic void op_inode_init_once(void *data) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct op_inode_info *oi = (struct op_inode_info *) data; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci inode_init_once(&oi->vfs_inode); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic int __init init_openprom_fs(void) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci int err; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci op_inode_cachep = kmem_cache_create("op_inode_cache", 4488c2ecf20Sopenharmony_ci sizeof(struct op_inode_info), 4498c2ecf20Sopenharmony_ci 0, 4508c2ecf20Sopenharmony_ci (SLAB_RECLAIM_ACCOUNT | 4518c2ecf20Sopenharmony_ci SLAB_MEM_SPREAD | SLAB_ACCOUNT), 4528c2ecf20Sopenharmony_ci op_inode_init_once); 4538c2ecf20Sopenharmony_ci if (!op_inode_cachep) 4548c2ecf20Sopenharmony_ci return -ENOMEM; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci err = register_filesystem(&openprom_fs_type); 4578c2ecf20Sopenharmony_ci if (err) 4588c2ecf20Sopenharmony_ci kmem_cache_destroy(op_inode_cachep); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return err; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic void __exit exit_openprom_fs(void) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci unregister_filesystem(&openprom_fs_type); 4668c2ecf20Sopenharmony_ci /* 4678c2ecf20Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 4688c2ecf20Sopenharmony_ci * destroy cache. 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_ci rcu_barrier(); 4718c2ecf20Sopenharmony_ci kmem_cache_destroy(op_inode_cachep); 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cimodule_init(init_openprom_fs) 4758c2ecf20Sopenharmony_cimodule_exit(exit_openprom_fs) 4768c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 477