aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hfsplus/super.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@tuxera.com>2010-11-23 08:37:47 -0500
committerChristoph Hellwig <hch@lst.de>2010-11-23 08:37:47 -0500
commit52399b171dfaea02b6944cd6feba49b624147126 (patch)
tree199eda8c91a51fa1d4e3c792abd97d9c0a50ae26 /fs/hfsplus/super.c
parent3b5ce8ae31e3c66655207907527476bbd3e5063b (diff)
hfsplus: use raw bio access for the volume headers
The hfsplus backup volume header is located two blocks from the end of the device. In case of device sizes that are not 4k aligned this means we can't access it using buffer_heads when using the default 4k block size. Switch to using raw bios to read/write all buffer headers. We were not relying on any caching behaviour of the buffer heads anyway. Additionally always read in the backup volume header during mount to verify that we can actually read it. Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Diffstat (limited to 'fs/hfsplus/super.c')
-rw-r--r--fs/hfsplus/super.c48
1 files changed, 22 insertions, 26 deletions
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 6a2349058618..fe8f7bffbea5 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -157,45 +157,40 @@ int hfsplus_sync_fs(struct super_block *sb, int wait)
157{ 157{
158 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 158 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
159 struct hfsplus_vh *vhdr = sbi->s_vhdr; 159 struct hfsplus_vh *vhdr = sbi->s_vhdr;
160 int write_backup = 0;
161 int error, error2;
160 162
161 dprint(DBG_SUPER, "hfsplus_write_super\n"); 163 dprint(DBG_SUPER, "hfsplus_write_super\n");
162 164
163 mutex_lock(&sbi->vh_mutex);
164 mutex_lock(&sbi->alloc_mutex);
165 sb->s_dirt = 0; 165 sb->s_dirt = 0;
166 166
167 mutex_lock(&sbi->vh_mutex);
168 mutex_lock(&sbi->alloc_mutex);
167 vhdr->free_blocks = cpu_to_be32(sbi->free_blocks); 169 vhdr->free_blocks = cpu_to_be32(sbi->free_blocks);
168 vhdr->next_cnid = cpu_to_be32(sbi->next_cnid); 170 vhdr->next_cnid = cpu_to_be32(sbi->next_cnid);
169 vhdr->folder_count = cpu_to_be32(sbi->folder_count); 171 vhdr->folder_count = cpu_to_be32(sbi->folder_count);
170 vhdr->file_count = cpu_to_be32(sbi->file_count); 172 vhdr->file_count = cpu_to_be32(sbi->file_count);
171 173
172 mark_buffer_dirty(sbi->s_vhbh);
173 if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) { 174 if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) {
174 if (sbi->sect_count) { 175 memcpy(sbi->s_backup_vhdr, sbi->s_vhdr, sizeof(*sbi->s_vhdr));
175 struct buffer_head *bh; 176 write_backup = 1;
176 u32 block, offset;
177
178 block = sbi->blockoffset;
179 block += (sbi->sect_count - 2) >> (sb->s_blocksize_bits - 9);
180 offset = ((sbi->sect_count - 2) << 9) & (sb->s_blocksize - 1);
181 printk(KERN_DEBUG "hfs: backup: %u,%u,%u,%u\n",
182 sbi->blockoffset, sbi->sect_count,
183 block, offset);
184 bh = sb_bread(sb, block);
185 if (bh) {
186 vhdr = (struct hfsplus_vh *)(bh->b_data + offset);
187 if (be16_to_cpu(vhdr->signature) == HFSPLUS_VOLHEAD_SIG) {
188 memcpy(vhdr, sbi->s_vhdr, sizeof(*vhdr));
189 mark_buffer_dirty(bh);
190 brelse(bh);
191 } else
192 printk(KERN_WARNING "hfs: backup not found!\n");
193 }
194 }
195 } 177 }
178
179 error = hfsplus_submit_bio(sb->s_bdev,
180 sbi->part_start + HFSPLUS_VOLHEAD_SECTOR,
181 sbi->s_vhdr, WRITE_SYNC);
182 if (!write_backup)
183 goto out;
184
185 error2 = hfsplus_submit_bio(sb->s_bdev,
186 sbi->part_start + sbi->sect_count - 2,
187 sbi->s_backup_vhdr, WRITE_SYNC);
188 if (!error)
189 error2 = error;
190out:
196 mutex_unlock(&sbi->alloc_mutex); 191 mutex_unlock(&sbi->alloc_mutex);
197 mutex_unlock(&sbi->vh_mutex); 192 mutex_unlock(&sbi->vh_mutex);
198 return 0; 193 return error;
199} 194}
200 195
201static void hfsplus_write_super(struct super_block *sb) 196static void hfsplus_write_super(struct super_block *sb)
@@ -229,7 +224,8 @@ static void hfsplus_put_super(struct super_block *sb)
229 hfs_btree_close(sbi->ext_tree); 224 hfs_btree_close(sbi->ext_tree);
230 iput(sbi->alloc_file); 225 iput(sbi->alloc_file);
231 iput(sbi->hidden_dir); 226 iput(sbi->hidden_dir);
232 brelse(sbi->s_vhbh); 227 kfree(sbi->s_vhdr);
228 kfree(sbi->s_backup_vhdr);
233 unload_nls(sbi->nls); 229 unload_nls(sbi->nls);
234 kfree(sb->s_fs_info); 230 kfree(sb->s_fs_info);
235 sb->s_fs_info = NULL; 231 sb->s_fs_info = NULL;