video/rockchip: rga: replace system_nrt_wq with system_wq
[firefly-linux-kernel-4.4.55.git] / fs / ext4 / xattr.c
index bf3130e275ee741361cd102de1ad25246fa39c0e..263002f0389df6d25995b1ed07c7e71ff0aa7585 100644 (file)
@@ -123,17 +123,18 @@ static __le32 ext4_xattr_block_csum(struct inode *inode,
 {
        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
        __u32 csum;
-       __le32 save_csum;
        __le64 dsk_block_nr = cpu_to_le64(block_nr);
+       __u32 dummy_csum = 0;
+       int offset = offsetof(struct ext4_xattr_header, h_checksum);
 
-       save_csum = hdr->h_checksum;
-       hdr->h_checksum = 0;
        csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&dsk_block_nr,
                           sizeof(dsk_block_nr));
-       csum = ext4_chksum(sbi, csum, (__u8 *)hdr,
-                          EXT4_BLOCK_SIZE(inode->i_sb));
+       csum = ext4_chksum(sbi, csum, (__u8 *)hdr, offset);
+       csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, sizeof(dummy_csum));
+       offset += sizeof(dummy_csum);
+       csum = ext4_chksum(sbi, csum, (__u8 *)hdr + offset,
+                          EXT4_BLOCK_SIZE(inode->i_sb) - offset);
 
-       hdr->h_checksum = save_csum;
        return cpu_to_le32(csum);
 }
 
@@ -1269,12 +1270,14 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
        int isize_diff; /* How much do we need to grow i_extra_isize */
 
        down_write(&EXT4_I(inode)->xattr_sem);
+       /*
+        * Set EXT4_STATE_NO_EXPAND to avoid recursion when marking inode dirty
+        */
+       ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND);
 retry:
        isize_diff = new_extra_isize - EXT4_I(inode)->i_extra_isize;
-       if (EXT4_I(inode)->i_extra_isize >= new_extra_isize) {
-               up_write(&EXT4_I(inode)->xattr_sem);
-               return 0;
-       }
+       if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
+               goto out;
 
        header = IHDR(inode, raw_inode);
        entry = IFIRST(header);
@@ -1299,8 +1302,7 @@ retry:
                                (void *)header, total_ino,
                                inode->i_sb->s_blocksize);
                EXT4_I(inode)->i_extra_isize = new_extra_isize;
-               error = 0;
-               goto cleanup;
+               goto out;
        }
 
        /*
@@ -1423,21 +1425,22 @@ retry:
                error = ext4_xattr_ibody_set(handle, inode, &i, is);
                if (error)
                        goto cleanup;
+               total_ino -= entry_size;
 
                entry = IFIRST(header);
                if (entry_size + EXT4_XATTR_SIZE(size) >= isize_diff)
                        shift_bytes = isize_diff;
                else
-                       shift_bytes = entry_size + size;
+                       shift_bytes = entry_size + EXT4_XATTR_SIZE(size);
                /* Adjust the offsets and shift the remaining entries ahead */
                ext4_xattr_shift_entries(entry, -shift_bytes,
                        (void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE +
                        EXT4_I(inode)->i_extra_isize + shift_bytes,
-                       (void *)header, total_ino - entry_size,
-                       inode->i_sb->s_blocksize);
+                       (void *)header, total_ino, inode->i_sb->s_blocksize);
 
                isize_diff -= shift_bytes;
                EXT4_I(inode)->i_extra_isize += shift_bytes;
+               header = IHDR(inode, raw_inode);
 
                i.name = b_entry_name;
                i.value = buffer;
@@ -1459,6 +1462,8 @@ retry:
                kfree(bs);
        }
        brelse(bh);
+out:
+       ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND);
        up_write(&EXT4_I(inode)->xattr_sem);
        return 0;
 
@@ -1470,6 +1475,10 @@ cleanup:
        kfree(is);
        kfree(bs);
        brelse(bh);
+       /*
+        * We deliberately leave EXT4_STATE_NO_EXPAND set here since inode
+        * size expansion failed.
+        */
        up_write(&EXT4_I(inode)->xattr_sem);
        return error;
 }