aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/hfsplus/bfind.c6
-rw-r--r--fs/hfsplus/bitmap.c3
-rw-r--r--fs/hfsplus/bnode.c70
-rw-r--r--fs/hfsplus/brec.c28
-rw-r--r--fs/hfsplus/btree.c33
-rw-r--r--fs/hfsplus/catalog.c85
-rw-r--r--fs/hfsplus/dir.c37
-rw-r--r--fs/hfsplus/extents.c96
-rw-r--r--fs/hfsplus/hfsplus_fs.h126
-rw-r--r--fs/hfsplus/hfsplus_raw.h3
-rw-r--r--fs/hfsplus/inode.c89
-rw-r--r--fs/hfsplus/ioctl.c6
-rw-r--r--fs/hfsplus/options.c44
-rw-r--r--fs/hfsplus/part_tbl.c129
-rw-r--r--fs/hfsplus/super.c130
-rw-r--r--fs/hfsplus/unicode.c38
-rw-r--r--fs/hfsplus/wrapper.c178
17 files changed, 701 insertions, 400 deletions
diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c
index d182438c7ae4..5d799c13205f 100644
--- a/fs/hfsplus/bfind.c
+++ b/fs/hfsplus/bfind.c
@@ -22,7 +22,8 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
22 return -ENOMEM; 22 return -ENOMEM;
23 fd->search_key = ptr; 23 fd->search_key = ptr;
24 fd->key = ptr + tree->max_key_len + 2; 24 fd->key = ptr + tree->max_key_len + 2;
25 dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", tree->cnid, __builtin_return_address(0)); 25 dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n",
26 tree->cnid, __builtin_return_address(0));
26 mutex_lock(&tree->tree_lock); 27 mutex_lock(&tree->tree_lock);
27 return 0; 28 return 0;
28} 29}
@@ -31,7 +32,8 @@ void hfs_find_exit(struct hfs_find_data *fd)
31{ 32{
32 hfs_bnode_put(fd->bnode); 33 hfs_bnode_put(fd->bnode);
33 kfree(fd->search_key); 34 kfree(fd->search_key);
34 dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n", fd->tree->cnid, __builtin_return_address(0)); 35 dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n",
36 fd->tree->cnid, __builtin_return_address(0));
35 mutex_unlock(&fd->tree->tree_lock); 37 mutex_unlock(&fd->tree->tree_lock);
36 fd->tree = NULL; 38 fd->tree = NULL;
37} 39}
diff --git a/fs/hfsplus/bitmap.c b/fs/hfsplus/bitmap.c
index ad57f5991eb1..1cad80c789cb 100644
--- a/fs/hfsplus/bitmap.c
+++ b/fs/hfsplus/bitmap.c
@@ -15,7 +15,8 @@
15 15
16#define PAGE_CACHE_BITS (PAGE_CACHE_SIZE * 8) 16#define PAGE_CACHE_BITS (PAGE_CACHE_SIZE * 8)
17 17
18int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *max) 18int hfsplus_block_allocate(struct super_block *sb, u32 size,
19 u32 offset, u32 *max)
19{ 20{
20 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 21 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
21 struct page *page; 22 struct page *page;
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c
index 29da6574ba77..1c42cc5b899f 100644
--- a/fs/hfsplus/bnode.c
+++ b/fs/hfsplus/bnode.c
@@ -42,7 +42,7 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
42u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off) 42u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
43{ 43{
44 __be16 data; 44 __be16 data;
45 // optimize later... 45 /* TODO: optimize later... */
46 hfs_bnode_read(node, &data, off, 2); 46 hfs_bnode_read(node, &data, off, 2);
47 return be16_to_cpu(data); 47 return be16_to_cpu(data);
48} 48}
@@ -50,7 +50,7 @@ u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
50u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off) 50u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off)
51{ 51{
52 u8 data; 52 u8 data;
53 // optimize later... 53 /* TODO: optimize later... */
54 hfs_bnode_read(node, &data, off, 1); 54 hfs_bnode_read(node, &data, off, 1);
55 return data; 55 return data;
56} 56}
@@ -96,7 +96,7 @@ void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
96void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data) 96void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data)
97{ 97{
98 __be16 v = cpu_to_be16(data); 98 __be16 v = cpu_to_be16(data);
99 // optimize later... 99 /* TODO: optimize later... */
100 hfs_bnode_write(node, &v, off, 2); 100 hfs_bnode_write(node, &v, off, 2);
101} 101}
102 102
@@ -212,7 +212,8 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
212 dst_page--; 212 dst_page--;
213 } 213 }
214 src -= len; 214 src -= len;
215 memmove(kmap(*dst_page) + src, kmap(*src_page) + src, len); 215 memmove(kmap(*dst_page) + src,
216 kmap(*src_page) + src, len);
216 kunmap(*src_page); 217 kunmap(*src_page);
217 set_page_dirty(*dst_page); 218 set_page_dirty(*dst_page);
218 kunmap(*dst_page); 219 kunmap(*dst_page);
@@ -250,14 +251,16 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
250 251
251 if (src == dst) { 252 if (src == dst) {
252 l = min(len, (int)PAGE_CACHE_SIZE - src); 253 l = min(len, (int)PAGE_CACHE_SIZE - src);
253 memmove(kmap(*dst_page) + src, kmap(*src_page) + src, l); 254 memmove(kmap(*dst_page) + src,
255 kmap(*src_page) + src, l);
254 kunmap(*src_page); 256 kunmap(*src_page);
255 set_page_dirty(*dst_page); 257 set_page_dirty(*dst_page);
256 kunmap(*dst_page); 258 kunmap(*dst_page);
257 259
258 while ((len -= l) != 0) { 260 while ((len -= l) != 0) {
259 l = min(len, (int)PAGE_CACHE_SIZE); 261 l = min(len, (int)PAGE_CACHE_SIZE);
260 memmove(kmap(*++dst_page), kmap(*++src_page), l); 262 memmove(kmap(*++dst_page),
263 kmap(*++src_page), l);
261 kunmap(*src_page); 264 kunmap(*src_page);
262 set_page_dirty(*dst_page); 265 set_page_dirty(*dst_page);
263 kunmap(*dst_page); 266 kunmap(*dst_page);
@@ -268,7 +271,8 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
268 do { 271 do {
269 src_ptr = kmap(*src_page) + src; 272 src_ptr = kmap(*src_page) + src;
270 dst_ptr = kmap(*dst_page) + dst; 273 dst_ptr = kmap(*dst_page) + dst;
271 if (PAGE_CACHE_SIZE - src < PAGE_CACHE_SIZE - dst) { 274 if (PAGE_CACHE_SIZE - src <
275 PAGE_CACHE_SIZE - dst) {
272 l = PAGE_CACHE_SIZE - src; 276 l = PAGE_CACHE_SIZE - src;
273 src = 0; 277 src = 0;
274 dst += l; 278 dst += l;
@@ -340,7 +344,8 @@ void hfs_bnode_unlink(struct hfs_bnode *node)
340 return; 344 return;
341 tmp->next = node->next; 345 tmp->next = node->next;
342 cnid = cpu_to_be32(tmp->next); 346 cnid = cpu_to_be32(tmp->next);
343 hfs_bnode_write(tmp, &cnid, offsetof(struct hfs_bnode_desc, next), 4); 347 hfs_bnode_write(tmp, &cnid,
348 offsetof(struct hfs_bnode_desc, next), 4);
344 hfs_bnode_put(tmp); 349 hfs_bnode_put(tmp);
345 } else if (node->type == HFS_NODE_LEAF) 350 } else if (node->type == HFS_NODE_LEAF)
346 tree->leaf_head = node->next; 351 tree->leaf_head = node->next;
@@ -351,15 +356,15 @@ void hfs_bnode_unlink(struct hfs_bnode *node)
351 return; 356 return;
352 tmp->prev = node->prev; 357 tmp->prev = node->prev;
353 cnid = cpu_to_be32(tmp->prev); 358 cnid = cpu_to_be32(tmp->prev);
354 hfs_bnode_write(tmp, &cnid, offsetof(struct hfs_bnode_desc, prev), 4); 359 hfs_bnode_write(tmp, &cnid,
360 offsetof(struct hfs_bnode_desc, prev), 4);
355 hfs_bnode_put(tmp); 361 hfs_bnode_put(tmp);
356 } else if (node->type == HFS_NODE_LEAF) 362 } else if (node->type == HFS_NODE_LEAF)
357 tree->leaf_tail = node->prev; 363 tree->leaf_tail = node->prev;
358 364
359 // move down? 365 /* move down? */
360 if (!node->prev && !node->next) { 366 if (!node->prev && !node->next)
361 printk(KERN_DEBUG "hfs_btree_del_level\n"); 367 dprint(DBG_BNODE_MOD, "hfs_btree_del_level\n");
362 }
363 if (!node->parent) { 368 if (!node->parent) {
364 tree->root = 0; 369 tree->root = 0;
365 tree->depth = 0; 370 tree->depth = 0;
@@ -379,16 +384,16 @@ struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid)
379 struct hfs_bnode *node; 384 struct hfs_bnode *node;
380 385
381 if (cnid >= tree->node_count) { 386 if (cnid >= tree->node_count) {
382 printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid); 387 printk(KERN_ERR "hfs: request for non-existent node "
388 "%d in B*Tree\n",
389 cnid);
383 return NULL; 390 return NULL;
384 } 391 }
385 392
386 for (node = tree->node_hash[hfs_bnode_hash(cnid)]; 393 for (node = tree->node_hash[hfs_bnode_hash(cnid)];
387 node; node = node->next_hash) { 394 node; node = node->next_hash)
388 if (node->this == cnid) { 395 if (node->this == cnid)
389 return node; 396 return node;
390 }
391 }
392 return NULL; 397 return NULL;
393} 398}
394 399
@@ -402,7 +407,9 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
402 loff_t off; 407 loff_t off;
403 408
404 if (cnid >= tree->node_count) { 409 if (cnid >= tree->node_count) {
405 printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid); 410 printk(KERN_ERR "hfs: request for non-existent node "
411 "%d in B*Tree\n",
412 cnid);
406 return NULL; 413 return NULL;
407 } 414 }
408 415
@@ -429,7 +436,8 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
429 } else { 436 } else {
430 spin_unlock(&tree->hash_lock); 437 spin_unlock(&tree->hash_lock);
431 kfree(node); 438 kfree(node);
432 wait_event(node2->lock_wq, !test_bit(HFS_BNODE_NEW, &node2->flags)); 439 wait_event(node2->lock_wq,
440 !test_bit(HFS_BNODE_NEW, &node2->flags));
433 return node2; 441 return node2;
434 } 442 }
435 spin_unlock(&tree->hash_lock); 443 spin_unlock(&tree->hash_lock);
@@ -483,7 +491,8 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
483 if (node) { 491 if (node) {
484 hfs_bnode_get(node); 492 hfs_bnode_get(node);
485 spin_unlock(&tree->hash_lock); 493 spin_unlock(&tree->hash_lock);
486 wait_event(node->lock_wq, !test_bit(HFS_BNODE_NEW, &node->flags)); 494 wait_event(node->lock_wq,
495 !test_bit(HFS_BNODE_NEW, &node->flags));
487 if (test_bit(HFS_BNODE_ERROR, &node->flags)) 496 if (test_bit(HFS_BNODE_ERROR, &node->flags))
488 goto node_error; 497 goto node_error;
489 return node; 498 return node;
@@ -497,7 +506,8 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
497 if (!test_bit(HFS_BNODE_NEW, &node->flags)) 506 if (!test_bit(HFS_BNODE_NEW, &node->flags))
498 return node; 507 return node;
499 508
500 desc = (struct hfs_bnode_desc *)(kmap(node->page[0]) + node->page_offset); 509 desc = (struct hfs_bnode_desc *)(kmap(node->page[0]) +
510 node->page_offset);
501 node->prev = be32_to_cpu(desc->prev); 511 node->prev = be32_to_cpu(desc->prev);
502 node->next = be32_to_cpu(desc->next); 512 node->next = be32_to_cpu(desc->next);
503 node->num_recs = be16_to_cpu(desc->num_recs); 513 node->num_recs = be16_to_cpu(desc->num_recs);
@@ -556,11 +566,13 @@ node_error:
556 566
557void hfs_bnode_free(struct hfs_bnode *node) 567void hfs_bnode_free(struct hfs_bnode *node)
558{ 568{
559 //int i; 569#if 0
570 int i;
560 571
561 //for (i = 0; i < node->tree->pages_per_bnode; i++) 572 for (i = 0; i < node->tree->pages_per_bnode; i++)
562 // if (node->page[i]) 573 if (node->page[i])
563 // page_cache_release(node->page[i]); 574 page_cache_release(node->page[i]);
575#endif
564 kfree(node); 576 kfree(node);
565} 577}
566 578
@@ -607,7 +619,8 @@ void hfs_bnode_get(struct hfs_bnode *node)
607 if (node) { 619 if (node) {
608 atomic_inc(&node->refcnt); 620 atomic_inc(&node->refcnt);
609 dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n", 621 dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n",
610 node->tree->cnid, node->this, atomic_read(&node->refcnt)); 622 node->tree->cnid, node->this,
623 atomic_read(&node->refcnt));
611 } 624 }
612} 625}
613 626
@@ -619,7 +632,8 @@ void hfs_bnode_put(struct hfs_bnode *node)
619 int i; 632 int i;
620 633
621 dprint(DBG_BNODE_REFS, "put_node(%d:%d): %d\n", 634 dprint(DBG_BNODE_REFS, "put_node(%d:%d): %d\n",
622 node->tree->cnid, node->this, atomic_read(&node->refcnt)); 635 node->tree->cnid, node->this,
636 atomic_read(&node->refcnt));
623 BUG_ON(!atomic_read(&node->refcnt)); 637 BUG_ON(!atomic_read(&node->refcnt));
624 if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock)) 638 if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock))
625 return; 639 return;
diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c
index 2f39d05443e1..2312de34bd42 100644
--- a/fs/hfsplus/brec.c
+++ b/fs/hfsplus/brec.c
@@ -39,7 +39,8 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
39 !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) { 39 !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) {
40 retval = node->tree->max_key_len + 2; 40 retval = node->tree->max_key_len + 2;
41 } else { 41 } else {
42 recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2); 42 recoff = hfs_bnode_read_u16(node,
43 node->tree->node_size - (rec + 1) * 2);
43 if (!recoff) 44 if (!recoff)
44 return 0; 45 return 0;
45 46
@@ -84,7 +85,8 @@ again:
84 end_rec_off = tree->node_size - (node->num_recs + 1) * 2; 85 end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
85 end_off = hfs_bnode_read_u16(node, end_rec_off); 86 end_off = hfs_bnode_read_u16(node, end_rec_off);
86 end_rec_off -= 2; 87 end_rec_off -= 2;
87 dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n", rec, size, end_off, end_rec_off); 88 dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n",
89 rec, size, end_off, end_rec_off);
88 if (size > end_rec_off - end_off) { 90 if (size > end_rec_off - end_off) {
89 if (new_node) 91 if (new_node)
90 panic("not enough room!\n"); 92 panic("not enough room!\n");
@@ -99,7 +101,9 @@ again:
99 } 101 }
100 node->num_recs++; 102 node->num_recs++;
101 /* write new last offset */ 103 /* write new last offset */
102 hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs); 104 hfs_bnode_write_u16(node,
105 offsetof(struct hfs_bnode_desc, num_recs),
106 node->num_recs);
103 hfs_bnode_write_u16(node, end_rec_off, end_off + size); 107 hfs_bnode_write_u16(node, end_rec_off, end_off + size);
104 data_off = end_off; 108 data_off = end_off;
105 data_rec_off = end_rec_off + 2; 109 data_rec_off = end_rec_off + 2;
@@ -151,7 +155,8 @@ skip:
151 if (tree->attributes & HFS_TREE_VARIDXKEYS) 155 if (tree->attributes & HFS_TREE_VARIDXKEYS)
152 key_len = be16_to_cpu(fd->search_key->key_len) + 2; 156 key_len = be16_to_cpu(fd->search_key->key_len) + 2;
153 else { 157 else {
154 fd->search_key->key_len = cpu_to_be16(tree->max_key_len); 158 fd->search_key->key_len =
159 cpu_to_be16(tree->max_key_len);
155 key_len = tree->max_key_len + 2; 160 key_len = tree->max_key_len + 2;
156 } 161 }
157 goto again; 162 goto again;
@@ -180,7 +185,8 @@ again:
180 mark_inode_dirty(tree->inode); 185 mark_inode_dirty(tree->inode);
181 } 186 }
182 hfs_bnode_dump(node); 187 hfs_bnode_dump(node);
183 dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n", fd->record, fd->keylength + fd->entrylength); 188 dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n",
189 fd->record, fd->keylength + fd->entrylength);
184 if (!--node->num_recs) { 190 if (!--node->num_recs) {
185 hfs_bnode_unlink(node); 191 hfs_bnode_unlink(node);
186 if (!node->parent) 192 if (!node->parent)
@@ -194,7 +200,9 @@ again:
194 __hfs_brec_find(node, fd); 200 __hfs_brec_find(node, fd);
195 goto again; 201 goto again;
196 } 202 }
197 hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs); 203 hfs_bnode_write_u16(node,
204 offsetof(struct hfs_bnode_desc, num_recs),
205 node->num_recs);
198 206
199 if (rec_off == end_off) 207 if (rec_off == end_off)
200 goto skip; 208 goto skip;
@@ -364,7 +372,8 @@ again:
364 newkeylen = hfs_bnode_read_u16(node, 14) + 2; 372 newkeylen = hfs_bnode_read_u16(node, 14) + 2;
365 else 373 else
366 fd->keylength = newkeylen = tree->max_key_len + 2; 374 fd->keylength = newkeylen = tree->max_key_len + 2;
367 dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n", rec, fd->keylength, newkeylen); 375 dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n",
376 rec, fd->keylength, newkeylen);
368 377
369 rec_off = tree->node_size - (rec + 2) * 2; 378 rec_off = tree->node_size - (rec + 2) * 2;
370 end_rec_off = tree->node_size - (parent->num_recs + 1) * 2; 379 end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
@@ -375,7 +384,7 @@ again:
375 end_off = hfs_bnode_read_u16(parent, end_rec_off); 384 end_off = hfs_bnode_read_u16(parent, end_rec_off);
376 if (end_rec_off - end_off < diff) { 385 if (end_rec_off - end_off < diff) {
377 386
378 printk(KERN_DEBUG "hfs: splitting index node...\n"); 387 dprint(DBG_BNODE_MOD, "hfs: splitting index node.\n");
379 fd->bnode = parent; 388 fd->bnode = parent;
380 new_node = hfs_bnode_split(fd); 389 new_node = hfs_bnode_split(fd);
381 if (IS_ERR(new_node)) 390 if (IS_ERR(new_node))
@@ -383,7 +392,8 @@ again:
383 parent = fd->bnode; 392 parent = fd->bnode;
384 rec = fd->record; 393 rec = fd->record;
385 rec_off = tree->node_size - (rec + 2) * 2; 394 rec_off = tree->node_size - (rec + 2) * 2;
386 end_rec_off = tree->node_size - (parent->num_recs + 1) * 2; 395 end_rec_off = tree->node_size -
396 (parent->num_recs + 1) * 2;
387 } 397 }
388 } 398 }
389 399
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index 22e4d4e32999..21023d9f8ff3 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -51,7 +51,8 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
51 goto free_inode; 51 goto free_inode;
52 52
53 /* Load the header */ 53 /* Load the header */
54 head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc)); 54 head = (struct hfs_btree_header_rec *)(kmap(page) +
55 sizeof(struct hfs_bnode_desc));
55 tree->root = be32_to_cpu(head->root); 56 tree->root = be32_to_cpu(head->root);
56 tree->leaf_count = be32_to_cpu(head->leaf_count); 57 tree->leaf_count = be32_to_cpu(head->leaf_count);
57 tree->leaf_head = be32_to_cpu(head->leaf_head); 58 tree->leaf_head = be32_to_cpu(head->leaf_head);
@@ -115,7 +116,9 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
115 116
116 tree->node_size_shift = ffs(size) - 1; 117 tree->node_size_shift = ffs(size) - 1;
117 118
118 tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; 119 tree->pages_per_bnode =
120 (tree->node_size + PAGE_CACHE_SIZE - 1) >>
121 PAGE_CACHE_SHIFT;
119 122
120 kunmap(page); 123 kunmap(page);
121 page_cache_release(page); 124 page_cache_release(page);
@@ -144,8 +147,10 @@ void hfs_btree_close(struct hfs_btree *tree)
144 while ((node = tree->node_hash[i])) { 147 while ((node = tree->node_hash[i])) {
145 tree->node_hash[i] = node->next_hash; 148 tree->node_hash[i] = node->next_hash;
146 if (atomic_read(&node->refcnt)) 149 if (atomic_read(&node->refcnt))
147 printk(KERN_CRIT "hfs: node %d:%d still has %d user(s)!\n", 150 printk(KERN_CRIT "hfs: node %d:%d "
148 node->tree->cnid, node->this, atomic_read(&node->refcnt)); 151 "still has %d user(s)!\n",
152 node->tree->cnid, node->this,
153 atomic_read(&node->refcnt));
149 hfs_bnode_free(node); 154 hfs_bnode_free(node);
150 tree->node_hash_cnt--; 155 tree->node_hash_cnt--;
151 } 156 }
@@ -166,7 +171,8 @@ void hfs_btree_write(struct hfs_btree *tree)
166 return; 171 return;
167 /* Load the header */ 172 /* Load the header */
168 page = node->page[0]; 173 page = node->page[0];
169 head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc)); 174 head = (struct hfs_btree_header_rec *)(kmap(page) +
175 sizeof(struct hfs_bnode_desc));
170 176
171 head->root = cpu_to_be32(tree->root); 177 head->root = cpu_to_be32(tree->root);
172 head->leaf_count = cpu_to_be32(tree->leaf_count); 178 head->leaf_count = cpu_to_be32(tree->leaf_count);
@@ -272,7 +278,8 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
272 tree->free_nodes--; 278 tree->free_nodes--;
273 mark_inode_dirty(tree->inode); 279 mark_inode_dirty(tree->inode);
274 hfs_bnode_put(node); 280 hfs_bnode_put(node);
275 return hfs_bnode_create(tree, idx); 281 return hfs_bnode_create(tree,
282 idx);
276 } 283 }
277 } 284 }
278 } 285 }
@@ -287,7 +294,7 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
287 kunmap(*pagep); 294 kunmap(*pagep);
288 nidx = node->next; 295 nidx = node->next;
289 if (!nidx) { 296 if (!nidx) {
290 printk(KERN_DEBUG "hfs: create new bmap node...\n"); 297 dprint(DBG_BNODE_MOD, "hfs: create new bmap node.\n");
291 next_node = hfs_bmap_new_bmap(node, idx); 298 next_node = hfs_bmap_new_bmap(node, idx);
292 } else 299 } else
293 next_node = hfs_bnode_find(tree, nidx); 300 next_node = hfs_bnode_find(tree, nidx);
@@ -329,7 +336,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
329 hfs_bnode_put(node); 336 hfs_bnode_put(node);
330 if (!i) { 337 if (!i) {
331 /* panic */; 338 /* panic */;
332 printk(KERN_CRIT "hfs: unable to free bnode %u. bmap not found!\n", node->this); 339 printk(KERN_CRIT "hfs: unable to free bnode %u. "
340 "bmap not found!\n",
341 node->this);
333 return; 342 return;
334 } 343 }
335 node = hfs_bnode_find(tree, i); 344 node = hfs_bnode_find(tree, i);
@@ -337,7 +346,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
337 return; 346 return;
338 if (node->type != HFS_NODE_MAP) { 347 if (node->type != HFS_NODE_MAP) {
339 /* panic */; 348 /* panic */;
340 printk(KERN_CRIT "hfs: invalid bmap found! (%u,%d)\n", node->this, node->type); 349 printk(KERN_CRIT "hfs: invalid bmap found! "
350 "(%u,%d)\n",
351 node->this, node->type);
341 hfs_bnode_put(node); 352 hfs_bnode_put(node);
342 return; 353 return;
343 } 354 }
@@ -350,7 +361,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
350 m = 1 << (~nidx & 7); 361 m = 1 << (~nidx & 7);
351 byte = data[off]; 362 byte = data[off];
352 if (!(byte & m)) { 363 if (!(byte & m)) {
353 printk(KERN_CRIT "hfs: trying to free free bnode %u(%d)\n", node->this, node->type); 364 printk(KERN_CRIT "hfs: trying to free free bnode "
365 "%u(%d)\n",
366 node->this, node->type);
354 kunmap(page); 367 kunmap(page);
355 hfs_bnode_put(node); 368 hfs_bnode_put(node);
356 return; 369 return;
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c
index 8af45fc5b051..b4ba1b319333 100644
--- a/fs/hfsplus/catalog.c
+++ b/fs/hfsplus/catalog.c
@@ -91,7 +91,8 @@ void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms)
91 perms->dev = 0; 91 perms->dev = 0;
92} 92}
93 93
94static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct inode *inode) 94static int hfsplus_cat_build_record(hfsplus_cat_entry *entry,
95 u32 cnid, struct inode *inode)
95{ 96{
96 struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); 97 struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
97 98
@@ -128,20 +129,32 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i
128 if (cnid == inode->i_ino) { 129 if (cnid == inode->i_ino) {
129 hfsplus_cat_set_perms(inode, &file->permissions); 130 hfsplus_cat_set_perms(inode, &file->permissions);
130 if (S_ISLNK(inode->i_mode)) { 131 if (S_ISLNK(inode->i_mode)) {
131 file->user_info.fdType = cpu_to_be32(HFSP_SYMLINK_TYPE); 132 file->user_info.fdType =
132 file->user_info.fdCreator = cpu_to_be32(HFSP_SYMLINK_CREATOR); 133 cpu_to_be32(HFSP_SYMLINK_TYPE);
134 file->user_info.fdCreator =
135 cpu_to_be32(HFSP_SYMLINK_CREATOR);
133 } else { 136 } else {
134 file->user_info.fdType = cpu_to_be32(sbi->type); 137 file->user_info.fdType =
135 file->user_info.fdCreator = cpu_to_be32(sbi->creator); 138 cpu_to_be32(sbi->type);
139 file->user_info.fdCreator =
140 cpu_to_be32(sbi->creator);
136 } 141 }
137 if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE) 142 if (HFSPLUS_FLG_IMMUTABLE &
138 file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); 143 (file->permissions.rootflags |
144 file->permissions.userflags))
145 file->flags |=
146 cpu_to_be16(HFSPLUS_FILE_LOCKED);
139 } else { 147 } else {
140 file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE); 148 file->user_info.fdType =
141 file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR); 149 cpu_to_be32(HFSP_HARDLINK_TYPE);
142 file->user_info.fdFlags = cpu_to_be16(0x100); 150 file->user_info.fdCreator =
143 file->create_date = HFSPLUS_I(sbi->hidden_dir)->create_date; 151 cpu_to_be32(HFSP_HFSPLUS_CREATOR);
144 file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode)->linkid); 152 file->user_info.fdFlags =
153 cpu_to_be16(0x100);
154 file->create_date =
155 HFSPLUS_I(sbi->hidden_dir)->create_date;
156 file->permissions.dev =
157 cpu_to_be32(HFSPLUS_I(inode)->linkid);
145 } 158 }
146 return sizeof(*file); 159 return sizeof(*file);
147 } 160 }
@@ -182,12 +195,14 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
182 return -EIO; 195 return -EIO;
183 } 196 }
184 197
185 hfsplus_cat_build_key_uni(fd->search_key, be32_to_cpu(tmp.thread.parentID), 198 hfsplus_cat_build_key_uni(fd->search_key,
186 &tmp.thread.nodeName); 199 be32_to_cpu(tmp.thread.parentID),
200 &tmp.thread.nodeName);
187 return hfs_brec_find(fd); 201 return hfs_brec_find(fd);
188} 202}
189 203
190int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct inode *inode) 204int hfsplus_create_cat(u32 cnid, struct inode *dir,
205 struct qstr *str, struct inode *inode)
191{ 206{
192 struct super_block *sb = dir->i_sb; 207 struct super_block *sb = dir->i_sb;
193 struct hfs_find_data fd; 208 struct hfs_find_data fd;
@@ -195,13 +210,15 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino
195 int entry_size; 210 int entry_size;
196 int err; 211 int err;
197 212
198 dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", str->name, cnid, inode->i_nlink); 213 dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n",
214 str->name, cnid, inode->i_nlink);
199 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 215 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
200 216
201 hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); 217 hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
202 entry_size = hfsplus_fill_cat_thread(sb, &entry, S_ISDIR(inode->i_mode) ? 218 entry_size = hfsplus_fill_cat_thread(sb, &entry,
219 S_ISDIR(inode->i_mode) ?
203 HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD, 220 HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD,
204 dir->i_ino, str); 221 dir->i_ino, str);
205 err = hfs_brec_find(&fd); 222 err = hfs_brec_find(&fd);
206 if (err != -ENOENT) { 223 if (err != -ENOENT) {
207 if (!err) 224 if (!err)
@@ -227,7 +244,8 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino
227 244
228 dir->i_size++; 245 dir->i_size++;
229 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 246 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
230 mark_inode_dirty(dir); 247 hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
248
231 hfs_find_exit(&fd); 249 hfs_find_exit(&fd);
232 return 0; 250 return 0;
233 251
@@ -249,7 +267,8 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
249 int err, off; 267 int err, off;
250 u16 type; 268 u16 type;
251 269
252 dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid); 270 dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n",
271 str ? str->name : NULL, cnid);
253 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 272 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
254 273
255 if (!str) { 274 if (!str) {
@@ -260,11 +279,15 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
260 if (err) 279 if (err)
261 goto out; 280 goto out;
262 281
263 off = fd.entryoffset + offsetof(struct hfsplus_cat_thread, nodeName); 282 off = fd.entryoffset +
283 offsetof(struct hfsplus_cat_thread, nodeName);
264 fd.search_key->cat.parent = cpu_to_be32(dir->i_ino); 284 fd.search_key->cat.parent = cpu_to_be32(dir->i_ino);
265 hfs_bnode_read(fd.bnode, &fd.search_key->cat.name.length, off, 2); 285 hfs_bnode_read(fd.bnode,
286 &fd.search_key->cat.name.length, off, 2);
266 len = be16_to_cpu(fd.search_key->cat.name.length) * 2; 287 len = be16_to_cpu(fd.search_key->cat.name.length) * 2;
267 hfs_bnode_read(fd.bnode, &fd.search_key->cat.name.unicode, off + 2, len); 288 hfs_bnode_read(fd.bnode,
289 &fd.search_key->cat.name.unicode,
290 off + 2, len);
268 fd.search_key->key_len = cpu_to_be16(6 + len); 291 fd.search_key->key_len = cpu_to_be16(6 + len);
269 } else 292 } else
270 hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); 293 hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str);
@@ -281,7 +304,8 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
281 hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_DATA); 304 hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_DATA);
282#endif 305#endif
283 306
284 off = fd.entryoffset + offsetof(struct hfsplus_cat_file, rsrc_fork); 307 off = fd.entryoffset +
308 offsetof(struct hfsplus_cat_file, rsrc_fork);
285 hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork)); 309 hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork));
286 hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC); 310 hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC);
287 } 311 }
@@ -308,7 +332,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
308 332
309 dir->i_size--; 333 dir->i_size--;
310 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 334 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
311 mark_inode_dirty(dir); 335 hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
312out: 336out:
313 hfs_find_exit(&fd); 337 hfs_find_exit(&fd);
314 338
@@ -325,7 +349,8 @@ int hfsplus_rename_cat(u32 cnid,
325 int entry_size, type; 349 int entry_size, type;
326 int err = 0; 350 int err = 0;
327 351
328 dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, src_name->name, 352 dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n",
353 cnid, src_dir->i_ino, src_name->name,
329 dst_dir->i_ino, dst_name->name); 354 dst_dir->i_ino, dst_name->name);
330 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd); 355 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd);
331 dst_fd = src_fd; 356 dst_fd = src_fd;
@@ -353,7 +378,6 @@ int hfsplus_rename_cat(u32 cnid,
353 goto out; 378 goto out;
354 dst_dir->i_size++; 379 dst_dir->i_size++;
355 dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC; 380 dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC;
356 mark_inode_dirty(dst_dir);
357 381
358 /* finally remove the old entry */ 382 /* finally remove the old entry */
359 hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); 383 hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
@@ -365,7 +389,6 @@ int hfsplus_rename_cat(u32 cnid,
365 goto out; 389 goto out;
366 src_dir->i_size--; 390 src_dir->i_size--;
367 src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC; 391 src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC;
368 mark_inode_dirty(src_dir);
369 392
370 /* remove old thread entry */ 393 /* remove old thread entry */
371 hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL); 394 hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL);
@@ -379,7 +402,8 @@ int hfsplus_rename_cat(u32 cnid,
379 402
380 /* create new thread entry */ 403 /* create new thread entry */
381 hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL); 404 hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL);
382 entry_size = hfsplus_fill_cat_thread(sb, &entry, type, dst_dir->i_ino, dst_name); 405 entry_size = hfsplus_fill_cat_thread(sb, &entry, type,
406 dst_dir->i_ino, dst_name);
383 err = hfs_brec_find(&dst_fd); 407 err = hfs_brec_find(&dst_fd);
384 if (err != -ENOENT) { 408 if (err != -ENOENT) {
385 if (!err) 409 if (!err)
@@ -387,6 +411,9 @@ int hfsplus_rename_cat(u32 cnid,
387 goto out; 411 goto out;
388 } 412 }
389 err = hfs_brec_insert(&dst_fd, &entry, entry_size); 413 err = hfs_brec_insert(&dst_fd, &entry, entry_size);
414
415 hfsplus_mark_inode_dirty(dst_dir, HFSPLUS_I_CAT_DIRTY);
416 hfsplus_mark_inode_dirty(src_dir, HFSPLUS_I_CAT_DIRTY);
390out: 417out:
391 hfs_bnode_put(dst_fd.bnode); 418 hfs_bnode_put(dst_fd.bnode);
392 hfs_find_exit(&src_fd); 419 hfs_find_exit(&src_fd);
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index ccab87145f7a..f896dc843026 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -66,11 +66,17 @@ again:
66 goto fail; 66 goto fail;
67 } 67 }
68 cnid = be32_to_cpu(entry.file.id); 68 cnid = be32_to_cpu(entry.file.id);
69 if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) && 69 if (entry.file.user_info.fdType ==
70 entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR) && 70 cpu_to_be32(HFSP_HARDLINK_TYPE) &&
71 (entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)->create_date || 71 entry.file.user_info.fdCreator ==
72 entry.file.create_date == HFSPLUS_I(sb->s_root->d_inode)->create_date) && 72 cpu_to_be32(HFSP_HFSPLUS_CREATOR) &&
73 HFSPLUS_SB(sb)->hidden_dir) { 73 (entry.file.create_date ==
74 HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)->
75 create_date ||
76 entry.file.create_date ==
77 HFSPLUS_I(sb->s_root->d_inode)->
78 create_date) &&
79 HFSPLUS_SB(sb)->hidden_dir) {
74 struct qstr str; 80 struct qstr str;
75 char name[32]; 81 char name[32];
76 82
@@ -83,11 +89,13 @@ again:
83 linkid = 0; 89 linkid = 0;
84 } else { 90 } else {
85 dentry->d_fsdata = (void *)(unsigned long)cnid; 91 dentry->d_fsdata = (void *)(unsigned long)cnid;
86 linkid = be32_to_cpu(entry.file.permissions.dev); 92 linkid =
93 be32_to_cpu(entry.file.permissions.dev);
87 str.len = sprintf(name, "iNode%d", linkid); 94 str.len = sprintf(name, "iNode%d", linkid);
88 str.name = name; 95 str.name = name;
89 hfsplus_cat_build_key(sb, fd.search_key, 96 hfsplus_cat_build_key(sb, fd.search_key,
90 HFSPLUS_SB(sb)->hidden_dir->i_ino, &str); 97 HFSPLUS_SB(sb)->hidden_dir->i_ino,
98 &str);
91 goto again; 99 goto again;
92 } 100 }
93 } else if (!dentry->d_fsdata) 101 } else if (!dentry->d_fsdata)
@@ -139,7 +147,8 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
139 filp->f_pos++; 147 filp->f_pos++;
140 /* fall through */ 148 /* fall through */
141 case 1: 149 case 1:
142 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); 150 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
151 fd.entrylength);
143 if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) { 152 if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) {
144 printk(KERN_ERR "hfs: bad catalog folder thread\n"); 153 printk(KERN_ERR "hfs: bad catalog folder thread\n");
145 err = -EIO; 154 err = -EIO;
@@ -169,14 +178,16 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
169 err = -EIO; 178 err = -EIO;
170 goto out; 179 goto out;
171 } 180 }
172 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); 181 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
182 fd.entrylength);
173 type = be16_to_cpu(entry.type); 183 type = be16_to_cpu(entry.type);
174 len = HFSPLUS_MAX_STRLEN; 184 len = HFSPLUS_MAX_STRLEN;
175 err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len); 185 err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len);
176 if (err) 186 if (err)
177 goto out; 187 goto out;
178 if (type == HFSPLUS_FOLDER) { 188 if (type == HFSPLUS_FOLDER) {
179 if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) { 189 if (fd.entrylength <
190 sizeof(struct hfsplus_cat_folder)) {
180 printk(KERN_ERR "hfs: small dir entry\n"); 191 printk(KERN_ERR "hfs: small dir entry\n");
181 err = -EIO; 192 err = -EIO;
182 goto out; 193 goto out;
@@ -202,7 +213,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
202 err = -EIO; 213 err = -EIO;
203 goto out; 214 goto out;
204 } 215 }
205 next: 216next:
206 filp->f_pos++; 217 filp->f_pos++;
207 if (filp->f_pos >= inode->i_size) 218 if (filp->f_pos >= inode->i_size)
208 goto out; 219 goto out;
@@ -273,7 +284,8 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
273 HFSPLUS_I(inode)->linkid = id; 284 HFSPLUS_I(inode)->linkid = id;
274 cnid = sbi->next_cnid++; 285 cnid = sbi->next_cnid++;
275 src_dentry->d_fsdata = (void *)(unsigned long)cnid; 286 src_dentry->d_fsdata = (void *)(unsigned long)cnid;
276 res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode); 287 res = hfsplus_create_cat(cnid, src_dir,
288 &src_dentry->d_name, inode);
277 if (res) 289 if (res)
278 /* panic? */ 290 /* panic? */
279 goto out; 291 goto out;
@@ -485,6 +497,7 @@ const struct inode_operations hfsplus_dir_inode_operations = {
485}; 497};
486 498
487const struct file_operations hfsplus_dir_operations = { 499const struct file_operations hfsplus_dir_operations = {
500 .fsync = hfsplus_file_fsync,
488 .read = generic_read_dir, 501 .read = generic_read_dir,
489 .readdir = hfsplus_readdir, 502 .readdir = hfsplus_readdir,
490 .unlocked_ioctl = hfsplus_ioctl, 503 .unlocked_ioctl = hfsplus_ioctl,
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c
index 0c9cb1820a52..52a0bcaa7b6d 100644
--- a/fs/hfsplus/extents.c
+++ b/fs/hfsplus/extents.c
@@ -83,7 +83,8 @@ static u32 hfsplus_ext_lastblock(struct hfsplus_extent *ext)
83 return be32_to_cpu(ext->start_block) + be32_to_cpu(ext->block_count); 83 return be32_to_cpu(ext->start_block) + be32_to_cpu(ext->block_count);
84} 84}
85 85
86static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) 86static void __hfsplus_ext_write_extent(struct inode *inode,
87 struct hfs_find_data *fd)
87{ 88{
88 struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 89 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
89 int res; 90 int res;
@@ -95,24 +96,32 @@ static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data
95 HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); 96 HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA);
96 97
97 res = hfs_brec_find(fd); 98 res = hfs_brec_find(fd);
98 if (hip->flags & HFSPLUS_FLG_EXT_NEW) { 99 if (hip->extent_state & HFSPLUS_EXT_NEW) {
99 if (res != -ENOENT) 100 if (res != -ENOENT)
100 return; 101 return;
101 hfs_brec_insert(fd, hip->cached_extents, 102 hfs_brec_insert(fd, hip->cached_extents,
102 sizeof(hfsplus_extent_rec)); 103 sizeof(hfsplus_extent_rec));
103 hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); 104 hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
104 } else { 105 } else {
105 if (res) 106 if (res)
106 return; 107 return;
107 hfs_bnode_write(fd->bnode, hip->cached_extents, 108 hfs_bnode_write(fd->bnode, hip->cached_extents,
108 fd->entryoffset, fd->entrylength); 109 fd->entryoffset, fd->entrylength);
109 hip->flags &= ~HFSPLUS_FLG_EXT_DIRTY; 110 hip->extent_state &= ~HFSPLUS_EXT_DIRTY;
110 } 111 }
112
113 /*
114 * We can't just use hfsplus_mark_inode_dirty here, because we
115 * also get called from hfsplus_write_inode, which should not
116 * redirty the inode. Instead the callers have to be careful
117 * to explicily mark the inode dirty, too.
118 */
119 set_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags);
111} 120}
112 121
113static void hfsplus_ext_write_extent_locked(struct inode *inode) 122static void hfsplus_ext_write_extent_locked(struct inode *inode)
114{ 123{
115 if (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_EXT_DIRTY) { 124 if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) {
116 struct hfs_find_data fd; 125 struct hfs_find_data fd;
117 126
118 hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); 127 hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
@@ -144,18 +153,20 @@ static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd,
144 return -ENOENT; 153 return -ENOENT;
145 if (fd->entrylength != sizeof(hfsplus_extent_rec)) 154 if (fd->entrylength != sizeof(hfsplus_extent_rec))
146 return -EIO; 155 return -EIO;
147 hfs_bnode_read(fd->bnode, extent, fd->entryoffset, sizeof(hfsplus_extent_rec)); 156 hfs_bnode_read(fd->bnode, extent, fd->entryoffset,
157 sizeof(hfsplus_extent_rec));
148 return 0; 158 return 0;
149} 159}
150 160
151static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct inode *inode, u32 block) 161static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd,
162 struct inode *inode, u32 block)
152{ 163{
153 struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 164 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
154 int res; 165 int res;
155 166
156 WARN_ON(!mutex_is_locked(&hip->extents_lock)); 167 WARN_ON(!mutex_is_locked(&hip->extents_lock));
157 168
158 if (hip->flags & HFSPLUS_FLG_EXT_DIRTY) 169 if (hip->extent_state & HFSPLUS_EXT_DIRTY)
159 __hfsplus_ext_write_extent(inode, fd); 170 __hfsplus_ext_write_extent(inode, fd);
160 171
161 res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino, 172 res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino,
@@ -164,10 +175,11 @@ static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct in
164 HFSPLUS_TYPE_DATA); 175 HFSPLUS_TYPE_DATA);
165 if (!res) { 176 if (!res) {
166 hip->cached_start = be32_to_cpu(fd->key->ext.start_block); 177 hip->cached_start = be32_to_cpu(fd->key->ext.start_block);
167 hip->cached_blocks = hfsplus_ext_block_count(hip->cached_extents); 178 hip->cached_blocks =
179 hfsplus_ext_block_count(hip->cached_extents);
168 } else { 180 } else {
169 hip->cached_start = hip->cached_blocks = 0; 181 hip->cached_start = hip->cached_blocks = 0;
170 hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); 182 hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
171 } 183 }
172 return res; 184 return res;
173} 185}
@@ -197,6 +209,7 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
197 struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 209 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
198 int res = -EIO; 210 int res = -EIO;
199 u32 ablock, dblock, mask; 211 u32 ablock, dblock, mask;
212 int was_dirty = 0;
200 int shift; 213 int shift;
201 214
202 /* Convert inode block to disk allocation block */ 215 /* Convert inode block to disk allocation block */
@@ -223,27 +236,37 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
223 return -EIO; 236 return -EIO;
224 237
225 mutex_lock(&hip->extents_lock); 238 mutex_lock(&hip->extents_lock);
239
240 /*
241 * hfsplus_ext_read_extent will write out a cached extent into
242 * the extents btree. In that case we may have to mark the inode
243 * dirty even for a pure read of an extent here.
244 */
245 was_dirty = (hip->extent_state & HFSPLUS_EXT_DIRTY);
226 res = hfsplus_ext_read_extent(inode, ablock); 246 res = hfsplus_ext_read_extent(inode, ablock);
227 if (!res) { 247 if (res) {
228 dblock = hfsplus_ext_find_block(hip->cached_extents,
229 ablock - hip->cached_start);
230 } else {
231 mutex_unlock(&hip->extents_lock); 248 mutex_unlock(&hip->extents_lock);
232 return -EIO; 249 return -EIO;
233 } 250 }
251 dblock = hfsplus_ext_find_block(hip->cached_extents,
252 ablock - hip->cached_start);
234 mutex_unlock(&hip->extents_lock); 253 mutex_unlock(&hip->extents_lock);
235 254
236done: 255done:
237 dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n", inode->i_ino, (long long)iblock, dblock); 256 dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n",
257 inode->i_ino, (long long)iblock, dblock);
238 mask = (1 << sbi->fs_shift) - 1; 258 mask = (1 << sbi->fs_shift) - 1;
239 map_bh(bh_result, sb, (dblock << sbi->fs_shift) + sbi->blockoffset + (iblock & mask)); 259 map_bh(bh_result, sb,
260 (dblock << sbi->fs_shift) + sbi->blockoffset +
261 (iblock & mask));
240 if (create) { 262 if (create) {
241 set_buffer_new(bh_result); 263 set_buffer_new(bh_result);
242 hip->phys_size += sb->s_blocksize; 264 hip->phys_size += sb->s_blocksize;
243 hip->fs_blocks++; 265 hip->fs_blocks++;
244 inode_add_bytes(inode, sb->s_blocksize); 266 inode_add_bytes(inode, sb->s_blocksize);
245 mark_inode_dirty(inode);
246 } 267 }
268 if (create || was_dirty)
269 mark_inode_dirty(inode);
247 return 0; 270 return 0;
248} 271}
249 272
@@ -326,7 +349,8 @@ found:
326 } 349 }
327} 350}
328 351
329int hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw *fork, int type) 352int hfsplus_free_fork(struct super_block *sb, u32 cnid,
353 struct hfsplus_fork_raw *fork, int type)
330{ 354{
331 struct hfs_find_data fd; 355 struct hfs_find_data fd;
332 hfsplus_extent_rec ext_entry; 356 hfsplus_extent_rec ext_entry;
@@ -373,12 +397,13 @@ int hfsplus_file_extend(struct inode *inode)
373 u32 start, len, goal; 397 u32 start, len, goal;
374 int res; 398 int res;
375 399
376 if (sbi->alloc_file->i_size * 8 < 400 if (sbi->total_blocks - sbi->free_blocks + 8 >
377 sbi->total_blocks - sbi->free_blocks + 8) { 401 sbi->alloc_file->i_size * 8) {
378 // extend alloc file 402 /* extend alloc file */
379 printk(KERN_ERR "hfs: extend alloc file! (%Lu,%u,%u)\n", 403 printk(KERN_ERR "hfs: extend alloc file! "
380 sbi->alloc_file->i_size * 8, 404 "(%llu,%u,%u)\n",
381 sbi->total_blocks, sbi->free_blocks); 405 sbi->alloc_file->i_size * 8,
406 sbi->total_blocks, sbi->free_blocks);
382 return -ENOSPC; 407 return -ENOSPC;
383 } 408 }
384 409
@@ -429,7 +454,7 @@ int hfsplus_file_extend(struct inode *inode)
429 start, len); 454 start, len);
430 if (!res) { 455 if (!res) {
431 hfsplus_dump_extent(hip->cached_extents); 456 hfsplus_dump_extent(hip->cached_extents);
432 hip->flags |= HFSPLUS_FLG_EXT_DIRTY; 457 hip->extent_state |= HFSPLUS_EXT_DIRTY;
433 hip->cached_blocks += len; 458 hip->cached_blocks += len;
434 } else if (res == -ENOSPC) 459 } else if (res == -ENOSPC)
435 goto insert_extent; 460 goto insert_extent;
@@ -438,7 +463,7 @@ out:
438 mutex_unlock(&hip->extents_lock); 463 mutex_unlock(&hip->extents_lock);
439 if (!res) { 464 if (!res) {
440 hip->alloc_blocks += len; 465 hip->alloc_blocks += len;
441 mark_inode_dirty(inode); 466 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY);
442 } 467 }
443 return res; 468 return res;
444 469
@@ -450,7 +475,7 @@ insert_extent:
450 hip->cached_extents[0].start_block = cpu_to_be32(start); 475 hip->cached_extents[0].start_block = cpu_to_be32(start);
451 hip->cached_extents[0].block_count = cpu_to_be32(len); 476 hip->cached_extents[0].block_count = cpu_to_be32(len);
452 hfsplus_dump_extent(hip->cached_extents); 477 hfsplus_dump_extent(hip->cached_extents);
453 hip->flags |= HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW; 478 hip->extent_state |= HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW;
454 hip->cached_start = hip->alloc_blocks; 479 hip->cached_start = hip->alloc_blocks;
455 hip->cached_blocks = len; 480 hip->cached_blocks = len;
456 481
@@ -466,8 +491,9 @@ void hfsplus_file_truncate(struct inode *inode)
466 u32 alloc_cnt, blk_cnt, start; 491 u32 alloc_cnt, blk_cnt, start;
467 int res; 492 int res;
468 493
469 dprint(DBG_INODE, "truncate: %lu, %Lu -> %Lu\n", 494 dprint(DBG_INODE, "truncate: %lu, %llu -> %llu\n",
470 inode->i_ino, (long long)hip->phys_size, inode->i_size); 495 inode->i_ino, (long long)hip->phys_size,
496 inode->i_size);
471 497
472 if (inode->i_size > hip->phys_size) { 498 if (inode->i_size > hip->phys_size) {
473 struct address_space *mapping = inode->i_mapping; 499 struct address_space *mapping = inode->i_mapping;
@@ -481,7 +507,8 @@ void hfsplus_file_truncate(struct inode *inode)
481 &page, &fsdata); 507 &page, &fsdata);
482 if (res) 508 if (res)
483 return; 509 return;
484 res = pagecache_write_end(NULL, mapping, size, 0, 0, page, fsdata); 510 res = pagecache_write_end(NULL, mapping, size,
511 0, 0, page, fsdata);
485 if (res < 0) 512 if (res < 0)
486 return; 513 return;
487 mark_inode_dirty(inode); 514 mark_inode_dirty(inode);
@@ -513,12 +540,12 @@ void hfsplus_file_truncate(struct inode *inode)
513 alloc_cnt - start, alloc_cnt - blk_cnt); 540 alloc_cnt - start, alloc_cnt - blk_cnt);
514 hfsplus_dump_extent(hip->cached_extents); 541 hfsplus_dump_extent(hip->cached_extents);
515 if (blk_cnt > start) { 542 if (blk_cnt > start) {
516 hip->flags |= HFSPLUS_FLG_EXT_DIRTY; 543 hip->extent_state |= HFSPLUS_EXT_DIRTY;
517 break; 544 break;
518 } 545 }
519 alloc_cnt = start; 546 alloc_cnt = start;
520 hip->cached_start = hip->cached_blocks = 0; 547 hip->cached_start = hip->cached_blocks = 0;
521 hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); 548 hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
522 hfs_brec_remove(&fd); 549 hfs_brec_remove(&fd);
523 } 550 }
524 hfs_find_exit(&fd); 551 hfs_find_exit(&fd);
@@ -527,7 +554,8 @@ void hfsplus_file_truncate(struct inode *inode)
527 hip->alloc_blocks = blk_cnt; 554 hip->alloc_blocks = blk_cnt;
528out: 555out:
529 hip->phys_size = inode->i_size; 556 hip->phys_size = inode->i_size;
530 hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; 557 hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >>
558 sb->s_blocksize_bits;
531 inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits); 559 inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
532 mark_inode_dirty(inode); 560 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY);
533} 561}
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index a5308f491e3e..d6857523336d 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -23,13 +23,16 @@
23#define DBG_EXTENT 0x00000020 23#define DBG_EXTENT 0x00000020
24#define DBG_BITMAP 0x00000040 24#define DBG_BITMAP 0x00000040
25 25
26//#define DBG_MASK (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD) 26#if 0
27//#define DBG_MASK (DBG_BNODE_MOD|DBG_CAT_MOD|DBG_INODE) 27#define DBG_MASK (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD)
28//#define DBG_MASK (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT) 28#define DBG_MASK (DBG_BNODE_MOD|DBG_CAT_MOD|DBG_INODE)
29#define DBG_MASK (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT)
30#endif
29#define DBG_MASK (0) 31#define DBG_MASK (0)
30 32
31#define dprint(flg, fmt, args...) \ 33#define dprint(flg, fmt, args...) \
32 if (flg & DBG_MASK) printk(fmt , ## args) 34 if (flg & DBG_MASK) \
35 printk(fmt , ## args)
33 36
34/* Runtime config options */ 37/* Runtime config options */
35#define HFSPLUS_DEF_CR_TYPE 0x3F3F3F3F /* '????' */ 38#define HFSPLUS_DEF_CR_TYPE 0x3F3F3F3F /* '????' */
@@ -37,7 +40,8 @@
37#define HFSPLUS_TYPE_DATA 0x00 40#define HFSPLUS_TYPE_DATA 0x00
38#define HFSPLUS_TYPE_RSRC 0xFF 41#define HFSPLUS_TYPE_RSRC 0xFF
39 42
40typedef int (*btree_keycmp)(const hfsplus_btree_key *, const hfsplus_btree_key *); 43typedef int (*btree_keycmp)(const hfsplus_btree_key *,
44 const hfsplus_btree_key *);
41 45
42#define NODE_HASH_SIZE 256 46#define NODE_HASH_SIZE 256
43 47
@@ -61,7 +65,6 @@ struct hfs_btree {
61 unsigned int max_key_len; 65 unsigned int max_key_len;
62 unsigned int depth; 66 unsigned int depth;
63 67
64 //unsigned int map1_size, map_size;
65 struct mutex tree_lock; 68 struct mutex tree_lock;
66 69
67 unsigned int pages_per_bnode; 70 unsigned int pages_per_bnode;
@@ -107,8 +110,8 @@ struct hfsplus_vh;
107struct hfs_btree; 110struct hfs_btree;
108 111
109struct hfsplus_sb_info { 112struct hfsplus_sb_info {
110 struct buffer_head *s_vhbh;
111 struct hfsplus_vh *s_vhdr; 113 struct hfsplus_vh *s_vhdr;
114 struct hfsplus_vh *s_backup_vhdr;
112 struct hfs_btree *ext_tree; 115 struct hfs_btree *ext_tree;
113 struct hfs_btree *cat_tree; 116 struct hfs_btree *cat_tree;
114 struct hfs_btree *attr_tree; 117 struct hfs_btree *attr_tree;
@@ -118,7 +121,8 @@ struct hfsplus_sb_info {
118 121
119 /* Runtime variables */ 122 /* Runtime variables */
120 u32 blockoffset; 123 u32 blockoffset;
121 u32 sect_count; 124 sector_t part_start;
125 sector_t sect_count;
122 int fs_shift; 126 int fs_shift;
123 127
124 /* immutable data from the volume header */ 128 /* immutable data from the volume header */
@@ -155,6 +159,12 @@ struct hfsplus_sb_info {
155#define HFSPLUS_SB_FORCE 2 159#define HFSPLUS_SB_FORCE 2
156#define HFSPLUS_SB_HFSX 3 160#define HFSPLUS_SB_HFSX 3
157#define HFSPLUS_SB_CASEFOLD 4 161#define HFSPLUS_SB_CASEFOLD 4
162#define HFSPLUS_SB_NOBARRIER 5
163
164static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb)
165{
166 return sb->s_fs_info;
167}
158 168
159 169
160struct hfsplus_inode_info { 170struct hfsplus_inode_info {
@@ -170,7 +180,7 @@ struct hfsplus_inode_info {
170 u32 cached_blocks; 180 u32 cached_blocks;
171 hfsplus_extent_rec first_extents; 181 hfsplus_extent_rec first_extents;
172 hfsplus_extent_rec cached_extents; 182 hfsplus_extent_rec cached_extents;
173 unsigned long flags; 183 unsigned int extent_state;
174 struct mutex extents_lock; 184 struct mutex extents_lock;
175 185
176 /* 186 /*
@@ -185,6 +195,11 @@ struct hfsplus_inode_info {
185 u32 linkid; 195 u32 linkid;
186 196
187 /* 197 /*
198 * Accessed using atomic bitops.
199 */
200 unsigned long flags;
201
202 /*
188 * Protected by i_mutex. 203 * Protected by i_mutex.
189 */ 204 */
190 sector_t fs_blocks; 205 sector_t fs_blocks;
@@ -195,12 +210,34 @@ struct hfsplus_inode_info {
195 struct inode vfs_inode; 210 struct inode vfs_inode;
196}; 211};
197 212
198#define HFSPLUS_FLG_RSRC 0x0001 213#define HFSPLUS_EXT_DIRTY 0x0001
199#define HFSPLUS_FLG_EXT_DIRTY 0x0002 214#define HFSPLUS_EXT_NEW 0x0002
200#define HFSPLUS_FLG_EXT_NEW 0x0004 215
216#define HFSPLUS_I_RSRC 0 /* represents a resource fork */
217#define HFSPLUS_I_CAT_DIRTY 1 /* has changes in the catalog tree */
218#define HFSPLUS_I_EXT_DIRTY 2 /* has changes in the extent tree */
219#define HFSPLUS_I_ALLOC_DIRTY 3 /* has changes in the allocation file */
220
221#define HFSPLUS_IS_RSRC(inode) \
222 test_bit(HFSPLUS_I_RSRC, &HFSPLUS_I(inode)->flags)
223
224static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode)
225{
226 return list_entry(inode, struct hfsplus_inode_info, vfs_inode);
227}
201 228
202#define HFSPLUS_IS_DATA(inode) (!(HFSPLUS_I(inode)->flags & HFSPLUS_FLG_RSRC)) 229/*
203#define HFSPLUS_IS_RSRC(inode) (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_RSRC) 230 * Mark an inode dirty, and also mark the btree in which the
231 * specific type of metadata is stored.
232 * For data or metadata that gets written back by into the catalog btree
233 * by hfsplus_write_inode a plain mark_inode_dirty call is enough.
234 */
235static inline void hfsplus_mark_inode_dirty(struct inode *inode,
236 unsigned int flag)
237{
238 set_bit(flag, &HFSPLUS_I(inode)->flags);
239 mark_inode_dirty(inode);
240}
204 241
205struct hfs_find_data { 242struct hfs_find_data {
206 /* filled by caller */ 243 /* filled by caller */
@@ -318,9 +355,12 @@ int hfs_brec_read(struct hfs_find_data *, void *, int);
318int hfs_brec_goto(struct hfs_find_data *, int); 355int hfs_brec_goto(struct hfs_find_data *, int);
319 356
320/* catalog.c */ 357/* catalog.c */
321int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); 358int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *,
322int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); 359 const hfsplus_btree_key *);
323void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *, u32, struct qstr *); 360int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *,
361 const hfsplus_btree_key *);
362void hfsplus_cat_build_key(struct super_block *sb,
363 hfsplus_btree_key *, u32, struct qstr *);
324int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *); 364int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *);
325int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *); 365int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *);
326int hfsplus_delete_cat(u32, struct inode *, struct qstr *); 366int hfsplus_delete_cat(u32, struct inode *, struct qstr *);
@@ -336,7 +376,8 @@ extern const struct file_operations hfsplus_dir_operations;
336int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); 376int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
337void hfsplus_ext_write_extent(struct inode *); 377void hfsplus_ext_write_extent(struct inode *);
338int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int); 378int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int);
339int hfsplus_free_fork(struct super_block *, u32, struct hfsplus_fork_raw *, int); 379int hfsplus_free_fork(struct super_block *, u32,
380 struct hfsplus_fork_raw *, int);
340int hfsplus_file_extend(struct inode *); 381int hfsplus_file_extend(struct inode *);
341void hfsplus_file_truncate(struct inode *); 382void hfsplus_file_truncate(struct inode *);
342 383
@@ -351,6 +392,7 @@ int hfsplus_cat_read_inode(struct inode *, struct hfs_find_data *);
351int hfsplus_cat_write_inode(struct inode *); 392int hfsplus_cat_write_inode(struct inode *);
352struct inode *hfsplus_new_inode(struct super_block *, int); 393struct inode *hfsplus_new_inode(struct super_block *, int);
353void hfsplus_delete_inode(struct inode *); 394void hfsplus_delete_inode(struct inode *);
395int hfsplus_file_fsync(struct file *file, int datasync);
354 396
355/* ioctl.c */ 397/* ioctl.c */
356long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); 398long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
@@ -362,6 +404,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size);
362 404
363/* options.c */ 405/* options.c */
364int hfsplus_parse_options(char *, struct hfsplus_sb_info *); 406int hfsplus_parse_options(char *, struct hfsplus_sb_info *);
407int hfsplus_parse_options_remount(char *input, int *force);
365void hfsplus_fill_defaults(struct hfsplus_sb_info *); 408void hfsplus_fill_defaults(struct hfsplus_sb_info *);
366int hfsplus_show_options(struct seq_file *, struct vfsmount *); 409int hfsplus_show_options(struct seq_file *, struct vfsmount *);
367 410
@@ -375,12 +418,16 @@ extern u16 hfsplus_decompose_table[];
375extern u16 hfsplus_compose_table[]; 418extern u16 hfsplus_compose_table[];
376 419
377/* unicode.c */ 420/* unicode.c */
378int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); 421int hfsplus_strcasecmp(const struct hfsplus_unistr *,
379int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); 422 const struct hfsplus_unistr *);
380int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); 423int hfsplus_strcmp(const struct hfsplus_unistr *,
381int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); 424 const struct hfsplus_unistr *);
382int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode, 425int hfsplus_uni2asc(struct super_block *,
383 struct qstr *str); 426 const struct hfsplus_unistr *, char *, int *);
427int hfsplus_asc2uni(struct super_block *,
428 struct hfsplus_unistr *, const char *, int);
429int hfsplus_hash_dentry(const struct dentry *dentry,
430 const struct inode *inode, struct qstr *str);
384int hfsplus_compare_dentry(const struct dentry *parent, 431int hfsplus_compare_dentry(const struct dentry *parent,
385 const struct inode *pinode, 432 const struct inode *pinode,
386 const struct dentry *dentry, const struct inode *inode, 433 const struct dentry *dentry, const struct inode *inode,
@@ -388,36 +435,9 @@ int hfsplus_compare_dentry(const struct dentry *parent,
388 435
389/* wrapper.c */ 436/* wrapper.c */
390int hfsplus_read_wrapper(struct super_block *); 437int hfsplus_read_wrapper(struct super_block *);
391
392int hfs_part_find(struct super_block *, sector_t *, sector_t *); 438int hfs_part_find(struct super_block *, sector_t *, sector_t *);
393 439int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
394/* access macros */ 440 void *data, int rw);
395static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb)
396{
397 return sb->s_fs_info;
398}
399
400static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode)
401{
402 return list_entry(inode, struct hfsplus_inode_info, vfs_inode);
403}
404
405#define sb_bread512(sb, sec, data) ({ \
406 struct buffer_head *__bh; \
407 sector_t __block; \
408 loff_t __start; \
409 int __offset; \
410 \
411 __start = (loff_t)(sec) << HFSPLUS_SECTOR_SHIFT;\
412 __block = __start >> (sb)->s_blocksize_bits; \
413 __offset = __start & ((sb)->s_blocksize - 1); \
414 __bh = sb_bread((sb), __block); \
415 if (likely(__bh != NULL)) \
416 data = (void *)(__bh->b_data + __offset);\
417 else \
418 data = NULL; \
419 __bh; \
420})
421 441
422/* time macros */ 442/* time macros */
423#define __hfsp_mt2ut(t) (be32_to_cpu(t) - 2082844800U) 443#define __hfsp_mt2ut(t) (be32_to_cpu(t) - 2082844800U)
diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h
index 6892899fd6fb..927cdd6d5bf5 100644
--- a/fs/hfsplus/hfsplus_raw.h
+++ b/fs/hfsplus/hfsplus_raw.h
@@ -36,7 +36,8 @@
36#define HFSP_WRAPOFF_EMBEDSIG 0x7C 36#define HFSP_WRAPOFF_EMBEDSIG 0x7C
37#define HFSP_WRAPOFF_EMBEDEXT 0x7E 37#define HFSP_WRAPOFF_EMBEDEXT 0x7E
38 38
39#define HFSP_HIDDENDIR_NAME "\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80HFS+ Private Data" 39#define HFSP_HIDDENDIR_NAME \
40 "\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80HFS+ Private Data"
40 41
41#define HFSP_HARDLINK_TYPE 0x686c6e6b /* 'hlnk' */ 42#define HFSP_HARDLINK_TYPE 0x686c6e6b /* 'hlnk' */
42#define HFSP_HFSPLUS_CREATOR 0x6866732b /* 'hfs+' */ 43#define HFSP_HFSPLUS_CREATOR 0x6866732b /* 'hfs+' */
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 8afd7e84f98d..a8df651747f0 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -8,6 +8,7 @@
8 * Inode handling routines 8 * Inode handling routines
9 */ 9 */
10 10
11#include <linux/blkdev.h>
11#include <linux/mm.h> 12#include <linux/mm.h>
12#include <linux/fs.h> 13#include <linux/fs.h>
13#include <linux/pagemap.h> 14#include <linux/pagemap.h>
@@ -77,7 +78,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask)
77 if (!tree) 78 if (!tree)
78 return 0; 79 return 0;
79 if (tree->node_size >= PAGE_CACHE_SIZE) { 80 if (tree->node_size >= PAGE_CACHE_SIZE) {
80 nidx = page->index >> (tree->node_size_shift - PAGE_CACHE_SHIFT); 81 nidx = page->index >>
82 (tree->node_size_shift - PAGE_CACHE_SHIFT);
81 spin_lock(&tree->hash_lock); 83 spin_lock(&tree->hash_lock);
82 node = hfs_bnode_findhash(tree, nidx); 84 node = hfs_bnode_findhash(tree, nidx);
83 if (!node) 85 if (!node)
@@ -90,7 +92,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask)
90 } 92 }
91 spin_unlock(&tree->hash_lock); 93 spin_unlock(&tree->hash_lock);
92 } else { 94 } else {
93 nidx = page->index << (PAGE_CACHE_SHIFT - tree->node_size_shift); 95 nidx = page->index <<
96 (PAGE_CACHE_SHIFT - tree->node_size_shift);
94 i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift); 97 i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift);
95 spin_lock(&tree->hash_lock); 98 spin_lock(&tree->hash_lock);
96 do { 99 do {
@@ -166,8 +169,8 @@ const struct dentry_operations hfsplus_dentry_operations = {
166 .d_compare = hfsplus_compare_dentry, 169 .d_compare = hfsplus_compare_dentry,
167}; 170};
168 171
169static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry, 172static struct dentry *hfsplus_file_lookup(struct inode *dir,
170 struct nameidata *nd) 173 struct dentry *dentry, struct nameidata *nd)
171{ 174{
172 struct hfs_find_data fd; 175 struct hfs_find_data fd;
173 struct super_block *sb = dir->i_sb; 176 struct super_block *sb = dir->i_sb;
@@ -190,7 +193,9 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
190 inode->i_ino = dir->i_ino; 193 inode->i_ino = dir->i_ino;
191 INIT_LIST_HEAD(&hip->open_dir_list); 194 INIT_LIST_HEAD(&hip->open_dir_list);
192 mutex_init(&hip->extents_lock); 195 mutex_init(&hip->extents_lock);
193 hip->flags = HFSPLUS_FLG_RSRC; 196 hip->extent_state = 0;
197 hip->flags = 0;
198 set_bit(HFSPLUS_I_RSRC, &hip->flags);
194 199
195 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 200 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
196 err = hfsplus_find_cat(sb, dir->i_ino, &fd); 201 err = hfsplus_find_cat(sb, dir->i_ino, &fd);
@@ -219,7 +224,8 @@ out:
219 return NULL; 224 return NULL;
220} 225}
221 226
222static void hfsplus_get_perms(struct inode *inode, struct hfsplus_perm *perms, int dir) 227static void hfsplus_get_perms(struct inode *inode,
228 struct hfsplus_perm *perms, int dir)
223{ 229{
224 struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); 230 struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
225 u16 mode; 231 u16 mode;
@@ -302,29 +308,41 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
302 return 0; 308 return 0;
303} 309}
304 310
305static int hfsplus_file_fsync(struct file *filp, int datasync) 311int hfsplus_file_fsync(struct file *file, int datasync)
306{ 312{
307 struct inode *inode = filp->f_mapping->host; 313 struct inode *inode = file->f_mapping->host;
308 struct super_block * sb; 314 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
309 int ret, err; 315 struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
310 316 int error = 0, error2;
311 /* sync the inode to buffers */ 317
312 ret = write_inode_now(inode, 0); 318 /*
313 319 * Sync inode metadata into the catalog and extent trees.
314 /* sync the superblock to buffers */ 320 */
315 sb = inode->i_sb; 321 sync_inode_metadata(inode, 1);
316 if (sb->s_dirt) { 322
317 if (!(sb->s_flags & MS_RDONLY)) 323 /*
318 hfsplus_sync_fs(sb, 1); 324 * And explicitly write out the btrees.
319 else 325 */
320 sb->s_dirt = 0; 326 if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags))
327 error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
328
329 if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags)) {
330 error2 =
331 filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
332 if (!error)
333 error = error2;
321 } 334 }
322 335
323 /* .. finally sync the buffers to disk */ 336 if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) {
324 err = sync_blockdev(sb->s_bdev); 337 error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
325 if (!ret) 338 if (!error)
326 ret = err; 339 error = error2;
327 return ret; 340 }
341
342 if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
343 blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
344
345 return error;
328} 346}
329 347
330static const struct inode_operations hfsplus_file_inode_operations = { 348static const struct inode_operations hfsplus_file_inode_operations = {
@@ -337,7 +355,7 @@ static const struct inode_operations hfsplus_file_inode_operations = {
337}; 355};
338 356
339static const struct file_operations hfsplus_file_operations = { 357static const struct file_operations hfsplus_file_operations = {
340 .llseek = generic_file_llseek, 358 .llseek = generic_file_llseek,
341 .read = do_sync_read, 359 .read = do_sync_read,
342 .aio_read = generic_file_aio_read, 360 .aio_read = generic_file_aio_read,
343 .write = do_sync_write, 361 .write = do_sync_write,
@@ -370,6 +388,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
370 INIT_LIST_HEAD(&hip->open_dir_list); 388 INIT_LIST_HEAD(&hip->open_dir_list);
371 mutex_init(&hip->extents_lock); 389 mutex_init(&hip->extents_lock);
372 atomic_set(&hip->opencnt, 0); 390 atomic_set(&hip->opencnt, 0);
391 hip->extent_state = 0;
373 hip->flags = 0; 392 hip->flags = 0;
374 memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec)); 393 memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
375 memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); 394 memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
@@ -457,7 +476,8 @@ void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
457 } 476 }
458} 477}
459 478
460void hfsplus_inode_write_fork(struct inode *inode, struct hfsplus_fork_raw *fork) 479void hfsplus_inode_write_fork(struct inode *inode,
480 struct hfsplus_fork_raw *fork)
461{ 481{
462 memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents, 482 memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents,
463 sizeof(hfsplus_extent_rec)); 483 sizeof(hfsplus_extent_rec));
@@ -499,13 +519,14 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
499 hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, 519 hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
500 sizeof(struct hfsplus_cat_file)); 520 sizeof(struct hfsplus_cat_file));
501 521
502 hfsplus_inode_read_fork(inode, HFSPLUS_IS_DATA(inode) ? 522 hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ?
503 &file->data_fork : &file->rsrc_fork); 523 &file->rsrc_fork : &file->data_fork);
504 hfsplus_get_perms(inode, &file->permissions, 0); 524 hfsplus_get_perms(inode, &file->permissions, 0);
505 inode->i_nlink = 1; 525 inode->i_nlink = 1;
506 if (S_ISREG(inode->i_mode)) { 526 if (S_ISREG(inode->i_mode)) {
507 if (file->permissions.dev) 527 if (file->permissions.dev)
508 inode->i_nlink = be32_to_cpu(file->permissions.dev); 528 inode->i_nlink =
529 be32_to_cpu(file->permissions.dev);
509 inode->i_op = &hfsplus_file_inode_operations; 530 inode->i_op = &hfsplus_file_inode_operations;
510 inode->i_fop = &hfsplus_file_operations; 531 inode->i_fop = &hfsplus_file_operations;
511 inode->i_mapping->a_ops = &hfsplus_aops; 532 inode->i_mapping->a_ops = &hfsplus_aops;
@@ -578,7 +599,9 @@ int hfsplus_cat_write_inode(struct inode *inode)
578 sizeof(struct hfsplus_cat_file)); 599 sizeof(struct hfsplus_cat_file));
579 hfsplus_inode_write_fork(inode, &file->data_fork); 600 hfsplus_inode_write_fork(inode, &file->data_fork);
580 hfsplus_cat_set_perms(inode, &file->permissions); 601 hfsplus_cat_set_perms(inode, &file->permissions);
581 if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE) 602 if (HFSPLUS_FLG_IMMUTABLE &
603 (file->permissions.rootflags |
604 file->permissions.userflags))
582 file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); 605 file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
583 else 606 else
584 file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED); 607 file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED);
@@ -588,6 +611,8 @@ int hfsplus_cat_write_inode(struct inode *inode)
588 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 611 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
589 sizeof(struct hfsplus_cat_file)); 612 sizeof(struct hfsplus_cat_file));
590 } 613 }
614
615 set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
591out: 616out:
592 hfs_find_exit(&fd); 617 hfs_find_exit(&fd);
593 return 0; 618 return 0;
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c
index 40a85a3ded6e..508ce662ce12 100644
--- a/fs/hfsplus/ioctl.c
+++ b/fs/hfsplus/ioctl.c
@@ -28,7 +28,7 @@ static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
28 28
29 if (inode->i_flags & S_IMMUTABLE) 29 if (inode->i_flags & S_IMMUTABLE)
30 flags |= FS_IMMUTABLE_FL; 30 flags |= FS_IMMUTABLE_FL;
31 if (inode->i_flags |= S_APPEND) 31 if (inode->i_flags & S_APPEND)
32 flags |= FS_APPEND_FL; 32 flags |= FS_APPEND_FL;
33 if (hip->userflags & HFSPLUS_FLG_NODUMP) 33 if (hip->userflags & HFSPLUS_FLG_NODUMP)
34 flags |= FS_NODUMP_FL; 34 flags |= FS_NODUMP_FL;
@@ -147,9 +147,11 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name,
147 res = -ERANGE; 147 res = -ERANGE;
148 } else 148 } else
149 res = -EOPNOTSUPP; 149 res = -EOPNOTSUPP;
150 if (!res) 150 if (!res) {
151 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 151 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
152 sizeof(struct hfsplus_cat_file)); 152 sizeof(struct hfsplus_cat_file));
153 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
154 }
153out: 155out:
154 hfs_find_exit(&fd); 156 hfs_find_exit(&fd);
155 return res; 157 return res;
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index f9ab276a4d8d..bb62a5882147 100644
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -23,6 +23,7 @@ enum {
23 opt_umask, opt_uid, opt_gid, 23 opt_umask, opt_uid, opt_gid,
24 opt_part, opt_session, opt_nls, 24 opt_part, opt_session, opt_nls,
25 opt_nodecompose, opt_decompose, 25 opt_nodecompose, opt_decompose,
26 opt_barrier, opt_nobarrier,
26 opt_force, opt_err 27 opt_force, opt_err
27}; 28};
28 29
@@ -37,6 +38,8 @@ static const match_table_t tokens = {
37 { opt_nls, "nls=%s" }, 38 { opt_nls, "nls=%s" },
38 { opt_decompose, "decompose" }, 39 { opt_decompose, "decompose" },
39 { opt_nodecompose, "nodecompose" }, 40 { opt_nodecompose, "nodecompose" },
41 { opt_barrier, "barrier" },
42 { opt_nobarrier, "nobarrier" },
40 { opt_force, "force" }, 43 { opt_force, "force" },
41 { opt_err, NULL } 44 { opt_err, NULL }
42}; 45};
@@ -65,6 +68,32 @@ static inline int match_fourchar(substring_t *arg, u32 *result)
65 return 0; 68 return 0;
66} 69}
67 70
71int hfsplus_parse_options_remount(char *input, int *force)
72{
73 char *p;
74 substring_t args[MAX_OPT_ARGS];
75 int token;
76
77 if (!input)
78 return 0;
79
80 while ((p = strsep(&input, ",")) != NULL) {
81 if (!*p)
82 continue;
83
84 token = match_token(p, tokens, args);
85 switch (token) {
86 case opt_force:
87 *force = 1;
88 break;
89 default:
90 break;
91 }
92 }
93
94 return 1;
95}
96
68/* Parse options from mount. Returns 0 on failure */ 97/* Parse options from mount. Returns 0 on failure */
69/* input is the options passed to mount() as a string */ 98/* input is the options passed to mount() as a string */
70int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi) 99int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
@@ -136,7 +165,9 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
136 if (p) 165 if (p)
137 sbi->nls = load_nls(p); 166 sbi->nls = load_nls(p);
138 if (!sbi->nls) { 167 if (!sbi->nls) {
139 printk(KERN_ERR "hfs: unable to load nls mapping \"%s\"\n", p); 168 printk(KERN_ERR "hfs: unable to load "
169 "nls mapping \"%s\"\n",
170 p);
140 kfree(p); 171 kfree(p);
141 return 0; 172 return 0;
142 } 173 }
@@ -148,6 +179,12 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
148 case opt_nodecompose: 179 case opt_nodecompose:
149 set_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags); 180 set_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags);
150 break; 181 break;
182 case opt_barrier:
183 clear_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags);
184 break;
185 case opt_nobarrier:
186 set_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags);
187 break;
151 case opt_force: 188 case opt_force:
152 set_bit(HFSPLUS_SB_FORCE, &sbi->flags); 189 set_bit(HFSPLUS_SB_FORCE, &sbi->flags);
153 break; 190 break;
@@ -177,7 +214,8 @@ int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
177 seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator); 214 seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator);
178 if (sbi->type != HFSPLUS_DEF_CR_TYPE) 215 if (sbi->type != HFSPLUS_DEF_CR_TYPE)
179 seq_printf(seq, ",type=%.4s", (char *)&sbi->type); 216 seq_printf(seq, ",type=%.4s", (char *)&sbi->type);
180 seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask, sbi->uid, sbi->gid); 217 seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask,
218 sbi->uid, sbi->gid);
181 if (sbi->part >= 0) 219 if (sbi->part >= 0)
182 seq_printf(seq, ",part=%u", sbi->part); 220 seq_printf(seq, ",part=%u", sbi->part);
183 if (sbi->session >= 0) 221 if (sbi->session >= 0)
@@ -186,5 +224,7 @@ int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
186 seq_printf(seq, ",nls=%s", sbi->nls->charset); 224 seq_printf(seq, ",nls=%s", sbi->nls->charset);
187 if (test_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags)) 225 if (test_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags))
188 seq_printf(seq, ",nodecompose"); 226 seq_printf(seq, ",nodecompose");
227 if (test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
228 seq_printf(seq, ",nobarrier");
189 return 0; 229 return 0;
190} 230}
diff --git a/fs/hfsplus/part_tbl.c b/fs/hfsplus/part_tbl.c
index 208b16c645cc..d66ad113b1cc 100644
--- a/fs/hfsplus/part_tbl.c
+++ b/fs/hfsplus/part_tbl.c
@@ -2,7 +2,8 @@
2 * linux/fs/hfsplus/part_tbl.c 2 * linux/fs/hfsplus/part_tbl.c
3 * 3 *
4 * Copyright (C) 1996-1997 Paul H. Hargrove 4 * Copyright (C) 1996-1997 Paul H. Hargrove
5 * This file may be distributed under the terms of the GNU General Public License. 5 * This file may be distributed under the terms of
6 * the GNU General Public License.
6 * 7 *
7 * Original code to handle the new style Mac partition table based on 8 * Original code to handle the new style Mac partition table based on
8 * a patch contributed by Holger Schemel (aeglos@valinor.owl.de). 9 * a patch contributed by Holger Schemel (aeglos@valinor.owl.de).
@@ -13,6 +14,7 @@
13 * 14 *
14 */ 15 */
15 16
17#include <linux/slab.h>
16#include "hfsplus_fs.h" 18#include "hfsplus_fs.h"
17 19
18/* offsets to various blocks */ 20/* offsets to various blocks */
@@ -58,77 +60,94 @@ struct new_pmap {
58 */ 60 */
59struct old_pmap { 61struct old_pmap {
60 __be16 pdSig; /* Signature bytes */ 62 __be16 pdSig; /* Signature bytes */
61 struct old_pmap_entry { 63 struct old_pmap_entry {
62 __be32 pdStart; 64 __be32 pdStart;
63 __be32 pdSize; 65 __be32 pdSize;
64 __be32 pdFSID; 66 __be32 pdFSID;
65 } pdEntry[42]; 67 } pdEntry[42];
66} __packed; 68} __packed;
67 69
70static int hfs_parse_old_pmap(struct super_block *sb, struct old_pmap *pm,
71 sector_t *part_start, sector_t *part_size)
72{
73 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
74 int i;
75
76 for (i = 0; i < 42; i++) {
77 struct old_pmap_entry *p = &pm->pdEntry[i];
78
79 if (p->pdStart && p->pdSize &&
80 p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
81 (sbi->part < 0 || sbi->part == i)) {
82 *part_start += be32_to_cpu(p->pdStart);
83 *part_size = be32_to_cpu(p->pdSize);
84 return 0;
85 }
86 }
87
88 return -ENOENT;
89}
90
91static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm,
92 sector_t *part_start, sector_t *part_size)
93{
94 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
95 int size = be32_to_cpu(pm->pmMapBlkCnt);
96 int res;
97 int i = 0;
98
99 do {
100 if (!memcmp(pm->pmPartType, "Apple_HFS", 9) &&
101 (sbi->part < 0 || sbi->part == i)) {
102 *part_start += be32_to_cpu(pm->pmPyPartStart);
103 *part_size = be32_to_cpu(pm->pmPartBlkCnt);
104 return 0;
105 }
106
107 if (++i >= size)
108 return -ENOENT;
109
110 res = hfsplus_submit_bio(sb->s_bdev,
111 *part_start + HFS_PMAP_BLK + i,
112 pm, READ);
113 if (res)
114 return res;
115 } while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC));
116
117 return -ENOENT;
118}
119
68/* 120/*
69 * hfs_part_find() 121 * Parse the partition map looking for the start and length of a
70 * 122 * HFS/HFS+ partition.
71 * Parse the partition map looking for the
72 * start and length of the 'part'th HFS partition.
73 */ 123 */
74int hfs_part_find(struct super_block *sb, 124int hfs_part_find(struct super_block *sb,
75 sector_t *part_start, sector_t *part_size) 125 sector_t *part_start, sector_t *part_size)
76{ 126{
77 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 127 void *data;
78 struct buffer_head *bh; 128 int res;
79 __be16 *data; 129
80 int i, size, res; 130 data = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
131 if (!data)
132 return -ENOMEM;
81 133
82 res = -ENOENT; 134 res = hfsplus_submit_bio(sb->s_bdev, *part_start + HFS_PMAP_BLK,
83 bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK, data); 135 data, READ);
84 if (!bh) 136 if (res)
85 return -EIO; 137 return res;
86 138
87 switch (be16_to_cpu(*data)) { 139 switch (be16_to_cpu(*((__be16 *)data))) {
88 case HFS_OLD_PMAP_MAGIC: 140 case HFS_OLD_PMAP_MAGIC:
89 { 141 res = hfs_parse_old_pmap(sb, data, part_start, part_size);
90 struct old_pmap *pm;
91 struct old_pmap_entry *p;
92
93 pm = (struct old_pmap *)bh->b_data;
94 p = pm->pdEntry;
95 size = 42;
96 for (i = 0; i < size; p++, i++) {
97 if (p->pdStart && p->pdSize &&
98 p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
99 (sbi->part < 0 || sbi->part == i)) {
100 *part_start += be32_to_cpu(p->pdStart);
101 *part_size = be32_to_cpu(p->pdSize);
102 res = 0;
103 }
104 }
105 break; 142 break;
106 }
107 case HFS_NEW_PMAP_MAGIC: 143 case HFS_NEW_PMAP_MAGIC:
108 { 144 res = hfs_parse_new_pmap(sb, data, part_start, part_size);
109 struct new_pmap *pm; 145 break;
110 146 default:
111 pm = (struct new_pmap *)bh->b_data; 147 res = -ENOENT;
112 size = be32_to_cpu(pm->pmMapBlkCnt);
113 for (i = 0; i < size;) {
114 if (!memcmp(pm->pmPartType,"Apple_HFS", 9) &&
115 (sbi->part < 0 || sbi->part == i)) {
116 *part_start += be32_to_cpu(pm->pmPyPartStart);
117 *part_size = be32_to_cpu(pm->pmPartBlkCnt);
118 res = 0;
119 break;
120 }
121 brelse(bh);
122 bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK + ++i, pm);
123 if (!bh)
124 return -EIO;
125 if (pm->pmSig != cpu_to_be16(HFS_NEW_PMAP_MAGIC))
126 break;
127 }
128 break; 148 break;
129 }
130 } 149 }
131 brelse(bh);
132 150
151 kfree(data);
133 return res; 152 return res;
134} 153}
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);
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c
index d800aa0f2c80..a3f0bfcc881e 100644
--- a/fs/hfsplus/unicode.c
+++ b/fs/hfsplus/unicode.c
@@ -17,14 +17,14 @@
17/* Returns folded char, or 0 if ignorable */ 17/* Returns folded char, or 0 if ignorable */
18static inline u16 case_fold(u16 c) 18static inline u16 case_fold(u16 c)
19{ 19{
20 u16 tmp; 20 u16 tmp;
21 21
22 tmp = hfsplus_case_fold_table[c >> 8]; 22 tmp = hfsplus_case_fold_table[c >> 8];
23 if (tmp) 23 if (tmp)
24 tmp = hfsplus_case_fold_table[tmp + (c & 0xff)]; 24 tmp = hfsplus_case_fold_table[tmp + (c & 0xff)];
25 else 25 else
26 tmp = c; 26 tmp = c;
27 return tmp; 27 return tmp;
28} 28}
29 29
30/* Compare unicode strings, return values like normal strcmp */ 30/* Compare unicode strings, return values like normal strcmp */
@@ -118,7 +118,9 @@ static u16 *hfsplus_compose_lookup(u16 *p, u16 cc)
118 return NULL; 118 return NULL;
119} 119}
120 120
121int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, char *astr, int *len_p) 121int hfsplus_uni2asc(struct super_block *sb,
122 const struct hfsplus_unistr *ustr,
123 char *astr, int *len_p)
122{ 124{
123 const hfsplus_unichr *ip; 125 const hfsplus_unichr *ip;
124 struct nls_table *nls = HFSPLUS_SB(sb)->nls; 126 struct nls_table *nls = HFSPLUS_SB(sb)->nls;
@@ -171,7 +173,8 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
171 goto same; 173 goto same;
172 c1 = be16_to_cpu(*ip); 174 c1 = be16_to_cpu(*ip);
173 if (likely(compose)) 175 if (likely(compose))
174 ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c1); 176 ce1 = hfsplus_compose_lookup(
177 hfsplus_compose_table, c1);
175 if (ce1) 178 if (ce1)
176 break; 179 break;
177 switch (c0) { 180 switch (c0) {
@@ -199,7 +202,8 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
199 if (ce2) { 202 if (ce2) {
200 i = 1; 203 i = 1;
201 while (i < ustrlen) { 204 while (i < ustrlen) {
202 ce1 = hfsplus_compose_lookup(ce2, be16_to_cpu(ip[i])); 205 ce1 = hfsplus_compose_lookup(ce2,
206 be16_to_cpu(ip[i]));
203 if (!ce1) 207 if (!ce1)
204 break; 208 break;
205 i++; 209 i++;
@@ -211,7 +215,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
211 goto done; 215 goto done;
212 } 216 }
213 } 217 }
214 same: 218same:
215 switch (c0) { 219 switch (c0) {
216 case 0: 220 case 0:
217 cc = 0x2400; 221 cc = 0x2400;
@@ -222,7 +226,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
222 default: 226 default:
223 cc = c0; 227 cc = c0;
224 } 228 }
225 done: 229done:
226 res = nls->uni2char(cc, op, len); 230 res = nls->uni2char(cc, op, len);
227 if (res < 0) { 231 if (res < 0) {
228 if (res == -ENAMETOOLONG) 232 if (res == -ENAMETOOLONG)
@@ -392,7 +396,9 @@ int hfsplus_compare_dentry(const struct dentry *parent,
392 astr1 += size; 396 astr1 += size;
393 len1 -= size; 397 len1 -= size;
394 398
395 if (!decompose || !(dstr1 = decompose_unichar(c, &dsize1))) { 399 if (decompose)
400 dstr1 = decompose_unichar(c, &dsize1);
401 if (!decompose || !dstr1) {
396 c1 = c; 402 c1 = c;
397 dstr1 = &c1; 403 dstr1 = &c1;
398 dsize1 = 1; 404 dsize1 = 1;
@@ -404,7 +410,9 @@ int hfsplus_compare_dentry(const struct dentry *parent,
404 astr2 += size; 410 astr2 += size;
405 len2 -= size; 411 len2 -= size;
406 412
407 if (!decompose || !(dstr2 = decompose_unichar(c, &dsize2))) { 413 if (decompose)
414 dstr2 = decompose_unichar(c, &dsize2);
415 if (!decompose || !dstr2) {
408 c2 = c; 416 c2 = c;
409 dstr2 = &c2; 417 dstr2 = &c2;
410 dsize2 = 1; 418 dsize2 = 1;
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}