diff options
Diffstat (limited to 'fs/hfsplus')
-rw-r--r-- | fs/hfsplus/brec.c | 4 | ||||
-rw-r--r-- | fs/hfsplus/catalog.c | 14 | ||||
-rw-r--r-- | fs/hfsplus/dir.c | 8 | ||||
-rw-r--r-- | fs/hfsplus/extents.c | 50 | ||||
-rw-r--r-- | fs/hfsplus/hfsplus_fs.h | 18 | ||||
-rw-r--r-- | fs/hfsplus/inode.c | 12 | ||||
-rw-r--r-- | fs/hfsplus/part_tbl.c | 32 | ||||
-rw-r--r-- | fs/hfsplus/super.c | 43 | ||||
-rw-r--r-- | fs/hfsplus/unicode.c | 35 | ||||
-rw-r--r-- | fs/hfsplus/wrapper.c | 92 |
10 files changed, 219 insertions, 89 deletions
diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c index 2312de34bd42..2a734cfccc92 100644 --- a/fs/hfsplus/brec.c +++ b/fs/hfsplus/brec.c | |||
@@ -43,6 +43,10 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec) | |||
43 | node->tree->node_size - (rec + 1) * 2); | 43 | node->tree->node_size - (rec + 1) * 2); |
44 | if (!recoff) | 44 | if (!recoff) |
45 | return 0; | 45 | return 0; |
46 | if (recoff > node->tree->node_size - 2) { | ||
47 | printk(KERN_ERR "hfs: recoff %d too large\n", recoff); | ||
48 | return 0; | ||
49 | } | ||
46 | 50 | ||
47 | retval = hfs_bnode_read_u16(node, recoff) + 2; | 51 | retval = hfs_bnode_read_u16(node, recoff) + 2; |
48 | if (retval > node->tree->max_key_len + 2) { | 52 | if (retval > node->tree->max_key_len + 2) { |
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index b4ba1b319333..4dfbfec357e8 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c | |||
@@ -212,7 +212,9 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, | |||
212 | 212 | ||
213 | dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", | 213 | dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", |
214 | str->name, cnid, inode->i_nlink); | 214 | str->name, cnid, inode->i_nlink); |
215 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); | 215 | err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); |
216 | if (err) | ||
217 | return err; | ||
216 | 218 | ||
217 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); | 219 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); |
218 | entry_size = hfsplus_fill_cat_thread(sb, &entry, | 220 | entry_size = hfsplus_fill_cat_thread(sb, &entry, |
@@ -269,7 +271,9 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
269 | 271 | ||
270 | dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", | 272 | dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", |
271 | str ? str->name : NULL, cnid); | 273 | str ? str->name : NULL, cnid); |
272 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); | 274 | err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); |
275 | if (err) | ||
276 | return err; | ||
273 | 277 | ||
274 | if (!str) { | 278 | if (!str) { |
275 | int len; | 279 | int len; |
@@ -347,12 +351,14 @@ int hfsplus_rename_cat(u32 cnid, | |||
347 | struct hfs_find_data src_fd, dst_fd; | 351 | struct hfs_find_data src_fd, dst_fd; |
348 | hfsplus_cat_entry entry; | 352 | hfsplus_cat_entry entry; |
349 | int entry_size, type; | 353 | int entry_size, type; |
350 | int err = 0; | 354 | int err; |
351 | 355 | ||
352 | dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", | 356 | dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", |
353 | cnid, src_dir->i_ino, src_name->name, | 357 | cnid, src_dir->i_ino, src_name->name, |
354 | dst_dir->i_ino, dst_name->name); | 358 | dst_dir->i_ino, dst_name->name); |
355 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd); | 359 | err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd); |
360 | if (err) | ||
361 | return err; | ||
356 | dst_fd = src_fd; | 362 | dst_fd = src_fd; |
357 | 363 | ||
358 | /* find the old dir entry and read the data */ | 364 | /* find the old dir entry and read the data */ |
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 4df5059c25da..25b2443a004c 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c | |||
@@ -38,7 +38,9 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry, | |||
38 | sb = dir->i_sb; | 38 | sb = dir->i_sb; |
39 | 39 | ||
40 | dentry->d_fsdata = NULL; | 40 | dentry->d_fsdata = NULL; |
41 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); | 41 | err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); |
42 | if (err) | ||
43 | return ERR_PTR(err); | ||
42 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); | 44 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); |
43 | again: | 45 | again: |
44 | err = hfs_brec_read(&fd, &entry, sizeof(entry)); | 46 | err = hfs_brec_read(&fd, &entry, sizeof(entry)); |
@@ -132,7 +134,9 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
132 | if (filp->f_pos >= inode->i_size) | 134 | if (filp->f_pos >= inode->i_size) |
133 | return 0; | 135 | return 0; |
134 | 136 | ||
135 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); | 137 | err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); |
138 | if (err) | ||
139 | return err; | ||
136 | hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); | 140 | hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); |
137 | err = hfs_brec_find(&fd); | 141 | err = hfs_brec_find(&fd); |
138 | if (err) | 142 | if (err) |
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index b1991a2a08e0..5849e3ef35cc 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c | |||
@@ -119,22 +119,31 @@ static void __hfsplus_ext_write_extent(struct inode *inode, | |||
119 | set_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags); | 119 | set_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags); |
120 | } | 120 | } |
121 | 121 | ||
122 | static void hfsplus_ext_write_extent_locked(struct inode *inode) | 122 | static int hfsplus_ext_write_extent_locked(struct inode *inode) |
123 | { | 123 | { |
124 | int res; | ||
125 | |||
124 | if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) { | 126 | if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) { |
125 | struct hfs_find_data fd; | 127 | struct hfs_find_data fd; |
126 | 128 | ||
127 | hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); | 129 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); |
130 | if (res) | ||
131 | return res; | ||
128 | __hfsplus_ext_write_extent(inode, &fd); | 132 | __hfsplus_ext_write_extent(inode, &fd); |
129 | hfs_find_exit(&fd); | 133 | hfs_find_exit(&fd); |
130 | } | 134 | } |
135 | return 0; | ||
131 | } | 136 | } |
132 | 137 | ||
133 | void hfsplus_ext_write_extent(struct inode *inode) | 138 | int hfsplus_ext_write_extent(struct inode *inode) |
134 | { | 139 | { |
140 | int res; | ||
141 | |||
135 | mutex_lock(&HFSPLUS_I(inode)->extents_lock); | 142 | mutex_lock(&HFSPLUS_I(inode)->extents_lock); |
136 | hfsplus_ext_write_extent_locked(inode); | 143 | res = hfsplus_ext_write_extent_locked(inode); |
137 | mutex_unlock(&HFSPLUS_I(inode)->extents_lock); | 144 | mutex_unlock(&HFSPLUS_I(inode)->extents_lock); |
145 | |||
146 | return res; | ||
138 | } | 147 | } |
139 | 148 | ||
140 | static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd, | 149 | static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd, |
@@ -194,9 +203,11 @@ static int hfsplus_ext_read_extent(struct inode *inode, u32 block) | |||
194 | block < hip->cached_start + hip->cached_blocks) | 203 | block < hip->cached_start + hip->cached_blocks) |
195 | return 0; | 204 | return 0; |
196 | 205 | ||
197 | hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); | 206 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); |
198 | res = __hfsplus_ext_cache_extent(&fd, inode, block); | 207 | if (!res) { |
199 | hfs_find_exit(&fd); | 208 | res = __hfsplus_ext_cache_extent(&fd, inode, block); |
209 | hfs_find_exit(&fd); | ||
210 | } | ||
200 | return res; | 211 | return res; |
201 | } | 212 | } |
202 | 213 | ||
@@ -209,6 +220,7 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock, | |||
209 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); | 220 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
210 | int res = -EIO; | 221 | int res = -EIO; |
211 | u32 ablock, dblock, mask; | 222 | u32 ablock, dblock, mask; |
223 | sector_t sector; | ||
212 | int was_dirty = 0; | 224 | int was_dirty = 0; |
213 | int shift; | 225 | int shift; |
214 | 226 | ||
@@ -255,10 +267,12 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock, | |||
255 | done: | 267 | done: |
256 | dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n", | 268 | dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n", |
257 | inode->i_ino, (long long)iblock, dblock); | 269 | inode->i_ino, (long long)iblock, dblock); |
270 | |||
258 | mask = (1 << sbi->fs_shift) - 1; | 271 | mask = (1 << sbi->fs_shift) - 1; |
259 | map_bh(bh_result, sb, | 272 | sector = ((sector_t)dblock << sbi->fs_shift) + |
260 | (dblock << sbi->fs_shift) + sbi->blockoffset + | 273 | sbi->blockoffset + (iblock & mask); |
261 | (iblock & mask)); | 274 | map_bh(bh_result, sb, sector); |
275 | |||
262 | if (create) { | 276 | if (create) { |
263 | set_buffer_new(bh_result); | 277 | set_buffer_new(bh_result); |
264 | hip->phys_size += sb->s_blocksize; | 278 | hip->phys_size += sb->s_blocksize; |
@@ -371,7 +385,9 @@ int hfsplus_free_fork(struct super_block *sb, u32 cnid, | |||
371 | if (total_blocks == blocks) | 385 | if (total_blocks == blocks) |
372 | return 0; | 386 | return 0; |
373 | 387 | ||
374 | hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); | 388 | res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); |
389 | if (res) | ||
390 | return res; | ||
375 | do { | 391 | do { |
376 | res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid, | 392 | res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid, |
377 | total_blocks, type); | 393 | total_blocks, type); |
@@ -469,7 +485,9 @@ out: | |||
469 | 485 | ||
470 | insert_extent: | 486 | insert_extent: |
471 | dprint(DBG_EXTENT, "insert new extent\n"); | 487 | dprint(DBG_EXTENT, "insert new extent\n"); |
472 | hfsplus_ext_write_extent_locked(inode); | 488 | res = hfsplus_ext_write_extent_locked(inode); |
489 | if (res) | ||
490 | goto out; | ||
473 | 491 | ||
474 | memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); | 492 | memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); |
475 | hip->cached_extents[0].start_block = cpu_to_be32(start); | 493 | hip->cached_extents[0].start_block = cpu_to_be32(start); |
@@ -500,7 +518,6 @@ void hfsplus_file_truncate(struct inode *inode) | |||
500 | struct page *page; | 518 | struct page *page; |
501 | void *fsdata; | 519 | void *fsdata; |
502 | u32 size = inode->i_size; | 520 | u32 size = inode->i_size; |
503 | int res; | ||
504 | 521 | ||
505 | res = pagecache_write_begin(NULL, mapping, size, 0, | 522 | res = pagecache_write_begin(NULL, mapping, size, 0, |
506 | AOP_FLAG_UNINTERRUPTIBLE, | 523 | AOP_FLAG_UNINTERRUPTIBLE, |
@@ -523,7 +540,12 @@ void hfsplus_file_truncate(struct inode *inode) | |||
523 | goto out; | 540 | goto out; |
524 | 541 | ||
525 | mutex_lock(&hip->extents_lock); | 542 | mutex_lock(&hip->extents_lock); |
526 | hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); | 543 | res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); |
544 | if (res) { | ||
545 | mutex_unlock(&hip->extents_lock); | ||
546 | /* XXX: We lack error handling of hfsplus_file_truncate() */ | ||
547 | return; | ||
548 | } | ||
527 | while (1) { | 549 | while (1) { |
528 | if (alloc_cnt == hip->first_blocks) { | 550 | if (alloc_cnt == hip->first_blocks) { |
529 | hfsplus_free_extents(sb, hip->first_extents, | 551 | hfsplus_free_extents(sb, hip->first_extents, |
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 38184e360932..d7674d051f52 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/mutex.h> | 14 | #include <linux/mutex.h> |
15 | #include <linux/buffer_head.h> | 15 | #include <linux/buffer_head.h> |
16 | #include <linux/blkdev.h> | ||
16 | #include "hfsplus_raw.h" | 17 | #include "hfsplus_raw.h" |
17 | 18 | ||
18 | #define DBG_BNODE_REFS 0x00000001 | 19 | #define DBG_BNODE_REFS 0x00000001 |
@@ -110,7 +111,9 @@ struct hfsplus_vh; | |||
110 | struct hfs_btree; | 111 | struct hfs_btree; |
111 | 112 | ||
112 | struct hfsplus_sb_info { | 113 | struct hfsplus_sb_info { |
114 | void *s_vhdr_buf; | ||
113 | struct hfsplus_vh *s_vhdr; | 115 | struct hfsplus_vh *s_vhdr; |
116 | void *s_backup_vhdr_buf; | ||
114 | struct hfsplus_vh *s_backup_vhdr; | 117 | struct hfsplus_vh *s_backup_vhdr; |
115 | struct hfs_btree *ext_tree; | 118 | struct hfs_btree *ext_tree; |
116 | struct hfs_btree *cat_tree; | 119 | struct hfs_btree *cat_tree; |
@@ -258,6 +261,15 @@ struct hfsplus_readdir_data { | |||
258 | struct hfsplus_cat_key key; | 261 | struct hfsplus_cat_key key; |
259 | }; | 262 | }; |
260 | 263 | ||
264 | /* | ||
265 | * Find minimum acceptible I/O size for an hfsplus sb. | ||
266 | */ | ||
267 | static inline unsigned short hfsplus_min_io_size(struct super_block *sb) | ||
268 | { | ||
269 | return max_t(unsigned short, bdev_logical_block_size(sb->s_bdev), | ||
270 | HFSPLUS_SECTOR_SIZE); | ||
271 | } | ||
272 | |||
261 | #define hfs_btree_open hfsplus_btree_open | 273 | #define hfs_btree_open hfsplus_btree_open |
262 | #define hfs_btree_close hfsplus_btree_close | 274 | #define hfs_btree_close hfsplus_btree_close |
263 | #define hfs_btree_write hfsplus_btree_write | 275 | #define hfs_btree_write hfsplus_btree_write |
@@ -374,7 +386,7 @@ extern const struct file_operations hfsplus_dir_operations; | |||
374 | 386 | ||
375 | /* extents.c */ | 387 | /* extents.c */ |
376 | int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); | 388 | int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); |
377 | void hfsplus_ext_write_extent(struct inode *); | 389 | int hfsplus_ext_write_extent(struct inode *); |
378 | int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int); | 390 | int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int); |
379 | int hfsplus_free_fork(struct super_block *, u32, | 391 | int hfsplus_free_fork(struct super_block *, u32, |
380 | struct hfsplus_fork_raw *, int); | 392 | struct hfsplus_fork_raw *, int); |
@@ -437,8 +449,8 @@ int hfsplus_compare_dentry(const struct dentry *parent, | |||
437 | /* wrapper.c */ | 449 | /* wrapper.c */ |
438 | int hfsplus_read_wrapper(struct super_block *); | 450 | int hfsplus_read_wrapper(struct super_block *); |
439 | int hfs_part_find(struct super_block *, sector_t *, sector_t *); | 451 | int hfs_part_find(struct super_block *, sector_t *, sector_t *); |
440 | int hfsplus_submit_bio(struct block_device *bdev, sector_t sector, | 452 | int hfsplus_submit_bio(struct super_block *sb, sector_t sector, |
441 | void *data, int rw); | 453 | void *buf, void **data, int rw); |
442 | 454 | ||
443 | /* time macros */ | 455 | /* time macros */ |
444 | #define __hfsp_mt2ut(t) (be32_to_cpu(t) - 2082844800U) | 456 | #define __hfsp_mt2ut(t) (be32_to_cpu(t) - 2082844800U) |
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 30486e01d003..4cc1e3a36ec7 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
@@ -195,11 +195,13 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, | |||
195 | hip->flags = 0; | 195 | hip->flags = 0; |
196 | set_bit(HFSPLUS_I_RSRC, &hip->flags); | 196 | set_bit(HFSPLUS_I_RSRC, &hip->flags); |
197 | 197 | ||
198 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); | 198 | err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); |
199 | err = hfsplus_find_cat(sb, dir->i_ino, &fd); | 199 | if (!err) { |
200 | if (!err) | 200 | err = hfsplus_find_cat(sb, dir->i_ino, &fd); |
201 | err = hfsplus_cat_read_inode(inode, &fd); | 201 | if (!err) |
202 | hfs_find_exit(&fd); | 202 | err = hfsplus_cat_read_inode(inode, &fd); |
203 | hfs_find_exit(&fd); | ||
204 | } | ||
203 | if (err) { | 205 | if (err) { |
204 | iput(inode); | 206 | iput(inode); |
205 | return ERR_PTR(err); | 207 | return ERR_PTR(err); |
diff --git a/fs/hfsplus/part_tbl.c b/fs/hfsplus/part_tbl.c index 40ad88c12c64..eb355d81e279 100644 --- a/fs/hfsplus/part_tbl.c +++ b/fs/hfsplus/part_tbl.c | |||
@@ -88,11 +88,12 @@ static int hfs_parse_old_pmap(struct super_block *sb, struct old_pmap *pm, | |||
88 | return -ENOENT; | 88 | return -ENOENT; |
89 | } | 89 | } |
90 | 90 | ||
91 | static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm, | 91 | static int hfs_parse_new_pmap(struct super_block *sb, void *buf, |
92 | sector_t *part_start, sector_t *part_size) | 92 | struct new_pmap *pm, sector_t *part_start, sector_t *part_size) |
93 | { | 93 | { |
94 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); | 94 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); |
95 | int size = be32_to_cpu(pm->pmMapBlkCnt); | 95 | int size = be32_to_cpu(pm->pmMapBlkCnt); |
96 | int buf_size = hfsplus_min_io_size(sb); | ||
96 | int res; | 97 | int res; |
97 | int i = 0; | 98 | int i = 0; |
98 | 99 | ||
@@ -107,11 +108,14 @@ static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm, | |||
107 | if (++i >= size) | 108 | if (++i >= size) |
108 | return -ENOENT; | 109 | return -ENOENT; |
109 | 110 | ||
110 | res = hfsplus_submit_bio(sb->s_bdev, | 111 | pm = (struct new_pmap *)((u8 *)pm + HFSPLUS_SECTOR_SIZE); |
111 | *part_start + HFS_PMAP_BLK + i, | 112 | if ((u8 *)pm - (u8 *)buf >= buf_size) { |
112 | pm, READ); | 113 | res = hfsplus_submit_bio(sb, |
113 | if (res) | 114 | *part_start + HFS_PMAP_BLK + i, |
114 | return res; | 115 | buf, (void **)&pm, READ); |
116 | if (res) | ||
117 | return res; | ||
118 | } | ||
115 | } while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC)); | 119 | } while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC)); |
116 | 120 | ||
117 | return -ENOENT; | 121 | return -ENOENT; |
@@ -124,15 +128,15 @@ static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm, | |||
124 | int hfs_part_find(struct super_block *sb, | 128 | int hfs_part_find(struct super_block *sb, |
125 | sector_t *part_start, sector_t *part_size) | 129 | sector_t *part_start, sector_t *part_size) |
126 | { | 130 | { |
127 | void *data; | 131 | void *buf, *data; |
128 | int res; | 132 | int res; |
129 | 133 | ||
130 | data = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL); | 134 | buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL); |
131 | if (!data) | 135 | if (!buf) |
132 | return -ENOMEM; | 136 | return -ENOMEM; |
133 | 137 | ||
134 | res = hfsplus_submit_bio(sb->s_bdev, *part_start + HFS_PMAP_BLK, | 138 | res = hfsplus_submit_bio(sb, *part_start + HFS_PMAP_BLK, |
135 | data, READ); | 139 | buf, &data, READ); |
136 | if (res) | 140 | if (res) |
137 | goto out; | 141 | goto out; |
138 | 142 | ||
@@ -141,13 +145,13 @@ int hfs_part_find(struct super_block *sb, | |||
141 | res = hfs_parse_old_pmap(sb, data, part_start, part_size); | 145 | res = hfs_parse_old_pmap(sb, data, part_start, part_size); |
142 | break; | 146 | break; |
143 | case HFS_NEW_PMAP_MAGIC: | 147 | case HFS_NEW_PMAP_MAGIC: |
144 | res = hfs_parse_new_pmap(sb, data, part_start, part_size); | 148 | res = hfs_parse_new_pmap(sb, buf, data, part_start, part_size); |
145 | break; | 149 | break; |
146 | default: | 150 | default: |
147 | res = -ENOENT; | 151 | res = -ENOENT; |
148 | break; | 152 | break; |
149 | } | 153 | } |
150 | out: | 154 | out: |
151 | kfree(data); | 155 | kfree(buf); |
152 | return res; | 156 | return res; |
153 | } | 157 | } |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 84a47b709f51..c106ca22e812 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
@@ -73,11 +73,13 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino) | |||
73 | 73 | ||
74 | if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID || | 74 | if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID || |
75 | inode->i_ino == HFSPLUS_ROOT_CNID) { | 75 | inode->i_ino == HFSPLUS_ROOT_CNID) { |
76 | hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); | 76 | err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); |
77 | err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); | 77 | if (!err) { |
78 | if (!err) | 78 | err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); |
79 | err = hfsplus_cat_read_inode(inode, &fd); | 79 | if (!err) |
80 | hfs_find_exit(&fd); | 80 | err = hfsplus_cat_read_inode(inode, &fd); |
81 | hfs_find_exit(&fd); | ||
82 | } | ||
81 | } else { | 83 | } else { |
82 | err = hfsplus_system_read_inode(inode); | 84 | err = hfsplus_system_read_inode(inode); |
83 | } | 85 | } |
@@ -133,9 +135,13 @@ static int hfsplus_system_write_inode(struct inode *inode) | |||
133 | static int hfsplus_write_inode(struct inode *inode, | 135 | static int hfsplus_write_inode(struct inode *inode, |
134 | struct writeback_control *wbc) | 136 | struct writeback_control *wbc) |
135 | { | 137 | { |
138 | int err; | ||
139 | |||
136 | dprint(DBG_INODE, "hfsplus_write_inode: %lu\n", inode->i_ino); | 140 | dprint(DBG_INODE, "hfsplus_write_inode: %lu\n", inode->i_ino); |
137 | 141 | ||
138 | hfsplus_ext_write_extent(inode); | 142 | err = hfsplus_ext_write_extent(inode); |
143 | if (err) | ||
144 | return err; | ||
139 | 145 | ||
140 | if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID || | 146 | if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID || |
141 | inode->i_ino == HFSPLUS_ROOT_CNID) | 147 | inode->i_ino == HFSPLUS_ROOT_CNID) |
@@ -197,17 +203,17 @@ int hfsplus_sync_fs(struct super_block *sb, int wait) | |||
197 | write_backup = 1; | 203 | write_backup = 1; |
198 | } | 204 | } |
199 | 205 | ||
200 | error2 = hfsplus_submit_bio(sb->s_bdev, | 206 | error2 = hfsplus_submit_bio(sb, |
201 | sbi->part_start + HFSPLUS_VOLHEAD_SECTOR, | 207 | sbi->part_start + HFSPLUS_VOLHEAD_SECTOR, |
202 | sbi->s_vhdr, WRITE_SYNC); | 208 | sbi->s_vhdr_buf, NULL, WRITE_SYNC); |
203 | if (!error) | 209 | if (!error) |
204 | error = error2; | 210 | error = error2; |
205 | if (!write_backup) | 211 | if (!write_backup) |
206 | goto out; | 212 | goto out; |
207 | 213 | ||
208 | error2 = hfsplus_submit_bio(sb->s_bdev, | 214 | error2 = hfsplus_submit_bio(sb, |
209 | sbi->part_start + sbi->sect_count - 2, | 215 | sbi->part_start + sbi->sect_count - 2, |
210 | sbi->s_backup_vhdr, WRITE_SYNC); | 216 | sbi->s_backup_vhdr_buf, NULL, WRITE_SYNC); |
211 | if (!error) | 217 | if (!error) |
212 | error2 = error; | 218 | error2 = error; |
213 | out: | 219 | out: |
@@ -251,8 +257,8 @@ static void hfsplus_put_super(struct super_block *sb) | |||
251 | hfs_btree_close(sbi->ext_tree); | 257 | hfs_btree_close(sbi->ext_tree); |
252 | iput(sbi->alloc_file); | 258 | iput(sbi->alloc_file); |
253 | iput(sbi->hidden_dir); | 259 | iput(sbi->hidden_dir); |
254 | kfree(sbi->s_vhdr); | 260 | kfree(sbi->s_vhdr_buf); |
255 | kfree(sbi->s_backup_vhdr); | 261 | kfree(sbi->s_backup_vhdr_buf); |
256 | unload_nls(sbi->nls); | 262 | unload_nls(sbi->nls); |
257 | kfree(sb->s_fs_info); | 263 | kfree(sb->s_fs_info); |
258 | sb->s_fs_info = NULL; | 264 | sb->s_fs_info = NULL; |
@@ -393,6 +399,13 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
393 | if (!sbi->rsrc_clump_blocks) | 399 | if (!sbi->rsrc_clump_blocks) |
394 | sbi->rsrc_clump_blocks = 1; | 400 | sbi->rsrc_clump_blocks = 1; |
395 | 401 | ||
402 | err = generic_check_addressable(sbi->alloc_blksz_shift, | ||
403 | sbi->total_blocks); | ||
404 | if (err) { | ||
405 | printk(KERN_ERR "hfs: filesystem size too large.\n"); | ||
406 | goto out_free_vhdr; | ||
407 | } | ||
408 | |||
396 | /* Set up operations so we can load metadata */ | 409 | /* Set up operations so we can load metadata */ |
397 | sb->s_op = &hfsplus_sops; | 410 | sb->s_op = &hfsplus_sops; |
398 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 411 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
@@ -417,6 +430,8 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
417 | sb->s_flags |= MS_RDONLY; | 430 | sb->s_flags |= MS_RDONLY; |
418 | } | 431 | } |
419 | 432 | ||
433 | err = -EINVAL; | ||
434 | |||
420 | /* Load metadata objects (B*Trees) */ | 435 | /* Load metadata objects (B*Trees) */ |
421 | sbi->ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID); | 436 | sbi->ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID); |
422 | if (!sbi->ext_tree) { | 437 | if (!sbi->ext_tree) { |
@@ -447,7 +462,9 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
447 | 462 | ||
448 | str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; | 463 | str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; |
449 | str.name = HFSP_HIDDENDIR_NAME; | 464 | str.name = HFSP_HIDDENDIR_NAME; |
450 | hfs_find_init(sbi->cat_tree, &fd); | 465 | err = hfs_find_init(sbi->cat_tree, &fd); |
466 | if (err) | ||
467 | goto out_put_root; | ||
451 | hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str); | 468 | hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str); |
452 | if (!hfs_brec_read(&fd, &entry, sizeof(entry))) { | 469 | if (!hfs_brec_read(&fd, &entry, sizeof(entry))) { |
453 | hfs_find_exit(&fd); | 470 | hfs_find_exit(&fd); |
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c index a3f0bfcc881e..a32998f29f0b 100644 --- a/fs/hfsplus/unicode.c +++ b/fs/hfsplus/unicode.c | |||
@@ -142,7 +142,11 @@ int hfsplus_uni2asc(struct super_block *sb, | |||
142 | /* search for single decomposed char */ | 142 | /* search for single decomposed char */ |
143 | if (likely(compose)) | 143 | if (likely(compose)) |
144 | ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c0); | 144 | ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c0); |
145 | if (ce1 && (cc = ce1[0])) { | 145 | if (ce1) |
146 | cc = ce1[0]; | ||
147 | else | ||
148 | cc = 0; | ||
149 | if (cc) { | ||
146 | /* start of a possibly decomposed Hangul char */ | 150 | /* start of a possibly decomposed Hangul char */ |
147 | if (cc != 0xffff) | 151 | if (cc != 0xffff) |
148 | goto done; | 152 | goto done; |
@@ -209,7 +213,8 @@ int hfsplus_uni2asc(struct super_block *sb, | |||
209 | i++; | 213 | i++; |
210 | ce2 = ce1; | 214 | ce2 = ce1; |
211 | } | 215 | } |
212 | if ((cc = ce2[0])) { | 216 | cc = ce2[0]; |
217 | if (cc) { | ||
213 | ip += i; | 218 | ip += i; |
214 | ustrlen -= i; | 219 | ustrlen -= i; |
215 | goto done; | 220 | goto done; |
@@ -301,7 +306,11 @@ int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, | |||
301 | while (outlen < HFSPLUS_MAX_STRLEN && len > 0) { | 306 | while (outlen < HFSPLUS_MAX_STRLEN && len > 0) { |
302 | size = asc2unichar(sb, astr, len, &c); | 307 | size = asc2unichar(sb, astr, len, &c); |
303 | 308 | ||
304 | if (decompose && (dstr = decompose_unichar(c, &dsize))) { | 309 | if (decompose) |
310 | dstr = decompose_unichar(c, &dsize); | ||
311 | else | ||
312 | dstr = NULL; | ||
313 | if (dstr) { | ||
305 | if (outlen + dsize > HFSPLUS_MAX_STRLEN) | 314 | if (outlen + dsize > HFSPLUS_MAX_STRLEN) |
306 | break; | 315 | break; |
307 | do { | 316 | do { |
@@ -346,15 +355,23 @@ int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode, | |||
346 | astr += size; | 355 | astr += size; |
347 | len -= size; | 356 | len -= size; |
348 | 357 | ||
349 | if (decompose && (dstr = decompose_unichar(c, &dsize))) { | 358 | if (decompose) |
359 | dstr = decompose_unichar(c, &dsize); | ||
360 | else | ||
361 | dstr = NULL; | ||
362 | if (dstr) { | ||
350 | do { | 363 | do { |
351 | c2 = *dstr++; | 364 | c2 = *dstr++; |
352 | if (!casefold || (c2 = case_fold(c2))) | 365 | if (casefold) |
366 | c2 = case_fold(c2); | ||
367 | if (!casefold || c2) | ||
353 | hash = partial_name_hash(c2, hash); | 368 | hash = partial_name_hash(c2, hash); |
354 | } while (--dsize > 0); | 369 | } while (--dsize > 0); |
355 | } else { | 370 | } else { |
356 | c2 = c; | 371 | c2 = c; |
357 | if (!casefold || (c2 = case_fold(c2))) | 372 | if (casefold) |
373 | c2 = case_fold(c2); | ||
374 | if (!casefold || c2) | ||
358 | hash = partial_name_hash(c2, hash); | 375 | hash = partial_name_hash(c2, hash); |
359 | } | 376 | } |
360 | } | 377 | } |
@@ -422,12 +439,14 @@ int hfsplus_compare_dentry(const struct dentry *parent, | |||
422 | c1 = *dstr1; | 439 | c1 = *dstr1; |
423 | c2 = *dstr2; | 440 | c2 = *dstr2; |
424 | if (casefold) { | 441 | if (casefold) { |
425 | if (!(c1 = case_fold(c1))) { | 442 | c1 = case_fold(c1); |
443 | if (!c1) { | ||
426 | dstr1++; | 444 | dstr1++; |
427 | dsize1--; | 445 | dsize1--; |
428 | continue; | 446 | continue; |
429 | } | 447 | } |
430 | if (!(c2 = case_fold(c2))) { | 448 | c2 = case_fold(c2); |
449 | if (!c2) { | ||
431 | dstr2++; | 450 | dstr2++; |
432 | dsize2--; | 451 | dsize2--; |
433 | continue; | 452 | continue; |
diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c index 4ac88ff79aa6..10e515a0d452 100644 --- a/fs/hfsplus/wrapper.c +++ b/fs/hfsplus/wrapper.c | |||
@@ -31,25 +31,67 @@ static void hfsplus_end_io_sync(struct bio *bio, int err) | |||
31 | complete(bio->bi_private); | 31 | complete(bio->bi_private); |
32 | } | 32 | } |
33 | 33 | ||
34 | int hfsplus_submit_bio(struct block_device *bdev, sector_t sector, | 34 | /* |
35 | void *data, int rw) | 35 | * hfsplus_submit_bio - Perfrom block I/O |
36 | * @sb: super block of volume for I/O | ||
37 | * @sector: block to read or write, for blocks of HFSPLUS_SECTOR_SIZE bytes | ||
38 | * @buf: buffer for I/O | ||
39 | * @data: output pointer for location of requested data | ||
40 | * @rw: direction of I/O | ||
41 | * | ||
42 | * The unit of I/O is hfsplus_min_io_size(sb), which may be bigger than | ||
43 | * HFSPLUS_SECTOR_SIZE, and @buf must be sized accordingly. On reads | ||
44 | * @data will return a pointer to the start of the requested sector, | ||
45 | * which may not be the same location as @buf. | ||
46 | * | ||
47 | * If @sector is not aligned to the bdev logical block size it will | ||
48 | * be rounded down. For writes this means that @buf should contain data | ||
49 | * that starts at the rounded-down address. As long as the data was | ||
50 | * read using hfsplus_submit_bio() and the same buffer is used things | ||
51 | * will work correctly. | ||
52 | */ | ||
53 | int hfsplus_submit_bio(struct super_block *sb, sector_t sector, | ||
54 | void *buf, void **data, int rw) | ||
36 | { | 55 | { |
37 | DECLARE_COMPLETION_ONSTACK(wait); | 56 | DECLARE_COMPLETION_ONSTACK(wait); |
38 | struct bio *bio; | 57 | struct bio *bio; |
39 | int ret = 0; | 58 | int ret = 0; |
59 | unsigned int io_size; | ||
60 | loff_t start; | ||
61 | int offset; | ||
62 | |||
63 | /* | ||
64 | * Align sector to hardware sector size and find offset. We | ||
65 | * assume that io_size is a power of two, which _should_ | ||
66 | * be true. | ||
67 | */ | ||
68 | io_size = hfsplus_min_io_size(sb); | ||
69 | start = (loff_t)sector << HFSPLUS_SECTOR_SHIFT; | ||
70 | offset = start & (io_size - 1); | ||
71 | sector &= ~((io_size >> HFSPLUS_SECTOR_SHIFT) - 1); | ||
40 | 72 | ||
41 | bio = bio_alloc(GFP_NOIO, 1); | 73 | bio = bio_alloc(GFP_NOIO, 1); |
42 | bio->bi_sector = sector; | 74 | bio->bi_sector = sector; |
43 | bio->bi_bdev = bdev; | 75 | bio->bi_bdev = sb->s_bdev; |
44 | bio->bi_end_io = hfsplus_end_io_sync; | 76 | bio->bi_end_io = hfsplus_end_io_sync; |
45 | bio->bi_private = &wait; | 77 | bio->bi_private = &wait; |
46 | 78 | ||
47 | /* | 79 | if (!(rw & WRITE) && data) |
48 | * We always submit one sector at a time, so bio_add_page must not fail. | 80 | *data = (u8 *)buf + offset; |
49 | */ | 81 | |
50 | if (bio_add_page(bio, virt_to_page(data), HFSPLUS_SECTOR_SIZE, | 82 | while (io_size > 0) { |
51 | offset_in_page(data)) != HFSPLUS_SECTOR_SIZE) | 83 | unsigned int page_offset = offset_in_page(buf); |
52 | BUG(); | 84 | unsigned int len = min_t(unsigned int, PAGE_SIZE - page_offset, |
85 | io_size); | ||
86 | |||
87 | ret = bio_add_page(bio, virt_to_page(buf), len, page_offset); | ||
88 | if (ret != len) { | ||
89 | ret = -EIO; | ||
90 | goto out; | ||
91 | } | ||
92 | io_size -= len; | ||
93 | buf = (u8 *)buf + len; | ||
94 | } | ||
53 | 95 | ||
54 | submit_bio(rw, bio); | 96 | submit_bio(rw, bio); |
55 | wait_for_completion(&wait); | 97 | wait_for_completion(&wait); |
@@ -57,8 +99,9 @@ int hfsplus_submit_bio(struct block_device *bdev, sector_t sector, | |||
57 | if (!bio_flagged(bio, BIO_UPTODATE)) | 99 | if (!bio_flagged(bio, BIO_UPTODATE)) |
58 | ret = -EIO; | 100 | ret = -EIO; |
59 | 101 | ||
102 | out: | ||
60 | bio_put(bio); | 103 | bio_put(bio); |
61 | return ret; | 104 | return ret < 0 ? ret : 0; |
62 | } | 105 | } |
63 | 106 | ||
64 | static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd) | 107 | static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd) |
@@ -141,23 +184,19 @@ int hfsplus_read_wrapper(struct super_block *sb) | |||
141 | 184 | ||
142 | if (hfsplus_get_last_session(sb, &part_start, &part_size)) | 185 | if (hfsplus_get_last_session(sb, &part_start, &part_size)) |
143 | goto out; | 186 | goto out; |
144 | if ((u64)part_start + part_size > 0x100000000ULL) { | ||
145 | pr_err("hfs: volumes larger than 2TB are not supported yet\n"); | ||
146 | goto out; | ||
147 | } | ||
148 | 187 | ||
149 | error = -ENOMEM; | 188 | error = -ENOMEM; |
150 | sbi->s_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL); | 189 | sbi->s_vhdr_buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL); |
151 | if (!sbi->s_vhdr) | 190 | if (!sbi->s_vhdr_buf) |
152 | goto out; | 191 | goto out; |
153 | sbi->s_backup_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL); | 192 | sbi->s_backup_vhdr_buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL); |
154 | if (!sbi->s_backup_vhdr) | 193 | if (!sbi->s_backup_vhdr_buf) |
155 | goto out_free_vhdr; | 194 | goto out_free_vhdr; |
156 | 195 | ||
157 | reread: | 196 | reread: |
158 | error = hfsplus_submit_bio(sb->s_bdev, | 197 | error = hfsplus_submit_bio(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, |
159 | part_start + HFSPLUS_VOLHEAD_SECTOR, | 198 | sbi->s_vhdr_buf, (void **)&sbi->s_vhdr, |
160 | sbi->s_vhdr, READ); | 199 | READ); |
161 | if (error) | 200 | if (error) |
162 | goto out_free_backup_vhdr; | 201 | goto out_free_backup_vhdr; |
163 | 202 | ||
@@ -172,8 +211,9 @@ reread: | |||
172 | if (!hfsplus_read_mdb(sbi->s_vhdr, &wd)) | 211 | if (!hfsplus_read_mdb(sbi->s_vhdr, &wd)) |
173 | goto out_free_backup_vhdr; | 212 | goto out_free_backup_vhdr; |
174 | wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT; | 213 | wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT; |
175 | part_start += wd.ablk_start + wd.embed_start * wd.ablk_size; | 214 | part_start += (sector_t)wd.ablk_start + |
176 | part_size = wd.embed_count * wd.ablk_size; | 215 | (sector_t)wd.embed_start * wd.ablk_size; |
216 | part_size = (sector_t)wd.embed_count * wd.ablk_size; | ||
177 | goto reread; | 217 | goto reread; |
178 | default: | 218 | default: |
179 | /* | 219 | /* |
@@ -186,9 +226,9 @@ reread: | |||
186 | goto reread; | 226 | goto reread; |
187 | } | 227 | } |
188 | 228 | ||
189 | error = hfsplus_submit_bio(sb->s_bdev, | 229 | error = hfsplus_submit_bio(sb, part_start + part_size - 2, |
190 | part_start + part_size - 2, | 230 | sbi->s_backup_vhdr_buf, |
191 | sbi->s_backup_vhdr, READ); | 231 | (void **)&sbi->s_backup_vhdr, READ); |
192 | if (error) | 232 | if (error) |
193 | goto out_free_backup_vhdr; | 233 | goto out_free_backup_vhdr; |
194 | 234 | ||