Whamcloud - gitweb
LU-3285 lov: add MDT target to the LOV device
[fs/lustre-release.git] / lustre / lov / lov_dev.c
index 2506c39..bf9dba2 100644 (file)
@@ -142,64 +142,114 @@ struct lu_context_key lov_session_key = {
 /* type constructor/destructor: lov_type_{init,fini,start,stop}() */
 LU_TYPE_INIT_FINI(lov, &lov_key, &lov_session_key);
 
+
+static int lov_mdc_dev_init(const struct lu_env *env, struct lov_device *ld,
+                           struct lu_device *mdc_dev, __u32 idx, __u32 nr)
+{
+       struct cl_device *cl;
+
+       ENTRY;
+       cl = cl_type_setup(env, &ld->ld_site, &lovsub_device_type,
+                          mdc_dev);
+       if (IS_ERR(cl))
+               RETURN(PTR_ERR(cl));
+
+       ld->ld_md_tgts[nr].ldm_mdc = cl;
+       ld->ld_md_tgts[nr].ldm_idx = idx;
+       RETURN(0);
+}
+
 static struct lu_device *lov_device_fini(const struct lu_env *env,
-                                         struct lu_device *d)
+                                        struct lu_device *d)
 {
-        int i;
-        struct lov_device *ld = lu2lov_dev(d);
+       struct lov_device *ld = lu2lov_dev(d);
+       int i;
 
-        LASSERT(ld->ld_lov != NULL);
-        if (ld->ld_target == NULL)
-                RETURN(NULL);
+       LASSERT(ld->ld_lov != NULL);
 
-        lov_foreach_target(ld, i) {
-                struct lovsub_device *lsd;
+       if (ld->ld_lmv != NULL) {
+               class_decref(ld->ld_lmv, "lov", d);
+               ld->ld_lmv = NULL;
+       }
 
-                lsd = ld->ld_target[i];
-                if (lsd != NULL) {
-                        cl_stack_fini(env, lovsub2cl_dev(lsd));
-                        ld->ld_target[i] = NULL;
-                }
-        }
-        RETURN(NULL);
+       if (ld->ld_md_tgts != NULL) {
+               for (i = 0; i < ld->ld_md_tgts_nr; i++) {
+                       if (ld->ld_md_tgts[i].ldm_mdc == NULL)
+                               continue;
+
+                       cl_stack_fini(env, ld->ld_md_tgts[i].ldm_mdc);
+                       ld->ld_md_tgts[i].ldm_mdc = NULL;
+                       ld->ld_lov->lov_mdc_tgts[i].lmtd_mdc = NULL;
+               }
+       }
+
+       if (ld->ld_target != NULL) {
+               lov_foreach_target(ld, i) {
+                       struct lovsub_device *lsd;
+
+                       lsd = ld->ld_target[i];
+                       if (lsd != NULL) {
+                               cl_stack_fini(env, lovsub2cl_dev(lsd));
+                               ld->ld_target[i] = NULL;
+                       }
+               }
+       }
+       RETURN(NULL);
 }
 
 static int lov_device_init(const struct lu_env *env, struct lu_device *d,
                            const char *name, struct lu_device *next)
 {
-        struct lov_device *ld = lu2lov_dev(d);
-        int i;
-        int rc = 0;
-
-        LASSERT(d->ld_site != NULL);
-        if (ld->ld_target == NULL)
-                RETURN(rc);
-
-        lov_foreach_target(ld, i) {
-                struct lovsub_device *lsd;
-                struct cl_device     *cl;
-                struct lov_tgt_desc  *desc;
-
-                desc = ld->ld_lov->lov_tgts[i];
-                if (desc == NULL)
-                        continue;
-
-                cl = cl_type_setup(env, d->ld_site, &lovsub_device_type,
-                                   desc->ltd_obd->obd_lu_dev);
-                if (IS_ERR(cl)) {
-                        rc = PTR_ERR(cl);
-                        break;
-                }
-                lsd = cl2lovsub_dev(cl);
-                ld->ld_target[i] = lsd;
-        }
+       struct lov_device *ld = lu2lov_dev(d);
+       int i;
+       int rc = 0;
+
+       /* check all added already MDC subdevices and initialize them */
+       for (i = 0; i < ld->ld_md_tgts_nr; i++) {
+               struct obd_device *mdc;
+               __u32 idx;
+
+               mdc = ld->ld_lov->lov_mdc_tgts[i].lmtd_mdc;
+               idx = ld->ld_lov->lov_mdc_tgts[i].lmtd_index;
+
+               if (mdc == NULL)
+                       continue;
+
+               rc = lov_mdc_dev_init(env, ld, mdc->obd_lu_dev, idx, i);
+               if (rc) {
+                       CERROR("%s: failed to add MDC %s as target: rc = %d\n",
+                              d->ld_obd->obd_name,
+                              obd_uuid2str(&mdc->obd_uuid), rc);
+                       GOTO(out_err, rc);
+               }
+       }
 
-        if (rc)
-                lov_device_fini(env, d);
-        else
-                ld->ld_flags |= LOV_DEV_INITIALIZED;
+       if (ld->ld_target == NULL)
+               RETURN(0);
 
-        RETURN(rc);
+       lov_foreach_target(ld, i) {
+               struct lovsub_device *lsd;
+               struct cl_device *cl;
+               struct lov_tgt_desc *desc;
+
+               desc = ld->ld_lov->lov_tgts[i];
+               if (desc == NULL)
+                       continue;
+
+               cl = cl_type_setup(env, &ld->ld_site, &lovsub_device_type,
+                                  desc->ltd_obd->obd_lu_dev);
+               if (IS_ERR(cl))
+                       GOTO(out_err, rc = PTR_ERR(cl));
+
+               lsd = cl2lovsub_dev(cl);
+               ld->ld_target[i] = lsd;
+       }
+       ld->ld_flags |= LOV_DEV_INITIALIZED;
+       RETURN(0);
+
+out_err:
+       lu_device_fini(d);
+       RETURN(rc);
 }
 
 /* Free the lov specific data created for the back end lu_device. */
