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 {
int32 type; /* descriptor type */
int32 ref_count;
int32 open_count;
struct fd_ops *ops;
union {
struct vnode *vnode;
+34 -31
View File
@@ -54,6 +54,7 @@ alloc_fd(void)
descriptor->u.vnode = NULL;
descriptor->cookie = NULL;
descriptor->ref_count = 1;
descriptor->open_count = 1;
descriptor->open_mode = 0;
descriptor->pos = 0;
@@ -108,9 +109,7 @@ put_fd(struct file_descriptor *descriptor)
// free the descriptor if we don't need it anymore
if (atomic_add(&descriptor->ref_count, -1) == 1) {
// close the underlying object (and free any resources allocated there)
if (descriptor->ops->fd_close)
descriptor->ops->fd_close(descriptor);
// free the underlying object
if (descriptor->ops->fd_free)
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
* reduces its reference counter.
/** Removes the file descriptor in the specified slot.
*/
static void
static struct file_descriptor *
remove_fd(struct io_context *context, int fd)
{
struct file_descriptor *descriptor = NULL;
if (fd < 0)
return;
return NULL;
mutex_lock(&context->io_mutex);
@@ -165,8 +163,7 @@ remove_fd(struct io_context *context, int fd)
mutex_unlock(&context->io_mutex);
if (descriptor)
put_fd(descriptor);
return 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 -
/*** USER routines ***/
@@ -592,18 +615,7 @@ _user_rewind_dir(int fd)
status_t
_user_close(int fd)
{
struct io_context *io = get_current_io_context(false);
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;
return common_close(fd, true);
}
@@ -856,16 +868,7 @@ _kern_rewind_dir(int fd)
status_t
_kern_close(int fd)
{
struct io_context *io = get_current_io_context(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;
return common_close(fd, true);
}