The commit is pushed to "branch-rh7-3.10.0-229.7.2-ovz" and will appear at 
https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-229.7.2.vz7.6.4
------>
commit 17c90deb8c54a3feef19d557008fcb510bed8cd3
Author: Dmitry Monakhov <dmonak...@openvz.org>
Date:   Mon Aug 31 20:03:06 2015 +0400

    pfcache/ext4: fix automatic csum calculation
    
    port from 2.6.32-x: diff-pfcache-ext4-fix-automatic-csum-calculation
    
    Bug#1) https://jira.sw.ru/browse/PSBM-23774
       truncate_data_csum should clear it's  state unconditionally
    
    Bug#2) BUG_ON fs/jbd2/transaction.c:1033
     truncate_data_csum call chain looks like follows:
     ->generic_file_buffered_write_iter
       ->ext4_da_write_begin
         ->ext4_journal_start( ,,1) : reserve 1 journal block
       ->ext4_write_end
         ->ext4_update_data_csum
           ->ext4_truncate_data_csum
             ->ext4_xattr_set
               ->ext4_journal_start(,,20): require 20 blocks,
                           but since journal already started
                           it use existing handle
                ->jbd2_journal_dirty_metadata
                   J_ASSERT_JH(jh, handle->h_buffer_credits > 0) -> FAILURE
    
     Obviously it is illegal to modify xattr from random context.
     In order to fix that bug it is reasonable to call ext4_truncate_data_csum()
     only from proper context (where journal was not started yet.)
     This patch splits ext4_update_csum in two peaces:
      1) check correct csum window position and drop csum if necessary (called 
from write_begin)
      2) update in-memory csum state (called from write_end)
    
    Minor fix: do not calculate csum for empty files.
    
    https://jira.sw.ru/browse/PSBM-39233
    
    Signed-off-by: Dmitry Monakhov <dmonak...@openvz.org>
---
 fs/ext4/ext4.h     |  3 ++-
 fs/ext4/inode.c    | 13 +++++++++++++
 fs/ext4/pfcache.c  | 41 +++++++++++++++++++++++------------------
 fs/ext4/truncate.h |  3 +++
 4 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 7059994..fc9608e 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2843,11 +2843,12 @@ extern long ext4_dump_pfcache(struct super_block *sb,
                                        struct pfcache_dump_request __user 
*dump);
 extern int ext4_load_data_csum(struct inode *inode);
 extern void ext4_start_data_csum(struct inode *inode);
+extern void ext4_check_pos_data_csum(struct inode *inode, loff_t pos);
 extern void ext4_update_data_csum(struct inode *inode, loff_t pos,
                                  unsigned len, struct page* page);
 extern void ext4_commit_data_csum(struct inode *inode);
 extern void ext4_clear_data_csum(struct inode *inode);
-extern int ext4_truncate_data_csum(struct inode *inode, loff_t end);
+extern void ext4_truncate_data_csum(struct inode *inode, loff_t end);
 extern void ext4_load_dir_csum(struct inode *inode);
 extern void ext4_save_dir_csum(struct inode *inode);
 static inline int ext4_want_data_csum(struct inode *dir)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 1b3462c..78fc407 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -238,6 +238,8 @@ void ext4_evict_inode(struct inode *inode)
         * protection against it
         */
        sb_start_intwrite(inode->i_sb);
+       if (inode->i_blocks && ext4_test_inode_state(inode, 
EXT4_STATE_PFCACHE_CSUM))
+               ext4_truncate_data_csum(inode, inode->i_size);
        handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE,
                                    ext4_blocks_for_truncate(inode)+3);
        if (IS_ERR(handle)) {
@@ -936,6 +938,10 @@ retry_grab:
        unlock_page(page);
 
 retry_journal:
+       /* Check csum window position before journal_start */
+       if (ext4_test_inode_state(inode, EXT4_STATE_PFCACHE_CSUM))
+               ext4_check_pos_data_csum(inode, pos);
+
        handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, needed_blocks);
        if (IS_ERR(handle)) {
                page_cache_release(page);
@@ -2593,6 +2599,10 @@ retry_grab:
         * of file which has an already mapped buffer.
         */
 retry_journal:
+       /* Check csum window position before journal_start */
+       if (ext4_test_inode_state(inode, EXT4_STATE_PFCACHE_CSUM))
+               ext4_check_pos_data_csum(inode, pos);
+
        handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE,
                                ext4_da_write_credits(inode, pos, len));
        if (IS_ERR(handle)) {
@@ -4640,6 +4650,9 @@ int ext4_setattr(struct dentry *dentry, struct iattr 
*attr)
                                if (error)
                                        goto err_out;
                        }
