aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hfsplus/wrapper.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/hfsplus/wrapper.c')
-rw-r--r--fs/hfsplus/wrapper.c178
1 files changed, 114 insertions, 64 deletions
diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c
index 8972c20b3216..196231794f64 100644
--- a/fs/hfsplus/wrapper.c
+++ b/fs/hfsplus/wrapper.c
@@ -24,6 +24,40 @@ struct hfsplus_wd {
24 u16 embed_count; 24 u16 embed_count;
25}; 25};
26 26
27static void hfsplus_end_io_sync(struct bio *bio, int err)
28{
29 if (err)
30 clear_bit(BIO_UPTODATE, &bio->bi_flags);
31 complete(bio->bi_private);
32}
33
34int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
35 void *data, int rw)
36{
37 DECLARE_COMPLETION_ONSTACK(wait);
38 struct bio *bio;
39
40 bio = bio_alloc(GFP_NOIO, 1);
41 bio->bi_sector = sector;
42 bio->bi_bdev = bdev;
43 bio->bi_end_io = hfsplus_end_io_sync;
44 bio->bi_private = &wait;
45
46 /*
47 * We always submit one sector at a time, so bio_add_page must not fail.
48 */
49 if (bio_add_page(bio, virt_to_page(data), HFSPLUS_SECTOR_SIZE,
50 offset_in_page(data)) != HFSPLUS_SECTOR_SIZE)
51 BUG();
52
53 submit_bio(rw, bio);
54 wait_for_completion(&wait);
55
56 if (!bio_flagged(bio, BIO_UPTODATE))
57 return -EIO;
58 return 0;
59}
60
27static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd) 61static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
28{ 62{
29 u32 extent; 63 u32 extent;
@@ -40,12 +74,14 @@ static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
40 !(attrib & HFSP_WRAP_ATTRIB_SPARED)) 74 !(attrib & HFSP_WRAP_ATTRIB_SPARED))
41 return 0; 75 return 0;
42 76
43 wd->ablk_size = be32_to_cpu(*(__be32 *)(bufptr + HFSP_WRAPOFF_ABLKSIZE)); 77 wd->ablk_size =
78 be32_to_cpu(*(__be32 *)(bufptr + HFSP_WRAPOFF_ABLKSIZE));
44 if (wd->ablk_size < HFSPLUS_SECTOR_SIZE) 79 if (wd->ablk_size < HFSPLUS_SECTOR_SIZE)
45 return 0; 80 return 0;
46 if (wd->ablk_size % HFSPLUS_SECTOR_SIZE) 81 if (wd->ablk_size % HFSPLUS_SECTOR_SIZE)
47 return 0; 82 return 0;
48 wd->ablk_start = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART)); 83 wd->ablk_start =
84 be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART));
49 85
50 extent = get_unaligned_be32(bufptr + HFSP_WRAPOFF_EMBEDEXT); 86 extent = get_unaligned_be32(bufptr + HFSP_WRAPOFF_EMBEDEXT);
51 wd->embed_start = (extent >> 16) & 0xFFFF; 87 wd->embed_start = (extent >> 16) & 0xFFFF;
@@ -68,7 +104,8 @@ static int hfsplus_get_last_session(struct super_block *sb,
68 if (HFSPLUS_SB(sb)->session >= 0) { 104 if (HFSPLUS_SB(sb)->session >= 0) {
69 te.cdte_track = HFSPLUS_SB(sb)->session; 105 te.cdte_track = HFSPLUS_SB(sb)->session;
70 te.cdte_format = CDROM_LBA; 106 te.cdte_format = CDROM_LBA;
71 res = ioctl_by_bdev(sb->s_bdev, CDROMREADTOCENTRY, (unsigned long)&te); 107 res = ioctl_by_bdev(sb->s_bdev,
108 CDROMREADTOCENTRY, (unsigned long)&te);
72 if (!res && (te.cdte_ctrl & CDROM_DATA_TRACK) == 4) { 109 if (!res && (te.cdte_ctrl & CDROM_DATA_TRACK) == 4) {
73 *start = (sector_t)te.cdte_addr.lba << 2; 110 *start = (sector_t)te.cdte_addr.lba << 2;
74 return 0; 111 return 0;
@@ -77,7 +114,8 @@ static int hfsplus_get_last_session(struct super_block *sb,
77 return -EINVAL; 114 return -EINVAL;
78 } 115 }
79 ms_info.addr_format = CDROM_LBA; 116 ms_info.addr_format = CDROM_LBA;
80 res = ioctl_by_bdev(sb->s_bdev, CDROMMULTISESSION, (unsigned long)&ms_info); 117 res = ioctl_by_bdev(sb->s_bdev, CDROMMULTISESSION,
118 (unsigned long)&ms_info);
81 if (!res && ms_info.xa_flag) 119 if (!res && ms_info.xa_flag)
82 *start = (sector_t)ms_info.addr.lba << 2; 120 *start = (sector_t)ms_info.addr.lba << 2;
83 return 0; 121 return 0;
@@ -88,100 +126,112 @@ static int hfsplus_get_last_session(struct super_block *sb,
88int hfsplus_read_wrapper(struct super_block *sb) 126int hfsplus_read_wrapper(struct super_block *sb)
89{ 127{
90 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 128 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
91 struct buffer_head *bh;
92 struct hfsplus_vh *vhdr;
93 struct hfsplus_wd wd; 129 struct hfsplus_wd wd;
94 sector_t part_start, part_size; 130 sector_t part_start, part_size;
95 u32 blocksize; 131 u32 blocksize;
132 int error = 0;
96 133
134 error = -EINVAL;
97 blocksize = sb_min_blocksize(sb, HFSPLUS_SECTOR_SIZE); 135 blocksize = sb_min_blocksize(sb, HFSPLUS_SECTOR_SIZE);
98 if (!blocksize) 136 if (!blocksize)
99 return -EINVAL; 137 goto out;
100 138
101 if (hfsplus_get_last_session(sb, &part_start, &part_size)) 139 if (hfsplus_get_last_session(sb, &part_start, &part_size))
102 return -EINVAL; 140 goto out;
103 if ((u64)part_start + part_size > 0x100000000ULL) { 141 if ((u64)part_start + part_size > 0x100000000ULL) {
104 pr_err("hfs: volumes larger than 2TB are not supported yet\n"); 142 pr_err("hfs: volumes larger than 2TB are not supported yet\n");
105 return -EINVAL; 143 goto out;
106 } 144 }
107 while (1) {
108 bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
109 if (!bh)
110 return -EIO;
111
112 if (vhdr->signature == cpu_to_be16(HFSP_WRAP_MAGIC)) {
113 if (!hfsplus_read_mdb(vhdr, &wd))
114 goto error;
115 wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT;
116 part_start += wd.ablk_start + wd.embed_start * wd.ablk_size;
117 part_size = wd.embed_count * wd.ablk_size;
118 brelse(bh);
119 bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
120 if (!bh)
121 return -EIO;
122 }
123 if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG))
124 break;
125 if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) {
126 set_bit(HFSPLUS_SB_HFSX, &sbi->flags);
127 break;
128 }
129 brelse(bh);
130 145
131 /* check for a partition block 146 error = -ENOMEM;
147 sbi->s_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
148 if (!sbi->s_vhdr)
149 goto out;
150 sbi->s_backup_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
151 if (!sbi->s_backup_vhdr)
152 goto out_free_vhdr;
153
154reread:
155 error = hfsplus_submit_bio(sb->s_bdev,
156 part_start + HFSPLUS_VOLHEAD_SECTOR,
157 sbi->s_vhdr, READ);
158 if (error)
159 goto out_free_backup_vhdr;
160
161 error = -EINVAL;
162 switch (sbi->s_vhdr->signature) {
163 case cpu_to_be16(HFSPLUS_VOLHEAD_SIGX):
164 set_bit(HFSPLUS_SB_HFSX, &sbi->flags);
165 /*FALLTHRU*/
166 case cpu_to_be16(HFSPLUS_VOLHEAD_SIG):
167 break;
168 case cpu_to_be16(HFSP_WRAP_MAGIC):
169 if (!hfsplus_read_mdb(sbi->s_vhdr, &wd))
170 goto out;
171 wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT;
172 part_start += wd.ablk_start + wd.embed_start * wd.ablk_size;
173 part_size = wd.embed_count * wd.ablk_size;
174 goto reread;
175 default:
176 /*
177 * Check for a partition block.
178 *
132 * (should do this only for cdrom/loop though) 179 * (should do this only for cdrom/loop though)
133 */ 180 */
134 if (hfs_part_find(sb, &part_start, &part_size)) 181 if (hfs_part_find(sb, &part_start, &part_size))
135 return -EINVAL; 182 goto out;
183 goto reread;
184 }
185
186 error = hfsplus_submit_bio(sb->s_bdev,
187 part_start + part_size - 2,
188 sbi->s_backup_vhdr, READ);
189 if (error)
190 goto out_free_backup_vhdr;
191
192 error = -EINVAL;
193 if (sbi->s_backup_vhdr->signature != sbi->s_vhdr->signature) {
194 printk(KERN_WARNING
195 "hfs: invalid secondary volume header\n");
196 goto out_free_backup_vhdr;
136 } 197 }
137 198
138 blocksize = be32_to_cpu(vhdr->blocksize); 199 blocksize = be32_to_cpu(sbi->s_vhdr->blocksize);
139 brelse(bh);
140 200
141 /* block size must be at least as large as a sector 201 /*
142 * and a multiple of 2 202 * Block size must be at least as large as a sector and a multiple of 2.
143 */ 203 */
144 if (blocksize < HFSPLUS_SECTOR_SIZE || 204 if (blocksize < HFSPLUS_SECTOR_SIZE || ((blocksize - 1) & blocksize))
145 ((blocksize - 1) & blocksize)) 205 goto out_free_backup_vhdr;
146 return -EINVAL;
147 sbi->alloc_blksz = blocksize; 206 sbi->alloc_blksz = blocksize;
148 sbi->alloc_blksz_shift = 0; 207 sbi->alloc_blksz_shift = 0;
149 while ((blocksize >>= 1) != 0) 208 while ((blocksize >>= 1) != 0)
150 sbi->alloc_blksz_shift++; 209 sbi->alloc_blksz_shift++;
151 blocksize = min(sbi->alloc_blksz, (u32)PAGE_SIZE); 210 blocksize = min(sbi->alloc_blksz, (u32)PAGE_SIZE);
152 211
153 /* align block size to block offset */ 212 /*
213 * Align block size to block offset.
214 */
154 while (part_start & ((blocksize >> HFSPLUS_SECTOR_SHIFT) - 1)) 215 while (part_start & ((blocksize >> HFSPLUS_SECTOR_SHIFT) - 1))
155 blocksize >>= 1; 216 blocksize >>= 1;
156 217
157 if (sb_set_blocksize(sb, blocksize) != blocksize) { 218 if (sb_set_blocksize(sb, blocksize) != blocksize) {
158 printk(KERN_ERR "hfs: unable to set blocksize to %u!\n", blocksize); 219 printk(KERN_ERR "hfs: unable to set blocksize to %u!\n",
159 return -EINVAL; 220 blocksize);
221 goto out_free_backup_vhdr;
160 } 222 }
161 223
162 sbi->blockoffset = 224 sbi->blockoffset =
163 part_start >> (sb->s_blocksize_bits - HFSPLUS_SECTOR_SHIFT); 225 part_start >> (sb->s_blocksize_bits - HFSPLUS_SECTOR_SHIFT);
226 sbi->part_start = part_start;
164 sbi->sect_count = part_size; 227 sbi->sect_count = part_size;
165 sbi->fs_shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits; 228 sbi->fs_shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits;
166
167 bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
168 if (!bh)
169 return -EIO;
170
171 /* should still be the same... */
172 if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) {
173 if (vhdr->signature != cpu_to_be16(HFSPLUS_VOLHEAD_SIGX))
174 goto error;
175 } else {
176 if (vhdr->signature != cpu_to_be16(HFSPLUS_VOLHEAD_SIG))
177 goto error;
178 }
179
180 sbi->s_vhbh = bh;
181 sbi->s_vhdr = vhdr;
182
183 return 0; 229 return 0;
184 error: 230
185 brelse(bh); 231out_free_backup_vhdr:
186 return -EINVAL; 232 kfree(sbi->s_backup_vhdr);
233out_free_vhdr:
234 kfree(sbi->s_vhdr);
235out:
236 return error;
187} 237}