Whamcloud - gitweb
093a4cd780200720b367b7cc9484096efbb8d81d
[fs/lustre-release.git] / lustre / utils / obdiolib.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  */
30 /*
31  * This file is part of Lustre, http://www.lustre.org/
32  * Lustre is a trademark of Sun Microsystems, Inc.
33  *
34  * lustre/utils/obdiolib.c
35  *
36  * Author: Eric Barton <eeb@clusterfs.com>
37  */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <errno.h>
42 #include <string.h>
43 #include <fcntl.h>
44 #include <sys/ioctl.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47
48 #include <liblustre.h>
49 #include "obdiolib.h"
50
51 void
52 obdio_iocinit (struct obdio_conn *conn)
53 {
54         memset (&conn->oc_data, 0, sizeof (conn->oc_data));
55         conn->oc_data.ioc_version = OBD_IOCTL_VERSION;
56         conn->oc_data.ioc_dev = conn->oc_device;
57         conn->oc_data.ioc_len = sizeof (conn->oc_data);
58 }
59
60 int
61 obdio_ioctl (struct obdio_conn *conn, int cmd)
62 {
63         char *buf = conn->oc_buffer;
64         int   rc;
65         int   rc2;
66
67         rc = obd_ioctl_pack (&conn->oc_data, &buf, sizeof (conn->oc_buffer));
68         if (rc != 0) {
69                 fprintf(stderr, "%s: obd_ioctl_pack: %d (%s)\n",
70                         __FUNCTION__, rc, strerror(errno));
71                 abort();
72         }
73
74         rc = ioctl (conn->oc_fd, cmd, buf);
75         if (rc != 0)
76                 return (rc);
77
78         rc2 = obd_ioctl_unpack (&conn->oc_data, buf, sizeof (conn->oc_buffer));
79         if (rc2 != 0) {
80                 fprintf(stderr, "%s: obd_ioctl_unpack: %d (%s)\n",
81                         __FUNCTION__, rc2, strerror(errno));
82                 abort ();
83         }
84
85         return (rc);
86 }
87
88 struct obdio_conn *
89 obdio_connect (int device)
90 {
91         struct obdio_conn  *conn;
92
93         conn = malloc (sizeof (*conn));
94         if (conn == NULL) {
95                 fprintf (stderr, "%s: no memory\n", __FUNCTION__);
96                 return (NULL);
97         }
98         memset (conn, 0, sizeof (*conn));
99
100         conn->oc_fd = open ("/dev/obd", O_RDWR);
101         if (conn->oc_fd < 0) {
102                 fprintf(stderr, "%s: Can't open /dev/obd: %s\n",
103                         __FUNCTION__, strerror(errno));
104                 goto failed;
105         }
106
107         conn->oc_device = device;
108         return (conn);
109
110  failed:
111         free (conn);
112         return (NULL);
113 }
114
115 void
116 obdio_disconnect (struct obdio_conn *conn, int flags)
117 {
118         close (conn->oc_fd);
119         /* obdclass will automatically close on last ref */
120         free (conn);
121 }
122
123 int
124 obdio_pread (struct obdio_conn *conn, __u64 oid,
125              void *buffer, __u32 count, __u64 offset)
126 {
127         obdio_iocinit (conn);
128
129         ostid_set_id(&conn->oc_data.ioc_obdo1.o_oi, oid);
130         conn->oc_data.ioc_obdo1.o_mode = S_IFREG;
131         conn->oc_data.ioc_obdo1.o_valid =
132                 OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE;
133
134         conn->oc_data.ioc_pbuf2 = buffer;
135         conn->oc_data.ioc_plen2 = count;
136         conn->oc_data.ioc_count = count;
137         conn->oc_data.ioc_offset = offset;
138
139         return (obdio_ioctl (conn, OBD_IOC_BRW_READ));
140 }
141
142 int
143 obdio_pwrite (struct obdio_conn *conn, __u64 oid,
144               void *buffer, __u32 count, __u64 offset)
145 {
146         obdio_iocinit (conn);
147
148         ostid_set_id(&conn->oc_data.ioc_obdo1.o_oi, oid);
149         conn->oc_data.ioc_obdo1.o_mode = S_IFREG;
150         conn->oc_data.ioc_obdo1.o_valid =
151                 OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE;
152
153         conn->oc_data.ioc_pbuf1 = (void*)1;
154         conn->oc_data.ioc_plen1 = 1;
155         conn->oc_data.ioc_pbuf2 = buffer;
156         conn->oc_data.ioc_plen2 = count;
157         conn->oc_data.ioc_count = count;
158         conn->oc_data.ioc_offset = offset;
159
160         return (obdio_ioctl (conn, OBD_IOC_BRW_WRITE));
161 }
162
163 int
164 obdio_enqueue (struct obdio_conn *conn, __u64 oid,
165                int mode, __u64 offset, __u32 count,
166                struct lustre_handle *lh)
167 {
168         int   rc;
169
170         obdio_iocinit (conn);
171
172         ostid_set_id(&conn->oc_data.ioc_obdo1.o_oi, oid);
173         conn->oc_data.ioc_obdo1.o_mode = S_IFREG;
174         conn->oc_data.ioc_obdo1.o_valid =
175                 OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE;
176
177         conn->oc_data.ioc_conn1 = mode;
178         conn->oc_data.ioc_count = count;
179         conn->oc_data.ioc_offset = offset;
180
181         rc = obdio_ioctl (conn, ECHO_IOC_ENQUEUE);
182
183         if (rc == 0)
184                 *lh = conn->oc_data.ioc_obdo1.o_handle;
185
186         return (rc);
187 }
188
189 int
190 obdio_cancel (struct obdio_conn *conn, struct lustre_handle *lh)
191 {
192         obdio_iocinit (conn);
193
194         conn->oc_data.ioc_obdo1.o_handle = *lh;
195         conn->oc_data.ioc_obdo1.o_valid = OBD_MD_FLHANDLE;
196
197         return (obdio_ioctl (conn, ECHO_IOC_CANCEL));
198 }
199
200 void *
201 obdio_alloc_aligned_buffer (void **spacep, int size)
202 {
203         int   pagemask = getpagesize() - 1;
204         void *space = malloc(size + pagemask);
205
206         if (space == NULL)
207                 return (NULL);
208
209         *spacep = (void *)(((unsigned long)space + pagemask) & ~pagemask);
210         return space;
211 }
212
213 struct obdio_barrier *
214 obdio_new_barrier (__u64 oid, __u64 id, int npeers)
215 {
216         struct obdio_barrier *b;
217
218         b = malloc(sizeof(*b));
219         if (b == NULL) {
220                 fprintf(stderr, "%s "LPX64": Can't allocate\n",
221                         __FUNCTION__, oid);
222                 return(NULL);
223         }
224
225         b->ob_id = id;
226         b->ob_oid = oid;
227         b->ob_npeers = npeers;
228         b->ob_ordinal = 0;
229         b->ob_count = 0;
230         return (b);
231 }
232
233 int
234 obdio_setup_barrier (struct obdio_conn *conn, struct obdio_barrier *b)
235 {
236         struct lustre_handle    lh;
237         int                     rc;
238         int                     rc2;
239         void                   *space, *fileptr;
240         struct obdio_barrier   *fileb;
241
242         if (b->ob_ordinal != 0 ||
243             b->ob_count != 0) {
244                 fprintf(stderr, "%s: invalid parameter\n", __FUNCTION__);
245                 abort ();
246         }
247
248         space = obdio_alloc_aligned_buffer(&fileptr, getpagesize());
249         if (space == NULL) {
250                 fprintf(stderr, "%s "LPX64": Can't allocate page buffer\n",
251                         __FUNCTION__, b->ob_oid);
252                 return (-1);
253         }
254
255         fileb = fileptr;
256         memset(fileb, 0, getpagesize());
257         *fileb = *b;
258
259         rc = obdio_enqueue(conn, b->ob_oid, LCK_PW, 0, getpagesize(), &lh);
260         if (rc != 0) {
261                 fprintf(stderr, "%s "LPX64": Error on enqueue: %s\n",
262                         __FUNCTION__, b->ob_oid, strerror(errno));
263                 goto out;
264         }
265
266         rc = obdio_pwrite(conn, b->ob_oid, fileb, getpagesize(), 0);
267         if (rc != 0)
268                 fprintf(stderr, "%s "LPX64": Error on write: %s\n",
269                         __FUNCTION__, b->ob_oid, strerror(errno));
270
271         rc2 = obdio_cancel (conn, &lh);
272         if (rc == 0 && rc2 != 0) {
273                 fprintf(stderr, "%s "LPX64": Error on cancel: %s\n",
274                         __FUNCTION__, b->ob_oid, strerror(errno));
275                 rc = rc2;
276         }
277  out:
278         free (space);
279         return (rc);
280 }
281
282 int
283 obdio_barrier (struct obdio_conn *conn, struct obdio_barrier *b)
284 {
285         struct lustre_handle   lh;
286         int                    rc;
287         int                    rc2;
288         void                  *space, *fileptr;
289         struct obdio_barrier  *fileb;
290         char                  *mode;
291
292         space = obdio_alloc_aligned_buffer(&fileptr, getpagesize());
293         if (space == NULL) {
294                 fprintf(stderr, "%s "LPX64": Can't allocate page buffer\n",
295                         __FUNCTION__, b->ob_oid);
296                 return (-1);
297         }
298
299         rc = obdio_enqueue(conn, b->ob_oid, LCK_PW, 0, getpagesize(), &lh);
300         if (rc != 0) {
301                 fprintf(stderr, "%s "LPX64": Error on PW enqueue: %s\n",
302                         __FUNCTION__, b->ob_oid, strerror(errno));
303                 goto out_1;
304         }
305
306         fileb = fileptr;
307         memset(fileb, 0xeb, getpagesize());
308         rc = obdio_pread(conn, b->ob_oid, fileb, getpagesize(), 0);
309         if (rc != 0) {
310                 fprintf(stderr, "%s "LPX64": Error on initial read: %s\n",
311                         __FUNCTION__, b->ob_oid, strerror(errno));
312                 goto out_2;
313         }
314
315         if (fileb->ob_id != b->ob_id ||
316             fileb->ob_oid != b->ob_oid ||
317             fileb->ob_npeers != b->ob_npeers ||
318             fileb->ob_count >= b->ob_npeers ||
319             fileb->ob_ordinal != b->ob_ordinal) {
320                 fprintf(stderr, "%s "LPX64": corrupt on initial read\n",
321                         __FUNCTION__, b->ob_id);
322                 fprintf(stderr,
323                         "  got ["LPX64","LPX64","LPX64","LPX64","LPX64"]\n",
324                         fileb->ob_id, fileb->ob_oid, fileb->ob_npeers,
325                         fileb->ob_ordinal, fileb->ob_count);
326                 fprintf(stderr,
327                        "  expected ["LPX64","LPX64","LPX64","LPX64","LPX64"]\n",
328                         b->ob_id, b->ob_oid, b->ob_npeers,
329                         b->ob_ordinal, b->ob_count);
330                 rc = -1;
331                 goto out_2;
332         }
333
334         fileb->ob_count++;
335         if (fileb->ob_count == fileb->ob_npeers) { /* I'm the last joiner */
336                 fileb->ob_count = 0;       /* join count for next barrier */
337                 fileb->ob_ordinal++;                 /* signal all joined */
338         }
339
340         rc = obdio_pwrite(conn, b->ob_oid, fileb, getpagesize(), 0);
341         if (rc != 0) {
342                 fprintf (stderr, "%s "LPX64": Error on initial write: %s\n",
343                          __FUNCTION__, b->ob_oid, strerror(errno));
344                 goto out_2;
345         }
346
347         mode = "PW";
348         b->ob_ordinal++;           /* now I wait... */
349         while (fileb->ob_ordinal != b->ob_ordinal) {
350                 rc = obdio_cancel (conn, &lh);
351                 if (rc != 0) {
352                         fprintf(stderr, "%s "LPX64": Error on %s cancel: %s\n",
353                                 __FUNCTION__, b->ob_oid, mode, strerror(errno));
354                         goto out_1;
355                 }
356
357                 mode = "PR";
358                 rc = obdio_enqueue(conn, b->ob_oid, LCK_PR,0,getpagesize(),&lh);
359                 if (rc != 0) {
360                         fprintf(stderr, "%s "LPX64": Error on PR enqueue: %s\n",
361                                 __FUNCTION__, b->ob_oid, strerror(errno));
362                         goto out_1;
363                 }
364
365                 memset (fileb, 0xeb, getpagesize());
366                 rc = obdio_pread(conn, b->ob_oid, fileb, getpagesize(), 0);
367                 if (rc != 0) {
368                         fprintf(stderr, "%s "LPX64": Error on read: %s\n",
369                                 __FUNCTION__, b->ob_oid, strerror(errno));
370                         goto out_2;
371                 }
372
373                 if (fileb->ob_id != b->ob_id ||
374                     fileb->ob_oid != b->ob_oid ||
375                     fileb->ob_npeers != b->ob_npeers ||
376                     fileb->ob_count >= b->ob_npeers ||
377                     (fileb->ob_ordinal != b->ob_ordinal - 1 &&
378                      fileb->ob_ordinal != b->ob_ordinal)) {
379                         fprintf(stderr, "%s "LPX64": corrupt\n",
380                                 __FUNCTION__, b->ob_id);
381                         fprintf(stderr, "  got ["LPX64","LPX64","LPX64","
382                                 LPX64","LPX64"]\n",
383                                 fileb->ob_id, fileb->ob_oid, fileb->ob_npeers,
384                                 fileb->ob_ordinal, fileb->ob_count);
385                         fprintf(stderr, "  expected ["LPX64","LPX64","LPX64
386                                 ","LPX64","LPX64"]\n",
387                                 b->ob_id, b->ob_oid, b->ob_npeers,
388                                 b->ob_ordinal, b->ob_count);
389                         rc = -1;
390                         goto out_2;
391                 }
392         }
393
394  out_2:
395         rc2 = obdio_cancel (conn, &lh);
396         if (rc == 0 && rc2 != 0) {
397                 fprintf(stderr, "%s "LPX64": Error on cancel: %s\n",
398                         __FUNCTION__, b->ob_oid, strerror(errno));
399                 rc = rc2;
400         }
401  out_1:
402         free (space);
403         return (rc);
404 }