/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * * Copyright (c) 2001, 2002 Cluster File Systems, Inc. * * This file is part of Lustre, http://www.lustre.org. * * Lustre is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * Lustre is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Lustre; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #define DEBUG_SUBSYSTEM S_ECHO #include #include #include #include #include static int echo_iocontrol(long cmd, struct lustre_handle *obdconn, int len, void *karg, void *uarg) { struct obd_device *obd = class_conn2obd(obdconn); struct echo_client_obd *ec = &obd->u.echo_client; struct obd_ioctl_data *data = karg; int rw = OBD_BRW_READ, rc = 0; ENTRY; if (obd == NULL) { CERROR("ioctl: No device\n"); GOTO(out, rc = -EINVAL); } switch (cmd) { case OBD_IOC_CREATE: { struct lov_stripe_md *lsm = NULL; #warning FIXME: save lsm into file handle for other ops, release on close rc = obd_create(&ec->conn, &data->ioc_obdo1, &lsm); GOTO(out, rc); } case OBD_IOC_GETATTR: rc = obd_getattr(&ec->conn, &data->ioc_obdo1, NULL); GOTO(out, rc); case OBD_IOC_SETATTR: rc = obd_setattr(&ec->conn, &data->ioc_obdo1, NULL); GOTO(out, rc); case OBD_IOC_DESTROY: { //void *ea; rc = obd_destroy(&ec->conn, &data->ioc_obdo1, NULL); GOTO(out, rc); } case OBD_IOC_OPEN: { struct lov_stripe_md *lsm = NULL; // XXX fill in from create rc = obd_open(&ec->conn, &data->ioc_obdo1, lsm); GOTO(out, rc); } case OBD_IOC_CLOSE: { struct lov_stripe_md *lsm = NULL; // XXX fill in from create rc = obd_close(&ec->conn, &data->ioc_obdo1, lsm); GOTO(out, rc); } case OBD_IOC_BRW_WRITE: rw = OBD_BRW_WRITE; case OBD_IOC_BRW_READ: { struct lov_stripe_md tmp_lsm; // XXX fill in from create struct lov_stripe_md *lsm = &tmp_lsm; // XXX fill in from create struct obd_brw_set *set; obd_count pages = 0; struct brw_page *pga, *pgp; __u64 id = data->ioc_obdo1.o_id; int gfp_mask = (id & 1) ? GFP_HIGHUSER : GFP_KERNEL; int verify = (id != 0); __u64 off; int j; set = obd_brw_set_new(); if (set == NULL) GOTO(out, rc = -ENOMEM); pages = data->ioc_count / PAGE_SIZE; off = data->ioc_offset; CDEBUG(D_INODE, "BRW %s with %d pages @ "LPX64"\n", rw == OBD_BRW_READ ? "read" : "write", pages, off); OBD_ALLOC(pga, pages * sizeof(*pga)); if (!pga) { CERROR("no memory for %d BRW per-page data\n", pages); GOTO(brw_free, rc = -ENOMEM); } memset(lsm, 0, sizeof(*lsm)); // XXX don't do this later lsm->lsm_object_id = id; // ensure id == lsm->lsm_object_id for (j = 0, pgp = pga; j < pages; j++, off += PAGE_SIZE, pgp++){ pgp->pg = alloc_pages(gfp_mask, 0); if (!pgp->pg) { CERROR("no memory for brw pages\n"); GOTO(brw_cleanup, rc = -ENOMEM); } pgp->count = PAGE_SIZE; pgp->off = off; pgp->flag = 0; if (verify) { void *addr = kmap(pgp->pg); if (rw == OBD_BRW_WRITE) page_debug_setup(addr, pgp->count, pgp->off, id); else page_debug_setup(addr, pgp->count, 0xdeadbeef00c0ffee, 0xdeadbeef00c0ffee); kunmap(pgp->pg); } } set->brw_callback = ll_brw_sync_wait; rc = obd_brw(rw, &ec->conn, lsm, j, pga, set); if (rc) CERROR("test_brw: error from obd_brw: rc = %d\n", rc); else { rc = ll_brw_sync_wait(set, CB_PHASE_START); if (rc) CERROR("test_brw: error from callback: rc = " "%d\n", rc); } EXIT; brw_cleanup: for (j = 0, pgp = pga; j < pages; j++, pgp++) { if (pgp->pg == NULL) continue; if (verify && !rc) { void *addr = kmap(pgp->pg); rc = page_debug_check("test_brw", addr, PAGE_SIZE, pgp->off, id); kunmap(pgp->pg); } __free_pages(pgp->pg, 0); } brw_free: obd_brw_set_free(set); OBD_FREE(pga, pages * sizeof(*pga)); GOTO(out, rc); } default: return -ENOTTY; } out: RETURN(rc); } static int echo_setup(struct obd_device *obddev, obd_count len, void *buf) { struct obd_ioctl_data* data = buf; struct echo_client_obd *ec = &obddev->u.echo_client; struct obd_device *tgt; int rc; ENTRY; if (data->ioc_inllen1 < 1) { CERROR("requires a TARGET OBD UUID\n"); RETURN(-EINVAL); } if (data->ioc_inllen1 > 37) { CERROR("OBD UUID must be less than 38 characters\n"); RETURN(-EINVAL); } MOD_INC_USE_COUNT; tgt = class_uuid2obd(data->ioc_inlbuf1); if (!tgt || !(tgt->obd_flags & OBD_ATTACHED) || !(tgt->obd_flags & OBD_SET_UP)) { CERROR("device not attached or not set up (%d)\n", data->ioc_dev); GOTO(error_dec, rc = -EINVAL); } rc = obd_connect(&ec->conn, tgt, NULL, NULL, NULL); if (rc) { CERROR("fail to connect to device %d\n", data->ioc_dev); GOTO(error_dec, rc = -EINVAL); } RETURN(rc); error_dec: MOD_DEC_USE_COUNT; RETURN(rc); } static int echo_cleanup(struct obd_device * obddev) { struct echo_client_obd *ec = &obddev->u.echo_client; int rc; ENTRY; if (!list_empty(&obddev->obd_exports)) { CERROR("still has clients!\n"); RETURN(-EBUSY); } rc = obd_disconnect(&ec->conn); if (rc) { CERROR("fail to disconnect device: %d\n", rc); RETURN(-EINVAL); } MOD_DEC_USE_COUNT; RETURN(0); } static int echo_connect(struct lustre_handle *conn, struct obd_device *src, obd_uuid_t cluuid, struct recovd_obd *recovd, ptlrpc_recovery_cb_t recover) { return class_connect(conn, src, cluuid); } static struct obd_ops echo_obd_ops = { o_setup: echo_setup, o_cleanup: echo_cleanup, o_iocontrol: echo_iocontrol, o_connect: echo_connect, o_disconnect: class_disconnect }; int echo_client_init(void) { extern struct lprocfs_vars status_class_var[]; return class_register_type(&echo_obd_ops, status_class_var, OBD_ECHO_CLIENT_DEVICENAME); } void echo_client_cleanup(void) { class_unregister_type(OBD_ECHO_CLIENT_DEVICENAME); }