blob: 24bb924c76d7d93e859a1ac03bc97a1c615ef7dc [file] [log] [blame]
/*
* 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 xfs_bstat_t:
* 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 xfs_bstat_t *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 xfs_bstat_t *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 xfs_bstat_t *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,
(xfs_bstat_t *)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 xfs_bstat_t to make a file appear offline
*
* Description
* HsmModifyInode uses the context provided by a previous
* HsmInitFileContext call to determine how to modify a xfs_bstat_t
* structure to make a dual-residency HSM file appear to be offline.
*
* Returns
* != 0, xfs_bstat_t structure was modified.
* == 0, if something is wrong with the file and it should not be dumped.
******************************************************************************/
extern int
HsmModifyInode(
hsm_f_ctxt_t *contextp,
xfs_bstat_t *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 = attr_setf(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 = attr_removef(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));
}
}
}