Index: hsmapi.c
===================================================================
--- hsmapi.c (nonexistent)
+++ hsmapi.c (revision 5)
@@ -0,0 +1,882 @@
+/*
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <uuid/uuid.h>
+#include <attr/attributes.h>
+#include <xfs/xfs.h>
+#include <xfs/jdm.h>
+
+#include <string.h>
+
+#include "config.h"
+
+#include "types.h"
+#include "hsmapi.h"
+#include "mlog.h"
+
+/* This version of the HSM API supports the DMF attribute used in the initial
+ * DMF release, as well as the attribute used in the pseudo multiple managed
+ * region DMF release.
+*/
+
+/* DMF attribute name, size, and format as stored within XFS. (Stolen directly
+ from "dmfsapi/dmf_dmattr.H".
+*/
+
+#define DMF_ATTR_NAME "SGI_DMI_DMFATTR" /* name of DMF's attr */
+
+typedef struct {
+ u_char fsys; /* filesystem type */
+ u_char version; /* attribute format version */
+ u_char state[2]; /* dm_state in MSB form */
+ u_char flags[2]; /* dm_flags in MSB form */
+ u_char bfid[16]; /* Bitfile ID in MSB form */
+} XFSattrvalue0_t;
+
+typedef struct {
+ u_char rg_offset[8]; /* region offset in MSB form */
+ u_char rg_size[8]; /* region length in MSB form */
+ u_char rg_state[2]; /* region dm_state in MSB form */
+ u_char rg_flags; /* managed region event bits */
+ u_char rg_fbits; /* region flag bits */
+} XFSattrregion_t;
+
+typedef struct {
+ u_char fsys; /* filesystem type */
+ u_char version; /* attribute format version */
+ u_char state[2]; /* global dm_state in MSB form */
+ u_char flags[2]; /* global dm_flags in MSB form */
+ u_char bfid[16]; /* Bitfile ID in MSB form. */
+ u_char sitetag[4]; /* site tag */
+ u_char regcnt[2]; /* number of regions in MSB form */
+} XFSattrvalue1_t;
+
+#define MIN_FORMAT1_ATTR_LEN (sizeof(XFSattrvalue1_t) + \
+ sizeof(XFSattrregion_t))
+
+/* supported fsys values */
+
+/* XFS DMAPI (w/o MMR) */
+#define FSYS_TYPE_XFS 1
+
+/* supported version values */
+
+/* original DMF attr format */
+#define DMF_ATTR_FORMAT_0 0
+/* DMF attr with multiple regions (real or pseudo) or with a non-zero
+ * site tag. attrs of this format consist of a XFSattrvalue1_t struct
+ * followed by 1 or more XFSattrregion_t structs */
+#define DMF_ATTR_FORMAT_1 1
+
+/* Interesting state field values */
+
+#define DMF_ST_DUALSTATE 2 /* file has backups plus online data */
+#define DMF_ST_OFFLINE 3 /* file has backups, no online data */
+#define DMF_ST_UNMIGRATING 4 /* file data is being staged in */
+#define DMF_ST_NOMIGR 5 /* file should not be migrated */
+#define DMF_ST_PARTIAL 6 /* file has backups plus parts online */
+
+/* DM_EVENT_* are defined in <xfs/dmapi.h>. Trying to avoid a dmapi dependency
+ * in xfsdump since dmapi is not commonly used, yet this code needs to know some
+ * of the event bits.
+ */
+#define DM_EVENT_READ 16
+#define DM_EVENT_WRITE 17
+#define DM_EVENT_TRUNCATE 18
+#define DM_EVENT_DESTROY 20
+
+/* Interesting bit combinations within the bs_dmevmask field of struct xfs_bstat
+ * OFL, UNM, and PAR files have exactly these bits set.
+ * DUL and MIG files have all but the DM_EVENT_READ bit set */
+#define DMF_EV_BITS ((1<<DM_EVENT_DESTROY) | \
+ (1<<DM_EVENT_READ) | \
+ (1<<DM_EVENT_WRITE) | \
+ (1<<DM_EVENT_TRUNCATE))
+
+/* OFL file's managed region event flags */
+#define DMF_MR_FLAGS (0x1 | 0x2 | 0x4)
+
+/* The following definitions provide the internal format of the hsm_fs_ctxt_t
+ and hsm_f_ctxt_t structures, respectively.
+*/
+
+typedef struct {
+ int dumpversion;
+ jdm_fshandle_t *fshanp;
+} dmf_fs_ctxt_t;
+
+typedef struct {
+ dmf_fs_ctxt_t fsys;
+ off64_t filesize;
+ int candidate;
+ int attrlen;
+ char attrval[5000]; /* sized bigger than any poss. value */
+} dmf_f_ctxt_t;
+
+/******************************************************************************
+* Name
+* msb_store - store a variable to u_char array in MSB format
+*
+* Returns
+* void
+******************************************************************************/
+static inline void
+msb_store(
+ u_char *dest,
+ uint64_t src,
+ int length)
+{
+ int i;
+
+ for (i = length - 1; i >= 0; i--) {
+ dest[i] = (u_char)(src & 0xff);
+ src >>= 8;
+ }
+}
+
+/******************************************************************************
+* Name
+* msb_load - load a variable from a u_char array in MSB format
+*
+* Returns
+* value
+******************************************************************************/
+static inline uint64_t
+msb_load(
+ u_char *src,
+ int length)
+{
+ uint64_t tmp = 0;
+ int i;
+
+ for (i = 0; i < length; i++) {
+ tmp = (tmp << 8) | src[i];
+ }
+ return tmp;
+}
+
+/******************************************************************************
+* Name
+* HsmInitFsysContext - allocate and initialize an HSM filesystem context
+*
+* Description
+* HsmInitFsysContext allocates and initializes an HSM filesystem
+* context to hold all filesystem information that might later be needed
+* by other HSM routines. The context is read-only, and can be shared
+* by multiple xfsdump dump streams. It should eventually be freed by
+* calling HsmDeleteFsysContext(). The caller must provide the mount
+* point of the filesystem to be dumped and the HSM API version that
+* xfsdump was compiled with.
+*
+* Note: The restore routines do not require an HSM filesystem context.
+*
+* Returns
+* != NULL, then a pointer to the filesystem context that was allocated.
+* == NULL, either the HSM libary is not compatible with xfsdump, or
+* the filesystem is not under HSM management.
+******************************************************************************/
+
+extern hsm_fs_ctxt_t *
+HsmInitFsysContext(
+const char *mountpoint,
+ int dumpversion)
+{
+ dmf_fs_ctxt_t *dmf_fs_ctxtp;
+
+ if (dumpversion != HSM_API_VERSION_1) {
+ return NULL; /* we can't handle this version */
+ }
+
+ /* Malloc space for a filesystem context, and initialize any fields
+ needed later by other routines.
+ */
+
+ if ((dmf_fs_ctxtp = malloc(sizeof(dmf_fs_ctxt_t))) == NULL) {
+ return NULL;
+ }
+ dmf_fs_ctxtp->dumpversion = dumpversion;
+
+ /* Get the filesystem's handle for later use in building file
+ handles in HsmInitFileContext.
+ */
+ dmf_fs_ctxtp->fshanp = jdm_getfshandle((char *)mountpoint);
+ if (dmf_fs_ctxtp->fshanp == NULL) {
+ free(dmf_fs_ctxtp);
+ return NULL;
+ }
+
+ return (hsm_fs_ctxt_t *)dmf_fs_ctxtp;
+}
+
+
+/******************************************************************************
+* Name
+* HsmDeleteFsysContext - delete an HSM filesystem context
+*
+* Description
+* HsmDeleteFsysContext releases all storage previously allocated to a
+* HSM filesystem context via HsmInitFsysContext.
+*
+* Returns
+* None.
+******************************************************************************/
+
+extern void
+HsmDeleteFsysContext(
+ hsm_fs_ctxt_t *contextp)
+{
+ free(contextp);
+}
+
+
+/******************************************************************************
+* Name
+* HsmEstimateFileSpace - return estimated offline file size
+*
+* Description
+* HsmEstimateFileSpace is called from within estimate_dump_space() only
+* if -a is selected. It estimates the number of bytes needed to dump
+* the file assuming that all dual-residency data will be dumped as holes.
+*
+* Returns
+* != 0, then *bytes contains the estimated size of the file in bytes.
+* == 0, then no estimate made. Caller should use his default estimator.
+******************************************************************************/
+
+extern int
+HsmEstimateFileSpace(
+ hsm_fs_ctxt_t *fscontextp,
+ hsm_f_ctxt_t *fcontextp,
+ const struct xfs_bstat *statp,
+ off64_t *bytes,
+ int accurate)
+{
+ /* If the estimate needs to be accurate, then we'll have to
+ * pay the price and read the DMF attribute, if there is one,
+ * to determine exactly what DMF state the file is in. Otherwise,
+ * make a guess based on information in the bstat. If a
+ * hsm_f_ctxt_t was provided, an accurate estimate is free.
+ */
+ if (fcontextp) {
+ dmf_f_ctxt_t *dmf_f_ctxt = (dmf_f_ctxt_t *)fcontextp;
+
+ if (dmf_f_ctxt->candidate) {
+ *bytes = 0; /* treat the entire file as offline */
+ return 1;
+ } else {
+ return 0;
+ }
+ } else if (accurate) {
+ dmf_fs_ctxt_t *dmf_fs_ctxtp = (dmf_fs_ctxt_t *)fscontextp;
+ dmf_f_ctxt_t dmf_f_ctxt;
+
+ /* This is an implicit HsmAllocateFileContext call. */
+
+ dmf_f_ctxt.fsys = *dmf_fs_ctxtp;
+ dmf_f_ctxt.candidate = 0;
+
+ /* Initialize the file context to determine the file's state. */
+
+ if (HsmInitFileContext((hsm_f_ctxt_t *)&dmf_f_ctxt, statp)) {
+ return 0;
+ }
+
+ /* If the file is dualstate, make it appear offline. */
+
+ if (dmf_f_ctxt.candidate) {
+ *bytes = 0; /* treat the entire file as offline */
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ /* This code is assuming that there are no MIG files, and so any
+ file with DMAPI event bits set will be dumped as OFL. The
+ non-dir dump size estimation will be somewhat low if there
+ are MIG files.
+ */
+ if ((statp->bs_mode & S_IFMT) != S_IFREG) {
+ return 0; /* not a regular file */
+ }
+ if ((statp->bs_xflags & XFS_XFLAG_HASATTR) == 0) {
+ return 0; /* no DMF attribute can possibly exist */
+ }
+ if ((statp->bs_dmevmask & DMF_EV_BITS) == 0) {
+ return 0;
+ }
+
+ *bytes = 0;
+ return 1;
+ }
+}
+
+
+/******************************************************************************
+* Name
+* HsmEstimateFileOffset - return estimated file offset
+*
+* Description
+* HsmEstimateFileOffset is called from within quantity2offset() only
+* if -a is selected. It estimates the offset within the file that has
+* 'bytecount' bytes of physical data preceding it assuming that all
+* dual-residency data in the file will be dumped as holes.
+*
+* Returns
+* != 0, then *byteoffset contains the estimated offset within the file.
+* == 0, then no estimate made. Caller should use his default estimator.
+******************************************************************************/
+
+/* ARGSUSED */
+extern int
+HsmEstimateFileOffset(
+ hsm_fs_ctxt_t *contextp,
+ const struct xfs_bstat *statp,
+ off64_t bytecount,
+ off64_t *byteoffset)
+{
+ dmf_fs_ctxt_t *dmf_fs_ctxtp = (dmf_fs_ctxt_t *)contextp;
+ dmf_f_ctxt_t dmf_f_ctxt;
+
+ /* This is an implicit HsmAllocateFileContext call. */
+
+ dmf_f_ctxt.fsys = *dmf_fs_ctxtp;
+ dmf_f_ctxt.candidate = 0;
+
+ /* Initialize the file context to determine the file's state. */
+
+ if (HsmInitFileContext((hsm_f_ctxt_t *)&dmf_f_ctxt, statp)) {
+ return 0;
+ }
+
+ /* If the file is dualstate, make it appear offline. */
+
+ if (dmf_f_ctxt.candidate) {
+ *byteoffset = statp->bs_size;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+/******************************************************************************
+* Name
+* HsmAllocateFileContext - allocate an HSM file context
+*
+* Description
+* HsmAllocateFileContext mallocs the maximum-sized file context that
+* might later needed by HsmInitFileContext(). The context is
+* read-write. Each xfsdump stream must have its own file context. This
+* context should eventually be freed by calling HsmDeleteFileContext().
+* The caller must provide the HSM filesystem context for the filesystem
+* being dumped.
+*
+* Note: The restore routines do not require an HSM file context.
+*
+* Returns
+* != NULL, then a pointer to the file context that was allocated.
+******************************************************************************/
+
+extern hsm_f_ctxt_t *
+HsmAllocateFileContext(
+ hsm_fs_ctxt_t *contextp)
+{
+ dmf_f_ctxt_t *dmf_f_ctxtp;
+
+ if ((dmf_f_ctxtp = malloc(sizeof(dmf_f_ctxt_t))) == NULL) {
+ return NULL;
+ }
+
+ /* Save the filesystem information in the file context. */
+
+ dmf_f_ctxtp->fsys = *(dmf_fs_ctxt_t *)contextp;
+ dmf_f_ctxtp->candidate = 0;
+
+ return (hsm_f_ctxt_t *)dmf_f_ctxtp;
+}
+
+
+/******************************************************************************
+* Name
+* HsmDeleteFileContext - delete a previously created HSM file context
+*
+* Description
+* HsmDeleteFileContext releases all storage previously allocated to a
+* HSM file context via HsmAllocateFileContext.
+*
+* Returns
+* None.
+******************************************************************************/
+
+extern void
+HsmDeleteFileContext(
+ hsm_f_ctxt_t *contextp)
+{
+ free(contextp);
+}
+
+
+/******************************************************************************
+* Name
+* HsmInitFileContext - initialize the HSM context for a particular file
+*
+* Description
+* HsmInitFileContext initializes an existing HSM file context for
+* subsequent operations on a particular regular file. Other HSM routines
+* use the context to access information collected by HsmInitFileContext
+* about the file rather than having to recollect the file's information
+* on each call.
+*
+* Returns
+* == 0, context was created.
+* != 0, if something is wrong with the file and it should not be dumped.
+******************************************************************************/
+
+extern int
+HsmInitFileContext(
+ hsm_f_ctxt_t *contextp,
+ const struct xfs_bstat *statp)
+{
+ dmf_f_ctxt_t *dmf_f_ctxtp = (dmf_f_ctxt_t *)contextp;
+ XFSattrvalue0_t *dmfattrp;
+ int state;
+ int error;
+ attr_multiop_t attr_op;
+
+ dmf_f_ctxtp->candidate = 0; /* assume file will NOT be of interest */
+
+ /* Try and rule out a dualstate inode by doing some quick tests. */
+
+ if ((statp->bs_mode & S_IFMT) != S_IFREG) {
+ return 0; /* not a regular file */
+ }
+ if ((statp->bs_xflags & XFS_XFLAG_HASATTR) == 0) {
+ return 0; /* no DMF attribute exists */
+ }
+ if ((statp->bs_dmevmask & DMF_EV_BITS) == 0) {
+ return 0; /* no interesting DMAPI bits set */
+ }
+
+ /* We have a likely candidate, so we have to pay the price and look
+ for the DMF attribute. (It could be in a disk block separate from
+ the inode.)
+ */
+ attr_op.am_opcode = ATTR_OP_GET;
+ attr_op.am_error = 0;
+ attr_op.am_attrname = DMF_ATTR_NAME;
+ attr_op.am_attrvalue = dmf_f_ctxtp->attrval;
+ attr_op.am_length = sizeof(dmf_f_ctxtp->attrval);
+ attr_op.am_flags = ATTR_ROOT;
+
+ error = jdm_attr_multi(dmf_f_ctxtp->fsys.fshanp,
+ (struct xfs_bstat *)statp,
+ (char *)&attr_op,
+ 1,
+ 0);
+ if (error || attr_op.am_error)
+ return 0; /* no DMF attribute */
+
+ dmf_f_ctxtp->attrlen = attr_op.am_length;
+ dmfattrp = (XFSattrvalue0_t *)dmf_f_ctxtp->attrval;
+
+ if (dmfattrp->fsys != FSYS_TYPE_XFS)
+ return 0; /* unsupported filesystem version */
+
+ switch(dmfattrp->version) {
+ case DMF_ATTR_FORMAT_0:
+ if (dmf_f_ctxtp->attrlen != sizeof(XFSattrvalue0_t))
+ return 0; /* wrong size */
+ break;
+ case DMF_ATTR_FORMAT_1:
+ if (dmf_f_ctxtp->attrlen < MIN_FORMAT1_ATTR_LEN)
+ return 0; /* wrong size */
+ break;
+ default:
+ return 0; /* unsupported attr version */
+ }
+
+ state = (int)msb_load(dmfattrp->state, sizeof(dmfattrp->state));
+ switch (state) {
+ case DMF_ST_DUALSTATE:
+ case DMF_ST_UNMIGRATING:
+ case DMF_ST_PARTIAL:
+ case DMF_ST_OFFLINE:
+ /* We have a DMF file that can be treated as offline */
+ dmf_f_ctxtp->candidate = 1;
+ dmf_f_ctxtp->filesize = statp->bs_size;
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+/*******************************************************************************
+* Name
+* HsmModifyInode - modify a struct xfs_bstat to make a file appear offline
+*
+* Description
+* HsmModifyInode uses the context provided by a previous
+* HsmInitFileContext call to determine how to modify a struct xfs_bstat
+* structure to make a dual-residency HSM file appear to be offline.
+*
+* Returns
+* != 0, struct xfs_bstat structure was modified.
+* == 0, if something is wrong with the file and it should not be dumped.
+8******************************************************************************/
+
+extern int
+HsmModifyInode(
+ hsm_f_ctxt_t *contextp,
+ struct xfs_bstat *statp)
+{
+ dmf_f_ctxt_t *dmf_f_ctxtp = (dmf_f_ctxt_t *)contextp;
+
+ if (dmf_f_ctxtp->candidate) {
+ statp->bs_dmevmask = DMF_EV_BITS;
+ }
+ return 1;
+}
+
+
+/******************************************************************************
+* Name
+* HsmModifyExtentMap - modify getbmapx array to make file appear offline
+*
+* Description
+* HsmModifyExtentMap uses the context provided by a previous
+* HsmInitFileContext call to determine how to modify a contiguous array
+* of getbmapx structures to make a dual-residency HSM file appear to
+* be offline.
+*
+* Returns
+* != 0, getbmapx array was successfully modified.
+* == 0, if something is wrong with the file and it should not be dumped.
+******************************************************************************/
+
+extern int
+HsmModifyExtentMap(
+ hsm_f_ctxt_t *contextp,
+ struct getbmapx *bmap)
+{
+ dmf_f_ctxt_t *dmf_f_ctxtp = (dmf_f_ctxt_t *)contextp;
+ int64_t length;
+
+ if (bmap[0].bmv_entries <= 0) {
+ return 1; /* caller must already be at EOF */
+ }
+
+ if (!dmf_f_ctxtp->candidate) {
+ return 1; /* not a dualstate file; dump as normal */
+ }
+
+ /* We are dumping a dualstate file. Make it look like there is only
+ one getbmapx extent and that it contains a hole which extends from
+ the current offset to the end of the file. The bmap[1].bmv_offset
+ should already be correct.
+ */
+
+ length = BTOBB(dmf_f_ctxtp->filesize) - bmap[1].bmv_offset;
+
+ if (length > 0) {
+ bmap[0].bmv_entries = 1; /* rest of file is one extent */
+
+ bmap[1].bmv_block = -1; /* convert to a hole */
+ bmap[1].bmv_length = length;
+ } else {
+ bmap[0].bmv_entries = 0; /* indicate at EOF */
+ }
+
+ return 1;
+}
+
+
+/******************************************************************************
+* Name
+* HsmFilterExistingAttribute - filter out unwanted extended attributes
+*
+* Description
+* HsmFilterExistingAttribute uses the context provided by a previous
+* HsmInitFileContext call to determine whether or not the extended
+* attribute with name 'namep' should be included in a file's dump image.
+* (An extended attribute can be modified within the dump by filtering
+* it out with this routine, then adding the new version of the attribute
+* back with HsmAddNewAttribute.)
+*
+* Note: this routine must be idempotent. It is possible that xfsdump
+* will call this routine a second time for the same attribute if after
+* the first call it discovers that there isn't room in its buffer to
+* hold the attribute value.
+*
+* Returns
+* != 0, the attribute was successfully examined. If '*skip_entry' is
+* non-zero, xfsdump will not add this attribute to the dump.
+* == 0, if something is wrong with the file and it should not be dumped.
+******************************************************************************/
+
+extern int
+HsmFilterExistingAttribute(
+ hsm_f_ctxt_t *hsm_f_ctxtp,
+const char *namep, /* attribute name */
+ uint32_t valuesz, /* value size */
+ int flag,
+ int *skip_entry)
+{
+ dmf_f_ctxt_t *dmf_f_ctxtp = (dmf_f_ctxt_t *)hsm_f_ctxtp;
+
+ *skip_entry = 0; /* assume we will not remove this attribute */
+
+ if (!dmf_f_ctxtp->candidate) {
+ return 1; /* not a dualstate file */
+ }
+ if (flag != ATTR_ROOT) {
+ return 1; /* not a root attribute */
+ }
+ if (strcmp(namep, DMF_ATTR_NAME)) {
+ return 1; /* not the right attribute */
+ }
+
+ if (valuesz < sizeof(XFSattrvalue0_t)) {
+ return 0; /* attribute is corrupt */
+ }
+
+ /* Remove the existing DMF attribute, as we will later replace it with
+ our own version.
+ */
+
+ *skip_entry = 1;
+ return 1;
+}
+
+
+/******************************************************************************
+* Name
+* HsmAddNewAttribute - add zero or more HSM attributes to a file's dump
+*
+* Description
+* HsmAddNewAttribute uses the context provided by a previous
+* HsmInitFileContext call to determine whether or not additional HSM
+* extended attributes need to be added to a file's dump image. On the
+* first call for a file, 'cursor' will be zero. xfsdump will increment
+* 'cursor' by one each time it asks for a new attribute. When no more
+* attributes are to be added, '*namepp' should be set to NULL.
+*
+* Note: this routine must be idempotent. It is possible that xfsdump
+* will call this routine a second time using the same cursor value if
+* it discovers that there isn't room in its buffer to hold the attribute
+* value it was given in the first call.
+*
+* Returns
+* != 0, call was successful. If '*namepp' is non-NULL, then it is the
+* name of an attribute to be added to the file's dump. '*valuep'
+* points the the value of the attribute, and '*valueszp' is the
+* value's size. If '*namep* is NULL, then there are no more
+* attributes to be added.
+* == 0, if something is wrong with the file and it should not be dumped.
+******************************************************************************/
+
+extern int
+HsmAddNewAttribute(
+ hsm_f_ctxt_t *hsm_f_ctxtp,
+ int cursor,
+ int flag,
+ char **namepp, /* pointer to new attribute name */
+ char **valuepp, /* pointer to its value */
+ uint32_t *valueszp) /* pointer to the value size */
+{
+ dmf_f_ctxt_t *dmf_f_ctxtp = (dmf_f_ctxt_t *)hsm_f_ctxtp;
+ XFSattrvalue1_t *dmfattr1p = (XFSattrvalue1_t *)dmf_f_ctxtp->attrval;
+
+ *namepp = NULL; /* assume we won't add an attribute */
+
+ if (!dmf_f_ctxtp->candidate) {
+ return 1; /* not a dualstate file */
+ }
+ if (flag != ATTR_ROOT) {
+ return 1; /* not in the root attribute section */
+ }
+
+ if (cursor > 0) {
+ return 1; /* there is only one attribute to add */
+ }
+
+ /* DMF writes format0 (XFSattrvalue0_t) attributes unless:
+ * - the file has multiple regions
+ * - the file has a non-zero site tag
+ *
+ * Here we are writing a single region (OFL), so we only dump a
+ * format1 attribute if the file has a non-zero site tag.
+ */
+ if (dmfattr1p->version == DMF_ATTR_FORMAT_1 &&
+ msb_load(dmfattr1p->sitetag, sizeof(dmfattr1p->sitetag)) != 0) {
+ XFSattrregion_t *reg;
+ reg = (XFSattrregion_t *)(dmf_f_ctxtp->attrval +
+ sizeof(XFSattrvalue1_t));
+ dmf_f_ctxtp->attrlen = MIN_FORMAT1_ATTR_LEN;
+
+ /* make one offline region the size of the whole file */
+ msb_store(dmfattr1p->regcnt, 1, sizeof(dmfattr1p->regcnt));
+ msb_store(reg->rg_offset, 0, sizeof(reg->rg_offset));
+ msb_store(reg->rg_size, dmf_f_ctxtp->filesize, sizeof(reg->rg_size));
+ msb_store(reg->rg_state, DMF_ST_OFFLINE, sizeof(reg->rg_state));
+ reg->rg_flags = DMF_MR_FLAGS;
+ reg->rg_fbits = 0;
+ } else {
+ /* writing a format0 attr. ensure correct length and version */
+ dmfattr1p->version = DMF_ATTR_FORMAT_0;
+ dmf_f_ctxtp->attrlen = sizeof(XFSattrvalue0_t);
+ }
+
+ /* set the global state to offline */
+ msb_store(dmfattr1p->state, DMF_ST_OFFLINE, sizeof(dmfattr1p->state));
+
+ *valuepp = (char *)dmfattr1p;
+ *namepp = DMF_ATTR_NAME;
+ *valueszp = dmf_f_ctxtp->attrlen;
+ return 1;
+}
+
+
+/******************************************************************************
+* Name
+* HsmBeginRestoreFile
+*
+* Description
+* HsmBeginRestoreFile is called after a file is created but before any
+* data has been restored to it. The hsm_flagp param can be used to
+* keep track of limited state between calls to the HSM restore routines.
+*
+* Note that this does not require a filesystem or file context like the
+* HSM calls for xfsdump. This is currently a crude interface to satisfy
+* a specific need. It can be generalized at a later time, if necessary.
+*
+* Returns
+* None.
+******************************************************************************/
+
+extern void
+HsmBeginRestoreFile(
+ bstat_t *bstatp,
+ int fd,
+ int *hsm_flagp)
+{
+ int rv;
+ XFSattrvalue0_t dmattr;
+
+ /* If it appears to be a DMF-managed file, set the NOMIGR attribute
+ * on it to prevent DMF from touching the file while we are restoring
+ * it. If it turns out to not be a DMF-managed file, we'll need to
+ * remove the attribute when the file is completed.
+ */
+ *hsm_flagp = 0;
+ if (bstatp->bs_dmevmask && bstatp->bs_xflags & XFS_XFLAG_HASATTR) {
+ memset(&dmattr, 0, sizeof(XFSattrvalue0_t));
+ dmattr.fsys = FSYS_TYPE_XFS;
+ msb_store(dmattr.state, DMF_ST_NOMIGR, sizeof(dmattr.state));
+
+ rv = fsetxattr(fd,
+ DMF_ATTR_NAME,
+ (char *)&dmattr,
+ sizeof(dmattr),
+ ATTR_ROOT);
+ if (rv == 0)
+ *hsm_flagp = 1;
+ }
+}
+
+
+/******************************************************************************
+* Name
+* HsmRestoreAttribute
+*
+* Description
+** HsmRestoreAttribute is called when restoring an extended attribute.
+* The hsm_flagp param can be used to keep track of limited state
+* between calls to the HSM restore routines.
+*
+* Note that this does not require a filesystem or file context like the
+* HSM calls for xfsdump. This is currently a crude interface to satisfy
+* a specific need. It can be generalized at a later time, if necessary.
+*
+* Returns
+* None.
+******************************************************************************/
+
+extern void
+HsmRestoreAttribute(
+ int flag, /* ext attr flags */
+ char *namep, /* pointer to new attribute name */
+ int *hsm_flagp)
+{
+ /* If the DMF attribute is being restored, then we will not
+ * have to remove the NOMIGR attribute when this file is
+ * being completed.
+ */
+ if (flag & ATTR_ROOT && !strcmp(namep, DMF_ATTR_NAME))
+ *hsm_flagp = 0;
+}
+
+
+/******************************************************************************
+* Name
+* HsmEndRestoreFile
+*
+* Description
+* HsmEndRestoreFile is called when all data and extended attributes
+* have been restored. The hsm_flagsp param can be used to keep track
+* of limited state between calls to the HSM restore routines.
+*
+* Note that this does not require a filesystem or file context like the
+* HSM calls for xfsdump. This is currently a crude interface to satisfy
+* a specific need. It can be generalized at a later time, if necessary.
+*
+* Returns
+* None.
+******************************************************************************/
+
+extern void
+HsmEndRestoreFile(
+ char *path,
+ int fd,
+ int *hsm_flagp)
+{
+ /* We put a NOMIGR on the file because we thought it was a
+ * DMF-managed file. If it was not, then we need to take
+ * that attribute off now.
+ */
+ if (*hsm_flagp) {
+ int rv;
+ rv = fremovexattr( fd, DMF_ATTR_NAME , ATTR_ROOT );
+ if (rv) {
+ mlog(MLOG_NORMAL | MLOG_WARNING,
+ _("error removing temp DMF attr on %s: %s\n"),
+ path,
+ strerror(errno));
+ }
+ }
+}
Index: .
===================================================================
--- . (nonexistent)
+++ . (revision 5)
Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~