]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/ext4/namei.c
ext4: fix ext4_flush_completed_IO wait semantics
[karo-tx-linux.git] / fs / ext4 / namei.c
index 2a42cc04466f6858f55fea7e4a8beb2f1232319f..6d600a69fc9dedcfa92b45064cfcb85e79260946 100644 (file)
@@ -55,6 +55,13 @@ static struct buffer_head *ext4_append(handle_t *handle,
 {
        struct buffer_head *bh;
 
+       if (unlikely(EXT4_SB(inode->i_sb)->s_max_dir_size_kb &&
+                    ((inode->i_size >> 10) >=
+                     EXT4_SB(inode->i_sb)->s_max_dir_size_kb))) {
+               *err = -ENOSPC;
+               return NULL;
+       }
+
        *block = inode->i_size >> inode->i_sb->s_blocksize_bits;
 
        bh = ext4_bread(handle, inode, *block, 1, err);
@@ -67,6 +74,12 @@ static struct buffer_head *ext4_append(handle_t *handle,
                        bh = NULL;
                }
        }
+       if (!bh && !(*err)) {
+               *err = -EIO;
+               ext4_error(inode->i_sb,
+                          "Directory hole detected on inode %lu\n",
+                          inode->i_ino);
+       }
        return bh;
 }
 
