diff options
-rw-r--r-- | fs/ext4/inode.c | 66 | ||||
-rw-r--r-- | fs/ext4/xattr.c | 258 | ||||
-rw-r--r-- | fs/ext4/xattr.h | 3 |
3 files changed, 184 insertions, 143 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 3e9415e2e74d..46def73d3472 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -239,7 +239,11 @@ void ext4_evict_inode(struct inode *inode) | |||
239 | */ | 239 | */ |
240 | sb_start_intwrite(inode->i_sb); | 240 | sb_start_intwrite(inode->i_sb); |
241 | 241 | ||
242 | handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, extra_credits); | 242 | if (!IS_NOQUOTA(inode)) |
243 | extra_credits += EXT4_MAXQUOTAS_DEL_BLOCKS(inode->i_sb); | ||
244 | |||
245 | handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, | ||
246 | ext4_blocks_for_truncate(inode)+extra_credits); | ||
243 | if (IS_ERR(handle)) { | 247 | if (IS_ERR(handle)) { |
244 | ext4_std_error(inode->i_sb, PTR_ERR(handle)); | 248 | ext4_std_error(inode->i_sb, PTR_ERR(handle)); |
245 | /* | 249 | /* |
@@ -251,36 +255,9 @@ void ext4_evict_inode(struct inode *inode) | |||
251 | sb_end_intwrite(inode->i_sb); | 255 | sb_end_intwrite(inode->i_sb); |
252 | goto no_delete; | 256 | goto no_delete; |
253 | } | 257 | } |
258 | |||
254 | if (IS_SYNC(inode)) | 259 | if (IS_SYNC(inode)) |
255 | ext4_handle_sync(handle); | 260 | ext4_handle_sync(handle); |
256 | |||
257 | /* | ||
258 | * Delete xattr inode before deleting the main inode. | ||
259 | */ | ||
260 | err = ext4_xattr_delete_inode(handle, inode, &ea_inode_array); | ||
261 | if (err) { | ||
262 | ext4_warning(inode->i_sb, | ||
263 | "couldn't delete inode's xattr (err %d)", err); | ||
264 | goto stop_handle; | ||
265 | } | ||
266 | |||
267 | if (!IS_NOQUOTA(inode)) | ||
268 | extra_credits += 2 * EXT4_QUOTA_DEL_BLOCKS(inode->i_sb); | ||
269 | |||
270 | if (!ext4_handle_has_enough_credits(handle, | ||
271 | ext4_blocks_for_truncate(inode) + extra_credits)) { | ||
272 | err = ext4_journal_extend(handle, | ||
273 | ext4_blocks_for_truncate(inode) + extra_credits); | ||
274 | if (err > 0) | ||
275 | err = ext4_journal_restart(handle, | ||
276 | ext4_blocks_for_truncate(inode) + extra_credits); | ||
277 | if (err != 0) { | ||
278 | ext4_warning(inode->i_sb, | ||
279 | "couldn't extend journal (err %d)", err); | ||
280 | goto stop_handle; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | inode->i_size = 0; | 261 | inode->i_size = 0; |
285 | err = ext4_mark_inode_dirty(handle, inode); | 262 | err = ext4_mark_inode_dirty(handle, inode); |
286 | if (err) { | 263 | if (err) { |
@@ -298,25 +275,17 @@ void ext4_evict_inode(struct inode *inode) | |||
298 | } | 275 | } |
299 | } | 276 | } |
300 | 277 | ||
301 | /* | 278 | /* Remove xattr references. */ |
302 | * ext4_ext_truncate() doesn't reserve any slop when it | 279 | err = ext4_xattr_delete_inode(handle, inode, &ea_inode_array, |
303 | * restarts journal transactions; therefore there may not be | 280 | extra_credits); |
304 | * enough credits left in the handle to remove the inode from | 281 | if (err) { |
305 | * the orphan list and set the dtime field. | 282 | ext4_warning(inode->i_sb, "xattr delete (err %d)", err); |
306 | */ | 283 | stop_handle: |
307 | if (!ext4_handle_has_enough_credits(handle, extra_credits)) { | 284 | ext4_journal_stop(handle); |
308 | err = ext4_journal_extend(handle, extra_credits); | 285 | ext4_orphan_del(NULL, inode); |
309 | if (err > 0) | 286 | sb_end_intwrite(inode->i_sb); |
310 | err = ext4_journal_restart(handle, extra_credits); | 287 | ext4_xattr_inode_array_free(ea_inode_array); |
311 | if (err != 0) { | 288 | goto no_delete; |
312 | ext4_warning(inode->i_sb, | ||
313 | "couldn't extend journal (err %d)", err); | ||
314 | stop_handle: | ||
315 | ext4_journal_stop(handle); | ||
316 | ext4_orphan_del(NULL, inode); | ||
317 | sb_end_intwrite(inode->i_sb); | ||
318 | goto no_delete; | ||
319 | } | ||
320 | } | 289 | } |
321 | 290 | ||
322 | /* | 291 | /* |
@@ -342,7 +311,6 @@ void ext4_evict_inode(struct inode *inode) | |||
342 | ext4_clear_inode(inode); | 311 | ext4_clear_inode(inode); |
343 | else | 312 | else |
344 | ext4_free_inode(handle, inode); | 313 | ext4_free_inode(handle, inode); |
345 | |||
346 | ext4_journal_stop(handle); | 314 | ext4_journal_stop(handle); |
347 | sb_end_intwrite(inode->i_sb); | 315 | sb_end_intwrite(inode->i_sb); |
348 | ext4_xattr_inode_array_free(ea_inode_array); | 316 | ext4_xattr_inode_array_free(ea_inode_array); |
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 | ||
111 | static int | ||
112 | ext4_expand_inode_array(struct ext4_xattr_inode_array **ea_inode_array, | ||
113 | struct inode *inode); | ||
114 | |||
111 | #ifdef CONFIG_LOCKDEP | 115 | #ifdef CONFIG_LOCKDEP |
112 | void ext4_xattr_inode_set_class(struct inode *ea_inode) | 116 | void 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 | ||
659 | static 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 | |||
708 | static void | ||
709 | ext4_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 | */ | ||
1988 | static int | ||
1989 | ext4_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 | */ |
2031 | int | 2121 | int |
2032 | ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, | 2122 | ext4_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 | ||
2070 | delete_external_ea: | 2158 | delete_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 | } | ||
2129 | cleanup: | 2201 | cleanup: |
2202 | brelse(iloc.bh); | ||
2130 | brelse(bh); | 2203 | brelse(bh); |
2131 | |||
2132 | return error; | 2204 | return error; |
2133 | } | 2205 | } |
2134 | 2206 | ||
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index adf761518a73..b2005a2716d9 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h | |||
@@ -169,7 +169,8 @@ extern int ext4_xattr_set_credits(struct inode *inode, size_t value_len); | |||
169 | 169 | ||
170 | extern int ext4_xattr_inode_unlink(struct inode *inode, unsigned long ea_ino); | 170 | extern int ext4_xattr_inode_unlink(struct inode *inode, unsigned long ea_ino); |
171 | extern int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, | 171 | extern int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, |
172 | struct ext4_xattr_inode_array **array); | 172 | struct ext4_xattr_inode_array **array, |
173 | int extra_credits); | ||
173 | extern void ext4_xattr_inode_array_free(struct ext4_xattr_inode_array *array); | 174 | extern void ext4_xattr_inode_array_free(struct ext4_xattr_inode_array *array); |
174 | 175 | ||
175 | extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, | 176 | extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, |