+                       if (ext4_test_inode_state(inode, 
EXT4_STATE_PFCACHE_CSUM))
+                               ext4_truncate_data_csum(inode, attr->ia_size);
+
                        handle = ext4_journal_start(inode, EXT4_HT_INODE, 3);
                        if (IS_ERR(handle)) {
                                error = PTR_ERR(handle);
diff --git a/fs/ext4/pfcache.c b/fs/ext4/pfcache.c
index bf45504..b9751ce 100644
--- a/fs/ext4/pfcache.c
+++ b/fs/ext4/pfcache.c
@@ -446,6 +446,8 @@ static int ext4_save_data_csum(struct inode *inode, u8 
*csum)
 {
        int ret;
 
+       WARN_ON(journal_current_handle());
+
        if (ext4_test_inode_state(inode, EXT4_STATE_PFCACHE_CSUM) &&
            EXT4_I(inode)->i_data_csum_end < 0 &&
            memcmp(EXT4_I(inode)->i_data_csum, csum, EXT4_DATA_CSUM_SIZE))
@@ -493,30 +495,30 @@ void ext4_save_dir_csum(struct inode *inode)
                        EXT4_DIR_CSUM_VALUE_LEN, 0);
 }
 
-int ext4_truncate_data_csum(struct inode *inode, loff_t pos)
+void ext4_truncate_data_csum(struct inode *inode, loff_t pos)
 {
-       int ret = 0;
 
        if (!S_ISREG(inode->i_mode))
-               return 0;
+               return;
 
        if (EXT4_I(inode)->i_data_csum_end < 0) {
+               WARN_ON(journal_current_handle());
                ext4_xattr_set(inode, EXT4_XATTR_INDEX_TRUSTED,
                                EXT4_DATA_CSUM_NAME, NULL, 0, 0);
                ext4_close_pfcache(inode);
        }
+       spin_lock(&inode->i_lock);
+       ext4_clear_data_csum(inode);
+       if (!pos && test_opt2(inode->i_sb, PFCACHE_CSUM))
+               ext4_init_data_csum(inode);
+       spin_unlock(&inode->i_lock);
+}
 
-       if (EXT4_I(inode)->i_data_csum_end < 0 ||
-           EXT4_I(inode)->i_data_csum_end > pos) {
-               spin_lock(&inode->i_lock);
-               ext4_clear_data_csum(inode);
-               if (!pos && test_opt2(inode->i_sb, PFCACHE_CSUM))
-                       ext4_init_data_csum(inode);
-               else
-                       ret = -1;
-               spin_unlock(&inode->i_lock);
-       }
-       return ret;
+void ext4_check_pos_data_csum(struct inode *inode, loff_t pos)
+{
+       if ((pos & ~(loff_t)(SHA_MESSAGE_BYTES-1)) !=
+           EXT4_I(inode)->i_data_csum_end)
+               ext4_truncate_data_csum(inode, pos);
 }
 
 static void sha_batch_transform(__u32 *digest, const char *data, unsigned 
rounds)
@@ -535,14 +537,14 @@ void ext4_update_data_csum(struct inode *inode, loff_t 
pos,
        __u32 *digest = (__u32 *)EXT4_I(inode)->i_data_csum;
        u8 *kaddr, *data;
 
+       if (!len)
+               return;
+
        len += pos & (SHA_MESSAGE_BYTES-1);
        len &= ~(SHA_MESSAGE_BYTES-1);
        pos &= ~(loff_t)(SHA_MESSAGE_BYTES-1);
 
-       if ((pos != EXT4_I(inode)->i_data_csum_end &&
-            ext4_truncate_data_csum(inode, pos)) || !len)
-               return;
-
+       BUG_ON(pos != EXT4_I(inode)->i_data_csum_end);
        EXT4_I(inode)->i_data_csum_end += len;
 
        kaddr = kmap_atomic(page);
@@ -567,6 +569,9 @@ static int ext4_finish_data_csum(struct inode *inode, u8 
*csum)
        if (end < 0)
                return 0;
 
+       if (!inode->i_size)
+               return -ENODATA;
+
        tail = inode->i_size - end;
        if (tail >= SHA_MESSAGE_BYTES)
                return -EIO;
diff --git a/fs/ext4/truncate.h b/fs/ext4/truncate.h
index 011ba66..bca59b8 100644
--- a/fs/ext4/truncate.h
+++ b/fs/ext4/truncate.h
@@ -11,6 +11,8 @@
 static inline void ext4_truncate_failed_write(struct inode *inode)
 {
        truncate_inode_pages(inode->i_mapping, inode->i_size);
+       if (ext4_test_inode_state(inode, EXT4_STATE_PFCACHE_CSUM))
+               ext4_truncate_data_csum(inode, inode->i_size);
        ext4_truncate(inode);
 }
 
@@ -39,5 +41,6 @@ static inline unsigned long ext4_blocks_for_truncate(struct 
inode *inode)
                needed = EXT4_MAX_TRANS_DATA;
 
        return EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + needed;
+
 }
 
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to