From 989b74bc70e4f6244d4acd5a946edb6a9dc8c52d Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Fri, 25 Jul 2003 03:14:10 +0000 Subject: [PATCH] Finish the xfs_copy port, fix a whitespace handling issue in xfs_bmap. 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 | 320 +++++++++++++++++++++++++++++++---------------- copy/xfs_copy.h | 13 +- debian/changelog | 3 +- doc/CHANGES | 1 + include/libxfs.h | 5 + io/xfs_bmap.sh | 5 +- libxfs/rdwr.c | 126 +++++++++++-------- 7 files changed, 298 insertions(+), 175 deletions(-) diff --git a/copy/xfs_copy.c b/copy/xfs_copy.c index 28e18a274..f92225b50 100644 --- a/copy/xfs_copy.c +++ b/copy/xfs_copy.c @@ -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; +} diff --git a/copy/xfs_copy.h b/copy/xfs_copy.h index 181c00c2f..bf41af57f 100644 --- a/copy/xfs_copy.h +++ b/copy/xfs_copy.h @@ -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; diff --git a/debian/changelog b/debian/changelog index dc143121c..c34b24065 100644 --- a/debian/changelog +++ b/debian/changelog @@ -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 Wed, 23 Jul 2003 10:36:28 +1000 diff --git a/doc/CHANGES b/doc/CHANGES index 1e7a16b04..6f5e4056e 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -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 diff --git a/include/libxfs.h b/include/libxfs.h index c2080ca01..d77ce718e 100644 --- a/include/libxfs.h +++ b/include/libxfs.h @@ -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 diff --git a/io/xfs_bmap.sh b/io/xfs_bmap.sh index f16438d3f..0f80c5320 100755 --- a/io/xfs_bmap.sh +++ b/io/xfs_bmap.sh @@ -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 diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c index 464b8d537..ed7146541 100644 --- a/libxfs/rdwr.c +++ b/libxfs/rdwr.c @@ -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 */ -- 2.47.2