+ OBD_ALLOC(lnb, npages * sizeof(struct niobuf_local));
+ OBD_ALLOC(rnb, npages * sizeof(struct niobuf_remote));
+
+ if (lnb == NULL || rnb == NULL)
+ GOTO(out, ret = -ENOMEM);
+
+ obdo_to_ioobj(oa, &ioo);
+
+ off = offset;
+
+ for(; tot_pages; tot_pages -= npages) {
+ if (tot_pages < npages)
+ npages = tot_pages;
+
+ for (i = 0; i < npages; i++, off += CFS_PAGE_SIZE) {
+ rnb[i].offset = off;
+ rnb[i].len = CFS_PAGE_SIZE;
+ }
+
+ ioo.ioo_bufcnt = npages;
+ oti->oti_transno = 0;
+
+ ret = obd_preprw(rw, exp, oa, 1, &ioo, npages, rnb, lnb, oti);
+ if (ret != 0)
+ GOTO(out, ret);
+
+ for (i = 0; i < npages; i++) {
+ cfs_page_t *page = lnb[i].page;
+
+ /* read past eof? */
+ if (page == NULL && lnb[i].rc == 0)
+ continue;
+
+ if (oa->o_id == ECHO_PERSISTENT_OBJID ||
+ (oa->o_valid & OBD_MD_FLFLAGS) == 0 ||
+ (oa->o_flags & OBD_FL_DEBUG_CHECK) == 0)
+ continue;
+
+ if (rw == OBD_BRW_WRITE)
+ echo_client_page_debug_setup(lsm, page, rw,
+ oa->o_id,
+ rnb[i].offset,
+ rnb[i].len);
+ else
+ echo_client_page_debug_check(lsm, page,
+ oa->o_id,
+ rnb[i].offset,
+ rnb[i].len);
+ }
+
+ ret = obd_commitrw(rw, exp, oa, 1, &ioo, npages, lnb, oti, ret);
+ if (ret != 0)
+ GOTO(out, ret);
+ }
+
+out:
+ if (lnb)
+ OBD_FREE(lnb, npages * sizeof(struct niobuf_local));
+ if (rnb)
+ OBD_FREE(rnb, npages * sizeof(struct niobuf_remote));
+ RETURN(ret);
+}
+
+int echo_client_brw_ioctl(int rw, struct obd_export *exp,
+ struct obd_ioctl_data *data)
+{
+ struct obd_device *obd = class_exp2obd(exp);
+ struct echo_client_obd *ec = &obd->u.echo_client;
+ struct obd_trans_info dummy_oti = { .oti_thread_id = -1 };
+ struct ec_object *eco;
+ int rc;
+ ENTRY;
+
+ rc = echo_get_object(&eco, obd, &data->ioc_obdo1);
+ if (rc)
+ RETURN(rc);
+
+ data->ioc_obdo1.o_valid &= ~OBD_MD_FLHANDLE;
+ data->ioc_obdo1.o_valid |= OBD_MD_FLGROUP;
+ data->ioc_obdo1.o_gr = FILTER_GROUP_ECHO;
+
+ switch((long)data->ioc_pbuf1) {
+ case 1:
+ if (data->ioc_pbuf2 == NULL) { // NULL user data pointer
+ rc = echo_client_kbrw(obd, rw, &data->ioc_obdo1,
+ eco->eco_lsm, data->ioc_offset,
+ data->ioc_count, &dummy_oti);
+ } else {
+#ifdef __KERNEL__
+ rc = echo_client_ubrw(obd, rw, &data->ioc_obdo1,
+ eco->eco_lsm, data->ioc_offset,
+ data->ioc_count, data->ioc_pbuf2,
+ &dummy_oti);
+#endif
+ }
+ break;
+ case 2:
+ rc = echo_client_async_page(ec->ec_exp, rw, &data->ioc_obdo1,
+ eco->eco_lsm, data->ioc_offset,
+ data->ioc_count, data->ioc_plen1);
+ break;
+ case 3:
+ rc = echo_client_prep_commit(ec->ec_exp, rw, &data->ioc_obdo1,
+ eco->eco_lsm, data->ioc_offset,
+ data->ioc_count, data->ioc_plen1,
+ &dummy_oti);
+ break;
+ default:
+ rc = -EINVAL;
+ }
+ echo_put_object(eco);
+ RETURN(rc);