* [PATCH v2] xfsdump: use the full 32-bit generation number
@ 2012-02-09 18:46 Bill Kendall
2012-02-12 23:47 ` Christoph Hellwig
0 siblings, 1 reply; 4+ messages in thread
From: Bill Kendall @ 2012-02-09 18:46 UTC (permalink / raw)
To: xfs
xfsdump historically has truncated the inode generation number to
the low 12 bits when writing out directory entries. This makes it
possible for xfsrestore to mistakingly think 2 directory entries
refer to the same inode when dealing with incremental or resumed
dumps. A message such as this is an indication of this problem:
WARNING: unable to unlink current file prior to restore
This patch changes xfsdump to use the full 32-bit inode generation
number. A change to part of the dump format (direnthdr_t) was
required, so the dump format version has been bumped to 3. xfsdump
also required changes to its inode-to-generation cache. This map is
not persistent though, so no compatibility or version changes were
required there.
xfsdump can still generate a format 2 dump using the new -K option.
This is useful when moving a filesystem to a system with an older
version of xfsrestore.
xfsrestore has been changed to support the old and new dump formats.
This required a change to its persistent data structures (for
cumulative restores), so the housekeeping version number was bumped
as well.
When restoring a series of incremental/resumed dumps, if the oldest
restore used 12-bit generation numbers then they will be used
throughout the restore series to avoid mass confusion.
In the rare case that a cumulative restore is done using a format 3
dump followed by a format 2 dump, the user must specifically tell
xfsrestore to use format 2 generation numbers throughout the restore
series by using the -K option on the first restore.
It's recommended that users do a level 0 backup of their filesystems
with the new xfsdump so that future incremental restores can take
advantage of the full 32-bit generation number.
This patch also fixes a couple of instances where the dump format
was being displayed with an incorrect value.
Signed-off-by: Bill Kendall <wkendall@sgi.com>
---
Changes in v2:
* add -K option to xfsdump and restore for
compatibility with format 2 dumps. xfsdump -K
generates format 2 dumps. xfsrestore -K forces
the use of format 2 (truncated) generation numbers.
* show correct current dump format when displaying
version information.
* detect cases where xfsrestore -K is required.
* validate checksums of a format 2 direnthdr_v1_t
before it's converted to a direnthdr_t.
I have a few xfstests to cover these changes. I'll submit them once
this has been reviewed in case they need to be tweaked.
common/arch_xlate.c | 54 ++++++++++++++++++++++++++--
common/arch_xlate.h | 5 +++
common/content_inode.h | 20 +++++++++--
common/global.c | 5 +++
common/global.h | 7 ++--
common/main.c | 16 +++-----
dump/content.c | 82 +++++++++++++++++++++++++++++++-----------
dump/getopt.h | 4 +-
dump/inomap.c | 45 +++++-------------------
dump/inomap.h | 2 +-
man/man8/xfsdump.8 | 7 ++++
man/man8/xfsrestore.8 | 9 +++++
restore/content.c | 88 +++++++++++++++++++++++++++++++++++++---------
restore/getopt.h | 4 +-
restore/tree.c | 91 +++++++++++++++++++++++++++++++++++++++--------
restore/tree.h | 16 +++++++--
16 files changed, 335 insertions(+), 120 deletions(-)
diff --git a/common/arch_xlate.c b/common/arch_xlate.c
index 1c7e880..c156313 100644
--- a/common/arch_xlate.c
+++ b/common/arch_xlate.c
@@ -438,8 +438,8 @@ xlate_direnthdr(direnthdr_t *dh1, direnthdr_t *dh2, int dir)
IXLATE(dh1, dh2, dh_ino);
IXLATE(dh1, dh2, dh_gen);
- IXLATE(dh1, dh2, dh_sz);
IXLATE(dh1, dh2, dh_checksum);
+ IXLATE(dh1, dh2, dh_sz);
if (dir < 0) {
ptr1 = dh2;
@@ -450,7 +450,53 @@ xlate_direnthdr(direnthdr_t *dh1, direnthdr_t *dh2, int dir)
mlog(MLOG_NITTY, "xlate_direnthdr: pre-xlate\n"
"\tdh_ino %llu\n"
- "\tdh_gen %d\n"
+ "\tdh_gen %u\n"
+ "\tdh_checksum %d\n"
+ "\tdh_sz %d\n"
+ "\tdh_name %.8s\n",
+ ptr1->dh_ino,
+ ptr1->dh_gen,
+ ptr1->dh_checksum,
+ ptr1->dh_sz,
+ ptr1->dh_name );
+
+ mlog(MLOG_NITTY, "xlate_direnthdr: post-xlate\n"
+ "\tdh_ino %llu\n"
+ "\tdh_gen %u\n"
+ "\tdh_checksum %d\n"
+ "\tdh_sz %d\n"
+ "\tdh_name %.8s\n",
+ ptr2->dh_ino,
+ ptr2->dh_gen,
+ ptr2->dh_checksum,
+ ptr2->dh_sz,
+ ptr2->dh_name );
+}
+
+/*
+ * xlate_direnthdr_v1 - endian convert struct direnthdr_v1
+ */
+void
+xlate_direnthdr_v1(direnthdr_v1_t *dh1, direnthdr_v1_t *dh2, int dir)
+{
+ direnthdr_v1_t *ptr1 = dh1;
+ direnthdr_v1_t *ptr2 = dh2;
+
+ IXLATE(dh1, dh2, dh_ino);
+ IXLATE(dh1, dh2, dh_gen);
+ IXLATE(dh1, dh2, dh_sz);
+ IXLATE(dh1, dh2, dh_checksum);
+
+ if (dir < 0) {
+ ptr1 = dh2;
+ ptr2 = dh1;
+ }
+
+ BXLATE(dh_name);
+
+ mlog(MLOG_NITTY, "xlate_direnthdr_v1: pre-xlate\n"
+ "\tdh_ino %llu\n"
+ "\tdh_gen %u\n"
"\tdh_sz %d\n"
"\tdh_checksum %d\n"
"\tdh_name %.8s\n",
@@ -460,9 +506,9 @@ xlate_direnthdr(direnthdr_t *dh1, direnthdr_t *dh2, int dir)
ptr1->dh_checksum,
ptr1->dh_name );
- mlog(MLOG_NITTY, "xlate_direnthdr: post-xlate\n"
+ mlog(MLOG_NITTY, "xlate_direnthdr_v1: post-xlate\n"
"\tdh_ino %llu\n"
- "\tdh_gen %d\n"
+ "\tdh_gen %u\n"
"\tdh_sz %d\n"
"\tdh_checksum %d\n"
"\tdh_name %.8s\n",
diff --git a/common/arch_xlate.h b/common/arch_xlate.h
index 3ad3c97..35333c6 100644
--- a/common/arch_xlate.h
+++ b/common/arch_xlate.h
@@ -98,6 +98,11 @@ void xlate_extenthdr(extenthdr_t *eh1, extenthdr_t *eh2, int dir);
void xlate_direnthdr(direnthdr_t *dh1, direnthdr_t *dh2, int dir);
/*
+ * xlate_direnthdr_v1 - endian convert struct direnthdr_v1
+ */
+void xlate_direnthdr_v1(direnthdr_v1_t *dh1, direnthdr_v1_t *dh2, int dir);
+
+/*
* xlate_extattrhdr - endian convert struct extattrhdr
*/
void xlate_extattrhdr(extattrhdr_t *eh1, extattrhdr_t *eh2, int dir);
diff --git a/common/content_inode.h b/common/content_inode.h
index 67c4f6d..a25b66e 100644
--- a/common/content_inode.h
+++ b/common/content_inode.h
@@ -284,26 +284,40 @@ typedef struct extenthdr extenthdr_t;
* a sequence of directory entries is always terminated with a null direnthdr_t.
* this is detected by looking for a zero ino.
*/
+typedef u_int32_t gen_t;
+
#define DIRENTHDR_ALIGN 8
#define DIRENTHDR_SZ 24
struct direnthdr {
xfs_ino_t dh_ino;
+ gen_t dh_gen;
+ u_int32_t dh_checksum;
+ u_int16_t dh_sz; /* overall size of record */
+ char dh_name[ 6 ];
+};
+
+typedef struct direnthdr direnthdr_t;
+
+/* the old direnthdr truncated the inode generation number
+ * to the low 12 bits.
+ */
+
+struct direnthdr_v1 {
+ xfs_ino_t dh_ino;
u_int16_t dh_gen; /* generation count & DENTGENMASK of ref'ed inode */
u_int16_t dh_sz; /* overall size of record */
u_int32_t dh_checksum;
char dh_name[ 8 ];
};
-typedef struct direnthdr direnthdr_t;
+typedef struct direnthdr_v1 direnthdr_v1_t;
/* truncated generation count
*/
#define DENTGENSZ 12 /* leave 4 bits for future flags */
#define DENTGENMASK (( 1 << DENTGENSZ ) - 1 )
-typedef u_int16_t gen_t;
-#define GEN_NULL ( ( gen_t )UINT16MAX )
#define BIGGEN2GEN( bg ) ( ( gen_t )( bg & DENTGENMASK ))
diff --git a/common/global.c b/common/global.c
index 737b731..8e49d8b 100644
--- a/common/global.c
+++ b/common/global.c
@@ -191,6 +191,10 @@ global_hdr_alloc( intgen_t argc, char *argv[ ] )
}
ghdrp->gh_timestamp = statb.st_mtime;
break;
+
+ case GETOPT_FMT2COMPAT:
+ ghdrp->gh_version = GLOBAL_HDR_VERSION_2;
+ break;
#endif /* DUMP */
}
}
@@ -276,6 +280,7 @@ global_version_check( u_int32_t version )
case GLOBAL_HDR_VERSION_0:
case GLOBAL_HDR_VERSION_1:
case GLOBAL_HDR_VERSION_2:
+ case GLOBAL_HDR_VERSION_3:
return BOOL_TRUE;
default:
return BOOL_FALSE;
diff --git a/common/global.h b/common/global.h
index ea2b732..6556a68 100644
--- a/common/global.h
+++ b/common/global.h
@@ -27,13 +27,14 @@
#define GLOBAL_HDR_VERSION_0 0
#define GLOBAL_HDR_VERSION_1 1
#define GLOBAL_HDR_VERSION_2 2
- /* version 2 adds encoding of holes and a change to on-tape inventory format.
+#define GLOBAL_HDR_VERSION_3 3
+ /* version 3 uses the full 32-bit inode generation number in direnthdr_t.
+ * version 2 adds encoding of holes and a change to on-tape inventory format.
* version 1 adds extended file attribute dumping.
* version 0 xfsrestore can't handle media produced
* by version 1 xfsdump.
*/
-#define GLOBAL_HDR_VERSION GLOBAL_HDR_VERSION_2
-#define GLOBAL_HDR_VERSION_PREV 1
+#define GLOBAL_HDR_VERSION GLOBAL_HDR_VERSION_3
#define GLOBAL_HDR_STRING_SZ 0x100
#define GLOBAL_HDR_TIME_SZ 4
diff --git a/common/main.c b/common/main.c
index 5880723..a01b02a 100644
--- a/common/main.c
+++ b/common/main.c
@@ -103,8 +103,6 @@ static char *strpbrkquotes( char *p, const char *sep );
/* definition of locally defined global variables ****************************/
-intgen_t version = 3;
-intgen_t subversion = 0;
char *progname = 0; /* used in all error output */
char *homedir = 0; /* directory invoked from */
bool_t pipeline = BOOL_FALSE;
@@ -400,10 +398,8 @@ main( int argc, char *argv[] )
*/
if ( infoonly ) {
mlog( MLOG_NORMAL,
- _("version %s (dump format %d.%d)\n"),
- VERSION,
- version,
- subversion );
+ _("version %s (dump format %d.0)\n"),
+ VERSION, GLOBAL_HDR_VERSION );
usage( );
return mlog_exit(EXIT_NORMAL, RV_OK); /* normal termination */
}
@@ -475,10 +471,8 @@ main( int argc, char *argv[] )
*/
sistr = sigintstr( );
mlog( MLOG_VERBOSE,
- _("version %s (dump format %d.%d)"),
- VERSION,
- version,
- subversion );
+ _("version %s (dump format %d.0)"),
+ VERSION, GLOBAL_HDR_VERSION );
if ( ! pipeline && ! stdoutpiped && sistr && dlog_allowed( )) {
mlog( MLOG_VERBOSE | MLOG_BARE, _(
" - "
@@ -930,6 +924,7 @@ usage( void )
#endif /* REVEAL */
ULO(_("(display dump inventory)"), GETOPT_INVPRINT );
ULO(_("(inhibit inventory update)"), GETOPT_NOINVUPDATE );
+ ULO(_("(generate format 2 dump)"), GETOPT_FMT2COMPAT );
ULO(_("<session label>"), GETOPT_DUMPLABEL );
ULO(_("<media label> ..."), GETOPT_MEDIALABEL );
#ifdef REVEAL
@@ -978,6 +973,7 @@ usage( void )
ULO(_("(don't prompt)"), GETOPT_FORCE );
ULO(_("(display dump inventory)"), GETOPT_INVPRINT );
ULO(_("(inhibit inventory update)"), GETOPT_NOINVUPDATE );
+ ULO(_("(force use of format 2 generation numbers)"),GETOPT_FMT2COMPAT );
ULO(_("<session label>"), GETOPT_DUMPLABEL );
#ifdef REVEAL
ULO(_("(timestamp messages)"), GETOPT_TIMESTAMP );
diff --git a/dump/content.c b/dump/content.c
index 3a7f508..78b303f 100644
--- a/dump/content.c
+++ b/dump/content.c
@@ -290,7 +290,7 @@ static rv_t dump_dirent( drive_t *drivep,
context_t *contextp,
xfs_bstat_t *,
xfs_ino_t,
- u_int32_t,
+ gen_t,
char *,
size_t );
static rv_t init_extent_group_context( jdm_fshandle_t *,
@@ -477,6 +477,10 @@ static bool_t sc_dumpextattrpr = BOOL_TRUE;
static bool_t sc_dumpasoffline = BOOL_FALSE;
/* dump dual-residency HSM files as offline
*/
+static bool_t sc_use_old_direntpr = BOOL_FALSE;
+ /* dump dirents as dirent_v1_t instead of dirent_t
+ * (for compat with dump format 2)
+ */
static bool_t sc_savequotas = BOOL_TRUE;
/* save quota information in dump
@@ -560,6 +564,7 @@ content_init( intgen_t argc,
ASSERT( sizeof( filehdr_t ) == FILEHDR_SZ );
ASSERT( sizeof( extenthdr_t ) == EXTENTHDR_SZ );
ASSERT( sizeof( direnthdr_t ) == DIRENTHDR_SZ );
+ ASSERT( sizeof( direnthdr_v1_t ) == DIRENTHDR_SZ );
ASSERT( DIRENTHDR_SZ % DIRENTHDR_ALIGN == 0 );
ASSERT( sizeofmember( content_hdr_t, ch_specific )
>=
@@ -573,6 +578,10 @@ content_init( intgen_t argc,
cwhdrtemplatep = ( content_hdr_t * )mwhdrtemplatep->mh_upper;
scwhdrtemplatep = ( content_inode_hdr_t * ) cwhdrtemplatep->ch_specific;
+ if ( gwhdrtemplatep->gh_version < GLOBAL_HDR_VERSION_3 ) {
+ sc_use_old_direntpr = BOOL_TRUE;
+ }
+
/* process command line args
*/
optind = 1;
@@ -2902,7 +2911,7 @@ dump_dir( ix_t strmix,
struct dirent *gdp = ( struct dirent *)contextp->cc_getdentsbufp;
size_t gdsz = contextp->cc_getdentsbufsz;
intgen_t gdcnt;
- u_int32_t gen;
+ gen_t gen;
rv_t rv;
/* no way this can be non-dir, but check anyway
@@ -3073,8 +3082,7 @@ dump_dir( ix_t strmix,
/* lookup the gen number in the ino-to-gen map.
* if it's not there, we have to get it the slow way.
*/
- gen = inomap_get_gen( NULL, p->d_ino );
- if (gen == GEN_NULL) {
+ if ( inomap_get_gen( NULL, p->d_ino, &gen) ) {
xfs_bstat_t statbuf;
intgen_t scrval;
@@ -5045,19 +5053,25 @@ dump_dirent( drive_t *drivep,
context_t *contextp,
xfs_bstat_t *statp,
xfs_ino_t ino,
- u_int32_t gen,
+ gen_t gen,
char *name,
size_t namelen )
{
drive_ops_t *dop = drivep->d_opsp;
- direnthdr_t *dhdrp = ( direnthdr_t * )contextp->cc_mdirentbufp;
- direnthdr_t *tmpdhdrp;
+ char *outbufp;
size_t direntbufsz = contextp->cc_mdirentbufsz;
size_t sz;
+ size_t name_offset;
intgen_t rval;
rv_t rv;
- sz = offsetofmember( direnthdr_t, dh_name )
+ if ( sc_use_old_direntpr ) {
+ name_offset = offsetofmember( direnthdr_v1_t, dh_name );
+ } else {
+ name_offset = offsetofmember( direnthdr_t, dh_name );
+ }
+
+ sz = name_offset
+
namelen
+
@@ -5081,28 +5095,52 @@ dump_dirent( drive_t *drivep,
ASSERT( sz <= UINT16MAX );
ASSERT( sz >= DIRENTHDR_SZ );
- memset( ( void * )dhdrp, 0, sz );
- dhdrp->dh_ino = ino;
- dhdrp->dh_sz = ( u_int16_t )sz;
- dhdrp->dh_gen = ( u_int16_t )( gen & DENTGENMASK );
+ outbufp = malloc(sz);
- if ( name ) {
- strcpy( dhdrp->dh_name, name );
- }
+ if ( sc_use_old_direntpr ) {
+ direnthdr_v1_t *dhdrp = ( direnthdr_v1_t * )contextp->cc_mdirentbufp;
+ direnthdr_v1_t *tmpdhdrp = ( direnthdr_v1_t * )outbufp;
+
+ memset( ( void * )dhdrp, 0, sz );
+ dhdrp->dh_ino = ino;
+ dhdrp->dh_sz = ( u_int16_t )sz;
+ dhdrp->dh_gen = ( u_int16_t )( gen & DENTGENMASK );
+ if ( name ) {
+ strcpy( dhdrp->dh_name, name );
+ }
- dhdrp->dh_checksum = calc_checksum( dhdrp, DIRENTHDR_SZ );
+ dhdrp->dh_checksum = calc_checksum( dhdrp, DIRENTHDR_SZ );
- tmpdhdrp = malloc(sz);
- xlate_direnthdr(dhdrp, tmpdhdrp, 1);
- if ( name ) {
- strcpy( tmpdhdrp->dh_name, name );
+ xlate_direnthdr_v1( dhdrp, tmpdhdrp, 1 );
+ if ( name ) {
+ strcpy( tmpdhdrp->dh_name, name );
+ }
+ } else {
+ direnthdr_t *dhdrp = ( direnthdr_t * )contextp->cc_mdirentbufp;
+ direnthdr_t *tmpdhdrp = ( direnthdr_t * )outbufp;
+
+ memset( ( void * )dhdrp, 0, sz );
+ dhdrp->dh_ino = ino;
+ dhdrp->dh_gen = gen;
+ dhdrp->dh_sz = ( u_int16_t )sz;
+ if ( name ) {
+ strcpy( dhdrp->dh_name, name );
+ }
+
+ dhdrp->dh_checksum = calc_checksum( dhdrp, DIRENTHDR_SZ );
+
+ xlate_direnthdr( dhdrp, tmpdhdrp, 1 );
+ if ( name ) {
+ strcpy( tmpdhdrp->dh_name, name );
+ }
}
- rval = write_buf( ( char * )tmpdhdrp,
+
+ rval = write_buf( outbufp,
sz,
( void * )drivep,
( gwbfp_t )dop->do_get_write_buf,
( wfp_t )dop->do_write );
- free(tmpdhdrp);
+ free(outbufp);
switch ( rval ) {
case 0:
rv = RV_OK;
diff --git a/dump/getopt.h b/dump/getopt.h
index ba26c93..3bab87a 100644
--- a/dump/getopt.h
+++ b/dump/getopt.h
@@ -27,7 +27,7 @@
* facilitating easy changes.
*/
-#define GETOPT_CMDSTRING "ab:c:d:ef:hl:mop:qs:t:v:z:AB:CDEFG:H:I:JL:M:NO:PRSTUVWY:"
+#define GETOPT_CMDSTRING "ab:c:d:ef:hl:mop:qs:t:v:z:AB:CDEFG:H:I:JKL:M:NO:PRSTUVWY:"
#define GETOPT_DUMPASOFFLINE 'a' /* dump DMF dualstate files as offline */
#define GETOPT_BLOCKSIZE 'b' /* blocksize for rmt */
@@ -65,7 +65,7 @@
#define GETOPT_MAXSTACKSZ 'H' /* maximum stack size (bytes) */
#define GETOPT_INVPRINT 'I' /* just display the inventory */
#define GETOPT_NOINVUPDATE 'J' /* do not update the dump inventory */
-/* 'K' */
+#define GETOPT_FMT2COMPAT 'K' /* use dump format 2 for compat with old restore */
#define GETOPT_DUMPLABEL 'L' /* dump session label (global.c) */
#define GETOPT_MEDIALABEL 'M' /* media object label (media.c) */
#define GETOPT_TIMESTAMP 'N' /* show timestamps in log msgs */
diff --git a/dump/inomap.c b/dump/inomap.c
index aa4f59d..9b385ec 100644
--- a/dump/inomap.c
+++ b/dump/inomap.c
@@ -940,18 +940,11 @@ cb_startpt( void *arg1,
/* map context and operators
*/
-/* define structure for ino to gen mapping. Allocate 12 bits for the gen
- * instead of the 32-bit gen that XFS uses, as xfsdump currently truncates
- * the gen to 12 bits.
+/* define structure for ino to gen mapping.
*/
-#if DENTGENSZ != 12
-#error DENTGENSZ has changed. i2gseg_t and its users must be updated.
-#endif
-
struct i2gseg {
u_int64_t s_valid;
- u_char_t s_lower[ INOPERSEG ];
- u_char_t s_upper[ INOPERSEG / 2 ];
+ gen_t s_gen[ INOPERSEG ];
};
typedef struct i2gseg i2gseg_t;
@@ -1382,51 +1375,31 @@ inomap_set_gen(void *contextp, xfs_ino_t ino, gen_t gen)
relino = ino - segp->base;
i2gsegp->s_valid |= (u_int64_t)1 << relino;
- i2gsegp->s_lower[ relino ] = ( u_char_t )( gen & 0xff );
- if ( relino & 1 ) {
- /* odd, goes in high nibble */
- i2gsegp->s_upper[relino / 2] &= ( u_char_t )( 0x0f );
- i2gsegp->s_upper[relino / 2] |=
- ( u_char_t )( ( gen >> 4 ) & 0xf0 );
- } else {
- /* even, goes in low nibble */
- i2gsegp->s_upper[ relino / 2 ] &= ( u_char_t )( 0xf0 );
- i2gsegp->s_upper[ relino / 2 ] |=
- ( u_char_t )( ( gen >> 8 ) & 0x0f );
- }
+ i2gsegp->s_gen[relino] = gen;
}
-gen_t
-inomap_get_gen( void *contextp, xfs_ino_t ino )
+intgen_t
+inomap_get_gen( void *contextp, xfs_ino_t ino, gen_t *gen )
{
seg_addr_t *addrp;
seg_addr_t addr;
seg_t *segp;
i2gseg_t *i2gsegp;
xfs_ino_t relino;
- gen_t gen;
addrp = contextp ? (seg_addr_t *)contextp : &addr;
if ( !inomap_find_seg( addrp, ino ) )
- return GEN_NULL;
+ return 1;
segp = inomap_addr2seg( addrp );
i2gsegp = &inomap.i2gmap[inomap_addr2segix( addrp )];
relino = ino - segp->base;
if ( ! (i2gsegp->s_valid & ((u_int64_t)1 << relino)) )
- return GEN_NULL;
-
- gen = i2gsegp->s_lower[relino];
- if (relino & 1) {
- /* odd, rest of gen in high nibble */
- gen |= ( (gen_t)i2gsegp->s_upper[relino / 2] & 0xf0 ) << 4;
- } else {
- /* even, rest of gen in low nibble */
- gen |= ( (gen_t)i2gsegp->s_upper[relino / 2] & 0x0f ) << 8;
- }
+ return 1;
- return gen;
+ *gen = i2gsegp->s_gen[relino];
+ return 0;
}
void
diff --git a/dump/inomap.h b/dump/inomap.h
index 16f2efb..7d1db1f 100644
--- a/dump/inomap.h
+++ b/dump/inomap.h
@@ -132,7 +132,7 @@ extern void *inomap_alloc_context( void );
extern void inomap_reset_context( void *contextp );
extern void inomap_free_context( void *contextp );
extern intgen_t inomap_get_state( void *contextp, xfs_ino_t ino );
-extern gen_t inomap_get_gen( void *contextp, xfs_ino_t ino );
+extern intgen_t inomap_get_gen( void *contextp, xfs_ino_t ino, gen_t *gen );
/* generators returning the next dir or non-dir ino selected in this dump.
diff --git a/man/man8/xfsdump.8 b/man/man8/xfsdump.8
index fb47f7b..7d261ed 100644
--- a/man/man8/xfsdump.8
+++ b/man/man8/xfsdump.8
@@ -333,6 +333,13 @@ Inhibits the normal update of the inventory.
This is useful when the media being dumped to
will be discarded or overwritten.
.TP 5
+.B \-K
+Generate a format 2 dump instead of the current format. This is useful
+if the dump will be restored on a system with an older
+.I xfsrestore
+which does not understand the current dump format. Use of this option
+is otherwise not recommended.
+.TP 5
\f3\-L\f1 \f2session_label\f1
Specifies a label for the dump session.
It can be any arbitrary string up to 255 characters long.
diff --git a/man/man8/xfsrestore.8 b/man/man8/xfsrestore.8
index aad97fa..60e4309 100644
--- a/man/man8/xfsrestore.8
+++ b/man/man8/xfsrestore.8
@@ -339,6 +339,15 @@ when it encounters an on-media session inventory,
but only if run with an effective user id of root
and only if this option is not given.
.TP 5
+.B \-K
+Force
+.I xfsrestore
+to use dump format 2 generation numbers. Normally the need for this is
+determined automatically, but this option is required on the first
+.I xfsrestore
+invocation in the rare case that a cumulative restore begins
+with a format 3 (or newer) dump and will be followed by a format 2 dump.
+.TP 5
\f3\-L\f1 \f2session_label\f1
Specifies the label
of the dump session to be restored.
diff --git a/restore/content.c b/restore/content.c
index a9e0b20..9aa8581 100644
--- a/restore/content.c
+++ b/restore/content.c
@@ -73,8 +73,10 @@
#define HOUSEKEEPING_MAGIC 0x686b6d61
/* "hkma" - see the housekeeping_magic field of pers_t below.
*/
-#define HOUSEKEEPING_VERSION 1
+#define HOUSEKEEPING_VERSION 2
/* see the housekeeping_version field of pers_t below.
+ * version 2 changed the size of a gen_t, which caused node_t
+ * to change in size. also p_truncategenpr was added to treepers_t.
*/
#define WRITE_TRIES_MAX 3
@@ -629,6 +631,9 @@ struct tran {
size64_t t_dirdumps;
/* bitset of streams which contain a directory dump
*/
+ bool_t t_truncategenpr;
+ /* force use of truncated generation numbers
+ */
sync_t t_sync1;
/* to single-thread attempt to validate command line
* selection of dump with online inventory
@@ -1165,6 +1170,9 @@ content_init( intgen_t argc, char *argv[ ], size64_t vmsz )
case GETOPT_ROOTPERM:
restore_rootdir_permissions = BOOL_TRUE;
break;
+ case GETOPT_FMT2COMPAT:
+ tranp->t_truncategenpr = BOOL_TRUE;
+ break;
}
}
@@ -1473,6 +1481,13 @@ content_init( intgen_t argc, char *argv[ ], size64_t vmsz )
GETOPT_NOSUBTREE );
return BOOL_FALSE;
}
+ if ( tranp->t_truncategenpr ) {
+ mlog( MLOG_NORMAL | MLOG_ERROR, _(
+ "-%c valid only when initiating "
+ "cumulative restore\n"),
+ GETOPT_FMT2COMPAT );
+ return BOOL_FALSE;
+ }
} else {
if ( ! resumepr && ! sesscpltpr ) {
mlog( MLOG_NORMAL | MLOG_ERROR, _(
@@ -1534,6 +1549,12 @@ content_init( intgen_t argc, char *argv[ ], size64_t vmsz )
GETOPT_NOSUBTREE );
return BOOL_FALSE;
}
+ if ( tranp->t_truncategenpr ) {
+ mlog( MLOG_NORMAL | MLOG_ERROR, _(
+ "-%c valid only when initiating restore\n"),
+ GETOPT_FMT2COMPAT );
+ return BOOL_FALSE;
+ }
}
if ( persp->a.valpr ) {
@@ -2328,12 +2349,21 @@ content_stream_restore( ix_t thrdix )
tranp->t_vmsz,
fullpr,
persp->a.restoredmpr,
- persp->a.dstdirisxfspr );
+ persp->a.dstdirisxfspr,
+ grhdrp->gh_version,
+ tranp->t_truncategenpr );
if ( ! ok ) {
Media_end( Mediap );
return mlog_exit(EXIT_ERROR, RV_ERROR);
}
tranp->t_treeinitdonepr = BOOL_TRUE;
+
+ } else {
+ ok = tree_check_dump_format( grhdrp->gh_version );
+ if ( ! ok ) {
+ Media_end( Mediap );
+ return mlog_exit(EXIT_ERROR, RV_ERROR);
+ }
}
/* commit the session and accumulative state
@@ -3071,7 +3101,7 @@ applydirdump( drive_t *drivep,
*/
rv = tree_addent( dirh,
dhdrp->dh_ino,
- ( size_t )dhdrp->dh_gen,
+ dhdrp->dh_gen,
dhdrp->dh_name,
namelen );
if ( rv != RV_OK ) {
@@ -8109,23 +8139,26 @@ read_dirent( drive_t *drivep,
size_t direntbufsz,
bool_t dhcs )
{
+ global_hdr_t *grhdrp = drivep->d_greadhdrp;
drive_ops_t *dop = drivep->d_opsp;
/* REFERENCED */
intgen_t nread;
intgen_t rval;
direnthdr_t tmpdh;
+ char *namep; // beginning of name following the direnthdr_t
+
+ ASSERT( sizeof( direnthdr_t ) == DIRENTHDR_SZ );
+ ASSERT( sizeof( direnthdr_v1_t ) == DIRENTHDR_SZ );
/* read the head of the dirent
*/
nread = read_buf( ( char * )&tmpdh,
- sizeof( direnthdr_t ),
+ DIRENTHDR_SZ,
( void * )drivep,
( rfp_t )dop->do_read,
( rrbfp_t )
dop->do_return_read_buf,
&rval );
- xlate_direnthdr(&tmpdh, dhdrp, 1);
-
switch( rval ) {
case 0:
break;
@@ -8142,27 +8175,46 @@ read_dirent( drive_t *drivep,
default:
return RV_CORE;
}
- ASSERT( ( size_t )nread == sizeof( direnthdr_t ));
+ ASSERT( ( size_t )nread == DIRENTHDR_SZ );
- mlog( MLOG_NITTY,
- "read dirent hdr ino %llu gen %u size %u\n",
- dhdrp->dh_ino,
- ( size_t )dhdrp->dh_gen,
- ( size_t )dhdrp->dh_sz );
+ if ( grhdrp->gh_version >= GLOBAL_HDR_VERSION_3 ) {
+ xlate_direnthdr(&tmpdh, dhdrp, 1);
+ namep = dhdrp->dh_name + sizeof(dhdrp->dh_name);
- if ( dhcs ) {
- if ( dhdrp->dh_sz == 0 ) {
+ if ( dhcs && !is_checksum_valid( dhdrp, DIRENTHDR_SZ )) {
mlog( MLOG_NORMAL | MLOG_WARNING, _(
- "corrupt directory entry header\n") );
+ "bad directory entry header checksum\n") );
return RV_CORRUPT;
}
- if ( !is_checksum_valid( dhdrp, DIRENTHDR_SZ )) {
+ } else {
+ direnthdr_v1_t dhdr_v1;
+ xlate_direnthdr_v1((direnthdr_v1_t *)&tmpdh, &dhdr_v1, 1);
+ dhdrp->dh_ino = dhdr_v1.dh_ino;
+ dhdrp->dh_gen = BIGGEN2GEN(dhdr_v1.dh_gen);
+ dhdrp->dh_checksum = dhdr_v1.dh_checksum;
+ dhdrp->dh_sz = dhdr_v1.dh_sz;
+ memcpy(dhdrp->dh_name, dhdr_v1.dh_name, sizeof(dhdr_v1.dh_name));
+ namep = dhdrp->dh_name + sizeof(dhdr_v1.dh_name);
+
+ if ( dhcs && !is_checksum_valid( &dhdr_v1, DIRENTHDR_SZ )) {
mlog( MLOG_NORMAL | MLOG_WARNING, _(
- "bad directory entry header checksum\n") );
+ "bad directory entry header checksum\n") );
return RV_CORRUPT;
}
}
+ mlog( MLOG_NITTY,
+ "read dirent hdr ino %llu gen %u size %u\n",
+ dhdrp->dh_ino,
+ ( size_t )dhdrp->dh_gen,
+ ( size_t )dhdrp->dh_sz );
+
+ if ( dhdrp->dh_sz == 0 ) {
+ mlog( MLOG_NORMAL | MLOG_WARNING, _(
+ "corrupt directory entry header\n") );
+ return RV_CORRUPT;
+ }
+
/* if null, return
*/
if ( dhdrp->dh_ino == 0 ) {
@@ -8177,7 +8229,7 @@ read_dirent( drive_t *drivep,
ASSERT( ! ( ( size_t )dhdrp->dh_sz & ( DIRENTHDR_ALIGN - 1 )));
if ( ( size_t )dhdrp->dh_sz > sizeof( direnthdr_t )) {
size_t remsz = ( size_t )dhdrp->dh_sz - sizeof( direnthdr_t );
- nread = read_buf( ( char * )( dhdrp + 1 ),
+ nread = read_buf( namep,
remsz,
( void * )drivep,
( rfp_t )dop->do_read,
diff --git a/restore/getopt.h b/restore/getopt.h
index 63568de..361bc61 100644
--- a/restore/getopt.h
+++ b/restore/getopt.h
@@ -26,7 +26,7 @@
* purpose is to contain that command string.
*/
-#define GETOPT_CMDSTRING "a:b:c:def:himn:op:qrs:tv:wABCDEFG:H:I:JL:M:NO:PQRS:TUVWX:Y:"
+#define GETOPT_CMDSTRING "a:b:c:def:himn:op:qrs:tv:wABCDEFG:H:I:JKL:M:NO:PQRS:TUVWX:Y:"
#define GETOPT_WORKSPACE 'a' /* workspace dir (content.c) */
#define GETOPT_BLOCKSIZE 'b' /* blocksize for rmt */
@@ -64,7 +64,7 @@
#define GETOPT_MAXSTACKSZ 'H' /* maximum stack size (bytes) */
#define GETOPT_INVPRINT 'I' /* just display the inventory */
#define GETOPT_NOINVUPDATE 'J' /* do not update the dump inventory */
-/* 'K' */
+#define GETOPT_FMT2COMPAT 'K' /* force use format 2 gen numbers */
#define GETOPT_DUMPLABEL 'L' /* dump session label (global.c) */
#define GETOPT_MEDIALABEL 'M' /* media object label (media.c) */
#define GETOPT_TIMESTAMP 'N' /* show timestamps in log msgs */
diff --git a/restore/tree.c b/restore/tree.c
index 9e4e83c..c2308ef 100644
--- a/restore/tree.c
+++ b/restore/tree.c
@@ -102,6 +102,10 @@ struct treePersStorage {
bool_t p_restoredmpr;
/* restore DMI event settings
*/
+ bool_t p_truncategenpr;
+ /* truncate inode generation number (for compatibility
+ * with xfsdump format 2 and earlier)
+ */
};
typedef struct treePersStorage treepers_t;
@@ -163,7 +167,7 @@ typedef struct tran tran_t;
/* node structure. each node represents a directory entry
*/
-#define NODESZ 48
+#define NODESZ 56
struct node {
xfs_ino_t n_ino; /* 8 8 ino */
@@ -175,9 +179,10 @@ struct node {
nh_t n_sibprevh; /* 4 36 prev sibling list - dbl link list */
nh_t n_cldh; /* 4 40 children list */
nh_t n_lnkh; /* 4 44 hard link list */
- gen_t n_gen; /* 2 46 generation count mod 0x10000 */
- u_char_t n_flags; /* 1 47 action and state flags */
- u_char_t n_nodehkbyte; /* 1 48 given to node abstraction */
+ gen_t n_gen; /* 4 48 generation count mod 0x10000 */
+ u_char_t n_flags; /* 1 49 action and state flags */
+ u_char_t n_nodehkbyte; /* 1 50 given to node abstraction */
+ char n_pad[6]; /* 6 56 */
};
typedef struct node node_t;
@@ -335,7 +340,9 @@ tree_init( char *hkdir,
size64_t vmsz,
bool_t fullpr,
bool_t restoredmpr,
- bool_t dstdirisxfspr )
+ bool_t dstdirisxfspr,
+ u_int32_t dumpformat,
+ bool_t truncategenpr )
{
off64_t nodeoff;
char *perspath;
@@ -496,6 +503,21 @@ tree_init( char *hkdir,
*/
persp->p_restoredmpr = restoredmpr;
+ /* record if truncated generation numbers are required
+ */
+ if ( dumpformat < GLOBAL_HDR_VERSION_3 ) {
+ persp->p_truncategenpr = BOOL_TRUE;
+ mlog( MLOG_NORMAL | MLOG_DEBUG | MLOG_TREE, _(
+ "dump format version %u used truncated inode generation numbers\n"),
+ dumpformat );
+ } else if ( truncategenpr ) {
+ persp->p_truncategenpr = BOOL_TRUE;
+ mlog( MLOG_NORMAL | MLOG_DEBUG | MLOG_TREE, _(
+ "forcing use of truncated inode generation numbers\n"));
+ } else {
+ persp->p_truncategenpr = BOOL_FALSE;
+ }
+
return BOOL_TRUE;
}
@@ -596,6 +618,15 @@ tree_sync( char *hkdir,
*/
persp->p_fullpr = fullpr;
+ /* regardless of the format of this dump, if the previously applied
+ * dump used truncated generation numbers, then we need to as well.
+ */
+ if ( persp->p_truncategenpr ) {
+ mlog( MLOG_NORMAL | MLOG_DEBUG | MLOG_TREE, _(
+ "using truncated inode generation numbers for "
+ "compatibility with previously applied restore\n") );
+ }
+
/* rsynchronize with the hash abstraction. it will map more of the
* persistent state file.
*/
@@ -621,6 +652,24 @@ tree_sync( char *hkdir,
return BOOL_TRUE;
}
+bool_t
+tree_check_dump_format( u_int32_t dumpformat )
+{
+ if ( dumpformat < GLOBAL_HDR_VERSION_3 && !persp->p_truncategenpr ) {
+ mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_TREE, _(
+ "encountered dump format %d after a "
+ "restore of format %d or newer\n"),
+ dumpformat, GLOBAL_HDR_VERSION_3 );
+ mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_TREE, _(
+ "to restore this series of dumps, use the -%c "
+ "option on the first restore\n"),
+ GETOPT_FMT2COMPAT );
+ return BOOL_FALSE;
+ }
+
+ return BOOL_TRUE;
+}
+
/* recursively descend the tree clearing REFED and DIRDUMPED and NEWORPH
* flags. force the orphanage to be refed and dumped, so we won't try
* to orphan it, and so things added to it won't look like they are
@@ -682,10 +731,13 @@ tree_begindir( filehdr_t *fhdrp, dah_t *dahp )
{
nh_t hardh;
xfs_ino_t ino = fhdrp->fh_stat.bs_ino;
- u_int32_t biggen = fhdrp->fh_stat.bs_gen;
- gen_t gen = BIGGEN2GEN( biggen );
+ gen_t gen = fhdrp->fh_stat.bs_gen;
dah_t dah;
+ if ( persp->p_truncategenpr ) {
+ gen = BIGGEN2GEN( gen );
+ }
+
/* sanity check - orphino is supposed to be an unused ino!
*/
ASSERT( ino != orphino );
@@ -708,7 +760,7 @@ tree_begindir( filehdr_t *fhdrp, dah_t *dahp )
"upgrading to dir\n",
ino,
gen,
- biggen );
+ fhdrp->fh_stat.bs_gen );
if ( ! tranp->t_toconlypr ) {
ASSERT( hardp->n_dah == DAH_NULL );
hardp->n_dah = dirattr_add( fhdrp );
@@ -721,7 +773,7 @@ tree_begindir( filehdr_t *fhdrp, dah_t *dahp )
"updating\n",
ino,
gen,
- biggen );
+ fhdrp->fh_stat.bs_gen );
hardp->n_dah = dirattr_add( fhdrp );
} else {
/* case 3: already has dirattr; must be restart
@@ -731,7 +783,7 @@ tree_begindir( filehdr_t *fhdrp, dah_t *dahp )
"retaining\n",
ino,
gen,
- biggen );
+ fhdrp->fh_stat.bs_gen );
}
hardp->n_flags |= NF_ISDIR;
hardp->n_flags |= NF_DUMPEDDIR;
@@ -745,7 +797,7 @@ tree_begindir( filehdr_t *fhdrp, dah_t *dahp )
"new\n",
ino,
gen,
- biggen );
+ fhdrp->fh_stat.bs_gen );
if ( ! tranp->t_toconlypr ) {
dah = dirattr_add( fhdrp );
} else {
@@ -767,11 +819,14 @@ tree_begindir( filehdr_t *fhdrp, dah_t *dahp )
}
rv_t
-tree_addent( nh_t parh, xfs_ino_t ino, size_t g, char *name, size_t namelen )
+tree_addent( nh_t parh, xfs_ino_t ino, gen_t gen, char *name, size_t namelen )
{
- gen_t gen = BIGGEN2GEN( g );
nh_t hardh;
+ if ( persp->p_truncategenpr ) {
+ gen = BIGGEN2GEN( gen );
+ }
+
/* sanity check - orphino is supposed to be an unused ino!
*/
ASSERT( ino != orphino );
@@ -1677,7 +1732,7 @@ rename_dirs( nh_t cldh,
*/
rv_t
tree_cb_links( xfs_ino_t ino,
- u_int32_t biggen,
+ gen_t gen,
int32_t ctime,
int32_t mtime,
bool_t ( * funcp )( void *contextp,
@@ -1688,13 +1743,16 @@ tree_cb_links( xfs_ino_t ino,
char *path1,
char *path2 )
{
- gen_t gen = BIGGEN2GEN( biggen );
nh_t hardh;
nh_t nh;
char *path;
bool_t ok;
int rval;
+ if ( persp->p_truncategenpr ) {
+ gen = BIGGEN2GEN( gen );
+ }
+
/* find the hardhead
*/
hardh = link_hardh( ino, gen );
@@ -1887,7 +1945,7 @@ tree_cb_links( xfs_ino_t ino,
"ino %llu gen %u not referenced: "
"placing in orphanage\n"),
ino,
- biggen );
+ gen );
nh = Node_alloc( ino,
gen,
NRH_NULL,
@@ -3357,6 +3415,7 @@ Node_alloc( xfs_ino_t ino, gen_t gen, nrh_t nrh, dah_t dah, size_t flags )
np->n_lnkh = NH_NULL;
np->n_gen = gen;
np->n_flags = ( u_char_t )flags;
+ memset(np->n_pad, 0, sizeof(np->n_pad));
Node_unmap( nh, &np );
return nh;
}
diff --git a/restore/tree.h b/restore/tree.h
index 93621c7..7b1a76a 100644
--- a/restore/tree.h
+++ b/restore/tree.h
@@ -32,7 +32,9 @@ extern bool_t tree_init( char *hkdir,
size64_t vmsz,
bool_t fullpr,
bool_t restoredmpr,
- bool_t dstdirisxfspr );
+ bool_t dstdirisxfspr,
+ u_int32_t dumpformat,
+ bool_t truncategenpr );
/* tree_sync - synchronizes with an existing tree abstraction
*/
@@ -42,6 +44,14 @@ extern bool_t tree_sync( char *hkdir,
bool_t fullpr,
bool_t dstdirisxfspr );
+/* tree_check_dump_format - detect the rare case where a
+ * cumulative restore begins with a format 3 (or newer)
+ * dump, and a later restore in the series encounters
+ * a format 2 dump. the restore will fail unless the
+ * original restore was told to use format 2 gen numbers.
+ */
+extern bool_t tree_check_dump_format( u_int32_t dumpformat );
+
/* tree_begindir - begins application of dumped directory to tree.
* returns handle to dir node. returns by reference the dirattr
@@ -53,7 +63,7 @@ extern nh_t tree_begindir( filehdr_t *fhdrp, dah_t *dahp );
*/
extern rv_t tree_addent( nh_t dirh,
xfs_ino_t ino,
- size_t gen,
+ gen_t gen,
char *name,
size_t namelen );
@@ -84,7 +94,7 @@ extern bool_t tree_subtree_parse( bool_t sensepr, char *path );
extern bool_t tree_post( char *path1, char *path2 );
extern rv_t tree_cb_links( xfs_ino_t ino,
- u_int32_t biggen,
+ gen_t gen,
int32_t ctime,
int32_t mtime,
bool_t ( * funcp )( void *contextp,
--
1.7.0.4
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH v2] xfsdump: use the full 32-bit generation number
2012-02-09 18:46 [PATCH v2] xfsdump: use the full 32-bit generation number Bill Kendall
@ 2012-02-12 23:47 ` Christoph Hellwig
2012-02-13 16:36 ` Bill Kendall
0 siblings, 1 reply; 4+ messages in thread
From: Christoph Hellwig @ 2012-02-12 23:47 UTC (permalink / raw)
To: Bill Kendall; +Cc: xfs
Looks generally good to me, but is there any good reason to not make
the -K argument extensible by requiring a version argument, even if
that one currently only supports 2 and 3 as valid values?
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2] xfsdump: use the full 32-bit generation number
2012-02-12 23:47 ` Christoph Hellwig
@ 2012-02-13 16:36 ` Bill Kendall
2012-02-13 16:45 ` Christoph Hellwig
0 siblings, 1 reply; 4+ messages in thread
From: Bill Kendall @ 2012-02-13 16:36 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: xfs
On 02/12/2012 05:47 PM, Christoph Hellwig wrote:
> Looks generally good to me, but is there any good reason to not make
> the -K argument extensible by requiring a version argument, even if
> that one currently only supports 2 and 3 as valid values?
I thought about doing that, but given the low frequency of format
changes decided it could wait until there's more than one old format
to support. -K without an argument could be treated as "generate
the previous media format", or with an argument it could generate
a specific format. I'm okay with requiring a version argument though,
being explicit is better.
FWIW, the way things have always worked is that xfsrestore provides
backwards compatibility for all dump formats. xfsdump has, until
now, always generated the current format. It's nice to provide
the ability to generate old formats during a transition period,
but long-term I don't see xfsdump retaining support for generating
all old formats.
Bill
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2] xfsdump: use the full 32-bit generation number
2012-02-13 16:36 ` Bill Kendall
@ 2012-02-13 16:45 ` Christoph Hellwig
0 siblings, 0 replies; 4+ messages in thread
From: Christoph Hellwig @ 2012-02-13 16:45 UTC (permalink / raw)
To: Bill Kendall; +Cc: Christoph Hellwig, xfs
On Mon, Feb 13, 2012 at 10:36:24AM -0600, Bill Kendall wrote:
> On 02/12/2012 05:47 PM, Christoph Hellwig wrote:
> >Looks generally good to me, but is there any good reason to not make
> >the -K argument extensible by requiring a version argument, even if
> >that one currently only supports 2 and 3 as valid values?
>
> I thought about doing that, but given the low frequency of format
> changes decided it could wait until there's more than one old format
> to support. -K without an argument could be treated as "generate
> the previous media format", or with an argument it could generate
> a specific format. I'm okay with requiring a version argument though,
> being explicit is better.
>
> FWIW, the way things have always worked is that xfsrestore provides
> backwards compatibility for all dump formats. xfsdump has, until
> now, always generated the current format. It's nice to provide
> the ability to generate old formats during a transition period,
> but long-term I don't see xfsdump retaining support for generating
> all old formats.
Ok, sounds fine. I'll put it into the repository and after that we
should aim for an xfsdump 3.1.0 release ASAP.
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2012-02-13 16:45 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-09 18:46 [PATCH v2] xfsdump: use the full 32-bit generation number Bill Kendall
2012-02-12 23:47 ` Christoph Hellwig
2012-02-13 16:36 ` Bill Kendall
2012-02-13 16:45 ` Christoph Hellwig
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox