Whamcloud - gitweb
LU-3866 hsm: permission checks on HSM operations
[fs/lustre-release.git] / lustre / mdt / mdt_hsm_cdt_client.c
index b47acea..3c873d5 100644 (file)
@@ -77,12 +77,12 @@ static int hsm_find_compatible_cb(const struct lu_env *env,
        hcdcb = data;
        /* a compatible request must be WAITING or STARTED
         * and not a cancel */
-       if (((larr->arr_status != ARS_WAITING) &&
-            (larr->arr_status != ARS_STARTED)) ||
-           (larr->arr_hai.hai_action == HSMA_CANCEL))
+       if ((larr->arr_status != ARS_WAITING &&
+            larr->arr_status != ARS_STARTED) ||
+           larr->arr_hai.hai_action == HSMA_CANCEL)
                RETURN(0);
 
-       hai = hai_zero(hcdcb->hal);
+       hai = hai_first(hcdcb->hal);
        for (i = 0; i < hcdcb->hal->hal_count; i++, hai = hai_next(hai)) {
                /* if request is a CANCEL:
                 * if cookie set in the request, there is no need to find a
@@ -92,7 +92,7 @@ static int hsm_find_compatible_cb(const struct lu_env *env,
                 * if the caller sets the cookie, we assume he also sets the
                 * arr_archive_id
                 */
-               if ((hai->hai_action == HSMA_CANCEL) && (hai->hai_cookie != 0))
+               if (hai->hai_action == HSMA_CANCEL && hai->hai_cookie != 0)
                        continue;
 
                if (!lu_fid_eq(&hai->hai_fid, &larr->arr_hai.hai_fid))
@@ -110,8 +110,8 @@ static int hsm_find_compatible_cb(const struct lu_env *env,
                 */
                hai->hai_cookie = larr->arr_hai.hai_cookie;
                /* we read the archive number from the request we cancel */
-               if ((hai->hai_action == HSMA_CANCEL) &&
-                   (hcdcb->hal->hal_archive_id == 0))
+               if (hai->hai_action == HSMA_CANCEL &&
+                   hcdcb->hal->hal_archive_id == 0)
                        hcdcb->hal->hal_archive_id = larr->arr_archive_id;
        }
        RETURN(0);
@@ -136,13 +136,13 @@ static int hsm_find_compatible(const struct lu_env *env, struct mdt_device *mdt,
        ENTRY;
 
        ok_cnt = 0;
-       hai = hai_zero(hal);
+       hai = hai_first(hal);
        for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
                /* in a cancel request hai_cookie may be set by caller to
                 * show the request to be canceled
                 * if not we need to search by FID
                 */
-               if ((hai->hai_action == HSMA_CANCEL) && (hai->hai_cookie != 0))
+               if (hai->hai_action == HSMA_CANCEL && hai->hai_cookie != 0)
                        ok_cnt++;
                else
                        hai->hai_cookie = 0;
@@ -181,7 +181,7 @@ static bool hsm_action_is_needed(struct hsm_action_item *hai, int hal_an,
        hsm_flags = hsm->mh_flags;
        switch (hai->hai_action) {
        case HSMA_ARCHIVE:
-               if ((hsm_flags & HS_DIRTY) || !(hsm_flags & HS_ARCHIVED))
+               if (hsm_flags & HS_DIRTY || !(hsm_flags & HS_ARCHIVED))
                        is_needed = true;
                break;
        case HSMA_RESTORE:
@@ -227,7 +227,7 @@ static bool hal_is_sane(struct hsm_action_list *hal)
        if (hal->hal_count == 0)
                RETURN(false);
 
-       hai = hai_zero(hal);
+       hai = hai_first(hal);
        for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
                if (!fid_is_sane(&hai->hai_fid))
                        RETURN(false);
@@ -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
  */
@@ -277,7 +314,7 @@ int mdt_hsm_add_actions(struct mdt_thread_info *mti,
        if (!hal_is_sane(hal))
                RETURN(-EINVAL);
 
-       *compound_id = cfs_atomic_inc_return(&cdt->cdt_compound_id);
+       *compound_id = atomic_inc_return(&cdt->cdt_compound_id);
 
        /* search for compatible request, if found hai_cookie is set
         * to the request cookie
@@ -287,7 +324,7 @@ int mdt_hsm_add_actions(struct mdt_thread_info *mti,
        if (rc)
                GOTO(out, rc);
 
-       hai = hai_zero(hal);
+       hai = hai_first(hal);
        for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
                int archive_id;
                __u64 flags;
@@ -310,10 +347,10 @@ int mdt_hsm_add_actions(struct mdt_thread_info *mti,
                 * do not record
                 */
                /* redundant case */
-               if ((hai->hai_action != HSMA_CANCEL) && (hai->hai_cookie != 0))
+               if (hai->hai_action != HSMA_CANCEL && hai->hai_cookie != 0)
                        continue;
                /* cancel nothing case */
-               if ((hai->hai_action == HSMA_CANCEL) && (hai->hai_cookie == 0))
+               if (hai->hai_action == HSMA_CANCEL && hai->hai_cookie == 0)
                        continue;
 
                /* new request or cancel request
@@ -321,21 +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)) {
-                       /* in case of archive remove, Lustre file
-                        * is not mandatory */
-                       if (hai->hai_action == HSMA_REMOVE)
+                       /* 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;
-                       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))
@@ -349,6 +395,7 @@ int mdt_hsm_add_actions(struct mdt_thread_info *mti,
 
                /* for cancel archive number is taken from canceled request
                 * for other request, we take from lma if not specified,
+                * or we use the default if none found in lma
                 * this works also for archive because the default value is 0
                 * /!\ there is a side effect: in case of restore on multiple
                 * files which are in different backend, the initial compound
@@ -356,48 +403,51 @@ int mdt_hsm_add_actions(struct mdt_thread_info *mti,
                 * warranty an agent can serve any combinaison of archive
                 * backend
                 */
-               if ((hai->hai_action != HSMA_CANCEL) &&
-                   (archive_id == 0))
-                       archive_id = mh.mh_arch_id;
+               if (hai->hai_action != HSMA_CANCEL && archive_id == 0) {
+                       if (mh.mh_arch_id != 0)
+                               archive_id = mh.mh_arch_id;
+                       else
+                               archive_id = cdt->cdt_default_archive_id;
+               }
 
                /* if restore, take an exclusive lock on layout */
                if (hai->hai_action == HSMA_RESTORE) {
-                       struct cdt_restore_handle       *crh;
-                       struct mdt_object               *child;
+                       struct cdt_restore_handle *crh;
+
+                       /* in V1 only whole file is supported. */
+                       if (hai->hai_extent.offset != 0)
+                               GOTO(out, rc = -EPROTO);
 
                        OBD_SLAB_ALLOC_PTR(crh, mdt_hsm_cdt_kmem);
                        if (crh == NULL)
                                GOTO(out, rc = -ENOMEM);
 
                        crh->crh_fid = hai->hai_fid;
-                       /* in V1 only whole file is supported
-                       crh->extent.start = hai->hai_extent.offset;
-                       crh->extent.end = hai->hai_extent.offset +
-                                           hai->hai_extent.length;
-                        */
+                       /* in V1 only whole file is supported. However the
+                        * restore may be due to truncate. */
                        crh->crh_extent.start = 0;
-                       crh->crh_extent.end = OBD_OBJECT_EOF;
+                       crh->crh_extent.end = hai->hai_extent.length;
 
                        mdt_lock_reg_init(&crh->crh_lh, LCK_EX);
-                       child = mdt_object_find_lock(mti, &crh->crh_fid,
-                                                    &crh->crh_lh,
-                                                    MDS_INODELOCK_LAYOUT);
-                       if (IS_ERR(child)) {
-                               rc = PTR_ERR(child);
+                       obj = mdt_object_find_lock(mti, &crh->crh_fid,
+                                                  &crh->crh_lh,
+                                                  MDS_INODELOCK_LAYOUT);
+                       if (IS_ERR(obj)) {
+                               rc = PTR_ERR(obj);
                                CERROR("%s: cannot take layout lock for "
                                       DFID": rc = %d\n", mdt_obd_name(mdt),
                                       PFID(&crh->crh_fid), rc);
                                OBD_SLAB_FREE_PTR(crh, mdt_hsm_cdt_kmem);
                                GOTO(out, rc);
                        }
+
                        /* we choose to not keep a keep a reference
                         * on the object during the restore time which can be
                         * very long */
-                       mdt_object_put(mti->mti_env, child);
+                       mdt_object_put(mti->mti_env, obj);
 
                        mutex_lock(&cdt->cdt_restore_lock);
-                       cfs_list_add_tail(&crh->crh_list,
-                                         &cdt->cdt_restore_hdl);
+                       list_add_tail(&crh->crh_list, &cdt->cdt_restore_hdl);
                        mutex_unlock(&cdt->cdt_restore_lock);
                }
 record:
@@ -416,7 +466,7 @@ record:
        GOTO(out, rc);
 out:
        /* if work has been added, wake up coordinator */
-       if ((rc == 0) || (rc == -ENODATA))
+       if (rc == 0 || rc == -ENODATA)
                mdt_hsm_cdt_wakeup(mdt);
 
        return rc;
@@ -438,7 +488,7 @@ int mdt_hsm_get_running(struct mdt_thread_info *mti,
        int                      i;
        ENTRY;
 
-       hai = hai_zero(hal);
+       hai = hai_first(hal);
        for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
                struct cdt_agent_req *car;
 
@@ -471,7 +521,6 @@ bool mdt_hsm_restore_is_running(struct mdt_thread_info *mti,
 {
        struct mdt_device               *mdt = mti->mti_mdt;
        struct coordinator              *cdt = &mdt->mdt_coordinator;
-       cfs_list_t                      *pos, *tmp;
        struct cdt_restore_handle       *crh;
        bool                             rc = false;
        ENTRY;
@@ -480,8 +529,7 @@ bool mdt_hsm_restore_is_running(struct mdt_thread_info *mti,
                RETURN(rc);
 
        mutex_lock(&cdt->cdt_restore_lock);
-       cfs_list_for_each_safe(pos, tmp, &cdt->cdt_restore_hdl) {
-               crh = cfs_list_entry(pos, struct cdt_restore_handle, crh_list);
+       list_for_each_entry(crh, &cdt->cdt_restore_hdl, crh_list) {
                if (lu_fid_eq(&crh->crh_fid, fid)) {
                        rc = true;
                        break;
@@ -507,7 +555,7 @@ int mdt_hsm_get_actions(struct mdt_thread_info *mti,
        int                      i, rc;
        ENTRY;
 
-       hai = hai_zero(hal);
+       hai = hai_first(hal);
        for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
                hai->hai_action = HSMA_NONE;
                if (!fid_is_sane(&hai->hai_fid))
@@ -530,7 +578,7 @@ int mdt_hsm_get_actions(struct mdt_thread_info *mti,
         * we may want do give back dynamic informations on the
         * running request
         */
-       hai = hai_zero(hal);
+       hai = hai_first(hal);
        for (i = 0; i < hal->hal_count; i++, hai = hai_next(hai)) {
                struct cdt_agent_req *car;