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