Whamcloud - gitweb
Merged branch 'peter' with the tip. Pre-merge tag is 't_20020302_networking'.
[fs/lustre-release.git] / lustre / osc / osc_request.c
index da8a9ad..f6bd069 100644 (file)
@@ -1,6 +1,19 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
  * Copryright (C) 2001 Cluster File Systems, Inc.
  *
+ *  This code is issued under the GNU General Public License.
+ *  See the file COPYING in this distribution
+ *
+ *  Author Peter Braam <braam@clusterfs.com>
+ * 
+ *  This server is single threaded at present (but can easily be multi
+ *  threaded). For testing and management it is treated as an
+ *  obd_device, although it does not export a full OBD method table
+ *  (the requests are coming in over the wire, so object target
+ *  modules do not have a full method table.)
+ * 
  */
 
 #define EXPORT_SYMTAB
 #include <linux/fs.h>
 #include <linux/stat.h>
 #include <asm/uaccess.h>
-#include <linux/vmalloc.h>
 #include <asm/segment.h>
 #include <linux/miscdevice.h>
 
+#define DEBUG_SUBSYSTEM S_OSC
+
 #include <linux/obd_support.h>
 #include <linux/obd_class.h>
 #include <linux/lustre_lib.h>
 #include <linux/lustre_idl.h>
 
-extern int ost_queue_req(struct obd_device *, struct ost_request *);
-
-struct ost_request *osc_prep_req(int size, int opcode)
+struct ptlrpc_client *osc_con2cl(struct obd_conn *conn)
 {
-       struct ost_request *request;
-       int rc;
-       ENTRY; 
+       struct osc_obd *osc = &conn->oc_dev->u.osc;
+       return &osc->osc_peer;
 
-       request = (struct ost_request *)kmalloc(sizeof(*request), GFP_KERNEL); 
+}
+
+static int osc_connect(struct obd_conn *conn)
+{
+       struct ptlrpc_request *request;
+       struct ptlrpc_client *peer = osc_con2cl(conn);
+       int rc; 
+       ENTRY;
+       
+       request = ptlrpc_prep_req(peer, OST_CONNECT, 0, NULL, 0, NULL);
        if (!request) { 
-               printk("osc_prep_req: request allocation out of memory\n");
-               return NULL;
+               CERROR("cannot pack req!\n"); 
+               return -ENOMEM;
        }
 
-       rc = ost_pack_req(NULL, 0, NULL, 0, 
-                         &request->rq_reqhdr, &request->rq_req, 
-                         &request->rq_reqlen, &request->rq_reqbuf);
+       request->rq_replen = 
+               sizeof(struct ptlrep_hdr) + sizeof(struct ost_rep);
+
+       rc = ptlrpc_queue_wait(peer, request);
        if (rc) { 
-               printk("llight request: cannot pack request %d\n", rc); 
-               return NULL;
+               EXIT;
+               goto out;
        }
-       request->rq_reqhdr->opc = opcode;
+      
+       CDEBUG(D_INODE, "received connid %d\n", request->rq_rep.ost->connid); 
 
+       conn->oc_id = request->rq_rep.ost->connid;
+ out:
+       ptlrpc_free_req(request);
        EXIT;
-       return request;
+       return rc;
 }
 
