aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hfsplus
diff options
context:
space:
mode:
Diffstat (limited to 'fs/hfsplus')
-rw-r--r--fs/hfsplus/brec.c4
-rw-r--r--fs/hfsplus/catalog.c14
-rw-r--r--fs/hfsplus/dir.c8
-rw-r--r--fs/hfsplus/extents.c50
-rw-r--r--fs/hfsplus/hfsplus_fs.h18
-rw-r--r--fs/hfsplus/inode.c12
-rw-r--r--fs/hfsplus/part_tbl.c32
-rw-r--r--fs/hfsplus/super.c43
-rw-r--r--fs/hfsplus/unicode.c35
-rw-r--r--fs/hfsplus/wrapper.c92
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);
43again: 45again:
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
122static void hfsplus_ext_write_extent_locked(struct inode *inode) 122static 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
133void hfsplus_ext_write_extent(struct inode *inode) 138int 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
140static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd, 149static 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,
255done: 267done:
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
470insert_extent: 486insert_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;
110struct hfs_btree; 111struct hfs_btree;
111 112
112struct hfsplus_sb_info { 113struct 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 */
267static 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 */
376int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); 388int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
377void hfsplus_ext_write_extent(struct inode *); 389int hfsplus_ext_write_extent(struct inode *);
378int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int); 390int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int);
379int hfsplus_free_fork(struct super_block *, u32, 391int 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 */
438int hfsplus_read_wrapper(struct super_block *); 450int hfsplus_read_wrapper(struct super_block *);
439int hfs_part_find(struct super_block *, sector_t *, sector_t *); 451int hfs_part_find(struct super_block *, sector_t *, sector_t *);
440int hfsplus_submit_bio(struct block_device *bdev, sector_t sector, 452int 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
91static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm, 91static 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,
124int hfs_part_find(struct super_block *sb, 128int 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 }
150out: 154out:
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)
133static int hfsplus_write_inode(struct inode *inode, 135static 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;
213out: 219out:
@@ -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
34int 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 */
53int 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
102out:
60 bio_put(bio); 103 bio_put(bio);
61 return ret; 104 return ret < 0 ? ret : 0;
62} 105}
63 106
64static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd) 107static 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
157reread: 196reread:
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