[PATCH v4 10/15] nilfs-utils: fsck: add skeleton of functionality for segments checking

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

This patch adds skeleton of functionality for segments checking.

With the best regards,
Vyacheslav Dubeyko.
--
From: Vyacheslav Dubeyko <slava@xxxxxxxxxxx>
Subject: [PATCH v4 10/15] nilfs-utils: fsck: add skeleton of functionality for segments checking

This patch adds skeleton of functionality for segments checking.

Signed-off-by: Vyacheslav Dubeyko <slava@xxxxxxxxxxx>
---
 sbin/fsck/nilfs_segment.c |  934 +++++++++++++++++++++++++++++++++++++++++++++
 sbin/fsck/nilfs_segment.h |   55 +++
 2 files changed, 989 insertions(+)
 create mode 100644 sbin/fsck/nilfs_segment.c
 create mode 100644 sbin/fsck/nilfs_segment.h

diff --git a/sbin/fsck/nilfs_segment.c b/sbin/fsck/nilfs_segment.c
new file mode 100644
index 0000000..94e2a30
--- /dev/null
+++ b/sbin/fsck/nilfs_segment.c
@@ -0,0 +1,934 @@
+/*
+ * nilfs_segment.c - NILFS segments checking, processing
+ *                   and recovering operations implementation
+ *
+ * Copyright (C) 2012 Vyacheslav Dubeyko <slava@xxxxxxxxxxx>
+ *
+ * This file is part of NILFS.
+ *
+ * NILFS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * NILFS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NILFS; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Written by Vyacheslav Dubeyko <slava@xxxxxxxxxxx>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif	/* HAVE_CONFIG_H */
+
+#include <stdio.h>
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif	/* HAVE_STDLIB_H */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif	/* HAVE_UNISTD_H */
+
+#if HAVE_STRING_H
+#include <string.h>
+#endif	/* HAVE_STRING_H */
+
+#include "fsck_common.h"
+#include "fsck_raw_ops.h"
+
+#include "nilfs_superblock.h"
+#include "nilfs_segment.h"
+
+/*****************************************************************************
+ * TODO SECTION
+ *****************************************************************************/
+
+/*
+ * 1. Check ss_sumbytes (total size of segment summary in bytes) during
+ *    segment summary checksum checking.
+ *
+ * 2. Check ss_sumsum (segment summary checksum).
+ *
+ * 3. Check ss_datasum (checksum of data).
+ *
+ * 4. Check ss_cno during checkpoint bitmap construction.
+ */
+
+/*****************************************************************************
+ * FUNCTIONS DECLARATION
+ *****************************************************************************/
+
+/* Build array of segments' references on each other */
+static int build_segs_reference_array(struct nilfs_super_block *sbp);
+
+/* Build bitmap of segments through segments' sequence */
+static int build_bitmap_of_segments(struct nilfs_super_block *sbp,
+						void *seg_buf,
+						__u64 *used_segs_count);
+
+/* Compare array of segments' references and bitmap of segments */
+static int compare_segments_ref_array_and_bitmap(void);
+
+/* Check log validity */
+static int is_nilfs_log_valid(__u64 segment,
+				__u32 log,
+				__u64 start_blk,
+				struct nilfs_super_block *sbp,
+				__u64 *next_start_blk_ptr,
+				void *seg_buf,
+				struct log_check *check_db);
+
+/* Read segment summary header for log */
+static int read_segment_summary_header(__u64 start_block,
+				struct nilfs_super_block *sbp,
+				struct nilfs_segment_summary *ss_ptr);
+
+/* Read segment summary for log */
+static int read_segment_summary(__u64 start_block,
+				struct nilfs_super_block *sbp,
+				void *seg_buf);
+
+/* Define reference of current segment */
+static int set_segment_reference(__u64 segment,
+				__u32 logs_count,
+				struct nilfs_super_block *sbp,
+				struct nilfs_segment_summary *ss_ptr,
+				struct nilfs_segment_reference *array_ptr);
+
+/* Set bit in bitmap for the segment */
+static int set_segment_bitmap(__u64 segment, void *bmp_ptr);
+
+/* Allocate memory for segment */
+static void *allocate_segment_buffer(__u32 size);
+
+/* Free allocated for segment memory */
+static void free_segment_buffer(void *ptr);
+
+/* Check validity of segment summary header */
+static int is_nilfs_ss_header_valid(__u64 segment, __u32 log,
+				struct nilfs_super_block *sbp,
+				struct nilfs_segment_summary *ss_ptr,
+				__u16 *check_mask,
+				int verbosity);
+
+/*****************************************************************************
+ * IMPLEMENTATION SECTION
+ *****************************************************************************/
+
+/*****************************************************************************
+ * NAME:  check_nilfs_segments (fsck.nilfs2)
+ *
+ * FUNCTION:  Go through all segments and check validity.
+ *            It checks validity of metadata organization in segment.
+ *            This function collects data that needs for next checking
+ *            phases.
+ *
+ * RETURNS:
+ * NILFS_OK - NILFS segments was checked successfully.
+ * %-CANNOT_CHECK_SEGMENTS - Segments checking fails because of internal error.
+ * %-CANNOT_BUILD_SEGS_REF_ARRAY - Cannot build segments' reference array.
+ * %-CANNOT_BUILD_SEGS_BITMAP - Cannot build segments bitmap.
+ */
+int check_nilfs_segments(void)
+{
+	int err = NILFS_OK;
+	__u64 used_segs_count = 0;
+	__u32 blk_size;
+	__u32 blks_per_seg;
+	struct nilfs_super_block *sb_ptr = NULL;
+	void *seg_buf = NULL;
+
+	internal_debug("%s", "begin to check volume's segments.");
+
+	if (!SEGS_CHECKING_ENV_READY) {
+		internal_error("%s",
+				nilfs_message[SEGS_CHECK_ENV_NOT_READY]);
+		return -CANNOT_CHECK_SEGMENTS;
+	}
+
+	sb_ptr = get_reliable_sb(CHECK_SB_BLOCK_SZ | CHECK_SB_BLOCKS_PER_SEG |
+					CHECK_SB_NSEGMENTS |
+					CHECK_SB_FIRST_DATA_BLOCK);
+	if (!sb_ptr) {
+		internal_warning("%s", nilfs_message[UNRELIABLE_SB]);
+		return -CANNOT_CHECK_SEGMENTS;
+	}
+
+	blk_size = (1UL << (le32_to_cpu(sb_ptr->s_log_block_size) +
+					NILFS_SB_BLOCK_SIZE_SHIFT));
+	blks_per_seg = le32_to_cpu(sb_ptr->s_blocks_per_segment);
+	seg_buf = allocate_segment_buffer(blks_per_seg * blk_size);
+	if (!seg_buf) {
+		internal_perror("%s",
+					nilfs_message[CANNOT_ALLOCATE]);
+		return -CANNOT_ALLOCATE;
+	}
+
+	err = build_segs_reference_array(sb_ptr);
+	if (err) {
+		internal_error("%s",
+				nilfs_message[CANNOT_CHECK_SEGMENTS]);
+		goto failed_check_nilfs_segments;
+	}
+
+	err = build_bitmap_of_segments(sb_ptr, seg_buf, &used_segs_count);
+	if (-BROKEN_SEGS_CHAIN == err)
+		goto end_check_nilfs_segments;
+	else if (err) {
+		internal_error("%s",
+				nilfs_message[CANNOT_CHECK_SEGMENTS]);
+		goto failed_check_nilfs_segments;
+	}
+
+	err = compare_segments_ref_array_and_bitmap();
+	if (err) {
+		internal_error("%s",
+				nilfs_message[CANNOT_CHECK_SEGMENTS]);
+		goto failed_check_nilfs_segments;
+	}
+
+end_check_nilfs_segments:
+	internal_debug("%s", "volume's segments have checked.");
+
+failed_check_nilfs_segments:
+	free_segment_buffer(seg_buf);
+	return err;
+} /* check_nilfs_segments() */
+
+/*****************************************************************************
+ * NAME:  build_segs_reference_array (fsck.nilfs2)
+ *
+ * FUNCTION:  Build array of segments' references on each other.
+ *
+ * PARAMETERS:
+ * @sbp: Pointer on superblock.
+ *
+ * RETURNS:
+ * NILFS_OK - Array of segments' references was built successfully.
+ * %-INVALID_PARAMETER - Input parameter is invalid.
+ * %-CANNOT_BUILD_SEGS_REF_ARRAY - Cannot build segments' reference array.
+ */
+static int build_segs_reference_array(struct nilfs_super_block *sbp)
+{
+	int err = NILFS_OK;
+	__u64 cur_seg = 0;
+	__u64 nsegs = 0;
+	struct nilfs_segment_summary ss_hdr, last_valid_ss_hdr;
+	__u32 cur_log = 0;
+	__u64 start_seg_blk = 0;
+	__u64 end_seg_blk = 0;
+	__u32 blks_per_seg = 0;
+	__u64 cur_start_log_blk = 0;
+	__u16 check_mask = 0;
+
+	internal_debug("sbp %p.", sbp);
+
+	if (!sbp) {
+		internal_error("%s",
+				nilfs_message[INVALID_PARAMETER]);
+		return -INVALID_PARAMETER;
+	}
+
+	nsegs = le64_to_cpu(sbp->s_nsegments);
+	blks_per_seg = le32_to_cpu(sbp->s_blocks_per_segment);
+
+	for (cur_seg = 0; cur_seg < nsegs; cur_seg++) {
+		cur_log = 0;
+		start_seg_blk = seg_num_to_start_block(cur_seg, sbp);
+		end_seg_blk = start_seg_blk + blks_per_seg - 1;
+		cur_start_log_blk = start_seg_blk;
+		memset(&last_valid_ss_hdr, 0xFF,
+				sizeof(struct nilfs_segment_summary));
+
+		/* go through logs */
+		do {
+			err = read_segment_summary_header(cur_start_log_blk,
+								sbp,
+								&ss_hdr);
+			if (err) {
+				internal_error(
+				    "SEG: %lld LOG: %d. %s",
+				    cur_seg, cur_log,
+				    nilfs_message[CANNOT_BUILD_SEGS_REF_ARRAY]);
+				err = -CANNOT_BUILD_SEGS_REF_ARRAY;
+				goto failed_build_segs_ref_array;
+			}
+
+			check_mask = CHECK_SS_MAGIC | CHECK_SS_BYTES;
+			err = is_nilfs_ss_header_valid(cur_seg, cur_log, sbp,
+							&ss_hdr, &check_mask,
+							KEEP_SILENCE);
+			if (-INVALID_SS_SIGNATURE == err ||
+					-UNSUPPORTED_SS_REV == err)
+				break;
+			else if (err) {
+				internal_error(
+				    "SEG: %lld LOG: %d. %s",
+				    cur_seg, cur_log,
+				    nilfs_message[CANNOT_BUILD_SEGS_REF_ARRAY]);
+				err = -CANNOT_BUILD_SEGS_REF_ARRAY;
+				goto failed_build_segs_ref_array;
+			}
+
+			memcpy(&last_valid_ss_hdr, &ss_hdr,
+					sizeof(struct nilfs_segment_summary));
+			cur_start_log_blk =
+			    cur_start_log_blk + le32_to_cpu(ss_hdr.ss_nblocks);
+			cur_log++;
+		} while (cur_start_log_blk < end_seg_blk);
+
+		if (0 == cur_log)
+			continue;
+
+		err = set_segment_reference(cur_seg, cur_log, sbp,
+						&last_valid_ss_hdr,
+						seg_refs_array_ptr);
+		if (err) {
+			internal_error(
+				"SEG: %lld. %s", cur_seg,
+				nilfs_message[CANNOT_BUILD_SEGS_REF_ARRAY]);
+			err = -CANNOT_BUILD_SEGS_REF_ARRAY;
+			goto failed_build_segs_ref_array;
+		}
+	}
+
+	return NILFS_OK;
+
+failed_build_segs_ref_array:
+	return err;
+} /* build_segs_reference_array() */
+
+/*****************************************************************************
+ * NAME:  build_bitmap_of_segments (fsck.nilfs2)
+ *
+ * FUNCTION:  Build bitmap of segments through segments' sequence.
+ *
+ * PARAMETERS:
+ * @sbp: Pointer on superblock.
+ * @seg_buf: Pointer on segment buffer (should be allocated before call).
+ * @used_segs_count: Calculated number of used segments [returned].
+ *
+ * RETURNS:
+ * NILFS_OK - Bitmap of segments was built successfully.
+ * %-INVALID_PARAMETER - Input parameter is invalid.
+ * %-CANNOT_BUILD_SEGS_BMP - Cannot build segments bitmap.
+ */
+static int build_bitmap_of_segments(struct nilfs_super_block *sbp,
+						void *seg_buf,
+						__u64 *used_segs_count)
+{
+	int err = NILFS_OK;
+	__u64 cur_seg = 0;
+	__u64 nsegs = 0;
+	__u64 segs_count = 0;
+	__u64 last_segment = 0;
+	__u32 cur_log = 0;
+	__u64 cur_seg_start_blk = 0;
+	__u64 cur_seg_end_blk = 0;
+	__u32 blks_per_seg = 0;
+	__u64 cur_log_start_blk = 0;
+	__u64 next_log_start_blk = 0;
+	struct segment_check *segments = detected_err_db.segments;
+
+	internal_debug("sbp %p, seg_buf %p, segments %p.",
+					sbp, seg_buf, segments);
+
+	if (!sbp || !seg_buf || !used_segs_count || !segments) {
+		internal_error("%s",
+				nilfs_message[INVALID_PARAMETER]);
+		return -INVALID_PARAMETER;
+	}
+
+	(*used_segs_count) = 0;
+
+	nsegs = le64_to_cpu(sbp->s_nsegments);
+	last_segment = le64_to_cpu(sbp->s_last_seq);
+	blks_per_seg = le32_to_cpu(sbp->s_blocks_per_segment);
+	cur_seg_start_blk = seg_num_to_start_block(cur_seg, sbp);
+	cur_seg_end_blk = cur_seg_start_blk + blks_per_seg - 1;
+
+	/* Build bitmap of segments through segments' sequence */
+	for (; segs_count <= nsegs; segs_count++) {
+
+		cur_log = 0;
+		cur_log_start_blk = cur_seg_start_blk;
+		next_log_start_blk = -1;
+
+		if (segs_count == nsegs) {
+			/*
+			 * Temporary the logic very simple.
+			 * Simply go through all the chains and
+			 * stop when the count of segments become
+			 * equal to number of segments on volume.
+			 *
+			 * TODO: implement properly.
+			 */
+
+			/*detected_err_db.volume.errs_bmp |=
+				SEGS_CHAIN_INCONSISTENT;
+			err = fs_description(BROKEN_SEGS_CHAIN,
+						cur_seg, cur_log);*/
+			break;
+		}
+
+		if (cur_seg >= detected_err_db.segs_count) {
+			internal_error("%s",
+				nilfs_message[CANNOT_BUILD_SEGS_BMP]);
+			internal_debug("cur_seg %lld, cur_log %d.",
+						cur_seg, cur_log);
+			err = -CANNOT_BUILD_SEGS_BMP;
+			goto failed_build_bitmap_of_segments;
+		}
+
+		if (0 == segments[cur_seg].logs_count)
+			goto define_next_segment;
+
+		if (!segments[cur_seg].logs) {
+			internal_error("%s",
+				nilfs_message[CANNOT_BUILD_SEGS_BMP]);
+			internal_debug("cur_seg %lld, cur_log %d.",
+						cur_seg, cur_log);
+			err = -CANNOT_BUILD_SEGS_BMP;
+			goto failed_build_bitmap_of_segments;
+		}
+
+		/* Go through logs */
+		do {
+			if ((cur_log + 1) > segments[cur_seg].logs_count)
+				break;
+
+			err = is_nilfs_log_valid(cur_seg,
+					cur_log,
+					cur_log_start_blk,
+					sbp,
+					&next_log_start_blk,
+					seg_buf,
+					&(segments[cur_seg].logs[cur_log]));
+
+			if (-EMPTY_LOG_DETECTED == err)
+				break;
+			else if (-INVALID_NILFS_LOG == err)
+				break;
+			else if (err) {
+				internal_error("%s",
+					nilfs_message[CANNOT_BUILD_SEGS_BMP]);
+				internal_debug("cur_seg %lld, cur_log %d.",
+							cur_seg, cur_log);
+				err = -CANNOT_BUILD_SEGS_BMP;
+				goto failed_build_bitmap_of_segments;
+			}
+
+			cur_log_start_blk = next_log_start_blk;
+			cur_log++;
+		} while (cur_log_start_blk < cur_seg_end_blk);
+
+
+		err = set_segment_bitmap(cur_seg, segments_bitmap_ptr);
+		if (err) {
+			internal_error("%s",
+					nilfs_message[CANNOT_BUILD_SEGS_BMP]);
+			internal_debug("cur_seg %lld.", cur_seg);
+			goto failed_build_bitmap_of_segments;
+		}
+
+define_next_segment:
+		if (cur_seg == last_segment)
+			break;
+
+		cur_seg = seg_refs_array_ptr[cur_seg].next_seg;
+		cur_seg_start_blk = seg_num_to_start_block(cur_seg, sbp);
+		cur_seg_end_blk = cur_seg_start_blk + blks_per_seg - 1;
+	}
+
+	(*used_segs_count) = segs_count;
+
+	internal_debug("used_segs_count %lld.",
+				(*used_segs_count));
+
+	return NILFS_OK;
+
+failed_build_bitmap_of_segments:
+	return err;
+} /* build_bitmap_of_segments() */
+
+/* Compare array of segments' references and bitmap of segments */
+static int compare_segments_ref_array_and_bitmap(void)
+{
+	/*segs_count = 0;
+
+	for (cur_seg = 0; segs_count < used_segs_count; segs_count++) {
+		err = check_segment_reference(cur_seg,
+						seg_refs_array_ptr,
+						segments_bitmap_ptr);
+		if (err);
+		cur_seg = get_next_seg_by_ref(cur_seg);
+	}*/
+
+	/*internal_info("<%s>: %s", __func__, nilfs_message[NOT_IMPLEMENTED]);*/
+
+	/* <TODO: implement> */
+	return NILFS_OK;
+} /* compare_segments_ref_array_and_bitmap() */
+
+/*****************************************************************************
+ * NAME:  is_nilfs_log_valid (fsck.nilfs2)
+ *
+ * FUNCTION:  Check log validity.
+ *
+ * PARAMETERS:
+ * @segment: Segment number.
+ * @log: Log number.
+ * @start_blk: Start block of log in segment.
+ * @sbp: Pointer on superblock.
+ * @next_start_blk_ptr: Pointer on returned value of next log start block.
+ * @seg_buf: Pointer on segment buffer (should be allocated before call).
+ * @check_db: Pointer on structure that contains checking flags for log.
+ *
+ * RETURNS:
+ * NILFS_OK - Log validity has checked successfully.
+ * %-INVALID_PARAMETER - Input parameter is invalid.
+ * %-EMPTY_LOG_DETECTED - Empty log is detected in the segment.
+ * %-CANNOT_CHECK_LOG - Cannot check log validity.
+ * %-INVALID_NILFS_LOG - NILFS log is in corrupted state.
+ */
+static int is_nilfs_log_valid(__u64 segment,
+				__u32 log,
+				__u64 start_blk,
+				struct nilfs_super_block *sbp,
+				__u64 *next_start_blk_ptr,
+				void *seg_buf,
+				struct log_check *check_db)
+{
+	int err = NILFS_OK;
+	struct nilfs_segment_summary *ss_ptr;
+
+	internal_debug("segment %lld, log %d, start_blk %lld.",
+					segment, log, start_blk);
+	internal_debug("next_start_blk_ptr %p, seg_buf %p.",
+				next_start_blk_ptr, seg_buf);
+
+	if (!next_start_blk_ptr || !seg_buf) {
+		internal_error("%s",
+				nilfs_message[INVALID_PARAMETER]);
+		return -INVALID_PARAMETER;
+	}
+
+	(*next_start_blk_ptr) = -1;
+
+	err = read_segment_summary(start_blk, sbp, seg_buf);
+	ss_ptr = (struct nilfs_segment_summary *)seg_buf;
+
+	if (-SS_FINFO_SECTION_EMPTY == err) {
+		if (0 == ss_ptr->ss_magic &&
+				0 == ss_ptr->ss_bytes &&
+				0 == ss_ptr->ss_nblocks &&
+				0 == ss_ptr->ss_nfinfo &&
+				0 == ss_ptr->ss_sumbytes) {
+			internal_debug("SEG %lld LOG: %d. %s",
+					segment, log,
+					nilfs_message[EMPTY_LOG_DETECTED]);
+			return -EMPTY_LOG_DETECTED;
+		}
+	} else if (-DATA_PROCCESSED_PARTIALLY == err)
+		err = NILFS_OK; /* Do nothing. Simply ignore error. */
+	else if (err) {
+		internal_error("SEG: %lld LOG: %d. %s",
+				segment, log,
+				nilfs_message[CANNOT_CHECK_LOG]);
+		err = -CANNOT_CHECK_LOG;
+		goto failed_check_log;
+	}
+
+	/* Check segment summary header */
+	check_db->ss_hdr.check_mask = SS_HEADER_ONLY_CHECK;
+
+	err = is_nilfs_ss_header_valid(segment, log, sbp, ss_ptr,
+					&(check_db->ss_hdr.check_mask),
+					BE_VERBOSE);
+
+	check_db->ss_hdr.check_mask |= ONLY_SS_HDR_HAS_CHECKED;
+
+	if (-INVALID_SS_SIGNATURE == err || -UNSUPPORTED_SS_REV == err) {
+		err = fs_description(INVALID_NILFS_LOG, segment, log);
+		goto end_check_log;
+	} else if (err) {
+		internal_error("SEG: %lld LOG: %d. %s",
+				segment, log,
+				nilfs_message[CANNOT_CHECK_LOG]);
+		err = -CANNOT_CHECK_LOG;
+		goto failed_check_log;
+	}
+
+	/* Check segment summary checksum */
+	/* Check segment summary */
+	/* Check rest of log */
+
+	(*next_start_blk_ptr) = start_blk + le32_to_cpu(ss_ptr->ss_nblocks);
+
+end_check_log:
+	/*internal_info("<%s>: %s", __func__, nilfs_message[NOT_IMPLEMENTED]);*/
+
+	/* <TODO: implement> */
+
+	return NILFS_OK;
+
+failed_check_log:
+	return err;
+} /* is_nilfs_log_valid() */
+
+/*****************************************************************************
+ * NAME:  allocate_segment_buffer (fsck.nilfs2)
+ *
+ * FUNCTION:  Allocate memory for segment buffer.
+ *
+ * PARAMETERS:
+ * @size: Buffer size in bytes.
+ *
+ * RETURNS:
+ * Valid memory pointer or NULL in the case of failure.
+ */
+static void *allocate_segment_buffer(__u32 size)
+{
+	void *ptr = NULL;
+
+	internal_debug("allocate memory %d for segment.",
+					size);
+
+	ptr = calloc(size, 1);
+	if (!ptr)
+		internal_perror("%s", nilfs_message[CANNOT_ALLOCATE]);
+
+	return ptr;
+} /* allocate_segment_buffer() */
+
+
+/*****************************************************************************
+ * NAME:  free_segment_buffer (fsck.nilfs2)
+ *
+ * FUNCTION:  Free allocated for segment memory.
+ *
+ * PARAMETERS:
+ * @size: Buffer size in bytes.
+ *
+ * RETURNS:
+ * Valid memory pointer or NULL in the case of failure.
+ */
+static void free_segment_buffer(void *ptr)
+{
+	internal_debug("free memory of segment buffer %p.",
+							ptr);
+
+	if (ptr)
+		free(ptr);
+} /* free_segment_buffer() */
+
+/*****************************************************************************
+ * NAME:  read_segment_summary_header (fsck.nilfs2)
+ *
+ * FUNCTION:  Read segment summary header for log.
+ *
+ * PARAMETERS:
+ * @start_block: Start block for read.
+ * @sbp: Pointer on superblock.
+ * @ss_ptr: Pointer on segment summary header buffer (should be allocated yet).
+ *
+ * RETURNS:
+ * NILFS_OK - Segment summary header was read successfully.
+ * %-INVALID_PARAMETER - Input parameter is invalid.
+ * %-DATA_PROCCESSED_PARTIALLY - Segment summary header is read partially.
+ */
+static int read_segment_summary_header(__u64 start_block,
+				struct nilfs_super_block *sbp,
+				struct nilfs_segment_summary *ss_ptr)
+{
+	int err = NILFS_OK;
+	__u32 blk_size;
+	__u32 read_bytes = 0;
+
+	internal_debug("start_block %lld, ss_ptr %p.",
+					start_block, ss_ptr);
+
+	if (!sbp || !ss_ptr) {
+		internal_error("%s",
+				nilfs_message[INVALID_PARAMETER]);
+		return -INVALID_PARAMETER;
+	}
+
+	blk_size = (1UL << (le32_to_cpu(sbp->s_log_block_size) +
+					NILFS_SB_BLOCK_SIZE_SHIFT));
+
+	err = read_raw_bytes(start_block * blk_size,
+				ss_ptr, sizeof(*ss_ptr),
+				&read_bytes);
+	if (err) {
+		internal_debug("start_block %lld %s",
+				start_block,
+				nilfs_message[CANNOT_READ_SEG_SUM_HEADER]);
+		goto failed_read_segment_summary_header;
+	}
+
+	if (read_bytes != sizeof(*ss_ptr)) {
+		internal_error("start_block %lld. %s",
+				start_block,
+				nilfs_message[DATA_PROCCESSED_PARTIALLY]);
+		err = -DATA_PROCCESSED_PARTIALLY;
+		goto failed_read_segment_summary_header;
+	}
+
+	return NILFS_OK;
+
+failed_read_segment_summary_header:
+	return err;
+} /* read_segment_summary() */
+
+/*****************************************************************************
+ * NAME:  read_segment_summary (fsck.nilfs2)
+ *
+ * FUNCTION:  Read segment summary for log.
+ *
+ * PARAMETERS:
+ * @start_block: Start block for read.
+ * @sbp: Pointer on superblock.
+ * @seg_buf: Pointer on segment buffer (should be allocated yet).
+ *
+ * RETURNS:
+ * NILFS_OK - Segment summary was read successfully.
+ * %-INVALID_PARAMETER - Input parameter is invalid.
+ * %-SS_FINFO_SECTION_EMPTY - Segment summary hasn't finfo section.
+ * %-CANNOT_READ_SEG_SUMMARY - Cannot read because of internal error.
+ * %-DATA_PROCCESSED_PARTIALLY - Segment summary is read partially.
+ */
+static int read_segment_summary(__u64 start_block,
+				struct nilfs_super_block *sbp,
+				void *seg_buf)
+{
+	int err = NILFS_OK;
+	__u64 read_offset;
+	__u32 blk_size;
+	__u32 blks_per_seg;
+	struct nilfs_segment_summary *ss_ptr = NULL;
+	__u32 seg_sum_size;
+	__u32 read_bytes = 0;
+
+	internal_debug("start_block %lld, sbp %p, seg_buf %p.",
+				start_block, sbp, seg_buf);
+
+	if (!sbp || !seg_buf) {
+		internal_error("%s",
+				nilfs_message[INVALID_PARAMETER]);
+		return -INVALID_PARAMETER;
+	}
+
+	ss_ptr = (struct nilfs_segment_summary *)seg_buf;
+	err = read_segment_summary_header(start_block, sbp, ss_ptr);
+	if (err)
+		goto failed_read_seg_sum;
+
+	seg_sum_size = le32_to_cpu(ss_ptr->ss_sumbytes);
+	blk_size = (1UL << (le32_to_cpu(sbp->s_log_block_size) +
+					NILFS_SB_BLOCK_SIZE_SHIFT));
+	blks_per_seg = le32_to_cpu(sbp->s_blocks_per_segment);
+
+	if (seg_sum_size < sizeof(struct nilfs_segment_summary))
+		return -SS_FINFO_SECTION_EMPTY;
+	else if (seg_sum_size > (blks_per_seg * blk_size))
+		seg_sum_size = blks_per_seg * blk_size;
+
+	read_offset = (start_block * blk_size) +
+				sizeof(struct nilfs_segment_summary);
+
+	err = read_raw_bytes(read_offset,
+			seg_buf + sizeof(struct nilfs_segment_summary),
+			seg_sum_size - sizeof(struct nilfs_segment_summary),
+			&read_bytes);
+	if (err) {
+		internal_debug("start_block %lld %s",
+				start_block,
+				nilfs_message[CANNOT_READ_SEG_SUMMARY]);
+		goto failed_read_seg_sum;
+	}
+
+	if (read_bytes !=
+			(le32_to_cpu(ss_ptr->ss_sumbytes) -
+				sizeof(struct nilfs_segment_summary))) {
+		internal_error("start_block %lld. %s",
+				start_block,
+				nilfs_message[DATA_PROCCESSED_PARTIALLY]);
+		err = -DATA_PROCCESSED_PARTIALLY;
+		goto failed_read_seg_sum;
+	}
+
+	return NILFS_OK;
+
+failed_read_seg_sum:
+	return err;
+}
+
+/*****************************************************************************
+ * NAME:  set_segment_reference (fsck.nilfs2)
+ *
+ * FUNCTION:  Define reference of current segment.
+ *
+ * PARAMETERS:
+ * @segment: Segment number.
+ * @logs_count: Count of logs in segment.
+ * @sbp: Pointer on superblock.
+ * @ss_ptr: Pointer on segment summary buffer.
+ * @array_ptr: Pointer on segments' references array.
+ *
+ * RETURNS:
+ * NILFS_OK - Segment's reference was defined successfully.
+ * %-INVALID_PARAMETER - Input parameter is invalid.
+ * %-CANNOT_ALLOCATE - Cannot allocate memory for log checking environment.
+ */
+static int set_segment_reference(__u64 segment,
+				__u32 logs_count,
+				struct nilfs_super_block *sbp,
+				struct nilfs_segment_summary *ss_ptr,
+				struct nilfs_segment_reference *array_ptr)
+{
+	__u64 next_seg;
+
+	internal_debug("SEG: %lld, logs_count %d",
+				segment, logs_count);
+	internal_debug("sbp %p, ss_ptr %p, array_ptr %p",
+				sbp, ss_ptr, array_ptr);
+
+	if (!sbp || !ss_ptr || !array_ptr) {
+		internal_error("%s", nilfs_message[INVALID_PARAMETER]);
+		return -INVALID_PARAMETER;
+	}
+
+	if (segment >= le64_to_cpu(sbp->s_nsegments)) {
+		internal_error("%s", nilfs_message[INVALID_PARAMETER]);
+		return -INVALID_PARAMETER;
+	}
+
+	next_seg = block_to_seg_num(le64_to_cpu(ss_ptr->ss_next), sbp);
+
+	array_ptr[segment].seg_seq_id = le64_to_cpu(ss_ptr->ss_seq);
+	array_ptr[segment].next_seg = next_seg;
+
+	if (next_seg < le64_to_cpu(sbp->s_nsegments))
+		array_ptr[next_seg].prev_seg = segment;
+
+	array_ptr[segment].logs_count = logs_count;
+
+	if (detected_err_db.segments) {
+		detected_err_db.segments[segment].logs =
+			calloc(sizeof(struct log_check), logs_count);
+		if (!detected_err_db.segments[segment].logs) {
+			internal_perror("%s",
+					nilfs_message[CANNOT_ALLOCATE]);
+			return -CANNOT_ALLOCATE;
+		}
+		detected_err_db.segments[segment].logs_count = logs_count;
+	}
+
+	return NILFS_OK;
+} /* set_segment_reference() */
+
+/* Set bit in bitmap for the segment */
+static int set_segment_bitmap(__u64 segment, void *bmp_ptr)
+{
+	/*internal_info("<%s>: %s", __func__, nilfs_message[NOT_IMPLEMENTED]);*/
+
+	/* <TODO: implement> */
+	return NILFS_OK;
+} /* set_segment_bitmap() */
+
+/*****************************************************************************
+ * NAME:  is_nilfs_ss_header_valid (fsck.nilfs2)
+ *
+ * FUNCTION:  Check validity of segment summary header.
+ *
+ * PARAMETERS:
+ * @segment: Segment number.
+ * @log: Log number.
+ * @sbp: Pointer on superblock.
+ * @ss_ptr: Pointer on segment summary header.
+ * @check_mask: Check mask defines what should be checked.
+ * @verbosity: Verbosity level [KEEP_SILENCE | BE_VERBOSE].
+ *
+ * RETURNS:
+ * NILFS_OK - Segment summary header was checked successfully.
+ * %-INVALID_PARAMETER - Input parameter is invalid.
+ * %-INVALID_SS_SIGNATURE - Segment summary header magic is invalid.
+ * %-UNSUPPORTED_SS_REV - Unsupported revision of segment summary header.
+ *
+ * @check_mask contains mask of flags on items which should be checked.
+ * During checking flags of valid items are unset. At the end of working
+ * @check_mask contains flags of corrupted items as set. These set flags
+ * inform about detected errors.
+ */
+static int is_nilfs_ss_header_valid(__u64 segment, __u32 log,
+				struct nilfs_super_block *sbp,
+				struct nilfs_segment_summary *ss_ptr,
+				__u16 *check_mask,
+				int verbosity)
+{
+	int err = NILFS_OK;
+
+	/* Declaration order is crucial!!! */
+	int ss_hdr_err_id[SS_HDR_CHECK_FLAGS_MAX] = {
+/*WARNING*/
+		INVALID_SS_SIGNATURE,		/*CHECK_SS_MAGIC*/
+		UNSUPPORTED_SS_REV,		/*CHECK_SS_HDR_REV*/
+/*CRITICAL*/
+		INVALID_SS_DATASUM,		/*CHECK_SS_DATASUM*/
+		INVALID_SS_SUMSUM,		/*CHECK_SS_SUMSUM*/
+		INVALID_SS_HEADER_SZ,		/*CHECK_SS_BYTES*/
+		INVALID_SS_NBLOCKS,		/*CHECK_SS_NBLOCKS*/
+		INVALID_SS_NEXT_SEG_BLK,	/*CHECK_SS_NEXT*/
+		INVALID_SS_NFINFO,		/*CHECK_SS_NFIFO*/
+		INVALID_SS_SUMBYTES,		/*CHECK_SS_SUMBYTES*/
+/*MINOR*/
+		INVALID_SS_SEQ,			/*CHECK_SS_SEQ*/
+		INVALID_SS_FLAGS,		/*CHECK_SS_FLAGS*/
+/*LOOKS_LIKE_ERROR*/
+		INVALID_SS_CREATE_TIME,		/*CHECK_SS_CREATE*/
+		INVALID_SS_CNO,			/*CHECK_SS_CNO*/
+	};
+
+	internal_debug("%s", "check segment summary header validity.");
+	internal_debug("SEG %lld, sbp %p, ss_ptr %p, check_mask %p.",
+				segment, sbp, ss_ptr, check_mask);
+
+	if (!sbp || !ss_ptr || !check_mask) {
+		err = INVALID_PARAMETER;
+		goto failed_check_seg_sum_hdr;
+	}
+
+	if (!nilfs_ss_header_is_valid(segment, sbp, ss_ptr, check_mask)) {
+		if (BE_VERBOSE == verbosity) {
+			print_fs_detected_errors(check_mask,
+					ss_hdr_err_id,
+					SS_HDR_CHECK_FLAGS_MAX,
+					segment,
+					log);
+		} else if (KEEP_SILENCE != verbosity) {
+			err = INVALID_PARAMETER;
+			goto failed_check_seg_sum_hdr;
+		}
+
+		if ((*check_mask) & CHECK_SS_MAGIC)
+			return -INVALID_SS_SIGNATURE;
+
+		if ((*check_mask) & CHECK_SS_HDR_REV)
+			return -UNSUPPORTED_SS_REV;
+	}
+
+	return NILFS_OK;
+
+failed_check_seg_sum_hdr:
+	internal_error("%s", nilfs_message[err]);
+	return -err;
+} /* is_nilfs_ss_header_valid() */
diff --git a/sbin/fsck/nilfs_segment.h b/sbin/fsck/nilfs_segment.h
new file mode 100644
index 0000000..6503a5c
--- /dev/null
+++ b/sbin/fsck/nilfs_segment.h
@@ -0,0 +1,55 @@
+/*
+ * nilfs_segment.h - Declarations of operations for NILFS segments
+ *                   checking, processing and recovering
+ *
+ * Copyright (C) 2012 Vyacheslav Dubeyko <slava@xxxxxxxxxxx>
+ *
+ * This file is part of NILFS.
+ *
+ * NILFS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * NILFS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NILFS; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Written by Vyacheslav Dubeyko <slava@xxxxxxxxxxx>
+ */
+
+#ifndef NILFS_SEGMENT_H
+#define NILFS_SEGMENT_H
+
+/* Pointer on segment references array */
+extern struct nilfs_segment_reference *seg_refs_array_ptr;
+
+/* Pointer on segments bitmap */
+extern int *segments_bitmap_ptr;
+
+/*
+ * SEGS_CHECKING_ENV_READY
+ *
+ * MACRO:  Check readiness of segments checking environment.
+ *
+ * RETURNS:
+ * NILFS_TRUE - Segments checking environment is ready.
+ * NILFS_FALSE - Segments checking environment is *not* ready.
+ */
+#define SEGS_CHECKING_ENV_READY \
+	((seg_refs_array_ptr && segments_bitmap_ptr) ? NILFS_TRUE : NILFS_FALSE)
+
+/*
+ * Go through all segments and check validity.
+ * It checks validity of metadata organization in segment.
+ * This function collects data that needs for next checking
+ * phases.
+ */
+int check_nilfs_segments(void);
+
+#endif /* NILFS_SEGMENT_H */
-- 
1.7.9.5



--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Filesystem Development]     [Linux BTRFS]     [Linux CIFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux