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