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 } 151