+ {
+ .ckd_cache = NULL
+ }
+};
+
+/** defgroup echo_page echo_page
+ *
+ * Echo page operations.
+ *
+ * @{
+ */
+cfs_page_t *echo_page_vmpage(const struct lu_env *env,
+ const struct cl_page_slice *slice)
+{
+ return cl2echo_page(slice)->ep_vmpage;
+}
+
+static void echo_page_discard(const struct lu_env *env,
+ const struct cl_page_slice *slice,
+ struct cl_io *unused)
+{
+ cl_page_delete(env, slice->cpl_page);
+}
+
+static int echo_page_is_vmlocked(const struct lu_env *env,
+ const struct cl_page_slice *slice)
+{
+ return 1;
+}
+
+static void echo_page_completion(const struct lu_env *env,
+ const struct cl_page_slice *slice,
+ int ioret)
+{
+ LASSERT(slice->cpl_page->cp_sync_io != NULL);
+}
+
+static void echo_page_fini(const struct lu_env *env,
+ struct cl_page_slice *slice)
+{
+ struct echo_page *ep = cl2echo_page(slice);
+ struct echo_object *eco = cl2echo_obj(slice->cpl_obj);
+ cfs_page_t *vmpage = ep->ep_vmpage;
+ ENTRY;
+
+ atomic_dec(&eco->eo_npages);
+ page_cache_release(vmpage);
+ OBD_SLAB_FREE_PTR(ep, echo_page_kmem);
+ EXIT;
+}
+
+static int echo_page_prep(const struct lu_env *env,
+ const struct cl_page_slice *slice,
+ struct cl_io *unused)
+{
+ return 0;
+}
+
+static int echo_page_print(const struct lu_env *env,
+ const struct cl_page_slice *slice,
+ void *cookie, lu_printer_t printer)
+{
+ struct echo_page *ep = cl2echo_page(slice);
+
+ (*printer)(env, cookie, LUSTRE_ECHO_CLIENT_NAME"-page@%p vm@%p\n",
+ ep, ep->ep_vmpage);
+ return 0;
+}
+
+static const struct cl_page_operations echo_page_ops = {
+ .cpo_discard = echo_page_discard,
+ .cpo_vmpage = echo_page_vmpage,
+ .cpo_fini = echo_page_fini,
+ .cpo_print = echo_page_print,
+ .cpo_is_vmlocked = echo_page_is_vmlocked,
+ .io = {
+ [CRT_READ] = {
+ .cpo_prep = echo_page_prep,
+ .cpo_completion = echo_page_completion,
+ },
+ [CRT_WRITE] = {
+ .cpo_prep = echo_page_prep,
+ .cpo_completion = echo_page_completion,
+ }
+ }
+};
+/** @} echo_page */
+
+/** \defgroup echo_lock echo_lock
+ *
+ * echo lock operations
+ *
+ * @{
+ */
+static void echo_lock_fini(const struct lu_env *env,
+ struct cl_lock_slice *slice)
+{
+ struct echo_lock *ecl = cl2echo_lock(slice);
+
+ LASSERT(list_empty(&ecl->el_chain));
+ OBD_SLAB_FREE_PTR(ecl, echo_lock_kmem);
+}
+
+static void echo_lock_delete(const struct lu_env *env,
+ const struct cl_lock_slice *slice)
+{
+ struct echo_lock *ecl = cl2echo_lock(slice);
+
+ LASSERT(list_empty(&ecl->el_chain));
+}
+
+static int echo_lock_fits_into(const struct lu_env *env,
+ const struct cl_lock_slice *slice,
+ const struct cl_lock_descr *need,
+ const struct cl_io *unused)
+{
+ return 1;
+}
+
+static struct cl_lock_operations echo_lock_ops = {
+ .clo_fini = echo_lock_fini,
+ .clo_delete = echo_lock_delete,
+ .clo_fits_into = echo_lock_fits_into
+};
+
+/** @} echo_lock */
+
+/** \defgroup echo_cl_ops echo_cl_ops
+ *
+ * operations for cl_object
+ *
+ * @{
+ */
+static struct cl_page *echo_page_init(const struct lu_env *env,
+ struct cl_object *obj,
+ struct cl_page *page, cfs_page_t *vmpage)
+{
+ struct echo_page *ep;
+ ENTRY;
+
+ OBD_SLAB_ALLOC_PTR_GFP(ep, echo_page_kmem, CFS_ALLOC_IO);
+ if (ep != NULL) {
+ struct echo_object *eco = cl2echo_obj(obj);
+ ep->ep_vmpage = vmpage;
+ page_cache_get(vmpage);
+ cl_page_slice_add(page, &ep->ep_cl, obj, &echo_page_ops);
+ atomic_inc(&eco->eo_npages);
+ }
+ RETURN(ERR_PTR(ep ? 0 : -ENOMEM));
+}
+
+static int echo_io_init(const struct lu_env *env, struct cl_object *obj,
+ struct cl_io *io)
+{
+ return 0;
+}
+
+static int echo_lock_init(const struct lu_env *env,
+ struct cl_object *obj, struct cl_lock *lock,
+ const struct cl_io *unused)
+{
+ struct echo_lock *el;
+ ENTRY;
+
+ OBD_SLAB_ALLOC_PTR_GFP(el, echo_lock_kmem, CFS_ALLOC_IO);
+ if (el != NULL) {
+ cl_lock_slice_add(lock, &el->el_cl, obj, &echo_lock_ops);
+ el->el_object = cl2echo_obj(obj);
+ CFS_INIT_LIST_HEAD(&el->el_chain);
+ }
+ RETURN(el == NULL ? -ENOMEM : 0);
+}
+
+static int echo_conf_set(const struct lu_env *env, struct cl_object *obj,
+ const struct cl_object_conf *conf)
+{
+ return 0;
+}
+
+static const struct cl_object_operations echo_cl_obj_ops = {
+ .coo_page_init = echo_page_init,
+ .coo_lock_init = echo_lock_init,
+ .coo_io_init = echo_io_init,
+ .coo_conf_set = echo_conf_set
+};
+/** @} echo_cl_ops */
+
+/** \defgroup echo_lu_ops echo_lu_ops
+ *
+ * operations for echo lu object.
+ *
+ * @{
+ */
+static int echo_object_init(const struct lu_env *env, struct lu_object *obj,
+ const struct lu_object_conf *conf)
+{
+ const struct cl_object_conf *cconf = lu2cl_conf(conf);
+ struct echo_object_conf *econf = cl2echo_conf(cconf);
+ struct echo_device *ed = cl2echo_dev(lu2cl_dev(obj->lo_dev));
+ struct echo_client_obd *ec = ed->ed_ec;
+ struct echo_object *eco = cl2echo_obj(lu2cl(obj));
+ ENTRY;
+
+ if (ed->ed_next) {
+ struct lu_object *below;
+ struct lu_device *under;
+
+ under = ed->ed_next;
+ below = under->ld_ops->ldo_object_alloc(env, obj->lo_header,
+ under);
+ if (below == NULL)
+ RETURN(-ENOMEM);
+ lu_object_add(obj, below);
+ }
+
+ LASSERT(econf->eoc_md);
+ eco->eo_lsm = *econf->eoc_md;
+ eco->eo_dev = ed;
+ atomic_set(&eco->eo_npages, 0);
+
+ /* clear the lsm pointer so that it won't get freed. */
+ *econf->eoc_md = NULL;
+
+ spin_lock(&ec->ec_lock);
+ list_add_tail(&eco->eo_obj_chain, &ec->ec_objects);
+ spin_unlock(&ec->ec_lock);
+
+ RETURN(0);
+}
+
+static void echo_object_free(const struct lu_env *env, struct lu_object *obj)
+{
+ struct echo_object *eco = cl2echo_obj(lu2cl(obj));
+ struct echo_client_obd *ec = eco->eo_dev->ed_ec;
+ struct lov_stripe_md *lsm = eco->eo_lsm;
+ ENTRY;
+
+ LASSERT(atomic_read(&eco->eo_npages) == 0);
+
+ spin_lock(&ec->ec_lock);
+ list_del_init(&eco->eo_obj_chain);
+ spin_unlock(&ec->ec_lock);
+
+ lu_object_fini(obj);
+ lu_object_header_fini(obj->lo_header);
+
+ if (lsm)
+ obd_free_memmd(ec->ec_exp, &lsm);
+ OBD_SLAB_FREE_PTR(eco, echo_object_kmem);
+ EXIT;
+}
+
+static int echo_object_print(const struct lu_env *env, void *cookie,
+ lu_printer_t p, const struct lu_object *o)
+{
+ struct echo_object *obj = cl2echo_obj(lu2cl(o));
+
+ return (*p)(env, cookie, "echoclient-object@%p", obj);
+}
+
+
+static const struct lu_object_operations echo_lu_obj_ops = {
+ .loo_object_init = echo_object_init,
+ .loo_object_delete = NULL,
+ .loo_object_release = NULL,
+ .loo_object_free = echo_object_free,
+ .loo_object_print = echo_object_print,
+ .loo_object_invariant = NULL
+};
+/** @} echo_lu_ops */
+
+/** \defgroup echo_lu_dev_ops
+ *
+ * Operations for echo lu device.
+ *
+ * @{
+ */
+static struct lu_object *echo_object_alloc(const struct lu_env *env,
+ const struct lu_object_header *hdr,
+ struct lu_device *dev)
+{
+ struct echo_object *eco;
+ struct lu_object *obj = NULL;
+ ENTRY;
+
+ /* we're the top dev. */
+ LASSERT(hdr == NULL);
+ OBD_SLAB_ALLOC_PTR_GFP(eco, echo_object_kmem, CFS_ALLOC_IO);
+ if (eco != NULL) {
+ struct cl_object_header *hdr = &eco->eo_hdr;
+
+ obj = &echo_obj2cl(eco)->co_lu;
+ cl_object_header_init(hdr);
+ lu_object_init(obj, &hdr->coh_lu, dev);
+ lu_object_add_top(&hdr->coh_lu, obj);
+
+ eco->eo_cl.co_ops = &echo_cl_obj_ops;
+ obj->lo_ops = &echo_lu_obj_ops;
+ }
+ RETURN(obj);
+}
+
+static struct lu_device_operations echo_device_lu_ops = {
+ .ldo_object_alloc = echo_object_alloc,
+};
+/** @} echo_lu_dev_ops */
+
+static struct cl_device_operations echo_device_cl_ops = {
+};
+
+/** \defgroup echo_init echo_init
+ *
+ * Init and fini functions for echo client.
+ *
+ * @{
+ */
+static int echo_site_init(const struct lu_env *env, struct echo_device *ed)
+{
+ struct cl_site *site = &ed->ed_site_myself;
+ int rc;
+
+ /* initialize site */
+ rc = cl_site_init(site, &ed->ed_cl);
+ if (rc) {
+ CERROR("Cannot initilize site for echo client(%d)\n", rc);
+ return rc;
+ }
+
+ rc = lu_site_init_finish(&site->cs_lu);
+ if (rc)
+ return rc;
+
+ ed->ed_site = site;
+ return 0;
+}
+
+static void echo_site_fini(const struct lu_env *env, struct echo_device *ed)
+{
+ if (ed->ed_site) {
+ cl_site_fini(ed->ed_site);
+ ed->ed_site = NULL;
+ }
+}
+
+static void *echo_thread_key_init(const struct lu_context *ctx,
+ struct lu_context_key *key)
+{
+ struct echo_thread_info *info;
+
+ OBD_SLAB_ALLOC_PTR_GFP(info, echo_thread_kmem, CFS_ALLOC_IO);
+ if (info == NULL)
+ info = ERR_PTR(-ENOMEM);
+ return info;
+}
+
+static void echo_thread_key_fini(const struct lu_context *ctx,
+ struct lu_context_key *key, void *data)
+{
+ struct echo_thread_info *info = data;
+ OBD_SLAB_FREE_PTR(info, echo_thread_kmem);
+}
+
+static void echo_thread_key_exit(const struct lu_context *ctx,
+ struct lu_context_key *key, void *data)
+{
+}
+
+static struct lu_context_key echo_thread_key = {
+ .lct_tags = LCT_CL_THREAD,
+ .lct_init = echo_thread_key_init,
+ .lct_fini = echo_thread_key_fini,
+ .lct_exit = echo_thread_key_exit
+};
+
+static void *echo_session_key_init(const struct lu_context *ctx,
+ struct lu_context_key *key)
+{
+ struct echo_session_info *session;
+
+ OBD_SLAB_ALLOC_PTR_GFP(session, echo_session_kmem, CFS_ALLOC_IO);
+ if (session == NULL)
+ session = ERR_PTR(-ENOMEM);
+ return session;
+}
+
+static void echo_session_key_fini(const struct lu_context *ctx,
+ struct lu_context_key *key, void *data)
+{
+ struct echo_session_info *session = data;
+ OBD_SLAB_FREE_PTR(session, echo_session_kmem);
+}
+
+static void echo_session_key_exit(const struct lu_context *ctx,
+ struct lu_context_key *key, void *data)
+{
+}
+
+static struct lu_context_key echo_session_key = {
+ .lct_tags = LCT_SESSION,
+ .lct_init = echo_session_key_init,
+ .lct_fini = echo_session_key_fini,
+ .lct_exit = echo_session_key_exit
+};
+
+LU_TYPE_INIT_FINI(echo, &echo_thread_key, &echo_session_key);