Commit 5d026c7242201e7c9d0e12fcb2bcaffead9d59fd

Authored by Kai Bankett
Committed by Al Viro
1 parent 516cdb68e5

fs: initial qnx6fs addition

Adds support for qnx6fs readonly support to the linux kernel.

* Mount option
  The option mmi_fs can be used to mount Harman Becker/Audi MMI 3G
  HDD qnx6fs filesystems.

* Documentation
  A high level filesystem stucture description can be found in the
  Documentation/filesystems directory. (qnx6.txt)

* Additional features
  - Active (stable) superblock selection
  - Superblock checksum check (enforced)
  - Supports mount of qnx6 filesystems with to host different endianess
  - Automatic endianess detection
  - Longfilename support (with non-enfocing crc check)
  - All blocksizes (512, 1024, 2048 and 4096 supported)

Signed-off-by: Kai Bankett <chaosman@ontika.net>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Showing 13 changed files with 1668 additions and 0 deletions Side-by-side Diff

Documentation/filesystems/qnx6.txt
  1 +The QNX6 Filesystem
  2 +===================
  3 +
  4 +The qnx6fs is used by newer QNX operating system versions. (e.g. Neutrino)
  5 +It got introduced in QNX 6.4.0 and is used default since 6.4.1.
  6 +
  7 +Option
  8 +======
  9 +
  10 +mmi_fs Mount filesystem as used for example by Audi MMI 3G system
  11 +
  12 +Specification
  13 +=============
  14 +
  15 +qnx6fs shares many properties with traditional Unix filesystems. It has the
  16 +concepts of blocks, inodes and directories.
  17 +On QNX it is possible to create little endian and big endian qnx6 filesystems.
  18 +This feature makes it possible to create and use a different endianness fs
  19 +for the target (QNX is used on quite a range of embedded systems) plattform
  20 +running on a different endianess.
  21 +The Linux driver handles endianness transparently. (LE and BE)
  22 +
  23 +Blocks
  24 +------
  25 +
  26 +The space in the device or file is split up into blocks. These are a fixed
  27 +size of 512, 1024, 2048 or 4096, which is decided when the filesystem is
  28 +created.
  29 +Blockpointers are 32bit, so the maximum space that can be adressed is
  30 +2^32 * 4096 bytes or 16TB
  31 +
  32 +The superblocks
  33 +---------------
  34 +
  35 +The superblock contains all global information about the filesystem.
  36 +Each qnx6fs got two superblocks, each one having a 64bit serial number.
  37 +That serial number is used to identify the "active" superblock.
  38 +In write mode with reach new snapshot (after each synchronous write), the
  39 +serial of the new master superblock is increased (old superblock serial + 1)
  40 +
  41 +So basically the snapshot functionality is realized by an atomic final
  42 +update of the serial number. Before updating that serial, all modifications
  43 +are done by copying all modified blocks during that specific write request
  44 +(or period) and building up a new (stable) filesystem structure under the
  45 +inactive superblock.
  46 +
  47 +Each superblock holds a set of root inodes for the different filesystem
  48 +parts. (Inode, Bitmap and Longfilenames)
  49 +Each of these root nodes holds information like total size of the stored
  50 +data and the adressing levels in that specific tree.
  51 +If the level value is 0, up to 16 direct blocks can be adressed by each
  52 +node.
  53 +Level 1 adds an additional indirect adressing level where each indirect
  54 +adressing block holds up to blocksize / 4 bytes pointers to data blocks.
  55 +Level 2 adds an additional indirect adressig block level (so, already up
  56 +to 16 * 256 * 256 = 1048576 blocks that can be adressed by such a tree)a
  57 +
  58 +Unused block pointers are always set to ~0 - regardless of root node,
  59 +indirect adressing blocks or inodes.
  60 +Data leaves are always on the lowest level. So no data is stored on upper
  61 +tree levels.
  62 +
  63 +The first Superblock is located at 0x2000. (0x2000 is the bootblock size)
  64 +The Audi MMI 3G first superblock directly starts at byte 0.
  65 +Second superblock position can either be calculated from the superblock
  66 +information (total number of filesystem blocks) or by taking the highest
  67 +device address, zeroing the last 3 bytes and then substracting 0x1000 from
  68 +that address.
  69 +
  70 +0x1000 is the size reserved for each superblock - regardless of the
  71 +blocksize of the filesystem.
  72 +
  73 +Inodes
  74 +------
  75 +
  76 +Each object in the filesystem is represented by an inode. (index node)
  77 +The inode structure contains pointers to the filesystem blocks which contain
  78 +the data held in the object and all of the metadata about an object except
  79 +its longname. (filenames longer than 27 characters)
  80 +The metadata about an object includes the permissions, owner, group, flags,
  81 +size, number of blocks used, access time, change time and modification time.
  82 +
  83 +Object mode field is POSIX format. (which makes things easier)
  84 +
  85 +There are also pointers to the first 16 blocks, if the object data can be
  86 +adressed with 16 direct blocks.
  87 +For more than 16 blocks an indirect adressing in form of another tree is
  88 +used. (scheme is the same as the one used for the superblock root nodes)
  89 +
  90 +The filesize is stored 64bit. Inode counting starts with 1. (whilst long
  91 +filename inodes start with 0)
  92 +
  93 +Directories
  94 +-----------
  95 +
  96 +A directory is a filesystem object and has an inode just like a file.
  97 +It is a specially formatted file containing records which associate each
  98 +name with an inode number.
  99 +'.' inode number points to the directory inode
  100 +'..' inode number points to the parent directory inode
  101 +Eeach filename record additionally got a filename length field.
  102 +
  103 +One special case are long filenames or subdirectory names.
  104 +These got set a filename length field of 0xff in the corresponding directory
  105 +record plus the longfile inode number also stored in that record.
  106 +With that longfilename inode number, the longfilename tree can be walked
  107 +starting with the superblock longfilename root node pointers.
  108 +
  109 +Special files
  110 +-------------
  111 +
  112 +Symbolic links are also filesystem objects with inodes. They got a specific
  113 +bit in the inode mode field identifying them as symbolic link.
  114 +The directory entry file inode pointer points to the target file inode.
  115 +
  116 +Hard links got an inode, a directory entry, but a specific mode bit set,
  117 +no block pointers and the directory file record pointing to the target file
  118 +inode.
  119 +
  120 +Character and block special devices do not exist in QNX as those files
  121 +are handled by the QNX kernel/drivers and created in /dev independant of the
  122 +underlaying filesystem.
  123 +
  124 +Long filenames
  125 +--------------
  126 +
  127 +Long filenames are stored in a seperate adressing tree. The staring point
  128 +is the longfilename root node in the active superblock.
  129 +Each data block (tree leaves) holds one long filename. That filename is
  130 +limited to 510 bytes. The first two starting bytes are used as length field
  131 +for the actual filename.
  132 +If that structure shall fit for all allowed blocksizes, it is clear why there
  133 +is a limit of 510 bytes for the actual filename stored.
  134 +
  135 +Bitmap
  136 +------
  137 +
  138 +The qnx6fs filesystem allocation bitmap is stored in a tree under bitmap
  139 +root node in the superblock and each bit in the bitmap represents one
  140 +filesystem block.
  141 +The first block is block 0, which starts 0x1000 after superblock start.
  142 +So for a normal qnx6fs 0x3000 (bootblock + superblock) is the physical
  143 +address at which block 0 is located.
  144 +
  145 +Bits at the end of the last bitmap block are set to 1, if the device is
  146 +smaller than addressing space in the bitmap.
  147 +
  148 +Bitmap system area
  149 +------------------
  150 +
  151 +The bitmap itself is devided into three parts.
  152 +First the system area, that is split into two halfs.
  153 +Then userspace.
  154 +
  155 +The requirement for a static, fixed preallocated system area comes from how
  156 +qnx6fs deals with writes.
  157 +Each superblock got it's own half of the system area. So superblock #1
  158 +always uses blocks from the lower half whilst superblock #2 just writes to
  159 +blocks represented by the upper half bitmap system area bits.
  160 +
  161 +Bitmap blocks, Inode blocks and indirect addressing blocks for those two
  162 +tree structures are treated as system blocks.
  163 +
  164 +The rational behind that is that a write request can work on a new snapshot
  165 +(system area of the inactive - resp. lower serial numbered superblock) while
  166 +at the same time there is still a complete stable filesystem structer in the
  167 +other half of the system area.
  168 +
  169 +When finished with writing (a sync write is completed, the maximum sync leap
  170 +time or a filesystem sync is requested), serial of the previously inactive
  171 +superblock atomically is increased and the fs switches over to that - then
  172 +stable declared - superblock.
  173 +
  174 +For all data outside the system area, blocks are just copied while writing.
... ... @@ -210,6 +210,7 @@
210 210 source "fs/omfs/Kconfig"
211 211 source "fs/hpfs/Kconfig"
212 212 source "fs/qnx4/Kconfig"
  213 +source "fs/qnx6/Kconfig"
