plot-llstat.8 l_getgroups.8 lst.8 routerstat.8 lshowmount.8 \
ll_recover_lost_found_objs.8 llog_reader.8 llapi_file_open.3 \
llapi_file_create.3 llapi_file_get_stripe.3 lustreapi.7 \
- lustre_rsync.8 lfs_migrate.1 lhbadm.8 ldev.8 ldev.conf.5 nids.5
+ lustre_rsync.8 lfs_migrate.1 lhbadm.8 ldev.8 ldev.conf.5 nids.5 \
+ lfs-hsm.1 llapi_hsm_state_get.3 llapi_hsm_state_set.3
if UTILS
man_MANS = $(MANFILES)
--- /dev/null
+.TH lfs-hsm 1 "November 9, 2012" Lustre "Lustre/HSM binding utility"
+.SH NAME
+.Blfs hsm_command
+lfs commands used to interact with HSM features
+.SH SYNOPSIS
+.B lfs hsm_state
+.RB <FILE> ...
+.br
+.B lfs hsm_set|hsm_clear
+.RB [ --norelease ]
+.RB [ --noarchive ]
+.RB [ --dirty ]
+.RB [ --exists ]
+.RB [ --archived ]
+.RB [ --lost ]
+.RB <FILE> ...
+.br
+.SH DESCRIPTION
+These are a set of lfs commands used to interact with Lustre/HSM binding feature.
+.TP
+.B lfs hsm_state <FILE> ...
+Display the current HSM flags and archive ID for provided files.
+.TP
+.B lfs hsm_set <FILE>...
+Set provided HSM flags on file list.
+.TP
+.B lfs hsm_clear <FILE>...
+Clear the HSM related flags on file list.
+.PP
+Non-privileged user can only change the following flags:
+.B norelease
+,
+.B noarchive
+and
+.B dirty.
+.PP
+.SH OPTIONS
+.TP
+.B \\--norelease
+File should never be released. File data will stay in Lustre even if a copy exists in HSM backend.
+.TP
+.B \\--noarchive
+File should never be archived. Useful if this is a temporary file, for example.
+.TP
+.B \\--dirty
+File content is not in sync with HSM backend. File should be archived again. (root only)
+.TP
+.B \\--exists
+A file copy exists in HSM backend. Useful mostly for debugging. (root only)
+.TP
+.B \\--archived
+An up-to-date file copy exists in HSM backend. Useful mostly for debugging. (root only)
+.TP
+.B \\--lost
+File copy in HSM backend is not usable anymore and file could not be restored. It should be archived again. (root only)
+.SH EXAMPLES
+.TP
+.B Display current HSM flag for foo:
+$ lfs hsm_state /mnt/lustre/foo
+
+/mnt/lustre/foo: (0x0000000b) exists dirty archived, archive_id: 1
+
+.TP
+.B Force a file to be considered as modified in lustre (dirty)
+$ lfs hsm_set --dirty /mnt/lustre/motd
+
+.SH AUTHOR
+Written by Aurelien Degremont.
+
+.SH KNOWN BUGS
+.PP
+Please report all bugs to http://jira.whamcloud.com/
+.SH SEE ALSO
+.BR lfs (1)
.SH AUTHOR
The lfs command is part of the Lustre filesystem.
.SH SEE ALSO
+.BR lfs-hsm (1),
.BR lctl (8),
.BR lustre (7)
--- /dev/null
+.TH lustreapi 3 "2012 Dec 21" Lustre "Lustre Application Interface Library"
+.SH NAME
+llapi_hsm_state_get \- get HSM state information for a file on Lustre filesystem
+.SH SYNOPSIS
+.nf
+.B #include <lustre/lustreapi.h>
+.sp
+.BI "int llapi_hsm_state_get(const char *" path ", struct hsm_user_state *" hus ");"
+.sp
+.fi
+.SH DESCRIPTION
+.LP
+.B llapi_hsm_state_get(\|)
+read HSM state information like HSM flags and HSM archive ID for file pointed by
+.IR path .
+Information is returned in
+.I hus
+which should already be allocated.
+
+.nf
+struct hsm_user_state {
+ __u32 hus_states;
+ __u32 hus_archive_id;
+};
+.fi
+.TP 20
+.I hus_states
+Flag mask for different HSM states and policy hints. See
+.I hsm_states
+enum for full list.
+.TP 20
+.I hus_archive_id
+External HSM ID used for this file.
+.LP
+
+.nf
+enum hsm_states {
+ HS_EXISTS,
+ HS_DIRTY,
+ HS_RELEASED,
+ HS_ARCHIVED,
+ HS_NORELEASE,
+ HS_NOARCHIVE,
+ HS_LOST,
+};
+.fi
+
+.TP 20
+.I HS_EXISTS
+A file copy exists in HSM backend.
+.TP
+.I HS_DIRTY
+File content is not in sync with HSM backend.
+.TP
+.I HS_RELEASED
+File content is no more present in Lustre and should be restored to be access.
+.TP
+.I HS_ARCHIVED
+An up-to-date file copy exists in HSM backend.
+.TP
+.I HS_NORELEASE
+File should never be released. File data will stay in Lustre even if a copy exists in HSM backend.
+.TP
+.I HS_NOARCHIVE
+File should never be archived. Useful if this is a temporary file by example.
+.TP
+.I HS_LOST
+File copy in backend is not usable anymore and file could not be restore.
+.SH RETURN VALUES
+.LP
+.B llapi_hsm_state_get(\|)
+returns:
+.TP
+0
+on success
+.TP
+!= 0
+on failure,
+.I errno
+is set appropriately.
+.SH ERRORS
+.TP 15
+.SM ENOMEM
+failed to allocate memory.
+.TP 15
+.SM ENAMETOOLONG
+.I path
+was too long.
+.TP 15
+.SM ENOENT
+.I path
+does not point to a file or a directory.
+.TP 15
+.SM ENOTTY
+.I path
+does not point to a Lustre filesystem.
+.SH EXAMPLE
+.nf
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <lustre/lustreapi.h>
+
+int main(int argc, char **argv)
+{
+ struct hsm_user_state hus;
+ int rc;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: prog FILEPATH\\n");
+ exit(1);
+ }
+
+ rc = llapi_hsm_state_get(argv[1], &hus);
+ if (rc) {
+ fprintf(stderr, "can't get hsm state for %s: %s\\n",
+ argv[1], strerror(errno = -rc));
+ exit(rc);
+ }
+
+ if (hus.hus_states & HS_RELEASED)
+ printf(" released");
+ if (hus.hus_states & HS_EXISTS)
+ printf(" exists");
+ if (hus.hus_states & HS_DIRTY)
+ printf(" dirty");
+ if (hus.hus_states & HS_ARCHIVED)
+ printf(" archived");
+
+ /* Display user-settable flags */
+ if (hus.hus_states & HS_NORELEASE)
+ printf(" never_release");
+ if (hus.hus_states & HS_NOARCHIVE)
+ printf(" never_archive");
+ if (hus.hus_states & HS_LOST)
+ printf(" lost_from_hsm");
+
+ if (hus.hus_archive_id != 0)
+ printf(", archive_id:%d", hus.hus_archive_id);
+
+ printf("\\n");
+
+ exit(0);
+}
+.fi
+.SH "SEE ALSO"
+.BR lustre (7),
+.BR lustreapi (7),
+.BR llapi_hsm_state_set (3)
--- /dev/null
+.TH lustreapi 3 "2012 Dec 21" Lustre "Lustre Application Interface Library"
+.SH NAME
+llapi_hsm_state_set \- set HSM flags for a file on Lustre filesystem
+.SH SYNOPSIS
+.nf
+.B #include <lustre/lustreapi.h>
+.sp
+.BI "int llapi_hsm_state_set(const char *" path ", __u64 " setmask ",
+.BI " __u64 " clearmask ", __u32 " archive_id ");"
+.sp
+.fi
+.SH DESCRIPTION
+.LP
+.B llapi_hsm_state_set(\|)
+sets, clears HSM flags and modifies archive ID for file pointed by
+.IR path .
+
+.TP 20
+.I setmask
+Mask of flags to be added.
+.TP 20
+.I clearmask
+Mask of flags to be removed.
+.TP 20
+.I archive_id
+Archive ID (greater than 0) used for this file. Use 0 if you do not want to
+change it.
+.LP
+See
+.BR llapi_hsm_state_get (3)
+for available flags.
+.LP
+.SH RETURN VALUES
+.LP
+.B llapi_hsm_state_set(\|)
+returns:
+.TP
+0
+on success
+.TP
+!= 0
+on failure,
+.I errno
+is set appropriately.
+.SH ERRORS
+.TP 15
+.SM ENOMEM
+failed to allocate memory.
+.TP 15
+.SM ENAMETOOLONG
+.I path
+was too long.
+.TP 15
+.SM ENOENT
+.I path
+does not point to a file or a directory.
+.TP 15
+.SM ENOTTY
+.I path
+does not point to a Lustre filesystem.
+.TP 15
+.SM EINVAL
+Provided masks resulted in an incompatible set of flags.
+.SH EXAMPLE
+
+.nf
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <lustre/lustreapi.h>
+
+int main(int argc, char **argv)
+{
+ int rc;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: prog FILEPATH\\n");
+ exit(1);
+ }
+
+ rc = llapi_hsm_state_set(argv[1], HS_DIRTY|HS_NORELEASE, 0, 0);
+ if (rc != 0) {
+ fprintf(stderr, "Can't change hsm flags for %s: %s\\n",
+ argv[1], strerror(errno = -rc));
+ exit(rc);
+ }
+
+ exit(0);
+}
+.fi
+.SH "SEE ALSO"
+.BR lustre (7),
+.BR lustreapi (7),
+.BR llapi_hsm_state_get (3)
.BR llapi_file_open (3),
.BR llapi_file_get_stripe (3),
.BR llapi_quotactl (3)
+.BR llapi_hsm_state_get (3)
+.BR llapi_hsm_state_set (3)
/* don't forget obdo_fid which is way down at the bottom so it can
* come after the definition of llog_cookie */
+enum hss_valid {
+ HSS_SETMASK = 0x01,
+ HSS_CLEARMASK = 0x02,
+ HSS_ARCHIVE_ID = 0x04,
+};
+
+struct hsm_state_set {
+ __u32 hss_valid;
+ __u32 hss_archive_id;
+ __u64 hss_setmask;
+ __u64 hss_clearmask;
+};
+
+extern void lustre_swab_hsm_user_state(struct hsm_user_state *hus);
+extern void lustre_swab_hsm_state_set(struct hsm_state_set *hss);
extern void lustre_swab_obd_statfs (struct obd_statfs *os);
__u64 hpk_padding2;
} __attribute__((packed));
-extern void lustre_swab_hsm_user_state(struct hsm_user_state *hus);
extern void lustre_swab_hsm_progress_kernel(struct hsm_progress_kernel *hpk);
+extern void lustre_swab_hsm_user_state(struct hsm_user_state *hus);
extern void lustre_swab_hsm_user_item(struct hsm_user_item *hui);
#endif
* See HSM_FLAGS below.
*/
enum hsm_states {
- HS_EXISTS = 0x00000001,
- HS_DIRTY = 0x00000002,
- HS_RELEASED = 0x00000004,
- HS_ARCHIVED = 0x00000008,
- HS_NORELEASE = 0x00000010,
- HS_NOARCHIVE = 0x00000020,
- HS_LOST = 0x00000040,
+ HS_EXISTS = 0x00000001,
+ HS_DIRTY = 0x00000002,
+ HS_RELEASED = 0x00000004,
+ HS_ARCHIVED = 0x00000008,
+ HS_NORELEASE = 0x00000010,
+ HS_NOARCHIVE = 0x00000020,
+ HS_LOST = 0x00000040,
};
/* HSM user-setable flags. */
* HSMÂ request progress state
*/
enum hsm_progress_states {
- HPS_WAITING = 1,
- HPS_RUNNING = 2,
- HPS_DONE = 3,
+ HPS_WAITING = 1,
+ HPS_RUNNING = 2,
+ HPS_DONE = 3,
};
-#define HPS_NONE 0
+#define HPS_NONE 0
static inline char *hsm_progress_state2name(enum hsm_progress_states s)
{
- switch (s) {
- case HPS_WAITING: return "waiting";
- case HPS_RUNNING: return "running";
- case HPS_DONE: return "done";
- default: return "unknown";
- }
+ switch (s) {
+ case HPS_WAITING: return "waiting";
+ case HPS_RUNNING: return "running";
+ case HPS_DONE: return "done";
+ default: return "unknown";
+ }
}
struct hsm_extent {
- __u64 offset;
- __u64 length;
+ __u64 offset;
+ __u64 length;
} __attribute__((packed));
/**
* current HSM flags and in-progress action.
*/
struct hsm_user_state {
- /** Current HSM states, from enum hsm_states. */
- __u32 hus_states;
- __u32 hus_archive_num;
- /** The current undergoing action, if there is one */
- __u32 hus_in_progress_state;
- __u32 hus_in_progress_action;
- struct hsm_extent hus_in_progress_location;
- char hus_extended_info[];
+ /** Current HSM states, from enum hsm_states. */
+ __u32 hus_states;
+ __u32 hus_archive_id;
+ /** The current undergoing action, if there is one */
+ __u32 hus_in_progress_state;
+ __u32 hus_in_progress_action;
+ struct hsm_extent hus_in_progress_location;
+ char hus_extended_info[];
};
struct hsm_state_set_ioc {
- struct lu_fid hssi_fid;
- __u64 hssi_setmask;
- __u64 hssi_clearmask;
+ struct lu_fid hssi_fid;
+ __u64 hssi_setmask;
+ __u64 hssi_clearmask;
};
/***** HSM user requests ******/
extern int llapi_get_version(char *buffer, int buffer_size, char **version);
extern int llapi_get_data_version(int fd, __u64 *data_version, __u64 flags);
+extern int llapi_hsm_state_get(const char *path, struct hsm_user_state *hus);
+extern int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
+ __u32 archive_id);
extern int llapi_create_volatile_idx(char *directory, int idx, int mode);
static inline int llapi_create_volatile(char *directory, int mode)
extern struct req_msg_field RMF_MDS_HSM_REQUEST;
extern struct req_msg_field RMF_MDS_HSM_USER_ITEM;
extern struct req_msg_field RMF_MDS_HSM_ARCHIVE;
+extern struct req_msg_field RMF_HSM_USER_STATE;
+extern struct req_msg_field RMF_HSM_STATE_SET;
/* seq-mgr fields */
extern struct req_msg_field RMF_SEQ_OPC;
MDT_PDO_LOCK = (1 << 1)
} mdl_type_t;
+/* memory structure for hsm attributes
+ * for fields description see the on disk structure hsm_attrs
+ * which is defined in lustre_idl.h
+ */
struct md_hsm {
__u32 mh_compat;
__u32 mh_flags;
#define IOEPOCH_INVAL 0
+/* memory structure for som attributes
+ * for fields description see the on disk structure som_attrs
+ * which is defined in lustre_idl.h
+ */
struct md_som_data {
__u32 msd_compat;
__u32 msd_incompat;
static int ll_lov_recreate_obj(struct inode *inode, unsigned long arg)
{
- struct ll_recreate_obj ucreat;
- ENTRY;
+ struct ll_recreate_obj ucreat;
+ ENTRY;
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
- RETURN(-EPERM);
+ if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ RETURN(-EPERM);
- if (cfs_copy_from_user(&ucreat, (struct ll_recreate_obj *)arg,
- sizeof(struct ll_recreate_obj)))
- RETURN(-EFAULT);
+ if (copy_from_user(&ucreat, (struct ll_recreate_obj *)arg,
+ sizeof(ucreat)))
+ RETURN(-EFAULT);
- RETURN(ll_lov_recreate(inode, ucreat.lrc_id, 0,
- ucreat.lrc_ost_idx));
+ RETURN(ll_lov_recreate(inode, ucreat.lrc_id, 0,
+ ucreat.lrc_ost_idx));
}
static int ll_lov_recreate_fid(struct inode *inode, unsigned long arg)
{
- struct lu_fid fid;
- obd_id id;
- obd_count ost_idx;
+ struct lu_fid fid;
+ obd_id id;
+ obd_count ost_idx;
ENTRY;
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
- RETURN(-EPERM);
+ if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ RETURN(-EPERM);
- if (cfs_copy_from_user(&fid, (struct lu_fid *)arg,
- sizeof(struct lu_fid)))
- RETURN(-EFAULT);
+ if (copy_from_user(&fid, (struct lu_fid *)arg, sizeof(fid)))
+ RETURN(-EFAULT);
- id = fid_oid(&fid) | ((fid_seq(&fid) & 0xffff) << 32);
- ost_idx = (fid_seq(&fid) >> 16) & 0xffff;
- RETURN(ll_lov_recreate(inode, id, 0, ost_idx));
+ id = fid_oid(&fid) | ((fid_seq(&fid) & 0xffff) << 32);
+ ost_idx = (fid_seq(&fid) >> 16) & 0xffff;
+ RETURN(ll_lov_recreate(inode, id, 0, ost_idx));
}
int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file,
static int ll_lov_setea(struct inode *inode, struct file *file,
unsigned long arg)
{
- int flags = MDS_OPEN_HAS_OBJS | FMODE_WRITE;
- struct lov_user_md *lump;
- int lum_size = sizeof(struct lov_user_md) +
- sizeof(struct lov_user_ost_data);
- int rc;
- ENTRY;
+ int flags = MDS_OPEN_HAS_OBJS | FMODE_WRITE;
+ struct lov_user_md *lump;
+ int lum_size = sizeof(struct lov_user_md) +
+ sizeof(struct lov_user_ost_data);
+ int rc;
+ ENTRY;
- if (!cfs_capable(CFS_CAP_SYS_ADMIN))
- RETURN(-EPERM);
+ if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ RETURN(-EPERM);
- OBD_ALLOC_LARGE(lump, lum_size);
- if (lump == NULL) {
+ OBD_ALLOC_LARGE(lump, lum_size);
+ if (lump == NULL)
RETURN(-ENOMEM);
- }
- if (cfs_copy_from_user(lump, (struct lov_user_md *)arg, lum_size)) {
- OBD_FREE_LARGE(lump, lum_size);
- RETURN(-EFAULT);
- }
- rc = ll_lov_setstripe_ea_info(inode, file, flags, lump, lum_size);
+ if (copy_from_user(lump, (struct lov_user_md *)arg, lum_size)) {
+ OBD_FREE_LARGE(lump, lum_size);
+ RETURN(-EFAULT);
+ }
+
+ rc = ll_lov_setstripe_ea_info(inode, file, flags, lump, lum_size);
- OBD_FREE_LARGE(lump, lum_size);
- RETURN(rc);
+ OBD_FREE_LARGE(lump, lum_size);
+ RETURN(rc);
}
static int ll_lov_setstripe(struct inode *inode, struct file *file,
- unsigned long arg)
-{
- struct lov_user_md_v3 lumv3;
- struct lov_user_md_v1 *lumv1 = (struct lov_user_md_v1 *)&lumv3;
- struct lov_user_md_v1 *lumv1p = (struct lov_user_md_v1 *)arg;
- struct lov_user_md_v3 *lumv3p = (struct lov_user_md_v3 *)arg;
- int lum_size;
- int rc;
- int flags = FMODE_WRITE;
- ENTRY;
+ unsigned long arg)
+{
+ struct lov_user_md_v3 lumv3;
+ struct lov_user_md_v1 *lumv1 = (struct lov_user_md_v1 *)&lumv3;
+ struct lov_user_md_v1 *lumv1p = (struct lov_user_md_v1 *)arg;
+ struct lov_user_md_v3 *lumv3p = (struct lov_user_md_v3 *)arg;
+ int lum_size, rc;
+ int flags = FMODE_WRITE;
+ ENTRY;
- /* first try with v1 which is smaller than v3 */
- lum_size = sizeof(struct lov_user_md_v1);
- if (cfs_copy_from_user(lumv1, lumv1p, lum_size))
- RETURN(-EFAULT);
+ /* first try with v1 which is smaller than v3 */
+ lum_size = sizeof(struct lov_user_md_v1);
+ if (copy_from_user(lumv1, lumv1p, lum_size))
+ RETURN(-EFAULT);
- if (lumv1->lmm_magic == LOV_USER_MAGIC_V3) {
- lum_size = sizeof(struct lov_user_md_v3);
- if (cfs_copy_from_user(&lumv3, lumv3p, lum_size))
- RETURN(-EFAULT);
- }
+ if (lumv1->lmm_magic == LOV_USER_MAGIC_V3) {
+ lum_size = sizeof(struct lov_user_md_v3);
+ if (copy_from_user(&lumv3, lumv3p, lum_size))
+ RETURN(-EFAULT);
+ }
- rc = ll_lov_setstripe_ea_info(inode, file, flags, lumv1, lum_size);
- if (rc == 0) {
+ rc = ll_lov_setstripe_ea_info(inode, file, flags, lumv1, lum_size);
+ if (rc == 0) {
struct lov_stripe_md *lsm;
__u32 gen;
int ll_fid2path(struct inode *inode, void *arg)
{
- struct obd_export *exp = ll_i2mdexp(inode);
- struct getinfo_fid2path *gfout, *gfin;
- int outsize, rc;
- ENTRY;
+ struct obd_export *exp = ll_i2mdexp(inode);
+ struct getinfo_fid2path *gfout, *gfin;
+ int outsize, rc;
+ ENTRY;
if (!cfs_capable(CFS_CAP_DAC_READ_SEARCH) &&
!(ll_i2sbi(inode)->ll_flags & LL_SBI_USER_FID2PATH))
RETURN(-EPERM);
- /* Need to get the buflen */
- OBD_ALLOC_PTR(gfin);
- if (gfin == NULL)
- RETURN(-ENOMEM);
- if (cfs_copy_from_user(gfin, arg, sizeof(*gfin))) {
- OBD_FREE_PTR(gfin);
- RETURN(-EFAULT);
- }
+ /* Need to get the buflen */
+ OBD_ALLOC_PTR(gfin);
+ if (gfin == NULL)
+ RETURN(-ENOMEM);
+ if (copy_from_user(gfin, arg, sizeof(*gfin))) {
+ OBD_FREE_PTR(gfin);
+ RETURN(-EFAULT);
+ }
- outsize = sizeof(*gfout) + gfin->gf_pathlen;
- OBD_ALLOC(gfout, outsize);
- if (gfout == NULL) {
- OBD_FREE_PTR(gfin);
- RETURN(-ENOMEM);
- }
- memcpy(gfout, gfin, sizeof(*gfout));
- OBD_FREE_PTR(gfin);
+ outsize = sizeof(*gfout) + gfin->gf_pathlen;
+ OBD_ALLOC(gfout, outsize);
+ if (gfout == NULL) {
+ OBD_FREE_PTR(gfin);
+ RETURN(-ENOMEM);
+ }
+ memcpy(gfout, gfin, sizeof(*gfout));
+ OBD_FREE_PTR(gfin);
- /* Call mdc_iocontrol */
- rc = obd_iocontrol(OBD_IOC_FID2PATH, exp, outsize, gfout, NULL);
- if (rc)
- GOTO(gf_free, rc);
- if (cfs_copy_to_user(arg, gfout, outsize))
- rc = -EFAULT;
+ /* Call mdc_iocontrol */
+ rc = obd_iocontrol(OBD_IOC_FID2PATH, exp, outsize, gfout, NULL);
+ if (rc)
+ GOTO(gf_free, rc);
+ if (copy_to_user(arg, gfout, outsize))
+ rc = -EFAULT;
gf_free:
- OBD_FREE(gfout, outsize);
- RETURN(rc);
+ OBD_FREE(gfout, outsize);
+ RETURN(rc);
}
static int ll_ioctl_fiemap(struct inode *inode, unsigned long arg)
if (fiemap_s == NULL)
RETURN(-ENOMEM);
- /* get the fiemap value */
- if (copy_from_user(fiemap_s,(struct ll_user_fiemap __user *)arg,
- sizeof(*fiemap_s)))
- GOTO(error, rc = -EFAULT);
+ /* get the fiemap value */
+ if (copy_from_user(fiemap_s, (struct ll_user_fiemap __user *)arg,
+ sizeof(*fiemap_s)))
+ GOTO(error, rc = -EFAULT);
/* If fm_extent_count is non-zero, read the first extent since
* it is used to calculate end_offset and device from previous
ret_bytes += (fiemap_s->fm_mapped_extents *
sizeof(struct ll_fiemap_extent));
- if (copy_to_user((void *)arg, fiemap_s, ret_bytes))
- rc = -EFAULT;
+ if (copy_to_user((void *)arg, fiemap_s, ret_bytes))
+ rc = -EFAULT;
error:
OBD_FREE_LARGE(fiemap_s, num_bytes);
case FSFILT_IOC_SETVERSION_OLD:
case FSFILT_IOC_SETVERSION:
*/
- case LL_IOC_FLUSHCTX:
- RETURN(ll_flush_ctx(inode));
- case LL_IOC_PATH2FID: {
- if (cfs_copy_to_user((void *)arg, ll_inode2fid(inode),
- sizeof(struct lu_fid)))
- RETURN(-EFAULT);
+ case LL_IOC_FLUSHCTX:
+ RETURN(ll_flush_ctx(inode));
+ case LL_IOC_PATH2FID: {
+ if (copy_to_user((void *)arg, ll_inode2fid(inode),
+ sizeof(struct lu_fid)))
+ RETURN(-EFAULT);
- RETURN(0);
- }
- case OBD_IOC_FID2PATH:
+ RETURN(0);
+ }
+ case OBD_IOC_FID2PATH:
RETURN(ll_fid2path(inode, (void *)arg));
- case LL_IOC_DATA_VERSION: {
- struct ioc_data_version idv;
- int rc;
+ case LL_IOC_DATA_VERSION: {
+ struct ioc_data_version idv;
+ int rc;
- if (cfs_copy_from_user(&idv, (char *)arg, sizeof(idv)))
- RETURN(-EFAULT);
+ if (copy_from_user(&idv, (char *)arg, sizeof(idv)))
+ RETURN(-EFAULT);
- rc = ll_data_version(inode, &idv.idv_version,
- !(idv.idv_flags & LL_DV_NOFLUSH));
+ rc = ll_data_version(inode, &idv.idv_version,
+ !(idv.idv_flags & LL_DV_NOFLUSH));
- if (rc == 0 &&
- cfs_copy_to_user((char *) arg, &idv, sizeof(idv)))
- RETURN(-EFAULT);
+ if (rc == 0 && copy_to_user((char *) arg, &idv, sizeof(idv)))
+ RETURN(-EFAULT);
- RETURN(rc);
- }
+ RETURN(rc);
+ }
case LL_IOC_GET_MDTIDX: {
int mdtidx;
RETURN(0);
}
- case OBD_IOC_GETDTNAME:
- case OBD_IOC_GETMDNAME:
- RETURN(ll_get_obd_name(inode, cmd, arg));
- default: {
- int err;
-
- if (LLIOC_STOP ==
- ll_iocontrol_call(inode, file, cmd, arg, &err))
- RETURN(err);
-
- RETURN(obd_iocontrol(cmd, ll_i2dtexp(inode), 0, NULL,
- (void *)arg));
- }
- }
+ case OBD_IOC_GETDTNAME:
+ case OBD_IOC_GETMDNAME:
+ RETURN(ll_get_obd_name(inode, cmd, arg));
+ case LL_IOC_HSM_STATE_GET: {
+ struct md_op_data *op_data;
+ struct hsm_user_state *hus;
+ int rc;
+
+ OBD_ALLOC_PTR(hus);
+ if (hus == NULL)
+ RETURN(-ENOMEM);
+
+ op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
+ LUSTRE_OPC_ANY, hus);
+ if (op_data == NULL) {
+ OBD_FREE_PTR(hus);
+ RETURN(-ENOMEM);
+ }
+
+ rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
+ op_data, NULL);
+
+ if (copy_to_user((void *)arg, hus, sizeof(*hus)))
+ rc = -EFAULT;
+
+ ll_finish_md_op_data(op_data);
+ OBD_FREE_PTR(hus);
+ RETURN(rc);
+ }
+ case LL_IOC_HSM_STATE_SET: {
+ struct md_op_data *op_data;
+ struct hsm_state_set *hss;
+ int rc;
+
+ OBD_ALLOC_PTR(hss);
+ if (hss == NULL)
+ RETURN(-ENOMEM);
+ if (copy_from_user(hss, (char *)arg, sizeof(*hss))) {
+ OBD_FREE_PTR(hss);
+ RETURN(-EFAULT);
+ }
+
+ /* Non-root users are forbidden to set or clear flags which are
+ * NOT defined in HSM_USER_MASK. */
+ if (((hss->hss_setmask | hss->hss_clearmask) & ~HSM_USER_MASK)
+ && !cfs_capable(CFS_CAP_SYS_ADMIN)) {
+ OBD_FREE_PTR(hss);
+ RETURN(-EPERM);
+ }
+
+ op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
+ LUSTRE_OPC_ANY, hss);
+ if (op_data == NULL) {
+ OBD_FREE_PTR(hss);
+ RETURN(-ENOMEM);
+ }
+
+ rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
+ op_data, NULL);
+
+ ll_finish_md_op_data(op_data);
+
+ OBD_FREE_PTR(hss);
+ RETURN(rc);
+ }
+
+ default: {
+ int err;
+
+ if (LLIOC_STOP ==
+ ll_iocontrol_call(inode, file, cmd, arg, &err))
+ RETURN(err);
+
+ RETURN(obd_iocontrol(cmd, ll_i2dtexp(inode), 0, NULL,
+ (void *)arg));
+ }
+ }
}
#ifndef HAVE_FILE_LLSEEK_SIZE
rc = obd_iocontrol(cmd, tgt->ltd_exp, len, karg, uarg);
break;
}
+ case LL_IOC_HSM_STATE_GET:
+ case LL_IOC_HSM_STATE_SET: {
+ struct md_op_data *op_data = karg;
+ struct lmv_tgt_desc *tgt;
+
+ tgt = lmv_find_target(lmv, &op_data->op_fid1);
+ if (!tgt->ltd_exp)
+ RETURN(-EINVAL);
+
+ rc = obd_iocontrol(cmd, lmv->tgts[0]->ltd_exp, len, karg, uarg);
+ break;
+ }
default:
for (i = 0; i < count; i++) {
struct obd_device *mdc_obd;
return rc;
}
+static int mdc_ioc_hsm_state_get(struct obd_export *exp,
+ struct md_op_data *op_data)
+{
+ struct hsm_user_state *hus = op_data->op_data;
+ struct obd_import *imp = class_exp2cliimp(exp);
+ struct hsm_user_state *req_hus;
+ struct ptlrpc_request *req;
+ int rc;
+ ENTRY;
+
+ req = ptlrpc_request_alloc(class_exp2cliimp(exp),
+ &RQF_MDS_HSM_STATE_GET);
+ if (req == NULL)
+ RETURN(-ENOMEM);
+
+ mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
+
+ rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_HSM_STATE_GET);
+ if (rc != 0) {
+ ptlrpc_request_free(req);
+ RETURN(rc);
+ }
+
+ mdc_pack_body(req, &op_data->op_fid1, op_data->op_capa1,
+ OBD_MD_FLRMTPERM, 0, op_data->op_suppgids[0], 0);
+
+ ptlrpc_request_set_replen(req);
+
+ rc = ptlrpc_queue_wait(req);
+ if (rc) {
+ /* check connection error first */
+ if (imp->imp_connect_error)
+ rc = imp->imp_connect_error;
+ GOTO(out, rc);
+ }
+
+ req_hus = req_capsule_server_get(&req->rq_pill, &RMF_HSM_USER_STATE);
+ if (req_hus == NULL)
+ GOTO(out, rc = -EPROTO);
+
+ *hus = *req_hus;
+
+ EXIT;
+out:
+ ptlrpc_req_finished(req);
+ return rc;
+}
+
+static int mdc_ioc_hsm_state_set(struct obd_export *exp,
+ struct md_op_data *op_data)
+{
+ struct hsm_state_set *hss = op_data->op_data;
+ struct obd_import *imp = class_exp2cliimp(exp);
+ struct hsm_state_set *req_hss;
+ struct ptlrpc_request *req;
+ int rc;
+ ENTRY;
+
+ req = ptlrpc_request_alloc(class_exp2cliimp(exp),
+ &RQF_MDS_HSM_STATE_SET);
+ if (req == NULL)
+ RETURN(-ENOMEM);
+
+ mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
+
+ rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_HSM_STATE_SET);
+ if (rc) {
+ ptlrpc_request_free(req);
+ RETURN(rc);
+ }
+
+ mdc_pack_body(req, &op_data->op_fid1, op_data->op_capa1,
+ OBD_MD_FLRMTPERM, 0, op_data->op_suppgids[0], 0);
+
+ /* Copy states */
+ req_hss = req_capsule_client_get(&req->rq_pill, &RMF_HSM_STATE_SET);
+ LASSERT(req_hss);
+ *req_hss = *hss;
+
+ ptlrpc_request_set_replen(req);
+
+ rc = ptlrpc_queue_wait(req);
+ if (rc) {
+ /* check connection error first */
+ if (imp->imp_connect_error)
+ rc = imp->imp_connect_error;
+ GOTO(out, rc);
+ }
+
+ EXIT;
+out:
+ ptlrpc_req_finished(req);
+ return rc;
+}
+
+
static struct kuc_hdr *changelog_kuc_hdr(char *buf, int len, int flags)
{
struct kuc_hdr *lh = (struct kuc_hdr *)buf;
case LL_IOC_HSM_PROGRESS:
rc = mdc_ioc_hsm_progress(exp, karg);
GOTO(out, rc);
+ case LL_IOC_HSM_STATE_GET:
+ rc = mdc_ioc_hsm_state_get(exp, karg);
+ GOTO(out, rc);
+ case LL_IOC_HSM_STATE_SET:
+ rc = mdc_ioc_hsm_state_set(exp, karg);
+ GOTO(out, rc);
case OBD_IOC_CLIENT_RECOVER:
rc = ptlrpc_recover_import(imp, data->ioc_inlbuf1, 0);
if (rc < 0)
} else {
ma->ma_lmm = buffer->lb_buf;
ma->ma_lmm_size = buffer->lb_len;
- ma->ma_need = MA_LOV | MA_INODE;
+ ma->ma_need = MA_LOV | MA_INODE | MA_HSM;
}
if (S_ISDIR(lu_object_attr(&next->mo_lu)) &&
case MDS_HSM_REQUEST:
case MDS_HSM_CT_REGISTER:
case MDS_HSM_CT_UNREGISTER:
+ case MDS_HSM_STATE_GET:
+ case MDS_HSM_STATE_SET:
case MDS_QUOTACHECK:
case MDS_QUOTACTL:
case QUOTA_DQACQ:
RETURN(rc);
}
+
+
+/**
+ * Retrieve the current HSM flags, archive id and undergoing HSM requests for
+ * the fid provided in RPC body.
+ *
+ * Current requests are read from coordinator states.
+ *
+ * This is MDS_HSM_STATE_GET RPC handler.
+ */
+int mdt_hsm_state_get(struct mdt_thread_info *info)
+{
+ struct mdt_object *obj = info->mti_object;
+ struct md_attr *ma = &info->mti_attr;
+ struct hsm_user_state *hus;
+ struct mdt_lock_handle *lh;
+ int rc;
+ ENTRY;
+
+ lh = &info->mti_lh[MDT_LH_CHILD];
+ mdt_lock_reg_init(lh, LCK_PR);
+ rc = mdt_object_lock(info, obj, lh, MDS_INODELOCK_LOOKUP,
+ MDT_LOCAL_LOCK);
+ if (rc)
+ RETURN(rc);
+
+ /* Only valid if client is remote */
+ rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
+ if (rc)
+ GOTO(out_unlock, rc = err_serious(rc));
+
+ ma->ma_valid = 0;
+ ma->ma_need = MA_HSM;
+ rc = mdt_attr_get_complex(info, obj, ma);
+ if (rc)
+ GOTO(out_ucred, rc);
+
+ if (req_capsule_get_size(info->mti_pill, &RMF_CAPA1, RCL_CLIENT))
+ mdt_set_capainfo(info, 0, &info->mti_body->fid1,
+ req_capsule_client_get(info->mti_pill, &RMF_CAPA1));
+
+ hus = req_capsule_server_get(info->mti_pill, &RMF_HSM_USER_STATE);
+ LASSERT(hus);
+
+ /* Current HSM flags */
+ hus->hus_states = ma->ma_hsm.mh_flags;
+ hus->hus_archive_id = ma->ma_hsm.mh_arch_id;
+
+ EXIT;
+out_ucred:
+ mdt_exit_ucred(info);
+out_unlock:
+ mdt_object_unlock(info, obj, lh, 1);
+ return rc;
+}
+
+/**
+ * Change HSM state and archive number of a file.
+ *
+ * Archive number is changed iif the value is not 0.
+ * The new flagset that will be computed should result in a coherent state.
+ * This function checks that are flags are compatible.
+ *
+ * This is MDS_HSM_STATE_SET RPC handler.
+ */
+int mdt_hsm_state_set(struct mdt_thread_info *info)
+{
+ struct mdt_object *obj = info->mti_object;
+ struct md_attr *ma = &info->mti_attr;
+ struct hsm_state_set *hss;
+ struct mdt_lock_handle *lh;
+ int rc;
+ __u64 flags;
+ ENTRY;
+
+ lh = &info->mti_lh[MDT_LH_CHILD];
+ mdt_lock_reg_init(lh, LCK_PW);
+ rc = mdt_object_lock(info, obj, lh, MDS_INODELOCK_LOOKUP,
+ MDT_LOCAL_LOCK);
+ if (rc)
+ RETURN(rc);
+
+ /* Only valid if client is remote */
+ rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
+ if (rc)
+ GOTO(out_obj, rc = err_serious(rc));
+
+ /* Read current HSM info */
+ ma->ma_valid = 0;
+ ma->ma_need = MA_HSM;
+ rc = mdt_attr_get_complex(info, obj, ma);
+ if (rc)
+ GOTO(out_ucred, rc);
+
+ hss = req_capsule_client_get(info->mti_pill, &RMF_HSM_STATE_SET);
+ LASSERT(hss);
+
+ if (req_capsule_get_size(info->mti_pill, &RMF_CAPA1, RCL_CLIENT))
+ mdt_set_capainfo(info, 0, &info->mti_body->fid1,
+ req_capsule_client_get(info->mti_pill, &RMF_CAPA1));
+
+ /* Change HSM flags depending on provided masks */
+ if (hss->hss_valid & HSS_SETMASK)
+ ma->ma_hsm.mh_flags |= hss->hss_setmask;
+ if (hss->hss_valid & HSS_CLEARMASK)
+ ma->ma_hsm.mh_flags &= ~hss->hss_clearmask;
+
+ /* Change archive_id if provided. */
+ if (hss->hss_valid & HSS_ARCHIVE_ID) {
+ if (!(ma->ma_hsm.mh_flags & HS_EXISTS)) {
+ CDEBUG(D_HSM, "Could not set an archive number for "
+ DFID "if HSM EXISTS flag is not set.\n",
+ PFID(&info->mti_body->fid1));
+ GOTO(out_ucred, rc);
+ }
+ ma->ma_hsm.mh_arch_id = hss->hss_archive_id;
+ }
+
+ /* Check for inconsistant HSM flagset.
+ * DIRTY without EXISTS: no dirty if no archive was created.
+ * DIRTY and RELEASED: a dirty file could not be released.
+ * RELEASED without ARCHIVED: do not release a non-archived file.
+ * LOST without ARCHIVED: cannot lost a non-archived file.
+ */
+ flags = ma->ma_hsm.mh_flags;
+ if (((flags & HS_DIRTY) && !(flags & HS_EXISTS)) ||
+ ((flags & HS_RELEASED) && (flags & HS_DIRTY)) ||
+ ((flags & HS_RELEASED) && !(flags & HS_ARCHIVED)) ||
+ ((flags & HS_LOST) && !(flags & HS_ARCHIVED))) {
+ CDEBUG(D_HSM, "Incompatible flag change on "DFID
+ "flags="LPX64"\n",
+ PFID(&info->mti_body->fid1), flags);
+ GOTO(out_ucred, rc = -EINVAL);
+ }
+
+ /* Save the modified flags */
+ rc = mdt_hsm_attr_set(info, obj, &ma->ma_hsm);
+ if (rc)
+ GOTO(out_ucred, rc);
+
+ EXIT;
+
+out_ucred:
+ mdt_exit_ucred(info);
+out_obj:
+ mdt_object_unlock(info, obj, lh, 1);
+ return rc;
+}
int mdt_hsm_ct_register(struct mdt_thread_info *info);
int mdt_hsm_ct_unregister(struct mdt_thread_info *info);
+/* mdt/mdt_hsm.c */
+int mdt_hsm_state_get(struct mdt_thread_info *info);
+int mdt_hsm_state_set(struct mdt_thread_info *info);
+
extern struct lu_context_key mdt_thread_key;
/* debug issues helper starts here*/
static inline int mdt_fail_write(const struct lu_env *env,
mdt_hsm_ct_register),
DEF_MDT_HDL(0 | HABEO_REFERO, MDS_HSM_CT_UNREGISTER,
mdt_hsm_ct_unregister),
+DEF_MDT_HDL(HABEO_CORPUS| HABEO_REFERO, MDS_HSM_STATE_GET,
+ mdt_hsm_state_get),
+DEF_MDT_HDL(HABEO_CORPUS| HABEO_REFERO, MDS_HSM_STATE_SET,
+ mdt_hsm_state_set),
};
#define DEF_OBD_HDL(flags, name, fn) \
repbody->ioepoch = o->mot_ioepoch;
}
} else if (flags & MDS_FMODE_EXEC) {
- rc = mdt_write_deny(o);
+ /* if file is released, we can't deny write because we must
+ * restore (write) it to access it.*/
+ if ((ma->ma_valid & MA_HSM) &&
+ (ma->ma_hsm.mh_flags & HS_RELEASED))
+ rc = 0;
+ else
+ rc = mdt_write_deny(o);
}
if (rc)
RETURN(rc);
ma->ma_lmm = req_capsule_server_get(pill, &RMF_MDT_MD);
ma->ma_lmm_size = req_capsule_get_size(pill, &RMF_MDT_MD,
RCL_SERVER);
- ma->ma_need = MA_INODE;
+ ma->ma_need = MA_INODE | MA_HSM;
if (ma->ma_lmm_size > 0)
ma->ma_need |= MA_LOV;
struct mdt_lock_handle *lhc,
__u64 *ibits)
{
- struct md_attr *ma = &info->mti_attr;
- __u64 open_flags = info->mti_spec.sp_cr_flags;
- ldlm_mode_t lm = LCK_CR;
- bool try_layout = false;
- bool create_layout = false;
- int rc = 0;
+ struct md_attr *ma = &info->mti_attr;
+ __u64 open_flags = info->mti_spec.sp_cr_flags;
+ ldlm_mode_t lm = LCK_CR;
+ bool try_layout = false;
+ bool create_layout = false;
+ int rc = 0;
ENTRY;
*ibits = 0;
if (open_flags & MDS_OPEN_LOCK) {
if (open_flags & FMODE_WRITE)
lm = LCK_CW;
- else if (open_flags & MDS_FMODE_EXEC)
+ /* if file is released, we can't deny write because we must
+ * restore (write) it to access it. */
+ else if ((open_flags & MDS_FMODE_EXEC) &&
+ !((ma->ma_valid & MA_HSM) &&
+ (ma->ma_hsm.mh_flags & HS_RELEASED)))
lm = LCK_PR;
else
lm = LCK_CR;
}
created = 1;
} else {
- /* We have to get attr & lov ea for this object */
+ /* We have to get attr & LOV EA, HSM bits for this object */
+ ma->ma_need |= MA_HSM;
result = mdt_attr_get_complex(info, child, ma);
/*
* The object is on remote node, return its FID for remote open.
&RMF_MDS_HSM_ARCHIVE,
};
+static const struct req_msg_field *mdt_hsm_state_get_server[] = {
+ &RMF_PTLRPC_BODY,
+ &RMF_HSM_USER_STATE,
+};
+
+static const struct req_msg_field *mdt_hsm_state_set[] = {
+ &RMF_PTLRPC_BODY,
+ &RMF_MDT_BODY,
+ &RMF_CAPA1,
+ &RMF_HSM_STATE_SET,
+};
+
static struct req_format *req_formats[] = {
&RQF_OBD_PING,
&RQF_OBD_SET_INFO,
&RQF_MDS_HSM_PROGRESS,
&RQF_MDS_HSM_CT_REGISTER,
&RQF_MDS_HSM_CT_UNREGISTER,
+ &RQF_MDS_HSM_STATE_GET,
+ &RQF_MDS_HSM_STATE_SET,
&RQF_QC_CALLBACK,
&RQF_OST_CONNECT,
&RQF_OST_DISCONNECT,
DEFINE_MSGF("idx_info", 0, sizeof(struct idx_info),
lustre_swab_idx_info, NULL);
EXPORT_SYMBOL(RMF_IDX_INFO);
+struct req_msg_field RMF_HSM_USER_STATE =
+ DEFINE_MSGF("hsm_user_state", 0, sizeof(struct hsm_user_state),
+ lustre_swab_hsm_user_state, NULL);
+EXPORT_SYMBOL(RMF_HSM_USER_STATE);
+
+struct req_msg_field RMF_HSM_STATE_SET =
+ DEFINE_MSGF("hsm_state_set", 0, sizeof(struct hsm_state_set),
+ lustre_swab_hsm_state_set, NULL);
+EXPORT_SYMBOL(RMF_HSM_STATE_SET);
struct req_msg_field RMF_MDS_HSM_PROGRESS =
DEFINE_MSGF("hsm_progress", 0, sizeof(struct hsm_progress_kernel),
DEFINE_REQ_FMT0("MDS_HSM_CT_UNREGISTER", empty, empty);
EXPORT_SYMBOL(RQF_MDS_HSM_CT_UNREGISTER);
+struct req_format RQF_MDS_HSM_STATE_GET =
+ DEFINE_REQ_FMT0("MDS_HSM_STATE_GET",
+ mdt_body_capa, mdt_hsm_state_get_server);
+EXPORT_SYMBOL(RQF_MDS_HSM_STATE_GET);
+
+struct req_format RQF_MDS_HSM_STATE_SET =
+ DEFINE_REQ_FMT0("MDS_HSM_STATE_SET", mdt_hsm_state_set, empty);
+EXPORT_SYMBOL(RQF_MDS_HSM_STATE_SET);
+
/* This is for split */
struct req_format RQF_MDS_WRITEPAGE =
DEFINE_REQ_FMT0("MDS_WRITEPAGE",
}
EXPORT_SYMBOL(lustre_swab_lustre_capa_key);
-void lustre_swab_hsm_state(struct hsm_state_set_ioc *hssi)
+void lustre_swab_hsm_user_state(struct hsm_user_state *state)
{
- lustre_swab_lu_fid(&hssi->hssi_fid);
- __swab64s(&hssi->hssi_setmask);
- __swab64s(&hssi->hssi_clearmask);
+ __swab32s(&state->hus_states);
+ __swab32s(&state->hus_archive_id);
}
-EXPORT_SYMBOL(lustre_swab_hsm_state);
+EXPORT_SYMBOL(lustre_swab_hsm_user_state);
+
+void lustre_swab_hsm_state_set(struct hsm_state_set *hss)
+{
+ __swab32s(&hss->hss_valid);
+ __swab64s(&hss->hss_setmask);
+ __swab64s(&hss->hss_clearmask);
+ __swab32s(&hss->hss_archive_id);
+}
+EXPORT_SYMBOL(lustre_swab_hsm_state_set);
void lustre_swab_hsm_extent(struct hsm_extent *extent)
{
(long long)(int)offsetof(struct hsm_user_state, hus_states));
LASSERTF((int)sizeof(((struct hsm_user_state *)0)->hus_states) == 4, "found %lld\n",
(long long)(int)sizeof(((struct hsm_user_state *)0)->hus_states));
- LASSERTF((int)offsetof(struct hsm_user_state, hus_archive_num) == 4, "found %lld\n",
- (long long)(int)offsetof(struct hsm_user_state, hus_archive_num));
- LASSERTF((int)sizeof(((struct hsm_user_state *)0)->hus_archive_num) == 4, "found %lld\n",
- (long long)(int)sizeof(((struct hsm_user_state *)0)->hus_archive_num));
+ LASSERTF((int)offsetof(struct hsm_user_state, hus_archive_id) == 4, "found %lld\n",
+ (long long)(int)offsetof(struct hsm_user_state, hus_archive_id));
+ LASSERTF((int)sizeof(((struct hsm_user_state *)0)->hus_archive_id) == 4, "found %lld\n",
+ (long long)(int)sizeof(((struct hsm_user_state *)0)->hus_archive_id));
LASSERTF((int)offsetof(struct hsm_user_state, hus_in_progress_state) == 8, "found %lld\n",
(long long)(int)offsetof(struct hsm_user_state, hus_in_progress_state));
LASSERTF((int)sizeof(((struct hsm_user_state *)0)->hus_in_progress_state) == 4, "found %lld\n",
(long long)(int)offsetof(struct hsm_user_state, hus_in_progress_location));
LASSERTF((int)sizeof(((struct hsm_user_state *)0)->hus_in_progress_location) == 16, "found %lld\n",
(long long)(int)sizeof(((struct hsm_user_state *)0)->hus_in_progress_location));
+
+ /* Checks for struct hsm_state_set */
+ LASSERTF((int)sizeof(struct hsm_state_set) == 24, "found %lld\n",
+ (long long)(int)sizeof(struct hsm_state_set));
+ LASSERTF((int)offsetof(struct hsm_state_set, hss_valid) == 0, "found %lld\n",
+ (long long)(int)offsetof(struct hsm_state_set, hss_valid));
+ LASSERTF((int)sizeof(((struct hsm_state_set *)0)->hss_valid) == 4, "found %lld\n",
+ (long long)(int)sizeof(((struct hsm_state_set *)0)->hss_valid));
+ LASSERTF((int)offsetof(struct hsm_state_set, hss_archive_id) == 4, "found %lld\n",
+ (long long)(int)offsetof(struct hsm_state_set, hss_archive_id));
+ LASSERTF((int)sizeof(((struct hsm_state_set *)0)->hss_archive_id) == 4, "found %lld\n",
+ (long long)(int)sizeof(((struct hsm_state_set *)0)->hss_archive_id));
+ LASSERTF((int)offsetof(struct hsm_state_set, hss_setmask) == 8, "found %lld\n",
+ (long long)(int)offsetof(struct hsm_state_set, hss_setmask));
+ LASSERTF((int)sizeof(((struct hsm_state_set *)0)->hss_setmask) == 8, "found %lld\n",
+ (long long)(int)sizeof(((struct hsm_state_set *)0)->hss_setmask));
+ LASSERTF((int)offsetof(struct hsm_state_set, hss_clearmask) == 16, "found %lld\n",
+ (long long)(int)offsetof(struct hsm_state_set, hss_clearmask));
+ LASSERTF((int)sizeof(((struct hsm_state_set *)0)->hss_clearmask) == 8, "found %lld\n",
+ (long long)(int)sizeof(((struct hsm_state_set *)0)->hss_clearmask));
}
noinst_SCRIPTS += posix.sh sanity-scrub.sh scrub-performance.sh ha.sh
noinst_SCRIPTS += sanity-quota-old.sh
noinst_SCRIPTS += resolveip
+noinst_SCRIPTS += sanity-hsm.sh
nobase_noinst_SCRIPTS = cfg/local.sh
nobase_noinst_SCRIPTS += test-groups/regression test-groups/regression-mpi
nobase_noinst_SCRIPTS += acl/make-tree acl/run cfg/ncli.sh
--- /dev/null
+#!/bin/bash
+#
+# Run select tests by setting ONLY, or as arguments to the script.
+# Skip specific tests by setting EXCEPT.
+#
+# Run test by setting NOSETUP=true when ltest has setup env for us
+#
+# exit on error
+set -e
+set +o monitor
+
+SRCDIR=`dirname $0`
+export PATH=$PWD/$SRCDIR:$SRCDIR:$PWD/$SRCDIR/utils:$PATH:/sbin
+
+ONLY=${ONLY:-"$*"}
+SANITY_HSM_EXCEPT=${SANITY_HSM_EXCEPT:-""}
+ALWAYS_EXCEPT="$SANITY_HSM_EXCEPT"
+# bug number for skipped test:
+# UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT!
+
+[ "$ALWAYS_EXCEPT$EXCEPT" ] &&
+ echo "Skipping tests: `echo $ALWAYS_EXCEPT $EXCEPT`"
+
+TMP=${TMP:-/tmp}
+
+ORIG_PWD=${PWD}
+
+LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)}
+. $LUSTRE/tests/test-framework.sh
+init_test_env $@
+. ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh}
+init_logging
+
+
+SANITYLOG=${TESTSUITELOG:-$TMP/$(basename $0 .sh).log}
+FAIL_ON_ERROR=false
+
+[ "$SANITYLOG" ] && rm -f $SANITYLOG || true
+check_and_setup_lustre
+
+DIR=${DIR:-$MOUNT}
+assert_DIR
+
+build_test_filter
+
+
+test_1() {
+ mkdir -p $DIR/$tdir
+ chmod 777 $DIR/$tdir
+
+ TESTFILE=$DIR/$tdir/file
+ $RUNAS touch $TESTFILE
+
+ # User flags
+ $RUNAS $LFS hsm_state $TESTFILE | grep -q "(0x00000000)" ||
+ error "wrong initial hsm state"
+ $RUNAS $LFS hsm_set --norelease $TESTFILE ||
+ error "user could not change hsm flags"
+ $RUNAS $LFS hsm_state $TESTFILE | grep -q "(0x00000010)" ||
+ error "wrong hsm state, should be: --norelease"
+ $RUNAS $LFS hsm_clear --norelease $TESTFILE ||
+ error "user could not clear hsm flags"
+ $RUNAS $LFS hsm_state $TESTFILE | grep -q "(0x00000000)" ||
+ error "wrong hsm state, should be empty"
+
+ # User could not change those flags...
+ $RUNAS $LFS hsm_set --exists $TESTFILE &&
+ error "user should not set this flag"
+ $RUNAS $LFS hsm_state $TESTFILE | grep -q "(0x00000000)" ||
+ error "wrong hsm state, should be empty"
+
+ # ...but root can
+ $LFS hsm_set --exists $TESTFILE ||
+ error "root could not change hsm flags"
+ $LFS hsm_state $TESTFILE | grep -q "(0x00000001)" ||
+ error "wrong hsm state, should be: --exists"
+ $LFS hsm_clear --exists $TESTFILE ||
+ error "root could not clear hsm state"
+ $LFS hsm_state $TESTFILE | grep -q "(0x00000000)" ||
+ error "wrong hsm state, should be empty"
+
+}
+run_test 1 "lfs hsm flags root/non-root access"
+
+test_2() {
+ mkdir -p $DIR/$tdir
+ TESTFILE=$DIR/$tdir/file
+ touch $TESTFILE
+
+ # New files are not dirty
+ $LFS hsm_state $TESTFILE | grep -q " (0x00000000)" ||
+ error "wrong hsm state: !0x0"
+
+ # For test, we simulate an archived file.
+ $LFS hsm_set --exists $TESTFILE || error "user could not change hsm flags"
+ $LFS hsm_state $TESTFILE | grep -q " (0x00000001)" ||
+ error "wrong hsm state: !0x1"
+
+ # chmod do not put the file dirty
+ chmod 600 $TESTFILE || error "could not chmod test file"
+ $LFS hsm_state $TESTFILE | grep -q " (0x00000001)" ||
+ error "wrong hsm state: !0x1"
+
+ # chown do not put the file dirty
+ chown $RUNAS_ID $TESTFILE || error "could not chown test file"
+ $LFS hsm_state $TESTFILE | grep -q " (0x00000001)" ||
+ error "wrong hsm state: !0x1"
+
+ # truncate put the file dirty
+ ./truncate $TESTFILE 1 || error "could not truncate test file"
+ $LFS hsm_state $TESTFILE | grep -q " (0x00000003)" ||
+ error "wrong hsm state: !0x3"
+ $LFS hsm_clear --dirty $TESTFILE || error "could not clear hsm flags"
+ $LFS hsm_state $TESTFILE | grep -q " (0x00000001)" ||
+ error "wrong hsm state: !0x1"
+}
+run_test 2 "Check file dirtyness when doing setattr"
+
+test_3() {
+ mkdir -p $DIR/$tdir
+ TESTFILE=$DIR/$tdir/file
+
+ # New files are not dirty
+ cp -p /etc/passwd $TESTFILE
+ $LFS hsm_state $TESTFILE | grep -q " (0x00000000)" ||
+ error "wrong hsm state: !0x0"
+
+ # For test, we simulate an archived file.
+ $LFS hsm_set --exists $TESTFILE ||
+ error "user could not change hsm flags"
+ $LFS hsm_state $TESTFILE | grep -q " (0x00000001)" ||
+ error "wrong hsm state: !0x1"
+
+ # Reading a file, does not set dirty
+ cat $TESTFILE > /dev/null || error "could not read file"
+ $LFS hsm_state $TESTFILE | grep -q " (0x00000001)" ||
+ error "wrong hsm state: !0x1"
+
+ # Open for write without modifying data, does not set dirty
+ openfile -f O_WRONLY $TESTFILE || error "could not open test file"
+ $LFS hsm_state $TESTFILE | grep -q " (0x00000001)" ||
+ error "wrong hsm state: !0x1"
+
+ # Append to a file sets it dirty
+ cp -p /etc/passwd $TESTFILE.append || error "could not create file"
+ $LFS hsm_set --exists $TESTFILE.append ||
+ error "user could not change hsm flags"
+ dd if=/etc/passwd of=$TESTFILE.append bs=1 count=3 \
+ conv=notrunc,fdatasync oflag=append status=noxfer ||
+ error "could not append to test file"
+ $LFS hsm_state $TESTFILE.append | grep -q " (0x00000003)" ||
+ error "wrong hsm state: !0x3"
+
+ # Modify a file sets it dirty
+ cp -p /etc/passwd $TESTFILE.modify || error "could not create file"
+ $LFS hsm_set --exists $TESTFILE.modify ||
+ error "user could not change hsm flags"
+ dd if=/dev/zero of=$TESTFILE.modify bs=1 count=3 \
+ conv=notrunc,fdatasync status=noxfer ||
+ error "could not modify test file"
+ $LFS hsm_state $TESTFILE.modify | grep -q " (0x00000003)" ||
+ error "wrong hsm state: !0x3"
+
+ # Open O_TRUNC sets dirty
+ cp -p /etc/passwd $TESTFILE.trunc || error "could not create file"
+ $LFS hsm_set --exists $TESTFILE.trunc ||
+ error "user could not change hsm flags"
+ cp /etc/group $TESTFILE.trunc || error "could not override a file"
+ $LFS hsm_state $TESTFILE.trunc | grep -q " (0x00000003)" ||
+ error "wrong hsm state: !0x3"
+
+ # Mmapped a file sets dirty
+ cp -p /etc/passwd $TESTFILE.mmap || error "could not create file"
+ $LFS hsm_set --exists $TESTFILE.mmap ||
+ error "user could not change hsm flags"
+ multiop $TESTFILE.mmap OSMWUc || error "could not mmap a file"
+ $LFS hsm_state $TESTFILE.mmap | grep -q " (0x00000003)" ||
+ error "wrong hsm state: !0x3"
+}
+run_test 3 "Check file dirtyness when opening for write"
+
+
+log "cleanup: ======================================================"
+cd $ORIG_PWD
+check_and_cleanup_lustre
+echo '=========================== finished ==============================='
+[ -f "$SANITYLOG" ] && cat $SANITYLOG && grep -q FAIL $SANITYLOG && exit 1 ||
+ true
+echo "$0: completed"
+
sgpdd-survey
sanity-scrub
lfsck
+sanity-hsm
static int lfs_fid2path(int argc, char **argv);
static int lfs_path2fid(int argc, char **argv);
static int lfs_data_version(int argc, char **argv);
+static int lfs_hsm_state(int argc, char **argv);
+static int lfs_hsm_set(int argc, char **argv);
+static int lfs_hsm_clear(int argc, char **argv);
/* all avaialable commands */
command_t cmdlist[] = {
"usage: path2fid <path>"},
{"data_version", lfs_data_version, 0, "Display file data version for "
"a given path.\n" "usage: data_version [-n] <path>"},
+ {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
+ "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
+ {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
+ "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
+ "[--archived] [--lost] <file> ..."},
+ {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
+ "files.\n"
+ "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
+ "[--archived] [--lost] <file> ..."},
{"help", Parser_help, 0, "help"},
{"exit", Parser_quit, 0, "quit"},
{"quit", Parser_quit, 0, "quit"},
return rc;
}
+static int lfs_hsm_state(int argc, char **argv)
+{
+ int rc;
+ int i = 1;
+ char *path;
+ struct hsm_user_state hus;
+
+ if (argc < 2)
+ return CMD_HELP;
+
+ do {
+ path = argv[i];
+
+ rc = llapi_hsm_state_get(path, &hus);
+ if (rc) {
+ fprintf(stderr, "can't get hsm state for %s: %s\n",
+ path, strerror(errno = -rc));
+ return rc;
+ }
+
+ /* Display path name and status flags */
+ printf("%s: (0x%08x)", path, hus.hus_states);
+
+ if (hus.hus_states & HS_RELEASED)
+ printf(" released");
+ if (hus.hus_states & HS_EXISTS)
+ printf(" exists");
+ if (hus.hus_states & HS_DIRTY)
+ printf(" dirty");
+ if (hus.hus_states & HS_ARCHIVED)
+ printf(" archived");
+ /* Display user-settable flags */
+ if (hus.hus_states & HS_NORELEASE)
+ printf(" never_release");
+ if (hus.hus_states & HS_NOARCHIVE)
+ printf(" never_archive");
+ if (hus.hus_states & HS_LOST)
+ printf(" lost_from_hsm");
+
+ if (hus.hus_archive_id != 0)
+ printf(", archive_id:%d", hus.hus_archive_id);
+ printf("\n");
+
+ } while (++i < argc);
+
+ return 0;
+}
+
+#define LFS_HSM_SET 0
+#define LFS_HSM_CLEAR 1
+
+/**
+ * Generic function to set or clear HSM flags.
+ * Used by hsm_set and hsm_clear.
+ *
+ * @mode if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
+ */
+static int lfs_hsm_change_flags(int argc, char **argv, int mode)
+{
+ struct option long_opts[] = {
+ {"lost", 0, 0, 'l'},
+ {"norelease", 0, 0, 'r'},
+ {"noarchive", 0, 0, 'a'},
+ {"archived", 0, 0, 'A'},
+ {"dirty", 0, 0, 'd'},
+ {"exists", 0, 0, 'e'},
+ {0, 0, 0, 0}
+ };
+ char short_opts[] = "lraAde";
+ __u64 mask = 0;
+ int c, rc;
+ char *path;
+
+ if (argc < 3)
+ return CMD_HELP;
+
+ optind = 0;
+ while ((c = getopt_long(argc, argv, short_opts,
+ long_opts, NULL)) != -1) {
+ switch (c) {
+ case 'l':
+ mask |= HS_LOST;
+ break;
+ case 'a':
+ mask |= HS_NOARCHIVE;
+ break;
+ case 'A':
+ mask |= HS_ARCHIVED;
+ break;
+ case 'r':
+ mask |= HS_NORELEASE;
+ break;
+ case 'd':
+ mask |= HS_DIRTY;
+ break;
+ case 'e':
+ mask |= HS_EXISTS;
+ break;
+ case '?':
+ return CMD_HELP;
+ default:
+ fprintf(stderr, "error: %s: option '%s' unrecognized\n",
+ argv[0], argv[optind - 1]);
+ return CMD_HELP;
+ }
+ }
+
+ /* User should have specified a flag */
+ if (mask == 0)
+ return CMD_HELP;
+
+ while (optind < argc) {
+
+ path = argv[optind];
+
+ /* If mode == 0, this means we apply the mask. */
+ if (mode == LFS_HSM_SET)
+ rc = llapi_hsm_state_set(path, mask, 0, 0);
+ else
+ rc = llapi_hsm_state_set(path, 0, mask, 0);
+
+ if (rc != 0) {
+ fprintf(stderr, "Can't change hsm flags for %s: %s\n",
+ path, strerror(errno = -rc));
+ return rc;
+ }
+ optind++;
+ }
+
+ return 0;
+}
+
+static int lfs_hsm_set(int argc, char **argv)
+{
+ return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
+}
+
+static int lfs_hsm_clear(int argc, char **argv)
+{
+ return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
+}
+
int main(int argc, char **argv)
{
int rc;
#include <lustre/lustreapi.h>
#include "lustreapi_internal.h"
-/*
- * fake functions, real one will come with HSM flags patch
- */
-static int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
- __u32 archive_num)
-{
- return 0;
-}
-
/****** HSM Copytool API ********/
#define CT_PRIV_MAGIC 0xC0BE2001
struct hsm_copytool_private {
return rc;
}
+
+/**
+ * Return the current HSM states and HSM requests related to file pointed by \a
+ * path.
+ *
+ * \param hus Should be allocated by caller. Will be filled with current file
+ * states.
+ *
+ * \retval 0 on success.
+ * \retval -errno on error.
+ */
+int llapi_hsm_state_get(const char *path, struct hsm_user_state *hus)
+{
+ int fd;
+ int rc;
+
+ fd = open(path, O_RDONLY | O_NONBLOCK);
+ if (fd < 0)
+ return -errno;
+
+ rc = ioctl(fd, LL_IOC_HSM_STATE_GET, hus);
+ /* If error, save errno value */
+ rc = rc ? -errno : 0;
+
+ close(fd);
+ return rc;
+}
+
+/**
+ * Set HSM states of file pointed by \a path.
+ *
+ * Using the provided bitmasks, the current HSM states for this file will be
+ * changed. \a archive_id could be used to change the archive number also. Set
+ * it to 0 if you do not want to change it.
+ *
+ * \param setmask Bitmask for flag to be set.
+ * \param clearmask Bitmask for flag to be cleared.
+ * \param archive_id Archive number identifier to use. 0 means no change.
+ *
+ * \retval 0 on success.
+ * \retval -errno on error.
+ */
+int llapi_hsm_state_set(const char *path, __u64 setmask, __u64 clearmask,
+ __u32 archive_id)
+{
+ struct hsm_state_set hss;
+ int fd;
+ int rc;
+
+ fd = open(path, O_WRONLY | O_LOV_DELAY_CREATE | O_NONBLOCK);
+ if (fd < 0)
+ return -errno;
+
+ hss.hss_valid = HSS_SETMASK|HSS_CLEARMASK;
+ hss.hss_setmask = setmask;
+ hss.hss_clearmask = clearmask;
+ /* Change archive_id if provided. We can only change
+ * to set something different than 0. */
+ if (archive_id > 0) {
+ hss.hss_valid |= HSS_ARCHIVE_ID;
+ hss.hss_archive_id = archive_id;
+ }
+ rc = ioctl(fd, LL_IOC_HSM_STATE_SET, &hss);
+ /* If error, save errno value */
+ rc = rc ? -errno : 0;
+
+ close(fd);
+ return rc;
+}
+
#define lustre_swab_lu_fid NULL
#define lustre_swab_hsm_progress_kernel NULL
#define lustre_swab_hsm_user_item NULL
+#define lustre_swab_hsm_user_state NULL
+#define lustre_swab_hsm_state_set NULL
#define dump_rniobuf NULL
#define dump_ioo NULL
#define dump_obdo NULL
BLANK_LINE();
CHECK_STRUCT(hsm_user_state);
CHECK_MEMBER(hsm_user_state, hus_states);
- CHECK_MEMBER(hsm_user_state, hus_archive_num);
+ CHECK_MEMBER(hsm_user_state, hus_archive_id);
CHECK_MEMBER(hsm_user_state, hus_in_progress_state);
CHECK_MEMBER(hsm_user_state, hus_in_progress_action);
CHECK_MEMBER(hsm_user_state, hus_in_progress_location);
}
static void
+check_hsm_state_set(void)
+{
+ BLANK_LINE();
+ CHECK_STRUCT(hsm_state_set);
+ CHECK_MEMBER(hsm_state_set, hss_valid);
+ CHECK_MEMBER(hsm_state_set, hss_archive_id);
+ CHECK_MEMBER(hsm_state_set, hss_setmask);
+ CHECK_MEMBER(hsm_state_set, hss_clearmask);
+}
+
+static void
system_string (char *cmdline, char *str, int len)
{
int fds[2];
check_hsm_progress_kernel();
check_hsm_user_item();
check_hsm_user_state();
+ check_hsm_state_set();
printf("}\n\n");
(long long)(int)offsetof(struct hsm_user_state, hus_states));
LASSERTF((int)sizeof(((struct hsm_user_state *)0)->hus_states) == 4, "found %lld\n",
(long long)(int)sizeof(((struct hsm_user_state *)0)->hus_states));
- LASSERTF((int)offsetof(struct hsm_user_state, hus_archive_num) == 4, "found %lld\n",
- (long long)(int)offsetof(struct hsm_user_state, hus_archive_num));
- LASSERTF((int)sizeof(((struct hsm_user_state *)0)->hus_archive_num) == 4, "found %lld\n",
- (long long)(int)sizeof(((struct hsm_user_state *)0)->hus_archive_num));
+ LASSERTF((int)offsetof(struct hsm_user_state, hus_archive_id) == 4, "found %lld\n",
+ (long long)(int)offsetof(struct hsm_user_state, hus_archive_id));
+ LASSERTF((int)sizeof(((struct hsm_user_state *)0)->hus_archive_id) == 4, "found %lld\n",
+ (long long)(int)sizeof(((struct hsm_user_state *)0)->hus_archive_id));
LASSERTF((int)offsetof(struct hsm_user_state, hus_in_progress_state) == 8, "found %lld\n",
(long long)(int)offsetof(struct hsm_user_state, hus_in_progress_state));
LASSERTF((int)sizeof(((struct hsm_user_state *)0)->hus_in_progress_state) == 4, "found %lld\n",
(long long)(int)offsetof(struct hsm_user_state, hus_in_progress_location));
LASSERTF((int)sizeof(((struct hsm_user_state *)0)->hus_in_progress_location) == 16, "found %lld\n",
(long long)(int)sizeof(((struct hsm_user_state *)0)->hus_in_progress_location));
+
+ /* Checks for struct hsm_state_set */
+ LASSERTF((int)sizeof(struct hsm_state_set) == 24, "found %lld\n",
+ (long long)(int)sizeof(struct hsm_state_set));
+ LASSERTF((int)offsetof(struct hsm_state_set, hss_valid) == 0, "found %lld\n",
+ (long long)(int)offsetof(struct hsm_state_set, hss_valid));
+ LASSERTF((int)sizeof(((struct hsm_state_set *)0)->hss_valid) == 4, "found %lld\n",
+ (long long)(int)sizeof(((struct hsm_state_set *)0)->hss_valid));
+ LASSERTF((int)offsetof(struct hsm_state_set, hss_archive_id) == 4, "found %lld\n",
+ (long long)(int)offsetof(struct hsm_state_set, hss_archive_id));
+ LASSERTF((int)sizeof(((struct hsm_state_set *)0)->hss_archive_id) == 4, "found %lld\n",
+ (long long)(int)sizeof(((struct hsm_state_set *)0)->hss_archive_id));
+ LASSERTF((int)offsetof(struct hsm_state_set, hss_setmask) == 8, "found %lld\n",
+ (long long)(int)offsetof(struct hsm_state_set, hss_setmask));
+ LASSERTF((int)sizeof(((struct hsm_state_set *)0)->hss_setmask) == 8, "found %lld\n",
+ (long long)(int)sizeof(((struct hsm_state_set *)0)->hss_setmask));
+ LASSERTF((int)offsetof(struct hsm_state_set, hss_clearmask) == 16, "found %lld\n",
+ (long long)(int)offsetof(struct hsm_state_set, hss_clearmask));
+ LASSERTF((int)sizeof(((struct hsm_state_set *)0)->hss_clearmask) == 8, "found %lld\n",
+ (long long)(int)sizeof(((struct hsm_state_set *)0)->hss_clearmask));
}