brintos

brintos / linux-shallow public Read only

0
0
Text · 17.5 KiB · 85925ec Raw
698 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * QNX6 file system, Linux implementation.4 *5 * Version : 1.0.06 *7 * History :8 *9 * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.10 * 16-02-2012 pagemap extension by Al Viro11 *12 */13 14#include <linux/module.h>15#include <linux/init.h>16#include <linux/slab.h>17#include <linux/highuid.h>18#include <linux/pagemap.h>19#include <linux/buffer_head.h>20#include <linux/writeback.h>21#include <linux/statfs.h>22#include <linux/seq_file.h>23#include <linux/crc32.h>24#include <linux/mpage.h>25#include <linux/fs_parser.h>26#include <linux/fs_context.h>27#include "qnx6.h"28 29static const struct super_operations qnx6_sops;30 31static void qnx6_put_super(struct super_block *sb);32static struct inode *qnx6_alloc_inode(struct super_block *sb);33static void qnx6_free_inode(struct inode *inode);34static int qnx6_reconfigure(struct fs_context *fc);35static int qnx6_statfs(struct dentry *dentry, struct kstatfs *buf);36static int qnx6_show_options(struct seq_file *seq, struct dentry *root);37 38static const struct super_operations qnx6_sops = {39	.alloc_inode	= qnx6_alloc_inode,40	.free_inode	= qnx6_free_inode,41	.put_super	= qnx6_put_super,42	.statfs		= qnx6_statfs,43	.show_options	= qnx6_show_options,44};45 46static int qnx6_show_options(struct seq_file *seq, struct dentry *root)47{48	struct super_block *sb = root->d_sb;49	struct qnx6_sb_info *sbi = QNX6_SB(sb);50 51	if (sbi->s_mount_opt & QNX6_MOUNT_MMI_FS)52		seq_puts(seq, ",mmi_fs");53	return 0;54}55 56static int qnx6_reconfigure(struct fs_context *fc)57{58	struct super_block *sb = fc->root->d_sb;59 60	sync_filesystem(sb);61	fc->sb_flags |= SB_RDONLY;62	return 0;63}64 65static unsigned qnx6_get_devblock(struct super_block *sb, __fs32 block)66{67	struct qnx6_sb_info *sbi = QNX6_SB(sb);68	return fs32_to_cpu(sbi, block) + sbi->s_blks_off;69}70 71static unsigned qnx6_block_map(struct inode *inode, unsigned iblock);72 73static int qnx6_get_block(struct inode *inode, sector_t iblock,74			struct buffer_head *bh, int create)75{76	unsigned phys;77 78	pr_debug("qnx6_get_block inode=[%ld] iblock=[%ld]\n",79		 inode->i_ino, (unsigned long)iblock);80 81	phys = qnx6_block_map(inode, iblock);82	if (phys) {83		/* logical block is before EOF */84		map_bh(bh, inode->i_sb, phys);85	}86	return 0;87}88 89static int qnx6_check_blockptr(__fs32 ptr)90{91	if (ptr == ~(__fs32)0) {92		pr_err("hit unused blockpointer.\n");93		return 0;94	}95	return 1;96}97 98static int qnx6_read_folio(struct file *file, struct folio *folio)99{100	return mpage_read_folio(folio, qnx6_get_block);101}102 103static void qnx6_readahead(struct readahead_control *rac)104{105	mpage_readahead(rac, qnx6_get_block);106}107 108/*109 * returns the block number for the no-th element in the tree110 * inodebits requred as there are multiple inodes in one inode block111 */112static unsigned qnx6_block_map(struct inode *inode, unsigned no)113{114	struct super_block *s = inode->i_sb;115	struct qnx6_sb_info *sbi = QNX6_SB(s);116	struct qnx6_inode_info *ei = QNX6_I(inode);117	unsigned block = 0;118	struct buffer_head *bh;119	__fs32 ptr;120	int levelptr;121	int ptrbits = sbi->s_ptrbits;122	int bitdelta;123	u32 mask = (1 << ptrbits) - 1;124	int depth = ei->di_filelevels;125	int i;126 127	bitdelta = ptrbits * depth;128	levelptr = no >> bitdelta;129 130	if (levelptr > QNX6_NO_DIRECT_POINTERS - 1) {131		pr_err("Requested file block number (%u) too big.", no);132		return 0;133	}134 135	block = qnx6_get_devblock(s, ei->di_block_ptr[levelptr]);136 137	for (i = 0; i < depth; i++) {138		bh = sb_bread(s, block);139		if (!bh) {140			pr_err("Error reading block (%u)\n", block);141			return 0;142		}143		bitdelta -= ptrbits;144		levelptr = (no >> bitdelta) & mask;145		ptr = ((__fs32 *)bh->b_data)[levelptr];146 147		if (!qnx6_check_blockptr(ptr))148			return 0;149 150		block = qnx6_get_devblock(s, ptr);151		brelse(bh);152	}153	return block;154}155 156static int qnx6_statfs(struct dentry *dentry, struct kstatfs *buf)157{158	struct super_block *sb = dentry->d_sb;159	struct qnx6_sb_info *sbi = QNX6_SB(sb);160	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);161 162	buf->f_type    = sb->s_magic;163	buf->f_bsize   = sb->s_blocksize;164	buf->f_blocks  = fs32_to_cpu(sbi, sbi->sb->sb_num_blocks);165	buf->f_bfree   = fs32_to_cpu(sbi, sbi->sb->sb_free_blocks);166	buf->f_files   = fs32_to_cpu(sbi, sbi->sb->sb_num_inodes);167	buf->f_ffree   = fs32_to_cpu(sbi, sbi->sb->sb_free_inodes);168	buf->f_bavail  = buf->f_bfree;169	buf->f_namelen = QNX6_LONG_NAME_MAX;170	buf->f_fsid    = u64_to_fsid(id);171 172	return 0;173}174 175/*176 * Check the root directory of the filesystem to make sure177 * it really _is_ a qnx6 filesystem, and to check the size178 * of the directory entry.179 */180static const char *qnx6_checkroot(struct super_block *s)181{182	static char match_root[2][3] = {".\0\0", "..\0"};183	int i, error = 0;184	struct qnx6_dir_entry *dir_entry;185	struct inode *root = d_inode(s->s_root);186	struct address_space *mapping = root->i_mapping;187	struct folio *folio = read_mapping_folio(mapping, 0, NULL);188 189	if (IS_ERR(folio))190		return "error reading root directory";191	dir_entry = kmap_local_folio(folio, 0);192	for (i = 0; i < 2; i++) {193		/* maximum 3 bytes - due to match_root limitation */194		if (strncmp(dir_entry[i].de_fname, match_root[i], 3))195			error = 1;196	}197	folio_release_kmap(folio, dir_entry);198	if (error)199		return "error reading root directory.";200	return NULL;201}202 203#ifdef CONFIG_QNX6FS_DEBUG204void qnx6_superblock_debug(struct qnx6_super_block *sb, struct super_block *s)205{206	struct qnx6_sb_info *sbi = QNX6_SB(s);207 208	pr_debug("magic: %08x\n", fs32_to_cpu(sbi, sb->sb_magic));209	pr_debug("checksum: %08x\n", fs32_to_cpu(sbi, sb->sb_checksum));210	pr_debug("serial: %llx\n", fs64_to_cpu(sbi, sb->sb_serial));211	pr_debug("flags: %08x\n", fs32_to_cpu(sbi, sb->sb_flags));212	pr_debug("blocksize: %08x\n", fs32_to_cpu(sbi, sb->sb_blocksize));213	pr_debug("num_inodes: %08x\n", fs32_to_cpu(sbi, sb->sb_num_inodes));214	pr_debug("free_inodes: %08x\n", fs32_to_cpu(sbi, sb->sb_free_inodes));215	pr_debug("num_blocks: %08x\n", fs32_to_cpu(sbi, sb->sb_num_blocks));216	pr_debug("free_blocks: %08x\n", fs32_to_cpu(sbi, sb->sb_free_blocks));217	pr_debug("inode_levels: %02x\n", sb->Inode.levels);218}219#endif220 221enum {222	Opt_mmifs223};224 225struct qnx6_context {226	unsigned long s_mount_opts;227};228 229static const struct fs_parameter_spec qnx6_param_spec[] = {230	fsparam_flag	("mmi_fs",	Opt_mmifs),231	{}232};233 234static int qnx6_parse_param(struct fs_context *fc, struct fs_parameter *param)235{236	struct qnx6_context *ctx = fc->fs_private;237	struct fs_parse_result result;238	int opt;239 240	opt = fs_parse(fc, qnx6_param_spec, param, &result);241	if (opt < 0)242		return opt;243 244	switch (opt) {245	case Opt_mmifs:246		ctx->s_mount_opts |= QNX6_MOUNT_MMI_FS;247		break;248	default:249		return -EINVAL;250	}251	return 0;252}253 254static struct buffer_head *qnx6_check_first_superblock(struct super_block *s,255				int offset, int silent)256{257	struct qnx6_sb_info *sbi = QNX6_SB(s);258	struct buffer_head *bh;259	struct qnx6_super_block *sb;260 261	/* Check the superblock signatures262	   start with the first superblock */263	bh = sb_bread(s, offset);264	if (!bh) {265		pr_err("unable to read the first superblock\n");266		return NULL;267	}268	sb = (struct qnx6_super_block *)bh->b_data;269	if (fs32_to_cpu(sbi, sb->sb_magic) != QNX6_SUPER_MAGIC) {270		sbi->s_bytesex = BYTESEX_BE;271		if (fs32_to_cpu(sbi, sb->sb_magic) == QNX6_SUPER_MAGIC) {272			/* we got a big endian fs */273			pr_debug("fs got different endianness.\n");274			return bh;275		} else276			sbi->s_bytesex = BYTESEX_LE;277		if (!silent) {278			if (offset == 0) {279				pr_err("wrong signature (magic) in superblock #1.\n");280			} else {281				pr_info("wrong signature (magic) at position (0x%lx) - will try alternative position (0x0000).\n",282					offset * s->s_blocksize);283			}284		}285		brelse(bh);286		return NULL;287	}288	return bh;289}290 291static struct inode *qnx6_private_inode(struct super_block *s,292					struct qnx6_root_node *p);293 294static int qnx6_fill_super(struct super_block *s, struct fs_context *fc)295{296	struct buffer_head *bh1 = NULL, *bh2 = NULL;297	struct qnx6_super_block *sb1 = NULL, *sb2 = NULL;298	struct qnx6_sb_info *sbi;299	struct qnx6_context *ctx = fc->fs_private;300	struct inode *root;301	const char *errmsg;302	struct qnx6_sb_info *qs;303	int ret = -EINVAL;304	u64 offset;305	int bootblock_offset = QNX6_BOOTBLOCK_SIZE;306	int silent = fc->sb_flags & SB_SILENT;307 308	qs = kzalloc(sizeof(struct qnx6_sb_info), GFP_KERNEL);309	if (!qs)310		return -ENOMEM;311	s->s_fs_info = qs;312	qs->s_mount_opt = ctx->s_mount_opts;313 314	/* Superblock always is 512 Byte long */315	if (!sb_set_blocksize(s, QNX6_SUPERBLOCK_SIZE)) {316		pr_err("unable to set blocksize\n");317		goto outnobh;318	}319 320	if (qs->s_mount_opt == QNX6_MOUNT_MMI_FS) {321		sb1 = qnx6_mmi_fill_super(s, silent);322		if (sb1)323			goto mmi_success;324		else325			goto outnobh;326	}327	sbi = QNX6_SB(s);328	sbi->s_bytesex = BYTESEX_LE;329	/* Check the superblock signatures330	   start with the first superblock */331	bh1 = qnx6_check_first_superblock(s,332		bootblock_offset / QNX6_SUPERBLOCK_SIZE, silent);333	if (!bh1) {334		/* try again without bootblock offset */335		bh1 = qnx6_check_first_superblock(s, 0, silent);336		if (!bh1) {337			pr_err("unable to read the first superblock\n");338			goto outnobh;339		}340		/* seems that no bootblock at partition start */341		bootblock_offset = 0;342	}343	sb1 = (struct qnx6_super_block *)bh1->b_data;344 345#ifdef CONFIG_QNX6FS_DEBUG346	qnx6_superblock_debug(sb1, s);347#endif348 349	/* checksum check - start at byte 8 and end at byte 512 */350	if (fs32_to_cpu(sbi, sb1->sb_checksum) !=351			crc32_be(0, (char *)(bh1->b_data + 8), 504)) {352		pr_err("superblock #1 checksum error\n");353		goto out;354	}355 356	/* set new blocksize */357	if (!sb_set_blocksize(s, fs32_to_cpu(sbi, sb1->sb_blocksize))) {358		pr_err("unable to set blocksize\n");359		goto out;360	}361	/* blocksize invalidates bh - pull it back in */362	brelse(bh1);363	bh1 = sb_bread(s, bootblock_offset >> s->s_blocksize_bits);364	if (!bh1)365		goto outnobh;366	sb1 = (struct qnx6_super_block *)bh1->b_data;367 368	/* calculate second superblock blocknumber */369	offset = fs32_to_cpu(sbi, sb1->sb_num_blocks) +370		(bootblock_offset >> s->s_blocksize_bits) +371		(QNX6_SUPERBLOCK_AREA >> s->s_blocksize_bits);372 373	/* set bootblock offset */374	sbi->s_blks_off = (bootblock_offset >> s->s_blocksize_bits) +375			  (QNX6_SUPERBLOCK_AREA >> s->s_blocksize_bits);376 377	/* next the second superblock */378	bh2 = sb_bread(s, offset);379	if (!bh2) {380		pr_err("unable to read the second superblock\n");381		goto out;382	}383	sb2 = (struct qnx6_super_block *)bh2->b_data;384	if (fs32_to_cpu(sbi, sb2->sb_magic) != QNX6_SUPER_MAGIC) {385		if (!silent)386			pr_err("wrong signature (magic) in superblock #2.\n");387		goto out;388	}389 390	/* checksum check - start at byte 8 and end at byte 512 */391	if (fs32_to_cpu(sbi, sb2->sb_checksum) !=392				crc32_be(0, (char *)(bh2->b_data + 8), 504)) {393		pr_err("superblock #2 checksum error\n");394		goto out;395	}396 397	if (fs64_to_cpu(sbi, sb1->sb_serial) >=398					fs64_to_cpu(sbi, sb2->sb_serial)) {399		/* superblock #1 active */400		sbi->sb_buf = bh1;401		sbi->sb = (struct qnx6_super_block *)bh1->b_data;402		brelse(bh2);403		pr_info("superblock #1 active\n");404	} else {405		/* superblock #2 active */406		sbi->sb_buf = bh2;407		sbi->sb = (struct qnx6_super_block *)bh2->b_data;408		brelse(bh1);409		pr_info("superblock #2 active\n");410	}411mmi_success:412	/* sanity check - limit maximum indirect pointer levels */413	if (sb1->Inode.levels > QNX6_PTR_MAX_LEVELS) {414		pr_err("too many inode levels (max %i, sb %i)\n",415		       QNX6_PTR_MAX_LEVELS, sb1->Inode.levels);416		goto out;417	}418	if (sb1->Longfile.levels > QNX6_PTR_MAX_LEVELS) {419		pr_err("too many longfilename levels (max %i, sb %i)\n",420		       QNX6_PTR_MAX_LEVELS, sb1->Longfile.levels);421		goto out;422	}423	s->s_op = &qnx6_sops;424	s->s_magic = QNX6_SUPER_MAGIC;425	s->s_flags |= SB_RDONLY;        /* Yup, read-only yet */426	s->s_time_min = 0;427	s->s_time_max = U32_MAX;428 429	/* ease the later tree level calculations */430	sbi = QNX6_SB(s);431	sbi->s_ptrbits = ilog2(s->s_blocksize / 4);432	sbi->inodes = qnx6_private_inode(s, &sb1->Inode);433	if (!sbi->inodes)434		goto out;435	sbi->longfile = qnx6_private_inode(s, &sb1->Longfile);436	if (!sbi->longfile)437		goto out1;438 439	/* prefetch root inode */440	root = qnx6_iget(s, QNX6_ROOT_INO);441	if (IS_ERR(root)) {442		pr_err("get inode failed\n");443		ret = PTR_ERR(root);444		goto out2;445	}446 447	ret = -ENOMEM;448	s->s_root = d_make_root(root);449	if (!s->s_root)450		goto out2;451 452	ret = -EINVAL;453	errmsg = qnx6_checkroot(s);454	if (errmsg != NULL) {455		if (!silent)456			pr_err("%s\n", errmsg);457		goto out3;458	}459	return 0;460 461out3:462	dput(s->s_root);463	s->s_root = NULL;464out2:465	iput(sbi->longfile);466out1:467	iput(sbi->inodes);468out:469	brelse(bh1);470	brelse(bh2);471outnobh:472	kfree(qs);473	s->s_fs_info = NULL;474	return ret;475}476 477static void qnx6_put_super(struct super_block *sb)478{479	struct qnx6_sb_info *qs = QNX6_SB(sb);480	brelse(qs->sb_buf);481	iput(qs->longfile);482	iput(qs->inodes);483	kfree(qs);484	sb->s_fs_info = NULL;485	return;486}487 488static sector_t qnx6_bmap(struct address_space *mapping, sector_t block)489{490	return generic_block_bmap(mapping, block, qnx6_get_block);491}492static const struct address_space_operations qnx6_aops = {493	.read_folio	= qnx6_read_folio,494	.readahead	= qnx6_readahead,495	.bmap		= qnx6_bmap496};497 498static struct inode *qnx6_private_inode(struct super_block *s,499					struct qnx6_root_node *p)500{501	struct inode *inode = new_inode(s);502	if (inode) {503		struct qnx6_inode_info *ei = QNX6_I(inode);504		struct qnx6_sb_info *sbi = QNX6_SB(s);505		inode->i_size = fs64_to_cpu(sbi, p->size);506		memcpy(ei->di_block_ptr, p->ptr, sizeof(p->ptr));507		ei->di_filelevels = p->levels;508		inode->i_mode = S_IFREG | S_IRUSR; /* probably wrong */509		inode->i_mapping->a_ops = &qnx6_aops;510	}511	return inode;512}513 514struct inode *qnx6_iget(struct super_block *sb, unsigned ino)515{516	struct qnx6_sb_info *sbi = QNX6_SB(sb);517	struct qnx6_inode_entry *raw_inode;518	struct inode *inode;519	struct qnx6_inode_info	*ei;520	struct address_space *mapping;521	struct folio *folio;522	u32 n, offs;523 524	inode = iget_locked(sb, ino);525	if (!inode)526		return ERR_PTR(-ENOMEM);527	if (!(inode->i_state & I_NEW))528		return inode;529 530	ei = QNX6_I(inode);531 532	inode->i_mode = 0;533 534	if (ino == 0) {535		pr_err("bad inode number on dev %s: %u is out of range\n",536		       sb->s_id, ino);537		iget_failed(inode);538		return ERR_PTR(-EIO);539	}540	n = (ino - 1) >> (PAGE_SHIFT - QNX6_INODE_SIZE_BITS);541	mapping = sbi->inodes->i_mapping;542	folio = read_mapping_folio(mapping, n, NULL);543	if (IS_ERR(folio)) {544		pr_err("major problem: unable to read inode from dev %s\n",545		       sb->s_id);546		iget_failed(inode);547		return ERR_CAST(folio);548	}549	offs = offset_in_folio(folio, (ino - 1) << QNX6_INODE_SIZE_BITS);550	raw_inode = kmap_local_folio(folio, offs);551 552	inode->i_mode    = fs16_to_cpu(sbi, raw_inode->di_mode);553	i_uid_write(inode, (uid_t)fs32_to_cpu(sbi, raw_inode->di_uid));554	i_gid_write(inode, (gid_t)fs32_to_cpu(sbi, raw_inode->di_gid));555	inode->i_size    = fs64_to_cpu(sbi, raw_inode->di_size);556	inode_set_mtime(inode, fs32_to_cpu(sbi, raw_inode->di_mtime), 0);557	inode_set_atime(inode, fs32_to_cpu(sbi, raw_inode->di_atime), 0);558	inode_set_ctime(inode, fs32_to_cpu(sbi, raw_inode->di_ctime), 0);559 560	/* calc blocks based on 512 byte blocksize */561	inode->i_blocks = (inode->i_size + 511) >> 9;562 563	memcpy(&ei->di_block_ptr, &raw_inode->di_block_ptr,564				sizeof(raw_inode->di_block_ptr));565	ei->di_filelevels = raw_inode->di_filelevels;566 567	if (S_ISREG(inode->i_mode)) {568		inode->i_fop = &generic_ro_fops;569		inode->i_mapping->a_ops = &qnx6_aops;570	} else if (S_ISDIR(inode->i_mode)) {571		inode->i_op = &qnx6_dir_inode_operations;572		inode->i_fop = &qnx6_dir_operations;573		inode->i_mapping->a_ops = &qnx6_aops;574	} else if (S_ISLNK(inode->i_mode)) {575		inode->i_op = &page_symlink_inode_operations;576		inode_nohighmem(inode);577		inode->i_mapping->a_ops = &qnx6_aops;578	} else579		init_special_inode(inode, inode->i_mode, 0);580	folio_release_kmap(folio, raw_inode);581	unlock_new_inode(inode);582	return inode;583}584 585static struct kmem_cache *qnx6_inode_cachep;586 587static struct inode *qnx6_alloc_inode(struct super_block *sb)588{589	struct qnx6_inode_info *ei;590	ei = alloc_inode_sb(sb, qnx6_inode_cachep, GFP_KERNEL);591	if (!ei)592		return NULL;593	return &ei->vfs_inode;594}595 596static void qnx6_free_inode(struct inode *inode)597{598	kmem_cache_free(qnx6_inode_cachep, QNX6_I(inode));599}600 601static void init_once(void *foo)602{603	struct qnx6_inode_info *ei = (struct qnx6_inode_info *) foo;604 605	inode_init_once(&ei->vfs_inode);606}607 608static int init_inodecache(void)609{610	qnx6_inode_cachep = kmem_cache_create("qnx6_inode_cache",611					     sizeof(struct qnx6_inode_info),612					     0, (SLAB_RECLAIM_ACCOUNT|613						SLAB_ACCOUNT),614					     init_once);615	if (!qnx6_inode_cachep)616		return -ENOMEM;617	return 0;618}619 620static void destroy_inodecache(void)621{622	/*623	 * Make sure all delayed rcu free inodes are flushed before we624	 * destroy cache.625	 */626	rcu_barrier();627	kmem_cache_destroy(qnx6_inode_cachep);628}629 630static int qnx6_get_tree(struct fs_context *fc)631{632	return get_tree_bdev(fc, qnx6_fill_super);633}634 635static void qnx6_free_fc(struct fs_context *fc)636{637	kfree(fc->fs_private);638}639 640static const struct fs_context_operations qnx6_context_ops = {641	.parse_param	= qnx6_parse_param,642	.get_tree	= qnx6_get_tree,643	.reconfigure	= qnx6_reconfigure,644	.free		= qnx6_free_fc,645};646 647static int qnx6_init_fs_context(struct fs_context *fc)648{649	struct qnx6_context *ctx;650 651	ctx = kzalloc(sizeof(struct qnx6_context), GFP_KERNEL);652	if (!ctx)653		return -ENOMEM;654	fc->ops = &qnx6_context_ops;655	fc->fs_private = ctx;656 657	return 0;658}659 660static struct file_system_type qnx6_fs_type = {661	.owner			= THIS_MODULE,662	.name			= "qnx6",663	.kill_sb		= kill_block_super,664	.fs_flags		= FS_REQUIRES_DEV,665	.init_fs_context	= qnx6_init_fs_context,666	.parameters		= qnx6_param_spec,667};668MODULE_ALIAS_FS("qnx6");669 670static int __init init_qnx6_fs(void)671{672	int err;673 674	err = init_inodecache();675	if (err)676		return err;677 678	err = register_filesystem(&qnx6_fs_type);679	if (err) {680		destroy_inodecache();681		return err;682	}683 684	pr_info("QNX6 filesystem 1.0.0 registered.\n");685	return 0;686}687 688static void __exit exit_qnx6_fs(void)689{690	unregister_filesystem(&qnx6_fs_type);691	destroy_inodecache();692}693 694module_init(init_qnx6_fs)695module_exit(exit_qnx6_fs)696MODULE_DESCRIPTION("QNX6 file system");697MODULE_LICENSE("GPL");698