]>
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 | ||
53af80ce BP |
122 | if (sdp->sd_lockstruct.ls_ops->lm_lock == NULL) { /* lock_nolock */ |
123 | if (!ret) | |
124 | ret = -EIO; | |
125 | clear_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags); | |
126 | goto skip_recovery; | |
127 | } | |
601ef0d5 BP |
128 | /* |
129 | * Drop the glock for our journal so another node can recover it. | |
130 | */ | |
131 | if (gfs2_holder_initialized(&sdp->sd_journal_gh)) { | |
132 | gfs2_glock_dq_wait(&sdp->sd_journal_gh); | |
133 | gfs2_holder_uninit(&sdp->sd_journal_gh); | |
134 | } | |
135 | sdp->sd_jinode_gh.gh_flags |= GL_NOCACHE; | |
136 | gfs2_glock_dq(&sdp->sd_jinode_gh); | |
137 | if (test_bit(SDF_FS_FROZEN, &sdp->sd_flags)) { | |
138 | /* Make sure gfs2_unfreeze works if partially-frozen */ | |
139 | flush_workqueue(gfs2_freeze_wq); | |
140 | atomic_set(&sdp->sd_freeze_state, SFS_FROZEN); | |
141 | thaw_super(sdp->sd_vfs); | |
142 | } else { | |
143 | wait_on_bit(&gl->gl_flags, GLF_DEMOTE, TASK_UNINTERRUPTIBLE); | |
144 | } | |
145 | ||
146 | /* | |
147 | * holder_uninit to force glock_put, to force dlm to let go | |
148 | */ | |
149 | gfs2_holder_uninit(&sdp->sd_jinode_gh); | |
150 | ||
151 | /* | |
152 | * Note: We need to be careful here: | |
153 | * Our iput of jd_inode will evict it. The evict will dequeue its | |
154 | * glock, but the glock dq will wait for the withdraw unless we have | |
155 | * exception code in glock_dq. | |
156 | */ | |
157 | iput(inode); | |
158 | /* | |
159 | * Wait until the journal inode's glock is freed. This allows try locks | |
160 | * on other nodes to be successful, otherwise we remain the owner of | |
161 | * the glock as far as dlm is concerned. | |
162 | */ | |
163 | if (gl->gl_ops->go_free) { | |
164 | set_bit(GLF_FREEING, &gl->gl_flags); | |
165 | wait_on_bit(&gl->gl_flags, GLF_FREEING, TASK_UNINTERRUPTIBLE); | |
166 | } | |
167 | ||
601ef0d5 BP |
168 | /* |
169 | * Dequeue the "live" glock, but keep a reference so it's never freed. | |
170 | */ | |
171 | gfs2_glock_hold(gl); | |
172 | gfs2_glock_dq_wait(&sdp->sd_live_gh); | |
173 | /* | |
174 | * We enqueue the "live" glock in EX so that all other nodes | |
175 | * get a demote request and act on it. We don't really want the | |
176 | * lock in EX, so we send a "try" lock with 1CB to produce a callback. | |
177 | */ | |
178 | fs_warn(sdp, "Requesting recovery of jid %d.\n", | |
179 | sdp->sd_lockstruct.ls_jid); | |
180 | gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | LM_FLAG_NOEXP, | |
181 | &sdp->sd_live_gh); | |
182 | msleep(GL_GLOCK_MAX_HOLD); | |
183 | /* | |
184 | * This will likely fail in a cluster, but succeed standalone: | |
185 | */ | |
186 | ret = gfs2_glock_nq(&sdp->sd_live_gh); | |
187 | ||
188 | /* | |
189 | * If we actually got the "live" lock in EX mode, there are no other | |
190 | * nodes available to replay our journal. So we try to replay it | |
191 | * ourselves. We hold the "live" glock to prevent other mounters | |
192 | * during recovery, then just dequeue it and reacquire it in our | |
193 | * normal SH mode. Just in case the problem that caused us to | |
194 | * withdraw prevents us from recovering our journal (e.g. io errors | |
195 | * and such) we still check if the journal is clean before proceeding | |
196 | * but we may wait forever until another mounter does the recovery. | |
197 | */ | |
198 | if (ret == 0) { | |
199 | fs_warn(sdp, "No other mounters found. Trying to recover our " | |
200 | "own journal jid %d.\n", sdp->sd_lockstruct.ls_jid); | |
201 | if (gfs2_recover_journal(sdp->sd_jdesc, 1)) | |
202 | fs_warn(sdp, "Unable to recover our journal jid %d.\n", | |
203 | sdp->sd_lockstruct.ls_jid); | |
204 | gfs2_glock_dq_wait(&sdp->sd_live_gh); | |
205 | gfs2_holder_reinit(LM_ST_SHARED, LM_FLAG_NOEXP | GL_EXACT, | |
206 | &sdp->sd_live_gh); | |
207 | gfs2_glock_nq(&sdp->sd_live_gh); | |
208 | } | |
209 | ||
210 | gfs2_glock_queue_put(gl); /* drop the extra reference we acquired */ | |
211 | clear_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags); | |
212 | ||
213 | /* | |
214 | * At this point our journal is evicted, so we need to get a new inode | |
215 | * for it. Once done, we need to call gfs2_find_jhead which | |
216 | * calls gfs2_map_journal_extents to map it for us again. | |
217 | * | |
218 | * Note that we don't really want it to look up a FREE block. The | |
219 | * GFS2_BLKST_FREE simply overrides a block check in gfs2_inode_lookup | |
220 | * which would otherwise fail because it requires grabbing an rgrp | |
221 | * glock, which would fail with -EIO because we're withdrawing. | |
222 | */ | |
223 | inode = gfs2_inode_lookup(sdp->sd_vfs, DT_UNKNOWN, | |
224 | sdp->sd_jdesc->jd_no_addr, no_formal_ino, | |
225 | GFS2_BLKST_FREE); | |
226 | if (IS_ERR(inode)) { | |
227 | fs_warn(sdp, "Reprocessing of jid %d failed with %ld.\n", | |
228 | sdp->sd_lockstruct.ls_jid, PTR_ERR(inode)); | |
229 | goto skip_recovery; | |
230 | } | |
231 | sdp->sd_jdesc->jd_inode = inode; | |
232 | ||
233 | /* | |
234 | * Now wait until recovery is complete. | |
235 | */ | |
236 | for (tries = 0; tries < 10; tries++) { | |
7d9f9249 | 237 | ret = check_journal_clean(sdp, sdp->sd_jdesc, false); |
601ef0d5 BP |
238 | if (!ret) |
239 | break; | |
240 | msleep(HZ); | |
241 | fs_warn(sdp, "Waiting for journal recovery jid %d.\n", | |
242 | sdp->sd_lockstruct.ls_jid); | |
243 | } | |
244 | skip_recovery: | |
245 | if (!ret) | |
246 | fs_warn(sdp, "Journal recovery complete for jid %d.\n", | |
247 | sdp->sd_lockstruct.ls_jid); | |
248 | else | |
249 | fs_warn(sdp, "Journal recovery skipped for %d until next " | |
250 | "mount.\n", sdp->sd_lockstruct.ls_jid); | |
251 | fs_warn(sdp, "Glock dequeues delayed: %lu\n", sdp->sd_glock_dqs_held); | |
252 | sdp->sd_glock_dqs_held = 0; | |
253 | wake_up_bit(&sdp->sd_flags, SDF_WITHDRAW_RECOVERY); | |
254 | } | |
255 | ||
badb55ec AG |
256 | void gfs2_lm(struct gfs2_sbd *sdp, const char *fmt, ...) |
257 | { | |
258 | struct va_format vaf; | |
259 | va_list args; | |
260 | ||
261 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW && | |
262 | test_bit(SDF_WITHDRAWN, &sdp->sd_flags)) | |
263 | return; | |
264 | ||
265 | va_start(args, fmt); | |
266 | vaf.fmt = fmt; | |
267 | vaf.va = &args; | |
268 | fs_err(sdp, "%pV", &vaf); | |
269 | va_end(args); | |
270 | } | |
271 | ||
272 | int gfs2_withdraw(struct gfs2_sbd *sdp) | |
da755fdb | 273 | { |
f057f6cd SW |
274 | struct lm_lockstruct *ls = &sdp->sd_lockstruct; |
275 | const struct lm_lockops *lm = ls->ls_ops; | |
da755fdb | 276 | |
d34843d0 | 277 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW && |
601ef0d5 BP |
278 | test_and_set_bit(SDF_WITHDRAWN, &sdp->sd_flags)) { |
279 | if (!test_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags)) | |
280 | return -1; | |
281 | ||
282 | wait_on_bit(&sdp->sd_flags, SDF_WITHDRAW_IN_PROG, | |
283 | TASK_UNINTERRUPTIBLE); | |
284 | return -1; | |
285 | } | |
286 | ||
287 | set_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags); | |
da755fdb | 288 | |
d34843d0 BP |
289 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) { |
290 | fs_err(sdp, "about to withdraw this file system\n"); | |
291 | BUG_ON(sdp->sd_args.ar_debug); | |
da755fdb | 292 | |
601ef0d5 BP |
293 | signal_our_withdraw(sdp); |
294 | ||
d34843d0 | 295 | kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE); |
f057f6cd | 296 | |
fd95e81c SW |
297 | if (!strcmp(sdp->sd_lockstruct.ls_ops->lm_proto_name, "lock_dlm")) |
298 | wait_for_completion(&sdp->sd_wdack); | |
299 | ||
d34843d0 BP |
300 | if (lm->lm_unmount) { |
301 | fs_err(sdp, "telling LM to unmount\n"); | |
302 | lm->lm_unmount(sdp); | |
303 | } | |
3e11e530 | 304 | set_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags); |
601ef0d5 | 305 | fs_err(sdp, "File system withdrawn\n"); |
d34843d0 | 306 | dump_stack(); |
601ef0d5 BP |
307 | clear_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags); |
308 | smp_mb__after_atomic(); | |
309 | wake_up_bit(&sdp->sd_flags, SDF_WITHDRAW_IN_PROG); | |
f057f6cd | 310 | } |
d34843d0 BP |
311 | |
312 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC) | |
d77d1b58 | 313 | panic("GFS2: fsid=%s: panic requested\n", sdp->sd_fsname); |
da755fdb SW |
314 | |
315 | return -1; | |
316 | } | |
317 | ||
b3b94faa DT |
318 | /** |
319 | * gfs2_assert_withdraw_i - Cause the machine to withdraw if @assertion is false | |
b3b94faa DT |
320 | */ |
321 | ||
8e28ef1f | 322 | void gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion, |
ca399c96 BP |
323 | const char *function, char *file, unsigned int line, |
324 | bool delayed) | |
b3b94faa | 325 | { |
ca399c96 BP |
326 | if (gfs2_withdrawn(sdp)) |
327 | return; | |
328 | ||
329 | fs_err(sdp, | |
330 | "fatal: assertion \"%s\" failed\n" | |
331 | " function = %s, file = %s, line = %u\n", | |
332 | assertion, function, file, line); | |
333 | ||
334 | /* | |
335 | * If errors=panic was specified on mount, it won't help to delay the | |
336 | * withdraw. | |
337 | */ | |
338 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC) | |
339 | delayed = false; | |
340 | ||
341 | if (delayed) | |
342 | gfs2_withdraw_delayed(sdp); | |
343 | else | |
344 | gfs2_withdraw(sdp); | |
18ec7d5c | 345 | dump_stack(); |
b3b94faa DT |
346 | } |
347 | ||
348 | /** | |
349 | * gfs2_assert_warn_i - Print a message to the console if @assertion is false | |
b3b94faa DT |
350 | */ |
351 | ||
8e28ef1f AG |
352 | void gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion, |
353 | const char *function, char *file, unsigned int line) | |
b3b94faa DT |
354 | { |
355 | if (time_before(jiffies, | |
356 | sdp->sd_last_warning + | |
357 | gfs2_tune_get(sdp, gt_complain_secs) * HZ)) | |
8e28ef1f | 358 | return; |
b3b94faa | 359 | |
d34843d0 | 360 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) |
8382e26b JP |
361 | fs_warn(sdp, "warning: assertion \"%s\" failed at function = %s, file = %s, line = %u\n", |
362 | assertion, function, file, line); | |
b3b94faa DT |
363 | |
364 | if (sdp->sd_args.ar_debug) | |
365 | BUG(); | |
18ec7d5c SW |
366 | else |
367 | dump_stack(); | |
b3b94faa | 368 | |
d34843d0 BP |
369 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC) |
370 | panic("GFS2: fsid=%s: warning: assertion \"%s\" failed\n" | |
371 | "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", | |
372 | sdp->sd_fsname, assertion, | |
373 | sdp->sd_fsname, function, file, line); | |
374 | ||
b3b94faa | 375 | sdp->sd_last_warning = jiffies; |
b3b94faa DT |
376 | } |
377 | ||
378 | /** | |
379 | * gfs2_consist_i - Flag a filesystem consistency error and withdraw | |
b3b94faa DT |
380 | */ |
381 | ||
a5ca2f1c AG |
382 | void gfs2_consist_i(struct gfs2_sbd *sdp, const char *function, |
383 | char *file, unsigned int line) | |
b3b94faa | 384 | { |
badb55ec AG |
385 | gfs2_lm(sdp, |
386 | "fatal: filesystem consistency error - function = %s, file = %s, line = %u\n", | |
387 | function, file, line); | |
a5ca2f1c | 388 | gfs2_withdraw(sdp); |
b3b94faa DT |
389 | } |
390 | ||
391 | /** | |
392 | * gfs2_consist_inode_i - Flag an inode consistency error and withdraw | |
b3b94faa DT |
393 | */ |
394 | ||
a5ca2f1c AG |
395 | void gfs2_consist_inode_i(struct gfs2_inode *ip, |
396 | const char *function, char *file, unsigned int line) | |
b3b94faa | 397 | { |
feaa7bba | 398 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
badb55ec AG |
399 | |
400 | gfs2_lm(sdp, | |
401 | "fatal: filesystem consistency error\n" | |
402 | " inode = %llu %llu\n" | |
403 | " function = %s, file = %s, line = %u\n", | |
404 | (unsigned long long)ip->i_no_formal_ino, | |
405 | (unsigned long long)ip->i_no_addr, | |
406 | function, file, line); | |
a5ca2f1c | 407 | gfs2_withdraw(sdp); |
b3b94faa DT |
408 | } |
409 | ||
410 | /** | |
411 | * gfs2_consist_rgrpd_i - Flag a RG consistency error and withdraw | |
b3b94faa DT |
412 | */ |
413 | ||
a5ca2f1c AG |
414 | void gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, |
415 | const char *function, char *file, unsigned int line) | |
b3b94faa DT |
416 | { |
417 | struct gfs2_sbd *sdp = rgd->rd_sbd; | |
98fb0574 | 418 | char fs_id_buf[sizeof(sdp->sd_fsname) + 7]; |
72244b6b | 419 | |
3792ce97 BP |
420 | sprintf(fs_id_buf, "fsid=%s: ", sdp->sd_fsname); |
421 | gfs2_rgrp_dump(NULL, rgd->rd_gl, fs_id_buf); | |
badb55ec AG |
422 | gfs2_lm(sdp, |
423 | "fatal: filesystem consistency error\n" | |
424 | " RG = %llu\n" | |
425 | " function = %s, file = %s, line = %u\n", | |
426 | (unsigned long long)rgd->rd_addr, | |
427 | function, file, line); | |
a5ca2f1c | 428 | gfs2_withdraw(sdp); |
b3b94faa DT |
429 | } |
430 | ||
431 | /** | |
432 | * gfs2_meta_check_ii - Flag a magic number consistency error and withdraw | |
433 | * Returns: -1 if this call withdrew the machine, | |
434 | * -2 if it was already withdrawn | |
435 | */ | |
436 | ||
437 | int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh, | |
438 | const char *type, const char *function, char *file, | |
439 | unsigned int line) | |
440 | { | |
441 | int me; | |
badb55ec AG |
442 | |
443 | gfs2_lm(sdp, | |
444 | "fatal: invalid metadata block\n" | |
445 | " bh = %llu (%s)\n" | |
446 | " function = %s, file = %s, line = %u\n", | |
447 | (unsigned long long)bh->b_blocknr, type, | |
448 | function, file, line); | |
449 | me = gfs2_withdraw(sdp); | |
b3b94faa DT |
450 | return (me) ? -1 : -2; |
451 | } | |
452 | ||
453 | /** | |
454 | * gfs2_metatype_check_ii - Flag a metadata type consistency error and withdraw | |
455 | * Returns: -1 if this call withdrew the machine, | |
456 | * -2 if it was already withdrawn | |
457 | */ | |
458 | ||
459 | int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh, | |
cd915493 | 460 | u16 type, u16 t, const char *function, |
b3b94faa DT |
461 | char *file, unsigned int line) |
462 | { | |
463 | int me; | |
badb55ec AG |
464 | |
465 | gfs2_lm(sdp, | |
466 | "fatal: invalid metadata block\n" | |
467 | " bh = %llu (type: exp=%u, found=%u)\n" | |
468 | " function = %s, file = %s, line = %u\n", | |
469 | (unsigned long long)bh->b_blocknr, type, t, | |
470 | function, file, line); | |
471 | me = gfs2_withdraw(sdp); | |
b3b94faa DT |
472 | return (me) ? -1 : -2; |
473 | } | |
474 | ||
475 | /** | |
476 | * gfs2_io_error_i - Flag an I/O error and withdraw | |
477 | * Returns: -1 if this call withdrew the machine, | |
478 | * 0 if it was already withdrawn | |
479 | */ | |
480 | ||
481 | int gfs2_io_error_i(struct gfs2_sbd *sdp, const char *function, char *file, | |
482 | unsigned int line) | |
483 | { | |
badb55ec AG |
484 | gfs2_lm(sdp, |
485 | "fatal: I/O error\n" | |
486 | " function = %s, file = %s, line = %u\n", | |
487 | function, file, line); | |
488 | return gfs2_withdraw(sdp); | |
b3b94faa DT |
489 | } |
490 | ||
491 | /** | |
9e1a9ecd AG |
492 | * gfs2_io_error_bh_i - Flag a buffer I/O error |
493 | * @withdraw: withdraw the filesystem | |
b3b94faa DT |
494 | */ |
495 | ||
9e1a9ecd AG |
496 | void gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, |
497 | const char *function, char *file, unsigned int line, | |
498 | bool withdraw) | |
b3b94faa | 499 | { |
69511080 BP |
500 | if (gfs2_withdrawn(sdp)) |
501 | return; | |
502 | ||
503 | fs_err(sdp, "fatal: I/O error\n" | |
504 | " block = %llu\n" | |
505 | " function = %s, file = %s, line = %u\n", | |
506 | (unsigned long long)bh->b_blocknr, function, file, line); | |
9e1a9ecd | 507 | if (withdraw) |
badb55ec | 508 | gfs2_withdraw(sdp); |
b3b94faa DT |
509 | } |
510 |