RETURN(rc);
}
case LL_IOC_HSM_CT_START:
+ if (!cfs_capable(CFS_CAP_SYS_ADMIN))
+ RETURN(-EPERM);
+
rc = copy_and_ioctl(cmd, sbi->ll_md_exp, (void *)arg,
sizeof(struct lustre_kernelcomm));
RETURN(rc);
if (req == NULL)
GOTO(out, rc = -ENOMEM);
- mdc_pack_body(req, NULL, NULL, OBD_MD_FLRMTPERM, 0, 0, 0);
+ mdc_pack_body(req, NULL, NULL, OBD_MD_FLRMTPERM, 0, -1, 0);
/* Copy hsm_progress struct */
req_hpk = req_capsule_client_get(&req->rq_pill, &RMF_MDS_HSM_PROGRESS);
if (req == NULL)
GOTO(out, rc = -ENOMEM);
- mdc_pack_body(req, NULL, NULL, OBD_MD_FLRMTPERM, 0, 0, 0);
+ mdc_pack_body(req, NULL, NULL, OBD_MD_FLRMTPERM, 0, -1, 0);
/* Copy hsm_progress struct */
archive_mask = req_capsule_client_get(&req->rq_pill,
if (req == NULL)
GOTO(out, rc = -ENOMEM);
- mdc_pack_body(req, NULL, NULL, OBD_MD_FLRMTPERM, 0, 0, 0);
+ mdc_pack_body(req, NULL, NULL, OBD_MD_FLRMTPERM, 0, -1, 0);
ptlrpc_request_set_replen(req);
RETURN(rc);
}
- mdc_pack_body(req, NULL, NULL, OBD_MD_FLRMTPERM, 0, 0, 0);
+ mdc_pack_body(req, NULL, NULL, OBD_MD_FLRMTPERM, 0, -1, 0);
/* Copy hsm_request struct */
req_hr = req_capsule_client_get(&req->rq_pill, &RMF_MDS_HSM_REQUEST);
cdt->cdt_last_cookie = cfs_time_current_sec();
atomic_set(&cdt->cdt_request_count, 0);
+ cdt->cdt_user_request_mask = (1UL << HSMA_RESTORE);
+ cdt->cdt_group_request_mask = (1UL << HSMA_RESTORE);
+ cdt->cdt_other_request_mask = (1UL << HSMA_RESTORE);
/* to avoid deadlock when start is made through /proc
* /proc entries are created by the coordinator thread */
RETURN(sz);
}
+static int
+lprocfs_rd_hsm_request_mask(char *page, char **start, off_t off,
+ int count, int *eof, __u64 mask)
+{
+ int i, rc = 0;
+ ENTRY;
+
+ for (i = 0; i < 8 * sizeof(mask); i++) {
+ if (mask & (1UL << i))
+ rc += snprintf(page + rc, count - rc, "%s%s",
+ rc == 0 ? "" : " ",
+ hsm_copytool_action2name(i));
+ }
+
+ rc += snprintf(page + rc, count - rc, "\n");
+
+ RETURN(rc);
+}
+
+static int
+lprocfs_rd_hsm_user_request_mask(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct mdt_device *mdt = data;
+ struct coordinator *cdt = &mdt->mdt_coordinator;
+
+ return lprocfs_rd_hsm_request_mask(page, start, off, count, eof,
+ cdt->cdt_user_request_mask);
+}
+
+static int
+lprocfs_rd_hsm_group_request_mask(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct mdt_device *mdt = data;
+ struct coordinator *cdt = &mdt->mdt_coordinator;
+
+ return lprocfs_rd_hsm_request_mask(page, start, off, count, eof,
+ cdt->cdt_group_request_mask);
+}
+
+static int
+lprocfs_rd_hsm_other_request_mask(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct mdt_device *mdt = data;
+ struct coordinator *cdt = &mdt->mdt_coordinator;
+
+ return lprocfs_rd_hsm_request_mask(page, start, off, count, eof,
+ cdt->cdt_other_request_mask);
+}
+
+static inline enum hsm_copytool_action
+hsm_copytool_name2action(const char *name)
+{
+ if (strcasecmp(name, "NOOP") == 0)
+ return HSMA_NONE;
+ else if (strcasecmp(name, "ARCHIVE") == 0)
+ return HSMA_ARCHIVE;
+ else if (strcasecmp(name, "RESTORE") == 0)
+ return HSMA_RESTORE;
+ else if (strcasecmp(name, "REMOVE") == 0)
+ return HSMA_REMOVE;
+ else if (strcasecmp(name, "CANCEL") == 0)
+ return HSMA_CANCEL;
+ else
+ return -1;
+}
+
+static int
+lprocfs_wr_hsm_request_mask(struct file *file, const char __user *user_buf,
+ unsigned long user_count, __u64 *mask)
+{
+ char *buf, *pos, *name;
+ size_t buf_size;
+ __u64 new_mask = 0;
+ int rc;
+ ENTRY;
+
+ if (!(user_count < 4096))
+ RETURN(-ENOMEM);
+
+ buf_size = user_count + 1;
+
+ OBD_ALLOC(buf, buf_size);
+ if (buf == NULL)
+ RETURN(-ENOMEM);
+
+ if (copy_from_user(buf, user_buf, buf_size - 1))
+ GOTO(out, rc = -EFAULT);
+
+ buf[buf_size - 1] = '\0';
+
+ pos = buf;
+ while ((name = strsep(&pos, " \t\v\n")) != NULL) {
+ int action;
+
+ if (*name == '\0')
+ continue;
+
+ action = hsm_copytool_name2action(name);
+ if (action < 0)
+ GOTO(out, rc = -EINVAL);
+
+ new_mask |= (1UL << action);
+ }
+
+ *mask = new_mask;
+ rc = user_count;
+out:
+ OBD_FREE(buf, buf_size);
+
+ RETURN(rc);
+}
+
+static int
+lprocfs_wr_hsm_user_request_mask(struct file *file, const char __user *buf,
+ unsigned long count, void *data)
+{
+ struct mdt_device *mdt = data;
+ struct coordinator *cdt = &mdt->mdt_coordinator;
+
+ return lprocfs_wr_hsm_request_mask(file, buf, count,
+ &cdt->cdt_user_request_mask);
+}
+
+static int
+lprocfs_wr_hsm_group_request_mask(struct file *file, const char __user *buf,
+ unsigned long count, void *data)
+{
+ struct mdt_device *mdt = data;
+ struct coordinator *cdt = &mdt->mdt_coordinator;
+
+ return lprocfs_wr_hsm_request_mask(file, buf, count,
+ &cdt->cdt_group_request_mask);
+}
+
+static int
+lprocfs_wr_hsm_other_request_mask(struct file *file, const char __user *buf,
+ unsigned long count, void *data)
+{
+ struct mdt_device *mdt = data;
+ struct coordinator *cdt = &mdt->mdt_coordinator;
+
+ return lprocfs_wr_hsm_request_mask(file, buf, count,
+ &cdt->cdt_other_request_mask);
+}
+
static struct lprocfs_vars lprocfs_mdt_hsm_vars[] = {
{ "agents", NULL, NULL, NULL, &mdt_hsm_agent_fops, 0 },
{ "agent_actions", NULL, NULL, NULL,
lprocfs_wr_hsm_cdt_timeout,
NULL, NULL, 0 },
{ "requests", NULL, NULL, NULL, &mdt_hsm_request_fops, 0 },
- { 0 }
+ { "user_request_mask", lprocfs_rd_hsm_user_request_mask,
+ lprocfs_wr_hsm_user_request_mask, },
+ { "group_request_mask", lprocfs_rd_hsm_group_request_mask,
+ lprocfs_wr_hsm_group_request_mask, },
+ { "other_request_mask", lprocfs_rd_hsm_other_request_mask,
+ lprocfs_wr_hsm_other_request_mask, },
+ { NULL }
};
RETURN(rc);
}
+static inline bool mdt_hsm_is_admin(struct mdt_thread_info *info)
+{
+ bool is_admin;
+ int rc;
+
+ if (info->mti_body == NULL)
+ return false;
+
+ rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
+ if (rc < 0)
+ return false;
+
+ is_admin = md_capable(mdt_ucred(info), CFS_CAP_SYS_ADMIN);
+
+ mdt_exit_ucred(info);
+
+ return is_admin;
+}
+
/**
* Extract information coming from a copytool and asks coordinator to update
* a request status depending on the update content.
*/
int mdt_hsm_progress(struct mdt_thread_info *info)
{
- struct mdt_body *body;
struct hsm_progress_kernel *hpk;
int rc;
ENTRY;
- body = req_capsule_client_get(info->mti_pill, &RMF_MDT_BODY);
- if (body == NULL)
- RETURN(-EPROTO);
-
hpk = req_capsule_client_get(info->mti_pill, &RMF_MDS_HSM_PROGRESS);
- if (hpk == NULL)
+
+ if (info->mti_body == NULL || hpk == NULL)
RETURN(-EPROTO);
+ if (!mdt_hsm_is_admin(info))
+ RETURN(-EPERM);
+
hpk->hpk_errval = lustre_errno_ntoh(hpk->hpk_errval);
CDEBUG(D_HSM, "Progress on "DFID": len="LPU64" err=%d\n",
int mdt_hsm_ct_register(struct mdt_thread_info *info)
{
- struct mdt_body *body;
struct ptlrpc_request *req = mdt_info_req(info);
__u32 *archives;
int rc;
ENTRY;
- body = req_capsule_client_get(info->mti_pill, &RMF_MDT_BODY);
- if (body == NULL)
- RETURN(-EPROTO);
+ if (!mdt_hsm_is_admin(info))
+ RETURN(-EPERM);
archives = req_capsule_client_get(info->mti_pill, &RMF_MDS_HSM_ARCHIVE);
if (archives == NULL)
int mdt_hsm_ct_unregister(struct mdt_thread_info *info)
{
- struct mdt_body *body;
struct ptlrpc_request *req = mdt_info_req(info);
int rc;
ENTRY;
- body = req_capsule_client_get(info->mti_pill, &RMF_MDT_BODY);
- if (body == NULL)
+ if (info->mti_body == NULL)
RETURN(-EPROTO);
+ if (!mdt_hsm_is_admin(info))
+ RETURN(-EPERM);
+
/* XXX: directly include this function here? */
rc = mdt_hsm_agent_unregister(info, &req->rq_export->exp_client_uuid);
int rc;
ENTRY;
+ if (info->mti_body == NULL || obj == NULL)
+ RETURN(-EPROTO);
+
+ /* Only valid if client is remote */
+ rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
+ if (rc < 0)
+ RETURN(err_serious(rc));
+
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));
+ if (rc < 0)
+ GOTO(out_ucred, rc);
ma->ma_valid = 0;
ma->ma_need = MA_HSM;
rc = mdt_attr_get_complex(info, obj, ma);
if (rc)
- GOTO(out_ucred, rc);
+ GOTO(out_unlock, rc);
if (req_capsule_get_size(info->mti_pill, &RMF_CAPA1, RCL_CLIENT))
mdt_set_capainfo(info, 0, &info->mti_body->fid1,
hus = req_capsule_server_get(info->mti_pill, &RMF_HSM_USER_STATE);
if (hus == NULL)
- GOTO(out_ucred, rc = -EPROTO);
+ GOTO(out_unlock, rc = -EPROTO);
/* 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);
+out_ucred:
+ mdt_exit_ucred(info);
+
return rc;
}
__u64 flags;
ENTRY;
+ hss = req_capsule_client_get(info->mti_pill, &RMF_HSM_STATE_SET);
+
+ if (info->mti_body == NULL || obj == NULL || hss == NULL)
+ RETURN(-EPROTO);
+
+ /* Only valid if client is remote */
+ rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
+ if (rc < 0)
+ RETURN(err_serious(rc));
+
lh = &info->mti_lh[MDT_LH_CHILD];
mdt_lock_reg_init(lh, LCK_PW);
rc = mdt_object_lock(info, obj, lh, MDS_INODELOCK_LOOKUP |
MDS_INODELOCK_XATTR, MDT_LOCAL_LOCK);
- if (rc)
- RETURN(rc);
+ if (rc < 0)
+ GOTO(out_ucred, 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));
+ 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));
+
+ /* 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) &&
+ !md_capable(mdt_ucred(info), CFS_CAP_SYS_ADMIN))
+ GOTO(out_unlock, rc = -EPERM);
/* 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);
- if (hss == NULL)
- GOTO(out_ucred, rc = -EPROTO);
-
- 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));
+ GOTO(out_unlock, rc);
/* Change HSM flags depending on provided masks */
if (hss->hss_valid & HSS_SETMASK)
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);
+ GOTO(out_unlock, rc);
}
ma->ma_hsm.mh_arch_id = hss->hss_archive_id;
}
/* Save the modified flags */
rc = mdt_hsm_attr_set(info, obj, &ma->ma_hsm);
if (rc)
- GOTO(out_ucred, rc);
+ GOTO(out_unlock, rc);
EXIT;
+out_unlock:
+ mdt_object_unlock(info, obj, lh, 1);
out_ucred:
mdt_exit_ucred(info);
-out_obj:
- mdt_object_unlock(info, obj, lh, 1);
+
return rc;
}
int rc;
ENTRY;
+ hca = req_capsule_server_get(info->mti_pill,
+ &RMF_MDS_HSM_CURRENT_ACTION);
+
+ if (info->mti_body == NULL || hca == NULL)
+ RETURN(-EPROTO);
+
/* Only valid if client is remote */
rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
if (rc)
req_capsule_client_get(info->mti_pill,
&RMF_CAPA1));
- hca = req_capsule_server_get(info->mti_pill,
- &RMF_MDS_HSM_CURRENT_ACTION);
- if (hca == NULL)
- GOTO(out_ucred, rc = -EPROTO);
-
/* Coordinator information */
hal_size = sizeof(*hal) +
cfs_size_round(MTI_NAME_MAXLEN) /* fsname */ +
int mdt_hsm_request(struct mdt_thread_info *info)
{
struct req_capsule *pill = info->mti_pill;
- struct mdt_body *body;
struct hsm_request *hr;
struct hsm_user_item *hui;
struct hsm_action_list *hal;
int hal_size, i, rc;
ENTRY;
- body = req_capsule_client_get(pill, &RMF_MDT_BODY);
hr = req_capsule_client_get(pill, &RMF_MDS_HSM_REQUEST);
hui = req_capsule_client_get(pill, &RMF_MDS_HSM_USER_ITEM);
data = req_capsule_client_get(pill, &RMF_GENERIC_DATA);
- if (body == NULL || hr == NULL || hui == NULL || data == NULL)
+ if (info->mti_body == NULL || hr == NULL || hui == NULL || data == NULL)
RETURN(-EPROTO);
/* Sanity check. Nothing to do with an empty list */
RETURN(-EPROTO);
/* Only valid if client is remote */
- rc = mdt_init_ucred(info, body);
+ rc = mdt_init_ucred(info, (struct mdt_body *)info->mti_body);
if (rc)
RETURN(err_serious(rc));
RETURN(true);
}
+static int
+hsm_action_permission(struct mdt_thread_info *mti,
+ struct mdt_object *obj,
+ enum hsm_copytool_action hsma)
+{
+ struct coordinator *cdt = &mti->mti_mdt->mdt_coordinator;
+ struct lu_ucred *uc = mdt_ucred(mti);
+ struct md_attr *ma = &mti->mti_attr;
+ const __u64 *mask;
+ int rc;
+ ENTRY;
+
+ if (hsma != HSMA_RESTORE &&
+ exp_connect_flags(mti->mti_exp) & OBD_CONNECT_RDONLY)
+ RETURN(-EROFS);
+
+ if (md_capable(uc, CFS_CAP_SYS_ADMIN))
+ RETURN(0);
+
+ ma->ma_need = MA_INODE;
+ rc = mdt_attr_get_complex(mti, obj, ma);
+ if (rc < 0)
+ RETURN(rc);
+
+ if (uc->uc_fsuid == ma->ma_attr.la_uid)
+ mask = &cdt->cdt_user_request_mask;
+ else if (lustre_in_group_p(uc, ma->ma_attr.la_gid))
+ mask = &cdt->cdt_group_request_mask;
+ else
+ mask = &cdt->cdt_other_request_mask;
+
+ if (!(0 <= hsma && hsma < 8 * sizeof(*mask)))
+ RETURN(-EINVAL);
+
+ RETURN(*mask & (1UL << hsma) ? 0 : -EPERM);
+}
+
/*
* Coordinator external API
*/
* if restore, we take the layout lock
*/
- /* if action is cancel, also no need to check */
- if (hai->hai_action == HSMA_CANCEL)
- goto record;
-
- /* get HSM attributes */
+ /* Get HSM attributes and check permissions. */
obj = mdt_hsm_get_md_hsm(mti, &hai->hai_fid, &mh);
- if (IS_ERR(obj) || obj == NULL) {
- /* in case of archive remove, Lustre file
- * is not mandatory */
- if (hai->hai_action == HSMA_REMOVE)
+ if (IS_ERR(obj)) {
+ /* In case of REMOVE and CANCEL a Lustre file
+ * is not mandatory, but restrict this
+ * exception to admins. */
+ if (md_capable(mdt_ucred(mti), CFS_CAP_SYS_ADMIN) &&
+ (hai->hai_action == HSMA_REMOVE ||
+ hai->hai_action == HSMA_CANCEL))
goto record;
- if (obj == NULL)
- GOTO(out, rc = -ENOENT);
- GOTO(out, rc = PTR_ERR(obj));
+ else
+ GOTO(out, rc = PTR_ERR(obj));
}
+
+ rc = hsm_action_permission(mti, obj, hai->hai_action);
mdt_object_put(mti->mti_env, obj);
+ if (rc < 0)
+ GOTO(out, rc);
+
+ /* if action is cancel, also no need to check */
+ if (hai->hai_action == HSMA_CANCEL)
+ goto record;
+
/* Check if an action is needed, compare request
* and HSM flags status */
if (!hsm_action_is_needed(hai, archive_id, flags, &mh))
* agents */
struct list_head cdt_restore_hdl; /**< list of restore lock
* handles */
+ /* Bitmasks indexed by the HSMA_XXX constants. */
+ __u64 cdt_user_request_mask;
+ __u64 cdt_group_request_mask;
+ __u64 cdt_other_request_mask;
};
/* mdt state flag bits */
DEF_MDT_HDL(HABEO_CORPUS| HABEO_REFERO, MDS_IS_SUBDIR, mdt_is_subdir),
DEF_MDT_HDL(0, MDS_QUOTACHECK, mdt_quotacheck),
DEF_MDT_HDL(0, MDS_QUOTACTL, mdt_quotactl),
-DEF_MDT_HDL(HABEO_CORPUS| HABEO_REFERO, MDS_HSM_PROGRESS, mdt_hsm_progress),
-DEF_MDT_HDL(HABEO_CORPUS| HABEO_REFERO, MDS_HSM_CT_REGISTER,
- mdt_hsm_ct_register),
-DEF_MDT_HDL(HABEO_CORPUS| 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),
-DEF_MDT_HDL(HABEO_CORPUS| HABEO_REFERO, MDS_HSM_ACTION, mdt_hsm_action),
-DEF_MDT_HDL(HABEO_CORPUS| HABEO_REFERO, MDS_HSM_REQUEST, mdt_hsm_request),
-DEF_MDT_HDL(HABEO_CORPUS|HABEO_REFERO, MDS_SWAP_LAYOUTS, mdt_swap_layouts)
+DEF_MDT_HDL(HABEO_CORPUS | HABEO_REFERO | MUTABOR, MDS_HSM_PROGRESS,
+ mdt_hsm_progress),
+DEF_MDT_HDL(HABEO_CORPUS | HABEO_REFERO | MUTABOR, MDS_HSM_CT_REGISTER,
+ mdt_hsm_ct_register),
+DEF_MDT_HDL(HABEO_CORPUS | HABEO_REFERO | MUTABOR, 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 | MUTABOR, MDS_HSM_STATE_SET,
+ mdt_hsm_state_set),
+DEF_MDT_HDL(HABEO_CORPUS | HABEO_REFERO, MDS_HSM_ACTION, mdt_hsm_action),
+DEF_MDT_HDL(HABEO_CORPUS | HABEO_REFERO, MDS_HSM_REQUEST, mdt_hsm_request),
+DEF_MDT_HDL(HABEO_CORPUS | HABEO_REFERO | MUTABOR, MDS_SWAP_LAYOUTS,
+ mdt_swap_layouts),
};
#define DEF_OBD_HDL(flags, name, fn) \
int rc2;
ENTRY;
+ if (exp_connect_flags(info->mti_exp) & OBD_CONNECT_RDONLY)
+ RETURN(-EROFS);
+
data = req_capsule_client_get(info->mti_pill, &RMF_CLOSE_DATA);
if (data == NULL)
RETURN(-EPROTO);
$LFS hsm_archive $file
wait_request_state $fid ARCHIVE SUCCEED
- $LFS hsm_release $file ||
- check_hsm_flags $file "0x0000000d"
+ $LFS hsm_release $file
+ check_hsm_flags $file "0x0000000d"
$LFS hsm_restore $file
wait_request_state $fid RESTORE SUCCEED
$RUNAS $LFS hsm_state $file ||
error "user '$RUNAS_ID' cannot get HSM state of '$file'"
- $LFS hsm_release $file ||
- check_hsm_flags $file "0x0000000d"
+ $LFS hsm_release $file
+ check_hsm_flags $file "0x0000000d"
# Check that ordinary user can accessed released file.
sum1=$($RUNAS md5sum $file) ||
}
run_test 24b "root can archive, release, and restore user files"
+cleanup_test_24c() {
+ trap 0
+ set_hsm_param user_request_mask RESTORE
+ set_hsm_param group_request_mask RESTORE
+ set_hsm_param other_request_mask RESTORE
+}
+
+test_24c() {
+ local file=$DIR/$tdir/$tfile
+ local action=archive
+ local user_save
+ local group_save
+ local other_save
+
+ # test needs a running copytool
+ copytool_setup
+
+ mkdir -p $DIR/$tdir
+
+ # Save the default masks and check that cleanup_24c will
+ # restore the request masks correctly.
+ user_save=$(get_hsm_param user_request_mask)
+ group_save=$(get_hsm_param group_request_mask)
+ other_save=$(get_hsm_param other_request_mask)
+
+ [ "$user_save" == RESTORE ] ||
+ error "user_request_mask is '$user_save' expected 'RESTORE'"
+ [ "$group_save" == RESTORE ] ||
+ error "group_request_mask is '$group_save' expected 'RESTORE'"
+ [ "$other_save" == RESTORE ] ||
+ error "other_request_mask is '$other_save' expected 'RESTORE'"
+
+ trap cleanup_test_24c EXIT
+
+ # User.
+ rm -f $file
+ make_small $file
+ chown $RUNAS_ID:nobody $file ||
+ error "cannot chown '$file' to '$RUNAS_ID:nobody'"
+
+ set_hsm_param user_request_mask ""
+ $RUNAS $LFS hsm_$action $file &&
+ error "$action by user should fail"
+
+ set_hsm_param user_request_mask $action
+ $RUNAS $LFS hsm_$action $file ||
+ error "$action by user should succeed"
+
+ # Group.
+ rm -f $file
+ make_small $file
+ chown nobody:$RUNAS_GID $file ||
+ error "cannot chown '$file' to 'nobody:$RUNAS_GID'"
+
+ set_hsm_param group_request_mask ""
+ $RUNAS $LFS hsm_$action $file &&
+ error "$action by group should fail"
+
+ set_hsm_param group_request_mask $action
+ $RUNAS $LFS hsm_$action $file ||
+ error "$action by group should succeed"
+
+ # Other.
+ rm -f $file
+ make_small $file
+ chown nobody:nobody $file ||
+ error "cannot chown '$file' to 'nobody:nobody'"
+
+ set_hsm_param other_request_mask ""
+ $RUNAS $LFS hsm_$action $file &&
+ error "$action by other should fail"
+
+ set_hsm_param other_request_mask $action
+ $RUNAS $LFS hsm_$action $file ||
+ error "$action by other should succeed"
+
+ copytool_cleanup
+ cleanup_test_24c
+}
+run_test 24c "check that user,group,other request masks work"
+
+cleanup_test_24d() {
+ trap 0
+ mount -o remount,rw $MOUNT2
+}
+
+test_24d() {
+ local file1=$DIR/$tdir/$tfile
+ local file2=$DIR2/$tdir/$tfile
+ local fid1
+ local fid2
+
+ copytool_setup
+
+ mkdir -p $DIR/$tdir
+ rm -f $file1
+ fid1=$(make_small $file1)
+
+ trap cleanup_test_24d EXIT
+
+ mount -o remount,ro $MOUNT2
+
+ fid2=$(path2fid $file2)
+ [ "$fid1" == "$fid2" ] ||
+ error "FID mismatch '$fid1' != '$fid2'"
+
+ $LFS hsm_archive $file2 &&
+ error "archive should fail on read-only mount"
+ check_hsm_flags $file1 "0x00000000"
+
+ $LFS hsm_archive $file1
+ wait_request_state $fid1 ARCHIVE SUCCEED
+
+ $LFS hsm_release $file1
+ $LFS hsm_restore $file2
+ wait_request_state $fid1 RESTORE SUCCEED
+
+ $LFS hsm_release $file1 || error "cannot release '$file1'"
+ dd if=$file2 of=/dev/null bs=1M || "cannot read '$file2'"
+
+ $LFS hsm_release $file2 &&
+ error "release should fail on read-only mount"
+
+ copytool_cleanup
+ cleanup_test_24d
+}
+run_test 24d "check that read-only mounts are respected"
+
test_25a() {
# test needs a running copytool
copytool_setup