diff options
author | Alexey Khoroshilov <khoroshilov@ispras.ru> | 2011-07-05 22:29:59 (GMT) |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2011-07-07 15:45:46 (GMT) |
commit | 5bd9d99d107c56ff7b35a29e930d85f91a07b2fd (patch) | |
tree | b5db237ebff38c90b95f01d8cca28bc8c2536e7f /fs/hfsplus/extents.c | |
parent | c6d5f5fa658f2569a7baaff5acda261a1316cee9 (diff) | |
download | linux-5bd9d99d107c56ff7b35a29e930d85f91a07b2fd.tar.xz |
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.c | 27 |
1 files changed, 18 insertions, 9 deletions
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index b9c1a4b..95065a8 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) if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) { struct hfs_find_data fd; - hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); - __hfsplus_ext_write_extent(inode, &fd); - hfs_find_exit(&fd); + if (!hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd)) { + __hfsplus_ext_write_extent(inode, &fd); + hfs_find_exit(&fd); + } } } @@ -194,9 +195,11 @@ static int hfsplus_ext_read_extent(struct inode *inode, u32 block) block < hip->cached_start + hip->cached_blocks) return 0; - hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); - res = __hfsplus_ext_cache_extent(&fd, inode, block); - hfs_find_exit(&fd); + res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); + if (!res) { + res = __hfsplus_ext_cache_extent(&fd, inode, block); + hfs_find_exit(&fd); + } return res; } @@ -374,7 +377,9 @@ int hfsplus_free_fork(struct super_block *sb, u32 cnid, if (total_blocks == blocks) return 0; - hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); + res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); + if (res) + return res; do { res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid, total_blocks, type); @@ -503,7 +508,6 @@ void hfsplus_file_truncate(struct inode *inode) struct page *page; void *fsdata; u32 size = inode->i_size; - int res; res = pagecache_write_begin(NULL, mapping, size, 0, AOP_FLAG_UNINTERRUPTIBLE, @@ -526,7 +530,12 @@ void hfsplus_file_truncate(struct inode *inode) goto out; mutex_lock(&hip->extents_lock); - hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); + res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); + if (res) { + mutex_unlock(&hip->extents_lock); + /* XXX: We lack error handling of hfsplus_file_truncate() */ + return; + } while (1) { if (alloc_cnt == hip->first_blocks) { hfsplus_free_extents(sb, hip->first_extents, |