596 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * linux/fs/sysv/inode.c4 *5 * minix/inode.c6 * Copyright (C) 1991, 1992 Linus Torvalds7 *8 * xenix/inode.c9 * Copyright (C) 1992 Doug Evans10 *11 * coh/inode.c12 * Copyright (C) 1993 Pascal Haible, Bruno Haible13 *14 * sysv/inode.c15 * Copyright (C) 1993 Paul B. Monday16 *17 * sysv/inode.c18 * Copyright (C) 1993 Bruno Haible19 * Copyright (C) 1997, 1998 Krzysztof G. Baranowski20 *21 * This file contains code for read/parsing the superblock.22 */23 24#include <linux/module.h>25#include <linux/init.h>26#include <linux/slab.h>27#include <linux/buffer_head.h>28#include "sysv.h"29 30/*31 * The following functions try to recognize specific filesystems.32 *33 * We recognize:34 * - Xenix FS by its magic number.35 * - SystemV FS by its magic number.36 * - Coherent FS by its funny fname/fpack field.37 * - SCO AFS by s_nfree == 0xffff38 * - V7 FS has no distinguishing features.39 *40 * We discriminate among SystemV4 and SystemV2 FS by the assumption that41 * the time stamp is not < 01-01-1980.42 */43 44enum {45 JAN_1_1980 = (10*365 + 2) * 24 * 60 * 6046};47 48static void detected_xenix(struct sysv_sb_info *sbi, unsigned *max_links)49{50 struct buffer_head *bh1 = sbi->s_bh1;51 struct buffer_head *bh2 = sbi->s_bh2;52 struct xenix_super_block * sbd1;53 struct xenix_super_block * sbd2;54 55 if (bh1 != bh2)56 sbd1 = sbd2 = (struct xenix_super_block *) bh1->b_data;57 else {58 /* block size = 512, so bh1 != bh2 */59 sbd1 = (struct xenix_super_block *) bh1->b_data;60 sbd2 = (struct xenix_super_block *) (bh2->b_data - 512);61 }62 63 *max_links = XENIX_LINK_MAX;64 sbi->s_fic_size = XENIX_NICINOD;65 sbi->s_flc_size = XENIX_NICFREE;66 sbi->s_sbd1 = (char *)sbd1;67 sbi->s_sbd2 = (char *)sbd2;68 sbi->s_sb_fic_count = &sbd1->s_ninode;69 sbi->s_sb_fic_inodes = &sbd1->s_inode[0];70 sbi->s_sb_total_free_inodes = &sbd2->s_tinode;71 sbi->s_bcache_count = &sbd1->s_nfree;72 sbi->s_bcache = &sbd1->s_free[0];73 sbi->s_free_blocks = &sbd2->s_tfree;74 sbi->s_sb_time = &sbd2->s_time;75 sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd1->s_isize);76 sbi->s_nzones = fs32_to_cpu(sbi, sbd1->s_fsize);77}78 79static void detected_sysv4(struct sysv_sb_info *sbi, unsigned *max_links)80{81 struct sysv4_super_block * sbd;82 struct buffer_head *bh1 = sbi->s_bh1;83 struct buffer_head *bh2 = sbi->s_bh2;84 85 if (bh1 == bh2)86 sbd = (struct sysv4_super_block *) (bh1->b_data + BLOCK_SIZE/2);87 else88 sbd = (struct sysv4_super_block *) bh2->b_data;89 90 *max_links = SYSV_LINK_MAX;91 sbi->s_fic_size = SYSV_NICINOD;92 sbi->s_flc_size = SYSV_NICFREE;93 sbi->s_sbd1 = (char *)sbd;94 sbi->s_sbd2 = (char *)sbd;95 sbi->s_sb_fic_count = &sbd->s_ninode;96 sbi->s_sb_fic_inodes = &sbd->s_inode[0];97 sbi->s_sb_total_free_inodes = &sbd->s_tinode;98 sbi->s_bcache_count = &sbd->s_nfree;99 sbi->s_bcache = &sbd->s_free[0];100 sbi->s_free_blocks = &sbd->s_tfree;101 sbi->s_sb_time = &sbd->s_time;102 sbi->s_sb_state = &sbd->s_state;103 sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize);104 sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);105}106 107static void detected_sysv2(struct sysv_sb_info *sbi, unsigned *max_links)108{109 struct sysv2_super_block *sbd;110 struct buffer_head *bh1 = sbi->s_bh1;111 struct buffer_head *bh2 = sbi->s_bh2;112 113 if (bh1 == bh2)114 sbd = (struct sysv2_super_block *) (bh1->b_data + BLOCK_SIZE/2);115 else116 sbd = (struct sysv2_super_block *) bh2->b_data;117 118 *max_links = SYSV_LINK_MAX;119 sbi->s_fic_size = SYSV_NICINOD;120 sbi->s_flc_size = SYSV_NICFREE;121 sbi->s_sbd1 = (char *)sbd;122 sbi->s_sbd2 = (char *)sbd;123 sbi->s_sb_fic_count = &sbd->s_ninode;124 sbi->s_sb_fic_inodes = &sbd->s_inode[0];125 sbi->s_sb_total_free_inodes = &sbd->s_tinode;126 sbi->s_bcache_count = &sbd->s_nfree;127 sbi->s_bcache = &sbd->s_free[0];128 sbi->s_free_blocks = &sbd->s_tfree;129 sbi->s_sb_time = &sbd->s_time;130 sbi->s_sb_state = &sbd->s_state;131 sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize);132 sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);133}134 135static void detected_coherent(struct sysv_sb_info *sbi, unsigned *max_links)136{137 struct coh_super_block * sbd;138 struct buffer_head *bh1 = sbi->s_bh1;139 140 sbd = (struct coh_super_block *) bh1->b_data;141 142 *max_links = COH_LINK_MAX;143 sbi->s_fic_size = COH_NICINOD;144 sbi->s_flc_size = COH_NICFREE;145 sbi->s_sbd1 = (char *)sbd;146 sbi->s_sbd2 = (char *)sbd;147 sbi->s_sb_fic_count = &sbd->s_ninode;148 sbi->s_sb_fic_inodes = &sbd->s_inode[0];149 sbi->s_sb_total_free_inodes = &sbd->s_tinode;150 sbi->s_bcache_count = &sbd->s_nfree;151 sbi->s_bcache = &sbd->s_free[0];152 sbi->s_free_blocks = &sbd->s_tfree;153 sbi->s_sb_time = &sbd->s_time;154 sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize);155 sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);156}157 158static void detected_v7(struct sysv_sb_info *sbi, unsigned *max_links)159{160 struct buffer_head *bh2 = sbi->s_bh2;161 struct v7_super_block *sbd = (struct v7_super_block *)bh2->b_data;162 163 *max_links = V7_LINK_MAX;164 sbi->s_fic_size = V7_NICINOD;165 sbi->s_flc_size = V7_NICFREE;166 sbi->s_sbd1 = (char *)sbd;167 sbi->s_sbd2 = (char *)sbd;168 sbi->s_sb_fic_count = &sbd->s_ninode;169 sbi->s_sb_fic_inodes = &sbd->s_inode[0];170 sbi->s_sb_total_free_inodes = &sbd->s_tinode;171 sbi->s_bcache_count = &sbd->s_nfree;172 sbi->s_bcache = &sbd->s_free[0];173 sbi->s_free_blocks = &sbd->s_tfree;174 sbi->s_sb_time = &sbd->s_time;175 sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize);176 sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);177}178 179static int detect_xenix(struct sysv_sb_info *sbi, struct buffer_head *bh)180{181 struct xenix_super_block *sbd = (struct xenix_super_block *)bh->b_data;182 if (*(__le32 *)&sbd->s_magic == cpu_to_le32(0x2b5544))183 sbi->s_bytesex = BYTESEX_LE;184 else if (*(__be32 *)&sbd->s_magic == cpu_to_be32(0x2b5544))185 sbi->s_bytesex = BYTESEX_BE;186 else187 return 0;188 switch (fs32_to_cpu(sbi, sbd->s_type)) {189 case 1:190 sbi->s_type = FSTYPE_XENIX;191 return 1;192 case 2:193 sbi->s_type = FSTYPE_XENIX;194 return 2;195 default:196 return 0;197 }198}199 200static int detect_sysv(struct sysv_sb_info *sbi, struct buffer_head *bh)201{202 struct super_block *sb = sbi->s_sb;203 /* All relevant fields are at the same offsets in R2 and R4 */204 struct sysv4_super_block * sbd;205 u32 type;206 207 sbd = (struct sysv4_super_block *) (bh->b_data + BLOCK_SIZE/2);208 if (*(__le32 *)&sbd->s_magic == cpu_to_le32(0xfd187e20))209 sbi->s_bytesex = BYTESEX_LE;210 else if (*(__be32 *)&sbd->s_magic == cpu_to_be32(0xfd187e20))211 sbi->s_bytesex = BYTESEX_BE;212 else213 return 0;214 215 type = fs32_to_cpu(sbi, sbd->s_type);216 217 if (fs16_to_cpu(sbi, sbd->s_nfree) == 0xffff) {218 sbi->s_type = FSTYPE_AFS;219 sbi->s_forced_ro = 1;220 if (!sb_rdonly(sb)) {221 printk("SysV FS: SCO EAFS on %s detected, " 222 "forcing read-only mode.\n", 223 sb->s_id);224 }225 return type;226 }227 228 if (fs32_to_cpu(sbi, sbd->s_time) < JAN_1_1980) {229 /* this is likely to happen on SystemV2 FS */230 if (type > 3 || type < 1)231 return 0;232 sbi->s_type = FSTYPE_SYSV2;233 return type;234 }235 if ((type > 3 || type < 1) && (type > 0x30 || type < 0x10))236 return 0;237 238 /* On Interactive Unix (ISC) Version 4.0/3.x s_type field = 0x10,239 0x20 or 0x30 indicates that symbolic links and the 14-character240 filename limit is gone. Due to lack of information about this241 feature read-only mode seems to be a reasonable approach... -KGB */242 243 if (type >= 0x10) {244 printk("SysV FS: can't handle long file names on %s, "245 "forcing read-only mode.\n", sb->s_id);246 sbi->s_forced_ro = 1;247 }248 249 sbi->s_type = FSTYPE_SYSV4;250 return type >= 0x10 ? type >> 4 : type;251}252 253static int detect_coherent(struct sysv_sb_info *sbi, struct buffer_head *bh)254{255 struct coh_super_block * sbd;256 257 sbd = (struct coh_super_block *) (bh->b_data + BLOCK_SIZE/2);258 if ((memcmp(sbd->s_fname,"noname",6) && memcmp(sbd->s_fname,"xxxxx ",6))259 || (memcmp(sbd->s_fpack,"nopack",6) && memcmp(sbd->s_fpack,"xxxxx\n",6)))260 return 0;261 sbi->s_bytesex = BYTESEX_PDP;262 sbi->s_type = FSTYPE_COH;263 return 1;264}265 266static int detect_sysv_odd(struct sysv_sb_info *sbi, struct buffer_head *bh)267{268 int size = detect_sysv(sbi, bh);269 270 return size>2 ? 0 : size;271}272 273static struct {274 int block;275 int (*test)(struct sysv_sb_info *, struct buffer_head *);276} flavours[] = {277 {1, detect_xenix},278 {0, detect_sysv},279 {0, detect_coherent},280 {9, detect_sysv_odd},281 {15,detect_sysv_odd},282 {18,detect_sysv},283};284 285static char *flavour_names[] = {286 [FSTYPE_XENIX] = "Xenix",287 [FSTYPE_SYSV4] = "SystemV",288 [FSTYPE_SYSV2] = "SystemV Release 2",289 [FSTYPE_COH] = "Coherent",290 [FSTYPE_V7] = "V7",291 [FSTYPE_AFS] = "AFS",292};293 294static void (*flavour_setup[])(struct sysv_sb_info *, unsigned *) = {295 [FSTYPE_XENIX] = detected_xenix,296 [FSTYPE_SYSV4] = detected_sysv4,297 [FSTYPE_SYSV2] = detected_sysv2,298 [FSTYPE_COH] = detected_coherent,299 [FSTYPE_V7] = detected_v7,300 [FSTYPE_AFS] = detected_sysv4,301};302 303static int complete_read_super(struct super_block *sb, int silent, int size)304{305 struct sysv_sb_info *sbi = SYSV_SB(sb);306 struct inode *root_inode;307 char *found = flavour_names[sbi->s_type];308 u_char n_bits = size+8;309 int bsize = 1 << n_bits;310 int bsize_4 = bsize >> 2;311 312 sbi->s_firstinodezone = 2;313 314 flavour_setup[sbi->s_type](sbi, &sb->s_max_links);315 if (sbi->s_firstdatazone < sbi->s_firstinodezone)316 return 0;317 318 sbi->s_ndatazones = sbi->s_nzones - sbi->s_firstdatazone;319 sbi->s_inodes_per_block = bsize >> 6;320 sbi->s_inodes_per_block_1 = (bsize >> 6)-1;321 sbi->s_inodes_per_block_bits = n_bits-6;322 sbi->s_ind_per_block = bsize_4;323 sbi->s_ind_per_block_2 = bsize_4*bsize_4;324 sbi->s_toobig_block = 10 + bsize_4 * (1 + bsize_4 * (1 + bsize_4));325 sbi->s_ind_per_block_bits = n_bits-2;326 327 sbi->s_ninodes = (sbi->s_firstdatazone - sbi->s_firstinodezone)328 << sbi->s_inodes_per_block_bits;329 330 if (!silent)331 printk("VFS: Found a %s FS (block size = %ld) on device %s\n",332 found, sb->s_blocksize, sb->s_id);333 334 sb->s_magic = SYSV_MAGIC_BASE + sbi->s_type;335 /* set up enough so that it can read an inode */336 sb->s_op = &sysv_sops;337 if (sbi->s_forced_ro)338 sb->s_flags |= SB_RDONLY;339 root_inode = sysv_iget(sb, SYSV_ROOT_INO);340 if (IS_ERR(root_inode)) {341 printk("SysV FS: get root inode failed\n");342 return 0;343 }344 sb->s_root = d_make_root(root_inode);345 if (!sb->s_root) {346 printk("SysV FS: get root dentry failed\n");347 return 0;348 }349 return 1;350}351 352static int sysv_fill_super(struct super_block *sb, void *data, int silent)353{354 struct buffer_head *bh1, *bh = NULL;355 struct sysv_sb_info *sbi;356 unsigned long blocknr;357 int size = 0, i;358 359 BUILD_BUG_ON(1024 != sizeof (struct xenix_super_block));360 BUILD_BUG_ON(512 != sizeof (struct sysv4_super_block));361 BUILD_BUG_ON(512 != sizeof (struct sysv2_super_block));362 BUILD_BUG_ON(500 != sizeof (struct coh_super_block));363 BUILD_BUG_ON(64 != sizeof (struct sysv_inode));364 365 sbi = kzalloc(sizeof(struct sysv_sb_info), GFP_KERNEL);366 if (!sbi)367 return -ENOMEM;368 369 sbi->s_sb = sb;370 sbi->s_block_base = 0;371 mutex_init(&sbi->s_lock);372 sb->s_fs_info = sbi;373 sb->s_time_min = 0;374 sb->s_time_max = U32_MAX;375 sb_set_blocksize(sb, BLOCK_SIZE);376 377 for (i = 0; i < ARRAY_SIZE(flavours) && !size; i++) {378 brelse(bh);379 bh = sb_bread(sb, flavours[i].block);380 if (!bh)381 continue;382 size = flavours[i].test(SYSV_SB(sb), bh);383 }384 385 if (!size)386 goto Eunknown;387 388 switch (size) {389 case 1:390 blocknr = bh->b_blocknr << 1;391 brelse(bh);392 sb_set_blocksize(sb, 512);393 bh1 = sb_bread(sb, blocknr);394 bh = sb_bread(sb, blocknr + 1);395 break;396 case 2:397 bh1 = bh;398 break;399 case 3:400 blocknr = bh->b_blocknr >> 1;401 brelse(bh);402 sb_set_blocksize(sb, 2048);403 bh1 = bh = sb_bread(sb, blocknr);404 break;405 default:406 goto Ebadsize;407 }408 409 if (bh && bh1) {410 sbi->s_bh1 = bh1;411 sbi->s_bh2 = bh;412 if (complete_read_super(sb, silent, size))413 return 0;414 }415 416 brelse(bh1);417 brelse(bh);418 sb_set_blocksize(sb, BLOCK_SIZE);419 printk("oldfs: cannot read superblock\n");420failed:421 kfree(sbi);422 return -EINVAL;423 424Eunknown:425 brelse(bh);426 if (!silent)427 printk("VFS: unable to find oldfs superblock on device %s\n",428 sb->s_id);429 goto failed;430Ebadsize:431 brelse(bh);432 if (!silent)433 printk("VFS: oldfs: unsupported block size (%dKb)\n",434 1<<(size-2));435 goto failed;436}437 438static int v7_sanity_check(struct super_block *sb, struct buffer_head *bh)439{440 struct v7_super_block *v7sb;441 struct sysv_inode *v7i;442 struct buffer_head *bh2;443 struct sysv_sb_info *sbi;444 445 sbi = sb->s_fs_info;446 447 /* plausibility check on superblock */448 v7sb = (struct v7_super_block *) bh->b_data;449 if (fs16_to_cpu(sbi, v7sb->s_nfree) > V7_NICFREE ||450 fs16_to_cpu(sbi, v7sb->s_ninode) > V7_NICINOD ||451 fs32_to_cpu(sbi, v7sb->s_fsize) > V7_MAXSIZE)452 return 0;453 454 /* plausibility check on root inode: it is a directory,455 with a nonzero size that is a multiple of 16 */456 bh2 = sb_bread(sb, 2);457 if (bh2 == NULL)458 return 0;459 460 v7i = (struct sysv_inode *)(bh2->b_data + 64);461 if ((fs16_to_cpu(sbi, v7i->i_mode) & ~0777) != S_IFDIR ||462 (fs32_to_cpu(sbi, v7i->i_size) == 0) ||463 (fs32_to_cpu(sbi, v7i->i_size) & 017) ||464 (fs32_to_cpu(sbi, v7i->i_size) > V7_NFILES *465 sizeof(struct sysv_dir_entry))) {466 brelse(bh2);467 return 0;468 }469 470 brelse(bh2);471 return 1;472}473 474static int v7_fill_super(struct super_block *sb, void *data, int silent)475{476 struct sysv_sb_info *sbi;477 struct buffer_head *bh;478 479 BUILD_BUG_ON(sizeof(struct v7_super_block) != 440);480 BUILD_BUG_ON(sizeof(struct sysv_inode) != 64);481 482 sbi = kzalloc(sizeof(struct sysv_sb_info), GFP_KERNEL);483 if (!sbi)484 return -ENOMEM;485 486 sbi->s_sb = sb;487 sbi->s_block_base = 0;488 sbi->s_type = FSTYPE_V7;489 mutex_init(&sbi->s_lock);490 sb->s_fs_info = sbi;491 sb->s_time_min = 0;492 sb->s_time_max = U32_MAX;493 494 sb_set_blocksize(sb, 512);495 496 if ((bh = sb_bread(sb, 1)) == NULL) {497 if (!silent)498 printk("VFS: unable to read V7 FS superblock on "499 "device %s.\n", sb->s_id);500 goto failed;501 }502 503 /* Try PDP-11 UNIX */504 sbi->s_bytesex = BYTESEX_PDP;505 if (v7_sanity_check(sb, bh))506 goto detected;507 508 /* Try PC/IX, v7/x86 */509 sbi->s_bytesex = BYTESEX_LE;510 if (v7_sanity_check(sb, bh))511 goto detected;512 513 goto failed;514 515detected:516 sbi->s_bh1 = bh;517 sbi->s_bh2 = bh;518 if (complete_read_super(sb, silent, 1))519 return 0;520 521failed:522 printk(KERN_ERR "VFS: could not find a valid V7 on %s.\n",523 sb->s_id);524 brelse(bh);525 kfree(sbi);526 return -EINVAL;527}528 529/* Every kernel module contains stuff like this. */530 531static struct dentry *sysv_mount(struct file_system_type *fs_type,532 int flags, const char *dev_name, void *data)533{534 return mount_bdev(fs_type, flags, dev_name, data, sysv_fill_super);535}536 537static struct dentry *v7_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, v7_fill_super);541}542 543static struct file_system_type sysv_fs_type = {544 .owner = THIS_MODULE,545 .name = "sysv",546 .mount = sysv_mount,547 .kill_sb = kill_block_super,548 .fs_flags = FS_REQUIRES_DEV,549};550MODULE_ALIAS_FS("sysv");551 552static struct file_system_type v7_fs_type = {553 .owner = THIS_MODULE,554 .name = "v7",555 .mount = v7_mount,556 .kill_sb = kill_block_super,557 .fs_flags = FS_REQUIRES_DEV,558};559MODULE_ALIAS_FS("v7");560MODULE_ALIAS("v7");561 562static int __init init_sysv_fs(void)563{564 int error;565 566 error = sysv_init_icache();567 if (error)568 goto out;569 error = register_filesystem(&sysv_fs_type);570 if (error)571 goto destroy_icache;572 error = register_filesystem(&v7_fs_type);573 if (error)574 goto unregister;575 return 0;576 577unregister:578 unregister_filesystem(&sysv_fs_type);579destroy_icache:580 sysv_destroy_icache();581out:582 return error;583}584 585static void __exit exit_sysv_fs(void)586{587 unregister_filesystem(&sysv_fs_type);588 unregister_filesystem(&v7_fs_type);589 sysv_destroy_icache();590}591 592module_init(init_sysv_fs)593module_exit(exit_sysv_fs)594MODULE_DESCRIPTION("SystemV Filesystem");595MODULE_LICENSE("GPL");596