Blame gfs2/convert/gfs2_convert.c

Packit 6ef888
/*****************************************************************************
Packit 6ef888
******************************************************************************
Packit 6ef888
**
Packit 6ef888
**  gfs2_convert - convert a gfs1 filesystem into a gfs2 filesystem.
Packit 6ef888
**
Packit 6ef888
******************************************************************************
Packit 6ef888
*****************************************************************************/
Packit 6ef888
Packit 6ef888
#include "clusterautoconfig.h"
Packit 6ef888
Packit 6ef888
#include <unistd.h>
Packit 6ef888
#include <stdio.h>
Packit 6ef888
#include <stdint.h>
Packit 6ef888
#include <stdlib.h>
Packit 6ef888
#include <libgen.h>
Packit 6ef888
#include <sys/types.h>
Packit 6ef888
#include <sys/stat.h>
Packit 6ef888
#include <fcntl.h>
Packit 6ef888
#include <stdarg.h>
Packit 6ef888
#include <dirent.h>
Packit 6ef888
#include <string.h>
Packit 6ef888
#include <time.h>
Packit 6ef888
#include <sys/time.h>
Packit 6ef888
#include <errno.h>
Packit 6ef888
#include <ctype.h>
Packit 6ef888
#include <termios.h>
Packit 6ef888
#include <libintl.h>
Packit 6ef888
#include <locale.h>
Packit 6ef888
#define _(String) gettext(String)
Packit 6ef888
Packit 6ef888
#include <linux/types.h>
Packit 6ef888
#include <linux/gfs2_ondisk.h>
Packit 6ef888
#include <logging.h>
Packit 6ef888
#include "osi_list.h"
Packit 6ef888
#include "copyright.cf"
Packit 6ef888
#include "libgfs2.h"
Packit 6ef888
Packit 6ef888
/* The following declares are needed because gfs2 can't have  */
Packit 6ef888
/* dependencies on gfs1:                                      */
Packit 6ef888
#define RGRP_STUFFED_BLKS(sb) (((sb)->sb_bsize - sizeof(struct gfs2_rgrp)) * GFS2_NBBY)
Packit 6ef888
#define RGRP_BITMAP_BLKS(sb) (((sb)->sb_bsize - sizeof(struct gfs2_meta_header)) * GFS2_NBBY)
Packit 6ef888
Packit 6ef888
/* Define some gfs1 constants from gfs1's gfs_ondisk.h */
Packit 6ef888
#define GFS_METATYPE_NONE       (0)
Packit 6ef888
#define GFS_METATYPE_SB         (1)    /* Super-Block */
Packit 6ef888
#define GFS_METATYPE_RG         (2)    /* Resource Group Header */
Packit 6ef888
#define GFS_METATYPE_RB         (3)    /* Resource Group Block Alloc BitBlock */
Packit 6ef888
#define GFS_METATYPE_DI         (4)    /* "Disk" inode (dinode) */
Packit 6ef888
#define GFS_METATYPE_IN         (5)    /* Indirect dinode block list */
Packit 6ef888
#define GFS_METATYPE_LF         (6)    /* Leaf dinode block list */
Packit 6ef888
#define GFS_METATYPE_JD         (7)    /* Journal Data */
Packit 6ef888
#define GFS_METATYPE_LH         (8)    /* Log Header (gfs_log_header) */
Packit 6ef888
#define GFS_METATYPE_LD         (9)    /* Log Descriptor (gfs_log_descriptor) */
Packit 6ef888
#define GFS_METATYPE_EA         (10)   /* Extended Attribute */
Packit 6ef888
#define GFS_METATYPE_ED         (11)   /* Extended Attribute data */
Packit 6ef888
Packit 6ef888
/* GFS1 Dinode types  */
Packit 6ef888
#define GFS_FILE_NON            (0)
Packit 6ef888
#define GFS_FILE_REG            (1)    /* regular file */
Packit 6ef888
#define GFS_FILE_DIR            (2)    /* directory */
Packit 6ef888
#define GFS_FILE_LNK            (5)    /* link */
Packit 6ef888
#define GFS_FILE_BLK            (7)    /* block device node */
Packit 6ef888
#define GFS_FILE_CHR            (8)    /* character device node */
Packit 6ef888
#define GFS_FILE_FIFO           (101)  /* fifo/pipe */
Packit 6ef888
#define GFS_FILE_SOCK           (102)  /* socket */
Packit 6ef888
Packit 6ef888
#define GFS_FORMAT_SB           (100)  /* Super-Block */
Packit 6ef888
#define GFS_FORMAT_FS           (1309) /* Filesystem (all-encompassing) */
Packit 6ef888
#define GFS_FORMAT_MULTI        (1401) /* Multi-Host */
Packit 6ef888
Packit 6ef888
#define DIV_RU(x, y) (((x) + (y) - 1) / (y))
Packit 6ef888
Packit 6ef888
struct inode_dir_block {
Packit 6ef888
	osi_list_t list;
Packit 6ef888
	uint64_t di_addr;
Packit 6ef888
	uint64_t di_paddr; /* Parent dir inode addr */
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
struct inode_block {
Packit 6ef888
	osi_list_t list;
Packit 6ef888
	uint64_t di_addr;
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
struct blocklist {
Packit 6ef888
	osi_list_t list;
Packit 6ef888
	uint64_t block;
Packit 6ef888
	struct metapath mp;
Packit 6ef888
	int height;
Packit 6ef888
	char *ptrbuf;
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
struct gfs2_options {
Packit 6ef888
	char *device;
Packit 6ef888
	unsigned int yes:1;
Packit 6ef888
	unsigned int no:1;
Packit 6ef888
	unsigned int query:1;
Packit 6ef888
};
Packit 6ef888
Packit 6ef888
struct gfs_sb  raw_gfs1_ondisk_sb;
Packit 6ef888
struct gfs2_sbd sb2;
Packit 6ef888
struct inode_block dirs_to_fix;  /* linked list of directories to fix */
Packit 6ef888
struct inode_dir_block cdpns_to_fix; /* linked list of cdpn symlinks */
Packit 6ef888
int seconds;
Packit 6ef888
struct timeval tv;
Packit 6ef888
uint64_t dirs_fixed;
Packit 6ef888
uint64_t cdpns_fixed;
Packit 6ef888
uint64_t dirents_fixed;
Packit 6ef888
struct gfs_jindex *sd_jindex = NULL;    /* gfs1 journal index in memory */
Packit 6ef888
int gfs2_inptrs;
Packit 6ef888
uint64_t gfs2_heightsize[GFS2_MAX_META_HEIGHT];
Packit 6ef888
uint64_t gfs2_jheightsize[GFS2_MAX_META_HEIGHT];
Packit 6ef888
uint32_t gfs2_max_height;
Packit 6ef888
uint32_t gfs2_max_jheight;
Packit 6ef888
uint64_t jindex_addr = 0, rindex_addr = 0;
Packit 6ef888
int print_level = MSG_NOTICE;
Packit 6ef888
unsigned orig_journals = 0;
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* This function is for libgfs's sake.                                       */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
void print_it(const char *label, const char *fmt, const char *fmt2, ...)
Packit 6ef888
{
Packit 6ef888
	va_list args;
Packit 6ef888
Packit 6ef888
	va_start(args, fmt2);
Packit 6ef888
	printf("%s: ", label);
Packit 6ef888
	vprintf(fmt, args);
Packit 6ef888
	va_end(args);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* convert_bitmaps - Convert gfs1 bitmaps to gfs2 bitmaps.                   */
Packit 6ef888
/*                   Fixes all unallocated metadata bitmap states (which are */
Packit 6ef888
/*                   valid in gfs1 but invalid in gfs2).                     */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static void convert_bitmaps(struct gfs2_sbd *sdp, struct rgrp_tree *rg)
Packit 6ef888
{
Packit 6ef888
	uint32_t blk;
Packit 6ef888
	int x, y;
Packit 6ef888
	struct gfs2_rindex *ri;
Packit 6ef888
	unsigned char state;
Packit 6ef888
Packit 6ef888
	ri = &rg->ri;
Packit 6ef888
	for (blk = 0; blk < ri->ri_length; blk++) {
Packit 6ef888
		struct gfs2_bitmap *bi;
Packit 6ef888
		x = (blk) ? sizeof(struct gfs2_meta_header) :
Packit 6ef888
			sizeof(struct gfs2_rgrp);
Packit 6ef888
Packit 6ef888
		bi = &rg->bits[blk];
Packit 6ef888
		for (; x < sdp->bsize; x++)
Packit 6ef888
			for (y = 0; y < GFS2_NBBY; y++) {
Packit 6ef888
				state = (bi->bi_bh->b_data[x] >>
Packit 6ef888
					 (GFS2_BIT_SIZE * y)) & 0x03;
Packit 6ef888
				if (state == 0x02) {/* unallocated metadata state invalid */
Packit 6ef888
					bi->bi_bh->b_data[x] &= ~(0x02 << (GFS2_BIT_SIZE * y));
Packit 6ef888
					bmodified(bi->bi_bh);
Packit 6ef888
				}
Packit 6ef888
			}
Packit 6ef888
	}
Packit 6ef888
}/* convert_bitmaps */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* convert_rgs - Convert gfs1 resource groups to gfs2.                       */
Packit 6ef888
/* Returns: 0 on success, -1 on failure                                      */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static int convert_rgs(struct gfs2_sbd *sbp)
Packit 6ef888
{
Packit 6ef888
	struct rgrp_tree *rgd;
Packit 6ef888
	struct osi_node *n, *next = NULL;
Packit 6ef888
	struct gfs_rgrp *rgd1;
Packit 6ef888
	int rgs = 0;
Packit 6ef888
Packit 6ef888
	/* --------------------------------- */
Packit 6ef888
	/* Now convert its rgs into gfs2 rgs */
Packit 6ef888
	/* --------------------------------- */
Packit 6ef888
	for (n = osi_first(&sbp->rgtree); n; n = next) {
Packit 6ef888
		next = osi_next(n);
Packit 6ef888
		rgd = (struct rgrp_tree *)n;
Packit 6ef888
Packit 6ef888
		rgd1 = (struct gfs_rgrp *)&rgd->rg; /* recast as gfs1 structure */
Packit 6ef888
		/* rg_freemeta is a gfs1 structure, so libgfs2 doesn't know to */
Packit 6ef888
		/* convert from be to cpu. We must do it now. */
Packit 6ef888
		rgd->rg.rg_free = rgd1->rg_free + be32_to_cpu(rgd1->rg_freemeta);
Packit 6ef888
		/* Zero it out so we don't add it again in case something breaks */
Packit 6ef888
		/* later on in the process and we have to re-run convert */
Packit 6ef888
		rgd1->rg_freemeta = 0;
Packit 6ef888
Packit 6ef888
		sbp->blks_total += rgd->ri.ri_data;
Packit 6ef888
		sbp->blks_alloced += (rgd->ri.ri_data - rgd->rg.rg_free);
Packit 6ef888
		sbp->dinodes_alloced += rgd1->rg_useddi;
Packit 6ef888
		convert_bitmaps(sbp, rgd);
Packit 6ef888
		/* Write the updated rgrp to the gfs2 buffer */
Packit 6ef888
		gfs2_rgrp_out(&rgd->rg, rgd->bits[0].bi_bh->b_data);
Packit 6ef888
		bmodified(rgd->bits[0].bi_bh);
Packit 6ef888
		rgs++;
Packit 6ef888
		if (rgs % 100 == 0) {
Packit 6ef888
			printf(".");
Packit 6ef888
			fflush(stdout);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}/* superblock_cvt */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* calc_gfs2_tree_height - calculate new dinode height as if this is gfs2    */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* This is similar to calc_tree_height in libgfs2 but at the point this      */
Packit 6ef888
/* function is called, I have the wrong (gfs1 not gfs2) constants in place.  */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static unsigned int calc_gfs2_tree_height(struct gfs2_inode *ip, uint64_t size)
Packit 6ef888
{
Packit 6ef888
	uint64_t *arr;
Packit 6ef888
	unsigned int max, height;
Packit 6ef888
Packit 6ef888
	if (ip->i_di.di_size > size)
Packit 6ef888
		size = ip->i_di.di_size;
Packit 6ef888
Packit 6ef888
	if (S_ISDIR(ip->i_di.di_mode)) {
Packit 6ef888
		arr = gfs2_jheightsize;
Packit 6ef888
		max = gfs2_max_jheight;
Packit 6ef888
	} else {
Packit 6ef888
		arr = gfs2_heightsize;
Packit 6ef888
		max = gfs2_max_height;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	for (height = 0; height < max; height++)
Packit 6ef888
		if (arr[height] >= size)
Packit 6ef888
			break;
Packit 6ef888
	/* If calc_gfs2_tree_height was called, the dinode is not stuffed or
Packit 6ef888
	   we would have returned before this point. After the call, a call is
Packit 6ef888
	   made to fix_metatree, which unstuffs the dinode. Therefore, the
Packit 6ef888
	   smallest height that can result after this call is 1. */
Packit 6ef888
	if (!height)
Packit 6ef888
		height = 1;
Packit 6ef888
Packit 6ef888
	return height;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* mp_gfs1_to_gfs2 - convert a gfs1 metapath to a gfs2 metapath.             */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static void mp_gfs1_to_gfs2(struct gfs2_sbd *sbp, int gfs1_h, int gfs2_h,
Packit 6ef888
		     struct metapath *gfs1mp, struct metapath *gfs2mp)
Packit 6ef888
{
Packit 6ef888
	uint64_t lblock;
Packit 6ef888
	int h;
Packit 6ef888
	uint64_t gfs1factor[GFS2_MAX_META_HEIGHT];
Packit 6ef888
	uint64_t gfs2factor[GFS2_MAX_META_HEIGHT];
Packit 6ef888
Packit 6ef888
	/* figure out multiplication factors for each height - gfs1 */
Packit 6ef888
	memset(&gfs1factor, 0, sizeof(gfs1factor));
Packit 6ef888
	gfs1factor[gfs1_h - 1] = 1ull;
Packit 6ef888
	for (h = gfs1_h - 1; h > 0; h--)
Packit 6ef888
		gfs1factor[h - 1] = gfs1factor[h] * sbp->sd_inptrs;
Packit 6ef888
Packit 6ef888
	/* figure out multiplication factors for each height - gfs2 */
Packit 6ef888
	memset(&gfs2factor, 0, sizeof(gfs2factor));
Packit 6ef888
	gfs2factor[gfs2_h - 1] = 1ull;
Packit 6ef888
	for (h = gfs2_h - 1; h > 0; h--)
Packit 6ef888
		gfs2factor[h - 1] = gfs2factor[h] * gfs2_inptrs;
Packit 6ef888
Packit 6ef888
	/* Convert from gfs1 to a logical block */
Packit 6ef888
	lblock = 0;
Packit 6ef888
	for (h = 0; h < gfs1_h; h++)
Packit 6ef888
		lblock += (gfs1mp->mp_list[h] * gfs1factor[h]);
Packit 6ef888
Packit 6ef888
	/* Convert from a logical block back to gfs2 */
Packit 6ef888
	memset(gfs2mp, 0, sizeof(*gfs2mp));
Packit 6ef888
	for (h = 0; h < gfs2_h; h++) {
Packit 6ef888
		/* Can't use do_div here because the factors are too large. */
Packit 6ef888
		gfs2mp->mp_list[h] = lblock / gfs2factor[h];
Packit 6ef888
		lblock %= gfs2factor[h];
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* fix_metatree - Fix up the metatree to match the gfs2 metapath info        */
Packit 6ef888
/*                Similar to gfs2_writei in libgfs2 but we're only           */
Packit 6ef888
/*                interested in rearranging the metadata while leaving the   */
Packit 6ef888
/*                actual data blocks intact.                                 */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static void fix_metatree(struct gfs2_sbd *sbp, struct gfs2_inode *ip,
Packit 6ef888
		  struct blocklist *blk, uint64_t *first_nonzero_ptr,
Packit 6ef888
		  unsigned int size)
Packit 6ef888
{
Packit 6ef888
	uint64_t block;
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	unsigned int amount, ptramt;
Packit 6ef888
	int hdrsize, h, copied = 0, new;
Packit 6ef888
	struct gfs2_meta_header mh;
Packit 6ef888
	char *srcptr = (char *)first_nonzero_ptr;
Packit 6ef888
Packit 6ef888
	mh.mh_magic = GFS2_MAGIC;
Packit 6ef888
	mh.mh_type = GFS2_METATYPE_IN;
Packit 6ef888
	mh.mh_format = GFS2_FORMAT_IN;
Packit 6ef888
	if (!ip->i_di.di_height)
Packit 6ef888
		unstuff_dinode(ip);
Packit 6ef888
Packit 6ef888
	ptramt = blk->mp.mp_list[blk->height] * sizeof(uint64_t);
Packit 6ef888
	amount = size;
Packit 6ef888
Packit 6ef888
	while (copied < size) {
Packit 6ef888
		bh = ip->i_bh;
Packit 6ef888
		/* First, build up the metatree */
Packit 6ef888
		for (h = 0; h < blk->height; h++) {
Packit 6ef888
			new = 0;
Packit 6ef888
			lookup_block(ip, bh, h, &blk->mp, 1, &new, &block);
Packit 6ef888
			if (bh != ip->i_bh)
Packit 6ef888
				brelse(bh);
Packit 6ef888
			if (!block)
Packit 6ef888
				break;
Packit 6ef888
Packit 6ef888
			bh = bread(sbp, block);
Packit 6ef888
			if (new)
Packit 6ef888
				memset(bh->b_data, 0, sbp->bsize);
Packit 6ef888
			gfs2_meta_header_out(&mh, bh->b_data);
Packit 6ef888
			bmodified(bh);
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		hdrsize = blk->height ? sizeof(struct gfs2_meta_header) :
Packit 6ef888
			sizeof(struct gfs2_dinode);
Packit 6ef888
Packit 6ef888
		if (amount > sbp->bsize - hdrsize - ptramt)
Packit 6ef888
			amount = sbp->bsize - hdrsize - ptramt;
Packit 6ef888
Packit 6ef888
		memcpy(bh->b_data + hdrsize + ptramt, (char *)srcptr, amount);
Packit 6ef888
		srcptr += amount;
Packit 6ef888
		bmodified(bh);
Packit 6ef888
		if (bh != ip->i_bh)
Packit 6ef888
			brelse(bh);
Packit 6ef888
Packit 6ef888
		copied += amount;
Packit 6ef888
Packit 6ef888
		if (hdrsize + ptramt + amount >= sbp->bsize) {
Packit 6ef888
			/* advance to the next metablock */
Packit 6ef888
			blk->mp.mp_list[blk->height] +=
Packit 6ef888
				(amount / sizeof(uint64_t));
Packit 6ef888
			for (h = blk->height; h > 0; h--) {
Packit 6ef888
				if (blk->mp.mp_list[h] >= gfs2_inptrs) {
Packit 6ef888
					blk->mp.mp_list[h] = 0;
Packit 6ef888
					blk->mp.mp_list[h - 1]++;
Packit 6ef888
					continue;
Packit 6ef888
				}
Packit 6ef888
				break;
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
		amount = size - copied;
Packit 6ef888
		ptramt = 0;
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* adjust_indirect_blocks - convert all gfs_indirect blocks to gfs2.         */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* This function converts all gfs_indirect blocks to GFS2.  The difference   */
Packit 6ef888
/* is that gfs1 indirect block has a 64-byte chunk of reserved space that    */
Packit 6ef888
/* gfs2 does not.  Since GFS block locations (relative to the start of the   */
Packit 6ef888
/* file have their locations defined by the offset from the end of the       */
Packit 6ef888
/* structure, all block pointers must be shifted.                            */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* Stuffed inodes don't need to be shifted at since there are no indirect    */
Packit 6ef888
/* blocks.  Inodes with height 1 don't need to be shifted either, because    */
Packit 6ef888
/* the dinode size is the same between gfs and gfs2 (232 bytes), and         */
Packit 6ef888
/* therefore you can fit the same number of block pointers after the dinode  */
Packit 6ef888
/* structure.  For the normal 4K block size, that's 483 pointers.  For 1K    */
Packit 6ef888
/* blocks, it's 99 pointers.                                                 */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* At height 2 things get complex.  GFS1 reserves an area of 64 (0x40) bytes */
Packit 6ef888
/* at the start of the indirect block, so for 4K blocks, you can fit 501     */
Packit 6ef888
/* pointers.  GFS2 doesn't reserve that space, so you can fit 509 pointers.  */
Packit 6ef888
/* For 1K blocks, it's 117 pointers in GFS1 and 125 in GFS2.                 */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* That means, for example, that if you have 4K blocks, a 946MB file will    */
Packit 6ef888
/* require a height of 3 for GFS, but only a height of 2 for GFS2.           */
Packit 6ef888
/* There isn't a good way to shift the pointers around from one height to    */
Packit 6ef888
/* another, so the only way to do it is to rebuild all those indirect blocks */
Packit 6ef888
/* from empty ones.                                                          */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* For example, with a 1K block size, if you do:                             */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* dd if=/mnt/gfs/big of=/tmp/tocompare skip=496572346368 bs=1024 count=1    */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* the resulting metadata paths will look vastly different for the data:     */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* height    0     1     2     3     4     5                                 */
Packit 6ef888
/* GFS1:  0x16  0x4b  0x70  0x11  0x5e  0x48                                 */
Packit 6ef888
/* GFS2:  0x10  0x21  0x78  0x05  0x14  0x76                                 */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* To complicate matters, we can't really require free space.  A user might  */
Packit 6ef888
/* be trying to migrate a "full" gfs1 file system to GFS2.  After we         */
Packit 6ef888
/* convert the journals to GFS2, we might have more free space, so we can    */
Packit 6ef888
/* allocate blocks at that time.                                             */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* Assumes: GFS1 values are in place for diptrs and inptrs.                  */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* Returns: 0 on success, -1 on failure                                      */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* Adapted from fsck.gfs2 metawalk.c's build_and_check_metalist              */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
Packit 6ef888
static void jdata_mp_gfs1_to_gfs2(struct gfs2_sbd *sbp, int gfs1_h, int gfs2_h,
Packit 6ef888
			   struct metapath *gfs1mp, struct metapath *gfs2mp,
Packit 6ef888
			   unsigned int *len, uint64_t dinode_size)
Packit 6ef888
{
Packit 6ef888
	uint64_t offset;
Packit 6ef888
	int h;
Packit 6ef888
	uint64_t gfs1factor[GFS2_MAX_META_HEIGHT];
Packit 6ef888
	uint64_t gfs2factor[GFS2_MAX_META_HEIGHT];
Packit 6ef888
Packit 6ef888
	/* figure out multiplication factors for each height - gfs1 */
Packit 6ef888
	memset(&gfs1factor, 0, sizeof(gfs1factor));
Packit 6ef888
	gfs1factor[gfs1_h - 1] = sbp->bsize - sizeof(struct gfs2_meta_header);
Packit 6ef888
	for (h = gfs1_h - 1; h > 0; h--)
Packit 6ef888
		gfs1factor[h - 1] = gfs1factor[h] * sbp->sd_inptrs;
Packit 6ef888
Packit 6ef888
	/* figure out multiplication factors for each height - gfs2 */
Packit 6ef888
	memset(&gfs2factor, 0, sizeof(gfs2factor));
Packit 6ef888
	gfs2factor[gfs2_h] = 1ull;
Packit 6ef888
	gfs2factor[gfs2_h - 1] = sbp->bsize;
Packit 6ef888
	for (h = gfs2_h - 1; h > 0; h--)
Packit 6ef888
		gfs2factor[h - 1] = gfs2factor[h] * gfs2_inptrs;
Packit 6ef888
Packit 6ef888
	/* Convert from gfs1 to an offset */
Packit 6ef888
	offset = 0;
Packit 6ef888
	for (h = 0; h < gfs1_h; h++)
Packit 6ef888
		offset += (gfs1mp->mp_list[h] * gfs1factor[h]);
Packit 6ef888
Packit 6ef888
	if (dinode_size - offset < *len)
Packit 6ef888
		*len = dinode_size - offset;
Packit 6ef888
Packit 6ef888
	/* Convert from an offset back to gfs2 */
Packit 6ef888
	memset(gfs2mp, 0, sizeof(*gfs2mp));
Packit 6ef888
	for (h = 0; h <= gfs2_h; h++) {
Packit 6ef888
		/* Can't use do_div here because the factors are too large. */
Packit 6ef888
		gfs2mp->mp_list[h] = offset / gfs2factor[h];
Packit 6ef888
		offset %= gfs2factor[h];
Packit 6ef888
	}
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static uint64_t fix_jdatatree(struct gfs2_sbd *sbp, struct gfs2_inode *ip,
Packit 6ef888
			      struct blocklist *blk, char *srcptr,
Packit 6ef888
			      unsigned int size)
Packit 6ef888
{
Packit 6ef888
	uint64_t block;
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	unsigned int amount, ptramt;
Packit 6ef888
	int h, copied = 0, new = 0;
Packit 6ef888
	struct gfs2_meta_header mh;
Packit 6ef888
Packit 6ef888
	mh.mh_magic = GFS2_MAGIC;
Packit 6ef888
	mh.mh_type = GFS2_METATYPE_IN;
Packit 6ef888
	mh.mh_format = GFS2_FORMAT_IN;
Packit 6ef888
Packit 6ef888
	if (!ip->i_di.di_height)
Packit 6ef888
		unstuff_dinode(ip);
Packit 6ef888
Packit 6ef888
	ptramt = blk->mp.mp_list[blk->height];
Packit 6ef888
	amount = size;
Packit 6ef888
Packit 6ef888
	while (copied < size) {
Packit 6ef888
		bh = ip->i_bh;
Packit 6ef888
		/* First, build up the metatree */
Packit 6ef888
		for (h = 0; h < blk->height; h++) {
Packit 6ef888
			new = 0;
Packit 6ef888
			lookup_block(ip, bh, h, &blk->mp, 1, &new, &block);
Packit 6ef888
			if (bh != ip->i_bh)
Packit 6ef888
				brelse(bh);
Packit 6ef888
			if (!block)
Packit 6ef888
				break;
Packit 6ef888
Packit 6ef888
			bh = bread(sbp, block);
Packit 6ef888
			if (new)
Packit 6ef888
				memset(bh->b_data, 0, sbp->bsize);
Packit 6ef888
			if (h < (blk->height - 1)) {
Packit 6ef888
				gfs2_meta_header_out(&mh, bh->b_data);
Packit 6ef888
				bmodified(bh);
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		if (amount > sbp->bsize - ptramt)
Packit 6ef888
			amount = sbp->bsize - ptramt;
Packit 6ef888
Packit 6ef888
		memcpy(bh->b_data + ptramt, (char *)srcptr, amount);
Packit 6ef888
		srcptr += amount;
Packit 6ef888
		bmodified(bh);
Packit 6ef888
		if (bh != ip->i_bh)
Packit 6ef888
			brelse(bh);
Packit 6ef888
Packit 6ef888
		copied += amount;
Packit 6ef888
Packit 6ef888
		if (ptramt + amount >= sbp->bsize) {
Packit 6ef888
			/* advance to the next metablock */
Packit 6ef888
			blk->mp.mp_list[blk->height] += amount;
Packit 6ef888
			for (h = blk->height; h > 0; h--) {
Packit 6ef888
				if (blk->mp.mp_list[h] >= gfs2_inptrs) {
Packit 6ef888
					blk->mp.mp_list[h] = 0;
Packit 6ef888
					blk->mp.mp_list[h - 1]++;
Packit 6ef888
					continue;
Packit 6ef888
				}
Packit 6ef888
				break;
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
		amount = size - copied;
Packit 6ef888
		ptramt = 0;
Packit 6ef888
	}
Packit 6ef888
	return block;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int get_inode_metablocks(struct gfs2_sbd *sbp, struct gfs2_inode *ip, struct blocklist *blocks)
Packit 6ef888
{
Packit 6ef888
	struct blocklist *blk, *newblk;
Packit 6ef888
	struct gfs2_buffer_head *bh, *dibh = ip->i_bh;
Packit 6ef888
	osi_list_t *tmp;
Packit 6ef888
	uint64_t *ptr1, block;
Packit 6ef888
	int h, ptrnum;
Packit 6ef888
	int bufsize = sbp->bsize - sizeof(struct gfs_indirect);
Packit 6ef888
Packit 6ef888
	/* Add dinode block to the list */
Packit 6ef888
	blk = malloc(sizeof(struct blocklist));
Packit 6ef888
	if (!blk) {
Packit 6ef888
		log_crit(_("Error: Can't allocate memory for indirect block fix\n"));
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	memset(blk, 0, sizeof(*blk));
Packit 6ef888
	blk->block = dibh->b_blocknr;
Packit 6ef888
	blk->ptrbuf = malloc(bufsize);
Packit 6ef888
	if (!blk->ptrbuf) {
Packit 6ef888
		log_crit(_("Error: Can't allocate memory"
Packit 6ef888
			 " for file conversion.\n"));
Packit 6ef888
		free(blk);
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	memset(blk->ptrbuf, 0, bufsize);
Packit 6ef888
	/* Fill in the pointers from the dinode buffer */
Packit 6ef888
	memcpy(blk->ptrbuf, dibh->b_data + sizeof(struct gfs_dinode),
Packit 6ef888
	       sbp->bsize - sizeof(struct gfs_dinode));
Packit 6ef888
	/* Zero out the pointers so we can fill them in later. */
Packit 6ef888
	memset(dibh->b_data + sizeof(struct gfs_dinode), 0,
Packit 6ef888
	       sbp->bsize - sizeof(struct gfs_dinode));
Packit 6ef888
	osi_list_add_prev(&blk->list, &blocks->list);
Packit 6ef888
Packit 6ef888
	/* Now run the metadata chain and build lists of all metadata blocks */
Packit 6ef888
	osi_list_foreach(tmp, &blocks->list) {
Packit 6ef888
		blk = osi_list_entry(tmp, struct blocklist, list);
Packit 6ef888
Packit 6ef888
		if (blk->height >= ip->i_di.di_height - 1)
Packit 6ef888
			continue;
Packit 6ef888
		for (ptr1 = (uint64_t *)blk->ptrbuf, ptrnum = 0;
Packit 6ef888
		     ptrnum < sbp->sd_inptrs; ptr1++, ptrnum++) {
Packit 6ef888
			if (!*ptr1)
Packit 6ef888
				continue;
Packit 6ef888
			block = be64_to_cpu(*ptr1);
Packit 6ef888
Packit 6ef888
			newblk = malloc(sizeof(struct blocklist));
Packit 6ef888
			if (!newblk) {
Packit 6ef888
				log_crit(_("Error: Can't allocate memory for indirect block fix.\n"));
Packit 6ef888
				return -1;
Packit 6ef888
			}
Packit 6ef888
			memset(newblk, 0, sizeof(*newblk));
Packit 6ef888
			newblk->ptrbuf = malloc(bufsize);
Packit 6ef888
			if (!newblk->ptrbuf) {
Packit 6ef888
				/* FIXME: This message should be different, to not conflit with the above file conversion */
Packit 6ef888
				log_crit(_("Error: Can't allocate memory for file conversion.\n"));
Packit 6ef888
				free(newblk);
Packit 6ef888
				return -1;
Packit 6ef888
			}
Packit 6ef888
			memset(newblk->ptrbuf, 0, bufsize);
Packit 6ef888
			newblk->block = block;
Packit 6ef888
			newblk->height = blk->height + 1;
Packit 6ef888
			/* Build the metapointer list from our predecessors */
Packit 6ef888
			for (h = 0; h < blk->height; h++)
Packit 6ef888
				newblk->mp.mp_list[h] = blk->mp.mp_list[h];
Packit 6ef888
			newblk->mp.mp_list[h] = ptrnum;
Packit 6ef888
			/* Queue it to be processed later on in the loop. */
Packit 6ef888
			osi_list_add_prev(&newblk->list, &blocks->list);
Packit 6ef888
			/* read the new metadata block's pointers */
Packit 6ef888
			bh = bread(sbp, block);
Packit 6ef888
			memcpy(newblk->ptrbuf, bh->b_data + sizeof(struct gfs_indirect), bufsize);
Packit 6ef888
			/* Zero the buffer so we can fill it in later */
Packit 6ef888
			memset(bh->b_data + sizeof(struct gfs_indirect), 0, bufsize);
Packit 6ef888
			bmodified(bh);
Packit 6ef888
			brelse(bh);
Packit 6ef888
			/* Free the block so we can reuse it. This allows us to
Packit 6ef888
			   convert a "full" file system. */
Packit 6ef888
			ip->i_di.di_blocks--;
Packit 6ef888
			gfs2_free_block(sbp, block);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int fix_ind_reg_or_dir(struct gfs2_sbd *sbp, struct gfs2_inode *ip, uint32_t di_height,
Packit 6ef888
		       uint32_t gfs2_hgt, struct blocklist *blk, struct blocklist *blocks)
Packit 6ef888
{
Packit 6ef888
	unsigned int len, bufsize;
Packit 6ef888
	uint64_t *ptr1, *ptr2;
Packit 6ef888
	int ptrnum;
Packit 6ef888
	struct metapath gfs2mp;
Packit 6ef888
Packit 6ef888
	bufsize = sbp->bsize - sizeof(struct gfs_indirect);
Packit 6ef888
	len = bufsize;
Packit 6ef888
Packit 6ef888
	/* Skip zero pointers at the start of the buffer.  This may 
Packit 6ef888
	   seem pointless, but the gfs1 blocks won't align with the 
Packit 6ef888
	   gfs2 blocks.  That means that a single block write of 
Packit 6ef888
	   gfs1's pointers is likely to span two blocks on gfs2. 
Packit 6ef888
	   That's a problem if the file system is full. 
Packit 6ef888
	   So I'm trying to truncate the data at the start and end 
Packit 6ef888
	   of the buffers (i.e. write only what we need to). */
Packit 6ef888
	for (ptr1 = (uint64_t *)blk->ptrbuf, ptrnum = 0;
Packit 6ef888
	     ptrnum < sbp->sd_inptrs; ptr1++, ptrnum++) {
Packit 6ef888
		if (*ptr1 != 0x00)
Packit 6ef888
			break;
Packit 6ef888
		len -= sizeof(uint64_t);
Packit 6ef888
	}
Packit 6ef888
	/* Skip zero bytes at the end of the buffer */
Packit 6ef888
	ptr2 = (uint64_t *)(blk->ptrbuf + bufsize) - 1;
Packit 6ef888
	while (len > 0 && *ptr2 == 0) {
Packit 6ef888
		ptr2--;
Packit 6ef888
		len -= sizeof(uint64_t);
Packit 6ef888
	}
Packit 6ef888
	blk->mp.mp_list[di_height - 1] = ptrnum;
Packit 6ef888
	mp_gfs1_to_gfs2(sbp, di_height, gfs2_hgt, &blk->mp, &gfs2mp);
Packit 6ef888
	memcpy(&blk->mp, &gfs2mp, sizeof(struct metapath));
Packit 6ef888
	blk->height -= di_height - gfs2_hgt;
Packit 6ef888
	if (len) {
Packit 6ef888
		fix_metatree(sbp, ip, blk, ptr1, len);
Packit 6ef888
		ip->i_di.di_goal_meta = be64_to_cpu(*ptr2);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int fix_ind_jdata(struct gfs2_sbd *sbp, struct gfs2_inode *ip, uint32_t di_height, 
Packit 6ef888
		  uint32_t gfs2_hgt, uint64_t dinode_size, struct blocklist *blk, 
Packit 6ef888
		  struct blocklist *blocks)
Packit 6ef888
{
Packit 6ef888
	/*FIXME: Messages here should be different, to not conflit with messages in get_inode_metablocks */
Packit 6ef888
	struct blocklist *newblk;
Packit 6ef888
	unsigned int len, bufsize;
Packit 6ef888
	uint64_t *ptr1, block;
Packit 6ef888
	int ptrnum, h;
Packit 6ef888
	struct metapath gfs2mp;
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
Packit 6ef888
	bufsize = sbp->bsize - sizeof(struct gfs2_meta_header);
Packit 6ef888
	/*
Packit 6ef888
	 * For each metadata block that holds jdata block pointers,
Packit 6ef888
	 * get the blk pointers and copy them block by block
Packit 6ef888
	 */
Packit 6ef888
	for (ptr1 = (uint64_t *) blk->ptrbuf, ptrnum = 0;
Packit 6ef888
	     ptrnum < sbp->sd_inptrs; ptr1++, ptrnum++) {
Packit 6ef888
		if (!*ptr1)
Packit 6ef888
			continue;
Packit 6ef888
		block = be64_to_cpu(*ptr1);
Packit 6ef888
Packit 6ef888
		newblk = malloc(sizeof(struct blocklist));
Packit 6ef888
		if (!newblk) {
Packit 6ef888
			log_crit(_("Error: Can't allocate memory for indirect block fix.\n"));
Packit 6ef888
			return -1;
Packit 6ef888
		}
Packit 6ef888
		memset(newblk, 0, sizeof(*newblk));
Packit 6ef888
		newblk->ptrbuf = malloc(bufsize); 
Packit 6ef888
		if (!newblk->ptrbuf) {
Packit 6ef888
			log_crit(_("Error: Can't allocate memory for file conversion.\n"));
Packit 6ef888
			free(newblk);
Packit 6ef888
			return -1;
Packit 6ef888
		}
Packit 6ef888
		memset(newblk->ptrbuf, 0, bufsize);
Packit 6ef888
		newblk->block = block;
Packit 6ef888
		newblk->height = blk->height + 1;
Packit 6ef888
		/* Build the metapointer list from our predecessors */
Packit 6ef888
		for (h=0; h < blk->height; h++)
Packit 6ef888
			newblk->mp.mp_list[h] = blk->mp.mp_list[h];
Packit 6ef888
		newblk->mp.mp_list[h] = ptrnum;
Packit 6ef888
		bh = bread(sbp, block);
Packit 6ef888
		/* This is a data block. i.e newblk->height == ip->i_di.di_height */
Packit 6ef888
		/* read in the jdata block */
Packit 6ef888
		memcpy(newblk->ptrbuf, bh->b_data +
Packit 6ef888
		       sizeof(struct gfs2_meta_header), bufsize);
Packit 6ef888
		memset(bh->b_data + sizeof(struct gfs2_meta_header), 0, bufsize);
Packit 6ef888
		bmodified(bh);
Packit 6ef888
		brelse(bh);
Packit 6ef888
		/* Free the block so we can reuse it. This allows us to
Packit 6ef888
		   convert a "full" file system */
Packit 6ef888
		ip->i_di.di_blocks--;
Packit 6ef888
		gfs2_free_block(sbp, block);
Packit 6ef888
Packit 6ef888
		len = bufsize;
Packit 6ef888
		jdata_mp_gfs1_to_gfs2(sbp, di_height, gfs2_hgt, &newblk->mp, &gfs2mp,
Packit 6ef888
				      &len, dinode_size);
Packit 6ef888
		memcpy(&newblk->mp, &gfs2mp, sizeof(struct metapath));
Packit 6ef888
		newblk->height -= di_height - gfs2_hgt;
Packit 6ef888
		if (len)
Packit 6ef888
			ip->i_di.di_goal_meta = fix_jdatatree(sbp, ip, newblk,
Packit 6ef888
							      newblk->ptrbuf, len);
Packit 6ef888
		free(newblk->ptrbuf);
Packit 6ef888
		free(newblk);
Packit 6ef888
	}
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int adjust_indirect_blocks(struct gfs2_sbd *sbp, struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	uint64_t dinode_size;
Packit 6ef888
	uint32_t gfs2_hgt, di_height;
Packit 6ef888
	osi_list_t *tmp=NULL, *x;
Packit 6ef888
	struct blocklist blocks, *blk;
Packit 6ef888
	int error = 0;
Packit 6ef888
Packit 6ef888
	int isdir = S_ISDIR(ip->i_di.di_mode); /* is always jdata */
Packit 6ef888
	int isjdata = ((GFS2_DIF_JDATA & ip->i_di.di_flags) && !isdir);
Packit 6ef888
	int isreg = (!isjdata && !isdir);
Packit 6ef888
	int issys = (GFS2_DIF_SYSTEM & ip->i_di.di_flags);
Packit 6ef888
Packit 6ef888
	/* regular files and dirs are same upto height=2
Packit 6ef888
	   jdata files (not dirs) are same only when height=0 */
Packit 6ef888
	if (((isreg||isdir) && ip->i_di.di_height <= 1) ||
Packit 6ef888
	    (isjdata && ip->i_di.di_height == 0)) {
Packit 6ef888
		if (!issys)
Packit 6ef888
			ip->i_di.di_goal_meta = ip->i_di.di_num.no_addr;
Packit 6ef888
		return 0; /* nothing to do */
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	osi_list_init(&blocks.list);
Packit 6ef888
Packit 6ef888
	error = get_inode_metablocks(sbp, ip, &blocks;;
Packit 6ef888
	if (error)
Packit 6ef888
		goto out;
Packit 6ef888
Packit 6ef888
	/* The gfs2 height may be different.  We need to rebuild the
Packit 6ef888
	   metadata tree to the gfs2 height. */
Packit 6ef888
	gfs2_hgt = calc_gfs2_tree_height(ip, ip->i_di.di_size);
Packit 6ef888
	/* Save off the size because we're going to empty the contents
Packit 6ef888
	   and add the data blocks back in later. */
Packit 6ef888
	dinode_size = ip->i_di.di_size;
Packit 6ef888
	ip->i_di.di_size = 0ULL;
Packit 6ef888
	di_height = ip->i_di.di_height;
Packit 6ef888
	ip->i_di.di_height = 0;
Packit 6ef888
Packit 6ef888
	/* Now run through the block list a second time.  If the block
Packit 6ef888
	   is a data block, rewrite the data to the gfs2 offset. */
Packit 6ef888
	osi_list_foreach_safe(tmp, &blocks.list, x) {
Packit 6ef888
Packit 6ef888
		blk = osi_list_entry(tmp, struct blocklist, list);
Packit 6ef888
		/* If it's not metadata that holds data block pointers
Packit 6ef888
		   (i.e. metadata pointing to other metadata) */
Packit 6ef888
		if (blk->height != di_height - 1) {
Packit 6ef888
			osi_list_del(tmp);
Packit 6ef888
			free(blk->ptrbuf);
Packit 6ef888
			free(blk);
Packit 6ef888
			continue;
Packit 6ef888
		}
Packit 6ef888
		if (isreg || isdir) /* more or less same way to deal with either */
Packit 6ef888
			error = fix_ind_reg_or_dir(sbp, ip, di_height, 
Packit 6ef888
						   gfs2_hgt, blk, &blocks;;
Packit 6ef888
		else if (isjdata)
Packit 6ef888
			error = fix_ind_jdata(sbp, ip, di_height, gfs2_hgt, 
Packit 6ef888
					      dinode_size, blk, &blocks;;
Packit 6ef888
		if (error)
Packit 6ef888
			goto out;
Packit 6ef888
Packit 6ef888
		osi_list_del(tmp);
Packit 6ef888
		free(blk->ptrbuf);
Packit 6ef888
		free(blk);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	ip->i_di.di_size = dinode_size;
Packit 6ef888
Packit 6ef888
	/* Set the new dinode height, which may or may not have changed.  */
Packit 6ef888
	/* The caller will take it from the ip and write it to the buffer */
Packit 6ef888
	ip->i_di.di_height = gfs2_hgt;
Packit 6ef888
	return error;
Packit 6ef888
Packit 6ef888
out:
Packit 6ef888
	while (!osi_list_empty(&blocks.list)) {
Packit 6ef888
		blk = osi_list_entry(tmp, struct blocklist, list);
Packit 6ef888
		osi_list_del(&blocks.list);
Packit 6ef888
		free(blk->ptrbuf);
Packit 6ef888
		free(blk);
Packit 6ef888
	}
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
const char *cdpn[14] = {"{hostname}", "{mach}", "{os}", "{uid}", "{gid}", "{sys}", "{jid}",
Packit 6ef888
			"@hostname", "@mach", "@os", "@uid", "@gid", "@sys", "@jid"};
Packit 6ef888
static int has_cdpn(const char *str)
Packit 6ef888
{
Packit 6ef888
	int i;
Packit 6ef888
	for (i=0; i<14; i++)
Packit 6ef888
		if (strstr(str, cdpn[i]) != NULL)
Packit 6ef888
			return 1;
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int fix_cdpn_symlink(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh, struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	char *linkptr = NULL;
Packit 6ef888
Packit 6ef888
	if (ip->i_di.di_height != 0)
Packit 6ef888
		return 0;
Packit 6ef888
Packit 6ef888
	linkptr = bh->b_data + sizeof(struct gfs_dinode);
Packit 6ef888
	if (has_cdpn(linkptr)) {
Packit 6ef888
		struct inode_dir_block *fix;
Packit 6ef888
		/* Save the symlink di_addr. We'll find the parent di_addr later */
Packit 6ef888
		fix = malloc(sizeof(struct inode_dir_block));
Packit 6ef888
		if (!fix) {
Packit 6ef888
			log_crit(_("Error: out of memory.\n"));
Packit 6ef888
			return -1;
Packit 6ef888
		}
Packit 6ef888
		memset(fix, 0, sizeof(struct inode_dir_block));
Packit 6ef888
		fix->di_addr = ip->i_di.di_num.no_addr;
Packit 6ef888
		osi_list_add_prev((osi_list_t *)&fix->list,
Packit 6ef888
				  (osi_list_t *)&cdpns_to_fix);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/*
Packit 6ef888
 * fix_xattr -
Packit 6ef888
 * Extended attributes can be either direct (in the ip->i_di.di_eattr block) or
Packit 6ef888
 * then can be at a maximum of 1 indirect level. Multiple levels of indirection
Packit 6ef888
 * are not supported. If the di_eattr block contains extended attribute data,
Packit 6ef888
 * i.e block type = GFS_METATYPE_EA, we ignore it.
Packit 6ef888
 * If the di_eattr block contains block pointers to extended attributes we need
Packit 6ef888
 * to fix the header. gfs1 uses gfs_indirect as the header which is 64 bytes
Packit 6ef888
 * bigger than gfs2_meta_header that gfs2 uses.
Packit 6ef888
 */
Packit 6ef888
static int fix_xattr(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh, struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	int len, old_hdr_sz, new_hdr_sz;
Packit 6ef888
	struct gfs2_buffer_head *eabh;
Packit 6ef888
	char *buf;
Packit 6ef888
Packit 6ef888
	/* Read in the i_di.di_eattr block */
Packit 6ef888
	eabh = bread(sbp, ip->i_di.di_eattr);
Packit 6ef888
        if (!gfs2_check_meta(eabh, GFS_METATYPE_IN)) {/* if it is an indirect block */
Packit 6ef888
		len = sbp->bsize - sizeof(struct gfs_indirect);
Packit 6ef888
		buf = malloc(len);
Packit 6ef888
		if (!buf) {
Packit 6ef888
			/*FIXME: Same message as fix_cdpn_symlink */
Packit 6ef888
			log_crit(_("Error: out of memory.\n"));
Packit 6ef888
			return -1;
Packit 6ef888
		}
Packit 6ef888
		old_hdr_sz = sizeof(struct gfs_indirect);
Packit 6ef888
		new_hdr_sz = sizeof(struct gfs2_meta_header);
Packit 6ef888
		memcpy(buf, eabh->b_data + old_hdr_sz, sbp->bsize - old_hdr_sz);
Packit 6ef888
		memset(eabh->b_data + new_hdr_sz, 0, sbp->bsize - new_hdr_sz);
Packit 6ef888
		memcpy(eabh->b_data + new_hdr_sz, buf, len);
Packit 6ef888
		free(buf);
Packit 6ef888
		bmodified(eabh);
Packit 6ef888
	}
Packit 6ef888
        brelse(eabh);
Packit 6ef888
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* adjust_inode - change an inode from gfs1 to gfs2                          */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* Returns: 0 on success, -1 on failure                                      */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inode *inode;
Packit 6ef888
	struct inode_block *fixdir;
Packit 6ef888
	int inode_was_gfs1;
Packit 6ef888
Packit 6ef888
	inode = lgfs2_gfs_inode_get(sbp, bh);
Packit 6ef888
	if (inode == NULL) {
Packit 6ef888
		log_crit(_("Error reading inode: %s\n"), strerror(errno));
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	inode_was_gfs1 = (inode->i_di.di_num.no_formal_ino ==
Packit 6ef888
					  inode->i_di.di_num.no_addr);
Packit 6ef888
	/* Fix the inode number: */
Packit 6ef888
	inode->i_di.di_num.no_formal_ino = sbp->md.next_inum;
Packit 6ef888
Packit 6ef888
	/* Fix the inode type: gfs1 uses di_type, gfs2 uses di_mode. */
Packit 6ef888
	inode->i_di.di_mode &= ~S_IFMT;
Packit 6ef888
	switch (inode->i_di.__pad1) { /* formerly di_type */
Packit 6ef888
	case GFS_FILE_DIR:           /* directory        */
Packit 6ef888
		inode->i_di.di_mode |= S_IFDIR;
Packit 6ef888
		/* Add this directory to the list of dirs to fix later. */
Packit 6ef888
		fixdir = malloc(sizeof(struct inode_block));
Packit 6ef888
		if (!fixdir) {
Packit 6ef888
			/*FIXME: Same message as fix_cdpn_symlink */
Packit 6ef888
			log_crit(_("Error: out of memory.\n"));
Packit 6ef888
			goto err_freei;
Packit 6ef888
		}
Packit 6ef888
		memset(fixdir, 0, sizeof(struct inode_block));
Packit 6ef888
		fixdir->di_addr = inode->i_di.di_num.no_addr;
Packit 6ef888
		osi_list_add_prev((osi_list_t *)&fixdir->list,
Packit 6ef888
						  (osi_list_t *)&dirs_to_fix);
Packit 6ef888
		break;
Packit 6ef888
	case GFS_FILE_REG:           /* regular file     */
Packit 6ef888
		inode->i_di.di_mode |= S_IFREG;
Packit 6ef888
		break;
Packit 6ef888
	case GFS_FILE_LNK:           /* symlink          */
Packit 6ef888
		inode->i_di.di_mode |= S_IFLNK;
Packit 6ef888
		break;
Packit 6ef888
	case GFS_FILE_BLK:           /* block device     */
Packit 6ef888
		inode->i_di.di_mode |= S_IFBLK;
Packit 6ef888
		break;
Packit 6ef888
	case GFS_FILE_CHR:           /* character device */
Packit 6ef888
		inode->i_di.di_mode |= S_IFCHR;
Packit 6ef888
		break;
Packit 6ef888
	case GFS_FILE_FIFO:          /* fifo / pipe      */
Packit 6ef888
		inode->i_di.di_mode |= S_IFIFO;
Packit 6ef888
		break;
Packit 6ef888
	case GFS_FILE_SOCK:          /* socket           */
Packit 6ef888
		inode->i_di.di_mode |= S_IFSOCK;
Packit 6ef888
		break;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	/* ----------------------------------------------------------- */
Packit 6ef888
	/* gfs2 inodes are slightly different from gfs1 inodes in that */
Packit 6ef888
	/* di_goal_meta has shifted locations and di_goal_data has     */
Packit 6ef888
	/* changed from 32-bits to 64-bits.  The following code        */
Packit 6ef888
	/* adjusts for the shift.                                      */
Packit 6ef888
	/*                                                             */
Packit 6ef888
	/* Note: It may sound absurd, but we need to check if this     */
Packit 6ef888
	/*       inode has already been converted to gfs2 or if it's   */
Packit 6ef888
	/*       still a gfs1 inode.  That's just in case there was a  */
Packit 6ef888
	/*       prior attempt to run gfs2_convert that never finished */
Packit 6ef888
	/*       (due to power out, ctrl-c, kill, segfault, whatever.) */
Packit 6ef888
	/*       If it is unconverted gfs1 we want to do a full        */
Packit 6ef888
	/*       conversion.  If it's a gfs2 inode from a prior run,   */
Packit 6ef888
	/*       we still need to renumber the inode, but here we      */
Packit 6ef888
	/*       don't want to shift the data around.                  */
Packit 6ef888
	/* ----------------------------------------------------------- */
Packit 6ef888
	if (inode_was_gfs1) {
Packit 6ef888
		struct gfs_dinode *gfs1_dinode_struct;
Packit 6ef888
		int ret = 0;
Packit 6ef888
Packit 6ef888
		gfs1_dinode_struct = (struct gfs_dinode *)&inode->i_di;
Packit 6ef888
		inode->i_di.di_goal_meta = inode->i_di.di_goal_data;
Packit 6ef888
		inode->i_di.di_goal_data = 0; /* make sure the upper 32b are 0 */
Packit 6ef888
		inode->i_di.di_goal_data = gfs1_dinode_struct->di_goal_dblk;
Packit 6ef888
		inode->i_di.di_generation = 0;
Packit 6ef888
Packit 6ef888
		if (adjust_indirect_blocks(sbp, inode))
Packit 6ef888
			goto err_freei;
Packit 6ef888
		/* Check for cdpns */
Packit 6ef888
		if (S_ISLNK(inode->i_di.di_mode)) {
Packit 6ef888
			ret = fix_cdpn_symlink(sbp, bh, inode);
Packit 6ef888
			if (ret)
Packit 6ef888
				goto err_freei;
Packit 6ef888
		}
Packit 6ef888
		/* Check for extended attributes */
Packit 6ef888
		if (inode->i_di.di_eattr) {
Packit 6ef888
			ret = fix_xattr(sbp, bh, inode);
Packit 6ef888
			if (ret)
Packit 6ef888
				goto err_freei;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	bmodified(inode->i_bh);
Packit 6ef888
	inode_put(&inode;; /* does gfs2_dinode_out if modified */
Packit 6ef888
	sbp->md.next_inum++; /* update inode count */
Packit 6ef888
	return 0;
Packit 6ef888
err_freei:
Packit 6ef888
	inode_put(&inode;;
Packit 6ef888
	return -1;
Packit 6ef888
} /* adjust_inode */
Packit 6ef888
Packit 6ef888
static int next_rg_meta(struct rgrp_tree *rgd, uint64_t *block, int first)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_bitmap *bits = NULL;
Packit 6ef888
	uint32_t length = rgd->ri.ri_length;
Packit 6ef888
	uint32_t blk = (first)? 0: (uint32_t)((*block + 1) - rgd->ri.ri_data0);
Packit 6ef888
	int i;
Packit 6ef888
Packit 6ef888
	if (!first && (*block < rgd->ri.ri_data0)) {
Packit 6ef888
		fprintf(stderr, "next_rg_meta:  Start block is outside rgrp bounds.\n");
Packit 6ef888
		exit(1);
Packit 6ef888
	}
Packit 6ef888
	for (i = 0; i < length; i++){
Packit 6ef888
		bits = &rgd->bits[i];
Packit 6ef888
		if (blk < bits->bi_len * GFS2_NBBY)
Packit 6ef888
			break;
Packit 6ef888
		blk -= bits->bi_len * GFS2_NBBY;
Packit 6ef888
	}
Packit 6ef888
	for (; i < length; i++){
Packit 6ef888
		bits = &rgd->bits[i];
Packit 6ef888
		blk = gfs2_bitfit((uint8_t *)bits->bi_bh->b_data + bits->bi_offset,
Packit 6ef888
		                   bits->bi_len, blk, GFS2_BLKST_DINODE);
Packit 6ef888
		if(blk != BFITNOENT){
Packit 6ef888
			*block = blk + (bits->bi_start * GFS2_NBBY) +
Packit 6ef888
				rgd->ri.ri_data0;
Packit 6ef888
			break;
Packit 6ef888
		}
Packit 6ef888
		blk = 0;
Packit 6ef888
	}
Packit 6ef888
	if (i == length)
Packit 6ef888
		return -1;
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int next_rg_metatype(struct gfs2_sbd *sdp, struct rgrp_tree *rgd,
Packit 6ef888
                            uint64_t *block, uint32_t type, int first)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_buffer_head *bh = NULL;
Packit 6ef888
Packit 6ef888
	do{
Packit 6ef888
		if (bh)
Packit 6ef888
			brelse(bh);
Packit 6ef888
		if (next_rg_meta(rgd, block, first))
Packit 6ef888
			return -1;
Packit 6ef888
		bh = bread(sdp, *block);
Packit 6ef888
		first = 0;
Packit 6ef888
	} while(gfs2_check_meta(bh, type));
Packit 6ef888
	brelse(bh);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* inode_renumber - renumber the inodes                                      */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* In gfs1, the inode number WAS the inode address.  In gfs2, the inodes are */
Packit 6ef888
/* numbered sequentially.                                                    */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* Returns: 0 on success, -1 on failure                                      */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static int inode_renumber(struct gfs2_sbd *sbp, uint64_t root_inode_addr, osi_list_t *cdpn_to_fix)
Packit 6ef888
{
Packit 6ef888
	struct rgrp_tree *rgd;
Packit 6ef888
	struct osi_node *n, *next = NULL;
Packit 6ef888
	uint64_t block = 0;
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	int first;
Packit 6ef888
	int error = 0;
Packit 6ef888
	int rgs_processed = 0;
Packit 6ef888
Packit 6ef888
	log_notice(_("Converting inodes.\n"));
Packit 6ef888
	sbp->md.next_inum = 1; /* starting inode numbering */
Packit 6ef888
	gettimeofday(&tv, NULL);
Packit 6ef888
	seconds = tv.tv_sec;
Packit 6ef888
Packit 6ef888
	/* ---------------------------------------------------------------- */
Packit 6ef888
	/* Traverse the resource groups to figure out where the inodes are. */
Packit 6ef888
	/* ---------------------------------------------------------------- */
Packit 6ef888
	for (n = osi_first(&sbp->rgtree); n; n = next) {
Packit 6ef888
		next = osi_next(n);
Packit 6ef888
		rgd = (struct rgrp_tree *)n;
Packit 6ef888
		rgs_processed++;
Packit 6ef888
		first = 1;
Packit 6ef888
		while (1) {    /* for all inodes in the resource group */
Packit 6ef888
			gettimeofday(&tv, NULL);
Packit 6ef888
			/* Put out a warm, fuzzy message every second so the customer */
Packit 6ef888
			/* doesn't think we hung.  (This may take a long time).       */
Packit 6ef888
			if (tv.tv_sec - seconds) {
Packit 6ef888
				seconds = tv.tv_sec;
Packit 6ef888
				log_notice(_("\r%llu inodes from %d rgs converted."),
Packit 6ef888
					   (unsigned long long)sbp->md.next_inum,
Packit 6ef888
					   rgs_processed);
Packit 6ef888
				fflush(stdout);
Packit 6ef888
			}
Packit 6ef888
			/* Get the next metadata block.  Break out if we reach the end. */
Packit 6ef888
			/* We have to check all metadata blocks because the bitmap may  */
Packit 6ef888
			/* be "11" (used meta) for both inodes and indirect blocks.     */
Packit 6ef888
			/* We need to process the inodes and change the indirect blocks */
Packit 6ef888
			/* to have a bitmap type of "01" (data).                        */
Packit 6ef888
			if (next_rg_metatype(sbp, rgd, &block, 0, first))
Packit 6ef888
				break;
Packit 6ef888
			/* If this is the root inode block, remember it for later: */
Packit 6ef888
			if (block == root_inode_addr) {
Packit 6ef888
				sbp->sd_sb.sb_root_dir.no_addr = block;
Packit 6ef888
				sbp->sd_sb.sb_root_dir.no_formal_ino = sbp->md.next_inum;
Packit 6ef888
			}
Packit 6ef888
			bh = bread(sbp, block);
Packit 6ef888
			if (!gfs2_check_meta(bh, GFS_METATYPE_DI)) {/* if it is an dinode */
Packit 6ef888
				/* Skip the rindex and jindex inodes for now. */
Packit 6ef888
				if (block != rindex_addr && block != jindex_addr) {
Packit 6ef888
					error = adjust_inode(sbp, bh);
Packit 6ef888
					if (error)
Packit 6ef888
						return error;
Packit 6ef888
				}
Packit 6ef888
			} else { /* It's metadata, but not an inode, so fix the bitmap. */
Packit 6ef888
				int blk, buf_offset;
Packit 6ef888
				int bitmap_byte; /* byte within the bitmap to fix */
Packit 6ef888
				int byte_bit; /* bit within the byte */
Packit 6ef888
Packit 6ef888
				/* Figure out the absolute bitmap byte we need to fix.   */
Packit 6ef888
				/* ignoring structure offsets and bitmap blocks for now. */
Packit 6ef888
				bitmap_byte = (block - rgd->ri.ri_data0) / GFS2_NBBY;
Packit 6ef888
				byte_bit = (block - rgd->ri.ri_data0) % GFS2_NBBY;
Packit 6ef888
				/* Now figure out which bitmap block the byte is on */
Packit 6ef888
				for (blk = 0; blk < rgd->ri.ri_length; blk++) {
Packit 6ef888
					struct gfs2_bitmap *bi = &rgd->bits[blk];
Packit 6ef888
					/* figure out offset of first bitmap byte for this map: */
Packit 6ef888
					buf_offset = (blk) ? sizeof(struct gfs2_meta_header) :
Packit 6ef888
						sizeof(struct gfs2_rgrp);
Packit 6ef888
					/* if it's on this page */
Packit 6ef888
					if (buf_offset + bitmap_byte < sbp->bsize) {
Packit 6ef888
						bi->bi_bh->b_data[buf_offset + bitmap_byte] &=
Packit 6ef888
							~(0x03 << (GFS2_BIT_SIZE * byte_bit));
Packit 6ef888
						bi->bi_bh->b_data[buf_offset + bitmap_byte] |=
Packit 6ef888
							(0x01 << (GFS2_BIT_SIZE * byte_bit));
Packit 6ef888
						bmodified(bi->bi_bh);
Packit 6ef888
						break;
Packit 6ef888
					}
Packit 6ef888
					bitmap_byte -= (sbp->bsize - buf_offset);
Packit 6ef888
				}
Packit 6ef888
			}
Packit 6ef888
			brelse(bh);
Packit 6ef888
			first = 0;
Packit 6ef888
		} /* while 1 */
Packit 6ef888
	} /* for all rgs */
Packit 6ef888
	log_notice(_("\r%llu inodes from %d rgs converted."),
Packit 6ef888
		   (unsigned long long)sbp->md.next_inum, rgs_processed);
Packit 6ef888
	fflush(stdout);
Packit 6ef888
	return 0;
Packit 6ef888
}/* inode_renumber */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* fetch_inum - fetch an inum entry from disk, given its block               */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static int fetch_inum(struct gfs2_sbd *sbp, uint64_t iblock,
Packit 6ef888
		      struct gfs2_inum *inum, uint64_t *eablk)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inode *fix_inode;
Packit 6ef888
Packit 6ef888
	fix_inode = lgfs2_inode_read(sbp, iblock);
Packit 6ef888
	if (fix_inode == NULL)
Packit 6ef888
		return 1;
Packit 6ef888
	inum->no_formal_ino = fix_inode->i_di.di_num.no_formal_ino;
Packit 6ef888
	inum->no_addr = fix_inode->i_di.di_num.no_addr;
Packit 6ef888
	if (eablk)
Packit 6ef888
		*eablk = fix_inode->i_di.di_eattr;
Packit 6ef888
Packit 6ef888
	inode_put(&fix_inode);
Packit 6ef888
	return 0;
Packit 6ef888
}/* fetch_inum */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* process_dirent_info - fix one dirent (directory entry) buffer             */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* We changed inode numbers, so we must update that number into the          */
Packit 6ef888
/* directory entries themselves.                                             */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* Returns: 0 on success, -1 on failure, -EISDIR when dentmod marked DT_DIR  */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static int process_dirent_info(struct gfs2_inode *dip, struct gfs2_sbd *sbp,
Packit 6ef888
			       struct gfs2_buffer_head *bh, int dir_entries, uint64_t dentmod)
Packit 6ef888
{
Packit 6ef888
	int error = 0;
Packit 6ef888
	struct gfs2_dirent *dent;
Packit 6ef888
	int de; /* directory entry index */
Packit 6ef888
	
Packit 6ef888
	error = gfs2_dirent_first(dip, bh, &dent);
Packit 6ef888
	if (error != IS_LEAF && error != IS_DINODE) {
Packit 6ef888
		log_crit(_("Error retrieving directory.\n"));
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	error = 0;
Packit 6ef888
	/* Go through every dirent in the buffer and process it. */
Packit 6ef888
	/* Turns out you can't trust dir_entries is correct.     */
Packit 6ef888
	for (de = 0; ; de++) {
Packit 6ef888
		struct gfs2_inum inum;
Packit 6ef888
		int dent_was_gfs1;
Packit 6ef888
Packit 6ef888
		if (dentmod) {
Packit 6ef888
			if (dent->de_type == cpu_to_be16(DT_LNK)
Packit 6ef888
			    && cpu_to_be64(dent->de_inum.no_addr) == dentmod) {
Packit 6ef888
				dent->de_type = cpu_to_be16(DT_DIR);
Packit 6ef888
				error = -EISDIR;
Packit 6ef888
				break;
Packit 6ef888
			}
Packit 6ef888
			goto skip_next;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		gettimeofday(&tv, NULL);
Packit 6ef888
		/* Do more warm fuzzy stuff for the customer. */
Packit 6ef888
		dirents_fixed++;
Packit 6ef888
		if (tv.tv_sec - seconds) {
Packit 6ef888
			seconds = tv.tv_sec;
Packit 6ef888
			log_notice(_("\r%llu directories, %llu dirents fixed."),
Packit 6ef888
				   (unsigned long long)dirs_fixed,
Packit 6ef888
				   (unsigned long long)dirents_fixed);
Packit 6ef888
			fflush(stdout);
Packit 6ef888
		}
Packit 6ef888
		/* fix the dirent's inode number based on the inode */
Packit 6ef888
		gfs2_inum_in(&inum, (char *)&dent->de_inum);
Packit 6ef888
		dent_was_gfs1 = (dent->de_inum.no_addr == dent->de_inum.no_formal_ino);
Packit 6ef888
		if (inum.no_formal_ino) { /* if not a sentinel (placeholder) */
Packit 6ef888
			error = fetch_inum(sbp, inum.no_addr, &inum, NULL);
Packit 6ef888
			if (error) {
Packit 6ef888
				log_crit(_("Error retrieving inode 0x%llx\n"),
Packit 6ef888
					 (unsigned long long)inum.no_addr);
Packit 6ef888
				break;
Packit 6ef888
			}
Packit 6ef888
			/* fix the dirent's inode number from the fetched inum. */
Packit 6ef888
			dent->de_inum.no_formal_ino = cpu_to_be64(inum.no_formal_ino);
Packit 6ef888
		}
Packit 6ef888
		/* Fix the dirent's filename hash: They are the same as gfs1 */
Packit 6ef888
		/* dent->de_hash = cpu_to_be32(gfs2_disk_hash((char *)(dent + 1), */
Packit 6ef888
		/*                             be16_to_cpu(dent->de_name_len))); */
Packit 6ef888
		/* Fix the dirent's file type.  Gfs1 used home-grown values.  */
Packit 6ef888
		/* Gfs2 uses standard values from include/linux/fs.h          */
Packit 6ef888
		/* Only do this if the dent was a true gfs1 dent, and not a   */
Packit 6ef888
		/* gfs2 dent converted from a previously aborted run.         */
Packit 6ef888
		if (dent_was_gfs1) {
Packit 6ef888
			switch be16_to_cpu(dent->de_type) {
Packit 6ef888
			case GFS_FILE_NON:
Packit 6ef888
				dent->de_type = cpu_to_be16(DT_UNKNOWN);
Packit 6ef888
				break;
Packit 6ef888
			case GFS_FILE_REG:    /* regular file */
Packit 6ef888
				dent->de_type = cpu_to_be16(DT_REG);
Packit 6ef888
				break;
Packit 6ef888
			case GFS_FILE_DIR:    /* directory */
Packit 6ef888
				dent->de_type = cpu_to_be16(DT_DIR);
Packit 6ef888
				break;
Packit 6ef888
			case GFS_FILE_LNK:    /* link */
Packit 6ef888
				dent->de_type = cpu_to_be16(DT_LNK);
Packit 6ef888
				break;
Packit 6ef888
			case GFS_FILE_BLK:    /* block device node */
Packit 6ef888
				dent->de_type = cpu_to_be16(DT_BLK);
Packit 6ef888
				break;
Packit 6ef888
			case GFS_FILE_CHR:    /* character device node */
Packit 6ef888
				dent->de_type = cpu_to_be16(DT_CHR);
Packit 6ef888
				break;
Packit 6ef888
			case GFS_FILE_FIFO:   /* fifo/pipe */
Packit 6ef888
				dent->de_type = cpu_to_be16(DT_FIFO);
Packit 6ef888
				break;
Packit 6ef888
			case GFS_FILE_SOCK:   /* socket */
Packit 6ef888
				dent->de_type = cpu_to_be16(DT_SOCK);
Packit 6ef888
				break;
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
		/*
Packit 6ef888
		 * Compare this dirent address with every one in the
Packit 6ef888
		 * cdpns_to_fix list to find if this directory (dip) is
Packit 6ef888
		 * a cdpn symlink's parent. If so add it to the list element
Packit 6ef888
		 */
Packit 6ef888
		if (dent->de_type == cpu_to_be16(DT_LNK)) {
Packit 6ef888
			osi_list_t *tmp;
Packit 6ef888
			struct inode_dir_block *fix;
Packit 6ef888
			osi_list_foreach(tmp, &cdpns_to_fix.list) {
Packit 6ef888
				fix = osi_list_entry(tmp, struct inode_dir_block, list);
Packit 6ef888
				if (fix->di_addr == inum.no_addr)
Packit 6ef888
					fix->di_paddr = dip->i_di.di_num.no_addr;
Packit 6ef888
			}
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
	skip_next:
Packit 6ef888
		error = gfs2_dirent_next(dip, bh, &dent);
Packit 6ef888
		if (error) {
Packit 6ef888
			if (error == -ENOENT) /* beyond the end of this bh */
Packit 6ef888
				error = 0;
Packit 6ef888
			break;
Packit 6ef888
		}
Packit 6ef888
	} /* for every directory entry */
Packit 6ef888
	return error;
Packit 6ef888
}/* process_dirent_info */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* fix_one_directory_exhash - fix one directory's inode numbers.             */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* This is for exhash directories, where the inode has a list of "leaf"      */
Packit 6ef888
/* blocks, each of which is a buffer full of dirents that must be processed. */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* Returns: 0 on success, -1 on failure                                      */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static int fix_one_directory_exhash(struct gfs2_sbd *sbp, struct gfs2_inode *dip, uint64_t dentmod)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_buffer_head *bh_leaf;
Packit 6ef888
	int error;
Packit 6ef888
	uint64_t leaf_block, prev_leaf_block;
Packit 6ef888
	uint32_t leaf_num;
Packit 6ef888
	
Packit 6ef888
	prev_leaf_block = 0;
Packit 6ef888
	/* for all the leafs, get the leaf block and process the dirents inside */
Packit 6ef888
	for (leaf_num = 0; ; leaf_num++) {
Packit 6ef888
		uint64_t buf;
Packit 6ef888
		struct gfs2_leaf leaf;
Packit 6ef888
Packit 6ef888
		error = gfs2_readi(dip, (char *)&buf, leaf_num * sizeof(uint64_t),
Packit 6ef888
						   sizeof(uint64_t));
Packit 6ef888
		if (!error) /* end of file */
Packit 6ef888
			return 0; /* success */
Packit 6ef888
		else if (error != sizeof(uint64_t)) {
Packit 6ef888
			log_crit(_("fix_one_directory_exhash: error reading directory.\n"));
Packit 6ef888
			return -1;
Packit 6ef888
		}
Packit 6ef888
		else {
Packit 6ef888
			leaf_block = be64_to_cpu(buf);
Packit 6ef888
			error = 0;
Packit 6ef888
		}
Packit 6ef888
	leaf_chain:
Packit 6ef888
		/* leaf blocks may be repeated, so skip the duplicates: */
Packit 6ef888
		if (leaf_block == prev_leaf_block) /* same block? */
Packit 6ef888
			continue;                      /* already converted */
Packit 6ef888
Packit 6ef888
		prev_leaf_block = leaf_block;
Packit 6ef888
		/* read the leaf buffer in */
Packit 6ef888
		error = gfs2_get_leaf(dip, leaf_block, &bh_leaf);
Packit 6ef888
		if (error) {
Packit 6ef888
			log_crit(_("Error reading leaf %llx\n"),
Packit 6ef888
				 (unsigned long long)leaf_block);
Packit 6ef888
			break;
Packit 6ef888
		}
Packit 6ef888
		gfs2_leaf_in(&leaf, bh_leaf->b_data);
Packit 6ef888
		error = process_dirent_info(dip, sbp, bh_leaf, leaf.lf_entries, dentmod);
Packit 6ef888
		bmodified(bh_leaf);
Packit 6ef888
		brelse(bh_leaf);
Packit 6ef888
		if (dentmod && error == -EISDIR) /* dentmod was marked DT_DIR, break out */
Packit 6ef888
			break;
Packit 6ef888
		if (leaf.lf_next) { /* leaf has a leaf chain, process leaves in chain */
Packit 6ef888
			leaf_block = leaf.lf_next;
Packit 6ef888
			error = 0;
Packit 6ef888
			goto leaf_chain;
Packit 6ef888
		}
Packit 6ef888
	} /* for leaf_num */
Packit 6ef888
	return 0;
Packit 6ef888
}/* fix_one_directory_exhash */
Packit 6ef888
Packit 6ef888
static int process_directory(struct gfs2_sbd *sbp, uint64_t dirblock, uint64_t dentmod)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inode *dip;
Packit 6ef888
	int error = 0;
Packit 6ef888
	/* read in the directory inode */
Packit 6ef888
	dip = lgfs2_inode_read(sbp, dirblock);
Packit 6ef888
	if (dip == NULL)
Packit 6ef888
		return -1;
Packit 6ef888
	/* fix the directory: either exhash (leaves) or linear (stuffed) */
Packit 6ef888
	if (dip->i_di.di_flags & GFS2_DIF_EXHASH) {
Packit 6ef888
		if (fix_one_directory_exhash(sbp, dip, dentmod)) {
Packit 6ef888
			log_crit(_("Error fixing exhash directory.\n"));
Packit 6ef888
			inode_put(&dip;;
Packit 6ef888
			return -1;
Packit 6ef888
		}
Packit 6ef888
	} else {
Packit 6ef888
		error = process_dirent_info(dip, sbp, dip->i_bh, dip->i_di.di_entries, dentmod);
Packit 6ef888
		if (error && error != -EISDIR) {
Packit 6ef888
			log_crit(_("Error fixing linear directory.\n"));
Packit 6ef888
			inode_put(&dip;;
Packit 6ef888
			return -1;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	bmodified(dip->i_bh);
Packit 6ef888
	inode_put(&dip;;
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* fix_directory_info - sync new inode numbers with directory info           */
Packit 6ef888
/* Returns: 0 on success, -1 on failure                                      */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static int fix_directory_info(struct gfs2_sbd *sbp, osi_list_t *dir_to_fix)
Packit 6ef888
{
Packit 6ef888
	osi_list_t *tmp, *fix;
Packit 6ef888
	struct inode_block *dir_iblk;
Packit 6ef888
	uint64_t dirblock;
Packit 6ef888
	uint32_t gfs1_inptrs = sbp->sd_inptrs;
Packit 6ef888
	/* Directory inodes have been converted to gfs2, use gfs2 inptrs */
Packit 6ef888
	sbp->sd_inptrs = (sbp->bsize - sizeof(struct gfs2_meta_header))
Packit 6ef888
		/ sizeof(uint64_t);
Packit 6ef888
Packit 6ef888
	dirs_fixed = 0;
Packit 6ef888
	dirents_fixed = 0;
Packit 6ef888
	gettimeofday(&tv, NULL);
Packit 6ef888
	seconds = tv.tv_sec;
Packit 6ef888
	log_notice(_("\nFixing file and directory information.\n"));
Packit 6ef888
	fflush(stdout);
Packit 6ef888
	tmp = NULL;
Packit 6ef888
	/* for every directory in the list */
Packit 6ef888
	for (fix = dir_to_fix->next; fix != dir_to_fix; fix = fix->next) {
Packit 6ef888
		if (tmp) {
Packit 6ef888
			osi_list_del(tmp);
Packit 6ef888
			free(tmp);
Packit 6ef888
		}
Packit 6ef888
		tmp = fix; /* remember the addr to free next time */
Packit 6ef888
		dirs_fixed++;
Packit 6ef888
		/* figure out the directory inode block and read it in */
Packit 6ef888
		dir_iblk = (struct inode_block *)fix;
Packit 6ef888
		dirblock = dir_iblk->di_addr; /* addr of dir inode */
Packit 6ef888
		if (process_directory(sbp, dirblock, 0)) {
Packit 6ef888
			log_crit(_("Error processing directory\n"));
Packit 6ef888
			return -1;
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	/* Free the last entry in memory: */
Packit 6ef888
	if (tmp) {
Packit 6ef888
		osi_list_del(tmp);
Packit 6ef888
		free(tmp);
Packit 6ef888
	}
Packit 6ef888
	sbp->sd_inptrs = gfs1_inptrs;
Packit 6ef888
	return 0;
Packit 6ef888
}/* fix_directory_info */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* fix_cdpn_symlinks - convert cdpn symlinks to empty directories            */
Packit 6ef888
/* Returns: 0 on success, -1 on failure                                      */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static int fix_cdpn_symlinks(struct gfs2_sbd *sbp, osi_list_t *cdpn_to_fix)
Packit 6ef888
{
Packit 6ef888
	osi_list_t *tmp, *x;
Packit 6ef888
	int error = 0;
Packit 6ef888
Packit 6ef888
	cdpns_fixed = 0;
Packit 6ef888
	osi_list_foreach_safe(tmp, cdpn_to_fix, x) {
Packit 6ef888
		struct gfs2_inum fix, dir;
Packit 6ef888
		struct inode_dir_block *l_fix;
Packit 6ef888
		struct gfs2_buffer_head *bh = NULL;
Packit 6ef888
		struct gfs2_inode *fix_inode;
Packit 6ef888
		uint64_t eablk;
Packit 6ef888
Packit 6ef888
		l_fix = osi_list_entry(tmp, struct inode_dir_block, list);
Packit 6ef888
		osi_list_del(tmp);
Packit 6ef888
Packit 6ef888
		/* convert symlink to empty dir */
Packit 6ef888
		error = fetch_inum(sbp, l_fix->di_addr, &fix, &eablk);
Packit 6ef888
		if (error) {
Packit 6ef888
			log_crit(_("Error retrieving inode at block %llx\n"), 
Packit 6ef888
				 (unsigned long long)l_fix->di_addr);
Packit 6ef888
			break;
Packit 6ef888
		}
Packit 6ef888
		error = fetch_inum(sbp, l_fix->di_paddr, &dir, NULL);
Packit 6ef888
		if (error) {
Packit 6ef888
			log_crit(_("Error retrieving inode at block %llx\n"),
Packit 6ef888
				 (unsigned long long)l_fix->di_paddr);
Packit 6ef888
			break;
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		/* initialize the symlink inode to be a directory */
Packit 6ef888
		error = init_dinode(sbp, &bh, &fix, S_IFDIR | 0755, 0, &dir;;
Packit 6ef888
		if (error != 0)
Packit 6ef888
			return -1;
Packit 6ef888
Packit 6ef888
		fix_inode = lgfs2_inode_get(sbp, bh);
Packit 6ef888
		if (fix_inode == NULL)
Packit 6ef888
			return -1;
Packit 6ef888
		fix_inode->i_di.di_eattr = eablk; /*fix extended attribute */
Packit 6ef888
		inode_put(&fix_inode);
Packit 6ef888
		bmodified(bh);
Packit 6ef888
		brelse(bh);
Packit 6ef888
Packit 6ef888
		/* fix the parent directory dirent entry for this inode */
Packit 6ef888
		error = process_directory(sbp, l_fix->di_paddr, l_fix->di_addr);
Packit 6ef888
		if (error) {
Packit 6ef888
			log_crit(_("Error trying to fix cdpn dentry\n"));
Packit 6ef888
			break;
Packit 6ef888
		}
Packit 6ef888
		free(l_fix);
Packit 6ef888
		cdpns_fixed++;
Packit 6ef888
	}
Packit 6ef888
	return error;
Packit 6ef888
} /* fix_cdpn_symlinks */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* Fetch gfs1 jindex structure from buffer                                   */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static void gfs1_jindex_in(struct gfs_jindex *jindex, char *buf)
Packit 6ef888
{
Packit 6ef888
	struct gfs_jindex *str = (struct gfs_jindex *)buf;
Packit 6ef888
Packit 6ef888
	jindex->ji_addr = be64_to_cpu(str->ji_addr);
Packit 6ef888
	jindex->ji_nsegment = be32_to_cpu(str->ji_nsegment);
Packit 6ef888
	memset(jindex->ji_reserved, 0, 64);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* read_gfs1_jiindex - read the gfs1 jindex file.                            */
Packit 6ef888
/* Returns: 0 on success, -1 on failure                                      */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static int read_gfs1_jiindex(struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inode *ip = sdp->md.jiinode;
Packit 6ef888
	char buf[sizeof(struct gfs_jindex)];
Packit 6ef888
	unsigned int j;
Packit 6ef888
	int error=0;
Packit 6ef888
	unsigned int tmp_mode = 0;
Packit 6ef888
Packit 6ef888
	if(ip->i_di.di_size % sizeof(struct gfs_jindex) != 0){
Packit 6ef888
		log_crit(_("The size reported in the journal index"
Packit 6ef888
				" inode is not a\n"
Packit 6ef888
				"\tmultiple of the size of a journal index.\n"));
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	if(!(sd_jindex = (struct gfs_jindex *)malloc(ip->i_di.di_size))) {
Packit 6ef888
		log_crit(_("Unable to allocate journal index\n"));
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	if(!memset(sd_jindex, 0, ip->i_di.di_size)) {
Packit 6ef888
		log_crit(_("Unable to zero journal index\n"));
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	/* ugly hack
Packit 6ef888
	 * Faking the gfs1_jindex inode as a directory to gfs2_readi
Packit 6ef888
	 * so it skips the metaheader struct in the data blocks
Packit 6ef888
	 * in the inode. gfs2_jindex inode doesn't have metaheaders
Packit 6ef888
	 * in the data blocks */
Packit 6ef888
	tmp_mode = ip->i_di.di_mode;
Packit 6ef888
	ip->i_di.di_mode &= ~S_IFMT;
Packit 6ef888
	ip->i_di.di_mode |= S_IFDIR;
Packit 6ef888
	for (j = 0; ; j++) {
Packit 6ef888
		struct gfs_jindex *journ;
Packit 6ef888
Packit 6ef888
		error = gfs2_readi(ip, buf, j * sizeof(struct gfs_jindex),
Packit 6ef888
						   sizeof(struct gfs_jindex));
Packit 6ef888
		if(!error)
Packit 6ef888
			break;
Packit 6ef888
		if (error != sizeof(struct gfs_jindex)){
Packit 6ef888
			log_crit(_("An error occurred while reading the"
Packit 6ef888
					" journal index file.\n"));
Packit 6ef888
			goto fail;
Packit 6ef888
		}
Packit 6ef888
		journ = sd_jindex + j;
Packit 6ef888
		gfs1_jindex_in(journ, buf);
Packit 6ef888
		sdp->jsize = (journ->ji_nsegment * 16 * sdp->bsize) >> 20;
Packit 6ef888
	}
Packit 6ef888
	ip->i_di.di_mode = tmp_mode;
Packit 6ef888
	if(j * sizeof(struct gfs_jindex) != ip->i_di.di_size){
Packit 6ef888
		log_crit(_("journal inode size invalid\n"));
Packit 6ef888
		goto fail;
Packit 6ef888
	}
Packit 6ef888
	sdp->md.journals = orig_journals = j;
Packit 6ef888
	return 0;
Packit 6ef888
Packit 6ef888
 fail:
Packit 6ef888
	free(sd_jindex);
Packit 6ef888
	return -1;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int sanity_check(struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	int error = 0;
Packit 6ef888
	if (!raw_gfs1_ondisk_sb.sb_quota_di.no_addr) {
Packit 6ef888
		log_crit(_("Error: Superblock Quota inode address is NULL\n"));
Packit 6ef888
		error = 1;
Packit 6ef888
	}
Packit 6ef888
	if (!raw_gfs1_ondisk_sb.sb_license_di.no_addr) {
Packit 6ef888
		log_crit(_("Error: Superblock Statfs inode address is NULL\n"));
Packit 6ef888
		error = 1;
Packit 6ef888
	}
Packit 6ef888
	if (!raw_gfs1_ondisk_sb.sb_seg_size) {
Packit 6ef888
		log_crit(_("Error: Superblock segment size is zero\n"));
Packit 6ef888
		error = 1;
Packit 6ef888
	}
Packit 6ef888
	return error;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* init - initialization code                                                */
Packit 6ef888
/* Returns: 0 on success, -1 on failure                                      */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static int init(struct gfs2_sbd *sbp, struct gfs2_options *opts)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	int rgcount;
Packit 6ef888
	struct gfs2_inum inum;
Packit 6ef888
Packit 6ef888
	memset(sbp, 0, sizeof(struct gfs2_sbd));
Packit 6ef888
	if ((sbp->device_fd = open(opts->device, O_RDWR)) < 0) {
Packit 6ef888
		perror(opts->device);
Packit 6ef888
		exit(-1);
Packit 6ef888
	}
Packit 6ef888
	/* --------------------------------- */
Packit 6ef888
	/* initialize the incore superblock  */
Packit 6ef888
	/* --------------------------------- */
Packit 6ef888
	sbp->sd_sb.sb_header.mh_magic = GFS2_MAGIC;
Packit 6ef888
	sbp->sd_sb.sb_header.mh_type = GFS2_METATYPE_SB;
Packit 6ef888
	sbp->sd_sb.sb_header.mh_format = GFS2_FORMAT_SB;
Packit 6ef888
Packit 6ef888
	osi_list_init((osi_list_t *)&dirs_to_fix);
Packit 6ef888
	osi_list_init((osi_list_t *)&cdpns_to_fix);
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	/* Initialize lists and read in the superblock.   */
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	sbp->jsize = GFS2_DEFAULT_JSIZE;
Packit 6ef888
	sbp->rgsize = GFS2_DEFAULT_RGSIZE;
Packit 6ef888
	sbp->qcsize = GFS2_DEFAULT_QCSIZE;
Packit 6ef888
	sbp->time = time(NULL);
Packit 6ef888
	sbp->blks_total = 0;   /* total blocks         - total them up later */
Packit 6ef888
	sbp->blks_alloced = 0; /* blocks allocated     - total them up later */
Packit 6ef888
	sbp->dinodes_alloced = 0; /* dinodes allocated - total them up later */
Packit 6ef888
	sbp->sd_sb.sb_bsize = GFS2_DEFAULT_BSIZE;
Packit 6ef888
	sbp->bsize = sbp->sd_sb.sb_bsize;
Packit 6ef888
	sbp->rgtree.osi_node = NULL;
Packit 6ef888
	if (compute_constants(sbp)) {
Packit 6ef888
		log_crit("%s\n", _("Failed to compute file system constants"));
Packit 6ef888
		exit(-1);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	bh = bread(sbp, GFS2_SB_ADDR >> sbp->sd_fsb2bb_shift);
Packit 6ef888
	memcpy(&raw_gfs1_ondisk_sb, (struct gfs_sb *)bh->b_data,
Packit 6ef888
		   sizeof(struct gfs_sb));
Packit 6ef888
	gfs2_sb_in(&sbp->sd_sb, bh->b_data);
Packit 6ef888
Packit 6ef888
	jindex_addr = be64_to_cpu(raw_gfs1_ondisk_sb.sb_jindex_di.no_addr);
Packit 6ef888
	rindex_addr = be64_to_cpu(raw_gfs1_ondisk_sb.sb_rindex_di.no_addr);
Packit 6ef888
Packit 6ef888
	sbp->bsize = sbp->sd_sb.sb_bsize;
Packit 6ef888
	sbp->fssize = lseek(sbp->device_fd, 0, SEEK_END) / sbp->sd_sb.sb_bsize;
Packit 6ef888
	sbp->sd_inptrs = (sbp->bsize - sizeof(struct gfs_indirect)) /
Packit 6ef888
		sizeof(uint64_t);
Packit 6ef888
	sbp->sd_diptrs = (sbp->bsize - sizeof(struct gfs_dinode)) /
Packit 6ef888
		sizeof(uint64_t);
Packit 6ef888
	sbp->sd_jbsize = sbp->bsize - sizeof(struct gfs2_meta_header);
Packit 6ef888
	brelse(bh);
Packit 6ef888
	if (compute_heightsize(sbp->bsize, sbp->sd_heightsize, &sbp->sd_max_height,
Packit 6ef888
				sbp->bsize, sbp->sd_diptrs, sbp->sd_inptrs)) {
Packit 6ef888
		log_crit("%s\n", _("Failed to compute file system constants"));
Packit 6ef888
		exit(-1);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (compute_heightsize(sbp->bsize, sbp->sd_jheightsize, &sbp->sd_max_jheight,
Packit 6ef888
				sbp->sd_jbsize, sbp->sd_diptrs, sbp->sd_inptrs)) {
Packit 6ef888
		log_crit("%s\n", _("Failed to compute file system constants"));
Packit 6ef888
		exit(-1);
Packit 6ef888
	}
Packit 6ef888
	/* -------------------------------------------------------- */
Packit 6ef888
	/* Our constants are for gfs1.  Need some for gfs2 as well. */
Packit 6ef888
	/* -------------------------------------------------------- */
Packit 6ef888
	gfs2_inptrs = (sbp->bsize - sizeof(struct gfs2_meta_header)) /
Packit 6ef888
                sizeof(uint64_t); /* How many ptrs can we fit on a block? */
Packit 6ef888
	memset(gfs2_heightsize, 0, sizeof(gfs2_heightsize));
Packit 6ef888
	if (compute_heightsize(sbp->bsize, gfs2_heightsize, &gfs2_max_height,
Packit 6ef888
				sbp->bsize, sbp->sd_diptrs, gfs2_inptrs)) {
Packit 6ef888
		log_crit("%s\n", _("Failed to compute file system constants"));
Packit 6ef888
		exit(-1);
Packit 6ef888
	}
Packit 6ef888
	memset(gfs2_jheightsize, 0, sizeof(gfs2_jheightsize));
Packit 6ef888
	if (compute_heightsize(sbp->bsize, gfs2_jheightsize, &gfs2_max_jheight,
Packit 6ef888
				sbp->sd_jbsize, sbp->sd_diptrs, gfs2_inptrs)) {
Packit 6ef888
		log_crit("%s\n", _("Failed to compute file system constants"));
Packit 6ef888
		exit(-1);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	/* Make sure we're really gfs1                    */
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	if (sbp->sd_sb.sb_fs_format != GFS_FORMAT_FS ||
Packit 6ef888
		sbp->sd_sb.sb_header.mh_type != GFS_METATYPE_SB ||
Packit 6ef888
		sbp->sd_sb.sb_header.mh_format != GFS_FORMAT_SB ||
Packit 6ef888
		sbp->sd_sb.sb_multihost_format != GFS_FORMAT_MULTI) {
Packit 6ef888
		log_crit(_("Error: %s does not look like a gfs1 filesystem.\n"), opts->device);
Packit 6ef888
		close(sbp->device_fd);
Packit 6ef888
		exit(-1);
Packit 6ef888
	}
Packit 6ef888
	/* get gfs1 rindex inode - gfs1's rindex inode ptr became __pad2 */
Packit 6ef888
	gfs2_inum_in(&inum, (char *)&raw_gfs1_ondisk_sb.sb_rindex_di);
Packit 6ef888
	sbp->md.riinode = lgfs2_gfs_inode_read(sbp, inum.no_addr);
Packit 6ef888
	if (sbp->md.riinode == NULL) {
Packit 6ef888
		log_crit(_("Could not read resource group index: %s\n"), strerror(errno));
Packit 6ef888
		exit(-1);
Packit 6ef888
	}
Packit 6ef888
	/* get gfs1 jindex inode - gfs1's journal index inode ptr became master */
Packit 6ef888
	gfs2_inum_in(&inum, (char *)&raw_gfs1_ondisk_sb.sb_jindex_di);
Packit 6ef888
	sbp->md.jiinode = lgfs2_inode_read(sbp, inum.no_addr);
Packit 6ef888
	if (sbp->md.jiinode == NULL) {
Packit 6ef888
		log_crit(_("Could not read journal index: %s\n"), strerror(errno));
Packit 6ef888
		exit(-1);
Packit 6ef888
	}
Packit 6ef888
	/* read in the journal index data */
Packit 6ef888
	read_gfs1_jiindex(sbp);
Packit 6ef888
	/* read in the resource group index data: */
Packit 6ef888
Packit 6ef888
	/* We've got a slight dilemma here.  In gfs1, we used to have a meta */
Packit 6ef888
	/* header in front of the rgindex pages.  In gfs2, we don't.  That's */
Packit 6ef888
	/* apparently only for directories.  So we need to fake out libgfs2  */
Packit 6ef888
	/* so that it adjusts for the metaheader by faking out the inode to  */
Packit 6ef888
	/* look like a directory, temporarily.                               */
Packit 6ef888
	sbp->md.riinode->i_di.di_mode &= ~S_IFMT;
Packit 6ef888
	sbp->md.riinode->i_di.di_mode |= S_IFDIR;
Packit 6ef888
	printf(_("Examining file system"));
Packit 6ef888
	if (gfs1_ri_update(sbp, 0, &rgcount, 0)){
Packit 6ef888
		log_crit(_("Unable to fill in resource group information.\n"));
Packit 6ef888
		return -1;
Packit 6ef888
	}
Packit 6ef888
	printf("\n");
Packit 6ef888
	fflush(stdout);
Packit 6ef888
	inode_put(&sbp->md.riinode);
Packit 6ef888
	inode_put(&sbp->md.jiinode);
Packit 6ef888
	log_debug(_("%d rgs found.\n"), rgcount);
Packit 6ef888
	return 0;
Packit 6ef888
}/* fill_super_block */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* give_warning - give the all-important warning message.                    */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static void give_warning(void)
Packit 6ef888
{
Packit 6ef888
	printf(_("This program will convert a gfs1 filesystem to a "	\
Packit 6ef888
		   "gfs2 filesystem.\n"));
Packit 6ef888
	printf(_("WARNING: This can't be undone.  It is strongly advised "	\
Packit 6ef888
		   "that you:\n\n"));
Packit 6ef888
	printf(_("   1. Back up your entire filesystem first.\n"));
Packit 6ef888
	printf(_("   2. Run fsck.gfs2 first to ensure filesystem integrity.\n"));
Packit 6ef888
	printf(_("   3. Make sure the filesystem is NOT mounted from any node.\n"));
Packit 6ef888
	printf(_("   4. Make sure you have the latest software versions.\n"));
Packit 6ef888
}/* give_warning */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* version  - print version information                                      */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static void version(void)
Packit 6ef888
{
Packit 6ef888
	log_notice(_("gfs2_convert version %s (built %s %s)\n"), VERSION,
Packit 6ef888
			   __DATE__, __TIME__);
Packit 6ef888
	log_notice("%s\n\n", REDHAT_COPYRIGHT);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* usage - print usage information                                           */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static void usage(const char *name)
Packit 6ef888
{
Packit 6ef888
	give_warning();
Packit 6ef888
	printf(_("\nUsage:\n"));
Packit 6ef888
	printf(_("%s [-hnqvVy] <device>\n\n"), name);
Packit 6ef888
	printf("Flags:\n");
Packit 6ef888
	printf(_("\th - print this help message\n"));
Packit 6ef888
	printf(_("\tn - assume 'no' to all questions\n"));
Packit 6ef888
	printf(_("\tq - quieter output\n"));
Packit 6ef888
	printf(_("\tv - more verbose output\n"));
Packit 6ef888
	printf(_("\tV - print version information\n"));
Packit 6ef888
	printf(_("\ty - assume 'yes' to all questions\n"));
Packit 6ef888
}/* usage */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* process_parameters                                                        */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static void process_parameters(int argc, char **argv, struct gfs2_options *opts)
Packit 6ef888
Packit 6ef888
{
Packit 6ef888
	int c;
Packit 6ef888
Packit 6ef888
	opts->yes = 0;
Packit 6ef888
	opts->no = 0;
Packit 6ef888
	if (argc == 1) {
Packit 6ef888
		usage(argv[0]);
Packit 6ef888
		exit(0);
Packit 6ef888
	}
Packit 6ef888
	while((c = getopt(argc, argv, "hnqvyV")) != -1) {
Packit 6ef888
		switch(c) {
Packit 6ef888
Packit 6ef888
		case 'h':
Packit 6ef888
			usage(argv[0]);
Packit 6ef888
			exit(0);
Packit 6ef888
			break;
Packit 6ef888
		case 'n':
Packit 6ef888
			opts->no = 1;
Packit 6ef888
			break;
Packit 6ef888
		case 'q':
Packit 6ef888
			decrease_verbosity();
Packit 6ef888
			break;
Packit 6ef888
		case 'v':
Packit 6ef888
			increase_verbosity();
Packit 6ef888
			break;
Packit 6ef888
		case 'V':
Packit 6ef888
			exit(0);
Packit 6ef888
		case 'y':
Packit 6ef888
			opts->yes = 1;
Packit 6ef888
			break;
Packit 6ef888
		default:
Packit 6ef888
			fprintf(stderr,_("Parameter not understood: %c\n"), c);
Packit 6ef888
			usage(argv[0]);
Packit 6ef888
			exit(0);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	if(argc > optind) {
Packit 6ef888
		opts->device = argv[optind];
Packit 6ef888
	} else {
Packit 6ef888
		fprintf(stderr, _("No device specified. Please use '-h' for help\n"));
Packit 6ef888
		exit(1);
Packit 6ef888
	}
Packit 6ef888
} /* process_parameters */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* rgrp_length - Calculate the length of a resource group                    */
Packit 6ef888
/* @size: The total size of the resource group                               */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static uint64_t rgrp_length(uint64_t size, struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	uint64_t bitbytes = RGRP_BITMAP_BLKS(&sdp->sd_sb) + 1;
Packit 6ef888
	uint64_t stuff = RGRP_STUFFED_BLKS(&sdp->sd_sb) + 1;
Packit 6ef888
	uint64_t blocks = 1;
Packit 6ef888
Packit 6ef888
	if (size >= stuff) {
Packit 6ef888
		size -= stuff;
Packit 6ef888
		while (size > bitbytes) {
Packit 6ef888
			blocks++;
Packit 6ef888
			size -= bitbytes;
Packit 6ef888
		}
Packit 6ef888
		if (size)
Packit 6ef888
			blocks++;
Packit 6ef888
	}
Packit 6ef888
	return blocks;
Packit 6ef888
}/* rgrp_length */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* journ_space_to_rg - convert gfs1 journal space to gfs2 rg space.          */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* In gfs1, the journals were kept separate from the files and directories.  */
Packit 6ef888
/* They had a dedicated section of the fs carved out for them.               */
Packit 6ef888
/* In gfs2, the journals are just files like any other, (but still hidden).  */
Packit 6ef888
/* Therefore, the old journal space has to be converted to normal resource   */
Packit 6ef888
/* group space.                                                              */
Packit 6ef888
/*                                                                           */
Packit 6ef888
/* Returns: 0 on success, -1 on failure                                      */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static int journ_space_to_rg(struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	int error = 0;
Packit 6ef888
	int j, x;
Packit 6ef888
	struct gfs_jindex *jndx;
Packit 6ef888
	struct rgrp_tree *rgd, *rgdhigh;
Packit 6ef888
	struct osi_node *n, *next = NULL;
Packit 6ef888
	struct gfs2_meta_header mh;
Packit 6ef888
	uint64_t ri_addr;
Packit 6ef888
Packit 6ef888
	mh.mh_magic = GFS2_MAGIC;
Packit 6ef888
	mh.mh_type = GFS2_METATYPE_RB;
Packit 6ef888
	mh.mh_format = GFS2_FORMAT_RB;
Packit 6ef888
	log_notice(_("Converting journal space to rg space.\n"));
Packit 6ef888
	/* Go through each journal, converting them one by one */
Packit 6ef888
	for (j = 0; j < orig_journals; j++) { /* for each journal */
Packit 6ef888
		uint64_t size;
Packit 6ef888
Packit 6ef888
		jndx = &sd_jindex[j];
Packit 6ef888
		/* go through all rg index entries, keeping track of the
Packit 6ef888
		   highest that's still in the first subdevice.
Packit 6ef888
		   Note: we really should go through all of the rgindex because
Packit 6ef888
		   we might have had rg's added by gfs_grow, and journals added
Packit 6ef888
		   by jadd.  gfs_grow adds rgs out of order, so we can't count
Packit 6ef888
		   on them being in ascending order. */
Packit 6ef888
		rgdhigh = NULL;
Packit 6ef888
		for (n = osi_first(&sdp->rgtree); n; n = next) {
Packit 6ef888
			next = osi_next(n);
Packit 6ef888
			rgd = (struct rgrp_tree *)n;
Packit 6ef888
			if (rgd->ri.ri_addr < jndx->ji_addr &&
Packit 6ef888
				((rgdhigh == NULL) ||
Packit 6ef888
				 (rgd->ri.ri_addr > rgdhigh->ri.ri_addr)))
Packit 6ef888
				rgdhigh = rgd;
Packit 6ef888
		} /* for each rg */
Packit 6ef888
		if (!rgdhigh) { /* if we somehow didn't find one. */
Packit 6ef888
			log_crit(_("Error: No suitable rg found for journal.\n"));
Packit 6ef888
			return -1;
Packit 6ef888
		}
Packit 6ef888
		log_info(_("Addr 0x%llx comes after rg at addr 0x%llx\n"),
Packit 6ef888
			 (unsigned long long)jndx->ji_addr,
Packit 6ef888
			 (unsigned long long)rgdhigh->ri.ri_addr);
Packit 6ef888
		ri_addr = jndx->ji_addr;
Packit 6ef888
		/* Allocate a new rgd entry which includes rg and ri. */
Packit 6ef888
		rgd = rgrp_insert(&sdp->rgtree, ri_addr);
Packit 6ef888
		/* convert the gfs1 rgrp into a new gfs2 rgrp */
Packit 6ef888
		size = jndx->ji_nsegment *
Packit 6ef888
			be32_to_cpu(raw_gfs1_ondisk_sb.sb_seg_size);
Packit 6ef888
		rgd->rg.rg_header.mh_magic = GFS2_MAGIC;
Packit 6ef888
		rgd->rg.rg_header.mh_type = GFS2_METATYPE_RG;
Packit 6ef888
		rgd->rg.rg_header.mh_format = GFS2_FORMAT_RG;
Packit 6ef888
		rgd->rg.rg_flags = 0;
Packit 6ef888
		rgd->rg.rg_dinodes = 0;
Packit 6ef888
Packit 6ef888
		rgd->ri.ri_addr = jndx->ji_addr; /* new rg addr becomes ji addr */
Packit 6ef888
		rgd->ri.ri_length = rgrp_length(size, sdp); /* aka bitblocks */
Packit 6ef888
Packit 6ef888
		rgd->ri.ri_data0 = jndx->ji_addr + rgd->ri.ri_length;
Packit 6ef888
		rgd->ri.ri_data = size - rgd->ri.ri_length;
Packit 6ef888
		/* Round down to nearest multiple of GFS2_NBBY */
Packit 6ef888
		while (rgd->ri.ri_data & 0x03)
Packit 6ef888
			rgd->ri.ri_data--;
Packit 6ef888
		sdp->blks_total += rgd->ri.ri_data; /* For statfs file update */
Packit 6ef888
		rgd->rg.rg_free = rgd->ri.ri_data;
Packit 6ef888
		rgd->ri.ri_bitbytes = rgd->ri.ri_data / GFS2_NBBY;
Packit 6ef888
Packit 6ef888
		if (gfs2_compute_bitstructs(sdp->sd_sb.sb_bsize, rgd)) {
Packit 6ef888
			log_crit(_("gfs2_convert: Error converting bitmaps.\n"));
Packit 6ef888
			exit(-1);
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		for (x = 0; x < rgd->ri.ri_length; x++)
Packit 6ef888
			rgd->bits[x].bi_bh = bget(sdp, rgd->ri.ri_addr + x);
Packit 6ef888
Packit 6ef888
		convert_bitmaps(sdp, rgd);
Packit 6ef888
		for (x = 0; x < rgd->ri.ri_length; x++) {
Packit 6ef888
			if (x)
Packit 6ef888
				gfs2_meta_header_out(&mh, rgd->bits[x].bi_bh->b_data);
Packit 6ef888
			else
Packit 6ef888
				gfs2_rgrp_out(&rgd->rg, rgd->bits[x].bi_bh->b_data);
Packit 6ef888
			bmodified(rgd->bits[x].bi_bh);
Packit 6ef888
		}
Packit 6ef888
	} /* for each journal */
Packit 6ef888
	return error;
Packit 6ef888
}/* journ_space_to_rg */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* update_inode_file - update the inode file with the new next_inum          */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static void update_inode_file(struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inode *ip = sdp->md.inum;
Packit 6ef888
	uint64_t buf;
Packit 6ef888
	int count;
Packit 6ef888
	
Packit 6ef888
	buf = cpu_to_be64(sdp->md.next_inum);
Packit 6ef888
	count = gfs2_writei(ip, &buf, 0, sizeof(uint64_t));
Packit 6ef888
	if (count != sizeof(uint64_t)) {
Packit 6ef888
		fprintf(stderr, "update_inode_file\n");
Packit 6ef888
		exit(1);
Packit 6ef888
	}
Packit 6ef888
	
Packit 6ef888
	log_debug(_("\nNext Inum: %llu\n"), (unsigned long long)sdp->md.next_inum);
Packit 6ef888
}/* update_inode_file */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* write_statfs_file - write the statfs file                                 */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static void write_statfs_file(struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inode *ip = sdp->md.statfs;
Packit 6ef888
	struct gfs2_statfs_change sc;
Packit 6ef888
	char buf[sizeof(struct gfs2_statfs_change)];
Packit 6ef888
	int count;
Packit 6ef888
Packit 6ef888
	sc.sc_total = sdp->blks_total;
Packit 6ef888
	sc.sc_free = sdp->blks_total - sdp->blks_alloced;
Packit 6ef888
	sc.sc_dinodes = sdp->dinodes_alloced;
Packit 6ef888
Packit 6ef888
	gfs2_statfs_change_out(&sc, buf);
Packit 6ef888
	count = gfs2_writei(ip, buf, 0, sizeof(struct gfs2_statfs_change));
Packit 6ef888
	if (count != sizeof(struct gfs2_statfs_change)) {
Packit 6ef888
		fprintf(stderr, "do_init (2)\n");
Packit 6ef888
		exit(1);
Packit 6ef888
	}
Packit 6ef888
}/* write_statfs_file */
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* remove_obsolete_gfs1 - remove obsolete gfs1 inodes.                       */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static void remove_obsolete_gfs1(struct gfs2_sbd *sbp)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inum inum;
Packit 6ef888
Packit 6ef888
	log_notice(_("Removing obsolete GFS1 file system structures.\n"));
Packit 6ef888
	fflush(stdout);
Packit 6ef888
	/* Delete the old gfs1 Journal index: */
Packit 6ef888
	gfs2_inum_in(&inum, (char *)&raw_gfs1_ondisk_sb.sb_jindex_di);
Packit 6ef888
	gfs2_freedi(sbp, inum.no_addr);
Packit 6ef888
Packit 6ef888
	/* Delete the old gfs1 rgindex: */
Packit 6ef888
	gfs2_inum_in(&inum, (char *)&raw_gfs1_ondisk_sb.sb_rindex_di);
Packit 6ef888
	gfs2_freedi(sbp, inum.no_addr);
Packit 6ef888
Packit 6ef888
	/* Delete the old gfs1 Quota file: */
Packit 6ef888
	gfs2_inum_in(&inum, (char *)&raw_gfs1_ondisk_sb.sb_quota_di);
Packit 6ef888
	gfs2_freedi(sbp, inum.no_addr);
Packit 6ef888
Packit 6ef888
	/* Delete the old gfs1 License file: */
Packit 6ef888
	gfs2_inum_in(&inum, (char *)&raw_gfs1_ondisk_sb.sb_license_di);
Packit 6ef888
	gfs2_freedi(sbp, inum.no_addr);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
/* lifted from libgfs2/structures.c                                          */
Packit 6ef888
/* ------------------------------------------------------------------------- */
Packit 6ef888
static int conv_build_jindex(struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	unsigned int j;
Packit 6ef888
Packit 6ef888
	sdp->md.jiinode = createi(sdp->master_dir, "jindex", S_IFDIR | 0700,
Packit 6ef888
				  GFS2_DIF_SYSTEM);
Packit 6ef888
	if (sdp->md.jiinode == NULL) {
Packit 6ef888
		return errno;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	sdp->md.journal = malloc(sdp->md.journals *
Packit 6ef888
				 sizeof(struct gfs2_inode *));
Packit 6ef888
	if (sdp->md.journal == NULL) {
Packit 6ef888
		return errno;
Packit 6ef888
	}
Packit 6ef888
	for (j = 0; j < sdp->md.journals; j++) {
Packit 6ef888
		char name[256];
Packit 6ef888
Packit 6ef888
		printf(_("Writing journal #%d..."), j + 1);
Packit 6ef888
		fflush(stdout);
Packit 6ef888
		sprintf(name, "journal%u", j);
Packit 6ef888
		sdp->md.journal[j] = createi(sdp->md.jiinode, name, S_IFREG |
Packit 6ef888
					     0600, GFS2_DIF_SYSTEM);
Packit 6ef888
		write_journal(sdp->md.journal[j], sdp->bsize,
Packit 6ef888
			      sdp->jsize << 20 >> sdp->sd_sb.sb_bsize_shift);
Packit 6ef888
		inode_put(&sdp->md.journal[j]);
Packit 6ef888
		printf(_("done.\n"));
Packit 6ef888
		fflush(stdout);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	free(sdp->md.journal);
Packit 6ef888
	inode_put(&sdp->md.jiinode);
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static unsigned int total_file_blocks(struct gfs2_sbd *sdp, 
Packit 6ef888
				      uint64_t filesize, int journaled)
Packit 6ef888
{
Packit 6ef888
	unsigned int data_blks = 0, meta_blks = 0;
Packit 6ef888
	unsigned int max, height, bsize;
Packit 6ef888
	uint64_t *arr;
Packit 6ef888
Packit 6ef888
	/* Now find the total meta blocks required for data_blks */
Packit 6ef888
	if (filesize <= sdp->bsize - sizeof(struct gfs2_dinode)) {
Packit 6ef888
		goto out;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	if (journaled) {
Packit 6ef888
		arr = sdp->sd_jheightsize;
Packit 6ef888
		max = sdp->sd_max_jheight;
Packit 6ef888
		bsize = sdp->sd_jbsize;
Packit 6ef888
	} else {
Packit 6ef888
		arr = sdp->sd_heightsize;
Packit 6ef888
		max = sdp->sd_max_height;
Packit 6ef888
		bsize = sdp->bsize;
Packit 6ef888
	}
Packit 6ef888
	data_blks = DIV_RU(filesize, bsize); /* total data blocks reqd */
Packit 6ef888
Packit 6ef888
	for (height = 0; height < max; height++)
Packit 6ef888
		if (arr[height] >= filesize)
Packit 6ef888
			break;
Packit 6ef888
	if (height == 1) {
Packit 6ef888
		goto out;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	meta_blks = DIV_RU(data_blks, sdp->sd_inptrs);
Packit 6ef888
out:
Packit 6ef888
	return data_blks + meta_blks;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* We check if the GFS2 filesystem files/structures created after the call to 
Packit 6ef888
 * check_fit() in main() will fit in the currently available free blocks
Packit 6ef888
 */
Packit 6ef888
static int check_fit(struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	unsigned int blks_need = 0, blks_avail = sdp->blks_total - sdp->blks_alloced;
Packit 6ef888
Packit 6ef888
	/* build_master() */
Packit 6ef888
	blks_need++; /*creation of master dir inode - 1 block */
Packit 6ef888
Packit 6ef888
	/* conv_build_jindex() */
Packit 6ef888
	{
Packit 6ef888
		blks_need++; /* creation of 'jindex' disk inode */
Packit 6ef888
		/* creation of journals */
Packit 6ef888
		blks_need += sdp->md.journals *
Packit 6ef888
			total_file_blocks(sdp, sdp->jsize << 20, 1);
Packit 6ef888
	}
Packit 6ef888
	/* build_per_node() */
Packit 6ef888
	{
Packit 6ef888
		blks_need++; /* creation of 'per_node' dir inode */
Packit 6ef888
		/* njourn x (inum_range + statfs_change + quota_change inodes) */
Packit 6ef888
		blks_need += sdp->md.journals * 3;
Packit 6ef888
		/* quota change inodes are prealloced */
Packit 6ef888
		blks_need += sdp->md.journals *
Packit 6ef888
			total_file_blocks(sdp, sdp->qcsize << 20, 1);
Packit 6ef888
	}
Packit 6ef888
	/* build_inum() */
Packit 6ef888
	blks_need++; /* creation of 'inum' disk inode */
Packit 6ef888
Packit 6ef888
	/* build_statfs() */
Packit 6ef888
	blks_need++; /* creation of 'statfs' disk inode */
Packit 6ef888
Packit 6ef888
	/* build_rindex() */
Packit 6ef888
	{
Packit 6ef888
		struct osi_node *n, *next = NULL;
Packit 6ef888
		unsigned int rg_count = 0;
Packit 6ef888
Packit 6ef888
		blks_need++; /* creationg of 'rindex' disk inode */
Packit 6ef888
		/* find the total # of rindex entries, gives size of rindex inode */
Packit 6ef888
		for (n = osi_first(&sdp->rgtree); n; n = next) {
Packit 6ef888
			next = osi_next(n);
Packit 6ef888
			rg_count++;
Packit 6ef888
		}
Packit 6ef888
		blks_need += total_file_blocks(sdp, rg_count *
Packit 6ef888
					       sizeof(struct gfs2_rindex), 1);
Packit 6ef888
	}
Packit 6ef888
	/* build_quota() */
Packit 6ef888
	blks_need++; /* quota inode block and uid=gid=0 quota - total 1 block */
Packit 6ef888
Packit 6ef888
	/* Up until this point we require blks_need blocks. We don't 
Packit 6ef888
	 * include the blocks freed by the next step (remove_obsolete_gfs1)
Packit 6ef888
	 * because it's possible for us to exceed the available blocks
Packit 6ef888
	 * before this step */
Packit 6ef888
Packit 6ef888
	return blks_avail > blks_need;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* We fetch the old quota inode block and copy the contents of the block
Packit 6ef888
 * (minus the struct gfs2_dinode) into the new quota block. We update the 
Packit 6ef888
 * inode height/size of the new quota file to that of the old one and set the 
Packit 6ef888
 * old quota inode height/size to zero, so only the inode block gets freed.
Packit 6ef888
 */
Packit 6ef888
static void copy_quotas(struct gfs2_sbd *sdp)
Packit 6ef888
{
Packit 6ef888
	struct gfs2_inum inum;
Packit 6ef888
	struct gfs2_inode *oq_ip, *nq_ip;
Packit 6ef888
	int err;
Packit 6ef888
Packit 6ef888
	err = gfs2_lookupi(sdp->master_dir, "quota", 5, &nq_ip);
Packit 6ef888
	if (err) {
Packit 6ef888
		fprintf(stderr, _("Couldn't lookup new quota file: %d\n"), err);
Packit 6ef888
		exit(1);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	gfs2_inum_in(&inum, (char *)&raw_gfs1_ondisk_sb.sb_quota_di);
Packit 6ef888
	oq_ip = lgfs2_inode_read(sdp, inum.no_addr);
Packit 6ef888
	if (oq_ip == NULL) {
Packit 6ef888
		fprintf(stderr, _("Couldn't lookup old quota file: %s\n"), strerror(errno));
Packit 6ef888
		exit(1);
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	nq_ip->i_di.di_height = oq_ip->i_di.di_height;
Packit 6ef888
	nq_ip->i_di.di_size = oq_ip->i_di.di_size;
Packit 6ef888
	nq_ip->i_di.di_blocks = oq_ip->i_di.di_blocks;
Packit 6ef888
	memcpy(nq_ip->i_bh->b_data + sizeof(struct gfs2_dinode), 
Packit 6ef888
	       oq_ip->i_bh->b_data + sizeof(struct gfs2_dinode),
Packit 6ef888
	       sdp->bsize - sizeof(struct gfs2_dinode));
Packit 6ef888
Packit 6ef888
	oq_ip->i_di.di_height = 0;
Packit 6ef888
	oq_ip->i_di.di_size = 0;
Packit 6ef888
Packit 6ef888
	bmodified(nq_ip->i_bh);
Packit 6ef888
	inode_put(&nq_ip);
Packit 6ef888
Packit 6ef888
	bmodified(oq_ip->i_bh);
Packit 6ef888
	inode_put(&oq_ip);
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
static int gfs2_query(struct gfs2_options *opts, const char *dev)
Packit 6ef888
{
Packit 6ef888
	int res = 0;
Packit 6ef888
Packit 6ef888
	if(opts->yes)
Packit 6ef888
		return 1;
Packit 6ef888
	if(opts->no)
Packit 6ef888
		return 0;
Packit 6ef888
Packit 6ef888
	opts->query = TRUE;
Packit 6ef888
	while (1) {
Packit 6ef888
		char *line = NULL;
Packit 6ef888
		size_t len = 0;
Packit 6ef888
		int ret;
Packit 6ef888
Packit 6ef888
		printf(_("Convert %s from GFS1 to GFS2? (y/n)"), dev);
Packit 6ef888
		fflush(stdout);
Packit 6ef888
		ret = getline(&line, &len, stdin);
Packit 6ef888
		res = rpmatch(line);
Packit 6ef888
		free(line);
Packit 6ef888
		if (ret <= 0)
Packit 6ef888
			continue;
Packit 6ef888
		if (res == 1 || res == 0)
Packit 6ef888
			break;
Packit 6ef888
		/* Unrecognized input; go again. */
Packit 6ef888
	}
Packit 6ef888
	opts->query = FALSE;
Packit 6ef888
	return res;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
int main(int argc, char **argv)
Packit 6ef888
{
Packit 6ef888
	int error;
Packit 6ef888
	struct gfs2_buffer_head *bh;
Packit 6ef888
	struct gfs2_options opts;
Packit 6ef888
Packit 6ef888
	/* Set i18n support to gfs2_convert */
Packit 6ef888
	setlocale(LC_ALL, "");
Packit 6ef888
	textdomain("gfs2-utils");
Packit 6ef888
Packit 6ef888
	version();
Packit 6ef888
	process_parameters(argc, argv, &opts);
Packit 6ef888
	error = init(&sb2, &opts);
Packit 6ef888
Packit 6ef888
	/*
Packit 6ef888
	 * Check for some common fs errors
Packit 6ef888
	 */
Packit 6ef888
	if (!error) {
Packit 6ef888
		if (sanity_check(&sb2)) {
Packit 6ef888
			log_crit(_("%s is not a clean gfs filesystem. Please use the"
Packit 6ef888
				   " fsck.gfs2 utility to correct these errors and"
Packit 6ef888
				   " try again.\n"), opts.device);
Packit 6ef888
			exit(0);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	/* Make them seal their fate.                     */
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	if (!error) {
Packit 6ef888
		give_warning();
Packit 6ef888
		if (!gfs2_query(&opts, opts.device)) {
Packit 6ef888
			log_crit(_("%s not converted.\n"), opts.device);
Packit 6ef888
			close(sb2.device_fd);
Packit 6ef888
			exit(0);
Packit 6ef888
		}
Packit 6ef888
	}
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	/* Convert incore gfs1 sb to gfs2 sb              */
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	if (!error) {
Packit 6ef888
		log_notice(_("Converting resource groups."));
Packit 6ef888
		fflush(stdout);
Packit 6ef888
		error = convert_rgs(&sb2;;
Packit 6ef888
		log_notice("\n");
Packit 6ef888
		if (error)
Packit 6ef888
			log_crit(_("%s: Unable to convert resource groups.\n"), opts.device);
Packit 6ef888
		fsync(sb2.device_fd); /* write the buffers to disk */
Packit 6ef888
	}
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	/* Renumber the inodes consecutively.             */
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	if (!error) {
Packit 6ef888
		/* Add a string notifying inode converstion start? */
Packit 6ef888
		error = inode_renumber(&sb2, sb2.sd_sb.sb_root_dir.no_addr,
Packit 6ef888
				       (osi_list_t *)&cdpns_to_fix);
Packit 6ef888
		if (error)
Packit 6ef888
			log_crit(_("\n%s: Error renumbering inodes.\n"), opts.device);
Packit 6ef888
		fsync(sb2.device_fd); /* write the buffers to disk */
Packit 6ef888
	}
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	/* Fix the directories to match the new numbers.  */
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	if (!error) {
Packit 6ef888
		error = fix_directory_info(&sb2, (osi_list_t *)&dirs_to_fix);
Packit 6ef888
		log_notice(_("\r%llu directories, %llu dirents fixed."),
Packit 6ef888
			   (unsigned long long)dirs_fixed,
Packit 6ef888
			   (unsigned long long)dirents_fixed);
Packit 6ef888
		fflush(stdout);
Packit 6ef888
		if (error)
Packit 6ef888
			log_crit(_("\n%s: Error fixing directories.\n"), opts.device);
Packit 6ef888
	}
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	/* Convert cdpn symlinks to empty dirs            */
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	if (!error) {
Packit 6ef888
		error = fix_cdpn_symlinks(&sb2, (osi_list_t *)&cdpns_to_fix);
Packit 6ef888
		log_notice(_("\r%llu cdpn symlinks moved to empty directories."),
Packit 6ef888
			   (unsigned long long)cdpns_fixed);
Packit 6ef888
		fflush(stdout);
Packit 6ef888
		if (error)
Packit 6ef888
			log_crit(_("\n%s: Error fixing cdpn symlinks.\n"), opts.device);
Packit 6ef888
	}
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	/* Convert journal space to rg space              */
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	if (!error) {
Packit 6ef888
		log_notice(_("\nConverting journals.\n"));
Packit 6ef888
		error = journ_space_to_rg(&sb2;;
Packit 6ef888
		if (error)
Packit 6ef888
			log_crit(_("%s: Error converting journal space.\n"), opts.device);
Packit 6ef888
		fsync(sb2.device_fd); /* write the buffers to disk */
Packit 6ef888
	}
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	/* Create our system files and directories.       */
Packit 6ef888
	/* ---------------------------------------------- */
Packit 6ef888
	if (!error) {
Packit 6ef888
		int jreduce = 0;
Packit 6ef888
Packit 6ef888
		/* Now we've got to treat it as a gfs2 file system */
Packit 6ef888
		if (compute_constants(&sb2)) {
Packit 6ef888
			log_crit("%s\n", _("Failed to compute file system constants"));
Packit 6ef888
			exit(-1);
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		/* Check if all the files we're about to create will 
Packit 6ef888
		 * fit into the space remaining on the device */
Packit 6ef888
		while (!check_fit(&sb2)) {
Packit 6ef888
			sb2.jsize--; /* reduce jsize by 1MB each time */
Packit 6ef888
			jreduce = 1;
Packit 6ef888
		}
Packit 6ef888
		if (jreduce)
Packit 6ef888
			log_notice(_("Reduced journal size to %u MB to accommodate "
Packit 6ef888
				   "GFS2 file system structures.\n"), sb2.jsize);
Packit 6ef888
		/* Build the master subdirectory. */
Packit 6ef888
		build_master(&sb2;; /* Does not do inode_put */
Packit 6ef888
		sb2.sd_sb.sb_master_dir = sb2.master_dir->i_di.di_num;
Packit 6ef888
		/* Build empty journal index file. */
Packit 6ef888
		error = conv_build_jindex(&sb2;;
Packit 6ef888
		if (error) {
Packit 6ef888
			log_crit(_("Error: could not build jindex: %s\n"), strerror(error));
Packit 6ef888
			exit(-1);
Packit 6ef888
		}
Packit 6ef888
		log_notice(_("Building GFS2 file system structures.\n"));
Packit 6ef888
		/* Build the per-node directories */
Packit 6ef888
		error = build_per_node(&sb2;;
Packit 6ef888
		if (error) {
Packit 6ef888
			log_crit(_("Error building per-node directories: %s\n"),
Packit 6ef888
			         strerror(error));
Packit 6ef888
			exit(-1);
Packit 6ef888
		}
Packit 6ef888
		/* Create the empty inode number file */
Packit 6ef888
		error = build_inum(&sb2;; /* Does not do inode_put */
Packit 6ef888
		if (error) {
Packit 6ef888
			log_crit(_("Error building inum inode: %s\n"),
Packit 6ef888
			         strerror(error));
Packit 6ef888
			exit(-1);
Packit 6ef888
		}
Packit 6ef888
		gfs2_lookupi(sb2.master_dir, "inum", 4, &sb2.md.inum);
Packit 6ef888
		/* Create the statfs file */
Packit 6ef888
		error = build_statfs(&sb2;; /* Does not do inode_put */
Packit 6ef888
		if (error) {
Packit 6ef888
			log_crit(_("Error building statfs inode: %s\n"),
Packit 6ef888
			         strerror(error));
Packit 6ef888
			exit(-1);
Packit 6ef888
		}
Packit 6ef888
		gfs2_lookupi(sb2.master_dir, "statfs", 6, &sb2.md.statfs);
Packit 6ef888
		do_init_statfs(&sb2;;
Packit 6ef888
Packit 6ef888
		/* Create the resource group index file */
Packit 6ef888
		error = build_rindex(&sb2;;
Packit 6ef888
		if (error) {
Packit 6ef888
			log_crit(_("Error building rindex inode: %s\n"),
Packit 6ef888
			         strerror(error));
Packit 6ef888
			exit(-1);
Packit 6ef888
		}
Packit 6ef888
		/* Create the quota file */
Packit 6ef888
		error = build_quota(&sb2;;
Packit 6ef888
		if (error) {
Packit 6ef888
			log_crit(_("Error building quota inode: %s\n"),
Packit 6ef888
			         strerror(error));
Packit 6ef888
			exit(-1);
Packit 6ef888
		}
Packit 6ef888
Packit 6ef888
		/* Copy out the master dinode */
Packit 6ef888
		{
Packit 6ef888
			struct gfs2_inode *ip = sb2.master_dir;
Packit 6ef888
			if (ip->i_bh->b_modified)
Packit 6ef888
				gfs2_dinode_out(&ip->i_di, ip->i_bh->b_data);
Packit 6ef888
		}
Packit 6ef888
		/* Copy old quotas */
Packit 6ef888
		copy_quotas(&sb2;;
Packit 6ef888
Packit 6ef888
		update_inode_file(&sb2;;
Packit 6ef888
		/* Now delete the now-obsolete gfs1 files: */
Packit 6ef888
		remove_obsolete_gfs1(&sb2;;
Packit 6ef888
Packit 6ef888
		write_statfs_file(&sb2;;
Packit 6ef888
Packit 6ef888
		inode_put(&sb2.master_dir);
Packit 6ef888
		inode_put(&sb2.md.inum);
Packit 6ef888
		inode_put(&sb2.md.statfs);
Packit 6ef888
Packit 6ef888
		fsync(sb2.device_fd); /* write the buffers to disk */
Packit 6ef888
Packit 6ef888
		/* Now free all the in memory */
Packit 6ef888
		gfs2_rgrp_free(&sb2.rgtree);
Packit 6ef888
		log_notice(_("Committing changes to disk.\n"));
Packit 6ef888
		fflush(stdout);
Packit 6ef888
		/* Set filesystem type in superblock to gfs2.  We do this at the */
Packit 6ef888
		/* end because if the tool is interrupted in the middle, we want */
Packit 6ef888
		/* it to not reject the partially converted fs as already done   */
Packit 6ef888
		/* when it's run a second time.                                  */
Packit 6ef888
		bh = bread(&sb2, LGFS2_SB_ADDR(&sb2));
Packit 6ef888
		sb2.sd_sb.sb_fs_format = GFS2_FORMAT_FS;
Packit 6ef888
		sb2.sd_sb.sb_multihost_format = GFS2_FORMAT_MULTI;
Packit 6ef888
		gfs2_sb_out(&sb2.sd_sb, bh->b_data);
Packit 6ef888
		bmodified(bh);
Packit 6ef888
		brelse(bh);
Packit 6ef888
Packit 6ef888
		error = fsync(sb2.device_fd);
Packit 6ef888
		if (error)
Packit 6ef888
			perror(opts.device);
Packit 6ef888
		else
Packit 6ef888
			log_notice(_("%s: filesystem converted successfully to gfs2.\n"), opts.device);
Packit 6ef888
	}
Packit 6ef888
	close(sb2.device_fd);
Packit 6ef888
	if (sd_jindex)
Packit 6ef888
		free(sd_jindex);
Packit 6ef888
	exit(0);
Packit 6ef888
}