213 214 source "fs/romfs/Kconfig"
214 215 source "fs/pstore/Kconfig"
215 216 source "fs/sysv/Kconfig"
... ... @@ -102,6 +102,7 @@
102 102 obj-$(CONFIG_AFFS_FS) += affs/
103 103 obj-$(CONFIG_ROMFS_FS) += romfs/
104 104 obj-$(CONFIG_QNX4FS_FS) += qnx4/
  105 +obj-$(CONFIG_QNX6FS_FS) += qnx6/
105 106 obj-$(CONFIG_AUTOFS4_FS) += autofs4/
106 107 obj-$(CONFIG_ADFS_FS) += adfs/
107 108 obj-$(CONFIG_FUSE_FS) += fuse/
  1 +config QNX6FS_FS
  2 + tristate "QNX6 file system support (read only)"
  3 + depends on BLOCK && CRC32
  4 + help
  5 + This is the file system used by the real-time operating systems
  6 + QNX 6 (also called QNX RTP).
  7 + Further information is available at <http://www.qnx.com/>.
  8 + Say Y if you intend to mount QNX hard disks or floppies formatted
  9 + with a mkqnx6fs.
  10 + However, keep in mind that this currently is a readonly driver!
  11 +
  12 + To compile this file system support as a module, choose M here: the
  13 + module will be called qnx6.
  14 +
  15 + If you don't know whether you need it, then you don't need it:
  16 + answer N.
  17 +
  18 +config QNX6FS_DEBUG
  19 + bool "QNX6 debugging information"
  20 + depends on QNX6FS_FS
  21 + help
  22 + Turns on extended debugging output.
  23 +
  24 + If you are not a developer working on the QNX6FS, you probably don't
  25 + want this:
  26 + answer N.
  1 +#
  2 +# Makefile for the linux qnx4-filesystem routines.
  3 +#
  4 +
  5 +obj-$(CONFIG_QNX6FS_FS) += qnx6.o
  6 +
  7 +qnx6-objs := inode.o dir.o namei.o super_mmi.o
  1 +
  2 + This is a snapshot of the QNX6 filesystem for Linux.
  3 + Please send diffs and remarks to <chaosman@ontika.net> .
  4 +
  5 +Credits :
  6 +
  7 +Al Viro <viro@ZenIV.linux.org.uk> (endless patience with me & support ;))
  8 +Kai Bankett <chaosman@ontika.net> (Maintainer)
  1 +/*
  2 + * QNX6 file system, Linux implementation.
  3 + *
  4 + * Version : 1.0.0
  5 + *
  6 + * History :
  7 + *
  8 + * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
  9 + * 16-02-2012 pagemap extension by Al Viro
  10 + *
  11 + */
  12 +
  13 +#include "qnx6.h"
  14 +
  15 +static unsigned qnx6_lfile_checksum(char *name, unsigned size)
  16 +{
  17 + unsigned crc = 0;
  18 + char *end = name + size;
  19 + while (name < end) {
  20 + crc = ((crc >> 1) + *(name++)) ^
  21 + ((crc & 0x00000001) ? 0x80000000 : 0);
  22 + }
  23 + return crc;
  24 +}
  25 +
  26 +static struct page *qnx6_get_page(struct inode *dir, unsigned long n)
  27 +{
  28 + struct address_space *mapping = dir->i_mapping;
  29 + struct page *page = read_mapping_page(mapping, n, NULL);
  30 + if (!IS_ERR(page))
  31 + kmap(page);
  32 + return page;
  33 +}
  34 +
  35 +static inline unsigned long dir_pages(struct inode *inode)
  36 +{
  37 + return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
  38 +}
  39 +
  40 +static unsigned last_entry(struct inode *inode, unsigned long page_nr)
  41 +{
  42 + unsigned long last_byte = inode->i_size;
  43 + last_byte -= page_nr << PAGE_CACHE_SHIFT;
  44 + if (last_byte > PAGE_CACHE_SIZE)
  45 + last_byte = PAGE_CACHE_SIZE;
  46 + return last_byte / QNX6_DIR_ENTRY_SIZE;
  47 +}
  48 +
  49 +static struct qnx6_long_filename *qnx6_longname(struct super_block *sb,
  50 + struct qnx6_long_dir_entry *de,
  51 + struct page **p)
  52 +{
  53 + struct qnx6_sb_info *sbi = QNX6_SB(sb);
  54 + u32 s = fs32_to_cpu(sbi, de->de_long_inode); /* in block units */
  55 + u32 n = s >> (PAGE_CACHE_SHIFT - sb->s_blocksize_bits); /* in pages */
  56 + /* within page */
  57 + u32 offs = (s << sb->s_blocksize_bits) & ~PAGE_CACHE_MASK;
  58 + struct address_space *mapping = sbi->longfile->i_mapping;
  59 + struct page *page = read_mapping_page(mapping, n, NULL);
  60 + if (IS_ERR(page))
  61 + return ERR_CAST(page);
  62 + kmap(*p = page);
  63 + return (struct qnx6_long_filename *)(page_address(page) + offs);
  64 +}
  65 +
  66 +static int qnx6_dir_longfilename(struct inode *inode,
  67 + struct qnx6_long_dir_entry *de,
  68 + void *dirent, loff_t pos,
  69 + unsigned de_inode, filldir_t filldir)
  70 +{
  71 + struct qnx6_long_filename *lf;
  72 + struct super_block *s = inode->i_sb;
  73 + struct qnx6_sb_info *sbi = QNX6_SB(s);
  74 + struct page *page;
  75 + int lf_size;
  76 +
  77 + if (de->de_size != 0xff) {
  78 + /* error - long filename entries always have size 0xff
  79 + in direntry */
  80 + printk(KERN_ERR "qnx6: invalid direntry size (%i).\n",
  81 + de->de_size);
  82 + return 0;
  83 + }
  84 + lf = qnx6_longname(s, de, &page);
  85 + if (IS_ERR(lf)) {
  86 + printk(KERN_ERR "qnx6:Error reading longname\n");
  87 + return 0;
  88 + }
  89 +
  90 + lf_size = fs16_to_cpu(sbi, lf->lf_size);
  91 +
  92 + if (lf_size > QNX6_LONG_NAME_MAX) {
  93 + QNX6DEBUG((KERN_INFO "file %s\n", lf->lf_fname));
  94 + printk(KERN_ERR "qnx6:Filename too long (%i)\n", lf_size);
  95 + qnx6_put_page(page);
  96 + return 0;
  97 + }
  98 +
  99 + /* calc & validate longfilename checksum
  100 + mmi 3g filesystem does not have that checksum */
  101 + if (!test_opt(s, MMI_FS) && fs32_to_cpu(sbi, de->de_checksum) !=
  102 + qnx6_lfile_checksum(lf->lf_fname, lf_size))
  103 + printk(KERN_INFO "qnx6: long filename checksum error.\n");
  104 +
  105 + QNX6DEBUG((KERN_INFO "qnx6_readdir:%.*s inode:%u\n",
  106 + lf_size, lf->lf_fname, de_inode));
  107 + if (filldir(dirent, lf->lf_fname, lf_size, pos, de_inode,
  108 + DT_UNKNOWN) < 0) {
  109 + qnx6_put_page(page);
  110 + return 0;
  111 + }
  112 +
  113 + qnx6_put_page(page);
  114 + /* success */
  115 + return 1;
  116 +}
  117 +
  118 +static int qnx6_readdir(struct file *filp, void *dirent, filldir_t filldir)
  119 +{
  120 + struct inode *inode = filp->f_path.dentry->d_inode;
  121 + struct super_block *s = inode->i_sb;
  122 + struct qnx6_sb_info *sbi = QNX6_SB(s);
  123 + loff_t pos = filp->f_pos & (QNX6_DIR_ENTRY_SIZE - 1);
  124 + unsigned long npages = dir_pages(inode);
  125 + unsigned long n = pos >> PAGE_CACHE_SHIFT;
  126 + unsigned start = (pos & ~PAGE_CACHE_MASK) / QNX6_DIR_ENTRY_SIZE;
  127 + bool done = false;
  128 +
  129 + if (filp->f_pos >= inode->i_size)
  130 + return 0;
  131 +
  132 + for ( ; !done && n < npages; n++, start = 0) {
  133 + struct page *page = qnx6_get_page(inode, n);
  134 + int limit = last_entry(inode, n);
  135 + struct qnx6_dir_entry *de;
  136 + int i = start;
  137 +
  138 + if (IS_ERR(page)) {
  139 + printk(KERN_ERR "qnx6_readdir: read failed\n");
  140 + filp->f_pos = (n + 1) << PAGE_CACHE_SHIFT;
  141 + return PTR_ERR(page);
  142 + }
  143 + de = ((struct qnx6_dir_entry *)page_address(page)) + start;
  144 + for (; i < limit; i++, de++, pos += QNX6_DIR_ENTRY_SIZE) {
  145 + int size = de->de_size;
  146 + u32 no_inode = fs32_to_cpu(sbi, de->de_inode);
  147 +
  148 + if (!no_inode || !size)
  149 + continue;
  150 +
  151 + if (size > QNX6_SHORT_NAME_MAX) {
  152 + /* long filename detected
  153 + get the filename from long filename
  154 + structure / block */
  155 + if (!qnx6_dir_longfilename(inode,
  156 + (struct qnx6_long_dir_entry *)de,
  157 + dirent, pos, no_inode,
  158 + filldir)) {
  159 + done = true;
  160 + break;
  161 + }
  162 + } else {
  163 + QNX6DEBUG((KERN_INFO "qnx6_readdir:%.*s"
  164 + " inode:%u\n", size, de->de_fname,
  165 + no_inode));
  166 + if (filldir(dirent, de->de_fname, size,
  167 + pos, no_inode, DT_UNKNOWN)
  168 + < 0) {
  169 + done = true;
  170 + break;
  171 + }
  172 + }
  173 + }
  174 + qnx6_put_page(page);
  175 + }
  176 + filp->f_pos = pos;
  177 + return 0;
  178 +}
  179 +
  180 +/*
  181 + * check if the long filename is correct.
  182 + */
  183 +static unsigned qnx6_long_match(int len, const char *name,
  184 + struct qnx6_long_dir_entry *de, struct inode *dir)
  185 +{
  186 + struct super_block *s = dir->i_sb;
  187 + struct qnx6_sb_info *sbi = QNX6_SB(s);
  188 + struct page *page;
  189 + int thislen;
  190 + struct qnx6_long_filename *lf = qnx6_longname(s, de, &page);
  191 +
  192 + if (IS_ERR(lf))
  193 + return 0;
  194 +
  195 + thislen = fs16_to_cpu(sbi, lf->lf_size);
  196 + if (len != thislen) {
  197 + qnx6_put_page(page);
  198 + return 0;
  199 + }
  200 + if (memcmp(name, lf->lf_fname, len) == 0) {
  201 + qnx6_put_page(page);
  202 + return fs32_to_cpu(sbi, de->de_inode);
  203 + }
  204 + qnx6_put_page(page);
  205 + return 0;
  206 +}
  207 +
  208 +/*
  209 + * check if the filename is correct.
  210 + */
  211 +static unsigned qnx6_match(struct super_block *s, int len, const char *name,
  212 + struct qnx6_dir_entry *de)
  213 +{
  214 + struct qnx6_sb_info *sbi = QNX6_SB(s);
  215 + if (memcmp(name, de->de_fname, len) == 0)
  216 + return fs32_to_cpu(sbi, de->de_inode);
  217 + return 0;
  218 +}
  219 +
  220 +
  221 +unsigned qnx6_find_entry(int len, struct inode *dir, const char *name,
  222 + struct page **res_page)
  223 +{
  224 + struct super_block *s = dir->i_sb;
  225 + struct qnx6_inode_info *ei = QNX6_I(dir);
  226 + struct page *page = NULL;
  227 + unsigned long start, n;
  228 + unsigned long npages = dir_pages(dir);
  229 + unsigned ino;
  230 + struct qnx6_dir_entry *de;
  231 + struct qnx6_long_dir_entry *lde;
  232 +
  233 + *res_page = NULL;
  234 +
  235 + if (npages == 0)
  236 + return 0;
  237 + start = ei->i_dir_start_lookup;
  238 + if (start >= npages)
  239 + start = 0;
  240 + n = start;
  241 +
  242 + do {
  243 + page = qnx6_get_page(dir, n);
  244 + if (!IS_ERR(page)) {
  245 + int limit = last_entry(dir, n);
  246 + int i;
  247 +
  248 + de = (struct qnx6_dir_entry *)page_address(page);
  249 + for (i = 0; i < limit; i++, de++) {
  250 + if (len <= QNX6_SHORT_NAME_MAX) {
  251 + /* short filename */
  252 + if (len != de->de_size)
  253 + continue;
  254 + ino = qnx6_match(s, len, name, de);
  255 + if (ino)
  256 + goto found;
  257 + } else if (de->de_size == 0xff) {
  258 + /* deal with long filename */
  259 + lde = (struct qnx6_long_dir_entry *)de;
  260 + ino = qnx6_long_match(len,
  261 + name, lde, dir);
  262 + if (ino)
  263 + goto found;
  264 + } else
  265 + printk(KERN_ERR "qnx6: undefined "
  266 + "filename size in inode.\n");
  267 + }
  268 + qnx6_put_page(page);
  269 + }
  270 +
  271 + if (++n >= npages)
  272 + n = 0;
  273 + } while (n != start);
  274 + return 0;
  275 +
  276 +found:
  277 + *res_page = page;
  278 + ei->i_dir_start_lookup = n;
  279 + return ino;
  280 +}
  281 +
  282 +const struct file_operations qnx6_dir_operations = {
  283 + .llseek = generic_file_llseek,
  284 + .read = generic_read_dir,
  285 + .readdir = qnx6_readdir,
  286 + .fsync = generic_file_fsync,
  287 +};
  288 +
  289 +const struct inode_operations qnx6_dir_inode_operations = {
  290 + .lookup = qnx6_lookup,
  291 +};
  1 +/*
  2 + * QNX6 file system, Linux implementation.
  3 + *
  4 + * Version : 1.0.0
  5 + *
  6 + * History :
  7 + *
  8 + * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
  9 + * 16-02-2012 pagemap extension by Al Viro
  10 + *
  11 + */
  12 +
  13 +#include <linux/module.h>
  14 +#include <linux/init.h>
  15 +#include <linux/slab.h>
  16 +#include <linux/highuid.h>
  17 +#include <linux/pagemap.h>
  18 +#include <linux/buffer_head.h>
  19 +#include <linux/writeback.h>
  20 +#include <linux/statfs.h>
  21 +#include <linux/parser.h>
  22 +#include <linux/seq_file.h>
  23 +#include <linux/mount.h>
  24 +#include <linux/crc32.h>
  25 +#include <linux/mpage.h>
  26 +#include "qnx6.h"
  27 +
  28 +static const struct super_operations qnx6_sops;
  29 +
  30 +static void qnx6_put_super(struct super_block *sb);
  31 +static struct inode *qnx6_alloc_inode(struct super_block *sb);
  32 +static void qnx6_destroy_inode(struct inode *inode);
  33 +static int qnx6_remount(struct super_block *sb, int *flags, char *data);
  34 +static int qnx6_statfs(struct dentry *dentry, struct kstatfs *buf);
  35 +static int qnx6_show_options(struct seq_file *seq, struct dentry *root);
  36 +
  37 +static const struct super_operations qnx6_sops = {
  38 + .alloc_inode = qnx6_alloc_inode,
  39 + .destroy_inode = qnx6_destroy_inode,
  40 + .put_super = qnx6_put_super,
  41 + .statfs = qnx6_statfs,
  42 + .remount_fs = qnx6_remount,
  43 + .show_options = qnx6_show_options,
  44 +};
  45 +
  46 +static 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 +
  56 +static int qnx6_remount(struct super_block *sb, int *flags, char *data)
  57 +{
  58 + *flags |= MS_RDONLY;
  59 + return 0;
  60 +}
  61 +
  62 +static unsigned qnx6_get_devblock(struct super_block *sb, __fs32 block)
  63 +{
  64 + struct qnx6_sb_info *sbi = QNX6_SB(sb);
  65 + return fs32_to_cpu(sbi, block) + sbi->s_blks_off;
  66 +}
  67 +
  68 +static unsigned qnx6_block_map(struct inode *inode, unsigned iblock);
  69 +
  70 +static int qnx6_get_block(struct inode *inode, sector_t iblock,
  71 + struct buffer_head *bh, int create)
  72 +{
  73 + unsigned phys;
  74 +
  75 + QNX6DEBUG((KERN_INFO "qnx6: qnx6_get_block inode=[%ld] iblock=[%ld]\n",
  76 + inode->i_ino, (unsigned long)iblock));
  77 +
  78 + phys = qnx6_block_map(inode, iblock);
  79 + if (phys) {
  80 + /* logical block is before EOF */
  81 + map_bh(bh, inode->i_sb, phys);
  82 + }
  83 + return 0;
  84 +}
  85 +
  86 +static int qnx6_check_blockptr(__fs32 ptr)
  87 +{
  88 + if (ptr == ~(__fs32)0) {
  89 + printk(KERN_ERR "qnx6: hit unused blockpointer.\n");
  90 + return 0;
  91 + }
  92 + return 1;
  93 +}
  94 +
  95 +static int qnx6_readpage(struct file *file, struct page *page)
  96 +{
  97 + return mpage_readpage(page, qnx6_get_block);
  98 +}
  99 +
  100 +static int qnx6_readpages(struct file *file, struct address_space *mapping,
  101 + struct list_head *pages, unsigned nr_pages)
  102 +{
  103 + return mpage_readpages(mapping, pages, nr_pages, qnx6_get_block);
  104 +}
  105 +
  106 +/*
  107 + * returns the block number for the no-th element in the tree
  108 + * inodebits requred as there are multiple inodes in one inode block
  109 + */
  110 +static unsigned qnx6_block_map(struct inode *inode, unsigned no)
  111 +{
  112 + struct super_block *s = inode->i_sb;
  113 + struct qnx6_sb_info *sbi = QNX6_SB(s);
  114 + struct qnx6_inode_info *ei = QNX6_I(inode);
  115 + unsigned block = 0;
  116 + struct buffer_head *bh;
  117 + __fs32 ptr;
  118 + int levelptr;
  119 + int ptrbits = sbi->s_ptrbits;
  120 + int bitdelta;
  121 + u32 mask = (1 << ptrbits) - 1;
  122 + int depth = ei->di_filelevels;
  123 + int i;
  124 +
  125 + bitdelta = ptrbits * depth;
  126 + levelptr = no >> bitdelta;
  127 +
  128 + if (levelptr > QNX6_NO_DIRECT_POINTERS - 1) {
  129 + printk(KERN_ERR "qnx6:Requested file block number (%u) too big.",
  130 + no);
  131 + return 0;
  132 + }
  133 +
  134 + block = qnx6_get_devblock(s, ei->di_block_ptr[levelptr]);
  135 +
  136 + for (i = 0; i < depth; i++) {
  137 + bh = sb_bread(s, block);
  138 + if (!bh) {
  139 + printk(KERN_ERR "qnx6:Error reading block (%u)\n",
  140 + 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 +
  156 +static 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.val[0] = (u32)id;
  171 + buf->f_fsid.val[1] = (u32)(id >> 32);
  172 +
  173 + return 0;
  174 +}
  175 +
  176 +/*
  177 + * Check the root directory of the filesystem to make sure
  178 + * it really _is_ a qnx6 filesystem, and to check the size
  179 + * of the directory entry.
  180 + */
  181 +static const char *qnx6_checkroot(struct super_block *s)
  182 +{
  183 + static char match_root[2][3] = {".\0\0", "..\0"};
  184 + int i, error = 0;
  185 + struct qnx6_dir_entry *dir_entry;
  186 + struct inode *root = s->s_root->d_inode;
  187 + struct address_space *mapping = root->i_mapping;
  188 + struct page *page = read_mapping_page(mapping, 0, NULL);
  189 + if (IS_ERR(page))
  190 + return "error reading root directory";
  191 + kmap(page);
  192 + dir_entry = page_address(page);
  193 + for (i = 0; i < 2; i++) {
  194 + /* maximum 3 bytes - due to match_root limitation */
  195 + if (strncmp(dir_entry[i].de_fname, match_root[i], 3))
  196 + error = 1;
  197 + }
  198 + qnx6_put_page(page);
  199 + if (error)
  200 + return "error reading root directory.";
  201 + return NULL;
  202 +}
  203 +
  204 +#ifdef CONFIG_QNX6FS_DEBUG
  205 +void qnx6_superblock_debug(struct qnx6_super_block *sb, struct super_block *s)
  206 +{
  207 + struct qnx6_sb_info *sbi = QNX6_SB(s);
  208 +
  209 + QNX6DEBUG((KERN_INFO "magic: %08x\n",
  210 + fs32_to_cpu(sbi, sb->sb_magic)));
  211 + QNX6DEBUG((KERN_INFO "checksum: %08x\n",
  212 + fs32_to_cpu(sbi, sb->sb_checksum)));
  213 + QNX6DEBUG((KERN_INFO "serial: %llx\n",
  214 + fs64_to_cpu(sbi, sb->sb_serial)));
  215 + QNX6DEBUG((KERN_INFO "flags: %08x\n",
  216 + fs32_to_cpu(sbi, sb->sb_flags)));
  217 + QNX6DEBUG((KERN_INFO "blocksize: %08x\n",
  218 + fs32_to_cpu(sbi, sb->sb_blocksize)));
  219 + QNX6DEBUG((KERN_INFO "num_inodes: %08x\n",
  220 + fs32_to_cpu(sbi, sb->sb_num_inodes)));
  221 + QNX6DEBUG((KERN_INFO "free_inodes: %08x\n",
  222 + fs32_to_cpu(sbi, sb->sb_free_inodes)));
  223 + QNX6DEBUG((KERN_INFO "num_blocks: %08x\n",
  224 + fs32_to_cpu(sbi, sb->sb_num_blocks)));
  225 + QNX6DEBUG((KERN_INFO "free_blocks: %08x\n",
  226 + fs32_to_cpu(sbi, sb->sb_free_blocks)));
  227 + QNX6DEBUG((KERN_INFO "inode_levels: %02x\n",
  228 + sb->Inode.levels));
  229 +}
  230 +#endif
  231 +
  232 +enum {
  233 + Opt_mmifs,
  234 + Opt_err
  235 +};
  236 +
  237 +static const match_table_t tokens = {
  238 + {Opt_mmifs, "mmi_fs"},
  239 + {Opt_err, NULL}
  240 +};
  241 +
  242 +static int qnx6_parse_options(char *options, struct super_block *sb)
  243 +{
  244 + char *p;
  245 + struct qnx6_sb_info *sbi = QNX6_SB(sb);
  246 + substring_t args[MAX_OPT_ARGS];
  247 +
  248 + if (!options)
  249 + return 1;
  250 +
  251 + while ((p = strsep(&options, ",")) != NULL) {
  252 + int token;
  253 + if (!*p)
  254 + continue;
  255 +
  256 + token = match_token(p, tokens, args);
  257 + switch (token) {
  258 + case Opt_mmifs:
  259 + set_opt(sbi->s_mount_opt, MMI_FS);
  260 + break;
  261 + default:
  262 + return 0;
  263 + }
  264 + }
  265 + return 1;
  266 +}
  267 +
  268 +static struct buffer_head *qnx6_check_first_superblock(struct super_block *s,
  269 + int offset, int silent)
  270 +{
  271 + struct qnx6_sb_info *sbi = QNX6_SB(s);
  272 + struct buffer_head *bh;
  273 + struct qnx6_super_block *sb;
  274 +
  275 + /* Check the superblock signatures
  276 + start with the first superblock */
  277 + bh = sb_bread(s, offset);
  278 + if (!bh) {
  279 + printk(KERN_ERR "qnx6: unable to read the first superblock\n");
  280 + return NULL;
  281 + }
  282 + sb = (struct qnx6_super_block *)bh->b_data;
  283 + if (fs32_to_cpu(sbi, sb->sb_magic) != QNX6_SUPER_MAGIC) {
  284 + sbi->s_bytesex = BYTESEX_BE;
  285 + if (fs32_to_cpu(sbi, sb->sb_magic) == QNX6_SUPER_MAGIC) {
  286 + /* we got a big endian fs */
  287 + QNX6DEBUG((KERN_INFO "qnx6: fs got different"
  288 + " endianess.\n"));
  289 + return bh;
  290 + } else
  291 + sbi->s_bytesex = BYTESEX_LE;
  292 + if (!silent) {
  293 + if (offset == 0) {
  294 + printk(KERN_ERR "qnx6: wrong signature (magic)"
  295 + " in superblock #1.\n");
  296 + } else {
  297 + printk(KERN_INFO "qnx6: wrong signature (magic)"
  298 + " at position (0x%lx) - will try"
  299 + " alternative position (0x0000).\n",
  300 + offset * s->s_blocksize);
  301 + }
  302 + }
  303 + brelse(bh);
  304 + return NULL;
  305 + }
  306 + return bh;
  307 +}
  308 +
  309 +static struct inode *qnx6_private_inode(struct super_block *s,
  310 + struct qnx6_root_node *p);
  311 +
  312 +static int qnx6_fill_super(struct super_block *s, void *data, int silent)
  313 +{
  314 + struct buffer_head *bh1 = NULL, *bh2 = NULL;
  315 + struct qnx6_super_block *sb1 = NULL, *sb2 = NULL;
  316 + struct qnx6_sb_info *sbi;
  317 + struct inode *root;
  318 + const char *errmsg;
  319 + struct qnx6_sb_info *qs;
  320 + int ret = -EINVAL;
  321 + u64 offset;
  322 + int bootblock_offset = QNX6_BOOTBLOCK_SIZE;
  323 +
  324 + qs = kzalloc(sizeof(struct qnx6_sb_info), GFP_KERNEL);
  325 + if (!qs)
  326 + return -ENOMEM;
  327 + s->s_fs_info = qs;
  328 +
  329 + /* Superblock always is 512 Byte long */
  330 + if (!sb_set_blocksize(s, QNX6_SUPERBLOCK_SIZE)) {
  331 + printk(KERN_ERR "qnx6: unable to set blocksize\n");
  332 + goto outnobh;
  333 + }
  334 +
  335 + /* parse the mount-options */
  336 + if (!qnx6_parse_options((char *) data, s)) {
  337 + printk(KERN_ERR "qnx6: invalid mount options.\n");
  338 + goto outnobh;
  339 + }
  340 + if (test_opt(s, MMI_FS)) {
  341 + sb1 = qnx6_mmi_fill_super(s, silent);
  342 + if (sb1)
  343 + goto mmi_success;
  344 + else
  345 + goto outnobh;
  346 + }
  347 + sbi = QNX6_SB(s);
  348 + sbi->s_bytesex = BYTESEX_LE;
  349 + /* Check the superblock signatures
  350 + start with the first superblock */
  351 + bh1 = qnx6_check_first_superblock(s,
  352 + bootblock_offset / QNX6_SUPERBLOCK_SIZE, silent);
  353 + if (!bh1) {
  354 + /* try again without bootblock offset */
  355 + bh1 = qnx6_check_first_superblock(s, 0, silent);
  356 + if (!bh1) {
  357 + printk(KERN_ERR "qnx6: unable to read the first superblock\n");
  358 + goto outnobh;
  359 + }
  360 + /* seems that no bootblock at partition start */
  361 + bootblock_offset = 0;
  362 + }
  363 + sb1 = (struct qnx6_super_block *)bh1->b_data;
  364 +
  365 +#ifdef CONFIG_QNX6FS_DEBUG
  366 + qnx6_superblock_debug(sb1, s);
  367 +#endif
  368 +
  369 + /* checksum check - start at byte 8 and end at byte 512 */
  370 + if (fs32_to_cpu(sbi, sb1->sb_checksum) !=
  371 + crc32_be(0, (char *)(bh1->b_data + 8), 504)) {
  372 + printk(KERN_ERR "qnx6: superblock #1 checksum error\n");
  373 + goto out;
  374 + }
  375 +
  376 + /* set new blocksize */
  377 + if (!sb_set_blocksize(s, fs32_to_cpu(sbi, sb1->sb_blocksize))) {
  378 + printk(KERN_ERR "qnx6: unable to set blocksize\n");
  379 + goto out;
  380 + }
  381 + /* blocksize invalidates bh - pull it back in */
  382 + brelse(bh1);
  383 + bh1 = sb_bread(s, bootblock_offset >> s->s_blocksize_bits);
  384 + if (!bh1)
  385 + goto outnobh;
  386 + sb1 = (struct qnx6_super_block *)bh1->b_data;
  387 +
  388 + /* calculate second superblock blocknumber */
  389 + offset = fs32_to_cpu(sbi, sb1->sb_num_blocks) +
  390 + (bootblock_offset >> s->s_blocksize_bits) +
  391 + (QNX6_SUPERBLOCK_AREA >> s->s_blocksize_bits);
  392 +
  393 + /* set bootblock offset */
  394 + sbi->s_blks_off = (bootblock_offset >> s->s_blocksize_bits) +
  395 + (QNX6_SUPERBLOCK_AREA >> s->s_blocksize_bits);
  396 +
  397 + /* next the second superblock */
  398 + bh2 = sb_bread(s, offset);
  399 + if (!bh2) {
  400 + printk(KERN_ERR "qnx6: unable to read the second superblock\n");
  401 + goto out;
  402 + }
  403 + sb2 = (struct qnx6_super_block *)bh2->b_data;
  404 + if (fs32_to_cpu(sbi, sb2->sb_magic) != QNX6_SUPER_MAGIC) {
  405 + if (!silent)
  406 + printk(KERN_ERR "qnx6: wrong signature (magic)"
  407 + " in superblock #2.\n");
  408 + goto out;
  409 + }
  410 +
  411 + /* checksum check - start at byte 8 and end at byte 512 */
  412 + if (fs32_to_cpu(sbi, sb2->sb_checksum) !=
  413 + crc32_be(0, (char *)(bh2->b_data + 8), 504)) {
  414 + printk(KERN_ERR "qnx6: superblock #2 checksum error\n");
  415 + goto out;
  416 + }
  417 +
  418 + if (fs64_to_cpu(sbi, sb1->sb_serial) >=
  419 + fs64_to_cpu(sbi, sb2->sb_serial)) {
  420 + /* superblock #1 active */
  421 + sbi->sb_buf = bh1;
  422 + sbi->sb = (struct qnx6_super_block *)bh1->b_data;
  423 + brelse(bh2);
  424 + printk(KERN_INFO "qnx6: superblock #1 active\n");
  425 + } else {
  426 + /* superblock #2 active */
  427 + sbi->sb_buf = bh2;
  428 + sbi->sb = (struct qnx6_super_block *)bh2->b_data;
  429 + brelse(bh1);
  430 + printk(KERN_INFO "qnx6: superblock #2 active\n");
  431 + }
  432 +mmi_success:
  433 + /* sanity check - limit maximum indirect pointer levels */
  434 + if (sb1->Inode.levels > QNX6_PTR_MAX_LEVELS) {
  435 + printk(KERN_ERR "qnx6: too many inode levels (max %i, sb %i)\n",
  436 + QNX6_PTR_MAX_LEVELS, sb1->Inode.levels);
  437 + goto out;
  438 + }
  439 + if (sb1->Longfile.levels > QNX6_PTR_MAX_LEVELS) {
  440 + printk(KERN_ERR "qnx6: too many longfilename levels"
  441 + " (max %i, sb %i)\n",
  442 + QNX6_PTR_MAX_LEVELS, sb1->Longfile.levels);
  443 + goto out;
  444 + }
  445 + s->s_op = &qnx6_sops;
  446 + s->s_magic = QNX6_SUPER_MAGIC;
  447 + s->s_flags |= MS_RDONLY; /* Yup, read-only yet */
  448 +
  449 + /* ease the later tree level calculations */
  450 + sbi = QNX6_SB(s);
  451 + sbi->s_ptrbits = ilog2(s->s_blocksize / 4);
  452 + sbi->inodes = qnx6_private_inode(s, &sb1->Inode);
  453 + if (!sbi->inodes)
  454 + goto out;
  455 + sbi->longfile = qnx6_private_inode(s, &sb1->Longfile);
  456 + if (!sbi->longfile)
  457 + goto out1;
  458 +
  459 + /* prefetch root inode */
  460 + root = qnx6_iget(s, QNX6_ROOT_INO);
  461 + if (IS_ERR(root)) {
  462 + printk(KERN_ERR "qnx6: get inode failed\n");
  463 + ret = PTR_ERR(root);
  464 + goto out2;
  465 + }
  466 +
  467 + ret = -ENOMEM;
  468 + s->s_root = d_make_root(root);
  469 + if (!s->s_root)
  470 + goto out2;
  471 +
  472 + ret = -EINVAL;
  473 + errmsg = qnx6_checkroot(s);
  474 + if (errmsg != NULL) {
  475 + if (!silent)
  476 + printk(KERN_ERR "qnx6: %s\n", errmsg);
  477 + goto out3;
  478 + }
  479 + return 0;
  480 +
  481 +out3:
  482 + dput(s->s_root);
  483 + s->s_root = NULL;
  484 +out2:
  485 + iput(sbi->longfile);
  486 +out1:
  487 + iput(sbi->inodes);
  488 +out:
  489 + if (bh1)
  490 + brelse(bh1);
  491 + if (bh2)
  492 + brelse(bh2);
  493 +outnobh:
  494 + kfree(qs);
  495 + s->s_fs_info = NULL;
  496 + return ret;
  497 +}
  498 +
  499 +static void qnx6_put_super(struct super_block *sb)
  500 +{
  501 + struct qnx6_sb_info *qs = QNX6_SB(sb);
  502 + brelse(qs->sb_buf);
  503 + iput(qs->longfile);
  504 + iput(qs->inodes);
  505 + kfree(qs);
  506 + sb->s_fs_info = NULL;
  507 + return;
  508 +}
  509 +
  510 +static sector_t qnx6_bmap(struct address_space *mapping, sector_t block)
  511 +{
  512 + return generic_block_bmap(mapping, block, qnx6_get_block);
  513 +}
  514 +static const struct address_space_operations qnx6_aops = {
  515 + .readpage = qnx6_readpage,
  516 + .readpages = qnx6_readpages,
  517 + .bmap = qnx6_bmap
  518 +};
  519 +
  520 +static struct inode *qnx6_private_inode(struct super_block *s,
  521 + struct qnx6_root_node *p)
  522 +{
  523 + struct inode *inode = new_inode(s);
  524 + if (inode) {
  525 + struct qnx6_inode_info *ei = QNX6_I(inode);
  526 + struct qnx6_sb_info *sbi = QNX6_SB(s);
  527 + inode->i_size = fs64_to_cpu(sbi, p->size);
  528 + memcpy(ei->di_block_ptr, p->ptr, sizeof(p->ptr));
  529 + ei->di_filelevels = p->levels;
  530 + inode->i_mode = S_IFREG | S_IRUSR; /* probably wrong */
  531 + inode->i_mapping->a_ops = &qnx6_aops;
  532 + }
  533 + return inode;
  534 +}
  535 +
  536 +struct inode *qnx6_iget(struct super_block *sb, unsigned ino)
  537 +{
  538 + struct qnx6_sb_info *sbi = QNX6_SB(sb);
  539 + struct qnx6_inode_entry *raw_inode;
  540 + struct inode *inode;
  541 + struct qnx6_inode_info *ei;
  542 + struct address_space *mapping;
  543 + struct page *page;
  544 + u32 n, offs;
  545 +
  546 + inode = iget_locked(sb, ino);
  547 + if (!inode)
  548 + return ERR_PTR(-ENOMEM);
  549 + if (!(inode->i_state & I_NEW))
  550 + return inode;
  551 +
  552 + ei = QNX6_I(inode);
  553 +
  554 + inode->i_mode = 0;
  555 +
  556 + if (ino == 0) {
  557 + printk(KERN_ERR "qnx6: bad inode number on dev %s: %u is "
  558 + "out of range\n",
  559 + sb->s_id, ino);
  560 + iget_failed(inode);
  561 + return ERR_PTR(-EIO);
  562 + }
  563 + n = (ino - 1) >> (PAGE_CACHE_SHIFT - QNX6_INODE_SIZE_BITS);
  564 + offs = (ino - 1) & (~PAGE_CACHE_MASK >> QNX6_INODE_SIZE_BITS);
  565 + mapping = sbi->inodes->i_mapping;
  566 + page = read_mapping_page(mapping, n, NULL);
  567 + if (IS_ERR(page)) {
  568 + printk(KERN_ERR "qnx6: major problem: unable to read inode from "
  569 + "dev %s\n", sb->s_id);
  570 + iget_failed(inode);
  571 + return ERR_CAST(page);
  572 + }
  573 + kmap(page);
  574 + raw_inode = ((struct qnx6_inode_entry *)page_address(page)) + offs;
  575 +
  576 + inode->i_mode = fs16_to_cpu(sbi, raw_inode->di_mode);
  577 + inode->i_uid = (uid_t)fs32_to_cpu(sbi, raw_inode->di_uid);
  578 + inode->i_gid = (gid_t)fs32_to_cpu(sbi, raw_inode->di_gid);
  579 + inode->i_size = fs64_to_cpu(sbi, raw_inode->di_size);
  580 + inode->i_mtime.tv_sec = fs32_to_cpu(sbi, raw_inode->di_mtime);
  581 + inode->i_mtime.tv_nsec = 0;
  582 + inode->i_atime.tv_sec = fs32_to_cpu(sbi, raw_inode->di_atime);
  583 + inode->i_atime.tv_nsec = 0;
  584 + inode->i_ctime.tv_sec = fs32_to_cpu(sbi, raw_inode->di_ctime);
  585 + inode->i_ctime.tv_nsec = 0;
  586 +
  587 + /* calc blocks based on 512 byte blocksize */
  588 + inode->i_blocks = (inode->i_size + 511) >> 9;
  589 +
  590 + memcpy(&ei->di_block_ptr, &raw_inode->di_block_ptr,
  591 + sizeof(raw_inode->di_block_ptr));
  592 + ei->di_filelevels = raw_inode->di_filelevels;
  593 +
  594 + if (S_ISREG(inode->i_mode)) {
  595 + inode->i_fop = &generic_ro_fops;
  596 + inode->i_mapping->a_ops = &qnx6_aops;
  597 + } else if (S_ISDIR(inode->i_mode)) {
  598 + inode->i_op = &qnx6_dir_inode_operations;
  599 + inode->i_fop = &qnx6_dir_operations;
  600 + inode->i_mapping->a_ops = &qnx6_aops;
  601 + } else if (S_ISLNK(inode->i_mode)) {
  602 + inode->i_op = &page_symlink_inode_operations;
  603 + inode->i_mapping->a_ops = &qnx6_aops;
  604 + } else
  605 + init_special_inode(inode, inode->i_mode, 0);
  606 + qnx6_put_page(page);
  607 + unlock_new_inode(inode);
  608 + return inode;
  609 +}
  610 +
  611 +static struct kmem_cache *qnx6_inode_cachep;
  612 +
  613 +static struct inode *qnx6_alloc_inode(struct super_block *sb)
  614 +{
  615 + struct qnx6_inode_info *ei;
  616 + ei = kmem_cache_alloc(qnx6_inode_cachep, GFP_KERNEL);
  617 + if (!ei)
  618 + return NULL;
  619 + return &ei->vfs_inode;
  620 +}
  621 +
  622 +static void qnx6_i_callback(struct rcu_head *head)
  623 +{
  624 + struct inode *inode = container_of(head, struct inode, i_rcu);
  625 + INIT_LIST_HEAD(&inode->i_dentry);
  626 + kmem_cache_free(qnx6_inode_cachep, QNX6_I(inode));
  627 +}
  628 +
  629 +static void qnx6_destroy_inode(struct inode *inode)
  630 +{
  631 + call_rcu(&inode->i_rcu, qnx6_i_callback);
  632 +}
  633 +
  634 +static void init_once(void *foo)
  635 +{
  636 + struct qnx6_inode_info *ei = (struct qnx6_inode_info *) foo;
  637 +
  638 + inode_init_once(&ei->vfs_inode);
  639 +}
  640 +
  641 +static int init_inodecache(void)
  642 +{
  643 + qnx6_inode_cachep = kmem_cache_create("qnx6_inode_cache",
  644 + sizeof(struct qnx6_inode_info),
  645 + 0, (SLAB_RECLAIM_ACCOUNT|
  646 + SLAB_MEM_SPREAD),
  647 + init_once);
  648 + if (!qnx6_inode_cachep)
  649 + return -ENOMEM;
  650 + return 0;
  651 +}
  652 +
  653 +static void destroy_inodecache(void)
  654 +{
  655 + kmem_cache_destroy(qnx6_inode_cachep);
  656 +}
  657 +
  658 +static struct dentry *qnx6_mount(struct file_system_type *fs_type,
  659 + int flags, const char *dev_name, void *data)
  660 +{
  661 + return mount_bdev(fs_type, flags, dev_name, data, qnx6_fill_super);
  662 +}
  663 +
  664 +static struct file_system_type qnx6_fs_type = {
  665 + .owner = THIS_MODULE,
  666 + .name = "qnx6",
  667 + .mount = qnx6_mount,
  668 + .kill_sb = kill_block_super,
  669 + .fs_flags = FS_REQUIRES_DEV,
  670 +};
  671 +
  672 +static int __init init_qnx6_fs(void)
  673 +{
  674 + int err;
  675 +
  676 + err = init_inodecache();
  677 + if (err)
  678 + return err;
  679 +
  680 + err = register_filesystem(&qnx6_fs_type);
  681 + if (err) {
  682 + destroy_inodecache();
  683 + return err;
  684 + }
  685 +
  686 + printk(KERN_INFO "QNX6 filesystem 1.0.0 registered.\n");
  687 + return 0;
  688 +}
  689 +
  690 +static void __exit exit_qnx6_fs(void)
  691 +{
  692 + unregister_filesystem(&qnx6_fs_type);
  693 + destroy_inodecache();
  694 +}
  695 +
  696 +module_init(init_qnx6_fs)
  697 +module_exit(exit_qnx6_fs)
  698 +MODULE_LICENSE("GPL");
  1 +/*
  2 + * QNX6 file system, Linux implementation.
  3 + *
  4 + * Version : 1.0.0
  5 + *
  6 + * History :
  7 + *
  8 + * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
  9 + * 16-02-2012 pagemap extension by Al Viro
  10 + *
  11 + */
  12 +
  13 +#include "qnx6.h"
  14 +
  15 +struct dentry *qnx6_lookup(struct inode *dir, struct dentry *dentry,
  16 + struct nameidata *nd)
  17 +{
  18 + unsigned ino;
  19 + struct page *page;
  20 + struct inode *foundinode = NULL;
  21 + const char *name = dentry->d_name.name;
  22 + int len = dentry->d_name.len;
  23 +
  24 + if (len > QNX6_LONG_NAME_MAX)
  25 + return ERR_PTR(-ENAMETOOLONG);
  26 +
  27 + ino = qnx6_find_entry(len, dir, name, &page);
  28 + if (ino) {
  29 + foundinode = qnx6_iget(dir->i_sb, ino);
  30 + qnx6_put_page(page);
  31 + if (IS_ERR(foundinode)) {
  32 + QNX6DEBUG((KERN_ERR "qnx6: lookup->iget -> "
  33 + " error %ld\n", PTR_ERR(foundinode)));
  34 + return ERR_CAST(foundinode);
  35 + }
  36 + } else {
  37 + QNX6DEBUG((KERN_INFO "qnx6_lookup: not found %s\n", name));
  38 + return NULL;
  39 + }
  40 + d_add(dentry, foundinode);
  41 + return NULL;
  42 +}
  1 +/*
  2 + * QNX6 file system, Linux implementation.
  3 + *
  4 + * Version : 1.0.0
  5 + *
  6 + * History :
  7 + *
  8 + * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
  9 + * 16-02-2012 page map extension by Al Viro
  10 + *
  11 + */
  12 +
  13 +#include <linux/fs.h>
  14 +#include <linux/pagemap.h>
  15 +
  16 +typedef __u16 __bitwise __fs16;
  17 +typedef __u32 __bitwise __fs32;
  18 +typedef __u64 __bitwise __fs64;
  19 +
  20 +#include <linux/qnx6_fs.h>
  21 +
  22 +#ifdef CONFIG_QNX6FS_DEBUG
  23 +#define QNX6DEBUG(X) printk X
  24 +#else
  25 +#define QNX6DEBUG(X) (void) 0
  26 +#endif
  27 +
  28 +struct qnx6_sb_info {
  29 + struct buffer_head *sb_buf; /* superblock buffer */
  30 + struct qnx6_super_block *sb; /* our superblock */
  31 + int s_blks_off; /* blkoffset fs-startpoint */
  32 + int s_ptrbits; /* indirect pointer bitfield */
  33 + unsigned long s_mount_opt; /* all mount options */
  34 + int s_bytesex; /* holds endianess info */
  35 + struct inode * inodes;
  36 + struct inode * longfile;
  37 +};
  38 +
  39 +struct qnx6_inode_info {
  40 + __fs32 di_block_ptr[QNX6_NO_DIRECT_POINTERS];
  41 + __u8 di_filelevels;
  42 + __u32 i_dir_start_lookup;
  43 + struct inode vfs_inode;
  44 +};
  45 +
  46 +extern struct inode *qnx6_iget(struct super_block *sb, unsigned ino);
  47 +extern struct dentry *qnx6_lookup(struct inode *dir, struct dentry *dentry,
  48 + struct nameidata *nd);
  49 +
  50 +#ifdef CONFIG_QNX6FS_DEBUG
  51 +extern void qnx6_superblock_debug(struct qnx6_super_block *,
  52 + struct super_block *);
  53 +#endif
  54 +
  55 +extern const struct inode_operations qnx6_dir_inode_operations;
  56 +extern const struct file_operations qnx6_dir_operations;
  57 +
  58 +static inline struct qnx6_sb_info *QNX6_SB(struct super_block *sb)
  59 +{
  60 + return sb->s_fs_info;
  61 +}
  62 +
  63 +static inline struct qnx6_inode_info *QNX6_I(struct inode *inode)
  64 +{
  65 + return container_of(inode, struct qnx6_inode_info, vfs_inode);
  66 +}
  67 +
  68 +#define clear_opt(o, opt) (o &= ~(QNX6_MOUNT_##opt))
  69 +#define set_opt(o, opt) (o |= (QNX6_MOUNT_##opt))
  70 +#define test_opt(sb, opt) (QNX6_SB(sb)->s_mount_opt & \
  71 + QNX6_MOUNT_##opt)
  72 +enum {
  73 + BYTESEX_LE,
  74 + BYTESEX_BE,
  75 +};
  76 +
  77 +static inline __u64 fs64_to_cpu(struct qnx6_sb_info *sbi, __fs64 n)
  78 +{
  79 + if (sbi->s_bytesex == BYTESEX_LE)
  80 + return le64_to_cpu((__force __le64)n);
  81 + else
  82 + return be64_to_cpu((__force __be64)n);
  83 +}
  84 +
  85 +static inline __fs64 cpu_to_fs64(struct qnx6_sb_info *sbi, __u64 n)
  86 +{
  87 + if (sbi->s_bytesex == BYTESEX_LE)
  88 + return (__force __fs64)cpu_to_le64(n);
  89 + else
  90 + return (__force __fs64)cpu_to_be64(n);
  91 +}
  92 +
  93 +static inline __u32 fs32_to_cpu(struct qnx6_sb_info *sbi, __fs32 n)
  94 +{
  95 + if (sbi->s_bytesex == BYTESEX_LE)
  96 + return le32_to_cpu((__force __le32)n);
  97 + else
  98 + return be32_to_cpu((__force __be32)n);
  99 +}
  100 +
  101 +static inline __fs32 cpu_to_fs32(struct qnx6_sb_info *sbi, __u32 n)
  102 +{
  103 + if (sbi->s_bytesex == BYTESEX_LE)
  104 + return (__force __fs32)cpu_to_le32(n);
  105 + else
  106 + return (__force __fs32)cpu_to_be32(n);
  107 +}
  108 +
  109 +static inline __u16 fs16_to_cpu(struct qnx6_sb_info *sbi, __fs16 n)
  110 +{
  111 + if (sbi->s_bytesex == BYTESEX_LE)
  112 + return le16_to_cpu((__force __le16)n);
  113 + else
  114 + return be16_to_cpu((__force __be16)n);
  115 +}
  116 +
  117 +static inline __fs16 cpu_to_fs16(struct qnx6_sb_info *sbi, __u16 n)
  118 +{
  119 + if (sbi->s_bytesex == BYTESEX_LE)
  120 + return (__force __fs16)cpu_to_le16(n);
  121 + else
  122 + return (__force __fs16)cpu_to_be16(n);
  123 +}
  124 +
  125 +extern struct qnx6_super_block *qnx6_mmi_fill_super(struct super_block *s,
  126 + int silent);
  127 +
  128 +static inline void qnx6_put_page(struct page *page)
  129 +{
  130 + kunmap(page);
  131 + page_cache_release(page);
  132 +}
  133 +
  134 +extern unsigned qnx6_find_entry(int len, struct inode *dir, const char *name,
  135 + struct page **res_page);
  1 +/*
  2 + * QNX6 file system, Linux implementation.
  3 + *
  4 + * Version : 1.0.0
  5 + *
  6 + * History :
  7 + *
  8 + * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
  9 + *
  10 + */
  11 +
  12 +#include <linux/buffer_head.h>
  13 +#include <linux/slab.h>
  14 +#include <linux/crc32.h>
  15 +#include "qnx6.h"
  16 +
  17 +static void qnx6_mmi_copy_sb(struct qnx6_super_block *qsb,
  18 + struct qnx6_mmi_super_block *sb)
  19 +{
  20 + qsb->sb_magic = sb->sb_magic;
  21 + qsb->sb_checksum = sb->sb_checksum;
  22 + qsb->sb_serial = sb->sb_serial;
  23 + qsb->sb_blocksize = sb->sb_blocksize;
  24 + qsb->sb_num_inodes = sb->sb_num_inodes;
  25 + qsb->sb_free_inodes = sb->sb_free_inodes;
  26 + qsb->sb_num_blocks = sb->sb_num_blocks;
  27 + qsb->sb_free_blocks = sb->sb_free_blocks;
  28 +
  29 + /* the rest of the superblock is the same */
  30 + memcpy(&qsb->Inode, &sb->Inode, sizeof(sb->Inode));
  31 + memcpy(&qsb->Bitmap, &sb->Bitmap, sizeof(sb->Bitmap));
  32 + memcpy(&qsb->Longfile, &sb->Longfile, sizeof(sb->Longfile));
  33 +}
  34 +
  35 +struct qnx6_super_block *qnx6_mmi_fill_super(struct super_block *s, int silent)
  36 +{
  37 + struct buffer_head *bh1, *bh2 = NULL;
  38 + struct qnx6_mmi_super_block *sb1, *sb2;
  39 + struct qnx6_super_block *qsb = NULL;
  40 + struct qnx6_sb_info *sbi;
  41 + __u64 offset;
  42 +
  43 + /* Check the superblock signatures
  44 + start with the first superblock */
  45 + bh1 = sb_bread(s, 0);
  46 + if (!bh1) {
  47 + printk(KERN_ERR "qnx6: Unable to read first mmi superblock\n");
  48 + return NULL;
  49 + }
  50 + sb1 = (struct qnx6_mmi_super_block *)bh1->b_data;
  51 + sbi = QNX6_SB(s);
  52 + if (fs32_to_cpu(sbi, sb1->sb_magic) != QNX6_SUPER_MAGIC) {
  53 + if (!silent) {
  54 + printk(KERN_ERR "qnx6: wrong signature (magic) in"
  55 + " superblock #1.\n");
  56 + goto out;
  57 + }
  58 + }
  59 +
  60 + /* checksum check - start at byte 8 and end at byte 512 */
  61 + if (fs32_to_cpu(sbi, sb1->sb_checksum) !=
  62 + crc32_be(0, (char *)(bh1->b_data + 8), 504)) {
  63 + printk(KERN_ERR "qnx6: superblock #1 checksum error\n");
  64 + goto out;
  65 + }
  66 +
  67 + /* calculate second superblock blocknumber */
  68 + offset = fs32_to_cpu(sbi, sb1->sb_num_blocks) + QNX6_SUPERBLOCK_AREA /
  69 + fs32_to_cpu(sbi, sb1->sb_blocksize);
  70 +
  71 + /* set new blocksize */
  72 + if (!sb_set_blocksize(s, fs32_to_cpu(sbi, sb1->sb_blocksize))) {
  73 + printk(KERN_ERR "qnx6: unable to set blocksize\n");
  74 + goto out;
  75 + }
  76 + /* blocksize invalidates bh - pull it back in */
  77 + brelse(bh1);
  78 + bh1 = sb_bread(s, 0);
  79 + if (!bh1)
  80 + goto out;
  81 + sb1 = (struct qnx6_mmi_super_block *)bh1->b_data;
  82 +
  83 + /* read second superblock */
  84 + bh2 = sb_bread(s, offset);
  85 + if (!bh2) {
  86 + printk(KERN_ERR "qnx6: unable to read the second superblock\n");
  87 + goto out;
  88 + }
  89 + sb2 = (struct qnx6_mmi_super_block *)bh2->b_data;
  90 + if (fs32_to_cpu(sbi, sb2->sb_magic) != QNX6_SUPER_MAGIC) {
  91 + if (!silent)
  92 + printk(KERN_ERR "qnx6: wrong signature (magic) in"
  93 + " superblock #2.\n");
  94 + goto out;
  95 + }
  96 +
  97 + /* checksum check - start at byte 8 and end at byte 512 */
  98 + if (fs32_to_cpu(sbi, sb2->sb_checksum)
  99 + != crc32_be(0, (char *)(bh2->b_data + 8), 504)) {
  100 + printk(KERN_ERR "qnx6: superblock #1 checksum error\n");
  101 + goto out;
  102 + }
  103 +
  104 + qsb = kmalloc(sizeof(*qsb), GFP_KERNEL);
  105 + if (!qsb) {
  106 + printk(KERN_ERR "qnx6: unable to allocate memory.\n");
  107 + goto out;
  108 + }
  109 +
  110 + if (fs64_to_cpu(sbi, sb1->sb_serial) >
  111 + fs64_to_cpu(sbi, sb2->sb_serial)) {
  112 + /* superblock #1 active */
  113 + qnx6_mmi_copy_sb(qsb, sb1);
  114 +#ifdef CONFIG_QNX6FS_DEBUG
  115 + qnx6_superblock_debug(qsb, s);
  116 +#endif
  117 + memcpy(bh1->b_data, qsb, sizeof(struct qnx6_super_block));
  118 +
  119 + sbi->sb_buf = bh1;
  120 + sbi->sb = (struct qnx6_super_block *)bh1->b_data;
  121 + brelse(bh2);
  122 + printk(KERN_INFO "qnx6: superblock #1 active\n");
  123 + } else {
  124 + /* superblock #2 active */
  125 + qnx6_mmi_copy_sb(qsb, sb2);
  126 +#ifdef CONFIG_QNX6FS_DEBUG
  127 + qnx6_superblock_debug(qsb, s);
  128 +#endif
  129 + memcpy(bh2->b_data, qsb, sizeof(struct qnx6_super_block));
  130 +
  131 + sbi->sb_buf = bh2;
  132 + sbi->sb = (struct qnx6_super_block *)bh2->b_data;
  133 + brelse(bh1);
  134 + printk(KERN_INFO "qnx6: superblock #2 active\n");
  135 + }
  136 + kfree(qsb);
  137 +
  138 + /* offset for mmi_fs is just SUPERBLOCK_AREA bytes */
  139 + sbi->s_blks_off = QNX6_SUPERBLOCK_AREA / s->s_blocksize;
  140 +
  141 + /* success */
  142 + return sbi->sb;
  143 +
  144 +out:
  145 + if (bh1 != NULL)
  146 + brelse(bh1);
  147 + if (bh2 != NULL)
  148 + brelse(bh2);
  149 + return NULL;
  150 +}
include/linux/magic.h
... ... @@ -42,6 +42,7 @@
42 42 #define OPENPROM_SUPER_MAGIC 0x9fa1
43 43 #define PROC_SUPER_MAGIC 0x9fa0
44 44 #define QNX4_SUPER_MAGIC 0x002f /* qnx4 fs detection */
  45 +#define QNX6_SUPER_MAGIC 0x68191122 /* qnx6 fs detection */
45 46  
46 47 #define REISERFS_SUPER_MAGIC 0x52654973 /* used by gcc */
47 48 /* used by file system utilities that
include/linux/qnx6_fs.h
  1 +/*
  2 + * Name : qnx6_fs.h
  3 + * Author : Kai Bankett
  4 + * Function : qnx6 global filesystem definitions
  5 + * History : 17-01-2012 created
  6 + */
  7 +#ifndef _LINUX_QNX6_FS_H
  8 +#define _LINUX_QNX6_FS_H
  9 +
  10 +#include <linux/types.h>
  11 +#include <linux/magic.h>
  12 +
  13 +#define QNX6_ROOT_INO 1
  14 +
  15 +/* for di_status */
  16 +#define QNX6_FILE_DIRECTORY 0x01
  17 +#define QNX6_FILE_DELETED 0x02
  18 +#define QNX6_FILE_NORMAL 0x03
  19 +
  20 +#define QNX6_SUPERBLOCK_SIZE 0x200 /* superblock always is 512 bytes */
  21 +#define QNX6_SUPERBLOCK_AREA 0x1000 /* area reserved for superblock */
  22 +#define QNX6_BOOTBLOCK_SIZE 0x2000 /* heading bootblock area */
  23 +#define QNX6_DIR_ENTRY_SIZE 0x20 /* dir entry size of 32 bytes */
  24 +#define QNX6_INODE_SIZE 0x80 /* each inode is 128 bytes */
  25 +#define QNX6_INODE_SIZE_BITS 7 /* inode entry size shift */
  26 +
  27 +#define QNX6_NO_DIRECT_POINTERS 16 /* 16 blockptrs in sbl/inode */
  28 +#define QNX6_PTR_MAX_LEVELS 5 /* maximum indirect levels */
  29 +
  30 +/* for filenames */
  31 +#define QNX6_SHORT_NAME_MAX 27
  32 +#define QNX6_LONG_NAME_MAX 510
  33 +
  34 +/* list of mount options */
  35 +#define QNX6_MOUNT_MMI_FS 0x010000 /* mount as Audi MMI 3G fs */
  36 +
  37 +/*
  38 + * This is the original qnx6 inode layout on disk.
  39 + * Each inode is 128 byte long.
  40 + */
  41 +struct qnx6_inode_entry {
  42 + __fs64 di_size;
  43 + __fs32 di_uid;
  44 + __fs32 di_gid;
  45 + __fs32 di_ftime;
  46 + __fs32 di_mtime;
  47 + __fs32 di_atime;
  48 + __fs32 di_ctime;
  49 + __fs16 di_mode;
  50 + __fs16 di_ext_mode;
  51 + __fs32 di_block_ptr[QNX6_NO_DIRECT_POINTERS];
  52 + __u8 di_filelevels;
  53 + __u8 di_status;
  54 + __u8 di_unknown2[2];
  55 + __fs32 di_zero2[6];
  56 +};
  57 +
  58 +/*
  59 + * Each directory entry is maximum 32 bytes long.
  60 + * If more characters or special characters required it is stored
  61 + * in the longfilenames structure.
  62 + */
  63 +struct qnx6_dir_entry {
  64 + __fs32 de_inode;
  65 + __u8 de_size;
  66 + char de_fname[QNX6_SHORT_NAME_MAX];
  67 +};
  68 +
  69 +/*
  70 + * Longfilename direntries have a different structure
  71 + */
  72 +struct qnx6_long_dir_entry {
  73 + __fs32 de_inode;
  74 + __u8 de_size;
  75 + __u8 de_unknown[3];
  76 + __fs32 de_long_inode;
  77 + __fs32 de_checksum;
  78 +};
  79 +
  80 +struct qnx6_long_filename {
  81 + __fs16 lf_size;
  82 + __u8 lf_fname[QNX6_LONG_NAME_MAX];
  83 +};
  84 +
  85 +struct qnx6_root_node {
  86 + __fs64 size;
  87 + __fs32 ptr[QNX6_NO_DIRECT_POINTERS];
  88 + __u8 levels;
  89 + __u8 mode;
  90 + __u8 spare[6];
  91 +};
  92 +
  93 +struct qnx6_super_block {
  94 + __fs32 sb_magic;
  95 + __fs32 sb_checksum;
  96 + __fs64 sb_serial;
  97 + __fs32 sb_ctime; /* time the fs was created */
  98 + __fs32 sb_atime; /* last access time */
  99 + __fs32 sb_flags;
  100 + __fs16 sb_version1; /* filesystem version information */
  101 + __fs16 sb_version2; /* filesystem version information */
  102 + __u8 sb_volumeid[16];
  103 + __fs32 sb_blocksize;
  104 + __fs32 sb_num_inodes;
  105 + __fs32 sb_free_inodes;
  106 + __fs32 sb_num_blocks;
  107 + __fs32 sb_free_blocks;
  108 + __fs32 sb_allocgroup;
  109 + struct qnx6_root_node Inode;
  110 + struct qnx6_root_node Bitmap;
  111 + struct qnx6_root_node Longfile;
  112 + struct qnx6_root_node Unknown;
  113 +};
  114 +
  115 +/* Audi MMI 3G superblock layout is different to plain qnx6 */
  116 +struct qnx6_mmi_super_block {
  117 + __fs32 sb_magic;
  118 + __fs32 sb_checksum;
  119 + __fs64 sb_serial;
  120 + __u8 sb_spare0[12];
  121 + __u8 sb_id[12];
  122 + __fs32 sb_blocksize;
  123 + __fs32 sb_num_inodes;
  124 + __fs32 sb_free_inodes;
  125 + __fs32 sb_num_blocks;
  126 + __fs32 sb_free_blocks;
  127 + __u8 sb_spare1[4];
  128 + struct qnx6_root_node Inode;
  129 + struct qnx6_root_node Bitmap;
  130 + struct qnx6_root_node Longfile;
  131 + struct qnx6_root_node Unknown;
  132 +};
  133 +
  134 +#endif