]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
Finish the xfs_copy port, fix a whitespace handling issue in xfs_bmap.
authorNathan Scott <nathans@sgi.com>
Fri, 25 Jul 2003 03:14:10 +0000 (03:14 +0000)
committerNathan Scott <nathans@sgi.com>
Fri, 25 Jul 2003 03:14:10 +0000 (03:14 +0000)
Write the log directly instead of calling xfs_db, fix UUID mismanagement
so that all target devices have different identifiers, add code to detect
when a too-small target device has been specified.

copy/xfs_copy.c
copy/xfs_copy.h
debian/changelog
doc/CHANGES
include/libxfs.h
io/xfs_bmap.sh
libxfs/rdwr.c

index 28e18a27462430c8767f311ffdd5154588500a7e..f92225b504be8f9f47665800267a92e3f1136659 100644 (file)
@@ -56,6 +56,8 @@ unsigned int  source_sectorsize;      /* source disk sectorsize */
 
 xfs_agblock_t  first_agbno;
 
+__uint64_t     barcount[11];
+
 unsigned int   num_targets;
 target_control *target;
 
@@ -73,6 +75,8 @@ pthread_mutex_t       mainwait;
 #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);
 
 /* general purpose message reporting routine */
 
@@ -126,18 +130,16 @@ do_message(int flags, int code, const char *fmt, ...)
 #define do_fatal(e,s)          do_message(ERR|LOG|PRE|LAST, e, s)
 #define do_vfatal(e,s,args...) do_message(ERR|LOG|PRE|LAST, e, s, ## args)
 #define die_perror(void)       \
