Blame view

fs/ext4/ext4_jbd2.c 7.91 KB
8984d137d   Andrew Morton   [PATCH] ext4: uni...
1
2
3
  /*
   * Interface between ext4 and JBD
   */
3dcf54515   Christoph Hellwig   ext4: move header...
4
  #include "ext4_jbd2.h"
8984d137d   Andrew Morton   [PATCH] ext4: uni...
5

d6797d14b   Theodore Ts'o   ext4: move ext4_f...
6
  #include <trace/events/ext4.h>
722887ddc   Theodore Ts'o   ext4: move the jb...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  /* Just increment the non-pointer handle value */
  static handle_t *ext4_get_nojournal(void)
  {
  	handle_t *handle = current->journal_info;
  	unsigned long ref_cnt = (unsigned long)handle;
  
  	BUG_ON(ref_cnt >= EXT4_NOJOURNAL_MAX_REF_COUNT);
  
  	ref_cnt++;
  	handle = (handle_t *)ref_cnt;
  
  	current->journal_info = handle;
  	return handle;
  }
  
  
  /* Decrement the non-pointer handle value */
  static void ext4_put_nojournal(handle_t *handle)
  {
  	unsigned long ref_cnt = (unsigned long)handle;
  
  	BUG_ON(ref_cnt == 0);
  
  	ref_cnt--;
  	handle = (handle_t *)ref_cnt;
  
  	current->journal_info = handle;
  }
  
  /*
   * Wrappers for jbd2_journal_start/end.
   */
5fe2fe895   Jan Kara   ext4: provide wra...
39
  static int ext4_journal_check_start(struct super_block *sb)
722887ddc   Theodore Ts'o   ext4: move the jb...
40
41
  {
  	journal_t *journal;
b10a44c36   Theodore Ts'o   ext4: add might_s...
42
  	might_sleep();
722887ddc   Theodore Ts'o   ext4: move the jb...
43
  	if (sb->s_flags & MS_RDONLY)
5fe2fe895   Jan Kara   ext4: provide wra...
44
  		return -EROFS;
722887ddc   Theodore Ts'o   ext4: move the jb...
45
46
  	WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE);
  	journal = EXT4_SB(sb)->s_journal;
722887ddc   Theodore Ts'o   ext4: move the jb...
47
48
49
50
51
  	/*
  	 * Special case here: if the journal has aborted behind our
  	 * backs (eg. EIO in the commit thread), then we still need to
  	 * take the FS itself readonly cleanly.
  	 */
5fe2fe895   Jan Kara   ext4: provide wra...
52
  	if (journal && is_journal_aborted(journal)) {
722887ddc   Theodore Ts'o   ext4: move the jb...
53
  		ext4_abort(sb, "Detected aborted journal");
5fe2fe895   Jan Kara   ext4: provide wra...
54
  		return -EROFS;
722887ddc   Theodore Ts'o   ext4: move the jb...
55
  	}
5fe2fe895   Jan Kara   ext4: provide wra...
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  	return 0;
  }
  
  handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,
  				  int type, int blocks, int rsv_blocks)
  {
  	journal_t *journal;
  	int err;
  
  	trace_ext4_journal_start(sb, blocks, rsv_blocks, _RET_IP_);
  	err = ext4_journal_check_start(sb);
  	if (err < 0)
  		return ERR_PTR(err);
  
  	journal = EXT4_SB(sb)->s_journal;
  	if (!journal)
  		return ext4_get_nojournal();
  	return jbd2__journal_start(journal, blocks, rsv_blocks, GFP_NOFS,
  				   type, line);
722887ddc   Theodore Ts'o   ext4: move the jb...
75
76
77
78
79
80
81
82
83
84
85
86
  }
  
  int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
  {
  	struct super_block *sb;
  	int err;
  	int rc;
  
  	if (!ext4_handle_valid(handle)) {
  		ext4_put_nojournal(handle);
  		return 0;
  	}
9d5065940   Lukas Czerner   ext4: fix NULL po...
87

6934da923   Lukas Czerner   ext4: fix potenti...
88
  	err = handle->h_err;
9d5065940   Lukas Czerner   ext4: fix NULL po...
89
  	if (!handle->h_transaction) {
6934da923   Lukas Czerner   ext4: fix potenti...
90
91
  		rc = jbd2_journal_stop(handle);
  		return err ? err : rc;
9d5065940   Lukas Czerner   ext4: fix NULL po...
92
  	}
722887ddc   Theodore Ts'o   ext4: move the jb...
93
  	sb = handle->h_transaction->t_journal->j_private;
722887ddc   Theodore Ts'o   ext4: move the jb...
94
95
96
97
98
99
100
101
  	rc = jbd2_journal_stop(handle);
  
  	if (!err)
  		err = rc;
  	if (err)
  		__ext4_std_error(sb, where, line, err);
  	return err;
  }