@@ -594,8 +607,11 @@ dx_probe(const struct qstr *d_name, struct inode *dir,
        u32 hash;
 
        frame->bh = NULL;
-       if (!(bh = ext4_bread (NULL,dir, 0, 0, err)))
+       if (!(bh = ext4_bread(NULL, dir, 0, 0, err))) {
+               if (*err == 0)
+                       *err = ERR_BAD_DX_DIR;
                goto fail;
+       }
        root = (struct dx_root *) bh->b_data;
        if (root->info.hash_version != DX_HASH_TEA &&
            root->info.hash_version != DX_HASH_HALF_MD4 &&
@@ -696,8 +712,11 @@ dx_probe(const struct qstr *d_name, struct inode *dir,
                frame->entries = entries;
                frame->at = at;
                if (!indirect--) return frame;
-               if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err)))
+               if (!(bh = ext4_bread(NULL, dir, dx_get_block(at), 0, err))) {
+                       if (!(*err))
+                               *err = ERR_BAD_DX_DIR;
                        goto fail2;
+               }
                at = entries = ((struct dx_node *) bh->b_data)->entries;
 
                if (!buffer_verified(bh) &&
@@ -807,8 +826,15 @@ static int ext4_htree_next_block(struct inode *dir, __u32 hash,
         */
        while (num_frames--) {
                if (!(bh = ext4_bread(NULL, dir, dx_get_block(p->at),
-                                     0, &err)))
+                                     0, &err))) {
+                       if (!err) {
+                               ext4_error(dir->i_sb,
+                                          "Directory hole detected on inode %lu\n",
+                                          dir->i_ino);
+                               return -EIO;
+                       }
                        return err; /* Failure */
+               }
 
                if (!buffer_verified(bh) &&
                    !ext4_dx_csum_verify(dir,
@@ -839,12 +865,19 @@ static int htree_dirblock_to_tree(struct file *dir_file,
 {
        struct buffer_head *bh;
        struct ext4_dir_entry_2 *de, *top;
-       int err, count = 0;
+       int err = 0, count = 0;
 
        dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n",
                                                        (unsigned long)block));
-       if (!(bh = ext4_bread (NULL, dir, block, 0, &err)))
+       if (!(bh = ext4_bread(NULL, dir, block, 0, &err))) {
+               if (!err) {
+                       err = -EIO;
+                       ext4_error(dir->i_sb,
+                                  "Directory hole detected on inode %lu\n",
+                                  dir->i_ino);
+               }
                return err;
+       }
 
        if (!buffer_verified(bh) &&
            !ext4_dirent_csum_verify(dir, (struct ext4_dir_entry *)bh->b_data))
@@ -1267,8 +1300,15 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q
                return NULL;
        do {
                block = dx_get_block(frame->at);
-               if (!(bh = ext4_bread(NULL, dir, block, 0, err)))
+               if (!(bh = ext4_bread(NULL, dir, block, 0, err))) {
+                       if (!(*err)) {
+                               *err = -EIO;
+                               ext4_error(dir->i_sb,
+                                          "Directory hole detected on inode %lu\n",
+                                          dir->i_ino);
+                       }
                        goto errout;
+               }
 
                if (!buffer_verified(bh) &&
                    !ext4_dirent_csum_verify(dir,
@@ -1801,9 +1841,15 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
        }
        blocks = dir->i_size >> sb->s_blocksize_bits;
        for (block = 0; block < blocks; block++) {
-               bh = ext4_bread(handle, dir, block, 0, &retval);
-               if(!bh)
+               if (!(bh = ext4_bread(handle, dir, block, 0, &retval))) {
+                       if (!retval) {
+                               retval = -EIO;
+                               ext4_error(inode->i_sb,
+                                          "Directory hole detected on inode %lu\n",
+                                          inode->i_ino);
+                       }
                        return retval;
+               }
                if (!buffer_verified(bh) &&
                    !ext4_dirent_csum_verify(dir,
                                (struct ext4_dir_entry *)bh->b_data))
@@ -1860,8 +1906,15 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
        entries = frame->entries;
        at = frame->at;
 
-       if (!(bh = ext4_bread(handle,dir, dx_get_block(frame->at), 0, &err)))
+       if (!(bh = ext4_bread(handle, dir, dx_get_block(frame->at), 0, &err))) {
+               if (!err) {
+                       err = -EIO;
+                       ext4_error(dir->i_sb,
+                                  "Directory hole detected on inode %lu\n",
+                                  dir->i_ino);
+               }
                goto cleanup;
+       }
 
        if (!buffer_verified(bh) &&
            !ext4_dirent_csum_verify(dir, (struct ext4_dir_entry *)bh->b_data))
@@ -2149,9 +2202,7 @@ retry:
        err = PTR_ERR(inode);
        if (!IS_ERR(inode)) {
                init_special_inode(inode, inode->i_mode, rdev);
-#ifdef CONFIG_EXT4_FS_XATTR
                inode->i_op = &ext4_special_inode_operations;
-#endif
                err = ext4_add_nondir(handle, dentry, inode);
        }
        ext4_journal_stop(handle);
@@ -2199,9 +2250,15 @@ retry:
        inode->i_op = &ext4_dir_inode_operations;
        inode->i_fop = &ext4_dir_operations;
        inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
-       dir_block = ext4_bread(handle, inode, 0, 1, &err);
-       if (!dir_block)
+       if (!(dir_block = ext4_bread(handle, inode, 0, 1, &err))) {
+               if (!err) {
+                       err = -EIO;
+                       ext4_error(inode->i_sb,
+                                  "Directory hole detected on inode %lu\n",
+                                  inode->i_ino);
+               }
                goto out_clear_inode;
+       }
        BUFFER_TRACE(dir_block, "get_write_access");
        err = ext4_journal_get_write_access(handle, dir_block);
        if (err)
@@ -2318,6 +2375,11 @@ static int empty_dir(struct inode *inode)
                                        EXT4_ERROR_INODE(inode,
                                                "error %d reading directory "
                                                "lblock %u", err, lblock);
+                               else
+                                       ext4_warning(inode->i_sb,
+                                               "bad directory (dir #%lu) - no data block",
+                                               inode->i_ino);
+
                                offset += sb->s_blocksize;
                                continue;
                        }
@@ -2362,7 +2424,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
        struct ext4_iloc iloc;
        int err = 0, rc;
 
-       if (!ext4_handle_valid(handle))
+       if (!EXT4_SB(sb)->s_journal)
                return 0;
 
        mutex_lock(&EXT4_SB(sb)->s_orphan_lock);
@@ -2436,8 +2498,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
        struct ext4_iloc iloc;
        int err = 0;
 
-       /* ext4_handle_valid() assumes a valid handle_t pointer */
-       if (handle && !ext4_handle_valid(handle))
+       if (!EXT4_SB(inode->i_sb)->s_journal)
                return 0;
 
        mutex_lock(&EXT4_SB(inode->i_sb)->s_orphan_lock);
@@ -2456,7 +2517,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
         * transaction handle with which to update the orphan list on
         * disk, but we still need to remove the inode from the linked
         * list in memory. */
-       if (sbi->s_journal && !handle)
+       if (!handle)
                goto out;
 
        err = ext4_reserve_inode_write(handle, inode, &iloc);
@@ -2826,9 +2887,15 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
                                goto end_rename;
                }
                retval = -EIO;
-               dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval);
-               if (!dir_bh)
+               if (!(dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval))) {
+                       if (!retval) {
+                               retval = -EIO;
+                               ext4_error(old_inode->i_sb,
+                                          "Directory hole detected on inode %lu\n",
+                                          old_inode->i_ino);
+                       }
                        goto end_rename;
+               }
                if (!buffer_verified(dir_bh) &&
                    !ext4_dirent_csum_verify(old_inode,
                                (struct ext4_dir_entry *)dir_bh->b_data))