We were handling closing of file descriptors incorrectly. The close_*()

and free_*_cookie() hooks of the underlying FS were always called
together when the reference count of the FD dropped to zero. When
blocking operations (reading/writing) on the FD were still in progress
this would never happen, though. Now we additionally maintain an open
count and call the close_*() hook when it drops to zero.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@11882 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2005-03-17 20:25:07 +00:00
parent 92290ecd54
commit d49f1b87a0
2 changed files with 35 additions and 31 deletions
+1
View File
@@ -36,6 +36,7 @@ struct fd_ops {
struct file_descriptor { struct file_descriptor {
int32 type; /* descriptor type */ int32 type; /* descriptor type */
int32 ref_count; int32 ref_count;
int32 open_count;
struct fd_ops *ops; struct fd_ops *ops;
union { union {
struct vnode *vnode; struct vnode *vnode;
+34 -31
View File
@@ -54,6 +54,7 @@ alloc_fd(void)
descriptor->u.vnode = NULL; descriptor->u.vnode = NULL;
descriptor->cookie = NULL; descriptor->cookie = NULL;
descriptor->ref_count = 1; descriptor->ref_count = 1;
descriptor->open_count = 1;
descriptor->open_mode = 0; descriptor->open_mode = 0;
descriptor->pos = 0; descriptor->pos = 0;
@@ -108,9 +109,7 @@ put_fd(struct file_descriptor *descriptor)
// free the descriptor if we don't need it anymore // free the descriptor if we don't need it anymore
if (atomic_add(&descriptor->ref_count, -1) == 1) { if (atomic_add(&descriptor->ref_count, -1) == 1) {
// close the underlying object (and free any resources allocated there) // free the underlying object
if (descriptor->ops->fd_close)
descriptor->ops->fd_close(descriptor);
if (descriptor->ops->fd_free) if (descriptor->ops->fd_free)
descriptor->ops->fd_free(descriptor); descriptor->ops->fd_free(descriptor);
@@ -141,17 +140,16 @@ get_fd(struct io_context *context, int fd)
} }
/** Removes the file descriptor in the specified slot, and /** Removes the file descriptor in the specified slot.
* reduces its reference counter.
*/ */
static void static struct file_descriptor *
remove_fd(struct io_context *context, int fd) remove_fd(struct io_context *context, int fd)
{ {
struct file_descriptor *descriptor = NULL; struct file_descriptor *descriptor = NULL;
if (fd < 0) if (fd < 0)
return; return NULL;
mutex_lock(&context->io_mutex); mutex_lock(&context->io_mutex);
@@ -165,8 +163,7 @@ remove_fd(struct io_context *context, int fd)
mutex_unlock(&context->io_mutex); mutex_unlock(&context->io_mutex);
if (descriptor) return descriptor;
put_fd(descriptor);
} }
@@ -302,6 +299,32 @@ fd_is_valid(int fd, bool kernel)
} }
static status_t
common_close(int fd, bool kernel)
{
struct io_context *io = get_current_io_context(kernel);
struct file_descriptor *descriptor = remove_fd(io, fd);
if (descriptor == NULL)
return B_FILE_ERROR;
#ifdef TRACE_FD
if (!kernel)
TRACE(("_user_close(descriptor = %p)\n", descriptor));
#endif
if (atomic_add(&descriptor->open_count, -1) == 1) {
if (descriptor->ops->fd_close)
descriptor->ops->fd_close(descriptor);
}
put_fd(descriptor);
// the reference associated with the slot
return B_OK;
}
// #pragma mark - // #pragma mark -
/*** USER routines ***/ /*** USER routines ***/
@@ -592,18 +615,7 @@ _user_rewind_dir(int fd)
status_t status_t
_user_close(int fd) _user_close(int fd)
{ {
struct io_context *io = get_current_io_context(false); return common_close(fd, true);
struct file_descriptor *descriptor = get_fd(io, fd);
if (descriptor == NULL)
return B_FILE_ERROR;
TRACE(("user_close(descriptor = %p)\n", descriptor));
remove_fd(io, fd);
put_fd(descriptor);
return B_OK;
} }
@@ -856,16 +868,7 @@ _kern_rewind_dir(int fd)
status_t status_t
_kern_close(int fd) _kern_close(int fd)
{ {
struct io_context *io = get_current_io_context(true); return common_close(fd, true);
struct file_descriptor *descriptor = get_fd(io, fd);
if (descriptor == NULL)
return B_FILE_ERROR;
remove_fd(io, fd);
put_fd(descriptor);
return B_OK;
} }