brintos

brintos / linux-shallow public Read only

0
0
Text · 11.8 KiB · db81570 Raw
487 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *	fs/bfs/inode.c4 *	BFS superblock and inode operations.5 *	Copyright (C) 1999-2018 Tigran Aivazian <aivazian.tigran@gmail.com>6 *	From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds.7 *	Made endianness-clean by Andrew Stribblehill <ads@wompom.org>, 2005.8 */9 10#include <linux/module.h>11#include <linux/mm.h>12#include <linux/slab.h>13#include <linux/init.h>14#include <linux/fs.h>15#include <linux/buffer_head.h>16#include <linux/vfs.h>17#include <linux/writeback.h>18#include <linux/uio.h>19#include <linux/uaccess.h>20#include "bfs.h"21 22MODULE_AUTHOR("Tigran Aivazian <aivazian.tigran@gmail.com>");23MODULE_DESCRIPTION("SCO UnixWare BFS filesystem for Linux");24MODULE_LICENSE("GPL");25 26#undef DEBUG27 28#ifdef DEBUG29#define dprintf(x...)	printf(x)30#else31#define dprintf(x...)32#endif33 34struct inode *bfs_iget(struct super_block *sb, unsigned long ino)35{36	struct bfs_inode *di;37	struct inode *inode;38	struct buffer_head *bh;39	int block, off;40 41	inode = iget_locked(sb, ino);42	if (!inode)43		return ERR_PTR(-ENOMEM);44	if (!(inode->i_state & I_NEW))45		return inode;46 47	if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(inode->i_sb)->si_lasti)) {48		printf("Bad inode number %s:%08lx\n", inode->i_sb->s_id, ino);49		goto error;50	}51 52	block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;53	bh = sb_bread(inode->i_sb, block);54	if (!bh) {55		printf("Unable to read inode %s:%08lx\n", inode->i_sb->s_id,56									ino);57		goto error;58	}59 60	off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;61	di = (struct bfs_inode *)bh->b_data + off;62 63	inode->i_mode = 0x0000FFFF & le32_to_cpu(di->i_mode);64	if (le32_to_cpu(di->i_vtype) == BFS_VDIR) {65		inode->i_mode |= S_IFDIR;66		inode->i_op = &bfs_dir_inops;67		inode->i_fop = &bfs_dir_operations;68	} else if (le32_to_cpu(di->i_vtype) == BFS_VREG) {69		inode->i_mode |= S_IFREG;70		inode->i_op = &bfs_file_inops;71		inode->i_fop = &bfs_file_operations;72		inode->i_mapping->a_ops = &bfs_aops;73	}74 75	BFS_I(inode)->i_sblock =  le32_to_cpu(di->i_sblock);76	BFS_I(inode)->i_eblock =  le32_to_cpu(di->i_eblock);77	BFS_I(inode)->i_dsk_ino = le16_to_cpu(di->i_ino);78	i_uid_write(inode, le32_to_cpu(di->i_uid));79	i_gid_write(inode,  le32_to_cpu(di->i_gid));80	set_nlink(inode, le32_to_cpu(di->i_nlink));81	inode->i_size = BFS_FILESIZE(di);82	inode->i_blocks = BFS_FILEBLOCKS(di);83	inode_set_atime(inode, le32_to_cpu(di->i_atime), 0);84	inode_set_mtime(inode, le32_to_cpu(di->i_mtime), 0);85	inode_set_ctime(inode, le32_to_cpu(di->i_ctime), 0);86 87	brelse(bh);88	unlock_new_inode(inode);89	return inode;90 91error:92	iget_failed(inode);93	return ERR_PTR(-EIO);94}95 96static struct bfs_inode *find_inode(struct super_block *sb, u16 ino, struct buffer_head **p)97{98	if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(sb)->si_lasti)) {99		printf("Bad inode number %s:%08x\n", sb->s_id, ino);100		return ERR_PTR(-EIO);101	}102 103	ino -= BFS_ROOT_INO;104 105	*p = sb_bread(sb, 1 + ino / BFS_INODES_PER_BLOCK);106	if (!*p) {107		printf("Unable to read inode %s:%08x\n", sb->s_id, ino);108		return ERR_PTR(-EIO);109	}110 111	return (struct bfs_inode *)(*p)->b_data +  ino % BFS_INODES_PER_BLOCK;112}113 114static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc)115{116	struct bfs_sb_info *info = BFS_SB(inode->i_sb);117	unsigned int ino = (u16)inode->i_ino;118	unsigned long i_sblock;119	struct bfs_inode *di;120	struct buffer_head *bh;121	int err = 0;122 123	dprintf("ino=%08x\n", ino);124 125	di = find_inode(inode->i_sb, ino, &bh);126	if (IS_ERR(di))127		return PTR_ERR(di);128 129	mutex_lock(&info->bfs_lock);130 131	if (ino == BFS_ROOT_INO)132		di->i_vtype = cpu_to_le32(BFS_VDIR);133	else134		di->i_vtype = cpu_to_le32(BFS_VREG);135 136	di->i_ino = cpu_to_le16(ino);137	di->i_mode = cpu_to_le32(inode->i_mode);138	di->i_uid = cpu_to_le32(i_uid_read(inode));139	di->i_gid = cpu_to_le32(i_gid_read(inode));140	di->i_nlink = cpu_to_le32(inode->i_nlink);141	di->i_atime = cpu_to_le32(inode_get_atime_sec(inode));142	di->i_mtime = cpu_to_le32(inode_get_mtime_sec(inode));143	di->i_ctime = cpu_to_le32(inode_get_ctime_sec(inode));144	i_sblock = BFS_I(inode)->i_sblock;145	di->i_sblock = cpu_to_le32(i_sblock);146	di->i_eblock = cpu_to_le32(BFS_I(inode)->i_eblock);147	di->i_eoffset = cpu_to_le32(i_sblock * BFS_BSIZE + inode->i_size - 1);148 149	mark_buffer_dirty(bh);150	if (wbc->sync_mode == WB_SYNC_ALL) {151		sync_dirty_buffer(bh);152		if (buffer_req(bh) && !buffer_uptodate(bh))153			err = -EIO;154	}155	brelse(bh);156	mutex_unlock(&info->bfs_lock);157	return err;158}159 160static void bfs_evict_inode(struct inode *inode)161{162	unsigned long ino = inode->i_ino;163	struct bfs_inode *di;164	struct buffer_head *bh;165	struct super_block *s = inode->i_sb;166	struct bfs_sb_info *info = BFS_SB(s);167	struct bfs_inode_info *bi = BFS_I(inode);168 169	dprintf("ino=%08lx\n", ino);170 171	truncate_inode_pages_final(&inode->i_data);172	invalidate_inode_buffers(inode);173	clear_inode(inode);174 175	if (inode->i_nlink)176		return;177 178	di = find_inode(s, inode->i_ino, &bh);179	if (IS_ERR(di))180		return;181 182	mutex_lock(&info->bfs_lock);183	/* clear on-disk inode */184	memset(di, 0, sizeof(struct bfs_inode));185	mark_buffer_dirty(bh);186	brelse(bh);187 188	if (bi->i_dsk_ino) {189		if (bi->i_sblock)190			info->si_freeb += bi->i_eblock + 1 - bi->i_sblock;191		info->si_freei++;192		clear_bit(ino, info->si_imap);193		bfs_dump_imap("evict_inode", s);194	}195 196	/*197	 * If this was the last file, make the previous block198	 * "last block of the last file" even if there is no199	 * real file there, saves us 1 gap.200	 */201	if (info->si_lf_eblk == bi->i_eblock)202		info->si_lf_eblk = bi->i_sblock - 1;203	mutex_unlock(&info->bfs_lock);204}205 206static void bfs_put_super(struct super_block *s)207{208	struct bfs_sb_info *info = BFS_SB(s);209 210	if (!info)211		return;212 213	mutex_destroy(&info->bfs_lock);214	kfree(info);215	s->s_fs_info = NULL;216}217 218static int bfs_statfs(struct dentry *dentry, struct kstatfs *buf)219{220	struct super_block *s = dentry->d_sb;221	struct bfs_sb_info *info = BFS_SB(s);222	u64 id = huge_encode_dev(s->s_bdev->bd_dev);223	buf->f_type = BFS_MAGIC;224	buf->f_bsize = s->s_blocksize;225	buf->f_blocks = info->si_blocks;226	buf->f_bfree = buf->f_bavail = info->si_freeb;227	buf->f_files = info->si_lasti + 1 - BFS_ROOT_INO;228	buf->f_ffree = info->si_freei;229	buf->f_fsid = u64_to_fsid(id);230	buf->f_namelen = BFS_NAMELEN;231	return 0;232}233 234static struct kmem_cache *bfs_inode_cachep;235 236static struct inode *bfs_alloc_inode(struct super_block *sb)237{238	struct bfs_inode_info *bi;239	bi = alloc_inode_sb(sb, bfs_inode_cachep, GFP_KERNEL);240	if (!bi)241		return NULL;242	return &bi->vfs_inode;243}244 245static void bfs_free_inode(struct inode *inode)246{247	kmem_cache_free(bfs_inode_cachep, BFS_I(inode));248}249 250static void init_once(void *foo)251{252	struct bfs_inode_info *bi = foo;253 254	inode_init_once(&bi->vfs_inode);255}256 257static int __init init_inodecache(void)258{259	bfs_inode_cachep = kmem_cache_create("bfs_inode_cache",260					     sizeof(struct bfs_inode_info),261					     0, (SLAB_RECLAIM_ACCOUNT|262						SLAB_ACCOUNT),263					     init_once);264	if (bfs_inode_cachep == NULL)265		return -ENOMEM;266	return 0;267}268 269static void destroy_inodecache(void)270{271	/*272	 * Make sure all delayed rcu free inodes are flushed before we273	 * destroy cache.274	 */275	rcu_barrier();276	kmem_cache_destroy(bfs_inode_cachep);277}278 279static const struct super_operations bfs_sops = {280	.alloc_inode	= bfs_alloc_inode,281	.free_inode	= bfs_free_inode,282	.write_inode	= bfs_write_inode,283	.evict_inode	= bfs_evict_inode,284	.put_super	= bfs_put_super,285	.statfs		= bfs_statfs,286};287 288void bfs_dump_imap(const char *prefix, struct super_block *s)289{290#ifdef DEBUG291	int i;292	char *tmpbuf = (char *)get_zeroed_page(GFP_KERNEL);293 294	if (!tmpbuf)295		return;296	for (i = BFS_SB(s)->si_lasti; i >= 0; i--) {297		if (i > PAGE_SIZE - 100) break;298		if (test_bit(i, BFS_SB(s)->si_imap))299			strcat(tmpbuf, "1");300		else301			strcat(tmpbuf, "0");302	}303	printf("%s: lasti=%08lx <%s>\n", prefix, BFS_SB(s)->si_lasti, tmpbuf);304	free_page((unsigned long)tmpbuf);305#endif306}307 308static int bfs_fill_super(struct super_block *s, void *data, int silent)309{310	struct buffer_head *bh, *sbh;311	struct bfs_super_block *bfs_sb;312	struct inode *inode;313	unsigned i;314	struct bfs_sb_info *info;315	int ret = -EINVAL;316	unsigned long i_sblock, i_eblock, i_eoff, s_size;317 318	info = kzalloc(sizeof(*info), GFP_KERNEL);319	if (!info)320		return -ENOMEM;321	mutex_init(&info->bfs_lock);322	s->s_fs_info = info;323	s->s_time_min = 0;324	s->s_time_max = U32_MAX;325 326	sb_set_blocksize(s, BFS_BSIZE);327 328	sbh = sb_bread(s, 0);329	if (!sbh)330		goto out;331	bfs_sb = (struct bfs_super_block *)sbh->b_data;332	if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) {333		if (!silent)334			printf("No BFS filesystem on %s (magic=%08x)\n", s->s_id,  le32_to_cpu(bfs_sb->s_magic));335		goto out1;336	}337	if (BFS_UNCLEAN(bfs_sb, s) && !silent)338		printf("%s is unclean, continuing\n", s->s_id);339 340	s->s_magic = BFS_MAGIC;341 342	if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end) ||343	    le32_to_cpu(bfs_sb->s_start) < sizeof(struct bfs_super_block) + sizeof(struct bfs_dirent)) {344		printf("Superblock is corrupted on %s\n", s->s_id);345		goto out1;346	}347 348	info->si_lasti = (le32_to_cpu(bfs_sb->s_start) - BFS_BSIZE) / sizeof(struct bfs_inode) + BFS_ROOT_INO - 1;349	if (info->si_lasti == BFS_MAX_LASTI)350		printf("NOTE: filesystem %s was created with 512 inodes, the real maximum is 511, mounting anyway\n", s->s_id);351	else if (info->si_lasti > BFS_MAX_LASTI) {352		printf("Impossible last inode number %lu > %d on %s\n", info->si_lasti, BFS_MAX_LASTI, s->s_id);353		goto out1;354	}355	for (i = 0; i < BFS_ROOT_INO; i++)356		set_bit(i, info->si_imap);357 358	s->s_op = &bfs_sops;359	inode = bfs_iget(s, BFS_ROOT_INO);360	if (IS_ERR(inode)) {361		ret = PTR_ERR(inode);362		goto out1;363	}364	s->s_root = d_make_root(inode);365	if (!s->s_root) {366		ret = -ENOMEM;367		goto out1;368	}369 370	info->si_blocks = (le32_to_cpu(bfs_sb->s_end) + 1) >> BFS_BSIZE_BITS;371	info->si_freeb = (le32_to_cpu(bfs_sb->s_end) + 1 - le32_to_cpu(bfs_sb->s_start)) >> BFS_BSIZE_BITS;372	info->si_freei = 0;373	info->si_lf_eblk = 0;374 375	/* can we read the last block? */376	bh = sb_bread(s, info->si_blocks - 1);377	if (!bh) {378		printf("Last block not available on %s: %lu\n", s->s_id, info->si_blocks - 1);379		ret = -EIO;380		goto out2;381	}382	brelse(bh);383 384	bh = NULL;385	for (i = BFS_ROOT_INO; i <= info->si_lasti; i++) {386		struct bfs_inode *di;387		int block = (i - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;388		int off = (i - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;389		unsigned long eblock;390 391		if (!off) {392			brelse(bh);393			bh = sb_bread(s, block);394		}395 396		if (!bh)397			continue;398 399		di = (struct bfs_inode *)bh->b_data + off;400 401		/* test if filesystem is not corrupted */402 403		i_eoff = le32_to_cpu(di->i_eoffset);404		i_sblock = le32_to_cpu(di->i_sblock);405		i_eblock = le32_to_cpu(di->i_eblock);406		s_size = le32_to_cpu(bfs_sb->s_end);407 408		if (i_sblock > info->si_blocks ||409			i_eblock > info->si_blocks ||410			i_sblock > i_eblock ||411			(i_eoff != le32_to_cpu(-1) && i_eoff > s_size) ||412			i_sblock * BFS_BSIZE > i_eoff) {413 414			printf("Inode 0x%08x corrupted on %s\n", i, s->s_id);415 416			brelse(bh);417			ret = -EIO;418			goto out2;419		}420 421		if (!di->i_ino) {422			info->si_freei++;423			continue;424		}425		set_bit(i, info->si_imap);426		info->si_freeb -= BFS_FILEBLOCKS(di);427 428		eblock =  le32_to_cpu(di->i_eblock);429		if (eblock > info->si_lf_eblk)430			info->si_lf_eblk = eblock;431	}432	brelse(bh);433	brelse(sbh);434	bfs_dump_imap("fill_super", s);435	return 0;436 437out2:438	dput(s->s_root);439	s->s_root = NULL;440out1:441	brelse(sbh);442out:443	mutex_destroy(&info->bfs_lock);444	kfree(info);445	s->s_fs_info = NULL;446	return ret;447}448 449static struct dentry *bfs_mount(struct file_system_type *fs_type,450	int flags, const char *dev_name, void *data)451{452	return mount_bdev(fs_type, flags, dev_name, data, bfs_fill_super);453}454 455static struct file_system_type bfs_fs_type = {456	.owner		= THIS_MODULE,457	.name		= "bfs",458	.mount		= bfs_mount,459	.kill_sb	= kill_block_super,460	.fs_flags	= FS_REQUIRES_DEV,461};462MODULE_ALIAS_FS("bfs");463 464static int __init init_bfs_fs(void)465{466	int err = init_inodecache();467	if (err)468		goto out1;469	err = register_filesystem(&bfs_fs_type);470	if (err)471		goto out;472	return 0;473out:474	destroy_inodecache();475out1:476	return err;477}478 479static void __exit exit_bfs_fs(void)480{481	unregister_filesystem(&bfs_fs_type);482	destroy_inodecache();483}484 485module_init(init_bfs_fs)486module_exit(exit_bfs_fs)487