+ LBUG ();
+ }
+
+ return (0);
+}
+
+static int
+echo_client_enqueue(struct obd_export *exp, struct obdo *oa,
+ int mode, obd_off offset, obd_size nob)
+{
+ struct obd_device *obd = exp->exp_obd;
+ struct echo_client_obd *ec = &obd->u.echo_client;
+ struct lustre_handle *ulh = obdo_handle (oa);
+ struct ldlm_enqueue_info einfo = { 0 };
+ struct obd_info oinfo = { { { 0 } } };
+ struct ec_object *eco;
+ struct ec_lock *ecl;
+ int rc;
+
+ if (!(mode == LCK_PR || mode == LCK_PW))
+ return -EINVAL;
+
+ if ((offset & (~CFS_PAGE_MASK)) != 0 ||
+ (nob & (~CFS_PAGE_MASK)) != 0)
+ return -EINVAL;
+
+ rc = echo_get_object (&eco, obd, oa);
+ if (rc != 0)
+ return rc;
+
+ rc = -ENOMEM;
+ OBD_ALLOC (ecl, sizeof (*ecl));
+ if (ecl == NULL)
+ goto failed_0;
+
+ ecl->ecl_mode = mode;
+ ecl->ecl_object = eco;
+ ecl->ecl_policy.l_extent.start = offset;
+ ecl->ecl_policy.l_extent.end =
+ (nob == 0) ? ((obd_off) -1) : (offset + nob - 1);
+
+ einfo.ei_type = LDLM_EXTENT;
+ einfo.ei_mode = mode;
+ einfo.ei_cb_bl = echo_ldlm_callback;
+ einfo.ei_cb_cp = ldlm_completion_ast;
+ einfo.ei_cb_gl = NULL;
+ einfo.ei_cbdata = eco;
+
+ oinfo.oi_policy = ecl->ecl_policy;
+ oinfo.oi_lockh = &ecl->ecl_lock_handle;
+ oinfo.oi_md = eco->eco_lsm;
+ rc = obd_enqueue(ec->ec_exp, &oinfo, &einfo, NULL);
+ if (rc != 0)
+ goto failed_1;
+
+ CDEBUG(D_INFO, "enqueue handle "LPX64"\n", ecl->ecl_lock_handle.cookie);
+
+ /* NB ecl takes object ref from echo_get_object() above */
+ spin_lock(&ec->ec_lock);
+
+ list_add(&ecl->ecl_exp_chain, &exp->exp_ec_data.eced_locks);
+ ulh->cookie = ecl->ecl_cookie = ec->ec_unique++;
+
+ spin_unlock(&ec->ec_lock);
+
+ oa->o_valid |= OBD_MD_FLHANDLE;
+ return 0;
+
+ failed_1:
+ OBD_FREE (ecl, sizeof (*ecl));
+ failed_0:
+ echo_put_object (eco);
+ return (rc);
+}
+
+static int
+echo_client_cancel(struct obd_export *exp, struct obdo *oa)
+{
+ struct obd_device *obd = exp->exp_obd;
+ struct echo_client_obd *ec = &obd->u.echo_client;
+ struct lustre_handle *ulh = obdo_handle (oa);
+ struct ec_lock *ecl = NULL;
+ int found = 0;
+ struct list_head *el;
+ int rc;
+
+ if ((oa->o_valid & OBD_MD_FLHANDLE) == 0)
+ return -EINVAL;
+
+ spin_lock (&ec->ec_lock);
+
+ list_for_each (el, &exp->exp_ec_data.eced_locks) {
+ ecl = list_entry (el, struct ec_lock, ecl_exp_chain);
+ found = (ecl->ecl_cookie == ulh->cookie);
+ if (found) {
+ list_del (&ecl->ecl_exp_chain);
+ break;
+ }
+ }
+
+ spin_unlock (&ec->ec_lock);
+
+ if (!found)
+ return (-ENOENT);
+
+ rc = obd_cancel(ec->ec_exp, ecl->ecl_object->eco_lsm, ecl->ecl_mode,
+ &ecl->ecl_lock_handle);
+
+ echo_put_object (ecl->ecl_object);
+ OBD_FREE (ecl, sizeof (*ecl));
+
+ return rc;
+}
+
+static int
+echo_client_iocontrol(unsigned int cmd, struct obd_export *exp,
+ int len, void *karg, void *uarg)
+{
+ struct obd_device *obd;
+ struct echo_client_obd *ec;
+ struct ec_object *eco;
+ struct obd_ioctl_data *data = karg;
+ struct obd_trans_info dummy_oti;
+ struct oti_req_ack_lock *ack_lock;
+ struct obdo *oa;
+ int rw = OBD_BRW_READ;
+ int rc = 0;
+ int i;
+ ENTRY;
+
+ unlock_kernel();
+
+ memset(&dummy_oti, 0, sizeof(dummy_oti));
+
+ obd = exp->exp_obd;
+ ec = &obd->u.echo_client;
+
+ switch (cmd) {
+ case OBD_IOC_CREATE: /* may create echo object */
+ if (!capable (CAP_SYS_ADMIN))
+ GOTO (out, rc = -EPERM);
+
+ rc = echo_create_object (obd, 1, &data->ioc_obdo1,
+ data->ioc_pbuf1, data->ioc_plen1,
+ &dummy_oti);
+ GOTO(out, rc);
+
+ case OBD_IOC_DESTROY:
+ if (!capable (CAP_SYS_ADMIN))
+ GOTO (out, rc = -EPERM);
+
+ rc = echo_get_object (&eco, obd, &data->ioc_obdo1);
+ if (rc == 0) {
+ oa = &data->ioc_obdo1;
+ oa->o_gr = FILTER_GROUP_ECHO;
+ oa->o_valid |= OBD_MD_FLGROUP;
+ rc = obd_destroy(ec->ec_exp, oa, eco->eco_lsm,
+ &dummy_oti, NULL);
+ if (rc == 0)
+ eco->eco_deleted = 1;
+ echo_put_object(eco);
+ }
+ GOTO(out, rc);
+
+ case OBD_IOC_GETATTR:
+ rc = echo_get_object (&eco, obd, &data->ioc_obdo1);
+ if (rc == 0) {
+ struct obd_info oinfo = { { { 0 } } };
+ oinfo.oi_md = eco->eco_lsm;
+ oinfo.oi_oa = &data->ioc_obdo1;
+ rc = obd_getattr(ec->ec_exp, &oinfo);
+ echo_put_object(eco);
+ }
+ GOTO(out, rc);
+
+ case OBD_IOC_SETATTR:
+ if (!capable (CAP_SYS_ADMIN))
+ GOTO (out, rc = -EPERM);
+
+ rc = echo_get_object (&eco, obd, &data->ioc_obdo1);
+ if (rc == 0) {
+ struct obd_info oinfo = { { { 0 } } };
+ oinfo.oi_oa = &data->ioc_obdo1;
+ oinfo.oi_md = eco->eco_lsm;
+
+ rc = obd_setattr(ec->ec_exp, &oinfo, NULL);
+ echo_put_object(eco);
+ }
+ GOTO(out, rc);
+
+ case OBD_IOC_BRW_WRITE:
+ if (!capable (CAP_SYS_ADMIN))
+ GOTO (out, rc = -EPERM);
+
+ rw = OBD_BRW_WRITE;
+ /* fall through */
+ case OBD_IOC_BRW_READ:
+ rc = echo_client_brw_ioctl(rw, exp, data);
+ GOTO(out, rc);
+
+ case ECHO_IOC_GET_STRIPE:
+ rc = echo_get_object(&eco, obd, &data->ioc_obdo1);
+ if (rc == 0) {
+ rc = echo_copyout_lsm(eco->eco_lsm, data->ioc_pbuf1,
+ data->ioc_plen1);
+ echo_put_object(eco);
+ }
+ GOTO(out, rc);
+
+ case ECHO_IOC_SET_STRIPE:
+ if (!capable (CAP_SYS_ADMIN))
+ GOTO (out, rc = -EPERM);
+
+ if (data->ioc_pbuf1 == NULL) { /* unset */
+ rc = echo_get_object(&eco, obd, &data->ioc_obdo1);
+ if (rc == 0) {
+ eco->eco_deleted = 1;
+ echo_put_object(eco);
+ }
+ } else {
+ rc = echo_create_object(obd, 0, &data->ioc_obdo1,
+ data->ioc_pbuf1,
+ data->ioc_plen1, &dummy_oti);
+ }
+ GOTO (out, rc);
+
+ case ECHO_IOC_ENQUEUE:
+ if (!capable (CAP_SYS_ADMIN))
+ GOTO (out, rc = -EPERM);
+
+ rc = echo_client_enqueue(exp, &data->ioc_obdo1,
+ data->ioc_conn1, /* lock mode */
+ data->ioc_offset, data->ioc_count);/*extent*/
+ GOTO (out, rc);
+
+ case ECHO_IOC_CANCEL:
+ rc = echo_client_cancel(exp, &data->ioc_obdo1);
+ GOTO (out, rc);
+
+ default:
+ CERROR ("echo_ioctl(): unrecognised ioctl %#x\n", cmd);