Blame gfs2/convert/gfs2_convert.c

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