5fe2fe895   Jan Kara   ext4: provide wra...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line,
  					int type)
  {
  	struct super_block *sb;
  	int err;
  
  	if (!ext4_handle_valid(handle))
  		return ext4_get_nojournal();
  
  	sb = handle->h_journal->j_private;
  	trace_ext4_journal_start_reserved(sb, handle->h_buffer_credits,
  					  _RET_IP_);
  	err = ext4_journal_check_start(sb);
  	if (err < 0) {
  		jbd2_journal_free_reserved(handle);
  		return ERR_PTR(err);
  	}
  
  	err = jbd2_journal_start_reserved(handle, type, line);
  	if (err < 0)
  		return ERR_PTR(err);
  	return handle;
  }
c197855ea   Stephen Hemminger   ext4: make local ...
125
126
127
128
  static void ext4_journal_abort_handle(const char *caller, unsigned int line,
  				      const char *err_fn,
  				      struct buffer_head *bh,
  				      handle_t *handle, int err)
722887ddc   Theodore Ts'o   ext4: move the jb...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  {
  	char nbuf[16];
  	const char *errstr = ext4_decode_error(NULL, err, nbuf);
  
  	BUG_ON(!ext4_handle_valid(handle));
  
  	if (bh)
  		BUFFER_TRACE(bh, "abort");
  
  	if (!handle->h_err)
  		handle->h_err = err;
  
  	if (is_handle_aborted(handle))
  		return;
  
  	printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s
  ",
  	       caller, line, errstr, err_fn);
  
  	jbd2_journal_abort_handle(handle);
  }
90c7201b9   Theodore Ts'o   ext4: Pass line n...
150
151
  int __ext4_journal_get_write_access(const char *where, unsigned int line,
  				    handle_t *handle, struct buffer_head *bh)
8984d137d   Andrew Morton   [PATCH] ext4: uni...
152
  {
0390131ba   Frank Mayhar   ext4: Allow ext4 ...
153
  	int err = 0;
b10a44c36   Theodore Ts'o   ext4: add might_s...
154
  	might_sleep();
0390131ba   Frank Mayhar   ext4: Allow ext4 ...
155
156
157
  	if (ext4_handle_valid(handle)) {
  		err = jbd2_journal_get_write_access(handle, bh);
  		if (err)
90c7201b9   Theodore Ts'o   ext4: Pass line n...
158
  			ext4_journal_abort_handle(where, line, __func__, bh,
0390131ba   Frank Mayhar   ext4: Allow ext4 ...
159
160
  						  handle, err);
  	}
8984d137d   Andrew Morton   [PATCH] ext4: uni...
161
162
  	return err;
  }
d6797d14b   Theodore Ts'o   ext4: move ext4_f...
163
164
165
166
167
168
169
170
171
172
173
174
  /*
   * The ext4 forget function must perform a revoke if we are freeing data
   * which has been journaled.  Metadata (eg. indirect blocks) must be
   * revoked in all cases.
   *
   * "bh" may be NULL: a metadata block may have been freed from memory
   * but there may still be a record of it in the journal, and that record
   * still needs to be revoked.
   *
   * If the handle isn't valid we're not journaling, but we still need to
   * call into ext4_journal_revoke() to put the buffer head.
   */
90c7201b9   Theodore Ts'o   ext4: Pass line n...
175
176
177
  int __ext4_forget(const char *where, unsigned int line, handle_t *handle,
  		  int is_metadata, struct inode *inode,
  		  struct buffer_head *bh, ext4_fsblk_t blocknr)
