2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /* ihandle.c - file descriptor cacheing for Inode handles. */
12 /************************************************************************/
14 #include <afsconfig.h>
15 #include <afs/param.h>
19 #include <sys/types.h>
28 #if defined(AFS_SUN5_ENV) || defined(AFS_NBSD_ENV)
29 #include <sys/fcntl.h>
30 #include <sys/resource.h>
35 #include <afs/afsint.h>
37 #include <afs/afssyscalls.h>
40 #include "viceinode.h"
41 #include "afs/afs_assert.h"
46 #define afs_stat stat64
47 #define afs_fstat fstat64
48 #else /* !O_LARGEFILE */
50 #define afs_fstat fstat
51 #endif /* !O_LARGEFILE */
52 #endif /* AFS_NT40_ENV */
54 #ifdef AFS_PTHREAD_ENV
55 pthread_once_t ih_glock_once
= PTHREAD_ONCE_INIT
;
56 pthread_mutex_t ih_glock_mutex
;
57 #endif /* AFS_PTHREAD_ENV */
59 /* Linked list of available inode handles */
60 IHandle_t
*ihAvailHead
;
61 IHandle_t
*ihAvailTail
;
63 /* Linked list of available file descriptor handles */
64 FdHandle_t
*fdAvailHead
;
65 FdHandle_t
*fdAvailTail
;
67 /* Linked list of available stream descriptor handles */
68 StreamHandle_t
*streamAvailHead
;
69 StreamHandle_t
*streamAvailTail
;
71 /* LRU list for file descriptor handles */
72 FdHandle_t
*fdLruHead
;
73 FdHandle_t
*fdLruTail
;
76 int ih_PkgDefaultsSet
= 0;
78 /* Most of the servers use fopen/fdopen. Since the FILE structure
79 * only has eight bits for the file descriptor, the cache size
80 * has to be less than 256. The cache can be made larger as long
81 * as you are sure you don't need fopen/fdopen. */
83 /* As noted in ihandle.h, the fileno member of FILE on most platforms
84 * in 2008 is a 16- or 32-bit signed int. -Matt
86 int fdMaxCacheSize
= 0;
89 /* Number of in use file descriptors */
92 /* Hash table for inode handles */
93 IHashBucket_t ihashTable
[I_HANDLE_HASH_SIZE
];
95 void *ih_sync_thread(void *);
97 /* start-time configurable I/O limits */
98 ih_init_params vol_io_params
;
100 void ih_PkgDefaults(void)
103 ih_PkgDefaultsSet
= 1;
105 /* default to well-known values */
106 vol_io_params
.fd_handle_setaside
= FD_HANDLE_SETASIDE
;
108 /* initial fd cachesize. the only one that will be used if
109 * the application does not call ih_UseLargeCache(). set this
110 * to a value representable in fileno member of the system's
111 * FILE structure (or equivalent). */
112 vol_io_params
.fd_initial_cachesize
= FD_DEFAULT_CACHESIZE
;
114 /* fd cache size that will be used if/when ih_UseLargeCache()
116 vol_io_params
.fd_max_cachesize
= FD_MAX_CACHESIZE
;
118 vol_io_params
.sync_behavior
= IH_SYNC_ONCLOSE
;
122 ih_SetSyncBehavior(const char *behavior
)
126 if (strcmp(behavior
, "always") == 0) {
127 val
= IH_SYNC_ALWAYS
;
129 } else if (strcmp(behavior
, "delayed") == 0) {
130 val
= IH_SYNC_DELAYED
;
132 } else if (strcmp(behavior
, "onclose") == 0) {
133 val
= IH_SYNC_ONCLOSE
;
135 } else if (strcmp(behavior
, "never") == 0) {
139 /* invalid behavior name */
143 vol_io_params
.sync_behavior
= val
;
147 #ifdef AFS_PTHREAD_ENV
148 /* Initialize the global ihandle mutex */
152 MUTEX_INIT(&ih_glock_mutex
, "ih glock", MUTEX_DEFAULT
, 0);
154 #endif /* AFS_PTHREAD_ENV */
156 /* Initialize the file descriptor cache */
161 osi_Assert(!ih_Inited
);
163 DLL_INIT_LIST(ihAvailHead
, ihAvailTail
);
164 DLL_INIT_LIST(fdAvailHead
, fdAvailTail
);
165 DLL_INIT_LIST(fdLruHead
, fdLruTail
);
166 for (i
= 0; i
< I_HANDLE_HASH_SIZE
; i
++) {
167 DLL_INIT_LIST(ihashTable
[i
].ihash_head
, ihashTable
[i
].ihash_tail
);
169 #if defined(AFS_NT40_ENV)
170 fdMaxCacheSize
= vol_io_params
.fd_max_cachesize
;
171 #elif defined(AFS_SUN5_ENV) || defined(AFS_NBSD_ENV)
174 osi_Assert(getrlimit(RLIMIT_NOFILE
, &rlim
) == 0);
175 rlim
.rlim_cur
= rlim
.rlim_max
;
176 osi_Assert(setrlimit(RLIMIT_NOFILE
, &rlim
) == 0);
177 fdMaxCacheSize
= rlim
.rlim_cur
- vol_io_params
.fd_handle_setaside
;
179 /* XXX this is to avoid using up all system fd netbsd is
180 * somewhat broken and have set maximum fd for a root process
181 * to the same as system fd that is avaible, so if the
182 * fileserver uses all up process fds, all system fd will be
185 * Check for this better
189 fdMaxCacheSize
= MIN(fdMaxCacheSize
, vol_io_params
.fd_max_cachesize
);
190 osi_Assert(fdMaxCacheSize
> 0);
192 #elif defined(AFS_HPUX_ENV)
193 /* Avoid problems with "UFSOpen: igetinode failed" panics on HPUX 11.0 */
197 long fdMax
= MAX(sysconf(_SC_OPEN_MAX
) - vol_io_params
.fd_handle_setaside
,
199 fdMaxCacheSize
= (int)MIN(fdMax
, vol_io_params
.fd_max_cachesize
);
202 fdCacheSize
= MIN(fdMaxCacheSize
, vol_io_params
.fd_initial_cachesize
);
204 if (vol_io_params
.sync_behavior
== IH_SYNC_DELAYED
) {
205 #ifdef AFS_PTHREAD_ENV
207 pthread_attr_t tattr
;
209 pthread_attr_init(&tattr
);
210 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
212 pthread_create(&syncer
, &tattr
, ih_sync_thread
, NULL
);
213 #else /* AFS_PTHREAD_ENV */
215 LWP_CreateProcess(ih_sync_thread
, 16*1024, LWP_MAX_PRIORITY
- 2,
216 NULL
, "ih_syncer", &syncer
);
217 #endif /* AFS_PTHREAD_ENV */
222 /* Make the file descriptor cache as big as possible. Don't this call
223 * if the program uses fopen or fdopen, if fd_max_cachesize cannot be
224 * represented in the fileno member of the system FILE structure (or
228 ih_UseLargeCache(void)
232 if (!ih_PkgDefaultsSet
) {
240 fdCacheSize
= fdMaxCacheSize
;
245 /* Allocate a chunk of inode handles */
247 iHandleAllocateChunk(void)
252 osi_Assert(ihAvailHead
== NULL
);
253 ihP
= (IHandle_t
*) malloc(I_HANDLE_MALLOCSIZE
* sizeof(IHandle_t
));
254 osi_Assert(ihP
!= NULL
);
255 for (i
= 0; i
< I_HANDLE_MALLOCSIZE
; i
++) {
256 ihP
[i
].ih_refcnt
= 0;
257 DLL_INSERT_TAIL(&ihP
[i
], ihAvailHead
, ihAvailTail
, ih_next
, ih_prev
);
261 /* Initialize an inode handle */
263 ih_init(int dev
, int vid
, Inode ino
)
265 int ihash
= IH_HASH(dev
, vid
, ino
);
268 if (!ih_PkgDefaultsSet
) {
277 /* Do we already have a handle for this Inode? */
278 for (ihP
= ihashTable
[ihash
].ihash_head
; ihP
; ihP
= ihP
->ih_next
) {
279 if (ihP
->ih_ino
== ino
&& ihP
->ih_vid
== vid
&& ihP
->ih_dev
== dev
) {
286 /* Allocate and initialize a new Inode handle */
287 if (ihAvailHead
== NULL
) {
288 iHandleAllocateChunk();
291 osi_Assert(ihP
->ih_refcnt
== 0);
292 DLL_DELETE(ihP
, ihAvailHead
, ihAvailTail
, ih_next
, ih_prev
);
299 DLL_INIT_LIST(ihP
->ih_fdhead
, ihP
->ih_fdtail
);
300 DLL_INSERT_TAIL(ihP
, ihashTable
[ihash
].ihash_head
,
301 ihashTable
[ihash
].ihash_tail
, ih_next
, ih_prev
);
306 /* Copy an inode handle */
308 ih_copy(IHandle_t
* ihP
)
311 osi_Assert(ih_Inited
);
312 osi_Assert(ihP
->ih_refcnt
> 0);
318 /* Allocate a chunk of file descriptor handles */
320 fdHandleAllocateChunk(void)
325 osi_Assert(fdAvailHead
== NULL
);
326 fdP
= (FdHandle_t
*) malloc(FD_HANDLE_MALLOCSIZE
* sizeof(FdHandle_t
));
327 osi_Assert(fdP
!= NULL
);
328 for (i
= 0; i
< FD_HANDLE_MALLOCSIZE
; i
++) {
329 fdP
[i
].fd_status
= FD_HANDLE_AVAIL
;
330 fdP
[i
].fd_refcnt
= 0;
332 fdP
[i
].fd_fd
= INVALID_FD
;
333 fdP
[i
].fd_ihnext
= NULL
;
334 fdP
[i
].fd_ihprev
= NULL
;
335 DLL_INSERT_TAIL(&fdP
[i
], fdAvailHead
, fdAvailTail
, fd_next
, fd_prev
);
339 /* Allocate a chunk of stream handles */
341 streamHandleAllocateChunk(void)
344 StreamHandle_t
*streamP
;
346 osi_Assert(streamAvailHead
== NULL
);
347 streamP
= (StreamHandle_t
*)
348 malloc(STREAM_HANDLE_MALLOCSIZE
* sizeof(StreamHandle_t
));
349 osi_Assert(streamP
!= NULL
);
350 for (i
= 0; i
< STREAM_HANDLE_MALLOCSIZE
; i
++) {
351 streamP
[i
].str_fd
= INVALID_FD
;
352 DLL_INSERT_TAIL(&streamP
[i
], streamAvailHead
, streamAvailTail
,
358 * Get a file descriptor handle given an Inode handle
359 * Takes the given file descriptor, and creates a new FdHandle_t for it,
360 * attached to the given IHandle_t. fd can be INVALID_FD, indicating that the
361 * caller failed to open the relevant file because we had too many FDs open;
362 * ih_attachfd_r will then just evict/close an existing fd in the cache, and
366 ih_attachfd_r(IHandle_t
*ihP
, FD_t fd
)
371 /* fdCacheSize limits the size of the descriptor cache, but
372 * we permit the number of open files to exceed fdCacheSize.
373 * We only recycle open file descriptors when the number
374 * of open files reaches the size of the cache */
375 if ((fdInUseCount
> fdCacheSize
|| fd
== INVALID_FD
) && fdLruHead
!= NULL
) {
377 osi_Assert(fdP
->fd_status
== FD_HANDLE_OPEN
);
378 DLL_DELETE(fdP
, fdLruHead
, fdLruTail
, fd_next
, fd_prev
);
379 DLL_DELETE(fdP
, fdP
->fd_ih
->ih_fdhead
, fdP
->fd_ih
->ih_fdtail
,
380 fd_ihnext
, fd_ihprev
);
381 closeFd
= fdP
->fd_fd
;
382 if (fd
== INVALID_FD
) {
383 fdCacheSize
--; /* reduce in order to not run into here too often */
384 DLL_INSERT_TAIL(fdP
, fdAvailHead
, fdAvailTail
, fd_next
, fd_prev
);
385 fdP
->fd_status
= FD_HANDLE_AVAIL
;
387 fdP
->fd_fd
= INVALID_FD
;
395 if (fdAvailHead
== NULL
) {
396 fdHandleAllocateChunk();
399 osi_Assert(fdP
->fd_status
== FD_HANDLE_AVAIL
);
400 DLL_DELETE(fdP
, fdAvailHead
, fdAvailTail
, fd_next
, fd_prev
);
401 closeFd
= INVALID_FD
;
404 fdP
->fd_status
= FD_HANDLE_INUSE
;
411 /* Add this handle to the Inode's list of open descriptors */
412 DLL_INSERT_TAIL(fdP
, ihP
->ih_fdhead
, ihP
->ih_fdtail
, fd_ihnext
,
415 if (closeFd
!= INVALID_FD
) {
426 ih_attachfd(IHandle_t
*ihP
, FD_t fd
)
434 fdP
= ih_attachfd_r(ihP
, fd
);
445 * Get a file descriptor handle given an Inode handle
448 ih_open(IHandle_t
* ihP
)
453 if (!ihP
) /* XXX should log here in the fileserver */
458 /* Do we already have an open file handle for this Inode? */
459 for (fdP
= ihP
->ih_fdtail
; fdP
!= NULL
; fdP
= fdP
->fd_ihprev
) {
460 if (fdP
->fd_status
== FD_HANDLE_CLOSING
) {
461 /* The handle was open when an IH_REALLYCLOSE was issued, so we
462 * cannot reuse it; it will be closed soon. */
467 * If we don't have positional i/o, don't try to share fds, since
468 * we can't do so in a threadsafe way.
470 if (fdP
->fd_status
== FD_HANDLE_INUSE
) {
473 osi_Assert(fdP
->fd_status
== FD_HANDLE_OPEN
);
475 osi_Assert(fdP
->fd_status
!= FD_HANDLE_AVAIL
);
476 #endif /* HAVE_PIO */
479 if (fdP
->fd_status
== FD_HANDLE_OPEN
) {
480 fdP
->fd_status
= FD_HANDLE_INUSE
;
481 DLL_DELETE(fdP
, fdLruHead
, fdLruTail
, fd_next
, fd_prev
);
489 * Try to open the Inode, return NULL on error.
496 if (fd
== INVALID_FD
&& (errno
!= EMFILE
|| fdLruHead
== NULL
) ) {
502 fdP
= ih_attachfd_r(ihP
, fd
);
504 osi_Assert(fd
== INVALID_FD
);
515 * Return a file descriptor handle to the cache
518 fd_close(FdHandle_t
* fdP
)
526 osi_Assert(ih_Inited
);
527 osi_Assert(fdInUseCount
> 0);
528 osi_Assert(fdP
->fd_status
== FD_HANDLE_INUSE
||
529 fdP
->fd_status
== FD_HANDLE_CLOSING
);
533 /* Call fd_reallyclose to really close the unused file handles if
534 * the previous attempt to close (ih_reallyclose()) all file handles
535 * failed (this is determined by checking the ihandle for the flag
536 * IH_REALLY_CLOSED) or we have too many open files.
538 if (fdP
->fd_status
== FD_HANDLE_CLOSING
||
539 ihP
->ih_flags
& IH_REALLY_CLOSED
|| fdInUseCount
> fdCacheSize
) {
541 return fd_reallyclose(fdP
);
545 if (fdP
->fd_refcnt
== 0) {
546 /* Put this descriptor back into the cache */
547 fdP
->fd_status
= FD_HANDLE_OPEN
;
548 DLL_INSERT_TAIL(fdP
, fdLruHead
, fdLruTail
, fd_next
, fd_prev
);
551 /* If this is not the only reference to the Inode then we can decrement
552 * the reference count, otherwise we need to call ih_release.
554 if (ihP
->ih_refcnt
> 1) {
566 * Actually close the file descriptor handle and return it to
570 fd_reallyclose(FdHandle_t
* fdP
)
579 osi_Assert(ih_Inited
);
580 osi_Assert(fdInUseCount
> 0);
581 osi_Assert(fdP
->fd_status
== FD_HANDLE_INUSE
||
582 fdP
->fd_status
== FD_HANDLE_CLOSING
);
585 closeFd
= fdP
->fd_fd
;
588 if (fdP
->fd_refcnt
== 0) {
589 DLL_DELETE(fdP
, ihP
->ih_fdhead
, ihP
->ih_fdtail
, fd_ihnext
, fd_ihprev
);
590 DLL_INSERT_TAIL(fdP
, fdAvailHead
, fdAvailTail
, fd_next
, fd_prev
);
592 fdP
->fd_status
= FD_HANDLE_AVAIL
;
595 fdP
->fd_fd
= INVALID_FD
;
598 /* All the file descriptor handles have been closed; reset
599 * the IH_REALLY_CLOSED flag indicating that ih_reallyclose
600 * has completed its job.
602 if (!ihP
->ih_fdhead
) {
603 ihP
->ih_flags
&= ~IH_REALLY_CLOSED
;
605 FdHandle_t
*lfdP
, *next
;
607 for (lfdP
= ihP
->ih_fdhead
; lfdP
!= NULL
; lfdP
= next
) {
608 next
= lfdP
->fd_ihnext
;
609 osi_Assert(lfdP
->fd_ih
== ihP
);
610 if (lfdP
->fd_status
!= FD_HANDLE_CLOSING
) {
615 /* no *future* fd should be subjected to this */
617 ihP
->ih_flags
&= ~IH_REALLY_CLOSED
;
620 if (fdP
->fd_refcnt
== 0) {
627 /* If this is not the only reference to the Inode then we can decrement
628 * the reference count, otherwise we need to call ih_release. */
629 if (ihP
->ih_refcnt
> 1) {
640 /* Enable buffered I/O on a file descriptor */
642 stream_fdopen(FD_t fd
)
644 StreamHandle_t
*streamP
;
647 if (streamAvailHead
== NULL
) {
648 streamHandleAllocateChunk();
650 streamP
= streamAvailHead
;
651 DLL_DELETE(streamP
, streamAvailHead
, streamAvailTail
, str_next
, str_prev
);
653 streamP
->str_fd
= fd
;
654 streamP
->str_buflen
= 0;
655 streamP
->str_bufoff
= 0;
656 streamP
->str_fdoff
= 0;
657 streamP
->str_error
= 0;
658 streamP
->str_eof
= 0;
659 streamP
->str_direction
= STREAM_DIRECTION_NONE
;
663 /* Open a file for buffered I/O */
665 stream_open(const char *filename
, const char *mode
)
667 FD_t fd
= INVALID_FD
;
669 if (strcmp(mode
, "r") == 0) {
670 fd
= OS_OPEN(filename
, O_RDONLY
, 0);
671 } else if (strcmp(mode
, "r+") == 0) {
672 fd
= OS_OPEN(filename
, O_RDWR
, 0);
673 } else if (strcmp(mode
, "w") == 0) {
674 fd
= OS_OPEN(filename
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0);
675 } else if (strcmp(mode
, "w+") == 0) {
676 fd
= OS_OPEN(filename
, O_RDWR
| O_TRUNC
| O_CREAT
, 0);
677 } else if (strcmp(mode
, "a") == 0) {
678 fd
= OS_OPEN(filename
, O_WRONLY
| O_APPEND
| O_CREAT
, 0);
679 } else if (strcmp(mode
, "a+") == 0) {
680 fd
= OS_OPEN(filename
, O_RDWR
| O_APPEND
| O_CREAT
, 0);
682 osi_Assert(FALSE
); /* not implemented */
685 if (fd
== INVALID_FD
) {
688 return stream_fdopen(fd
);
691 /* fread for buffered I/O handles */
693 stream_read(void *ptr
, afs_fsize_t size
, afs_fsize_t nitems
,
694 StreamHandle_t
* streamP
)
696 afs_fsize_t nbytes
, bytesRead
, bytesToRead
;
699 /* Need to seek before changing direction */
700 if (streamP
->str_direction
== STREAM_DIRECTION_NONE
) {
701 streamP
->str_direction
= STREAM_DIRECTION_READ
;
702 streamP
->str_bufoff
= 0;
703 streamP
->str_buflen
= 0;
705 osi_Assert(streamP
->str_direction
== STREAM_DIRECTION_READ
);
709 nbytes
= size
* nitems
;
711 while (nbytes
> 0 && !streamP
->str_eof
) {
712 if (streamP
->str_buflen
== 0) {
713 streamP
->str_bufoff
= 0;
714 streamP
->str_buflen
=
715 OS_PREAD(streamP
->str_fd
, streamP
->str_buffer
,
716 STREAM_HANDLE_BUFSIZE
, streamP
->str_fdoff
);
717 if (streamP
->str_buflen
< 0) {
718 streamP
->str_error
= errno
;
719 streamP
->str_buflen
= 0;
722 } else if (streamP
->str_buflen
== 0) {
723 streamP
->str_eof
= 1;
726 streamP
->str_fdoff
+= streamP
->str_buflen
;
729 bytesToRead
= nbytes
;
730 if (bytesToRead
> streamP
->str_buflen
) {
731 bytesToRead
= streamP
->str_buflen
;
733 memcpy(p
, streamP
->str_buffer
+ streamP
->str_bufoff
, bytesToRead
);
735 streamP
->str_bufoff
+= bytesToRead
;
736 streamP
->str_buflen
-= bytesToRead
;
737 bytesRead
+= bytesToRead
;
738 nbytes
-= bytesToRead
;
741 return (bytesRead
/ size
);
744 /* fwrite for buffered I/O handles */
746 stream_write(void *ptr
, afs_fsize_t size
, afs_fsize_t nitems
,
747 StreamHandle_t
* streamP
)
751 afs_fsize_t nbytes
, bytesWritten
, bytesToWrite
;
753 /* Need to seek before changing direction */
754 if (streamP
->str_direction
== STREAM_DIRECTION_NONE
) {
755 streamP
->str_direction
= STREAM_DIRECTION_WRITE
;
756 streamP
->str_bufoff
= 0;
757 streamP
->str_buflen
= STREAM_HANDLE_BUFSIZE
;
759 osi_Assert(streamP
->str_direction
== STREAM_DIRECTION_WRITE
);
762 nbytes
= size
* nitems
;
766 if (streamP
->str_buflen
== 0) {
767 rc
= OS_PWRITE(streamP
->str_fd
, streamP
->str_buffer
,
768 STREAM_HANDLE_BUFSIZE
, streamP
->str_fdoff
);
770 streamP
->str_error
= errno
;
774 streamP
->str_fdoff
+= rc
;
775 streamP
->str_bufoff
= 0;
776 streamP
->str_buflen
= STREAM_HANDLE_BUFSIZE
;
779 bytesToWrite
= nbytes
;
780 if (bytesToWrite
> streamP
->str_buflen
) {
781 bytesToWrite
= streamP
->str_buflen
;
783 memcpy(streamP
->str_buffer
+ streamP
->str_bufoff
, p
, bytesToWrite
);
785 streamP
->str_bufoff
+= bytesToWrite
;
786 streamP
->str_buflen
-= bytesToWrite
;
787 bytesWritten
+= bytesToWrite
;
788 nbytes
-= bytesToWrite
;
791 return (bytesWritten
/ size
);
794 /* fseek for buffered I/O handles */
796 stream_aseek(StreamHandle_t
* streamP
, afs_foff_t offset
)
801 if (streamP
->str_direction
== STREAM_DIRECTION_WRITE
802 && streamP
->str_bufoff
> 0) {
803 rc
= OS_PWRITE(streamP
->str_fd
, streamP
->str_buffer
,
804 streamP
->str_bufoff
, streamP
->str_fdoff
);
806 streamP
->str_error
= errno
;
810 streamP
->str_fdoff
= offset
;
811 streamP
->str_bufoff
= 0;
812 streamP
->str_buflen
= 0;
813 streamP
->str_eof
= 0;
814 streamP
->str_direction
= STREAM_DIRECTION_NONE
;
818 /* fflush for buffered I/O handles */
820 stream_flush(StreamHandle_t
* streamP
)
825 if (streamP
->str_direction
== STREAM_DIRECTION_WRITE
826 && streamP
->str_bufoff
> 0) {
827 rc
= OS_PWRITE(streamP
->str_fd
, streamP
->str_buffer
,
828 streamP
->str_bufoff
, streamP
->str_fdoff
);
830 streamP
->str_error
= errno
;
833 streamP
->str_fdoff
+= rc
;
835 streamP
->str_bufoff
= 0;
836 streamP
->str_buflen
= STREAM_HANDLE_BUFSIZE
;
842 /* Free a buffered I/O handle */
844 stream_close(StreamHandle_t
* streamP
, int reallyClose
)
849 osi_Assert(streamP
!= NULL
);
850 if (streamP
->str_direction
== STREAM_DIRECTION_WRITE
851 && streamP
->str_bufoff
> 0) {
852 rc
= OS_PWRITE(streamP
->str_fd
, streamP
->str_buffer
,
853 streamP
->str_bufoff
, streamP
->str_fdoff
);
857 streamP
->str_fdoff
+= rc
;
861 rc
= OS_CLOSE(streamP
->str_fd
);
866 streamP
->str_fd
= INVALID_FD
;
869 DLL_INSERT_TAIL(streamP
, streamAvailHead
, streamAvailTail
,
875 /* Close all unused file descriptors associated with the inode
876 * handle. Called with IH_LOCK held. May drop and reacquire
877 * IH_LOCK. Sets the IH_REALLY_CLOSED flag in the inode handle
878 * if it fails to close all file handles.
881 ih_fdclose(IHandle_t
* ihP
)
883 int closeCount
, closedAll
;
884 FdHandle_t
*fdP
, *head
, *tail
, *next
;
886 osi_Assert(ihP
->ih_refcnt
> 0);
889 DLL_INIT_LIST(head
, tail
);
890 ihP
->ih_flags
&= ~IH_REALLY_CLOSED
;
893 * Remove the file descriptors for this Inode from the LRU queue
894 * and the IHandle queue and put them on a temporary queue so we
895 * can drop the lock before we close the files.
897 for (fdP
= ihP
->ih_fdhead
; fdP
!= NULL
; fdP
= next
) {
898 next
= fdP
->fd_ihnext
;
899 osi_Assert(fdP
->fd_ih
== ihP
);
900 osi_Assert(fdP
->fd_status
== FD_HANDLE_OPEN
901 || fdP
->fd_status
== FD_HANDLE_INUSE
902 || fdP
->fd_status
== FD_HANDLE_CLOSING
);
903 if (fdP
->fd_status
== FD_HANDLE_OPEN
) {
904 /* Note that FdHandle_t's do not count against the parent
905 * IHandle_t ref count when they are FD_HANDLE_OPEN. So, we don't
906 * need to dec the parent IHandle_t ref count for each one we pull
908 DLL_DELETE(fdP
, ihP
->ih_fdhead
, ihP
->ih_fdtail
, fd_ihnext
,
910 DLL_DELETE(fdP
, fdLruHead
, fdLruTail
, fd_next
, fd_prev
);
911 DLL_INSERT_TAIL(fdP
, head
, tail
, fd_next
, fd_prev
);
914 fdP
->fd_status
= FD_HANDLE_CLOSING
;
915 ihP
->ih_flags
|= IH_REALLY_CLOSED
;
919 /* If the ihandle reference count is 1, we should have
920 * closed all file descriptors.
922 if (ihP
->ih_refcnt
== 1 || closedAll
) {
923 osi_Assert(closedAll
);
924 osi_Assert(!ihP
->ih_fdhead
);
925 osi_Assert(!ihP
->ih_fdtail
);
929 return 0; /* No file descriptors closed */
934 * Close the file descriptors
937 for (fdP
= head
; fdP
!= NULL
; fdP
= fdP
->fd_next
) {
938 OS_CLOSE(fdP
->fd_fd
);
939 fdP
->fd_status
= FD_HANDLE_AVAIL
;
941 fdP
->fd_fd
= INVALID_FD
;
947 osi_Assert(fdInUseCount
>= closeCount
);
948 fdInUseCount
-= closeCount
;
951 * Append the temporary queue to the list of available descriptors
953 if (fdAvailHead
== NULL
) {
957 fdAvailTail
->fd_next
= head
;
958 head
->fd_prev
= fdAvailTail
;
965 /* Close all cached file descriptors for this inode. */
967 ih_reallyclose(IHandle_t
* ihP
)
973 ihP
->ih_refcnt
++; /* must not disappear over unlock */
974 if (ihP
->ih_synced
) {
976 osi_Assert(vol_io_params
.sync_behavior
!= IH_SYNC_ALWAYS
);
977 osi_Assert(vol_io_params
.sync_behavior
!= IH_SYNC_NEVER
);
990 osi_Assert(ihP
->ih_refcnt
> 0);
994 if (ihP
->ih_refcnt
> 1) {
1004 /* Release an Inode handle. All cached file descriptors for this
1005 * inode are closed when the last reference to this handle is released
1008 ih_release(IHandle_t
* ihP
)
1016 osi_Assert(ihP
->ih_refcnt
> 0);
1018 if (ihP
->ih_refcnt
> 1) {
1024 ihash
= IH_HASH(ihP
->ih_dev
, ihP
->ih_vid
, ihP
->ih_ino
);
1025 DLL_DELETE(ihP
, ihashTable
[ihash
].ihash_head
,
1026 ihashTable
[ihash
].ihash_tail
, ih_next
, ih_prev
);
1032 DLL_INSERT_TAIL(ihP
, ihAvailHead
, ihAvailTail
, ih_next
, ih_prev
);
1038 /* Sync an inode to disk if its handle isn't NULL */
1040 ih_condsync(IHandle_t
* ihP
)
1052 code
= FDH_SYNC(fdP
);
1064 for (ihash
= 0; ihash
< I_HANDLE_HASH_SIZE
; ihash
++) {
1065 IHandle_t
*ihP
, *ihPnext
;
1067 ihP
= ihashTable
[ihash
].ihash_head
;
1069 ihP
->ih_refcnt
++; /* must not disappear over unlock */
1070 for (; ihP
; ihP
= ihPnext
) {
1072 if (ihP
->ih_synced
) {
1079 if (fd
!= INVALID_FD
) {
1087 /* when decrementing the refcount, the ihandle might disappear
1088 and we might not even be able to proceed to the next one.
1089 Hence the gymnastics putting a hold on the next one already */
1090 ihPnext
= ihP
->ih_next
;
1091 if (ihPnext
) ihPnext
->ih_refcnt
++;
1093 if (ihP
->ih_refcnt
> 1) {
1107 ih_sync_thread(void *dummy
) {
1110 #ifdef AFS_PTHREAD_ENV
1112 #else /* AFS_PTHREAD_ENV */
1114 #endif /* AFS_PTHREAD_ENV */
1122 /*************************************************************************
1123 * OS specific support routines.
1124 *************************************************************************/
1125 #ifndef AFS_NAMEI_ENV
1127 ih_icreate(IHandle_t
* ih
, int dev
, char *part
, Inode nI
, int p1
, int p2
,
1131 #ifdef AFS_3DISPARES
1132 /* See viceinode.h */
1133 if (p2
== INODESPECIAL
) {
1139 ino
= ICREATE(dev
, part
, nI
, p1
, p2
, p3
, p4
);
1142 #endif /* AFS_NAMEI_ENV */
1144 #if defined(AFS_NT40_ENV) || !defined(AFS_NAMEI_ENV)
1145 /* Unix namei implements its own more efficient IH_CREATE_INIT; this wrapper
1146 * is for everyone else */
1148 ih_icreate_init(IHandle_t
*lh
, int dev
, char *part
, Inode nearInode
,
1149 afs_uint32 p1
, afs_uint32 p2
, afs_uint32 p3
, afs_uint32 p4
)
1152 Inode ino
= IH_CREATE(lh
, dev
, part
, nearInode
, p1
, p2
, p3
, p4
);
1153 if (!VALID_INO(ino
)) {
1156 IH_INIT(ihP
, dev
, p1
, ino
);
1166 if (!GetFileSizeEx(fd
, &size
))
1168 return size
.QuadPart
;
1170 struct afs_stat status
;
1171 if (afs_fstat(fd
, &status
) < 0)
1173 return status
.st_size
;
1179 ih_pread(int fd
, void * buf
, size_t count
, afs_foff_t offset
)
1182 code
= OS_SEEK(fd
, offset
, 0);
1185 return OS_READ(fd
, buf
, count
);
1189 ih_pwrite(int fd
, const void * buf
, size_t count
, afs_foff_t offset
)
1192 code
= OS_SEEK(fd
, offset
, 0);
1195 return OS_WRITE(fd
, buf
, count
);
1197 #endif /* !HAVE_PIO */
1199 #ifndef AFS_NT40_ENV
1201 ih_isunlinked(int fd
)
1203 struct afs_stat status
;
1204 if (afs_fstat(fd
, &status
) < 0) {
1207 if (status
.st_nlink
< 1) {
1212 #endif /* !AFS_NT40_ENV */
1215 ih_fdsync(FdHandle_t
*fdP
)
1217 switch (vol_io_params
.sync_behavior
) {
1218 case IH_SYNC_ALWAYS
:
1219 return OS_SYNC(fdP
->fd_fd
);
1220 case IH_SYNC_DELAYED
:
1221 case IH_SYNC_ONCLOSE
:
1223 fdP
->fd_ih
->ih_synced
= 1;