From 13787b1d87b10c693db274c4d2b718e75e88c12f Mon Sep 17 00:00:00 2001 From: "John L. Hammond" Date: Thu, 5 Sep 2013 12:44:27 -0500 Subject: [PATCH] LU-3866 hsm: permission checks on HSM operations In the LL_IOC_HSM_CT_START case of ll_dir_ioctl() require CAP_SYS_ADMIN, since the local handler for this ioctl may modify the global KUC table. In the MDC HSM handlers that do not pack a real suppgid, use -1 rather than 0 for the suppgid in mdt_body. In mdt_hsm_release() and the the MDT HSM RPC handlers require a read-write client mount for all operations except restore, get HSM state, and get HSM actions. Require CAP_SYS_ADMIN for MDS_HSM_PROGRESS, MDS_HSM_CT_REGISTER, and MDS_HSM_CT_UNREGISTER. Require CAP_SYS_ADMIN in mdt_hsm_state_set() for setting flags not in HSM_USER_MASK. Add per-coordinator bit masks (cdt_{user,group,other}_request_mask) indexed by the HSMA constants to govern permissions on the various requests types. By default each mask is set to allow restore only. Add files /proc/fs/lustre/mdt/*/hsm/{user,group,other}_request_mask to get and set these masks. Signed-off-by: John L. Hammond Change-Id: Ifcb3c0950ebb11187cce62f15abbe8746f1ff7c2 Reviewed-on: http://review.whamcloud.com/7565 Tested-by: Hudson Tested-by: Maloo Reviewed-by: Aurelien Degremont Reviewed-by: Faccini Bruno Reviewed-by: Jinshan Xiong Reviewed-by: Oleg Drokin --- lustre/llite/dir.c | 3 + lustre/mdc/mdc_request.c | 8 +- lustre/mdt/mdt_coordinator.c | 159 +++++++++++++++++++++++++++++++++++++++- lustre/mdt/mdt_hsm.c | 132 ++++++++++++++++++++------------- lustre/mdt/mdt_hsm_cdt_client.c | 68 ++++++++++++++--- lustre/mdt/mdt_internal.h | 4 + lustre/mdt/mdt_mds.c | 25 ++++--- lustre/mdt/mdt_open.c | 3 + lustre/tests/sanity-hsm.sh | 136 +++++++++++++++++++++++++++++++++- 9 files changed, 453 insertions(+), 85 deletions(-) diff --git a/lustre/llite/dir.c b/lustre/llite/dir.c index c90c543..04cf9d2 100644 --- a/lustre/llite/dir.c +++ b/lustre/llite/dir.c @@ -1899,6 +1899,9 @@ out_rmdir: 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); diff --git a/lustre/mdc/mdc_request.c b/lustre/mdc/mdc_request.c index b9e5cac..ab9a375 100644 --- a/lustre/mdc/mdc_request.c +++ b/lustre/mdc/mdc_request.c @@ -1268,7 +1268,7 @@ static int mdc_ioc_hsm_progress(struct obd_export *exp, 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); @@ -1300,7 +1300,7 @@ static int mdc_ioc_hsm_ct_register(struct obd_import *imp, __u32 archives) 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, @@ -1375,7 +1375,7 @@ static int mdc_ioc_hsm_ct_unregister(struct obd_import *imp) 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); @@ -1498,7 +1498,7 @@ static int mdc_ioc_hsm_request(struct obd_export *exp, 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); diff --git a/lustre/mdt/mdt_coordinator.c b/lustre/mdt/mdt_coordinator.c index 991a03e..9d5d4cd 100644 --- a/lustre/mdt/mdt_coordinator.c +++ b/lustre/mdt/mdt_coordinator.c @@ -961,6 +961,9 @@ int mdt_hsm_cdt_start(struct mdt_device *mdt) 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 */ @@ -2033,6 +2036,154 @@ int lprocfs_rd_hsm_cdt_control(char *page, char **start, off_t off, 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, @@ -2055,5 +2206,11 @@ static struct lprocfs_vars lprocfs_mdt_hsm_vars[] = { 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 } }; diff --git a/lustre/mdt/mdt_hsm.c b/lustre/mdt/mdt_hsm.c index a7a39dc..58a91ee 100644 --- a/lustre/mdt/mdt_hsm.c +++ b/lustre/mdt/mdt_hsm.c @@ -77,6 +77,25 @@ int mdt_hsm_attr_set(struct mdt_thread_info *info, struct mdt_object *obj, 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. @@ -87,19 +106,18 @@ int mdt_hsm_attr_set(struct mdt_thread_info *info, struct mdt_object *obj, */ 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", @@ -121,15 +139,13 @@ int mdt_hsm_progress(struct mdt_thread_info *info) 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) @@ -144,15 +160,16 @@ int mdt_hsm_ct_register(struct mdt_thread_info *info) 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); @@ -176,23 +193,26 @@ int mdt_hsm_state_get(struct mdt_thread_info *info) 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, @@ -200,17 +220,18 @@ int mdt_hsm_state_get(struct mdt_thread_info *info) 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; } @@ -233,32 +254,39 @@ int mdt_hsm_state_set(struct mdt_thread_info *info) __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) @@ -272,7 +300,7 @@ int mdt_hsm_state_set(struct mdt_thread_info *info) 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; } @@ -297,14 +325,15 @@ int mdt_hsm_state_set(struct mdt_thread_info *info) /* 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; } @@ -323,6 +352,12 @@ int mdt_hsm_action(struct mdt_thread_info *info) 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) @@ -333,11 +368,6 @@ int mdt_hsm_action(struct mdt_thread_info *info) 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 */ + @@ -415,7 +445,6 @@ out_ucred: 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; @@ -428,12 +457,11 @@ int mdt_hsm_request(struct mdt_thread_info *info) 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 */ @@ -450,7 +478,7 @@ int mdt_hsm_request(struct mdt_thread_info *info) 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)); diff --git a/lustre/mdt/mdt_hsm_cdt_client.c b/lustre/mdt/mdt_hsm_cdt_client.c index ac8da871..3c873d5a 100644 --- a/lustre/mdt/mdt_hsm_cdt_client.c +++ b/lustre/mdt/mdt_hsm_cdt_client.c @@ -245,6 +245,43 @@ static bool hal_is_sane(struct hsm_action_list *hal) 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 */ @@ -321,23 +358,30 @@ int mdt_hsm_add_actions(struct mdt_thread_info *mti, * 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)) diff --git a/lustre/mdt/mdt_internal.h b/lustre/mdt/mdt_internal.h index 1317255..5fb3c9a 100644 --- a/lustre/mdt/mdt_internal.h +++ b/lustre/mdt/mdt_internal.h @@ -145,6 +145,10 @@ struct coordinator { * 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 */ diff --git a/lustre/mdt/mdt_mds.c b/lustre/mdt/mdt_mds.c index 7c7d95e..8084dab 100644 --- a/lustre/mdt/mdt_mds.c +++ b/lustre/mdt/mdt_mds.c @@ -139,18 +139,19 @@ DEF_MDT_HDL_VAR(0, MDS_SYNC, mdt_sync), 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) \ diff --git a/lustre/mdt/mdt_open.c b/lustre/mdt/mdt_open.c index 0cb4d93..76ed060 100644 --- a/lustre/mdt/mdt_open.c +++ b/lustre/mdt/mdt_open.c @@ -1975,6 +1975,9 @@ static int mdt_hsm_release(struct mdt_thread_info *info, struct mdt_object *o, 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); diff --git a/lustre/tests/sanity-hsm.sh b/lustre/tests/sanity-hsm.sh index 8687a61..b6be099 100644 --- a/lustre/tests/sanity-hsm.sh +++ b/lustre/tests/sanity-hsm.sh @@ -1485,8 +1485,8 @@ test_24b() { $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 @@ -1495,8 +1495,8 @@ test_24b() { $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) || @@ -1509,6 +1509,134 @@ test_24b() { } 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 -- 1.8.3.1