summaryrefslogtreecommitdiffstats
path: root/fs/ext4/xattr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4/xattr.c')
-rw-r--r--fs/ext4/xattr.c258
1 files changed, 165 insertions, 93 deletions
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 53980ee164ed..649dc2953901 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -108,6 +108,10 @@ const struct xattr_handler *ext4_xattr_handlers[] = {
108#define EA_BLOCK_CACHE(inode) (((struct ext4_sb_info *) \ 108#define EA_BLOCK_CACHE(inode) (((struct ext4_sb_info *) \
109 inode->i_sb->s_fs_info)->s_ea_block_cache) 109 inode->i_sb->s_fs_info)->s_ea_block_cache)
110 110
111static int
112ext4_expand_inode_array(struct ext4_xattr_inode_array **ea_inode_array,
113 struct inode *inode);
114
111#ifdef CONFIG_LOCKDEP 115#ifdef CONFIG_LOCKDEP
112void ext4_xattr_inode_set_class(struct inode *ea_inode) 116void ext4_xattr_inode_set_class(struct inode *ea_inode)
113{ 117{
@@ -652,6 +656,128 @@ static void ext4_xattr_update_super_block(handle_t *handle,
652 } 656 }
653} 657}
654 658
659static int ext4_xattr_ensure_credits(handle_t *handle, struct inode *inode,
660 int credits, struct buffer_head *bh,
661 bool dirty, bool block_csum)
662{
663 int error;
664
665 if (!ext4_handle_valid(handle))
666 return 0;
667
668 if (handle->h_buffer_credits >= credits)
669 return 0;
670
671 error = ext4_journal_extend(handle, credits - handle->h_buffer_credits);
672 if (!error)
673 return 0;
674 if (error < 0) {
675 ext4_warning(inode->i_sb, "Extend journal (error %d)", error);
676 return error;
677 }
678
679 if (bh && dirty) {
680 if (block_csum)
681 ext4_xattr_block_csum_set(inode, bh);
682 error = ext4_handle_dirty_metadata(handle, NULL, bh);
683 if (error) {
684 ext4_warning(inode->i_sb, "Handle metadata (error %d)",
685 error);
686 return error;
687 }
688 }
689
690 error = ext4_journal_restart(handle, credits);
691 if (error) {
692 ext4_warning(inode->i_sb, "Restart journal (error %d)", error);
693 return error;
694 }
695
696 if (bh) {
697 error = ext4_journal_get_write_access(handle, bh);
698 if (error) {
699 ext4_warning(inode->i_sb,
700 "Get write access failed (error %d)",
701 error);
702 return error;
703 }
704 }
705 return 0;
706}
707
708static void
709ext4_xattr_inode_remove_all(handle_t *handle, struct inode *parent,
710 struct buffer_head *bh,
711 struct ext4_xattr_entry *first, bool block_csum,
712 struct ext4_xattr_inode_array **ea_inode_array,
713 int extra_credits)
714{
715 struct inode *ea_inode;
716 struct ext4_xattr_entry *entry;
717 bool dirty = false;
718 unsigned int ea_ino;
719 int err;
720 int credits;
721
722 /* One credit for dec ref on ea_inode, one for orphan list addition, */
723 credits = 2 + extra_credits;
724
725 for (entry = first; !IS_LAST_ENTRY(entry);
726 entry = EXT4_XATTR_NEXT(entry)) {
727 if (!entry->e_value_inum)
728 continue;
729 ea_ino = le32_to_cpu(entry->e_value_inum);
730 err = ext4_xattr_inode_iget(parent, ea_ino, &ea_inode);
731 if (err)
732 continue;
733
734 err = ext4_expand_inode_array(ea_inode_array, ea_inode);
735 if (err) {
736 ext4_warning_inode(ea_inode,
737 "Expand inode array err=%d", err);
738 iput(ea_inode);
739 continue;
740 }
741
742 err = ext4_xattr_ensure_credits(handle, parent, credits, bh,
743 dirty, block_csum);
744 if (err) {
745 ext4_warning_inode(ea_inode, "Ensure credits err=%d",
746 err);
747 continue;
748 }
749
750 inode_lock(ea_inode);
751 clear_nlink(ea_inode);
752 ext4_orphan_add(handle, ea_inode);
753 inode_unlock(ea_inode);
754
755 /*
756 * Forget about ea_inode within the same transaction that
757 * decrements the ref count. This avoids duplicate decrements in
758 * case the rest of the work spills over to subsequent
759 * transactions.
760 */
761 entry->e_value_inum = 0;
762 entry->e_value_size = 0;
763
764 dirty = true;
765 }
766
767 if (dirty) {
768 /*
769 * Note that we are deliberately skipping csum calculation for
770 * the final update because we do not expect any journal
771 * restarts until xattr block is freed.
772 */
773
774 err = ext4_handle_dirty_metadata(handle, NULL, bh);
775 if (err)
776 ext4_warning_inode(parent,
777 "handle dirty metadata err=%d", err);
778 }
779}
780
655/* 781/*
656 * Release the xattr block BH: If the reference count is > 1, decrement it; 782 * Release the xattr block BH: If the reference count is > 1, decrement it;
657 * otherwise free the block. 783 * otherwise free the block.
@@ -1982,42 +2108,6 @@ ext4_expand_inode_array(struct ext4_xattr_inode_array **ea_inode_array,
1982 return 0; 2108 return 0;
1983} 2109}
1984 2110
1985/**
1986 * Add xattr inode to orphan list
1987 */
1988static int
1989ext4_xattr_inode_orphan_add(handle_t *handle, struct inode *inode, int credits,
1990 struct ext4_xattr_inode_array *ea_inode_array)
1991{
1992 int idx = 0, error = 0;
1993 struct inode *ea_inode;
1994
1995 if (ea_inode_array == NULL)
1996 return 0;
1997
1998 for (; idx < ea_inode_array->count; ++idx) {
1999 if (!ext4_handle_has_enough_credits(handle, credits)) {
2000 error = ext4_journal_extend(handle, credits);
2001 if (error > 0)
2002 error = ext4_journal_restart(handle, credits);
2003
2004 if (error != 0) {
2005 ext4_warning(inode->i_sb,
2006 "couldn't extend journal "
2007 "(err %d)", error);
2008 return error;
2009 }
2010 }
2011 ea_inode = ea_inode_array->inodes[idx];
2012 inode_lock(ea_inode);
2013 ext4_orphan_add(handle, ea_inode);
2014 inode_unlock(ea_inode);
2015 /* the inode's i_count will be released by caller */
2016 }
2017
2018 return 0;
2019}
2020
2021/* 2111/*
2022 * ext4_xattr_delete_inode() 2112 * ext4_xattr_delete_inode()
2023 * 2113 *
@@ -2030,16 +2120,23 @@ ext4_xattr_inode_orphan_add(handle_t *handle, struct inode *inode, int credits,
2030 */ 2120 */
2031int 2121int
2032ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, 2122ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
2033 struct ext4_xattr_inode_array **ea_inode_array) 2123 struct ext4_xattr_inode_array **ea_inode_array,
2124 int extra_credits)
2034{ 2125{
2035 struct buffer_head *bh = NULL; 2126 struct buffer_head *bh = NULL;
2036 struct ext4_xattr_ibody_header *header; 2127 struct ext4_xattr_ibody_header *header;
2037 struct ext4_inode *raw_inode; 2128 struct ext4_inode *raw_inode;
2038 struct ext4_iloc iloc; 2129 struct ext4_iloc iloc = { .bh = NULL };
2039 struct ext4_xattr_entry *entry; 2130 int error;
2040 struct inode *ea_inode; 2131
2041 unsigned int ea_ino; 2132 error = ext4_xattr_ensure_credits(handle, inode, extra_credits,
2042 int credits = 3, error = 0; 2133 NULL /* bh */,
2134 false /* dirty */,
2135 false /* block_csum */);
2136 if (error) {
2137 EXT4_ERROR_INODE(inode, "ensure credits (error %d)", error);
2138 goto cleanup;
2139 }
2043 2140
2044 if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) 2141 if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR))
2045 goto delete_external_ea; 2142 goto delete_external_ea;
@@ -2047,31 +2144,20 @@ ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
2047 error = ext4_get_inode_loc(inode, &iloc); 2144 error = ext4_get_inode_loc(inode, &iloc);
2048 if (error) 2145 if (error)
2049 goto cleanup; 2146 goto cleanup;
2147
2148 error = ext4_journal_get_write_access(handle, iloc.bh);
2149 if (error)
2150 goto cleanup;
2151
2050 raw_inode = ext4_raw_inode(&iloc); 2152 raw_inode = ext4_raw_inode(&iloc);
2051 header = IHDR(inode, raw_inode); 2153 header = IHDR(inode, raw_inode);
2052 for (entry = IFIRST(header); !IS_LAST_ENTRY(entry); 2154 ext4_xattr_inode_remove_all(handle, inode, iloc.bh, IFIRST(header),
2053 entry = EXT4_XATTR_NEXT(entry)) { 2155 false /* block_csum */, ea_inode_array,
2054 if (!entry->e_value_inum) 2156 extra_credits);
2055 continue;
2056 ea_ino = le32_to_cpu(entry->e_value_inum);
2057 error = ext4_xattr_inode_iget(inode, ea_ino, &ea_inode);
2058 if (error)
2059 continue;
2060 error = ext4_expand_inode_array(ea_inode_array, ea_inode);
2061 if (error) {
2062 iput(ea_inode);
2063 brelse(iloc.bh);
2064 goto cleanup;
2065 }
2066 entry->e_value_inum = 0;
2067 }
2068 brelse(iloc.bh);
2069 2157
2070delete_external_ea: 2158delete_external_ea:
2071 if (!EXT4_I(inode)->i_file_acl) { 2159 if (!EXT4_I(inode)->i_file_acl) {
2072 /* add xattr inode to orphan list */ 2160 error = 0;
2073 error = ext4_xattr_inode_orphan_add(handle, inode, credits,
2074 *ea_inode_array);
2075 goto cleanup; 2161 goto cleanup;
2076 } 2162 }
2077 bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); 2163 bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
@@ -2089,46 +2175,32 @@ delete_external_ea:
2089 goto cleanup; 2175 goto cleanup;
2090 } 2176 }
2091 2177
2092 for (entry = BFIRST(bh); !IS_LAST_ENTRY(entry); 2178 if (ext4_has_feature_ea_inode(inode->i_sb)) {
2093 entry = EXT4_XATTR_NEXT(entry)) { 2179 error = ext4_journal_get_write_access(handle, bh);
2094 if (!entry->e_value_inum)
2095 continue;
2096 ea_ino = le32_to_cpu(entry->e_value_inum);
2097 error = ext4_xattr_inode_iget(inode, ea_ino, &ea_inode);
2098 if (error)
2099 continue;
2100 error = ext4_expand_inode_array(ea_inode_array, ea_inode);
2101 if (error)
2102 goto cleanup;
2103 entry->e_value_inum = 0;
2104 }
2105
2106 /* add xattr inode to orphan list */
2107 error = ext4_xattr_inode_orphan_add(handle, inode, credits,
2108 *ea_inode_array);
2109 if (error)
2110 goto cleanup;
2111
2112 if (!IS_NOQUOTA(inode))
2113 credits += 2 * EXT4_QUOTA_DEL_BLOCKS(inode->i_sb);
2114
2115 if (!ext4_handle_has_enough_credits(handle, credits)) {
2116 error = ext4_journal_extend(handle, credits);
2117 if (error > 0)
2118 error = ext4_journal_restart(handle, credits);
2119 if (error) { 2180 if (error) {
2120 ext4_warning(inode->i_sb, 2181 EXT4_ERROR_INODE(inode, "write access %llu",
2121 "couldn't extend journal (err %d)", error); 2182 EXT4_I(inode)->i_file_acl);
2122 goto cleanup; 2183 goto cleanup;
2123 } 2184 }
2185 ext4_xattr_inode_remove_all(handle, inode, bh,
2186 BFIRST(bh),
2187 true /* block_csum */,
2188 ea_inode_array,
2189 extra_credits);
2124 } 2190 }
2125 2191
2126 ext4_xattr_release_block(handle, inode, bh); 2192 ext4_xattr_release_block(handle, inode, bh);
2193 /* Update i_file_acl within the same transaction that releases block. */
2127 EXT4_I(inode)->i_file_acl = 0; 2194 EXT4_I(inode)->i_file_acl = 0;
2128 2195 error = ext4_mark_inode_dirty(handle, inode);
2196 if (error) {
2197 EXT4_ERROR_INODE(inode, "mark inode dirty (error %d)",
2198 error);
2199 goto cleanup;
2200 }
2129cleanup: 2201cleanup:
2202 brelse(iloc.bh);
2130 brelse(bh); 2203 brelse(bh);
2131
2132 return error; 2204 return error;
2133} 2205}
2134 2206