Whamcloud - gitweb
b=21581 too long file / path names for old tar
[fs/lustre-release.git] / libsysio / src / ioctx.c
1 /*
2  *    This Cplant(TM) source code is the property of Sandia National
3  *    Laboratories.
4  *
5  *    This Cplant(TM) source code is copyrighted by Sandia National
6  *    Laboratories.
7  *
8  *    The redistribution of this Cplant(TM) source code is subject to the
9  *    terms of the GNU Lesser General Public License
10  *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
11  *
12  *    Cplant(TM) Copyright 1998-2004 Sandia Corporation. 
13  *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
14  *    license for use of this work by or on behalf of the US Government.
15  *    Export of this program may require a license from the United States
16  *    Government.
17  */
18
19 /*
20  * This library is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU Lesser General Public
22  * License as published by the Free Software Foundation; either
23  * version 2.1 of the License, or (at your option) any later version.
24  * 
25  * This library is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28  * Lesser General Public License for more details.
29  * 
30  * You should have received a copy of the GNU Lesser General Public
31  * License along with this library; if not, write to the Free Software
32  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33  *
34  * Questions or comments about this library should be sent to:
35  *
36  * Lee Ward
37  * Sandia National Laboratories, New Mexico
38  * P.O. Box 5800
39  * Albuquerque, NM 87185-1110
40  *
41  * lee@sandia.gov
42  */
43
44 #include <stdlib.h>
45 #include <string.h>
46 #include <errno.h>
47 #include <sched.h>
48 #include <assert.h>
49 #include <sys/uio.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <sys/queue.h>
53
54 #include "sysio.h"
55 #include "xtio.h"
56 #include "inode.h"
57
58 #if defined(REDSTORM)
59 #include <catamount/do_iostats.h>
60 #endif
61
62
63 /*
64  * Asynchronous IO context support.
65  */
66
67 /*
68  * List of all outstanding (in-flight) asynch IO requests tracked
69  * by the system.
70  */
71 static LIST_HEAD( ,ioctx) aioq;
72
73 /*
74  * Free callback entry.
75  */
76 #define cb_free(cb)             free(cb)
77
78 /*
79  * Initialization. Must be called before using any other routine in this
80  * module.
81  */
82 int
83 _sysio_ioctx_init()
84 {
85
86         LIST_INIT(&aioq);
87         return 0;
88 }
89
90 /*
91  * Enter an IO context onto the async IO events queue.
92  */
93 void
94 _sysio_ioctx_enter(struct ioctx *ioctx)
95 {
96
97         LIST_INSERT_HEAD(&aioq, ioctx, ioctx_link);
98 }
99
100 /*
101  * Allocate and initialize a new IO context.
102  */
103 struct ioctx *
104 _sysio_ioctx_new(struct inode *ino,
105                  int wr,
106                  const struct iovec *iov,
107                  size_t iovlen,
108                  const struct intnl_xtvec *xtv,
109                  size_t xtvlen)
110 {
111         struct ioctx *ioctx;
112
113         ioctx = malloc(sizeof(struct ioctx));
114         if (!ioctx)
115                 return NULL;
116
117         I_REF(ino);
118
119         IOCTX_INIT(ioctx,
120                    0,
121                    wr,
122                    ino,
123                    iov, iovlen,
124                    xtv, xtvlen);
125
126         /*
127          * Link request onto the outstanding requests queue.
128          */
129         _sysio_ioctx_enter(ioctx);
130
131         return ioctx;
132 }
133
134 /*
135  * Add an IO completion call-back to the end of the context call-back queue.
136  * These are called in iowait() as the last thing, right before the context
137  * is destroyed.
138  *
139  * They are called in order. Beware.
140  */
141 int
142 _sysio_ioctx_cb(struct ioctx *ioctx,
143                 void (*f)(struct ioctx *, void *),
144                 void *data)
145 {
146         struct ioctx_callback *entry;
147
148         entry = malloc(sizeof(struct ioctx_callback));
149         if (!entry)
150                 return -ENOMEM;
151
152         entry->iocb_f = f;
153         entry->iocb_data = data;
154
155         TAILQ_INSERT_TAIL(&ioctx->ioctx_cbq, entry, iocb_next);
156
157         return 0;
158 }
159
160 /*
161  * Find an IO context given it's identifier.
162  *
163  * NB: This is dog-slow. If there are alot of these, we will need to change
164  * this implementation.
165  */
166 struct ioctx *
167 _sysio_ioctx_find(void *id)
168 {
169         struct ioctx *ioctx;
170
171         for (ioctx = aioq.lh_first; ioctx; ioctx = ioctx->ioctx_link.le_next)
172                 if (ioctx == id)
173                         return ioctx;
174
175         return NULL;
176 }
177
178 /*
179  * Check if asynchronous IO operation is complete.
180  */
181 int
182 _sysio_ioctx_done(struct ioctx *ioctx)
183 {
184
185         if (ioctx->ioctx_done)
186                 return 1;
187         if (!(*ioctx->ioctx_ino->i_ops.inop_iodone)(ioctx))
188                 return 0;
189         ioctx->ioctx_done = 1;
190         return 1;
191 }
192
193 /*
194  * Wait for asynchronous IO operation to complete, return status
195  * and dispose of the context.
196  *
197  * Note:
198  * The context is no longer valid after return.
199  */
200 ssize_t
201 _sysio_ioctx_wait(struct ioctx *ioctx)
202 {
203         ssize_t cc;
204
205         /*
206          * Wait for async operation to complete.
207          */
208         while (!_sysio_ioctx_done(ioctx)) {
209 #ifdef POSIX_PRIORITY_SCHEDULING
210                 (void )sched_yield();
211 #endif
212         }
213
214         /*
215          * Get status.
216          */
217         cc = ioctx->ioctx_cc;
218         if (cc < 0)
219                 cc = -ioctx->ioctx_errno;
220
221         /*
222          * Dispose.
223          */
224         _sysio_ioctx_complete(ioctx);
225
226         return cc;
227 }
228
229 /*
230  * Free callback entry.
231  */
232 void
233 _sysio_ioctx_cb_free(struct ioctx_callback *cb)
234 {
235
236         cb_free(cb);
237 }
238
239 /*
240  * Complete an asynchronous IO request.
241  */
242 void
243 _sysio_ioctx_complete(struct ioctx *ioctx)
244 {
245         struct ioctx_callback *entry;
246
247
248         /* update IO stats */
249         _SYSIO_UPDACCT(ioctx->ioctx_write, ioctx->ioctx_cc);
250
251         /*
252          * Run the call-back queue.
253          */
254         while ((entry = ioctx->ioctx_cbq.tqh_first)) {
255                 TAILQ_REMOVE(&ioctx->ioctx_cbq, entry, iocb_next);
256                 (*entry->iocb_f)(ioctx, entry->iocb_data);
257                 cb_free(entry);
258         }
259
260         /*
261          * Unlink from the file record's outstanding request queue.
262          */
263         LIST_REMOVE(ioctx, ioctx_link);
264
265         if (ioctx->ioctx_fast)
266                 return;
267
268         I_RELE(ioctx->ioctx_ino);
269
270         free(ioctx);
271 }