[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