[Ocfs-tools-commits] smushran commits r45 - trunk/fsck

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Wed Jun 2 16:09:24 CDT 2004


Author: smushran
Date: 2004-06-02 15:09:22 -0500 (Wed, 02 Jun 2004)
New Revision: 45

Added:
   trunk/fsck/blked.c
   trunk/fsck/utils.c
Log:
blked.ocfs added

Added: trunk/fsck/blked.c
===================================================================
--- trunk/fsck/blked.c	2004-06-02 20:08:57 UTC (rev 44)
+++ trunk/fsck/blked.c	2004-06-02 20:09:22 UTC (rev 45)
@@ -0,0 +1,455 @@
+/*
+ * blked.c
+ *
+ * ocfs file system block editor
+ *
+ * Copyright (C) 2003, 2004 Oracle.  All rights reserved.
+ *
+ * This program 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.
+ * 
+ * This program 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 this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ * Authors: Sunil Mushran
+ */
+
+#include "fsck.h"
+
+#define MAX_EXTENTS	2048
+#define OCFS_HBT_WAIT	10
+
+int prn_len = 1;
+int cnt_err = 0;
+int cnt_wrn = 0;
+int cnt_obj = 0;
+bool int_err = false;
+bool prn_err = false;
+
+__u32 OcfsDebugCtxt = 0;
+__u32 OcfsDebugLevel = 0;
+__u32 debug_context = 0;
+__u32 debug_level = 0;
+__u32 debug_exclude = 0;
+
+bool never_mounted = false;
+__u32 fs_version = 0;
+
+ocfs_global_ctxt OcfsGlobalCtxt;
+ocfsck_context ctxt;
+extern void version(char *progname);
+void handle_signal(int sig);
+int parse_blked_cmdline(int argc, char **argv);
+int blked_initialize(char **buf);
+bool verify_params(void);
+int edit_structure(ocfs_disk_structure *s, char *buf, int idx, int *changed,
+		   char *option);
+
+char *usage_str = 
+"usage: blked.ocfs [OPTIONS] device\n"
+"	-n No hearbeat check\n"
+"	-V Version";
+
+/*
+ * parse_blked_cmdline()
+ *
+ */
+int parse_blked_cmdline(int argc, char **argv)
+{
+	int c;
+	int ret = -1;
+	char *p;
+
+	ctxt.no_hb_chk = false;
+	ctxt.write_changes = false;
+	ctxt.verbose = false;
+
+	if (argc < 2) {
+		usage();
+		goto bail;
+	}
+
+	while (1) {
+		c = getopt(argc, argv, "nwvV?h:l:o:");
+
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'o':
+			p = strchr(optarg, '.');
+			if (!p)
+				ctxt.offset = atoll(optarg);
+			else {
+				*p = '\0';
+				ctxt.offset  = ((__u64) strtoul(optarg, NULL, 0)) << 32;
+				ctxt.offset |= strtoul(++p, NULL, 0);
+			}
+			break;
+		case 'h':
+			ctxt.offset |= ((__u64) strtoul(optarg, NULL, 0)) << 32;
+			break;
+		case 'l':
+			ctxt.offset |= strtoul(optarg, NULL, 0);
+			break;
+		case 'n':
+			ctxt.no_hb_chk = true;
+			break;
+		case 'w':
+			ctxt.write_changes = true;
+			break;
+		case 'v':
+			ctxt.verbose = true;
+			break;
+		case 'V':
+			version(argv[0]);
+			goto bail;
+		default:
+		case '?':
+			usage();
+			goto bail;
+		}
+	}
+
+	if (ctxt.write_changes)
+		ctxt.no_hb_chk = false;
+
+	ret = 0;
+bail:
+	return ret;
+}				/* parse_blked_cmdline */
+
+/*
+ * blked_initialize()
+ *
+ */
+int blked_initialize(char **buf)
+{
+	int ret = -1;
+	int fd;
+
+	if (ctxt.write_changes)
+		ctxt.flags = O_RDWR | O_LARGEFILE | O_SYNC;
+	else
+		ctxt.flags = O_RDONLY | O_LARGEFILE;
+
+	if (bind_raw(ctxt.device, &ctxt.raw_minor, ctxt.raw_device, sizeof(ctxt.raw_device)))
+		goto bail;
+
+	if (ctxt.verbose)
+		CLEAR_AND_PRINT("Bound %s to %s", ctxt.device, ctxt.raw_device);
+
+	if ((fd = myopen(ctxt.raw_device, ctxt.flags)) == -1) {
+		LOG_ERROR("Error opening %s.\n%s.", ctxt.raw_device,
+			  strerror(errno));
+		goto bail;
+	} else
+		ctxt.fd = fd;
+
+	if ((ctxt.hdr = malloc_aligned(OCFS_SECTOR_SIZE)) == NULL) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	if ((*buf = malloc_aligned(OCFS_SECTOR_SIZE)) == NULL) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+
+	/* Read the super block */
+	if (read_one_sector(fd, (char *)ctxt.hdr, 0, 0) == -1) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	/* Get the device size */
+	if (get_device_size(fd) == -1) {
+		LOG_ERROR("unable to get the device size. exiting");
+		goto bail;
+	}
+
+	ret = 0;
+
+bail:
+	return ret;
+}				/* blked_initialize */
+
+/*
+ * verify_params()
+ *
+ */
+bool verify_params(void)
+{
+	bool ret = false;
+
+	if (ctxt.offset % OCFS_SECTOR_SIZE) {
+		LOG_ERROR("invalid offset. exiting");
+		goto bail;
+	}
+
+	ret = true;
+bail:
+	return ret;
+}				/* verify_params */
+
+/*
+ * main()
+ *
+ */
+int main(int argc, char **argv)
+{
+	int i, changed;
+	char *buf = NULL;
+	ocfs_disk_structure *s;
+	ocfs_layout_t *l;
+	__u64 blocknum;
+//	GHashTable *bad = NULL;
+	char option = '\0';
+
+	memset(&ctxt, 0, sizeof(ctxt));
+	init_global_context();
+
+#define INSTALL_SIGNAL(sig)						\
+	do {								\
+		if (signal(sig, handle_signal) == SIG_ERR) {		\
+		    fprintf(stderr, "Could not set " #sig "\n");	\
+		    goto bail;						\
+		}							\
+	} while (0)
+
+	INSTALL_SIGNAL(SIGTERM);
+	INSTALL_SIGNAL(SIGINT);
+
+	init_raw_cleanup_message();
+
+	if (parse_blked_cmdline(argc, argv) == -1)
+		goto bail;
+
+	printf("offset=%llu, hi=%u, lo=%u\n", ctxt.offset, HI(ctxt.offset), LO(ctxt.offset));
+	if (!verify_params)
+		goto bail;
+
+	if (optind >= argc) {
+		usage();
+		goto bail;
+	}
+
+	version(argv[0]);
+
+	strncpy(ctxt.device, argv[optind], OCFS_MAX_FILENAME_LENGTH);
+
+	if (blked_initialize(&buf) == -1) {
+		goto bail;
+	}
+
+	/* Exit if not an OCFS volume */
+	if (memcmp(ctxt.hdr->signature, OCFS_VOLUME_SIGNATURE,
+		   strlen(OCFS_VOLUME_SIGNATURE))) {
+		printf("%s: bad signature in super block\n", ctxt.device);
+		goto bail;
+	}
+#if 0
+	/* Exit if heartbeat detected */
+	if (!ctxt.no_hb_chk) {
+		if (!check_heart_beat(&ctxt.fd, OCFSCK_PUBLISH_OFF,
+				      OCFS_SECTOR_SIZE))
+			goto quiet_bail;
+	}
+#endif
+
+	if (read_one_sector(ctxt.fd, buf, ctxt.offset, 0) == -1) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	blocknum = ctxt.offset/OCFS_SECTOR_SIZE;
+
+	l = &(ocfs_header_layout[ocfs_header_layout_sz - 1]);
+	if (blocknum < l->block + l->num_blocks) {
+		for (i = 0; i < ocfs_header_layout_sz; ++i) {
+			option = '\0';
+			l = &(ocfs_header_layout[i]);
+			if ((s = l->kind) == NULL || s->cls == NULL ||
+			    s->read == NULL || s->write == NULL)
+			       	continue;
+			if (blocknum >= l->block &&
+			    blocknum < l->block + l->num_blocks) {
+				s->output(buf, 0, NULL, stdout);
+				while (ctxt.write_changes) {
+					changed = 0;
+					if (edit_structure(s, buf, 0, &changed, &option) != -1)
+						continue;
+
+					if (!changed)
+						break;
+
+					if ((confirm_changes(ctxt.offset, s, buf, 0, NULL)) == -1)
+						LOG_PRINT("Abort write");
+
+					break;
+				}
+			}
+		}
+	} else {
+		s = find_matching_struct(buf, 0);
+		if (s) {
+			s->output(buf, 0, NULL, stdout);
+			while (ctxt.write_changes) {
+				changed = 0;
+				if (edit_structure(s, buf, 0, &changed, &option) != -1)
+					continue;
+
+				if (!changed)
+					break;
+
+				if ((confirm_changes(ctxt.offset, s, buf, 0, NULL)) == -1)
+					LOG_PRINT("Abort write");
+
+				break;
+			}
+		} else
+			LOG_ERROR("unknown structure");
+	}
+
+bail:
+	myclose(ctxt.fd);
+
+	unbind_raw(ctxt.raw_minor);
+
+	free_aligned(buf);
+	free_aligned(ctxt.hdr);
+	exit(0);
+}				/* main */
+
+/*
+ * edit_structure()
+ *
+ */
+int edit_structure(ocfs_disk_structure *s, char *buf, int idx, int *changed, char *option)
+{
+	int ret = 0;
+	int fld;
+	ocfs_class *cls;
+	ocfs_class_member *m;
+	GString *cur;
+	GString *dflt;
+	char *newval = NULL;
+	char *bad;
+	char *loc;
+
+	if ((newval = malloc(USER_INPUT_MAX)) == NULL) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	*changed = 0;
+	cls = s->cls;
+	*option = '\0';
+
+	while (1) {
+		cur = dflt = NULL;
+		bad = NULL;
+	
+		LOG_PRINT("choose a field to edit (1-%d) or 'q' to quit) : ", cls->num_members);
+		if (fgets(newval, USER_INPUT_MAX, stdin) == NULL) {
+			ret = -1;
+			break;
+		}
+
+		if ((loc = rindex(newval, '\n')) != NULL)
+			*loc = '\0';
+
+	       	if (strcasecmp(newval, "q") == 0 || strcasecmp(newval, "quit") == 0) {
+			*option = tolower(*newval);
+			ret = -1;
+			break;
+		}
+
+		fld = strtol(newval, &bad, 10);
+		fld--;
+
+		if (bad == newval || IS_INVALID_FIELD_NUM(cls, fld)) {
+			ret = 0;
+			LOG_ERROR("bad field number");
+			break;
+		}
+	
+		// show current value and default value	
+		m = &(cls->members[fld]);
+		if (m->to_string(&cur, buf, &(m->type))==-1) {
+			ret = -1;
+			LOG_ERROR("to_string failed");
+			break;
+		}
+
+		if (s->defaults(buf, &dflt, idx, fld)==-1) {
+			ret = -1;
+			LOG_ERROR("defaults failed");
+			break;
+		}
+
+		LOG_PRINT("%s : %s (default=%s)\n", m->name,
+			  cur ? cur->str : "", dflt ? dflt->str : "");
+
+		// get new value and validate it
+		if (fgets(newval, USER_INPUT_MAX, stdin) == NULL) {
+			ret = -1;
+			break;
+		}
+
+		if ((loc = rindex(newval, '\n')) != NULL)
+			*loc = '\0';
+
+	       	if (strcasecmp(newval, "q")==0 || strcasecmp(newval, "quit")==0) {
+			ret = -1;
+			break;
+		}
+
+		if (strcmp(newval, "?")==0 || strcasecmp(newval, "help")==0) {
+			char *help = m->helptext(&(m->type));
+			printf("%s\n", help);
+			free(help);
+			ret = 0;
+			break;
+		}
+
+		if ((ret = m->from_string(newval, buf, &(m->type))) == -1) {
+			LOG_ERROR("bad entry");
+			ret = -1;
+			break;
+		}
+
+		(*changed)++;
+		
+		if (dflt) {
+			g_string_free(dflt, true);
+			dflt = NULL;
+		}
+
+		if (cur) {
+			g_string_free(cur, true);
+			cur = NULL;
+		}
+	}
+
+	if (dflt)
+		g_string_free(dflt, true);
+
+	if (cur)
+		g_string_free(cur, true);
+
+bail:
+	safefree(newval);
+
+	return ret;
+}				/* edit_structure */

Added: trunk/fsck/utils.c
===================================================================
--- trunk/fsck/utils.c	2004-06-02 20:08:57 UTC (rev 44)
+++ trunk/fsck/utils.c	2004-06-02 20:09:22 UTC (rev 45)
@@ -0,0 +1,1296 @@
+/*
+ * utils.c
+ *
+ * ocfs file system check utility
+ *
+ * Copyright (C) 2003, 2004 Oracle.  All rights reserved.
+ *
+ * This program 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.
+ * 
+ * This program 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 this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ * Authors: Kurt Hackel, Sunil Mushran
+ */
+
+#include "fsck.h"
+
+extern ocfsck_context ctxt;
+extern char *usage_str; 
+
+extern int prn_len;
+extern int cnt_err;
+extern int cnt_wrn;
+extern int cnt_obj;
+extern bool int_err;
+extern bool prn_err;
+
+/*
+ * usage()
+ *
+ */
+void usage(void)
+{
+	printf("%s\n", usage_str);
+}				/* usage */
+
+void init_global_context(void)
+{
+	char *tmp;
+
+	memset(&OcfsGlobalCtxt, 0, sizeof(ocfs_global_ctxt));
+	OcfsGlobalCtxt.obj_id.type = OCFS_TYPE_GLOBAL_DATA;
+	OcfsGlobalCtxt.obj_id.size = sizeof (ocfs_global_ctxt);
+	OcfsGlobalCtxt.pref_node_num = 31;
+	OcfsGlobalCtxt.node_name = "user-tool";
+	OcfsGlobalCtxt.comm_info.type = OCFS_UDP;
+	OcfsGlobalCtxt.comm_info.ip_addr = "0.0.0.0";
+	OcfsGlobalCtxt.comm_info.ip_port = OCFS_IPC_DEFAULT_PORT;
+	OcfsGlobalCtxt.comm_info.ip_mask = NULL;
+	OcfsGlobalCtxt.comm_info_read = true;
+	memset(&OcfsGlobalCtxt.guid.id.host_id, 'f', HOSTID_LEN);
+	memset(&OcfsGlobalCtxt.guid.id.mac_id,  '0', MACID_LEN);
+
+	tmp = getenv("debug_level");
+	if (tmp)
+		debug_level = atoi(tmp);
+	tmp = getenv("debug_context");
+	if (tmp)
+		debug_context = atoi(tmp);
+	tmp = getenv("debug_exclude");
+	if (tmp)
+		debug_exclude = atoi(tmp);
+}
+
+
+/*
+ * confirm_changes()
+ *
+ */
+int confirm_changes(__u64 off, ocfs_disk_structure *s, char *buf, int idx, GHashTable *bad)
+{
+	int ret = -1;
+	char *yesno, *loc;
+	int fd = ctxt.fd;
+
+	yesno = malloc(USER_INPUT_MAX);
+	if (!yesno) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	if (s->output(buf, idx, bad, stdout)==-1) {
+		//fprintf(stderr, "at least one bad field found\n");
+	}
+
+	printf("\n\nDo you really want to write your changes out? : ");
+
+	if (fgets(yesno, USER_INPUT_MAX, stdin) == NULL) {
+		ret = -1;
+		goto bail;
+	}
+
+	if ((loc = rindex(yesno, '\n')) != NULL)
+		*loc = '\0';
+
+       	if (strcasecmp(yesno, "yes")==0 || strcasecmp(yesno, "y")==0) {
+		if (s->write(fd, buf, off, idx)==-1)
+			LOG_ERROR("failed to write data to disk");
+		else {
+			GHashTable *tmp = NULL;
+			ret = s->verify(fd, buf, idx, &tmp);
+			if (tmp != NULL)
+				g_hash_table_destroy(tmp);
+		}
+	}
+
+bail:
+	safefree(yesno);
+	return ret;
+}				/* confirm_changes */
+
+static char *saved_block = NULL;
+/*
+ * read_print_struct()
+ *
+ */
+int read_print_struct(ocfs_disk_structure *s, char *buf, __u64 off, int idx, GHashTable **bad)
+{
+	int ret = 0;
+	int fd = ctxt.fd;
+	
+	if (saved_block == NULL)
+		saved_block = malloc(512);
+
+	if (saved_block == NULL)
+		return -1;
+
+	if (s->read(fd, buf, off, idx)==-1) {
+		LOG_ERROR("failed to read data");
+		return -2;
+	}
+
+	memcpy(saved_block, buf, 512);
+
+	if (s->sig_match) {
+		if (s->sig_match(buf, idx)==-EINVAL) {
+			LOG_ERROR("Bad signature found");
+			ret = -1;
+			if (ctxt.write_changes) {
+				if (!*bad)
+					*bad = g_hash_table_new(g_direct_hash, g_direct_equal);
+				ret = confirm_changes(off, s, buf, idx, *bad);
+				LOG_PRINT("Fixed");
+			} else
+				LOG_PRINT("To fix, rerun with -w");
+			/* restore the original if the new one was not written */
+			if (ret == -1)
+				memcpy(buf, saved_block, 512);
+		}
+	}
+
+	if (s->verify(fd, buf, idx, bad)==-1) {
+		LOG_ERROR("structure failed verification");
+		ret = -1;
+	}
+
+	if (ret == -1 || (ret == 0 && ctxt.verbose)) {
+		if (s->output(buf, idx, *bad, stdout)==-1) {
+			//fprintf(stderr, "at least one bad field found\n");
+			//ret = -1;
+		}
+	}
+
+	return ret;
+}				/* read_print_struct */
+
+
+/*
+ * get_device_size()
+ *
+ */
+int get_device_size(int fd)
+{
+	int ret = -1;
+	__u32 numblks;
+	struct stat buf;
+
+	if (fstat(fd, &buf) == -1) {
+		printf("%s: %s\n", ctxt.device, strerror(errno));
+		goto bail;
+	}
+
+	if (ctxt.dev_is_file) {		/* used during testing */
+		ctxt.device_size = buf.st_size;
+		goto finito;
+	} else if (S_ISCHR(buf.st_mode)) {
+		char *junk;
+		__u64 hi, lo, new, delta, last;
+		int ret;
+
+		junk = malloc_aligned(512);
+		hi = 0xfffffffffffffd00;
+		lo = 0ULL;
+		new = hi >> 1;
+
+		ctxt.device_size = 0;
+		do {
+			last = new;
+			myseek64(fd, new, SEEK_SET);
+			ret = read(fd, junk, 512);
+			if (ret == 512) {
+				// go higher
+				ctxt.device_size = (new + 512);
+				lo = new;
+				delta = (hi - lo) >> 1;
+				new = hi - delta;
+				new &= 0xfffffffffffffd00;
+			} else {
+				// go lower
+				hi = new;
+				delta = (hi - lo) >> 1;
+				new = lo + delta;
+				new &= 0xfffffffffffffd00;
+			}
+			
+			if (last == new || hi <= lo)
+				break;
+		} while (1);
+		while (ret == 512)
+		{
+			ctxt.device_size = (new + 512);
+			myseek64(fd, new, SEEK_SET);
+			ret = read(fd, junk, 512);
+			new += 512;
+		}
+		goto finito;
+	} else {
+		if (ioctl(fd, BLKGETSIZE, &numblks) == -1) {
+			printf("%s: %s\n", ctxt.device, strerror(errno));
+			goto bail;
+		} 
+		ctxt.device_size = numblks;
+		ctxt.device_size *= OCFS_SECTOR_SIZE;
+		goto finito;
+	}
+
+finito:
+	ret = 0;
+bail:
+	return ret;
+}				/* get_device_size */
+
+
+void handle_signal(int sig)
+{
+    switch (sig) {
+    case SIGTERM:
+    case SIGINT:
+	myclose(ctxt.fd);
+	unbind_raw(ctxt.raw_minor);
+	exit(1);
+    }
+}
+
+
+/*
+ * check_heart_beat()
+ *
+ */
+int check_heart_beat(int *file, __u64 publ_off, __u32 sect_size)
+{
+	char *publish = NULL;
+	ocfs_super osb;
+	int ret = 0;
+	int i;
+	int waittime;
+	char *node_names[OCFS_MAXIMUM_NODES];
+	__u32 nodemap;
+
+	for (i = 0; i < OCFS_MAXIMUM_NODES; ++i)
+		node_names[i] = NULL;
+
+	memset (&osb, 0, sizeof(ocfs_super));
+
+	if (!read_publish(*file, publ_off, sect_size, (void **)&publish)) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	/* alloc osb and pop sect_size */
+	osb.sect_size = sect_size;
+
+        /* call ocfs_update_publish_map(first_time = true) */
+	ocfs_update_publish_map (&osb, (void *)publish, true);
+
+	/* sleep(OCFS_NM_HEARTBEAT_TIME * 10) */
+	printf("Checking heart beat on volume ");
+	waittime = (OCFS_NM_HEARTBEAT_TIME/1000);
+	waittime = (waittime ? waittime : 1);
+	for (i = 0; i < OCFS_HBT_WAIT; ++i) {
+		printf(".");
+		fflush(stdout);
+		sleep(waittime);
+	}
+   
+	/* Close and re-open device to force disk read */
+	myclose(*file);
+
+	if ((*file = myopen(ctxt.raw_device, ctxt.flags)) == -1) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	memset (publish, 0, sect_size);
+	if (!read_publish(*file, publ_off, sect_size, (void **)&publish)) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	/* call ocfs_update_publish_map(first_time = false) */
+	ocfs_update_publish_map (&osb, (void *)publish, false);
+
+	printf("\r                                                \r");
+	fflush(stdout);
+
+	/* OCFS currently supports upto 32 nodes */
+	nodemap = LO(osb.publ_map);
+	if (!nodemap)
+		goto success;
+
+	/* Get names of all the nodes */
+	get_node_names(*file, ctxt.hdr, node_names, sect_size);
+
+	/* Prints the ones which are mounted */
+	printf("%s is mounted on nodes:", ctxt.device);
+	print_node_names(node_names, nodemap);
+
+	if (ctxt.write_changes) {
+		ctxt.write_changes = false;
+		printf("umount volume on node(s) before running fsck -w\n");
+		printf("Continuing in read-only mode\n");
+	}
+
+	printf("As %s is mounted on one or more nodes, fsck.ocfs may "
+	       "display false-positive errors\n", ctxt.device);
+
+success:
+	ret = 1;
+bail:
+	for (i = 0; i < OCFS_MAXIMUM_NODES; ++i)
+		free(node_names[i]);
+
+	free_aligned(publish);
+	return ret;
+}				/* check_heart_beat */
+
+/*
+ * read_publish()
+ *
+ */
+int read_publish(int file, __u64 publ_off, __u32 sect_size, void **buf)
+{
+	int ret = 0;
+	__u32 pub_len;
+
+	pub_len = OCFS_MAXIMUM_NODES * sect_size;
+
+	if (!*buf) {
+		if (!(*buf = malloc_aligned(pub_len))) {
+			LOG_INTERNAL();
+			goto bail;
+		}
+	}
+
+	if (myseek64(file, publ_off, SEEK_SET) == -1) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	if (myread(file, *buf, pub_len) == -1) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+			
+	ret = 1;
+
+bail:
+	return ret;
+}				/* read_publish */
+
+/*
+ * get_node_names()
+ *
+ */
+int get_node_names(int file, ocfs_vol_disk_hdr *volhdr, char **node_names,
+		   __u32 sect_size)
+{
+	char *buf = NULL;
+	char *p;
+	int len;
+	int ret = 0;
+	int i;
+	ocfs_disk_node_config_info *conf;
+
+	len = volhdr->node_cfg_size;
+	if (!(buf = (char *) malloc_aligned(len))) {
+		LOG_INTERNAL();
+		goto bail;
+	} else
+		memset(buf, 0, len);
+
+	if (myseek64(file, volhdr->node_cfg_off, SEEK_SET) == -1) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	if (myread(file, buf, len) == -1) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	p = buf + (sect_size * 2);
+	for (i = 0; i < OCFS_MAXIMUM_NODES; ++i, p += sect_size) {
+		conf = (ocfs_disk_node_config_info *)p;
+		if (conf->node_name[0])
+			node_names[i] = strdup(conf->node_name);
+	}
+
+	ret = 1;
+bail:
+	free_aligned(buf);
+	return ret;
+}				/* get_node_names */
+
+
+/*
+ * print_node_names()
+ *
+ */
+void print_node_names(char **node_names, __u32 nodemap)
+{
+	int i, j;
+	char comma = '\0';
+
+	for (j = 1, i = 0; i < OCFS_MAXIMUM_NODES; ++i, j <<= 1) {
+		if (nodemap & j) {
+			if (node_names[i])
+				printf("%c %s", comma, node_names[i]);
+			else
+				printf("%c %d", comma, i);
+			comma = ',';
+		}
+	}
+	printf("\n");
+}				/* print_node_names */
+
+/*
+ * print_free_bits()
+ *
+ */
+void print_free_bits(GArray *bits, char *str)
+{
+	__u32 i, j, k;
+	__u32 bit1, bit2;
+
+	if (!bits)
+		goto bail;
+
+#if 0
+	for (i = 0; i < bits->len; ++i) {
+		bit1 = g_array_index(bits, __u32, i);
+		if (i == 0)
+			printf("\nbits: ");
+		printf("%d, ", bit1);
+	}
+	printf("\n");
+#endif
+
+	for (i = 0; i < bits->len;) {
+		bit1 = g_array_index(bits, __u32, i);
+		for (k = 0, j = i + 1; j < bits->len; ++k, ++j) {
+			bit2 = g_array_index(bits, __u32, j);
+			if (bit1 + k + 1 != bit2)
+				break;
+		}
+		if (k)
+			LOG_ERROR("Bits %u-%u are unset in the %s bitmap",
+				  bit1, bit1 + k, str);
+		else
+			LOG_ERROR("Bit %u is unset in the %s bitmap", bit1, str);
+		i += k + 1;
+	}
+
+bail:
+	return ;
+}				/* print_free_bits */
+
+/*
+ * check_global_bitmap()
+ *
+ */
+int check_global_bitmap(int fd)
+{
+	int ret = -1;
+	bitmap_data *bm1;
+	bitmap_data *bm2;
+	__u8 *vol_bm = NULL;
+	__u32 i;
+	__u32 j;
+	GArray *bits = NULL;
+	
+	bits = g_array_new(false, true, sizeof(__u32));
+
+	/* sorting the global bitmap data on alloc_node and bit_num */
+	qsort(ctxt.vol_bm_data->data, ctxt.vol_bm_data->len,
+	      sizeof(bitmap_data), &qsort_compare);
+#if 0
+	for (i = 0; i < ctxt.vol_bm_data->len; ++i) {
+		bm1 = &(g_array_index(ctxt.vol_bm_data, bitmap_data, i));
+		printf("BOO: bit=%u, num=%u, blk=%u.%u, fe=%u.%u\n", bm1->bitnum,
+		       bm1->num, HILO(bm1->fss_off), HILO(bm1->parent_off));
+	}
+#endif
+
+	/* walk the list and check for any duplicates */
+	for (i = 0; i < ctxt.vol_bm_data->len; ++i) {
+		bm1 = &(g_array_index(ctxt.vol_bm_data, bitmap_data, i));
+		for (j = i + 1; j < ctxt.vol_bm_data->len; ++j) {
+			bm2 = &(g_array_index(ctxt.vol_bm_data, bitmap_data, j));
+			if (bm2->bitnum == bm1->bitnum) {
+				LOG_ERROR("Block %u.%u (bit# %u) allocated "
+					  "to File Entries %u.%u and %u.%u",
+					  HILO(bm1->fss_off), bm1->bitnum,
+					  HILO(bm1->parent_off),
+					  HILO(bm2->parent_off));
+				continue;
+			} else
+				break;
+		}
+	}
+
+	/* make a temp copy of the volume bitmap */
+	if ((vol_bm = malloc_aligned(VOL_BITMAP_BYTES)) == NULL) {
+		LOG_INTERNAL();
+		goto bail;
+	} else
+		memcpy(vol_bm, ctxt.vol_bm, VOL_BITMAP_BYTES);
+
+	/* clearing all the allocated bits in the global bitmap */
+	for (i = 0; i < ctxt.vol_bm_data->len; ++i) {
+		bm1 = &(g_array_index(ctxt.vol_bm_data, bitmap_data, i));
+		j = __test_and_clear_bit(bm1->bitnum, vol_bm);
+		if (!j) {
+			if (!test_bit(bm1->bitnum, ctxt.vol_bm))
+				g_array_append_val(bits, bm1->bitnum);
+		}
+	}
+
+	print_free_bits(bits, "global");
+
+#ifdef STILL_DEBUGGING
+	/* cross check... ensure no bit in the global bitmap is set */
+	/* The first 1MB in the bitmap is for the system fe's */
+	j = VOL_BITMAP_BYTES / ctxt.hdr->cluster_size;
+	for (i = j; i < ctxt.hdr->num_clusters; ++i) {
+		if (test_bit(i, vol_bm))
+			LOG_ERROR("Bit %u in the global bitmap is "
+				  "unaccounted", i);
+	}
+#endif
+
+	ret = 0;
+bail:
+	if (bits)
+		g_array_free(bits, true);
+	free_aligned(vol_bm);
+	return ret;
+}				/* check_global_bitmap */
+
+
+/*
+ * check_node_bitmaps()
+ *
+ * Checks extent and directory bitmaps for all nodes
+ *
+ */
+int check_node_bitmaps(int fd, GArray *bm_data, __u8 **node_bm,
+		       __u32 *node_bm_sz, char *str)
+{
+	int ret = -1;
+	bitmap_data *bm1;
+	bitmap_data *bm2;
+	__u8 *temp_bm[OCFS_MAXIMUM_NODES];
+	__u32 i;
+	__u32 j;
+
+	/* sorting the node bitmap data on alloc_node and bit_num */
+	qsort(bm_data->data, bm_data->len, sizeof(bitmap_data), &qsort_compare);
+#ifdef STILL_DEBUGGING
+	for (i = 0; i < bm_data->len; ++i) {
+		bm1 = &(g_array_index(bm_data, bitmap_data, i));
+	}
+#endif
+	for (i = 0; i < bm_data->len; ++i) {
+		bm1 = &(g_array_index(bm_data, bitmap_data, i));
+		for (j = i + 1; j < bm_data->len; ++j) {
+			bm2 = &(g_array_index(bm_data, bitmap_data, j));
+			if (bm2->alloc_node != bm1->alloc_node)
+				break;
+			if (bm2->bitnum == bm1->bitnum) {
+				LOG_ERROR("Block %u.%u (bit# %u) allocated "
+					  "to %s %u.%u and %u.%u on node %u",
+					  HILO(bm1->fss_off), bm1->bitnum,
+					  str, HILO(bm1->parent_off),
+					  HILO(bm2->parent_off), bm1->alloc_node);
+				continue;
+			} else
+				break;
+		}
+	}
+
+	/* make a temp copy of the node bitmaps */
+	for (i = 0; i < OCFS_MAXIMUM_NODES; ++i) {
+		if (!node_bm_sz[i]) {
+			temp_bm[i] = NULL;
+			continue;
+		}
+		if ((temp_bm[i] = malloc_aligned(node_bm_sz[i])) == NULL) {
+			LOG_INTERNAL();
+			goto bail;
+		} else
+			memcpy(temp_bm[i], node_bm[i], node_bm_sz[i]);
+	}
+
+	/* clearing all the allocated bits in the extent bitmap */
+	for (i = 0; i < bm_data->len; ++i) {
+		bm1 = &(g_array_index(bm_data, bitmap_data, i));
+		if (!temp_bm[bm1->alloc_node]) {
+			LOG_ERROR("%s bitmap for node %d not allocated but "
+				  "structure at offset %u.%u suggests otherwise",
+				  str, bm1->alloc_node, HILO(bm1->fss_off));
+			continue;
+		}
+		j = __test_and_clear_bit(bm1->bitnum, temp_bm[bm1->alloc_node]);
+		if (!j) {
+			if (!test_bit(bm1->bitnum, node_bm[bm1->alloc_node]))
+				LOG_ERROR("Bit %u is unset in the %s bitmap "
+					  "of node %d", bm1->bitnum, str,
+					  bm1->alloc_node);
+		}
+	}
+
+#ifdef STILL_DEBUGGING
+	/* cross check... ensure no bit in the extent/directory bitmap is set */
+	for (i = 0; i < OCFS_MAXIMUM_NODES; ++i) {
+		if (!temp_bm[i])
+			continue;
+		len = node_bm_sz[i] * 8;
+		for (j = 0; j < len; ++j) {
+			if (test_bit(j, temp_bm[i]))
+				LOG_ERROR("Bit %u in the %s bitmap of node "
+					  "%d is unaccounted", j, str, i);
+		}
+	}
+#endif
+
+	ret = 0;
+bail:
+	for (i = 0; i < OCFS_MAXIMUM_NODES; ++i)
+		free_aligned(temp_bm[i]);
+	return ret;
+}				/* check_node_bitmaps */
+
+
+/*
+ * qsort_compare()
+ *
+ */
+int qsort_compare(const void *q1, const void *q2)
+{
+	bitmap_data *bm1 = (bitmap_data *)q1;
+	bitmap_data *bm2 = (bitmap_data *)q2;
+	__s32 ret;
+
+	ret = bm1->alloc_node - bm2->alloc_node;
+	if (!ret)
+		ret = bm1->bitnum - bm2->bitnum;
+
+	return ret;
+}				/* qsort_compare */
+
+static int fe_compare_func(const void *m1, const void *m2);
+
+/* if we ever rewrite this as a shared library or 
+ * parallelized fsck we will have to change this */
+ocfs_dir_node *globaldir = NULL;
+
+static int fe_compare_func(const void *m1, const void *m2)
+{
+	ocfs_file_entry *fe1, *fe2;
+	__u8 idx1, idx2;
+	int ret;
+
+	if (globaldir == NULL) {
+		LOG_INTERNAL();
+		exit(0);
+	}
+
+	idx1 = *(__u8 *)m1;
+	idx2 = *(__u8 *)m2;
+
+	fe1 = (ocfs_file_entry *) ((char *)FIRST_FILE_ENTRY(globaldir) + (idx1 * OCFS_SECTOR_SIZE));
+	fe2 = (ocfs_file_entry *) ((char *)FIRST_FILE_ENTRY(globaldir) + (idx2 * OCFS_SECTOR_SIZE));
+
+	if (IS_FE_DELETED(fe1->sync_flags) ||
+	    (!(fe1->sync_flags & OCFS_SYNC_FLAG_VALID)) ||
+	    IS_FE_DELETED(fe2->sync_flags) ||
+	    (!(fe2->sync_flags & OCFS_SYNC_FLAG_VALID)))
+		return 0;
+
+	ret = strncmp(fe1->filename, fe2->filename, 255);
+	
+	return -ret;
+}
+
+
+/*
+ * traverse_dir_nodes()
+ *
+ */
+void traverse_dir_nodes(int fd, __u64 offset, char *dirpath)
+{
+	int i;
+	int ret;
+	char *dirbuf = NULL;
+	ocfs_file_entry *febuf = NULL;
+	__u64 dir_offset;
+	__u64 off;
+	ocfs_disk_structure *dirst;
+	ocfs_disk_structure *fest;
+	GHashTable *bad;
+	ocfs_dir_node *dir;
+	__u8 *index = NULL;
+	int deleted_files;
+   
+	dirst = &dirnode_t;
+	fest = &fileent_t;
+	bad = NULL;
+
+	if ((index = malloc(256)) == NULL) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	if ((dirbuf = malloc_aligned(DIR_NODE_SIZE)) == NULL) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	if ((febuf = (ocfs_file_entry *) malloc_aligned(OCFS_SECTOR_SIZE)) == NULL) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	dir_offset = offset;
+	dir = (ocfs_dir_node *)dirbuf;
+
+	CLEAR_AND_PRINT(dirpath);
+
+	while (1) {
+		ret = read_print_struct(dirst, dirbuf, dir_offset, 0, &bad);
+
+		if (bad)
+			g_hash_table_destroy(bad);
+
+		if (ret == -1) {
+			LOG_ERROR("failed to read directory at offset %u.%u",
+				  HILO(dir_offset));
+			goto bail;
+		}
+
+		/* check the dir->index integrity */
+		globaldir = dir;
+		memcpy(index, dir->index, dir->num_ent_used);
+		qsort(index, dir->num_ent_used, sizeof(__u8), fe_compare_func);
+
+		if (memcmp(index, dir->index, dir->num_ent_used) != 0) {
+			__u8 *idxtmp = NULL;
+
+			LOG_ERROR("Bad dir index found");
+			printf("\n");
+			for (i=0; i<254; ++i) {
+				if (dir->index[i] != index[i]) {
+					ocfs_file_entry *f1, *f2;
+					f1 = (ocfs_file_entry *)((char *)dirbuf + 512 + (dir->index[i]*512));
+					f2 = (ocfs_file_entry *)((char *)dirbuf + 512 + (index[i]*512));
+					printf("%d, %s: %d, %s\n", dir->index[i], f1->filename, index[i], f2->filename);
+				}
+			}
+			if (ctxt.write_changes) {
+				if ((idxtmp = malloc(256)) == NULL) {
+					LOG_INTERNAL();
+					goto bail;
+				}
+				memcpy(idxtmp, dir->index, 256);
+				memcpy(dir->index, index, dir->num_ent_used);
+				if (dirst->write(ctxt.fd, dirbuf, dir_offset, 0) == -1) {
+					LOG_ERROR("failed to write at offset %u.%u",
+						  HILO(dir_offset));
+					memcpy(dir->index, idxtmp, 256);
+				}
+				safefree(idxtmp);
+				LOG_PRINT("Fixed");
+			} else
+				LOG_PRINT("To fix, rerun with -w");
+		}
+
+		/* check the undeletable dir bug, BUG #3016598 */
+		for (i=0, deleted_files=0; i < dir->num_ent_used; i++) {
+			if (IS_FE_DELETED((FILEENT(dir, i))->sync_flags))
+				deleted_files++;
+		}
+		if (dir->num_ent_used && dir->num_ent_used == deleted_files) {
+			/* we hit the bug... fix by zeroing num_ent_used */
+			LOG_ERROR("Undeletable directory found");
+			if (ctxt.write_changes) {
+				dir->num_ent_used = 0;
+				if (dirst->write(ctxt.fd, dirbuf, dir_offset, 0)==-1) {
+					LOG_ERROR("failed to write at offset %u/%u", dir_offset);
+					dir->num_ent_used = 1;
+				}
+				LOG_PRINT("Fixed");
+			} else
+				LOG_PRINT("To fix, rerun with -w");
+		}
+
+		/* Add bitmap entry for the dirnode itself */
+		add_bm_data(dir->alloc_file_off, 1, dir->alloc_node, 
+			    dir_offset,
+			    (dir->alloc_node == OCFS_INVALID_NODE_NUM ? bm_filedata : bm_dir));
+
+		// TODO: add in directory editing here
+		for (i = 0; i < dir->num_ent_used; i++) {
+			off = dir_offset;
+			off += OCFS_SECTOR_SIZE;	/* move past the dirnode header */
+			off += (OCFS_SECTOR_SIZE * dir->index[i]);
+
+			ret = read_print_struct(fest, (char *)febuf, off, 0, &bad);
+			if (bad)
+				g_hash_table_destroy(bad);
+			if (ret == -1) {
+				LOG_ERROR("failed to read file entry at offset %u.%u",
+					  HILO(off));
+				continue;
+			}
+
+			// TODO: add in file entry editing here
+
+			if (!IS_FE_DELETED(febuf->sync_flags))
+				check_file_entry(fd, febuf, off, false, dirpath);
+		}
+
+		/* is there another directory chained off of this one? */
+		if (dir->next_node_ptr == -1)
+			break;		// nope, we're done
+		else
+			dir_offset = dir->next_node_ptr;	// keep going
+	}
+
+bail:
+	free_aligned(dirbuf);
+	free_aligned(febuf);
+	safefree(index);
+}				/* traverse_dir_nodes */
+
+/*
+ * handle_one_cdsl_entry()
+ *
+ */
+void handle_one_cdsl_entry(int fd, ocfs_file_entry *fe, __u64 offset)
+{
+}				/* handle_one_cdsl_entry */
+
+
+/*
+ * check_file_entry()
+ *
+ */
+void check_file_entry(int fd, ocfs_file_entry *fe, __u64 offset,
+		      bool systemfile, char *dirpath)
+{
+	void *buf = NULL;
+	int indx = 0;
+	int val = 0;
+	char *path = NULL;
+
+	if (systemfile)
+		val = 3;
+	else {
+		if (fe->attribs & OCFS_ATTRIB_FILE_CDSL)
+			val = 1;
+		else if (fe->attribs & OCFS_ATTRIB_DIRECTORY)
+			val = 2;
+		else if (fe->attribs & (OCFS_ATTRIB_REG | OCFS_ATTRIB_SYMLINK))
+			val = 3;
+		else {
+			LOG_ERROR ("unknown attribs %x at offset %u.%u",
+				   fe->attribs, HILO(offset));
+			goto bail;
+		}
+	}
+
+	++cnt_obj;
+	if (val == 2)
+		path = g_strdup_printf("%s%s/", dirpath, fe->filename);
+	else
+		path = g_strdup_printf("%s%s", dirpath, fe->filename);
+
+	switch (val) {
+	case 1:
+		CLEAR_AND_PRINT(path);
+		handle_one_cdsl_entry(fd, fe, offset);
+		break;
+
+	case 2:
+		if (fe->extents[0].disk_off) {
+			handle_leaf_extents(fd, fe->extents, 1,
+				 	OCFS_INVALID_NODE_NUM, fe->this_sector);
+			traverse_dir_nodes(fd, fe->extents[0].disk_off, path);
+		} else
+			LOG_ERROR("Invalid dir entry at %u.%u", HILO(offset));
+		break;
+
+	case 3:
+		CLEAR_AND_PRINT(path);
+		if (fe->local_ext)
+			handle_leaf_extents(fd, fe->extents,
+					    OCFS_MAX_FILE_ENTRY_EXTENTS,
+					    OCFS_INVALID_NODE_NUM, fe->this_sector);
+		else {
+			if ((buf = malloc_aligned(MAX_EXTENTS * OCFS_SECTOR_SIZE)) == NULL) {
+				LOG_INTERNAL();
+				goto bail;
+			}
+
+			traverse_fe_extents(fd, fe, buf, &indx);
+
+			/* check ext->next_data_ext */
+			check_next_data_ext(fe, buf, indx);
+
+			/* check fe->last_ext_ptr */
+			check_fe_last_data_ext(fe, buf, indx);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+bail:
+	safefree(path);
+	free_aligned(buf);
+	return ;
+}				/* check_file_entry */
+
+/*
+ * add_bm_data()
+ *
+ */
+bitmap_data * add_bm_data(__u64 start, __u64 len, __s32 alloc_node,
+			  __u64 parent_offset, int type)
+{
+	bitmap_data *bm = NULL;
+	__u32 bitnum = 0;
+	__u32 num = 0;
+	void *buf = NULL;
+	void *p;
+	int i;
+
+	switch (type) {
+	case bm_extent:
+		bitnum = start >> OCFS_LOG_SECTOR_SIZE;
+		num = len;
+		break;
+
+	case bm_dir:
+		bitnum = start / OCFS_DEFAULT_DIR_NODE_SIZE;
+		num = len;
+		break;
+
+	case bm_symlink:
+		break;
+
+	case bm_filedata:
+		bitnum = (start - ctxt.hdr->data_start_off) >>
+				ctxt.cluster_size_bits;
+		num = len >> ctxt.cluster_size_bits;
+		break;
+
+	default:
+		break;
+	}
+
+	if (num == 0)
+		goto bail;
+
+	if ((buf = malloc(sizeof(bitmap_data) * num)) == NULL) {
+		LOG_INTERNAL();
+		goto bail;
+	}
+
+	for (i = 0, p = buf; i < num; ++i) {
+		bm = (bitmap_data *)p;
+		bm->bitnum = bitnum + i;
+		bm->fss_off = start;
+		bm->alloc_node = alloc_node;
+		bm->parent_off = parent_offset;
+		p += sizeof(bitmap_data);
+	}
+
+	bm = (bitmap_data *)buf;
+
+	switch (type) {
+	case bm_dir:
+		g_array_append_vals(ctxt.dir_bm_data, bm, num);
+		break;
+
+	case bm_extent:
+		g_array_append_vals(ctxt.ext_bm_data, bm, num);
+		break;
+
+	case bm_filedata:
+		g_array_append_vals(ctxt.vol_bm_data, bm, num);
+		break;
+
+	default:
+		break;
+	}
+
+bail:
+	return bm;
+}				/* add_bm_data */
+
+
+/*
+ * handle_leaf_extents()
+ *
+ */
+int handle_leaf_extents (int fd, ocfs_alloc_ext *arr, int num, __u32 node,
+			 __u64 parent_offset)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < num; i++) {
+		if (arr[i].disk_off)
+			if (!add_bm_data(arr[i].disk_off, arr[i].num_bytes,
+					 node, parent_offset, bm_filedata))
+				ret = -1;
+	}
+
+	return ret;
+}				/* handle_leaf_extents */
+
+
+/*
+ * traverse_extent()
+ *
+ */
+void traverse_extent(int fd, ocfs_extent_group * exthdr, int flag, void *buf,
+		     int *indx)
+{
+	ocfs_extent_group *ext = NULL;
+	int i;
+	int j;
+	__u64 len;
+	int ret;
+	int type;
+	ocfs_disk_structure *disk_struct;
+	GHashTable *bad;
+
+	if (*indx >= MAX_EXTENTS) {
+		LOG_ERROR("Too many extents after ext=%u.%u",
+			  HILO(exthdr->this_ext));
+		goto bail;
+	}
+
+	for (i = 0; i < exthdr->next_free_ext; ++i) {
+		if (!exthdr->extents[i].disk_off)
+			continue;
+
+		ext = (ocfs_extent_group *) (buf + (*indx * OCFS_SECTOR_SIZE));
+		++*indx;
+
+		if (flag == OCFS_EXTENT_HEADER)
+			disk_struct = &exthdr_t;
+		else
+			disk_struct = &extdat_t;
+
+		ret = read_print_struct(disk_struct, (char *)ext,
+					exthdr->extents[i].disk_off, 0, &bad);
+
+		if (bad)
+			g_hash_table_destroy(bad);
+
+		if (ret == -1) {
+			LOG_ERROR("failed to read extent at offset %u.%u",
+				  HILO(exthdr->extents[i].disk_off));
+			goto bail;
+		}
+
+		// TODO: add in extent editing here
+
+		/* check up_hdr_node_ptr */
+		if (exthdr->this_ext != ext->up_hdr_node_ptr) {
+			LOG_ERROR("up_hdr_node_ptr %u.%u in extent %u.%u "
+				  "should be %u.%u", HILO(ext->up_hdr_node_ptr),
+				  HILO(ext->this_ext), HILO(exthdr->this_ext));
+		}
+
+		/* check first file offset */
+		if (exthdr->extents[i].file_off != ext->extents[0].file_off) {
+			LOG_ERROR("extents[0].file_off=%u.%u in extent %u.%u "
+				  "should be %u.%u", HILO(ext->extents[0].file_off),
+				  HILO(ext->this_ext), HILO(exthdr->extents[i].file_off));
+		}
+
+		/* check total bytes */
+		for (j = 0, len = 0; j < OCFS_MAX_DATA_EXTENTS; j++)
+			len += ext->extents[j].num_bytes;
+
+		if (exthdr->extents[i].num_bytes != len) {
+			LOG_ERROR("total num_bytes in extent %u.%u is %u.%u "
+				  "but should be %u.%u", HILO(ext->this_ext),
+				  HILO(len), HILO(exthdr->extents[i].num_bytes));
+		}
+
+		/* Add bitmap entry for the extent itself */
+		add_bm_data(ext->alloc_file_off, 1, ext->alloc_node, ext->this_ext,
+			    bm_extent);
+
+		if (flag == OCFS_EXTENT_HEADER) {
+			type = ext->granularity ? OCFS_EXTENT_HEADER : OCFS_EXTENT_DATA;
+			traverse_extent(fd, ext, type, buf, indx);
+		} else {
+			handle_leaf_extents(fd, ext->extents, ext->next_free_ext,
+					    OCFS_INVALID_NODE_NUM, ext->this_ext);
+		}
+	}
+
+bail:
+	return ;
+}				/* traverse_extent */
+
+
+/*
+ * traverse_fe_extents()
+ *
+ */
+void traverse_fe_extents(int fd, ocfs_file_entry *fe, void *buf, int *indx)
+{
+	int i;
+	int j;
+	int ret;
+	__u64 len;
+	ocfs_extent_group *ext = NULL;
+	int type;
+	ocfs_disk_structure *disk_struct;
+	GHashTable *bad;
+
+	if (*indx >= MAX_EXTENTS) {
+		LOG_ERROR("error too many extents in fe at offset %u.%u",
+			  HILO(fe->this_sector));
+		goto bail;
+	}
+
+	for (i = 0; i < fe->next_free_ext; i++) {
+		if (!fe->extents[i].disk_off)
+			continue;
+
+		ext = (ocfs_extent_group *) (buf + (*indx * OCFS_SECTOR_SIZE));
+		++*indx;
+
+		if (fe->granularity)
+			disk_struct = &exthdr_t;
+		else
+			disk_struct = &extdat_t;
+
+		ret = read_print_struct(disk_struct, (char *)ext, 
+					fe->extents[i].disk_off, 0, &bad);
+		if (bad)
+			g_hash_table_destroy(bad);
+
+		if (ret == -1) {
+			LOG_ERROR("failed to read extent at offset %u.%u",
+				  HILO(fe->extents[i].disk_off));
+			goto bail;
+		}
+
+		// TODO: add in extent editing here
+		if (fe->this_sector != ext->up_hdr_node_ptr) {
+			LOG_ERROR("up_hdr_node_ptr %u.%u in extent %u.%u "
+				  "should be %u.%u", HILO(ext->up_hdr_node_ptr),
+				  HILO(ext->this_ext), HILO(fe->this_sector));
+		}
+
+		/* check first file offset */
+		if (fe->extents[i].file_off != ext->extents[0].file_off) {
+			LOG_ERROR("extents[0].file_off=%u.%u in extent %u.%u "
+				  "should be %u.%u", HILO(ext->extents[0].file_off),
+				  HILO(ext->this_ext), HILO(fe->extents[i].file_off));
+		}
+
+		/* check total bytes */
+		for (j = 0, len = 0; j < OCFS_MAX_DATA_EXTENTS; j++)
+			len += ext->extents[j].num_bytes;
+
+		if (fe->extents[i].num_bytes != len) {
+			LOG_ERROR("total num_bytes in extent %u.%u is %u.%u "
+				  "but should be %u.%u", HILO(ext->this_ext),
+				  HILO(len), HILO(fe->extents[i].num_bytes));
+		}
+
+		/* Add bitmap entry for the extent itself */
+		add_bm_data(ext->alloc_file_off, 1, ext->alloc_node, ext->this_ext,
+			    bm_extent);
+
+		if (fe->granularity) {
+			type = ext->granularity ? OCFS_EXTENT_HEADER : OCFS_EXTENT_DATA;
+			traverse_extent(fd, ext, type, buf, indx);
+		} else {
+			handle_leaf_extents(fd, ext->extents, ext->next_free_ext,
+					    OCFS_INVALID_NODE_NUM, ext->this_ext);
+		}
+	}
+
+bail:
+	return ;
+}				/* traverse_fe_extents */
+
+
+/*
+ * check_next_data_ext()
+ *
+ */
+int check_next_data_ext(ocfs_file_entry *fe, void *buf, int indx)
+{
+	void *ptr;
+	int i;
+	__u64 next_data_ext;
+	ocfs_extent_group *ext;
+	int ret = 0;
+
+	ptr = buf + ((indx - 1) * OCFS_SECTOR_SIZE);
+
+	for (i = indx - 1, next_data_ext = 0; i >= 0; --i,
+	     ptr -= OCFS_SECTOR_SIZE) {
+		ext = (ocfs_extent_group *)ptr;
+
+		if (ext->type != OCFS_EXTENT_DATA)
+			continue;
+
+		if (ext->next_data_ext != next_data_ext) {
+			LOG_ERROR("ext->next_data_ext=%u.%u in extent "
+				  "%u.%u instead of %u.%u",
+				  HILO(ext->next_data_ext),
+				  HILO(ext->this_ext),
+				  HILO(next_data_ext));
+			ret = -1;
+		}
+		next_data_ext = ext->this_ext;
+	}
+
+	return ret;
+}				/* check_next_data_ext */
+
+/*
+ * check_fe_last_data_ext()
+ *
+ */
+int check_fe_last_data_ext(ocfs_file_entry *fe, void *buf, int indx)
+{
+	ocfs_extent_group *ext;
+	int ret = 0;
+
+	ext = (ocfs_extent_group *) (buf + ((indx - 1) * OCFS_SECTOR_SIZE));
+
+	if (fe->last_ext_ptr != ext->this_ext) {
+		LOG_ERROR("fe->last_ext_ptr=%u.%u in fe %u.%u "
+			  "instead of %u.%u", HILO(fe->last_ext_ptr),
+			  HILO(fe->this_sector), HILO(ext->this_ext));
+		ret = -1;
+	}
+
+	return ret;
+}				/* check_fe_last_data_ext */



More information about the Ocfs-tools-commits mailing list