-       do { \
-               do_message(ERR|LOG|PRE|LAST, errno, \
-                       _("Aborting XFS copy - reason")); \
-               exit(1); \
-       } while (0);
+               do { \
+                       do_message(ERR|LOG|PRE|LAST, errno, \
+                               _("Aborting XFS copy - reason")); \
+                       exit(1); \
+               } while (0)
 
 void
 check_errors(void)
 {
-       int i, first_error = 0;
-
-       /* now check for errors */
+       int     i, first_error = 0;
 
        for (i = 0; i < num_targets; i++)  {
                if (target[i].state == INACTIVE)  {
@@ -168,37 +170,42 @@ check_errors(void)
  * don't have to worry about alignment and mins because those
  * are taken care of when the buffer's read in
  */
+int
+do_write(thread_args *args)
+{
+       int     res, error = 0;
+
+       if (target[args->id].position != w_buf.position)  {
+               if (lseek64(args->fd, w_buf.position, SEEK_SET) < 0)  {
+                       error = target[args->id].err_type = 1;
+               } else  {
+                       target[args->id].position = w_buf.position;
+               }
+       }
+
+       if ((res = write(target[args->id].fd, w_buf.data,
+                               w_buf.length)) == w_buf.length)  {
+               target[args->id].position += res;
+       } else  {
+               error = 2;
+       }
+
+       if (error) {
+               target[args->id].error = errno;
+               target[args->id].position = w_buf.position;
+       }
+       return error;
+}
 
 void *
 begin_reader(void *arg)
 {
        thread_args     *args = arg;
-       int             res, error = 0;
 
        for (;;) {
                pthread_mutex_lock(&args->wait);
-
-               /* write */
-               if (target[args->id].position != w_buf.position)  {
-                       if (lseek64(args->fd, w_buf.position, SEEK_SET) < 0)  {
-                               error = 1;
-                               target[args->id].err_type = 1;
-                       } else  {
-                               target[args->id].position = w_buf.position;
-                       }
-               }
-
-               if ((res = write(target[args->id].fd, w_buf.data,
-                               w_buf.length)) == w_buf.length)  {
-                       target[args->id].position += res;
-               } else  {
-                       error = 2;
-               }
-
-               if (error)  {
+               if (do_write(args))
                        goto handle_error;
-               }
-
                pthread_mutex_lock(&glob_masks.mutex);
                if (--glob_masks.num_working == 0)
                        pthread_mutex_unlock(&mainwait);
@@ -209,9 +216,6 @@ begin_reader(void *arg)
 handle_error:
        /* error will be logged by primary thread */
 
-       target[args->id].error = errno;
-       target[args->id].position = w_buf.position;
-
        pthread_mutex_lock(&glob_masks.mutex);
        target[args->id].state = INACTIVE;
        if (--glob_masks.num_working == 0)
@@ -284,9 +288,7 @@ handler()
                                do_warn(
        _("%s:  thread %d died unexpectedly, target \"%s\" incomplete\n"),
                                        progname, i, target[i].name);
-
-                               do_warn(
-                                       _("%s:  offset was probably %lld\n"),
+                               do_warn(_("%s:  offset was probably %lld\n"),
                                        progname, target[i].position);
                                do_fatal(target[i].error,
                                        _("Aborting XFS copy - reason"));
@@ -312,27 +314,43 @@ usage(void)
        exit(1);
 }
 
-__uint64_t barcount[11];
-int howfar = 0;
-char *bar[11] = {
-       " 0% ",
-       " ... 10% ",
-       " ... 20% ",
-       " ... 30% ",
-       " ... 40% ",
-       " ... 50% ",
-       " ... 60% ",
-       " ... 70% ",
-       " ... 80% ",
-       " ... 90% ",
-       " ... 100%\n\n",
-};
-
 void
-bump_bar(int tenths)
+init_bar(__uint64_t source_blocks)
+{
+       int     i;
+
+       for (i = 0; i < 11; i++)
+               barcount[i] = (source_blocks/10)*i;
+}
+
+int
+bump_bar(int tenths, __uint64_t numblocks)
 {
-       printf("%s", bar[tenths]);
-       fflush(stdout);
+       static char *bar[11] = {
+               " 0% ",
+               " ... 10% ",
+               " ... 20% ",
+               " ... 30% ",
+               " ... 40% ",
+               " ... 50% ",
+               " ... 60% ",
+               " ... 70% ",
+               " ... 80% ",
+               " ... 90% ",
+               " ... 100%\n\n",
+       };
+
+       if (tenths > 10)  {
+               printf("%s", bar[10]);
+               fflush(stdout);
+       } else  {
+               while (tenths < 10 && numblocks > barcount[tenths])  {
+                       printf("%s", bar[tenths]);
+                       fflush(stdout);
+                       tenths++;
+               }
+       }
+       return tenths;
 }
 
 static xfs_off_t source_position = -1;
@@ -405,7 +423,7 @@ read_wbuf(int fd, wbuf *buf, xfs_mount_t *mp)
        buf->length = res;
 }
 
-int
+void
 read_ag_header(int fd, xfs_agnumber_t agno, wbuf *buf, ag_header_t *ag,
                xfs_mount_t *mp, int blocksize, int sectorsize)
 {
@@ -446,9 +464,9 @@ read_ag_header(int fd, xfs_agnumber_t agno, wbuf *buf, ag_header_t *ag,
        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);
-       return 1;
 }
 
+
 void
 write_wbuf(void)
 {
@@ -473,13 +491,13 @@ write_wbuf(void)
 int
 main(int argc, char **argv)
 {
-       int             i;
+       int             i, j;
+       int             howfar = 0;
        int             open_flags;
-       xfs_off_t       pos;
+       xfs_off_t       pos, end_pos;
        size_t          length;
        int             c, size, sizeb, first_residue, tmp_residue;
        __uint64_t      numblocks = 0;
-       __uint64_t      source_blocks;
        int             wblocks = 0;
        int             num_threads = 0;
        struct dioattr  d;
@@ -489,7 +507,6 @@ main(int argc, char **argv)
        int             source_is_file = 0;
        int             buffered_output = 0;
        int             duplicate_uuids = 0;
-       uuid_t          fsid;
        uint            btree_levels, current_level;
        ag_header_t     ag_hdr;
        xfs_mount_t     *mp;
@@ -717,16 +734,13 @@ main(int argc, char **argv)
        ASSERT( ((((XFS_AGFL_DADDR(mp) + 1) * source_sectorsize)
                                + first_residue) % source_blocksize) == 0);
 
-       if (!duplicate_uuids)
-               uuid_generate(fsid);
-
        /* now open targets */
 
        open_flags = O_RDWR;
 
        for (i = 0; i < num_targets; i++)  {
                int     write_last_block = 0;
-
+       
                if (stat64(target[i].name, &statbuf) < 0)  {
                        /* ok, assume it's a file and create it */
 
@@ -778,14 +792,19 @@ main(int argc, char **argv)
                                        progname, target[i].name);
                                die_perror();
                        }
+                       wbuf_align = MAX(wbuf_align, d.d_mem);
+                       wbuf_size = MIN(d.d_maxiosz, wbuf_size);
+                       wbuf_miniosize = MAX(d.d_miniosz, wbuf_miniosize);
+
                } else  {
-                       char *buf[XFS_MAX_SECTORSIZE] = { 0 };
+                       char    *lb[XFS_MAX_SECTORSIZE] = { 0 };
+                       off64_t off;
 
                        /* ensure device files are sufficiently large */
 
-                       if (pwrite64(target[i].fd, buf, sizeof(buf),
-                                    (mp->m_sb.sb_dblocks * source_blocksize)
-                                       - sizeof(buf)))  {
+                       off = mp->m_sb.sb_dblocks * source_blocksize;
+                       off -= sizeof(lb);
+                       if (pwrite64(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"),
@@ -793,10 +812,6 @@ main(int argc, char **argv)
                                die_perror();
                        }
                }
-
-               wbuf_align = MAX(wbuf_align, d.d_mem);
-               wbuf_size = MIN(d.d_maxiosz, wbuf_size);
-               wbuf_miniosize = MAX(d.d_miniosz, wbuf_miniosize);
        }
 
        /* initialize locks and bufs */
@@ -815,9 +830,8 @@ main(int argc, char **argv)
 
        wblocks = wbuf_size / BBSIZE;
 
-       if (wbuf_init(&btree_buf, MAX(MAX(source_blocksize, source_sectorsize),
-                                       wbuf_miniosize), wbuf_align,
-                                       wbuf_miniosize, 1) == NULL)  {
+       if (wbuf_init(&btree_buf, MAX(source_blocksize, wbuf_miniosize),
+                               wbuf_align, wbuf_miniosize, 1) == NULL)  {
                do_log(_("Error initializing btree buf 1\n"));
                die_perror();
        }
@@ -844,6 +858,11 @@ main(int argc, char **argv)
        }
 
        for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++)  {
+               if (!duplicate_uuids)
+                       uuid_generate(tcarg->uuid);
+               else
+                       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);
                        die_perror();
@@ -873,12 +892,9 @@ main(int argc, char **argv)
 
        num_ags = mp->m_sb.sb_agcount;
 
-       source_blocks = mp->m_sb.sb_blocksize / BBSIZE
+       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);
-
-       for (i = 0; i < 11; i++)
-               barcount[i] = (source_blocks/10)*i;
+                           - (__uint64_t)mp->m_sb.sb_fdblocks + 10 * num_ags));
 
        kids = num_targets;
        block = (xfs_alloc_block_t *) btree_buf.data;
@@ -889,10 +905,7 @@ main(int argc, char **argv)
                read_ag_header(source_fd, agno, &w_buf, &ag_hdr, mp,
                        source_blocksize, source_sectorsize);
 
-               /* reset uuid and if applicable the in_progress bit */
-
-               if (!duplicate_uuids)
-                       uuid_copy(ag_hdr.xfs_sb->sb_uuid, fsid);
+               /* set the in_progress bit for the first AG */
 
                if (agno == 0)
                        INT_SET(ag_hdr.xfs_sb->sb_inprogress, ARCH_CONVERT, 1);
@@ -1021,11 +1034,8 @@ main(int argc, char **argv)
 
                                                w_buf.position += w_buf.length;
 
-                                               while (howfar < 10 && numblocks 
-                                                       > barcount[howfar])  {
-                                                       bump_bar(howfar);
-                                                       howfar++;
-                                               }
+                                               howfar = bump_bar(
+                                                       howfar, numblocks);
                                        }
                                }
 
