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