aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorCarlos Maiolino <cmaiolino@redhat.com>2012-09-27 09:31:33 -0400
committerTheodore Ts'o <tytso@mit.edu>2012-09-27 09:31:33 -0400
commit6d1ab10e69ff5f3cb63920ba965ec0f1f0bdaf8d (patch)
tree7a6efd62087edb8103c6b409aa81e0229bdd4ef4 /fs
parentbbdd68086ca4a8976226e23efd08e2058d34dd81 (diff)
ext4: ext4_bread usage audit
When ext4_bread() returns NULL and err is set to zero, this means there is no phyical block mapped to the specified logical block number. (Previous to commit 90b0a97323, err was uninitialized in this case, which caused other problems.) The directory handling routines use ext4_bread() in many places, the fact that ext4_bread() now returns NULL with err set to zero could cause problems since a number of these functions will simply return the value of err if the result of ext4_bread() was the NULL pointer, causing the caller of the function to think that the function was successful. Since directories should never contain holes, this case can only happen if the file system is corrupted. This commit audits all of the callers of ext4_bread(), and makes sure they do the right thing if a hole in a directory is found by ext4_bread(). Some ext4_bread() callers did not need any changes either because they already had its own hole detector paths. Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/namei.c87
1 files changed, 75 insertions, 12 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index bd87b7a66afb..6d600a69fc9d 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -74,6 +74,12 @@ static struct buffer_head *ext4_append(handle_t *handle,
74 bh = NULL; 74 bh = NULL;
75 } 75 }
76 } 76 }
77 if (!bh && !(*err)) {
78 *err = -EIO;
79 ext4_error(inode->i_sb,
80 "Directory hole detected on inode %lu\n",
81 inode->i_ino);
82 }
77 return bh; 83 return bh;
78} 84}
79 85
@@ -601,8 +607,11 @@ dx_probe(const struct qstr *d_name, struct inode *dir,
601 u32 hash; 607 u32 hash;
602 608
603 frame->bh = NULL; 609 frame->bh = NULL;
604 if (!(bh = ext4_bread (NULL,dir, 0, 0, err))) 610 if (!(bh = ext4_bread(NULL, dir, 0, 0, err))) {
611 if (*err == 0)
612 *err = ERR_BAD_DX_DIR;
605 goto fail; 613 goto fail;
614 }
606 root = (struct dx_root *) bh->b_data; 615 root = (struct dx_root *) bh->b_data;
607 if (root->info.hash_version != DX_HASH_TEA && 616 if (root->info.hash_version != DX_HASH_TEA &&
608 root->info.hash_version != DX_HASH_HALF_MD4 && 617 root->info.hash_version != DX_HASH_HALF_MD4 &&
@@ -703,8 +712,11 @@ dx_probe(const struct qstr *d_name, struct inode *dir,
703 frame->entries = entries; 712 frame->entries = entries;
704 frame->at = at; 713 frame->at = at;
705 if (!indirect--) return frame; 714 if (!indirect--) return frame;
706 if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err))) 715 if (!(bh = ext4_bread(NULL, dir, dx_get_block(at), 0, err))) {
716 if (!(*err))
717 *err = ERR_BAD_DX_DIR;
707 goto fail2; 718 goto fail2;
719 }
708 at = entries = ((struct dx_node *) bh->b_data)->entries; 720 at = entries = ((struct dx_node *) bh->b_data)->entries;
709 721
710 if (!buffer_verified(bh) && 722 if (!buffer_verified(bh) &&
@@ -814,8 +826,15 @@ static int ext4_htree_next_block(struct inode *dir, __u32 hash,
814 */ 826 */
815 while (num_frames--) { 827 while (num_frames--) {
816 if (!(bh = ext4_bread(NULL, dir, dx_get_block(p->at), 828 if (!(bh = ext4_bread(NULL, dir, dx_get_block(p->at),
817 0, &err))) 829 0, &err))) {
830 if (!err) {
831 ext4_error(dir->i_sb,
832 "Directory hole detected on inode %lu\n",
833 dir->i_ino);
834 return -EIO;
835 }
818 return err; /* Failure */ 836 return err; /* Failure */
837 }
819 838
820 if (!buffer_verified(bh) && 839 if (!buffer_verified(bh) &&
821 !ext4_dx_csum_verify(dir, 840 !ext4_dx_csum_verify(dir,
@@ -850,8 +869,15 @@ static int htree_dirblock_to_tree(struct file *dir_file,
850 869
851 dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n", 870 dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n",
852 (unsigned long)block)); 871 (unsigned long)block));
853 if (!(bh = ext4_bread (NULL, dir, block, 0, &err))) 872 if (!(bh = ext4_bread(NULL, dir, block, 0, &err))) {
873 if (!err) {
874 err = -EIO;
875 ext4_error(dir->i_sb,
876 "Directory hole detected on inode %lu\n",
877 dir->i_ino);
878 }
854 return err; 879 return err;
880 }
855 881
856 if (!buffer_verified(bh) && 882 if (!buffer_verified(bh) &&
857 !ext4_dirent_csum_verify(dir, (struct ext4_dir_entry *)bh->b_data)) 883 !ext4_dirent_csum_verify(dir, (struct ext4_dir_entry *)bh->b_data))
@@ -1274,8 +1300,15 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q
1274 return NULL; 1300 return NULL;
1275 do { 1301 do {
1276 block = dx_get_block(frame->at); 1302 block = dx_get_block(frame->at);
1277 if (!(bh = ext4_bread(NULL, dir, block, 0, err))) 1303 if (!(bh = ext4_bread(NULL, dir, block, 0, err))) {
1304 if (!(*err)) {
1305 *err = -EIO;
1306 ext4_error(dir->i_sb,
1307 "Directory hole detected on inode %lu\n",
1308 dir->i_ino);
1309 }
1278 goto errout; 1310 goto errout;
1311 }
1279 1312
1280 if (!buffer_verified(bh) && 1313 if (!buffer_verified(bh) &&
1281 !ext4_dirent_csum_verify(dir, 1314 !ext4_dirent_csum_verify(dir,
@@ -1808,9 +1841,15 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
1808 } 1841 }
1809 blocks = dir->i_size >> sb->s_blocksize_bits; 1842 blocks = dir->i_size >> sb->s_blocksize_bits;
1810 for (block = 0; block < blocks; block++) { 1843 for (block = 0; block < blocks; block++) {
1811 bh = ext4_bread(handle, dir, block, 0, &retval); 1844 if (!(bh = ext4_bread(handle, dir, block, 0, &retval))) {
1812 if(!bh) 1845 if (!retval) {
1846 retval = -EIO;
1847 ext4_error(inode->i_sb,
1848 "Directory hole detected on inode %lu\n",
1849 inode->i_ino);
1850 }
1813 return retval; 1851 return retval;
1852 }
1814 if (!buffer_verified(bh) && 1853 if (!buffer_verified(bh) &&
1815 !ext4_dirent_csum_verify(dir, 1854 !ext4_dirent_csum_verify(dir,
1816 (struct ext4_dir_entry *)bh->b_data)) 1855 (struct ext4_dir_entry *)bh->b_data))
@@ -1867,8 +1906,15 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
1867 entries = frame->entries; 1906 entries = frame->entries;
1868 at = frame->at; 1907 at = frame->at;
1869 1908
1870 if (!(bh = ext4_bread(handle,dir, dx_get_block(frame->at), 0, &err))) 1909 if (!(bh = ext4_bread(handle, dir, dx_get_block(frame->at), 0, &err))) {
1910 if (!err) {
1911 err = -EIO;
1912 ext4_error(dir->i_sb,
1913 "Directory hole detected on inode %lu\n",
1914 dir->i_ino);
1915 }
1871 goto cleanup; 1916 goto cleanup;
1917 }
1872 1918
1873 if (!buffer_verified(bh) && 1919 if (!buffer_verified(bh) &&
1874 !ext4_dirent_csum_verify(dir, (struct ext4_dir_entry *)bh->b_data)) 1920 !ext4_dirent_csum_verify(dir, (struct ext4_dir_entry *)bh->b_data))
@@ -2204,9 +2250,15 @@ retry:
2204 inode->i_op = &ext4_dir_inode_operations; 2250 inode->i_op = &ext4_dir_inode_operations;
2205 inode->i_fop = &ext4_dir_operations; 2251 inode->i_fop = &ext4_dir_operations;
2206 inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize; 2252 inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
2207 dir_block = ext4_bread(handle, inode, 0, 1, &err); 2253 if (!(dir_block = ext4_bread(handle, inode, 0, 1, &err))) {
2208 if (!dir_block) 2254 if (!err) {
2255 err = -EIO;
2256 ext4_error(inode->i_sb,
2257 "Directory hole detected on inode %lu\n",
2258 inode->i_ino);
2259 }
2209 goto out_clear_inode; 2260 goto out_clear_inode;
2261 }
2210 BUFFER_TRACE(dir_block, "get_write_access"); 2262 BUFFER_TRACE(dir_block, "get_write_access");
2211 err = ext4_journal_get_write_access(handle, dir_block); 2263 err = ext4_journal_get_write_access(handle, dir_block);
2212 if (err) 2264 if (err)
@@ -2323,6 +2375,11 @@ static int empty_dir(struct inode *inode)
2323 EXT4_ERROR_INODE(inode, 2375 EXT4_ERROR_INODE(inode,
2324 "error %d reading directory " 2376 "error %d reading directory "
2325 "lblock %u", err, lblock); 2377 "lblock %u", err, lblock);
2378 else
2379 ext4_warning(inode->i_sb,
2380 "bad directory (dir #%lu) - no data block",
2381 inode->i_ino);
2382
2326 offset += sb->s_blocksize; 2383 offset += sb->s_blocksize;
2327 continue; 2384 continue;
2328 } 2385 }
@@ -2830,9 +2887,15 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
2830 goto end_rename; 2887 goto end_rename;
2831 } 2888 }
2832 retval = -EIO; 2889 retval = -EIO;
2833 dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval); 2890 if (!(dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval))) {
2834 if (!dir_bh) 2891 if (!retval) {
2892 retval = -EIO;
2893 ext4_error(old_inode->i_sb,
2894 "Directory hole detected on inode %lu\n",
2895 old_inode->i_ino);
2896 }
2835 goto end_rename; 2897 goto end_rename;
2898 }
2836 if (!buffer_verified(dir_bh) && 2899 if (!buffer_verified(dir_bh) &&
2837 !ext4_dirent_csum_verify(old_inode, 2900 !ext4_dirent_csum_verify(old_inode,
2838 (struct ext4_dir_entry *)dir_bh->b_data)) 2901 (struct ext4_dir_entry *)dir_bh->b_data))