aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hfsplus
diff options
context:
space:
mode:
authorAl Viro <viro@ftp.linux.org.uk>2010-10-14 09:53:42 -0400
committerChristoph Hellwig <hch@lst.de>2010-10-14 09:53:42 -0400
commitb6b41424f0ec28e9a167fa29b003327860b4b71b (patch)
tree9e17a235542259f82a3a1e2c3d2a1906f2ac4749 /fs/hfsplus
parentee52716245877b821f5ddbb3ace85b73084fb450 (diff)
hfsplus: hfs_bnode_find() can fail, resulting in hfs_bnode_split() breakage
oops and fs corruption; the latter can happen even on valid fs in case of oom. [hch: port of commit 3d10a15d6919488204bdb264050d156ced20d9aa from hfs] Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Diffstat (limited to 'fs/hfsplus')
-rw-r--r--fs/hfsplus/brec.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c
index c88e5d72a402..fa903641992f 100644
--- a/fs/hfsplus/brec.c
+++ b/fs/hfsplus/brec.c
@@ -216,7 +216,7 @@ skip:
216static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) 216static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
217{ 217{
218 struct hfs_btree *tree; 218 struct hfs_btree *tree;
219 struct hfs_bnode *node, *new_node; 219 struct hfs_bnode *node, *new_node, *next_node;
220 struct hfs_bnode_desc node_desc; 220 struct hfs_bnode_desc node_desc;
221 int num_recs, new_rec_off, new_off, old_rec_off; 221 int num_recs, new_rec_off, new_off, old_rec_off;
222 int data_start, data_end, size; 222 int data_start, data_end, size;
@@ -235,6 +235,17 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
235 new_node->type = node->type; 235 new_node->type = node->type;
236 new_node->height = node->height; 236 new_node->height = node->height;
237 237
238 if (node->next)
239 next_node = hfs_bnode_find(tree, node->next);
240 else
241 next_node = NULL;
242
243 if (IS_ERR(next_node)) {
244 hfs_bnode_put(node);
245 hfs_bnode_put(new_node);
246 return next_node;
247 }
248
238 size = tree->node_size / 2 - node->num_recs * 2 - 14; 249 size = tree->node_size / 2 - node->num_recs * 2 - 14;
239 old_rec_off = tree->node_size - 4; 250 old_rec_off = tree->node_size - 4;
240 num_recs = 1; 251 num_recs = 1;
@@ -248,6 +259,8 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
248 /* panic? */ 259 /* panic? */
249 hfs_bnode_put(node); 260 hfs_bnode_put(node);
250 hfs_bnode_put(new_node); 261 hfs_bnode_put(new_node);
262 if (next_node)
263 hfs_bnode_put(next_node);
251 return ERR_PTR(-ENOSPC); 264 return ERR_PTR(-ENOSPC);
252 } 265 }
253 266
@@ -302,8 +315,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
302 hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc)); 315 hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc));
303 316
304 /* update next bnode header */ 317 /* update next bnode header */
305 if (new_node->next) { 318 if (next_node) {
306 struct hfs_bnode *next_node = hfs_bnode_find(tree, new_node->next);
307 next_node->prev = new_node->this; 319 next_node->prev = new_node->this;
308 hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc)); 320 hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc));
309 node_desc.prev = cpu_to_be32(next_node->prev); 321 node_desc.prev = cpu_to_be32(next_node->prev);