+static int lov_get_info(struct obd_export *exp, __u32 keylen,
+ void *key, __u32 *vallen, void *val)
+{
+ struct obd_device *obddev = class_exp2obd(exp);
+ struct lov_obd *lov = &obddev->u.lov;
+ int i;
+ ENTRY;
+
+ if (!vallen || !val)
+ RETURN(-EFAULT);
+
+ if (keylen > strlen("lock_to_stripe") &&
+ strcmp(key, "lock_to_stripe") == 0) {
+ struct {
+ char name[16];
+ struct ldlm_lock *lock;
+ struct lov_stripe_md *lsm;
+ } *data = key;
+ struct lov_oinfo *loi;
+ struct ldlm_res_id *res_id = &data->lock->l_resource->lr_name;
+ __u32 *stripe = val;
+
+ if (*vallen < sizeof(*stripe))
+ RETURN(-EFAULT);
+ *vallen = sizeof(*stripe);
+
+ /* XXX This is another one of those bits that will need to
+ * change if we ever actually support nested LOVs. It uses
+ * the lock's export to find out which stripe it is. */
+ /* XXX - it's assumed all the locks for deleted OSTs have
+ * been cancelled. Also, the export for deleted OSTs will
+ * be NULL and won't match the lock's export. */
+ for (i = 0, loi = data->lsm->lsm_oinfo;
+ i < data->lsm->lsm_stripe_count;
+ i++, loi++) {
+ if (lov->tgts[loi->loi_ost_idx].ltd_exp ==
+ data->lock->l_conn_export &&
+ loi->loi_id == res_id->name[0] &&
+ loi->loi_gr == res_id->name[2]) {
+ *stripe = i;
+ RETURN(0);
+ }
+ }
+ LDLM_ERROR(data->lock, "lock on inode without such object\n");
+ dump_lsm(D_ERROR, data->lsm);
+ RETURN(-ENXIO);
+ } else if (keylen >= strlen("size_to_stripe") &&
+ strcmp(key, "size_to_stripe") == 0) {
+ struct {
+ int stripe_number;
+ __u64 size;
+ struct lov_stripe_md *lsm;
+ } *data = val;
+
+ if (*vallen < sizeof(*data))
+ RETURN(-EFAULT);
+
+ data->size = lov_size_to_stripe(data->lsm, data->size,
+ data->stripe_number);
+ RETURN(0);
+ } else if (keylen >= strlen("last_id") && strcmp(key, "last_id") == 0) {
+ __u32 size = sizeof(obd_id);
+ obd_id *ids = val;
+ int rc = 0;
+
+ for (i = 0; i < lov->desc.ld_tgt_count; i++) {
+ if (!lov->tgts[i].active)
+ continue;
+ rc = obd_get_info(lov->tgts[i].ltd_exp,
+ keylen, key, &size, &(ids[i]));
+ if (rc != 0)
+ RETURN(rc);
+ }
+ RETURN(0);
+ } else if (keylen >= strlen("lovdesc") && strcmp(key, "lovdesc") == 0) {
+ struct lov_desc *desc_ret = val;
+ *desc_ret = lov->desc;
+
+ RETURN(0);
+ }
+
+ RETURN(-EINVAL);
+}
+
+static int lov_set_info(struct obd_export *exp, obd_count keylen,
+ void *key, obd_count vallen, void *val)
+{
+ struct obd_device *obddev = class_exp2obd(exp);
+ struct lov_obd *lov = &obddev->u.lov;
+ int i, rc = 0, err;
+ ENTRY;
+
+#define KEY_IS(str) \
+ (keylen == strlen(str) && memcmp(key, str, keylen) == 0)
+
+ if (KEY_IS("async")) {
+ struct lov_desc *desc = &lov->desc;
+ struct lov_tgt_desc *tgts = lov->tgts;
+
+ if (vallen != sizeof(int))
+ RETURN(-EINVAL);
+ lov->async = *((int*) val);
+
+ for (i = 0; i < desc->ld_tgt_count; i++, tgts++) {
+ struct obd_uuid *tgt_uuid = &tgts->uuid;
+ struct obd_device *tgt_obd;
+
+ tgt_obd = class_find_client_obd(tgt_uuid,
+ LUSTRE_OSC_NAME,
+ &obddev->obd_uuid);
+ if (!tgt_obd) {
+ CERROR("Target %s not attached\n",
+ tgt_uuid->uuid);
+ if (!rc)
+ rc = -EINVAL;
+ continue;
+ }
+
+ err = obd_set_info(tgt_obd->obd_self_export,
+ keylen, key, vallen, val);
+ if (err) {
+ CERROR("Failed to set async on target %s\n",
+ tgt_obd->obd_name);
+ if (!rc)
+ rc = err;
+ }
+ }
+ RETURN(rc);
+ }
+
+ if (KEY_IS("mds_conn")) {
+ if (vallen != sizeof(__u32))
+ RETURN(-EINVAL);
+ } else if (KEY_IS("unlinked") || KEY_IS("unrecovery")) {
+ if (vallen != 0)
+ RETURN(-EINVAL);
+ } else if (KEY_IS("sec")) {
+ struct lov_tgt_desc *tgt;
+ struct obd_export *exp;
+ int rc = 0, err, i;
+
+ spin_lock(&lov->lov_lock);
+ for (i = 0, tgt = lov->tgts; i < lov->desc.ld_tgt_count;
+ i++, tgt++) {
+ exp = tgt->ltd_exp;
+ /* during setup time the connections to osc might
+ * haven't been established.
+ */
+ if (exp == NULL) {
+ struct obd_device *tgt_obd;
+
+ tgt_obd = class_find_client_obd(&tgt->uuid,
+ LUSTRE_OSC_NAME,
+ &obddev->obd_uuid);
+ if (!tgt_obd) {
+ CERROR("can't set security flavor, "
+ "device %s not attached?\n",
+ tgt->uuid.uuid);
+ rc = -EINVAL;
+ continue;
+ }
+ exp = tgt_obd->obd_self_export;
+ }
+
+ err = obd_set_info(exp, keylen, key, vallen, val);
+ if (!rc)
+ rc = err;
+ }
+ spin_unlock(&lov->lov_lock);
+
+ RETURN(rc);
+ } else if (KEY_IS("flush_cred")) {
+ struct lov_tgt_desc *tgt;
+ int rc = 0, i;
+
+ for (i = 0, tgt = lov->tgts; i < lov->desc.ld_tgt_count;
+ i++, tgt++) {
+ if (!tgt->ltd_exp)
+ continue;
+ rc = obd_set_info(tgt->ltd_exp,
+ keylen, key, vallen, val);
+ if (rc)
+ RETURN(rc);
+ }
+
+ RETURN(0);
+ } else {
+ RETURN(-EINVAL);
+ }
+
+ for (i = 0; i < lov->desc.ld_tgt_count; i++) {
+ if (val && !obd_uuid_equals(val, &lov->tgts[i].uuid))
+ continue;
+
+ if (!val && !lov->tgts[i].active)
+ continue;
+
+ err = obd_set_info(lov->tgts[i].ltd_exp,
+ keylen, key, vallen, val);
+ if (!rc)
+ rc = err;
+ }
+ RETURN(rc);
+#undef KEY_IS
+}
+
+#if 0
+struct lov_multi_wait {
+ struct ldlm_lock *lock;
+ wait_queue_t wait;
+ int completed;
+ int generation;
+};
+
+int lov_complete_many(struct obd_export *exp, struct lov_stripe_md *lsm,
+ struct lustre_handle *lockh)
+{
+ struct lov_lock_handles *lov_lockh = NULL;
+ struct lustre_handle *lov_lockhp;
+ struct lov_obd *lov;
+ struct lov_oinfo *loi;
+ struct lov_multi_wait *queues;
+ int rc = 0, i;
+ ENTRY;
+
+ if (lsm_bad_magic(lsm))
+ RETURN(-EINVAL);
+
+ if (!exp || !exp->exp_obd)
+ RETURN(-ENODEV);
+
+ LASSERT(lockh != NULL);
+ if (lsm->lsm_stripe_count > 1) {
+ lov_lockh = lov_handle2llh(lockh);
+ if (lov_lockh == NULL) {
+ CERROR("LOV: invalid lov lock handle %p\n", lockh);
+ RETURN(-EINVAL);
+ }
+
+ lov_lockhp = lov_lockh->llh_handles;
+ } else {
+ lov_lockhp = lockh;
+ }
+
+ OBD_ALLOC(queues, lsm->lsm_stripe_count * sizeof(*queues));
+ if (queues == NULL)
+ GOTO(out, rc = -ENOMEM);
+
+ lov = &exp->exp_obd->u.lov;
+ for (i = 0, loi = lsm->lsm_oinfo; i < lsm->lsm_stripe_count;
+ i++, loi++, lov_lockhp++) {
+ struct ldlm_lock *lock;
+ struct obd_device *obd;
+ unsigned long irqflags;
+
+ lock = ldlm_handle2lock(lov_lockhp);
+ if (lock == NULL) {
+ CDEBUG(D_HA, "lov idx %d subobj "LPX64" no lock?\n",
+ loi->loi_ost_idx, loi->loi_id);
+ queues[i].completed = 1;
+ continue;
+ }
+
+ queues[i].lock = lock;
+ init_waitqueue_entry(&(queues[i].wait), current);
+ add_wait_queue(lock->l_waitq, &(queues[i].wait));
+
+ obd = class_exp2obd(lock->l_conn_export);
+ if (obd != NULL)
+ imp = obd->u.cli.cl_import;
+ if (imp != NULL) {
+ spin_lock_irqsave(&imp->imp_lock, irqflags);
+ queues[i].generation = imp->imp_generation;
+ spin_unlock_irqrestore(&imp->imp_lock, irqflags);
+ }
+ }
+
+ lwi = LWI_TIMEOUT_INTR(obd_timeout * HZ, ldlm_expired_completion_wait,
+ interrupted_completion_wait, &lwd);
+ rc = l_wait_event_added(check_multi_complete(queues, lsm), &lwi);
+
+ for (i = 0; i < lsm->lsm_stripe_count; i++)
+ remove_wait_queue(lock->l_waitq, &(queues[i].wait));
+
+ if (rc == -EINTR || rc == -ETIMEDOUT) {
+
+
+ }
+
+ out:
+ if (lov_lockh != NULL)
+ lov_llh_put(lov_lockh);
+ RETURN(rc);
+}
+#endif
+