aboutsummaryrefslogtreecommitdiffstats
path: root/fs/hfsplus/extents.c
diff options
context:
space:
mode:
authorAlexey Khoroshilov <khoroshilov@ispras.ru>2011-07-05 18:29:59 -0400
committerChristoph Hellwig <hch@lst.de>2011-07-07 11:45:46 -0400
commit5bd9d99d107c56ff7b35a29e930d85f91a07b2fd (patch)
treeb5db237ebff38c90b95f01d8cca28bc8c2536e7f /fs/hfsplus/extents.c
parentc6d5f5fa658f2569a7baaff5acda261a1316cee9 (diff)
hfsplus: add error checking for hfs_find_init()
hfs_find_init() may fail with ENOMEM, but there are places, where the returned value is not checked. The consequences can be very unpleasant, e.g. kfree uninitialized pointer and inappropriate mutex unlocking. The patch adds checks for errors in hfs_find_init(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru> Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/hfsplus/extents.c')
-rw-r--r--fs/hfsplus/extents.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c
index b9c1a4b5ba89..95065a89e7e2 100644
--- a/fs/hfsplus/extents.c
+++ b/fs/hfsplus/extents.c
@@ -124,9 +124,10 @@ static void hfsplus_ext_write_extent_locked(struct inode *inode)
124 if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) { 124 if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) {
125 struct hfs_find_data fd; 125 struct hfs_find_data fd;
126 126
127 hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); 127 if (!hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd)) {
128 __hfsplus_ext_write_extent(inode, &fd); 128 __hfsplus_ext_write_extent(inode, &fd);
129 hfs_find_exit(&fd); 129 hfs_find_exit(&fd);
130 }
130 } 131 }
131} 132}
132 133
@@ -194,9 +195,11 @@ static int hfsplus_ext_read_extent(struct inode *inode, u32 block)
194 block < hip->cached_start + hip->cached_blocks) 195 block < hip->cached_start + hip->cached_blocks)
195 return 0; 196 return 0;
196 197
197 hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); 198 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
198 res = __hfsplus_ext_cache_extent(&fd, inode, block); 199 if (!res) {
199 hfs_find_exit(&fd); 200 res = __hfsplus_ext_cache_extent(&fd, inode, block);
201 hfs_find_exit(&fd);
202 }
200 return res; 203 return res;
201} 204}
202 205
@@ -374,7 +377,9 @@ int hfsplus_free_fork(struct super_block *sb, u32 cnid,
374 if (total_blocks == blocks) 377 if (total_blocks == blocks)
375 return 0; 378 return 0;
376 379
377 hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); 380 res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
381 if (res)
382 return res;
378 do { 383 do {
379 res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid, 384 res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid,
380 total_blocks, type); 385 total_blocks, type);
@@ -503,7 +508,6 @@ void hfsplus_file_truncate(struct inode *inode)
503 struct page *page; 508 struct page *page;
504 void *fsdata; 509 void *fsdata;
505 u32 size = inode->i_size; 510 u32 size = inode->i_size;
506 int res;
507 511
508 res = pagecache_write_begin(NULL, mapping, size, 0, 512 res = pagecache_write_begin(NULL, mapping, size, 0,
509 AOP_FLAG_UNINTERRUPTIBLE, 513 AOP_FLAG_UNINTERRUPTIBLE,
@@ -526,7 +530,12 @@ void hfsplus_file_truncate(struct inode *inode)
526 goto out; 530 goto out;
527 531
528 mutex_lock(&hip->extents_lock); 532 mutex_lock(&hip->extents_lock);
529 hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); 533 res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
534 if (res) {
535 mutex_unlock(&hip->extents_lock);
536 /* XXX: We lack error handling of hfsplus_file_truncate() */
537 return;
538 }
530 while (1) { 539 while (1) {
531 if (alloc_cnt == hip->first_blocks) { 540 if (alloc_cnt == hip->first_blocks) {
532 hfsplus_free_extents(sb, hip->first_extents, 541 hfsplus_free_extents(sb, hip->first_extents,