Hi Andrew,

Today's linux-next merge of the akpm-current tree got a conflict in
fs/ext4/inode.c between commit 4958dee0e70f ("ext4: simplify truncation
code in ext4_setattr()") from the ext4 tree and commit fb6854ec9753
("truncate: drop 'oldsize' truncate_pagecache() parameter") from the
akpm-current tree.

I fixed it up (see below) and can carry the fix as necessary (no action
is required).

-- 
Cheers,
Stephen Rothwell                    s...@canb.auug.org.au

diff --cc fs/ext4/inode.c
index fc4051e,9257d79..0000000
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@@ -4598,9 -4523,7 +4598,8 @@@ int ext4_setattr(struct dentry *dentry
                ext4_journal_stop(handle);
        }
  
 -      if (attr->ia_valid & ATTR_SIZE) {
 +      if (attr->ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) {
 +              handle_t *handle;
-               loff_t oldsize = inode->i_size;
  
                if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
                        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
@@@ -4608,69 -4531,71 +4607,69 @@@
                        if (attr->ia_size > sbi->s_bitmap_maxbytes)
                                return -EFBIG;
                }
 -      }
 -
 -      if (S_ISREG(inode->i_mode) &&
 -          attr->ia_valid & ATTR_SIZE &&
 -          (attr->ia_size < inode->i_size)) {
 -              handle_t *handle;
 -
 -              handle = ext4_journal_start(inode, EXT4_HT_INODE, 3);
 -              if (IS_ERR(handle)) {
 -                      error = PTR_ERR(handle);
 -                      goto err_out;
 -              }
 -              if (ext4_handle_valid(handle)) {
 -                      error = ext4_orphan_add(handle, inode);
 -                      orphan = 1;
 -              }
 -              EXT4_I(inode)->i_disksize = attr->ia_size;
 -              rc = ext4_mark_inode_dirty(handle, inode);
 -              if (!error)
 -                      error = rc;
 -              ext4_journal_stop(handle);
 -
 -              if (ext4_should_order_data(inode)) {
 -                      error = ext4_begin_ordered_truncate(inode,
 +              if (S_ISREG(inode->i_mode) &&
 +                  (attr->ia_size < inode->i_size)) {
 +                      if (ext4_should_order_data(inode)) {
 +                              error = ext4_begin_ordered_truncate(inode,
                                                            attr->ia_size);
 -                      if (error) {
 -                              /* Do as much error cleanup as possible */
 -                              handle = ext4_journal_start(inode,
 -                                                          EXT4_HT_INODE, 3);
 -                              if (IS_ERR(handle)) {
 -                                      ext4_orphan_del(NULL, inode);
 +                              if (error)
                                        goto err_out;
 -                              }
 -                              ext4_orphan_del(handle, inode);
 -                              orphan = 0;
 -                              ext4_journal_stop(handle);
 +                      }
 +                      handle = ext4_journal_start(inode, EXT4_HT_INODE, 3);
 +                      if (IS_ERR(handle)) {
 +                              error = PTR_ERR(handle);
                                goto err_out;
                        }
 -              }
 -      }
 -
 -      if (attr->ia_valid & ATTR_SIZE) {
 -              if (attr->ia_size != inode->i_size) {
 -                      i_size_write(inode, attr->ia_size);
 -                      /*
 -                       * Blocks are going to be removed from the inode. Wait
 -                       * for dio in flight.  Temporarily disable
 -                       * dioread_nolock to prevent livelock.
 -                       */
 -                      if (orphan) {
 -                              if (!ext4_should_journal_data(inode)) {
 -                                      ext4_inode_block_unlocked_dio(inode);
 -                                      inode_dio_wait(inode);
 -                                      ext4_inode_resume_unlocked_dio(inode);
 -                              } else
 -                                      ext4_wait_for_tail_page_commit(inode);
 +                      if (ext4_handle_valid(handle)) {
 +                              error = ext4_orphan_add(handle, inode);
 +                              orphan = 1;
                        }
 +                      down_write(&EXT4_I(inode)->i_data_sem);
 +                      EXT4_I(inode)->i_disksize = attr->ia_size;
 +                      rc = ext4_mark_inode_dirty(handle, inode);
 +                      if (!error)
 +                              error = rc;
                        /*
 -                       * Truncate pagecache after we've waited for commit
 -                       * in data=journal mode to make pages freeable.
 +                       * We have to update i_size under i_data_sem together
 +                       * with i_disksize to avoid races with writeback code
 +                       * running ext4_wb_update_i_disksize().
                         */
 -                      truncate_pagecache(inode, inode->i_size);
 +                      if (!error)
 +                              i_size_write(inode, attr->ia_size);
 +                      up_write(&EXT4_I(inode)->i_data_sem);
 +                      ext4_journal_stop(handle);
 +                      if (error) {
 +                              ext4_orphan_del(NULL, inode);
 +                              goto err_out;
 +                      }
 +              } else
 +                      i_size_write(inode, attr->ia_size);
 +
 +              /*
 +               * Blocks are going to be removed from the inode. Wait
 +               * for dio in flight.  Temporarily disable
 +               * dioread_nolock to prevent livelock.
 +               */
 +              if (orphan) {
 +                      if (!ext4_should_journal_data(inode)) {
 +                              ext4_inode_block_unlocked_dio(inode);
 +                              inode_dio_wait(inode);
 +                              ext4_inode_resume_unlocked_dio(inode);
 +                      } else
 +                              ext4_wait_for_tail_page_commit(inode);
                }
 -              ext4_truncate(inode);
 +              /*
 +               * Truncate pagecache after we've waited for commit
 +               * in data=journal mode to make pages freeable.
 +               */
-               truncate_pagecache(inode, oldsize, inode->i_size);
++              truncate_pagecache(inode, inode->i_size);
        }
 +      /*
 +       * We want to call ext4_truncate() even if attr->ia_size ==
 +       * inode->i_size for cases like truncation of fallocated space
 +       */
 +      if (attr->ia_valid & ATTR_SIZE)
 +              ext4_truncate(inode);
  
        if (!rc) {
                setattr_copy(inode, attr);

Attachment: pgpClUI7xF2kQ.pgp
Description: PGP signature

Reply via email to