Whamcloud - gitweb
LU-1338 hsm: HSM flags feature
authorAurelien Degremont <aurelien.degremont@cea.fr>
Mon, 14 Jan 2013 22:43:54 +0000 (23:43 +0100)
committerOleg Drokin <green@whamcloud.com>
Wed, 30 Jan 2013 22:45:10 +0000 (17:45 -0500)
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 <aurelien.degremont@cea.fr>
Signed-off-by: JC Lafoucriere <jacques-charles.lafoucriere@cea.fr>
Change-Id: Ic8f82ddc9a56206307c2e5be2523fb7ce42b8638
Reviewed-on: http://review.whamcloud.com/3035
Tested-by: Hudson
Reviewed-by: Johann Lombardi <johann.lombardi@intel.com>
Tested-by: Maloo <whamcloud.maloo@gmail.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
30 files changed:
lustre/doc/Makefile.am
lustre/doc/lfs-hsm.1 [new file with mode: 0644]
lustre/doc/lfs.1
lustre/doc/llapi_hsm_state_get.3 [new file with mode: 0644]
lustre/doc/llapi_hsm_state_set.3 [new file with mode: 0644]
lustre/doc/lustreapi.7
lustre/include/lustre/lustre_idl.h
lustre/include/lustre/lustre_user.h
lustre/include/lustre/lustreapi.h
lustre/include/lustre_req_layout.h
lustre/include/md_object.h
lustre/llite/file.c
lustre/lmv/lmv_obd.c
lustre/mdc/mdc_request.c
lustre/mdt/mdt_handler.c
lustre/mdt/mdt_hsm.c
lustre/mdt/mdt_internal.h
lustre/mdt/mdt_mds.c
lustre/mdt/mdt_open.c
lustre/ptlrpc/layout.c
lustre/ptlrpc/pack_generic.c
lustre/ptlrpc/wiretest.c
lustre/tests/Makefile.am
lustre/tests/sanity-hsm.sh [new file with mode: 0644]
lustre/tests/test-groups/regression
lustre/utils/lfs.c
lustre/utils/liblustreapi_hsm.c
lustre/utils/req-layout.c
lustre/utils/wirecheck.c
lustre/utils/wiretest.c

index c1926a0..475aabc 100644 (file)
@@ -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 (file)
index 0000000..72e2d76
--- /dev/null
@@ -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 <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)
index 1d7d9ce..8293655 100644 (file)
@@ -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 (file)
index 0000000..70bf405
--- /dev/null
@@ -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 <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)
diff --git a/lustre/doc/llapi_hsm_state_set.3 b/lustre/doc/llapi_hsm_state_set.3
new file mode 100644 (file)
index 0000000..1d2e83c
--- /dev/null
@@ -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 <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)
index d266be6..b3fc90a 100644 (file)
@@ -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)
index b21b605..4cf77c8 100644 (file)
@@ -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
index 09f11f6..1e8ecca 100644 (file)
@@ -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 ******/
index 4bb4691..15ace62 100644 (file)
@@ -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)
index bcc4849..7e3c55d 100644 (file)
@@ -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;
index b9ea4ce..e966fce 100644 (file)
@@ -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;
index 39a9edd..8d04d4e 100644 (file)
@@ -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
index d39cad5..8a79475 100644 (file)
@@ -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;
index a76f279..dd4339c 100644 (file)
@@ -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)
index 41cc425..236b94c 100644 (file)
@@ -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:
index 3e23d61..7a21ccb 100644 (file)
@@ -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;
+}
index 9a4c5c4..a612392 100644 (file)
@@ -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,
index 76fc974..49a87dd 100644 (file)
@@ -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)                                   \
index 4d87ae4..81375ed 100644 (file)
@@ -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.
index 38f3c29..0af7276 100644 (file)
@@ -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",
index 12db432..f814abe 100644 (file)
@@ -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)
 {
index bfff3bc..a4e2dcd 100644 (file)
@@ -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));
 }
 
index 1d09245..77c781f 100644 (file)
@@ -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 (file)
index 0000000..a03a327
--- /dev/null
@@ -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"
+
index 3dffd1a..4fb093f 100644 (file)
@@ -22,3 +22,4 @@ obdfilter-survey
 sgpdd-survey
 sanity-scrub
 lfsck
+sanity-hsm
index df60d24..ef99892 100644 (file)
@@ -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 <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"},
@@ -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;
index c32fcfe..f065359 100644 (file)
 #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 {
@@ -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;
+}
+
index bcdf387..da0f131 100644 (file)
@@ -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
index 03aa467..99de60b 100644 (file)
@@ -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");
 
index 2cee23c..2ac64cd 100644 (file)
@@ -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));
 }