From: Aurelien Degremont Date: Mon, 14 Jan 2013 22:43:54 +0000 (+0100) Subject: LU-1338 hsm: HSM flags feature X-Git-Tag: 2.3.61~83 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=c42b426c87c3d3b1dc9eda612cc831293dc80d68 LU-1338 hsm: HSM flags feature This extends lustre_hsm_attrs struct in MDD to store HSM per-file information. It adds infrastructure (function, RPCs, ...) to read and modify it, from MDT code or from user-space on clients through llapi and lfs command. This patch implements: - lfs hsm_state - lfs hsm_set - lfs hsm_clear matching llapi functions: - llapi_hsm_state_get() - llapi_hsm_state_set() matching mdt functions: - mdt_hsm_state_get() - mdt_hsm_state_set() and MDS RPC: - MDS_HSM_STATE_GET - MDS_HSM_STATE_SET Signed-off-by: Aurelien Degremont Signed-off-by: JC Lafoucriere Change-Id: Ic8f82ddc9a56206307c2e5be2523fb7ce42b8638 Reviewed-on: http://review.whamcloud.com/3035 Tested-by: Hudson Reviewed-by: Johann Lombardi Tested-by: Maloo Reviewed-by: Andreas Dilger --- diff --git a/lustre/doc/Makefile.am b/lustre/doc/Makefile.am index c1926a0..475aabc 100644 --- a/lustre/doc/Makefile.am +++ b/lustre/doc/Makefile.am @@ -53,7 +53,8 @@ MANFILES = lustre.7 lfs.1 mount.lustre.8 mkfs.lustre.8 tunefs.lustre.8 lctl.8 \ 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) diff --git a/lustre/doc/lfs-hsm.1 b/lustre/doc/lfs-hsm.1 new file mode 100644 index 0000000..72e2d76 --- /dev/null +++ b/lustre/doc/lfs-hsm.1 @@ -0,0 +1,74 @@ +.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 ... +.br +.B lfs hsm_set|hsm_clear +.RB [ --norelease ] +.RB [ --noarchive ] +.RB [ --dirty ] +.RB [ --exists ] +.RB [ --archived ] +.RB [ --lost ] +.RB ... +.br +.SH DESCRIPTION +These are a set of lfs commands used to interact with Lustre/HSM binding feature. +.TP +.B lfs hsm_state ... +Display the current HSM flags and archive ID for provided files. +.TP +.B lfs hsm_set ... +Set provided HSM flags on file list. +.TP +.B lfs hsm_clear ... +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) diff --git a/lustre/doc/lfs.1 b/lustre/doc/lfs.1 index 1d7d9ce..8293655 100644 --- a/lustre/doc/lfs.1 +++ b/lustre/doc/lfs.1 @@ -300,5 +300,6 @@ The \fBlfs find\fR command isn't as comprehensive as \fBfind\fR(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) diff --git a/lustre/doc/llapi_hsm_state_get.3 b/lustre/doc/llapi_hsm_state_get.3 new file mode 100644 index 0000000..70bf4055 --- /dev/null +++ b/lustre/doc/llapi_hsm_state_get.3 @@ -0,0 +1,150 @@ +.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 +.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 +#include +#include + +#include + +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) diff --git a/lustre/doc/llapi_hsm_state_set.3 b/lustre/doc/llapi_hsm_state_set.3 new file mode 100644 index 0000000..1d2e83c --- /dev/null +++ b/lustre/doc/llapi_hsm_state_set.3 @@ -0,0 +1,95 @@ +.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 +.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 +#include +#include + +#include + +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) diff --git a/lustre/doc/lustreapi.7 b/lustre/doc/lustreapi.7 index d266be6..b3fc90a 100644 --- a/lustre/doc/lustreapi.7 +++ b/lustre/doc/lustreapi.7 @@ -9,3 +9,5 @@ The lustreapi library provides functions to access and/or modify settings specif .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) diff --git a/lustre/include/lustre/lustre_idl.h b/lustre/include/lustre/lustre_idl.h index b21b605..4cf77c8 100644 --- a/lustre/include/lustre/lustre_idl.h +++ b/lustre/include/lustre/lustre_idl.h @@ -1553,6 +1553,21 @@ struct lov_mds_md_v3 { /* LOV EA mds/wire data (little-endian) */ /* 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); @@ -3318,8 +3333,8 @@ struct hsm_progress_kernel { __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 diff --git a/lustre/include/lustre/lustre_user.h b/lustre/include/lustre/lustre_user.h index 09f11f6..1e8ecca 100644 --- a/lustre/include/lustre/lustre_user.h +++ b/lustre/include/lustre/lustre_user.h @@ -745,13 +745,13 @@ struct ioc_data_version { * 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. */ @@ -770,25 +770,25 @@ enum hsm_states { * 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)); /** @@ -798,20 +798,20 @@ struct hsm_extent { * 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 ******/ diff --git a/lustre/include/lustre/lustreapi.h b/lustre/include/lustre/lustreapi.h index 4bb4691..15ace62 100644 --- a/lustre/include/lustre/lustreapi.h +++ b/lustre/include/lustre/lustreapi.h @@ -233,6 +233,9 @@ extern int llapi_fd2fid(const int fd, lustre_fid *fid); 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) diff --git a/lustre/include/lustre_req_layout.h b/lustre/include/lustre_req_layout.h index bcc4849..7e3c55d 100644 --- a/lustre/include/lustre_req_layout.h +++ b/lustre/include/lustre_req_layout.h @@ -282,6 +282,8 @@ extern struct req_msg_field RMF_MDS_HSM_PROGRESS; 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; diff --git a/lustre/include/md_object.h b/lustre/include/md_object.h index b9ea4ce..e966fce 100644 --- a/lustre/include/md_object.h +++ b/lustre/include/md_object.h @@ -134,6 +134,10 @@ typedef enum { 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; @@ -143,6 +147,10 @@ struct md_hsm { #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; diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 39a9edd..8d04d4e 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -1285,37 +1285,36 @@ out: 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, @@ -1435,56 +1434,55 @@ out: 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; @@ -1697,43 +1695,43 @@ out: 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) @@ -1755,10 +1753,10 @@ 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 @@ -1780,8 +1778,8 @@ static int ll_ioctl_fiemap(struct inode *inode, unsigned long arg) 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); @@ -1907,33 +1905,32 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 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; @@ -1947,20 +1944,83 @@ long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 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 diff --git a/lustre/lmv/lmv_obd.c b/lustre/lmv/lmv_obd.c index d39cad5..8a79475 100644 --- a/lustre/lmv/lmv_obd.c +++ b/lustre/lmv/lmv_obd.c @@ -864,6 +864,18 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp, 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; diff --git a/lustre/mdc/mdc_request.c b/lustre/mdc/mdc_request.c index a76f279..dd4339c 100644 --- a/lustre/mdc/mdc_request.c +++ b/lustre/mdc/mdc_request.c @@ -1274,6 +1274,102 @@ out: 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; @@ -1555,6 +1651,12 @@ static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len, 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) diff --git a/lustre/mdt/mdt_handler.c b/lustre/mdt/mdt_handler.c index 41cc425..236b94c 100644 --- a/lustre/mdt/mdt_handler.c +++ b/lustre/mdt/mdt_handler.c @@ -713,7 +713,7 @@ static int mdt_getattr_internal(struct mdt_thread_info *info, } 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)) && @@ -3104,6 +3104,8 @@ static int mdt_msg_check_version(struct lustre_msg *msg) 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: diff --git a/lustre/mdt/mdt_hsm.c b/lustre/mdt/mdt_hsm.c index 3e23d61..7a21ccb 100644 --- a/lustre/mdt/mdt_hsm.c +++ b/lustre/mdt/mdt_hsm.c @@ -157,3 +157,151 @@ int mdt_hsm_ct_unregister(struct mdt_thread_info *info) 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; +} diff --git a/lustre/mdt/mdt_internal.h b/lustre/mdt/mdt_internal.h index 9a4c5c4..a612392 100644 --- a/lustre/mdt/mdt_internal.h +++ b/lustre/mdt/mdt_internal.h @@ -777,6 +777,10 @@ int mdt_hsm_progress(struct mdt_thread_info *info); 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, diff --git a/lustre/mdt/mdt_mds.c b/lustre/mdt/mdt_mds.c index 76fc974..49a87dd 100644 --- a/lustre/mdt/mdt_mds.c +++ b/lustre/mdt/mdt_mds.c @@ -147,6 +147,10 @@ DEF_MDT_HDL(0 | HABEO_REFERO, MDS_HSM_CT_REGISTER, 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) \ diff --git a/lustre/mdt/mdt_open.c b/lustre/mdt/mdt_open.c index 4d87ae4..81375ed 100644 --- a/lustre/mdt/mdt_open.c +++ b/lustre/mdt/mdt_open.c @@ -704,7 +704,13 @@ static int mdt_mfd_open(struct mdt_thread_info *info, struct mdt_object *p, 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); @@ -996,7 +1002,7 @@ void mdt_reconstruct_open(struct mdt_thread_info *info, 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; @@ -1121,19 +1127,23 @@ static int mdt_object_open_lock(struct mdt_thread_info *info, 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; @@ -1564,7 +1574,8 @@ int mdt_reint_open(struct mdt_thread_info *info, struct mdt_lock_handle *lhc) } 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. diff --git a/lustre/ptlrpc/layout.c b/lustre/ptlrpc/layout.c index 38f3c29..0af7276 100644 --- a/lustre/ptlrpc/layout.c +++ b/lustre/ptlrpc/layout.c @@ -596,6 +596,18 @@ static const struct req_msg_field *mdt_hsm_ct_register[] = { &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, @@ -638,6 +650,8 @@ static struct req_format *req_formats[] = { &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, @@ -1016,6 +1030,15 @@ struct req_msg_field RMF_IDX_INFO = 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), @@ -1344,6 +1367,15 @@ struct req_format RQF_MDS_HSM_CT_UNREGISTER = 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", diff --git a/lustre/ptlrpc/pack_generic.c b/lustre/ptlrpc/pack_generic.c index 12db432..f814abe 100644 --- a/lustre/ptlrpc/pack_generic.c +++ b/lustre/ptlrpc/pack_generic.c @@ -2477,13 +2477,21 @@ void lustre_swab_lustre_capa_key(struct lustre_capa_key *k) } 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) { diff --git a/lustre/ptlrpc/wiretest.c b/lustre/ptlrpc/wiretest.c index bfff3bc..a4e2dcd 100644 --- a/lustre/ptlrpc/wiretest.c +++ b/lustre/ptlrpc/wiretest.c @@ -4330,10 +4330,10 @@ void lustre_assert_wire_constants(void) (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", @@ -4346,5 +4346,25 @@ void lustre_assert_wire_constants(void) (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)); } diff --git a/lustre/tests/Makefile.am b/lustre/tests/Makefile.am index 1d09245..77c781f 100644 --- a/lustre/tests/Makefile.am +++ b/lustre/tests/Makefile.am @@ -34,6 +34,7 @@ noinst_SCRIPTS += parallel-scale-nfsv3.sh parallel-scale-nfsv4.sh 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 diff --git a/lustre/tests/sanity-hsm.sh b/lustre/tests/sanity-hsm.sh new file mode 100644 index 0000000..a03a327 --- /dev/null +++ b/lustre/tests/sanity-hsm.sh @@ -0,0 +1,190 @@ +#!/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" + diff --git a/lustre/tests/test-groups/regression b/lustre/tests/test-groups/regression index 3dffd1a..4fb093f 100644 --- a/lustre/tests/test-groups/regression +++ b/lustre/tests/test-groups/regression @@ -22,3 +22,4 @@ obdfilter-survey sgpdd-survey sanity-scrub lfsck +sanity-hsm diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index df60d24..ef99892 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -104,6 +104,9 @@ static int lfs_changelog_clear(int argc, char **argv); 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[] = { @@ -238,6 +241,15 @@ command_t cmdlist[] = { "usage: path2fid "}, {"data_version", lfs_data_version, 0, "Display file data version for " "a given path.\n" "usage: data_version [-n] "}, + {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, " + "undergoing actions) for given files.\n usage: hsm_state ..."}, + {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n" + "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] " + "[--archived] [--lost] ..."}, + {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified " + "files.\n" + "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] " + "[--archived] [--lost] ..."}, {"help", Parser_help, 0, "help"}, {"exit", Parser_quit, 0, "quit"}, {"quit", Parser_quit, 0, "quit"}, @@ -2710,6 +2722,148 @@ static int lfs_data_version(int argc, char **argv) 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; diff --git a/lustre/utils/liblustreapi_hsm.c b/lustre/utils/liblustreapi_hsm.c index c32fcfe..f065359 100644 --- a/lustre/utils/liblustreapi_hsm.c +++ b/lustre/utils/liblustreapi_hsm.c @@ -58,15 +58,6 @@ #include #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 { @@ -452,3 +443,73 @@ out_unlink: 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; +} + diff --git a/lustre/utils/req-layout.c b/lustre/utils/req-layout.c index bcdf387..da0f131 100644 --- a/lustre/utils/req-layout.c +++ b/lustre/utils/req-layout.c @@ -85,6 +85,8 @@ #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 diff --git a/lustre/utils/wirecheck.c b/lustre/utils/wirecheck.c index 03aa467..99de60b 100644 --- a/lustre/utils/wirecheck.c +++ b/lustre/utils/wirecheck.c @@ -1861,7 +1861,7 @@ check_hsm_user_state(void) 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); @@ -1956,6 +1956,17 @@ static void check_layout_intent(void) } 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]; @@ -2321,6 +2332,7 @@ main(int argc, char **argv) check_hsm_progress_kernel(); check_hsm_user_item(); check_hsm_user_state(); + check_hsm_state_set(); printf("}\n\n"); diff --git a/lustre/utils/wiretest.c b/lustre/utils/wiretest.c index 2cee23c..2ac64cd 100644 --- a/lustre/utils/wiretest.c +++ b/lustre/utils/wiretest.c @@ -4338,10 +4338,10 @@ void lustre_assert_wire_constants(void) (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", @@ -4354,5 +4354,25 @@ void lustre_assert_wire_constants(void) (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)); }