@@ -1098,39 +1108,53 @@ main(int argc, char **argv)
 
                                        w_buf.position += w_buf.length;
 
-                                       while (howfar < 10 &&
-                                              numblocks > barcount[howfar])  {
-                                               bump_bar(howfar);
-                                               howfar++;
-                                       }
+                                       howfar = bump_bar(howfar, numblocks);
                                }
                        }
                }
        }
 
        if (kids > 0)  {
-               /* reread and rewrite the first ag */
+               /* write a clean log using the specified UUID */
 
-               read_ag_header(source_fd, 0, &w_buf, &ag_hdr, mp,
-                       source_blocksize, source_sectorsize);
+               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);
 
-               ag_hdr.xfs_sb->sb_inprogress = 0;
+                       pos = write_log_header(source_fd, &w_buf, mp);
+                       end_pos = write_log_trailer(source_fd, &w_buf, mp);
 
-               if (!duplicate_uuids)
-                       uuid_copy(ag_hdr.xfs_sb->sb_uuid, fsid);
+                       w_buf.position = pos;
+                       memset(w_buf.data, 0, w_buf.length);
 
-               write_wbuf();
-               bump_bar(10);
-       }
+                       while (w_buf.position < end_pos)  {
+                               do_write(tcarg);
+                               w_buf.position += w_buf.length;
+                       }
+                       tcarg++;
+               }
 
