linux/fs/adfs/super.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  linux/fs/adfs/super.c
   4 *
   5 *  Copyright (C) 1997-1999 Russell King
   6 */
   7#include <linux/module.h>
   8#include <linux/init.h>
   9#include <linux/parser.h>
  10#include <linux/mount.h>
  11#include <linux/seq_file.h>
  12#include <linux/slab.h>
  13#include <linux/statfs.h>
  14#include <linux/user_namespace.h>
  15#include "adfs.h"
  16#include "dir_f.h"
  17#include "dir_fplus.h"
  18
  19#define ADFS_SB_FLAGS SB_NOATIME
  20
  21#define ADFS_DEFAULT_OWNER_MASK S_IRWXU
  22#define ADFS_DEFAULT_OTHER_MASK (S_IRWXG | S_IRWXO)
  23
  24void __adfs_error(struct super_block *sb, const char *function, const char *fmt, ...)
  25{
  26        struct va_format vaf;
  27        va_list args;
  28
  29        va_start(args, fmt);
  30        vaf.fmt = fmt;
  31        vaf.va = &args;
  32
  33        printk(KERN_CRIT "ADFS-fs error (device %s)%s%s: %pV\n",
  34                sb->s_id, function ? ": " : "",
  35                function ? function : "", &vaf);
  36
  37        va_end(args);
  38}
  39
  40void adfs_msg(struct super_block *sb, const char *pfx, const char *fmt, ...)
  41{
  42        struct va_format vaf;
  43        va_list args;
  44
  45        va_start(args, fmt);
  46        vaf.fmt = fmt;
  47        vaf.va = &args;
  48        printk("%sADFS-fs (%s): %pV\n", pfx, sb->s_id, &vaf);
  49        va_end(args);
  50}
  51
  52static int adfs_checkdiscrecord(struct adfs_discrecord *dr)
  53{
  54        unsigned int max_idlen;
  55        int i;
  56
  57        /* sector size must be 256, 512 or 1024 bytes */
  58        if (dr->log2secsize != 8 &&
  59            dr->log2secsize != 9 &&
  60            dr->log2secsize != 10)
  61                return 1;
  62
  63        /* idlen must be at least log2secsize + 3 */
  64        if (dr->idlen < dr->log2secsize + 3)
  65                return 1;
  66
  67        /* we cannot have such a large disc that we
  68         * are unable to represent sector offsets in
  69         * 32 bits.  This works out at 2.0 TB.
  70         */
  71        if (le32_to_cpu(dr->disc_size_high) >> dr->log2secsize)
  72                return 1;
  73
  74        /*
  75         * Maximum idlen is limited to 16 bits for new directories by
  76         * the three-byte storage of an indirect disc address.  For
  77         * big directories, idlen must be no greater than 19 v2 [1.0]
  78         */
  79        max_idlen = dr->format_version ? 19 : 16;
  80        if (dr->idlen > max_idlen)
  81                return 1;
  82
  83        /* reserved bytes should be zero */
  84        for (i = 0; i < sizeof(dr->unused52); i++)
  85                if (dr->unused52[i] != 0)
  86                        return 1;
  87
  88        return 0;
  89}
  90
  91static unsigned char adfs_calczonecheck(struct super_block *sb, unsigned char *map)
  92{
  93        unsigned int v0, v1, v2, v3;
  94        int i;
  95
  96        v0 = v1 = v2 = v3 = 0;
  97        for (i = sb->s_blocksize - 4; i; i -= 4) {
  98                v0 += map[i]     + (v3 >> 8);
  99                v3 &= 0xff;
 100                v1 += map[i + 1] + (v0 >> 8);
 101                v0 &= 0xff;
 102                v2 += map[i + 2] + (v1 >> 8);
 103                v1 &= 0xff;
 104                v3 += map[i + 3] + (v2 >> 8);
 105                v2 &= 0xff;
 106        }
 107        v0 +=           v3 >> 8;
 108        v1 += map[1] + (v0 >> 8);
 109        v2 += map[2] + (v1 >> 8);
 110        v3 += map[3] + (v2 >> 8);
 111
 112        return v0 ^ v1 ^ v2 ^ v3;
 113}
 114
 115static int adfs_checkmap(struct super_block *sb, struct adfs_discmap *dm)
 116{
 117        unsigned char crosscheck = 0, zonecheck = 1;
 118        int i;
 119
 120        for (i = 0; i < ADFS_SB(sb)->s_map_size; i++) {
 121                unsigned char *map;
 122
 123                map = dm[i].dm_bh->b_data;
 124
 125                if (adfs_calczonecheck(sb, map) != map[0]) {
 126                        adfs_error(sb, "zone %d fails zonecheck", i);
 127                        zonecheck = 0;
 128                }
 129                crosscheck ^= map[3];
 130        }
 131        if (crosscheck != 0xff)
 132                adfs_error(sb, "crosscheck != 0xff");
 133        return crosscheck == 0xff && zonecheck;
 134}
 135
 136static void adfs_put_super(struct super_block *sb)
 137{
 138        int i;
 139        struct adfs_sb_info *asb = ADFS_SB(sb);
 140
 141        for (i = 0; i < asb->s_map_size; i++)
 142                brelse(asb->s_map[i].dm_bh);
 143        kfree(asb->s_map);
 144        kfree_rcu(asb, rcu);
 145}
 146
 147static int adfs_show_options(struct seq_file *seq, struct dentry *root)
 148{
 149        struct adfs_sb_info *asb = ADFS_SB(root->d_sb);
 150
 151        if (!uid_eq(asb->s_uid, GLOBAL_ROOT_UID))
 152                seq_printf(seq, ",uid=%u", from_kuid_munged(&init_user_ns, asb->s_uid));
 153        if (!gid_eq(asb->s_gid, GLOBAL_ROOT_GID))
 154                seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, asb->s_gid));
 155        if (asb->s_owner_mask != ADFS_DEFAULT_OWNER_MASK)
 156                seq_printf(seq, ",ownmask=%o", asb->s_owner_mask);
 157        if (asb->s_other_mask != ADFS_DEFAULT_OTHER_MASK)
 158                seq_printf(seq, ",othmask=%o", asb->s_other_mask);
 159        if (asb->s_ftsuffix != 0)
 160                seq_printf(seq, ",ftsuffix=%u", asb->s_ftsuffix);
 161
 162        return 0;
 163}
 164
 165enum {Opt_uid, Opt_gid, Opt_ownmask, Opt_othmask, Opt_ftsuffix, Opt_err};
 166
 167static const match_table_t tokens = {
 168        {Opt_uid, "uid=%u"},
 169        {Opt_gid, "gid=%u"},
 170        {Opt_ownmask, "ownmask=%o"},
 171        {Opt_othmask, "othmask=%o"},
 172        {Opt_ftsuffix, "ftsuffix=%u"},
 173        {Opt_err, NULL}
 174};
 175
 176static int parse_options(struct super_block *sb, struct adfs_sb_info *asb,
 177                         char *options)
 178{
 179        char *p;
 180        int option;
 181
 182        if (!options)
 183                return 0;
 184
 185        while ((p = strsep(&options, ",")) != NULL) {
 186                substring_t args[MAX_OPT_ARGS];
 187                int token;
 188                if (!*p)
 189                        continue;
 190
 191                token = match_token(p, tokens, args);
 192                switch (token) {
 193                case Opt_uid:
 194                        if (match_int(args, &option))
 195                                return -EINVAL;
 196                        asb->s_uid = make_kuid(current_user_ns(), option);
 197                        if (!uid_valid(asb->s_uid))
 198                                return -EINVAL;
 199                        break;
 200                case Opt_gid:
 201                        if (match_int(args, &option))
 202                                return -EINVAL;
 203                        asb->s_gid = make_kgid(current_user_ns(), option);
 204                        if (!gid_valid(asb->s_gid))
 205                                return -EINVAL;
 206                        break;
 207                case Opt_ownmask:
 208                        if (match_octal(args, &option))
 209                                return -EINVAL;
 210                        asb->s_owner_mask = option;
 211                        break;
 212                case Opt_othmask:
 213                        if (match_octal(args, &option))
 214                                return -EINVAL;
 215                        asb->s_other_mask = option;
 216                        break;
 217                case Opt_ftsuffix:
 218                        if (match_int(args, &option))
 219                                return -EINVAL;
 220                        asb->s_ftsuffix = option;
 221                        break;
 222                default:
 223                        adfs_msg(sb, KERN_ERR,
 224                                 "unrecognised mount option \"%s\" or missing value",
 225                                 p);
 226                        return -EINVAL;
 227                }
 228        }
 229        return 0;
 230}
 231
 232static int adfs_remount(struct super_block *sb, int *flags, char *data)
 233{
 234        struct adfs_sb_info temp_asb;
 235        int ret;
 236
 237        sync_filesystem(sb);
 238        *flags |= ADFS_SB_FLAGS;
 239
 240        temp_asb = *ADFS_SB(sb);
 241        ret = parse_options(sb, &temp_asb, data);
 242        if (ret == 0)
 243                *ADFS_SB(sb) = temp_asb;
 244
 245        return ret;
 246}
 247
 248static int adfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 249{
 250        struct super_block *sb = dentry->d_sb;
 251        struct adfs_sb_info *sbi = ADFS_SB(sb);
 252        struct adfs_discrecord *dr = adfs_map_discrecord(sbi->s_map);
 253        u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 254
 255        buf->f_type    = ADFS_SUPER_MAGIC;
 256        buf->f_namelen = sbi->s_namelen;
 257        buf->f_bsize   = sb->s_blocksize;
 258        buf->f_blocks  = adfs_disc_size(dr) >> sb->s_blocksize_bits;
 259        buf->f_files   = sbi->s_ids_per_zone * sbi->s_map_size;
 260        buf->f_bavail  =
 261        buf->f_bfree   = adfs_map_free(sb);
 262        buf->f_ffree   = (long)(buf->f_bfree * buf->f_files) / (long)buf->f_blocks;
 263        buf->f_fsid.val[0] = (u32)id;
 264        buf->f_fsid.val[1] = (u32)(id >> 32);
 265
 266        return 0;
 267}
 268
 269static struct kmem_cache *adfs_inode_cachep;
 270
 271static struct inode *adfs_alloc_inode(struct super_block *sb)
 272{
 273        struct adfs_inode_info *ei;
 274        ei = kmem_cache_alloc(adfs_inode_cachep, GFP_KERNEL);
 275        if (!ei)
 276                return NULL;
 277        return &ei->vfs_inode;
 278}
 279
 280static void adfs_free_inode(struct inode *inode)
 281{
 282        kmem_cache_free(adfs_inode_cachep, ADFS_I(inode));
 283}
 284
 285static void init_once(void *foo)
 286{
 287        struct adfs_inode_info *ei = (struct adfs_inode_info *) foo;
 288
 289        inode_init_once(&ei->vfs_inode);
 290}
 291
 292static int __init init_inodecache(void)
 293{
 294        adfs_inode_cachep = kmem_cache_create("adfs_inode_cache",
 295                                             sizeof(struct adfs_inode_info),
 296                                             0, (SLAB_RECLAIM_ACCOUNT|
 297                                                SLAB_MEM_SPREAD|SLAB_ACCOUNT),
 298                                             init_once);
 299        if (adfs_inode_cachep == NULL)
 300                return -ENOMEM;
 301        return 0;
 302}
 303
 304static void destroy_inodecache(void)
 305{
 306        /*
 307         * Make sure all delayed rcu free inodes are flushed before we
 308         * destroy cache.
 309         */
 310        rcu_barrier();
 311        kmem_cache_destroy(adfs_inode_cachep);
 312}
 313
 314static const struct super_operations adfs_sops = {
 315        .alloc_inode    = adfs_alloc_inode,
 316        .free_inode     = adfs_free_inode,
 317        .drop_inode     = generic_delete_inode,
 318        .write_inode    = adfs_write_inode,
 319        .put_super      = adfs_put_super,
 320        .statfs         = adfs_statfs,
 321        .remount_fs     = adfs_remount,
 322        .show_options   = adfs_show_options,
 323};
 324
 325static struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecord *dr)
 326{
 327        struct adfs_discmap *dm;
 328        unsigned int map_addr, zone_size, nzones;
 329        int i, zone;
 330        struct adfs_sb_info *asb = ADFS_SB(sb);
 331
 332        nzones    = asb->s_map_size;
 333        zone_size = (8 << dr->log2secsize) - le16_to_cpu(dr->zone_spare);
 334        map_addr  = (nzones >> 1) * zone_size -
 335                     ((nzones > 1) ? ADFS_DR_SIZE_BITS : 0);
 336        map_addr  = signed_asl(map_addr, asb->s_map2blk);
 337
 338        asb->s_ids_per_zone = zone_size / (asb->s_idlen + 1);
 339
 340        dm = kmalloc_array(nzones, sizeof(*dm), GFP_KERNEL);
 341        if (dm == NULL) {
 342                adfs_error(sb, "not enough memory");
 343                return ERR_PTR(-ENOMEM);
 344        }
 345
 346        for (zone = 0; zone < nzones; zone++, map_addr++) {
 347                dm[zone].dm_startbit = 0;
 348                dm[zone].dm_endbit   = zone_size;
 349                dm[zone].dm_startblk = zone * zone_size - ADFS_DR_SIZE_BITS;
 350                dm[zone].dm_bh       = sb_bread(sb, map_addr);
 351
 352                if (!dm[zone].dm_bh) {
 353                        adfs_error(sb, "unable to read map");
 354                        goto error_free;
 355                }
 356        }
 357
 358        /* adjust the limits for the first and last map zones */
 359        i = zone - 1;
 360        dm[0].dm_startblk = 0;
 361        dm[0].dm_startbit = ADFS_DR_SIZE_BITS;
 362        dm[i].dm_endbit   = (adfs_disc_size(dr) >> dr->log2bpmb) +
 363                            (ADFS_DR_SIZE_BITS - i * zone_size);
 364
 365        if (adfs_checkmap(sb, dm))
 366                return dm;
 367
 368        adfs_error(sb, "map corrupted");
 369
 370error_free:
 371        while (--zone >= 0)
 372                brelse(dm[zone].dm_bh);
 373
 374        kfree(dm);
 375        return ERR_PTR(-EIO);
 376}
 377
 378static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 379{
 380        struct adfs_discrecord *dr;
 381        struct buffer_head *bh;
 382        struct object_info root_obj;
 383        unsigned char *b_data;
 384        unsigned int blocksize;
 385        struct adfs_sb_info *asb;
 386        struct inode *root;
 387        int ret = -EINVAL;
 388
 389        sb->s_flags |= ADFS_SB_FLAGS;
 390
 391        asb = kzalloc(sizeof(*asb), GFP_KERNEL);
 392        if (!asb)
 393                return -ENOMEM;
 394        sb->s_fs_info = asb;
 395
 396        /* set default options */
 397        asb->s_uid = GLOBAL_ROOT_UID;
 398        asb->s_gid = GLOBAL_ROOT_GID;
 399        asb->s_owner_mask = ADFS_DEFAULT_OWNER_MASK;
 400        asb->s_other_mask = ADFS_DEFAULT_OTHER_MASK;
 401        asb->s_ftsuffix = 0;
 402
 403        if (parse_options(sb, asb, data))
 404                goto error;
 405
 406        sb_set_blocksize(sb, BLOCK_SIZE);
 407        if (!(bh = sb_bread(sb, ADFS_DISCRECORD / BLOCK_SIZE))) {
 408                adfs_msg(sb, KERN_ERR, "error: unable to read superblock");
 409                ret = -EIO;
 410                goto error;
 411        }
 412
 413        b_data = bh->b_data + (ADFS_DISCRECORD % BLOCK_SIZE);
 414
 415        if (adfs_checkbblk(b_data)) {
 416                ret = -EINVAL;
 417                goto error_badfs;
 418        }
 419
 420        dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
 421
 422        /*
 423         * Do some sanity checks on the ADFS disc record
 424         */
 425        if (adfs_checkdiscrecord(dr)) {
 426                ret = -EINVAL;
 427                goto error_badfs;
 428        }
 429
 430        blocksize = 1 << dr->log2secsize;
 431        brelse(bh);
 432
 433        if (sb_set_blocksize(sb, blocksize)) {
 434                bh = sb_bread(sb, ADFS_DISCRECORD / sb->s_blocksize);
 435                if (!bh) {
 436                        adfs_msg(sb, KERN_ERR,
 437                                 "error: couldn't read superblock on 2nd try.");
 438                        ret = -EIO;
 439                        goto error;
 440                }
 441                b_data = bh->b_data + (ADFS_DISCRECORD % sb->s_blocksize);
 442                if (adfs_checkbblk(b_data)) {
 443                        adfs_msg(sb, KERN_ERR,
 444                                 "error: disc record mismatch, very weird!");
 445                        ret = -EINVAL;
 446                        goto error_free_bh;
 447                }
 448                dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
 449        } else {
 450                if (!silent)
 451                        adfs_msg(sb, KERN_ERR,
 452                                 "error: unsupported blocksize");
 453                ret = -EINVAL;
 454                goto error;
 455        }
 456
 457        /*
 458         * blocksize on this device should now be set to the ADFS log2secsize
 459         */
 460
 461        sb->s_magic             = ADFS_SUPER_MAGIC;
 462        asb->s_idlen            = dr->idlen;
 463        asb->s_map_size         = dr->nzones | (dr->nzones_high << 8);
 464        asb->s_map2blk          = dr->log2bpmb - dr->log2secsize;
 465        asb->s_log2sharesize    = dr->log2sharesize;
 466
 467        asb->s_map = adfs_read_map(sb, dr);
 468        if (IS_ERR(asb->s_map)) {
 469                ret =  PTR_ERR(asb->s_map);
 470                goto error_free_bh;
 471        }
 472
 473        brelse(bh);
 474
 475        /*
 476         * set up enough so that we can read an inode
 477         */
 478        sb->s_op = &adfs_sops;
 479
 480        dr = adfs_map_discrecord(asb->s_map);
 481
 482        root_obj.parent_id = root_obj.indaddr = le32_to_cpu(dr->root);
 483        root_obj.name_len  = 0;
 484        /* Set root object date as 01 Jan 1987 00:00:00 */
 485        root_obj.loadaddr  = 0xfff0003f;
 486        root_obj.execaddr  = 0xec22c000;
 487        root_obj.size      = ADFS_NEWDIR_SIZE;
 488        root_obj.attr      = ADFS_NDA_DIRECTORY   | ADFS_NDA_OWNER_READ |
 489                             ADFS_NDA_OWNER_WRITE | ADFS_NDA_PUBLIC_READ;
 490
 491        /*
 492         * If this is a F+ disk with variable length directories,
 493         * get the root_size from the disc record.
 494         */
 495        if (dr->format_version) {
 496                root_obj.size = le32_to_cpu(dr->root_size);
 497                asb->s_dir     = &adfs_fplus_dir_ops;
 498                asb->s_namelen = ADFS_FPLUS_NAME_LEN;
 499        } else {
 500                asb->s_dir     = &adfs_f_dir_ops;
 501                asb->s_namelen = ADFS_F_NAME_LEN;
 502        }
 503        /*
 504         * ,xyz hex filetype suffix may be added by driver
 505         * to files that have valid RISC OS filetype
 506         */
 507        if (asb->s_ftsuffix)
 508                asb->s_namelen += 4;
 509
 510        sb->s_d_op = &adfs_dentry_operations;
 511        root = adfs_iget(sb, &root_obj);
 512        sb->s_root = d_make_root(root);
 513        if (!sb->s_root) {
 514                int i;
 515                for (i = 0; i < asb->s_map_size; i++)
 516                        brelse(asb->s_map[i].dm_bh);
 517                kfree(asb->s_map);
 518                adfs_error(sb, "get root inode failed\n");
 519                ret = -EIO;
 520                goto error;
 521        }
 522        return 0;
 523
 524error_badfs:
 525        if (!silent)
 526                adfs_msg(sb, KERN_ERR,
 527                         "error: can't find an ADFS filesystem on dev %s.",
 528                         sb->s_id);
 529error_free_bh:
 530        brelse(bh);
 531error:
 532        sb->s_fs_info = NULL;
 533        kfree(asb);
 534        return ret;
 535}
 536
 537static struct dentry *adfs_mount(struct file_system_type *fs_type,
 538        int flags, const char *dev_name, void *data)
 539{
 540        return mount_bdev(fs_type, flags, dev_name, data, adfs_fill_super);
 541}
 542
 543static struct file_system_type adfs_fs_type = {
 544        .owner          = THIS_MODULE,
 545        .name           = "adfs",
 546        .mount          = adfs_mount,
 547        .kill_sb        = kill_block_super,
 548        .fs_flags       = FS_REQUIRES_DEV,
 549};
 550MODULE_ALIAS_FS("adfs");
 551
 552static int __init init_adfs_fs(void)
 553{
 554        int err = init_inodecache();
 555        if (err)
 556                goto out1;
 557        err = register_filesystem(&adfs_fs_type);
 558        if (err)
 559                goto out;
 560        return 0;
 561out:
 562        destroy_inodecache();
 563out1:
 564        return err;
 565}
 566
 567static void __exit exit_adfs_fs(void)
 568{
 569        unregister_filesystem(&adfs_fs_type);
 570        destroy_inodecache();
 571}
 572
 573module_init(init_adfs_fs)
 574module_exit(exit_adfs_fs)
 575MODULE_LICENSE("GPL");
 576