999 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * NILFS recovery logic4 *5 * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.6 *7 * Written by Ryusuke Konishi.8 */9 10#include <linux/buffer_head.h>11#include <linux/blkdev.h>12#include <linux/swap.h>13#include <linux/slab.h>14#include <linux/crc32.h>15#include "nilfs.h"16#include "segment.h"17#include "sufile.h"18#include "page.h"19#include "segbuf.h"20 21/*22 * Segment check result23 */24enum {25 NILFS_SEG_VALID,26 NILFS_SEG_NO_SUPER_ROOT,27 NILFS_SEG_FAIL_IO,28 NILFS_SEG_FAIL_MAGIC,29 NILFS_SEG_FAIL_SEQ,30 NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT,31 NILFS_SEG_FAIL_CHECKSUM_FULL,32 NILFS_SEG_FAIL_CONSISTENCY,33};34 35/* work structure for recovery */36struct nilfs_recovery_block {37 ino_t ino; /*38 * Inode number of the file that this block39 * belongs to40 */41 sector_t blocknr; /* block number */42 __u64 vblocknr; /* virtual block number */43 unsigned long blkoff; /* File offset of the data block (per block) */44 struct list_head list;45};46 47 48static int nilfs_warn_segment_error(struct super_block *sb, int err)49{50 const char *msg = NULL;51 52 switch (err) {53 case NILFS_SEG_FAIL_IO:54 nilfs_err(sb, "I/O error reading segment");55 return -EIO;56 case NILFS_SEG_FAIL_MAGIC:57 msg = "Magic number mismatch";58 break;59 case NILFS_SEG_FAIL_SEQ:60 msg = "Sequence number mismatch";61 break;62 case NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT:63 msg = "Checksum error in super root";64 break;65 case NILFS_SEG_FAIL_CHECKSUM_FULL:66 msg = "Checksum error in segment payload";67 break;68 case NILFS_SEG_FAIL_CONSISTENCY:69 msg = "Inconsistency found";70 break;71 case NILFS_SEG_NO_SUPER_ROOT:72 msg = "No super root in the last segment";73 break;74 default:75 nilfs_err(sb, "unrecognized segment error %d", err);76 return -EINVAL;77 }78 nilfs_warn(sb, "invalid segment: %s", msg);79 return -EINVAL;80}81 82/**83 * nilfs_compute_checksum - compute checksum of blocks continuously84 * @nilfs: nilfs object85 * @bhs: buffer head of start block86 * @sum: place to store result87 * @offset: offset bytes in the first block88 * @check_bytes: number of bytes to be checked89 * @start: DBN of start block90 * @nblock: number of blocks to be checked91 */92static int nilfs_compute_checksum(struct the_nilfs *nilfs,93 struct buffer_head *bhs, u32 *sum,94 unsigned long offset, u64 check_bytes,95 sector_t start, unsigned long nblock)96{97 unsigned int blocksize = nilfs->ns_blocksize;98 unsigned long size;99 u32 crc;100 101 BUG_ON(offset >= blocksize);102 check_bytes -= offset;103 size = min_t(u64, check_bytes, blocksize - offset);104 crc = crc32_le(nilfs->ns_crc_seed,105 (unsigned char *)bhs->b_data + offset, size);106 if (--nblock > 0) {107 do {108 struct buffer_head *bh;109 110 bh = __bread(nilfs->ns_bdev, ++start, blocksize);111 if (!bh)112 return -EIO;113 check_bytes -= size;114 size = min_t(u64, check_bytes, blocksize);115 crc = crc32_le(crc, bh->b_data, size);116 brelse(bh);117 } while (--nblock > 0);118 }119 *sum = crc;120 return 0;121}122 123/**124 * nilfs_read_super_root_block - read super root block125 * @nilfs: nilfs object126 * @sr_block: disk block number of the super root block127 * @pbh: address of a buffer_head pointer to return super root buffer128 * @check: CRC check flag129 */130int nilfs_read_super_root_block(struct the_nilfs *nilfs, sector_t sr_block,131 struct buffer_head **pbh, int check)132{133 struct buffer_head *bh_sr;134 struct nilfs_super_root *sr;135 u32 crc;136 int ret;137 138 *pbh = NULL;139 bh_sr = __bread(nilfs->ns_bdev, sr_block, nilfs->ns_blocksize);140 if (unlikely(!bh_sr)) {141 ret = NILFS_SEG_FAIL_IO;142 goto failed;143 }144 145 sr = (struct nilfs_super_root *)bh_sr->b_data;146 if (check) {147 unsigned int bytes = le16_to_cpu(sr->sr_bytes);148 149 if (bytes == 0 || bytes > nilfs->ns_blocksize) {150 ret = NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT;151 goto failed_bh;152 }153 if (nilfs_compute_checksum(154 nilfs, bh_sr, &crc, sizeof(sr->sr_sum), bytes,155 sr_block, 1)) {156 ret = NILFS_SEG_FAIL_IO;157 goto failed_bh;158 }159 if (crc != le32_to_cpu(sr->sr_sum)) {160 ret = NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT;161 goto failed_bh;162 }163 }164 *pbh = bh_sr;165 return 0;166 167 failed_bh:168 brelse(bh_sr);169 170 failed:171 return nilfs_warn_segment_error(nilfs->ns_sb, ret);172}173 174/**175 * nilfs_read_log_header - read summary header of the specified log176 * @nilfs: nilfs object177 * @start_blocknr: start block number of the log178 * @sum: pointer to return segment summary structure179 */180static struct buffer_head *181nilfs_read_log_header(struct the_nilfs *nilfs, sector_t start_blocknr,182 struct nilfs_segment_summary **sum)183{184 struct buffer_head *bh_sum;185 186 bh_sum = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize);187 if (bh_sum)188 *sum = (struct nilfs_segment_summary *)bh_sum->b_data;189 return bh_sum;190}191 192/**193 * nilfs_validate_log - verify consistency of log194 * @nilfs: nilfs object195 * @seg_seq: sequence number of segment196 * @bh_sum: buffer head of summary block197 * @sum: segment summary struct198 */199static int nilfs_validate_log(struct the_nilfs *nilfs, u64 seg_seq,200 struct buffer_head *bh_sum,201 struct nilfs_segment_summary *sum)202{203 unsigned long nblock;204 u32 crc;205 int ret;206 207 ret = NILFS_SEG_FAIL_MAGIC;208 if (le32_to_cpu(sum->ss_magic) != NILFS_SEGSUM_MAGIC)209 goto out;210 211 ret = NILFS_SEG_FAIL_SEQ;212 if (le64_to_cpu(sum->ss_seq) != seg_seq)213 goto out;214 215 nblock = le32_to_cpu(sum->ss_nblocks);216 ret = NILFS_SEG_FAIL_CONSISTENCY;217 if (unlikely(nblock == 0 || nblock > nilfs->ns_blocks_per_segment))218 /* This limits the number of blocks read in the CRC check */219 goto out;220 221 ret = NILFS_SEG_FAIL_IO;222 if (nilfs_compute_checksum(nilfs, bh_sum, &crc, sizeof(sum->ss_datasum),223 ((u64)nblock << nilfs->ns_blocksize_bits),224 bh_sum->b_blocknr, nblock))225 goto out;226 227 ret = NILFS_SEG_FAIL_CHECKSUM_FULL;228 if (crc != le32_to_cpu(sum->ss_datasum))229 goto out;230 ret = 0;231out:232 return ret;233}234 235/**236 * nilfs_read_summary_info - read an item on summary blocks of a log237 * @nilfs: nilfs object238 * @pbh: the current buffer head on summary blocks [in, out]239 * @offset: the current byte offset on summary blocks [in, out]240 * @bytes: byte size of the item to be read241 */242static void *nilfs_read_summary_info(struct the_nilfs *nilfs,243 struct buffer_head **pbh,244 unsigned int *offset, unsigned int bytes)245{246 void *ptr;247 sector_t blocknr;248 249 BUG_ON((*pbh)->b_size < *offset);250 if (bytes > (*pbh)->b_size - *offset) {251 blocknr = (*pbh)->b_blocknr;252 brelse(*pbh);253 *pbh = __bread(nilfs->ns_bdev, blocknr + 1,254 nilfs->ns_blocksize);255 if (unlikely(!*pbh))256 return NULL;257 *offset = 0;258 }259 ptr = (*pbh)->b_data + *offset;260 *offset += bytes;261 return ptr;262}263 264/**265 * nilfs_skip_summary_info - skip items on summary blocks of a log266 * @nilfs: nilfs object267 * @pbh: the current buffer head on summary blocks [in, out]268 * @offset: the current byte offset on summary blocks [in, out]269 * @bytes: byte size of the item to be skipped270 * @count: number of items to be skipped271 */272static void nilfs_skip_summary_info(struct the_nilfs *nilfs,273 struct buffer_head **pbh,274 unsigned int *offset, unsigned int bytes,275 unsigned long count)276{277 unsigned int rest_item_in_current_block278 = ((*pbh)->b_size - *offset) / bytes;279 280 if (count <= rest_item_in_current_block) {281 *offset += bytes * count;282 } else {283 sector_t blocknr = (*pbh)->b_blocknr;284 unsigned int nitem_per_block = (*pbh)->b_size / bytes;285 unsigned int bcnt;286 287 count -= rest_item_in_current_block;288 bcnt = DIV_ROUND_UP(count, nitem_per_block);289 *offset = bytes * (count - (bcnt - 1) * nitem_per_block);290 291 brelse(*pbh);292 *pbh = __bread(nilfs->ns_bdev, blocknr + bcnt,293 nilfs->ns_blocksize);294 }295}296 297/**298 * nilfs_scan_dsync_log - get block information of a log written for data sync299 * @nilfs: nilfs object300 * @start_blocknr: start block number of the log301 * @sum: log summary information302 * @head: list head to add nilfs_recovery_block struct303 */304static int nilfs_scan_dsync_log(struct the_nilfs *nilfs, sector_t start_blocknr,305 struct nilfs_segment_summary *sum,306 struct list_head *head)307{308 struct buffer_head *bh;309 unsigned int offset;310 u32 nfinfo, sumbytes;311 sector_t blocknr;312 ino_t ino;313 int err = -EIO;314 315 nfinfo = le32_to_cpu(sum->ss_nfinfo);316 if (!nfinfo)317 return 0;318 319 sumbytes = le32_to_cpu(sum->ss_sumbytes);320 blocknr = start_blocknr + DIV_ROUND_UP(sumbytes, nilfs->ns_blocksize);321 bh = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize);322 if (unlikely(!bh))323 goto out;324 325 offset = le16_to_cpu(sum->ss_bytes);326 for (;;) {327 unsigned long nblocks, ndatablk, nnodeblk;328 struct nilfs_finfo *finfo;329 330 finfo = nilfs_read_summary_info(nilfs, &bh, &offset,331 sizeof(*finfo));332 if (unlikely(!finfo))333 goto out;334 335 ino = le64_to_cpu(finfo->fi_ino);336 nblocks = le32_to_cpu(finfo->fi_nblocks);337 ndatablk = le32_to_cpu(finfo->fi_ndatablk);338 nnodeblk = nblocks - ndatablk;339 340 while (ndatablk-- > 0) {341 struct nilfs_recovery_block *rb;342 struct nilfs_binfo_v *binfo;343 344 binfo = nilfs_read_summary_info(nilfs, &bh, &offset,345 sizeof(*binfo));346 if (unlikely(!binfo))347 goto out;348 349 rb = kmalloc(sizeof(*rb), GFP_NOFS);350 if (unlikely(!rb)) {351 err = -ENOMEM;352 goto out;353 }354 rb->ino = ino;355 rb->blocknr = blocknr++;356 rb->vblocknr = le64_to_cpu(binfo->bi_vblocknr);357 rb->blkoff = le64_to_cpu(binfo->bi_blkoff);358 /* INIT_LIST_HEAD(&rb->list); */359 list_add_tail(&rb->list, head);360 }361 if (--nfinfo == 0)362 break;363 blocknr += nnodeblk; /* always 0 for data sync logs */364 nilfs_skip_summary_info(nilfs, &bh, &offset, sizeof(__le64),365 nnodeblk);366 if (unlikely(!bh))367 goto out;368 }369 err = 0;370 out:371 brelse(bh); /* brelse(NULL) is just ignored */372 return err;373}374 375static void dispose_recovery_list(struct list_head *head)376{377 while (!list_empty(head)) {378 struct nilfs_recovery_block *rb;379 380 rb = list_first_entry(head, struct nilfs_recovery_block, list);381 list_del(&rb->list);382 kfree(rb);383 }384}385 386struct nilfs_segment_entry {387 struct list_head list;388 __u64 segnum;389};390 391static int nilfs_segment_list_add(struct list_head *head, __u64 segnum)392{393 struct nilfs_segment_entry *ent = kmalloc(sizeof(*ent), GFP_NOFS);394 395 if (unlikely(!ent))396 return -ENOMEM;397 398 ent->segnum = segnum;399 INIT_LIST_HEAD(&ent->list);400 list_add_tail(&ent->list, head);401 return 0;402}403 404void nilfs_dispose_segment_list(struct list_head *head)405{406 while (!list_empty(head)) {407 struct nilfs_segment_entry *ent;408 409 ent = list_first_entry(head, struct nilfs_segment_entry, list);410 list_del(&ent->list);411 kfree(ent);412 }413}414 415static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,416 struct super_block *sb,417 struct nilfs_recovery_info *ri)418{419 struct list_head *head = &ri->ri_used_segments;420 struct nilfs_segment_entry *ent, *n;421 struct inode *sufile = nilfs->ns_sufile;422 __u64 segnum[4];423 int err;424 int i;425 426 segnum[0] = nilfs->ns_segnum;427 segnum[1] = nilfs->ns_nextnum;428 segnum[2] = ri->ri_segnum;429 segnum[3] = ri->ri_nextnum;430 431 /*432 * Releasing the next segment of the latest super root.433 * The next segment is invalidated by this recovery.434 */435 err = nilfs_sufile_free(sufile, segnum[1]);436 if (unlikely(err)) {437 if (err == -ENOENT) {438 nilfs_err(sb,439 "checkpoint log inconsistency at block %llu (segment %llu): next segment %llu is unallocated",440 (unsigned long long)nilfs->ns_last_pseg,441 (unsigned long long)nilfs->ns_segnum,442 (unsigned long long)segnum[1]);443 err = -EINVAL;444 }445 goto failed;446 }447 448 for (i = 1; i < 4; i++) {449 err = nilfs_segment_list_add(head, segnum[i]);450 if (unlikely(err))451 goto failed;452 }453 454 /*455 * Collecting segments written after the latest super root.456 * These are marked dirty to avoid being reallocated in the next write.457 */458 list_for_each_entry_safe(ent, n, head, list) {459 if (ent->segnum != segnum[0]) {460 err = nilfs_sufile_scrap(sufile, ent->segnum);461 if (unlikely(err))462 goto failed;463 }464 list_del(&ent->list);465 kfree(ent);466 }467 468 /* Allocate new segments for recovery */469 err = nilfs_sufile_alloc(sufile, &segnum[0]);470 if (unlikely(err))471 goto failed;472 473 nilfs->ns_pseg_offset = 0;474 nilfs->ns_seg_seq = ri->ri_seq + 2;475 nilfs->ns_nextnum = nilfs->ns_segnum = segnum[0];476 477 failed:478 /* No need to recover sufile because it will be destroyed on error */479 return err;480}481 482static int nilfs_recovery_copy_block(struct the_nilfs *nilfs,483 struct nilfs_recovery_block *rb,484 loff_t pos, struct page *page)485{486 struct buffer_head *bh_org;487 size_t from = pos & ~PAGE_MASK;488 void *kaddr;489 490 bh_org = __bread(nilfs->ns_bdev, rb->blocknr, nilfs->ns_blocksize);491 if (unlikely(!bh_org))492 return -EIO;493 494 kaddr = kmap_local_page(page);495 memcpy(kaddr + from, bh_org->b_data, bh_org->b_size);496 kunmap_local(kaddr);497 brelse(bh_org);498 return 0;499}500 501static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs,502 struct super_block *sb,503 struct nilfs_root *root,504 struct list_head *head,505 unsigned long *nr_salvaged_blocks)506{507 struct inode *inode;508 struct nilfs_recovery_block *rb, *n;509 unsigned int blocksize = nilfs->ns_blocksize;510 struct folio *folio;511 loff_t pos;512 int err = 0, err2 = 0;513 514 list_for_each_entry_safe(rb, n, head, list) {515 inode = nilfs_iget(sb, root, rb->ino);516 if (IS_ERR(inode)) {517 err = PTR_ERR(inode);518 inode = NULL;519 goto failed_inode;520 }521 522 pos = rb->blkoff << inode->i_blkbits;523 err = block_write_begin(inode->i_mapping, pos, blocksize,524 &folio, nilfs_get_block);525 if (unlikely(err)) {526 loff_t isize = inode->i_size;527 528 if (pos + blocksize > isize)529 nilfs_write_failed(inode->i_mapping,530 pos + blocksize);531 goto failed_inode;532 }533 534 err = nilfs_recovery_copy_block(nilfs, rb, pos, &folio->page);535 if (unlikely(err))536 goto failed_page;537 538 err = nilfs_set_file_dirty(inode, 1);539 if (unlikely(err))540 goto failed_page;541 542 block_write_end(NULL, inode->i_mapping, pos, blocksize,543 blocksize, folio, NULL);544 545 folio_unlock(folio);546 folio_put(folio);547 548 (*nr_salvaged_blocks)++;549 goto next;550 551 failed_page:552 folio_unlock(folio);553 folio_put(folio);554 555 failed_inode:556 nilfs_warn(sb,557 "error %d recovering data block (ino=%lu, block-offset=%llu)",558 err, (unsigned long)rb->ino,559 (unsigned long long)rb->blkoff);560 if (!err2)561 err2 = err;562 next:563 iput(inode); /* iput(NULL) is just ignored */564 list_del_init(&rb->list);565 kfree(rb);566 }567 return err2;568}569 570/**571 * nilfs_do_roll_forward - salvage logical segments newer than the latest572 * checkpoint573 * @nilfs: nilfs object574 * @sb: super block instance575 * @root: NILFS root instance576 * @ri: pointer to a nilfs_recovery_info577 */578static int nilfs_do_roll_forward(struct the_nilfs *nilfs,579 struct super_block *sb,580 struct nilfs_root *root,581 struct nilfs_recovery_info *ri)582{583 struct buffer_head *bh_sum = NULL;584 struct nilfs_segment_summary *sum = NULL;585 sector_t pseg_start;586 sector_t seg_start, seg_end; /* Starting/ending DBN of full segment */587 unsigned long nsalvaged_blocks = 0;588 unsigned int flags;589 u64 seg_seq;590 __u64 segnum, nextnum = 0;591 int empty_seg = 0;592 int err = 0, ret;593 LIST_HEAD(dsync_blocks); /* list of data blocks to be recovered */594 enum {595 RF_INIT_ST,596 RF_DSYNC_ST, /* scanning data-sync segments */597 };598 int state = RF_INIT_ST;599 600 pseg_start = ri->ri_lsegs_start;601 seg_seq = ri->ri_lsegs_start_seq;602 segnum = nilfs_get_segnum_of_block(nilfs, pseg_start);603 nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);604 605 while (segnum != ri->ri_segnum || pseg_start <= ri->ri_pseg_start) {606 brelse(bh_sum);607 bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);608 if (!bh_sum) {609 err = -EIO;610 goto failed;611 }612 613 ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);614 if (ret) {615 if (ret == NILFS_SEG_FAIL_IO) {616 err = -EIO;617 goto failed;618 }619 goto strayed;620 }621 622 flags = le16_to_cpu(sum->ss_flags);623 if (flags & NILFS_SS_SR)624 goto confused;625 626 /* Found a valid partial segment; do recovery actions */627 nextnum = nilfs_get_segnum_of_block(nilfs,628 le64_to_cpu(sum->ss_next));629 empty_seg = 0;630 nilfs->ns_ctime = le64_to_cpu(sum->ss_create);631 if (!(flags & NILFS_SS_GC))632 nilfs->ns_nongc_ctime = nilfs->ns_ctime;633 634 switch (state) {635 case RF_INIT_ST:636 if (!(flags & NILFS_SS_LOGBGN) ||637 !(flags & NILFS_SS_SYNDT))638 goto try_next_pseg;639 state = RF_DSYNC_ST;640 fallthrough;641 case RF_DSYNC_ST:642 if (!(flags & NILFS_SS_SYNDT))643 goto confused;644 645 err = nilfs_scan_dsync_log(nilfs, pseg_start, sum,646 &dsync_blocks);647 if (unlikely(err))648 goto failed;649 if (flags & NILFS_SS_LOGEND) {650 err = nilfs_recover_dsync_blocks(651 nilfs, sb, root, &dsync_blocks,652 &nsalvaged_blocks);653 if (unlikely(err))654 goto failed;655 state = RF_INIT_ST;656 }657 break; /* Fall through to try_next_pseg */658 }659 660 try_next_pseg:661 if (pseg_start == ri->ri_lsegs_end)662 break;663 pseg_start += le32_to_cpu(sum->ss_nblocks);664 if (pseg_start < seg_end)665 continue;666 goto feed_segment;667 668 strayed:669 if (pseg_start == ri->ri_lsegs_end)670 break;671 672 feed_segment:673 /* Looking to the next full segment */674 if (empty_seg++)675 break;676 seg_seq++;677 segnum = nextnum;678 nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);679 pseg_start = seg_start;680 }681 682 if (nsalvaged_blocks) {683 nilfs_info(sb, "salvaged %lu blocks", nsalvaged_blocks);684 ri->ri_need_recovery = NILFS_RECOVERY_ROLLFORWARD_DONE;685 }686 out:687 brelse(bh_sum);688 dispose_recovery_list(&dsync_blocks);689 return err;690 691 confused:692 err = -EINVAL;693 failed:694 nilfs_err(sb,695 "error %d roll-forwarding partial segment at blocknr = %llu",696 err, (unsigned long long)pseg_start);697 goto out;698}699 700static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,701 struct nilfs_recovery_info *ri)702{703 struct buffer_head *bh;704 int err;705 706 if (nilfs_get_segnum_of_block(nilfs, ri->ri_lsegs_start) !=707 nilfs_get_segnum_of_block(nilfs, ri->ri_super_root))708 return;709 710 bh = __getblk(nilfs->ns_bdev, ri->ri_lsegs_start, nilfs->ns_blocksize);711 if (WARN_ON(!bh))712 return; /* should never happen */713 714 lock_buffer(bh);715 memset(bh->b_data, 0, bh->b_size);716 set_buffer_uptodate(bh);717 set_buffer_dirty(bh);718 unlock_buffer(bh);719 720 err = sync_dirty_buffer(bh);721 if (unlikely(err))722 nilfs_warn(nilfs->ns_sb,723 "buffer sync write failed during post-cleaning of recovery.");724 brelse(bh);725}726 727/**728 * nilfs_abort_roll_forward - cleaning up after a failed rollforward recovery729 * @nilfs: nilfs object730 */731static void nilfs_abort_roll_forward(struct the_nilfs *nilfs)732{733 struct nilfs_inode_info *ii, *n;734 LIST_HEAD(head);735 736 /* Abandon inodes that have read recovery data */737 spin_lock(&nilfs->ns_inode_lock);738 list_splice_init(&nilfs->ns_dirty_files, &head);739 spin_unlock(&nilfs->ns_inode_lock);740 if (list_empty(&head))741 return;742 743 set_nilfs_purging(nilfs);744 list_for_each_entry_safe(ii, n, &head, i_dirty) {745 spin_lock(&nilfs->ns_inode_lock);746 list_del_init(&ii->i_dirty);747 spin_unlock(&nilfs->ns_inode_lock);748 749 iput(&ii->vfs_inode);750 }751 clear_nilfs_purging(nilfs);752}753 754/**755 * nilfs_salvage_orphan_logs - salvage logs written after the latest checkpoint756 * @nilfs: nilfs object757 * @sb: super block instance758 * @ri: pointer to a nilfs_recovery_info struct to store search results.759 *760 * Return Value: On success, 0 is returned. On error, one of the following761 * negative error code is returned.762 *763 * %-EINVAL - Inconsistent filesystem state.764 *765 * %-EIO - I/O error766 *767 * %-ENOSPC - No space left on device (only in a panic state).768 *769 * %-ERESTARTSYS - Interrupted.770 *771 * %-ENOMEM - Insufficient memory available.772 */773int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,774 struct super_block *sb,775 struct nilfs_recovery_info *ri)776{777 struct nilfs_root *root;778 int err;779 780 if (ri->ri_lsegs_start == 0 || ri->ri_lsegs_end == 0)781 return 0;782 783 err = nilfs_attach_checkpoint(sb, ri->ri_cno, true, &root);784 if (unlikely(err)) {785 nilfs_err(sb, "error %d loading the latest checkpoint", err);786 return err;787 }788 789 err = nilfs_do_roll_forward(nilfs, sb, root, ri);790 if (unlikely(err))791 goto failed;792 793 if (ri->ri_need_recovery == NILFS_RECOVERY_ROLLFORWARD_DONE) {794 err = nilfs_prepare_segment_for_recovery(nilfs, sb, ri);795 if (unlikely(err)) {796 nilfs_err(sb, "error %d preparing segment for recovery",797 err);798 goto failed;799 }800 801 err = nilfs_attach_log_writer(sb, root);802 if (unlikely(err))803 goto failed;804 805 set_nilfs_discontinued(nilfs);806 err = nilfs_construct_segment(sb);807 nilfs_detach_log_writer(sb);808 809 if (unlikely(err)) {810 nilfs_err(sb, "error %d writing segment for recovery",811 err);812 goto put_root;813 }814 815 nilfs_finish_roll_forward(nilfs, ri);816 }817 818put_root:819 nilfs_put_root(root);820 return err;821 822failed:823 nilfs_abort_roll_forward(nilfs);824 goto put_root;825}826 827/**828 * nilfs_search_super_root - search the latest valid super root829 * @nilfs: the_nilfs830 * @ri: pointer to a nilfs_recovery_info struct to store search results.831 *832 * nilfs_search_super_root() looks for the latest super-root from a partial833 * segment pointed by the superblock. It sets up struct the_nilfs through834 * this search. It fills nilfs_recovery_info (ri) required for recovery.835 *836 * Return Value: On success, 0 is returned. On error, one of the following837 * negative error code is returned.838 *839 * %-EINVAL - No valid segment found840 *841 * %-EIO - I/O error842 *843 * %-ENOMEM - Insufficient memory available.844 */845int nilfs_search_super_root(struct the_nilfs *nilfs,846 struct nilfs_recovery_info *ri)847{848 struct buffer_head *bh_sum = NULL;849 struct nilfs_segment_summary *sum = NULL;850 sector_t pseg_start, pseg_end, sr_pseg_start = 0;851 sector_t seg_start, seg_end; /* range of full segment (block number) */852 sector_t b, end;853 unsigned long nblocks;854 unsigned int flags;855 u64 seg_seq;856 __u64 segnum, nextnum = 0;857 __u64 cno;858 LIST_HEAD(segments);859 int empty_seg = 0, scan_newer = 0;860 int ret;861 862 pseg_start = nilfs->ns_last_pseg;863 seg_seq = nilfs->ns_last_seq;864 cno = nilfs->ns_last_cno;865 segnum = nilfs_get_segnum_of_block(nilfs, pseg_start);866 867 /* Calculate range of segment */868 nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);869 870 /* Read ahead segment */871 b = seg_start;872 while (b <= seg_end)873 __breadahead(nilfs->ns_bdev, b++, nilfs->ns_blocksize);874 875 for (;;) {876 brelse(bh_sum);877 ret = NILFS_SEG_FAIL_IO;878 bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);879 if (!bh_sum)880 goto failed;881 882 ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);883 if (ret) {884 if (ret == NILFS_SEG_FAIL_IO)885 goto failed;886 goto strayed;887 }888 889 nblocks = le32_to_cpu(sum->ss_nblocks);890 pseg_end = pseg_start + nblocks - 1;891 if (unlikely(pseg_end > seg_end)) {892 ret = NILFS_SEG_FAIL_CONSISTENCY;893 goto strayed;894 }895 896 /* A valid partial segment */897 ri->ri_pseg_start = pseg_start;898 ri->ri_seq = seg_seq;899 ri->ri_segnum = segnum;900 nextnum = nilfs_get_segnum_of_block(nilfs,901 le64_to_cpu(sum->ss_next));902 ri->ri_nextnum = nextnum;903 empty_seg = 0;904 905 flags = le16_to_cpu(sum->ss_flags);906 if (!(flags & NILFS_SS_SR) && !scan_newer) {907 /*908 * This will never happen because a superblock909 * (last_segment) always points to a pseg with910 * a super root.911 */912 ret = NILFS_SEG_FAIL_CONSISTENCY;913 goto failed;914 }915 916 if (pseg_start == seg_start) {917 nilfs_get_segment_range(nilfs, nextnum, &b, &end);918 while (b <= end)919 __breadahead(nilfs->ns_bdev, b++,920 nilfs->ns_blocksize);921 }922 if (!(flags & NILFS_SS_SR)) {923 if (!ri->ri_lsegs_start && (flags & NILFS_SS_LOGBGN)) {924 ri->ri_lsegs_start = pseg_start;925 ri->ri_lsegs_start_seq = seg_seq;926 }927 if (flags & NILFS_SS_LOGEND)928 ri->ri_lsegs_end = pseg_start;929 goto try_next_pseg;930 }931 932 /* A valid super root was found. */933 ri->ri_cno = cno++;934 ri->ri_super_root = pseg_end;935 ri->ri_lsegs_start = ri->ri_lsegs_end = 0;936 937 nilfs_dispose_segment_list(&segments);938 sr_pseg_start = pseg_start;939 nilfs->ns_pseg_offset = pseg_start + nblocks - seg_start;940 nilfs->ns_seg_seq = seg_seq;941 nilfs->ns_segnum = segnum;942 nilfs->ns_cno = cno; /* nilfs->ns_cno = ri->ri_cno + 1 */943 nilfs->ns_ctime = le64_to_cpu(sum->ss_create);944 nilfs->ns_nextnum = nextnum;945 946 if (scan_newer)947 ri->ri_need_recovery = NILFS_RECOVERY_SR_UPDATED;948 else {949 if (nilfs->ns_mount_state & NILFS_VALID_FS)950 goto super_root_found;951 scan_newer = 1;952 }953 954 try_next_pseg:955 /* Standing on a course, or met an inconsistent state */956 pseg_start += nblocks;957 if (pseg_start < seg_end)958 continue;959 goto feed_segment;960 961 strayed:962 /* Off the trail */963 if (!scan_newer)964 /*965 * This can happen if a checkpoint was written without966 * barriers, or as a result of an I/O failure.967 */968 goto failed;969 970 feed_segment:971 /* Looking to the next full segment */972 if (empty_seg++)973 goto super_root_found; /* found a valid super root */974 975 ret = nilfs_segment_list_add(&segments, segnum);976 if (unlikely(ret))977 goto failed;978 979 seg_seq++;980 segnum = nextnum;981 nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);982 pseg_start = seg_start;983 }984 985 super_root_found:986 /* Updating pointers relating to the latest checkpoint */987 brelse(bh_sum);988 list_splice_tail(&segments, &ri->ri_used_segments);989 nilfs->ns_last_pseg = sr_pseg_start;990 nilfs->ns_last_seq = nilfs->ns_seg_seq;991 nilfs->ns_last_cno = ri->ri_cno;992 return 0;993 994 failed:995 brelse(bh_sum);996 nilfs_dispose_segment_list(&segments);997 return ret < 0 ? ret : nilfs_warn_segment_error(nilfs->ns_sb, ret);998}999