d6797d14b   Theodore Ts'o   ext4: move ext4_f...
178
179
180
181
182
183
184
185
186
187
188
189
190
  {
  	int err;
  
  	might_sleep();
  
  	trace_ext4_forget(inode, is_metadata, blocknr);
  	BUFFER_TRACE(bh, "enter");
  
  	jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, "
  		  "data mode %x
  ",
  		  bh, is_metadata, inode->i_mode,
  		  test_opt(inode->i_sb, DATA_FLAGS));
e4684b3fb   Theodore Ts'o   ext4: fold ext4_j...
191
192
193
194
195
  	/* In the no journal case, we can just do a bforget and return */
  	if (!ext4_handle_valid(handle)) {
  		bforget(bh);
  		return 0;
  	}
d6797d14b   Theodore Ts'o   ext4: move ext4_f...
196
197
198
199
200
201
202
203
204
  	/* Never use the revoke function if we are doing full data
  	 * journaling: there is no need to, and a V1 superblock won't
  	 * support it.  Otherwise, only skip the revoke on un-journaled
  	 * data blocks. */
  
  	if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
  	    (!is_metadata && !ext4_should_journal_data(inode))) {
  		if (bh) {
  			BUFFER_TRACE(bh, "call jbd2_journal_forget");
b7e57e7c2   Theodore Ts'o   ext4: fold ext4_j...
205
206
  			err = jbd2_journal_forget(handle, bh);
  			if (err)
90c7201b9   Theodore Ts'o   ext4: Pass line n...
207
208
  				ext4_journal_abort_handle(where, line, __func__,
  							  bh, handle, err);
b7e57e7c2   Theodore Ts'o   ext4: fold ext4_j...
209
  			return err;
d6797d14b   Theodore Ts'o   ext4: move ext4_f...
210
211
212
213
214
215
216
  		}
  		return 0;
  	}
  
  	/*
  	 * data!=journal && (is_metadata || should_journal_data(inode))
  	 */
e4684b3fb   Theodore Ts'o   ext4: fold ext4_j...
217
218
219
  	BUFFER_TRACE(bh, "call jbd2_journal_revoke");
  	err = jbd2_journal_revoke(handle, blocknr, bh);
  	if (err) {
90c7201b9   Theodore Ts'o   ext4: Pass line n...
220
221
  		ext4_journal_abort_handle(where, line, __func__,
  					  bh, handle, err);
c398eda0e   Theodore Ts'o   ext4: Pass line n...
222
223
  		__ext4_abort(inode->i_sb, where, line,
  			   "error %d when attempting revoke", err);
e4684b3fb   Theodore Ts'o   ext4: fold ext4_j...
224
  	}
d6797d14b   Theodore Ts'o   ext4: move ext4_f...
225
226
227
  	BUFFER_TRACE(bh, "exit");
  	return err;
  }
90c7201b9   Theodore Ts'o   ext4: Pass line n...
228
  int __ext4_journal_get_create_access(const char *where, unsigned int line,
8984d137d   Andrew Morton   [PATCH] ext4: uni...
229
230
  				handle_t *handle, struct buffer_head *bh)
  {
0390131ba   Frank Mayhar   ext4: Allow ext4 ...
231
232
233
234
235
  	int err = 0;
  
  	if (ext4_handle_valid(handle)) {
  		err = jbd2_journal_get_create_access(handle, bh);
  		if (err)
90c7201b9   Theodore Ts'o   ext4: Pass line n...
236
237
  			ext4_journal_abort_handle(where, line, __func__,
  						  bh, handle, err);
0390131ba   Frank Mayhar   ext4: Allow ext4 ...
238
  	}
8984d137d   Andrew Morton   [PATCH] ext4: uni...
239
240
  	return err;
  }
90c7201b9   Theodore Ts'o   ext4: Pass line n...
241
242
243
  int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
  				 handle_t *handle, struct inode *inode,
  				 struct buffer_head *bh)
