Whamcloud - gitweb
Branch b1_4
[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 <assert.h>
48 #include <sys/uio.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <sys/queue.h>
52
53 #include "xtio.h"
54 #include "sysio.h"
55 #include "inode.h"
56
57 #if defined(REDSTORM)
58 #include <catamount/do_iostats.h>
59 #endif
60
61
62 /*
63  * Asynchronous IO context support.
64  */
65
66 /*
67  * List of all outstanding (in-flight) asynch IO requests tracked
68  * by the system.
69  */
70 static LIST_HEAD( ,ioctx) aioq;
71
72 /*
73  * Free callback entry.
74  */
75 #define cb_free(cb)             free(cb)
76
77 /*
78  * Initialization. Must be called before using any other routine in this
79  * module.
80  */
81 int
82 _sysio_ioctx_init()
83 {
84
85         LIST_INIT(&aioq);
86         return 0;
87 }
88
89 /*
90  * Enter an IO context onto the async IO events queue.
91  */
92 void
93 _sysio_ioctx_enter(struct ioctx *ioctx)
94 {
95
96         LIST_INSERT_HEAD(&aioq, ioctx, ioctx_link);
97 }
98
99 /*
100  * Allocate and initialize a new IO context.
101  */
102 struct ioctx *
103 _sysio_ioctx_new(struct inode *ino,
104                  int wr,
105                  const struct iovec *iov,
106                  size_t iovlen,
107                  const struct intnl_xtvec *xtv,
108                  size_t xtvlen)
109 {
110         struct ioctx *ioctx;
111
112         ioctx = malloc(sizeof(struct ioctx));
113         if (!ioctx)
114                 return NULL;
115
116         I_REF(ino);
117
118         IOCTX_INIT(ioctx,
119                    0,
120                    wr,
121                    ino,
122                    iov, iovlen,
123                    xtv, xtvlen);
124
125         /*
126          * Link request onto the outstanding requests queue.
127          */
128         _sysio_ioctx_enter(ioctx);
129
130         return ioctx;
131 }
132
133 /*
134  * Add an IO completion call-back to the end of the context call-back queue.
135  * These are called in iowait() as the last thing, right before the context
136  * is destroyed.
137  *
138  * They are called in order. Beware.
139  */
140 int
141 _sysio_ioctx_cb(struct ioctx *ioctx,
142                 void (*f)(struct ioctx *, void *),
143                 void *data)
144 {
145         struct ioctx_callback *entry;
146
147         entry = malloc(sizeof(struct ioctx_callback));
148         if (!entry)
149                 return -ENOMEM;
150
151         entry->iocb_f = f;
152         entry->iocb_data = data;
153
154         TAILQ_INSERT_TAIL(&ioctx->ioctx_cbq, entry, iocb_next);
155
156         return 0;
157 }
158
159 /*
160  * Find an IO context given it's identifier.
161  *
162  * NB: This is dog-slow. If there are alot of these, we will need to change
163  * this implementation.
164  */
165 struct ioctx *
166 _sysio_ioctx_find(void *id)
167 {
168         struct ioctx *ioctx;
169
170         for (ioctx = aioq.lh_first; ioctx; ioctx = ioctx->ioctx_link.le_next)
171                 if (ioctx == id)
172                         return ioctx;
173
174         return NULL;
175 }
176
177 /*
178  * Wait for asynchronous IO operation to complete, return status
179  * and dispose of the context.
180  *
181  * Note:
182  * The context is no longer valid after return.
183  */
184 ssize_t
185 _sysio_ioctx_wait(struct ioctx *ioctx)
186 {
187         ssize_t cc;
188
189         /*
190          * Wait for async operation to complete.
191          */
192         while (!(ioctx->ioctx_done ||
193                  (*ioctx->ioctx_ino->i_ops.inop_iodone)(ioctx)))
194                 ;
195
196         /*
197          * Get status.
198          */
199         cc = ioctx->ioctx_cc;
200         if (cc < 0)
201                 cc = -ioctx->ioctx_errno;
202
203         /*
204          * Dispose.
205          */
206         _sysio_ioctx_complete(ioctx);
207
208         return cc;
209 }
210
211 /*
212  * Free callback entry.
213  */
214 void
215 _sysio_ioctx_cb_free(struct ioctx_callback *cb)
216 {
217
218         cb_free(cb);
219 }
220
221 /*
222  * Complete an asynchronous IO request.
223  */
224 void
225 _sysio_ioctx_complete(struct ioctx *ioctx)
226 {
227         struct ioctx_callback *entry;
228
229
230         /* update IO stats */
231         _SYSIO_UPDACCT(ioctx->ioctx_write, ioctx);
232
233         /*
234          * Run the call-back queue.
235          */
236         while ((entry = ioctx->ioctx_cbq.tqh_first)) {
237                 TAILQ_REMOVE(&ioctx->ioctx_cbq, entry, iocb_next);
238                 (*entry->iocb_f)(ioctx, entry->iocb_data);
239                 cb_free(entry);
240         }
241
242         /*
243          * Unlink from the file record's outstanding request queue.
244          */
245         LIST_REMOVE(ioctx, ioctx_link);
246
247         if (ioctx->ioctx_fast)
248                 return;
249
250         I_RELE(ioctx->ioctx_ino);
251
252         free(ioctx);
253 }