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 pr_err("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 pr_err("wrong signature (magic) in superblock #1.\n"); 55 goto out; 56 } 57 } 58 59 /* checksum check - start at byte 8 and end at byte 512 */ 60 if (fs32_to_cpu(sbi, sb1->sb_checksum) != 61 crc32_be(0, (char *)(bh1->b_data + 8), 504)) { 62 pr_err("superblock #1 checksum error\n"); 63 goto out; 64 } 65 66 /* calculate second superblock blocknumber */ 67 offset = fs32_to_cpu(sbi, sb1->sb_num_blocks) + QNX6_SUPERBLOCK_AREA / 68 fs32_to_cpu(sbi, sb1->sb_blocksize); 69 70 /* set new blocksize */ 71 if (!sb_set_blocksize(s, fs32_to_cpu(sbi, sb1->sb_blocksize))) { 72 pr_err("unable to set blocksize\n"); 73 goto out; 74 } 75 /* blocksize invalidates bh - pull it back in */ 76 brelse(bh1); 77 bh1 = sb_bread(s, 0); 78 if (!bh1) 79 goto out; 80 sb1 = (struct qnx6_mmi_super_block *)bh1->b_data; 81 82 /* read second superblock */ 83 bh2 = sb_bread(s, offset); 84 if (!bh2) { 85 pr_err("unable to read the second superblock\n"); 86 goto out; 87 } 88 sb2 = (struct qnx6_mmi_super_block *)bh2->b_data; 89 if (fs32_to_cpu(sbi, sb2->sb_magic) != QNX6_SUPER_MAGIC) { 90 if (!silent) 91 pr_err("wrong signature (magic) in superblock #2.\n"); 92 goto out; 93 } 94 95 /* checksum check - start at byte 8 and end at byte 512 */ 96 if (fs32_to_cpu(sbi, sb2->sb_checksum) 97 != crc32_be(0, (char *)(bh2->b_data + 8), 504)) { 98 pr_err("superblock #1 checksum error\n"); 99 goto out; 100 } 101 102 qsb = kmalloc(sizeof(*qsb), GFP_KERNEL); 103 if (!qsb) { 104 pr_err("unable to allocate memory.\n"); 105 goto out; 106 } 107 108 if (fs64_to_cpu(sbi, sb1->sb_serial) > 109 fs64_to_cpu(sbi, sb2->sb_serial)) { 110 /* superblock #1 active */ 111 qnx6_mmi_copy_sb(qsb, sb1); 112 #ifdef CONFIG_QNX6FS_DEBUG 113 qnx6_superblock_debug(qsb, s); 114 #endif 115 memcpy(bh1->b_data, qsb, sizeof(struct qnx6_super_block)); 116 117 sbi->sb_buf = bh1; 118 sbi->sb = (struct qnx6_super_block *)bh1->b_data; 119 brelse(bh2); 120 pr_info("superblock #1 active\n"); 121 } else { 122 /* superblock #2 active */ 123 qnx6_mmi_copy_sb(qsb, sb2); 124 #ifdef CONFIG_QNX6FS_DEBUG 125 qnx6_superblock_debug(qsb, s); 126 #endif 127 memcpy(bh2->b_data, qsb, sizeof(struct qnx6_super_block)); 128 129 sbi->sb_buf = bh2; 130 sbi->sb = (struct qnx6_super_block *)bh2->b_data; 131 brelse(bh1); 132 pr_info("superblock #2 active\n"); 133 } 134 kfree(qsb); 135 136 /* offset for mmi_fs is just SUPERBLOCK_AREA bytes */ 137 sbi->s_blks_off = QNX6_SUPERBLOCK_AREA / s->s_blocksize; 138 139 /* success */ 140 return sbi->sb; 141 142 out: 143 if (bh1 != NULL) 144 brelse(bh1); 145 if (bh2 != NULL) 146 brelse(bh2); 147 return NULL; 148 } 149