Whamcloud - gitweb
Merge b_md to HEAD for 0.5.19 release.
[fs/lustre-release.git] / lustre / obdecho / echo_client.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (c) 2001, 2002 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #include <linux/version.h>
23 #include <linux/module.h>
24 #include <linux/fs.h>
25
26 #define DEBUG_SUBSYSTEM S_ECHO
27
28 #include <linux/obd_support.h>
29 #include <linux/obd_class.h>
30 #include <linux/obd_echo.h>
31 #include <linux/lustre_debug.h>
32 #include <linux/lprocfs_status.h>
33
34 static int echo_iocontrol(unsigned int cmd, struct lustre_handle *obdconn, int len,
35                           void *karg, void *uarg)
36 {
37         struct obd_device *obd = class_conn2obd(obdconn);
38         struct echo_client_obd *ec = &obd->u.echo_client;
39         struct obd_ioctl_data *data = karg;
40         int rw = OBD_BRW_READ, rc = 0;
41         struct lov_stripe_md *lsm = NULL;
42         ENTRY;
43
44         if (obd == NULL) {
45                 CERROR("ioctl: No device\n");
46                 GOTO(out, rc = -EINVAL);
47         }
48
49         if (data->ioc_inllen1 == sizeof(*lsm)) {
50                 lsm = (struct lov_stripe_md *)data->ioc_inlbuf1;
51         } else if (data->ioc_inllen1 != 0) {
52                 CERROR("nonzero ioc_inllen1 != sizeof(struct lov_stripe_md)\n");
53                 GOTO(out, rc = -EINVAL);
54         }
55
56         switch (cmd) {
57         case OBD_IOC_CREATE: {
58                 struct lov_stripe_md *tmp_lsm = NULL;
59                 rc = obd_create(&ec->conn, &data->ioc_obdo1, &tmp_lsm);
60                 if (lsm && tmp_lsm ) {
61                         memcpy(lsm, tmp_lsm, sizeof(*tmp_lsm));
62                         data->ioc_conn2 = 1;
63                 }
64
65                 GOTO(out, rc);
66         }
67
68         case OBD_IOC_GETATTR:
69                 rc = obd_getattr(&ec->conn, &data->ioc_obdo1, lsm);
70                 GOTO(out, rc);
71
72         case OBD_IOC_SETATTR:
73                 rc = obd_setattr(&ec->conn, &data->ioc_obdo1, lsm);
74                 GOTO(out, rc);
75
76         case OBD_IOC_DESTROY:
77                 rc = obd_destroy(&ec->conn, &data->ioc_obdo1, lsm);
78                 GOTO(out, rc);
79
80         case OBD_IOC_OPEN:
81                 rc = obd_open(&ec->conn, &data->ioc_obdo1, lsm);
82                 GOTO(out, rc);
83
84         case OBD_IOC_CLOSE:
85                 rc = obd_close(&ec->conn, &data->ioc_obdo1, lsm);
86                 GOTO(out, rc);
87
88         case OBD_IOC_BRW_WRITE:
89                 rw = OBD_BRW_WRITE;
90         case OBD_IOC_BRW_READ: {
91                 struct lov_stripe_md tmp_lsm;
92                 struct obd_brw_set *set;
93                 obd_count pages = 0;
94                 struct brw_page *pga, *pgp;
95                 __u64 off, id = data->ioc_obdo1.o_id;
96                 int gfp_mask = (id & 1) ? GFP_HIGHUSER : GFP_KERNEL;
97                 int j, verify = (id != 0);
98
99                 if (lsm && lsm->lsm_object_id != id) {
100                         CERROR("LSM object ID ("LPU64") != id ("LPU64")\n",
101                                lsm->lsm_object_id, id);
102                         GOTO(out, rc = -EINVAL);
103                 }
104
105                 if (!lsm) {
106                         memset(&tmp_lsm, 0, sizeof(tmp_lsm));
107                         lsm = &tmp_lsm;
108                         lsm->lsm_object_id = id;
109                 }
110
111                 if (data->ioc_count < 0) {
112                         CERROR("invalid buffer size: "LPD64"\n",
113                                data->ioc_count);
114                         GOTO(out, rc = -EINVAL);
115                 }
116
117                 set = obd_brw_set_new();
118                 if (set == NULL)
119                         GOTO(out, rc = -ENOMEM);
120
121                 pages = data->ioc_count / PAGE_SIZE;
122                 off = data->ioc_offset;
123
124                 CDEBUG(D_INODE, "BRW %s with %d pages @ "LPX64"\n",
125                        rw == OBD_BRW_READ ? "read" : "write", pages, off);
126                 OBD_ALLOC(pga, pages * sizeof(*pga));
127                 if (!pga) {
128                         CERROR("no memory for %d BRW per-page data\n", pages);
129                         GOTO(brw_free, rc = -ENOMEM);
130                 }
131
132                 for (j = 0, pgp = pga; j < pages; j++, off += PAGE_SIZE, pgp++){
133                         pgp->pg = alloc_pages(gfp_mask, 0);
134                         if (!pgp->pg) {
135                                 CERROR("no memory for brw pages\n");
136                                 GOTO(brw_cleanup, rc = -ENOMEM);
137                         }
138                         pgp->count = PAGE_SIZE;
139                         pgp->off = off;
140                         pgp->flag = 0;
141
142                         if (verify) {
143                                 void *addr = kmap(pgp->pg);
144
145                                 if (rw == OBD_BRW_WRITE)
146                                         page_debug_setup(addr, pgp->count,
147                                                          pgp->off, id);
148                                 else
149                                         page_debug_setup(addr, pgp->count,
150                                                          0xdeadbeef00c0ffee,
151                                                          0xdeadbeef00c0ffee);
152                                 kunmap(pgp->pg);
153                         }
154                 }
155
156                 set->brw_callback = ll_brw_sync_wait;
157                 rc = obd_brw(rw, &ec->conn, lsm, j, pga, set);
158                 if (rc)
159                         CERROR("test_brw: error from obd_brw: rc = %d\n", rc);
160                 else {
161                         rc = ll_brw_sync_wait(set, CB_PHASE_START);
162                         if (rc)
163                                 CERROR("test_brw: error from callback: rc = "
164                                        "%d\n", rc);
165                 }
166                 EXIT;
167         brw_cleanup:
168                 for (j = 0, pgp = pga; j < pages; j++, pgp++) {
169                         if (pgp->pg == NULL)
170                                 continue;
171
172                         if (verify && !rc) {
173                                 void *addr = kmap(pgp->pg);
174
175                                 rc = page_debug_check("test_brw", addr,
176                                                        pgp->count, pgp->off, id);
177                                 kunmap(pgp->pg);
178                         }
179                         __free_pages(pgp->pg, 0);
180                 }
181         brw_free:
182                 obd_brw_set_free(set);
183                 OBD_FREE(pga, pages * sizeof(*pga));
184                 GOTO(out, rc);
185         }
186         default:
187                 CERROR ("echo_ioctl(): unrecognised ioctl %#x\n", cmd);
188                 GOTO (out, rc = -ENOTTY);
189         }
190
191  out:
192         RETURN(rc);
193 }
194
195 static int echo_setup(struct obd_device *obddev, obd_count len, void *buf)
196 {
197         struct obd_ioctl_data* data = buf;
198         struct echo_client_obd *ec = &obddev->u.echo_client;
199         struct obd_device *tgt;
200         int rc;
201         ENTRY;
202
203         if (data->ioc_inllen1 < 1) {
204                 CERROR("requires a TARGET OBD UUID\n");
205                 RETURN(-EINVAL);
206         }
207         if (data->ioc_inllen1 > 37) {
208                 CERROR("OBD UUID must be less than 38 characters\n");
209                 RETURN(-EINVAL);
210         }
211
212         tgt = class_uuid2obd(data->ioc_inlbuf1);
213         if (!tgt || !(tgt->obd_flags & OBD_ATTACHED) ||
214             !(tgt->obd_flags & OBD_SET_UP)) {
215                 CERROR("device not attached or not set up (%d)\n",
216                        data->ioc_dev);
217                 RETURN(rc = -EINVAL);
218         }
219
220         rc = obd_connect(&ec->conn, tgt, NULL, NULL, NULL);
221         if (rc)
222                 CERROR("fail to connect to device %d\n", data->ioc_dev);
223         RETURN(rc);
224 }
225
226 static int echo_cleanup(struct obd_device * obddev)
227 {
228         struct echo_client_obd *ec = &obddev->u.echo_client;
229         int rc;
230         ENTRY;
231
232         if (!list_empty(&obddev->obd_exports)) {
233                 CERROR("still has clients!\n");
234                 RETURN(-EBUSY);
235         }
236
237         rc = obd_disconnect(&ec->conn);
238         if (rc) {
239                 CERROR("fail to disconnect device: %d\n", rc);
240                 RETURN(-EINVAL);
241         }
242
243         RETURN(0);
244 }
245
246 static int echo_connect(struct lustre_handle *conn, struct obd_device *src,
247                         obd_uuid_t cluuid, struct recovd_obd *recovd,
248                         ptlrpc_recovery_cb_t recover)
249 {
250         return class_connect(conn, src, cluuid);
251 }
252
253 static struct obd_ops echo_obd_ops = {
254         o_owner:       THIS_MODULE,
255         o_setup:       echo_setup,
256         o_cleanup:     echo_cleanup,
257         o_iocontrol:   echo_iocontrol,
258         o_connect:     echo_connect,
259         o_disconnect:  class_disconnect
260 };
261
262 int echo_client_init(void)
263 {
264         extern struct lprocfs_vars status_class_var[];
265
266         return class_register_type(&echo_obd_ops, status_class_var,
267                                    OBD_ECHO_CLIENT_DEVICENAME);
268 }
269
270 void echo_client_cleanup(void)
271 {
272         class_unregister_type(OBD_ECHO_CLIENT_DEVICENAME);
273 }