[Ocfs2-tools-commits] zab commits r348 - in trunk: fsck.ocfs2
fsck.ocfs2/include libocfs2 libocfs2/include
svn-commits at oss.oracle.com
svn-commits at oss.oracle.com
Wed Oct 27 18:37:31 CDT 2004
Author: zab
Date: 2004-10-27 18:37:29 -0500 (Wed, 27 Oct 2004)
New Revision: 348
Modified:
trunk/fsck.ocfs2/fsck.c
trunk/fsck.ocfs2/include/pass1.h
trunk/fsck.ocfs2/include/problem.h
trunk/fsck.ocfs2/journal.c
trunk/fsck.ocfs2/pass0.c
trunk/fsck.ocfs2/pass1.c
trunk/libocfs2/include/ocfs2.h
trunk/libocfs2/ocfs2_err.et.in
Log:
strengthen journal replay and misc fixes encountered along the way.
o add format checking to prompt(), fix up some bonehead callers
o have mark_block_used return whether or not the block was already used
o add comments to the top of journal.c
o don't replay a journal that has bad tags
o don't replay a journal that references another's blocks
o don't replay a journal that references another's blocks
o add some prompting to journal replay, improve messages
o add a '-y' option to force yes
o add ocfs2_{clusters,blocks}_in_{blocks,bytes}()
Modified: trunk/fsck.ocfs2/fsck.c
===================================================================
--- trunk/fsck.ocfs2/fsck.c 2004-10-27 06:48:43 UTC (rev 347)
+++ trunk/fsck.ocfs2/fsck.c 2004-10-27 23:37:29 UTC (rev 348)
@@ -21,7 +21,45 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*
- * Authors: Zach Brown
+ * --
+ * Roughly o2fsck performs the following operations. Each pass' file has
+ * more details.
+ *
+ * - replay the journals if needed
+ * - walk the journal extents looking for simple inconsistencies
+ * - loops, doubly referenced blocks
+ * - need this code later anyway for verifying files
+ * and i_clusters/i_size
+ * - prompt to proceed if errors (mention backup superblock)
+ * - ignore entirely or partially replay?
+ *
+ * - pass0: clean up the inode allocators
+ * - kill loops, chains can't share groups
+ * - move local allocs back to the global or something?
+ * - verify just enough of the fields to make iterating work
+ *
+ * - pass1: walk inodes
+ * - record all valid clusters that inodes point to
+ * - make sure extent trees in inodes are consistent
+ * - inconsistencies mark inodes for deletion
+ * - update cluster bitmap
+ * - have bits reflect our set of referenced clusters
+ * - again, how to resolve local/global?
+ * * from this point on the library can trust the cluster bitmap
+ *
+ * - update the inode allocators
+ * - make sure our set of valid inodes matches the bits
+ * - make sure all the bit totals add up
+ * * from this point on the library can trust the inode allocators
+ *
+ * This makes it so only these early passes need to have global
+ * allocation goo in memory. The rest can use the library as
+ * usual.
+ *
+ * so what do we do about the extent metadata allocators? track them in
+ * the same way we track inodes in the inode suballocators, I guess. store
+ * with whatever key they have. do the suballocators only allocate extent
+ * list blocks that are only owned by a tree? that'd make it pretty easy.
*/
#include <getopt.h>
#include <limits.h>
@@ -184,7 +222,7 @@
initialize_ocfs_error_table();
- while((c = getopt(argc, argv, "b:B:npv")) != EOF) {
+ while((c = getopt(argc, argv, "b:B:npvy")) != EOF) {
switch (c) {
case 'b':
blkno = read_number(optarg);
@@ -224,6 +262,11 @@
ost->ost_answer = 1;
break;
+ case 'y':
+ ost->ost_ask = 0;
+ ost->ost_answer = 1;
+ break;
+
case 'v':
verbose = 1;
break;
Modified: trunk/fsck.ocfs2/include/pass1.h
===================================================================
--- trunk/fsck.ocfs2/include/pass1.h 2004-10-27 06:48:43 UTC (rev 347)
+++ trunk/fsck.ocfs2/include/pass1.h 2004-10-27 23:37:29 UTC (rev 348)
@@ -27,7 +27,7 @@
#include "fsck.h"
errcode_t o2fsck_pass1(o2fsck_state *ost);
-void o2fsck_mark_block_used(o2fsck_state *ost, uint64_t blkno);
+int o2fsck_mark_block_used(o2fsck_state *ost, uint64_t blkno);
#endif /* __O2FSCK_PASS1_H__ */
Modified: trunk/fsck.ocfs2/include/problem.h
===================================================================
--- trunk/fsck.ocfs2/include/problem.h 2004-10-27 06:48:43 UTC (rev 347)
+++ trunk/fsck.ocfs2/include/problem.h 2004-10-27 23:37:29 UTC (rev 348)
@@ -33,7 +33,8 @@
/* returns non-zero for yes and zero for no. The caller is expected to
* provide a thorough description of the state and the action that will
* be taken depending on the answer. Without \n termination. */
-int prompt(o2fsck_state *ost, unsigned flags, const char *fmt, ...);
+int prompt(o2fsck_state *ost, unsigned flags, const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)));
#endif /* __O2FSCK_PROBLEM_H__ */
Modified: trunk/fsck.ocfs2/journal.c
===================================================================
--- trunk/fsck.ocfs2/journal.c 2004-10-27 06:48:43 UTC (rev 347)
+++ trunk/fsck.ocfs2/journal.c 2004-10-27 23:37:29 UTC (rev 348)
@@ -21,8 +21,22 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*
- * Authors: Zach Brown
+ * --
+ * This replays the jbd journals for each node. First all the journals are
+ * walked to detect inconsistencies. Only journals with no problems will be
+ * replayed. IO errors during replay will just result in partial journal
+ * replay, just like jbd does in the kernel. Journals that don't pass
+ * consistency checks, like having overlapping blocks or strange fields, are
+ * ignored and left for later passes to clean up. Overlap testing is done
+ * using o2fsck_state's used block bitmap.
+
+ * XXX
+ * future passes need to guarantee journals exist and are the same size
+ * pass fsck trigger back up, write dirty fs, always zap/write
+ * revocation code is totally untested
+ * some setup errors, like finding the dlm system inode, are fatal
*/
+
#include <stdint.h>
#include <string.h>
#include <inttypes.h>
@@ -36,12 +50,15 @@
#include "ocfs2.h"
#include "ocfs2_disk_dlm.h"
#include "pass1.h"
+#include "problem.h"
#include "util.h"
static char *whoami = "journal recovery";
struct journal_info {
int ji_node;
+ unsigned ji_replay:1;
+
uint64_t ji_ino;
struct rb_root ji_revoke;
journal_superblock_t *ji_jsb;
@@ -185,19 +202,24 @@
return block;
}
-static uint64_t count_tags(char *buf, size_t size)
+static errcode_t count_tags(o2fsck_state *ost, char *buf, size_t size,
+ uint64_t *nr_ret)
{
journal_block_tag_t *tag, *last;
uint64_t nr = 0;
if (size < sizeof(journal_header_t) + sizeof(*tag))
- return 0;
+ return OCFS2_ET_BAD_JOURNAL_TAG;
tag = (journal_block_tag_t *)&buf[sizeof(journal_header_t)];
last = (journal_block_tag_t *)&buf[size - sizeof(*tag)];
for(; tag <= last; tag++) {
nr++;
+ if (ocfs2_block_out_of_range(ost->ost_fs,
+ be32_to_cpu(tag->t_blocknr)))
+ return OCFS2_ET_BAD_JOURNAL_TAG;
+
if (tag->t_flags & cpu_to_be32(JFS_FLAG_LAST_TAG))
break;
/* inline uuids are 16 bytes, tags are 8 */
@@ -205,34 +227,45 @@
tag += 2;
}
- return nr;
+ *nr_ret = nr;
+ return 0;
}
static errcode_t lookup_journal_block(o2fsck_state *ost,
struct journal_info *ji,
uint64_t blkoff,
- uint64_t *blkno)
+ uint64_t *blkno,
+ int check_dup)
{
errcode_t err;
int contig;
- err = ocfs2_extent_map_get_blocks(ji->ji_cinode, blkoff,
- 1, blkno, &contig);
+ err = ocfs2_extent_map_get_blocks(ji->ji_cinode, blkoff, 1, blkno,
+ &contig);
if (err)
com_err(whoami, err, "while looking up logical block "
"%"PRIu64" in node %d's journal", blkoff, ji->ji_node);
+
+ if (check_dup && o2fsck_mark_block_used(ost, *blkno)) {
+ printf("Logical block %"PRIu64" in node %d's journal maps to "
+ "block %"PRIu64" which has already been used in "
+ "another journal.\n", blkoff, ji->ji_node, *blkno);
+ err = OCFS2_ET_DUPLICATE_BLOCK;
+ }
+
return err;
}
static errcode_t read_journal_block(o2fsck_state *ost,
struct journal_info *ji,
uint64_t blkoff,
- char *buf)
+ char *buf,
+ int check_dup)
{
errcode_t err;
uint64_t blkno;
- err = lookup_journal_block(ost, ji, blkoff, &blkno);
+ err = lookup_journal_block(ost, ji, blkoff, &blkno, check_dup);
if (err)
return err;
@@ -275,7 +308,7 @@
if (revoke_this_block(&ji->ji_revoke, tag.t_blocknr, seq))
goto skip_io;
- err = read_journal_block(ost, ji, *next_block, io_buf);
+ err = read_journal_block(ost, ji, *next_block, io_buf, 1);
if (err) {
ret = err;
goto skip_io;
@@ -308,9 +341,9 @@
static errcode_t walk_journal(o2fsck_state *ost, int node,
struct journal_info *ji, char *buf, int recover)
{
- errcode_t err = 0;
+ errcode_t err, ret = 0;
uint32_t next_seq;
- uint64_t next_block;
+ uint64_t next_block, nr;
journal_superblock_t *jsb = ji->ji_jsb;
journal_header_t jh;
@@ -321,16 +354,23 @@
if (next_block == 0)
return 0;
- while(1) {
- verbosef("next_seq %"PRIu32" next_block %"PRIu64"\n", next_seq,
+ /* ret is set when bad tags are seen in the first scan and when there
+ * are io errors in the recovery scan. Only stop walking the journal
+ * when bad tags are seen in the first scan. */
+ while(recover || !ret) {
+ verbosef("next_seq %"PRIu32" final_seq %"PRIu32" next_block "
+ "%"PRIu64"\n", next_seq, ji->ji_final_seq,
next_block);
if (recover && seq_geq(next_seq, ji->ji_final_seq))
break;
- err = read_journal_block(ost, ji, next_block, buf);
- if (err)
+ /* only mark the blocks used on the first pass */
+ err = read_journal_block(ost, ji, next_block, buf, !recover);
+ if (err) {
+ ret = err;
break;
+ }
next_block = jwrap(jsb, next_block + 1);
@@ -353,14 +393,21 @@
switch(jh.h_blocktype) {
case JFS_DESCRIPTOR_BLOCK:
verbosef("found a desc type %x\n", jh.h_blocktype);
- if (!recover) {
- next_block = jwrap(jsb, next_block +
- count_tags(buf, jsb->s_blocksize));
+ /* replay the blocks described in the desc block */
+ if (recover) {
+ err = replay_blocks(ost, ji, buf, next_seq,
+ &next_block);
+ if (err)
+ ret = err;
continue;
}
- err = replay_blocks(ost, ji, buf, next_seq,
- &next_block);
+ /* just record the blocks as used and carry on */
+ err = count_tags(ost, buf, jsb->s_blocksize, &nr);
+ if (err)
+ ret = err;
+ else
+ next_block = jwrap(jsb, next_block + nr);
break;
case JFS_COMMIT_BLOCK:
@@ -386,14 +433,15 @@
ji->ji_set_final_seq = 1;
ji->ji_final_seq = next_seq;
} else if (ji->ji_final_seq != next_seq) {
- err = OCFS2_ET_IO;
- com_err(whoami, err, "while recovering the journal and found "
- "that we arrived at seq %"PRIu32" instead of seq "
- "%"PRIu32" as we expected from a previous scan.",
- next_seq, ji->ji_final_seq);
+ printf("Replaying node %d's journal stopped at seq %"PRIu32" "
+ "but an initial scan indicated that it should have "
+ "stopped at seq %"PRIu32"\n", ji->ji_node, next_seq,
+ ji->ji_final_seq);
+ if (ret == 0)
+ err = OCFS2_ET_IO;
}
- return err;
+ return ret;
}
static errcode_t prep_journal_info(o2fsck_state *ost, int node,
@@ -430,7 +478,7 @@
goto out;
}
- err = lookup_journal_block(ost, ji, 0, &ji->ji_jsb_block);
+ err = lookup_journal_block(ost, ji, 0, &ji->ji_jsb_block, 1);
if (err)
goto out;
@@ -463,34 +511,14 @@
return pub->mounted;
}
-/* XXX The only job this has is to replay the journal if it can. It doesn't
- * participate in book-keeping and doesn't try to fix up the journals. It is
- * just replaying as much as it can for the main fsck passes.
- *
- * For now this is very simple and paranoid. Any errors encountered
- * are fatal and stop fsck. I propose:
- *
- * - Allocation errors are always fatal. If we can't allocate what little
- * we need to replay the journals there's no way we will be able to
- * perform a full fsck. Instead of wiping the journal we should leave
- * the task to someone with enough mem (it won't be a lot, this is largely
- * academic.)
- *
- * - block IO errors should only effect the bits of journal recovery
- * they hit. The rest should be recovered and fsck can pick up
- * the pieces. remapping around bad blocks, etc.
- *
- * - Missing journals, insane fields, etc, should be cleared and left
- * for fsck to pick up.
- *
- * XXX pass fsck trigger back up, write dirty fs, always zap/write */
+/* XXX be more strict with the error codes that trickle up to here */
errcode_t o2fsck_replay_journals(o2fsck_state *ost)
{
errcode_t err = 0, ret = 0;
struct journal_info *jis, *ji;
journal_superblock_t *jsb;
char *buf = NULL, *dlm_buf = NULL;
- int i, max_nodes, buflen;
+ int i, max_nodes, buflen, journal_trouble = 0;
uint64_t dlm_ino;
max_nodes = OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_max_nodes;
@@ -522,40 +550,43 @@
goto out;
}
- for (i = 0; i < max_nodes ; i++) {
+ printf("Checking each node's journal.\n");
+
+ for (i = 0, ji = jis; i < max_nodes; i++, ji++) {
if (!publish_mounted_set(ost->ost_fs, dlm_buf, i, max_nodes)) {
verbosef("node %d is clean\n", i);
continue;
}
+ ji->ji_replay = 1;
+
/* check mounted bits in the publish doo-dah. */
- err = prep_journal_info(ost, i, &jis[i]);
- if (err) {
- ret = err;
- continue;
- }
+ err = prep_journal_info(ost, i, ji);
+ if (err == 0)
+ err = walk_journal(ost, i, ji, buf, 0);
- err = walk_journal(ost, i, &jis[i], buf, 0);
if (err) {
- ret = err;
- continue;
+ ji->ji_replay = 0;
+ printf("Node %d's journal can not be replayed.\n", i);
+ journal_trouble = 1;
}
}
- for (i = 0, ji = jis; ret == 0 && i < max_nodes; i++, ji++) {
- if (!ji->ji_ino)
+ for (i = 0, ji = jis; i < max_nodes; i++, ji++) {
+ if (!ji->ji_replay)
continue;
+ if (!prompt(ost, PY, "Node %d's journal needs to be replayed. "
+ "Do so?", i)) {
+ journal_trouble = 1;
+ continue;
+ }
+
err = walk_journal(ost, i, ji, buf, 1);
if (err) {
- ret = err;
+ journal_trouble = 1;
continue;
}
- /* only write back the journal super block if we were
- * able to replay the journal */
- if (ji->ji_jsb_block == 0)
- continue;
-
jsb = ji->ji_jsb;
/* reset the journal */
jsb->s_start = 0;
@@ -563,14 +594,40 @@
if (ji->ji_set_final_seq)
jsb->s_sequence = ji->ji_final_seq + 1;
+ /* we don't write back a clean 'mounted' bit here. That would
+ * have to also include having recovered the orphan dir. we
+ * updated s_start, though, so we won't replay the journal
+ * again. */
err = ocfs2_write_journal_superblock(ost->ost_fs,
ji->ji_jsb_block,
(char *)ji->ji_jsb);
- if (err)
- ret = err;
+ if (err) {
+ com_err(whoami, err, "while writing node %d's journal "
+ "super block", i);
+ journal_trouble = 1;
+ }
+
+ printf("Node %d's journal replayed successfully.\n", i);
}
+ /* XXX make sure we maintain journal_trouble in all cases */
+ if (journal_trouble &&
+ !prompt(ost, PN, "There were problems replaying journals. This "
+ "means that the file system is almost certainly badly "
+ "damanged and that fsck might do more harm than good if "
+ "it continues to try and repair. Should fsck continue "
+ "trying to repair the filesystem?")) {
+ printf("Exiting.\n");
+ exit(FSCK_ERROR);
+ }
+
out:
+ if (ret) {
+ printf("fsck does not deal gracefully with failure to even "
+ "discover a volume's journals. Exiting.\n");
+ exit(FSCK_ERROR);
+ }
+
if (jis) {
for (i = 0, ji = jis; ret == 0 && i < max_nodes; i++, ji++) {
if (ji->ji_jsb)
Modified: trunk/fsck.ocfs2/pass0.c
===================================================================
--- trunk/fsck.ocfs2/pass0.c 2004-10-27 06:48:43 UTC (rev 347)
+++ trunk/fsck.ocfs2/pass0.c 2004-10-27 23:37:29 UTC (rev 348)
@@ -21,8 +21,14 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*
- * Authors: Zach Brown
+ * Pass 0 verifies that the inode suballocators can be iterated over by
+ * latter passes without risk of running into corruption. Usually our passes
+ * are analagous to ext{2,3} but ocfs2's allocation is more dynamic. As
+ * pass 0 it only makes sure that basic iteration in pass 1 will work. After
+ * building a set of active inodes Pass 1 will call back into us to sync the
+ * bitmaps with the active inodes.
*/
+
#include <string.h>
#include <inttypes.h>
#include <time.h>
@@ -49,8 +55,10 @@
struct chain_state *cs, ocfs2_group_desc *bg,
uint64_t blkno)
{
- verbosef("checking desc at %"PRIu64" bg: %"PRIu64"\n", blkno,
- bg->bg_blkno);
+ verbosef("checking desc at %"PRIu64"; blkno %"PRIu64" size %u bits %u "
+ "free_bits %u chain %u generation %u\n", blkno, bg->bg_blkno,
+ bg->bg_size, bg->bg_bits, bg->bg_free_bits_count,
+ bg->bg_chain, bg->bg_generation);
/* We'll only consider this a valid descriptor if its signature,
* parent inode, and generation all check out */
@@ -114,6 +122,9 @@
errcode_t ret;
int rc;
+ verbosef("free %u total %u blkno %"PRIu64"\n", chain->c_free,
+ chain->c_total, chain->c_blkno);
+
if (ocfs2_block_out_of_range(ost->ost_fs, blkno))
return 0;
@@ -235,7 +246,10 @@
max_chain_rec = cl->cl_next_free_rec;
for (i = 0; i < max_chain_rec; i++) {
- cs.cs_chain_no = i;
+ /* clear it for each run */
+ cs = (struct chain_state) {
+ .cs_chain_no = i,
+ };
ret = check_chain(ost, di, &cs, &cl->cl_recs[i], buf1, buf2);
/* XXX do things :) */
}
@@ -243,42 +257,6 @@
return 0;
}
-/*
- * here's a little rough-draft of what I think the procedure should
- * look like. I'm probably missing things.
- *
- * - replay the journals if needed
- * - walk the journal extents looking for simple inconsistencies
- * - loops, doubly referenced blocks
- * - need this code later anyway for verifying files
- * and i_clusters/i_size
- * - prompt to proceed if errors (mention backup superblock)
- * - ignore entirely or partially replay?
- *
- * - clean up the inode allocators
- * - kill loops, chains can't share groups
- * - move local allocs back to the global or something?
- * - verify just enough of the fields to make iterating work
- *
- * - walk inodes
- * - record all valid clusters that inodes point to
- * - make sure extent trees in inodes are consistent
- * - inconsistencies mark inodes for deletion
- *
- * - update cluster bitmap
- * - have bits reflect our set of referenced clusters
- * - again, how to resolve local/global?
- * * from this point on the library can trust the cluster bitmap
- *
- * - update the inode allocators
- * - make sure our set of valid inodes matches the bits
- * - make sure all the bit totals add up
- * * from this point on the library can trust the inode allocators
- *
- * This makes it so only these early passes need to have global
- * allocation goo in memory. The rest can use the library as
- * usual.
- */
errcode_t o2fsck_pass0(o2fsck_state *ost)
{
@@ -325,6 +303,7 @@
blocks + ost->ost_fs->fs_blocksize,
blocks +
(ost->ost_fs->fs_blocksize * 2));
+
/* XXX maybe helped by the alternate super block */
if (ret) {
}
Modified: trunk/fsck.ocfs2/pass1.c
===================================================================
--- trunk/fsck.ocfs2/pass1.c 2004-10-27 06:48:43 UTC (rev 347)
+++ trunk/fsck.ocfs2/pass1.c 2004-10-27 23:37:29 UTC (rev 348)
@@ -39,14 +39,17 @@
static const char *whoami = "pass1";
-void o2fsck_mark_block_used(o2fsck_state *ost, uint64_t blkno)
+/* XXX need to, you know, do things with this. */
+int o2fsck_mark_block_used(o2fsck_state *ost, uint64_t blkno)
{
int was_set;
+
ocfs2_bitmap_set(ost->ost_found_blocks, blkno, &was_set);
- if (was_set) {
- verbosef("duplicate block %"PRIu64"\n", blkno);
- ocfs2_bitmap_set(ost->ost_dup_blocks, blkno, NULL);
- }
+
+ if (was_set) /* XX can go away one all callers handle this */
+ verbosef("!! duplicate block %"PRIu64"\n", blkno);
+
+ return was_set;
}
/* XXX should walk down all the i_fields to make sure we're veryfying
@@ -178,14 +181,6 @@
ocfs2_free(&buf);
}
-/* XXX maybe this should be a helper in libocfs2? */
-static uint64_t blocks_holding_bytes(ocfs2_filesys *fs, uint64_t bytes)
-{
- int b_bits = OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits;
-
- return (bytes + fs->fs_blocksize - 1) >> b_bits;
-}
-
static void check_link_data(struct verifying_blocks *vb)
{
ocfs2_dinode *di = vb->vb_di;
@@ -216,7 +211,7 @@
}
}
- expected = blocks_holding_bytes(ost->ost_fs, vb->vb_link_len + 1);
+ expected = ocfs2_blocks_in_bytes(ost->ost_fs, vb->vb_link_len + 1);
if (di->i_size != vb->vb_link_len) {
if (prompt(ost, PY, "The target of symlink inode %"PRIu64" "
@@ -235,8 +230,8 @@
if (vb->vb_num_blocks != expected) {
if (prompt(ost, PN, "The target of symlink inode %"PRIu64" "
"fits in %"PRIu64" blocks but the inode has "
- "%"PRIu64" allocated. Clear the inode?", expected,
- di->i_blkno)) {
+ "%"PRIu64" allocated. Clear the inode?",
+ di->i_blkno, expected, di->i_blkno)) {
vb->vb_clear = 1;
return;
}
@@ -290,15 +285,6 @@
return 0;
}
-/* XXX maybe this should be a helper in libocfs2? */
-static uint64_t clusters_holding_blocks(ocfs2_filesys *fs, uint64_t num_blocks)
-{
- int c_to_b_bits = OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits -
- OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits;
-
- return (num_blocks + ((1 << c_to_b_bits) - 1)) >> c_to_b_bits;
-}
-
static int check_gd_block(ocfs2_filesys *fs, uint64_t gd_blkno, int chain_num,
void *priv_data)
{
@@ -392,10 +378,10 @@
#endif
if (vb.vb_num_blocks > 0)
- expected = clusters_holding_blocks(fs, vb.vb_last_block + 1);
+ expected = ocfs2_clusters_in_blocks(fs, vb.vb_last_block + 1);
if (di->i_clusters < expected &&
- prompt(ost, PY, "inode %"PRIu64" has %"PRIu64" clusters but its "
+ prompt(ost, PY, "inode %"PRIu64" has %"PRIu32" clusters but its "
"blocks fit in %"PRIu64" clusters. Correct the number of "
"clusters?", di->i_blkno, di->i_clusters, expected)) {
di->i_clusters = expected;
Modified: trunk/libocfs2/include/ocfs2.h
===================================================================
--- trunk/libocfs2/include/ocfs2.h 2004-10-27 06:48:43 UTC (rev 347)
+++ trunk/libocfs2/include/ocfs2.h 2004-10-27 23:37:29 UTC (rev 348)
@@ -403,6 +403,15 @@
void *priv_data),
void *priv_data);
+/*
+ * ${foo}_to_${bar} is a floor function. blocks_to_clusters will
+ * returns the cluster that contains a block, not the number of clusters
+ * that hold a given number of blocks.
+ *
+ * ${foo}_in_${bar} is a ceiling function. clusters_in_blocks will give
+ * the number of clusters needed to hold a given number of blocks.
+ */
+
static inline uint64_t ocfs2_clusters_to_blocks(ocfs2_filesys *fs,
uint32_t clusters)
{
@@ -423,10 +432,35 @@
return (uint32_t)(blocks >> b_to_c_bits);
}
+static inline uint64_t ocfs2_blocks_in_bytes(ocfs2_filesys *fs, uint64_t bytes)
+{
+ uint64_t ret = bytes + fs->fs_blocksize - 1;
+
+ if (ret < bytes) /* deal with wrapping */
+ ret = UINT64_MAX;
+ return ret;
+
+ return ret >> OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits;
+}
+
+static inline uint64_t ocfs2_clusters_in_blocks(ocfs2_filesys *fs,
+ uint64_t blocks)
+{
+ int c_to_b_bits = OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits -
+ OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits;
+ uint64_t ret = blocks + ((1 << c_to_b_bits) - 1);
+
+ if (ret < blocks) /* deal with wrapping */
+ blocks = UINT64_MAX;
+
+ return ret >> c_to_b_bits;
+}
+
static inline int ocfs2_block_out_of_range(ocfs2_filesys *fs, uint64_t block)
{
return (block < OCFS2_SUPER_BLOCK_BLKNO) || (block > fs->fs_blocks);
}
+
#endif /* _FILESYS_H */
Modified: trunk/libocfs2/ocfs2_err.et.in
===================================================================
--- trunk/libocfs2/ocfs2_err.et.in 2004-10-27 06:48:43 UTC (rev 347)
+++ trunk/libocfs2/ocfs2_err.et.in 2004-10-27 23:37:29 UTC (rev 348)
@@ -62,6 +62,9 @@
ec OCFS2_ET_BAD_JOURNAL_REVOKE,
"Invalid revoke record in journal"
+ec OCFS2_ET_BAD_JOURNAL_TAG,
+ "Invalid block tag in journal"
+
ec OCFS2_ET_INODE_NOT_VALID,
"Inode is not valid (active)"
@@ -107,4 +110,7 @@
ec OCFS2_ET_EXTENT_NOT_FOUND,
"No mapping exists for the given extent range"
+ec OCFS2_ET_DUPLICATE_BLOCK,
+ "Duplicate block discovered"
+
end
More information about the Ocfs2-tools-commits
mailing list