-extern int osc_queue_wait(struct obd_conn *conn, struct ost_request *req)
+static int osc_disconnect(struct obd_conn *conn)
 {
-       struct obd_device *client = conn->oc_dev;
-       struct obd_device *target = client->u.osc.osc_tgt;
-       int rc;
-
+       struct ptlrpc_request *request;
+       struct ptlrpc_client *peer = osc_con2cl(conn);
+       int rc; 
        ENTRY;
-       /* set the connection id */
-       req->rq_req->connid = conn->oc_id;
-
-       CDEBUG(D_INODE, "tgt at %p, conn id %d, opcode %d request at: %p\n", 
-              &conn->oc_dev->u.osc.osc_tgt->u.ost, 
-              conn->oc_id, req->rq_reqhdr->opc, req);
+       
+       request = ptlrpc_prep_req(peer, OST_DISCONNECT, 0, NULL, 0, NULL);
+       if (!request) { 
+               CERROR("cannot pack req!\n"); 
+               return -ENOMEM;
+       }
+       request->rq_req.ost->connid = conn->oc_id;
+       request->rq_replen = 
+               sizeof(struct ptlrep_hdr) + sizeof(struct ost_rep);
 
-       /* XXX fix the race here (wait_for_event?)*/
-       /* hand the packet over to the server */
-       rc =  ost_queue_req(target, req); 
+       rc = ptlrpc_queue_wait(peer, request);
        if (rc) { 
-               printk("osc_queue_wait: error %d, opcode %d\n", rc, 
-                      req->rq_reqhdr->opc); 
-               return -rc;
+               EXIT;
+               goto out;
        }
-
-       /* wait for the reply */
-       init_waitqueue_head(&req->rq_wait_for_rep);
-       interruptible_sleep_on(&req->rq_wait_for_rep);
-
-       ost_unpack_rep(req->rq_repbuf, req->rq_replen, &req->rq_rephdr, 
-                      &req->rq_rep); 
-       printk("-->osc_queue_wait: buf %p len %d status %d\n", 
-              req->rq_repbuf, req->rq_replen, req->rq_rephdr->status); 
-
+ out:
+       ptlrpc_free_req(request);
        EXIT;
-       return req->rq_rephdr->status;
-}
-
-void osc_free_req(struct ost_request *request)
-{
-       if (request->rq_repbuf)
-               kfree(request->rq_repbuf);
-       kfree(request);
+       return rc;
 }
 
 
-int osc_connect(struct obd_conn *conn)
+static int osc_getattr(struct obd_conn *conn, struct obdo *oa)
 {
-       struct ost_request *request;
+       struct ptlrpc_request *request;
+       struct ptlrpc_client *peer = osc_con2cl(conn);
        int rc; 
-       ENTRY;
-       
-       request = osc_prep_req(sizeof(*request), OST_CONNECT);
+
+       request = ptlrpc_prep_req(peer, OST_GETATTR, 0, NULL, 0, NULL);
        if (!request) { 
-               printk("osc_connect: cannot pack req!\n"); 
+               CERROR("cannot pack req!\n"); 
                return -ENOMEM;
        }
-
-       rc = osc_queue_wait(conn, request);
+       
+       memcpy(&request->rq_req.ost->oa, oa, sizeof(*oa));
+       request->rq_req.ost->oa.o_valid = ~0;
+       request->rq_replen = 
+               sizeof(struct ptlrep_hdr) + sizeof(struct ost_rep);
+       
+       rc = ptlrpc_queue_wait(peer, request);
        if (rc) { 
                EXIT;
                goto out;
        }
-      
-       CDEBUG(D_INODE, "received connid %d\n", request->rq_rep->connid); 
 
-       conn->oc_id = request->rq_rep->connid;
+       CDEBUG(D_INODE, "mode: %o\n", request->rq_rep.ost->oa.o_mode); 
+       if (oa) { 
+               memcpy(oa, &request->rq_rep.ost->oa, sizeof(*oa));
+       }
+
  out:
-       osc_free_req(request);
-       EXIT;
-       return rc;
+       ptlrpc_free_req(request);
+       return 0;
 }
 
-int osc_disconnect(struct obd_conn *conn)
+static int osc_setattr(struct obd_conn *conn, struct obdo *oa)
 {
-       struct ost_request *request;
+       struct ptlrpc_request *request;
+       struct ptlrpc_client *peer = osc_con2cl(conn);
        int rc; 
-       ENTRY;
-       
-       request = osc_prep_req(sizeof(*request), OST_DISCONNECT);
+
+       request = ptlrpc_prep_req(peer, OST_SETATTR, 0, NULL, 0, NULL);
        if (!request) { 
-               printk("osc_connect: cannot pack req!\n"); 
+               CERROR("cannot pack req!\n"); 
                return -ENOMEM;
        }
-
-       rc = osc_queue_wait(conn, request);
+       
+       memcpy(&request->rq_req.ost->oa, oa, sizeof(*oa));
+       request->rq_replen = 
+               sizeof(struct ptlrep_hdr) + sizeof(struct ost_rep);
+       
+       rc = ptlrpc_queue_wait(peer, request);
        if (rc) { 
                EXIT;
                goto out;
        }
+
  out:
-       osc_free_req(request);
-       EXIT;
-       return rc;
+       ptlrpc_free_req(request);
+       return 0;
 }
 
