[Ocfs2-tools-devel] [PATCH 2/4] Clear unallocated inode groups

tristan tristan.ye at oracle.com
Fri Mar 19 00:50:32 PDT 2010


Goldwyn Rodrigues wrote:
> Clears all inode groups which have no allocated inodes, freeing
> space in the global_bitmap
>
> Signed-off-by: Goldwyn Rodrigues <rgoldwyn at suse.de>
> ---
>  Makefile                      |    2 +-
>  defrag.ocfs2/Makefile         |    2 +-
>  defrag.ocfs2/alloc.c          |  230 +++++++++++++++++++++++++++++++++++++++++
>  defrag.ocfs2/defrag.c         |   21 +++-
>  defrag.ocfs2/include/defrag.h |    4 +-
>  5 files changed, 250 insertions(+), 9 deletions(-)
>  create mode 100644 defrag.ocfs2/alloc.c
>
> diff --git a/Makefile b/Makefile
> index 88106fb..ecb56dc 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -20,7 +20,7 @@ CHKCONFIG_DEP = chkconfig
>  COMPILE_PY = 1
>  endif
>  
> -SUBDIRS = include libtools-internal libo2dlm libo2cb libocfs2 fsck.ocfs2 mkfs.ocfs2 mounted.ocfs2 tunefs.ocfs2 debugfs.ocfs2 o2cb_ctl ocfs2_hb_ctl mount.ocfs2 ocfs2_controld o2image listuuid sizetest extras fswreck patches
> +SUBDIRS = include libtools-internal libo2dlm libo2cb libocfs2 fsck.ocfs2 mkfs.ocfs2 mounted.ocfs2 tunefs.ocfs2 debugfs.ocfs2 o2cb_ctl ocfs2_hb_ctl mount.ocfs2 ocfs2_controld o2image listuuid sizetest extras fswreck patches defrag.ocfs2
>  
>  ifdef BUILD_OCFS2CONSOLE
>  SUBDIRS += ocfs2console
> diff --git a/defrag.ocfs2/Makefile b/defrag.ocfs2/Makefile
> index b59c6a4..8bc48e0 100644
> --- a/defrag.ocfs2/Makefile
> +++ b/defrag.ocfs2/Makefile
> @@ -13,7 +13,7 @@ LIBOCFS2_DEPS = $(TOPDIR)/libocfs2/libocfs2.a
>  
>  CFLAGS += -g
>  
> -CFILES =	defrag.c
> +CFILES =	defrag.c alloc.c
>  
>  HFILES = 	include/defrag.h
>  
> diff --git a/defrag.ocfs2/alloc.c b/defrag.ocfs2/alloc.c
> new file mode 100644
> index 0000000..7eb7079
> --- /dev/null
> +++ b/defrag.ocfs2/alloc.c
> @@ -0,0 +1,230 @@
> +/* -*- mode: c; c-basic-offset: 8; -*-
> + * vim: noexpandtab sw=8 ts=8 sts=0:
> + *
> + * Copyright (C) 1993-2004 Theodore Ts'o.
> + * Copyright (C) 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, version 2,  as published by the Free Software Foundation.
> + * 
> + * 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.
> + *
> + */
> +#include <getopt.h>
> +#include <limits.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <string.h>
> +#include <inttypes.h>
> +#include <signal.h>
> +#include <libgen.h>
> +
> +#include "defrag.h"
> +
> +
> +extern int verbose;
> +extern char *whoami;
> +
> +static errcode_t cr_clear_unused(ocfs2_filesys *fs, struct ocfs2_chain_rec *cr,
> +		int chain_num, int *total, int *used)
> +{
> +	char *buf = NULL, *pbuf = NULL, *tbuf;
> +	struct ocfs2_group_desc *gd = NULL, *pgd = NULL;
> +	errcode_t ret = 0;
> +	uint64_t blkno = cr->c_blkno;
> +	int check_free, check_total;
> +
> +	if (!blkno)
> +		return 0;
> +	*total = *used = 0;
> +
> +	ret = ocfs2_malloc_block(fs->fs_io, &buf);
> +	if (ret)
> +		return ret;
> +	memset(buf, 0, fs->fs_blocksize);
> +
> +	ret = ocfs2_malloc_block(fs->fs_io, &pbuf);
> +	if (ret)
> +		return ret;
> +	memset(pbuf, 0, fs->fs_blocksize);
> +
> +	check_total = check_free = 0;
> +
> +	while (blkno) {
> +		ret = ocfs2_read_group_desc(fs, blkno, buf);
> +		if (ret)
> +			goto out;
> +		gd = (struct ocfs2_group_desc *)buf;
> +
> +
> +		if (gd->bg_blkno != blkno) {
> +			ret = OCFS2_CHAIN_ERROR;
> +			goto out;
> +		}
> +		verbosef("gd blkno:%"PRIu64" free:%d tot:%d\n",
> +				(uint64_t) gd->bg_blkno, gd->bg_free_bits_count,
> +				gd->bg_bits);
> +
> +		if ((gd->bg_free_bits_count+1 == gd->bg_bits) &&
> +				(gd->bg_bitmap[0] == 1)) {
> +			/* Clear corresponding in global bitmap */
> +			ret = ocfs2_free_clusters(fs, gd->bg_bits, gd->bg_blkno);
> +			if (ret)
> +				return ret;
> +
> +			cr->c_total -= gd->bg_bits;
> +			cr->c_free -= gd->bg_free_bits_count;
> +			*used += 1;
> +			*total += gd->bg_bits;
> +			if (pgd) {
> +				pgd->bg_next_group = gd->bg_next_group;
> +				/* XXX - Resulting in dual write. Improvise */
> +				ret = ocfs2_write_group_desc(fs,
> +						pgd->bg_blkno, pbuf);
> +				if (ret)
> +					goto out;
> +
> +			} else
> +				cr->c_blkno = gd->bg_next_group;
> +		} else {
> +			check_total += gd->bg_bits;
> +			check_free += gd->bg_free_bits_count;
> +		}
> +
> +		if (gd->bg_chain != chain_num) {
> +			verbosef("Changing chain value of group desc %"PRIu64
> +				" from %d to %d\n", (uint64_t)gd->bg_blkno,
> +				gd->bg_chain, chain_num);
> +			gd->bg_chain = chain_num;
> +			ret = ocfs2_write_group_desc(fs, blkno, buf);
> +			if (ret)
> +				goto out;
> +		}
> +		/* Swap buf and previous buf */
> +		tbuf = pbuf;
> +		pbuf = buf;
> +		buf = tbuf;

Oh, sorry, I missed one corner case in last mail, need to consider the 
case when removed group is #1 group:

if ((!pgd && (cr->c_blkno != gd->bg_next_group)) ||
(pgd && (pgd->bg_next_group != gd->bg_next_group))) {

tbuf = pbuf;
pbuf = buf;
buf = tbuf;
pgd = (struct ocfs2_group_desc *)pbuf;
}

blkno = gd->bg_next_group;

> +
> +		/* Get the next group desc block number in the chain */
> +		pgd = (struct ocfs2_group_desc *)pbuf;
> +		blkno = pgd->bg_next_group;
> +	}
> +
> +	if ((check_free != cr->c_free) || (check_total != cr->c_total)) {
> +		fprintf(stderr, "Chain rec[%d] count (%d/%d) does not match "
> +			"with calculated (%d/%d)", chain_num, cr->c_free,
> +			cr->c_total, check_free, check_total);
> +		ret = OCFS2_CHAIN_ERROR;
> +	}
> +out:
> +	if (buf)
> +		ocfs2_free(&buf);
> +	if (pbuf)
> +		ocfs2_free(&pbuf);
> +	return ret;
> +}
> +
> +
> +static errcode_t clear_unused_regions(ocfs2_filesys *fs, uint64_t blkno)
> +{
> +	char *buf = NULL;
> +	struct ocfs2_dinode *inode;
> +	int n, i;
> +	errcode_t ret = 0;
> +	struct ocfs2_chain_list *cl = &inode->id2.i_chain;
> +
> +	ret = ocfs2_malloc_block(fs->fs_io, &buf);
> +	if (ret)
> +		return ret;
> +	verbosef("Reading inode: %"PRIu64"\n", blkno);
> +	ret = ocfs2_read_inode(fs, blkno, buf);
> +	if (ret)
> +		goto out_buf;
> +
> +	inode = (struct ocfs2_dinode *)buf;
> +
> +	ret = OCFS2_ET_INODE_NOT_VALID;
> +	if (!(inode->i_flags & OCFS2_VALID_FL)) {
> +		printf("Allocator inode %"PRIu64" not active\n", blkno);
> +		goto out_buf;
> +	}
> +
> +	if (!(inode->i_flags & OCFS2_CHAIN_FL)) {
> +		printf("Allocator inode %"PRIu64" not a valid chain\n", blkno);
> +		goto out_buf;
> +	}
> +	
> +	cl = &inode->id2.i_chain;
> +	n = ocfs2_chain_recs_per_inode(fs->fs_blocksize);
> +	n--;
> +	while ((cl->cl_recs[n].c_blkno == 0) && (n > 0))
> +		n--;
> +	verbosef("Total chain recs to process: %d next_free:%d\n",
> +			n, cl->cl_next_free_rec);
> +
> +	i = 0;
> +	while (i <= n) {
> +		struct ocfs2_chain_rec *cr = &cl->cl_recs[i];
> +		int total = 0, used = 0;
> +		ret = cr_clear_unused(fs, cr, i, &total, &used);
> +		if (ret)
> +			goto out;
> +		/* Update inode parameters with the cleared regions */
> +		inode->id1.bitmap1.i_used -= used;
> +		inode->id1.bitmap1.i_total -= total;
> +		verbosef("cr i:%d blkno:%"PRIu64" tot:%d free:%d\n", i,
> +				(uint64_t)cr->c_blkno, cr->c_total, cr->c_free);
> +
> +		if (cr->c_blkno == 0) {
> +			/* Move the last rec to current position
> +			   and process it next*/
> +			cl->cl_recs[i] = cl->cl_recs[n];
> +			memset(&cl->cl_recs[n], 0,
> +					sizeof(struct ocfs2_chain_rec));
> +			n--;
> +		} else
> +			i++;
> +	}
> +	cl->cl_next_free_rec = n+1;
> +
> +out:
> +	/* Correct the rest of inode values */
> +	inode->i_clusters = inode->id1.bitmap1.i_total;
> +	inode->i_size = inode->i_clusters * fs->fs_clustersize;
> +	ret = ocfs2_write_inode(fs, blkno, buf);
> +out_buf:
> +	if (buf)
> +		ocfs2_free(&buf);
> +	return ret;
> +
> +}
> +
> +
> +
> +/* Clears all unused inode groups and block groups */
> +errcode_t allocators_clear_unused(struct defrag_state *dst)
> +{
> +	int slot, max_slots = OCFS2_RAW_SB(dst->dst_fs->fs_super)->s_max_slots;
> +	errcode_t ret = 0;
> +	uint64_t blkno;
> +
> +	for (slot = 0; slot < max_slots; slot++) {
> +		ret = ocfs2_lookup_system_inode(dst->dst_fs,
> +				INODE_ALLOC_SYSTEM_INODE,slot, &blkno);
> +		if (ret)
> +			return ret;
> +		verbosef("Inode allocator[%d] -\n", slot);
> +		clear_unused_regions(dst->dst_fs, blkno);
> +	}
> +	return ret;
> +}
> +
> diff --git a/defrag.ocfs2/defrag.c b/defrag.ocfs2/defrag.c
> index cf81aa6..22b71d7 100644
> --- a/defrag.ocfs2/defrag.c
> +++ b/defrag.ocfs2/defrag.c
> @@ -132,6 +132,7 @@ static void print_uuid(struct defrag_state *dst)
>  static void print_version(void)
>  {
>  	fprintf(stderr, "%s %s\n", whoami, VERSION);
> +	fprintf(stdout, "WARNING: Unstable version.\n");
>  }
>  
>  static void print_help(void)
> @@ -229,13 +230,13 @@ int main(int argc, char **argv)
>  
>  	if (mount_flags & (OCFS2_MF_MOUNTED | OCFS2_MF_BUSY)) {
>  		if (!(open_flags & OCFS2_FLAG_RW))
> -			fprintf(stdout, "\nWARNING!!! Running fsck.ocfs2 (read-"
> -					"only) on a mounted filesystem may detect "
> -					"invalid errors.\n\n");
> +			fprintf(stdout, "\nWARNING!!! Running defrag.ocfs2 "
> +					"(read-only) on a mounted filesystem "
> +					"may corrupt the filesystem.\n\n");
>  		else
> -			fprintf(stdout, "\nWARNING!!! Running fsck.ocfs2 on a "
> -					"mounted filesystem may cause SEVERE "
> -					"filesystem damage.\n\n");
> +			fprintf(stdout, "\nWARNING!!! Running defrag.ocfs2 on"
> +					" a mounted filesystem may cause "
> +					"SEVERE filesystem damage.\n\n");
>  	}
>  
>  	ret = open_and_check(dst, filename, open_flags, blkno, blksize);
> @@ -265,6 +266,14 @@ int main(int argc, char **argv)
>  		retval = DEFRAG_ERROR;
>  		goto out;
>  	}
> +	printf("Pass 1: Clearing unused groups in Allocators\n");
> +	ret = allocators_clear_unused(dst);
> +	if (ret) {
> +		fprintf(stderr, "Error while clearing unused inode groups\n"
> +				"Please execute fsck.ocfs2\n");
> +		retval |= DEFRAG_ERROR;
> +	}
> +
>  	ocfs2_write_super(dst->dst_fs);
>  	ocfs2_close(dst->dst_fs);
>  	
> diff --git a/defrag.ocfs2/include/defrag.h b/defrag.ocfs2/include/defrag.h
> index 7c25e89..e845893 100644
> --- a/defrag.ocfs2/include/defrag.h
> +++ b/defrag.ocfs2/include/defrag.h
> @@ -1,7 +1,7 @@
>  /* -*- mode: c; c-basic-offset: 8; -*-
>   * vim: noexpandtab sw=8 ts=8 sts=0:
>   *
> - * defrag.h
> + * fsck.h
>   *
>   * Copyright (C) 2002 Oracle Corporation.  All rights reserved.
>   *
> @@ -42,5 +42,7 @@ extern int verbose;
>  } while (0)
>  
>  
> +errcode_t allocators_clear_unused(struct defrag_state *);
> +
>  #endif /* __OCFS2_DEFRAG_H__ */
>  




More information about the Ocfs2-tools-devel mailing list