Whamcloud - gitweb
LU-4064 hsm: create files to be imported on agent node
[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/stat.h>
50 #include <sys/queue.h>
51
52 #include "sysio.h"
53 #include "file.h"
54 #include "inode.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         F_REF(fil);
110         I_REF(ino);
111
112         return fil;
113 }
114
115 /*
116  * Destroy open file record.
117  */
118 void
119 _sysio_fgone(struct file *fil)
120 {
121         int     err;
122
123         assert(!fil->f_ref);
124         assert(fil->f_ino);
125         err = (*fil->f_ino->i_ops.inop_close)(fil->f_ino);
126         I_RELE(fil->f_ino);
127         assert(!err);
128         free(fil);
129 }
130
131 /*
132  * IO operation completion handler.
133  */
134 void
135 _sysio_fcompletio(struct ioctx *ioctx, struct file *fil)
136 {
137         _SYSIO_OFF_T off;
138
139         if (ioctx->ioctx_cc <= 0)
140                 return;
141
142         assert(ioctx->ioctx_ino == fil->f_ino);
143         off = fil->f_pos + ioctx->ioctx_cc;
144         if (fil->f_pos && off <= fil->f_pos)
145                 abort();
146         fil->f_pos = off;
147 }
148
149 /*
150  * Grow (or truncate) the file descriptor table.
151  */
152 static int
153 fd_grow(oftab_t *oftab, size_t n)
154 {
155         int     fd;
156         size_t  count;
157         struct file **noftab, **filp;
158
159         /*
160          * Sanity check the new size.
161          */
162         fd = (int )n;
163         if ((size_t )fd != n)
164                 return -EMFILE;
165
166         n++;    /* index -> size */
167         assert(n > oftab->size);
168
169         if (n > oftab->max)
170                 return -ERANGE;
171
172         if (n < 8)
173                 n = 8;
174         if (n - oftab->size < oftab->size)
175                 n = (n + 1) * 2;
176         noftab = realloc(oftab->table, n * sizeof(struct file *));
177         if (!noftab)
178                 return -ENOMEM;
179         oftab->table = noftab;
180         count = oftab->size;
181         oftab->size = n;
182         if (n < count)
183                 return 0;
184         filp = oftab->table + count;
185         n -= count;
186         while (n--)
187                 *filp++ = NULL;
188         return 0;
189 }
190
191 #ifdef ZERO_SUM_MEMORY
192 static void free_oftab(oftab_t *ot)
193 {
194         if (ot->table) {
195                 free(ot->table);
196                 ot->size = 0;
197         }
198 }
199
200 void
201 _sysio_fd_shutdown()
202 {
203         free_oftab(&_sysio_oftab[OFTAB_NATIVE]);
204         free_oftab(&_sysio_oftab[OFTAB_VIRTUAL]);
205 }
206 #endif
207
208 /*
209  * Find a free slot in the open files table which >= @low
210  * low < 0 means any
211  */
212 static int
213 find_free_fildes(oftab_t *oftab, int low)
214  {
215         int     n;
216         int     err;
217         struct file **filp;
218  
219         if (low < 0)
220                 low = oftab->offset;
221
222         n = low - oftab->offset;
223         if (n < 0)
224                 return -ENFILE;
225
226         for (filp = oftab->table + n;
227              n < oftab->size && *filp;
228              n++, filp++)
229                 ;
230
231         if (n >= oftab->size) {
232                 err = fd_grow(oftab, n);
233                 if (err)
234                         return err;
235                 filp = &oftab->table[n];
236                 assert(!*filp);
237         }
238  
239         return oftab->offset + n;
240 }
241
242 /*
243  * Find open file record from file descriptor.
244  * clear this entry if 'clear' is non-zero
245  */
246 static struct file *
247 __sysio_fd_get(int fd, int clear)
248 {
249         oftab_t *oftab;
250         struct file *file;
251
252         init_oftab();
253
254         if (fd < 0)
255                 return NULL;
256
257         oftab = select_oftab(fd);
258         if (!oftab->table || fd >= oftab->offset + oftab->size)
259                 return NULL;
260
261         file = oftab->table[fd - oftab->offset];
262         if (clear)
263                 oftab->table[fd - oftab->offset] = NULL;
264
265         return file;
266 }
267
268 /*
269  * Find open file record from file descriptor.
270  */
271 struct file *
272 _sysio_fd_find(int fd)
273 {
274         return __sysio_fd_get(fd, 0);
275 }
276
277 /*
278  * Close an open descriptor.
279  */
280 int
281 _sysio_fd_close(int fd)
282 {
283         struct file *fil;
284
285         fil = __sysio_fd_get(fd, 1);
286         if (!fil)
287                 return -EBADF;
288
289         F_RELE(fil);
290
291         return 0;
292 }
293
294 /*
295  * Associate open file record with given file descriptor (if forced), or any
296  * available file descriptor if less than zero, or any available descriptor
297  * greater than or equal to the given one if not forced.
298  */
299 int
300 _sysio_fd_set(struct file *fil, int fd, int force)
301 {
302         int     err;
303         struct file *ofil;
304         oftab_t *oftab;
305
306         if (force && fd < 0)
307                 abort();
308
309         init_oftab();
310
311         oftab = select_oftab(fd);
312
313         /*
314          * Search for a free descriptor if needed.
315          */
316         if (!force) {
317                 fd = find_free_fildes(oftab, fd);
318                 if (fd < 0)
319                         return fd;
320         }
321
322         if (fd - oftab->offset >= oftab->size) {
323                 err = fd_grow(oftab, fd - oftab->offset);
324                 if (err)
325                         return err;
326         }
327
328         /*
329          * Remember old.
330          */
331         ofil = __sysio_fd_get(fd, 1);
332         if (ofil) {
333                 /* FIXME sometimes we could intercept open/socket to create
334                  * a fd, but missing close()? currently we have this problem
335                  * with resolv lib. as a workaround simply destroy the file
336                  * struct here. And this hack will break the behavior of
337                  * DUPFD.
338                  */
339                 if (fd >= 0 && oftab == &_sysio_oftab[0])
340                         free(ofil);
341                 else
342                         F_RELE(ofil);
343         }
344
345         oftab->table[fd - oftab->offset] = fil;
346
347         return fd;
348 }
349
350 /*
351  * Duplicate old file descriptor.
352  *
353  * If the new file descriptor is less than zero, the new file descriptor
354  * is chosen freely. Otherwise, choose an available descriptor greater
355  * than or equal to the new, if not forced. Otherwise, if forced, (re)use
356  * the new.
357  */
358 int
359 _sysio_fd_dup(int oldfd, int newfd, int force)
360 {
361         struct file *fil;
362         int     fd;
363
364         init_oftab();
365
366         if (oldfd == newfd && oldfd >= 0)
367                 return newfd;
368
369         fil = _sysio_fd_find(oldfd);
370         if (!fil)
371                 return -EBADF;
372
373         /* old & new must belong to the same oftab */
374         if (select_oftab(oldfd) != select_oftab(newfd))
375                 return -EINVAL;
376
377         fd = _sysio_fd_set(fil, newfd, force);
378         if (fd >= 0)
379                 F_REF(fil);
380         return fd;
381 }
382
383 void
384 _sysio_oftable_close_all(oftab_t *oftab)
385 {
386         struct file **filp;
387         int fd;
388
389         for (fd = 0, filp = oftab->table;
390              (size_t )fd < oftab->size;
391              fd++, filp++) {
392                 if (!*filp)
393                         continue;
394                 F_RELE(*filp);
395                 *filp = NULL;
396         }
397 }
398
399 int
400 _sysio_fd_close_all()
401 {
402         /* Close all open descriptors */
403         _sysio_oftable_close_all(&_sysio_oftab[OFTAB_VIRTUAL]);
404         /* FIXME: libsysio does not currently perform enough cleanup of
405          * open files to allow __liblustre_cleanup_() to safely call
406          * unmount(). See the related FIXME comment in that function
407          * for details. The following disabled code is left in place to
408          * document the solution that was originally under consideration
409          * but never fully implemented. */
410 #if 0
411         _sysio_oftable_close_all(&_sysio_oftab[OFTAB_NATIVE]);
412 #endif
413
414         /* Release current working directory */
415         if (_sysio_cwd) {
416                 P_RELE(_sysio_cwd);
417                 _sysio_cwd = NULL;
418         }
419
420         return 0;
421 }