93fa5b65cba93b8b5d92a742296fe18496d81f0a
[openafs.git] / src / vol / ihandle.h
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* An IHandle_t is an abstraction allowing the file and volume operations to
11  * pass the elements required to identify a file to the underlying file
12  * systen. For the usual Vice inode operations, this is no more than the
13  * usual device and inode numbers. For the user space file system used on NT
14  * we also need the volume id to identify the file. 
15  *
16  * An FdHandle_t is an abstraction used to associate file descroptors
17  * with Inode handles. IH_OPEN is used to get a file descriptor that
18  * can be used in subsequent I/O operations. File descriptor handles are
19  * cached by IO_CLOSE. To make sure a file descriptor is really closed call
20  * IH_REALLYCLOSE.
21  *
22  * The IHandle_t also provides a place to do other optimizations. In the
23  * NT user space file system, we keep a separate special file for the
24  * link counts and using the IHandle_t allows keeping the details of
25  * that at a lower level than the IDEC and IINC calls.
26  *
27  * To use the IHandle_t there are a new set of IH_xxxx/FDH_XXXX operations.
28  * Each takes a pointer to an IHandle_t or an FdHandle_t as the first
29  * argument. This pointer is  considered an in/out variable. In particular,
30  * the open file descriptors for a given Inode are stored in a linked list
31  * of FdHandle_t hanging off of each IHandle_t. IH_OPEN returns NULL on error,
32  * and a valid FdHandle_t otherwise. All other IH_xxxx/FDH_xxxx macros return
33  * -1 on error and 0 on success.
34  *
35  * Inode handle operations:
36  * IH_INIT - Initialize the Inode handle with the device, volume id, and ino
37  * IH_COPY - Copy Inode handle info to a new handle with no open descriptors.
38  * IH_REALLYCLOSE - Close all cached file descriptors for Inode handle
39  * IH_RELEASE - release a Inode handle, close all cached file descriptors
40  * IH_CONDSYNC -  snyc the Inode if it has any open file descriptors
41  *
42  * Inode operation replacements:
43  * IH_CREATE - create a file in the underlying filesystem and setup the
44  *      information needed to reference this file in the IHandle_t.
45  * IH_OPEN - open the file belonging to the associated inode and set the
46  *      file descriptor.
47  * IH_IREAD/IH_IWRITE - read/write an Inode.
48  * IH_INC/IH_DEC - increment/decrement the link count.
49  *
50  * Replacements for C runtime file operations
51  * FDH_READ/FDH_WRITE - read/write using the file descriptor.
52  * FDH_READV/FDH_WRITEV - readv/writev (Unix only)
53  * FDH_SEEK - set file handle's read/write position
54  * FDH_CLOSE - return a file descriptor to the cache
55  * FDH_REALLYCLOSE - Close a file descriptor, do not return to the cache
56  * FDH_SYNC - Unconditionally sync an open file.
57  * FDH_TRUNC - Truncate a file
58  *
59  * status information:
60  * FDH_SIZE - returns the size of the file.
61  * FDH_NLINK - returns the link count of the file.
62  *
63  * Miscellaneous:
64  * FDH_FDOPEN - create a descriptor for buffered I/O
65  * STREAM_READ/STREAM_WRITE - buffered file I/O
66  */
67
68 #ifndef _IHANDLE_H_
69 #define _IHANDLE_H_
70
71 #ifdef AFS_PTHREAD_ENV
72 #include <assert.h>
73 #include <pthread.h>
74 extern pthread_once_t ih_glock_once;
75 extern pthread_mutex_t ih_glock_mutex;
76 extern void ih_glock_init(void);
77 #define IH_LOCK \
78     assert(pthread_once(&ih_glock_once, ih_glock_init) == 0 && \
79            pthread_mutex_lock(&ih_glock_mutex) == 0);
80 #define IH_UNLOCK \
81     assert(pthread_mutex_unlock(&ih_glock_mutex) == 0);
82 #else /* AFS_PTHREAD_ENV */
83 #define IH_LOCK
84 #define IH_UNLOCK
85 #endif /* AFS_PTHREAD_ENV */
86
87 #ifndef DLL_INIT_LIST
88 /*
89  * Macro to initialize a doubly linked list, lifted from Encina
90  */
91 #define DLL_INIT_LIST(head, tail)       \
92     do {                                \
93         (head) = NULL;                  \
94         (tail) = NULL;                  \
95     } while(0)
96
97 /*
98  * Macro to remove an element from a doubly linked list
99  */
100 #define DLL_DELETE(ptr,head,tail,next,prev)     \
101     do {                                        \
102         if ((ptr)->next)                        \
103             (ptr)->next->prev = (ptr)->prev;    \
104         else                                    \
105             (tail) = (ptr)->prev;               \
106         if ((ptr)->prev)                        \
107             (ptr)->prev->next = (ptr)->next;    \
108         else                                    \
109             (head) = (ptr)->next;               \
110         (ptr)->next = (ptr)->prev = NULL;       \
111         assert(!(head) || !((head)->prev)); \
112     } while(0)
113
114 /*
115  * Macro to insert an element at the tail of a doubly linked list
116  */
117 #define DLL_INSERT_TAIL(ptr,head,tail,next,prev) \
118     do {                                         \
119         (ptr)->next = NULL;                      \
120         (ptr)->prev = (tail);                    \
121         (tail) = (ptr);                          \
122         if ((ptr)->prev)                         \
123             (ptr)->prev->next = (ptr);           \
124         else                                     \
125             (head) = (ptr);                      \
126         assert((head) && ((head)->prev == NULL)); \
127     } while(0)
128
129 #endif /* DLL_INIT_LIST */
130
131 #ifdef AFS_NT40_ENV
132 typedef __int64 Inode;
133 #else
134 #include <afs/afssyscalls.h>
135 #endif
136
137 /* The dir package's page hashing function is dependent upon the layout of
138  * IHandle_t as well as the containing DirHandle in viced/viced.h. Make
139  * Sure the volume id is still used as the hash after any changes to either
140  * structure.
141  */
142
143 /* forward declaration */
144 struct IHandle_s;
145
146 /* File descriptors are HANDLE's on NT. The following typedef helps catch
147  * type errors.
148  */
149 #ifdef AFS_NT40_ENV
150 typedef HANDLE FD_t;
151 #else
152 typedef int FD_t;
153 #endif
154 #define INVALID_FD ((FD_t)-1)
155
156 /* file descriptor handle */
157 typedef struct FdHandle_s {
158     int fd_status; /* status flags */
159     FD_t fd_fd; /* file descriptor */
160     struct IHandle_s *fd_ih; /* Pointer to Inode handle */
161     struct FdHandle_s *fd_next; /* LRU/Avail list pointers */
162     struct FdHandle_s *fd_prev;
163     struct FdHandle_s *fd_ihnext; /* Inode handle's list of file descriptors */
164     struct FdHandle_s *fd_ihprev;
165 } FdHandle_t;
166
167 /* File descriptor status values */
168 #define FD_HANDLE_AVAIL         1       /* handle is not open and available */
169 #define FD_HANDLE_OPEN          2       /* handle is open and not in use */
170 #define FD_HANDLE_INUSE         3       /* handle is open and in use */
171
172 /* buffered file descriptor handle */
173 #define STREAM_HANDLE_BUFSIZE   2048    /* buffer size for STR_READ/STR_WRITE */
174 typedef struct StreamHandle_s {
175     FD_t str_fd;                        /* file descriptor */
176     int str_direction;                  /* current read/write direction */
177     int str_buflen;                     /* bytes remaining in buffer */
178     int str_bufoff;                     /* current offset into buffer */
179     int str_error;                      /* error code */
180     int str_eof;                        /* end of file flag */
181     struct StreamHandle_s *str_next;    /* Avail list pointers */
182     struct StreamHandle_s *str_prev;
183     char str_buffer[STREAM_HANDLE_BUFSIZE]; /* data buffer */
184 } StreamHandle_t;
185
186 #define STREAM_DIRECTION_NONE   1       /* stream is in initial mode */
187 #define STREAM_DIRECTION_READ   2       /* stream is in input mode */
188 #define STREAM_DIRECTION_WRITE  3       /* stream is in output mode */
189
190 /* number handles allocated at a shot */
191 #define I_HANDLE_MALLOCSIZE     ((size_t)((4096/sizeof(IHandle_t))))
192 #define FD_HANDLE_MALLOCSIZE    ((size_t)((4096/sizeof(FdHandle_t))))
193 #define STREAM_HANDLE_MALLOCSIZE 1
194
195 /* Number of file descriptors needed for non-cached I/O */
196 #define FD_HANDLE_SETASIDE      64
197
198 /* Don't try to have more than 256 files open at once if you are planning
199  * to use fopen or fdopen. The FILE structure has an eight bit field for
200  * the file descriptor.  */
201 #define FD_DEFAULT_CACHESIZE (255-FD_HANDLE_SETASIDE)
202
203 /* We need some limit on the number of files open at once. Some systems
204  * say we can open lots of files, but when we do they run out of slots
205  * in the file table.
206  */
207 #define FD_MAX_CACHESIZE (2000 - FD_HANDLE_SETASIDE)
208
209 /* Inode handle */
210 typedef struct IHandle_s {
211     int ih_vid; /* Parent volume id. */
212     int ih_dev; /* device id. */
213     int ih_flags; /* Flags */
214     Inode ih_ino; /* Inode number */
215     int ih_refcnt; /* reference count */
216     struct FdHandle_s *ih_fdhead;   /* List of open file desciptors */
217     struct FdHandle_s *ih_fdtail;
218     struct IHandle_s *ih_next;      /* Links for avail list/hash chains */
219     struct IHandle_s *ih_prev;
220 } IHandle_t;
221
222 /* Flags for the Inode handle */
223 #define IH_REALLY_CLOSED                1
224
225 /* Hash function for inode handles */
226 #define I_HANDLE_HASH_SIZE      1024    /* power of 2 */
227 /* The casts to int's ensure NT gets the xor operation correct. */
228 #define IH_HASH(D, V, I) ((int)(((D)^(V)^((int)(I)))&(I_HANDLE_HASH_SIZE-1)))
229
230 /*
231  * Hash buckets for inode handles
232  */
233 typedef struct IHashBucket_s {
234     IHandle_t           *ihash_head;
235     IHandle_t           *ihash_tail;
236 } IHashBucket_t;
237
238 /* Prototypes for handle support routines. */
239 #ifdef AFS_NAMEI_ENV
240 #ifdef AFS_NT40_ENV
241 #include "ntops.h"
242 #else
243 #include "namei_ops.h"
244 #endif
245 extern void ih_clear(IHandle_t *h);
246 extern Inode ih_create(IHandle_t *h, int dev, char *part, Inode nI, int p1,
247                      int p2, int p3, int p4);
248 extern FILE *ih_fdopen(FdHandle_t *h, char *fdperms);
249 #endif /* AFS_NAMEI_ENV */
250
251 /*
252  * Prototypes for file descriptor cache routined
253  */
254 extern void ih_UseLargeCache(void);
255 extern IHandle_t *ih_init(int dev, int vid, Inode ino);
256 extern IHandle_t *ih_copy(IHandle_t *ihP);
257 extern FdHandle_t *ih_open(IHandle_t *ihP);
258 extern int fd_close(FdHandle_t *fdP);
259 extern int fd_reallyclose(FdHandle_t *fdP);
260 extern StreamHandle_t *stream_fdopen(FD_t fd);
261 extern StreamHandle_t *stream_open(char *file, char *mode);
262 extern int stream_read(void *ptr, int size, int nitems,
263                        StreamHandle_t *streamP);
264 extern int stream_write(void *ptr, int size, int nitems,
265                         StreamHandle_t *streamP);
266 extern int stream_seek(StreamHandle_t *streamP, int offset, int whence);
267 extern int stream_flush(StreamHandle_t *streamP);
268 extern int stream_close(StreamHandle_t *streamP, int reallyClose);
269 extern int ih_reallyclose(IHandle_t *ihP);
270 extern int ih_release(IHandle_t *ihP);
271 extern int ih_condsync(IHandle_t *ihP);
272
273 /* Macros common to user space and inode API's. */
274 #define IH_INIT(H, D, V, I) ((H) = ih_init((D), (V), (I)))
275
276 #define IH_COPY(D, S) ((D) = ih_copy(S))
277
278 #define IH_NLINK(H) ih_nlink(H)
279
280 #define IH_OPEN(H) ih_open(H)
281
282 #define FDH_CLOSE(H) (fd_close(H), (H)=NULL, 0)
283
284 #define FDH_REALLYCLOSE(H) (fd_reallyclose(H), (H)=NULL, 0)
285
286 #define FDH_FDOPEN(H, A) stream_fdopen((H)->fd_fd)
287
288 #define STREAM_FDOPEN(A, B) stream_fdopen(A)
289
290 #define STREAM_OPEN(A, B) stream_open(A, B)
291
292 #define STREAM_READ(A, B, C, H) stream_read(A, B, C, H)
293
294 #define STREAM_WRITE(A, B, C, H) stream_write(A, B, C, H)
295
296 #define STREAM_SEEK(H, A, B) stream_seek(H, A, B)
297
298 #define STREAM_FLUSH(H) stream_flush(H)
299
300 #define STREAM_ERROR(H) ((H)->str_error)
301
302 #define STREAM_EOF(H) ((H)->str_eof)
303
304 #define STREAM_CLOSE(H) stream_close(H, 0)
305
306 #define STREAM_REALLYCLOSE(H) stream_close(H, 1)
307
308 #define IH_RELEASE(H) (ih_release(H), (H)=NULL, 0)
309
310 #define IH_REALLYCLOSE(H) ih_reallyclose(H)
311
312 #define IH_CONDSYNC(H) ih_condsync(H)
313
314 #ifdef AFS_NAMEI_ENV
315
316 #ifdef AFS_NT40_ENV
317 #define IH_CREATE(H, D, P, N, P1, P2, P3, P4) \
318         nt_icreate(H, P, P1, P2, P3, P4)
319
320 #define OS_IOPEN(H) nt_iopen(H)
321 #define OS_OPEN(F, M, P) nt_open(F, M, P)
322 #define OS_CLOSE(FD) nt_close(FD)
323
324 #define OS_READ(FD, B, S) nt_read(FD, B, S)
325 #define OS_WRITE(FD, B, S) nt_write(FD, B, S)
326 #define OS_SEEK(FD, O, F) nt_seek(FD, O, F)
327
328 #define OS_SYNC(FD) nt_fsync(FD)
329 #define OS_TRUNC(FD, L) nt_ftruncate(FD, L)
330 #define OS_SIZE(FD) nt_size(FD)
331
332 #define IH_INC(H, I, P) nt_inc(H, I, P)
333 #define IH_DEC(H, I, P) nt_dec(H, I, P)
334 #define IH_IREAD(H, O, B, S) nt_iread(H, O, B, S)
335 #define IH_IWRITE(H, O, B, S) nt_iwrite(H, O, B, S)
336
337 #else /* AFS_NT40_ENV */
338 #define IH_CREATE(H, D, P, N, P1, P2, P3, P4) \
339         namei_icreate(H, P, P1, P2, P3, P4)
340
341 #define OS_IOPEN(H) namei_iopen(H)
342 #define OS_OPEN(F, M, P) open(F, M, P)
343 #define OS_CLOSE(FD) close(FD)
344
345 #define OS_READ(FD, B, S) read(FD, B, S)
346 #define OS_WRITE(FD, B, S) write(FD, B, S)
347 #define OS_SEEK(FD, O, F) lseek(FD, O, F)
348
349 #define OS_SYNC(FD) fsync(FD)
350 #define OS_TRUNC(FD, L) ftruncate(FD, L)
351 #define OS_SIZE(FD) ih_size(FD)
352
353 #define IH_INC(H, I, P) namei_inc(H, I, P)
354 #define IH_DEC(H, I, P) namei_dec(H, I, P)
355 #define IH_IREAD(H, O, B, S) namei_iread(H, O, B, S)
356 #define IH_IWRITE(H, O, B, S) namei_iwrite(H, O, B, S)
357 #endif /* AFS_NT40_ENV */
358
359 #else /* AFS_NAMEI_ENV */
360 extern Inode ih_icreate(IHandle_t *ih, int dev, char *part, Inode nI, int p1,\
361                         int p2, int p3, int p4);
362
363 #define IH_CREATE(H, D, P, N, P1, P2, P3, P4) \
364         ih_icreate(H, D, P, N, P1, P2, P3, P4)
365
366 #ifdef AFS_LINUX22_ENV
367 #define OS_IOPEN(H) -1
368 #else
369 #define OS_IOPEN(H) (IOPEN((H)->ih_dev, (H)->ih_ino, O_RDWR))
370 #endif
371 #define OS_OPEN(F, M, P) open(F, M, P)
372 #define OS_CLOSE(FD) close(FD)
373
374 #define OS_READ(FD, B, S) read(FD, B, S)
375 #define OS_WRITE(FD, B, S) write(FD, B, S)
376 #define OS_SEEK(FD, O, F) lseek(FD, O, F)
377
378 #define OS_SYNC(FD) fsync(FD)
379 #define OS_TRUNC(FD, L) ftruncate(FD, L)
380 #define OS_SIZE(FD) ih_size(FD)
381
382 #ifdef AFS_LINUX22_ENV
383 #define IH_INC(H, I, P) -1
384 #define IH_DEC(H, I, P) -1
385 #define IH_IREAD(H, O, B, S) -1
386 #define IH_IWRITE(H, O, B, S) -1
387 #else
388 #define IH_INC(H, I, P) IINC((H)->ih_dev, I, P)
389 #define IH_DEC(H, I, P) IDEC((H)->ih_dev, I, P)
390 #define IH_IREAD(H, O, B, S) inode_read((H)->ih_dev, (H)->ih_ino, (H)->ih_vid,\
391                                         O, B, S)
392 #define IH_IWRITE(H, O, B, S) \
393         inode_write((H)->ih_dev, (H)->ih_ino, (H)->ih_vid, O, B, S)
394 #endif /* AFS_LINUX22_ENV */
395
396
397 #endif /* AFS_NAMEI_ENV */
398
399 #ifndef AFS_NT40_ENV
400 #define FDH_READV(H, I, N) readv((H)->fd_fd, I, N)
401 #define FDH_WRITEV(H, I, N) writev((H)->fd_fd, I, N)
402 #endif
403
404 #define FDH_READ(H, B, S) OS_READ((H)->fd_fd, B, S)
405 #define FDH_WRITE(H, B, S) OS_WRITE((H)->fd_fd, B, S)
406 #define FDH_SEEK(H, O, F) OS_SEEK((H)->fd_fd, O, F)
407
408 #define FDH_SYNC(H) OS_SYNC((H)->fd_fd)
409 #define FDH_TRUNC(H, L) OS_TRUNC((H)->fd_fd, L)
410 #define FDH_SIZE(H) OS_SIZE((H)->fd_fd)
411
412 #endif /* _IHANDLE_H_ */