aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hfsplus/super.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/hfsplus/super.c')
-rw-r--r--fs/hfsplus/super.c130
1 files changed, 79 insertions, 51 deletions
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index ddf712e4700e..6ee6ad20acf2 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -10,6 +10,7 @@
10#include <linux/module.h> 10#include <linux/module.h>
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/pagemap.h> 12#include <linux/pagemap.h>
13#include <linux/blkdev.h>
13#include <linux/fs.h> 14#include <linux/fs.h>
14#include <linux/slab.h> 15#include <linux/slab.h>
15#include <linux/vfs.h> 16#include <linux/vfs.h>
@@ -66,6 +67,7 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
66 INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list); 67 INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list);
67 mutex_init(&HFSPLUS_I(inode)->extents_lock); 68 mutex_init(&HFSPLUS_I(inode)->extents_lock);
68 HFSPLUS_I(inode)->flags = 0; 69 HFSPLUS_I(inode)->flags = 0;
70 HFSPLUS_I(inode)->extent_state = 0;
69 HFSPLUS_I(inode)->rsrc_inode = NULL; 71 HFSPLUS_I(inode)->rsrc_inode = NULL;
70 atomic_set(&HFSPLUS_I(inode)->opencnt, 0); 72 atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
71 73
@@ -157,45 +159,65 @@ int hfsplus_sync_fs(struct super_block *sb, int wait)
157{ 159{
158 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 160 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
159 struct hfsplus_vh *vhdr = sbi->s_vhdr; 161 struct hfsplus_vh *vhdr = sbi->s_vhdr;
162 int write_backup = 0;
163 int error, error2;
164
165 if (!wait)
166 return 0;
160 167
161 dprint(DBG_SUPER, "hfsplus_write_super\n"); 168 dprint(DBG_SUPER, "hfsplus_write_super\n");
162 169
163 mutex_lock(&sbi->vh_mutex);
164 mutex_lock(&sbi->alloc_mutex);
165 sb->s_dirt = 0; 170 sb->s_dirt = 0;
166 171
172 /*
173 * Explicitly write out the special metadata inodes.
174 *
175 * While these special inodes are marked as hashed and written
176 * out peridocically by the flusher threads we redirty them
177 * during writeout of normal inodes, and thus the life lock
178 * prevents us from getting the latest state to disk.
179 */
180 error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
181 error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
182 if (!error)
183 error = error2;
184 error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
185 if (!error)
186 error = error2;
187
188 mutex_lock(&sbi->vh_mutex);
189 mutex_lock(&sbi->alloc_mutex);
167 vhdr->free_blocks = cpu_to_be32(sbi->free_blocks); 190 vhdr->free_blocks = cpu_to_be32(sbi->free_blocks);
168 vhdr->next_cnid = cpu_to_be32(sbi->next_cnid); 191 vhdr->next_cnid = cpu_to_be32(sbi->next_cnid);
169 vhdr->folder_count = cpu_to_be32(sbi->folder_count); 192 vhdr->folder_count = cpu_to_be32(sbi->folder_count);
170 vhdr->file_count = cpu_to_be32(sbi->file_count); 193 vhdr->file_count = cpu_to_be32(sbi->file_count);
171 194
172 mark_buffer_dirty(sbi->s_vhbh);
173 if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) { 195 if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) {
174 if (sbi->sect_count) { 196 memcpy(sbi->s_backup_vhdr, sbi->s_vhdr, sizeof(*sbi->s_vhdr));
175 struct buffer_head *bh; 197 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 } 198 }
199
200 error2 = hfsplus_submit_bio(sb->s_bdev,
201 sbi->part_start + HFSPLUS_VOLHEAD_SECTOR,
202 sbi->s_vhdr, WRITE_SYNC);
203 if (!error)
204 error = error2;
205 if (!write_backup)
206 goto out;
207
208 error2 = hfsplus_submit_bio(sb->s_bdev,
209 sbi->part_start + sbi->sect_count - 2,
210 sbi->s_backup_vhdr, WRITE_SYNC);
211 if (!error)
212 error2 = error;
213out:
196 mutex_unlock(&sbi->alloc_mutex); 214 mutex_unlock(&sbi->alloc_mutex);
197 mutex_unlock(&sbi->vh_mutex); 215 mutex_unlock(&sbi->vh_mutex);
198 return 0; 216
217 if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
218 blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL);
219
220 return error;
199} 221}
200 222
201static void hfsplus_write_super(struct super_block *sb) 223static void hfsplus_write_super(struct super_block *sb)
@@ -215,23 +237,22 @@ static void hfsplus_put_super(struct super_block *sb)
215 if (!sb->s_fs_info) 237 if (!sb->s_fs_info)
216 return; 238 return;
217 239
218 if (sb->s_dirt)
219 hfsplus_write_super(sb);
220 if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) { 240 if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) {
221 struct hfsplus_vh *vhdr = sbi->s_vhdr; 241 struct hfsplus_vh *vhdr = sbi->s_vhdr;
222 242
223 vhdr->modify_date = hfsp_now2mt(); 243 vhdr->modify_date = hfsp_now2mt();
224 vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT); 244 vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT);
225 vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT); 245 vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT);
226 mark_buffer_dirty(sbi->s_vhbh); 246
227 sync_dirty_buffer(sbi->s_vhbh); 247 hfsplus_sync_fs(sb, 1);
228 } 248 }
229 249
230 hfs_btree_close(sbi->cat_tree); 250 hfs_btree_close(sbi->cat_tree);
231 hfs_btree_close(sbi->ext_tree); 251 hfs_btree_close(sbi->ext_tree);
232 iput(sbi->alloc_file); 252 iput(sbi->alloc_file);
233 iput(sbi->hidden_dir); 253 iput(sbi->hidden_dir);
234 brelse(sbi->s_vhbh); 254 kfree(sbi->s_vhdr);
255 kfree(sbi->s_backup_vhdr);
235 unload_nls(sbi->nls); 256 unload_nls(sbi->nls);
236 kfree(sb->s_fs_info); 257 kfree(sb->s_fs_info);
237 sb->s_fs_info = NULL; 258 sb->s_fs_info = NULL;
@@ -263,26 +284,31 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
263 return 0; 284 return 0;
264 if (!(*flags & MS_RDONLY)) { 285 if (!(*flags & MS_RDONLY)) {
265 struct hfsplus_vh *vhdr = HFSPLUS_SB(sb)->s_vhdr; 286 struct hfsplus_vh *vhdr = HFSPLUS_SB(sb)->s_vhdr;
266 struct hfsplus_sb_info sbi; 287 int force = 0;
267 288
268 memset(&sbi, 0, sizeof(struct hfsplus_sb_info)); 289 if (!hfsplus_parse_options_remount(data, &force))
269 sbi.nls = HFSPLUS_SB(sb)->nls;
270 if (!hfsplus_parse_options(data, &sbi))
271 return -EINVAL; 290 return -EINVAL;
272 291
273 if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { 292 if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
274 printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, " 293 printk(KERN_WARNING "hfs: filesystem was "
275 "running fsck.hfsplus is recommended. leaving read-only.\n"); 294 "not cleanly unmounted, "
295 "running fsck.hfsplus is recommended. "
296 "leaving read-only.\n");
276 sb->s_flags |= MS_RDONLY; 297 sb->s_flags |= MS_RDONLY;
277 *flags |= MS_RDONLY; 298 *flags |= MS_RDONLY;
278 } else if (test_bit(HFSPLUS_SB_FORCE, &sbi.flags)) { 299 } else if (force) {
279 /* nothing */ 300 /* nothing */
280 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { 301 } else if (vhdr->attributes &
281 printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.\n"); 302 cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
303 printk(KERN_WARNING "hfs: filesystem is marked locked, "
304 "leaving read-only.\n");
282 sb->s_flags |= MS_RDONLY; 305 sb->s_flags |= MS_RDONLY;
283 *flags |= MS_RDONLY; 306 *flags |= MS_RDONLY;
284 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { 307 } else if (vhdr->attributes &
285 printk(KERN_WARNING "hfs: filesystem is marked journaled, leaving read-only.\n"); 308 cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
309 printk(KERN_WARNING "hfs: filesystem is "
310 "marked journaled, "
311 "leaving read-only.\n");
286 sb->s_flags |= MS_RDONLY; 312 sb->s_flags |= MS_RDONLY;
287 *flags |= MS_RDONLY; 313 *flags |= MS_RDONLY;
288 } 314 }
@@ -372,17 +398,22 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
372 sb->s_maxbytes = MAX_LFS_FILESIZE; 398 sb->s_maxbytes = MAX_LFS_FILESIZE;
373 399
374 if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { 400 if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
375 printk(KERN_WARNING "hfs: Filesystem was not cleanly unmounted, " 401 printk(KERN_WARNING "hfs: Filesystem was "
376 "running fsck.hfsplus is recommended. mounting read-only.\n"); 402 "not cleanly unmounted, "
403 "running fsck.hfsplus is recommended. "
404 "mounting read-only.\n");
377 sb->s_flags |= MS_RDONLY; 405 sb->s_flags |= MS_RDONLY;
378 } else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) { 406 } else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) {
379 /* nothing */ 407 /* nothing */
380 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { 408 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
381 printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n"); 409 printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n");
382 sb->s_flags |= MS_RDONLY; 410 sb->s_flags |= MS_RDONLY;
383 } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) && !(sb->s_flags & MS_RDONLY)) { 411 } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) &&
384 printk(KERN_WARNING "hfs: write access to a journaled filesystem is not supported, " 412 !(sb->s_flags & MS_RDONLY)) {
385 "use the force option at your own risk, mounting read-only.\n"); 413 printk(KERN_WARNING "hfs: write access to "
414 "a journaled filesystem is not supported, "
415 "use the force option at your own risk, "
416 "mounting read-only.\n");
386 sb->s_flags |= MS_RDONLY; 417 sb->s_flags |= MS_RDONLY;
387 } 418 }
388 419
@@ -449,19 +480,16 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
449 be32_add_cpu(&vhdr->write_count, 1); 480 be32_add_cpu(&vhdr->write_count, 1);
450 vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT); 481 vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
451 vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT); 482 vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
452 mark_buffer_dirty(sbi->s_vhbh); 483 hfsplus_sync_fs(sb, 1);
453 sync_dirty_buffer(sbi->s_vhbh);
454 484
455 if (!sbi->hidden_dir) { 485 if (!sbi->hidden_dir) {
456 printk(KERN_DEBUG "hfs: create hidden dir...\n");
457
458 mutex_lock(&sbi->vh_mutex); 486 mutex_lock(&sbi->vh_mutex);
459 sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR); 487 sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
460 hfsplus_create_cat(sbi->hidden_dir->i_ino, sb->s_root->d_inode, 488 hfsplus_create_cat(sbi->hidden_dir->i_ino, sb->s_root->d_inode,
461 &str, sbi->hidden_dir); 489 &str, sbi->hidden_dir);
462 mutex_unlock(&sbi->vh_mutex); 490 mutex_unlock(&sbi->vh_mutex);
463 491
464 mark_inode_dirty(sbi->hidden_dir); 492 hfsplus_mark_inode_dirty(sbi->hidden_dir, HFSPLUS_I_CAT_DIRTY);
465 } 493 }
466out: 494out:
467 unload_nls(sbi->nls); 495 unload_nls(sbi->nls);