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