int restore_mdt_index, int restore_open_flags,
bool is_error);
extern int llapi_hsm_action_end(struct hsm_copyaction_private **phcp,
- const struct hsm_extent *he, int flags,
- int errval);
+ const struct hsm_extent *he,
+ int hp_flags, int errval);
extern int llapi_hsm_action_progress(struct hsm_copyaction_private *hcp,
const struct hsm_extent *he, int hp_flags);
extern int llapi_hsm_action_get_dfid(const struct hsm_copyaction_private *hcp,
uc->uc_fsgid = 0;
uc->uc_suppgids[0] = -1;
uc->uc_suppgids[1] = -1;
- uc->uc_cap = 0;
+ uc->uc_cap = CFS_CAP_FS_MASK;
uc->uc_umask = 0777;
uc->uc_ginfo = NULL;
uc->uc_identity = NULL;
/**
* Check release is permitted for the current HSM flags.
*/
-static bool mdt_hsm_release_allow(struct md_attr *ma)
+static bool mdt_hsm_release_allow(const struct md_attr *ma)
{
if (!(ma->ma_valid & MA_HSM))
return false;
{
const struct lu_env *env = info->mti_env;
struct md_op_spec *spec = &info->mti_spec;
- struct lu_fid *rootfid = &info->mti_tmp_fid1;
+ struct lu_fid *local_root_fid = &info->mti_tmp_fid1;
struct mdt_object *obj = NULL;
struct mdt_object *local_root;
static const char name[] = "i_am_nobody";
struct lu_name *lname;
+ struct lu_ucred *uc;
+ cfs_cap_t uc_cap_save;
int rc;
ENTRY;
- rc = dt_root_get(env, mdt->mdt_bottom, rootfid);
+ rc = dt_root_get(env, mdt->mdt_bottom, local_root_fid);
if (rc != 0)
RETURN(ERR_PTR(rc));
- local_root = mdt_object_find(env, mdt, rootfid);
+ local_root = mdt_object_find(env, mdt, local_root_fid);
if (IS_ERR(local_root))
RETURN(local_root);
}
lname = mdt_name(env, (char *)name, sizeof(name) - 1);
+
+ uc = lu_ucred(env);
+ uc_cap_save = uc->uc_cap;
+ uc->uc_cap |= 1 << CFS_CAP_DAC_OVERRIDE;
rc = mdo_create(env, mdt_object_child(local_root), lname,
mdt_object_child(obj), spec, attr);
- if (rc == 0) {
- rc = mo_open(env, mdt_object_child(obj), MDS_OPEN_CREATED);
- if (rc < 0)
- CERROR("%s: cannot open volatile file "DFID", orphan "
- "file will be left in PENDING directory until "
- "next reboot, rc = %d\n", mdt_obd_name(mdt),
- PFID(fid), rc);
+ uc->uc_cap = uc_cap_save;
+ if (rc < 0) {
+ CERROR("%s: cannot create volatile file "DFID": rc = %d\n",
+ mdt_obd_name(mdt), PFID(fid), rc);
+ GOTO(out, rc);
}
- EXIT;
+
+ rc = mo_open(env, mdt_object_child(obj), MDS_OPEN_CREATED);
+ if (rc < 0)
+ CERROR("%s: cannot open volatile file "DFID", orphan "
+ "file will be left in PENDING directory until "
+ "next reboot, rc = %d\n", mdt_obd_name(mdt),
+ PFID(fid), rc);
+ GOTO(out, rc);
out:
if (rc < 0) {
/* ma_need was set before but it seems fine to change it in order to
* avoid modifying the one from RPC */
- ma->ma_need = MA_HSM | MA_LOV;
+ ma->ma_need = MA_HSM;
rc = mdt_attr_get_complex(info, o, ma);
if (rc != 0)
GOTO(out_unlock, rc);
}
ma->ma_valid = MA_INODE;
- ma->ma_attr.la_valid &= LA_SIZE | LA_MTIME | LA_ATIME;
+ ma->ma_attr.la_valid &= LA_ATIME | LA_MTIME | LA_CTIME | LA_SIZE;
rc = mo_attr_set(info->mti_env, mdt_object_child(o), ma);
if (rc < 0)
GOTO(out_unlock, rc);
+ ma->ma_need = MA_INODE | MA_LOV;
+ rc = mdt_attr_get_complex(info, o, ma);
+ if (rc < 0)
+ GOTO(out_unlock, rc);
+
if (!(ma->ma_valid & MA_LOV)) {
/* Even empty file are released */
memset(ma->ma_lmm, 0, sizeof(*ma->ma_lmm));
ma->ma_lmm->lmm_magic = cpu_to_le32(LOV_MAGIC_V1_DEF);
ma->ma_lmm->lmm_pattern = cpu_to_le32(LOV_PATTERN_RAID0);
ma->ma_lmm->lmm_stripe_size = cpu_to_le32(LOV_MIN_STRIPE_SIZE);
- ma->ma_valid |= MA_LOV;
+ ma->ma_lmm_size = sizeof(*ma->ma_lmm);
} else {
/* Magic must be LOV_MAGIC_Vx_DEF otherwise LOD will interpret
* ma_lmm as lov_user_md, then it will be confused by union of
/* Hopefully it's not used in this call path */
orp_ma = &info->mti_u.som.attr;
- orp_ma->ma_valid = MA_INODE | MA_LOV;
- orp_ma->ma_attr.la_mode = S_IFREG;
- orp_ma->ma_attr.la_valid = LA_MODE;
+ orp_ma->ma_attr.la_mode = S_IFREG | S_IWUSR;
+ orp_ma->ma_attr.la_uid = ma->ma_attr.la_uid;
+ orp_ma->ma_attr.la_gid = ma->ma_attr.la_gid;
+ orp_ma->ma_attr.la_valid = LA_MODE | LA_UID | LA_GID;
orp_ma->ma_lmm = ma->ma_lmm;
orp_ma->ma_lmm_size = ma->ma_lmm_size;
+ orp_ma->ma_valid = MA_INODE | MA_LOV;
orphan = mdt_orphan_open(info, info->mti_mdt, &data->cd_fid, orp_ma,
FMODE_WRITE);
if (IS_ERR(orphan)) {
ma->ma_valid = 0;
ma->ma_need = 0;
+
return rc;
}
# bug number for skipped test:
# UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT!
# skip test cases failed before landing - Jinshan
-ALWAYS_EXCEPT="$SANITY_HSM_EXCEPT 12a 12b 12n 13 24 30a 31a 34 35 36 58 59"
+
+ALWAYS_EXCEPT="$SANITY_HSM_EXCEPT 12a 12b 12n 13 30a 31a 34 35 36 58 59"
ALWAYS_EXCEPT="$ALWAYS_EXCEPT 110a 200 201 221 222a 223a 223b 225"
LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)}
}
run_test 23 "Release does not change a/mtime (utime)"
-test_24() {
+test_24a() {
+ local file=$DIR/$tdir/$tfile
+ local fid
+ local atime0
+ local atime1
+ local mtime0
+ local mtime1
+ local ctime0
+ local ctime1
+
# test needs a running copytool
copytool_setup
mkdir -p $DIR/$tdir
-
- local f=$DIR/$tdir/test_mtime
+ rm -f $file
+ fid=$(make_small $file)
# Create a file and check its states
- local fid=$(make_small $f)
- check_hsm_flags $f "0x00000000"
+ check_hsm_flags $file "0x00000000"
- # make mtime is different
+ # Ensure atime is less than mtime and ctime.
sleep 1
- echo "append" >> $f
- local MTIME=$(stat -c "%Y" $f)
- local ATIME=$(stat -c "%X" $f)
+ echo >> $file
- $LFS hsm_archive $f || error "could not archive file"
+ atime0=$(stat -c "%X" $file)
+ mtime0=$(stat -c "%Y" $file)
+ ctime0=$(stat -c "%Z" $file)
+
+ [ $atime0 -lt $mtime0 ] ||
+ error "atime $atime0 is not less than mtime $mtime0"
+
+ [ $atime0 -lt $ctime0 ] ||
+ error "atime $atime0 is not less than ctime $ctime0"
+
+ # Archive should not change any timestamps.
+ $LFS hsm_archive $file || error "cannot archive '$file'"
wait_request_state $fid ARCHIVE SUCCEED
- # Release and check states
- $LFS hsm_release $f || error "could not release file"
- check_hsm_flags $f "0x0000000d"
+ atime1=$(stat -c "%X" $file)
+ mtime1=$(stat -c "%Y" $file)
+ ctime1=$(stat -c "%Z" $file)
+
+ [ $atime0 -eq $atime1 ] ||
+ error "archive changed atime from $atime0 to $atime1"
+
+ [ $mtime0 -eq $mtime1 ] ||
+ error "archive changed mtime from $mtime0 to $mtime1"
+
+ [ $ctime0 -eq $ctime1 ] ||
+ error "archive changed ctime from $ctime0 to $ctime1"
+
+ # Release should not change any timestamps.
+ $LFS hsm_release $file || error "cannot release '$file'"
+ check_hsm_flags $file "0x0000000d"
+
+ atime1=$(stat -c "%X" $file)
+ mtime1=$(stat -c "%Y" $file)
+ ctime1=$(stat -c "%Z" $file)
+
+ [ $atime0 -eq $atime1 ] ||
+ error "release changed atime from $atime0 to $atime1"
+
+ [ $mtime0 -eq $mtime1 ] ||
+ error "release changed mtime from $mtime0 to $mtime1"
+
+ [ $ctime0 -eq $ctime1 ] ||
+ error "release changed ctime from $ctime0 to $ctime1"
+
+ # Restore should not change atime or mtime and should not
+ # decrease ctime.
+ $LFS hsm_restore $file
+ wait_request_state $fid RESTORE SUCCEED
+
+ atime1=$(stat -c "%X" $file)
+ mtime1=$(stat -c "%Y" $file)
+ ctime1=$(stat -c "%Z" $file)
+
+ [ $atime0 -eq $atime1 ] ||
+ error "restore changed atime from $atime0 to $atime1"
+
+ [ $mtime0 -eq $mtime1 ] ||
+ error "restore changed mtime from $mtime0 to $mtime1"
+
+ [ $ctime0 -le $ctime1 ] ||
+ error "restore changed ctime from $ctime0 to $ctime1"
+
+ copytool_cleanup
+
+ # Once more, after unmount and mount.
+ umount_client $MOUNT || error "cannot unmount '$MOUNT'"
+ mount_client $MOUNT || error "cannot mount '$MOUNT'"
+
+ atime1=$(stat -c "%X" $file)
+ mtime1=$(stat -c "%Y" $file)
+ ctime1=$(stat -c "%Z" $file)
+
+ [ $atime0 -eq $atime1 ] ||
+ error "remount changed atime from $atime0 to $atime1"
+
+ [ $mtime0 -eq $mtime1 ] ||
+ error "remount changed mtime from $mtime0 to $mtime1"
+
+ [ $ctime0 -le $ctime1 ] ||
+ error "remount changed ctime from $ctime0 to $ctime1"
+}
+run_test 24a "Archive, release, and restore does not change a/mtime (i/o)"
+
+test_24b() {
+ local file=$DIR/$tdir/$tfile
+ local fid
+ local sum0
+ local sum1
+ # LU-3811
+
+ # Test needs a running copytool.
+ copytool_setup
+ mkdir -p $DIR/$tdir
+
+ # Check that root can do HSM actions on a ordinary user's file.
+ rm -f $file
+ fid=$(make_small $file)
+ sum0=$(md5sum $file)
+
+ chown $RUNAS_ID:$RUNAS_GID $file ||
+ error "cannot chown '$file' to '$RUNAS_ID'"
+
+ chmod ugo-w $DIR/$tdir ||
+ error "cannot chmod '$DIR/$tdir'"
+
+ $LFS hsm_archive $file
+ wait_request_state $fid ARCHIVE SUCCEED
+
+ $LFS hsm_release $file ||
+ check_hsm_flags $file "0x0000000d"
+
+ $LFS hsm_restore $file
+ wait_request_state $fid RESTORE SUCCEED
+
+ # Check that ordinary user can get HSM state.
+ $RUNAS $LFS hsm_state $file ||
+ error "user '$RUNAS_ID' cannot get HSM state of '$file'"
+
+ $LFS hsm_release $file ||
+ check_hsm_flags $file "0x0000000d"
- [ "$(stat -c "%Y" $f)" -eq "$MTIME" ] ||
- error "mtime should be $MTIME"
+ # Check that ordinary user can accessed released file.
+ sum1=$($RUNAS md5sum $file) ||
+ error "user '$RUNAS_ID' cannot read '$file'"
- [ "$(stat -c "%X" $f)" -eq "$ATIME" ] ||
- error "atime should be $ATIME"
+ [ "$sum0" == "$sum1" ] ||
+ error "md5sum mismatch for '$file'"
copytool_cleanup
}
-run_test 24 "Release does not change a/mtime (i/o)"
+run_test 24b "root can archive, release, and restore user files"
test_25a() {
# test needs a running copytool
.o_chunk_size = ONE_MB,
};
-/* The LLAPI will hold an open FD on lustre for us. Additionally open one on
- * the archive FS root to make sure it doesn't drop out from under us (and
- * remind the admin to shutdown the copytool before unmounting). */
+/* hsm_copytool_private will hold an open FD on the lustre mount point
+ * for us. Additionally open one on the archive FS root to make sure
+ * it doesn't drop out from under us (and remind the admin to shutdown
+ * the copytool before unmounting). */
+
static int arc_fd = -1;
static int err_major;
}
}
- if (rc == 0) {
- rc = fsync(dst_fd);
- if (rc < 0) {
- rc = -errno;
- CT_ERROR("'%s' fsync failed (%s)\n", dst,
- strerror(-rc));
- err_major++;
- }
- }
-
free(buf);
return rc;
}
static int ct_fini(struct hsm_copyaction_private **phcp,
- const struct hsm_action_item *hai, int flags, int ct_rc)
+ const struct hsm_action_item *hai, int hp_flags, int ct_rc)
{
char lstr[PATH_MAX];
int rc;
CT_TRACE("Action completed, notifying coordinator "
- "cookie="LPX64", FID="DFID", flags=%d err=%d\n",
+ "cookie="LPX64", FID="DFID", hp_flags=%d err=%d\n",
hai->hai_cookie, PFID(&hai->hai_fid),
- flags, -ct_rc);
+ hp_flags, -ct_rc);
ct_path_lustre(lstr, sizeof(lstr), opt.o_mnt, &hai->hai_fid);
- rc = llapi_hsm_action_end(phcp, &hai->hai_extent, flags, abs(ct_rc));
+ rc = llapi_hsm_action_end(phcp, &hai->hai_extent, hp_flags, abs(ct_rc));
if (rc == -ECANCELED)
CT_ERROR("'%s' completed action has been canceled: "
"cookie="LPX64", FID="DFID"\n", lstr, hai->hai_cookie,
int rc;
int rcf = 0;
bool rename_needed = false;
- int ct_flags = 0;
+ int hp_flags = 0;
int open_flags;
int src_fd = -1;
int dst_fd = -1;
rename_needed = true;
}
- CT_TRACE("'%s' archived to %s\n", src, dst);
+ CT_TRACE("'%s' archiving to %s\n", src, dst);
if (opt.o_dry_run) {
rc = 0;
goto fini_major;
}
- src_fd = open(src, O_RDONLY | O_NOATIME | O_NONBLOCK | O_NOFOLLOW);
- if (src_fd == -1) {
+ src_fd = llapi_hsm_action_get_fd(hcp);
+ if (src_fd < 0) {
CT_ERROR("'%s' open read failed (%s)\n", src, strerror(errno));
rc = -errno;
goto fini_major;
goto fini_major;
}
+ rc = fsync(dst_fd);
+ if (rc < 0) {
+ CT_ERROR("'%s' cannot synchronize archive file '%s' (%s)\n",
+ src, dst, strerror(errno));
+ rc = -errno;
+ goto fini_major;
+ }
+
CT_TRACE("'%s' data archived to '%s' done\n", src, dst);
/* attrs will remain on the MDS; no need to copy them, except possibly
unlink(dst);
if (ct_is_retryable(rc))
- ct_flags |= HP_FLAG_RETRY;
+ hp_flags |= HP_FLAG_RETRY;
rcf = rc;
close(dst_fd);
if (hcp != NULL)
- rc = ct_fini(&hcp, hai, ct_flags, rcf);
+ rc = ct_fini(&hcp, hai, hp_flags, rcf);
return rc;
}
char lov_buf[XATTR_SIZE_MAX];
size_t lov_size = sizeof(lov_buf);
int rc;
- int flags = 0;
+ int hp_flags = 0;
int src_fd = -1;
int dst_fd = -1;
int mdt_index = -1; /* Not implemented */
int open_flags = 0;
bool set_lovea;
- lustre_fid dfid;
-
+ struct lu_fid dfid;
/* we fill lustre so:
* source = lustre FID in the backend
* destination = data FID = volatile file
strerror(-rc));
err_major++;
if (ct_is_retryable(rc))
- flags |= HP_FLAG_RETRY;
+ hp_flags |= HP_FLAG_RETRY;
goto fini;
}
fini:
if (hcp != NULL)
- rc = ct_fini(&hcp, hai, flags, rc);
+ rc = ct_fini(&hcp, hai, hp_flags, rc);
/* object swaping is done by cdt at copy end, so close of volatile file
* cannot be done before */
/* set llapi message level */
llapi_msg_set_level(opt.o_verbose);
- arc_fd = open(opt.o_hsm_root, O_DIRECTORY);
+ arc_fd = open(opt.o_hsm_root, O_RDONLY);
if (arc_fd < 0) {
CT_ERROR("cannot open archive at '%s': %s\n", opt.o_hsm_root,
strerror(errno));
#include <lustre/lustreapi.h>
#include "lustreapi_internal.h"
+#define OPEN_BY_FID_PATH dot_lustre_name"/fid"
+
/****** HSM Copytool API ********/
#define CT_PRIV_MAGIC 0xC0BE2001
struct hsm_copytool_private {
int magic;
char *mnt;
int mnt_fd;
+ int open_by_fid_fd;
lustre_kernelcomm kuc;
__u32 archives;
};
__s32 data_fd;
const struct hsm_copytool_private *ct_priv;
struct hsm_copy copy;
+ struct stat stat;
};
#include <libcfs/libcfs.h>
if (ct == NULL)
return -ENOMEM;
- ct->mnt_fd = open(mnt, O_DIRECTORY | O_RDONLY | O_NONBLOCK);
- if (ct->mnt_fd < 0) {
- rc = -errno;
- goto out_err;
- }
+ ct->magic = CT_PRIV_MAGIC;
+ ct->mnt_fd = -1;
+ ct->open_by_fid_fd = -1;
+ ct->kuc.lk_rfd = LK_NOFD;
+ ct->kuc.lk_wfd = LK_NOFD;
ct->mnt = strdup(mnt);
if (ct->mnt == NULL) {
goto out_err;
}
- ct->magic = CT_PRIV_MAGIC;
+ ct->mnt_fd = open(ct->mnt, O_RDONLY);
+ if (ct->mnt_fd < 0) {
+ rc = -errno;
+ goto out_err;
+ }
+
+ ct->open_by_fid_fd = openat(ct->mnt_fd, OPEN_BY_FID_PATH, O_RDONLY);
+ if (ct->open_by_fid_fd < 0) {
+ rc = -errno;
+ goto out_err;
+ }
/* no archives specified means "match all". */
ct->archives = 0;
out_err:
if (!(ct->mnt_fd < 0))
close(ct->mnt_fd);
+
+ if (!(ct->open_by_fid_fd < 0))
+ close(ct->open_by_fid_fd);
+
if (ct->mnt != NULL)
free(ct->mnt);
+
free(ct);
+
return rc;
}
/* Shut down the kernelcomms */
libcfs_ukuc_stop(&ct->kuc);
+ close(ct->open_by_fid_fd);
close(ct->mnt_fd);
free(ct->mnt);
free(ct);
return rc;
}
+static int ct_open_by_fid(const struct hsm_copytool_private *ct,
+ const struct lu_fid *fid, int open_flags)
+{
+ char fid_name[FID_NOBRACE_LEN + 1];
+
+ snprintf(fid_name, sizeof(fid_name), DFID_NOBRACE, PFID(fid));
+
+ return openat(ct->open_by_fid_fd, fid_name, open_flags);
+}
+
+static int ct_stat_by_fid(const struct hsm_copytool_private *ct,
+ const struct lu_fid *fid,
+ struct stat *buf)
+{
+ char fid_name[FID_NOBRACE_LEN + 1];
+
+ snprintf(fid_name, sizeof(fid_name), DFID_NOBRACE, PFID(fid));
+
+ return fstatat(ct->open_by_fid_fd, fid_name, buf, 0);
+}
+
/** Create the destination volatile file for a restore operation.
*
* \param hcp Private copyaction handle.
* \return 0 on success.
*/
static int create_restore_volatile(struct hsm_copyaction_private *hcp,
- int mdt_index, int flags)
+ int mdt_index, int open_flags)
{
int rc;
int fd;
if (rc < 0) {
/* fid_parent() failed, try to keep on going */
llapi_error(LLAPI_MSG_ERROR, rc,
- "cannot get parent path to restore "DFID
+ "cannot get parent path to restore "DFID" "
"using '%s'", PFID(&hai->hai_fid), mnt);
snprintf(parent, sizeof(parent), "%s", mnt);
}
- fd = llapi_create_volatile_idx(parent, mdt_index, flags);
+ fd = llapi_create_volatile_idx(parent, mdt_index, open_flags);
if (fd < 0)
return fd;
+ rc = fchown(fd, hcp->stat.st_uid, hcp->stat.st_gid);
+ if (rc < 0)
+ goto err_cleanup;
+
rc = llapi_fd2fid(fd, &hai->hai_dfid);
if (rc < 0)
goto err_cleanup;
goto ok_out;
if (hai->hai_action == HSMA_RESTORE) {
+ rc = ct_stat_by_fid(hcp->ct_priv, &hai->hai_fid, &hcp->stat);
+ if (rc < 0)
+ goto err_out;
+
rc = create_restore_volatile(hcp, restore_mdt_index,
restore_open_flags);
if (rc < 0)
* \return 0 on success.
*/
int llapi_hsm_action_end(struct hsm_copyaction_private **phcp,
- const struct hsm_extent *he, int flags, int errval)
+ const struct hsm_extent *he, int hp_flags, int errval)
{
struct hsm_copyaction_private *hcp;
struct hsm_action_item *hai;
hai = &hcp->copy.hc_hai;
+ if (hai->hai_action == HSMA_RESTORE && errval == 0) {
+ struct timeval tv[2];
+
+ /* Set {a,m}time of volatile file to that of original. */
+ tv[0].tv_sec = hcp->stat.st_atime;
+ tv[0].tv_usec = 0;
+ tv[1].tv_sec = hcp->stat.st_mtime;
+ tv[1].tv_usec = 0;
+ if (futimes(hcp->data_fd, tv) < 0) {
+ errval = -errno;
+ goto end;
+ }
+
+ rc = fsync(hcp->data_fd);
+ if (rc < 0) {
+ errval = -errno;
+ goto end;
+ }
+ }
+
+end:
/* In some cases, like restore, 2 FIDs are used.
* Set the right FID to use here. */
if (hai->hai_action == HSMA_ARCHIVE || hai->hai_action == HSMA_RESTORE)
/* Fill the last missing data that will be needed by
* kernel to send a hsm_progress. */
- hcp->copy.hc_flags = flags;
+ hcp->copy.hc_flags = hp_flags;
hcp->copy.hc_errval = abs(errval);
hcp->copy.hc_hai.hai_extent = *he;
if (hcp->magic != CP_PRIV_MAGIC)
return -EINVAL;
- if (hai->hai_action != HSMA_RESTORE)
+ if (hai->hai_action == HSMA_ARCHIVE)
+ return ct_open_by_fid(hcp->ct_priv, &hai->hai_dfid,
+ O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NONBLOCK);
+ else if (hai->hai_action == HSMA_RESTORE)
+ return dup(hcp->data_fd);
+ else
return -EINVAL;
-
- return dup(hcp->data_fd);
}
/**