8984d137d   Andrew Morton   [PATCH] ext4: uni...
244
  {
0390131ba   Frank Mayhar   ext4: Allow ext4 ...
245
  	int err = 0;
b10a44c36   Theodore Ts'o   ext4: add might_s...
246
  	might_sleep();
13fca323e   Theodore Ts'o   ext4: mark metada...
247
248
  	set_buffer_meta(bh);
  	set_buffer_prio(bh);
0390131ba   Frank Mayhar   ext4: Allow ext4 ...
249
250
  	if (ext4_handle_valid(handle)) {
  		err = jbd2_journal_dirty_metadata(handle, bh);
c5d311926   Dmitry Monakhov   ext4: fix over-de...
251
252
  		/* Errors can only happen due to aborted journal or a nasty bug */
  		if (!is_handle_aborted(handle) && WARN_ON_ONCE(err)) {
91aa11fae   Jan Kara   jbd2: Fix use aft...
253
254
  			ext4_journal_abort_handle(where, line, __func__, bh,
  						  handle, err);
66a4cb187   Theodore Ts'o   jbd2: improve err...
255
256
257
258
259
260
261
262
263
264
  			if (inode == NULL) {
  				pr_err("EXT4: jbd2_journal_dirty_metadata "
  				       "failed: handle type %u started at "
  				       "line %u, credits %u/%u, errcode %d",
  				       handle->h_type,
  				       handle->h_line_no,
  				       handle->h_requested_credits,
  				       handle->h_buffer_credits, err);
  				return err;
  			}
ae1495b12   Theodore Ts'o   ext4: call ext4_e...
265
266
267
268
269
270
271
272
273
  			ext4_error_inode(inode, where, line,
  					 bh->b_blocknr,
  					 "journal_dirty_metadata failed: "
  					 "handle type %u started at line %u, "
  					 "credits %u/%u, errcode %d",
  					 handle->h_type,
  					 handle->h_line_no,
  					 handle->h_requested_credits,
  					 handle->h_buffer_credits, err);
9ea7a0df6   Theodore Ts'o   jbd2: add debuggi...
274
  		}
0390131ba   Frank Mayhar   ext4: Allow ext4 ...
275
  	} else {
73b50c1c9   Curt Wohlgemuth   ext4: Fix BUG_ON ...
276
  		if (inode)
fe188c0e0   Theodore Ts'o   ext4: Assure that...
277
278
279
  			mark_buffer_dirty_inode(bh, inode);
  		else
  			mark_buffer_dirty(bh);
0390131ba   Frank Mayhar   ext4: Allow ext4 ...
280
281
282
  		if (inode && inode_needs_sync(inode)) {
  			sync_dirty_buffer(bh);
  			if (buffer_req(bh) && !buffer_uptodate(bh)) {
1c13d5c08   Theodore Ts'o   ext4: Save error ...
283
284
285
286
287
  				struct ext4_super_block *es;
  
  				es = EXT4_SB(inode->i_sb)->s_es;
  				es->s_last_error_block =
  					cpu_to_le64(bh->b_blocknr);
c398eda0e   Theodore Ts'o   ext4: Pass line n...
288
289
290
  				ext4_error_inode(inode, where, line,
  						 bh->b_blocknr,
  					"IO error syncing itable block");
0390131ba   Frank Mayhar   ext4: Allow ext4 ...
291
292
293
294
  				err = -EIO;
  			}
  		}
  	}
8984d137d   Andrew Morton   [PATCH] ext4: uni...
295
296
  	return err;
  }
a0375156c   Theodore Ts'o   ext4: Clean up s_...
297

90c7201b9   Theodore Ts'o   ext4: Pass line n...
298
  int __ext4_handle_dirty_super(const char *where, unsigned int line,
b50924c2c   Artem Bityutskiy   ext4: remove unne...
299
  			      handle_t *handle, struct super_block *sb)
a0375156c   Theodore Ts'o   ext4: Clean up s_...
300
301
302
  {
  	struct buffer_head *bh = EXT4_SB(sb)->s_sbh;
  	int err = 0;
06db49e68   Theodore Ts'o   ext4: fix metadat...
303
  	ext4_superblock_csum_set(sb);
a0375156c   Theodore Ts'o   ext4: Clean up s_...
304
305
306
  	if (ext4_handle_valid(handle)) {
  		err = jbd2_journal_dirty_metadata(handle, bh);
  		if (err)
90c7201b9   Theodore Ts'o   ext4: Pass line n...
307
308
  			ext4_journal_abort_handle(where, line, __func__,
  						  bh, handle, err);
06db49e68   Theodore Ts'o   ext4: fix metadat...
309
  	} else
a9c473178   Darrick J. Wong   ext4: calculate a...
310
  		mark_buffer_dirty(bh);
a0375156c   Theodore Ts'o   ext4: Clean up s_...
311
312
  	return err;
  }