Whamcloud - gitweb
Branch b1_4
[fs/lustre-release.git] / libsysio / src / file.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 <stdlib.h>
45 #include <assert.h>
46 #include <errno.h>
47 #include <sys/types.h>
48 #include <sys/stat.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 and it's size.
61  */
62 static struct file **_sysio_oftab = NULL;
63 static size_t _sysio_oftab_size = 0;
64
65 /*
66  * Create and initialize open file record.
67  */
68 struct file *
69 _sysio_fnew(struct inode *ino, int flags)
70 {
71         struct file *fil;
72
73         fil = malloc(sizeof(struct file));
74         if (!fil)
75                 return NULL;
76
77         _SYSIO_FINIT(fil, ino, flags);
78         I_REF(ino);
79
80         return fil;
81 }
82
83 /*
84  * Destroy open file record.
85  */
86 void
87 _sysio_fgone(struct file *fil)
88 {
89         int     err;
90
91         assert(!fil->f_ref);
92         assert(fil->f_ino);
93         err = (*fil->f_ino->i_ops.inop_close)(fil->f_ino);
94         assert(!err);
95         free(fil);
96 }
97
98 /*
99  * IO operation completion handler.
100  */
101 void
102 _sysio_fcompletio(struct ioctx *ioctx, struct file *fil)
103 {
104         _SYSIO_OFF_T off;
105
106         if (ioctx->ioctx_cc <= 0)
107                 return;
108
109         assert(ioctx->ioctx_ino == fil->f_ino);
110         off = fil->f_pos + ioctx->ioctx_cc;
111         if (fil->f_pos && off <= fil->f_pos)
112                 abort();
113         fil->f_pos = off;
114 }
115
116 /*
117  * Grow (or truncate) the file descriptor table.
118  */
119 static int
120 fd_grow(size_t n)
121 {
122         size_t  count;
123         struct file **noftab, **filp;
124
125         /*
126          * Sanity check the new size.
127          */
128         if ((int )n < 0)
129                 return -EMFILE;
130
131         /*
132          * We never shrink the table.
133          */
134         if (n <= _sysio_oftab_size)
135                 return 0;
136
137         noftab = realloc(_sysio_oftab, n * sizeof(struct file *));
138         if (!noftab)
139                 return -ENOMEM;
140         _sysio_oftab = noftab;
141         count = _sysio_oftab_size;
142         _sysio_oftab_size = n;
143         filp = _sysio_oftab + count;
144         n -= count;
145         while (n--)
146                 *filp++ = NULL;
147         return 0;
148 }
149
150 #if ZERO_SUM_MEMORY
151 void
152 _sysio_fd_shutdown()
153 {
154
155         free(_sysio_oftab);
156         _sysio_oftab_size = 0;
157 }
158 #endif
159
160 /*
161  * Find a free slot in the open files table greater than or equal to the
162  * argument.
163  */
164 static int
165 find_free_fildes(int low)
166 {
167         int     n;
168         int     err;
169         struct file **filp;
170
171         for (n = low, filp = _sysio_oftab + low;
172              n >= 0 && (unsigned )n < _sysio_oftab_size && *filp;
173              n++, filp++)
174                 ;
175         if (n < 0)
176                 return -ENFILE;
177         if ((unsigned )n >= _sysio_oftab_size) {
178                 err = fd_grow((unsigned )n + 1);
179                 if (err)
180                         return err;
181                 filp = &_sysio_oftab[n];
182                 assert(!*filp);
183         }
184
185         return n;
186 }
187
188 /*
189  * Find open file record from file descriptor.
190  */
191 struct file *
192 _sysio_fd_find(int fd)
193 {
194         if (fd < 0 || (unsigned )fd >= _sysio_oftab_size)
195                 return NULL;
196
197         return _sysio_oftab[fd];
198 }
199
200 /*
201  * Close an open descriptor.
202  */
203 int
204 _sysio_fd_close(int fd)
205 {
206         struct file *fil;
207
208         fil = _sysio_fd_find(fd);
209         if (!fil)
210                 return -EBADF;
211
212         _sysio_oftab[fd] = NULL;
213
214         F_RELE(fil);
215
216         return 0;
217 }
218
219 /*
220  * Associate open file record with given file descriptor (if forced), or any
221  * available file descriptor if less than zero, or any available descriptor
222  * greater than or equal to the given one if not forced.
223  */
224 int
225 _sysio_fd_set(struct file *fil, int fd, int force)
226 {
227         int     err;
228         struct file *ofil;
229
230         /*
231          * Search for a free descriptor if needed.
232          */
233         if (fd < 0 || !force) {
234                 if (fd < 0)
235                         fd = 0;
236                 fd = find_free_fildes(fd);
237                 if (fd < 0)
238                         return fd;
239         }
240
241         if ((unsigned )fd >= _sysio_oftab_size) {
242                 err = fd_grow((unsigned )fd + 1);
243                 if (err)
244                         return err;
245         }
246
247         /*
248          * Remember old.
249          */
250         ofil = _sysio_fd_find(fd);
251         /*
252          * Take the entry.
253          */
254         _sysio_oftab[fd] = fil;
255         if (ofil)
256                 F_RELE(ofil);
257
258         return fd;
259 }
260
261 /*
262  * Duplicate old file descriptor.
263  *
264  * If the new file descriptor is less than zero, the new file descriptor
265  * is chosen freely. Otherwise, choose an available descriptor greater
266  * than or equal to the new, if not forced. Otherwise, if forced, (re)use
267  * the new.
268  */
269 int
270 _sysio_fd_dup(int oldfd, int newfd, int force)
271 {
272         struct file *fil;
273         int     fd;
274
275         if (oldfd == newfd)
276                 return newfd;
277
278         fil = _sysio_fd_find(oldfd);
279         if (!fil)
280                 return -EBADF;
281
282         fd = _sysio_fd_set(fil, newfd, force);
283         if (fd >= 0)
284                 F_REF(fil);
285         return fd;
286 }
287
288 int
289 _sysio_fd_close_all()
290 {
291         int     fd;
292         struct file **filp;
293
294         /*
295          * Close all open descriptors.
296          */
297         for (fd = 0, filp = _sysio_oftab;
298              (size_t )fd < _sysio_oftab_size;
299              fd++, filp++) {
300                 if (!*filp)
301                         continue;
302                 F_RELE(*filp);
303                 *filp = NULL;
304         }
305
306         /*
307          * Release current working directory.
308          */
309         if (_sysio_cwd) {
310                 P_RELE(_sysio_cwd);
311                 _sysio_cwd = NULL;
312         }
313
314         return 0;
315 }