+static int
+lov_add_obd(struct obd_device *obd, struct obd_uuid *uuidp, int index, int gen)
+{
+ struct lov_obd *lov = &obd->u.lov;
+ struct lov_tgt_desc *tgt;
+ struct obd_export *exp_observer;
+ __u32 bufsize;
+ __u32 size = 2;
+ obd_id params[2];
+ char name[32] = "CATLIST";
+ int rc, old_count;
+ ENTRY;
+
+ CDEBUG(D_CONFIG, "uuid: %s idx: %d gen: %d\n",
+ uuidp->uuid, index, gen);
+
+ if (index < 0) {
+ CERROR("request to add OBD %s at invalid index: %d\n",
+ uuidp->uuid, index);
+ RETURN(-EINVAL);
+ }
+
+ if (gen <= 0) {
+ CERROR("request to add OBD %s with invalid generation: %d\n",
+ uuidp->uuid, gen);
+ RETURN(-EINVAL);
+ }
+
+ bufsize = sizeof(struct lov_tgt_desc) * (index + 1);
+ if (bufsize > lov->bufsize) {
+ OBD_ALLOC(tgt, bufsize);
+ if (tgt == NULL) {
+ CERROR("couldn't allocate %d bytes for new table.\n",
+ bufsize);
+ RETURN(-ENOMEM);
+ }
+
+ memset(tgt, 0, bufsize);
+ if (lov->tgts) {
+ memcpy(tgt, lov->tgts, lov->bufsize);
+ OBD_FREE(lov->tgts, lov->bufsize);
+ }
+
+ lov->tgts = tgt;
+ lov->bufsize = bufsize;
+ CDEBUG(D_CONFIG, "tgts: %p bufsize: %d\n",
+ lov->tgts, lov->bufsize);
+ }
+
+ tgt = lov->tgts + index;
+ if (!obd_uuid_empty(&tgt->uuid)) {
+ CERROR("OBD already assigned at LOV target index %d\n",
+ index);
+ RETURN(-EEXIST);
+ }
+
+ tgt->uuid = *uuidp;
+ /* XXX - add a sanity check on the generation number. */
+ tgt->ltd_gen = gen;
+
+ old_count = lov->desc.ld_tgt_count;
+ if (index >= lov->desc.ld_tgt_count)
+ lov->desc.ld_tgt_count = index + 1;
+
+ CDEBUG(D_CONFIG, "idx: %d ltd_gen: %d ld_tgt_count: %d\n",
+ index, tgt->ltd_gen, lov->desc.ld_tgt_count);
+
+ if (lov->refcount == 0)
+ RETURN(0);
+
+ if (tgt->ltd_exp) {
+ struct obd_device *osc_obd;
+
+ osc_obd = class_exp2obd(tgt->ltd_exp);
+ if (osc_obd)
+ osc_obd->obd_no_recov = 0;
+ }
+
+ rc = lov_connect_obd(obd, tgt, 1);
+ if (rc || !obd->obd_observer)
+ RETURN(rc);
+
+ /* tell the mds_lov about the new target */
+ obd_llog_finish(obd->obd_observer, &obd->obd_observer->obd_llogs,
+ old_count);
+ obd_llog_cat_initialize(obd->obd_observer,
+ &obd->obd_observer->obd_llogs,
+ lov->desc.ld_tgt_count, name);
+
+ params[0] = index;
+ rc = obd_get_info(tgt->ltd_exp, strlen("last_id"), "last_id", &size,
+ ¶ms[1]);
+ if (rc)
+ GOTO(out, rc);
+
+ exp_observer = obd->obd_observer->obd_self_export;
+ rc = obd_set_info(exp_observer, strlen("next_id"),"next_id", 2, params);
+ if (rc)
+ GOTO(out, rc);
+
+ rc = lov_notify(obd, tgt->ltd_exp->exp_obd, 1);
+ GOTO(out, rc);
+ out:
+ if (rc && tgt->ltd_exp != NULL)
+ lov_disconnect_obd(obd, tgt, 0);
+ return rc;
+}
+
+static int
+lov_del_obd(struct obd_device *obd, struct obd_uuid *uuidp, int index, int gen)
+{
+ struct lov_obd *lov = &obd->u.lov;
+ struct lov_tgt_desc *tgt;
+ int count = lov->desc.ld_tgt_count;
+ int rc = 0;
+ ENTRY;
+
+ CDEBUG(D_CONFIG, "uuid: %s idx: %d gen: %d\n",
+ uuidp->uuid, index, gen);
+
+ if (index >= count) {
+ CERROR("LOV target index %d >= number of LOV OBDs %d.\n",
+ index, count);
+ RETURN(-EINVAL);
+ }
+
+ tgt = lov->tgts + index;
+
+ if (obd_uuid_empty(&tgt->uuid)) {
+ CERROR("LOV target at index %d is not setup.\n", index);
+ RETURN(-EINVAL);
+ }
+
+ if (strncmp(uuidp->uuid, tgt->uuid.uuid, sizeof uuidp->uuid) != 0) {
+ CERROR("LOV target UUID %s at index %d doesn't match %s.\n",
+ tgt->uuid.uuid, index, uuidp->uuid);
+ RETURN(-EINVAL);
+ }
+
+ if (tgt->ltd_exp) {
+ struct obd_device *osc_obd;
+
+ osc_obd = class_exp2obd(tgt->ltd_exp);
+ if (osc_obd) {
+ osc_obd->obd_no_recov = 1;
+ rc = obd_llog_finish(osc_obd, &osc_obd->obd_llogs, 1);
+ if (rc)
+ CERROR("osc_llog_finish error: %d\n", rc);
+ }
+ lov_disconnect_obd(obd, tgt, 0);
+ }
+
+ /* XXX - right now there is a dependency on ld_tgt_count being the
+ * maximum tgt index for computing the mds_max_easize. So we can't
+ * shrink it. */
+
+ /* lt_gen = 0 will mean it will not match the gen of any valid loi */
+ memset(tgt, 0, sizeof(*tgt));
+
+ CDEBUG(D_CONFIG, "uuid: %s idx: %d gen: %d exp: %p active: %d\n",
+ tgt->uuid.uuid, index, tgt->ltd_gen, tgt->ltd_exp, tgt->active);
+
+ RETURN(rc);
+}
+
+static int lov_process_config(struct obd_device *obd, obd_count len, void *buf)
+{
+ struct lustre_cfg *lcfg = buf;
+ struct obd_uuid obd_uuid;
+ int cmd;
+ int index;
+ int gen;
+ int rc = 0;
+ ENTRY;
+
+ switch(cmd = lcfg->lcfg_command) {
+ case LCFG_LOV_ADD_OBD:
+ case LCFG_LOV_DEL_OBD: {
+ if (lcfg->lcfg_inllen1 > sizeof(obd_uuid.uuid))
+ GOTO(out, rc = -EINVAL);
+
+ obd_str2uuid(&obd_uuid, lcfg->lcfg_inlbuf1);
+
+ if (sscanf(lcfg->lcfg_inlbuf2, "%d", &index) != 1)
+ GOTO(out, rc = -EINVAL);
+ if (sscanf(lcfg->lcfg_inlbuf3, "%d", &gen) != 1)
+ GOTO(out, rc = -EINVAL);
+ if (cmd == LCFG_LOV_ADD_OBD)
+ rc = lov_add_obd(obd, &obd_uuid, index, gen);
+ else
+ rc = lov_del_obd(obd, &obd_uuid, index, gen);
+ GOTO(out, rc);
+ }
+ default: {
+ CERROR("Unknown command: %d\n", lcfg->lcfg_command);
+ GOTO(out, rc = -EINVAL);
+
+ }
+ }
+out:
+ RETURN(rc);
+}
+