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:
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user