|
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 |
}
|