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