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