|
@@ -202,58 +202,63 @@ int nilfs_read_super_root_block(struct the_nilfs *nilfs, sector_t sr_block,
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * load_segment_summary - read segment summary of the specified partial segment
|
|
|
|
|
|
+ * nilfs_read_log_header - read summary header of the specified log
|
|
* @nilfs: nilfs object
|
|
* @nilfs: nilfs object
|
|
- * @pseg_start: start disk block number of partial segment
|
|
|
|
- * @seg_seq: sequence number requested
|
|
|
|
- * @ssi: pointer to nilfs_segsum_info struct to store information
|
|
|
|
|
|
+ * @start_blocknr: start block number of the log
|
|
|
|
+ * @sum: pointer to return segment summary structure
|
|
*/
|
|
*/
|
|
-static int
|
|
|
|
-load_segment_summary(struct the_nilfs *nilfs, sector_t pseg_start,
|
|
|
|
- u64 seg_seq, struct nilfs_segsum_info *ssi)
|
|
|
|
|
|
+static struct buffer_head *
|
|
|
|
+nilfs_read_log_header(struct the_nilfs *nilfs, sector_t start_blocknr,
|
|
|
|
+ struct nilfs_segment_summary **sum)
|
|
{
|
|
{
|
|
struct buffer_head *bh_sum;
|
|
struct buffer_head *bh_sum;
|
|
- struct nilfs_segment_summary *sum;
|
|
|
|
|
|
+
|
|
|
|
+ bh_sum = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize);
|
|
|
|
+ if (bh_sum)
|
|
|
|
+ *sum = (struct nilfs_segment_summary *)bh_sum->b_data;
|
|
|
|
+ return bh_sum;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * nilfs_validate_log - verify consistency of log
|
|
|
|
+ * @nilfs: nilfs object
|
|
|
|
+ * @seg_seq: sequence number of segment
|
|
|
|
+ * @bh_sum: buffer head of summary block
|
|
|
|
+ * @sum: segment summary struct
|
|
|
|
+ */
|
|
|
|
+static int nilfs_validate_log(struct the_nilfs *nilfs, u64 seg_seq,
|
|
|
|
+ struct buffer_head *bh_sum,
|
|
|
|
+ struct nilfs_segment_summary *sum)
|
|
|
|
+{
|
|
unsigned long nblock;
|
|
unsigned long nblock;
|
|
u32 crc;
|
|
u32 crc;
|
|
- int ret = NILFS_SEG_FAIL_IO;
|
|
|
|
|
|
+ int ret;
|
|
|
|
|
|
- bh_sum = __bread(nilfs->ns_bdev, pseg_start, nilfs->ns_blocksize);
|
|
|
|
- if (!bh_sum)
|
|
|
|
|
|
+ ret = NILFS_SEG_FAIL_MAGIC;
|
|
|
|
+ if (le32_to_cpu(sum->ss_magic) != NILFS_SEGSUM_MAGIC)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
- sum = (struct nilfs_segment_summary *)bh_sum->b_data;
|
|
|
|
-
|
|
|
|
- /* Check consistency of segment summary */
|
|
|
|
- if (le32_to_cpu(sum->ss_magic) != NILFS_SEGSUM_MAGIC) {
|
|
|
|
- ret = NILFS_SEG_FAIL_MAGIC;
|
|
|
|
- goto failed;
|
|
|
|
- }
|
|
|
|
- store_segsum_info(ssi, sum, nilfs->ns_blocksize);
|
|
|
|
- if (seg_seq != ssi->seg_seq) {
|
|
|
|
- ret = NILFS_SEG_FAIL_SEQ;
|
|
|
|
- goto failed;
|
|
|
|
- }
|
|
|
|
|
|
+ ret = NILFS_SEG_FAIL_SEQ;
|
|
|
|
+ if (le64_to_cpu(sum->ss_seq) != seg_seq)
|
|
|
|
+ goto out;
|
|
|
|
|
|
- nblock = ssi->nblocks;
|
|
|
|
- if (unlikely(nblock == 0 || nblock > nilfs->ns_blocks_per_segment)) {
|
|
|
|
|
|
+ nblock = le32_to_cpu(sum->ss_nblocks);
|
|
|
|
+ ret = NILFS_SEG_FAIL_CONSISTENCY;
|
|
|
|
+ if (unlikely(nblock == 0 || nblock > nilfs->ns_blocks_per_segment))
|
|
/* This limits the number of blocks read in the CRC check */
|
|
/* This limits the number of blocks read in the CRC check */
|
|
- ret = NILFS_SEG_FAIL_CONSISTENCY;
|
|
|
|
- goto failed;
|
|
|
|
- }
|
|
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ ret = NILFS_SEG_FAIL_IO;
|
|
if (nilfs_compute_checksum(nilfs, bh_sum, &crc, sizeof(sum->ss_datasum),
|
|
if (nilfs_compute_checksum(nilfs, bh_sum, &crc, sizeof(sum->ss_datasum),
|
|
((u64)nblock << nilfs->ns_blocksize_bits),
|
|
((u64)nblock << nilfs->ns_blocksize_bits),
|
|
- pseg_start, nblock)) {
|
|
|
|
- ret = NILFS_SEG_FAIL_IO;
|
|
|
|
- goto failed;
|
|
|
|
- }
|
|
|
|
- if (crc == le32_to_cpu(sum->ss_datasum))
|
|
|
|
- ret = 0;
|
|
|
|
- else
|
|
|
|
- ret = NILFS_SEG_FAIL_CHECKSUM_FULL;
|
|
|
|
- failed:
|
|
|
|
- brelse(bh_sum);
|
|
|
|
- out:
|
|
|
|
|
|
+ bh_sum->b_blocknr, nblock))
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ ret = NILFS_SEG_FAIL_CHECKSUM_FULL;
|
|
|
|
+ if (crc != le32_to_cpu(sum->ss_datasum))
|
|
|
|
+ goto out;
|
|
|
|
+ ret = 0;
|
|
|
|
+out:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -589,6 +594,8 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
|
|
struct nilfs_recovery_info *ri)
|
|
struct nilfs_recovery_info *ri)
|
|
{
|
|
{
|
|
struct nilfs_segsum_info ssi;
|
|
struct nilfs_segsum_info ssi;
|
|
|
|
+ struct buffer_head *bh_sum = NULL;
|
|
|
|
+ struct nilfs_segment_summary *sum;
|
|
sector_t pseg_start;
|
|
sector_t pseg_start;
|
|
sector_t seg_start, seg_end; /* Starting/ending DBN of full segment */
|
|
sector_t seg_start, seg_end; /* Starting/ending DBN of full segment */
|
|
unsigned long nsalvaged_blocks = 0;
|
|
unsigned long nsalvaged_blocks = 0;
|
|
@@ -610,8 +617,14 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
|
|
nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);
|
|
nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);
|
|
|
|
|
|
while (segnum != ri->ri_segnum || pseg_start <= ri->ri_pseg_start) {
|
|
while (segnum != ri->ri_segnum || pseg_start <= ri->ri_pseg_start) {
|
|
|
|
+ brelse(bh_sum);
|
|
|
|
+ bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);
|
|
|
|
+ if (!bh_sum) {
|
|
|
|
+ err = -EIO;
|
|
|
|
+ goto failed;
|
|
|
|
+ }
|
|
|
|
|
|
- ret = load_segment_summary(nilfs, pseg_start, seg_seq, &ssi);
|
|
|
|
|
|
+ ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);
|
|
if (ret) {
|
|
if (ret) {
|
|
if (ret == NILFS_SEG_FAIL_IO) {
|
|
if (ret == NILFS_SEG_FAIL_IO) {
|
|
err = -EIO;
|
|
err = -EIO;
|
|
@@ -619,6 +632,8 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
|
|
}
|
|
}
|
|
goto strayed;
|
|
goto strayed;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ store_segsum_info(&ssi, sum, nilfs->ns_blocksize);
|
|
if (unlikely(NILFS_SEG_HAS_SR(&ssi)))
|
|
if (unlikely(NILFS_SEG_HAS_SR(&ssi)))
|
|
goto confused;
|
|
goto confused;
|
|
|
|
|
|
@@ -682,6 +697,7 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
|
|
ri->ri_need_recovery = NILFS_RECOVERY_ROLLFORWARD_DONE;
|
|
ri->ri_need_recovery = NILFS_RECOVERY_ROLLFORWARD_DONE;
|
|
}
|
|
}
|
|
out:
|
|
out:
|
|
|
|
+ brelse(bh_sum);
|
|
dispose_recovery_list(&dsync_blocks);
|
|
dispose_recovery_list(&dsync_blocks);
|
|
nilfs_detach_writer(nilfs, sbi);
|
|
nilfs_detach_writer(nilfs, sbi);
|
|
return err;
|
|
return err;
|
|
@@ -807,6 +823,8 @@ int nilfs_search_super_root(struct the_nilfs *nilfs,
|
|
struct nilfs_recovery_info *ri)
|
|
struct nilfs_recovery_info *ri)
|
|
{
|
|
{
|
|
struct nilfs_segsum_info ssi;
|
|
struct nilfs_segsum_info ssi;
|
|
|
|
+ struct buffer_head *bh_sum = NULL;
|
|
|
|
+ struct nilfs_segment_summary *sum;
|
|
sector_t pseg_start, pseg_end, sr_pseg_start = 0;
|
|
sector_t pseg_start, pseg_end, sr_pseg_start = 0;
|
|
sector_t seg_start, seg_end; /* range of full segment (block number) */
|
|
sector_t seg_start, seg_end; /* range of full segment (block number) */
|
|
sector_t b, end;
|
|
sector_t b, end;
|
|
@@ -831,12 +849,20 @@ int nilfs_search_super_root(struct the_nilfs *nilfs,
|
|
__breadahead(nilfs->ns_bdev, b++, nilfs->ns_blocksize);
|
|
__breadahead(nilfs->ns_bdev, b++, nilfs->ns_blocksize);
|
|
|
|
|
|
for (;;) {
|
|
for (;;) {
|
|
- ret = load_segment_summary(nilfs, pseg_start, seg_seq, &ssi);
|
|
|
|
|
|
+ brelse(bh_sum);
|
|
|
|
+ ret = NILFS_SEG_FAIL_IO;
|
|
|
|
+ bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);
|
|
|
|
+ if (!bh_sum)
|
|
|
|
+ goto failed;
|
|
|
|
+
|
|
|
|
+ ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);
|
|
if (ret) {
|
|
if (ret) {
|
|
if (ret == NILFS_SEG_FAIL_IO)
|
|
if (ret == NILFS_SEG_FAIL_IO)
|
|
goto failed;
|
|
goto failed;
|
|
goto strayed;
|
|
goto strayed;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ store_segsum_info(&ssi, sum, nilfs->ns_blocksize);
|
|
pseg_end = pseg_start + ssi.nblocks - 1;
|
|
pseg_end = pseg_start + ssi.nblocks - 1;
|
|
if (unlikely(pseg_end > seg_end)) {
|
|
if (unlikely(pseg_end > seg_end)) {
|
|
ret = NILFS_SEG_FAIL_CONSISTENCY;
|
|
ret = NILFS_SEG_FAIL_CONSISTENCY;
|
|
@@ -936,6 +962,7 @@ int nilfs_search_super_root(struct the_nilfs *nilfs,
|
|
|
|
|
|
super_root_found:
|
|
super_root_found:
|
|
/* Updating pointers relating to the latest checkpoint */
|
|
/* Updating pointers relating to the latest checkpoint */
|
|
|
|
+ brelse(bh_sum);
|
|
list_splice_tail(&segments, &ri->ri_used_segments);
|
|
list_splice_tail(&segments, &ri->ri_used_segments);
|
|
nilfs->ns_last_pseg = sr_pseg_start;
|
|
nilfs->ns_last_pseg = sr_pseg_start;
|
|
nilfs->ns_last_seq = nilfs->ns_seg_seq;
|
|
nilfs->ns_last_seq = nilfs->ns_seg_seq;
|
|
@@ -943,6 +970,7 @@ int nilfs_search_super_root(struct the_nilfs *nilfs,
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
failed:
|
|
failed:
|
|
|
|
+ brelse(bh_sum);
|
|
nilfs_dispose_segment_list(&segments);
|
|
nilfs_dispose_segment_list(&segments);
|
|
return (ret < 0) ? ret : nilfs_warn_segment_error(ret);
|
|
return (ret < 0) ? ret : nilfs_warn_segment_error(ret);
|
|
}
|
|
}
|