@@ -209,9 +259,24 @@ static struct lu_device *lov_device_free(const struct lu_env *env,
        struct lov_device *ld = lu2lov_dev(d);
        const int nr = ld->ld_target_nr;
 
+       lu_site_fini(&ld->ld_site);
+
        cl_device_fini(lu2cl_dev(d));
-       if (ld->ld_target != NULL)
+       if (ld->ld_target) {
                OBD_FREE(ld->ld_target, nr * sizeof ld->ld_target[0]);
+               ld->ld_target = NULL;
+       }
+       if (ld->ld_md_tgts) {
+               OBD_FREE(ld->ld_md_tgts,
+                        sizeof(*ld->ld_md_tgts) * LOV_MDC_TGT_MAX);
+               ld->ld_md_tgts = NULL;
+       }
+       /* free array of MDCs */
+       if (ld->ld_lov->lov_mdc_tgts) {
+               OBD_FREE(ld->ld_lov->lov_mdc_tgts,
+                        sizeof(*ld->ld_lov->lov_mdc_tgts) * LOV_MDC_TGT_MAX);
+               ld->ld_lov->lov_mdc_tgts = NULL;
+       }
 
        OBD_FREE_PTR(ld);
        return NULL;
@@ -283,11 +348,9 @@ static int lov_cl_add_target(const struct lu_env *env, struct lu_device *dev,
                 RETURN(-EINVAL);
         }
 
-        rc = lov_expand_targets(env, ld);
-        if (rc == 0 && ld->ld_flags & LOV_DEV_INITIALIZED) {
-                LASSERT(dev->ld_site != NULL);
-
-               cl = cl_type_setup(env, dev->ld_site, &lovsub_device_type,
+       rc = lov_expand_targets(env, ld);
+       if (rc == 0 && ld->ld_flags & LOV_DEV_INITIALIZED) {
+               cl = cl_type_setup(env, &ld->ld_site, &lovsub_device_type,
                                   tgt->ltd_obd->obd_lu_dev);
                if (!IS_ERR(cl)) {
                        lsd = cl2lovsub_dev(cl);
@@ -303,34 +366,139 @@ static int lov_cl_add_target(const struct lu_env *env, struct lu_device *dev,
         RETURN(rc);
 }
 
-static int lov_process_config(const struct lu_env *env,
-                              struct lu_device *d, struct lustre_cfg *cfg)
+/**
+ * Add new MDC target device in LOV.
+ *
+ * This function is part of the configuration log processing. It adds new MDC
+ * device to the MDC device array indexed by their indexes.
+ *
+ * \param[in] env      execution environment
+ * \param[in] d                LU device of LOV device
+ * \param[in] mdc      MDC device to add
+ * \param[in] idx      MDC device index
+ *
+ * \retval             0 if successful
+ * \retval             negative value on error
+ */
+static int lov_add_mdc_target(const struct lu_env *env, struct lu_device *d,
+                             struct obd_device *mdc, __u32 idx)
 {
-        struct obd_device *obd = d->ld_obd;
-        int cmd;
-        int rc;
-        int gen;
-        __u32 index;
+       struct lov_device *ld = lu2lov_dev(d);
+       struct obd_device *lov_obd = d->ld_obd;
+       struct obd_device *lmv_obd;
+       int next;
+       int rc = 0;
 
-        obd_getref(obd);
+       ENTRY;
 
-        cmd = cfg->lcfg_command;
-        rc = lov_process_config_base(d->ld_obd, cfg, &index, &gen);
-        if (rc == 0) {
-                switch(cmd) {
-                case LCFG_LOV_ADD_OBD:
-                case LCFG_LOV_ADD_INA:
-                        rc = lov_cl_add_target(env, d, index);
-                        if (rc != 0)
-                               lov_del_target(d->ld_obd, index, NULL, 0);
-                        break;
-                case LCFG_LOV_DEL_OBD:
-                        lov_cl_del_target(env, d, index);
-                        break;
-                }
-        }
-        obd_putref(obd);
-        RETURN(rc);
+       LASSERT(mdc != NULL);
+       if (ld->ld_md_tgts_nr == LOV_MDC_TGT_MAX) {
+               /* If the maximum value of LOV_MDC_TGT_MAX will become too
+                * small then all MD target handling must be rewritten in LOD
+                * manner, check lod_add_device() and related functionality.
+                */
+               CERROR("%s: cannot serve more than %d MDC devices\n",
+                      lov_obd->obd_name, LOV_MDC_TGT_MAX);
+               RETURN(-ERANGE);
+       }
+
+       /* grab FLD from lmv, do that here, when first MDC is added
+        * to be sure LMV is set up and can be found */
+       if (ld->ld_lmv == NULL) {
+               next = 0;
+               while ((lmv_obd = class_devices_in_group(&lov_obd->obd_uuid,
+                                                        &next)) != NULL) {
+                       if ((strncmp(lmv_obd->obd_type->typ_name,
+                                    LUSTRE_LMV_NAME,
+                                    strlen(LUSTRE_LMV_NAME)) == 0))
+                               break;
+               }
+               if (lmv_obd == NULL) {
+                       CERROR("%s: cannot find LMV OBD by UUID (%s)\n",
+                              lov_obd->obd_name,
+                              obd_uuid2str(&lmv_obd->obd_uuid));
+                       RETURN(-ENODEV);
+               }
+               spin_lock(&lmv_obd->obd_dev_lock);
+               class_incref(lmv_obd, "lov", ld);
+               spin_unlock(&lmv_obd->obd_dev_lock);
+               ld->ld_lmv = lmv_obd;
+       }
+
+       LASSERT(lov_obd->u.lov.lov_mdc_tgts[ld->ld_md_tgts_nr].lmtd_mdc ==
+               NULL);
+
+       if (ld->ld_flags & LOV_DEV_INITIALIZED) {
+               rc = lov_mdc_dev_init(env, ld, mdc->obd_lu_dev, idx,
+                                     ld->ld_md_tgts_nr);
+               if (rc) {
+                       CERROR("%s: failed to add MDC %s as target: rc = %d\n",
+                              lov_obd->obd_name, obd_uuid2str(&mdc->obd_uuid),
+                              rc);
+                       RETURN(rc);
+               }
+       }
+
+       lov_obd->u.lov.lov_mdc_tgts[ld->ld_md_tgts_nr].lmtd_mdc = mdc;
+       lov_obd->u.lov.lov_mdc_tgts[ld->ld_md_tgts_nr].lmtd_index = idx;
+       ld->ld_md_tgts_nr++;
+
+       RETURN(rc);
+}
+
+static int lov_process_config(const struct lu_env *env,
+                              struct lu_device *d, struct lustre_cfg *cfg)
+{
+       struct obd_device *obd = d->ld_obd;
+       int cmd;
+       int rc;
+       int gen;
+       __u32 index;
+
+       obd_getref(obd);
+
+       cmd = cfg->lcfg_command;
+
+       rc = lov_process_config_base(d->ld_obd, cfg, &index, &gen);
+       if (rc < 0)
+               GOTO(out, rc);
+
+       switch (cmd) {
+       case LCFG_LOV_ADD_OBD:
+       case LCFG_LOV_ADD_INA:
+               rc = lov_cl_add_target(env, d, index);
+               if (rc != 0)
+                       lov_del_target(d->ld_obd, index, NULL, 0);
+               break;
+       case LCFG_LOV_DEL_OBD:
+               lov_cl_del_target(env, d, index);
+               break;
+       case LCFG_ADD_MDC:
+       {
+               struct obd_device       *mdc;
+               struct obd_uuid          tgt_uuid;
+
+               /* modify_mdc_tgts add 0:lustre-clilmv  1:lustre-MDT0000_UUID
+                * 2:0  3:1  4:lustre-MDT0000-mdc_UUID */
+               if (LUSTRE_CFG_BUFLEN(cfg, 1) > sizeof(tgt_uuid.uuid))
+                       GOTO(out, rc = -EINVAL);
+
+               obd_str2uuid(&tgt_uuid, lustre_cfg_buf(cfg, 1));
+
+               if (sscanf(lustre_cfg_buf(cfg, 2), "%d", &index) != 1)
+                       GOTO(out, rc = -EINVAL);
+
+               mdc = class_find_client_obd(&tgt_uuid, LUSTRE_MDC_NAME,
+                                           &obd->obd_uuid);
+               if (mdc == NULL)
+                       GOTO(out, rc = -ENODEV);
+               rc = lov_add_mdc_target(env, d, mdc, index);
+               break;
+       }
+       }
+out:
+       obd_putref(obd);
+       RETURN(rc);
 }
 
 static const struct lu_device_operations lov_lu_ops = {
@@ -359,13 +527,45 @@ static struct lu_device *lov_device_alloc(const struct lu_env *env,
         obd = class_name2obd(lustre_cfg_string(cfg, 0));
         LASSERT(obd != NULL);
         rc = lov_setup(obd, cfg);
-        if (rc) {
-                lov_device_free(env, d);
-                RETURN(ERR_PTR(rc));
-        }
+       if (rc)
+               GOTO(out, rc);
+
+       /* Alloc MDC devices array */
+       /* XXX: need dynamic allocation at some moment */
+       OBD_ALLOC(ld->ld_md_tgts, sizeof(*ld->ld_md_tgts) * LOV_MDC_TGT_MAX);
+       if (ld->ld_md_tgts == NULL)
+               GOTO(out, rc = -ENOMEM);
+
+       ld->ld_md_tgts_nr = 0;
+
+       ld->ld_lov = &obd->u.lov;
+       OBD_ALLOC(ld->ld_lov->lov_mdc_tgts,
+                 sizeof(*ld->ld_lov->lov_mdc_tgts) * LOV_MDC_TGT_MAX);
+       if (ld->ld_lov->lov_mdc_tgts == NULL)
+               GOTO(out_md_tgts, rc = -ENOMEM);
+
+       rc = lu_site_init(&ld->ld_site, d);
+       if (rc != 0)
+               GOTO(out_mdc_tgts, rc);
+
+       rc = lu_site_init_finish(&ld->ld_site);
+       if (rc != 0)
+               GOTO(out_site, rc);
+
+       RETURN(d);
+out_site:
+       lu_site_fini(&ld->ld_site);
+out_mdc_tgts:
+       OBD_FREE(ld->ld_lov->lov_mdc_tgts,
+                sizeof(*ld->ld_lov->lov_mdc_tgts) * LOV_MDC_TGT_MAX);
+       ld->ld_lov->lov_mdc_tgts = NULL;
+out_md_tgts:
+       OBD_FREE(ld->ld_md_tgts, sizeof(*ld->ld_md_tgts) * LOV_MDC_TGT_MAX);
+       ld->ld_md_tgts = NULL;
+out:
+       OBD_FREE_PTR(ld);
 
-        ld->ld_lov = &obd->u.lov;
-        RETURN(d);
+       return ERR_PTR(rc);
 }
 
 static const struct lu_device_type_operations lov_device_type_ops = {