26 #include <linux/slab.h>
59 static int nilfs_warn_segment_error(
int err)
64 "NILFS warning: I/O error on loading last segment\n");
68 "NILFS warning: Segment magic number invalid\n");
72 "NILFS warning: Sequence number mismatch\n");
76 "NILFS warning: Checksum error in super root\n");
80 "NILFS warning: Checksum error in segment payload\n");
84 "NILFS warning: Inconsistent segment\n");
88 "NILFS warning: No super root in the last segment\n");
104 static int nilfs_compute_checksum(
struct the_nilfs *nilfs,
105 struct buffer_head *bhs,
u32 *
sum,
113 BUG_ON(offset >= blocksize);
115 size =
min_t(
u64, check_bytes, blocksize - offset);
117 (
unsigned char *)bhs->b_data + offset, size);
120 struct buffer_head *bh;
126 size =
min_t(
u64, check_bytes, blocksize);
127 crc =
crc32_le(crc, bh->b_data, size);
129 }
while (--nblock > 0);
143 struct buffer_head **pbh,
int check)
145 struct buffer_head *bh_sr;
165 if (nilfs_compute_checksum(
166 nilfs, bh_sr, &crc,
sizeof(sr->
sr_sum), bytes,
183 return nilfs_warn_segment_error(ret);
192 static struct buffer_head *
196 struct buffer_head *bh_sum;
211 static int nilfs_validate_log(
struct the_nilfs *nilfs,
u64 seg_seq,
212 struct buffer_head *bh_sum,
215 unsigned long nblock;
234 if (nilfs_compute_checksum(nilfs, bh_sum, &crc,
sizeof(sum->
ss_datasum),
236 bh_sum->b_blocknr, nblock))
254 static void *nilfs_read_summary_info(
struct the_nilfs *nilfs,
255 struct buffer_head **pbh,
256 unsigned int *offset,
unsigned int bytes)
261 BUG_ON((*pbh)->b_size < *offset);
262 if (bytes > (*pbh)->b_size - *offset) {
263 blocknr = (*pbh)->b_blocknr;
271 ptr = (*pbh)->b_data + *
offset;
284 static void nilfs_skip_summary_info(
struct the_nilfs *nilfs,
285 struct buffer_head **pbh,
286 unsigned int *offset,
unsigned int bytes,
289 unsigned int rest_item_in_current_block
290 = ((*pbh)->b_size - *
offset) / bytes;
292 if (count <= rest_item_in_current_block) {
293 *offset += bytes *
count;
295 sector_t blocknr = (*pbh)->b_blocknr;
296 unsigned int nitem_per_block = (*pbh)->b_size /
bytes;
299 count -= rest_item_in_current_block;
301 *offset = bytes * (count - (bcnt - 1) * nitem_per_block);
320 struct buffer_head *bh;
322 u32 nfinfo, sumbytes;
339 unsigned long nblocks, ndatablk, nnodeblk;
342 finfo = nilfs_read_summary_info(nilfs, &bh, &offset,
350 nnodeblk = nblocks - ndatablk;
352 while (ndatablk-- > 0) {
356 binfo = nilfs_read_summary_info(nilfs, &bh, &offset,
376 nilfs_skip_summary_info(nilfs, &bh, &offset,
sizeof(
__le64),
387 static void dispose_recovery_list(
struct list_head *head)
389 while (!list_empty(head)) {
403 static int nilfs_segment_list_add(
struct list_head *head,
__u64 segnum)
411 INIT_LIST_HEAD(&ent->
list);
418 while (!list_empty(head)) {
427 static int nilfs_prepare_segment_for_recovery(
struct the_nilfs *nilfs,
447 err = nilfs_sufile_free(sufile, segnum[1]);
451 for (i = 1; i < 4; i++) {
452 err = nilfs_segment_list_add(head, segnum[i]);
462 if (ent->
segnum != segnum[0]) {
463 err = nilfs_sufile_scrap(sufile, ent->
segnum);
485 static int nilfs_recovery_copy_block(
struct the_nilfs *nilfs,
489 struct buffer_head *bh_org;
497 memcpy(kaddr + bh_offset(bh_org), bh_org->b_data, bh_org->b_size);
503 static int nilfs_recover_dsync_blocks(
struct the_nilfs *nilfs,
507 unsigned long *nr_salvaged_blocks)
514 int err = 0, err2 = 0;
519 err = PTR_ERR(inode);
528 loff_t isize = inode->
i_size;
529 if (pos + blocksize > isize)
534 err = nilfs_recovery_copy_block(nilfs, rb, page);
543 blocksize, page,
NULL);
548 (*nr_salvaged_blocks)++;
557 "NILFS warning: error recovering data block "
558 "(err=%d, ino=%lu, block-offset=%llu)\n",
559 err, (
unsigned long)rb->
ino,
560 (
unsigned long long)rb->
blkoff);
565 list_del_init(&rb->
list);
578 static int nilfs_do_roll_forward(
struct the_nilfs *nilfs,
583 struct buffer_head *bh_sum =
NULL;
587 unsigned long nsalvaged_blocks = 0;
590 __u64 segnum, nextnum = 0;
598 int state = RF_INIT_ST;
602 segnum = nilfs_get_segnum_of_block(nilfs, pseg_start);
603 nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);
605 while (segnum != ri->
ri_segnum || pseg_start <= ri->ri_pseg_start) {
607 bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);
613 ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);
627 nextnum = nilfs_get_segnum_of_block(nilfs,
642 if (!(flags & NILFS_SS_SYNDT))
645 err = nilfs_scan_dsync_log(nilfs, pseg_start, sum,
650 err = nilfs_recover_dsync_blocks(
651 nilfs, sb, root, &dsync_blocks,
664 if (pseg_start < seg_end)
678 nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);
679 pseg_start = seg_start;
682 if (nsalvaged_blocks) {
684 sb->
s_id, nsalvaged_blocks);
689 dispose_recovery_list(&dsync_blocks);
696 "NILFS (device %s): Error roll-forwarding "
697 "(err=%d, pseg block=%llu). ",
698 sb->
s_id, err, (
unsigned long long)pseg_start);
702 static void nilfs_finish_roll_forward(
struct the_nilfs *nilfs,
705 struct buffer_head *bh;
714 memset(bh->b_data, 0, bh->b_size);
715 set_buffer_dirty(bh);
719 "NILFS warning: buffer sync write failed during "
720 "post-cleaning of recovery.\n");
756 "NILFS: error loading the latest checkpoint.\n");
760 err = nilfs_do_roll_forward(nilfs, sb, root, ri);
765 err = nilfs_prepare_segment_for_recovery(nilfs, sb, ri);
776 set_nilfs_discontinued(nilfs);
786 nilfs_finish_roll_forward(nilfs, ri);
815 struct buffer_head *bh_sum =
NULL;
817 sector_t pseg_start, pseg_end, sr_pseg_start = 0;
820 unsigned long nblocks;
823 __u64 segnum, nextnum = 0;
826 int empty_seg = 0, scan_newer = 0;
832 segnum = nilfs_get_segnum_of_block(nilfs, pseg_start);
835 nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);
845 bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);
849 ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);
857 pseg_end = pseg_start + nblocks - 1;
867 nextnum = nilfs_get_segnum_of_block(nilfs,
873 if (!(flags & NILFS_SS_SR) && !scan_newer) {
881 if (pseg_start == seg_start) {
882 nilfs_get_segment_range(nilfs, nextnum, &b, &end);
887 if (!(flags & NILFS_SS_SR)) {
892 if (flags & NILFS_SS_LOGEND)
903 sr_pseg_start = pseg_start;
915 goto super_root_found;
921 pseg_start += nblocks;
922 if (pseg_start < seg_end)
938 goto super_root_found;
940 ret = nilfs_segment_list_add(&segments, segnum);
946 nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);
947 pseg_start = seg_start;
962 return (ret < 0) ? ret : nilfs_warn_segment_error(ret);