brintos

brintos / linux-shallow public Read only

0
0
Text · 15.1 KiB · 5c0d07d Raw
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