.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
---|
3 | 4 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. |
---|
4 | | - * |
---|
5 | | - * This copyrighted material is made available to anyone wishing to use, |
---|
6 | | - * modify, copy, or redistribute it subject to the terms and conditions |
---|
7 | | - * of the GNU General Public License version 2. |
---|
8 | 5 | */ |
---|
9 | 6 | |
---|
10 | 7 | #include <linux/module.h> |
---|
.. | .. |
---|
114 | 111 | struct gfs2_revoke_replay *rr; |
---|
115 | 112 | |
---|
116 | 113 | while (!list_empty(head)) { |
---|
117 | | - rr = list_entry(head->next, struct gfs2_revoke_replay, rr_list); |
---|
| 114 | + rr = list_first_entry(head, struct gfs2_revoke_replay, rr_list); |
---|
118 | 115 | list_del(&rr->rr_list); |
---|
119 | 116 | kfree(rr); |
---|
120 | 117 | } |
---|
121 | 118 | } |
---|
122 | 119 | |
---|
| 120 | +int __get_log_header(struct gfs2_sbd *sdp, const struct gfs2_log_header *lh, |
---|
| 121 | + unsigned int blkno, struct gfs2_log_header_host *head) |
---|
| 122 | +{ |
---|
| 123 | + u32 hash, crc; |
---|
| 124 | + |
---|
| 125 | + if (lh->lh_header.mh_magic != cpu_to_be32(GFS2_MAGIC) || |
---|
| 126 | + lh->lh_header.mh_type != cpu_to_be32(GFS2_METATYPE_LH) || |
---|
| 127 | + (blkno && be32_to_cpu(lh->lh_blkno) != blkno)) |
---|
| 128 | + return 1; |
---|
| 129 | + |
---|
| 130 | + hash = crc32(~0, lh, LH_V1_SIZE - 4); |
---|
| 131 | + hash = ~crc32_le_shift(hash, 4); /* assume lh_hash is zero */ |
---|
| 132 | + |
---|
| 133 | + if (be32_to_cpu(lh->lh_hash) != hash) |
---|
| 134 | + return 1; |
---|
| 135 | + |
---|
| 136 | + crc = crc32c(~0, (void *)lh + LH_V1_SIZE + 4, |
---|
| 137 | + sdp->sd_sb.sb_bsize - LH_V1_SIZE - 4); |
---|
| 138 | + |
---|
| 139 | + if ((lh->lh_crc != 0 && be32_to_cpu(lh->lh_crc) != crc)) |
---|
| 140 | + return 1; |
---|
| 141 | + |
---|
| 142 | + head->lh_sequence = be64_to_cpu(lh->lh_sequence); |
---|
| 143 | + head->lh_flags = be32_to_cpu(lh->lh_flags); |
---|
| 144 | + head->lh_tail = be32_to_cpu(lh->lh_tail); |
---|
| 145 | + head->lh_blkno = be32_to_cpu(lh->lh_blkno); |
---|
| 146 | + |
---|
| 147 | + head->lh_local_total = be64_to_cpu(lh->lh_local_total); |
---|
| 148 | + head->lh_local_free = be64_to_cpu(lh->lh_local_free); |
---|
| 149 | + head->lh_local_dinodes = be64_to_cpu(lh->lh_local_dinodes); |
---|
| 150 | + |
---|
| 151 | + return 0; |
---|
| 152 | +} |
---|
123 | 153 | /** |
---|
124 | 154 | * get_log_header - read the log header for a given segment |
---|
125 | 155 | * @jd: the journal |
---|
.. | .. |
---|
137 | 167 | static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk, |
---|
138 | 168 | struct gfs2_log_header_host *head) |
---|
139 | 169 | { |
---|
140 | | - struct gfs2_log_header *lh; |
---|
| 170 | + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); |
---|
141 | 171 | struct buffer_head *bh; |
---|
142 | | - u32 hash, crc; |
---|
143 | 172 | int error; |
---|
144 | 173 | |
---|
145 | 174 | error = gfs2_replay_read_block(jd, blk, &bh); |
---|
146 | 175 | if (error) |
---|
147 | 176 | return error; |
---|
148 | | - lh = (void *)bh->b_data; |
---|
149 | 177 | |
---|
150 | | - hash = crc32(~0, lh, LH_V1_SIZE - 4); |
---|
151 | | - hash = ~crc32_le_shift(hash, 4); /* assume lh_hash is zero */ |
---|
152 | | - |
---|
153 | | - crc = crc32c(~0, (void *)lh + LH_V1_SIZE + 4, |
---|
154 | | - bh->b_size - LH_V1_SIZE - 4); |
---|
155 | | - |
---|
156 | | - error = lh->lh_header.mh_magic != cpu_to_be32(GFS2_MAGIC) || |
---|
157 | | - lh->lh_header.mh_type != cpu_to_be32(GFS2_METATYPE_LH) || |
---|
158 | | - be32_to_cpu(lh->lh_blkno) != blk || |
---|
159 | | - be32_to_cpu(lh->lh_hash) != hash || |
---|
160 | | - (lh->lh_crc != 0 && be32_to_cpu(lh->lh_crc) != crc); |
---|
161 | | - |
---|
| 178 | + error = __get_log_header(sdp, (const struct gfs2_log_header *)bh->b_data, |
---|
| 179 | + blk, head); |
---|
162 | 180 | brelse(bh); |
---|
163 | | - |
---|
164 | | - if (!error) { |
---|
165 | | - head->lh_sequence = be64_to_cpu(lh->lh_sequence); |
---|
166 | | - head->lh_flags = be32_to_cpu(lh->lh_flags); |
---|
167 | | - head->lh_tail = be32_to_cpu(lh->lh_tail); |
---|
168 | | - head->lh_blkno = be32_to_cpu(lh->lh_blkno); |
---|
169 | | - } |
---|
170 | | - return error; |
---|
171 | | -} |
---|
172 | | - |
---|
173 | | -/** |
---|
174 | | - * find_good_lh - find a good log header |
---|
175 | | - * @jd: the journal |
---|
176 | | - * @blk: the segment to start searching from |
---|
177 | | - * @lh: the log header to fill in |
---|
178 | | - * @forward: if true search forward in the log, else search backward |
---|
179 | | - * |
---|
180 | | - * Call get_log_header() to get a log header for a segment, but if the |
---|
181 | | - * segment is bad, either scan forward or backward until we find a good one. |
---|
182 | | - * |
---|
183 | | - * Returns: errno |
---|
184 | | - */ |
---|
185 | | - |
---|
186 | | -static int find_good_lh(struct gfs2_jdesc *jd, unsigned int *blk, |
---|
187 | | - struct gfs2_log_header_host *head) |
---|
188 | | -{ |
---|
189 | | - unsigned int orig_blk = *blk; |
---|
190 | | - int error; |
---|
191 | | - |
---|
192 | | - for (;;) { |
---|
193 | | - error = get_log_header(jd, *blk, head); |
---|
194 | | - if (error <= 0) |
---|
195 | | - return error; |
---|
196 | | - |
---|
197 | | - if (++*blk == jd->jd_blocks) |
---|
198 | | - *blk = 0; |
---|
199 | | - |
---|
200 | | - if (*blk == orig_blk) { |
---|
201 | | - gfs2_consist_inode(GFS2_I(jd->jd_inode)); |
---|
202 | | - return -EIO; |
---|
203 | | - } |
---|
204 | | - } |
---|
205 | | -} |
---|
206 | | - |
---|
207 | | -/** |
---|
208 | | - * jhead_scan - make sure we've found the head of the log |
---|
209 | | - * @jd: the journal |
---|
210 | | - * @head: this is filled in with the log descriptor of the head |
---|
211 | | - * |
---|
212 | | - * At this point, seg and lh should be either the head of the log or just |
---|
213 | | - * before. Scan forward until we find the head. |
---|
214 | | - * |
---|
215 | | - * Returns: errno |
---|
216 | | - */ |
---|
217 | | - |
---|
218 | | -static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head) |
---|
219 | | -{ |
---|
220 | | - unsigned int blk = head->lh_blkno; |
---|
221 | | - struct gfs2_log_header_host lh; |
---|
222 | | - int error; |
---|
223 | | - |
---|
224 | | - for (;;) { |
---|
225 | | - if (++blk == jd->jd_blocks) |
---|
226 | | - blk = 0; |
---|
227 | | - |
---|
228 | | - error = get_log_header(jd, blk, &lh); |
---|
229 | | - if (error < 0) |
---|
230 | | - return error; |
---|
231 | | - if (error == 1) |
---|
232 | | - continue; |
---|
233 | | - |
---|
234 | | - if (lh.lh_sequence == head->lh_sequence) { |
---|
235 | | - gfs2_consist_inode(GFS2_I(jd->jd_inode)); |
---|
236 | | - return -EIO; |
---|
237 | | - } |
---|
238 | | - if (lh.lh_sequence < head->lh_sequence) |
---|
239 | | - break; |
---|
240 | | - |
---|
241 | | - *head = lh; |
---|
242 | | - } |
---|
243 | | - |
---|
244 | | - return 0; |
---|
245 | | -} |
---|
246 | | - |
---|
247 | | -/** |
---|
248 | | - * gfs2_find_jhead - find the head of a log |
---|
249 | | - * @jd: the journal |
---|
250 | | - * @head: the log descriptor for the head of the log is returned here |
---|
251 | | - * |
---|
252 | | - * Do a binary search of a journal and find the valid log entry with the |
---|
253 | | - * highest sequence number. (i.e. the log head) |
---|
254 | | - * |
---|
255 | | - * Returns: errno |
---|
256 | | - */ |
---|
257 | | - |
---|
258 | | -int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head) |
---|
259 | | -{ |
---|
260 | | - struct gfs2_log_header_host lh_1, lh_m; |
---|
261 | | - u32 blk_1, blk_2, blk_m; |
---|
262 | | - int error; |
---|
263 | | - |
---|
264 | | - blk_1 = 0; |
---|
265 | | - blk_2 = jd->jd_blocks - 1; |
---|
266 | | - |
---|
267 | | - for (;;) { |
---|
268 | | - blk_m = (blk_1 + blk_2) / 2; |
---|
269 | | - |
---|
270 | | - error = find_good_lh(jd, &blk_1, &lh_1); |
---|
271 | | - if (error) |
---|
272 | | - return error; |
---|
273 | | - |
---|
274 | | - error = find_good_lh(jd, &blk_m, &lh_m); |
---|
275 | | - if (error) |
---|
276 | | - return error; |
---|
277 | | - |
---|
278 | | - if (blk_1 == blk_m || blk_m == blk_2) |
---|
279 | | - break; |
---|
280 | | - |
---|
281 | | - if (lh_1.lh_sequence <= lh_m.lh_sequence) |
---|
282 | | - blk_1 = blk_m; |
---|
283 | | - else |
---|
284 | | - blk_2 = blk_m; |
---|
285 | | - } |
---|
286 | | - |
---|
287 | | - error = jhead_scan(jd, &lh_1); |
---|
288 | | - if (error) |
---|
289 | | - return error; |
---|
290 | | - |
---|
291 | | - *head = lh_1; |
---|
292 | 181 | |
---|
293 | 182 | return error; |
---|
294 | 183 | } |
---|
.. | .. |
---|
305 | 194 | * Returns: errno |
---|
306 | 195 | */ |
---|
307 | 196 | |
---|
308 | | -static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, |
---|
| 197 | +static int foreach_descriptor(struct gfs2_jdesc *jd, u32 start, |
---|
309 | 198 | unsigned int end, int pass) |
---|
310 | 199 | { |
---|
311 | 200 | struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); |
---|
.. | .. |
---|
375 | 264 | struct gfs2_log_header_host *head) |
---|
376 | 265 | { |
---|
377 | 266 | struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); |
---|
| 267 | + u32 lblock = head->lh_blkno; |
---|
378 | 268 | |
---|
379 | | - sdp->sd_log_flush_head = head->lh_blkno; |
---|
380 | | - gfs2_replay_incr_blk(jd, &sdp->sd_log_flush_head); |
---|
381 | | - gfs2_write_log_header(sdp, jd, head->lh_sequence + 1, 0, |
---|
| 269 | + gfs2_replay_incr_blk(jd, &lblock); |
---|
| 270 | + gfs2_write_log_header(sdp, jd, head->lh_sequence + 1, 0, lblock, |
---|
382 | 271 | GFS2_LOG_HEAD_UNMOUNT | GFS2_LOG_HEAD_RECOVERY, |
---|
383 | 272 | REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC); |
---|
| 273 | + if (jd->jd_jid == sdp->sd_lockstruct.ls_jid) { |
---|
| 274 | + sdp->sd_log_flush_head = lblock; |
---|
| 275 | + gfs2_log_incr_head(sdp); |
---|
| 276 | + } |
---|
384 | 277 | } |
---|
385 | 278 | |
---|
386 | 279 | |
---|
.. | .. |
---|
403 | 296 | sdp->sd_lockstruct.ls_ops->lm_recovery_result(sdp, jid, message); |
---|
404 | 297 | } |
---|
405 | 298 | |
---|
| 299 | +/** |
---|
| 300 | + * update_statfs_inode - Update the master statfs inode or zero out the local |
---|
| 301 | + * statfs inode for a given journal. |
---|
| 302 | + * @jd: The journal |
---|
| 303 | + * @head: If NULL, @inode is the local statfs inode and we need to zero it out. |
---|
| 304 | + * Otherwise, it @head contains the statfs change info that needs to be |
---|
| 305 | + * synced to the master statfs inode (pointed to by @inode). |
---|
| 306 | + * @inode: statfs inode to update. |
---|
| 307 | + */ |
---|
| 308 | +static int update_statfs_inode(struct gfs2_jdesc *jd, |
---|
| 309 | + struct gfs2_log_header_host *head, |
---|
| 310 | + struct inode *inode) |
---|
| 311 | +{ |
---|
| 312 | + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); |
---|
| 313 | + struct gfs2_inode *ip; |
---|
| 314 | + struct buffer_head *bh; |
---|
| 315 | + struct gfs2_statfs_change_host sc; |
---|
| 316 | + int error = 0; |
---|
| 317 | + |
---|
| 318 | + BUG_ON(!inode); |
---|
| 319 | + ip = GFS2_I(inode); |
---|
| 320 | + |
---|
| 321 | + error = gfs2_meta_inode_buffer(ip, &bh); |
---|
| 322 | + if (error) |
---|
| 323 | + goto out; |
---|
| 324 | + |
---|
| 325 | + spin_lock(&sdp->sd_statfs_spin); |
---|
| 326 | + |
---|
| 327 | + if (head) { /* Update the master statfs inode */ |
---|
| 328 | + gfs2_statfs_change_in(&sc, bh->b_data + sizeof(struct gfs2_dinode)); |
---|
| 329 | + sc.sc_total += head->lh_local_total; |
---|
| 330 | + sc.sc_free += head->lh_local_free; |
---|
| 331 | + sc.sc_dinodes += head->lh_local_dinodes; |
---|
| 332 | + gfs2_statfs_change_out(&sc, bh->b_data + sizeof(struct gfs2_dinode)); |
---|
| 333 | + |
---|
| 334 | + fs_info(sdp, "jid=%u: Updated master statfs Total:%lld, " |
---|
| 335 | + "Free:%lld, Dinodes:%lld after change " |
---|
| 336 | + "[%+lld,%+lld,%+lld]\n", jd->jd_jid, sc.sc_total, |
---|
| 337 | + sc.sc_free, sc.sc_dinodes, head->lh_local_total, |
---|
| 338 | + head->lh_local_free, head->lh_local_dinodes); |
---|
| 339 | + } else { /* Zero out the local statfs inode */ |
---|
| 340 | + memset(bh->b_data + sizeof(struct gfs2_dinode), 0, |
---|
| 341 | + sizeof(struct gfs2_statfs_change)); |
---|
| 342 | + /* If it's our own journal, reset any in-memory changes too */ |
---|
| 343 | + if (jd->jd_jid == sdp->sd_lockstruct.ls_jid) { |
---|
| 344 | + memset(&sdp->sd_statfs_local, 0, |
---|
| 345 | + sizeof(struct gfs2_statfs_change_host)); |
---|
| 346 | + } |
---|
| 347 | + } |
---|
| 348 | + spin_unlock(&sdp->sd_statfs_spin); |
---|
| 349 | + |
---|
| 350 | + mark_buffer_dirty(bh); |
---|
| 351 | + brelse(bh); |
---|
| 352 | + gfs2_inode_metasync(ip->i_gl); |
---|
| 353 | + |
---|
| 354 | +out: |
---|
| 355 | + return error; |
---|
| 356 | +} |
---|
| 357 | + |
---|
| 358 | +/** |
---|
| 359 | + * recover_local_statfs - Update the master and local statfs changes for this |
---|
| 360 | + * journal. |
---|
| 361 | + * |
---|
| 362 | + * Previously, statfs updates would be read in from the local statfs inode and |
---|
| 363 | + * synced to the master statfs inode during recovery. |
---|
| 364 | + * |
---|
| 365 | + * We now use the statfs updates in the journal head to update the master statfs |
---|
| 366 | + * inode instead of reading in from the local statfs inode. To preserve backward |
---|
| 367 | + * compatibility with kernels that can't do this, we still need to keep the |
---|
| 368 | + * local statfs inode up to date by writing changes to it. At some point in the |
---|
| 369 | + * future, we can do away with the local statfs inodes altogether and keep the |
---|
| 370 | + * statfs changes solely in the journal. |
---|
| 371 | + * |
---|
| 372 | + * @jd: the journal |
---|
| 373 | + * @head: the journal head |
---|
| 374 | + * |
---|
| 375 | + * Returns: errno |
---|
| 376 | + */ |
---|
| 377 | +static void recover_local_statfs(struct gfs2_jdesc *jd, |
---|
| 378 | + struct gfs2_log_header_host *head) |
---|
| 379 | +{ |
---|
| 380 | + int error; |
---|
| 381 | + struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); |
---|
| 382 | + |
---|
| 383 | + if (!head->lh_local_total && !head->lh_local_free |
---|
| 384 | + && !head->lh_local_dinodes) /* No change */ |
---|
| 385 | + goto zero_local; |
---|
| 386 | + |
---|
| 387 | + /* First update the master statfs inode with the changes we |
---|
| 388 | + * found in the journal. */ |
---|
| 389 | + error = update_statfs_inode(jd, head, sdp->sd_statfs_inode); |
---|
| 390 | + if (error) |
---|
| 391 | + goto out; |
---|
| 392 | + |
---|
| 393 | +zero_local: |
---|
| 394 | + /* Zero out the local statfs inode so any changes in there |
---|
| 395 | + * are not re-recovered. */ |
---|
| 396 | + error = update_statfs_inode(jd, NULL, |
---|
| 397 | + find_local_statfs_inode(sdp, jd->jd_jid)); |
---|
| 398 | +out: |
---|
| 399 | + return; |
---|
| 400 | +} |
---|
| 401 | + |
---|
406 | 402 | void gfs2_recover_func(struct work_struct *work) |
---|
407 | 403 | { |
---|
408 | 404 | struct gfs2_jdesc *jd = container_of(work, struct gfs2_jdesc, jd_work); |
---|
.. | .. |
---|
416 | 412 | int error = 0; |
---|
417 | 413 | int jlocked = 0; |
---|
418 | 414 | |
---|
| 415 | + if (gfs2_withdrawn(sdp)) { |
---|
| 416 | + fs_err(sdp, "jid=%u: Recovery not attempted due to withdraw.\n", |
---|
| 417 | + jd->jd_jid); |
---|
| 418 | + goto fail; |
---|
| 419 | + } |
---|
419 | 420 | t_start = ktime_get(); |
---|
420 | 421 | if (sdp->sd_args.ar_spectator) |
---|
421 | 422 | goto fail; |
---|
.. | .. |
---|
439 | 440 | |
---|
440 | 441 | default: |
---|
441 | 442 | goto fail; |
---|
442 | | - }; |
---|
| 443 | + } |
---|
443 | 444 | |
---|
444 | 445 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, |
---|
445 | 446 | LM_FLAG_NOEXP | GL_NOCACHE, &ji_gh); |
---|
.. | .. |
---|
456 | 457 | if (error) |
---|
457 | 458 | goto fail_gunlock_ji; |
---|
458 | 459 | |
---|
459 | | - error = gfs2_find_jhead(jd, &head); |
---|
| 460 | + error = gfs2_find_jhead(jd, &head, true); |
---|
460 | 461 | if (error) |
---|
461 | 462 | goto fail_gunlock_ji; |
---|
462 | 463 | t_jhd = ktime_get(); |
---|
| 464 | + fs_info(sdp, "jid=%u: Journal head lookup took %lldms\n", jd->jd_jid, |
---|
| 465 | + ktime_ms_delta(t_jhd, t_jlck)); |
---|
463 | 466 | |
---|
464 | 467 | if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) { |
---|
465 | 468 | fs_info(sdp, "jid=%u: Acquiring the transaction lock...\n", |
---|
.. | .. |
---|
467 | 470 | |
---|
468 | 471 | /* Acquire a shared hold on the freeze lock */ |
---|
469 | 472 | |
---|
470 | | - error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, |
---|
471 | | - LM_FLAG_NOEXP | LM_FLAG_PRIORITY, |
---|
472 | | - &thaw_gh); |
---|
| 473 | + error = gfs2_freeze_lock(sdp, &thaw_gh, LM_FLAG_PRIORITY); |
---|
473 | 474 | if (error) |
---|
474 | 475 | goto fail_gunlock_ji; |
---|
475 | 476 | |
---|
.. | .. |
---|
499 | 500 | } |
---|
500 | 501 | |
---|
501 | 502 | t_tlck = ktime_get(); |
---|
502 | | - fs_info(sdp, "jid=%u: Replaying journal...\n", jd->jd_jid); |
---|
| 503 | + fs_info(sdp, "jid=%u: Replaying journal...0x%x to 0x%x\n", |
---|
| 504 | + jd->jd_jid, head.lh_tail, head.lh_blkno); |
---|
503 | 505 | |
---|
| 506 | + /* We take the sd_log_flush_lock here primarily to prevent log |
---|
| 507 | + * flushes and simultaneous journal replays from stomping on |
---|
| 508 | + * each other wrt sd_log_bio. */ |
---|
| 509 | + down_read(&sdp->sd_log_flush_lock); |
---|
504 | 510 | for (pass = 0; pass < 2; pass++) { |
---|
505 | 511 | lops_before_scan(jd, &head, pass); |
---|
506 | 512 | error = foreach_descriptor(jd, head.lh_tail, |
---|
507 | 513 | head.lh_blkno, pass); |
---|
508 | 514 | lops_after_scan(jd, error, pass); |
---|
509 | | - if (error) |
---|
| 515 | + if (error) { |
---|
| 516 | + up_read(&sdp->sd_log_flush_lock); |
---|
510 | 517 | goto fail_gunlock_thaw; |
---|
| 518 | + } |
---|
511 | 519 | } |
---|
512 | 520 | |
---|
| 521 | + recover_local_statfs(jd, &head); |
---|
513 | 522 | clean_journal(jd, &head); |
---|
| 523 | + up_read(&sdp->sd_log_flush_lock); |
---|
514 | 524 | |
---|
515 | | - gfs2_glock_dq_uninit(&thaw_gh); |
---|
| 525 | + gfs2_freeze_unlock(&thaw_gh); |
---|
516 | 526 | t_rep = ktime_get(); |
---|
517 | 527 | fs_info(sdp, "jid=%u: Journal replayed in %lldms [jlck:%lldms, " |
---|
518 | 528 | "jhead:%lldms, tlck:%lldms, replay:%lldms]\n", |
---|
.. | .. |
---|
534 | 544 | goto done; |
---|
535 | 545 | |
---|
536 | 546 | fail_gunlock_thaw: |
---|
537 | | - gfs2_glock_dq_uninit(&thaw_gh); |
---|
| 547 | + gfs2_freeze_unlock(&thaw_gh); |
---|
538 | 548 | fail_gunlock_ji: |
---|
539 | 549 | if (jlocked) { |
---|
540 | 550 | gfs2_glock_dq_uninit(&ji_gh); |
---|