Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * Interface between ext4 and JBD
4 : : */
5 : :
6 : : #include "ext4_jbd2.h"
7 : :
8 : : #include <trace/events/ext4.h>
9 : :
10 : : /* Just increment the non-pointer handle value */
11 : 0 : static handle_t *ext4_get_nojournal(void)
12 : : {
13 : 0 : handle_t *handle = current->journal_info;
14 : 0 : unsigned long ref_cnt = (unsigned long)handle;
15 : :
16 [ # # ]: 0 : BUG_ON(ref_cnt >= EXT4_NOJOURNAL_MAX_REF_COUNT);
17 : :
18 : 0 : ref_cnt++;
19 : 0 : handle = (handle_t *)ref_cnt;
20 : :
21 : 0 : current->journal_info = handle;
22 : 0 : return handle;
23 : : }
24 : :
25 : :
26 : : /* Decrement the non-pointer handle value */
27 : 0 : static void ext4_put_nojournal(handle_t *handle)
28 : : {
29 : 0 : unsigned long ref_cnt = (unsigned long)handle;
30 : :
31 [ # # ]: 0 : BUG_ON(ref_cnt == 0);
32 : :
33 : 0 : ref_cnt--;
34 : 0 : handle = (handle_t *)ref_cnt;
35 : :
36 : 0 : current->journal_info = handle;
37 : 0 : }
38 : :
39 : : /*
40 : : * Wrappers for jbd2_journal_start/end.
41 : : */
42 : 2781178 : static int ext4_journal_check_start(struct super_block *sb)
43 : : {
44 : : journal_t *journal;
45 : :
46 : 2781178 : might_sleep();
47 : :
48 [ + + ]: 2781178 : if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
49 : : return -EIO;
50 : :
51 [ + + ]: 2781184 : if (sb_rdonly(sb))
52 : : return -EROFS;
53 [ - + ]: 2781182 : WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE);
54 : 2781180 : journal = EXT4_SB(sb)->s_journal;
55 : : /*
56 : : * Special case here: if the journal has aborted behind our
57 : : * backs (eg. EIO in the commit thread), then we still need to
58 : : * take the FS itself readonly cleanly.
59 : : */
60 [ + - - + ]: 5562360 : if (journal && is_journal_aborted(journal)) {
61 : 0 : ext4_abort(sb, "Detected aborted journal");
62 : 0 : return -EROFS;
63 : : }
64 : : return 0;
65 : : }
66 : :
67 : 2781166 : handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,
68 : : int type, int blocks, int rsv_blocks)
69 : : {
70 : : journal_t *journal;
71 : : int err;
72 : :
73 : 2781166 : trace_ext4_journal_start(sb, blocks, rsv_blocks, _RET_IP_);
74 : 2781176 : err = ext4_journal_check_start(sb);
75 [ - + ]: 2781170 : if (err < 0)
76 : 0 : return ERR_PTR(err);
77 : :
78 : 2781170 : journal = EXT4_SB(sb)->s_journal;
79 [ - + ]: 2781170 : if (!journal)
80 : 0 : return ext4_get_nojournal();
81 : 2781170 : return jbd2__journal_start(journal, blocks, rsv_blocks, GFP_NOFS,
82 : : type, line);
83 : : }
84 : :
85 : 2781162 : int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
86 : : {
87 : : struct super_block *sb;
88 : : int err;
89 : : int rc;
90 : :
91 [ - + ]: 2781162 : if (!ext4_handle_valid(handle)) {
92 : 0 : ext4_put_nojournal(handle);
93 : 0 : return 0;
94 : : }
95 : :
96 : 2781162 : err = handle->h_err;
97 [ - + ]: 2781162 : if (!handle->h_transaction) {
98 : 0 : rc = jbd2_journal_stop(handle);
99 [ # # ]: 0 : return err ? err : rc;
100 : : }
101 : :
102 : 2781162 : sb = handle->h_transaction->t_journal->j_private;
103 : 2781162 : rc = jbd2_journal_stop(handle);
104 : :
105 [ + + ]: 2781186 : if (!err)
106 : : err = rc;
107 [ - + ]: 2781186 : if (err)
108 : 0 : __ext4_std_error(sb, where, line, err);
109 : 2781184 : return err;
110 : : }
111 : :
112 : 0 : handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line,
113 : : int type)
114 : : {
115 : : struct super_block *sb;
116 : : int err;
117 : :
118 [ # # ]: 0 : if (!ext4_handle_valid(handle))
119 : 0 : return ext4_get_nojournal();
120 : :
121 : 0 : sb = handle->h_journal->j_private;
122 : 0 : trace_ext4_journal_start_reserved(sb, handle->h_buffer_credits,
123 : 0 : _RET_IP_);
124 : 0 : err = ext4_journal_check_start(sb);
125 [ # # ]: 0 : if (err < 0) {
126 : 0 : jbd2_journal_free_reserved(handle);
127 : 0 : return ERR_PTR(err);
128 : : }
129 : :
130 : 0 : err = jbd2_journal_start_reserved(handle, type, line);
131 [ # # ]: 0 : if (err < 0)
132 : 0 : return ERR_PTR(err);
133 : : return handle;
134 : : }
135 : :
136 : 0 : static void ext4_journal_abort_handle(const char *caller, unsigned int line,
137 : : const char *err_fn,
138 : : struct buffer_head *bh,
139 : : handle_t *handle, int err)
140 : : {
141 : : char nbuf[16];
142 : 0 : const char *errstr = ext4_decode_error(NULL, err, nbuf);
143 : :
144 [ # # ]: 0 : BUG_ON(!ext4_handle_valid(handle));
145 : :
146 : : if (bh)
147 : : BUFFER_TRACE(bh, "abort");
148 : :
149 [ # # ]: 0 : if (!handle->h_err)
150 : 0 : handle->h_err = err;
151 : :
152 [ # # ]: 0 : if (is_handle_aborted(handle))
153 : 0 : return;
154 : :
155 : 0 : printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n",
156 : : caller, line, errstr, err_fn);
157 : :
158 : : jbd2_journal_abort_handle(handle);
159 : : }
160 : :
161 : 4317210 : int __ext4_journal_get_write_access(const char *where, unsigned int line,
162 : : handle_t *handle, struct buffer_head *bh)
163 : : {
164 : : int err = 0;
165 : :
166 : 4317210 : might_sleep();
167 : :
168 [ + + ]: 4317210 : if (ext4_handle_valid(handle)) {
169 : 4317202 : err = jbd2_journal_get_write_access(handle, bh);
170 [ - + ]: 4317200 : if (err)
171 : 0 : ext4_journal_abort_handle(where, line, __func__, bh,
172 : : handle, err);
173 : : }
174 : 4317208 : return err;
175 : : }
176 : :
177 : : /*
178 : : * The ext4 forget function must perform a revoke if we are freeing data
179 : : * which has been journaled. Metadata (eg. indirect blocks) must be
180 : : * revoked in all cases.
181 : : *
182 : : * "bh" may be NULL: a metadata block may have been freed from memory
183 : : * but there may still be a record of it in the journal, and that record
184 : : * still needs to be revoked.
185 : : *
186 : : * If the handle isn't valid we're not journaling, but we still need to
187 : : * call into ext4_journal_revoke() to put the buffer head.
188 : : */
189 : 3260 : int __ext4_forget(const char *where, unsigned int line, handle_t *handle,
190 : : int is_metadata, struct inode *inode,
191 : : struct buffer_head *bh, ext4_fsblk_t blocknr)
192 : : {
193 : : int err;
194 : :
195 : 3260 : might_sleep();
196 : :
197 : 3260 : trace_ext4_forget(inode, is_metadata, blocknr);
198 : : BUFFER_TRACE(bh, "enter");
199 : :
200 : : jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, "
201 : : "data mode %x\n",
202 : : bh, is_metadata, inode->i_mode,
203 : : test_opt(inode->i_sb, DATA_FLAGS));
204 : :
205 : : /* In the no journal case, we can just do a bforget and return */
206 [ - + ]: 3260 : if (!ext4_handle_valid(handle)) {
207 : : bforget(bh);
208 : : return 0;
209 : : }
210 : :
211 : : /* Never use the revoke function if we are doing full data
212 : : * journaling: there is no need to, and a V1 superblock won't
213 : : * support it. Otherwise, only skip the revoke on un-journaled
214 : : * data blocks. */
215 : :
216 [ + - - + ]: 6520 : if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
217 [ # # ]: 0 : (!is_metadata && !ext4_should_journal_data(inode))) {
218 [ # # ]: 0 : if (bh) {
219 : : BUFFER_TRACE(bh, "call jbd2_journal_forget");
220 : 0 : err = jbd2_journal_forget(handle, bh);
221 [ # # ]: 0 : if (err)
222 : 0 : ext4_journal_abort_handle(where, line, __func__,
223 : : bh, handle, err);
224 : 0 : return err;
225 : : }
226 : : return 0;
227 : : }
228 : :
229 : : /*
230 : : * data!=journal && (is_metadata || should_journal_data(inode))
231 : : */
232 : : BUFFER_TRACE(bh, "call jbd2_journal_revoke");
233 : 3260 : err = jbd2_journal_revoke(handle, blocknr, bh);
234 [ - + ]: 3260 : if (err) {
235 : 0 : ext4_journal_abort_handle(where, line, __func__,
236 : : bh, handle, err);
237 : 0 : __ext4_abort(inode->i_sb, where, line,
238 : : "error %d when attempting revoke", err);
239 : : }
240 : : BUFFER_TRACE(bh, "exit");
241 : 3260 : return err;
242 : : }
243 : :
244 : 84920 : int __ext4_journal_get_create_access(const char *where, unsigned int line,
245 : : handle_t *handle, struct buffer_head *bh)
246 : : {
247 : : int err = 0;
248 : :
249 [ + - ]: 84920 : if (ext4_handle_valid(handle)) {
250 : 84920 : err = jbd2_journal_get_create_access(handle, bh);
251 [ - + ]: 84920 : if (err)
252 : 0 : ext4_journal_abort_handle(where, line, __func__,
253 : : bh, handle, err);
254 : : }
255 : 84920 : return err;
256 : : }
257 : :
258 : 4384434 : int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
259 : : handle_t *handle, struct inode *inode,
260 : : struct buffer_head *bh)
261 : : {
262 : : int err = 0;
263 : :
264 : 4384434 : might_sleep();
265 : :
266 : : set_buffer_meta(bh);
267 : : set_buffer_prio(bh);
268 [ + - ]: 4384410 : if (ext4_handle_valid(handle)) {
269 : 4384410 : err = jbd2_journal_dirty_metadata(handle, bh);
270 : : /* Errors can only happen due to aborted journal or a nasty bug */
271 [ + + - + : 4384420 : if (!is_handle_aborted(handle) && WARN_ON_ONCE(err)) {
# # - + ]
272 : 0 : ext4_journal_abort_handle(where, line, __func__, bh,
273 : : handle, err);
274 [ # # ]: 0 : if (inode == NULL) {
275 : 0 : pr_err("EXT4: jbd2_journal_dirty_metadata "
276 : : "failed: handle type %u started at "
277 : : "line %u, credits %u/%u, errcode %d",
278 : : handle->h_type,
279 : : handle->h_line_no,
280 : : handle->h_requested_credits,
281 : : handle->h_buffer_credits, err);
282 : 0 : return err;
283 : : }
284 : 0 : ext4_error_inode(inode, where, line,
285 : : bh->b_blocknr,
286 : : "journal_dirty_metadata failed: "
287 : : "handle type %u started at line %u, "
288 : : "credits %u/%u, errcode %d",
289 : : handle->h_type,
290 : : handle->h_line_no,
291 : : handle->h_requested_credits,
292 : : handle->h_buffer_credits, err);
293 : : }
294 : : } else {
295 [ # # ]: 0 : if (inode)
296 : 0 : mark_buffer_dirty_inode(bh, inode);
297 : : else
298 : 0 : mark_buffer_dirty(bh);
299 [ # # # # ]: 0 : if (inode && inode_needs_sync(inode)) {
300 : 0 : sync_dirty_buffer(bh);
301 [ # # # # ]: 0 : if (buffer_req(bh) && !buffer_uptodate(bh)) {
302 : : struct ext4_super_block *es;
303 : :
304 : 0 : es = EXT4_SB(inode->i_sb)->s_es;
305 : 0 : es->s_last_error_block =
306 : 0 : cpu_to_le64(bh->b_blocknr);
307 : 0 : ext4_error_inode(inode, where, line,
308 : : bh->b_blocknr,
309 : : "IO error syncing itable block");
310 : : err = -EIO;
311 : : }
312 : : }
313 : : }
314 : 4384400 : return err;
315 : : }
316 : :
317 : 17430 : int __ext4_handle_dirty_super(const char *where, unsigned int line,
318 : : handle_t *handle, struct super_block *sb)
319 : : {
320 : 17430 : struct buffer_head *bh = EXT4_SB(sb)->s_sbh;
321 : : int err = 0;
322 : :
323 : 17430 : ext4_superblock_csum_set(sb);
324 [ + - ]: 17430 : if (ext4_handle_valid(handle)) {
325 : 17430 : err = jbd2_journal_dirty_metadata(handle, bh);
326 [ - + ]: 17430 : if (err)
327 : 0 : ext4_journal_abort_handle(where, line, __func__,
328 : : bh, handle, err);
329 : : } else
330 : 0 : mark_buffer_dirty(bh);
331 : 17430 : return err;
332 : : }
|