]>
Commit | Line | Data |
---|---|---|
7336d0e6 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
b3b94faa DT |
2 | /* |
3 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | |
3a8a9a10 | 4 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. |
b3b94faa DT |
5 | */ |
6 | ||
d77d1b58 JP |
7 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
8 | ||
b3b94faa DT |
9 | #include <linux/spinlock.h> |
10 | #include <linux/completion.h> | |
11 | #include <linux/buffer_head.h> | |
12 | #include <linux/crc32.h> | |
5c676f6d | 13 | #include <linux/gfs2_ondisk.h> |
601ef0d5 | 14 | #include <linux/delay.h> |
7c0f6ba6 | 15 | #include <linux/uaccess.h> |
b3b94faa DT |
16 | |
17 | #include "gfs2.h" | |
5c676f6d | 18 | #include "incore.h" |
b3b94faa | 19 | #include "glock.h" |
601ef0d5 BP |
20 | #include "glops.h" |
21 | #include "log.h" | |
0d91061a BP |
22 | #include "lops.h" |
23 | #include "recovery.h" | |
72244b6b | 24 | #include "rgrp.h" |
0d91061a | 25 | #include "super.h" |
5c676f6d | 26 | #include "util.h" |
b3b94faa | 27 | |
e18b890b | 28 | struct kmem_cache *gfs2_glock_cachep __read_mostly; |
009d8518 | 29 | struct kmem_cache *gfs2_glock_aspace_cachep __read_mostly; |
e18b890b CL |
30 | struct kmem_cache *gfs2_inode_cachep __read_mostly; |
31 | struct kmem_cache *gfs2_bufdata_cachep __read_mostly; | |
6bdd9be6 | 32 | struct kmem_cache *gfs2_rgrpd_cachep __read_mostly; |
37b2c837 | 33 | struct kmem_cache *gfs2_quotad_cachep __read_mostly; |
b54e9a0b | 34 | struct kmem_cache *gfs2_qadata_cachep __read_mostly; |
e8c92ed7 | 35 | mempool_t *gfs2_page_pool __read_mostly; |
b3b94faa | 36 | |
b3b94faa DT |
37 | void gfs2_assert_i(struct gfs2_sbd *sdp) |
38 | { | |
8382e26b | 39 | fs_emerg(sdp, "fatal assertion failed\n"); |
b3b94faa DT |
40 | } |
41 | ||
0d91061a BP |
42 | /** |
43 | * check_journal_clean - Make sure a journal is clean for a spectator mount | |
44 | * @sdp: The GFS2 superblock | |
45 | * @jd: The journal descriptor | |
46 | * | |
47 | * Returns: 0 if the journal is clean or locked, else an error | |
48 | */ | |
7d9f9249 BP |
49 | int check_journal_clean(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd, |
50 | bool verbose) | |
0d91061a BP |
51 | { |
52 | int error; | |
53 | struct gfs2_holder j_gh; | |
54 | struct gfs2_log_header_host head; | |
55 | struct gfs2_inode *ip; | |
56 | ||
57 | ip = GFS2_I(jd->jd_inode); | |
58 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_NOEXP | | |
59 | GL_EXACT | GL_NOCACHE, &j_gh); | |
60 | if (error) { | |
7d9f9249 BP |
61 | if (verbose) |
62 | fs_err(sdp, "Error %d locking journal for spectator " | |
63 | "mount.\n", error); | |
0d91061a BP |
64 | return -EPERM; |
65 | } | |
66 | error = gfs2_jdesc_check(jd); | |
67 | if (error) { | |
7d9f9249 BP |
68 | if (verbose) |
69 | fs_err(sdp, "Error checking journal for spectator " | |
70 | "mount.\n"); | |
0d91061a BP |
71 | goto out_unlock; |
72 | } | |
73 | error = gfs2_find_jhead(jd, &head, false); | |
74 | if (error) { | |
7d9f9249 BP |
75 | if (verbose) |
76 | fs_err(sdp, "Error parsing journal for spectator " | |
77 | "mount.\n"); | |
0d91061a BP |
78 | goto out_unlock; |
79 | } | |
80 | if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) { | |
81 | error = -EPERM; | |
7d9f9249 BP |
82 | if (verbose) |
83 | fs_err(sdp, "jid=%u: Journal is dirty, so the first " | |
84 | "mounter must not be a spectator.\n", | |
85 | jd->jd_jid); | |
0d91061a BP |
86 | } |
87 | ||
88 | out_unlock: | |
89 | gfs2_glock_dq_uninit(&j_gh); | |
90 | return error; | |
91 | } | |
92 | ||
601ef0d5 BP |
93 | static void signal_our_withdraw(struct gfs2_sbd *sdp) |
94 | { | |
95 | struct gfs2_glock *gl = sdp->sd_live_gh.gh_gl; | |
96 | struct inode *inode = sdp->sd_jdesc->jd_inode; | |
97 | struct gfs2_inode *ip = GFS2_I(inode); | |
98 | u64 no_formal_ino = ip->i_no_formal_ino; | |
99 | int ret = 0; | |
100 | int tries; | |
101 | ||
102 | if (test_bit(SDF_NORECOVERY, &sdp->sd_flags)) | |
103 | return; | |
104 | ||
105 | /* Prevent any glock dq until withdraw recovery is complete */ | |
106 | set_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags); | |
107 | /* | |
108 | * Don't tell dlm we're bailing until we have no more buffers in the | |
109 | * wind. If journal had an IO error, the log code should just purge | |
110 | * the outstanding buffers rather than submitting new IO. Making the | |
111 | * file system read-only will flush the journal, etc. | |
112 | * | |
113 | * During a normal unmount, gfs2_make_fs_ro calls gfs2_log_shutdown | |
114 | * which clears SDF_JOURNAL_LIVE. In a withdraw, we must not write | |
115 | * any UNMOUNT log header, so we can't call gfs2_log_shutdown, and | |
116 | * therefore we need to clear SDF_JOURNAL_LIVE manually. | |
117 | */ | |
118 | clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags); | |
119 | if (!sb_rdonly(sdp->sd_vfs)) | |
120 | ret = gfs2_make_fs_ro(sdp); | |
121 | ||
122 | /* | |
123 | * Drop the glock for our journal so another node can recover it. | |
124 | */ | |
125 | if (gfs2_holder_initialized(&sdp->sd_journal_gh)) { | |
126 | gfs2_glock_dq_wait(&sdp->sd_journal_gh); | |
127 | gfs2_holder_uninit(&sdp->sd_journal_gh); | |
128 | } | |
129 | sdp->sd_jinode_gh.gh_flags |= GL_NOCACHE; | |
130 | gfs2_glock_dq(&sdp->sd_jinode_gh); | |
131 | if (test_bit(SDF_FS_FROZEN, &sdp->sd_flags)) { | |
132 | /* Make sure gfs2_unfreeze works if partially-frozen */ | |
133 | flush_workqueue(gfs2_freeze_wq); | |
134 | atomic_set(&sdp->sd_freeze_state, SFS_FROZEN); | |
135 | thaw_super(sdp->sd_vfs); | |
136 | } else { | |
137 | wait_on_bit(&gl->gl_flags, GLF_DEMOTE, TASK_UNINTERRUPTIBLE); | |
138 | } | |
139 | ||
140 | /* | |
141 | * holder_uninit to force glock_put, to force dlm to let go | |
142 | */ | |
143 | gfs2_holder_uninit(&sdp->sd_jinode_gh); | |
144 | ||
145 | /* | |
146 | * Note: We need to be careful here: | |
147 | * Our iput of jd_inode will evict it. The evict will dequeue its | |
148 | * glock, but the glock dq will wait for the withdraw unless we have | |
149 | * exception code in glock_dq. | |
150 | */ | |
151 | iput(inode); | |
152 | /* | |
153 | * Wait until the journal inode's glock is freed. This allows try locks | |
154 | * on other nodes to be successful, otherwise we remain the owner of | |
155 | * the glock as far as dlm is concerned. | |
156 | */ | |
157 | if (gl->gl_ops->go_free) { | |
158 | set_bit(GLF_FREEING, &gl->gl_flags); | |
159 | wait_on_bit(&gl->gl_flags, GLF_FREEING, TASK_UNINTERRUPTIBLE); | |
160 | } | |
161 | ||
162 | if (sdp->sd_lockstruct.ls_ops->lm_lock == NULL) { /* lock_nolock */ | |
163 | clear_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags); | |
164 | goto skip_recovery; | |
165 | } | |
166 | /* | |
167 | * Dequeue the "live" glock, but keep a reference so it's never freed. | |
168 | */ | |
169 | gfs2_glock_hold(gl); | |
170 | gfs2_glock_dq_wait(&sdp->sd_live_gh); | |
171 | /* | |
172 | * We enqueue the "live" glock in EX so that all other nodes | |
173 | * get a demote request and act on it. We don't really want the | |
174 | * lock in EX, so we send a "try" lock with 1CB to produce a callback. | |
175 | */ | |
176 | fs_warn(sdp, "Requesting recovery of jid %d.\n", | |
177 | sdp->sd_lockstruct.ls_jid); | |
178 | gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | LM_FLAG_NOEXP, | |
179 | &sdp->sd_live_gh); | |
180 | msleep(GL_GLOCK_MAX_HOLD); | |
181 | /* | |
182 | * This will likely fail in a cluster, but succeed standalone: | |
183 | */ | |
184 | ret = gfs2_glock_nq(&sdp->sd_live_gh); | |
185 | ||
186 | /* | |
187 | * If we actually got the "live" lock in EX mode, there are no other | |
188 | * nodes available to replay our journal. So we try to replay it | |
189 | * ourselves. We hold the "live" glock to prevent other mounters | |
190 | * during recovery, then just dequeue it and reacquire it in our | |
191 | * normal SH mode. Just in case the problem that caused us to | |
192 | * withdraw prevents us from recovering our journal (e.g. io errors | |
193 | * and such) we still check if the journal is clean before proceeding | |
194 | * but we may wait forever until another mounter does the recovery. | |
195 | */ | |
196 | if (ret == 0) { | |
197 | fs_warn(sdp, "No other mounters found. Trying to recover our " | |
198 | "own journal jid %d.\n", sdp->sd_lockstruct.ls_jid); | |
199 | if (gfs2_recover_journal(sdp->sd_jdesc, 1)) | |
200 | fs_warn(sdp, "Unable to recover our journal jid %d.\n", | |
201 | sdp->sd_lockstruct.ls_jid); | |
202 | gfs2_glock_dq_wait(&sdp->sd_live_gh); | |
203 | gfs2_holder_reinit(LM_ST_SHARED, LM_FLAG_NOEXP | GL_EXACT, | |
204 | &sdp->sd_live_gh); | |
205 | gfs2_glock_nq(&sdp->sd_live_gh); | |
206 | } | |
207 | ||
208 | gfs2_glock_queue_put(gl); /* drop the extra reference we acquired */ | |
209 | clear_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags); | |
210 | ||
211 | /* | |
212 | * At this point our journal is evicted, so we need to get a new inode | |
213 | * for it. Once done, we need to call gfs2_find_jhead which | |
214 | * calls gfs2_map_journal_extents to map it for us again. | |
215 | * | |
216 | * Note that we don't really want it to look up a FREE block. The | |
217 | * GFS2_BLKST_FREE simply overrides a block check in gfs2_inode_lookup | |
218 | * which would otherwise fail because it requires grabbing an rgrp | |
219 | * glock, which would fail with -EIO because we're withdrawing. | |
220 | */ | |
221 | inode = gfs2_inode_lookup(sdp->sd_vfs, DT_UNKNOWN, | |
222 | sdp->sd_jdesc->jd_no_addr, no_formal_ino, | |
223 | GFS2_BLKST_FREE); | |
224 | if (IS_ERR(inode)) { | |
225 | fs_warn(sdp, "Reprocessing of jid %d failed with %ld.\n", | |
226 | sdp->sd_lockstruct.ls_jid, PTR_ERR(inode)); | |
227 | goto skip_recovery; | |
228 | } | |
229 | sdp->sd_jdesc->jd_inode = inode; | |
230 | ||
231 | /* | |
232 | * Now wait until recovery is complete. | |
233 | */ | |
234 | for (tries = 0; tries < 10; tries++) { | |
7d9f9249 | 235 | ret = check_journal_clean(sdp, sdp->sd_jdesc, false); |
601ef0d5 BP |
236 | if (!ret) |
237 | break; | |
238 | msleep(HZ); | |
239 | fs_warn(sdp, "Waiting for journal recovery jid %d.\n", | |
240 | sdp->sd_lockstruct.ls_jid); | |
241 | } | |
242 | skip_recovery: | |
243 | if (!ret) | |
244 | fs_warn(sdp, "Journal recovery complete for jid %d.\n", | |
245 | sdp->sd_lockstruct.ls_jid); | |
246 | else | |
247 | fs_warn(sdp, "Journal recovery skipped for %d until next " | |
248 | "mount.\n", sdp->sd_lockstruct.ls_jid); | |
249 | fs_warn(sdp, "Glock dequeues delayed: %lu\n", sdp->sd_glock_dqs_held); | |
250 | sdp->sd_glock_dqs_held = 0; | |
251 | wake_up_bit(&sdp->sd_flags, SDF_WITHDRAW_RECOVERY); | |
252 | } | |
253 | ||
badb55ec AG |
254 | void gfs2_lm(struct gfs2_sbd *sdp, const char *fmt, ...) |
255 | { | |
256 | struct va_format vaf; | |
257 | va_list args; | |
258 | ||
259 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW && | |
260 | test_bit(SDF_WITHDRAWN, &sdp->sd_flags)) | |
261 | return; | |
262 | ||
263 | va_start(args, fmt); | |
264 | vaf.fmt = fmt; | |
265 | vaf.va = &args; | |
266 | fs_err(sdp, "%pV", &vaf); | |
267 | va_end(args); | |
268 | } | |
269 | ||
270 | int gfs2_withdraw(struct gfs2_sbd *sdp) | |
da755fdb | 271 | { |
f057f6cd SW |
272 | struct lm_lockstruct *ls = &sdp->sd_lockstruct; |
273 | const struct lm_lockops *lm = ls->ls_ops; | |
da755fdb | 274 | |
d34843d0 | 275 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW && |
601ef0d5 BP |
276 | test_and_set_bit(SDF_WITHDRAWN, &sdp->sd_flags)) { |
277 | if (!test_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags)) | |
278 | return -1; | |
279 | ||
280 | wait_on_bit(&sdp->sd_flags, SDF_WITHDRAW_IN_PROG, | |
281 | TASK_UNINTERRUPTIBLE); | |
282 | return -1; | |
283 | } | |
284 | ||
285 | set_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags); | |
da755fdb | 286 | |
d34843d0 BP |
287 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) { |
288 | fs_err(sdp, "about to withdraw this file system\n"); | |
289 | BUG_ON(sdp->sd_args.ar_debug); | |
da755fdb | 290 | |
601ef0d5 BP |
291 | signal_our_withdraw(sdp); |
292 | ||
d34843d0 | 293 | kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE); |
f057f6cd | 294 | |
fd95e81c SW |
295 | if (!strcmp(sdp->sd_lockstruct.ls_ops->lm_proto_name, "lock_dlm")) |
296 | wait_for_completion(&sdp->sd_wdack); | |
297 | ||
d34843d0 BP |
298 | if (lm->lm_unmount) { |
299 | fs_err(sdp, "telling LM to unmount\n"); | |
300 | lm->lm_unmount(sdp); | |
301 | } | |
3e11e530 | 302 | set_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags); |
601ef0d5 | 303 | fs_err(sdp, "File system withdrawn\n"); |
d34843d0 | 304 | dump_stack(); |
601ef0d5 BP |
305 | clear_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags); |
306 | smp_mb__after_atomic(); | |
307 | wake_up_bit(&sdp->sd_flags, SDF_WITHDRAW_IN_PROG); | |
f057f6cd | 308 | } |
d34843d0 BP |
309 | |
310 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC) | |
d77d1b58 | 311 | panic("GFS2: fsid=%s: panic requested\n", sdp->sd_fsname); |
da755fdb SW |
312 | |
313 | return -1; | |
314 | } | |
315 | ||
b3b94faa DT |
316 | /** |
317 | * gfs2_assert_withdraw_i - Cause the machine to withdraw if @assertion is false | |
b3b94faa DT |
318 | */ |
319 | ||
8e28ef1f | 320 | void gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion, |
ca399c96 BP |
321 | const char *function, char *file, unsigned int line, |
322 | bool delayed) | |
b3b94faa | 323 | { |
ca399c96 BP |
324 | if (gfs2_withdrawn(sdp)) |
325 | return; | |
326 | ||
327 | fs_err(sdp, | |
328 | "fatal: assertion \"%s\" failed\n" | |
329 | " function = %s, file = %s, line = %u\n", | |
330 | assertion, function, file, line); | |
331 | ||
332 | /* | |
333 | * If errors=panic was specified on mount, it won't help to delay the | |
334 | * withdraw. | |
335 | */ | |
336 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC) | |
337 | delayed = false; | |
338 | ||
339 | if (delayed) | |
340 | gfs2_withdraw_delayed(sdp); | |
341 | else | |
342 | gfs2_withdraw(sdp); | |
18ec7d5c | 343 | dump_stack(); |
b3b94faa DT |
344 | } |
345 | ||
346 | /** | |
347 | * gfs2_assert_warn_i - Print a message to the console if @assertion is false | |
b3b94faa DT |
348 | */ |
349 | ||
8e28ef1f AG |
350 | void gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion, |
351 | const char *function, char *file, unsigned int line) | |
b3b94faa DT |
352 | { |
353 | if (time_before(jiffies, | |
354 | sdp->sd_last_warning + | |
355 | gfs2_tune_get(sdp, gt_complain_secs) * HZ)) | |
8e28ef1f | 356 | return; |
b3b94faa | 357 | |
d34843d0 | 358 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) |
8382e26b JP |
359 | fs_warn(sdp, "warning: assertion \"%s\" failed at function = %s, file = %s, line = %u\n", |
360 | assertion, function, file, line); | |
b3b94faa DT |
361 | |
362 | if (sdp->sd_args.ar_debug) | |
363 | BUG(); | |
18ec7d5c SW |
364 | else |
365 | dump_stack(); | |
b3b94faa | 366 | |
d34843d0 BP |
367 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC) |
368 | panic("GFS2: fsid=%s: warning: assertion \"%s\" failed\n" | |
369 | "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", | |
370 | sdp->sd_fsname, assertion, | |
371 | sdp->sd_fsname, function, file, line); | |
372 | ||
b3b94faa | 373 | sdp->sd_last_warning = jiffies; |
b3b94faa DT |
374 | } |
375 | ||
376 | /** | |
377 | * gfs2_consist_i - Flag a filesystem consistency error and withdraw | |
b3b94faa DT |
378 | */ |
379 | ||
a5ca2f1c AG |
380 | void gfs2_consist_i(struct gfs2_sbd *sdp, const char *function, |
381 | char *file, unsigned int line) | |
b3b94faa | 382 | { |
badb55ec AG |
383 | gfs2_lm(sdp, |
384 | "fatal: filesystem consistency error - function = %s, file = %s, line = %u\n", | |
385 | function, file, line); | |
a5ca2f1c | 386 | gfs2_withdraw(sdp); |
b3b94faa DT |
387 | } |
388 | ||
389 | /** | |
390 | * gfs2_consist_inode_i - Flag an inode consistency error and withdraw | |
b3b94faa DT |
391 | */ |
392 | ||
a5ca2f1c AG |
393 | void gfs2_consist_inode_i(struct gfs2_inode *ip, |
394 | const char *function, char *file, unsigned int line) | |
b3b94faa | 395 | { |
feaa7bba | 396 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
badb55ec AG |
397 | |
398 | gfs2_lm(sdp, | |
399 | "fatal: filesystem consistency error\n" | |
400 | " inode = %llu %llu\n" | |
401 | " function = %s, file = %s, line = %u\n", | |
402 | (unsigned long long)ip->i_no_formal_ino, | |
403 | (unsigned long long)ip->i_no_addr, | |
404 | function, file, line); | |
a5ca2f1c | 405 | gfs2_withdraw(sdp); |
b3b94faa DT |
406 | } |
407 | ||
408 | /** | |
409 | * gfs2_consist_rgrpd_i - Flag a RG consistency error and withdraw | |
b3b94faa DT |
410 | */ |
411 | ||
a5ca2f1c AG |
412 | void gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, |
413 | const char *function, char *file, unsigned int line) | |
b3b94faa DT |
414 | { |
415 | struct gfs2_sbd *sdp = rgd->rd_sbd; | |
98fb0574 | 416 | char fs_id_buf[sizeof(sdp->sd_fsname) + 7]; |
72244b6b | 417 | |
3792ce97 BP |
418 | sprintf(fs_id_buf, "fsid=%s: ", sdp->sd_fsname); |
419 | gfs2_rgrp_dump(NULL, rgd->rd_gl, fs_id_buf); | |
badb55ec AG |
420 | gfs2_lm(sdp, |
421 | "fatal: filesystem consistency error\n" | |
422 | " RG = %llu\n" | |
423 | " function = %s, file = %s, line = %u\n", | |
424 | (unsigned long long)rgd->rd_addr, | |
425 | function, file, line); | |
a5ca2f1c | 426 | gfs2_withdraw(sdp); |
b3b94faa DT |
427 | } |
428 | ||
429 | /** | |
430 | * gfs2_meta_check_ii - Flag a magic number consistency error and withdraw | |
431 | * Returns: -1 if this call withdrew the machine, | |
432 | * -2 if it was already withdrawn | |
433 | */ | |
434 | ||
435 | int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh, | |
436 | const char *type, const char *function, char *file, | |
437 | unsigned int line) | |
438 | { | |
439 | int me; | |
badb55ec AG |
440 | |
441 | gfs2_lm(sdp, | |
442 | "fatal: invalid metadata block\n" | |
443 | " bh = %llu (%s)\n" | |
444 | " function = %s, file = %s, line = %u\n", | |
445 | (unsigned long long)bh->b_blocknr, type, | |
446 | function, file, line); | |
447 | me = gfs2_withdraw(sdp); | |
b3b94faa DT |
448 | return (me) ? -1 : -2; |
449 | } | |
450 | ||
451 | /** | |
452 | * gfs2_metatype_check_ii - Flag a metadata type consistency error and withdraw | |
453 | * Returns: -1 if this call withdrew the machine, | |
454 | * -2 if it was already withdrawn | |
455 | */ | |
456 | ||
457 | int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh, | |
cd915493 | 458 | u16 type, u16 t, const char *function, |
b3b94faa DT |
459 | char *file, unsigned int line) |
460 | { | |
461 | int me; | |
badb55ec AG |
462 | |
463 | gfs2_lm(sdp, | |
464 | "fatal: invalid metadata block\n" | |
465 | " bh = %llu (type: exp=%u, found=%u)\n" | |
466 | " function = %s, file = %s, line = %u\n", | |
467 | (unsigned long long)bh->b_blocknr, type, t, | |
468 | function, file, line); | |
469 | me = gfs2_withdraw(sdp); | |
b3b94faa DT |
470 | return (me) ? -1 : -2; |
471 | } | |
472 | ||
473 | /** | |
474 | * gfs2_io_error_i - Flag an I/O error and withdraw | |
475 | * Returns: -1 if this call withdrew the machine, | |
476 | * 0 if it was already withdrawn | |
477 | */ | |
478 | ||
479 | int gfs2_io_error_i(struct gfs2_sbd *sdp, const char *function, char *file, | |
480 | unsigned int line) | |
481 | { | |
badb55ec AG |
482 | gfs2_lm(sdp, |
483 | "fatal: I/O error\n" | |
484 | " function = %s, file = %s, line = %u\n", | |
485 | function, file, line); | |
486 | return gfs2_withdraw(sdp); | |
b3b94faa DT |
487 | } |
488 | ||
489 | /** | |
9e1a9ecd AG |
490 | * gfs2_io_error_bh_i - Flag a buffer I/O error |
491 | * @withdraw: withdraw the filesystem | |
b3b94faa DT |
492 | */ |
493 | ||
9e1a9ecd AG |
494 | void gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, |
495 | const char *function, char *file, unsigned int line, | |
496 | bool withdraw) | |
b3b94faa | 497 | { |
69511080 BP |
498 | if (gfs2_withdrawn(sdp)) |
499 | return; | |
500 | ||
501 | fs_err(sdp, "fatal: I/O error\n" | |
502 | " block = %llu\n" | |
503 | " function = %s, file = %s, line = %u\n", | |
504 | (unsigned long long)bh->b_blocknr, function, file, line); | |
9e1a9ecd | 505 | if (withdraw) |
badb55ec | 506 | gfs2_withdraw(sdp); |
b3b94faa DT |
507 | } |
508 |