Merge tag 'clk-for-linus-3.11' of git://git.linaro.org/people/mturquette/linux
[firefly-linux-kernel-4.4.55.git] / fs / ext4 / namei.c
index 6653fc35ecb7dda920377a7d45ab8efef2091b2d..234b834d5a9749991e30a97e24e6017124c4e51d 100644 (file)
@@ -918,11 +918,8 @@ static int htree_dirblock_to_tree(struct file *dir_file,
                                bh->b_data, bh->b_size,
                                (block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb))
                                         + ((char *)de - bh->b_data))) {
-                       /* On error, skip the f_pos to the next block. */
-                       dir_file->f_pos = (dir_file->f_pos |
-                                       (dir->i_sb->s_blocksize - 1)) + 1;
-                       brelse(bh);
-                       return count;
+                       /* silently ignore the rest of the block */
+                       break;
                }
                ext4fs_dirhash(de->name, de->name_len, hinfo);
                if ((hinfo->hash < start_hash) ||
@@ -2299,6 +2296,45 @@ retry:
        return err;
 }
 
+static int ext4_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       handle_t *handle;
+       struct inode *inode;
+       int err, retries = 0;
+
+       dquot_initialize(dir);
+
+retry:
+       inode = ext4_new_inode_start_handle(dir, mode,
+                                           NULL, 0, NULL,
+                                           EXT4_HT_DIR,
+                       EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
+                         4 + EXT4_XATTR_TRANS_BLOCKS);
+       handle = ext4_journal_current_handle();
+       err = PTR_ERR(inode);
+       if (!IS_ERR(inode)) {
+               inode->i_op = &ext4_file_inode_operations;
+               inode->i_fop = &ext4_file_operations;
+               ext4_set_aops(inode);
+               err = ext4_orphan_add(handle, inode);
+               if (err)
+                       goto err_drop_inode;
+               mark_inode_dirty(inode);
+               d_tmpfile(dentry, inode);
+               unlock_new_inode(inode);
+       }
+       if (handle)
+               ext4_journal_stop(handle);
+       if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
+               goto retry;
+       return err;
+err_drop_inode:
+       ext4_journal_stop(handle);
+       unlock_new_inode(inode);
+       iput(inode);
+       return err;
+}
+
 struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
                          struct ext4_dir_entry_2 *de,
                          int blocksize, int csum_size,
@@ -2906,7 +2942,7 @@ static int ext4_link(struct dentry *old_dentry,
 retry:
        handle = ext4_journal_start(dir, EXT4_HT_DIR,
                (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
-                EXT4_INDEX_EXTRA_TRANS_BLOCKS));
+                EXT4_INDEX_EXTRA_TRANS_BLOCKS) + 1);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -2920,6 +2956,11 @@ retry:
        err = ext4_add_entry(handle, dentry, inode);
        if (!err) {
                ext4_mark_inode_dirty(handle, inode);
+               /* this can happen only for tmpfile being
+                * linked the first time
+                */
+               if (inode->i_nlink == 1)
+                       ext4_orphan_del(handle, inode);
                d_instantiate(dentry, inode);
        } else {
                drop_nlink(inode);
@@ -3172,6 +3213,7 @@ const struct inode_operations ext4_dir_inode_operations = {
        .mkdir          = ext4_mkdir,
        .rmdir          = ext4_rmdir,
        .mknod          = ext4_mknod,
+       .tmpfile        = ext4_tmpfile,
        .rename         = ext4_rename,
        .setattr        = ext4_setattr,
        .setxattr       = generic_setxattr,