+out:
+ lu_env_fini(&env);
+ RETURN(rc);
+}
+
+static int mgs_connect_to_osd(struct mgs_device *m, const char *nextdev)
+{
+ struct obd_connect_data *data = NULL;
+ struct obd_device *obd;
+ int rc;
+ ENTRY;
+
+ OBD_ALLOC_PTR(data);
+ if (data == NULL)
+ RETURN(-ENOMEM);
+
+ obd = class_name2obd(nextdev);
+ if (obd == NULL) {
+ CERROR("can't locate next device: %s\n", nextdev);
+ GOTO(out, rc = -ENOTCONN);
+ }
+
+ data->ocd_version = LUSTRE_VERSION_CODE;
+
+ rc = obd_connect(NULL, &m->mgs_bottom_exp, obd,
+ &obd->obd_uuid, data, NULL);
+ if (rc) {
+ CERROR("cannot connect to next dev %s (%d)\n", nextdev, rc);
+ GOTO(out, rc);
+ }
+
+ m->mgs_bottom = lu2dt_dev(m->mgs_bottom_exp->exp_obd->obd_lu_dev);
+ m->mgs_dt_dev.dd_lu_dev.ld_site = m->mgs_bottom->dd_lu_dev.ld_site;
+ LASSERT(m->mgs_dt_dev.dd_lu_dev.ld_site);
+out:
+ OBD_FREE_PTR(data);
+ RETURN(rc);
+}
+
+static struct tgt_handler mgs_mgs_handlers[] = {
+TGT_RPC_HANDLER(MGS_FIRST_OPC,
+ 0, MGS_CONNECT, mgs_connect,
+ &RQF_CONNECT, LUSTRE_OBD_VERSION),
+TGT_RPC_HANDLER(MGS_FIRST_OPC,
+ 0, MGS_DISCONNECT, mgs_disconnect,
+ &RQF_MDS_DISCONNECT, LUSTRE_OBD_VERSION),
+TGT_MGS_HDL_VAR(0, MGS_EXCEPTION, mgs_exception),
+TGT_MGS_HDL (HABEO_REFERO | MUTABOR, MGS_SET_INFO, mgs_set_info),
+TGT_MGS_HDL (HABEO_REFERO | MUTABOR, MGS_TARGET_REG, mgs_target_reg),
+TGT_MGS_HDL_VAR(0, MGS_TARGET_DEL, mgs_target_del),
+TGT_MGS_HDL (HABEO_REFERO, MGS_CONFIG_READ, mgs_config_read),
+};
+
+static struct tgt_handler mgs_obd_handlers[] = {
+TGT_OBD_HDL(0, OBD_PING, tgt_obd_ping),
+};
+
+static struct tgt_handler mgs_dlm_handlers[] = {
+[LDLM_ENQUEUE - LDLM_FIRST_OPC] = {
+ .th_name = "LDLM_ENQUEUE",
+ /* don't use th_fail_id for MGS to don't interfere with MDS tests.
+ * * There are no tests for MGS with OBD_FAIL_LDLM_ENQUEUE_NET so it
+ * * is safe. If such tests will be needed we have to distinguish
+ * * MDS and MGS fail ids, e.g use OBD_FAIL_MGS_ENQUEUE_NET for MGS
+ * * instead of common OBD_FAIL_LDLM_ENQUEUE_NET */
+ .th_fail_id = 0,
+ .th_opc = LDLM_ENQUEUE,
+ .th_flags = HABEO_CLAVIS,
+ .th_act = tgt_enqueue,
+ .th_fmt = &RQF_LDLM_ENQUEUE,
+ .th_version = LUSTRE_DLM_VERSION,
+ },
+};
+
+static struct tgt_handler mgs_llog_handlers[] = {
+TGT_LLOG_HDL (0, LLOG_ORIGIN_HANDLE_CREATE, mgs_llog_open),
+TGT_LLOG_HDL (0, LLOG_ORIGIN_HANDLE_NEXT_BLOCK, tgt_llog_next_block),
+TGT_LLOG_HDL (0, LLOG_ORIGIN_HANDLE_READ_HEADER, tgt_llog_read_header),
+TGT_LLOG_HDL_VAR(0, LLOG_ORIGIN_HANDLE_CLOSE, tgt_llog_close),
+TGT_LLOG_HDL (0, LLOG_ORIGIN_HANDLE_PREV_BLOCK, tgt_llog_prev_block),
+};
+
+static struct tgt_opc_slice mgs_common_slice[] = {
+ {
+ .tos_opc_start = MGS_FIRST_OPC,
+ .tos_opc_end = MGS_LAST_OPC,
+ .tos_hs = mgs_mgs_handlers
+ },
+ {
+ .tos_opc_start = OBD_FIRST_OPC,
+ .tos_opc_end = OBD_LAST_OPC,
+ .tos_hs = mgs_obd_handlers
+ },
+ {
+ .tos_opc_start = LDLM_FIRST_OPC,
+ .tos_opc_end = LDLM_LAST_OPC,
+ .tos_hs = mgs_dlm_handlers
+ },
+ {
+ .tos_opc_start = LLOG_FIRST_OPC,
+ .tos_opc_end = LLOG_LAST_OPC,
+ .tos_hs = mgs_llog_handlers
+ },
+ {
+ .tos_opc_start = SEC_FIRST_OPC,
+ .tos_opc_end = SEC_LAST_OPC,
+ .tos_hs = tgt_sec_ctx_handlers
+ },
+ {
+ .tos_hs = NULL
+ }
+};
+
+static int mgs_init0(const struct lu_env *env, struct mgs_device *mgs,
+ struct lu_device_type *ldt, struct lustre_cfg *lcfg)
+{
+ struct ptlrpc_service_conf conf;
+ struct obd_device *obd;
+ struct lustre_mount_info *lmi;
+ struct llog_ctxt *ctxt;
+ int rc;
+
+ ENTRY;
+
+ lmi = server_get_mount(lustre_cfg_string(lcfg, 0));
+ if (lmi == NULL)
+ RETURN(-ENODEV);
+
+ mgs->mgs_dt_dev.dd_lu_dev.ld_ops = &mgs_lu_ops;
+
+ rc = mgs_connect_to_osd(mgs, lustre_cfg_string(lcfg, 3));
+ if (rc)
+ GOTO(err_lmi, rc);
+
+ obd = class_name2obd(lustre_cfg_string(lcfg, 0));
+ LASSERT(obd);
+ mgs->mgs_obd = obd;
+ mgs->mgs_obd->obd_lu_dev = &mgs->mgs_dt_dev.dd_lu_dev;
+
+ obd->u.obt.obt_magic = OBT_MAGIC;
+ obd->u.obt.obt_instance = 0;
+
+ /* namespace for mgs llog */
+ obd->obd_namespace = ldlm_namespace_new(obd ,"MGS",
+ LDLM_NAMESPACE_SERVER,
+ LDLM_NAMESPACE_MODEST,
+ LDLM_NS_TYPE_MGT);
+ if (obd->obd_namespace == NULL)
+ GOTO(err_ops, rc = -ENOMEM);
+
+ /* No recovery for MGCs */
+ obd->obd_replayable = 0;
+
+ rc = tgt_init(env, &mgs->mgs_lut, obd, mgs->mgs_bottom,
+ mgs_common_slice, OBD_FAIL_MGS_ALL_REQUEST_NET,
+ OBD_FAIL_MGS_ALL_REPLY_NET);
+ if (rc)
+ GOTO(err_ns, rc);
+
+ rc = mgs_fs_setup(env, mgs);
+ if (rc) {
+ CERROR("%s: MGS filesystem method init failed: rc = %d\n",
+ obd->obd_name, rc);
+ GOTO(err_tgt, rc);
+ }
+
+ rc = llog_setup(env, obd, &obd->obd_olg, LLOG_CONFIG_ORIG_CTXT,
+ obd, &llog_osd_ops);
+ if (rc)
+ GOTO(err_fs, rc);
+
+ /* XXX: we need this trick till N:1 stack is supported
+ * set "current" directory for named llogs */
+ ctxt = llog_get_context(mgs->mgs_obd, LLOG_CONFIG_ORIG_CTXT);
+ LASSERT(ctxt);
+ ctxt->loc_dir = mgs->mgs_configs_dir;
+ llog_ctxt_put(ctxt);
+
+ /* Internal mgs setup */
+ mgs_init_fsdb_list(mgs);
+ mutex_init(&mgs->mgs_mutex);
+ mgs->mgs_start_time = cfs_time_current_sec();
+ spin_lock_init(&mgs->mgs_lock);
+
+ rc = lproc_mgs_setup(mgs, lustre_cfg_string(lcfg, 3));
+ if (rc != 0) {
+ CERROR("%s: cannot initialize proc entry: rc = %d\n",
+ obd->obd_name, rc);
+ GOTO(err_llog, rc);
+ }
+
+ ptlrpc_init_client(LDLM_CB_REQUEST_PORTAL, LDLM_CB_REPLY_PORTAL,
+ "mgs_ldlm_client", &obd->obd_ldlm_client);
+
+ conf = (typeof(conf)) {
+ .psc_name = LUSTRE_MGS_NAME,
+ .psc_watchdog_factor = MGS_SERVICE_WATCHDOG_FACTOR,
+ .psc_buf = {
+ .bc_nbufs = MGS_NBUFS,
+ .bc_buf_size = MGS_BUFSIZE,
+ .bc_req_max_size = MGS_MAXREQSIZE,
+ .bc_rep_max_size = MGS_MAXREPSIZE,
+ .bc_req_portal = MGS_REQUEST_PORTAL,
+ .bc_rep_portal = MGC_REPLY_PORTAL,
+ },
+ .psc_thr = {
+ .tc_thr_name = "ll_mgs",
+ .tc_nthrs_init = MGS_NTHRS_INIT,
+ .tc_nthrs_max = MGS_NTHRS_MAX,
+ .tc_ctx_tags = LCT_MG_THREAD,
+ },
+ .psc_ops = {
+ .so_req_handler = tgt_request_handle,
+ .so_req_printer = target_print_req,
+ },
+ };
+
+ /* Start the service threads */
+ mgs->mgs_service = ptlrpc_register_service(&conf, obd->obd_proc_entry);
+ if (IS_ERR(mgs->mgs_service)) {
+ rc = PTR_ERR(mgs->mgs_service);
+ CERROR("failed to start mgs service: %d\n", rc);
+ mgs->mgs_service = NULL;
+ GOTO(err_lproc, rc);
+ }
+
+ ping_evictor_start();
+
+ CDEBUG(D_INFO, "MGS %s started\n", obd->obd_name);
+
+ /* device stack is not yet fully setup to keep no objects behind */
+ lu_site_purge(env, mgs2lu_dev(mgs)->ld_site, ~0);
+ RETURN(0);
+err_lproc:
+ lproc_mgs_cleanup(mgs);
+err_llog:
+ ctxt = llog_get_context(mgs->mgs_obd, LLOG_CONFIG_ORIG_CTXT);
+ if (ctxt) {
+ ctxt->loc_dir = NULL;
+ llog_cleanup(env, ctxt);
+ }
+err_tgt:
+ tgt_fini(env, &mgs->mgs_lut);
+err_fs:
+ /* No extra cleanup needed for llog_init_commit_thread() */
+ mgs_fs_cleanup(env, mgs);
+err_ns:
+ ldlm_namespace_free(obd->obd_namespace, NULL, 0);
+ obd->obd_namespace = NULL;
+err_ops:
+ lu_site_purge(env, mgs2lu_dev(mgs)->ld_site, ~0);
+ if (!cfs_hash_is_empty(mgs2lu_dev(mgs)->ld_site->ls_obj_hash)) {
+ LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, D_ERROR, NULL);
+ lu_site_print(env, mgs2lu_dev(mgs)->ld_site, &msgdata,
+ lu_cdebug_printer);
+ }
+ obd_disconnect(mgs->mgs_bottom_exp);
+err_lmi:
+ if (lmi)
+ server_put_mount(lustre_cfg_string(lcfg, 0), lmi->lmi_mnt);
+ RETURN(rc);
+}
+
+static struct lu_device *mgs_device_free(const struct lu_env *env,
+ struct lu_device *lu)
+{
+ struct mgs_device *mgs = lu2mgs_dev(lu);
+ ENTRY;
+
+ dt_device_fini(&mgs->mgs_dt_dev);
+ OBD_FREE_PTR(mgs);
+ RETURN(NULL);
+}
+
+static int mgs_process_config(const struct lu_env *env,
+ struct lu_device *dev,
+ struct lustre_cfg *lcfg)
+{
+ LBUG();
+ return 0;
+}
+
+static int mgs_object_init(const struct lu_env *env, struct lu_object *o,
+ const struct lu_object_conf *unused)
+{
+ struct mgs_device *d = lu2mgs_dev(o->lo_dev);
+ struct lu_device *under;
+ struct lu_object *below;
+ int rc = 0;
+ ENTRY;
+
+ /* do no set .do_ops as mgs calls to bottom osd directly */
+
+ CDEBUG(D_INFO, "object init, fid = "DFID"\n",
+ PFID(lu_object_fid(o)));
+
+ under = &d->mgs_bottom->dd_lu_dev;
+ below = under->ld_ops->ldo_object_alloc(env, o->lo_header, under);
+ if (below != NULL)
+ lu_object_add(o, below);
+ else
+ rc = -ENOMEM;
+
+ return 0;
+}
+
+static void mgs_object_free(const struct lu_env *env, struct lu_object *o)
+{
+ struct mgs_object *obj = lu2mgs_obj(o);
+ struct lu_object_header *h = o->lo_header;
+
+ dt_object_fini(&obj->mgo_obj);
+ lu_object_header_fini(h);
+ OBD_FREE_PTR(obj);
+}
+
+static int mgs_object_print(const struct lu_env *env, void *cookie,
+ lu_printer_t p, const struct lu_object *l)
+{
+ const struct mgs_object *o = lu2mgs_obj((struct lu_object *) l);
+
+ return (*p)(env, cookie, LUSTRE_MGS_NAME"-object@%p", o);
+}
+
+struct lu_object_operations mgs_lu_obj_ops = {
+ .loo_object_init = mgs_object_init,
+ .loo_object_free = mgs_object_free,
+ .loo_object_print = mgs_object_print,
+};
+
+struct lu_object *mgs_object_alloc(const struct lu_env *env,
+ const struct lu_object_header *hdr,
+ struct lu_device *d)
+{
+ struct lu_object_header *h;
+ struct mgs_object *o;
+ struct lu_object *l;
+
+ LASSERT(hdr == NULL);
+
+ OBD_ALLOC_PTR(o);
+ if (o != NULL) {
+ l = &o->mgo_obj.do_lu;
+ h = &o->mgo_header;
+
+ lu_object_header_init(h);
+ dt_object_init(&o->mgo_obj, h, d);
+ lu_object_add_top(h, l);
+
+ l->lo_ops = &mgs_lu_obj_ops;
+
+ return l;
+ } else {
+ return NULL;
+ }
+}
+
+const struct lu_device_operations mgs_lu_ops = {
+ .ldo_object_alloc = mgs_object_alloc,
+ .ldo_process_config = mgs_process_config,
+};
+
+static struct lu_device *mgs_device_alloc(const struct lu_env *env,
+ struct lu_device_type *type,
+ struct lustre_cfg *lcfg)
+{
+ struct mgs_device *mgs;
+ struct lu_device *ludev;
+
+ OBD_ALLOC_PTR(mgs);
+ if (mgs == NULL) {
+ ludev = ERR_PTR(-ENOMEM);
+ } else {
+ int rc;
+
+ ludev = mgs2lu_dev(mgs);
+ dt_device_init(&mgs->mgs_dt_dev, type);
+ rc = mgs_init0(env, mgs, type, lcfg);
+ if (rc != 0) {
+ mgs_device_free(env, ludev);
+ ludev = ERR_PTR(rc);
+ }
+ }
+ return ludev;
+}
+
+static struct lu_device *mgs_device_fini(const struct lu_env *env,
+ struct lu_device *d)
+{
+ struct mgs_device *mgs = lu2mgs_dev(d);
+ struct obd_device *obd = mgs->mgs_obd;
+ struct llog_ctxt *ctxt;
+
+ ENTRY;
+
+ LASSERT(mgs->mgs_bottom);
+
+ class_disconnect_exports(obd);
+
+ ping_evictor_stop();
+
+ ptlrpc_unregister_service(mgs->mgs_service);
+
+ obd_exports_barrier(obd);
+ obd_zombie_barrier();
+
+ tgt_fini(env, &mgs->mgs_lut);
+ mgs_cleanup_fsdb_list(mgs);
+ lproc_mgs_cleanup(mgs);
+
+ ctxt = llog_get_context(mgs->mgs_obd, LLOG_CONFIG_ORIG_CTXT);
+ if (ctxt) {
+ ctxt->loc_dir = NULL;
+ llog_cleanup(env, ctxt);
+ }
+
+ mgs_fs_cleanup(env, mgs);
+
+ ldlm_namespace_free(obd->obd_namespace, NULL, 1);
+ obd->obd_namespace = NULL;
+
+ lu_site_purge(env, d->ld_site, ~0);
+ if (!cfs_hash_is_empty(d->ld_site->ls_obj_hash)) {
+ LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, D_ERROR, NULL);
+ lu_site_print(env, d->ld_site, &msgdata, lu_cdebug_printer);
+ }
+
+ LASSERT(mgs->mgs_bottom_exp);
+ obd_disconnect(mgs->mgs_bottom_exp);
+
+ server_put_mount(obd->obd_name, NULL);
+
+ RETURN(NULL);
+}
+
+/* context key constructor/destructor: mgs_key_init, mgs_key_fini */
+LU_KEY_INIT_FINI(mgs, struct mgs_thread_info);
+
+LU_TYPE_INIT_FINI(mgs, &mgs_thread_key);
+
+LU_CONTEXT_KEY_DEFINE(mgs, LCT_MG_THREAD);
+
+static struct lu_device_type_operations mgs_device_type_ops = {
+ .ldto_init = mgs_type_init,
+ .ldto_fini = mgs_type_fini,
+
+ .ldto_start = mgs_type_start,
+ .ldto_stop = mgs_type_stop,
+
+ .ldto_device_alloc = mgs_device_alloc,
+ .ldto_device_free = mgs_device_free,
+
+ .ldto_device_fini = mgs_device_fini
+};
+
+static struct lu_device_type mgs_device_type = {
+ .ldt_tags = LU_DEVICE_DT,
+ .ldt_name = LUSTRE_MGS_NAME,
+ .ldt_ops = &mgs_device_type_ops,
+ .ldt_ctx_tags = LCT_MG_THREAD
+};
+
+static int mgs_obd_connect(const struct lu_env *env, struct obd_export **exp,
+ struct obd_device *obd, struct obd_uuid *cluuid,
+ struct obd_connect_data *data, void *localdata)
+{
+ struct obd_export *lexp;
+ struct lustre_handle conn = { 0 };
+ int rc;
+
+ ENTRY;
+
+ if (exp == NULL || obd == NULL || cluuid == NULL)
+ RETURN(-EINVAL);
+
+ rc = class_connect(&conn, obd, cluuid);
+ if (rc)
+ RETURN(rc);
+
+ lexp = class_conn2export(&conn);
+ if (lexp == NULL)
+ RETURN(-EFAULT);
+
+ if (data != NULL) {
+ data->ocd_connect_flags &= MGS_CONNECT_SUPPORTED;
+ data->ocd_version = LUSTRE_VERSION_CODE;
+ lexp->exp_connect_data = *data;
+ }
+
+ tgt_counter_incr(lexp, LPROC_MGS_CONNECT);
+
+ rc = mgs_export_stats_init(obd, lexp, localdata);
+ if (rc)
+ class_disconnect(lexp);
+ else
+ *exp = lexp;
+
+ RETURN(rc);
+}
+
+static int mgs_obd_reconnect(const struct lu_env *env, struct obd_export *exp,
+ struct obd_device *obd, struct obd_uuid *cluuid,
+ struct obd_connect_data *data, void *localdata)
+{
+ ENTRY;
+
+ if (exp == NULL || obd == NULL || cluuid == NULL)
+ RETURN(-EINVAL);
+
+ tgt_counter_incr(exp, LPROC_MGS_CONNECT);
+
+ if (data != NULL) {
+ data->ocd_connect_flags &= MGS_CONNECT_SUPPORTED;
+ data->ocd_version = LUSTRE_VERSION_CODE;
+ exp->exp_connect_data = *data;
+ }
+
+ RETURN(mgs_export_stats_init(obd, exp, localdata));
+}
+
+static int mgs_obd_disconnect(struct obd_export *exp)
+{
+ int rc;
+
+ ENTRY;
+
+ LASSERT(exp);
+
+ mgs_fsc_cleanup(exp);
+
+ class_export_get(exp);
+ tgt_counter_incr(exp, LPROC_MGS_DISCONNECT);
+
+ rc = server_disconnect_export(exp);
+ class_export_put(exp);
+ RETURN(rc);