aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hfsplus
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /fs/hfsplus
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'fs/hfsplus')
-rw-r--r--fs/hfsplus/bfind.c23
-rw-r--r--fs/hfsplus/bitmap.c23
-rw-r--r--fs/hfsplus/bnode.c70
-rw-r--r--fs/hfsplus/brec.c57
-rw-r--r--fs/hfsplus/btree.c100
-rw-r--r--fs/hfsplus/catalog.c127
-rw-r--r--fs/hfsplus/dir.c237
-rw-r--r--fs/hfsplus/extents.c275
-rw-r--r--fs/hfsplus/hfsplus_fs.h207
-rw-r--r--fs/hfsplus/hfsplus_raw.h6
-rw-r--r--fs/hfsplus/inode.c274
-rw-r--r--fs/hfsplus/ioctl.c157
-rw-r--r--fs/hfsplus/options.c54
-rw-r--r--fs/hfsplus/part_tbl.c130
-rw-r--r--fs/hfsplus/super.c508
-rw-r--r--fs/hfsplus/unicode.c72
-rw-r--r--fs/hfsplus/wrapper.c199
17 files changed, 1484 insertions, 1035 deletions
diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c
index 5007a41f1be9..5d799c13205f 100644
--- a/fs/hfsplus/bfind.c
+++ b/fs/hfsplus/bfind.c
@@ -22,8 +22,9 @@ 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 down(&tree->tree_lock); 26 tree->cnid, __builtin_return_address(0));
27 mutex_lock(&tree->tree_lock);
27 return 0; 28 return 0;
28} 29}
29 30
@@ -31,8 +32,9 @@ 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",
35 up(&fd->tree->tree_lock); 36 fd->tree->cnid, __builtin_return_address(0));
37 mutex_unlock(&fd->tree->tree_lock);
36 fd->tree = NULL; 38 fd->tree = NULL;
37} 39}
38 40
@@ -52,6 +54,10 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
52 rec = (e + b) / 2; 54 rec = (e + b) / 2;
53 len = hfs_brec_lenoff(bnode, rec, &off); 55 len = hfs_brec_lenoff(bnode, rec, &off);
54 keylen = hfs_brec_keylen(bnode, rec); 56 keylen = hfs_brec_keylen(bnode, rec);
57 if (keylen == 0) {
58 res = -EINVAL;
59 goto fail;
60 }
55 hfs_bnode_read(bnode, fd->key, off, keylen); 61 hfs_bnode_read(bnode, fd->key, off, keylen);
56 cmpval = bnode->tree->keycmp(fd->key, fd->search_key); 62 cmpval = bnode->tree->keycmp(fd->key, fd->search_key);
57 if (!cmpval) { 63 if (!cmpval) {
@@ -67,6 +73,10 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
67 if (rec != e && e >= 0) { 73 if (rec != e && e >= 0) {
68 len = hfs_brec_lenoff(bnode, e, &off); 74 len = hfs_brec_lenoff(bnode, e, &off);
69 keylen = hfs_brec_keylen(bnode, e); 75 keylen = hfs_brec_keylen(bnode, e);
76 if (keylen == 0) {
77 res = -EINVAL;
78 goto fail;
79 }
70 hfs_bnode_read(bnode, fd->key, off, keylen); 80 hfs_bnode_read(bnode, fd->key, off, keylen);
71 } 81 }
72done: 82done:
@@ -75,6 +85,7 @@ done:
75 fd->keylength = keylen; 85 fd->keylength = keylen;
76 fd->entryoffset = off + keylen; 86 fd->entryoffset = off + keylen;
77 fd->entrylength = len - keylen; 87 fd->entrylength = len - keylen;
88fail:
78 return res; 89 return res;
79} 90}
80 91
@@ -198,6 +209,10 @@ int hfs_brec_goto(struct hfs_find_data *fd, int cnt)
198 209
199 len = hfs_brec_lenoff(bnode, fd->record, &off); 210 len = hfs_brec_lenoff(bnode, fd->record, &off);
200 keylen = hfs_brec_keylen(bnode, fd->record); 211 keylen = hfs_brec_keylen(bnode, fd->record);
212 if (keylen == 0) {
213 res = -EINVAL;
214 goto out;
215 }
201 fd->keyoffset = off; 216 fd->keyoffset = off;
202 fd->keylength = keylen; 217 fd->keylength = keylen;
203 fd->entryoffset = off + keylen; 218 fd->entryoffset = off + keylen;
diff --git a/fs/hfsplus/bitmap.c b/fs/hfsplus/bitmap.c
index ea30afc2a03c..1cad80c789cb 100644
--- a/fs/hfsplus/bitmap.c
+++ b/fs/hfsplus/bitmap.c
@@ -15,8 +15,10 @@
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{
21 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
20 struct page *page; 22 struct page *page;
21 struct address_space *mapping; 23 struct address_space *mapping;
22 __be32 *pptr, *curr, *end; 24 __be32 *pptr, *curr, *end;
@@ -29,8 +31,8 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *ma
29 return size; 31 return size;
30 32
31 dprint(DBG_BITMAP, "block_allocate: %u,%u,%u\n", size, offset, len); 33 dprint(DBG_BITMAP, "block_allocate: %u,%u,%u\n", size, offset, len);
32 mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex); 34 mutex_lock(&sbi->alloc_mutex);
33 mapping = HFSPLUS_SB(sb).alloc_file->i_mapping; 35 mapping = sbi->alloc_file->i_mapping;
34 page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL); 36 page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL);
35 if (IS_ERR(page)) { 37 if (IS_ERR(page)) {
36 start = size; 38 start = size;
@@ -150,16 +152,17 @@ done:
150 set_page_dirty(page); 152 set_page_dirty(page);
151 kunmap(page); 153 kunmap(page);
152 *max = offset + (curr - pptr) * 32 + i - start; 154 *max = offset + (curr - pptr) * 32 + i - start;
153 HFSPLUS_SB(sb).free_blocks -= *max; 155 sbi->free_blocks -= *max;
154 sb->s_dirt = 1; 156 sb->s_dirt = 1;
155 dprint(DBG_BITMAP, "-> %u,%u\n", start, *max); 157 dprint(DBG_BITMAP, "-> %u,%u\n", start, *max);
156out: 158out:
157 mutex_unlock(&HFSPLUS_SB(sb).alloc_file->i_mutex); 159 mutex_unlock(&sbi->alloc_mutex);
158 return start; 160 return start;
159} 161}
160 162
161int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count) 163int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)
162{ 164{
165 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
163 struct page *page; 166 struct page *page;
164 struct address_space *mapping; 167 struct address_space *mapping;
165 __be32 *pptr, *curr, *end; 168 __be32 *pptr, *curr, *end;
@@ -172,11 +175,11 @@ int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)
172 175
173 dprint(DBG_BITMAP, "block_free: %u,%u\n", offset, count); 176 dprint(DBG_BITMAP, "block_free: %u,%u\n", offset, count);
174 /* are all of the bits in range? */ 177 /* are all of the bits in range? */
175 if ((offset + count) > HFSPLUS_SB(sb).total_blocks) 178 if ((offset + count) > sbi->total_blocks)
176 return -2; 179 return -2;
177 180
178 mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex); 181 mutex_lock(&sbi->alloc_mutex);
179 mapping = HFSPLUS_SB(sb).alloc_file->i_mapping; 182 mapping = sbi->alloc_file->i_mapping;
180 pnr = offset / PAGE_CACHE_BITS; 183 pnr = offset / PAGE_CACHE_BITS;
181 page = read_mapping_page(mapping, pnr, NULL); 184 page = read_mapping_page(mapping, pnr, NULL);
182 pptr = kmap(page); 185 pptr = kmap(page);
@@ -224,9 +227,9 @@ done:
224out: 227out:
225 set_page_dirty(page); 228 set_page_dirty(page);
226 kunmap(page); 229 kunmap(page);
227 HFSPLUS_SB(sb).free_blocks += len; 230 sbi->free_blocks += len;
228 sb->s_dirt = 1; 231 sb->s_dirt = 1;
229 mutex_unlock(&HFSPLUS_SB(sb).alloc_file->i_mutex); 232 mutex_unlock(&sbi->alloc_mutex);
230 233
231 return 0; 234 return 0;
232} 235}
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 c88e5d72a402..2312de34bd42 100644
--- a/fs/hfsplus/brec.c
+++ b/fs/hfsplus/brec.c
@@ -39,13 +39,17 @@ 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 if (node->tree->attributes & HFS_TREE_BIGKEYS) 46
46 retval = hfs_bnode_read_u16(node, recoff) + 2; 47 retval = hfs_bnode_read_u16(node, recoff) + 2;
47 else 48 if (retval > node->tree->max_key_len + 2) {
48 retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1; 49 printk(KERN_ERR "hfs: keylen %d too large\n",
50 retval);
51 retval = 0;
52 }
49 } 53 }
50 return retval; 54 return retval;
51} 55}
@@ -81,7 +85,8 @@ again:
81 end_rec_off = tree->node_size - (node->num_recs + 1) * 2; 85 end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
82 end_off = hfs_bnode_read_u16(node, end_rec_off); 86 end_off = hfs_bnode_read_u16(node, end_rec_off);
83 end_rec_off -= 2; 87 end_rec_off -= 2;
84 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);
85 if (size > end_rec_off - end_off) { 90 if (size > end_rec_off - end_off) {
86 if (new_node) 91 if (new_node)
87 panic("not enough room!\n"); 92 panic("not enough room!\n");
@@ -96,7 +101,9 @@ again:
96 } 101 }
97 node->num_recs++; 102 node->num_recs++;
98 /* write new last offset */ 103 /* write new last offset */
99 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);
100 hfs_bnode_write_u16(node, end_rec_off, end_off + size); 107 hfs_bnode_write_u16(node, end_rec_off, end_off + size);
101 data_off = end_off; 108 data_off = end_off;
102 data_rec_off = end_rec_off + 2; 109 data_rec_off = end_rec_off + 2;
@@ -148,7 +155,8 @@ skip:
148 if (tree->attributes & HFS_TREE_VARIDXKEYS) 155 if (tree->attributes & HFS_TREE_VARIDXKEYS)
149 key_len = be16_to_cpu(fd->search_key->key_len) + 2; 156 key_len = be16_to_cpu(fd->search_key->key_len) + 2;
150 else { 157 else {
151 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);
152 key_len = tree->max_key_len + 2; 160 key_len = tree->max_key_len + 2;
153 } 161 }
154 goto again; 162 goto again;
@@ -177,7 +185,8 @@ again:
177 mark_inode_dirty(tree->inode); 185 mark_inode_dirty(tree->inode);
178 } 186 }
179 hfs_bnode_dump(node); 187 hfs_bnode_dump(node);
180 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);
181 if (!--node->num_recs) { 190 if (!--node->num_recs) {
182 hfs_bnode_unlink(node); 191 hfs_bnode_unlink(node);
183 if (!node->parent) 192 if (!node->parent)
@@ -191,7 +200,9 @@ again:
191 __hfs_brec_find(node, fd); 200 __hfs_brec_find(node, fd);
192 goto again; 201 goto again;
193 } 202 }
194 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);
195 206
196 if (rec_off == end_off) 207 if (rec_off == end_off)
197 goto skip; 208 goto skip;
@@ -216,7 +227,7 @@ skip:
216static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) 227static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
217{ 228{
218 struct hfs_btree *tree; 229 struct hfs_btree *tree;
219 struct hfs_bnode *node, *new_node; 230 struct hfs_bnode *node, *new_node, *next_node;
220 struct hfs_bnode_desc node_desc; 231 struct hfs_bnode_desc node_desc;
221 int num_recs, new_rec_off, new_off, old_rec_off; 232 int num_recs, new_rec_off, new_off, old_rec_off;
222 int data_start, data_end, size; 233 int data_start, data_end, size;
@@ -235,6 +246,17 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
235 new_node->type = node->type; 246 new_node->type = node->type;
236 new_node->height = node->height; 247 new_node->height = node->height;
237 248
249 if (node->next)
250 next_node = hfs_bnode_find(tree, node->next);
251 else
252 next_node = NULL;
253
254 if (IS_ERR(next_node)) {
255 hfs_bnode_put(node);
256 hfs_bnode_put(new_node);
257 return next_node;
258 }
259
238 size = tree->node_size / 2 - node->num_recs * 2 - 14; 260 size = tree->node_size / 2 - node->num_recs * 2 - 14;
239 old_rec_off = tree->node_size - 4; 261 old_rec_off = tree->node_size - 4;
240 num_recs = 1; 262 num_recs = 1;
@@ -248,6 +270,8 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
248 /* panic? */ 270 /* panic? */
249 hfs_bnode_put(node); 271 hfs_bnode_put(node);
250 hfs_bnode_put(new_node); 272 hfs_bnode_put(new_node);
273 if (next_node)
274 hfs_bnode_put(next_node);
251 return ERR_PTR(-ENOSPC); 275 return ERR_PTR(-ENOSPC);
252 } 276 }
253 277
@@ -302,8 +326,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
302 hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc)); 326 hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc));
303 327
304 /* update next bnode header */ 328 /* update next bnode header */
305 if (new_node->next) { 329 if (next_node) {
306 struct hfs_bnode *next_node = hfs_bnode_find(tree, new_node->next);
307 next_node->prev = new_node->this; 330 next_node->prev = new_node->this;
308 hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc)); 331 hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc));
309 node_desc.prev = cpu_to_be32(next_node->prev); 332 node_desc.prev = cpu_to_be32(next_node->prev);
@@ -349,7 +372,8 @@ again:
349 newkeylen = hfs_bnode_read_u16(node, 14) + 2; 372 newkeylen = hfs_bnode_read_u16(node, 14) + 2;
350 else 373 else
351 fd->keylength = newkeylen = tree->max_key_len + 2; 374 fd->keylength = newkeylen = tree->max_key_len + 2;
352 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);
353 377
354 rec_off = tree->node_size - (rec + 2) * 2; 378 rec_off = tree->node_size - (rec + 2) * 2;
355 end_rec_off = tree->node_size - (parent->num_recs + 1) * 2; 379 end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
@@ -360,7 +384,7 @@ again:
360 end_off = hfs_bnode_read_u16(parent, end_rec_off); 384 end_off = hfs_bnode_read_u16(parent, end_rec_off);
361 if (end_rec_off - end_off < diff) { 385 if (end_rec_off - end_off < diff) {
362 386
363 printk(KERN_DEBUG "hfs: splitting index node...\n"); 387 dprint(DBG_BNODE_MOD, "hfs: splitting index node.\n");
364 fd->bnode = parent; 388 fd->bnode = parent;
365 new_node = hfs_bnode_split(fd); 389 new_node = hfs_bnode_split(fd);
366 if (IS_ERR(new_node)) 390 if (IS_ERR(new_node))
@@ -368,7 +392,8 @@ again:
368 parent = fd->bnode; 392 parent = fd->bnode;
369 rec = fd->record; 393 rec = fd->record;
370 rec_off = tree->node_size - (rec + 2) * 2; 394 rec_off = tree->node_size - (rec + 2) * 2;
371 end_rec_off = tree->node_size - (parent->num_recs + 1) * 2; 395 end_rec_off = tree->node_size -
396 (parent->num_recs + 1) * 2;
372 } 397 }
373 } 398 }
374 399
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index e49fcee1e293..21023d9f8ff3 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -30,7 +30,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
30 if (!tree) 30 if (!tree)
31 return NULL; 31 return NULL;
32 32
33 init_MUTEX(&tree->tree_lock); 33 mutex_init(&tree->tree_lock);
34 spin_lock_init(&tree->hash_lock); 34 spin_lock_init(&tree->hash_lock);
35 tree->sb = sb; 35 tree->sb = sb;
36 tree->cnid = id; 36 tree->cnid = id;
@@ -39,13 +39,20 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
39 goto free_tree; 39 goto free_tree;
40 tree->inode = inode; 40 tree->inode = inode;
41 41
42 if (!HFSPLUS_I(tree->inode)->first_blocks) {
43 printk(KERN_ERR
44 "hfs: invalid btree extent records (0 size).\n");
45 goto free_inode;
46 }
47
42 mapping = tree->inode->i_mapping; 48 mapping = tree->inode->i_mapping;
43 page = read_mapping_page(mapping, 0, NULL); 49 page = read_mapping_page(mapping, 0, NULL);
44 if (IS_ERR(page)) 50 if (IS_ERR(page))
45 goto free_tree; 51 goto free_inode;
46 52
47 /* Load the header */ 53 /* Load the header */
48 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));
49 tree->root = be32_to_cpu(head->root); 56 tree->root = be32_to_cpu(head->root);
50 tree->leaf_count = be32_to_cpu(head->leaf_count); 57 tree->leaf_count = be32_to_cpu(head->leaf_count);
51 tree->leaf_head = be32_to_cpu(head->leaf_head); 58 tree->leaf_head = be32_to_cpu(head->leaf_head);
@@ -57,40 +64,72 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
57 tree->max_key_len = be16_to_cpu(head->max_key_len); 64 tree->max_key_len = be16_to_cpu(head->max_key_len);
58 tree->depth = be16_to_cpu(head->depth); 65 tree->depth = be16_to_cpu(head->depth);
59 66
60 /* Set the correct compare function */ 67 /* Verify the tree and set the correct compare function */
61 if (id == HFSPLUS_EXT_CNID) { 68 switch (id) {
69 case HFSPLUS_EXT_CNID:
70 if (tree->max_key_len != HFSPLUS_EXT_KEYLEN - sizeof(u16)) {
71 printk(KERN_ERR "hfs: invalid extent max_key_len %d\n",
72 tree->max_key_len);
73 goto fail_page;
74 }
75 if (tree->attributes & HFS_TREE_VARIDXKEYS) {
76 printk(KERN_ERR "hfs: invalid extent btree flag\n");
77 goto fail_page;
78 }
79
62 tree->keycmp = hfsplus_ext_cmp_key; 80 tree->keycmp = hfsplus_ext_cmp_key;
63 } else if (id == HFSPLUS_CAT_CNID) { 81 break;
64 if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) && 82 case HFSPLUS_CAT_CNID:
83 if (tree->max_key_len != HFSPLUS_CAT_KEYLEN - sizeof(u16)) {
84 printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n",
85 tree->max_key_len);
86 goto fail_page;
87 }
88 if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) {
89 printk(KERN_ERR "hfs: invalid catalog btree flag\n");
90 goto fail_page;
91 }
92
93 if (test_bit(HFSPLUS_SB_HFSX, &HFSPLUS_SB(sb)->flags) &&
65 (head->key_type == HFSPLUS_KEY_BINARY)) 94 (head->key_type == HFSPLUS_KEY_BINARY))
66 tree->keycmp = hfsplus_cat_bin_cmp_key; 95 tree->keycmp = hfsplus_cat_bin_cmp_key;
67 else { 96 else {
68 tree->keycmp = hfsplus_cat_case_cmp_key; 97 tree->keycmp = hfsplus_cat_case_cmp_key;
69 HFSPLUS_SB(sb).flags |= HFSPLUS_SB_CASEFOLD; 98 set_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
70 } 99 }
71 } else { 100 break;
101 default:
72 printk(KERN_ERR "hfs: unknown B*Tree requested\n"); 102 printk(KERN_ERR "hfs: unknown B*Tree requested\n");
73 goto fail_page; 103 goto fail_page;
74 } 104 }
75 105
106 if (!(tree->attributes & HFS_TREE_BIGKEYS)) {
107 printk(KERN_ERR "hfs: invalid btree flag\n");
108 goto fail_page;
109 }
110
76 size = tree->node_size; 111 size = tree->node_size;
77 if (!is_power_of_2(size)) 112 if (!is_power_of_2(size))
78 goto fail_page; 113 goto fail_page;
79 if (!tree->node_count) 114 if (!tree->node_count)
80 goto fail_page; 115 goto fail_page;
116
81 tree->node_size_shift = ffs(size) - 1; 117 tree->node_size_shift = ffs(size) - 1;
82 118
83 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;
84 122
85 kunmap(page); 123 kunmap(page);
86 page_cache_release(page); 124 page_cache_release(page);
87 return tree; 125 return tree;
88 126
89 fail_page: 127 fail_page:
90 tree->inode->i_mapping->a_ops = &hfsplus_aops;
91 page_cache_release(page); 128 page_cache_release(page);
92 free_tree: 129 free_inode:
130 tree->inode->i_mapping->a_ops = &hfsplus_aops;
93 iput(tree->inode); 131 iput(tree->inode);
132 free_tree:
94 kfree(tree); 133 kfree(tree);
95 return NULL; 134 return NULL;
96} 135}
@@ -108,8 +147,10 @@ void hfs_btree_close(struct hfs_btree *tree)
108 while ((node = tree->node_hash[i])) { 147 while ((node = tree->node_hash[i])) {
109 tree->node_hash[i] = node->next_hash; 148 tree->node_hash[i] = node->next_hash;
110 if (atomic_read(&node->refcnt)) 149 if (atomic_read(&node->refcnt))
111 printk(KERN_CRIT "hfs: node %d:%d still has %d user(s)!\n", 150 printk(KERN_CRIT "hfs: node %d:%d "
112 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));
113 hfs_bnode_free(node); 154 hfs_bnode_free(node);
114 tree->node_hash_cnt--; 155 tree->node_hash_cnt--;
115 } 156 }
@@ -130,7 +171,8 @@ void hfs_btree_write(struct hfs_btree *tree)
130 return; 171 return;
131 /* Load the header */ 172 /* Load the header */
132 page = node->page[0]; 173 page = node->page[0];
133 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));
134 176
135 head->root = cpu_to_be32(tree->root); 177 head->root = cpu_to_be32(tree->root);
136 head->leaf_count = cpu_to_be32(tree->leaf_count); 178 head->leaf_count = cpu_to_be32(tree->leaf_count);
@@ -192,17 +234,18 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
192 234
193 while (!tree->free_nodes) { 235 while (!tree->free_nodes) {
194 struct inode *inode = tree->inode; 236 struct inode *inode = tree->inode;
237 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
195 u32 count; 238 u32 count;
196 int res; 239 int res;
197 240
198 res = hfsplus_file_extend(inode); 241 res = hfsplus_file_extend(inode);
199 if (res) 242 if (res)
200 return ERR_PTR(res); 243 return ERR_PTR(res);
201 HFSPLUS_I(inode).phys_size = inode->i_size = 244 hip->phys_size = inode->i_size =
202 (loff_t)HFSPLUS_I(inode).alloc_blocks << 245 (loff_t)hip->alloc_blocks <<
203 HFSPLUS_SB(tree->sb).alloc_blksz_shift; 246 HFSPLUS_SB(tree->sb)->alloc_blksz_shift;
204 HFSPLUS_I(inode).fs_blocks = HFSPLUS_I(inode).alloc_blocks << 247 hip->fs_blocks =
205 HFSPLUS_SB(tree->sb).fs_shift; 248 hip->alloc_blocks << HFSPLUS_SB(tree->sb)->fs_shift;
206 inode_set_bytes(inode, inode->i_size); 249 inode_set_bytes(inode, inode->i_size);
207 count = inode->i_size >> tree->node_size_shift; 250 count = inode->i_size >> tree->node_size_shift;
208 tree->free_nodes = count - tree->node_count; 251 tree->free_nodes = count - tree->node_count;
@@ -235,7 +278,8 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
235 tree->free_nodes--; 278 tree->free_nodes--;
236 mark_inode_dirty(tree->inode); 279 mark_inode_dirty(tree->inode);
237 hfs_bnode_put(node); 280 hfs_bnode_put(node);
238 return hfs_bnode_create(tree, idx); 281 return hfs_bnode_create(tree,
282 idx);
239 } 283 }
240 } 284 }
241 } 285 }
@@ -250,7 +294,7 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
250 kunmap(*pagep); 294 kunmap(*pagep);
251 nidx = node->next; 295 nidx = node->next;
252 if (!nidx) { 296 if (!nidx) {
253 printk(KERN_DEBUG "hfs: create new bmap node...\n"); 297 dprint(DBG_BNODE_MOD, "hfs: create new bmap node.\n");
254 next_node = hfs_bmap_new_bmap(node, idx); 298 next_node = hfs_bmap_new_bmap(node, idx);
255 } else 299 } else
256 next_node = hfs_bnode_find(tree, nidx); 300 next_node = hfs_bnode_find(tree, nidx);
@@ -292,7 +336,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
292 hfs_bnode_put(node); 336 hfs_bnode_put(node);
293 if (!i) { 337 if (!i) {
294 /* panic */; 338 /* panic */;
295 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);
296 return; 342 return;
297 } 343 }
298 node = hfs_bnode_find(tree, i); 344 node = hfs_bnode_find(tree, i);
@@ -300,7 +346,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
300 return; 346 return;
301 if (node->type != HFS_NODE_MAP) { 347 if (node->type != HFS_NODE_MAP) {
302 /* panic */; 348 /* panic */;
303 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);
304 hfs_bnode_put(node); 352 hfs_bnode_put(node);
305 return; 353 return;
306 } 354 }
@@ -313,7 +361,9 @@ void hfs_bmap_free(struct hfs_bnode *node)
313 m = 1 << (~nidx & 7); 361 m = 1 << (~nidx & 7);
314 byte = data[off]; 362 byte = data[off];
315 if (!(byte & m)) { 363 if (!(byte & m)) {
316 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);
317 kunmap(page); 367 kunmap(page);
318 hfs_bnode_put(node); 368 hfs_bnode_put(node);
319 return; 369 return;
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c
index f6874acb2cf2..b4ba1b319333 100644
--- a/fs/hfsplus/catalog.c
+++ b/fs/hfsplus/catalog.c
@@ -67,7 +67,7 @@ static void hfsplus_cat_build_key_uni(hfsplus_btree_key *key, u32 parent,
67 key->key_len = cpu_to_be16(6 + ustrlen); 67 key->key_len = cpu_to_be16(6 + ustrlen);
68} 68}
69 69
70static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms) 70void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms)
71{ 71{
72 if (inode->i_flags & S_IMMUTABLE) 72 if (inode->i_flags & S_IMMUTABLE)
73 perms->rootflags |= HFSPLUS_FLG_IMMUTABLE; 73 perms->rootflags |= HFSPLUS_FLG_IMMUTABLE;
@@ -77,15 +77,25 @@ static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
77 perms->rootflags |= HFSPLUS_FLG_APPEND; 77 perms->rootflags |= HFSPLUS_FLG_APPEND;
78 else 78 else
79 perms->rootflags &= ~HFSPLUS_FLG_APPEND; 79 perms->rootflags &= ~HFSPLUS_FLG_APPEND;
80 HFSPLUS_I(inode).rootflags = perms->rootflags; 80
81 HFSPLUS_I(inode).userflags = perms->userflags; 81 perms->userflags = HFSPLUS_I(inode)->userflags;
82 perms->mode = cpu_to_be16(inode->i_mode); 82 perms->mode = cpu_to_be16(inode->i_mode);
83 perms->owner = cpu_to_be32(inode->i_uid); 83 perms->owner = cpu_to_be32(inode->i_uid);
84 perms->group = cpu_to_be32(inode->i_gid); 84 perms->group = cpu_to_be32(inode->i_gid);
85
86 if (S_ISREG(inode->i_mode))
87 perms->dev = cpu_to_be32(inode->i_nlink);
88 else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode))
89 perms->dev = cpu_to_be32(inode->i_rdev);
90 else
91 perms->dev = 0;
85} 92}
86 93
87static 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)
88{ 96{
97 struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
98
89 if (S_ISDIR(inode->i_mode)) { 99 if (S_ISDIR(inode->i_mode)) {
90 struct hfsplus_cat_folder *folder; 100 struct hfsplus_cat_folder *folder;
91 101
@@ -93,13 +103,13 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i
93 memset(folder, 0, sizeof(*folder)); 103 memset(folder, 0, sizeof(*folder));
94 folder->type = cpu_to_be16(HFSPLUS_FOLDER); 104 folder->type = cpu_to_be16(HFSPLUS_FOLDER);
95 folder->id = cpu_to_be32(inode->i_ino); 105 folder->id = cpu_to_be32(inode->i_ino);
96 HFSPLUS_I(inode).create_date = 106 HFSPLUS_I(inode)->create_date =
97 folder->create_date = 107 folder->create_date =
98 folder->content_mod_date = 108 folder->content_mod_date =
99 folder->attribute_mod_date = 109 folder->attribute_mod_date =
100 folder->access_date = hfsp_now2mt(); 110 folder->access_date = hfsp_now2mt();
101 hfsplus_set_perms(inode, &folder->permissions); 111 hfsplus_cat_set_perms(inode, &folder->permissions);
102 if (inode == HFSPLUS_SB(inode->i_sb).hidden_dir) 112 if (inode == sbi->hidden_dir)
103 /* invisible and namelocked */ 113 /* invisible and namelocked */
104 folder->user_info.frFlags = cpu_to_be16(0x5000); 114 folder->user_info.frFlags = cpu_to_be16(0x5000);
105 return sizeof(*folder); 115 return sizeof(*folder);
@@ -111,28 +121,40 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i
111 file->type = cpu_to_be16(HFSPLUS_FILE); 121 file->type = cpu_to_be16(HFSPLUS_FILE);
112 file->flags = cpu_to_be16(HFSPLUS_FILE_THREAD_EXISTS); 122 file->flags = cpu_to_be16(HFSPLUS_FILE_THREAD_EXISTS);
113 file->id = cpu_to_be32(cnid); 123 file->id = cpu_to_be32(cnid);
114 HFSPLUS_I(inode).create_date = 124 HFSPLUS_I(inode)->create_date =
115 file->create_date = 125 file->create_date =
116 file->content_mod_date = 126 file->content_mod_date =
117 file->attribute_mod_date = 127 file->attribute_mod_date =
118 file->access_date = hfsp_now2mt(); 128 file->access_date = hfsp_now2mt();
119 if (cnid == inode->i_ino) { 129 if (cnid == inode->i_ino) {
120 hfsplus_set_perms(inode, &file->permissions); 130 hfsplus_cat_set_perms(inode, &file->permissions);
121 if (S_ISLNK(inode->i_mode)) { 131 if (S_ISLNK(inode->i_mode)) {
122 file->user_info.fdType = cpu_to_be32(HFSP_SYMLINK_TYPE); 132 file->user_info.fdType =
123 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);
124 } else { 136 } else {
125 file->user_info.fdType = cpu_to_be32(HFSPLUS_SB(inode->i_sb).type); 137 file->user_info.fdType =
126 file->user_info.fdCreator = cpu_to_be32(HFSPLUS_SB(inode->i_sb).creator); 138 cpu_to_be32(sbi->type);
139 file->user_info.fdCreator =
140 cpu_to_be32(sbi->creator);
127 } 141 }
128 if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE) 142 if (HFSPLUS_FLG_IMMUTABLE &
129 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);
130 } else { 147 } else {
131 file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE); 148 file->user_info.fdType =
132 file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR); 149 cpu_to_be32(HFSP_HARDLINK_TYPE);
133 file->user_info.fdFlags = cpu_to_be16(0x100); 150 file->user_info.fdCreator =
134 file->create_date = HFSPLUS_I(HFSPLUS_SB(inode->i_sb).hidden_dir).create_date; 151 cpu_to_be32(HFSP_HFSPLUS_CREATOR);
135 file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode).dev); 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);
136 } 158 }
137 return sizeof(*file); 159 return sizeof(*file);
138 } 160 }
@@ -173,27 +195,30 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
173 return -EIO; 195 return -EIO;
174 } 196 }
175 197
176 hfsplus_cat_build_key_uni(fd->search_key, be32_to_cpu(tmp.thread.parentID), 198 hfsplus_cat_build_key_uni(fd->search_key,
177 &tmp.thread.nodeName); 199 be32_to_cpu(tmp.thread.parentID),
200 &tmp.thread.nodeName);
178 return hfs_brec_find(fd); 201 return hfs_brec_find(fd);
179} 202}
180 203
181int 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)
182{ 206{
207 struct super_block *sb = dir->i_sb;
183 struct hfs_find_data fd; 208 struct hfs_find_data fd;
184 struct super_block *sb;
185 hfsplus_cat_entry entry; 209 hfsplus_cat_entry entry;
186 int entry_size; 210 int entry_size;
187 int err; 211 int err;
188 212
189 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",
190 sb = dir->i_sb; 214 str->name, cnid, inode->i_nlink);
191 hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); 215 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
192 216
193 hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); 217 hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
194 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) ?
195 HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD, 220 HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD,
196 dir->i_ino, str); 221 dir->i_ino, str);
197 err = hfs_brec_find(&fd); 222 err = hfs_brec_find(&fd);
198 if (err != -ENOENT) { 223 if (err != -ENOENT) {
199 if (!err) 224 if (!err)
@@ -219,7 +244,8 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino
219 244
220 dir->i_size++; 245 dir->i_size++;
221 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 246 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
222 mark_inode_dirty(dir); 247 hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
248
223 hfs_find_exit(&fd); 249 hfs_find_exit(&fd);
224 return 0; 250 return 0;
225 251
@@ -234,16 +260,16 @@ err2:
234 260
235int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) 261int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
236{ 262{
237 struct super_block *sb; 263 struct super_block *sb = dir->i_sb;
238 struct hfs_find_data fd; 264 struct hfs_find_data fd;
239 struct hfsplus_fork_raw fork; 265 struct hfsplus_fork_raw fork;
240 struct list_head *pos; 266 struct list_head *pos;
241 int err, off; 267 int err, off;
242 u16 type; 268 u16 type;
243 269
244 dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid); 270 dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n",
245 sb = dir->i_sb; 271 str ? str->name : NULL, cnid);
246 hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); 272 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
247 273
248 if (!str) { 274 if (!str) {
249 int len; 275 int len;
@@ -253,11 +279,15 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
253 if (err) 279 if (err)
254 goto out; 280 goto out;
255 281
256 off = fd.entryoffset + offsetof(struct hfsplus_cat_thread, nodeName); 282 off = fd.entryoffset +
283 offsetof(struct hfsplus_cat_thread, nodeName);
257 fd.search_key->cat.parent = cpu_to_be32(dir->i_ino); 284 fd.search_key->cat.parent = cpu_to_be32(dir->i_ino);
258 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);
259 len = be16_to_cpu(fd.search_key->cat.name.length) * 2; 287 len = be16_to_cpu(fd.search_key->cat.name.length) * 2;
260 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);
261 fd.search_key->key_len = cpu_to_be16(6 + len); 291 fd.search_key->key_len = cpu_to_be16(6 + len);
262 } else 292 } else
263 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);
@@ -274,12 +304,13 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
274 hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_DATA); 304 hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_DATA);
275#endif 305#endif
276 306
277 off = fd.entryoffset + offsetof(struct hfsplus_cat_file, rsrc_fork); 307 off = fd.entryoffset +
308 offsetof(struct hfsplus_cat_file, rsrc_fork);
278 hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork)); 309 hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork));
279 hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC); 310 hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC);
280 } 311 }
281 312
282 list_for_each(pos, &HFSPLUS_I(dir).open_dir_list) { 313 list_for_each(pos, &HFSPLUS_I(dir)->open_dir_list) {
283 struct hfsplus_readdir_data *rd = 314 struct hfsplus_readdir_data *rd =
284 list_entry(pos, struct hfsplus_readdir_data, list); 315 list_entry(pos, struct hfsplus_readdir_data, list);
285 if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0) 316 if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0)
@@ -301,7 +332,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
301 332
302 dir->i_size--; 333 dir->i_size--;
303 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 334 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
304 mark_inode_dirty(dir); 335 hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
305out: 336out:
306 hfs_find_exit(&fd); 337 hfs_find_exit(&fd);
307 338
@@ -312,16 +343,16 @@ int hfsplus_rename_cat(u32 cnid,
312 struct inode *src_dir, struct qstr *src_name, 343 struct inode *src_dir, struct qstr *src_name,
313 struct inode *dst_dir, struct qstr *dst_name) 344 struct inode *dst_dir, struct qstr *dst_name)
314{ 345{
315 struct super_block *sb; 346 struct super_block *sb = src_dir->i_sb;
316 struct hfs_find_data src_fd, dst_fd; 347 struct hfs_find_data src_fd, dst_fd;
317 hfsplus_cat_entry entry; 348 hfsplus_cat_entry entry;
318 int entry_size, type; 349 int entry_size, type;
319 int err = 0; 350 int err = 0;
320 351
321 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,
322 dst_dir->i_ino, dst_name->name); 354 dst_dir->i_ino, dst_name->name);
323 sb = src_dir->i_sb; 355 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd);
324 hfs_find_init(HFSPLUS_SB(sb).cat_tree, &src_fd);
325 dst_fd = src_fd; 356 dst_fd = src_fd;
326 357
327 /* find the old dir entry and read the data */ 358 /* find the old dir entry and read the data */
@@ -347,7 +378,6 @@ int hfsplus_rename_cat(u32 cnid,
347 goto out; 378 goto out;
348 dst_dir->i_size++; 379 dst_dir->i_size++;
349 dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC; 380 dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC;
350 mark_inode_dirty(dst_dir);
351 381
352 /* finally remove the old entry */ 382 /* finally remove the old entry */
353 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);
@@ -359,7 +389,6 @@ int hfsplus_rename_cat(u32 cnid,
359 goto out; 389 goto out;
360 src_dir->i_size--; 390 src_dir->i_size--;
361 src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC; 391 src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC;
362 mark_inode_dirty(src_dir);
363 392
364 /* remove old thread entry */ 393 /* remove old thread entry */
365 hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL); 394 hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL);
@@ -373,7 +402,8 @@ int hfsplus_rename_cat(u32 cnid,
373 402
374 /* create new thread entry */ 403 /* create new thread entry */
375 hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL); 404 hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL);
376 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);
377 err = hfs_brec_find(&dst_fd); 407 err = hfs_brec_find(&dst_fd);
378 if (err != -ENOENT) { 408 if (err != -ENOENT) {
379 if (!err) 409 if (!err)
@@ -381,6 +411,9 @@ int hfsplus_rename_cat(u32 cnid,
381 goto out; 411 goto out;
382 } 412 }
383 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);
384out: 417out:
385 hfs_bnode_put(dst_fd.bnode); 418 hfs_bnode_put(dst_fd.bnode);
386 hfs_find_exit(&src_fd); 419 hfs_find_exit(&src_fd);
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 764fd1bdca88..4df5059c25da 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -37,9 +37,8 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
37 37
38 sb = dir->i_sb; 38 sb = dir->i_sb;
39 39
40 dentry->d_op = &hfsplus_dentry_operations;
41 dentry->d_fsdata = NULL; 40 dentry->d_fsdata = NULL;
42 hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); 41 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
43 hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); 42 hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name);
44again: 43again:
45 err = hfs_brec_read(&fd, &entry, sizeof(entry)); 44 err = hfs_brec_read(&fd, &entry, sizeof(entry));
@@ -66,11 +65,17 @@ again:
66 goto fail; 65 goto fail;
67 } 66 }
68 cnid = be32_to_cpu(entry.file.id); 67 cnid = be32_to_cpu(entry.file.id);
69 if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) && 68 if (entry.file.user_info.fdType ==
70 entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR) && 69 cpu_to_be32(HFSP_HARDLINK_TYPE) &&
71 (entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb).hidden_dir).create_date || 70 entry.file.user_info.fdCreator ==
72 entry.file.create_date == HFSPLUS_I(sb->s_root->d_inode).create_date) && 71 cpu_to_be32(HFSP_HFSPLUS_CREATOR) &&
73 HFSPLUS_SB(sb).hidden_dir) { 72 (entry.file.create_date ==
73 HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)->
74 create_date ||
75 entry.file.create_date ==
76 HFSPLUS_I(sb->s_root->d_inode)->
77 create_date) &&
78 HFSPLUS_SB(sb)->hidden_dir) {
74 struct qstr str; 79 struct qstr str;
75 char name[32]; 80 char name[32];
76 81
@@ -83,10 +88,13 @@ again:
83 linkid = 0; 88 linkid = 0;
84 } else { 89 } else {
85 dentry->d_fsdata = (void *)(unsigned long)cnid; 90 dentry->d_fsdata = (void *)(unsigned long)cnid;
86 linkid = be32_to_cpu(entry.file.permissions.dev); 91 linkid =
92 be32_to_cpu(entry.file.permissions.dev);
87 str.len = sprintf(name, "iNode%d", linkid); 93 str.len = sprintf(name, "iNode%d", linkid);
88 str.name = name; 94 str.name = name;
89 hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str); 95 hfsplus_cat_build_key(sb, fd.search_key,
96 HFSPLUS_SB(sb)->hidden_dir->i_ino,
97 &str);
90 goto again; 98 goto again;
91 } 99 }
92 } else if (!dentry->d_fsdata) 100 } else if (!dentry->d_fsdata)
@@ -101,7 +109,7 @@ again:
101 if (IS_ERR(inode)) 109 if (IS_ERR(inode))
102 return ERR_CAST(inode); 110 return ERR_CAST(inode);
103 if (S_ISREG(inode->i_mode)) 111 if (S_ISREG(inode->i_mode))
104 HFSPLUS_I(inode).dev = linkid; 112 HFSPLUS_I(inode)->linkid = linkid;
105out: 113out:
106 d_add(dentry, inode); 114 d_add(dentry, inode);
107 return NULL; 115 return NULL;
@@ -124,7 +132,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
124 if (filp->f_pos >= inode->i_size) 132 if (filp->f_pos >= inode->i_size)
125 return 0; 133 return 0;
126 134
127 hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); 135 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
128 hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); 136 hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
129 err = hfs_brec_find(&fd); 137 err = hfs_brec_find(&fd);
130 if (err) 138 if (err)
@@ -138,7 +146,8 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
138 filp->f_pos++; 146 filp->f_pos++;
139 /* fall through */ 147 /* fall through */
140 case 1: 148 case 1:
141 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); 149 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
150 fd.entrylength);
142 if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) { 151 if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) {
143 printk(KERN_ERR "hfs: bad catalog folder thread\n"); 152 printk(KERN_ERR "hfs: bad catalog folder thread\n");
144 err = -EIO; 153 err = -EIO;
@@ -168,20 +177,23 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
168 err = -EIO; 177 err = -EIO;
169 goto out; 178 goto out;
170 } 179 }
171 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); 180 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
181 fd.entrylength);
172 type = be16_to_cpu(entry.type); 182 type = be16_to_cpu(entry.type);
173 len = HFSPLUS_MAX_STRLEN; 183 len = HFSPLUS_MAX_STRLEN;
174 err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len); 184 err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len);
175 if (err) 185 if (err)
176 goto out; 186 goto out;
177 if (type == HFSPLUS_FOLDER) { 187 if (type == HFSPLUS_FOLDER) {
178 if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) { 188 if (fd.entrylength <
189 sizeof(struct hfsplus_cat_folder)) {
179 printk(KERN_ERR "hfs: small dir entry\n"); 190 printk(KERN_ERR "hfs: small dir entry\n");
180 err = -EIO; 191 err = -EIO;
181 goto out; 192 goto out;
182 } 193 }
183 if (HFSPLUS_SB(sb).hidden_dir && 194 if (HFSPLUS_SB(sb)->hidden_dir &&
184 HFSPLUS_SB(sb).hidden_dir->i_ino == be32_to_cpu(entry.folder.id)) 195 HFSPLUS_SB(sb)->hidden_dir->i_ino ==
196 be32_to_cpu(entry.folder.id))
185 goto next; 197 goto next;
186 if (filldir(dirent, strbuf, len, filp->f_pos, 198 if (filldir(dirent, strbuf, len, filp->f_pos,
187 be32_to_cpu(entry.folder.id), DT_DIR)) 199 be32_to_cpu(entry.folder.id), DT_DIR))
@@ -200,7 +212,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
200 err = -EIO; 212 err = -EIO;
201 goto out; 213 goto out;
202 } 214 }
203 next: 215next:
204 filp->f_pos++; 216 filp->f_pos++;
205 if (filp->f_pos >= inode->i_size) 217 if (filp->f_pos >= inode->i_size)
206 goto out; 218 goto out;
@@ -217,7 +229,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
217 } 229 }
218 filp->private_data = rd; 230 filp->private_data = rd;
219 rd->file = filp; 231 rd->file = filp;
220 list_add(&rd->list, &HFSPLUS_I(inode).open_dir_list); 232 list_add(&rd->list, &HFSPLUS_I(inode)->open_dir_list);
221 } 233 }
222 memcpy(&rd->key, fd.key, sizeof(struct hfsplus_cat_key)); 234 memcpy(&rd->key, fd.key, sizeof(struct hfsplus_cat_key));
223out: 235out:
@@ -229,38 +241,18 @@ static int hfsplus_dir_release(struct inode *inode, struct file *file)
229{ 241{
230 struct hfsplus_readdir_data *rd = file->private_data; 242 struct hfsplus_readdir_data *rd = file->private_data;
231 if (rd) { 243 if (rd) {
244 mutex_lock(&inode->i_mutex);
232 list_del(&rd->list); 245 list_del(&rd->list);
246 mutex_unlock(&inode->i_mutex);
233 kfree(rd); 247 kfree(rd);
234 } 248 }
235 return 0; 249 return 0;
236} 250}
237 251
238static int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode,
239 struct nameidata *nd)
240{
241 struct inode *inode;
242 int res;
243
244 inode = hfsplus_new_inode(dir->i_sb, mode);
245 if (!inode)
246 return -ENOSPC;
247
248 res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
249 if (res) {
250 inode->i_nlink = 0;
251 hfsplus_delete_inode(inode);
252 iput(inode);
253 return res;
254 }
255 hfsplus_instantiate(dentry, inode, inode->i_ino);
256 mark_inode_dirty(inode);
257 return 0;
258}
259
260static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir, 252static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
261 struct dentry *dst_dentry) 253 struct dentry *dst_dentry)
262{ 254{
263 struct super_block *sb = dst_dir->i_sb; 255 struct hfsplus_sb_info *sbi = HFSPLUS_SB(dst_dir->i_sb);
264 struct inode *inode = src_dentry->d_inode; 256 struct inode *inode = src_dentry->d_inode;
265 struct inode *src_dir = src_dentry->d_parent->d_inode; 257 struct inode *src_dir = src_dentry->d_parent->d_inode;
266 struct qstr str; 258 struct qstr str;
@@ -270,7 +262,10 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
270 262
271 if (HFSPLUS_IS_RSRC(inode)) 263 if (HFSPLUS_IS_RSRC(inode))
272 return -EPERM; 264 return -EPERM;
265 if (!S_ISREG(inode->i_mode))
266 return -EPERM;
273 267
268 mutex_lock(&sbi->vh_mutex);
274 if (inode->i_ino == (u32)(unsigned long)src_dentry->d_fsdata) { 269 if (inode->i_ino == (u32)(unsigned long)src_dentry->d_fsdata) {
275 for (;;) { 270 for (;;) {
276 get_random_bytes(&id, sizeof(cnid)); 271 get_random_bytes(&id, sizeof(cnid));
@@ -279,40 +274,42 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
279 str.len = sprintf(name, "iNode%d", id); 274 str.len = sprintf(name, "iNode%d", id);
280 res = hfsplus_rename_cat(inode->i_ino, 275 res = hfsplus_rename_cat(inode->i_ino,
281 src_dir, &src_dentry->d_name, 276 src_dir, &src_dentry->d_name,
282 HFSPLUS_SB(sb).hidden_dir, &str); 277 sbi->hidden_dir, &str);
283 if (!res) 278 if (!res)
284 break; 279 break;
285 if (res != -EEXIST) 280 if (res != -EEXIST)
286 return res; 281 goto out;
287 } 282 }
288 HFSPLUS_I(inode).dev = id; 283 HFSPLUS_I(inode)->linkid = id;
289 cnid = HFSPLUS_SB(sb).next_cnid++; 284 cnid = sbi->next_cnid++;
290 src_dentry->d_fsdata = (void *)(unsigned long)cnid; 285 src_dentry->d_fsdata = (void *)(unsigned long)cnid;
291 res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode); 286 res = hfsplus_create_cat(cnid, src_dir,
287 &src_dentry->d_name, inode);
292 if (res) 288 if (res)
293 /* panic? */ 289 /* panic? */
294 return res; 290 goto out;
295 HFSPLUS_SB(sb).file_count++; 291 sbi->file_count++;
296 } 292 }
297 cnid = HFSPLUS_SB(sb).next_cnid++; 293 cnid = sbi->next_cnid++;
298 res = hfsplus_create_cat(cnid, dst_dir, &dst_dentry->d_name, inode); 294 res = hfsplus_create_cat(cnid, dst_dir, &dst_dentry->d_name, inode);
299 if (res) 295 if (res)
300 return res; 296 goto out;
301 297
302 inc_nlink(inode); 298 inc_nlink(inode);
303 hfsplus_instantiate(dst_dentry, inode, cnid); 299 hfsplus_instantiate(dst_dentry, inode, cnid);
304 atomic_inc(&inode->i_count); 300 ihold(inode);
305 inode->i_ctime = CURRENT_TIME_SEC; 301 inode->i_ctime = CURRENT_TIME_SEC;
306 mark_inode_dirty(inode); 302 mark_inode_dirty(inode);
307 HFSPLUS_SB(sb).file_count++; 303 sbi->file_count++;
308 sb->s_dirt = 1; 304 dst_dir->i_sb->s_dirt = 1;
309 305out:
310 return 0; 306 mutex_unlock(&sbi->vh_mutex);
307 return res;
311} 308}
312 309
313static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) 310static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
314{ 311{
315 struct super_block *sb = dir->i_sb; 312 struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
316 struct inode *inode = dentry->d_inode; 313 struct inode *inode = dentry->d_inode;
317 struct qstr str; 314 struct qstr str;
318 char name[32]; 315 char name[32];
@@ -322,21 +319,24 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
322 if (HFSPLUS_IS_RSRC(inode)) 319 if (HFSPLUS_IS_RSRC(inode))
323 return -EPERM; 320 return -EPERM;
324 321
322 mutex_lock(&sbi->vh_mutex);
325 cnid = (u32)(unsigned long)dentry->d_fsdata; 323 cnid = (u32)(unsigned long)dentry->d_fsdata;
326 if (inode->i_ino == cnid && 324 if (inode->i_ino == cnid &&
327 atomic_read(&HFSPLUS_I(inode).opencnt)) { 325 atomic_read(&HFSPLUS_I(inode)->opencnt)) {
328 str.name = name; 326 str.name = name;
329 str.len = sprintf(name, "temp%lu", inode->i_ino); 327 str.len = sprintf(name, "temp%lu", inode->i_ino);
330 res = hfsplus_rename_cat(inode->i_ino, 328 res = hfsplus_rename_cat(inode->i_ino,
331 dir, &dentry->d_name, 329 dir, &dentry->d_name,
332 HFSPLUS_SB(sb).hidden_dir, &str); 330 sbi->hidden_dir, &str);
333 if (!res) 331 if (!res) {
334 inode->i_flags |= S_DEAD; 332 inode->i_flags |= S_DEAD;
335 return res; 333 drop_nlink(inode);
334 }
335 goto out;
336 } 336 }
337 res = hfsplus_delete_cat(cnid, dir, &dentry->d_name); 337 res = hfsplus_delete_cat(cnid, dir, &dentry->d_name);
338 if (res) 338 if (res)
339 return res; 339 goto out;
340 340
341 if (inode->i_nlink > 0) 341 if (inode->i_nlink > 0)
342 drop_nlink(inode); 342 drop_nlink(inode);
@@ -344,10 +344,10 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
344 clear_nlink(inode); 344 clear_nlink(inode);
345 if (!inode->i_nlink) { 345 if (!inode->i_nlink) {
346 if (inode->i_ino != cnid) { 346 if (inode->i_ino != cnid) {
347 HFSPLUS_SB(sb).file_count--; 347 sbi->file_count--;
348 if (!atomic_read(&HFSPLUS_I(inode).opencnt)) { 348 if (!atomic_read(&HFSPLUS_I(inode)->opencnt)) {
349 res = hfsplus_delete_cat(inode->i_ino, 349 res = hfsplus_delete_cat(inode->i_ino,
350 HFSPLUS_SB(sb).hidden_dir, 350 sbi->hidden_dir,
351 NULL); 351 NULL);
352 if (!res) 352 if (!res)
353 hfsplus_delete_inode(inode); 353 hfsplus_delete_inode(inode);
@@ -356,107 +356,108 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
356 } else 356 } else
357 hfsplus_delete_inode(inode); 357 hfsplus_delete_inode(inode);
358 } else 358 } else
359 HFSPLUS_SB(sb).file_count--; 359 sbi->file_count--;
360 inode->i_ctime = CURRENT_TIME_SEC; 360 inode->i_ctime = CURRENT_TIME_SEC;
361 mark_inode_dirty(inode); 361 mark_inode_dirty(inode);
362 362out:
363 mutex_unlock(&sbi->vh_mutex);
363 return res; 364 return res;
364} 365}
365 366
366static int hfsplus_mkdir(struct inode *dir, struct dentry *dentry, int mode)
367{
368 struct inode *inode;
369 int res;
370
371 inode = hfsplus_new_inode(dir->i_sb, S_IFDIR | mode);
372 if (!inode)
373 return -ENOSPC;
374
375 res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
376 if (res) {
377 inode->i_nlink = 0;
378 hfsplus_delete_inode(inode);
379 iput(inode);
380 return res;
381 }
382 hfsplus_instantiate(dentry, inode, inode->i_ino);
383 mark_inode_dirty(inode);
384 return 0;
385}
386
387static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry) 367static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry)
388{ 368{
389 struct inode *inode; 369 struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
370 struct inode *inode = dentry->d_inode;
390 int res; 371 int res;
391 372
392 inode = dentry->d_inode;
393 if (inode->i_size != 2) 373 if (inode->i_size != 2)
394 return -ENOTEMPTY; 374 return -ENOTEMPTY;
375
376 mutex_lock(&sbi->vh_mutex);
395 res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name); 377 res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name);
396 if (res) 378 if (res)
397 return res; 379 goto out;
398 clear_nlink(inode); 380 clear_nlink(inode);
399 inode->i_ctime = CURRENT_TIME_SEC; 381 inode->i_ctime = CURRENT_TIME_SEC;
400 hfsplus_delete_inode(inode); 382 hfsplus_delete_inode(inode);
401 mark_inode_dirty(inode); 383 mark_inode_dirty(inode);
402 return 0; 384out:
385 mutex_unlock(&sbi->vh_mutex);
386 return res;
403} 387}
404 388
405static int hfsplus_symlink(struct inode *dir, struct dentry *dentry, 389static int hfsplus_symlink(struct inode *dir, struct dentry *dentry,
406 const char *symname) 390 const char *symname)
407{ 391{
408 struct super_block *sb; 392 struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
409 struct inode *inode; 393 struct inode *inode;
410 int res; 394 int res = -ENOSPC;
411 395
412 sb = dir->i_sb; 396 mutex_lock(&sbi->vh_mutex);
413 inode = hfsplus_new_inode(sb, S_IFLNK | S_IRWXUGO); 397 inode = hfsplus_new_inode(dir->i_sb, S_IFLNK | S_IRWXUGO);
414 if (!inode) 398 if (!inode)
415 return -ENOSPC; 399 goto out;
416 400
417 res = page_symlink(inode, symname, strlen(symname) + 1); 401 res = page_symlink(inode, symname, strlen(symname) + 1);
418 if (res) { 402 if (res)
419 inode->i_nlink = 0; 403 goto out_err;
420 hfsplus_delete_inode(inode);
421 iput(inode);
422 return res;
423 }
424 404
425 mark_inode_dirty(inode);
426 res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); 405 res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
406 if (res)
407 goto out_err;
427 408
428 if (!res) { 409 hfsplus_instantiate(dentry, inode, inode->i_ino);
429 hfsplus_instantiate(dentry, inode, inode->i_ino); 410 mark_inode_dirty(inode);
430 mark_inode_dirty(inode); 411 goto out;
431 }
432 412
413out_err:
414 inode->i_nlink = 0;
415 hfsplus_delete_inode(inode);
416 iput(inode);
417out:
418 mutex_unlock(&sbi->vh_mutex);
433 return res; 419 return res;
434} 420}
435 421
436static int hfsplus_mknod(struct inode *dir, struct dentry *dentry, 422static int hfsplus_mknod(struct inode *dir, struct dentry *dentry,
437 int mode, dev_t rdev) 423 int mode, dev_t rdev)
438{ 424{
439 struct super_block *sb; 425 struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
440 struct inode *inode; 426 struct inode *inode;
441 int res; 427 int res = -ENOSPC;
442 428
443 sb = dir->i_sb; 429 mutex_lock(&sbi->vh_mutex);
444 inode = hfsplus_new_inode(sb, mode); 430 inode = hfsplus_new_inode(dir->i_sb, mode);
445 if (!inode) 431 if (!inode)
446 return -ENOSPC; 432 goto out;
433
434 if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode))
435 init_special_inode(inode, mode, rdev);
447 436
448 res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); 437 res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
449 if (res) { 438 if (res) {
450 inode->i_nlink = 0; 439 inode->i_nlink = 0;
451 hfsplus_delete_inode(inode); 440 hfsplus_delete_inode(inode);
452 iput(inode); 441 iput(inode);
453 return res; 442 goto out;
454 } 443 }
455 init_special_inode(inode, mode, rdev); 444
456 hfsplus_instantiate(dentry, inode, inode->i_ino); 445 hfsplus_instantiate(dentry, inode, inode->i_ino);
457 mark_inode_dirty(inode); 446 mark_inode_dirty(inode);
447out:
448 mutex_unlock(&sbi->vh_mutex);
449 return res;
450}
458 451
459 return 0; 452static int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode,
453 struct nameidata *nd)
454{
455 return hfsplus_mknod(dir, dentry, mode, 0);
456}
457
458static int hfsplus_mkdir(struct inode *dir, struct dentry *dentry, int mode)
459{
460 return hfsplus_mknod(dir, dentry, mode | S_IFDIR, 0);
460} 461}
461 462
462static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry, 463static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -466,7 +467,10 @@ static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry,
466 467
467 /* Unlink destination if it already exists */ 468 /* Unlink destination if it already exists */
468 if (new_dentry->d_inode) { 469 if (new_dentry->d_inode) {
469 res = hfsplus_unlink(new_dir, new_dentry); 470 if (S_ISDIR(new_dentry->d_inode->i_mode))
471 res = hfsplus_rmdir(new_dir, new_dentry);
472 else
473 res = hfsplus_unlink(new_dir, new_dentry);
470 if (res) 474 if (res)
471 return res; 475 return res;
472 } 476 }
@@ -492,6 +496,7 @@ const struct inode_operations hfsplus_dir_inode_operations = {
492}; 496};
493 497
494const struct file_operations hfsplus_dir_operations = { 498const struct file_operations hfsplus_dir_operations = {
499 .fsync = hfsplus_file_fsync,
495 .read = generic_read_dir, 500 .read = generic_read_dir,
496 .readdir = hfsplus_readdir, 501 .readdir = hfsplus_readdir,
497 .unlocked_ioctl = hfsplus_ioctl, 502 .unlocked_ioctl = hfsplus_ioctl,
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c
index 0022eec63cda..b1991a2a08e0 100644
--- a/fs/hfsplus/extents.c
+++ b/fs/hfsplus/extents.c
@@ -83,37 +83,60 @@ 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{
89 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
88 int res; 90 int res;
89 91
90 hfsplus_ext_build_key(fd->search_key, inode->i_ino, HFSPLUS_I(inode).cached_start, 92 WARN_ON(!mutex_is_locked(&hip->extents_lock));
91 HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); 93
94 hfsplus_ext_build_key(fd->search_key, inode->i_ino, hip->cached_start,
95 HFSPLUS_IS_RSRC(inode) ?
96 HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA);
97
92 res = hfs_brec_find(fd); 98 res = hfs_brec_find(fd);
93 if (HFSPLUS_I(inode).flags & HFSPLUS_FLG_EXT_NEW) { 99 if (hip->extent_state & HFSPLUS_EXT_NEW) {
94 if (res != -ENOENT) 100 if (res != -ENOENT)
95 return; 101 return;
96 hfs_brec_insert(fd, HFSPLUS_I(inode).cached_extents, sizeof(hfsplus_extent_rec)); 102 hfs_brec_insert(fd, hip->cached_extents,
97 HFSPLUS_I(inode).flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); 103 sizeof(hfsplus_extent_rec));
104 hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
98 } else { 105 } else {
99 if (res) 106 if (res)
100 return; 107 return;
101 hfs_bnode_write(fd->bnode, HFSPLUS_I(inode).cached_extents, fd->entryoffset, fd->entrylength); 108 hfs_bnode_write(fd->bnode, hip->cached_extents,
102 HFSPLUS_I(inode).flags &= ~HFSPLUS_FLG_EXT_DIRTY; 109 fd->entryoffset, fd->entrylength);
110 hip->extent_state &= ~HFSPLUS_EXT_DIRTY;
103 } 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);
104} 120}
105 121
106void hfsplus_ext_write_extent(struct inode *inode) 122static void hfsplus_ext_write_extent_locked(struct inode *inode)
107{ 123{
108 if (HFSPLUS_I(inode).flags & HFSPLUS_FLG_EXT_DIRTY) { 124 if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) {
109 struct hfs_find_data fd; 125 struct hfs_find_data fd;
110 126
111 hfs_find_init(HFSPLUS_SB(inode->i_sb).ext_tree, &fd); 127 hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
112 __hfsplus_ext_write_extent(inode, &fd); 128 __hfsplus_ext_write_extent(inode, &fd);
113 hfs_find_exit(&fd); 129 hfs_find_exit(&fd);
114 } 130 }
115} 131}
116 132
133void hfsplus_ext_write_extent(struct inode *inode)
134{
135 mutex_lock(&HFSPLUS_I(inode)->extents_lock);
136 hfsplus_ext_write_extent_locked(inode);
137 mutex_unlock(&HFSPLUS_I(inode)->extents_lock);
138}
139
117static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd, 140static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd,
118 struct hfsplus_extent *extent, 141 struct hfsplus_extent *extent,
119 u32 cnid, u32 block, u8 type) 142 u32 cnid, u32 block, u8 type)
@@ -130,39 +153,48 @@ static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd,
130 return -ENOENT; 153 return -ENOENT;
131 if (fd->entrylength != sizeof(hfsplus_extent_rec)) 154 if (fd->entrylength != sizeof(hfsplus_extent_rec))
132 return -EIO; 155 return -EIO;
133 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));
134 return 0; 158 return 0;
135} 159}
136 160
137static 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)
138{ 163{
164 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
139 int res; 165 int res;
140 166
141 if (HFSPLUS_I(inode).flags & HFSPLUS_FLG_EXT_DIRTY) 167 WARN_ON(!mutex_is_locked(&hip->extents_lock));
168
169 if (hip->extent_state & HFSPLUS_EXT_DIRTY)
142 __hfsplus_ext_write_extent(inode, fd); 170 __hfsplus_ext_write_extent(inode, fd);
143 171
144 res = __hfsplus_ext_read_extent(fd, HFSPLUS_I(inode).cached_extents, inode->i_ino, 172 res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino,
145 block, HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); 173 block, HFSPLUS_IS_RSRC(inode) ?
174 HFSPLUS_TYPE_RSRC :
175 HFSPLUS_TYPE_DATA);
146 if (!res) { 176 if (!res) {
147 HFSPLUS_I(inode).cached_start = be32_to_cpu(fd->key->ext.start_block); 177 hip->cached_start = be32_to_cpu(fd->key->ext.start_block);
148 HFSPLUS_I(inode).cached_blocks = hfsplus_ext_block_count(HFSPLUS_I(inode).cached_extents); 178 hip->cached_blocks =
179 hfsplus_ext_block_count(hip->cached_extents);
149 } else { 180 } else {
150 HFSPLUS_I(inode).cached_start = HFSPLUS_I(inode).cached_blocks = 0; 181 hip->cached_start = hip->cached_blocks = 0;
151 HFSPLUS_I(inode).flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); 182 hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
152 } 183 }
153 return res; 184 return res;
154} 185}
155 186
156static int hfsplus_ext_read_extent(struct inode *inode, u32 block) 187static int hfsplus_ext_read_extent(struct inode *inode, u32 block)
157{ 188{
189 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
158 struct hfs_find_data fd; 190 struct hfs_find_data fd;
159 int res; 191 int res;
160 192
161 if (block >= HFSPLUS_I(inode).cached_start && 193 if (block >= hip->cached_start &&
162 block < HFSPLUS_I(inode).cached_start + HFSPLUS_I(inode).cached_blocks) 194 block < hip->cached_start + hip->cached_blocks)
163 return 0; 195 return 0;
164 196
165 hfs_find_init(HFSPLUS_SB(inode->i_sb).ext_tree, &fd); 197 hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
166 res = __hfsplus_ext_cache_extent(&fd, inode, block); 198 res = __hfsplus_ext_cache_extent(&fd, inode, block);
167 hfs_find_exit(&fd); 199 hfs_find_exit(&fd);
168 return res; 200 return res;
@@ -172,21 +204,22 @@ static int hfsplus_ext_read_extent(struct inode *inode, u32 block)
172int hfsplus_get_block(struct inode *inode, sector_t iblock, 204int hfsplus_get_block(struct inode *inode, sector_t iblock,
173 struct buffer_head *bh_result, int create) 205 struct buffer_head *bh_result, int create)
174{ 206{
175 struct super_block *sb; 207 struct super_block *sb = inode->i_sb;
208 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
209 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
176 int res = -EIO; 210 int res = -EIO;
177 u32 ablock, dblock, mask; 211 u32 ablock, dblock, mask;
212 int was_dirty = 0;
178 int shift; 213 int shift;
179 214
180 sb = inode->i_sb;
181
182 /* Convert inode block to disk allocation block */ 215 /* Convert inode block to disk allocation block */
183 shift = HFSPLUS_SB(sb).alloc_blksz_shift - sb->s_blocksize_bits; 216 shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits;
184 ablock = iblock >> HFSPLUS_SB(sb).fs_shift; 217 ablock = iblock >> sbi->fs_shift;
185 218
186 if (iblock >= HFSPLUS_I(inode).fs_blocks) { 219 if (iblock >= hip->fs_blocks) {
187 if (iblock > HFSPLUS_I(inode).fs_blocks || !create) 220 if (iblock > hip->fs_blocks || !create)
188 return -EIO; 221 return -EIO;
189 if (ablock >= HFSPLUS_I(inode).alloc_blocks) { 222 if (ablock >= hip->alloc_blocks) {
190 res = hfsplus_file_extend(inode); 223 res = hfsplus_file_extend(inode);
191 if (res) 224 if (res)
192 return res; 225 return res;
@@ -194,36 +227,46 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
194 } else 227 } else
195 create = 0; 228 create = 0;
196 229
197 if (ablock < HFSPLUS_I(inode).first_blocks) { 230 if (ablock < hip->first_blocks) {
198 dblock = hfsplus_ext_find_block(HFSPLUS_I(inode).first_extents, ablock); 231 dblock = hfsplus_ext_find_block(hip->first_extents, ablock);
199 goto done; 232 goto done;
200 } 233 }
201 234
202 if (inode->i_ino == HFSPLUS_EXT_CNID) 235 if (inode->i_ino == HFSPLUS_EXT_CNID)
203 return -EIO; 236 return -EIO;
204 237
205 mutex_lock(&HFSPLUS_I(inode).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);
206 res = hfsplus_ext_read_extent(inode, ablock); 246 res = hfsplus_ext_read_extent(inode, ablock);
207 if (!res) { 247 if (res) {
208 dblock = hfsplus_ext_find_block(HFSPLUS_I(inode).cached_extents, ablock - 248 mutex_unlock(&hip->extents_lock);
209 HFSPLUS_I(inode).cached_start);
210 } else {
211 mutex_unlock(&HFSPLUS_I(inode).extents_lock);
212 return -EIO; 249 return -EIO;
213 } 250 }
214 mutex_unlock(&HFSPLUS_I(inode).extents_lock); 251 dblock = hfsplus_ext_find_block(hip->cached_extents,
252 ablock - hip->cached_start);
253 mutex_unlock(&hip->extents_lock);
215 254
216done: 255done:
217 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",
218 mask = (1 << HFSPLUS_SB(sb).fs_shift) - 1; 257 inode->i_ino, (long long)iblock, dblock);
219 map_bh(bh_result, sb, (dblock << HFSPLUS_SB(sb).fs_shift) + HFSPLUS_SB(sb).blockoffset + (iblock & mask)); 258 mask = (1 << sbi->fs_shift) - 1;
259 map_bh(bh_result, sb,
260 (dblock << sbi->fs_shift) + sbi->blockoffset +
261 (iblock & mask));
220 if (create) { 262 if (create) {
221 set_buffer_new(bh_result); 263 set_buffer_new(bh_result);
222 HFSPLUS_I(inode).phys_size += sb->s_blocksize; 264 hip->phys_size += sb->s_blocksize;
223 HFSPLUS_I(inode).fs_blocks++; 265 hip->fs_blocks++;
224 inode_add_bytes(inode, sb->s_blocksize); 266 inode_add_bytes(inode, sb->s_blocksize);
225 mark_inode_dirty(inode);
226 } 267 }
268 if (create || was_dirty)
269 mark_inode_dirty(inode);
227 return 0; 270 return 0;
228} 271}
229 272
@@ -306,7 +349,8 @@ found:
306 } 349 }
307} 350}
308 351
309int 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)
310{ 354{
311 struct hfs_find_data fd; 355 struct hfs_find_data fd;
312 hfsplus_extent_rec ext_entry; 356 hfsplus_extent_rec ext_entry;
@@ -327,7 +371,7 @@ int hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw
327 if (total_blocks == blocks) 371 if (total_blocks == blocks)
328 return 0; 372 return 0;
329 373
330 hfs_find_init(HFSPLUS_SB(sb).ext_tree, &fd); 374 hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
331 do { 375 do {
332 res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid, 376 res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid,
333 total_blocks, type); 377 total_blocks, type);
@@ -348,29 +392,34 @@ int hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw
348int hfsplus_file_extend(struct inode *inode) 392int hfsplus_file_extend(struct inode *inode)
349{ 393{
350 struct super_block *sb = inode->i_sb; 394 struct super_block *sb = inode->i_sb;
395 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
396 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
351 u32 start, len, goal; 397 u32 start, len, goal;
352 int res; 398 int res;
353 399
354 if (HFSPLUS_SB(sb).alloc_file->i_size * 8 < HFSPLUS_SB(sb).total_blocks - HFSPLUS_SB(sb).free_blocks + 8) { 400 if (sbi->alloc_file->i_size * 8 <
355 // extend alloc file 401 sbi->total_blocks - sbi->free_blocks + 8) {
356 printk(KERN_ERR "hfs: extend alloc file! (%Lu,%u,%u)\n", HFSPLUS_SB(sb).alloc_file->i_size * 8, 402 /* extend alloc file */
357 HFSPLUS_SB(sb).total_blocks, HFSPLUS_SB(sb).free_blocks); 403 printk(KERN_ERR "hfs: extend alloc file! "
404 "(%llu,%u,%u)\n",
405 sbi->alloc_file->i_size * 8,
406 sbi->total_blocks, sbi->free_blocks);
358 return -ENOSPC; 407 return -ENOSPC;
359 } 408 }
360 409
361 mutex_lock(&HFSPLUS_I(inode).extents_lock); 410 mutex_lock(&hip->extents_lock);
362 if (HFSPLUS_I(inode).alloc_blocks == HFSPLUS_I(inode).first_blocks) 411 if (hip->alloc_blocks == hip->first_blocks)
363 goal = hfsplus_ext_lastblock(HFSPLUS_I(inode).first_extents); 412 goal = hfsplus_ext_lastblock(hip->first_extents);
364 else { 413 else {
365 res = hfsplus_ext_read_extent(inode, HFSPLUS_I(inode).alloc_blocks); 414 res = hfsplus_ext_read_extent(inode, hip->alloc_blocks);
366 if (res) 415 if (res)
367 goto out; 416 goto out;
368 goal = hfsplus_ext_lastblock(HFSPLUS_I(inode).cached_extents); 417 goal = hfsplus_ext_lastblock(hip->cached_extents);
369 } 418 }
370 419
371 len = HFSPLUS_I(inode).clump_blocks; 420 len = hip->clump_blocks;
372 start = hfsplus_block_allocate(sb, HFSPLUS_SB(sb).total_blocks, goal, &len); 421 start = hfsplus_block_allocate(sb, sbi->total_blocks, goal, &len);
373 if (start >= HFSPLUS_SB(sb).total_blocks) { 422 if (start >= sbi->total_blocks) {
374 start = hfsplus_block_allocate(sb, goal, 0, &len); 423 start = hfsplus_block_allocate(sb, goal, 0, &len);
375 if (start >= goal) { 424 if (start >= goal) {
376 res = -ENOSPC; 425 res = -ENOSPC;
@@ -379,56 +428,56 @@ int hfsplus_file_extend(struct inode *inode)
379 } 428 }
380 429
381 dprint(DBG_EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len); 430 dprint(DBG_EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len);
382 if (HFSPLUS_I(inode).alloc_blocks <= HFSPLUS_I(inode).first_blocks) { 431
383 if (!HFSPLUS_I(inode).first_blocks) { 432 if (hip->alloc_blocks <= hip->first_blocks) {
433 if (!hip->first_blocks) {
384 dprint(DBG_EXTENT, "first extents\n"); 434 dprint(DBG_EXTENT, "first extents\n");
385 /* no extents yet */ 435 /* no extents yet */
386 HFSPLUS_I(inode).first_extents[0].start_block = cpu_to_be32(start); 436 hip->first_extents[0].start_block = cpu_to_be32(start);
387 HFSPLUS_I(inode).first_extents[0].block_count = cpu_to_be32(len); 437 hip->first_extents[0].block_count = cpu_to_be32(len);
388 res = 0; 438 res = 0;
389 } else { 439 } else {
390 /* try to append to extents in inode */ 440 /* try to append to extents in inode */
391 res = hfsplus_add_extent(HFSPLUS_I(inode).first_extents, 441 res = hfsplus_add_extent(hip->first_extents,
392 HFSPLUS_I(inode).alloc_blocks, 442 hip->alloc_blocks,
393 start, len); 443 start, len);
394 if (res == -ENOSPC) 444 if (res == -ENOSPC)
395 goto insert_extent; 445 goto insert_extent;
396 } 446 }
397 if (!res) { 447 if (!res) {
398 hfsplus_dump_extent(HFSPLUS_I(inode).first_extents); 448 hfsplus_dump_extent(hip->first_extents);
399 HFSPLUS_I(inode).first_blocks += len; 449 hip->first_blocks += len;
400 } 450 }
401 } else { 451 } else {
402 res = hfsplus_add_extent(HFSPLUS_I(inode).cached_extents, 452 res = hfsplus_add_extent(hip->cached_extents,
403 HFSPLUS_I(inode).alloc_blocks - 453 hip->alloc_blocks - hip->cached_start,
404 HFSPLUS_I(inode).cached_start,
405 start, len); 454 start, len);
406 if (!res) { 455 if (!res) {
407 hfsplus_dump_extent(HFSPLUS_I(inode).cached_extents); 456 hfsplus_dump_extent(hip->cached_extents);
408 HFSPLUS_I(inode).flags |= HFSPLUS_FLG_EXT_DIRTY; 457 hip->extent_state |= HFSPLUS_EXT_DIRTY;
409 HFSPLUS_I(inode).cached_blocks += len; 458 hip->cached_blocks += len;
410 } else if (res == -ENOSPC) 459 } else if (res == -ENOSPC)
411 goto insert_extent; 460 goto insert_extent;
412 } 461 }
413out: 462out:
414 mutex_unlock(&HFSPLUS_I(inode).extents_lock); 463 mutex_unlock(&hip->extents_lock);
415 if (!res) { 464 if (!res) {
416 HFSPLUS_I(inode).alloc_blocks += len; 465 hip->alloc_blocks += len;
417 mark_inode_dirty(inode); 466 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY);
418 } 467 }
419 return res; 468 return res;
420 469
421insert_extent: 470insert_extent:
422 dprint(DBG_EXTENT, "insert new extent\n"); 471 dprint(DBG_EXTENT, "insert new extent\n");
423 hfsplus_ext_write_extent(inode); 472 hfsplus_ext_write_extent_locked(inode);
424 473
425 memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec)); 474 memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
426 HFSPLUS_I(inode).cached_extents[0].start_block = cpu_to_be32(start); 475 hip->cached_extents[0].start_block = cpu_to_be32(start);
427 HFSPLUS_I(inode).cached_extents[0].block_count = cpu_to_be32(len); 476 hip->cached_extents[0].block_count = cpu_to_be32(len);
428 hfsplus_dump_extent(HFSPLUS_I(inode).cached_extents); 477 hfsplus_dump_extent(hip->cached_extents);
429 HFSPLUS_I(inode).flags |= HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW; 478 hip->extent_state |= HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW;
430 HFSPLUS_I(inode).cached_start = HFSPLUS_I(inode).alloc_blocks; 479 hip->cached_start = hip->alloc_blocks;
431 HFSPLUS_I(inode).cached_blocks = len; 480 hip->cached_blocks = len;
432 481
433 res = 0; 482 res = 0;
434 goto out; 483 goto out;
@@ -437,13 +486,16 @@ insert_extent:
437void hfsplus_file_truncate(struct inode *inode) 486void hfsplus_file_truncate(struct inode *inode)
438{ 487{
439 struct super_block *sb = inode->i_sb; 488 struct super_block *sb = inode->i_sb;
489 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
440 struct hfs_find_data fd; 490 struct hfs_find_data fd;
441 u32 alloc_cnt, blk_cnt, start; 491 u32 alloc_cnt, blk_cnt, start;
442 int res; 492 int res;
443 493
444 dprint(DBG_INODE, "truncate: %lu, %Lu -> %Lu\n", inode->i_ino, 494 dprint(DBG_INODE, "truncate: %lu, %llu -> %llu\n",
445 (long long)HFSPLUS_I(inode).phys_size, inode->i_size); 495 inode->i_ino, (long long)hip->phys_size,
446 if (inode->i_size > HFSPLUS_I(inode).phys_size) { 496 inode->i_size);
497
498 if (inode->i_size > hip->phys_size) {
447 struct address_space *mapping = inode->i_mapping; 499 struct address_space *mapping = inode->i_mapping;
448 struct page *page; 500 struct page *page;
449 void *fsdata; 501 void *fsdata;
@@ -455,52 +507,55 @@ void hfsplus_file_truncate(struct inode *inode)
455 &page, &fsdata); 507 &page, &fsdata);
456 if (res) 508 if (res)
457 return; 509 return;
458 res = pagecache_write_end(NULL, mapping, size, 0, 0, page, fsdata); 510 res = pagecache_write_end(NULL, mapping, size,
511 0, 0, page, fsdata);
459 if (res < 0) 512 if (res < 0)
460 return; 513 return;
461 mark_inode_dirty(inode); 514 mark_inode_dirty(inode);
462 return; 515 return;
463 } else if (inode->i_size == HFSPLUS_I(inode).phys_size) 516 } else if (inode->i_size == hip->phys_size)
464 return; 517 return;
465 518
466 blk_cnt = (inode->i_size + HFSPLUS_SB(sb).alloc_blksz - 1) >> HFSPLUS_SB(sb).alloc_blksz_shift; 519 blk_cnt = (inode->i_size + HFSPLUS_SB(sb)->alloc_blksz - 1) >>
467 alloc_cnt = HFSPLUS_I(inode).alloc_blocks; 520 HFSPLUS_SB(sb)->alloc_blksz_shift;
521 alloc_cnt = hip->alloc_blocks;
468 if (blk_cnt == alloc_cnt) 522 if (blk_cnt == alloc_cnt)
469 goto out; 523 goto out;
470 524
471 mutex_lock(&HFSPLUS_I(inode).extents_lock); 525 mutex_lock(&hip->extents_lock);
472 hfs_find_init(HFSPLUS_SB(sb).ext_tree, &fd); 526 hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
473 while (1) { 527 while (1) {
474 if (alloc_cnt == HFSPLUS_I(inode).first_blocks) { 528 if (alloc_cnt == hip->first_blocks) {
475 hfsplus_free_extents(sb, HFSPLUS_I(inode).first_extents, 529 hfsplus_free_extents(sb, hip->first_extents,
476 alloc_cnt, alloc_cnt - blk_cnt); 530 alloc_cnt, alloc_cnt - blk_cnt);
477 hfsplus_dump_extent(HFSPLUS_I(inode).first_extents); 531 hfsplus_dump_extent(hip->first_extents);
478 HFSPLUS_I(inode).first_blocks = blk_cnt; 532 hip->first_blocks = blk_cnt;
479 break; 533 break;
480 } 534 }
481 res = __hfsplus_ext_cache_extent(&fd, inode, alloc_cnt); 535 res = __hfsplus_ext_cache_extent(&fd, inode, alloc_cnt);
482 if (res) 536 if (res)
483 break; 537 break;
484 start = HFSPLUS_I(inode).cached_start; 538 start = hip->cached_start;
485 hfsplus_free_extents(sb, HFSPLUS_I(inode).cached_extents, 539 hfsplus_free_extents(sb, hip->cached_extents,
486 alloc_cnt - start, alloc_cnt - blk_cnt); 540 alloc_cnt - start, alloc_cnt - blk_cnt);
487 hfsplus_dump_extent(HFSPLUS_I(inode).cached_extents); 541 hfsplus_dump_extent(hip->cached_extents);
488 if (blk_cnt > start) { 542 if (blk_cnt > start) {
489 HFSPLUS_I(inode).flags |= HFSPLUS_FLG_EXT_DIRTY; 543 hip->extent_state |= HFSPLUS_EXT_DIRTY;
490 break; 544 break;
491 } 545 }
492 alloc_cnt = start; 546 alloc_cnt = start;
493 HFSPLUS_I(inode).cached_start = HFSPLUS_I(inode).cached_blocks = 0; 547 hip->cached_start = hip->cached_blocks = 0;
494 HFSPLUS_I(inode).flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); 548 hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
495 hfs_brec_remove(&fd); 549 hfs_brec_remove(&fd);
496 } 550 }
497 hfs_find_exit(&fd); 551 hfs_find_exit(&fd);
498 mutex_unlock(&HFSPLUS_I(inode).extents_lock); 552 mutex_unlock(&hip->extents_lock);
499 553
500 HFSPLUS_I(inode).alloc_blocks = blk_cnt; 554 hip->alloc_blocks = blk_cnt;
501out: 555out:
502 HFSPLUS_I(inode).phys_size = inode->i_size; 556 hip->phys_size = inode->i_size;
503 HFSPLUS_I(inode).fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; 557 hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >>
504 inode_set_bytes(inode, HFSPLUS_I(inode).fs_blocks << sb->s_blocksize_bits); 558 sb->s_blocksize_bits;
505 mark_inode_dirty(inode); 559 inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
560 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY);
506} 561}
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index dc856be3c2b0..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,8 +65,7 @@ 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; 68 struct mutex tree_lock;
65 struct semaphore tree_lock;
66 69
67 unsigned int pages_per_bnode; 70 unsigned int pages_per_bnode;
68 spinlock_t hash_lock; 71 spinlock_t hash_lock;
@@ -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,19 +121,25 @@ 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 /* Stuff in host order from Vol Header */ 128 /* immutable data from the volume header */
125 u32 alloc_blksz; 129 u32 alloc_blksz;
126 int alloc_blksz_shift; 130 int alloc_blksz_shift;
127 u32 total_blocks; 131 u32 total_blocks;
132 u32 data_clump_blocks, rsrc_clump_blocks;
133
134 /* mutable data from the volume header, protected by alloc_mutex */
128 u32 free_blocks; 135 u32 free_blocks;
129 u32 next_alloc; 136 struct mutex alloc_mutex;
137
138 /* mutable data from the volume header, protected by vh_mutex */
130 u32 next_cnid; 139 u32 next_cnid;
131 u32 file_count; 140 u32 file_count;
132 u32 folder_count; 141 u32 folder_count;
133 u32 data_clump_blocks, rsrc_clump_blocks; 142 struct mutex vh_mutex;
134 143
135 /* Config options */ 144 /* Config options */
136 u32 creator; 145 u32 creator;
@@ -143,49 +152,92 @@ struct hfsplus_sb_info {
143 int part, session; 152 int part, session;
144 153
145 unsigned long flags; 154 unsigned long flags;
146
147 struct hlist_head rsrc_inodes;
148}; 155};
149 156
150#define HFSPLUS_SB_WRITEBACKUP 0x0001 157#define HFSPLUS_SB_WRITEBACKUP 0
151#define HFSPLUS_SB_NODECOMPOSE 0x0002 158#define HFSPLUS_SB_NODECOMPOSE 1
152#define HFSPLUS_SB_FORCE 0x0004 159#define HFSPLUS_SB_FORCE 2
153#define HFSPLUS_SB_HFSX 0x0008 160#define HFSPLUS_SB_HFSX 3
154#define HFSPLUS_SB_CASEFOLD 0x0010 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}
155 168
156 169
157struct hfsplus_inode_info { 170struct hfsplus_inode_info {
158 struct mutex extents_lock; 171 atomic_t opencnt;
159 u32 clump_blocks, alloc_blocks; 172
160 sector_t fs_blocks; 173 /*
161 /* Allocation extents from catalog record or volume header */ 174 * Extent allocation information, protected by extents_lock.
162 hfsplus_extent_rec first_extents; 175 */
163 u32 first_blocks; 176 u32 first_blocks;
177 u32 clump_blocks;
178 u32 alloc_blocks;
179 u32 cached_start;
180 u32 cached_blocks;
181 hfsplus_extent_rec first_extents;
164 hfsplus_extent_rec cached_extents; 182 hfsplus_extent_rec cached_extents;
165 u32 cached_start, cached_blocks; 183 unsigned int extent_state;
166 atomic_t opencnt; 184 struct mutex extents_lock;
167 185
186 /*
187 * Immutable data.
188 */
168 struct inode *rsrc_inode; 189 struct inode *rsrc_inode;
169 unsigned long flags;
170
171 __be32 create_date; 190 __be32 create_date;
172 /* Device number in hfsplus_permissions in catalog */
173 u32 dev;
174 /* BSD system and user file flags */
175 u8 rootflags;
176 u8 userflags;
177 191
192 /*
193 * Protected by sbi->vh_mutex.
194 */
195 u32 linkid;
196
197 /*
198 * Accessed using atomic bitops.
199 */
200 unsigned long flags;
201
202 /*
203 * Protected by i_mutex.
204 */
205 sector_t fs_blocks;
206 u8 userflags; /* BSD user file flags */
178 struct list_head open_dir_list; 207 struct list_head open_dir_list;
179 loff_t phys_size; 208 loff_t phys_size;
209
180 struct inode vfs_inode; 210 struct inode vfs_inode;
181}; 211};
182 212
183#define HFSPLUS_FLG_RSRC 0x0001 213#define HFSPLUS_EXT_DIRTY 0x0001
184#define HFSPLUS_FLG_EXT_DIRTY 0x0002 214#define HFSPLUS_EXT_NEW 0x0002
185#define HFSPLUS_FLG_EXT_NEW 0x0004
186 215
187#define HFSPLUS_IS_DATA(inode) (!(HFSPLUS_I(inode).flags & HFSPLUS_FLG_RSRC)) 216#define HFSPLUS_I_RSRC 0 /* represents a resource fork */
188#define HFSPLUS_IS_RSRC(inode) (HFSPLUS_I(inode).flags & HFSPLUS_FLG_RSRC) 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}
228
229/*
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}
189 241
190struct hfs_find_data { 242struct hfs_find_data {
191 /* filled by caller */ 243 /* filled by caller */
@@ -303,14 +355,18 @@ int hfs_brec_read(struct hfs_find_data *, void *, int);
303int hfs_brec_goto(struct hfs_find_data *, int); 355int hfs_brec_goto(struct hfs_find_data *, int);
304 356
305/* catalog.c */ 357/* catalog.c */
306int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); 358int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *,
307int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); 359 const hfsplus_btree_key *);
308void 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 *);
309int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *); 364int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *);
310int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *); 365int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *);
311int hfsplus_delete_cat(u32, struct inode *, struct qstr *); 366int hfsplus_delete_cat(u32, struct inode *, struct qstr *);
312int hfsplus_rename_cat(u32, struct inode *, struct qstr *, 367int hfsplus_rename_cat(u32, struct inode *, struct qstr *,
313 struct inode *, struct qstr *); 368 struct inode *, struct qstr *);
369void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms);
314 370
315/* dir.c */ 371/* dir.c */
316extern const struct inode_operations hfsplus_dir_inode_operations; 372extern const struct inode_operations hfsplus_dir_inode_operations;
@@ -320,7 +376,8 @@ extern const struct file_operations hfsplus_dir_operations;
320int 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 *);
321void hfsplus_ext_write_extent(struct inode *); 377void hfsplus_ext_write_extent(struct inode *);
322int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int); 378int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int);
323int 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);
324int hfsplus_file_extend(struct inode *); 381int hfsplus_file_extend(struct inode *);
325void hfsplus_file_truncate(struct inode *); 382void hfsplus_file_truncate(struct inode *);
326 383
@@ -335,6 +392,7 @@ int hfsplus_cat_read_inode(struct inode *, struct hfs_find_data *);
335int hfsplus_cat_write_inode(struct inode *); 392int hfsplus_cat_write_inode(struct inode *);
336struct inode *hfsplus_new_inode(struct super_block *, int); 393struct inode *hfsplus_new_inode(struct super_block *, int);
337void hfsplus_delete_inode(struct inode *); 394void hfsplus_delete_inode(struct inode *);
395int hfsplus_file_fsync(struct file *file, int datasync);
338 396
339/* ioctl.c */ 397/* ioctl.c */
340long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); 398long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
@@ -346,6 +404,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size);
346 404
347/* options.c */ 405/* options.c */
348int 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);
349void hfsplus_fill_defaults(struct hfsplus_sb_info *); 408void hfsplus_fill_defaults(struct hfsplus_sb_info *);
350int hfsplus_show_options(struct seq_file *, struct vfsmount *); 409int hfsplus_show_options(struct seq_file *, struct vfsmount *);
351 410
@@ -359,56 +418,26 @@ extern u16 hfsplus_decompose_table[];
359extern u16 hfsplus_compose_table[]; 418extern u16 hfsplus_compose_table[];
360 419
361/* unicode.c */ 420/* unicode.c */
362int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); 421int hfsplus_strcasecmp(const struct hfsplus_unistr *,
363int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); 422 const struct hfsplus_unistr *);
364int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); 423int hfsplus_strcmp(const struct hfsplus_unistr *,
365int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); 424 const struct hfsplus_unistr *);
366int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str); 425int hfsplus_uni2asc(struct super_block *,
367int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2); 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);
431int hfsplus_compare_dentry(const struct dentry *parent,
432 const struct inode *pinode,
433 const struct dentry *dentry, const struct inode *inode,
434 unsigned int len, const char *str, const struct qstr *name);
368 435
369/* wrapper.c */ 436/* wrapper.c */
370int hfsplus_read_wrapper(struct super_block *); 437int hfsplus_read_wrapper(struct super_block *);
371
372int hfs_part_find(struct super_block *, sector_t *, sector_t *); 438int hfs_part_find(struct super_block *, sector_t *, sector_t *);
373 439int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
374/* access macros */ 440 void *data, int rw);
375/*
376static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb)
377{
378 return sb->s_fs_info;
379}
380static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode)
381{
382 return list_entry(inode, struct hfsplus_inode_info, vfs_inode);
383}
384*/
385#define HFSPLUS_SB(super) (*(struct hfsplus_sb_info *)(super)->s_fs_info)
386#define HFSPLUS_I(inode) (*list_entry(inode, struct hfsplus_inode_info, vfs_inode))
387
388#if 1
389#define hfsplus_kmap(p) ({ struct page *__p = (p); kmap(__p); })
390#define hfsplus_kunmap(p) ({ struct page *__p = (p); kunmap(__p); __p; })
391#else
392#define hfsplus_kmap(p) kmap(p)
393#define hfsplus_kunmap(p) kunmap(p)
394#endif
395
396#define sb_bread512(sb, sec, data) ({ \
397 struct buffer_head *__bh; \
398 sector_t __block; \
399 loff_t __start; \
400 int __offset; \
401 \
402 __start = (loff_t)(sec) << HFSPLUS_SECTOR_SHIFT;\
403 __block = __start >> (sb)->s_blocksize_bits; \
404 __offset = __start & ((sb)->s_blocksize - 1); \
405 __bh = sb_bread((sb), __block); \
406 if (likely(__bh != NULL)) \
407 data = (void *)(__bh->b_data + __offset);\
408 else \
409 data = NULL; \
410 __bh; \
411})
412 441
413/* time macros */ 442/* time macros */
414#define __hfsp_mt2ut(t) (be32_to_cpu(t) - 2082844800U) 443#define __hfsp_mt2ut(t) (be32_to_cpu(t) - 2082844800U)
@@ -419,6 +448,4 @@ static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode)
419#define hfsp_ut2mt(t) __hfsp_ut2mt((t).tv_sec) 448#define hfsp_ut2mt(t) __hfsp_ut2mt((t).tv_sec)
420#define hfsp_now2mt() __hfsp_ut2mt(get_seconds()) 449#define hfsp_now2mt() __hfsp_ut2mt(get_seconds())
421 450
422#define kdev_t_to_nr(x) (x)
423
424#endif 451#endif
diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h
index fe99fe8db61a..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+' */
@@ -200,6 +201,7 @@ struct hfsplus_cat_key {
200 struct hfsplus_unistr name; 201 struct hfsplus_unistr name;
201} __packed; 202} __packed;
202 203
204#define HFSPLUS_CAT_KEYLEN (sizeof(struct hfsplus_cat_key))
203 205
204/* Structs from hfs.h */ 206/* Structs from hfs.h */
205struct hfsp_point { 207struct hfsp_point {
@@ -323,7 +325,7 @@ struct hfsplus_ext_key {
323 __be32 start_block; 325 __be32 start_block;
324} __packed; 326} __packed;
325 327
326#define HFSPLUS_EXT_KEYLEN 12 328#define HFSPLUS_EXT_KEYLEN sizeof(struct hfsplus_ext_key)
327 329
328/* HFS+ generic BTree key */ 330/* HFS+ generic BTree key */
329typedef union { 331typedef union {
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index c5a979d62c65..b248a6cfcad9 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>
@@ -36,7 +37,7 @@ static int hfsplus_write_begin(struct file *file, struct address_space *mapping,
36 *pagep = NULL; 37 *pagep = NULL;
37 ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, 38 ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
38 hfsplus_get_block, 39 hfsplus_get_block,
39 &HFSPLUS_I(mapping->host).phys_size); 40 &HFSPLUS_I(mapping->host)->phys_size);
40 if (unlikely(ret)) { 41 if (unlikely(ret)) {
41 loff_t isize = mapping->host->i_size; 42 loff_t isize = mapping->host->i_size;
42 if (pos + len > isize) 43 if (pos + len > isize)
@@ -62,13 +63,13 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask)
62 63
63 switch (inode->i_ino) { 64 switch (inode->i_ino) {
64 case HFSPLUS_EXT_CNID: 65 case HFSPLUS_EXT_CNID:
65 tree = HFSPLUS_SB(sb).ext_tree; 66 tree = HFSPLUS_SB(sb)->ext_tree;
66 break; 67 break;
67 case HFSPLUS_CAT_CNID: 68 case HFSPLUS_CAT_CNID:
68 tree = HFSPLUS_SB(sb).cat_tree; 69 tree = HFSPLUS_SB(sb)->cat_tree;
69 break; 70 break;
70 case HFSPLUS_ATTR_CNID: 71 case HFSPLUS_ATTR_CNID:
71 tree = HFSPLUS_SB(sb).attr_tree; 72 tree = HFSPLUS_SB(sb)->attr_tree;
72 break; 73 break;
73 default: 74 default:
74 BUG(); 75 BUG();
@@ -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 {
@@ -143,7 +146,6 @@ static int hfsplus_writepages(struct address_space *mapping,
143const struct address_space_operations hfsplus_btree_aops = { 146const struct address_space_operations hfsplus_btree_aops = {
144 .readpage = hfsplus_readpage, 147 .readpage = hfsplus_readpage,
145 .writepage = hfsplus_writepage, 148 .writepage = hfsplus_writepage,
146 .sync_page = block_sync_page,
147 .write_begin = hfsplus_write_begin, 149 .write_begin = hfsplus_write_begin,
148 .write_end = generic_write_end, 150 .write_end = generic_write_end,
149 .bmap = hfsplus_bmap, 151 .bmap = hfsplus_bmap,
@@ -153,7 +155,6 @@ const struct address_space_operations hfsplus_btree_aops = {
153const struct address_space_operations hfsplus_aops = { 155const struct address_space_operations hfsplus_aops = {
154 .readpage = hfsplus_readpage, 156 .readpage = hfsplus_readpage,
155 .writepage = hfsplus_writepage, 157 .writepage = hfsplus_writepage,
156 .sync_page = block_sync_page,
157 .write_begin = hfsplus_write_begin, 158 .write_begin = hfsplus_write_begin,
158 .write_end = generic_write_end, 159 .write_end = generic_write_end,
159 .bmap = hfsplus_bmap, 160 .bmap = hfsplus_bmap,
@@ -166,18 +167,19 @@ const struct dentry_operations hfsplus_dentry_operations = {
166 .d_compare = hfsplus_compare_dentry, 167 .d_compare = hfsplus_compare_dentry,
167}; 168};
168 169
169static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry, 170static struct dentry *hfsplus_file_lookup(struct inode *dir,
170 struct nameidata *nd) 171 struct dentry *dentry, struct nameidata *nd)
171{ 172{
172 struct hfs_find_data fd; 173 struct hfs_find_data fd;
173 struct super_block *sb = dir->i_sb; 174 struct super_block *sb = dir->i_sb;
174 struct inode *inode = NULL; 175 struct inode *inode = NULL;
176 struct hfsplus_inode_info *hip;
175 int err; 177 int err;
176 178
177 if (HFSPLUS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc")) 179 if (HFSPLUS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc"))
178 goto out; 180 goto out;
179 181
180 inode = HFSPLUS_I(dir).rsrc_inode; 182 inode = HFSPLUS_I(dir)->rsrc_inode;
181 if (inode) 183 if (inode)
182 goto out; 184 goto out;
183 185
@@ -185,12 +187,15 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
185 if (!inode) 187 if (!inode)
186 return ERR_PTR(-ENOMEM); 188 return ERR_PTR(-ENOMEM);
187 189
190 hip = HFSPLUS_I(inode);
188 inode->i_ino = dir->i_ino; 191 inode->i_ino = dir->i_ino;
189 INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list); 192 INIT_LIST_HEAD(&hip->open_dir_list);
190 mutex_init(&HFSPLUS_I(inode).extents_lock); 193 mutex_init(&hip->extents_lock);
191 HFSPLUS_I(inode).flags = HFSPLUS_FLG_RSRC; 194 hip->extent_state = 0;
195 hip->flags = 0;
196 set_bit(HFSPLUS_I_RSRC, &hip->flags);
192 197
193 hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); 198 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
194 err = hfsplus_find_cat(sb, dir->i_ino, &fd); 199 err = hfsplus_find_cat(sb, dir->i_ino, &fd);
195 if (!err) 200 if (!err)
196 err = hfsplus_cat_read_inode(inode, &fd); 201 err = hfsplus_cat_read_inode(inode, &fd);
@@ -199,42 +204,48 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
199 iput(inode); 204 iput(inode);
200 return ERR_PTR(err); 205 return ERR_PTR(err);
201 } 206 }
202 HFSPLUS_I(inode).rsrc_inode = dir; 207 hip->rsrc_inode = dir;
203 HFSPLUS_I(dir).rsrc_inode = inode; 208 HFSPLUS_I(dir)->rsrc_inode = inode;
204 igrab(dir); 209 igrab(dir);
205 hlist_add_head(&inode->i_hash, &HFSPLUS_SB(sb).rsrc_inodes); 210
211 /*
212 * __mark_inode_dirty expects inodes to be hashed. Since we don't
213 * want resource fork inodes in the regular inode space, we make them
214 * appear hashed, but do not put on any lists. hlist_del()
215 * will work fine and require no locking.
216 */
217 hlist_add_fake(&inode->i_hash);
218
206 mark_inode_dirty(inode); 219 mark_inode_dirty(inode);
207out: 220out:
208 d_add(dentry, inode); 221 d_add(dentry, inode);
209 return NULL; 222 return NULL;
210} 223}
211 224
212static void hfsplus_get_perms(struct inode *inode, struct hfsplus_perm *perms, int dir) 225static void hfsplus_get_perms(struct inode *inode,
226 struct hfsplus_perm *perms, int dir)
213{ 227{
214 struct super_block *sb = inode->i_sb; 228 struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
215 u16 mode; 229 u16 mode;
216 230
217 mode = be16_to_cpu(perms->mode); 231 mode = be16_to_cpu(perms->mode);
218 232
219 inode->i_uid = be32_to_cpu(perms->owner); 233 inode->i_uid = be32_to_cpu(perms->owner);
220 if (!inode->i_uid && !mode) 234 if (!inode->i_uid && !mode)
221 inode->i_uid = HFSPLUS_SB(sb).uid; 235 inode->i_uid = sbi->uid;
222 236
223 inode->i_gid = be32_to_cpu(perms->group); 237 inode->i_gid = be32_to_cpu(perms->group);
224 if (!inode->i_gid && !mode) 238 if (!inode->i_gid && !mode)
225 inode->i_gid = HFSPLUS_SB(sb).gid; 239 inode->i_gid = sbi->gid;
226 240
227 if (dir) { 241 if (dir) {
228 mode = mode ? (mode & S_IALLUGO) : 242 mode = mode ? (mode & S_IALLUGO) : (S_IRWXUGO & ~(sbi->umask));
229 (S_IRWXUGO & ~(HFSPLUS_SB(sb).umask));
230 mode |= S_IFDIR; 243 mode |= S_IFDIR;
231 } else if (!mode) 244 } else if (!mode)
232 mode = S_IFREG | ((S_IRUGO|S_IWUGO) & 245 mode = S_IFREG | ((S_IRUGO|S_IWUGO) & ~(sbi->umask));
233 ~(HFSPLUS_SB(sb).umask));
234 inode->i_mode = mode; 246 inode->i_mode = mode;
235 247
236 HFSPLUS_I(inode).rootflags = perms->rootflags; 248 HFSPLUS_I(inode)->userflags = perms->userflags;
237 HFSPLUS_I(inode).userflags = perms->userflags;
238 if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE) 249 if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE)
239 inode->i_flags |= S_IMMUTABLE; 250 inode->i_flags |= S_IMMUTABLE;
240 else 251 else
@@ -245,30 +256,13 @@ static void hfsplus_get_perms(struct inode *inode, struct hfsplus_perm *perms, i
245 inode->i_flags &= ~S_APPEND; 256 inode->i_flags &= ~S_APPEND;
246} 257}
247 258
248static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
249{
250 if (inode->i_flags & S_IMMUTABLE)
251 perms->rootflags |= HFSPLUS_FLG_IMMUTABLE;
252 else
253 perms->rootflags &= ~HFSPLUS_FLG_IMMUTABLE;
254 if (inode->i_flags & S_APPEND)
255 perms->rootflags |= HFSPLUS_FLG_APPEND;
256 else
257 perms->rootflags &= ~HFSPLUS_FLG_APPEND;
258 perms->userflags = HFSPLUS_I(inode).userflags;
259 perms->mode = cpu_to_be16(inode->i_mode);
260 perms->owner = cpu_to_be32(inode->i_uid);
261 perms->group = cpu_to_be32(inode->i_gid);
262 perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev);
263}
264
265static int hfsplus_file_open(struct inode *inode, struct file *file) 259static int hfsplus_file_open(struct inode *inode, struct file *file)
266{ 260{
267 if (HFSPLUS_IS_RSRC(inode)) 261 if (HFSPLUS_IS_RSRC(inode))
268 inode = HFSPLUS_I(inode).rsrc_inode; 262 inode = HFSPLUS_I(inode)->rsrc_inode;
269 if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) 263 if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
270 return -EOVERFLOW; 264 return -EOVERFLOW;
271 atomic_inc(&HFSPLUS_I(inode).opencnt); 265 atomic_inc(&HFSPLUS_I(inode)->opencnt);
272 return 0; 266 return 0;
273} 267}
274 268
@@ -277,12 +271,13 @@ static int hfsplus_file_release(struct inode *inode, struct file *file)
277 struct super_block *sb = inode->i_sb; 271 struct super_block *sb = inode->i_sb;
278 272
279 if (HFSPLUS_IS_RSRC(inode)) 273 if (HFSPLUS_IS_RSRC(inode))
280 inode = HFSPLUS_I(inode).rsrc_inode; 274 inode = HFSPLUS_I(inode)->rsrc_inode;
281 if (atomic_dec_and_test(&HFSPLUS_I(inode).opencnt)) { 275 if (atomic_dec_and_test(&HFSPLUS_I(inode)->opencnt)) {
282 mutex_lock(&inode->i_mutex); 276 mutex_lock(&inode->i_mutex);
283 hfsplus_file_truncate(inode); 277 hfsplus_file_truncate(inode);
284 if (inode->i_flags & S_DEAD) { 278 if (inode->i_flags & S_DEAD) {
285 hfsplus_delete_cat(inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL); 279 hfsplus_delete_cat(inode->i_ino,
280 HFSPLUS_SB(sb)->hidden_dir, NULL);
286 hfsplus_delete_inode(inode); 281 hfsplus_delete_inode(inode);
287 } 282 }
288 mutex_unlock(&inode->i_mutex); 283 mutex_unlock(&inode->i_mutex);
@@ -311,29 +306,41 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
311 return 0; 306 return 0;
312} 307}
313 308
314static int hfsplus_file_fsync(struct file *filp, int datasync) 309int hfsplus_file_fsync(struct file *file, int datasync)
315{ 310{
316 struct inode *inode = filp->f_mapping->host; 311 struct inode *inode = file->f_mapping->host;
317 struct super_block * sb; 312 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
318 int ret, err; 313 struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
319 314 int error = 0, error2;
320 /* sync the inode to buffers */ 315
321 ret = write_inode_now(inode, 0); 316 /*
322 317 * Sync inode metadata into the catalog and extent trees.
323 /* sync the superblock to buffers */ 318 */
324 sb = inode->i_sb; 319 sync_inode_metadata(inode, 1);
325 if (sb->s_dirt) { 320
326 if (!(sb->s_flags & MS_RDONLY)) 321 /*
327 hfsplus_sync_fs(sb, 1); 322 * And explicitly write out the btrees.
328 else 323 */
329 sb->s_dirt = 0; 324 if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags))
325 error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
326
327 if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags)) {
328 error2 =
329 filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
330 if (!error)
331 error = error2;
330 } 332 }
331 333
332 /* .. finally sync the buffers to disk */ 334 if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) {
333 err = sync_blockdev(sb->s_bdev); 335 error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
334 if (!ret) 336 if (!error)
335 ret = err; 337 error = error2;
336 return ret; 338 }
339
340 if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
341 blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
342
343 return error;
337} 344}
338 345
339static const struct inode_operations hfsplus_file_inode_operations = { 346static const struct inode_operations hfsplus_file_inode_operations = {
@@ -346,7 +353,7 @@ static const struct inode_operations hfsplus_file_inode_operations = {
346}; 353};
347 354
348static const struct file_operations hfsplus_file_operations = { 355static const struct file_operations hfsplus_file_operations = {
349 .llseek = generic_file_llseek, 356 .llseek = generic_file_llseek,
350 .read = do_sync_read, 357 .read = do_sync_read,
351 .aio_read = generic_file_aio_read, 358 .aio_read = generic_file_aio_read,
352 .write = do_sync_write, 359 .write = do_sync_write,
@@ -361,47 +368,53 @@ static const struct file_operations hfsplus_file_operations = {
361 368
362struct inode *hfsplus_new_inode(struct super_block *sb, int mode) 369struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
363{ 370{
371 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
364 struct inode *inode = new_inode(sb); 372 struct inode *inode = new_inode(sb);
373 struct hfsplus_inode_info *hip;
374
365 if (!inode) 375 if (!inode)
366 return NULL; 376 return NULL;
367 377
368 inode->i_ino = HFSPLUS_SB(sb).next_cnid++; 378 inode->i_ino = sbi->next_cnid++;
369 inode->i_mode = mode; 379 inode->i_mode = mode;
370 inode->i_uid = current_fsuid(); 380 inode->i_uid = current_fsuid();
371 inode->i_gid = current_fsgid(); 381 inode->i_gid = current_fsgid();
372 inode->i_nlink = 1; 382 inode->i_nlink = 1;
373 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; 383 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
374 INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list); 384
375 mutex_init(&HFSPLUS_I(inode).extents_lock); 385 hip = HFSPLUS_I(inode);
376 atomic_set(&HFSPLUS_I(inode).opencnt, 0); 386 INIT_LIST_HEAD(&hip->open_dir_list);
377 HFSPLUS_I(inode).flags = 0; 387 mutex_init(&hip->extents_lock);
378 memset(HFSPLUS_I(inode).first_extents, 0, sizeof(hfsplus_extent_rec)); 388 atomic_set(&hip->opencnt, 0);
379 memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec)); 389 hip->extent_state = 0;
380 HFSPLUS_I(inode).alloc_blocks = 0; 390 hip->flags = 0;
381 HFSPLUS_I(inode).first_blocks = 0; 391 memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
382 HFSPLUS_I(inode).cached_start = 0; 392 memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
383 HFSPLUS_I(inode).cached_blocks = 0; 393 hip->alloc_blocks = 0;
384 HFSPLUS_I(inode).phys_size = 0; 394 hip->first_blocks = 0;
385 HFSPLUS_I(inode).fs_blocks = 0; 395 hip->cached_start = 0;
386 HFSPLUS_I(inode).rsrc_inode = NULL; 396 hip->cached_blocks = 0;
397 hip->phys_size = 0;
398 hip->fs_blocks = 0;
399 hip->rsrc_inode = NULL;
387 if (S_ISDIR(inode->i_mode)) { 400 if (S_ISDIR(inode->i_mode)) {
388 inode->i_size = 2; 401 inode->i_size = 2;
389 HFSPLUS_SB(sb).folder_count++; 402 sbi->folder_count++;
390 inode->i_op = &hfsplus_dir_inode_operations; 403 inode->i_op = &hfsplus_dir_inode_operations;
391 inode->i_fop = &hfsplus_dir_operations; 404 inode->i_fop = &hfsplus_dir_operations;
392 } else if (S_ISREG(inode->i_mode)) { 405 } else if (S_ISREG(inode->i_mode)) {
393 HFSPLUS_SB(sb).file_count++; 406 sbi->file_count++;
394 inode->i_op = &hfsplus_file_inode_operations; 407 inode->i_op = &hfsplus_file_inode_operations;
395 inode->i_fop = &hfsplus_file_operations; 408 inode->i_fop = &hfsplus_file_operations;
396 inode->i_mapping->a_ops = &hfsplus_aops; 409 inode->i_mapping->a_ops = &hfsplus_aops;
397 HFSPLUS_I(inode).clump_blocks = HFSPLUS_SB(sb).data_clump_blocks; 410 hip->clump_blocks = sbi->data_clump_blocks;
398 } else if (S_ISLNK(inode->i_mode)) { 411 } else if (S_ISLNK(inode->i_mode)) {
399 HFSPLUS_SB(sb).file_count++; 412 sbi->file_count++;
400 inode->i_op = &page_symlink_inode_operations; 413 inode->i_op = &page_symlink_inode_operations;
401 inode->i_mapping->a_ops = &hfsplus_aops; 414 inode->i_mapping->a_ops = &hfsplus_aops;
402 HFSPLUS_I(inode).clump_blocks = 1; 415 hip->clump_blocks = 1;
403 } else 416 } else
404 HFSPLUS_SB(sb).file_count++; 417 sbi->file_count++;
405 insert_inode_hash(inode); 418 insert_inode_hash(inode);
406 mark_inode_dirty(inode); 419 mark_inode_dirty(inode);
407 sb->s_dirt = 1; 420 sb->s_dirt = 1;
@@ -414,11 +427,11 @@ void hfsplus_delete_inode(struct inode *inode)
414 struct super_block *sb = inode->i_sb; 427 struct super_block *sb = inode->i_sb;
415 428
416 if (S_ISDIR(inode->i_mode)) { 429 if (S_ISDIR(inode->i_mode)) {
417 HFSPLUS_SB(sb).folder_count--; 430 HFSPLUS_SB(sb)->folder_count--;
418 sb->s_dirt = 1; 431 sb->s_dirt = 1;
419 return; 432 return;
420 } 433 }
421 HFSPLUS_SB(sb).file_count--; 434 HFSPLUS_SB(sb)->file_count--;
422 if (S_ISREG(inode->i_mode)) { 435 if (S_ISREG(inode->i_mode)) {
423 if (!inode->i_nlink) { 436 if (!inode->i_nlink) {
424 inode->i_size = 0; 437 inode->i_size = 0;
@@ -434,34 +447,40 @@ void hfsplus_delete_inode(struct inode *inode)
434void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork) 447void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
435{ 448{
436 struct super_block *sb = inode->i_sb; 449 struct super_block *sb = inode->i_sb;
450 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
451 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
437 u32 count; 452 u32 count;
438 int i; 453 int i;
439 454
440 memcpy(&HFSPLUS_I(inode).first_extents, &fork->extents, 455 memcpy(&hip->first_extents, &fork->extents, sizeof(hfsplus_extent_rec));
441 sizeof(hfsplus_extent_rec));
442 for (count = 0, i = 0; i < 8; i++) 456 for (count = 0, i = 0; i < 8; i++)
443 count += be32_to_cpu(fork->extents[i].block_count); 457 count += be32_to_cpu(fork->extents[i].block_count);
444 HFSPLUS_I(inode).first_blocks = count; 458 hip->first_blocks = count;
445 memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec)); 459 memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
446 HFSPLUS_I(inode).cached_start = 0; 460 hip->cached_start = 0;
447 HFSPLUS_I(inode).cached_blocks = 0; 461 hip->cached_blocks = 0;
448 462
449 HFSPLUS_I(inode).alloc_blocks = be32_to_cpu(fork->total_blocks); 463 hip->alloc_blocks = be32_to_cpu(fork->total_blocks);
450 inode->i_size = HFSPLUS_I(inode).phys_size = be64_to_cpu(fork->total_size); 464 hip->phys_size = inode->i_size = be64_to_cpu(fork->total_size);
451 HFSPLUS_I(inode).fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; 465 hip->fs_blocks =
452 inode_set_bytes(inode, HFSPLUS_I(inode).fs_blocks << sb->s_blocksize_bits); 466 (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
453 HFSPLUS_I(inode).clump_blocks = be32_to_cpu(fork->clump_size) >> HFSPLUS_SB(sb).alloc_blksz_shift; 467 inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
454 if (!HFSPLUS_I(inode).clump_blocks) 468 hip->clump_blocks =
455 HFSPLUS_I(inode).clump_blocks = HFSPLUS_IS_RSRC(inode) ? HFSPLUS_SB(sb).rsrc_clump_blocks : 469 be32_to_cpu(fork->clump_size) >> sbi->alloc_blksz_shift;
456 HFSPLUS_SB(sb).data_clump_blocks; 470 if (!hip->clump_blocks) {
471 hip->clump_blocks = HFSPLUS_IS_RSRC(inode) ?
472 sbi->rsrc_clump_blocks :
473 sbi->data_clump_blocks;
474 }
457} 475}
458 476
459void hfsplus_inode_write_fork(struct inode *inode, struct hfsplus_fork_raw *fork) 477void hfsplus_inode_write_fork(struct inode *inode,
478 struct hfsplus_fork_raw *fork)
460{ 479{
461 memcpy(&fork->extents, &HFSPLUS_I(inode).first_extents, 480 memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents,
462 sizeof(hfsplus_extent_rec)); 481 sizeof(hfsplus_extent_rec));
463 fork->total_size = cpu_to_be64(inode->i_size); 482 fork->total_size = cpu_to_be64(inode->i_size);
464 fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode).alloc_blocks); 483 fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode)->alloc_blocks);
465} 484}
466 485
467int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) 486int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
@@ -472,7 +491,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
472 491
473 type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset); 492 type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset);
474 493
475 HFSPLUS_I(inode).dev = 0; 494 HFSPLUS_I(inode)->linkid = 0;
476 if (type == HFSPLUS_FOLDER) { 495 if (type == HFSPLUS_FOLDER) {
477 struct hfsplus_cat_folder *folder = &entry.folder; 496 struct hfsplus_cat_folder *folder = &entry.folder;
478 497
@@ -486,8 +505,8 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
486 inode->i_atime = hfsp_mt2ut(folder->access_date); 505 inode->i_atime = hfsp_mt2ut(folder->access_date);
487 inode->i_mtime = hfsp_mt2ut(folder->content_mod_date); 506 inode->i_mtime = hfsp_mt2ut(folder->content_mod_date);
488 inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date); 507 inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date);
489 HFSPLUS_I(inode).create_date = folder->create_date; 508 HFSPLUS_I(inode)->create_date = folder->create_date;
490 HFSPLUS_I(inode).fs_blocks = 0; 509 HFSPLUS_I(inode)->fs_blocks = 0;
491 inode->i_op = &hfsplus_dir_inode_operations; 510 inode->i_op = &hfsplus_dir_inode_operations;
492 inode->i_fop = &hfsplus_dir_operations; 511 inode->i_fop = &hfsplus_dir_operations;
493 } else if (type == HFSPLUS_FILE) { 512 } else if (type == HFSPLUS_FILE) {
@@ -498,13 +517,14 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
498 hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, 517 hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
499 sizeof(struct hfsplus_cat_file)); 518 sizeof(struct hfsplus_cat_file));
500 519
501 hfsplus_inode_read_fork(inode, HFSPLUS_IS_DATA(inode) ? 520 hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ?
502 &file->data_fork : &file->rsrc_fork); 521 &file->rsrc_fork : &file->data_fork);
503 hfsplus_get_perms(inode, &file->permissions, 0); 522 hfsplus_get_perms(inode, &file->permissions, 0);
504 inode->i_nlink = 1; 523 inode->i_nlink = 1;
505 if (S_ISREG(inode->i_mode)) { 524 if (S_ISREG(inode->i_mode)) {
506 if (file->permissions.dev) 525 if (file->permissions.dev)
507 inode->i_nlink = be32_to_cpu(file->permissions.dev); 526 inode->i_nlink =
527 be32_to_cpu(file->permissions.dev);
508 inode->i_op = &hfsplus_file_inode_operations; 528 inode->i_op = &hfsplus_file_inode_operations;
509 inode->i_fop = &hfsplus_file_operations; 529 inode->i_fop = &hfsplus_file_operations;
510 inode->i_mapping->a_ops = &hfsplus_aops; 530 inode->i_mapping->a_ops = &hfsplus_aops;
@@ -518,7 +538,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
518 inode->i_atime = hfsp_mt2ut(file->access_date); 538 inode->i_atime = hfsp_mt2ut(file->access_date);
519 inode->i_mtime = hfsp_mt2ut(file->content_mod_date); 539 inode->i_mtime = hfsp_mt2ut(file->content_mod_date);
520 inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date); 540 inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date);
521 HFSPLUS_I(inode).create_date = file->create_date; 541 HFSPLUS_I(inode)->create_date = file->create_date;
522 } else { 542 } else {
523 printk(KERN_ERR "hfs: bad catalog entry used to create inode\n"); 543 printk(KERN_ERR "hfs: bad catalog entry used to create inode\n");
524 res = -EIO; 544 res = -EIO;
@@ -533,12 +553,12 @@ int hfsplus_cat_write_inode(struct inode *inode)
533 hfsplus_cat_entry entry; 553 hfsplus_cat_entry entry;
534 554
535 if (HFSPLUS_IS_RSRC(inode)) 555 if (HFSPLUS_IS_RSRC(inode))
536 main_inode = HFSPLUS_I(inode).rsrc_inode; 556 main_inode = HFSPLUS_I(inode)->rsrc_inode;
537 557
538 if (!main_inode->i_nlink) 558 if (!main_inode->i_nlink)
539 return 0; 559 return 0;
540 560
541 if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb).cat_tree, &fd)) 561 if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb)->cat_tree, &fd))
542 /* panic? */ 562 /* panic? */
543 return -EIO; 563 return -EIO;
544 564
@@ -554,7 +574,7 @@ int hfsplus_cat_write_inode(struct inode *inode)
554 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 574 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
555 sizeof(struct hfsplus_cat_folder)); 575 sizeof(struct hfsplus_cat_folder));
556 /* simple node checks? */ 576 /* simple node checks? */
557 hfsplus_set_perms(inode, &folder->permissions); 577 hfsplus_cat_set_perms(inode, &folder->permissions);
558 folder->access_date = hfsp_ut2mt(inode->i_atime); 578 folder->access_date = hfsp_ut2mt(inode->i_atime);
559 folder->content_mod_date = hfsp_ut2mt(inode->i_mtime); 579 folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
560 folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime); 580 folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
@@ -576,12 +596,10 @@ int hfsplus_cat_write_inode(struct inode *inode)
576 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 596 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
577 sizeof(struct hfsplus_cat_file)); 597 sizeof(struct hfsplus_cat_file));
578 hfsplus_inode_write_fork(inode, &file->data_fork); 598 hfsplus_inode_write_fork(inode, &file->data_fork);
579 if (S_ISREG(inode->i_mode)) 599 hfsplus_cat_set_perms(inode, &file->permissions);
580 HFSPLUS_I(inode).dev = inode->i_nlink; 600 if (HFSPLUS_FLG_IMMUTABLE &
581 if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) 601 (file->permissions.rootflags |
582 HFSPLUS_I(inode).dev = kdev_t_to_nr(inode->i_rdev); 602 file->permissions.userflags))
583 hfsplus_set_perms(inode, &file->permissions);
584 if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
585 file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); 603 file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
586 else 604 else
587 file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED); 605 file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED);
@@ -591,6 +609,8 @@ int hfsplus_cat_write_inode(struct inode *inode)
591 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 609 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
592 sizeof(struct hfsplus_cat_file)); 610 sizeof(struct hfsplus_cat_file));
593 } 611 }
612
613 set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
594out: 614out:
595 hfs_find_exit(&fd); 615 hfs_find_exit(&fd);
596 return 0; 616 return 0;
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c
index ac405f099026..fbaa6690c8e0 100644
--- a/fs/hfsplus/ioctl.c
+++ b/fs/hfsplus/ioctl.c
@@ -17,83 +17,98 @@
17#include <linux/mount.h> 17#include <linux/mount.h>
18#include <linux/sched.h> 18#include <linux/sched.h>
19#include <linux/xattr.h> 19#include <linux/xattr.h>
20#include <linux/smp_lock.h>
21#include <asm/uaccess.h> 20#include <asm/uaccess.h>
22#include "hfsplus_fs.h" 21#include "hfsplus_fs.h"
23 22
24long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 23static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
25{ 24{
26 struct inode *inode = filp->f_path.dentry->d_inode; 25 struct inode *inode = file->f_path.dentry->d_inode;
26 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
27 unsigned int flags = 0;
28
29 if (inode->i_flags & S_IMMUTABLE)
30 flags |= FS_IMMUTABLE_FL;
31 if (inode->i_flags & S_APPEND)
32 flags |= FS_APPEND_FL;
33 if (hip->userflags & HFSPLUS_FLG_NODUMP)
34 flags |= FS_NODUMP_FL;
35
36 return put_user(flags, user_flags);
37}
38
39static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
40{
41 struct inode *inode = file->f_path.dentry->d_inode;
42 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
27 unsigned int flags; 43 unsigned int flags;
44 int err = 0;
28 45
29 lock_kernel(); 46 err = mnt_want_write(file->f_path.mnt);
30 switch (cmd) { 47 if (err)
31 case HFSPLUS_IOC_EXT2_GETFLAGS: 48 goto out;
32 flags = 0;
33 if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_IMMUTABLE)
34 flags |= FS_IMMUTABLE_FL; /* EXT2_IMMUTABLE_FL */
35 if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_APPEND)
36 flags |= FS_APPEND_FL; /* EXT2_APPEND_FL */
37 if (HFSPLUS_I(inode).userflags & HFSPLUS_FLG_NODUMP)
38 flags |= FS_NODUMP_FL; /* EXT2_NODUMP_FL */
39 return put_user(flags, (int __user *)arg);
40 case HFSPLUS_IOC_EXT2_SETFLAGS: {
41 int err = 0;
42 err = mnt_want_write(filp->f_path.mnt);
43 if (err) {
44 unlock_kernel();
45 return err;
46 }
47 49
48 if (!is_owner_or_cap(inode)) { 50 if (!inode_owner_or_capable(inode)) {
49 err = -EACCES; 51 err = -EACCES;
50 goto setflags_out; 52 goto out_drop_write;
51 } 53 }
52 if (get_user(flags, (int __user *)arg)) {
53 err = -EFAULT;
54 goto setflags_out;
55 }
56 if (flags & (FS_IMMUTABLE_FL|FS_APPEND_FL) ||
57 HFSPLUS_I(inode).rootflags & (HFSPLUS_FLG_IMMUTABLE|HFSPLUS_FLG_APPEND)) {
58 if (!capable(CAP_LINUX_IMMUTABLE)) {
59 err = -EPERM;
60 goto setflags_out;
61 }
62 }
63 54
64 /* don't silently ignore unsupported ext2 flags */ 55 if (get_user(flags, user_flags)) {
65 if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) { 56 err = -EFAULT;
66 err = -EOPNOTSUPP; 57 goto out_drop_write;
67 goto setflags_out; 58 }
68 } 59
69 if (flags & FS_IMMUTABLE_FL) { /* EXT2_IMMUTABLE_FL */ 60 mutex_lock(&inode->i_mutex);
70 inode->i_flags |= S_IMMUTABLE; 61
71 HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_IMMUTABLE; 62 if ((flags & (FS_IMMUTABLE_FL|FS_APPEND_FL)) ||
72 } else { 63 inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
73 inode->i_flags &= ~S_IMMUTABLE; 64 if (!capable(CAP_LINUX_IMMUTABLE)) {
74 HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_IMMUTABLE; 65 err = -EPERM;
75 } 66 goto out_unlock_inode;
76 if (flags & FS_APPEND_FL) { /* EXT2_APPEND_FL */
77 inode->i_flags |= S_APPEND;
78 HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_APPEND;
79 } else {
80 inode->i_flags &= ~S_APPEND;
81 HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_APPEND;
82 } 67 }
83 if (flags & FS_NODUMP_FL) /* EXT2_NODUMP_FL */
84 HFSPLUS_I(inode).userflags |= HFSPLUS_FLG_NODUMP;
85 else
86 HFSPLUS_I(inode).userflags &= ~HFSPLUS_FLG_NODUMP;
87
88 inode->i_ctime = CURRENT_TIME_SEC;
89 mark_inode_dirty(inode);
90setflags_out:
91 mnt_drop_write(filp->f_path.mnt);
92 unlock_kernel();
93 return err;
94 } 68 }
69
70 /* don't silently ignore unsupported ext2 flags */
71 if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) {
72 err = -EOPNOTSUPP;
73 goto out_unlock_inode;
74 }
75
76 if (flags & FS_IMMUTABLE_FL)
77 inode->i_flags |= S_IMMUTABLE;
78 else
79 inode->i_flags &= ~S_IMMUTABLE;
80
81 if (flags & FS_APPEND_FL)
82 inode->i_flags |= S_APPEND;
83 else
84 inode->i_flags &= ~S_APPEND;
85
86 if (flags & FS_NODUMP_FL)
87 hip->userflags |= HFSPLUS_FLG_NODUMP;
88 else
89 hip->userflags &= ~HFSPLUS_FLG_NODUMP;
90
91 inode->i_ctime = CURRENT_TIME_SEC;
92 mark_inode_dirty(inode);
93
94out_unlock_inode:
95 mutex_unlock(&inode->i_mutex);
96out_drop_write:
97 mnt_drop_write(file->f_path.mnt);
98out:
99 return err;
100}
101
102long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
103{
104 void __user *argp = (void __user *)arg;
105
106 switch (cmd) {
107 case HFSPLUS_IOC_EXT2_GETFLAGS:
108 return hfsplus_ioctl_getflags(file, argp);
109 case HFSPLUS_IOC_EXT2_SETFLAGS:
110 return hfsplus_ioctl_setflags(file, argp);
95 default: 111 default:
96 unlock_kernel();
97 return -ENOTTY; 112 return -ENOTTY;
98 } 113 }
99} 114}
@@ -110,7 +125,7 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name,
110 if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) 125 if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
111 return -EOPNOTSUPP; 126 return -EOPNOTSUPP;
112 127
113 res = hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd); 128 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
114 if (res) 129 if (res)
115 return res; 130 return res;
116 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 131 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
@@ -132,9 +147,11 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name,
132 res = -ERANGE; 147 res = -ERANGE;
133 } else 148 } else
134 res = -EOPNOTSUPP; 149 res = -EOPNOTSUPP;
135 if (!res) 150 if (!res) {
136 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 151 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
137 sizeof(struct hfsplus_cat_file)); 152 sizeof(struct hfsplus_cat_file));
153 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
154 }
138out: 155out:
139 hfs_find_exit(&fd); 156 hfs_find_exit(&fd);
140 return res; 157 return res;
@@ -153,7 +170,7 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
153 return -EOPNOTSUPP; 170 return -EOPNOTSUPP;
154 171
155 if (size) { 172 if (size) {
156 res = hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd); 173 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
157 if (res) 174 if (res)
158 return res; 175 return res;
159 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 176 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
@@ -177,7 +194,7 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
177 } else 194 } else
178 res = size ? -ERANGE : 4; 195 res = size ? -ERANGE : 4;
179 } else 196 } else
180 res = -ENODATA; 197 res = -EOPNOTSUPP;
181out: 198out:
182 if (size) 199 if (size)
183 hfs_find_exit(&fd); 200 hfs_find_exit(&fd);
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index 572628b4b07d..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,20 +165,28 @@ 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 }
143 kfree(p); 174 kfree(p);
144 break; 175 break;
145 case opt_decompose: 176 case opt_decompose:
146 sbi->flags &= ~HFSPLUS_SB_NODECOMPOSE; 177 clear_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags);
147 break; 178 break;
148 case opt_nodecompose: 179 case opt_nodecompose:
149 sbi->flags |= HFSPLUS_SB_NODECOMPOSE; 180 set_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags);
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);
150 break; 187 break;
151 case opt_force: 188 case opt_force:
152 sbi->flags |= HFSPLUS_SB_FORCE; 189 set_bit(HFSPLUS_SB_FORCE, &sbi->flags);
153 break; 190 break;
154 default: 191 default:
155 return 0; 192 return 0;
@@ -171,20 +208,23 @@ done:
171 208
172int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt) 209int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
173{ 210{
174 struct hfsplus_sb_info *sbi = &HFSPLUS_SB(mnt->mnt_sb); 211 struct hfsplus_sb_info *sbi = HFSPLUS_SB(mnt->mnt_sb);
175 212
176 if (sbi->creator != HFSPLUS_DEF_CR_TYPE) 213 if (sbi->creator != HFSPLUS_DEF_CR_TYPE)
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)
184 seq_printf(seq, ",session=%u", sbi->session); 222 seq_printf(seq, ",session=%u", sbi->session);
185 if (sbi->nls) 223 if (sbi->nls)
186 seq_printf(seq, ",nls=%s", sbi->nls->charset); 224 seq_printf(seq, ",nls=%s", sbi->nls->charset);
187 if (sbi->flags & HFSPLUS_SB_NODECOMPOSE) 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 1528a6fd0299..40ad88c12c64 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,76 +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 buffer_head *bh; 127 void *data;
78 __be16 *data; 128 int res;
79 int i, size, res;
80 129
81 res = -ENOENT; 130 data = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
82 bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK, data); 131 if (!data)
83 if (!bh) 132 return -ENOMEM;
84 return -EIO;
85 133
86 switch (be16_to_cpu(*data)) { 134 res = hfsplus_submit_bio(sb->s_bdev, *part_start + HFS_PMAP_BLK,
135 data, READ);
136 if (res)
137 goto out;
138
139 switch (be16_to_cpu(*((__be16 *)data))) {
87 case HFS_OLD_PMAP_MAGIC: 140 case HFS_OLD_PMAP_MAGIC:
88 { 141 res = hfs_parse_old_pmap(sb, data, part_start, part_size);
89 struct old_pmap *pm;
90 struct old_pmap_entry *p;
91
92 pm = (struct old_pmap *)bh->b_data;
93 p = pm->pdEntry;
94 size = 42;
95 for (i = 0; i < size; p++, i++) {
96 if (p->pdStart && p->pdSize &&
97 p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
98 (HFSPLUS_SB(sb).part < 0 || HFSPLUS_SB(sb).part == i)) {
99 *part_start += be32_to_cpu(p->pdStart);
100 *part_size = be32_to_cpu(p->pdSize);
101 res = 0;
102 }
103 }
104 break; 142 break;
105 }
106 case HFS_NEW_PMAP_MAGIC: 143 case HFS_NEW_PMAP_MAGIC:
107 { 144 res = hfs_parse_new_pmap(sb, data, part_start, part_size);
108 struct new_pmap *pm; 145 break;
109 146 default:
110 pm = (struct new_pmap *)bh->b_data; 147 res = -ENOENT;
111 size = be32_to_cpu(pm->pmMapBlkCnt);
112 for (i = 0; i < size;) {
113 if (!memcmp(pm->pmPartType,"Apple_HFS", 9) &&
114 (HFSPLUS_SB(sb).part < 0 || HFSPLUS_SB(sb).part == i)) {
115 *part_start += be32_to_cpu(pm->pmPyPartStart);
116 *part_size = be32_to_cpu(pm->pmPartBlkCnt);
117 res = 0;
118 break;
119 }
120 brelse(bh);
121 bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK + ++i, pm);
122 if (!bh)
123 return -EIO;
124 if (pm->pmSig != cpu_to_be16(HFS_NEW_PMAP_MAGIC))
125 break;
126 }
127 break; 148 break;
128 }
129 } 149 }
130 brelse(bh); 150out:
131 151 kfree(data);
132 return res; 152 return res;
133} 153}
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 3b55c050c742..84a47b709f51 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -10,9 +10,9 @@
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/smp_lock.h>
16#include <linux/vfs.h> 16#include <linux/vfs.h>
17#include <linux/nls.h> 17#include <linux/nls.h>
18 18
@@ -21,40 +21,11 @@ static void hfsplus_destroy_inode(struct inode *inode);
21 21
22#include "hfsplus_fs.h" 22#include "hfsplus_fs.h"
23 23
24struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino) 24static int hfsplus_system_read_inode(struct inode *inode)
25{ 25{
26 struct hfs_find_data fd; 26 struct hfsplus_vh *vhdr = HFSPLUS_SB(inode->i_sb)->s_vhdr;
27 struct hfsplus_vh *vhdr;
28 struct inode *inode;
29 long err = -EIO;
30 27
31 inode = iget_locked(sb, ino); 28 switch (inode->i_ino) {
32 if (!inode)
33 return ERR_PTR(-ENOMEM);
34 if (!(inode->i_state & I_NEW))
35 return inode;
36
37 INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
38 mutex_init(&HFSPLUS_I(inode).extents_lock);
39 HFSPLUS_I(inode).flags = 0;
40 HFSPLUS_I(inode).rsrc_inode = NULL;
41 atomic_set(&HFSPLUS_I(inode).opencnt, 0);
42
43 if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID) {
44 read_inode:
45 hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd);
46 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
47 if (!err)
48 err = hfsplus_cat_read_inode(inode, &fd);
49 hfs_find_exit(&fd);
50 if (err)
51 goto bad_inode;
52 goto done;
53 }
54 vhdr = HFSPLUS_SB(inode->i_sb).s_vhdr;
55 switch(inode->i_ino) {
56 case HFSPLUS_ROOT_CNID:
57 goto read_inode;
58 case HFSPLUS_EXT_CNID: 29 case HFSPLUS_EXT_CNID:
59 hfsplus_inode_read_fork(inode, &vhdr->ext_file); 30 hfsplus_inode_read_fork(inode, &vhdr->ext_file);
60 inode->i_mapping->a_ops = &hfsplus_btree_aops; 31 inode->i_mapping->a_ops = &hfsplus_btree_aops;
@@ -75,74 +46,102 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
75 inode->i_mapping->a_ops = &hfsplus_btree_aops; 46 inode->i_mapping->a_ops = &hfsplus_btree_aops;
76 break; 47 break;
77 default: 48 default:
78 goto bad_inode; 49 return -EIO;
50 }
51
52 return 0;
53}
54
55struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
56{
57 struct hfs_find_data fd;
58 struct inode *inode;
59 int err;
60
61 inode = iget_locked(sb, ino);
62 if (!inode)
63 return ERR_PTR(-ENOMEM);
64 if (!(inode->i_state & I_NEW))
65 return inode;
66
67 INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list);
68 mutex_init(&HFSPLUS_I(inode)->extents_lock);
69 HFSPLUS_I(inode)->flags = 0;
70 HFSPLUS_I(inode)->extent_state = 0;
71 HFSPLUS_I(inode)->rsrc_inode = NULL;
72 atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
73
74 if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
75 inode->i_ino == HFSPLUS_ROOT_CNID) {
76 hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
77 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
78 if (!err)
79 err = hfsplus_cat_read_inode(inode, &fd);
80 hfs_find_exit(&fd);
81 } else {
82 err = hfsplus_system_read_inode(inode);
83 }
84
85 if (err) {
86 iget_failed(inode);
87 return ERR_PTR(err);
79 } 88 }
80 89
81done:
82 unlock_new_inode(inode); 90 unlock_new_inode(inode);
83 return inode; 91 return inode;
84
85bad_inode:
86 iget_failed(inode);
87 return ERR_PTR(err);
88} 92}
89 93
90static int hfsplus_write_inode(struct inode *inode, 94static int hfsplus_system_write_inode(struct inode *inode)
91 struct writeback_control *wbc)
92{ 95{
93 struct hfsplus_vh *vhdr; 96 struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
94 int ret = 0; 97 struct hfsplus_vh *vhdr = sbi->s_vhdr;
98 struct hfsplus_fork_raw *fork;
99 struct hfs_btree *tree = NULL;
95 100
96 dprint(DBG_INODE, "hfsplus_write_inode: %lu\n", inode->i_ino);
97 hfsplus_ext_write_extent(inode);
98 if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID) {
99 return hfsplus_cat_write_inode(inode);
100 }
101 vhdr = HFSPLUS_SB(inode->i_sb).s_vhdr;
102 switch (inode->i_ino) { 101 switch (inode->i_ino) {
103 case HFSPLUS_ROOT_CNID:
104 ret = hfsplus_cat_write_inode(inode);
105 break;
106 case HFSPLUS_EXT_CNID: 102 case HFSPLUS_EXT_CNID:
107 if (vhdr->ext_file.total_size != cpu_to_be64(inode->i_size)) { 103 fork = &vhdr->ext_file;
108 HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP; 104 tree = sbi->ext_tree;
109 inode->i_sb->s_dirt = 1;
110 }
111 hfsplus_inode_write_fork(inode, &vhdr->ext_file);
112 hfs_btree_write(HFSPLUS_SB(inode->i_sb).ext_tree);
113 break; 105 break;
114 case HFSPLUS_CAT_CNID: 106 case HFSPLUS_CAT_CNID:
115 if (vhdr->cat_file.total_size != cpu_to_be64(inode->i_size)) { 107 fork = &vhdr->cat_file;
116 HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP; 108 tree = sbi->cat_tree;
117 inode->i_sb->s_dirt = 1;
118 }
119 hfsplus_inode_write_fork(inode, &vhdr->cat_file);
120 hfs_btree_write(HFSPLUS_SB(inode->i_sb).cat_tree);
121 break; 109 break;
122 case HFSPLUS_ALLOC_CNID: 110 case HFSPLUS_ALLOC_CNID:
123 if (vhdr->alloc_file.total_size != cpu_to_be64(inode->i_size)) { 111 fork = &vhdr->alloc_file;
124 HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
125 inode->i_sb->s_dirt = 1;
126 }
127 hfsplus_inode_write_fork(inode, &vhdr->alloc_file);
128 break; 112 break;
129 case HFSPLUS_START_CNID: 113 case HFSPLUS_START_CNID:
130 if (vhdr->start_file.total_size != cpu_to_be64(inode->i_size)) { 114 fork = &vhdr->start_file;
131 HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
132 inode->i_sb->s_dirt = 1;
133 }
134 hfsplus_inode_write_fork(inode, &vhdr->start_file);
135 break; 115 break;
136 case HFSPLUS_ATTR_CNID: 116 case HFSPLUS_ATTR_CNID:
137 if (vhdr->attr_file.total_size != cpu_to_be64(inode->i_size)) { 117 fork = &vhdr->attr_file;
138 HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP; 118 tree = sbi->attr_tree;
139 inode->i_sb->s_dirt = 1; 119 default:
140 } 120 return -EIO;
141 hfsplus_inode_write_fork(inode, &vhdr->attr_file); 121 }
142 hfs_btree_write(HFSPLUS_SB(inode->i_sb).attr_tree); 122
143 break; 123 if (fork->total_size != cpu_to_be64(inode->i_size)) {
124 set_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags);
125 inode->i_sb->s_dirt = 1;
144 } 126 }
145 return ret; 127 hfsplus_inode_write_fork(inode, fork);
128 if (tree)
129 hfs_btree_write(tree);
130 return 0;
131}
132
133static int hfsplus_write_inode(struct inode *inode,
134 struct writeback_control *wbc)
135{
136 dprint(DBG_INODE, "hfsplus_write_inode: %lu\n", inode->i_ino);
137
138 hfsplus_ext_write_extent(inode);
139
140 if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
141 inode->i_ino == HFSPLUS_ROOT_CNID)
142 return hfsplus_cat_write_inode(inode);
143 else
144 return hfsplus_system_write_inode(inode);
146} 145}
147 146
148static void hfsplus_evict_inode(struct inode *inode) 147static void hfsplus_evict_inode(struct inode *inode)
@@ -151,52 +150,74 @@ static void hfsplus_evict_inode(struct inode *inode)
151 truncate_inode_pages(&inode->i_data, 0); 150 truncate_inode_pages(&inode->i_data, 0);
152 end_writeback(inode); 151 end_writeback(inode);
153 if (HFSPLUS_IS_RSRC(inode)) { 152 if (HFSPLUS_IS_RSRC(inode)) {
154 HFSPLUS_I(HFSPLUS_I(inode).rsrc_inode).rsrc_inode = NULL; 153 HFSPLUS_I(HFSPLUS_I(inode)->rsrc_inode)->rsrc_inode = NULL;
155 iput(HFSPLUS_I(inode).rsrc_inode); 154 iput(HFSPLUS_I(inode)->rsrc_inode);
156 } 155 }
157} 156}
158 157
159int hfsplus_sync_fs(struct super_block *sb, int wait) 158int hfsplus_sync_fs(struct super_block *sb, int wait)
160{ 159{
161 struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; 160 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
161 struct hfsplus_vh *vhdr = sbi->s_vhdr;
162 int write_backup = 0;
163 int error, error2;
164
165 if (!wait)
166 return 0;
162 167
163 dprint(DBG_SUPER, "hfsplus_write_super\n"); 168 dprint(DBG_SUPER, "hfsplus_write_super\n");
164 169
165 lock_super(sb);
166 sb->s_dirt = 0; 170 sb->s_dirt = 0;
167 171
168 vhdr->free_blocks = cpu_to_be32(HFSPLUS_SB(sb).free_blocks); 172 /*
169 vhdr->next_alloc = cpu_to_be32(HFSPLUS_SB(sb).next_alloc); 173 * Explicitly write out the special metadata inodes.
170 vhdr->next_cnid = cpu_to_be32(HFSPLUS_SB(sb).next_cnid); 174 *
171 vhdr->folder_count = cpu_to_be32(HFSPLUS_SB(sb).folder_count); 175 * While these special inodes are marked as hashed and written
172 vhdr->file_count = cpu_to_be32(HFSPLUS_SB(sb).file_count); 176 * out peridocically by the flusher threads we redirty them
173 177 * during writeout of normal inodes, and thus the life lock
174 mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh); 178 * prevents us from getting the latest state to disk.
175 if (HFSPLUS_SB(sb).flags & HFSPLUS_SB_WRITEBACKUP) { 179 */
176 if (HFSPLUS_SB(sb).sect_count) { 180 error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
177 struct buffer_head *bh; 181 error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
178 u32 block, offset; 182 if (!error)
179 183 error = error2;
180 block = HFSPLUS_SB(sb).blockoffset; 184 error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
181 block += (HFSPLUS_SB(sb).sect_count - 2) >> (sb->s_blocksize_bits - 9); 185 if (!error)
182 offset = ((HFSPLUS_SB(sb).sect_count - 2) << 9) & (sb->s_blocksize - 1); 186 error = error2;
183 printk(KERN_DEBUG "hfs: backup: %u,%u,%u,%u\n", HFSPLUS_SB(sb).blockoffset, 187
184 HFSPLUS_SB(sb).sect_count, block, offset); 188 mutex_lock(&sbi->vh_mutex);
185 bh = sb_bread(sb, block); 189 mutex_lock(&sbi->alloc_mutex);
186 if (bh) { 190 vhdr->free_blocks = cpu_to_be32(sbi->free_blocks);
187 vhdr = (struct hfsplus_vh *)(bh->b_data + offset); 191 vhdr->next_cnid = cpu_to_be32(sbi->next_cnid);
188 if (be16_to_cpu(vhdr->signature) == HFSPLUS_VOLHEAD_SIG) { 192 vhdr->folder_count = cpu_to_be32(sbi->folder_count);
189 memcpy(vhdr, HFSPLUS_SB(sb).s_vhdr, sizeof(*vhdr)); 193 vhdr->file_count = cpu_to_be32(sbi->file_count);
190 mark_buffer_dirty(bh); 194
191 brelse(bh); 195 if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) {
192 } else 196 memcpy(sbi->s_backup_vhdr, sbi->s_vhdr, sizeof(*sbi->s_vhdr));
193 printk(KERN_WARNING "hfs: backup not found!\n"); 197 write_backup = 1;
194 }
195 }
196 HFSPLUS_SB(sb).flags &= ~HFSPLUS_SB_WRITEBACKUP;
197 } 198 }
198 unlock_super(sb); 199
199 return 0; 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:
214 mutex_unlock(&sbi->alloc_mutex);
215 mutex_unlock(&sbi->vh_mutex);
216
217 if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
218 blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL);
219
220 return error;
200} 221}
201 222
202static void hfsplus_write_super(struct super_block *sb) 223static void hfsplus_write_super(struct super_block *sb)
@@ -209,48 +230,47 @@ static void hfsplus_write_super(struct super_block *sb)
209 230
210static void hfsplus_put_super(struct super_block *sb) 231static void hfsplus_put_super(struct super_block *sb)
211{ 232{
233 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
234
212 dprint(DBG_SUPER, "hfsplus_put_super\n"); 235 dprint(DBG_SUPER, "hfsplus_put_super\n");
236
213 if (!sb->s_fs_info) 237 if (!sb->s_fs_info)
214 return; 238 return;
215 239
216 lock_kernel(); 240 if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) {
217 241 struct hfsplus_vh *vhdr = sbi->s_vhdr;
218 if (sb->s_dirt)
219 hfsplus_write_super(sb);
220 if (!(sb->s_flags & MS_RDONLY) && HFSPLUS_SB(sb).s_vhdr) {
221 struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).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(HFSPLUS_SB(sb).s_vhbh); 246
227 sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh); 247 hfsplus_sync_fs(sb, 1);
228 } 248 }
229 249
230 hfs_btree_close(HFSPLUS_SB(sb).cat_tree); 250 hfs_btree_close(sbi->cat_tree);
231 hfs_btree_close(HFSPLUS_SB(sb).ext_tree); 251 hfs_btree_close(sbi->ext_tree);
232 iput(HFSPLUS_SB(sb).alloc_file); 252 iput(sbi->alloc_file);
233 iput(HFSPLUS_SB(sb).hidden_dir); 253 iput(sbi->hidden_dir);
234 brelse(HFSPLUS_SB(sb).s_vhbh); 254 kfree(sbi->s_vhdr);
235 unload_nls(HFSPLUS_SB(sb).nls); 255 kfree(sbi->s_backup_vhdr);
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;
238
239 unlock_kernel();
240} 259}
241 260
242static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf) 261static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
243{ 262{
244 struct super_block *sb = dentry->d_sb; 263 struct super_block *sb = dentry->d_sb;
264 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
245 u64 id = huge_encode_dev(sb->s_bdev->bd_dev); 265 u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
246 266
247 buf->f_type = HFSPLUS_SUPER_MAGIC; 267 buf->f_type = HFSPLUS_SUPER_MAGIC;
248 buf->f_bsize = sb->s_blocksize; 268 buf->f_bsize = sb->s_blocksize;
249 buf->f_blocks = HFSPLUS_SB(sb).total_blocks << HFSPLUS_SB(sb).fs_shift; 269 buf->f_blocks = sbi->total_blocks << sbi->fs_shift;
250 buf->f_bfree = HFSPLUS_SB(sb).free_blocks << HFSPLUS_SB(sb).fs_shift; 270 buf->f_bfree = sbi->free_blocks << sbi->fs_shift;
251 buf->f_bavail = buf->f_bfree; 271 buf->f_bavail = buf->f_bfree;
252 buf->f_files = 0xFFFFFFFF; 272 buf->f_files = 0xFFFFFFFF;
253 buf->f_ffree = 0xFFFFFFFF - HFSPLUS_SB(sb).next_cnid; 273 buf->f_ffree = 0xFFFFFFFF - sbi->next_cnid;
254 buf->f_fsid.val[0] = (u32)id; 274 buf->f_fsid.val[0] = (u32)id;
255 buf->f_fsid.val[1] = (u32)(id >> 32); 275 buf->f_fsid.val[1] = (u32)(id >> 32);
256 buf->f_namelen = HFSPLUS_MAX_STRLEN; 276 buf->f_namelen = HFSPLUS_MAX_STRLEN;
@@ -263,27 +283,32 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
263 if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) 283 if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
264 return 0; 284 return 0;
265 if (!(*flags & MS_RDONLY)) { 285 if (!(*flags & MS_RDONLY)) {
266 struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; 286 struct hfsplus_vh *vhdr = HFSPLUS_SB(sb)->s_vhdr;
267 struct hfsplus_sb_info sbi; 287 int force = 0;
268 288
269 memset(&sbi, 0, sizeof(struct hfsplus_sb_info)); 289 if (!hfsplus_parse_options_remount(data, &force))
270 sbi.nls = HFSPLUS_SB(sb).nls;
271 if (!hfsplus_parse_options(data, &sbi))
272 return -EINVAL; 290 return -EINVAL;
273 291
274 if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { 292 if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
275 printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, " 293 printk(KERN_WARNING "hfs: filesystem was "
276 "running fsck.hfsplus is recommended. leaving read-only.\n"); 294 "not cleanly unmounted, "
295 "running fsck.hfsplus is recommended. "
296 "leaving read-only.\n");
277 sb->s_flags |= MS_RDONLY; 297 sb->s_flags |= MS_RDONLY;
278 *flags |= MS_RDONLY; 298 *flags |= MS_RDONLY;
279 } else if (sbi.flags & HFSPLUS_SB_FORCE) { 299 } else if (force) {
280 /* nothing */ 300 /* nothing */
281 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { 301 } else if (vhdr->attributes &
282 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");
283 sb->s_flags |= MS_RDONLY; 305 sb->s_flags |= MS_RDONLY;
284 *flags |= MS_RDONLY; 306 *flags |= MS_RDONLY;
285 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { 307 } else if (vhdr->attributes &
286 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");
287 sb->s_flags |= MS_RDONLY; 312 sb->s_flags |= MS_RDONLY;
288 *flags |= MS_RDONLY; 313 *flags |= MS_RDONLY;
289 } 314 }
@@ -313,19 +338,22 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
313 struct inode *root, *inode; 338 struct inode *root, *inode;
314 struct qstr str; 339 struct qstr str;
315 struct nls_table *nls = NULL; 340 struct nls_table *nls = NULL;
316 int err = -EINVAL; 341 int err;
317 342
343 err = -EINVAL;
318 sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); 344 sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
319 if (!sbi) 345 if (!sbi)
320 return -ENOMEM; 346 goto out;
321 347
322 sb->s_fs_info = sbi; 348 sb->s_fs_info = sbi;
323 INIT_HLIST_HEAD(&sbi->rsrc_inodes); 349 mutex_init(&sbi->alloc_mutex);
350 mutex_init(&sbi->vh_mutex);
324 hfsplus_fill_defaults(sbi); 351 hfsplus_fill_defaults(sbi);
352
353 err = -EINVAL;
325 if (!hfsplus_parse_options(data, sbi)) { 354 if (!hfsplus_parse_options(data, sbi)) {
326 printk(KERN_ERR "hfs: unable to parse mount options\n"); 355 printk(KERN_ERR "hfs: unable to parse mount options\n");
327 err = -EINVAL; 356 goto out_unload_nls;
328 goto cleanup;
329 } 357 }
330 358
331 /* temporarily use utf8 to correctly find the hidden dir below */ 359 /* temporarily use utf8 to correctly find the hidden dir below */
@@ -333,140 +361,160 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
333 sbi->nls = load_nls("utf8"); 361 sbi->nls = load_nls("utf8");
334 if (!sbi->nls) { 362 if (!sbi->nls) {
335 printk(KERN_ERR "hfs: unable to load nls for utf8\n"); 363 printk(KERN_ERR "hfs: unable to load nls for utf8\n");
336 err = -EINVAL; 364 goto out_unload_nls;
337 goto cleanup;
338 } 365 }
339 366
340 /* Grab the volume header */ 367 /* Grab the volume header */
341 if (hfsplus_read_wrapper(sb)) { 368 if (hfsplus_read_wrapper(sb)) {
342 if (!silent) 369 if (!silent)
343 printk(KERN_WARNING "hfs: unable to find HFS+ superblock\n"); 370 printk(KERN_WARNING "hfs: unable to find HFS+ superblock\n");
344 err = -EINVAL; 371 goto out_unload_nls;
345 goto cleanup;
346 } 372 }
347 vhdr = HFSPLUS_SB(sb).s_vhdr; 373 vhdr = sbi->s_vhdr;
348 374
349 /* Copy parts of the volume header into the superblock */ 375 /* Copy parts of the volume header into the superblock */
350 sb->s_magic = HFSPLUS_VOLHEAD_SIG; 376 sb->s_magic = HFSPLUS_VOLHEAD_SIG;
351 if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION || 377 if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION ||
352 be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) { 378 be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) {
353 printk(KERN_ERR "hfs: wrong filesystem version\n"); 379 printk(KERN_ERR "hfs: wrong filesystem version\n");
354 goto cleanup; 380 goto out_free_vhdr;
355 } 381 }
356 HFSPLUS_SB(sb).total_blocks = be32_to_cpu(vhdr->total_blocks); 382 sbi->total_blocks = be32_to_cpu(vhdr->total_blocks);
357 HFSPLUS_SB(sb).free_blocks = be32_to_cpu(vhdr->free_blocks); 383 sbi->free_blocks = be32_to_cpu(vhdr->free_blocks);
358 HFSPLUS_SB(sb).next_alloc = be32_to_cpu(vhdr->next_alloc); 384 sbi->next_cnid = be32_to_cpu(vhdr->next_cnid);
359 HFSPLUS_SB(sb).next_cnid = be32_to_cpu(vhdr->next_cnid); 385 sbi->file_count = be32_to_cpu(vhdr->file_count);
360 HFSPLUS_SB(sb).file_count = be32_to_cpu(vhdr->file_count); 386 sbi->folder_count = be32_to_cpu(vhdr->folder_count);
361 HFSPLUS_SB(sb).folder_count = be32_to_cpu(vhdr->folder_count); 387 sbi->data_clump_blocks =
362 HFSPLUS_SB(sb).data_clump_blocks = be32_to_cpu(vhdr->data_clump_sz) >> HFSPLUS_SB(sb).alloc_blksz_shift; 388 be32_to_cpu(vhdr->data_clump_sz) >> sbi->alloc_blksz_shift;
363 if (!HFSPLUS_SB(sb).data_clump_blocks) 389 if (!sbi->data_clump_blocks)
364 HFSPLUS_SB(sb).data_clump_blocks = 1; 390 sbi->data_clump_blocks = 1;
365 HFSPLUS_SB(sb).rsrc_clump_blocks = be32_to_cpu(vhdr->rsrc_clump_sz) >> HFSPLUS_SB(sb).alloc_blksz_shift; 391 sbi->rsrc_clump_blocks =
366 if (!HFSPLUS_SB(sb).rsrc_clump_blocks) 392 be32_to_cpu(vhdr->rsrc_clump_sz) >> sbi->alloc_blksz_shift;
367 HFSPLUS_SB(sb).rsrc_clump_blocks = 1; 393 if (!sbi->rsrc_clump_blocks)
394 sbi->rsrc_clump_blocks = 1;
368 395
369 /* Set up operations so we can load metadata */ 396 /* Set up operations so we can load metadata */
370 sb->s_op = &hfsplus_sops; 397 sb->s_op = &hfsplus_sops;
371 sb->s_maxbytes = MAX_LFS_FILESIZE; 398 sb->s_maxbytes = MAX_LFS_FILESIZE;
372 399
373 if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { 400 if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
374 printk(KERN_WARNING "hfs: Filesystem was not cleanly unmounted, " 401 printk(KERN_WARNING "hfs: Filesystem was "
375 "running fsck.hfsplus is recommended. mounting read-only.\n"); 402 "not cleanly unmounted, "
403 "running fsck.hfsplus is recommended. "
404 "mounting read-only.\n");
376 sb->s_flags |= MS_RDONLY; 405 sb->s_flags |= MS_RDONLY;
377 } else if (sbi->flags & HFSPLUS_SB_FORCE) { 406 } else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) {
378 /* nothing */ 407 /* nothing */
379 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { 408 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
380 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");
381 sb->s_flags |= MS_RDONLY; 410 sb->s_flags |= MS_RDONLY;
382 } 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)) &&
383 printk(KERN_WARNING "hfs: write access to a journaled filesystem is not supported, " 412 !(sb->s_flags & MS_RDONLY)) {
384 "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");
385 sb->s_flags |= MS_RDONLY; 417 sb->s_flags |= MS_RDONLY;
386 } 418 }
387 sbi->flags &= ~HFSPLUS_SB_FORCE;
388 419
389 /* Load metadata objects (B*Trees) */ 420 /* Load metadata objects (B*Trees) */
390 HFSPLUS_SB(sb).ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID); 421 sbi->ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID);
391 if (!HFSPLUS_SB(sb).ext_tree) { 422 if (!sbi->ext_tree) {
392 printk(KERN_ERR "hfs: failed to load extents file\n"); 423 printk(KERN_ERR "hfs: failed to load extents file\n");
393 goto cleanup; 424 goto out_free_vhdr;
394 } 425 }
395 HFSPLUS_SB(sb).cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID); 426 sbi->cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID);
396 if (!HFSPLUS_SB(sb).cat_tree) { 427 if (!sbi->cat_tree) {
397 printk(KERN_ERR "hfs: failed to load catalog file\n"); 428 printk(KERN_ERR "hfs: failed to load catalog file\n");
398 goto cleanup; 429 goto out_close_ext_tree;
399 } 430 }
400 431
401 inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID); 432 inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID);
402 if (IS_ERR(inode)) { 433 if (IS_ERR(inode)) {
403 printk(KERN_ERR "hfs: failed to load allocation file\n"); 434 printk(KERN_ERR "hfs: failed to load allocation file\n");
404 err = PTR_ERR(inode); 435 err = PTR_ERR(inode);
405 goto cleanup; 436 goto out_close_cat_tree;
406 } 437 }
407 HFSPLUS_SB(sb).alloc_file = inode; 438 sbi->alloc_file = inode;
408 439
409 /* Load the root directory */ 440 /* Load the root directory */
410 root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID); 441 root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID);
411 if (IS_ERR(root)) { 442 if (IS_ERR(root)) {
412 printk(KERN_ERR "hfs: failed to load root directory\n"); 443 printk(KERN_ERR "hfs: failed to load root directory\n");
413 err = PTR_ERR(root); 444 err = PTR_ERR(root);
414 goto cleanup; 445 goto out_put_alloc_file;
415 } 446 }
416 sb->s_root = d_alloc_root(root);
417 if (!sb->s_root) {
418 iput(root);
419 err = -ENOMEM;
420 goto cleanup;
421 }
422 sb->s_root->d_op = &hfsplus_dentry_operations;
423 447
424 str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; 448 str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
425 str.name = HFSP_HIDDENDIR_NAME; 449 str.name = HFSP_HIDDENDIR_NAME;
426 hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); 450 hfs_find_init(sbi->cat_tree, &fd);
427 hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str); 451 hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str);
428 if (!hfs_brec_read(&fd, &entry, sizeof(entry))) { 452 if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
429 hfs_find_exit(&fd); 453 hfs_find_exit(&fd);
430 if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) 454 if (entry.type != cpu_to_be16(HFSPLUS_FOLDER))
431 goto cleanup; 455 goto out_put_root;
432 inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id)); 456 inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id));
433 if (IS_ERR(inode)) { 457 if (IS_ERR(inode)) {
434 err = PTR_ERR(inode); 458 err = PTR_ERR(inode);
435 goto cleanup; 459 goto out_put_root;
436 } 460 }
437 HFSPLUS_SB(sb).hidden_dir = inode; 461 sbi->hidden_dir = inode;
438 } else 462 } else
439 hfs_find_exit(&fd); 463 hfs_find_exit(&fd);
440 464
441 if (sb->s_flags & MS_RDONLY) 465 if (!(sb->s_flags & MS_RDONLY)) {
442 goto out; 466 /*
467 * H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused
468 * all three are registered with Apple for our use
469 */
470 vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION);
471 vhdr->modify_date = hfsp_now2mt();
472 be32_add_cpu(&vhdr->write_count, 1);
473 vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
474 vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
475 hfsplus_sync_fs(sb, 1);
443 476
444 /* H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused 477 if (!sbi->hidden_dir) {
445 * all three are registered with Apple for our use 478 mutex_lock(&sbi->vh_mutex);
446 */ 479 sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
447 vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION); 480 hfsplus_create_cat(sbi->hidden_dir->i_ino, root, &str,
448 vhdr->modify_date = hfsp_now2mt(); 481 sbi->hidden_dir);
449 be32_add_cpu(&vhdr->write_count, 1); 482 mutex_unlock(&sbi->vh_mutex);
450 vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT); 483
451 vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT); 484 hfsplus_mark_inode_dirty(sbi->hidden_dir,
452 mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh); 485 HFSPLUS_I_CAT_DIRTY);
453 sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh); 486 }
454
455 if (!HFSPLUS_SB(sb).hidden_dir) {
456 printk(KERN_DEBUG "hfs: create hidden dir...\n");
457 HFSPLUS_SB(sb).hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
458 hfsplus_create_cat(HFSPLUS_SB(sb).hidden_dir->i_ino, sb->s_root->d_inode,
459 &str, HFSPLUS_SB(sb).hidden_dir);
460 mark_inode_dirty(HFSPLUS_SB(sb).hidden_dir);
461 } 487 }
462out: 488
489 sb->s_d_op = &hfsplus_dentry_operations;
490 sb->s_root = d_alloc_root(root);
491 if (!sb->s_root) {
492 err = -ENOMEM;
493 goto out_put_hidden_dir;
494 }
495
463 unload_nls(sbi->nls); 496 unload_nls(sbi->nls);
464 sbi->nls = nls; 497 sbi->nls = nls;
465 return 0; 498 return 0;
466 499
467cleanup: 500out_put_hidden_dir:
468 hfsplus_put_super(sb); 501 iput(sbi->hidden_dir);
502out_put_root:
503 iput(root);
504out_put_alloc_file:
505 iput(sbi->alloc_file);
506out_close_cat_tree:
507 hfs_btree_close(sbi->cat_tree);
508out_close_ext_tree:
509 hfs_btree_close(sbi->ext_tree);
510out_free_vhdr:
511 kfree(sbi->s_vhdr);
512 kfree(sbi->s_backup_vhdr);
513out_unload_nls:
514 unload_nls(sbi->nls);
469 unload_nls(nls); 515 unload_nls(nls);
516 kfree(sbi);
517out:
470 return err; 518 return err;
471} 519}
472 520
@@ -484,25 +532,31 @@ static struct inode *hfsplus_alloc_inode(struct super_block *sb)
484 return i ? &i->vfs_inode : NULL; 532 return i ? &i->vfs_inode : NULL;
485} 533}
486 534
535static void hfsplus_i_callback(struct rcu_head *head)
536{
537 struct inode *inode = container_of(head, struct inode, i_rcu);
538
539 INIT_LIST_HEAD(&inode->i_dentry);
540 kmem_cache_free(hfsplus_inode_cachep, HFSPLUS_I(inode));
541}
542
487static void hfsplus_destroy_inode(struct inode *inode) 543static void hfsplus_destroy_inode(struct inode *inode)
488{ 544{
489 kmem_cache_free(hfsplus_inode_cachep, &HFSPLUS_I(inode)); 545 call_rcu(&inode->i_rcu, hfsplus_i_callback);
490} 546}
491 547
492#define HFSPLUS_INODE_SIZE sizeof(struct hfsplus_inode_info) 548#define HFSPLUS_INODE_SIZE sizeof(struct hfsplus_inode_info)
493 549
494static int hfsplus_get_sb(struct file_system_type *fs_type, 550static struct dentry *hfsplus_mount(struct file_system_type *fs_type,
495 int flags, const char *dev_name, void *data, 551 int flags, const char *dev_name, void *data)
496 struct vfsmount *mnt)
497{ 552{
498 return get_sb_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super, 553 return mount_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super);
499 mnt);
500} 554}
501 555
502static struct file_system_type hfsplus_fs_type = { 556static struct file_system_type hfsplus_fs_type = {
503 .owner = THIS_MODULE, 557 .owner = THIS_MODULE,
504 .name = "hfsplus", 558 .name = "hfsplus",
505 .get_sb = hfsplus_get_sb, 559 .mount = hfsplus_mount,
506 .kill_sb = kill_block_super, 560 .kill_sb = kill_block_super,
507 .fs_flags = FS_REQUIRES_DEV, 561 .fs_flags = FS_REQUIRES_DEV,
508}; 562};
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c
index 628ccf6fa402..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,10 +118,12 @@ 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;
125 u8 *op; 127 u8 *op;
126 u16 cc, c0, c1; 128 u16 cc, c0, c1;
127 u16 *ce1, *ce2; 129 u16 *ce1, *ce2;
@@ -132,7 +134,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
132 ustrlen = be16_to_cpu(ustr->length); 134 ustrlen = be16_to_cpu(ustr->length);
133 len = *len_p; 135 len = *len_p;
134 ce1 = NULL; 136 ce1 = NULL;
135 compose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); 137 compose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
136 138
137 while (ustrlen > 0) { 139 while (ustrlen > 0) {
138 c0 = be16_to_cpu(*ip++); 140 c0 = be16_to_cpu(*ip++);
@@ -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)
@@ -246,7 +250,7 @@ out:
246static inline int asc2unichar(struct super_block *sb, const char *astr, int len, 250static inline int asc2unichar(struct super_block *sb, const char *astr, int len,
247 wchar_t *uc) 251 wchar_t *uc)
248{ 252{
249 int size = HFSPLUS_SB(sb).nls->char2uni(astr, len, uc); 253 int size = HFSPLUS_SB(sb)->nls->char2uni(astr, len, uc);
250 if (size <= 0) { 254 if (size <= 0) {
251 *uc = '?'; 255 *uc = '?';
252 size = 1; 256 size = 1;
@@ -293,7 +297,7 @@ int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr,
293 u16 *dstr, outlen = 0; 297 u16 *dstr, outlen = 0;
294 wchar_t c; 298 wchar_t c;
295 299
296 decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); 300 decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
297 while (outlen < HFSPLUS_MAX_STRLEN && len > 0) { 301 while (outlen < HFSPLUS_MAX_STRLEN && len > 0) {
298 size = asc2unichar(sb, astr, len, &c); 302 size = asc2unichar(sb, astr, len, &c);
299 303
@@ -320,7 +324,8 @@ int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr,
320 * Composed unicode characters are decomposed and case-folding is performed 324 * Composed unicode characters are decomposed and case-folding is performed
321 * if the appropriate bits are (un)set on the superblock. 325 * if the appropriate bits are (un)set on the superblock.
322 */ 326 */
323int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str) 327int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode,
328 struct qstr *str)
324{ 329{
325 struct super_block *sb = dentry->d_sb; 330 struct super_block *sb = dentry->d_sb;
326 const char *astr; 331 const char *astr;
@@ -330,8 +335,8 @@ int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str)
330 wchar_t c; 335 wchar_t c;
331 u16 c2; 336 u16 c2;
332 337
333 casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD); 338 casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
334 decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); 339 decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
335 hash = init_name_hash(); 340 hash = init_name_hash();
336 astr = str->name; 341 astr = str->name;
337 len = str->len; 342 len = str->len;
@@ -363,9 +368,12 @@ int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str)
363 * Composed unicode characters are decomposed and case-folding is performed 368 * Composed unicode characters are decomposed and case-folding is performed
364 * if the appropriate bits are (un)set on the superblock. 369 * if the appropriate bits are (un)set on the superblock.
365 */ 370 */
366int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2) 371int hfsplus_compare_dentry(const struct dentry *parent,
372 const struct inode *pinode,
373 const struct dentry *dentry, const struct inode *inode,
374 unsigned int len, const char *str, const struct qstr *name)
367{ 375{
368 struct super_block *sb = dentry->d_sb; 376 struct super_block *sb = parent->d_sb;
369 int casefold, decompose, size; 377 int casefold, decompose, size;
370 int dsize1, dsize2, len1, len2; 378 int dsize1, dsize2, len1, len2;
371 const u16 *dstr1, *dstr2; 379 const u16 *dstr1, *dstr2;
@@ -373,12 +381,12 @@ int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *
373 u16 c1, c2; 381 u16 c1, c2;
374 wchar_t c; 382 wchar_t c;
375 383
376 casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD); 384 casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
377 decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE); 385 decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
378 astr1 = s1->name; 386 astr1 = str;
379 len1 = s1->len; 387 len1 = len;
380 astr2 = s2->name; 388 astr2 = name->name;
381 len2 = s2->len; 389 len2 = name->len;
382 dsize1 = dsize2 = 0; 390 dsize1 = dsize2 = 0;
383 dstr1 = dstr2 = NULL; 391 dstr1 = dstr2 = NULL;
384 392
@@ -388,7 +396,9 @@ int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *
388 astr1 += size; 396 astr1 += size;
389 len1 -= size; 397 len1 -= size;
390 398
391 if (!decompose || !(dstr1 = decompose_unichar(c, &dsize1))) { 399 if (decompose)
400 dstr1 = decompose_unichar(c, &dsize1);
401 if (!decompose || !dstr1) {
392 c1 = c; 402 c1 = c;
393 dstr1 = &c1; 403 dstr1 = &c1;
394 dsize1 = 1; 404 dsize1 = 1;
@@ -400,7 +410,9 @@ int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *
400 astr2 += size; 410 astr2 += size;
401 len2 -= size; 411 len2 -= size;
402 412
403 if (!decompose || !(dstr2 = decompose_unichar(c, &dsize2))) { 413 if (decompose)
414 dstr2 = decompose_unichar(c, &dsize2);
415 if (!decompose || !dstr2) {
404 c2 = c; 416 c2 = c;
405 dstr2 = &c2; 417 dstr2 = &c2;
406 dsize2 = 1; 418 dsize2 = 1;
diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c
index bed78ac8f6d1..4ac88ff79aa6 100644
--- a/fs/hfsplus/wrapper.c
+++ b/fs/hfsplus/wrapper.c
@@ -24,6 +24,43 @@ 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 int ret = 0;
40
41 bio = bio_alloc(GFP_NOIO, 1);
42 bio->bi_sector = sector;
43 bio->bi_bdev = bdev;
44 bio->bi_end_io = hfsplus_end_io_sync;
45 bio->bi_private = &wait;
46
47 /*
48 * We always submit one sector at a time, so bio_add_page must not fail.
49 */
50 if (bio_add_page(bio, virt_to_page(data), HFSPLUS_SECTOR_SIZE,
51 offset_in_page(data)) != HFSPLUS_SECTOR_SIZE)
52 BUG();
53
54 submit_bio(rw, bio);
55 wait_for_completion(&wait);
56
57 if (!bio_flagged(bio, BIO_UPTODATE))
58 ret = -EIO;
59
60 bio_put(bio);
61 return ret;
62}
63
27static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd) 64static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
28{ 65{
29 u32 extent; 66 u32 extent;
@@ -40,12 +77,14 @@ static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
40 !(attrib & HFSP_WRAP_ATTRIB_SPARED)) 77 !(attrib & HFSP_WRAP_ATTRIB_SPARED))
41 return 0; 78 return 0;
42 79
43 wd->ablk_size = be32_to_cpu(*(__be32 *)(bufptr + HFSP_WRAPOFF_ABLKSIZE)); 80 wd->ablk_size =
81 be32_to_cpu(*(__be32 *)(bufptr + HFSP_WRAPOFF_ABLKSIZE));
44 if (wd->ablk_size < HFSPLUS_SECTOR_SIZE) 82 if (wd->ablk_size < HFSPLUS_SECTOR_SIZE)
45 return 0; 83 return 0;
46 if (wd->ablk_size % HFSPLUS_SECTOR_SIZE) 84 if (wd->ablk_size % HFSPLUS_SECTOR_SIZE)
47 return 0; 85 return 0;
48 wd->ablk_start = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART)); 86 wd->ablk_start =
87 be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART));
49 88
50 extent = get_unaligned_be32(bufptr + HFSP_WRAPOFF_EMBEDEXT); 89 extent = get_unaligned_be32(bufptr + HFSP_WRAPOFF_EMBEDEXT);
51 wd->embed_start = (extent >> 16) & 0xFFFF; 90 wd->embed_start = (extent >> 16) & 0xFFFF;
@@ -65,10 +104,11 @@ static int hfsplus_get_last_session(struct super_block *sb,
65 *start = 0; 104 *start = 0;
66 *size = sb->s_bdev->bd_inode->i_size >> 9; 105 *size = sb->s_bdev->bd_inode->i_size >> 9;
67 106
68 if (HFSPLUS_SB(sb).session >= 0) { 107 if (HFSPLUS_SB(sb)->session >= 0) {
69 te.cdte_track = HFSPLUS_SB(sb).session; 108 te.cdte_track = HFSPLUS_SB(sb)->session;
70 te.cdte_format = CDROM_LBA; 109 te.cdte_format = CDROM_LBA;
71 res = ioctl_by_bdev(sb->s_bdev, CDROMREADTOCENTRY, (unsigned long)&te); 110 res = ioctl_by_bdev(sb->s_bdev,
111 CDROMREADTOCENTRY, (unsigned long)&te);
72 if (!res && (te.cdte_ctrl & CDROM_DATA_TRACK) == 4) { 112 if (!res && (te.cdte_ctrl & CDROM_DATA_TRACK) == 4) {
73 *start = (sector_t)te.cdte_addr.lba << 2; 113 *start = (sector_t)te.cdte_addr.lba << 2;
74 return 0; 114 return 0;
@@ -77,7 +117,8 @@ static int hfsplus_get_last_session(struct super_block *sb,
77 return -EINVAL; 117 return -EINVAL;
78 } 118 }
79 ms_info.addr_format = CDROM_LBA; 119 ms_info.addr_format = CDROM_LBA;
80 res = ioctl_by_bdev(sb->s_bdev, CDROMMULTISESSION, (unsigned long)&ms_info); 120 res = ioctl_by_bdev(sb->s_bdev, CDROMMULTISESSION,
121 (unsigned long)&ms_info);
81 if (!res && ms_info.xa_flag) 122 if (!res && ms_info.xa_flag)
82 *start = (sector_t)ms_info.addr.lba << 2; 123 *start = (sector_t)ms_info.addr.lba << 2;
83 return 0; 124 return 0;
@@ -87,97 +128,113 @@ static int hfsplus_get_last_session(struct super_block *sb,
87/* Takes in super block, returns true if good data read */ 128/* Takes in super block, returns true if good data read */
88int hfsplus_read_wrapper(struct super_block *sb) 129int hfsplus_read_wrapper(struct super_block *sb)
89{ 130{
90 struct buffer_head *bh; 131 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
91 struct hfsplus_vh *vhdr;
92 struct hfsplus_wd wd; 132 struct hfsplus_wd wd;
93 sector_t part_start, part_size; 133 sector_t part_start, part_size;
94 u32 blocksize; 134 u32 blocksize;
135 int error = 0;
95 136
137 error = -EINVAL;
96 blocksize = sb_min_blocksize(sb, HFSPLUS_SECTOR_SIZE); 138 blocksize = sb_min_blocksize(sb, HFSPLUS_SECTOR_SIZE);
97 if (!blocksize) 139 if (!blocksize)
98 return -EINVAL; 140 goto out;
99 141
100 if (hfsplus_get_last_session(sb, &part_start, &part_size)) 142 if (hfsplus_get_last_session(sb, &part_start, &part_size))
101 return -EINVAL; 143 goto out;
102 if ((u64)part_start + part_size > 0x100000000ULL) { 144 if ((u64)part_start + part_size > 0x100000000ULL) {
103 pr_err("hfs: volumes larger than 2TB are not supported yet\n"); 145 pr_err("hfs: volumes larger than 2TB are not supported yet\n");
104 return -EINVAL; 146 goto out;
105 } 147 }
106 while (1) {
107 bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
108 if (!bh)
109 return -EIO;
110
111 if (vhdr->signature == cpu_to_be16(HFSP_WRAP_MAGIC)) {
112 if (!hfsplus_read_mdb(vhdr, &wd))
113 goto error;
114 wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT;
115 part_start += wd.ablk_start + wd.embed_start * wd.ablk_size;
116 part_size = wd.embed_count * wd.ablk_size;
117 brelse(bh);
118 bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
119 if (!bh)
120 return -EIO;
121 }
122 if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG))
123 break;
124 if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) {
125 HFSPLUS_SB(sb).flags |= HFSPLUS_SB_HFSX;
126 break;
127 }
128 brelse(bh);
129 148
130 /* check for a partition block 149 error = -ENOMEM;
150 sbi->s_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
151 if (!sbi->s_vhdr)
152 goto out;
153 sbi->s_backup_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
154 if (!sbi->s_backup_vhdr)
155 goto out_free_vhdr;
156
157reread:
158 error = hfsplus_submit_bio(sb->s_bdev,
159 part_start + HFSPLUS_VOLHEAD_SECTOR,
160 sbi->s_vhdr, READ);
161 if (error)
162 goto out_free_backup_vhdr;
163
164 error = -EINVAL;
165 switch (sbi->s_vhdr->signature) {
166 case cpu_to_be16(HFSPLUS_VOLHEAD_SIGX):
167 set_bit(HFSPLUS_SB_HFSX, &sbi->flags);
168 /*FALLTHRU*/
169 case cpu_to_be16(HFSPLUS_VOLHEAD_SIG):
170 break;
171 case cpu_to_be16(HFSP_WRAP_MAGIC):
172 if (!hfsplus_read_mdb(sbi->s_vhdr, &wd))
173 goto out_free_backup_vhdr;
174 wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT;
175 part_start += wd.ablk_start + wd.embed_start * wd.ablk_size;
176 part_size = wd.embed_count * wd.ablk_size;
177 goto reread;
178 default:
179 /*
180 * Check for a partition block.
181 *
131 * (should do this only for cdrom/loop though) 182 * (should do this only for cdrom/loop though)
132 */ 183 */
133 if (hfs_part_find(sb, &part_start, &part_size)) 184 if (hfs_part_find(sb, &part_start, &part_size))
134 return -EINVAL; 185 goto out_free_backup_vhdr;
186 goto reread;
135 } 187 }
136 188
137 blocksize = be32_to_cpu(vhdr->blocksize); 189 error = hfsplus_submit_bio(sb->s_bdev,
138 brelse(bh); 190 part_start + part_size - 2,
191 sbi->s_backup_vhdr, READ);
192 if (error)
193 goto out_free_backup_vhdr;
194
195 error = -EINVAL;
196 if (sbi->s_backup_vhdr->signature != sbi->s_vhdr->signature) {
197 printk(KERN_WARNING
198 "hfs: invalid secondary volume header\n");
199 goto out_free_backup_vhdr;
200 }
201
202 blocksize = be32_to_cpu(sbi->s_vhdr->blocksize);
139 203
140 /* block size must be at least as large as a sector 204 /*
141 * and a multiple of 2 205 * Block size must be at least as large as a sector and a multiple of 2.
142 */ 206 */
143 if (blocksize < HFSPLUS_SECTOR_SIZE || 207 if (blocksize < HFSPLUS_SECTOR_SIZE || ((blocksize - 1) & blocksize))
144 ((blocksize - 1) & blocksize)) 208 goto out_free_backup_vhdr;
145 return -EINVAL; 209 sbi->alloc_blksz = blocksize;
146 HFSPLUS_SB(sb).alloc_blksz = blocksize; 210 sbi->alloc_blksz_shift = 0;
147 HFSPLUS_SB(sb).alloc_blksz_shift = 0;
148 while ((blocksize >>= 1) != 0) 211 while ((blocksize >>= 1) != 0)
149 HFSPLUS_SB(sb).alloc_blksz_shift++; 212 sbi->alloc_blksz_shift++;
150 blocksize = min(HFSPLUS_SB(sb).alloc_blksz, (u32)PAGE_SIZE); 213 blocksize = min(sbi->alloc_blksz, (u32)PAGE_SIZE);
151 214
152 /* align block size to block offset */ 215 /*
216 * Align block size to block offset.
217 */
153 while (part_start & ((blocksize >> HFSPLUS_SECTOR_SHIFT) - 1)) 218 while (part_start & ((blocksize >> HFSPLUS_SECTOR_SHIFT) - 1))
154 blocksize >>= 1; 219 blocksize >>= 1;
155 220
156 if (sb_set_blocksize(sb, blocksize) != blocksize) { 221 if (sb_set_blocksize(sb, blocksize) != blocksize) {
157 printk(KERN_ERR "hfs: unable to set blocksize to %u!\n", blocksize); 222 printk(KERN_ERR "hfs: unable to set blocksize to %u!\n",
158 return -EINVAL; 223 blocksize);
224 goto out_free_backup_vhdr;
159 } 225 }
160 226
161 HFSPLUS_SB(sb).blockoffset = part_start >> 227 sbi->blockoffset =
162 (sb->s_blocksize_bits - HFSPLUS_SECTOR_SHIFT); 228 part_start >> (sb->s_blocksize_bits - HFSPLUS_SECTOR_SHIFT);
163 HFSPLUS_SB(sb).sect_count = part_size; 229 sbi->part_start = part_start;
164 HFSPLUS_SB(sb).fs_shift = HFSPLUS_SB(sb).alloc_blksz_shift - 230 sbi->sect_count = part_size;
165 sb->s_blocksize_bits; 231 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 (vhdr->signature != (HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX ?
173 cpu_to_be16(HFSPLUS_VOLHEAD_SIGX) :
174 cpu_to_be16(HFSPLUS_VOLHEAD_SIG)))
175 goto error;
176 HFSPLUS_SB(sb).s_vhbh = bh;
177 HFSPLUS_SB(sb).s_vhdr = vhdr;
178
179 return 0; 232 return 0;
180 error: 233
181 brelse(bh); 234out_free_backup_vhdr:
182 return -EINVAL; 235 kfree(sbi->s_backup_vhdr);
236out_free_vhdr:
237 kfree(sbi->s_vhdr);
238out:
239 return error;
183} 240}