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