-
-int osc_getattr(struct obd_conn *conn, struct obdo *oa)
+static int osc_create(struct obd_conn *conn, struct obdo *oa)
 {
-       struct ost_request *request;
+       struct ptlrpc_request *request;
+       struct ptlrpc_client *peer = osc_con2cl(conn);
        int rc; 
 
-       request = osc_prep_req(sizeof(*request), OST_GETATTR);
+       if (!oa) { 
+               CERROR("oa NULL\n"); 
+       }
+       request = ptlrpc_prep_req(peer, OST_CREATE, 0, NULL, 0, NULL);
        if (!request) { 
-               printk("osc_connect: cannot pack req!\n"); 
+               CERROR("cannot pack req!\n"); 
                return -ENOMEM;
        }
        
-       memcpy(&request->rq_req->oa, oa, sizeof(*oa));
-       request->rq_req->oa.o_valid = ~0;
+       memcpy(&request->rq_req.ost->oa, oa, sizeof(*oa));
+       request->rq_req.ost->oa.o_valid = ~0;
+       request->rq_replen = 
+               sizeof(struct ptlrep_hdr) + sizeof(struct ost_rep);
        
-       rc = osc_queue_wait(conn, request);
+       rc = ptlrpc_queue_wait(peer, request);
        if (rc) { 
                EXIT;
                goto out;
        }
+       memcpy(oa, &request->rq_rep.ost->oa, sizeof(*oa));
 
-       CDEBUG(D_INODE, "mode: %o\n", request->rq_rep->oa.o_mode); 
-       if (oa) { 
-               memcpy(oa, &request->rq_rep->oa, sizeof(*oa));
+ out:
+       ptlrpc_free_req(request);
+       return 0;
+}
+
+static int osc_punch(struct obd_conn *conn, struct obdo *oa, obd_size count,
+                     obd_off offset)
+{
+       struct ptlrpc_request *request;
+       struct ptlrpc_client *peer = osc_con2cl(conn);
+       int rc; 
+
+       if (!oa) { 
+               CERROR("oa NULL\n"); 
+       }
+       request = ptlrpc_prep_req(peer, OST_PUNCH, 0, NULL, 0, NULL);
+       if (!request) { 
+               CERROR("cannot pack req!\n"); 
+               return -ENOMEM;
+       }
+       
+       memcpy(&request->rq_req.ost->oa, oa, sizeof(*oa));
+       request->rq_req.ost->oa.o_valid = ~0;
+       request->rq_req.ost->oa.o_size = offset;
+       request->rq_req.ost->oa.o_blocks = count;
+       request->rq_replen = 
+               sizeof(struct ptlrep_hdr) + sizeof(struct ost_rep);
+       
+       rc = ptlrpc_queue_wait(peer, request);
+       if (rc) { 
+               EXIT;
+               goto out;
        }
+       memcpy(oa, &request->rq_rep.ost->oa, sizeof(*oa));
 
  out:
-       osc_free_req(request);
+       ptlrpc_free_req(request);
        return 0;
 }
 
-int osc_create(struct obd_conn *conn, struct obdo *oa)
+static int osc_destroy(struct obd_conn *conn, struct obdo *oa)
 {
-       struct ost_request *request;
+       struct ptlrpc_request *request;
+       struct ptlrpc_client *peer = osc_con2cl(conn);
        int rc; 
 
        if (!oa) { 
-               printk(__FUNCTION__ ": oa NULL\n"); 
+               CERROR("oa NULL\n"); 
        }
-       request = osc_prep_req(sizeof(*request), OST_CREATE);
+       request = ptlrpc_prep_req(peer, OST_DESTROY, 0, NULL, 0, NULL);
        if (!request) { 
-               printk("osc_connect: cannot pack req!\n"); 
+               CERROR("cannot pack req!\n"); 
                return -ENOMEM;
        }
        
-       memcpy(&request->rq_req->oa, oa, sizeof(*oa));
-       request->rq_req->oa.o_valid = ~0;
+       memcpy(&request->rq_req.ost->oa, oa, sizeof(*oa));
+       request->rq_req.ost->oa.o_valid = ~0;
+       request->rq_replen = 
+               sizeof(struct ptlrep_hdr) + sizeof(struct ost_rep);
        
-       rc = osc_queue_wait(conn, request);
+       rc = ptlrpc_queue_wait(peer, request);
        if (rc) { 
                EXIT;
                goto out;
        }
-       memcpy(oa, &request->rq_rep->oa, sizeof(*oa));
+       memcpy(oa, &request->rq_rep.ost->oa, sizeof(*oa));
 
  out:
-       osc_free_req(request);
+       ptlrpc_free_req(request);
        return 0;
 }
 
+int osc_sendpage(struct obd_conn *conn, struct ptlrpc_request *req,
+                 struct niobuf *dst, struct niobuf *src)
+{
+        if (conn->oc_id != -1) {
+                /* local sendpage */
+                memcpy((char *)(unsigned long)dst->addr,
+                       (char *)(unsigned long)src->addr, src->len);
+        } else {
+                struct ptlrpc_client *cl = osc_con2cl(conn);
+                struct ptlrpc_bulk_desc *bulk;
+               char *buf;
+                int rc;
+
+                bulk = ptlrpc_prep_bulk(&cl->cli_server);
+                if (bulk == NULL)
+                        return -ENOMEM;
+
+                spin_lock(&cl->cli_lock);
+                bulk->b_xid = cl->cli_xid++;
+                spin_unlock(&cl->cli_lock);
+
+               OBD_ALLOC(buf, src->len);
+               if (!buf) {
+                        OBD_FREE(bulk, sizeof(*bulk));
+                       return -ENOMEM;
+                }
+
+                memcpy(buf, (char *)(unsigned long)src->addr, src->len);
+
+                bulk->b_buf = buf;
+                bulk->b_buflen = src->len;
+                /* FIXME: maybe we should add an XID to struct niobuf? */
+                bulk->b_xid = (__u32)(unsigned long)src->page;
+
+               rc = ptlrpc_send_bulk(bulk, OSC_BULK_PORTAL);
+                if (rc != 0) {
+                        CERROR("send_bulk failed: %d\n", rc);
+                        BUG();
+                        return rc;
+                }
+                wait_event_interruptible(bulk->b_waitq,
+                                         ptlrpc_check_bulk_sent(bulk));
+
+                if (bulk->b_flags == PTL_RPC_INTR) {
+                        EXIT;
+                        /* FIXME: hey hey, we leak here. */
+                        return -EINTR;
+                }
+
+                OBD_FREE(bulk, sizeof(*bulk));
+                OBD_FREE(buf, src->len);
+        }
+
+        return 0;
+}
+
+int osc_brw_read(struct obd_conn *conn, obd_count num_oa, struct obdo **oa,
+                 obd_count *oa_bufs, struct page **buf, obd_size *count,
+                 obd_off *offset, obd_flag *flags)
+{
+       struct ptlrpc_client *cl = osc_con2cl(conn);
+        struct ptlrpc_request *request;
+        int pages;
+       int rc; 
+       struct obd_ioobj ioo;
+       struct niobuf src;
+       int size1, size2 = 0; 
+       void *ptr1, *ptr2;
+       int i, j, n;
+        struct ptlrpc_bulk_desc **bulk;
+
+       size1 = num_oa * sizeof(ioo); 
+        pages = 0;
+       for (i = 0; i < num_oa; i++) { 
+               size2 += oa_bufs[i] * sizeof(src);
+                pages += oa_bufs[i];
+       }
+
+        /* We actually pack a _third_ buffer, with XIDs for bulk pages */
+        size2 += pages * sizeof(__u32);
+       request = ptlrpc_prep_req(cl, OST_BRW, size1, NULL, size2, NULL);
+       if (!request) { 
+               CERROR("cannot pack req!\n"); 
+               return -ENOMEM;
+       }
+        request->rq_req.ost->cmd = OBD_BRW_READ;
+
+        OBD_ALLOC(bulk, pages * sizeof(struct ptlrpc_bulk_desc *));
+        if (bulk == NULL) {
+                CERROR("cannot alloc bulk desc vector\n");
+                return -ENOMEM;
+        }
+        memset(bulk, 0, pages * sizeof(struct ptlrpc_bulk_desc *));
+
+        n = 0;
+        ptr1 = ost_req_buf1(request->rq_req.ost);
+        ptr2 = ost_req_buf2(request->rq_req.ost);
+        for (i = 0; i < num_oa; i++) {
+                ost_pack_ioo(&ptr1, oa[i], oa_bufs[i]); 
+                for (j = 0; j < oa_bufs[i]; j++) {
+                        bulk[n] = ptlrpc_prep_bulk(&cl->cli_server);
+                        if (bulk[n] == NULL) {
+                                CERROR("cannot alloc bulk desc\n");
+                                rc = -ENOMEM;
+                                goto out;
+                        }
+
+                        spin_lock(&cl->cli_lock);
+                        bulk[n]->b_xid = cl->cli_xid++;
+                        spin_unlock(&cl->cli_lock);
+                        bulk[n]->b_buf = kmap(buf[n]);
+                        bulk[n]->b_buflen = PAGE_SIZE;
+                        bulk[n]->b_portal = OST_BULK_PORTAL;
+                        ost_pack_niobuf(&ptr2, bulk[n]->b_buf, offset[n],
+                                        count[n], flags[n]);
+                        n++;
+                }
+        }
+
+        /* This is kinda silly--put the XIDs in the "third" buffer. */
+        for (n = 0; n < pages; n++) {
+                *(__u32 *)ptr2 = bulk[n]->b_xid;
+                ptr2 = (char *)ptr2 + sizeof(__u32);
+
+                rc = ptlrpc_wait_bulk(bulk[n]);
+                if (rc)
+                        goto out;
+        }
+
+        request->rq_replen = sizeof(struct ptlrep_hdr) + sizeof(struct ost_rep);
+        rc = ptlrpc_queue_wait(cl, request);
+
+ out:
+        /* FIXME: if we've called ptlrpc_wait_bulk but rc != 0, we need to
+         * abort those bulk listeners. */
+
+        if (request->rq_rephdr)
+                OBD_FREE(request->rq_rephdr, request->rq_replen);
+        n = 0;
+        for (i = 0; i < num_oa; i++) {
+                for (j = 0; j < oa_bufs[i]; j++) {
+                        if (bulk[n] == NULL)
+                                continue;
+                        kunmap(bulk[n]->b_buf);
+                        OBD_FREE(bulk[n], sizeof(struct ptlrpc_bulk_desc));
+                        n++;
+                }
+        }
+
+        OBD_FREE(bulk, pages * sizeof(struct ptlrpc_bulk_desc *));
+        ptlrpc_free_req(request);
+        return rc;
+}
+
+int osc_brw_write(struct obd_conn *conn, obd_count num_oa, struct obdo **oa,
+                  obd_count *oa_bufs, struct page **buf, obd_size *count,
+                  obd_off *offset, obd_flag *flags)
+{
+       struct ptlrpc_client *cl = osc_con2cl(conn);
+        struct ptlrpc_request *request;
+       struct obd_ioobj ioo;
+       struct niobuf src;
+       int pages, rc, i, j, n, size1, size2 = 0; 
+       void *ptr1, *ptr2;
+
+       size1 = num_oa * sizeof(ioo); 
+        pages = 0;
+       for (i = 0; i < num_oa; i++) { 
+               size2 += oa_bufs[i] * sizeof(src);
+                pages += oa_bufs[i];
+       }
+
+       request = ptlrpc_prep_req(cl, OST_BRW, size1, NULL, size2, NULL);
+       if (!request) { 
+               CERROR("cannot pack req!\n"); 
+               return -ENOMEM;
+       }
+        request->rq_req.ost->cmd = OBD_BRW_WRITE;
+
+       n = 0;
+       ptr1 = ost_req_buf1(request->rq_req.ost);
+       ptr2 = ost_req_buf2(request->rq_req.ost);
+        for (i = 0; i < num_oa; i++) {
+               ost_pack_ioo(&ptr1, oa[i], oa_bufs[i]); 
+                for (j = 0; j < oa_bufs[i]; j++) {
+                        ost_pack_niobuf(&ptr2, kmap(buf[n]), offset[n],
+                                        count[n], flags[n]);
+                       n++;
+               }
+       }
+
+       request->rq_replen = sizeof(struct ptlrep_hdr) +
+                sizeof(struct ost_rep) + pages * sizeof(struct niobuf);
+       rc = ptlrpc_queue_wait(cl, request);
+       if (rc) { 
+               EXIT;
+               goto out;
+       }
+
+        ptr2 = ost_rep_buf2(request->rq_rep.ost);
+        if (request->rq_rep.ost->buflen2 != n * sizeof(struct niobuf)) {
+                CERROR("buffer length wrong (%d vs. %d)\n",
+                       request->rq_rep.ost->buflen2, n * sizeof(struct niobuf));
+                EXIT;
+                goto out;
+        }
+
+        for (i = 0; i < num_oa; i++) {
+                for (j = 0; j < oa_bufs[i]; j++) {
+                       struct niobuf *dst;
+                       src.addr = (__u64)(unsigned long)buf[n];
+                       src.len = count[n];
+                       ost_unpack_niobuf(&ptr2, &dst);
+                       osc_sendpage(conn, request, dst, &src);
+                       n++;
+               }
+       }
+
+        /* Reuse the request structure for the completion request. */
+        OBD_FREE(request->rq_rephdr, request->rq_replen);
+        request->rq_rephdr = NULL;
+        request->rq_repbuf = NULL;
+       request->rq_reqhdr->opc = OST_BRW_COMPLETE;
+       request->rq_replen = sizeof(struct ptlrep_hdr) + sizeof(struct ost_rep);
+       rc = ptlrpc_queue_wait(cl, request);
+       if (rc) { 
+               EXIT;
+               goto out;
+       }
+
+ out:
+       if (request->rq_rephdr)
+               OBD_FREE(request->rq_rephdr, request->rq_replen);
+       n = 0;
+        for (i = 0; i < num_oa; i++) {
+                for (j = 0; j < oa_bufs[i]; j++) {
+                       kunmap(buf[n]);
+                       n++;
+               }
+       }
+
+       ptlrpc_free_req(request);
+       return 0;
+}
+
+int osc_brw(int rw, struct obd_conn *conn, obd_count num_oa,
+             struct obdo **oa, obd_count *oa_bufs, struct page **buf,
+             obd_size *count, obd_off *offset, obd_flag *flags)
+{
+        if (rw == OBD_BRW_READ) {
+                return osc_brw_read(conn, num_oa, oa, oa_bufs, buf, count,
+                                    offset, flags);
+        } else {
+                return osc_brw_write(conn, num_oa, oa, oa_bufs, buf, count,
+                                     offset, flags);
+        }
+}
 
 /* mount the file system (secretly) */
 static int osc_setup(struct obd_device *obddev, obd_count len,
                        void *buf)
                        
 {
-       struct obd_ioctl_data* data = buf;
        struct osc_obd *osc = &obddev->u.osc;
+       struct obd_ioctl_data *data = (struct obd_ioctl_data *)buf;
+       int rc;
+       int dev = data->ioc_dev;
         ENTRY;
 
-       if (data->ioc_dev  < 0 || data->ioc_dev > MAX_OBD_DEVICES) { 
-               EXIT;
-               return -ENODEV;
-       }
-
-        osc->osc_tgt = &obd_dev[data->ioc_dev];
-       printk("OSC: tgt %d ost at %p\n", data->ioc_dev, &osc->osc_tgt->u.ost); 
-        if ( ! (osc->osc_tgt->obd_flags & OBD_ATTACHED) || 
-             ! (osc->osc_tgt->obd_flags & OBD_SET_UP) ){
-                printk("device not attached or not set up (%d)\n", 
-                       data->ioc_dev);
-                EXIT;
-               return -EINVAL;
-        } 
+       rc = ptlrpc_connect_client(dev, "ost", 
+                                  OST_REQUEST_PORTAL, 
+                                  OSC_REPLY_PORTAL,    
+                                  ost_pack_req, 
+                                  ost_unpack_rep,
+                                  &osc->osc_peer); 
 
         MOD_INC_USE_COUNT;
-        EXIT; 
-        return 0;
+        EXIT;
+        return rc;
 } 
 
-
 static int osc_cleanup(struct obd_device * obddev)
 {
-        ENTRY;
-
-        if ( !(obddev->obd_flags & OBD_SET_UP) ) {
-                EXIT;
-                return 0;
-        }
-
         MOD_DEC_USE_COUNT;
-        EXIT;
         return 0;
 }
 
-
 struct obd_ops osc_obd_ops = { 
        o_setup:   osc_setup,
        o_cleanup: osc_cleanup, 
        o_create: osc_create,
+       o_destroy: osc_destroy,
        o_getattr: osc_getattr,
+       o_setattr: osc_setattr,
        o_connect: osc_connect,
-       o_disconnect: osc_disconnect
+       o_disconnect: osc_disconnect,
+       o_brw: osc_brw,
+       o_punch: osc_punch
 };
 
 static int __init osc_init(void)
@@ -283,4 +586,3 @@ MODULE_LICENSE("GPL");
 
 module_init(osc_init);
 module_exit(osc_exit);
-