Commit | Line | Data |
---|---|---|
8984d137 AM |
1 | /* |
2 | * Interface between ext4 and JBD | |
3 | */ | |
4 | ||
3dcf5451 | 5 | #include "ext4_jbd2.h" |
8984d137 | 6 | |
d6797d14 TT |
7 | #include <trace/events/ext4.h> |
8 | ||
722887dd TT |
9 | /* Just increment the non-pointer handle value */ |
10 | static handle_t *ext4_get_nojournal(void) | |
11 | { | |
12 | handle_t *handle = current->journal_info; | |
13 | unsigned long ref_cnt = (unsigned long)handle; | |
14 | ||
15 | BUG_ON(ref_cnt >= EXT4_NOJOURNAL_MAX_REF_COUNT); | |
16 | ||
17 | ref_cnt++; | |
18 | handle = (handle_t *)ref_cnt; | |
19 | ||
20 | current->journal_info = handle; | |
21 | return handle; | |
22 | } | |
23 | ||
24 | ||
25 | /* Decrement the non-pointer handle value */ | |
26 | static void ext4_put_nojournal(handle_t *handle) | |
27 | { | |
28 | unsigned long ref_cnt = (unsigned long)handle; | |
29 | ||
30 | BUG_ON(ref_cnt == 0); | |
31 | ||
32 | ref_cnt--; | |
33 | handle = (handle_t *)ref_cnt; | |
34 | ||
35 | current->journal_info = handle; | |
36 | } | |
37 | ||
38 | /* | |
39 | * Wrappers for jbd2_journal_start/end. | |
40 | */ | |
9924a92a TT |
41 | handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line, |
42 | int type, int nblocks) | |
722887dd TT |
43 | { |
44 | journal_t *journal; | |
45 | ||
b10a44c3 TT |
46 | might_sleep(); |
47 | ||
722887dd TT |
48 | trace_ext4_journal_start(sb, nblocks, _RET_IP_); |
49 | if (sb->s_flags & MS_RDONLY) | |
50 | return ERR_PTR(-EROFS); | |
51 | ||
52 | WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE); | |
53 | journal = EXT4_SB(sb)->s_journal; | |
54 | if (!journal) | |
55 | return ext4_get_nojournal(); | |
56 | /* | |
57 | * Special case here: if the journal has aborted behind our | |
58 | * backs (eg. EIO in the commit thread), then we still need to | |
59 | * take the FS itself readonly cleanly. | |
60 | */ | |
61 | if (is_journal_aborted(journal)) { | |
62 | ext4_abort(sb, "Detected aborted journal"); | |
63 | return ERR_PTR(-EROFS); | |
64 | } | |
8f7d89f3 | 65 | return jbd2__journal_start(journal, nblocks, 0, GFP_NOFS, type, line); |
722887dd TT |
66 | } |
67 | ||
68 | int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle) | |
69 | { | |
70 | struct super_block *sb; | |
71 | int err; | |
72 | int rc; | |
73 | ||
74 | if (!ext4_handle_valid(handle)) { | |
75 | ext4_put_nojournal(handle); | |
76 | return 0; | |
77 | } | |
78 | sb = handle->h_transaction->t_journal->j_private; | |
79 | err = handle->h_err; | |
80 | rc = jbd2_journal_stop(handle); | |
81 | ||
82 | if (!err) | |
83 | err = rc; | |
84 | if (err) | |
85 | __ext4_std_error(sb, where, line, err); | |
86 | return err; | |
87 | } | |
88 | ||
89 | void ext4_journal_abort_handle(const char *caller, unsigned int line, | |
90 | const char *err_fn, struct buffer_head *bh, | |
91 | handle_t *handle, int err) | |
92 | { | |
93 | char nbuf[16]; | |
94 | const char *errstr = ext4_decode_error(NULL, err, nbuf); | |
95 | ||
96 | BUG_ON(!ext4_handle_valid(handle)); | |
97 | ||
98 | if (bh) | |
99 | BUFFER_TRACE(bh, "abort"); | |
100 | ||
101 | if (!handle->h_err) | |
102 | handle->h_err = err; | |
103 | ||
104 | if (is_handle_aborted(handle)) | |
105 | return; | |
106 | ||
107 | printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n", | |
108 | caller, line, errstr, err_fn); | |
109 | ||
110 | jbd2_journal_abort_handle(handle); | |
111 | } | |
112 | ||
90c7201b TT |
113 | int __ext4_journal_get_write_access(const char *where, unsigned int line, |
114 | handle_t *handle, struct buffer_head *bh) | |
8984d137 | 115 | { |
0390131b FM |
116 | int err = 0; |
117 | ||
b10a44c3 TT |
118 | might_sleep(); |
119 | ||
0390131b FM |
120 | if (ext4_handle_valid(handle)) { |
121 | err = jbd2_journal_get_write_access(handle, bh); | |
122 | if (err) | |
90c7201b | 123 | ext4_journal_abort_handle(where, line, __func__, bh, |
0390131b FM |
124 | handle, err); |
125 | } | |
8984d137 AM |
126 | return err; |
127 | } | |
128 | ||
d6797d14 TT |
129 | /* |
130 | * The ext4 forget function must perform a revoke if we are freeing data | |
131 | * which has been journaled. Metadata (eg. indirect blocks) must be | |
132 | * revoked in all cases. | |
133 | * | |
134 | * "bh" may be NULL: a metadata block may have been freed from memory | |
135 | * but there may still be a record of it in the journal, and that record | |
136 | * still needs to be revoked. | |
137 | * | |
138 | * If the handle isn't valid we're not journaling, but we still need to | |
139 | * call into ext4_journal_revoke() to put the buffer head. | |
140 | */ | |
90c7201b TT |
141 | int __ext4_forget(const char *where, unsigned int line, handle_t *handle, |
142 | int is_metadata, struct inode *inode, | |
143 | struct buffer_head *bh, ext4_fsblk_t blocknr) | |
d6797d14 TT |
144 | { |
145 | int err; | |
146 | ||
147 | might_sleep(); | |
148 | ||
149 | trace_ext4_forget(inode, is_metadata, blocknr); | |
150 | BUFFER_TRACE(bh, "enter"); | |
151 | ||
152 | jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, " | |
153 | "data mode %x\n", | |
154 | bh, is_metadata, inode->i_mode, | |
155 | test_opt(inode->i_sb, DATA_FLAGS)); | |
156 | ||
e4684b3f TT |
157 | /* In the no journal case, we can just do a bforget and return */ |
158 | if (!ext4_handle_valid(handle)) { | |
159 | bforget(bh); | |
160 | return 0; | |
161 | } | |
162 | ||
d6797d14 TT |
163 | /* Never use the revoke function if we are doing full data |
164 | * journaling: there is no need to, and a V1 superblock won't | |
165 | * support it. Otherwise, only skip the revoke on un-journaled | |
166 | * data blocks. */ | |
167 | ||
168 | if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA || | |
169 | (!is_metadata && !ext4_should_journal_data(inode))) { | |
170 | if (bh) { | |
171 | BUFFER_TRACE(bh, "call jbd2_journal_forget"); | |
b7e57e7c TT |
172 | err = jbd2_journal_forget(handle, bh); |
173 | if (err) | |
90c7201b TT |
174 | ext4_journal_abort_handle(where, line, __func__, |
175 | bh, handle, err); | |
b7e57e7c | 176 | return err; |
d6797d14 TT |
177 | } |
178 | return 0; | |
179 | } | |
180 | ||
181 | /* | |
182 | * data!=journal && (is_metadata || should_journal_data(inode)) | |
183 | */ | |
e4684b3f TT |
184 | BUFFER_TRACE(bh, "call jbd2_journal_revoke"); |
185 | err = jbd2_journal_revoke(handle, blocknr, bh); | |
186 | if (err) { | |
90c7201b TT |
187 | ext4_journal_abort_handle(where, line, __func__, |
188 | bh, handle, err); | |
c398eda0 TT |
189 | __ext4_abort(inode->i_sb, where, line, |
190 | "error %d when attempting revoke", err); | |
e4684b3f | 191 | } |
d6797d14 TT |
192 | BUFFER_TRACE(bh, "exit"); |
193 | return err; | |
194 | } | |
195 | ||
90c7201b | 196 | int __ext4_journal_get_create_access(const char *where, unsigned int line, |
8984d137 AM |
197 | handle_t *handle, struct buffer_head *bh) |
198 | { | |
0390131b FM |
199 | int err = 0; |
200 | ||
201 | if (ext4_handle_valid(handle)) { | |
202 | err = jbd2_journal_get_create_access(handle, bh); | |
203 | if (err) | |
90c7201b TT |
204 | ext4_journal_abort_handle(where, line, __func__, |
205 | bh, handle, err); | |
0390131b | 206 | } |
8984d137 AM |
207 | return err; |
208 | } | |
209 | ||
90c7201b TT |
210 | int __ext4_handle_dirty_metadata(const char *where, unsigned int line, |
211 | handle_t *handle, struct inode *inode, | |
212 | struct buffer_head *bh) | |
8984d137 | 213 | { |
0390131b FM |
214 | int err = 0; |
215 | ||
b10a44c3 TT |
216 | might_sleep(); |
217 | ||
13fca323 TT |
218 | set_buffer_meta(bh); |
219 | set_buffer_prio(bh); | |
0390131b FM |
220 | if (ext4_handle_valid(handle)) { |
221 | err = jbd2_journal_dirty_metadata(handle, bh); | |
9ea7a0df TT |
222 | if (err) { |
223 | /* Errors can only happen if there is a bug */ | |
224 | handle->h_err = err; | |
225 | __ext4_journal_stop(where, line, handle); | |
226 | } | |
0390131b | 227 | } else { |
73b50c1c | 228 | if (inode) |
fe188c0e TT |
229 | mark_buffer_dirty_inode(bh, inode); |
230 | else | |
231 | mark_buffer_dirty(bh); | |
0390131b FM |
232 | if (inode && inode_needs_sync(inode)) { |
233 | sync_dirty_buffer(bh); | |
234 | if (buffer_req(bh) && !buffer_uptodate(bh)) { | |
1c13d5c0 TT |
235 | struct ext4_super_block *es; |
236 | ||
237 | es = EXT4_SB(inode->i_sb)->s_es; | |
238 | es->s_last_error_block = | |
239 | cpu_to_le64(bh->b_blocknr); | |
c398eda0 TT |
240 | ext4_error_inode(inode, where, line, |
241 | bh->b_blocknr, | |
242 | "IO error syncing itable block"); | |
0390131b FM |
243 | err = -EIO; |
244 | } | |
245 | } | |
246 | } | |
8984d137 AM |
247 | return err; |
248 | } | |
a0375156 | 249 | |
90c7201b | 250 | int __ext4_handle_dirty_super(const char *where, unsigned int line, |
b50924c2 | 251 | handle_t *handle, struct super_block *sb) |
a0375156 TT |
252 | { |
253 | struct buffer_head *bh = EXT4_SB(sb)->s_sbh; | |
254 | int err = 0; | |
255 | ||
06db49e6 | 256 | ext4_superblock_csum_set(sb); |
a0375156 TT |
257 | if (ext4_handle_valid(handle)) { |
258 | err = jbd2_journal_dirty_metadata(handle, bh); | |
259 | if (err) | |
90c7201b TT |
260 | ext4_journal_abort_handle(where, line, __func__, |
261 | bh, handle, err); | |
06db49e6 | 262 | } else |
a9c47317 | 263 | mark_buffer_dirty(bh); |
a0375156 TT |
264 | return err; |
265 | } |