/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * * lov/lov.c * * Copyright (C) 2002 Cluster File Systems, Inc. * Author: Phil Schwan * * This code is issued under the GNU General Public License. * See the file COPYING in this distribution */ #define EXPORT_SYMTAB #define DEBUG_SUBSYSTEM S_LOV #include #include extern struct obd_device obd_dev[MAX_OBD_DEVICES]; /* obd methods */ static int lov_connect(struct obd_conn *conn) { int rc; MOD_INC_USE_COUNT; rc = gen_connect(conn); if (rc) MOD_DEC_USE_COUNT; return rc; } static int lov_disconnect(struct obd_conn *conn) { int rc; rc = gen_disconnect(conn); if (!rc) MOD_DEC_USE_COUNT; /* XXX cleanup preallocated inodes */ return rc; } static int lov_getattr(struct obd_conn *conn, struct obdo *oa) { int rc; ENTRY; if (!gen_client(conn)) RETURN(-EINVAL); rc = obd_getattr(&conn->oc_dev->obd_multi_conn[0], oa); RETURN(rc); } static int lov_setattr(struct obd_conn *conn, struct obdo *oa) { int rc, retval, i; ENTRY; if (!gen_client(conn)) RETURN(-EINVAL); for (i = 0; i < conn->oc_dev->obd_multi_count; i++) { rc = obd_setattr(&conn->oc_dev->obd_multi_conn[i], oa); if (i == 0) retval = rc; else if (retval != rc) CERROR("different results on multiple OBDs!\n"); } RETURN(rc); } static int lov_open(struct obd_conn *conn, struct obdo *oa) { int rc, retval, i; ENTRY; if (!gen_client(conn)) RETURN(-EINVAL); for (i = 0; i < conn->oc_dev->obd_multi_count; i++) { rc = obd_open(&conn->oc_dev->obd_multi_conn[i], oa); if (i == 0) retval = rc; else if (retval != rc) CERROR("different results on multiple OBDs!\n"); } RETURN(rc); } static int lov_close(struct obd_conn *conn, struct obdo *oa) { int rc, retval, i; ENTRY; if (!gen_client(conn)) RETURN(-EINVAL); for (i = 0; i < conn->oc_dev->obd_multi_count; i++) { rc = obd_close(&conn->oc_dev->obd_multi_conn[i], oa); if (i == 0) retval = rc; else if (retval != rc) CERROR("different results on multiple OBDs!\n"); } RETURN(rc); } static int lov_create(struct obd_conn *conn, struct obdo *oa) { int rc, i; ENTRY; if (!gen_client(conn)) RETURN(-EINVAL); for (i = 0; i < conn->oc_dev->obd_multi_count; i++) rc = obd_create(&conn->oc_dev->obd_multi_conn[i], oa); return rc; } static int filter_destroy(struct obd_conn *conn, struct obdo *oa) { #if 0 struct obd_device * obddev; struct obd_client * cli; struct inode * inode; struct file *dir; struct file *object; int rc; struct obd_run_ctxt saved; if (!(cli = gen_client(conn))) { CERROR("invalid client %u\n", conn->oc_id); EXIT; return -EINVAL; } obddev = conn->oc_dev; object = filter_obj_open(obddev, oa->o_id, oa->o_mode); if (!object || IS_ERR(object)) { EXIT; return -ENOENT; } inode = object->f_dentry->d_inode; inode->i_nlink = 1; inode->i_mode = 010000; push_ctxt(&saved, &obddev->u.filter.fo_ctxt); dir = filter_parent(oa->o_id, oa->o_mode); if (IS_ERR(dir)) { rc = PTR_ERR(dir); EXIT; goto out; } dget(dir->f_dentry); dget(object->f_dentry); rc = vfs_unlink(dir->f_dentry->d_inode, object->f_dentry); filp_close(dir, 0); filp_close(object, 0); out: pop_ctxt(&saved); EXIT; return rc; #endif return 0; } /* FIXME: maybe we'll just make one node the authoritative attribute node, then * we can send this 'punch' to just the authoritative node and the nodes * that the punch will affect. */ static int lov_punch(struct obd_conn *conn, struct obdo *oa, obd_size count, obd_off offset) { int rc, retval, i; ENTRY; if (!gen_client(conn)) RETURN(-EINVAL); for (i = 0; i < conn->oc_dev->obd_multi_count; i++) { rc = obd_punch(&conn->oc_dev->obd_multi_conn[i], oa, count, offset); if (i == 0) retval = rc; else if (retval != rc) CERROR("different results on multiple OBDs!\n"); } RETURN(rc); } /* buffer must lie in user memory here */ static int lov_read(struct obd_conn *conn, struct obdo *oa, char *buf, obd_size *count, obd_off offset) { int rc, i; obd_off off = offset; obd_size retval = 0; ENTRY; if (!gen_client(conn)) RETURN(-EINVAL); while (off < offset + count) { int stripe, conn; obd_size size, tmp; stripe = off / conn->oc_dev->u.lov.lov_stripe_size; size = (stripe + 1) * conn->oc_dev->u.lov.lov_strip_size - off; if (size > *count) size = *count; conn = stripe % conn->oc_dev->obd_multi_count; tmp = size; rc = obd_read(&conn->oc_dev->obd_multi_conn[conn], oa, buf, &size, off); if (rc == 0) retval += size; else { CERROR("read(off=%Lu, count=%Lu): %d\n", (unsigned long long)off, (unsigned long long)size, rc); break; } buf += size; } *count = retval; RETURN(rc); } /* buffer must lie in user memory here */ static int filter_write(struct obd_conn *conn, struct obdo *oa, char *buf, obd_size *count, obd_off offset) { int err; struct file * file; unsigned long retval; ENTRY; if (!gen_client(conn)) { CDEBUG(D_IOCTL, "invalid client %u\n", conn->oc_id); EXIT; return -EINVAL; } file = filter_obj_open(conn->oc_dev, oa->o_id, oa->o_mode); if (!file || IS_ERR(file)) { EXIT; return -PTR_ERR(file); } /* count doubles as retval */ retval = file->f_op->write(file, buf, *count, (loff_t *)&offset); filp_close(file, 0); if ( retval >= 0 ) { err = 0; *count = retval; EXIT; } else { err = retval; *count = 0; EXIT; } return err; } static int lov_enqueue(struct obd_conn *conn, struct ldlm_namespace *ns, struct ldlm_handle *parent_lock, __u64 *res_id, __u32 type, struct ldlm_extent *extent, __u32 mode, int *flags, void *data, int datalen, struct ldlm_handle *lockh) { int rc; ENTRY; if (!gen_client(conn)) RETURN(-EINVAL); rc = obd_enqueue(&conn->oc_dev->obd_multi_conn[0], ns, parent_lock, res_id, type, extent, mode, flags, data, datalen, lockh); RETURN(rc); } static int lov_cancel(struct obd_conn *conn, __u32 mode, struct ldlm_handle *lockh) { int rc; ENTRY; if (!gen_client(conn)) RETURN(-EINVAL); rc = obd_cancel(&conn->oc_dev->obd_multi_conn[0], oa); RETURN(rc); } struct obd_ops lov_obd_ops = { o_setup: gen_multi_setup, o_cleanup: gen_multi_cleanup, o_create: lov_create, o_destroy: lov_destroy, o_getattr: lov_getattr, o_setattr: lov_setattr, o_open: lov_open, o_close: lov_close, o_connect: lov_connect, o_disconnect: lov_disconnect, o_brw: lov_pgcache_brw, o_punch: lov_punch, o_enqueue: lov_enqueue, o_cancel: lov_cancel }; #define LOV_VERSION "v0.1" static int __init lov_init(void) { printk(KERN_INFO "Lustre Logical Object Volume driver " LOV_VERSION ", phil@clusterfs.com\n"); return obd_register_type(&lov_obd_ops, OBD_LOV_DEVICENAME); } static void __exit lov_exit(void) { obd_unregister_type(OBD_LOV_DEVICENAME); } MODULE_AUTHOR("Phil Schwan "); MODULE_DESCRIPTION("Lustre Logical Object Volume OBD driver v0.1"); MODULE_LICENSE("GPL"); module_init(lov_init); module_exit(lov_exit);