-       /* nathans TODO: come back and do this properly... */
-       for (i = 0; i < num_targets; i++)  {
-               char command[2048];
+               /* reread and rewrite superblocks (UUID and in-progress) */
+               /* [backwards, so inprogress bit only updated when done] */
+
+               if (duplicate_uuids)
+                       num_ags = 1;
+               for (i = num_ags - 1; i >= 0; i--)  {
+                       read_ag_header(source_fd, i, &w_buf, &ag_hdr, mp,
+                               source_blocksize, source_sectorsize);
+                       if (i == 0)
+                               ag_hdr.xfs_sb->sb_inprogress = 0;
 
-               snprintf(command, sizeof(command),
-                       "%s -x -c 'uuid rewrite' %s >/dev/null 2>&1\n",
-                       "/usr/sbin/xfs_db", target[i].name);
-               system(command);
+                       /* 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);
+                               tcarg++;
+                       }
+               }
+
+               bump_bar(100, 0);
        }
 
        check_errors();
@@ -1139,3 +1163,77 @@ main(int argc, char **argv)
        /*NOTREACHED*/
        return 0;
 }
+
+xfs_caddr_t
+next_log_chunk(xfs_caddr_t 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);
+               memset(buf->data, 0, buf->length);
+               return buf->data;
+       }
+       return p + offset;
+}
+
+/*
+ * 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;
+       xfs_off_t       logstart;
+       int             offset;
+
+       logstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT;
+       buf->position = rounddown(logstart, (xfs_off_t)buf->length);
+
+       memset(p, 0, buf->size);
+       if (logstart % buf->length)  {  /* unaligned */
+               read_wbuf(fd, buf, mp);
+               offset = logstart - buf->position;
+               p += offset;
+               memset(p, 0, buf->length - 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);
+
+       return logstart + roundup(offset, buf->length);
+}
+
+/*
+ * May do an aligned read of the last buffer in the log (& zero
+ * the start of that buffer).  Returns the disk address at the
+ * end of last aligned buffer in the log.
+ */
+xfs_off_t
+write_log_trailer(int fd, wbuf *buf, xfs_mount_t *mp)
+{
+       xfs_off_t       logend;
+       int             offset;
+
+       logend = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart) << BBSHIFT;
+       logend += XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks);
+
+       buf->position = rounddown(logend, (xfs_off_t)buf->length);
+
+       if (logend % buf->length)  {    /* unaligned */
+               read_wbuf(fd, buf, mp);
+               offset = (int)(logend - buf->position);
+               memset(buf->data, 0, offset);
+               do_write(buf->owner);
+       }
+
+       return buf->position;
+}
index 181c00c2f0895ae888711fd2a7e48b8cbdf3a118..bf41af57fe6ae6bc5c286b830f788ec87c779934 100644 (file)
@@ -54,26 +54,29 @@ typedef struct ag_header  {
 
 /*
  * The position/buf_position, length/buf_length, data/buffer pairs
- * exist because of alignment constraints for direct i/o and dealing
+ * exist because of alignment constraints for direct I/O and dealing
  * with scenarios where either the source or target or both is a file
  * and the blocksize of the filesystem where file resides is different
  * from that of the filesystem image being duplicated.  You can get
- * alignment problems resulting in things like ag's starting on
+ * alignment problems resulting from things like AG's starting on
  * non-aligned points in the filesystem.  So you have to be able
  * to read from points "before" the requested starting point and
  * read in more data than requested.
  */
+struct t_args;
 typedef struct {
        int             id;             /* buffer ID */
        size_t          size;           /* size of buffer -- fixed */
        size_t          min_io_size;    /* for direct I/O */
-       xfs_off_t       position;       /* requested position */
-       size_t          length;         /* length of buffer (bytes) */
+       xfs_off_t       position;       /* requested position (bytes) */
+       size_t          length;         /* requested length (bytes) */
        char            *data;          /* pointer to data buffer */
+       struct t_args   *owner;         /* for non-parallel writes */
 } wbuf;
 
-typedef struct {
+typedef struct t_args {
        int             id;
+       uuid_t          uuid;
        pthread_mutex_t wait;
        int             fd;
 } thread_args;
index dc143121ccf5cb254a825444a260681bb0d0080e..c34b240654c05b53d81b8cb99c2de75496650a09 100644 (file)
@@ -1,6 +1,7 @@
 xfsprogs (2.5.4-1) unstable; urgency=low
 
-  * New upstream release, with new xfs_copy command
+  * New upstream release, includes xfs_copy command
+  * Fix shell quoting in xfs_bmap, from Kai S. Juse (closes: 202588)
 
  -- Nathan Scott <nathans@debian.org>  Wed, 23 Jul 2003 10:36:28 +1000
 
index 1e7a16b04b9a34b1c7646f32088bf15d42b1c21d..6f5e4056edeec478c4b44cfdc59eb219c71de85c 100644 (file)
@@ -2,6 +2,7 @@ xfsprogs-2.5.4 (23 July 2003)
        - Update xfs_io bmap command to report unwritten extent flag
          if it is set on an extent (in verbose mode only).
        - Introducing xfs_copy.
+       - Fix shell quoting problem in xfs_bmap script.
 
 xfsprogs-2.5.3 (07 July 2003)
        - Update xfs_io commands which take user input in terms of
index c2080ca01073e75cca479a404b4937b2d339c8d9..d77ce718ea4cc6534c1fcc3fdfae4054dffd59a1 100644 (file)
@@ -124,8 +124,13 @@ extern void        libxfs_device_zero (dev_t, xfs_daddr_t, uint);
 extern void    libxfs_device_close (dev_t);
 
 /* check or write log footer: specify device, log size in blocks & uuid */
+typedef xfs_caddr_t (libxfs_get_block_t)(xfs_caddr_t, int, void *);
+
 extern int     libxfs_log_clear (dev_t, xfs_daddr_t, uint, uuid_t *,
                                int, int, int);
+extern int     libxfs_log_header (xfs_caddr_t, uuid_t *, int, int, int,
+                               libxfs_get_block_t *, void *);
+
 
 /*
  * Define a user-level mount structure with all we need
index f16438d3f6f4e482d2b6cfcb686e7a134759a022..0f80c5320eb6871a9f5660226765beec65b3bfc6 100755 (executable)
@@ -53,12 +53,11 @@ do
 done
 $VERSION && $DIRNAME/xfs_io -p xfs_bmap -V
 
-set -- extra $@
-shift $OPTIND
+shift `expr $OPTIND - 1`
 
 while [ "$1" != "" ]
 do
-       eval $DIRNAME/xfs_io -r -p xfs_bmap -c \"bmap $OPTS\" $1
+       $DIRNAME/xfs_io -r -p xfs_bmap -c "bmap $OPTS" "$1"
        status=$?
        [ $status -ne 0 ] && exit $status
        shift
index 464b8d5376a62819dd0132293c0b7ea771c7df4c..ed71465410d8c4ea316e7401fdc410176823f337 100644 (file)
@@ -82,20 +82,9 @@ libxfs_device_zero(dev_t dev, xfs_daddr_t start, uint len)
        free(z);
 }
 
-int
-libxfs_log_clear(
-       dev_t       device,
-       xfs_daddr_t start,
-       uint        length,
-       uuid_t      *fs_uuid,
-       int         version,
-       int         sunit,
-       int         fmt)
+static void unmount_record(void *p)
 {
-       xfs_buf_t               *buf;
-       xlog_rec_header_t       *head;
-       xlog_op_header_t        *op;
-       int                     i, len;
+       xlog_op_header_t        *op = (xlog_op_header_t *)p;
        /* the data section must be 32 bit size aligned */
        struct {
            __uint16_t magic;
@@ -103,6 +92,39 @@ libxfs_log_clear(
            __uint32_t pad2; /* may as well make it 64 bits */
        } magic = { XLOG_UNMOUNT_TYPE, 0, 0 };
 
+       memset(p, 0, BBSIZE);
+       INT_SET(op->oh_tid,             ARCH_CONVERT, 1);
+       INT_SET(op->oh_len,             ARCH_CONVERT, sizeof(magic));
+       INT_SET(op->oh_clientid,        ARCH_CONVERT, XFS_LOG);
+       INT_SET(op->oh_flags,           ARCH_CONVERT, XLOG_UNMOUNT_TRANS);
+       INT_SET(op->oh_res2,            ARCH_CONVERT, 0);
+
+       /* and the data for this op */
+       memcpy(p + sizeof(xlog_op_header_t), &magic, sizeof(magic));
+}
+
+static xfs_caddr_t next(xfs_caddr_t ptr, int offset, void *private)
+{
+       xfs_buf_t       *buf = (xfs_buf_t *)private;
+
+       if (XFS_BUF_COUNT(buf) < (int)(ptr - XFS_BUF_PTR(buf)) + offset)
+               abort();
+       return ptr + offset;
+}
+
+int
+libxfs_log_clear(
+       dev_t                   device,
+       xfs_daddr_t             start,
+       uint                    length,
+       uuid_t                  *fs_uuid,
+       int                     version,
+       int                     sunit,
+       int                     fmt)
+{
+       xfs_buf_t               *buf;
+       int                     len;
+
        if (!device || !fs_uuid)
                return -EINVAL;
 
@@ -110,22 +132,41 @@ libxfs_log_clear(
        libxfs_device_zero(device, start, length);
 
        /* then write a log record header */
-       if ((version == 2) && sunit)
-               len = BTOBB(sunit);
-       else
-               len = 1;
+       len = ((version == 2) && sunit) ? BTOBB(sunit) : 2;
+       len = MAX(len, 2);
        buf = libxfs_getbuf(device, start, len);
        if (!buf)
                return -1;
+       libxfs_log_header(XFS_BUF_PTR(buf),
+                         fs_uuid, version, sunit, fmt, next, buf);
+       if (libxfs_writebuf(buf, 0))
+               return -1;
+
+       return 0;
+}
 
-       memset(XFS_BUF_PTR(buf), 0, BBSIZE * len);
-       head = (xlog_rec_header_t *)XFS_BUF_PTR(buf);
+int
+libxfs_log_header(
+       xfs_caddr_t             caddr,
+       uuid_t                  *fs_uuid,
+       int                     version,
+       int                     sunit,
+       int                     fmt,
+       libxfs_get_block_t      *nextfunc,
+       void                    *private)
+{
+       xlog_rec_header_t       *head = (xlog_rec_header_t *)caddr;
+       xfs_caddr_t             p = caddr;
+       uint                    cycle_lsn;
+       int                     i, len;
+
+       len = ((version == 2) && sunit) ? BTOBB(sunit) : 1;
 
        /* note that oh_tid actually contains the cycle number
         * and the tid is stored in h_cycle_data[0] - that's the
         * way things end up on disk.
         */
-
+       memset(p, 0, BBSIZE);
        INT_SET(head->h_magicno,        ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM);
        INT_SET(head->h_cycle,          ARCH_CONVERT, 1);
        INT_SET(head->h_version,        ARCH_CONVERT, version);
@@ -145,46 +186,21 @@ libxfs_log_clear(
 
        memcpy(&head->h_fs_uuid, fs_uuid, sizeof(uuid_t));
 
-       if (len > 1) {
-               xfs_caddr_t     dp;
-               uint            cycle_lsn;
+       len = MAX(len, 2);
+       p = nextfunc(p, BBSIZE, private);
+       unmount_record(p);
 
-               cycle_lsn = CYCLE_LSN_NOCONV(head->h_lsn, ARCH_CONVERT);
-               dp = XFS_BUF_PTR(buf) + BBSIZE;
-               for (i = 1; i < len; i++) {
-                       *(uint *)dp = cycle_lsn;
-                       dp += BBSIZE;
-               }
+       cycle_lsn = CYCLE_LSN_NOCONV(head->h_lsn, ARCH_CONVERT);
+       for (i = 2; i < len; i++) {
+               p = nextfunc(p, BBSIZE, private);
+               memset(p, 0, BBSIZE);
+               *(uint *)p = cycle_lsn;
        }
 
-       if (libxfs_writebuf(buf, 0))
-               return -1;
-
-       buf = libxfs_getbuf(device, start + 1, 1);
-       if (!buf)
-               return -1;
-
-       /* now a log unmount op */
-       memset(XFS_BUF_PTR(buf), 0, BBSIZE);
-       op = (xlog_op_header_t *)XFS_BUF_PTR(buf);
-       INT_SET(op->oh_tid,             ARCH_CONVERT, 1);
-       INT_SET(op->oh_len,             ARCH_CONVERT, sizeof(magic));
-       INT_SET(op->oh_clientid,        ARCH_CONVERT, XFS_LOG);
-       INT_SET(op->oh_flags,           ARCH_CONVERT, XLOG_UNMOUNT_TRANS);
-       INT_SET(op->oh_res2,            ARCH_CONVERT, 0);
-
-       /* and the data for this op */
-
-       memcpy(XFS_BUF_PTR(buf) + sizeof(xlog_op_header_t),
-               &magic,
-               sizeof(magic));
-
-       if (libxfs_writebuf(buf, 0))
-               return -1;
-
-       return 0;
+       return BBTOB(len);
 }
 
+
 /*
  * Simple I/O interface
  */