162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/sysv/inode.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * minix/inode.c 662306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * xenix/inode.c 962306a36Sopenharmony_ci * Copyright (C) 1992 Doug Evans 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * coh/inode.c 1262306a36Sopenharmony_ci * Copyright (C) 1993 Pascal Haible, Bruno Haible 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * sysv/inode.c 1562306a36Sopenharmony_ci * Copyright (C) 1993 Paul B. Monday 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * sysv/inode.c 1862306a36Sopenharmony_ci * Copyright (C) 1993 Bruno Haible 1962306a36Sopenharmony_ci * Copyright (C) 1997, 1998 Krzysztof G. Baranowski 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * This file contains code for read/parsing the superblock. 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/module.h> 2562306a36Sopenharmony_ci#include <linux/init.h> 2662306a36Sopenharmony_ci#include <linux/slab.h> 2762306a36Sopenharmony_ci#include <linux/buffer_head.h> 2862306a36Sopenharmony_ci#include "sysv.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * The following functions try to recognize specific filesystems. 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * We recognize: 3462306a36Sopenharmony_ci * - Xenix FS by its magic number. 3562306a36Sopenharmony_ci * - SystemV FS by its magic number. 3662306a36Sopenharmony_ci * - Coherent FS by its funny fname/fpack field. 3762306a36Sopenharmony_ci * - SCO AFS by s_nfree == 0xffff 3862306a36Sopenharmony_ci * - V7 FS has no distinguishing features. 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * We discriminate among SystemV4 and SystemV2 FS by the assumption that 4162306a36Sopenharmony_ci * the time stamp is not < 01-01-1980. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cienum { 4562306a36Sopenharmony_ci JAN_1_1980 = (10*365 + 2) * 24 * 60 * 60 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic void detected_xenix(struct sysv_sb_info *sbi, unsigned *max_links) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct buffer_head *bh1 = sbi->s_bh1; 5162306a36Sopenharmony_ci struct buffer_head *bh2 = sbi->s_bh2; 5262306a36Sopenharmony_ci struct xenix_super_block * sbd1; 5362306a36Sopenharmony_ci struct xenix_super_block * sbd2; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (bh1 != bh2) 5662306a36Sopenharmony_ci sbd1 = sbd2 = (struct xenix_super_block *) bh1->b_data; 5762306a36Sopenharmony_ci else { 5862306a36Sopenharmony_ci /* block size = 512, so bh1 != bh2 */ 5962306a36Sopenharmony_ci sbd1 = (struct xenix_super_block *) bh1->b_data; 6062306a36Sopenharmony_ci sbd2 = (struct xenix_super_block *) (bh2->b_data - 512); 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci *max_links = XENIX_LINK_MAX; 6462306a36Sopenharmony_ci sbi->s_fic_size = XENIX_NICINOD; 6562306a36Sopenharmony_ci sbi->s_flc_size = XENIX_NICFREE; 6662306a36Sopenharmony_ci sbi->s_sbd1 = (char *)sbd1; 6762306a36Sopenharmony_ci sbi->s_sbd2 = (char *)sbd2; 6862306a36Sopenharmony_ci sbi->s_sb_fic_count = &sbd1->s_ninode; 6962306a36Sopenharmony_ci sbi->s_sb_fic_inodes = &sbd1->s_inode[0]; 7062306a36Sopenharmony_ci sbi->s_sb_total_free_inodes = &sbd2->s_tinode; 7162306a36Sopenharmony_ci sbi->s_bcache_count = &sbd1->s_nfree; 7262306a36Sopenharmony_ci sbi->s_bcache = &sbd1->s_free[0]; 7362306a36Sopenharmony_ci sbi->s_free_blocks = &sbd2->s_tfree; 7462306a36Sopenharmony_ci sbi->s_sb_time = &sbd2->s_time; 7562306a36Sopenharmony_ci sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd1->s_isize); 7662306a36Sopenharmony_ci sbi->s_nzones = fs32_to_cpu(sbi, sbd1->s_fsize); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void detected_sysv4(struct sysv_sb_info *sbi, unsigned *max_links) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct sysv4_super_block * sbd; 8262306a36Sopenharmony_ci struct buffer_head *bh1 = sbi->s_bh1; 8362306a36Sopenharmony_ci struct buffer_head *bh2 = sbi->s_bh2; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (bh1 == bh2) 8662306a36Sopenharmony_ci sbd = (struct sysv4_super_block *) (bh1->b_data + BLOCK_SIZE/2); 8762306a36Sopenharmony_ci else 8862306a36Sopenharmony_ci sbd = (struct sysv4_super_block *) bh2->b_data; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci *max_links = SYSV_LINK_MAX; 9162306a36Sopenharmony_ci sbi->s_fic_size = SYSV_NICINOD; 9262306a36Sopenharmony_ci sbi->s_flc_size = SYSV_NICFREE; 9362306a36Sopenharmony_ci sbi->s_sbd1 = (char *)sbd; 9462306a36Sopenharmony_ci sbi->s_sbd2 = (char *)sbd; 9562306a36Sopenharmony_ci sbi->s_sb_fic_count = &sbd->s_ninode; 9662306a36Sopenharmony_ci sbi->s_sb_fic_inodes = &sbd->s_inode[0]; 9762306a36Sopenharmony_ci sbi->s_sb_total_free_inodes = &sbd->s_tinode; 9862306a36Sopenharmony_ci sbi->s_bcache_count = &sbd->s_nfree; 9962306a36Sopenharmony_ci sbi->s_bcache = &sbd->s_free[0]; 10062306a36Sopenharmony_ci sbi->s_free_blocks = &sbd->s_tfree; 10162306a36Sopenharmony_ci sbi->s_sb_time = &sbd->s_time; 10262306a36Sopenharmony_ci sbi->s_sb_state = &sbd->s_state; 10362306a36Sopenharmony_ci sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize); 10462306a36Sopenharmony_ci sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic void detected_sysv2(struct sysv_sb_info *sbi, unsigned *max_links) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct sysv2_super_block *sbd; 11062306a36Sopenharmony_ci struct buffer_head *bh1 = sbi->s_bh1; 11162306a36Sopenharmony_ci struct buffer_head *bh2 = sbi->s_bh2; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (bh1 == bh2) 11462306a36Sopenharmony_ci sbd = (struct sysv2_super_block *) (bh1->b_data + BLOCK_SIZE/2); 11562306a36Sopenharmony_ci else 11662306a36Sopenharmony_ci sbd = (struct sysv2_super_block *) bh2->b_data; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci *max_links = SYSV_LINK_MAX; 11962306a36Sopenharmony_ci sbi->s_fic_size = SYSV_NICINOD; 12062306a36Sopenharmony_ci sbi->s_flc_size = SYSV_NICFREE; 12162306a36Sopenharmony_ci sbi->s_sbd1 = (char *)sbd; 12262306a36Sopenharmony_ci sbi->s_sbd2 = (char *)sbd; 12362306a36Sopenharmony_ci sbi->s_sb_fic_count = &sbd->s_ninode; 12462306a36Sopenharmony_ci sbi->s_sb_fic_inodes = &sbd->s_inode[0]; 12562306a36Sopenharmony_ci sbi->s_sb_total_free_inodes = &sbd->s_tinode; 12662306a36Sopenharmony_ci sbi->s_bcache_count = &sbd->s_nfree; 12762306a36Sopenharmony_ci sbi->s_bcache = &sbd->s_free[0]; 12862306a36Sopenharmony_ci sbi->s_free_blocks = &sbd->s_tfree; 12962306a36Sopenharmony_ci sbi->s_sb_time = &sbd->s_time; 13062306a36Sopenharmony_ci sbi->s_sb_state = &sbd->s_state; 13162306a36Sopenharmony_ci sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize); 13262306a36Sopenharmony_ci sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void detected_coherent(struct sysv_sb_info *sbi, unsigned *max_links) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct coh_super_block * sbd; 13862306a36Sopenharmony_ci struct buffer_head *bh1 = sbi->s_bh1; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci sbd = (struct coh_super_block *) bh1->b_data; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci *max_links = COH_LINK_MAX; 14362306a36Sopenharmony_ci sbi->s_fic_size = COH_NICINOD; 14462306a36Sopenharmony_ci sbi->s_flc_size = COH_NICFREE; 14562306a36Sopenharmony_ci sbi->s_sbd1 = (char *)sbd; 14662306a36Sopenharmony_ci sbi->s_sbd2 = (char *)sbd; 14762306a36Sopenharmony_ci sbi->s_sb_fic_count = &sbd->s_ninode; 14862306a36Sopenharmony_ci sbi->s_sb_fic_inodes = &sbd->s_inode[0]; 14962306a36Sopenharmony_ci sbi->s_sb_total_free_inodes = &sbd->s_tinode; 15062306a36Sopenharmony_ci sbi->s_bcache_count = &sbd->s_nfree; 15162306a36Sopenharmony_ci sbi->s_bcache = &sbd->s_free[0]; 15262306a36Sopenharmony_ci sbi->s_free_blocks = &sbd->s_tfree; 15362306a36Sopenharmony_ci sbi->s_sb_time = &sbd->s_time; 15462306a36Sopenharmony_ci sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize); 15562306a36Sopenharmony_ci sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic void detected_v7(struct sysv_sb_info *sbi, unsigned *max_links) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct buffer_head *bh2 = sbi->s_bh2; 16162306a36Sopenharmony_ci struct v7_super_block *sbd = (struct v7_super_block *)bh2->b_data; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci *max_links = V7_LINK_MAX; 16462306a36Sopenharmony_ci sbi->s_fic_size = V7_NICINOD; 16562306a36Sopenharmony_ci sbi->s_flc_size = V7_NICFREE; 16662306a36Sopenharmony_ci sbi->s_sbd1 = (char *)sbd; 16762306a36Sopenharmony_ci sbi->s_sbd2 = (char *)sbd; 16862306a36Sopenharmony_ci sbi->s_sb_fic_count = &sbd->s_ninode; 16962306a36Sopenharmony_ci sbi->s_sb_fic_inodes = &sbd->s_inode[0]; 17062306a36Sopenharmony_ci sbi->s_sb_total_free_inodes = &sbd->s_tinode; 17162306a36Sopenharmony_ci sbi->s_bcache_count = &sbd->s_nfree; 17262306a36Sopenharmony_ci sbi->s_bcache = &sbd->s_free[0]; 17362306a36Sopenharmony_ci sbi->s_free_blocks = &sbd->s_tfree; 17462306a36Sopenharmony_ci sbi->s_sb_time = &sbd->s_time; 17562306a36Sopenharmony_ci sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize); 17662306a36Sopenharmony_ci sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic int detect_xenix(struct sysv_sb_info *sbi, struct buffer_head *bh) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct xenix_super_block *sbd = (struct xenix_super_block *)bh->b_data; 18262306a36Sopenharmony_ci if (*(__le32 *)&sbd->s_magic == cpu_to_le32(0x2b5544)) 18362306a36Sopenharmony_ci sbi->s_bytesex = BYTESEX_LE; 18462306a36Sopenharmony_ci else if (*(__be32 *)&sbd->s_magic == cpu_to_be32(0x2b5544)) 18562306a36Sopenharmony_ci sbi->s_bytesex = BYTESEX_BE; 18662306a36Sopenharmony_ci else 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci switch (fs32_to_cpu(sbi, sbd->s_type)) { 18962306a36Sopenharmony_ci case 1: 19062306a36Sopenharmony_ci sbi->s_type = FSTYPE_XENIX; 19162306a36Sopenharmony_ci return 1; 19262306a36Sopenharmony_ci case 2: 19362306a36Sopenharmony_ci sbi->s_type = FSTYPE_XENIX; 19462306a36Sopenharmony_ci return 2; 19562306a36Sopenharmony_ci default: 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic int detect_sysv(struct sysv_sb_info *sbi, struct buffer_head *bh) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct super_block *sb = sbi->s_sb; 20362306a36Sopenharmony_ci /* All relevant fields are at the same offsets in R2 and R4 */ 20462306a36Sopenharmony_ci struct sysv4_super_block * sbd; 20562306a36Sopenharmony_ci u32 type; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci sbd = (struct sysv4_super_block *) (bh->b_data + BLOCK_SIZE/2); 20862306a36Sopenharmony_ci if (*(__le32 *)&sbd->s_magic == cpu_to_le32(0xfd187e20)) 20962306a36Sopenharmony_ci sbi->s_bytesex = BYTESEX_LE; 21062306a36Sopenharmony_ci else if (*(__be32 *)&sbd->s_magic == cpu_to_be32(0xfd187e20)) 21162306a36Sopenharmony_ci sbi->s_bytesex = BYTESEX_BE; 21262306a36Sopenharmony_ci else 21362306a36Sopenharmony_ci return 0; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci type = fs32_to_cpu(sbi, sbd->s_type); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (fs16_to_cpu(sbi, sbd->s_nfree) == 0xffff) { 21862306a36Sopenharmony_ci sbi->s_type = FSTYPE_AFS; 21962306a36Sopenharmony_ci sbi->s_forced_ro = 1; 22062306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 22162306a36Sopenharmony_ci printk("SysV FS: SCO EAFS on %s detected, " 22262306a36Sopenharmony_ci "forcing read-only mode.\n", 22362306a36Sopenharmony_ci sb->s_id); 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci return type; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (fs32_to_cpu(sbi, sbd->s_time) < JAN_1_1980) { 22962306a36Sopenharmony_ci /* this is likely to happen on SystemV2 FS */ 23062306a36Sopenharmony_ci if (type > 3 || type < 1) 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci sbi->s_type = FSTYPE_SYSV2; 23362306a36Sopenharmony_ci return type; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci if ((type > 3 || type < 1) && (type > 0x30 || type < 0x10)) 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* On Interactive Unix (ISC) Version 4.0/3.x s_type field = 0x10, 23962306a36Sopenharmony_ci 0x20 or 0x30 indicates that symbolic links and the 14-character 24062306a36Sopenharmony_ci filename limit is gone. Due to lack of information about this 24162306a36Sopenharmony_ci feature read-only mode seems to be a reasonable approach... -KGB */ 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (type >= 0x10) { 24462306a36Sopenharmony_ci printk("SysV FS: can't handle long file names on %s, " 24562306a36Sopenharmony_ci "forcing read-only mode.\n", sb->s_id); 24662306a36Sopenharmony_ci sbi->s_forced_ro = 1; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci sbi->s_type = FSTYPE_SYSV4; 25062306a36Sopenharmony_ci return type >= 0x10 ? type >> 4 : type; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic int detect_coherent(struct sysv_sb_info *sbi, struct buffer_head *bh) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct coh_super_block * sbd; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci sbd = (struct coh_super_block *) (bh->b_data + BLOCK_SIZE/2); 25862306a36Sopenharmony_ci if ((memcmp(sbd->s_fname,"noname",6) && memcmp(sbd->s_fname,"xxxxx ",6)) 25962306a36Sopenharmony_ci || (memcmp(sbd->s_fpack,"nopack",6) && memcmp(sbd->s_fpack,"xxxxx\n",6))) 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci sbi->s_bytesex = BYTESEX_PDP; 26262306a36Sopenharmony_ci sbi->s_type = FSTYPE_COH; 26362306a36Sopenharmony_ci return 1; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int detect_sysv_odd(struct sysv_sb_info *sbi, struct buffer_head *bh) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci int size = detect_sysv(sbi, bh); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return size>2 ? 0 : size; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic struct { 27462306a36Sopenharmony_ci int block; 27562306a36Sopenharmony_ci int (*test)(struct sysv_sb_info *, struct buffer_head *); 27662306a36Sopenharmony_ci} flavours[] = { 27762306a36Sopenharmony_ci {1, detect_xenix}, 27862306a36Sopenharmony_ci {0, detect_sysv}, 27962306a36Sopenharmony_ci {0, detect_coherent}, 28062306a36Sopenharmony_ci {9, detect_sysv_odd}, 28162306a36Sopenharmony_ci {15,detect_sysv_odd}, 28262306a36Sopenharmony_ci {18,detect_sysv}, 28362306a36Sopenharmony_ci}; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic char *flavour_names[] = { 28662306a36Sopenharmony_ci [FSTYPE_XENIX] = "Xenix", 28762306a36Sopenharmony_ci [FSTYPE_SYSV4] = "SystemV", 28862306a36Sopenharmony_ci [FSTYPE_SYSV2] = "SystemV Release 2", 28962306a36Sopenharmony_ci [FSTYPE_COH] = "Coherent", 29062306a36Sopenharmony_ci [FSTYPE_V7] = "V7", 29162306a36Sopenharmony_ci [FSTYPE_AFS] = "AFS", 29262306a36Sopenharmony_ci}; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic void (*flavour_setup[])(struct sysv_sb_info *, unsigned *) = { 29562306a36Sopenharmony_ci [FSTYPE_XENIX] = detected_xenix, 29662306a36Sopenharmony_ci [FSTYPE_SYSV4] = detected_sysv4, 29762306a36Sopenharmony_ci [FSTYPE_SYSV2] = detected_sysv2, 29862306a36Sopenharmony_ci [FSTYPE_COH] = detected_coherent, 29962306a36Sopenharmony_ci [FSTYPE_V7] = detected_v7, 30062306a36Sopenharmony_ci [FSTYPE_AFS] = detected_sysv4, 30162306a36Sopenharmony_ci}; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic int complete_read_super(struct super_block *sb, int silent, int size) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct sysv_sb_info *sbi = SYSV_SB(sb); 30662306a36Sopenharmony_ci struct inode *root_inode; 30762306a36Sopenharmony_ci char *found = flavour_names[sbi->s_type]; 30862306a36Sopenharmony_ci u_char n_bits = size+8; 30962306a36Sopenharmony_ci int bsize = 1 << n_bits; 31062306a36Sopenharmony_ci int bsize_4 = bsize >> 2; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci sbi->s_firstinodezone = 2; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci flavour_setup[sbi->s_type](sbi, &sb->s_max_links); 31562306a36Sopenharmony_ci if (sbi->s_firstdatazone < sbi->s_firstinodezone) 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci sbi->s_ndatazones = sbi->s_nzones - sbi->s_firstdatazone; 31962306a36Sopenharmony_ci sbi->s_inodes_per_block = bsize >> 6; 32062306a36Sopenharmony_ci sbi->s_inodes_per_block_1 = (bsize >> 6)-1; 32162306a36Sopenharmony_ci sbi->s_inodes_per_block_bits = n_bits-6; 32262306a36Sopenharmony_ci sbi->s_ind_per_block = bsize_4; 32362306a36Sopenharmony_ci sbi->s_ind_per_block_2 = bsize_4*bsize_4; 32462306a36Sopenharmony_ci sbi->s_toobig_block = 10 + bsize_4 * (1 + bsize_4 * (1 + bsize_4)); 32562306a36Sopenharmony_ci sbi->s_ind_per_block_bits = n_bits-2; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci sbi->s_ninodes = (sbi->s_firstdatazone - sbi->s_firstinodezone) 32862306a36Sopenharmony_ci << sbi->s_inodes_per_block_bits; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (!silent) 33162306a36Sopenharmony_ci printk("VFS: Found a %s FS (block size = %ld) on device %s\n", 33262306a36Sopenharmony_ci found, sb->s_blocksize, sb->s_id); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci sb->s_magic = SYSV_MAGIC_BASE + sbi->s_type; 33562306a36Sopenharmony_ci /* set up enough so that it can read an inode */ 33662306a36Sopenharmony_ci sb->s_op = &sysv_sops; 33762306a36Sopenharmony_ci if (sbi->s_forced_ro) 33862306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 33962306a36Sopenharmony_ci root_inode = sysv_iget(sb, SYSV_ROOT_INO); 34062306a36Sopenharmony_ci if (IS_ERR(root_inode)) { 34162306a36Sopenharmony_ci printk("SysV FS: get root inode failed\n"); 34262306a36Sopenharmony_ci return 0; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci sb->s_root = d_make_root(root_inode); 34562306a36Sopenharmony_ci if (!sb->s_root) { 34662306a36Sopenharmony_ci printk("SysV FS: get root dentry failed\n"); 34762306a36Sopenharmony_ci return 0; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci return 1; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic int sysv_fill_super(struct super_block *sb, void *data, int silent) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci struct buffer_head *bh1, *bh = NULL; 35562306a36Sopenharmony_ci struct sysv_sb_info *sbi; 35662306a36Sopenharmony_ci unsigned long blocknr; 35762306a36Sopenharmony_ci int size = 0, i; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci BUILD_BUG_ON(1024 != sizeof (struct xenix_super_block)); 36062306a36Sopenharmony_ci BUILD_BUG_ON(512 != sizeof (struct sysv4_super_block)); 36162306a36Sopenharmony_ci BUILD_BUG_ON(512 != sizeof (struct sysv2_super_block)); 36262306a36Sopenharmony_ci BUILD_BUG_ON(500 != sizeof (struct coh_super_block)); 36362306a36Sopenharmony_ci BUILD_BUG_ON(64 != sizeof (struct sysv_inode)); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci sbi = kzalloc(sizeof(struct sysv_sb_info), GFP_KERNEL); 36662306a36Sopenharmony_ci if (!sbi) 36762306a36Sopenharmony_ci return -ENOMEM; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci sbi->s_sb = sb; 37062306a36Sopenharmony_ci sbi->s_block_base = 0; 37162306a36Sopenharmony_ci mutex_init(&sbi->s_lock); 37262306a36Sopenharmony_ci sb->s_fs_info = sbi; 37362306a36Sopenharmony_ci sb->s_time_min = 0; 37462306a36Sopenharmony_ci sb->s_time_max = U32_MAX; 37562306a36Sopenharmony_ci sb_set_blocksize(sb, BLOCK_SIZE); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(flavours) && !size; i++) { 37862306a36Sopenharmony_ci brelse(bh); 37962306a36Sopenharmony_ci bh = sb_bread(sb, flavours[i].block); 38062306a36Sopenharmony_ci if (!bh) 38162306a36Sopenharmony_ci continue; 38262306a36Sopenharmony_ci size = flavours[i].test(SYSV_SB(sb), bh); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (!size) 38662306a36Sopenharmony_ci goto Eunknown; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci switch (size) { 38962306a36Sopenharmony_ci case 1: 39062306a36Sopenharmony_ci blocknr = bh->b_blocknr << 1; 39162306a36Sopenharmony_ci brelse(bh); 39262306a36Sopenharmony_ci sb_set_blocksize(sb, 512); 39362306a36Sopenharmony_ci bh1 = sb_bread(sb, blocknr); 39462306a36Sopenharmony_ci bh = sb_bread(sb, blocknr + 1); 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci case 2: 39762306a36Sopenharmony_ci bh1 = bh; 39862306a36Sopenharmony_ci break; 39962306a36Sopenharmony_ci case 3: 40062306a36Sopenharmony_ci blocknr = bh->b_blocknr >> 1; 40162306a36Sopenharmony_ci brelse(bh); 40262306a36Sopenharmony_ci sb_set_blocksize(sb, 2048); 40362306a36Sopenharmony_ci bh1 = bh = sb_bread(sb, blocknr); 40462306a36Sopenharmony_ci break; 40562306a36Sopenharmony_ci default: 40662306a36Sopenharmony_ci goto Ebadsize; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (bh && bh1) { 41062306a36Sopenharmony_ci sbi->s_bh1 = bh1; 41162306a36Sopenharmony_ci sbi->s_bh2 = bh; 41262306a36Sopenharmony_ci if (complete_read_super(sb, silent, size)) 41362306a36Sopenharmony_ci return 0; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci brelse(bh1); 41762306a36Sopenharmony_ci brelse(bh); 41862306a36Sopenharmony_ci sb_set_blocksize(sb, BLOCK_SIZE); 41962306a36Sopenharmony_ci printk("oldfs: cannot read superblock\n"); 42062306a36Sopenharmony_cifailed: 42162306a36Sopenharmony_ci kfree(sbi); 42262306a36Sopenharmony_ci return -EINVAL; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ciEunknown: 42562306a36Sopenharmony_ci brelse(bh); 42662306a36Sopenharmony_ci if (!silent) 42762306a36Sopenharmony_ci printk("VFS: unable to find oldfs superblock on device %s\n", 42862306a36Sopenharmony_ci sb->s_id); 42962306a36Sopenharmony_ci goto failed; 43062306a36Sopenharmony_ciEbadsize: 43162306a36Sopenharmony_ci brelse(bh); 43262306a36Sopenharmony_ci if (!silent) 43362306a36Sopenharmony_ci printk("VFS: oldfs: unsupported block size (%dKb)\n", 43462306a36Sopenharmony_ci 1<<(size-2)); 43562306a36Sopenharmony_ci goto failed; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic int v7_sanity_check(struct super_block *sb, struct buffer_head *bh) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci struct v7_super_block *v7sb; 44162306a36Sopenharmony_ci struct sysv_inode *v7i; 44262306a36Sopenharmony_ci struct buffer_head *bh2; 44362306a36Sopenharmony_ci struct sysv_sb_info *sbi; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci sbi = sb->s_fs_info; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* plausibility check on superblock */ 44862306a36Sopenharmony_ci v7sb = (struct v7_super_block *) bh->b_data; 44962306a36Sopenharmony_ci if (fs16_to_cpu(sbi, v7sb->s_nfree) > V7_NICFREE || 45062306a36Sopenharmony_ci fs16_to_cpu(sbi, v7sb->s_ninode) > V7_NICINOD || 45162306a36Sopenharmony_ci fs32_to_cpu(sbi, v7sb->s_fsize) > V7_MAXSIZE) 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* plausibility check on root inode: it is a directory, 45562306a36Sopenharmony_ci with a nonzero size that is a multiple of 16 */ 45662306a36Sopenharmony_ci bh2 = sb_bread(sb, 2); 45762306a36Sopenharmony_ci if (bh2 == NULL) 45862306a36Sopenharmony_ci return 0; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci v7i = (struct sysv_inode *)(bh2->b_data + 64); 46162306a36Sopenharmony_ci if ((fs16_to_cpu(sbi, v7i->i_mode) & ~0777) != S_IFDIR || 46262306a36Sopenharmony_ci (fs32_to_cpu(sbi, v7i->i_size) == 0) || 46362306a36Sopenharmony_ci (fs32_to_cpu(sbi, v7i->i_size) & 017) || 46462306a36Sopenharmony_ci (fs32_to_cpu(sbi, v7i->i_size) > V7_NFILES * 46562306a36Sopenharmony_ci sizeof(struct sysv_dir_entry))) { 46662306a36Sopenharmony_ci brelse(bh2); 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci brelse(bh2); 47162306a36Sopenharmony_ci return 1; 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic int v7_fill_super(struct super_block *sb, void *data, int silent) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct sysv_sb_info *sbi; 47762306a36Sopenharmony_ci struct buffer_head *bh; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct v7_super_block) != 440); 48062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct sysv_inode) != 64); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci sbi = kzalloc(sizeof(struct sysv_sb_info), GFP_KERNEL); 48362306a36Sopenharmony_ci if (!sbi) 48462306a36Sopenharmony_ci return -ENOMEM; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci sbi->s_sb = sb; 48762306a36Sopenharmony_ci sbi->s_block_base = 0; 48862306a36Sopenharmony_ci sbi->s_type = FSTYPE_V7; 48962306a36Sopenharmony_ci mutex_init(&sbi->s_lock); 49062306a36Sopenharmony_ci sb->s_fs_info = sbi; 49162306a36Sopenharmony_ci sb->s_time_min = 0; 49262306a36Sopenharmony_ci sb->s_time_max = U32_MAX; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci sb_set_blocksize(sb, 512); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if ((bh = sb_bread(sb, 1)) == NULL) { 49762306a36Sopenharmony_ci if (!silent) 49862306a36Sopenharmony_ci printk("VFS: unable to read V7 FS superblock on " 49962306a36Sopenharmony_ci "device %s.\n", sb->s_id); 50062306a36Sopenharmony_ci goto failed; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* Try PDP-11 UNIX */ 50462306a36Sopenharmony_ci sbi->s_bytesex = BYTESEX_PDP; 50562306a36Sopenharmony_ci if (v7_sanity_check(sb, bh)) 50662306a36Sopenharmony_ci goto detected; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* Try PC/IX, v7/x86 */ 50962306a36Sopenharmony_ci sbi->s_bytesex = BYTESEX_LE; 51062306a36Sopenharmony_ci if (v7_sanity_check(sb, bh)) 51162306a36Sopenharmony_ci goto detected; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci goto failed; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cidetected: 51662306a36Sopenharmony_ci sbi->s_bh1 = bh; 51762306a36Sopenharmony_ci sbi->s_bh2 = bh; 51862306a36Sopenharmony_ci if (complete_read_super(sb, silent, 1)) 51962306a36Sopenharmony_ci return 0; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cifailed: 52262306a36Sopenharmony_ci printk(KERN_ERR "VFS: could not find a valid V7 on %s.\n", 52362306a36Sopenharmony_ci sb->s_id); 52462306a36Sopenharmony_ci brelse(bh); 52562306a36Sopenharmony_ci kfree(sbi); 52662306a36Sopenharmony_ci return -EINVAL; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci/* Every kernel module contains stuff like this. */ 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic struct dentry *sysv_mount(struct file_system_type *fs_type, 53262306a36Sopenharmony_ci int flags, const char *dev_name, void *data) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci return mount_bdev(fs_type, flags, dev_name, data, sysv_fill_super); 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic struct dentry *v7_mount(struct file_system_type *fs_type, 53862306a36Sopenharmony_ci int flags, const char *dev_name, void *data) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci return mount_bdev(fs_type, flags, dev_name, data, v7_fill_super); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic struct file_system_type sysv_fs_type = { 54462306a36Sopenharmony_ci .owner = THIS_MODULE, 54562306a36Sopenharmony_ci .name = "sysv", 54662306a36Sopenharmony_ci .mount = sysv_mount, 54762306a36Sopenharmony_ci .kill_sb = kill_block_super, 54862306a36Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV, 54962306a36Sopenharmony_ci}; 55062306a36Sopenharmony_ciMODULE_ALIAS_FS("sysv"); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic struct file_system_type v7_fs_type = { 55362306a36Sopenharmony_ci .owner = THIS_MODULE, 55462306a36Sopenharmony_ci .name = "v7", 55562306a36Sopenharmony_ci .mount = v7_mount, 55662306a36Sopenharmony_ci .kill_sb = kill_block_super, 55762306a36Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV, 55862306a36Sopenharmony_ci}; 55962306a36Sopenharmony_ciMODULE_ALIAS_FS("v7"); 56062306a36Sopenharmony_ciMODULE_ALIAS("v7"); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic int __init init_sysv_fs(void) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci int error; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci error = sysv_init_icache(); 56762306a36Sopenharmony_ci if (error) 56862306a36Sopenharmony_ci goto out; 56962306a36Sopenharmony_ci error = register_filesystem(&sysv_fs_type); 57062306a36Sopenharmony_ci if (error) 57162306a36Sopenharmony_ci goto destroy_icache; 57262306a36Sopenharmony_ci error = register_filesystem(&v7_fs_type); 57362306a36Sopenharmony_ci if (error) 57462306a36Sopenharmony_ci goto unregister; 57562306a36Sopenharmony_ci return 0; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ciunregister: 57862306a36Sopenharmony_ci unregister_filesystem(&sysv_fs_type); 57962306a36Sopenharmony_cidestroy_icache: 58062306a36Sopenharmony_ci sysv_destroy_icache(); 58162306a36Sopenharmony_ciout: 58262306a36Sopenharmony_ci return error; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic void __exit exit_sysv_fs(void) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci unregister_filesystem(&sysv_fs_type); 58862306a36Sopenharmony_ci unregister_filesystem(&v7_fs_type); 58962306a36Sopenharmony_ci sysv_destroy_icache(); 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cimodule_init(init_sysv_fs) 59362306a36Sopenharmony_cimodule_exit(exit_sysv_fs) 59462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 595