18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/affs/inode.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (c) 1996 Hans-Joachim Widmaier - Rewritten 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * (C) 1991 Linus Torvalds - minix filesystem 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/statfs.h> 178c2ecf20Sopenharmony_ci#include <linux/parser.h> 188c2ecf20Sopenharmony_ci#include <linux/magic.h> 198c2ecf20Sopenharmony_ci#include <linux/sched.h> 208c2ecf20Sopenharmony_ci#include <linux/cred.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci#include <linux/writeback.h> 238c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 248c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 258c2ecf20Sopenharmony_ci#include <linux/iversion.h> 268c2ecf20Sopenharmony_ci#include "affs.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic int affs_statfs(struct dentry *dentry, struct kstatfs *buf); 298c2ecf20Sopenharmony_cistatic int affs_show_options(struct seq_file *m, struct dentry *root); 308c2ecf20Sopenharmony_cistatic int affs_remount (struct super_block *sb, int *flags, char *data); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic void 338c2ecf20Sopenharmony_ciaffs_commit_super(struct super_block *sb, int wait) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci struct affs_sb_info *sbi = AFFS_SB(sb); 368c2ecf20Sopenharmony_ci struct buffer_head *bh = sbi->s_root_bh; 378c2ecf20Sopenharmony_ci struct affs_root_tail *tail = AFFS_ROOT_TAIL(sb, bh); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci lock_buffer(bh); 408c2ecf20Sopenharmony_ci affs_secs_to_datestamp(ktime_get_real_seconds(), &tail->disk_change); 418c2ecf20Sopenharmony_ci affs_fix_checksum(sb, bh); 428c2ecf20Sopenharmony_ci unlock_buffer(bh); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 458c2ecf20Sopenharmony_ci if (wait) 468c2ecf20Sopenharmony_ci sync_dirty_buffer(bh); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic void 508c2ecf20Sopenharmony_ciaffs_put_super(struct super_block *sb) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct affs_sb_info *sbi = AFFS_SB(sb); 538c2ecf20Sopenharmony_ci pr_debug("%s()\n", __func__); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&sbi->sb_work); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int 598c2ecf20Sopenharmony_ciaffs_sync_fs(struct super_block *sb, int wait) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci affs_commit_super(sb, wait); 628c2ecf20Sopenharmony_ci return 0; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void flush_superblock(struct work_struct *work) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct affs_sb_info *sbi; 688c2ecf20Sopenharmony_ci struct super_block *sb; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci sbi = container_of(work, struct affs_sb_info, sb_work.work); 718c2ecf20Sopenharmony_ci sb = sbi->sb; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci spin_lock(&sbi->work_lock); 748c2ecf20Sopenharmony_ci sbi->work_queued = 0; 758c2ecf20Sopenharmony_ci spin_unlock(&sbi->work_lock); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci affs_commit_super(sb, 1); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_civoid affs_mark_sb_dirty(struct super_block *sb) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct affs_sb_info *sbi = AFFS_SB(sb); 838c2ecf20Sopenharmony_ci unsigned long delay; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (sb_rdonly(sb)) 868c2ecf20Sopenharmony_ci return; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci spin_lock(&sbi->work_lock); 898c2ecf20Sopenharmony_ci if (!sbi->work_queued) { 908c2ecf20Sopenharmony_ci delay = msecs_to_jiffies(dirty_writeback_interval * 10); 918c2ecf20Sopenharmony_ci queue_delayed_work(system_long_wq, &sbi->sb_work, delay); 928c2ecf20Sopenharmony_ci sbi->work_queued = 1; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci spin_unlock(&sbi->work_lock); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic struct kmem_cache * affs_inode_cachep; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic struct inode *affs_alloc_inode(struct super_block *sb) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct affs_inode_info *i; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci i = kmem_cache_alloc(affs_inode_cachep, GFP_KERNEL); 1048c2ecf20Sopenharmony_ci if (!i) 1058c2ecf20Sopenharmony_ci return NULL; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci inode_set_iversion(&i->vfs_inode, 1); 1088c2ecf20Sopenharmony_ci i->i_lc = NULL; 1098c2ecf20Sopenharmony_ci i->i_ext_bh = NULL; 1108c2ecf20Sopenharmony_ci i->i_pa_cnt = 0; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return &i->vfs_inode; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic void affs_free_inode(struct inode *inode) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci kmem_cache_free(affs_inode_cachep, AFFS_I(inode)); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void init_once(void *foo) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct affs_inode_info *ei = (struct affs_inode_info *) foo; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci mutex_init(&ei->i_link_lock); 1258c2ecf20Sopenharmony_ci mutex_init(&ei->i_ext_lock); 1268c2ecf20Sopenharmony_ci inode_init_once(&ei->vfs_inode); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int __init init_inodecache(void) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci affs_inode_cachep = kmem_cache_create("affs_inode_cache", 1328c2ecf20Sopenharmony_ci sizeof(struct affs_inode_info), 1338c2ecf20Sopenharmony_ci 0, (SLAB_RECLAIM_ACCOUNT| 1348c2ecf20Sopenharmony_ci SLAB_MEM_SPREAD|SLAB_ACCOUNT), 1358c2ecf20Sopenharmony_ci init_once); 1368c2ecf20Sopenharmony_ci if (affs_inode_cachep == NULL) 1378c2ecf20Sopenharmony_ci return -ENOMEM; 1388c2ecf20Sopenharmony_ci return 0; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic void destroy_inodecache(void) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci /* 1448c2ecf20Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 1458c2ecf20Sopenharmony_ci * destroy cache. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci rcu_barrier(); 1488c2ecf20Sopenharmony_ci kmem_cache_destroy(affs_inode_cachep); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic const struct super_operations affs_sops = { 1528c2ecf20Sopenharmony_ci .alloc_inode = affs_alloc_inode, 1538c2ecf20Sopenharmony_ci .free_inode = affs_free_inode, 1548c2ecf20Sopenharmony_ci .write_inode = affs_write_inode, 1558c2ecf20Sopenharmony_ci .evict_inode = affs_evict_inode, 1568c2ecf20Sopenharmony_ci .put_super = affs_put_super, 1578c2ecf20Sopenharmony_ci .sync_fs = affs_sync_fs, 1588c2ecf20Sopenharmony_ci .statfs = affs_statfs, 1598c2ecf20Sopenharmony_ci .remount_fs = affs_remount, 1608c2ecf20Sopenharmony_ci .show_options = affs_show_options, 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cienum { 1648c2ecf20Sopenharmony_ci Opt_bs, Opt_mode, Opt_mufs, Opt_notruncate, Opt_prefix, Opt_protect, 1658c2ecf20Sopenharmony_ci Opt_reserved, Opt_root, Opt_setgid, Opt_setuid, 1668c2ecf20Sopenharmony_ci Opt_verbose, Opt_volume, Opt_ignore, Opt_err, 1678c2ecf20Sopenharmony_ci}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic const match_table_t tokens = { 1708c2ecf20Sopenharmony_ci {Opt_bs, "bs=%u"}, 1718c2ecf20Sopenharmony_ci {Opt_mode, "mode=%o"}, 1728c2ecf20Sopenharmony_ci {Opt_mufs, "mufs"}, 1738c2ecf20Sopenharmony_ci {Opt_notruncate, "nofilenametruncate"}, 1748c2ecf20Sopenharmony_ci {Opt_prefix, "prefix=%s"}, 1758c2ecf20Sopenharmony_ci {Opt_protect, "protect"}, 1768c2ecf20Sopenharmony_ci {Opt_reserved, "reserved=%u"}, 1778c2ecf20Sopenharmony_ci {Opt_root, "root=%u"}, 1788c2ecf20Sopenharmony_ci {Opt_setgid, "setgid=%u"}, 1798c2ecf20Sopenharmony_ci {Opt_setuid, "setuid=%u"}, 1808c2ecf20Sopenharmony_ci {Opt_verbose, "verbose"}, 1818c2ecf20Sopenharmony_ci {Opt_volume, "volume=%s"}, 1828c2ecf20Sopenharmony_ci {Opt_ignore, "grpquota"}, 1838c2ecf20Sopenharmony_ci {Opt_ignore, "noquota"}, 1848c2ecf20Sopenharmony_ci {Opt_ignore, "quota"}, 1858c2ecf20Sopenharmony_ci {Opt_ignore, "usrquota"}, 1868c2ecf20Sopenharmony_ci {Opt_err, NULL}, 1878c2ecf20Sopenharmony_ci}; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int 1908c2ecf20Sopenharmony_ciparse_options(char *options, kuid_t *uid, kgid_t *gid, int *mode, int *reserved, s32 *root, 1918c2ecf20Sopenharmony_ci int *blocksize, char **prefix, char *volume, unsigned long *mount_opts) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci char *p; 1948c2ecf20Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* Fill in defaults */ 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci *uid = current_uid(); 1998c2ecf20Sopenharmony_ci *gid = current_gid(); 2008c2ecf20Sopenharmony_ci *reserved = 2; 2018c2ecf20Sopenharmony_ci *root = -1; 2028c2ecf20Sopenharmony_ci *blocksize = -1; 2038c2ecf20Sopenharmony_ci volume[0] = ':'; 2048c2ecf20Sopenharmony_ci volume[1] = 0; 2058c2ecf20Sopenharmony_ci *mount_opts = 0; 2068c2ecf20Sopenharmony_ci if (!options) 2078c2ecf20Sopenharmony_ci return 1; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci while ((p = strsep(&options, ",")) != NULL) { 2108c2ecf20Sopenharmony_ci int token, n, option; 2118c2ecf20Sopenharmony_ci if (!*p) 2128c2ecf20Sopenharmony_ci continue; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci token = match_token(p, tokens, args); 2158c2ecf20Sopenharmony_ci switch (token) { 2168c2ecf20Sopenharmony_ci case Opt_bs: 2178c2ecf20Sopenharmony_ci if (match_int(&args[0], &n)) 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci if (n != 512 && n != 1024 && n != 2048 2208c2ecf20Sopenharmony_ci && n != 4096) { 2218c2ecf20Sopenharmony_ci pr_warn("Invalid blocksize (512, 1024, 2048, 4096 allowed)\n"); 2228c2ecf20Sopenharmony_ci return 0; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci *blocksize = n; 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci case Opt_mode: 2278c2ecf20Sopenharmony_ci if (match_octal(&args[0], &option)) 2288c2ecf20Sopenharmony_ci return 0; 2298c2ecf20Sopenharmony_ci *mode = option & 0777; 2308c2ecf20Sopenharmony_ci affs_set_opt(*mount_opts, SF_SETMODE); 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci case Opt_mufs: 2338c2ecf20Sopenharmony_ci affs_set_opt(*mount_opts, SF_MUFS); 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci case Opt_notruncate: 2368c2ecf20Sopenharmony_ci affs_set_opt(*mount_opts, SF_NO_TRUNCATE); 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci case Opt_prefix: 2398c2ecf20Sopenharmony_ci kfree(*prefix); 2408c2ecf20Sopenharmony_ci *prefix = match_strdup(&args[0]); 2418c2ecf20Sopenharmony_ci if (!*prefix) 2428c2ecf20Sopenharmony_ci return 0; 2438c2ecf20Sopenharmony_ci affs_set_opt(*mount_opts, SF_PREFIX); 2448c2ecf20Sopenharmony_ci break; 2458c2ecf20Sopenharmony_ci case Opt_protect: 2468c2ecf20Sopenharmony_ci affs_set_opt(*mount_opts, SF_IMMUTABLE); 2478c2ecf20Sopenharmony_ci break; 2488c2ecf20Sopenharmony_ci case Opt_reserved: 2498c2ecf20Sopenharmony_ci if (match_int(&args[0], reserved)) 2508c2ecf20Sopenharmony_ci return 0; 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci case Opt_root: 2538c2ecf20Sopenharmony_ci if (match_int(&args[0], root)) 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci case Opt_setgid: 2578c2ecf20Sopenharmony_ci if (match_int(&args[0], &option)) 2588c2ecf20Sopenharmony_ci return 0; 2598c2ecf20Sopenharmony_ci *gid = make_kgid(current_user_ns(), option); 2608c2ecf20Sopenharmony_ci if (!gid_valid(*gid)) 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci affs_set_opt(*mount_opts, SF_SETGID); 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci case Opt_setuid: 2658c2ecf20Sopenharmony_ci if (match_int(&args[0], &option)) 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci *uid = make_kuid(current_user_ns(), option); 2688c2ecf20Sopenharmony_ci if (!uid_valid(*uid)) 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci affs_set_opt(*mount_opts, SF_SETUID); 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci case Opt_verbose: 2738c2ecf20Sopenharmony_ci affs_set_opt(*mount_opts, SF_VERBOSE); 2748c2ecf20Sopenharmony_ci break; 2758c2ecf20Sopenharmony_ci case Opt_volume: { 2768c2ecf20Sopenharmony_ci char *vol = match_strdup(&args[0]); 2778c2ecf20Sopenharmony_ci if (!vol) 2788c2ecf20Sopenharmony_ci return 0; 2798c2ecf20Sopenharmony_ci strlcpy(volume, vol, 32); 2808c2ecf20Sopenharmony_ci kfree(vol); 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci case Opt_ignore: 2848c2ecf20Sopenharmony_ci /* Silently ignore the quota options */ 2858c2ecf20Sopenharmony_ci break; 2868c2ecf20Sopenharmony_ci default: 2878c2ecf20Sopenharmony_ci pr_warn("Unrecognized mount option \"%s\" or missing value\n", 2888c2ecf20Sopenharmony_ci p); 2898c2ecf20Sopenharmony_ci return 0; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci return 1; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int affs_show_options(struct seq_file *m, struct dentry *root) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct super_block *sb = root->d_sb; 2988c2ecf20Sopenharmony_ci struct affs_sb_info *sbi = AFFS_SB(sb); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (sb->s_blocksize) 3018c2ecf20Sopenharmony_ci seq_printf(m, ",bs=%lu", sb->s_blocksize); 3028c2ecf20Sopenharmony_ci if (affs_test_opt(sbi->s_flags, SF_SETMODE)) 3038c2ecf20Sopenharmony_ci seq_printf(m, ",mode=%o", sbi->s_mode); 3048c2ecf20Sopenharmony_ci if (affs_test_opt(sbi->s_flags, SF_MUFS)) 3058c2ecf20Sopenharmony_ci seq_puts(m, ",mufs"); 3068c2ecf20Sopenharmony_ci if (affs_test_opt(sbi->s_flags, SF_NO_TRUNCATE)) 3078c2ecf20Sopenharmony_ci seq_puts(m, ",nofilenametruncate"); 3088c2ecf20Sopenharmony_ci if (affs_test_opt(sbi->s_flags, SF_PREFIX)) 3098c2ecf20Sopenharmony_ci seq_printf(m, ",prefix=%s", sbi->s_prefix); 3108c2ecf20Sopenharmony_ci if (affs_test_opt(sbi->s_flags, SF_IMMUTABLE)) 3118c2ecf20Sopenharmony_ci seq_puts(m, ",protect"); 3128c2ecf20Sopenharmony_ci if (sbi->s_reserved != 2) 3138c2ecf20Sopenharmony_ci seq_printf(m, ",reserved=%u", sbi->s_reserved); 3148c2ecf20Sopenharmony_ci if (sbi->s_root_block != (sbi->s_reserved + sbi->s_partition_size - 1) / 2) 3158c2ecf20Sopenharmony_ci seq_printf(m, ",root=%u", sbi->s_root_block); 3168c2ecf20Sopenharmony_ci if (affs_test_opt(sbi->s_flags, SF_SETGID)) 3178c2ecf20Sopenharmony_ci seq_printf(m, ",setgid=%u", 3188c2ecf20Sopenharmony_ci from_kgid_munged(&init_user_ns, sbi->s_gid)); 3198c2ecf20Sopenharmony_ci if (affs_test_opt(sbi->s_flags, SF_SETUID)) 3208c2ecf20Sopenharmony_ci seq_printf(m, ",setuid=%u", 3218c2ecf20Sopenharmony_ci from_kuid_munged(&init_user_ns, sbi->s_uid)); 3228c2ecf20Sopenharmony_ci if (affs_test_opt(sbi->s_flags, SF_VERBOSE)) 3238c2ecf20Sopenharmony_ci seq_puts(m, ",verbose"); 3248c2ecf20Sopenharmony_ci if (sbi->s_volume[0]) 3258c2ecf20Sopenharmony_ci seq_printf(m, ",volume=%s", sbi->s_volume); 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci/* This function definitely needs to be split up. Some fine day I'll 3308c2ecf20Sopenharmony_ci * hopefully have the guts to do so. Until then: sorry for the mess. 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic int affs_fill_super(struct super_block *sb, void *data, int silent) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct affs_sb_info *sbi; 3368c2ecf20Sopenharmony_ci struct buffer_head *root_bh = NULL; 3378c2ecf20Sopenharmony_ci struct buffer_head *boot_bh; 3388c2ecf20Sopenharmony_ci struct inode *root_inode = NULL; 3398c2ecf20Sopenharmony_ci s32 root_block; 3408c2ecf20Sopenharmony_ci int size, blocksize; 3418c2ecf20Sopenharmony_ci u32 chksum; 3428c2ecf20Sopenharmony_ci int num_bm; 3438c2ecf20Sopenharmony_ci int i, j; 3448c2ecf20Sopenharmony_ci kuid_t uid; 3458c2ecf20Sopenharmony_ci kgid_t gid; 3468c2ecf20Sopenharmony_ci int reserved; 3478c2ecf20Sopenharmony_ci unsigned long mount_flags; 3488c2ecf20Sopenharmony_ci int tmp_flags; /* fix remount prototype... */ 3498c2ecf20Sopenharmony_ci u8 sig[4]; 3508c2ecf20Sopenharmony_ci int ret; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci pr_debug("read_super(%s)\n", data ? (const char *)data : "no options"); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci sb->s_magic = AFFS_SUPER_MAGIC; 3558c2ecf20Sopenharmony_ci sb->s_op = &affs_sops; 3568c2ecf20Sopenharmony_ci sb->s_flags |= SB_NODIRATIME; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci sb->s_time_gran = NSEC_PER_SEC; 3598c2ecf20Sopenharmony_ci sb->s_time_min = sys_tz.tz_minuteswest * 60 + AFFS_EPOCH_DELTA; 3608c2ecf20Sopenharmony_ci sb->s_time_max = 86400LL * U32_MAX + 86400 + sb->s_time_min; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci sbi = kzalloc(sizeof(struct affs_sb_info), GFP_KERNEL); 3638c2ecf20Sopenharmony_ci if (!sbi) 3648c2ecf20Sopenharmony_ci return -ENOMEM; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci sb->s_fs_info = sbi; 3678c2ecf20Sopenharmony_ci sbi->sb = sb; 3688c2ecf20Sopenharmony_ci mutex_init(&sbi->s_bmlock); 3698c2ecf20Sopenharmony_ci spin_lock_init(&sbi->symlink_lock); 3708c2ecf20Sopenharmony_ci spin_lock_init(&sbi->work_lock); 3718c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&sbi->sb_work, flush_superblock); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block, 3748c2ecf20Sopenharmony_ci &blocksize,&sbi->s_prefix, 3758c2ecf20Sopenharmony_ci sbi->s_volume, &mount_flags)) { 3768c2ecf20Sopenharmony_ci pr_err("Error parsing options\n"); 3778c2ecf20Sopenharmony_ci return -EINVAL; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci /* N.B. after this point s_prefix must be released */ 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci sbi->s_flags = mount_flags; 3828c2ecf20Sopenharmony_ci sbi->s_mode = i; 3838c2ecf20Sopenharmony_ci sbi->s_uid = uid; 3848c2ecf20Sopenharmony_ci sbi->s_gid = gid; 3858c2ecf20Sopenharmony_ci sbi->s_reserved= reserved; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* Get the size of the device in 512-byte blocks. 3888c2ecf20Sopenharmony_ci * If we later see that the partition uses bigger 3898c2ecf20Sopenharmony_ci * blocks, we will have to change it. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci size = i_size_read(sb->s_bdev->bd_inode) >> 9; 3938c2ecf20Sopenharmony_ci pr_debug("initial blocksize=%d, #blocks=%d\n", 512, size); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci affs_set_blocksize(sb, PAGE_SIZE); 3968c2ecf20Sopenharmony_ci /* Try to find root block. Its location depends on the block size. */ 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci i = bdev_logical_block_size(sb->s_bdev); 3998c2ecf20Sopenharmony_ci j = PAGE_SIZE; 4008c2ecf20Sopenharmony_ci if (blocksize > 0) { 4018c2ecf20Sopenharmony_ci i = j = blocksize; 4028c2ecf20Sopenharmony_ci size = size / (blocksize / 512); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci for (blocksize = i; blocksize <= j; blocksize <<= 1, size >>= 1) { 4068c2ecf20Sopenharmony_ci sbi->s_root_block = root_block; 4078c2ecf20Sopenharmony_ci if (root_block < 0) 4088c2ecf20Sopenharmony_ci sbi->s_root_block = (reserved + size - 1) / 2; 4098c2ecf20Sopenharmony_ci pr_debug("setting blocksize to %d\n", blocksize); 4108c2ecf20Sopenharmony_ci affs_set_blocksize(sb, blocksize); 4118c2ecf20Sopenharmony_ci sbi->s_partition_size = size; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* The root block location that was calculated above is not 4148c2ecf20Sopenharmony_ci * correct if the partition size is an odd number of 512- 4158c2ecf20Sopenharmony_ci * byte blocks, which will be rounded down to a number of 4168c2ecf20Sopenharmony_ci * 1024-byte blocks, and if there were an even number of 4178c2ecf20Sopenharmony_ci * reserved blocks. Ideally, all partition checkers should 4188c2ecf20Sopenharmony_ci * report the real number of blocks of the real blocksize, 4198c2ecf20Sopenharmony_ci * but since this just cannot be done, we have to try to 4208c2ecf20Sopenharmony_ci * find the root block anyways. In the above case, it is one 4218c2ecf20Sopenharmony_ci * block behind the calculated one. So we check this one, too. 4228c2ecf20Sopenharmony_ci */ 4238c2ecf20Sopenharmony_ci for (num_bm = 0; num_bm < 2; num_bm++) { 4248c2ecf20Sopenharmony_ci pr_debug("Dev %s, trying root=%u, bs=%d, " 4258c2ecf20Sopenharmony_ci "size=%d, reserved=%d\n", 4268c2ecf20Sopenharmony_ci sb->s_id, 4278c2ecf20Sopenharmony_ci sbi->s_root_block + num_bm, 4288c2ecf20Sopenharmony_ci blocksize, size, reserved); 4298c2ecf20Sopenharmony_ci root_bh = affs_bread(sb, sbi->s_root_block + num_bm); 4308c2ecf20Sopenharmony_ci if (!root_bh) 4318c2ecf20Sopenharmony_ci continue; 4328c2ecf20Sopenharmony_ci if (!affs_checksum_block(sb, root_bh) && 4338c2ecf20Sopenharmony_ci be32_to_cpu(AFFS_ROOT_HEAD(root_bh)->ptype) == T_SHORT && 4348c2ecf20Sopenharmony_ci be32_to_cpu(AFFS_ROOT_TAIL(sb, root_bh)->stype) == ST_ROOT) { 4358c2ecf20Sopenharmony_ci sbi->s_hashsize = blocksize / 4 - 56; 4368c2ecf20Sopenharmony_ci sbi->s_root_block += num_bm; 4378c2ecf20Sopenharmony_ci goto got_root; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci affs_brelse(root_bh); 4408c2ecf20Sopenharmony_ci root_bh = NULL; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci if (!silent) 4448c2ecf20Sopenharmony_ci pr_err("No valid root block on device %s\n", sb->s_id); 4458c2ecf20Sopenharmony_ci return -EINVAL; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* N.B. after this point bh must be released */ 4488c2ecf20Sopenharmony_cigot_root: 4498c2ecf20Sopenharmony_ci /* Keep super block in cache */ 4508c2ecf20Sopenharmony_ci sbi->s_root_bh = root_bh; 4518c2ecf20Sopenharmony_ci root_block = sbi->s_root_block; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* Find out which kind of FS we have */ 4548c2ecf20Sopenharmony_ci boot_bh = sb_bread(sb, 0); 4558c2ecf20Sopenharmony_ci if (!boot_bh) { 4568c2ecf20Sopenharmony_ci pr_err("Cannot read boot block\n"); 4578c2ecf20Sopenharmony_ci return -EINVAL; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci memcpy(sig, boot_bh->b_data, 4); 4608c2ecf20Sopenharmony_ci brelse(boot_bh); 4618c2ecf20Sopenharmony_ci chksum = be32_to_cpu(*(__be32 *)sig); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* Dircache filesystems are compatible with non-dircache ones 4648c2ecf20Sopenharmony_ci * when reading. As long as they aren't supported, writing is 4658c2ecf20Sopenharmony_ci * not recommended. 4668c2ecf20Sopenharmony_ci */ 4678c2ecf20Sopenharmony_ci if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS 4688c2ecf20Sopenharmony_ci || chksum == MUFS_DCOFS) && !sb_rdonly(sb)) { 4698c2ecf20Sopenharmony_ci pr_notice("Dircache FS - mounting %s read only\n", sb->s_id); 4708c2ecf20Sopenharmony_ci sb->s_flags |= SB_RDONLY; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci switch (chksum) { 4738c2ecf20Sopenharmony_ci case MUFS_FS: 4748c2ecf20Sopenharmony_ci case MUFS_INTLFFS: 4758c2ecf20Sopenharmony_ci case MUFS_DCFFS: 4768c2ecf20Sopenharmony_ci affs_set_opt(sbi->s_flags, SF_MUFS); 4778c2ecf20Sopenharmony_ci fallthrough; 4788c2ecf20Sopenharmony_ci case FS_INTLFFS: 4798c2ecf20Sopenharmony_ci case FS_DCFFS: 4808c2ecf20Sopenharmony_ci affs_set_opt(sbi->s_flags, SF_INTL); 4818c2ecf20Sopenharmony_ci break; 4828c2ecf20Sopenharmony_ci case MUFS_FFS: 4838c2ecf20Sopenharmony_ci affs_set_opt(sbi->s_flags, SF_MUFS); 4848c2ecf20Sopenharmony_ci break; 4858c2ecf20Sopenharmony_ci case FS_FFS: 4868c2ecf20Sopenharmony_ci break; 4878c2ecf20Sopenharmony_ci case MUFS_OFS: 4888c2ecf20Sopenharmony_ci affs_set_opt(sbi->s_flags, SF_MUFS); 4898c2ecf20Sopenharmony_ci fallthrough; 4908c2ecf20Sopenharmony_ci case FS_OFS: 4918c2ecf20Sopenharmony_ci affs_set_opt(sbi->s_flags, SF_OFS); 4928c2ecf20Sopenharmony_ci sb->s_flags |= SB_NOEXEC; 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci case MUFS_DCOFS: 4958c2ecf20Sopenharmony_ci case MUFS_INTLOFS: 4968c2ecf20Sopenharmony_ci affs_set_opt(sbi->s_flags, SF_MUFS); 4978c2ecf20Sopenharmony_ci fallthrough; 4988c2ecf20Sopenharmony_ci case FS_DCOFS: 4998c2ecf20Sopenharmony_ci case FS_INTLOFS: 5008c2ecf20Sopenharmony_ci affs_set_opt(sbi->s_flags, SF_INTL); 5018c2ecf20Sopenharmony_ci affs_set_opt(sbi->s_flags, SF_OFS); 5028c2ecf20Sopenharmony_ci sb->s_flags |= SB_NOEXEC; 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci default: 5058c2ecf20Sopenharmony_ci pr_err("Unknown filesystem on device %s: %08X\n", 5068c2ecf20Sopenharmony_ci sb->s_id, chksum); 5078c2ecf20Sopenharmony_ci return -EINVAL; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (affs_test_opt(mount_flags, SF_VERBOSE)) { 5118c2ecf20Sopenharmony_ci u8 len = AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0]; 5128c2ecf20Sopenharmony_ci pr_notice("Mounting volume \"%.*s\": Type=%.3s\\%c, Blocksize=%d\n", 5138c2ecf20Sopenharmony_ci len > 31 ? 31 : len, 5148c2ecf20Sopenharmony_ci AFFS_ROOT_TAIL(sb, root_bh)->disk_name + 1, 5158c2ecf20Sopenharmony_ci sig, sig[3] + '0', blocksize); 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci sb->s_flags |= SB_NODEV | SB_NOSUID; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci sbi->s_data_blksize = sb->s_blocksize; 5218c2ecf20Sopenharmony_ci if (affs_test_opt(sbi->s_flags, SF_OFS)) 5228c2ecf20Sopenharmony_ci sbi->s_data_blksize -= 24; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci tmp_flags = sb->s_flags; 5258c2ecf20Sopenharmony_ci ret = affs_init_bitmap(sb, &tmp_flags); 5268c2ecf20Sopenharmony_ci if (ret) 5278c2ecf20Sopenharmony_ci return ret; 5288c2ecf20Sopenharmony_ci sb->s_flags = tmp_flags; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci /* set up enough so that it can read an inode */ 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci root_inode = affs_iget(sb, root_block); 5338c2ecf20Sopenharmony_ci if (IS_ERR(root_inode)) 5348c2ecf20Sopenharmony_ci return PTR_ERR(root_inode); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL)) 5378c2ecf20Sopenharmony_ci sb->s_d_op = &affs_intl_dentry_operations; 5388c2ecf20Sopenharmony_ci else 5398c2ecf20Sopenharmony_ci sb->s_d_op = &affs_dentry_operations; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci sb->s_root = d_make_root(root_inode); 5428c2ecf20Sopenharmony_ci if (!sb->s_root) { 5438c2ecf20Sopenharmony_ci pr_err("AFFS: Get root inode failed\n"); 5448c2ecf20Sopenharmony_ci return -ENOMEM; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci sb->s_export_op = &affs_export_ops; 5488c2ecf20Sopenharmony_ci pr_debug("s_flags=%lX\n", sb->s_flags); 5498c2ecf20Sopenharmony_ci return 0; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic int 5538c2ecf20Sopenharmony_ciaffs_remount(struct super_block *sb, int *flags, char *data) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci struct affs_sb_info *sbi = AFFS_SB(sb); 5568c2ecf20Sopenharmony_ci int blocksize; 5578c2ecf20Sopenharmony_ci kuid_t uid; 5588c2ecf20Sopenharmony_ci kgid_t gid; 5598c2ecf20Sopenharmony_ci int mode; 5608c2ecf20Sopenharmony_ci int reserved; 5618c2ecf20Sopenharmony_ci int root_block; 5628c2ecf20Sopenharmony_ci unsigned long mount_flags; 5638c2ecf20Sopenharmony_ci int res = 0; 5648c2ecf20Sopenharmony_ci char volume[32]; 5658c2ecf20Sopenharmony_ci char *prefix = NULL; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci pr_debug("%s(flags=0x%x,opts=\"%s\")\n", __func__, *flags, data); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci sync_filesystem(sb); 5708c2ecf20Sopenharmony_ci *flags |= SB_NODIRATIME; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci memcpy(volume, sbi->s_volume, 32); 5738c2ecf20Sopenharmony_ci if (!parse_options(data, &uid, &gid, &mode, &reserved, &root_block, 5748c2ecf20Sopenharmony_ci &blocksize, &prefix, volume, 5758c2ecf20Sopenharmony_ci &mount_flags)) { 5768c2ecf20Sopenharmony_ci kfree(prefix); 5778c2ecf20Sopenharmony_ci return -EINVAL; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci flush_delayed_work(&sbi->sb_work); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci sbi->s_flags = mount_flags; 5838c2ecf20Sopenharmony_ci sbi->s_mode = mode; 5848c2ecf20Sopenharmony_ci sbi->s_uid = uid; 5858c2ecf20Sopenharmony_ci sbi->s_gid = gid; 5868c2ecf20Sopenharmony_ci /* protect against readers */ 5878c2ecf20Sopenharmony_ci spin_lock(&sbi->symlink_lock); 5888c2ecf20Sopenharmony_ci if (prefix) { 5898c2ecf20Sopenharmony_ci kfree(sbi->s_prefix); 5908c2ecf20Sopenharmony_ci sbi->s_prefix = prefix; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci memcpy(sbi->s_volume, volume, 32); 5938c2ecf20Sopenharmony_ci spin_unlock(&sbi->symlink_lock); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb)) 5968c2ecf20Sopenharmony_ci return 0; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (*flags & SB_RDONLY) 5998c2ecf20Sopenharmony_ci affs_free_bitmap(sb); 6008c2ecf20Sopenharmony_ci else 6018c2ecf20Sopenharmony_ci res = affs_init_bitmap(sb, flags); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci return res; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic int 6078c2ecf20Sopenharmony_ciaffs_statfs(struct dentry *dentry, struct kstatfs *buf) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci struct super_block *sb = dentry->d_sb; 6108c2ecf20Sopenharmony_ci int free; 6118c2ecf20Sopenharmony_ci u64 id = huge_encode_dev(sb->s_bdev->bd_dev); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci pr_debug("%s() partsize=%d, reserved=%d\n", 6148c2ecf20Sopenharmony_ci __func__, AFFS_SB(sb)->s_partition_size, 6158c2ecf20Sopenharmony_ci AFFS_SB(sb)->s_reserved); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci free = affs_count_free_blocks(sb); 6188c2ecf20Sopenharmony_ci buf->f_type = AFFS_SUPER_MAGIC; 6198c2ecf20Sopenharmony_ci buf->f_bsize = sb->s_blocksize; 6208c2ecf20Sopenharmony_ci buf->f_blocks = AFFS_SB(sb)->s_partition_size - AFFS_SB(sb)->s_reserved; 6218c2ecf20Sopenharmony_ci buf->f_bfree = free; 6228c2ecf20Sopenharmony_ci buf->f_bavail = free; 6238c2ecf20Sopenharmony_ci buf->f_fsid = u64_to_fsid(id); 6248c2ecf20Sopenharmony_ci buf->f_namelen = AFFSNAMEMAX; 6258c2ecf20Sopenharmony_ci return 0; 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_cistatic struct dentry *affs_mount(struct file_system_type *fs_type, 6298c2ecf20Sopenharmony_ci int flags, const char *dev_name, void *data) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci return mount_bdev(fs_type, flags, dev_name, data, affs_fill_super); 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic void affs_kill_sb(struct super_block *sb) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct affs_sb_info *sbi = AFFS_SB(sb); 6378c2ecf20Sopenharmony_ci kill_block_super(sb); 6388c2ecf20Sopenharmony_ci if (sbi) { 6398c2ecf20Sopenharmony_ci affs_free_bitmap(sb); 6408c2ecf20Sopenharmony_ci affs_brelse(sbi->s_root_bh); 6418c2ecf20Sopenharmony_ci kfree(sbi->s_prefix); 6428c2ecf20Sopenharmony_ci mutex_destroy(&sbi->s_bmlock); 6438c2ecf20Sopenharmony_ci kfree(sbi); 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic struct file_system_type affs_fs_type = { 6488c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6498c2ecf20Sopenharmony_ci .name = "affs", 6508c2ecf20Sopenharmony_ci .mount = affs_mount, 6518c2ecf20Sopenharmony_ci .kill_sb = affs_kill_sb, 6528c2ecf20Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV, 6538c2ecf20Sopenharmony_ci}; 6548c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("affs"); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic int __init init_affs_fs(void) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci int err = init_inodecache(); 6598c2ecf20Sopenharmony_ci if (err) 6608c2ecf20Sopenharmony_ci goto out1; 6618c2ecf20Sopenharmony_ci err = register_filesystem(&affs_fs_type); 6628c2ecf20Sopenharmony_ci if (err) 6638c2ecf20Sopenharmony_ci goto out; 6648c2ecf20Sopenharmony_ci return 0; 6658c2ecf20Sopenharmony_ciout: 6668c2ecf20Sopenharmony_ci destroy_inodecache(); 6678c2ecf20Sopenharmony_ciout1: 6688c2ecf20Sopenharmony_ci return err; 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic void __exit exit_affs_fs(void) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci unregister_filesystem(&affs_fs_type); 6748c2ecf20Sopenharmony_ci destroy_inodecache(); 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Amiga filesystem support for Linux"); 6788c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cimodule_init(init_affs_fs) 6818c2ecf20Sopenharmony_cimodule_exit(exit_affs_fs) 682