* [PATCH v4 07/15] nilfs-utils: fsck: NILFS segment summary header check implementation
@ 2012-11-12 9:36 Vyacheslav Dubeyko
0 siblings, 0 replies; only message in thread
From: Vyacheslav Dubeyko @ 2012-11-12 9:36 UTC (permalink / raw)
To: linux-nilfs
Hi,
This patch adds nilfs_ss_header_is_valid() function with the purpose of making segment summary header check.
With the best regards,
Vyacheslav Dubeyko.
--
From: Vyacheslav Dubeyko <slava-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org>
Subject: [PATCH v4 07/15] nilfs-utils: fsck: NILFS segment summary header check implementation
This patch adds nilfs_ss_header_is_valid() function with the purpose of making segment summary header check.
Signed-off-by: Vyacheslav Dubeyko <slava-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org>
---
lib/segment.c | 509 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 509 insertions(+)
create mode 100644 lib/segment.c
diff --git a/lib/segment.c b/lib/segment.c
new file mode 100644
index 0000000..9c14fb6
--- /dev/null
+++ b/lib/segment.c
@@ -0,0 +1,509 @@
+/*
+ * segment.c - NILFS2 segment checking functionality
+ *
+ * Copyright (C) 2012 Vyacheslav Dubeyko <slava-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org>
+ *
+ * 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-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org>
+ */
+
+#include "nilfs.h"
+#include "nilfs_messages.h"
+#include "fsck_nilfs2.h"
+
+/*
+ * ss_check_magic - Check magic signature of segment summary header.
+ * @ss_ptr: pointer on segment summary header.
+ * @check_mask: mask that defines what should be checked and returns error.
+ *
+ * Return value:
+ * NILFS_OK - no internal errors were occured.
+ * %-INVALID_SS_SIGNATURE - segment summary header has invalid magic.
+ *
+ * In the case of valid successfull call @check_mask keeps
+ * flags with detected errors.
+ */
+static int ss_check_magic(struct nilfs_segment_summary *ss_ptr,
+ __u16 *check_mask)
+{
+ int err = NILFS_OK;
+
+ if (!(*check_mask & CHECK_SS_MAGIC))
+ return NILFS_OK; /* nothing to be checked */
+
+ if (le32_to_cpu(ss_ptr->ss_magic) != NILFS_SEGSUM_MAGIC)
+ err = INVALID_SS_SIGNATURE;
+ else
+ *check_mask &= ~CHECK_SS_MAGIC;
+
+ internal_debug("ss_magic %#x.",
+ le32_to_cpu(ss_ptr->ss_magic));
+ internal_debug("check_mask %x.", *check_mask);
+
+ return (err > 0) ? -err : err;
+} /* ss_check_magic() */
+
+/*
+ * ss_check_header_size - Check segment summary header size in bytes.
+ * @ss_ptr: pointer on segment summary header.
+ * @check_mask: mask that defines what should be checked and returns error.
+ *
+ * Return value:
+ * NILFS_OK - no internal errors were occured.
+ * %-INVALID_SS_HEADER_SZ - size of segment summary header is invalid.
+ * %-UNSUPPORTED_SS_REV - unsupported revision of segment summary.
+ *
+ * In the case of valid successfull call @check_mask keeps
+ * flags with detected errors.
+ */
+static int ss_check_header_size(struct nilfs_segment_summary *ss_ptr,
+ __u16 *check_mask)
+{
+ int err = NILFS_OK;
+ __u16 ss_bytes = le16_to_cpu(ss_ptr->ss_bytes);
+
+ if (!(*check_mask & CHECK_SS_BYTES))
+ return NILFS_OK; /* nothing to be checked */
+
+ if (ss_bytes < sizeof(struct nilfs_segment_summary)) {
+ err = INVALID_SS_HEADER_SZ;
+ *check_mask &= (~CHECK_SS_HDR_REV);
+ } else if (ss_bytes > sizeof(struct nilfs_segment_summary)) {
+ err = UNSUPPORTED_SS_REV;
+ *check_mask &= (~CHECK_SS_BYTES);
+ } else
+ *check_mask &= (~(CHECK_SS_BYTES | CHECK_SS_HDR_REV));
+
+ internal_debug("ss_bytes %d.",
+ le16_to_cpu(ss_ptr->ss_bytes));
+ internal_debug("check_mask %x.", *check_mask);
+
+ return (err > 0) ? -err : err;
+} /* ss_check_header_size() */
+
+/*
+ * ss_check_segment_sequence_number - Check segment sequence number.
+ * @segment: current segment number.
+ * @sbp: pointer on superblock.
+ * @ss_ptr: pointer on segment summary header.
+ * @check_mask: mask that defines what should be checked and returns error.
+ *
+ * Return value:
+ * NILFS_OK - no internal errors were occured.
+ * %-INVALID_SS_SEQ - segment summary header keeps invalid seq number.
+ *
+ * In the case of valid successfull call @check_mask keeps
+ * flags with detected errors.
+ */
+static int ss_check_segment_sequence_number(__u64 segment,
+ struct nilfs_super_block *sbp,
+ struct nilfs_segment_summary *ss_ptr,
+ __u16 *check_mask)
+{
+ int err = NILFS_OK;
+ __u64 sequence_number;
+ __u64 nsegs;
+ __u64 iteration;
+
+ if (!(*check_mask & CHECK_SS_SEQ))
+ return NILFS_OK; /* nothing to be checked */
+
+ sequence_number = le64_to_cpu(ss_ptr->ss_seq);
+ nsegs = le64_to_cpu(sbp->s_nsegments);
+ iteration = sequence_number / nsegs;
+
+ if ((segment + (nsegs * iteration)) != sequence_number)
+ err = INVALID_SS_SEQ;
+ else
+ *check_mask &= ~CHECK_SS_SEQ;
+
+ internal_debug("ss_seq %lld.",
+ le64_to_cpu(ss_ptr->ss_seq));
+ internal_debug("check_mask %x.", *check_mask);
+
+ return (err > 0) ? -err : err;
+} /* ss_check_segment_sequence_number() */
+
+/*
+ * ss_check_seg_used_blocks_number - Check number of really used blocks.
+ * @sbp: pointer on superblock.
+ * @ss_ptr: pointer on segment summary header.
+ * @check_mask: mask that defines what should be checked and returns error.
+ *
+ * Return value:
+ * NILFS_OK - no internal errors were occured.
+ * %-INVALID_SS_NBLOCKS - invalid number of really used blocks in segment.
+ *
+ * In the case of valid successfull call @check_mask keeps
+ * flags with detected errors.
+ */
+static int ss_check_seg_used_blocks_number(struct nilfs_super_block *sbp,
+ struct nilfs_segment_summary *ss_ptr,
+ __u16 *check_mask)
+{
+ int err = NILFS_OK;
+ __u32 nblocks;
+ __u32 blk_size;
+ __u32 seg_sum_blocks;
+
+ if (!(*check_mask & CHECK_SS_NBLOCKS))
+ return NILFS_OK; /* nothing to be checked */
+
+ nblocks = le32_to_cpu(ss_ptr->ss_nblocks);
+ blk_size = (1UL << (le32_to_cpu(sbp->s_log_block_size) +
+ NILFS_SB_BLOCK_SIZE_SHIFT));
+ seg_sum_blocks =
+ ROUNDUP_DIV(le32_to_cpu(ss_ptr->ss_sumbytes), blk_size);
+
+ if (nblocks > le32_to_cpu(sbp->s_blocks_per_segment) ||
+ nblocks <= seg_sum_blocks)
+ err = INVALID_SS_NBLOCKS;
+ else
+ *check_mask &= ~CHECK_SS_NBLOCKS;
+
+ internal_debug("ss_nblocks %d.", nblocks);
+ internal_debug("check_mask %x.", *check_mask);
+
+ return (err > 0) ? -err : err;
+} /* ss_check_seg_used_blocks_number() */
+
+/*
+ * ss_check_flags - Check segment summary header flags.
+ * @ss_ptr: pointer on segment summary header.
+ * @check_mask: mask that defines what should be checked and returns error.
+ *
+ * Return value:
+ * NILFS_OK - no internal errors were occured.
+ * %-INVALID_SS_FLAGS - unknown flags were detected.
+ *
+ * In the case of valid successfull call @check_mask keeps
+ * flags with detected errors.
+ */
+static int ss_check_flags(struct nilfs_segment_summary *ss_ptr,
+ __u16 *check_mask)
+{
+ int err = NILFS_OK;
+ __u16 known_flags = NILFS_SS_LOGBGN | NILFS_SS_LOGEND |
+ NILFS_SS_SR | NILFS_SS_SYNDT |
+ NILFS_SS_GC;
+
+ if (!(*check_mask & CHECK_SS_FLAGS))
+ return NILFS_OK; /* nothing to be checked */
+
+ if (le16_to_cpu(ss_ptr->ss_flags) & ~known_flags)
+ err = INVALID_SS_FLAGS;
+ else
+ *check_mask &= ~CHECK_SS_FLAGS;
+
+ internal_debug("ss_flags %d.",
+ le16_to_cpu(ss_ptr->ss_flags));
+ internal_debug("check_mask %x.", *check_mask);
+
+ return (err > 0) ? -err : err;
+} /* ss_check_flags() */
+
+/*
+ * ss_check_creation_timestamp - Check segment summary header creation time.
+ * @sbp: pointer on superblock.
+ * @ss_ptr: pointer on segment summary header.
+ * @check_mask: mask that defines what should be checked and returns error.
+ *
+ * Return value:
+ * NILFS_OK - no internal errors were occured.
+ * %-INVALID_SS_CREATE_TIME - creation timestamp has strange value.
+ *
+ * In the case of valid successfull call @check_mask keeps
+ * flags with detected errors.
+ */
+static int ss_check_creation_timestamp(struct nilfs_super_block *sbp,
+ struct nilfs_segment_summary *ss_ptr,
+ __u16 *check_mask)
+{
+ int err = NILFS_OK;
+ __u64 ss_create;
+
+ if (!(*check_mask & CHECK_SS_CREATE))
+ return NILFS_OK; /* nothing to be checked */
+
+ ss_create = le64_to_cpu(ss_ptr->ss_create);
+
+ if (ss_create >= time(NULL) || ss_create < le64_to_cpu(sbp->s_ctime))
+ err = INVALID_SS_CREATE_TIME;
+ else
+ *check_mask &= ~CHECK_SS_CREATE;
+
+ internal_debug("ss_create %s.",
+ ctime((const time_t *)&ss_create));
+ internal_debug("check_mask %x.", *check_mask);
+
+ return (err > 0) ? -err : err;
+} /* ss_check_creation_timestamp() */
+
+/*
+ * ss_check_next_seg_start_block - Check next segment start block.
+ * @segment: segment sequence number.
+ * @sbp: pointer on superblock.
+ * @ss_ptr: pointer on segment summary header.
+ * @check_mask: mask that defines what should be checked and returns error.
+ *
+ * Return value:
+ * NILFS_OK - no internal errors were occured.
+ * %-INVALID_SS_NEXT_SEG_BLK - next segment start block is invalid.
+ *
+ * In the case of valid successfull call @check_mask keeps
+ * flags with detected errors.
+ */
+static int ss_check_next_seg_start_block(__u64 segment,
+ struct nilfs_super_block *sbp,
+ struct nilfs_segment_summary *ss_ptr,
+ __u16 *check_mask)
+{
+ int err = NILFS_OK;
+ __u64 cur_seg_start_block;
+ __u64 next_seg_start_block;
+ __u64 nsegs;
+ __u32 blks_per_seg;
+ __u64 seg_start_diff;
+ __u64 first_data_block;
+
+ if (!(*check_mask & CHECK_SS_NEXT))
+ return NILFS_OK; /* nothing to be checked */
+
+ cur_seg_start_block = seg_num_to_start_block(segment, sbp);
+ next_seg_start_block = le64_to_cpu(ss_ptr->ss_next);
+ nsegs = le64_to_cpu(sbp->s_nsegments);
+ blks_per_seg = le32_to_cpu(sbp->s_blocks_per_segment);
+ first_data_block = le64_to_cpu(sbp->s_first_data_block);
+ seg_start_diff = (next_seg_start_block > cur_seg_start_block ?
+ next_seg_start_block - cur_seg_start_block :
+ cur_seg_start_block - next_seg_start_block);
+
+ if (next_seg_start_block >= (nsegs * blks_per_seg))
+ err = INVALID_SS_NEXT_SEG_BLK;
+ else if (0 == seg_start_diff)
+ err = INVALID_SS_NEXT_SEG_BLK;
+ else if (0 == segment || next_seg_start_block == first_data_block) {
+ if ((seg_start_diff + first_data_block) < blks_per_seg ||
+ (seg_start_diff + first_data_block) % blks_per_seg)
+ err = INVALID_SS_NEXT_SEG_BLK;
+ else
+ *check_mask &= ~CHECK_SS_NEXT;
+ } else {
+ if (seg_start_diff < blks_per_seg ||
+ seg_start_diff % blks_per_seg)
+ err = INVALID_SS_NEXT_SEG_BLK;
+ else
+ *check_mask &= ~CHECK_SS_NEXT;
+ }
+
+ internal_debug("ss_next %lld.",
+ le64_to_cpu(ss_ptr->ss_next));
+ internal_debug("check_mask %x.", *check_mask);
+
+ return (err > 0) ? -err : err;
+} /* ss_check_next_seg_start_block() */
+
+/*
+ * ss_check_nfifo - Check number of finfo structures.
+ * @sbp: pointer on superblock.
+ * @ss_ptr: pointer on segment summary header.
+ * @check_mask: mask that defines what should be checked and returns error.
+ *
+ * Return value:
+ * NILFS_OK - no internal errors were occured.
+ * %-INVALID_SS_NFINFO - invalid number of finfo structures.
+ *
+ * In the case of valid successfull call @check_mask keeps
+ * flags with detected errors.
+ */
+static int ss_check_nfifo(struct nilfs_super_block *sbp,
+ struct nilfs_segment_summary *ss_ptr,
+ __u16 *check_mask)
+{
+ int err = NILFS_OK;
+ __u32 min_finfo_size;
+ __u32 blk_size;
+
+ if (!(*check_mask & CHECK_SS_NFINFO))
+ return NILFS_OK; /* nothing to be checked */
+
+ min_finfo_size = le32_to_cpu(ss_ptr->ss_nfinfo) *
+ (sizeof(struct nilfs_finfo) + sizeof(union nilfs_binfo));
+ blk_size = (1UL << (le32_to_cpu(sbp->s_log_block_size) +
+ NILFS_SB_BLOCK_SIZE_SHIFT));
+
+ if (le32_to_cpu(ss_ptr->ss_sumbytes) <=
+ sizeof(struct nilfs_segment_summary))
+ err = INVALID_SS_NFINFO;
+ else if (min_finfo_size >
+ (le32_to_cpu(ss_ptr->ss_sumbytes) -
+ sizeof(struct nilfs_segment_summary)))
+ err = INVALID_SS_NFINFO;
+ else if (ROUNDUP_DIV(min_finfo_size, blk_size) >
+ le32_to_cpu(ss_ptr->ss_nblocks))
+ err = INVALID_SS_NFINFO;
+ else
+ *check_mask &= ~CHECK_SS_NFINFO;
+
+ internal_debug("ss_nfinfo %d.",
+ le32_to_cpu(ss_ptr->ss_nfinfo));
+ internal_debug("check_mask %x.", *check_mask);
+
+ return (err > 0) ? -err : err;
+} /* ss_check_nfifo() */
+
+/*
+ * ss_check_cno - Check checkpoint number.
+ * @sbp: pointer on superblock.
+ * @ss_ptr: pointer on segment summary header.
+ * @check_mask: mask that defines what should be checked and returns error.
+ *
+ * Return value:
+ * NILFS_OK - no internal errors were occured.
+ * %-INVALID_SS_CNO - invalid checkpoint number.
+ *
+ * In the case of valid successfull call @check_mask keeps
+ * flags with detected errors.
+ */
+static int ss_check_cno(struct nilfs_super_block *sbp,
+ struct nilfs_segment_summary *ss_ptr,
+ __u16 *check_mask)
+{
+ int err = NILFS_OK;
+
+ if (!(*check_mask & CHECK_SS_CNO))
+ return NILFS_OK; /* nothing to be checked */
+
+ if (le64_to_cpu(ss_ptr->ss_cno) > le64_to_cpu(sbp->s_last_cno))
+ err = INVALID_SS_CNO;
+ else
+ *check_mask &= ~CHECK_SS_CNO;
+
+ internal_debug("ss_cno %lld.",
+ le64_to_cpu(ss_ptr->ss_cno));
+ internal_debug("check_mask %x.", *check_mask);
+
+ return (err > 0) ? -err : err;
+} /* ss_check_cno() */
+
+/*
+ * nilfs_ss_header_is_valid - Check that segment summary header is valid.
+ * @segment: segment sequence number.
+ * @sbp: pointer on superblock.
+ * @ss_ptr: pointer on segment summary header.
+ * @check_mask: mask that defines what should be checked and returns error.
+ *
+ * Return value:
+ * NILFS_TRUE - segment summary header is valid.
+ * NILFS_FALSE - segment summary header is in corrupted state.
+ *
+ * @check_mask contains mask of flags on items which should be checked.
+ * During checking flags of valid items are unset. At the end of execution
+ * @check_mask contains flags of corrupted items as set. These set flags
+ * inform about detected errors.
+ */
+int nilfs_ss_header_is_valid(__u64 segment,
+ struct nilfs_super_block *sbp,
+ struct nilfs_segment_summary *ss_ptr,
+ __u16 *check_mask)
+{
+ int err = NILFS_OK;
+ int sub_err = NILFS_OK;
+
+ internal_debug("SEG: %lld, sbp %p, ss_ptr %p",
+ segment, sbp, ss_ptr);
+ internal_debug("check_mask ptr %p", check_mask);
+ if (check_mask)
+ internal_debug("check_mask %x", *check_mask);
+
+ if (!sbp || !ss_ptr || !check_mask) {
+ internal_error("%s",
+ nilfs_message[INVALID_PARAMETER]);
+ err = -INVALID_PARAMETER;
+ goto end_ss_check;
+ }
+
+ if (segment >= le64_to_cpu(sbp->s_nsegments)) {
+ internal_error("%s",
+ nilfs_message[INVALID_PARAMETER]);
+ err = -INVALID_PARAMETER;
+ goto end_ss_check;
+ }
+
+ sub_err = ss_check_magic(ss_ptr, check_mask);
+ if (sub_err) {
+ err = sub_err;
+ *check_mask = CHECK_SS_MAGIC;
+ goto end_ss_check;
+ }
+
+ sub_err = ss_check_header_size(ss_ptr, check_mask);
+ if (sub_err) {
+ err = sub_err;
+ if (-UNSUPPORTED_SS_REV == sub_err)
+ *check_mask = CHECK_SS_HDR_REV;
+ else
+ *check_mask = CHECK_SS_BYTES;
+ goto end_ss_check;
+ }
+
+ sub_err = ss_check_segment_sequence_number(segment, sbp,
+ ss_ptr, check_mask);
+ if (sub_err)
+ err = sub_err;
+
+ sub_err = ss_check_seg_used_blocks_number(sbp, ss_ptr, check_mask);
+ if (sub_err)
+ err = sub_err;
+
+ sub_err = ss_check_flags(ss_ptr, check_mask);
+ if (sub_err)
+ err = sub_err;
+
+ sub_err = ss_check_creation_timestamp(sbp, ss_ptr, check_mask);
+ if (sub_err)
+ err = sub_err;
+
+ sub_err = ss_check_next_seg_start_block(segment, sbp,
+ ss_ptr, check_mask);
+ if (sub_err)
+ err = sub_err;
+
+ sub_err = ss_check_nfifo(sbp, ss_ptr, check_mask);
+ if (sub_err)
+ err = sub_err;
+
+ sub_err = ss_check_cno(sbp, ss_ptr, check_mask);
+ if (sub_err)
+ err = sub_err;
+
+end_ss_check:
+ if (-UNSUPPORTED_SS_REV == err) {
+ internal_debug("SEG: %lld unsupported segment summary",
+ segment);
+ return NILFS_TRUE;
+ } else if (err) {
+ internal_debug("SEG: %lld segment summary is corrupted",
+ segment);
+ return NILFS_FALSE;
+ } else {
+ internal_debug("SEG: %lld segment summary is correct",
+ segment);
+ return NILFS_TRUE;
+ }
+} /* nilfs_ss_header_is_valid() */
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2012-11-12 9:36 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-11-12 9:36 [PATCH v4 07/15] nilfs-utils: fsck: NILFS segment summary header check implementation Vyacheslav Dubeyko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).