Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Kai Bankett and committed by
Al Viro
5d026c72 516cdb68

+1668
+174
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.
+1
fs/Kconfig
··· 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"
+1
fs/Makefile
··· 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/
+26
fs/qnx6/Kconfig
··· 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.
+7
fs/qnx6/Makefile
··· 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
+8
fs/qnx6/README
··· 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)
+291
fs/qnx6/dir.c
··· 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 + };
+698
fs/qnx6/inode.c
··· 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");
+42
fs/qnx6/namei.c
··· 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 + }
+135
fs/qnx6/qnx6.h
··· 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);
+150
fs/qnx6/super_mmi.c
··· 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 + }
+1
include/linux/magic.h
··· 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
+134
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