[Ocfs2-tools-commits] smushran commits r1215 - in trunk: libocfs2/include tunefs.ocfs2

svn-commits@oss.oracle.com svn-commits at oss.oracle.com
Wed Jul 19 12:31:51 CDT 2006


Author: smushran
Signed-off-by: mfasheh
Signed-off-by: jlbec
Date: 2006-07-19 12:31:50 -0500 (Wed, 19 Jul 2006)
New Revision: 1215

Modified:
   trunk/libocfs2/include/ocfs2.h
   trunk/tunefs.ocfs2/tunefs.c
Log:
tunefs - fs extend feature added
Signed-Off-by: mfasheh
Signed-Off-by: jlbec

Modified: trunk/libocfs2/include/ocfs2.h
===================================================================
--- trunk/libocfs2/include/ocfs2.h	2006-07-19 17:28:17 UTC (rev 1214)
+++ trunk/libocfs2/include/ocfs2.h	2006-07-19 17:31:50 UTC (rev 1215)
@@ -655,6 +655,21 @@
 	return (uint32_t)(ret >> c_to_b_bits);
 }
 
+/* given a cluster offset, calculate which block group it belongs to
+ * and return that block offset. */
+static inline uint64_t ocfs2_which_cluster_group(ocfs2_filesys *fs,
+						 uint16_t cpg,
+						 uint32_t cluster)
+{
+	struct ocfs2_super_block *sb = OCFS2_RAW_SB(fs->fs_super);
+	uint32_t group_no;
+
+	group_no = cluster / cpg;
+	if (!group_no)
+		return sb->s_first_cluster_group;
+	return ocfs2_clusters_to_blocks(fs, group_no * cpg);
+}
+
 static inline int ocfs2_block_out_of_range(ocfs2_filesys *fs, uint64_t block)
 {
 	return (block < OCFS2_SUPER_BLOCK_BLKNO) || (block > fs->fs_blocks);

Modified: trunk/tunefs.ocfs2/tunefs.c
===================================================================
--- trunk/tunefs.ocfs2/tunefs.c	2006-07-19 17:28:17 UTC (rev 1214)
+++ trunk/tunefs.ocfs2/tunefs.c	2006-07-19 17:31:50 UTC (rev 1215)
@@ -3,7 +3,7 @@
  *
  * ocfs2 tune utility
  *
- * Copyright (C) 2004 Oracle Corporation.  All rights reserved.
+ * Copyright (C) 2004, 2006 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
@@ -48,6 +48,7 @@
 #include <ocfs2.h>
 #include <ocfs2_fs.h>
 #include <ocfs1_fs_compat.h>
+#include <bitops.h>
 
 #include <jbd.h>
 
@@ -64,7 +65,7 @@
 
 typedef struct _ocfs2_tune_opts {
 	uint16_t num_slots;
-	uint64_t vol_size;
+	uint64_t num_blocks;
 	uint64_t jrnl_size;
 	char *vol_label;
 	char *progname;
@@ -79,13 +80,14 @@
 static ocfs2_tune_opts opts;
 static ocfs2_filesys *fs_gbl = NULL;
 static int cluster_locked = 0;
+static int resize = 0;
 
 static void usage(const char *progname)
 {
 	fprintf(stderr, "usage: %s [-N number-of-node-slots] "
 			"[-L volume-label]\n"
-			"\t[-J journal-options] [-S volume-size] [-qvV] "
-			"device\n",
+			"\t[-J journal-options] [-S] [-qvV] "
+			"device [blocks-count]\n",
 			progname);
 	exit(0);
 }
@@ -231,9 +233,7 @@
 {
 	int c;
 	int show_version = 0;
-	int ret;
 	char *dummy;
-	uint64_t val;
 
 	static struct option long_options[] = {
 		{ "label", 1, 0, 'L' },
@@ -254,7 +254,7 @@
 	opts.prompt = 1;
 
 	while (1) {
-		c = getopt_long(argc, argv, "L:N:J:S:vqVx", long_options, 
+		c = getopt_long(argc, argv, "L:N:J:SvqVx", long_options,
 				NULL);
 
 		if (c == -1)
@@ -297,10 +297,7 @@
 			break;
 
 		case 'S':
-			ret = get_number(optarg, &val);
-			if (ret)
-				exit(1);
-			opts.vol_size = val;
+			resize = 1;
 			break;
 
 		case 'v':
@@ -328,6 +325,12 @@
 	if (!opts.quiet || show_version)
 		version(opts.progname);
 
+	if (resize && (opts.num_slots || opts.jrnl_size)) {
+		com_err(opts.progname, 0, "Cannot resize volume while adding slots "
+			"or resizing the journals");
+		exit(0);
+	}
+
 	if (show_version)
 		exit(0);
 
@@ -335,12 +338,80 @@
 		usage(opts.progname);
 
 	opts.device = strdup(argv[optind]);
+	optind++;
 
+	if (optind < argc) {
+		if (resize) {
+			opts.num_blocks = strtoull(argv[optind], &dummy, 0);
+			if ((*dummy)) {
+				com_err(opts.progname, 0, "Block count bad - %s",
+					argv[optind]);
+				exit(1);
+			}
+		}
+		optind++;
+	}
+
+	if (optind < argc)
+		usage(opts.progname);
+
 	opts.tune_time = time(NULL);
 
 	return ;
 }
 
+static void get_vol_size(ocfs2_filesys *fs)
+{
+	errcode_t ret = 0;
+	uint64_t num_blocks;
+
+	ret = ocfs2_get_device_size(opts.device, fs->fs_blocksize,
+				    &num_blocks);
+	if (ret) {
+		com_err(opts.progname, ret, "while getting size of device %s",
+			opts.device);
+		exit(1);
+	}
+
+	if (!opts.num_blocks)
+		opts.num_blocks = num_blocks;
+
+	if (opts.num_blocks > num_blocks) {
+		fprintf(stderr, "The containing partition (or device) "
+			"is only %"PRIu64" blocks.\n", num_blocks);
+		exit(1);
+	}
+
+	return ;
+}
+
+static int validate_vol_size(ocfs2_filesys *fs)
+{
+	uint64_t num_blocks;
+
+	if (opts.num_blocks == fs->fs_blocks) {
+		fprintf(stderr, "The filesystem is already "
+			"%"PRIu64" blocks\n", fs->fs_blocks);
+		return -1;
+	}
+
+	if (opts.num_blocks < fs->fs_blocks) {
+		fprintf(stderr, "Cannot shrink volume size from "
+		       "%"PRIu64" blocks to %"PRIu64" blocks\n",
+		       fs->fs_blocks, opts.num_blocks);
+		return -1;
+	}
+
+	num_blocks = ocfs2_clusters_to_blocks(fs, 1);
+	if (num_blocks > (opts.num_blocks - fs->fs_blocks)) {
+		fprintf(stderr, "Cannot grow volume size less than "
+		       "%d blocks\n", num_blocks);
+		return -1;
+	}
+
+	return 0;
+}
+
 static errcode_t add_slots(ocfs2_filesys *fs)
 {
 	errcode_t ret = 0;
@@ -459,6 +530,165 @@
 	return ret;
 }
 
+static void get_total_free_bits(struct ocfs2_group_desc *gd, int *bits)
+{
+	int end = 0;
+	int start;
+
+	*bits = 0;
+
+	while (end < gd->bg_bits) {
+		start = ocfs2_find_next_bit_clear(gd->bg_bitmap, gd->bg_bits, end);
+		if (start >= gd->bg_bits)
+			break;
+		end = ocfs2_find_next_bit_set(gd->bg_bitmap, gd->bg_bits, start);
+		*bits += (end - start);
+	}
+}
+
+static errcode_t validate_chain_group(ocfs2_filesys *fs, struct ocfs2_dinode *di,
+				      int chain)
+{
+	errcode_t ret = 0;
+	uint64_t blkno;
+	char *buf = NULL;
+	struct ocfs2_group_desc *gd;
+	struct ocfs2_chain_list *cl;
+	struct ocfs2_chain_rec *cr;
+	uint32_t total = 0;
+	uint32_t free = 0;
+	uint32_t bits;
+
+	ret = ocfs2_malloc_block(fs->fs_io, &buf);
+	if (ret)
+		goto bail;
+
+	total = 0;
+	free = 0;
+
+	cl = &(di->id2.i_chain);
+	cr = &(cl->cl_recs[chain]);
+	blkno = cr->c_blkno;
+
+	while (blkno) {
+		ret = ocfs2_read_group_desc(fs, blkno, buf);
+		if (ret) {
+			com_err(opts.progname, ret,
+				"while reading group descriptor at "
+				"block %"PRIu64"", blkno);
+			goto bail;
+		}
+
+		gd = (struct ocfs2_group_desc *)buf;
+
+		if (gd->bg_parent_dinode != di->i_blkno) {
+			ret = OCFS2_ET_CORRUPT_CHAIN;
+			com_err(opts.progname, ret, " - group descriptor at "
+				"%"PRIu64" does not belong to allocator %"PRIu64"",
+				blkno, di->i_blkno);
+			goto bail;
+		}
+
+		if (gd->bg_chain != chain) {
+			ret = OCFS2_ET_CORRUPT_CHAIN;
+			com_err(opts.progname, ret, " - group descriptor at "
+				"%"PRIu64" does not agree to the chain it "
+				"belongs to in allocator %"PRIu64"",
+				blkno, di->i_blkno);
+			goto bail;
+		}
+
+		get_total_free_bits(gd, &bits);
+		if (bits != gd->bg_free_bits_count) {
+			ret = OCFS2_ET_CORRUPT_CHAIN;
+			com_err(opts.progname, ret, " - group descriptor at "
+				"%"PRIu64" does not have a consistent free "
+				"bit count", blkno);
+			goto bail;
+		}
+
+		if (gd->bg_bits > gd->bg_size * 8) {
+			ret = OCFS2_ET_CORRUPT_CHAIN;
+			com_err(opts.progname, ret, " - group descriptor at "
+				"%"PRIu64" does not have a valid total bit "
+				"count", blkno);
+			goto bail;
+		}
+
+		if (gd->bg_free_bits_count >= gd->bg_bits) {
+			ret = OCFS2_ET_CORRUPT_CHAIN;
+			com_err(opts.progname, ret, " - group descriptor at "
+				"%"PRIu64" has inconsistent free/total bit "
+				"counts", blkno);
+			goto bail;
+		}
+
+		total += gd->bg_bits;
+		free += gd->bg_free_bits_count;
+		blkno = gd->bg_next_group;
+	}
+
+	if (cr->c_total != total) {
+		ret = OCFS2_ET_CORRUPT_CHAIN;
+		com_err(opts.progname, ret, " - total bits for chain %u in "
+			"allocator %"PRIu64" does not match its chained group "
+			"descriptors", chain, di->i_blkno);
+		goto bail;
+
+	}
+
+	if (cr->c_free != free) {
+		ret = OCFS2_ET_CORRUPT_CHAIN;
+		com_err(opts.progname, ret, " - free bits for chain %u in "
+			"allocator %"PRIu64" does not match its chained group "
+			"descriptors", chain, di->i_blkno);
+		goto bail;
+	}
+
+bail:
+	if (buf)
+		ocfs2_free(&buf);
+
+	return ret;
+}
+
+static errcode_t global_bitmap_check(ocfs2_filesys *fs)
+{
+	errcode_t ret = 0;
+	uint64_t bm_blkno = 0;
+	char *buf = NULL;
+	struct ocfs2_chain_list *cl;
+	struct ocfs2_dinode *di;
+	int i;
+
+	ret = ocfs2_malloc_block(fs->fs_io, &buf);
+	if (ret)
+		goto bail;
+
+	ret = ocfs2_lookup_system_inode(fs, GLOBAL_BITMAP_SYSTEM_INODE, 0,
+					&bm_blkno);
+	if (ret)
+		goto bail;
+
+	ret = ocfs2_read_inode(fs, bm_blkno, buf);
+	if (ret)
+		goto bail;
+
+	di = (struct ocfs2_dinode *)buf;
+	cl = &(di->id2.i_chain);
+
+	for (i = 0; i < cl->cl_next_free_rec; ++i) {
+		ret = validate_chain_group(fs, di, i);
+		if (ret)
+			goto bail;
+	}
+
+bail:
+	if (buf)
+		ocfs2_free(&buf);
+	return ret;
+}
+
 static void update_volume_label(ocfs2_filesys *fs, int *changed)
 {
   	memset (OCFS2_RAW_SB(fs->fs_super)->s_label, 0,
@@ -544,8 +774,196 @@
 
 static errcode_t update_volume_size(ocfs2_filesys *fs, int *changed)
 {
-	printf("TODO: update_volume_size\n");
-	return 0;
+	errcode_t ret = 0;
+	struct ocfs2_dinode *di;
+	uint64_t bm_blkno = 0;
+	uint64_t gd_blkno = 0;
+	uint64_t lgd_blkno = 0;
+	char *in_buf = NULL;
+	char *gd_buf = NULL;
+	char *lgd_buf = NULL;
+	struct ocfs2_chain_list *cl;
+	struct ocfs2_chain_rec *cr;
+	struct ocfs2_group_desc *gd;
+	uint32_t cluster_chunk;
+	uint32_t num_new_clusters, save_new_clusters;
+	uint32_t first_new_cluster;
+	uint16_t chain;
+	uint32_t used_bits;
+	uint32_t total_bits;
+	uint32_t num_bits;
+	int flush_lgd = 0;
+	char *zero_buf = NULL;
+
+	ret = ocfs2_malloc_block(fs->fs_io, &in_buf);
+	if (ret)
+		goto bail;
+
+	ret = ocfs2_malloc_block(fs->fs_io, &gd_buf);
+	if (ret)
+		goto bail;
+
+	ret = ocfs2_malloc_block(fs->fs_io, &lgd_buf);
+	if (ret)
+		goto bail;
+
+	ret = ocfs2_malloc_blocks(fs->fs_io, ocfs2_clusters_to_blocks(fs, 1),
+				  &zero_buf);
+	if (ret)
+		goto bail;
+
+	memset(zero_buf, 0, fs->fs_clustersize);
+
+	/* read global bitmap */
+	ret = ocfs2_lookup_system_inode(fs, GLOBAL_BITMAP_SYSTEM_INODE, 0,
+					&bm_blkno);
+	if (ret)
+		goto bail;
+
+	ret = ocfs2_read_inode(fs, bm_blkno, in_buf);
+	if (ret)
+		goto bail;
+
+	di = (struct ocfs2_dinode *)in_buf;
+	cl = &(di->id2.i_chain);
+
+	total_bits = di->id1.bitmap1.i_total;
+	used_bits = di->id1.bitmap1.i_used;
+
+	first_new_cluster = di->i_clusters;
+	save_new_clusters = num_new_clusters =
+	       	ocfs2_blocks_to_clusters(fs, opts.num_blocks) - di->i_clusters;
+
+	/* Find the blknum of the last cluster group */
+	lgd_blkno = ocfs2_which_cluster_group(fs, cl->cl_cpg, first_new_cluster - 1);
+
+	ret = ocfs2_read_group_desc(fs, lgd_blkno, lgd_buf);
+	if (ret)
+		goto bail;
+
+	gd = (struct ocfs2_group_desc *)lgd_buf;
+
+	/* If only one cluster group then see if we need to adjust up cl_cpg */
+	if (cl->cl_next_free_rec == 1) {
+		if (cl->cl_cpg < 8 * gd->bg_size)
+			cl->cl_cpg = 8 * gd->bg_size;
+	}
+
+	chain = gd->bg_chain;
+
+	/* If possible round off the last group to cpg */
+	cluster_chunk = MIN(num_new_clusters,
+			    (cl->cl_cpg - (gd->bg_bits/cl->cl_bpc)));
+	if (cluster_chunk) {
+		num_new_clusters -= cluster_chunk;
+		first_new_cluster += cluster_chunk;
+
+		num_bits = cluster_chunk * cl->cl_bpc;
+
+		gd->bg_bits += num_bits;
+		gd->bg_free_bits_count += num_bits;
+
+		cr = &(cl->cl_recs[chain]);
+		cr->c_total += num_bits;
+		cr->c_free += num_bits;
+
+		total_bits += num_bits;
+
+		fs->fs_clusters += cluster_chunk;
+		fs->fs_blocks += ocfs2_clusters_to_blocks(fs, cluster_chunk);
+
+		/* This cluster group block is written after the new */
+		/* cluster groups are written to disk */
+		flush_lgd = 1;
+	}
+
+	/* Init the new groups and write to disk */
+	/* Add these groups one by one starting from the first chain after */
+	/* the one containing the last group */
+
+	gd = (struct ocfs2_group_desc *)gd_buf;
+
+	while(num_new_clusters) {
+		gd_blkno = ocfs2_which_cluster_group(fs, cl->cl_cpg,
+						     first_new_cluster);
+		cluster_chunk = MIN(num_new_clusters, cl->cl_cpg);
+		num_new_clusters -= cluster_chunk;
+		first_new_cluster += cluster_chunk;
+
+		if (++chain >= cl->cl_count)
+			chain = 0;
+
+		ocfs2_init_group_desc(fs, gd, gd_blkno,
+				      fs->fs_super->i_fs_generation, di->i_blkno,
+				      (cluster_chunk *cl->cl_bpc), chain);
+
+		/* Add group to chain */
+		cr = &(cl->cl_recs[chain]);
+		if (chain >= cl->cl_next_free_rec) {
+			cl->cl_next_free_rec++;
+			cr->c_free = 0;
+			cr->c_total = 0;
+			cr->c_blkno = 0;
+		}
+
+		gd->bg_next_group = cr->c_blkno;
+		cr->c_blkno = gd_blkno;
+		cr->c_free += gd->bg_free_bits_count;
+		cr->c_total += gd->bg_bits;
+
+		used_bits += (gd->bg_bits - gd->bg_free_bits_count);
+		total_bits += gd->bg_bits;
+
+		fs->fs_clusters += cluster_chunk;
+		fs->fs_blocks += ocfs2_clusters_to_blocks(fs, cluster_chunk);
+
+		/* Initialize the first cluster in the group */
+		ret = io_write_block(fs->fs_io, gd_blkno,
+				     ocfs2_clusters_to_blocks(fs, 1), zero_buf);
+		if (ret)
+			goto bail;
+
+		/* write a new group descriptor */
+		ret = ocfs2_write_group_desc(fs, gd_blkno, gd_buf);
+		if (ret)
+			goto bail;
+	}
+
+	di->id1.bitmap1.i_total = total_bits;
+	di->id1.bitmap1.i_used = used_bits;
+
+	di->i_clusters += save_new_clusters;
+	di->i_size = (uint64_t) di->i_clusters * fs->fs_clustersize;
+
+	fs->fs_super->i_clusters = di->i_clusters;
+
+	block_signals(SIG_BLOCK);
+	/* Flush that last group descriptor we updated before the new ones */
+	if (flush_lgd) {
+		ret = ocfs2_write_group_desc(fs, lgd_blkno, lgd_buf);
+		if (ret)
+			goto bail;
+	}
+
+	/* write the global bitmap inode */
+	ret = ocfs2_write_inode(fs, bm_blkno, in_buf);
+	if (ret)
+		goto bail;
+	block_signals(SIG_UNBLOCK);
+
+	*changed = 1;
+
+bail:
+	if (zero_buf)
+		ocfs2_free(&zero_buf);
+	if (in_buf)
+		ocfs2_free(&in_buf);
+	if (gd_buf)
+		ocfs2_free(&gd_buf);
+	if (lgd_buf)
+		ocfs2_free(&lgd_buf);
+
+	return ret;
 }
 
 int main(int argc, char **argv)
@@ -555,11 +973,10 @@
 	int upd_label = 0;
 	int upd_slots = 0;
 	int upd_jrnls = 0;
-	int upd_vsize = 0;
+	int upd_blocks = 0;
 	uint16_t tmp;
 	uint64_t def_jrnl_size = 0;
 	uint64_t num_clusters;
-	uint64_t vol_size = 0;
 	int dirty = 0;
 
 	initialize_ocfs_error_table();
@@ -596,6 +1013,9 @@
 	}
 	fs_gbl = fs;
 
+	if (resize)
+		get_vol_size(fs);
+
 	ret = ocfs2_initialize_dlm(fs);
 	if (ret) {
 		com_err(opts.progname, ret, " ");
@@ -617,6 +1037,15 @@
 	if (ret || dirty)
 		goto unlock;
 
+	/* If operation requires touching the global bitmap, ensure it is good */
+	/* This is to handle failed resize */
+	if (opts.num_blocks || opts.num_slots || opts.jrnl_size) {
+		if (global_bitmap_check(fs)) {
+			fprintf(stderr, "Global bitmap check failed. Run fsck.ocfs2.\n");
+			goto unlock;
+		}
+	}
+
 	/* validate volume label */
 	if (opts.vol_label) {
 		printf("Changing volume label from %s to %s\n",
@@ -630,8 +1059,8 @@
 			printf("Changing number of node slots from %d to %d\n",
 			       tmp, opts.num_slots);
 		} else {
-			printf("ERROR: Node slots (%d) has to be larger than "
-			       "configured node slots (%d)\n", 
+			fprintf(stderr, "Node slots (%d) has to be larger than "
+				"configured node slots (%d)\n",
 			       opts.num_slots, tmp);
 			goto unlock;
 		}
@@ -653,25 +1082,28 @@
 			       def_jrnl_size, opts.jrnl_size);
 		else {
 			if (!opts.num_slots) {
-				printf("ERROR: Journal size %"PRIu64" has to be larger "
-				       "than %"PRIu64"\n", opts.jrnl_size, def_jrnl_size);
+				fprintf(stderr, "Journal size %"PRIu64" has to "
+					"be larger " "than %"PRIu64"\n",
+					opts.jrnl_size, def_jrnl_size);
 				goto unlock;
 			}
 		}
 	}
 
 	/* validate volume size */
-	if (opts.vol_size) {
-		num_clusters = (opts.vol_size + fs->fs_clustersize - 1) >>
-				OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits;
-		opts.vol_size = num_clusters <<
-				OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits;
+	if (opts.num_blocks) {
+		if (validate_vol_size(fs))
+			opts.num_blocks = 0;
+		else
+			printf("Changing volume size %"PRIu64" blocks to "
+			       "%"PRIu64" blocks\n", fs->fs_blocks,
+			       opts.num_blocks);
+	}
 
-		vol_size = fs->fs_clusters <<
-			OCFS2_RAW_SB(fs->fs_super)->s_clustersize_bits;
-
-		printf("Changing volume size %"PRIu64" to %"PRIu64"\n",
-		       vol_size, opts.vol_size);
+	if (!opts.vol_label && !opts.num_slots &&
+	    !opts.jrnl_size && !opts.num_blocks) {
+		fprintf(stderr, "Nothing to do. Exiting.\n");
+		goto unlock;
 	}
 
 	/* Abort? */
@@ -715,18 +1147,19 @@
 	}
 
 	/* update volume size */
-	if (opts.vol_size) {
-		ret = update_volume_size(fs, &upd_vsize);
+	if (opts.num_blocks) {
+		ret = update_volume_size(fs, &upd_blocks);
 		if (ret) {
-			com_err(opts.progname, ret, "while updating volume size");
+			com_err(opts.progname, ret,
+				"while updating volume size");
 			goto unlock;
 		}
-		if (upd_vsize)
+		if (upd_blocks)
 			printf("Resized volume\n");
 	}
 
 	/* write superblock */
-	if (upd_label || upd_slots || upd_vsize) {
+	if (upd_label || upd_slots || upd_blocks) {
 		block_signals(SIG_BLOCK);
 		ret = ocfs2_write_super(fs);
 		if (ret) {




More information about the Ocfs2-tools-commits mailing list