Whamcloud - gitweb
import libsysio for b_newsysio
[fs/lustre-release.git] / libsysio / src / file_hack.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-2003 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 <unistd.h>
45 #include <stdlib.h>
46 #include <assert.h>
47 #include <errno.h>
48 #include <sys/types.h>
49 #include <sys/queue.h>
50
51 #include "sysio.h"
52 #include "file.h"
53 #include "inode.h"
54
55 /*
56  * Support for file IO.
57  */
58
59 /*
60  * The open files table
61  */
62 typedef struct oftab {
63         struct file   **table;  /* table array */
64         size_t          size;   /* current table size */
65         int             offset; /* base fd number */
66         int             max;    /* max size */
67 } oftab_t;
68
69 #define OFTAB_NATIVE    (0)
70 #define OFTAB_VIRTUAL   (1)
71
72 static oftab_t _sysio_oftab[2] = {
73         {NULL, 0, 0, 0},
74         {NULL, 0, 0, 1024*1024},
75 };
76
77 static int native_max_fds = 0;
78
79 static inline void init_oftab()
80 {
81         if (!native_max_fds) {
82                 native_max_fds = sysconf(_SC_OPEN_MAX);
83                 if (native_max_fds <= 0)
84                         abort();
85                 _sysio_oftab[OFTAB_NATIVE].max = native_max_fds - 1;
86                 _sysio_oftab[OFTAB_VIRTUAL].offset = native_max_fds;
87         }
88 }
89
90 static inline oftab_t *select_oftab(int fd)
91 {
92         return & _sysio_oftab[fd >= native_max_fds || fd < 0];
93 }
94
95 /*
96  * Create and initialize open file record.
97  */
98 struct file *
99 _sysio_fnew(struct inode *ino, int flags)
100 {
101         struct file *fil;
102
103         fil = malloc(sizeof(struct file));
104         if (!fil)
105                 return NULL;
106
107         _SYSIO_FINIT(fil, ino, flags);
108         I_REF(ino);
109
110         return fil;
111 }
112
113 /*
114  * Destroy open file record.
115  */
116 void
117 _sysio_fgone(struct file *fil)
118 {
119         int     err;
120
121         assert(!fil->f_ref);
122         assert(fil->f_ino);
123         err = (*fil->f_ino->i_ops.inop_close)(fil->f_ino);
124         assert(!err);
125         free(fil);
126 }
127
128 /*
129  * IO operation completion handler.
130  */
131 void
132 _sysio_fcompletio(struct ioctx *ioctx, struct file *fil)
133 {
134         _SYSIO_OFF_T off;
135
136         if (ioctx->ioctx_cc <= 0)
137                 return;
138
139         assert(ioctx->ioctx_ino == fil->f_ino);
140         off = fil->f_pos + ioctx->ioctx_cc;
141         if (fil->f_pos && off <= fil->f_pos)
142                 abort();
143         fil->f_pos = off;
144 }
145
146 /*
147  * Grow (or truncate) the file descriptor table.
148  */
149 static int
150 fd_grow(oftab_t *oftab, size_t n)
151 {
152         int     fd;
153         size_t  count;
154         struct file **noftab, **filp;
155
156         /*
157          * Sanity check the new size.
158          */
159         fd = (int )n;
160         if ((size_t )fd != n)
161                 return -EMFILE;
162
163         n++;    /* index -> size */
164         assert(n > oftab->size);
165
166         if (n > oftab->max)
167                 return -ERANGE;
168
169         if (n < 8)
170                 n = 8;
171         if (n - oftab->size < oftab->size)
172                 n = (n + 1) * 2;
173         noftab = realloc(oftab->table, n * sizeof(struct file *));
174         if (!noftab)
175                 return -ENOMEM;
176         oftab->table = noftab;
177         count = oftab->size;
178         oftab->size = n;
179         if (n < count)
180                 return 0;
181         filp = oftab->table + count;
182         n -= count;
183         while (n--)
184                 *filp++ = NULL;
185         return 0;
186 }
187
188 #if ZERO_SUM_MEMORY
189 static void free_oftab(oftab_t *ot)
190 {
191         if (ot->table) {
192                 free(ot->table);
193                 ot->size = 0;
194         }
195 }
196
197 void
198 _sysio_fd_shutdown()
199 {
200         free_oftab(&_sysio_oftab[OFTAB_NATIVE]);
201         free_oftab(&_sysio_oftab[OFTAB_VIRTUAL]);
202 }
203 #endif
204
205 /*
206  * Find a free slot in the open files table which >= @low
207  * low < 0 means any
208  */
209 static int
210 find_free_fildes(oftab_t *oftab, int low)
211  {
212         int     n;
213         int     err;
214         struct file **filp;
215  
216         if (low < 0)
217                 low = oftab->offset;
218
219         n = low - oftab->offset;
220         if (n < 0)
221                 return -ENFILE;
222
223         for (filp = oftab->table + n;
224              n < oftab->size && *filp;
225              n++, filp++)
226                 ;
227
228         if (n >= oftab->size) {
229                 err = fd_grow(oftab, n);
230                 if (err)
231                         return err;
232                 filp = &oftab->table[n];
233                 assert(!*filp);
234         }
235  
236         return oftab->offset + n;
237 }
238
239 /*
240  * Find open file record from file descriptor.
241  * clear this entry if 'clear' is non-zero
242  */
243 static struct file *
244 __sysio_fd_get(int fd, int clear)
245 {
246         oftab_t *oftab;
247         struct file *file;
248
249         init_oftab();
250
251         if (fd < 0)
252                 return NULL;
253
254         oftab = select_oftab(fd);
255         if (!oftab->table || fd >= oftab->offset + oftab->size)
256                 return NULL;
257
258         file = oftab->table[fd - oftab->offset];
259         if (clear)
260                 oftab->table[fd - oftab->offset] = NULL;
261
262         return file;
263 }
264
265 /*
266  * Find open file record from file descriptor.
267  */
268 struct file *
269 _sysio_fd_find(int fd)
270 {
271         return __sysio_fd_get(fd, 0);
272 }
273
274 /*
275  * Close an open descriptor.
276  */
277 int
278 _sysio_fd_close(int fd)
279 {
280         struct file *fil;
281
282         fil = fil = __sysio_fd_get(fd, 1);
283         if (!fil)
284                 return -EBADF;
285
286         F_RELE(fil);
287
288         return 0;
289 }
290
291 /*
292  * Associate open file record with given file descriptor (if forced), or any
293  * available file descriptor if less than zero, or any available descriptor
294  * greater than or equal to the given one if not forced.
295  */
296 int
297 _sysio_fd_set(struct file *fil, int fd, int force)
298 {
299         int     err;
300         struct file *ofil;
301         oftab_t *oftab;
302
303         if (force && fd < 0)
304                 abort();
305
306         init_oftab();
307
308         oftab = select_oftab(fd);
309
310         /*
311          * Search for a free descriptor if needed.
312          */
313         if (!force) {
314                 fd = find_free_fildes(oftab, fd);
315                 if (fd < 0)
316                         return fd;
317         }
318
319         if (fd - oftab->offset >= oftab->size) {
320                 err = fd_grow(oftab, fd - oftab->offset);
321                 if (err)
322                         return err;
323         }
324
325         /*
326          * Remember old.
327          */
328         ofil = __sysio_fd_get(fd, 1);
329         if (ofil) {
330                 /* FIXME sometimes we could intercept open/socket to create
331                  * a fd, but missing close()? currently we have this problem
332                  * with resolv lib. as a workaround simply destroy the file
333                  * struct here. And this hack will break the behavior of
334                  * DUPFD.
335                  */
336                 if (fd >= 0 && oftab == &_sysio_oftab[0])
337                         free(ofil);
338                 else
339                         F_RELE(ofil);
340         }
341
342         oftab->table[fd - oftab->offset] = fil;
343
344         return fd;
345 }
346
347 /*
348  * Duplicate old file descriptor.
349  *
350  * If the new file descriptor is less than zero, the new file descriptor
351  * is chosen freely. Otherwise, choose an available descriptor greater
352  * than or equal to the new, if not forced. Otherwise, if forced, (re)use
353  * the new.
354  */
355 int
356 _sysio_fd_dup(int oldfd, int newfd, int force)
357 {
358         struct file *fil;
359         int     fd;
360
361         init_oftab();
362
363         if (oldfd == newfd)
364                 return 0;
365
366         fil = _sysio_fd_find(oldfd);
367         if (!fil)
368                 return -EBADF;
369
370         /* old & new must belong to the same oftab */
371         if (select_oftab(oldfd) != select_oftab(newfd))
372                 return -EINVAL;
373
374         fd = _sysio_fd_set(fil, newfd, force);
375         if (fd >= 0)
376                 F_REF(fil);
377         return fd;
378 }
379
380 void
381 _sysio_oftable_close_all(oftab_t *oftab)
382 {
383         struct file **filp;
384         int fd;
385
386         for (fd = 0, filp = oftab->table;
387              (size_t )fd < oftab->size;
388              fd++, filp++) {
389                 if (!*filp)
390                         continue;
391                 F_RELE(*filp);
392                 *filp = NULL;
393         }
394 }
395
396 int
397 _sysio_fd_close_all()
398 {
399         int     fd;
400         struct file **filp;
401         oftab_t *oftab;
402         int i;
403
404         /*
405          * Close all open descriptors.
406          */
407         _sysio_oftable_close_all(&_sysio_oftab[OFTAB_VIRTUAL]);
408         /* XXX see liblustre/llite_lib.c for explaination */
409 #if 0
410         _sysio_oftable_close_all(&_sysio_oftab[OFTAB_NATIVE]);
411 #endif
412
413         /*
414          * Release current working directory.
415          */
416         if (_sysio_cwd) {
417                 P_RELE(_sysio_cwd);
418                 _sysio_cwd = NULL;
419         }
420
421         return 0;
422 }