* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <xfs/libxfs.h>
+#include "libxfs.h"
#include <sys/stat.h>
#include <sys/wait.h>
#include <pthread.h>
#include <signal.h>
#include <stdarg.h>
#include "xfs_copy.h"
+#include "libxlog.h"
#define rounddown(x, y) (((x)/(y))*(y))
+#define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0)
-extern int platform_check_ismounted(char *, char *, struct stat64 *, int);
+extern int platform_check_ismounted(char *, char *, struct stat *, int);
int logfd;
char *logfile_name;
xfs_agblock_t first_agbno;
-__uint64_t barcount[11];
+uint64_t barcount[11];
unsigned int num_targets;
target_control *target;
#define ACTIVE 1
#define INACTIVE 2
-xfs_off_t write_log_trailer(int fd, wbuf *w, xfs_mount_t *mp);
-xfs_off_t write_log_header(int fd, wbuf *w, xfs_mount_t *mp);
+xfs_off_t write_log_trailer(int fd, wbuf *w, xfs_mount_t *mp);
+xfs_off_t write_log_header(int fd, wbuf *w, xfs_mount_t *mp);
+static int format_logs(struct xfs_mount *);
/* general purpose message reporting routine */
#define PRE 0x08 /* append strerror string */
#define LAST 0x10 /* final message we print */
+void
+signal_maskfunc(int addset, int newset)
+{
+ sigset_t set;
+
+ sigemptyset(&set);
+ sigaddset(&set, addset);
+ sigprocmask(newset, &set, NULL);
+}
+
void
do_message(int flags, int code, const char *fmt, ...)
{
va_list ap;
int eek = 0;
- va_start(ap, fmt);
- if (flags & LOG)
+ if (flags & LOG) {
+ va_start(ap, fmt);
if (vfprintf(logerr, fmt, ap) <= 0)
eek = 1;
+ va_end(ap);
+ }
if (eek)
flags |= ERR; /* failed, force stderr */
- if (flags & ERR)
+ if (flags & ERR) {
+ va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
- else if (flags & OUT)
+ va_end(ap);
+ } else if (flags & OUT) {
+ va_start(ap, fmt);
vfprintf(stdout, fmt, ap);
- va_end(ap);
+ va_end(ap);
+ }
if (flags & PRE) {
do_message(flags & ~PRE, 0, ": %s\n", strerror(code));
exit(1); \
} while (0)
+/* workaround craziness in the xlog routines */
+int xlog_recover_do_trans(struct xlog *log, struct xlog_recover *t, int p)
+{
+ return 0;
+}
+
void
check_errors(void)
{
if (target[i].err_type == 0)
do_log(_("write error"));
else
- do_log(_("lseek64 error"));
+ do_log(_("lseek error"));
do_log(_(" at offset %lld\n"), target[i].position);
}
}
* are taken care of when the buffer's read in
*/
int
-do_write(thread_args *args)
+do_write(
+ thread_args *args,
+ wbuf *buf)
{
- int res, error = 0;
+ int res;
+ int error = 0;
+
+ if (!buf)
+ buf = &w_buf;
- if (target[args->id].position != w_buf.position) {
- if (lseek64(args->fd, w_buf.position, SEEK_SET) < 0) {
+ if (target[args->id].position != buf->position) {
+ if (lseek(args->fd, buf->position, SEEK_SET) < 0) {
error = target[args->id].err_type = 1;
} else {
- target[args->id].position = w_buf.position;
+ target[args->id].position = buf->position;
}
}
- if ((res = write(target[args->id].fd, w_buf.data,
- w_buf.length)) == w_buf.length) {
+ if ((res = write(target[args->id].fd, buf->data,
+ buf->length)) == buf->length) {
target[args->id].position += res;
} else {
error = 2;
if (error) {
target[args->id].error = errno;
- target[args->id].position = w_buf.position;
+ target[args->id].position = buf->position;
}
return error;
}
for (;;) {
pthread_mutex_lock(&args->wait);
- if (do_write(args))
+ if (do_write(args, NULL))
goto handle_error;
pthread_mutex_lock(&glob_masks.mutex);
if (--glob_masks.num_working == 0)
}
void
-killall(void)
+handler(int sig)
{
- int i;
-
- /* only the parent gets to kill things */
-
- if (getpid() != parent_pid)
- return;
-
- for (i = 0; i < num_targets; i++) {
- if (target[i].state == ACTIVE) {
- /* kill up target threads */
- pthread_kill(target[i].pid, SIGKILL);
- pthread_mutex_unlock(&targ[i].wait);
- }
- }
-}
-
-void
-handler()
-{
- pid_t pid = getpid();
+ pid_t pid;
int status, i;
pid = wait(&status);
target[i].position);
} else {
do_warn(
- _("%s: lseek64 error on target %d \"%s\" at offset %lld\n"),
+ _("%s: lseek error on target %d \"%s\" at offset %lld\n"),
progname, i, target[i].name,
target[i].position);
}
usage(void)
{
fprintf(stderr,
- _("Usage: %s [-bd] [-L logfile] source target [target ...]\n"),
+ _("Usage: %s [-bdV] [-L logfile] source target [target ...]\n"),
progname);
exit(1);
}
void
-init_bar(__uint64_t source_blocks)
+init_bar(uint64_t source_blocks)
{
int i;
}
int
-bump_bar(int tenths, __uint64_t numblocks)
+bump_bar(int tenths, uint64_t numblocks)
{
static char *bar[11] = {
" 0% ",
wbuf *
wbuf_init(wbuf *buf, int data_size, int data_align, int min_io_size, int id)
{
- buf->id = id;
- if ((buf->data = memalign(data_align, data_size)) == NULL)
- return NULL;
+ ASSERT(data_size % BBSIZE == 0);
+ while ((buf->data = memalign(data_align, data_size)) == NULL) {
+ data_size >>= 1;
+ if (data_size < min_io_size)
+ return NULL;
+ }
ASSERT(min_io_size % BBSIZE == 0);
+ buf->data_align = data_align;
buf->min_io_size = min_io_size;
- buf->size = MAX(data_size, 2*min_io_size);
+ buf->size = data_size;
+ buf->id = id;
return buf;
}
}
if (source_position != buf->position) {
- lres = lseek64(fd, buf->position, SEEK_SET);
+ lres = lseek(fd, buf->position, SEEK_SET);
if (lres < 0LL) {
- do_warn(_("%s: lseek64 failure at offset %lld\n"),
+ do_warn(_("%s: lseek failure at offset %lld\n"),
progname, source_position);
die_perror();
}
if (buf->length > buf->size) {
do_warn(_("assert error: buf->length = %d, buf->size = %d\n"),
buf->length, buf->size);
- killall();
- abort();
+ exit(1);
}
if ((res = read(fd, buf->data, buf->length)) < 0) {
off = XFS_AG_DADDR(mp, agno, XFS_SB_DADDR);
buf->position = (xfs_off_t) off * (xfs_off_t) BBSIZE;
length = buf->length = first_agbno * blocksize;
-
+ if (length == 0) {
+ do_log(_("ag header buffer invalid!\n"));
+ exit(1);
+ }
+
/* handle alignment stuff */
newpos = rounddown(buf->position, (xfs_off_t) buf->min_io_size);
if (buf->length % buf->min_io_size != 0)
buf->length = roundup(buf->length, buf->min_io_size);
- ASSERT(length != 0);
read_wbuf(fd, buf, mp);
ASSERT(buf->length >= length);
- ag->xfs_sb = (xfs_sb_t *) (buf->data + diff);
- ASSERT(INT_GET(ag->xfs_sb->sb_magicnum, ARCH_CONVERT)==XFS_SB_MAGIC);
+ ag->xfs_sb = (xfs_dsb_t *) (buf->data + diff);
+ ASSERT(be32_to_cpu(ag->xfs_sb->sb_magicnum) == XFS_SB_MAGIC);
ag->xfs_agf = (xfs_agf_t *) (buf->data + diff + sectorsize);
- ASSERT(INT_GET(ag->xfs_agf->agf_magicnum, ARCH_CONVERT)==XFS_AGF_MAGIC);
- ag->xfs_agi = (xfs_agi_t *) (buf->data + diff + 2*sectorsize);
- ASSERT(INT_GET(ag->xfs_agi->agi_magicnum, ARCH_CONVERT)==XFS_AGI_MAGIC);
- ag->xfs_agfl = (xfs_agfl_t *) (buf->data + diff + 3*sectorsize);
+ ASSERT(be32_to_cpu(ag->xfs_agf->agf_magicnum) == XFS_AGF_MAGIC);
+ ag->xfs_agi = (xfs_agi_t *) (buf->data + diff + 2 * sectorsize);
+ ASSERT(be32_to_cpu(ag->xfs_agi->agi_magicnum) == XFS_AGI_MAGIC);
+ ag->xfs_agfl = (xfs_agfl_t *) (buf->data + diff + 3 * sectorsize);
}
write_wbuf(void)
{
int i;
+ int badness = 0;
/* verify target threads */
for (i = 0; i < num_targets; i++)
for (i = 0; i < num_targets; i++)
if (target[i].state != INACTIVE)
pthread_mutex_unlock(&targ[i].wait); /* wake up */
+ else
+ badness++;
+
+ /*
+ * If all the targets are inactive then there won't be any io
+ * threads left to release mainwait. We're screwed, so bail out.
+ */
+ if (badness == num_targets) {
+ check_errors();
+ exit(1);
+ }
- sigrelse(SIGCHLD);
+ signal_maskfunc(SIGCHLD, SIG_UNBLOCK);
pthread_mutex_lock(&mainwait);
- sighold(SIGCHLD);
+ signal_maskfunc(SIGCHLD, SIG_BLOCK);
}
+void
+sb_update_uuid(
+ xfs_sb_t *sb, /* Original fs superblock */
+ ag_header_t *ag_hdr, /* AG hdr to update for this copy */
+ thread_args *tcarg) /* Args for this thread, with UUID */
+{
+ /*
+ * If this filesystem has CRCs, the original UUID is stamped into
+ * all metadata. If we don't have an existing meta_uuid field in the
+ * the original filesystem and we are changing the UUID in this copy,
+ * we must copy the original sb_uuid to the sb_meta_uuid slot and set
+ * the incompat flag for the feature on this copy.
+ */
+ if (xfs_sb_version_hascrc(sb) && !xfs_sb_version_hasmetauuid(sb) &&
+ !uuid_equal(&tcarg->uuid, &sb->sb_uuid)) {
+ __be32 feat;
+
+ feat = be32_to_cpu(ag_hdr->xfs_sb->sb_features_incompat);
+ feat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
+ ag_hdr->xfs_sb->sb_features_incompat = cpu_to_be32(feat);
+ platform_uuid_copy(&ag_hdr->xfs_sb->sb_meta_uuid,
+ &sb->sb_uuid);
+ }
+
+ /* Copy the (possibly new) fs-identifier UUID into sb_uuid */
+ platform_uuid_copy(&ag_hdr->xfs_sb->sb_uuid, &tcarg->uuid);
+
+ /* We may have changed the UUID, so update the superblock CRC */
+ if (xfs_sb_version_hascrc(sb))
+ xfs_update_cksum((char *)ag_hdr->xfs_sb, sb->sb_sectsize,
+ XFS_SB_CRC_OFF);
+}
int
main(int argc, char **argv)
int i, j;
int howfar = 0;
int open_flags;
- xfs_off_t pos, end_pos;
+ xfs_off_t pos;
size_t length;
- int c, first_residue, tmp_residue;
- __uint64_t size, sizeb;
- __uint64_t numblocks = 0;
+ int c;
+ uint64_t size, sizeb;
+ uint64_t numblocks = 0;
int wblocks = 0;
int num_threads = 0;
struct dioattr d;
ag_header_t ag_hdr;
xfs_mount_t *mp;
xfs_mount_t mbuf;
+ struct xlog xlog;
xfs_buf_t *sbp;
xfs_sb_t *sb;
xfs_agnumber_t num_ags, agno;
xfs_agblock_t bno;
xfs_daddr_t begin, next_begin, ag_begin, new_begin, ag_end;
- xfs_alloc_block_t *block;
+ struct xfs_btree_block *block;
xfs_alloc_ptr_t *ptr;
xfs_alloc_rec_t *rec_ptr;
extern char *optarg;
extern int optind;
libxfs_init_t xargs;
thread_args *tcarg;
- struct stat64 statbuf;
+ struct stat statbuf;
progname = basename(argv[0]);
parent_pid = getpid();
- if (atexit(killall)) {
- do_log(_("%s: couldn't register atexit function.\n"), progname);
- die_perror();
- }
-
/* open up source -- is it a file? */
open_flags = O_RDONLY;
die_perror();
}
- if (fstat64(source_fd, &statbuf) < 0) {
+ if (fstat(source_fd, &statbuf) < 0) {
do_log(_("%s: couldn't stat source \"%s\"\n"),
progname, source_name);
die_perror();
}
wbuf_align = d.d_mem;
- wbuf_size = d.d_maxiosz;
+ wbuf_size = MIN(d.d_maxiosz, 1 * 1024 * 1024);
wbuf_miniosize = d.d_miniosz;
} else {
/* set arbitrary I/O params, miniosize at least 1 disk block */
- wbuf_align = 4096*4;
- wbuf_size = 1024 * 4000;
+ wbuf_align = getpagesize();
+ wbuf_size = 1 * 1024 * 1024;
wbuf_miniosize = -1; /* set after mounting source fs */
}
/* prepare the libxfs_init structure */
memset(&xargs, 0, sizeof(xargs));
- xargs.notvolmsg = "oh no %s";
+ xargs.isdirect = LIBXFS_DIRECT;
xargs.isreadonly = LIBXFS_ISREADONLY;
- xargs.notvolok = 1;
if (source_is_file) {
xargs.dname = source_name;
exit(1);
}
- /* prepare the mount structure */
-
- sbp = libxfs_readbuf(xargs.ddev, XFS_SB_DADDR, 1, 0);
memset(&mbuf, 0, sizeof(xfs_mount_t));
+
+ /* We don't yet know the sector size, so read maximal size */
+ libxfs_buftarg_init(&mbuf, xargs.ddev, xargs.logdev, xargs.rtdev);
+ sbp = libxfs_readbuf(mbuf.m_ddev_targp, XFS_SB_DADDR,
+ 1 << (XFS_MAX_SECTORSIZE_LOG - BBSHIFT), 0, NULL);
sb = &mbuf.m_sb;
- libxfs_xlate_sb(XFS_BUF_PTR(sbp), sb, 1, XFS_SB_ALL_BITS);
+ libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbp));
+
+ /* Do it again, now with proper length and verifier */
+ libxfs_putbuf(sbp);
+ libxfs_purgebuf(sbp);
+ sbp = libxfs_readbuf(mbuf.m_ddev_targp, XFS_SB_DADDR,
+ 1 << (sb->sb_sectlog - BBSHIFT),
+ 0, &xfs_sb_buf_ops);
+ libxfs_putbuf(sbp);
- mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 1);
+ mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 0);
if (mp == NULL) {
do_log(_("%s: %s filesystem failed to initialize\n"
"%s: Aborting.\n"), progname, source_name, progname);
exit(1);
}
+
+ /*
+ * Set up the mount pointer to access the log and check whether the log
+ * is clean. Fail on a dirty or corrupt log in non-duplicate mode
+ * because the log is formatted as part of the copy and we don't want to
+ * destroy data. We also need the current log cycle to format v5
+ * superblock logs correctly.
+ */
+ memset(&xlog, 0, sizeof(struct xlog));
+ mp->m_log = &xlog;
+ c = xlog_is_dirty(mp, mp->m_log, &xargs, 0);
+ if (!duplicate) {
+ if (c == 1) {
+ do_log(_(
+"Error: source filesystem log is dirty. Mount the filesystem to replay the\n"
+"log, unmount and retry xfs_copy.\n"));
+ exit(1);
+ } else if (c < 0) {
+ do_log(_(
+"Error: could not determine the log head or tail of the source filesystem.\n"
+"Mount the filesystem to replay the log or run xfs_repair.\n"));
+ exit(1);
+ }
+ }
+
source_blocksize = mp->m_sb.sb_blocksize;
source_sectorsize = mp->m_sb.sb_sectsize;
ASSERT(source_blocksize % source_sectorsize == 0);
ASSERT(source_sectorsize % BBSIZE == 0);
- if (source_blocksize > source_sectorsize) {
- /* get number of leftover sectors in last block of ag header */
-
- tmp_residue = ((XFS_AGFL_DADDR(mp) + 1) * source_sectorsize)
- % source_blocksize;
- first_residue = (tmp_residue == 0) ? 0 :
- source_blocksize - tmp_residue;
- ASSERT(first_residue % source_sectorsize == 0);
- } else if (source_blocksize == source_sectorsize) {
- first_residue = 0;
- } else {
+ if (source_blocksize < source_sectorsize) {
do_log(_("Error: filesystem block size is smaller than the"
" disk sectorsize.\nAborting XFS copy now.\n"));
exit(1);
}
- first_agbno = (((XFS_AGFL_DADDR(mp) + 1) * source_sectorsize)
- + first_residue) / source_blocksize;
- ASSERT(first_agbno != 0);
- ASSERT( ((((XFS_AGFL_DADDR(mp) + 1) * source_sectorsize)
- + first_residue) % source_blocksize) == 0);
+ first_agbno = XFS_AGFL_BLOCK(mp) + 1;
/* now open targets */
for (i = 0; i < num_targets; i++) {
int write_last_block = 0;
-
- if (stat64(target[i].name, &statbuf) < 0) {
+
+ if (stat(target[i].name, &statbuf) < 0) {
/* ok, assume it's a file and create it */
do_out(_("Creating file %s\n"), target[i].name);
if (write_last_block) {
/* ensure regular files are correctly sized */
- if (ftruncate64(target[i].fd, mp->m_sb.sb_dblocks *
+ if (ftruncate(target[i].fd, mp->m_sb.sb_dblocks *
source_blocksize)) {
do_log(_("%s: cannot grow data section.\n"),
progname);
}
}
} else {
- char *lb[XFS_MAX_SECTORSIZE] = { 0 };
+ char *lb[XFS_MAX_SECTORSIZE] = { NULL };
off64_t off;
/* ensure device files are sufficiently large */
off = mp->m_sb.sb_dblocks * source_blocksize;
off -= sizeof(lb);
- if (pwrite64(target[i].fd, lb, sizeof(lb), off) < 0) {
+ if (pwrite(target[i].fd, lb, sizeof(lb), off) < 0) {
do_log(_("%s: failed to write last block\n"),
progname);
do_log(_("\tIs target \"%s\" too small?\n"),
exit(1);
}
/* need to start out blocking */
- pthread_mutex_lock(&mainwait);
+ pthread_mutex_lock(&mainwait);
/* set up sigchild signal handler */
signal(SIGCHLD, handler);
- sighold(SIGCHLD);
+ signal_maskfunc(SIGCHLD, SIG_BLOCK);
/* make children */
for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++) {
if (!duplicate)
- uuid_generate(tcarg->uuid);
+ platform_uuid_generate(&tcarg->uuid);
else
- uuid_copy(tcarg->uuid, mp->m_sb.sb_uuid);
+ platform_uuid_copy(&tcarg->uuid, &mp->m_sb.sb_uuid);
if (pthread_mutex_init(&tcarg->wait, NULL) != 0) {
do_log(_("Error creating thread mutex %d\n"), i);
exit(1);
}
/* need to start out blocking */
- pthread_mutex_lock(&tcarg->wait);
+ pthread_mutex_lock(&tcarg->wait);
}
for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++) {
num_ags = mp->m_sb.sb_agcount;
init_bar(mp->m_sb.sb_blocksize / BBSIZE
- * ((__uint64_t)mp->m_sb.sb_dblocks
- - (__uint64_t)mp->m_sb.sb_fdblocks + 10 * num_ags));
+ * ((uint64_t)mp->m_sb.sb_dblocks
+ - (uint64_t)mp->m_sb.sb_fdblocks + 10 * num_ags));
kids = num_targets;
- block = (xfs_alloc_block_t *) btree_buf.data;
for (agno = 0; agno < num_ags && kids > 0; agno++) {
/* read in first blocks of the ag */
/* set the in_progress bit for the first AG */
if (agno == 0)
- INT_SET(ag_hdr.xfs_sb->sb_inprogress, ARCH_CONVERT, 1);
+ ag_hdr.xfs_sb->sb_inprogress = 1;
/* save what we need (agf) in the btree buffer */
- bcopy(ag_hdr.xfs_agf, btree_buf.data, source_sectorsize);
+ memmove(btree_buf.data, ag_hdr.xfs_agf, source_sectorsize);
ag_hdr.xfs_agf = (xfs_agf_t *) btree_buf.data;
btree_buf.length = source_blocksize;
/* traverse btree until we get to the leftmost leaf node */
- bno = INT_GET(ag_hdr.xfs_agf->agf_roots[XFS_BTNUM_BNOi],
- ARCH_CONVERT);
+ bno = be32_to_cpu(ag_hdr.xfs_agf->agf_roots[XFS_BTNUM_BNOi]);
current_level = 0;
- btree_levels = INT_GET(
- ag_hdr.xfs_agf->agf_levels[XFS_BTNUM_BNOi],
- ARCH_CONVERT);
+ btree_levels = be32_to_cpu(ag_hdr.xfs_agf->
+ agf_levels[XFS_BTNUM_BNOi]);
ag_end = XFS_AGB_TO_DADDR(mp, agno,
- INT_GET(ag_hdr.xfs_agf->agf_length,ARCH_CONVERT) - 1)
- + source_blocksize/BBSIZE;
+ be32_to_cpu(ag_hdr.xfs_agf->agf_length) - 1)
+ + source_blocksize / BBSIZE;
for (;;) {
/* none of this touches the w_buf buffer */
- ASSERT(current_level < btree_levels);
+ if (current_level >= btree_levels) {
+ do_log(
+ _("Error: current level %d >= btree levels %d\n"),
+ current_level, btree_levels);
+ exit(1);
+ }
current_level++;
btree_buf.length = source_blocksize;
read_wbuf(source_fd, &btree_buf, mp);
- block = (xfs_alloc_block_t *) ((char *) btree_buf.data
- + pos - btree_buf.position);
-
- ASSERT(INT_GET(block->bb_magic,ARCH_CONVERT) ==
- XFS_ABTB_MAGIC);
+ block = (struct xfs_btree_block *)
+ ((char *)btree_buf.data +
+ pos - btree_buf.position);
+
+ if (be32_to_cpu(block->bb_magic) !=
+ (xfs_sb_version_hascrc(&mp->m_sb) ?
+ XFS_ABTB_CRC_MAGIC : XFS_ABTB_MAGIC)) {
+ do_log(_("Bad btree magic 0x%x\n"),
+ be32_to_cpu(block->bb_magic));
+ exit(1);
+ }
- if (INT_GET(block->bb_level,ARCH_CONVERT) == 0)
+ if (be16_to_cpu(block->bb_level) == 0)
break;
- ptr = XFS_BTREE_PTR_ADDR(sourceb_blocksize, xfs_alloc,
- block, 1, mp->m_alloc_mxr[1]),
-
- bno = INT_GET(ptr[0], ARCH_CONVERT);
+ ptr = XFS_ALLOC_PTR_ADDR(mp, block, 1,
+ mp->m_alloc_mxr[1]);
+ bno = be32_to_cpu(ptr[0]);
}
/* align first data copy but don't overwrite ag header */
/* handle the rest of the ag */
for (;;) {
- if (INT_GET(block->bb_level,ARCH_CONVERT) != 0) {
+ if (be16_to_cpu(block->bb_level) != 0) {
do_log(
_("WARNING: source filesystem inconsistent.\n"));
do_log(
exit(1);
}
- rec_ptr = XFS_BTREE_REC_ADDR(source_blocksize,
- xfs_alloc, block, 1, mp->m_alloc_mxr[0]);
-
- for (i = 0;
- i < INT_GET(block->bb_numrecs,ARCH_CONVERT);
- i++, rec_ptr++) {
+ rec_ptr = XFS_ALLOC_REC_ADDR(mp, block, 1);
+ for (i = 0; i < be16_to_cpu(block->bb_numrecs);
+ i++, rec_ptr++) {
/* calculate in daddr's */
begin = next_begin;
*/
sizeb = XFS_AGB_TO_DADDR(mp, agno,
- INT_GET(rec_ptr->ar_startblock,
- ARCH_CONVERT)) - begin;
+ be32_to_cpu(rec_ptr->ar_startblock)) -
+ begin;
size = roundup(sizeb <<BBSHIFT, wbuf_miniosize);
if (size > 0) {
/* copy extent */
/* round next starting point down */
new_begin = XFS_AGB_TO_DADDR(mp, agno,
- INT_GET(rec_ptr->ar_startblock,
- ARCH_CONVERT) +
- INT_GET(rec_ptr->ar_blockcount,
- ARCH_CONVERT));
+ be32_to_cpu(rec_ptr->ar_startblock) +
+ be32_to_cpu(rec_ptr->ar_blockcount));
next_begin = rounddown(new_begin,
w_buf.min_io_size >> BBSHIFT);
}
- if (INT_GET(block->bb_rightsib,ARCH_CONVERT) ==
- NULLAGBLOCK)
+ if (be32_to_cpu(block->bb_u.s.bb_rightsib) == NULLAGBLOCK)
break;
/* read in next btree record block */
btree_buf.position = pos = (xfs_off_t)
- XFS_AGB_TO_DADDR(mp, agno,
- INT_GET(block->bb_rightsib,
- ARCH_CONVERT)) << BBSHIFT;
+ XFS_AGB_TO_DADDR(mp, agno, be32_to_cpu(
+ block->bb_u.s.bb_rightsib)) << BBSHIFT;
btree_buf.length = source_blocksize;
/* let read_wbuf handle alignment */
read_wbuf(source_fd, &btree_buf, mp);
- block = (xfs_alloc_block_t *) ((char *) btree_buf.data
- + pos - btree_buf.position);
+ block = (struct xfs_btree_block *)
+ ((char *) btree_buf.data +
+ pos - btree_buf.position);
- ASSERT(INT_GET(block->bb_magic,ARCH_CONVERT) ==
- XFS_ABTB_MAGIC);
+ ASSERT(be32_to_cpu(block->bb_magic) == XFS_ABTB_MAGIC ||
+ be32_to_cpu(block->bb_magic) == XFS_ABTB_CRC_MAGIC);
}
/*
}
if (kids > 0) {
- if (!duplicate) {
-
+ if (!duplicate)
/* write a clean log using the specified UUID */
- for (j = 0, tcarg = targ; j < num_targets; j++) {
- w_buf.owner = tcarg;
- w_buf.length = rounddown(w_buf.size,
- w_buf.min_io_size);
- pos = write_log_header(
- source_fd, &w_buf, mp);
- end_pos = write_log_trailer(
- source_fd, &w_buf, mp);
- w_buf.position = pos;
- memset(w_buf.data, 0, w_buf.length);
-
- while (w_buf.position < end_pos) {
- do_write(tcarg);
- w_buf.position += w_buf.length;
- }
- tcarg++;
- }
- } else {
+ format_logs(mp);
+ else
num_ags = 1;
- }
/* reread and rewrite superblocks (UUID and in-progress) */
/* [backwards, so inprogress bit only updated when done] */
/* do each thread in turn, each has its own UUID */
for (j = 0, tcarg = targ; j < num_targets; j++) {
- uuid_copy(ag_hdr.xfs_sb->sb_uuid, tcarg->uuid);
- do_write(tcarg);
+ sb_update_uuid(sb, &ag_hdr, tcarg);
+ do_write(tcarg, NULL);
tcarg++;
}
}
}
check_errors();
- killall();
- pthread_exit(NULL);
- /*NOTREACHED*/
+ libxfs_umount(mp);
+ libxfs_destroy();
+
return 0;
}
-xfs_caddr_t
-next_log_chunk(xfs_caddr_t p, int offset, void *private)
+char *
+next_log_chunk(char *p, int offset, void *private)
{
wbuf *buf = (wbuf *)private;
if (buf->length < (int)(p - buf->data) + offset) {
/* need to flush this one, then start afresh */
- do_write(buf->owner);
+ do_write(buf->owner, NULL);
memset(buf->data, 0, buf->length);
return buf->data;
}
/*
* Writes a log header at the start of the log (with the real
* filesystem UUID embedded into it), and writes to all targets.
- *
+ *
* Returns the next buffer-length-aligned disk address.
*/
xfs_off_t
write_log_header(int fd, wbuf *buf, xfs_mount_t *mp)
{
- xfs_caddr_t p = buf->data;
+ char *p = buf->data;
xfs_off_t logstart;
int offset;
}
offset = libxfs_log_header(p, &buf->owner->uuid,
- XFS_SB_VERSION_HASLOGV2(&mp->m_sb) ? 2 : 1,
- mp->m_sb.sb_logsunit, XLOG_FMT,
- next_log_chunk, buf);
- do_write(buf->owner);
+ xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
+ mp->m_sb.sb_logsunit, XLOG_FMT, NULLCOMMITLSN,
+ NULLCOMMITLSN, next_log_chunk, buf);
+ do_write(buf->owner, NULL);
- return logstart + roundup(offset, buf->length);
+ return roundup(logstart + offset, buf->length);
}
/*
read_wbuf(fd, buf, mp);
offset = (int)(logend - buf->position);
memset(buf->data, 0, offset);
- do_write(buf->owner);
+ do_write(buf->owner, NULL);
}
return buf->position;
}
+
+/*
+ * Clear a log by writing a record at the head, the tail and zeroing everything
+ * in between.
+ */
+static void
+clear_log(
+ struct xfs_mount *mp,
+ thread_args *tcarg)
+{
+ xfs_off_t pos;
+ xfs_off_t end_pos;
+
+ w_buf.owner = tcarg;
+ w_buf.length = rounddown(w_buf.size, w_buf.min_io_size);
+ pos = write_log_header(source_fd, &w_buf, mp);
+ end_pos = write_log_trailer(source_fd, &w_buf, mp);
+ w_buf.position = pos;
+ memset(w_buf.data, 0, w_buf.length);
+
+ while (w_buf.position < end_pos) {
+ do_write(tcarg, NULL);
+ w_buf.position += w_buf.length;
+ }
+}
+
+/*
+ * Format the log to a particular cycle number. This is required for version 5
+ * superblock filesystems to provide metadata LSN validity guarantees.
+ */
+static void
+format_log(
+ struct xfs_mount *mp,
+ thread_args *tcarg,
+ wbuf *buf)
+{
+ int logstart;
+ int length;
+ int cycle = XLOG_INIT_CYCLE;
+
+ buf->owner = tcarg;
+ buf->length = buf->size;
+ buf->position = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT;
+
+ logstart = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logstart);
+ length = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
+
+ /*
+ * Bump the cycle number on v5 superblock filesystems to guarantee that
+ * all existing metadata LSNs are valid (behind the current LSN) on the
+ * target fs.
+ */
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ cycle = mp->m_log->l_curr_cycle + 1;
+
+ /*
+ * Format the entire log into the memory buffer and write it out. If the
+ * write fails, mark the target inactive so the failure is reported.
+ */
+ libxfs_log_clear(NULL, buf->data, logstart, length, &buf->owner->uuid,
+ xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
+ mp->m_sb.sb_logsunit, XLOG_FMT, cycle, true);
+ if (do_write(buf->owner, buf))
+ target[tcarg->id].state = INACTIVE;
+}
+
+static int
+format_logs(
+ struct xfs_mount *mp)
+{
+ thread_args *tcarg;
+ int i;
+ wbuf logbuf;
+ int logsize;
+
+ if (xfs_sb_version_hascrc(&mp->m_sb)) {
+ logsize = XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks);
+ if (!wbuf_init(&logbuf, logsize, w_buf.data_align,
+ w_buf.min_io_size, w_buf.id))
+ return -ENOMEM;
+ }
+
+ for (i = 0, tcarg = targ; i < num_targets; i++) {
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ format_log(mp, tcarg, &logbuf);
+ else
+ clear_log(mp, tcarg);
+ tcarg++;
+ }
+
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ free(logbuf.data);
+
+ return 0;
+}