Whamcloud - gitweb
763ddb80c2f69a34b6d79e24f87830e6c0eda842
[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(long 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)
61                         memcpy(lsm, tmp_lsm, sizeof(*tmp_lsm));
62
63                 GOTO(out, rc);
64         }
65
66         case OBD_IOC_GETATTR:
67                 rc = obd_getattr(&ec->conn, &data->ioc_obdo1, lsm);
68                 GOTO(out, rc);
69
70         case OBD_IOC_SETATTR:
71                 rc = obd_setattr(&ec->conn, &data->ioc_obdo1, lsm);
72                 GOTO(out, rc);
73
74         case OBD_IOC_DESTROY:
75                 rc = obd_destroy(&ec->conn, &data->ioc_obdo1, lsm);
76                 GOTO(out, rc);
77
78         case OBD_IOC_OPEN:
79                 rc = obd_open(&ec->conn, &data->ioc_obdo1, lsm);
80                 GOTO(out, rc);
81
82         case OBD_IOC_CLOSE:
83                 rc = obd_close(&ec->conn, &data->ioc_obdo1, lsm);
84                 GOTO(out, rc);
85
86         case OBD_IOC_BRW_WRITE:
87                 rw = OBD_BRW_WRITE;
88         case OBD_IOC_BRW_READ: {
89                 struct lov_stripe_md tmp_lsm;
90                 struct obd_brw_set *set;
91                 obd_count pages = 0;
92                 struct brw_page *pga, *pgp;
93                 __u64 off, id = data->ioc_obdo1.o_id;
94                 int gfp_mask = (id & 1) ? GFP_HIGHUSER : GFP_KERNEL;
95                 int j, verify = (id != 0);
96
97                 if (lsm && lsm->lsm_object_id != id) {
98                         CERROR("LSM object ID ("LPU64") != id ("LPU64")\n",
99                                lsm->lsm_object_id, id);
100                         GOTO(out, rc = -EINVAL);
101                 }
102
103                 if (!lsm) {
104                         memset(&tmp_lsm, 0, sizeof(tmp_lsm));
105                         lsm = &tmp_lsm;
106                         lsm->lsm_object_id = id;
107                 }
108
109                 if (data->ioc_count < 0) {
110                         CERROR("invalid buffer size: "LPD64"\n",
111                                data->ioc_count);
112                         GOTO(out, rc = -EINVAL);
113                 }
114
115                 set = obd_brw_set_new();
116                 if (set == NULL)
117                         GOTO(out, rc = -ENOMEM);
118
119                 pages = data->ioc_count / PAGE_SIZE;
120                 off = data->ioc_offset;
121
122                 CDEBUG(D_INODE, "BRW %s with %d pages @ "LPX64"\n",
123                        rw == OBD_BRW_READ ? "read" : "write", pages, off);
124                 OBD_ALLOC(pga, pages * sizeof(*pga));
125                 if (!pga) {
126                         CERROR("no memory for %d BRW per-page data\n", pages);
127                         GOTO(brw_free, rc = -ENOMEM);
128                 }
129
130                 for (j = 0, pgp = pga; j < pages; j++, off += PAGE_SIZE, pgp++){
131                         pgp->pg = alloc_pages(gfp_mask, 0);
132                         if (!pgp->pg) {
133                                 CERROR("no memory for brw pages\n");
134                                 GOTO(brw_cleanup, rc = -ENOMEM);
135                         }
136                         pgp->count = PAGE_SIZE;
137                         pgp->off = off;
138                         pgp->flag = 0;
139
140                         if (verify) {
141                                 void *addr = kmap(pgp->pg);
142
143                                 if (rw == OBD_BRW_WRITE)
144                                         page_debug_setup(addr, pgp->count,
145                                                          pgp->off, id);
146                                 else
147                                         page_debug_setup(addr, pgp->count,
148                                                          0xdeadbeef00c0ffee,
149                                                          0xdeadbeef00c0ffee);
150                                 kunmap(pgp->pg);
151                         }
152                 }
153
154                 set->brw_callback = ll_brw_sync_wait;
155                 rc = obd_brw(rw, &ec->conn, lsm, j, pga, set);
156                 if (rc)
157                         CERROR("test_brw: error from obd_brw: rc = %d\n", rc);
158                 else {
159                         rc = ll_brw_sync_wait(set, CB_PHASE_START);
160                         if (rc)
161                                 CERROR("test_brw: error from callback: rc = "
162                                        "%d\n", rc);
163                 }
164                 EXIT;
165         brw_cleanup:
166                 for (j = 0, pgp = pga; j < pages; j++, pgp++) {
167                         if (pgp->pg == NULL)
168                                 continue;
169
170                         if (verify && !rc) {
171                                 void *addr = kmap(pgp->pg);
172
173                                 rc = page_debug_check("test_brw", addr,
174                                                        PAGE_SIZE, pgp->off, id);
175                                 kunmap(pgp->pg);
176                         }
177                         __free_pages(pgp->pg, 0);
178                 }
179         brw_free:
180                 obd_brw_set_free(set);
181                 OBD_FREE(pga, pages * sizeof(*pga));
182                 GOTO(out, rc);
183         }
184         default:
185                 return -ENOTTY;
186         }
187
188  out:
189         RETURN(rc);
190 }
191
192 static int echo_setup(struct obd_device *obddev, obd_count len, void *buf)
193 {
194         struct obd_ioctl_data* data = buf;
195         struct echo_client_obd *ec = &obddev->u.echo_client;
196         struct obd_device *tgt;
197         int rc;
198         ENTRY;
199
200         if (data->ioc_inllen1 < 1) {
201                 CERROR("requires a TARGET OBD UUID\n");
202                 RETURN(-EINVAL);
203         }
204         if (data->ioc_inllen1 > 37) {
205                 CERROR("OBD UUID must be less than 38 characters\n");
206                 RETURN(-EINVAL);
207         }
208
209         MOD_INC_USE_COUNT;
210         tgt = class_uuid2obd(data->ioc_inlbuf1);
211         if (!tgt || !(tgt->obd_flags & OBD_ATTACHED) ||
212             !(tgt->obd_flags & OBD_SET_UP)) {
213                 CERROR("device not attached or not set up (%d)\n",
214                        data->ioc_dev);
215                 GOTO(error_dec, rc = -EINVAL);
216         }
217
218         rc = obd_connect(&ec->conn, tgt, NULL, NULL, NULL);
219         if (rc) {
220                 CERROR("fail to connect to device %d\n", data->ioc_dev);
221                 GOTO(error_dec, rc = -EINVAL);
222         }
223         RETURN(rc);
224 error_dec:
225         MOD_DEC_USE_COUNT;
226         RETURN(rc);
227 }
228
229 static int echo_cleanup(struct obd_device * obddev)
230 {
231         struct echo_client_obd *ec = &obddev->u.echo_client;
232         int rc;
233         ENTRY;
234
235         if (!list_empty(&obddev->obd_exports)) {
236                 CERROR("still has clients!\n");
237                 RETURN(-EBUSY);
238         }
239
240         rc = obd_disconnect(&ec->conn);
241         if (rc) {
242                 CERROR("fail to disconnect device: %d\n", rc);
243                 RETURN(-EINVAL);
244         }
245
246         MOD_DEC_USE_COUNT;
247         RETURN(0);
248 }
249
250 static int echo_connect(struct lustre_handle *conn, struct obd_device *src,
251                         obd_uuid_t cluuid, struct recovd_obd *recovd,
252                         ptlrpc_recovery_cb_t recover)
253 {
254         return class_connect(conn, src, cluuid);
255 }
256
257 static struct obd_ops echo_obd_ops = {
258         o_setup:       echo_setup,
259         o_cleanup:     echo_cleanup,
260         o_iocontrol:   echo_iocontrol,
261         o_connect:     echo_connect,
262         o_disconnect:  class_disconnect
263 };
264
265 int echo_client_init(void)
266 {
267         extern struct lprocfs_vars status_class_var[];
268
269         return class_register_type(&echo_obd_ops, status_class_var,
270                                    OBD_ECHO_CLIENT_DEVICENAME);
271 }
272
273 void echo_client_cleanup(void)
274 {
275         class_unregister_type(OBD_ECHO_CLIENT_DEVICENAME);
276 }