Commit 964815bc authored by Alexandre Julliard's avatar Alexandre Julliard

Added an unmount_device request that invalidates all file descriptors

open on a given Unix device.
parent 66868e53
......@@ -851,6 +851,18 @@ struct unlock_file_reply
struct unmount_device_request
{
struct request_header __header;
obj_handle_t handle;
};
struct unmount_device_reply
{
struct reply_header __header;
};
struct create_socket_request
{
struct request_header __header;
......@@ -3592,6 +3604,7 @@ enum request
REQ_flush_file,
REQ_lock_file,
REQ_unlock_file,
REQ_unmount_device,
REQ_create_socket,
REQ_accept_socket,
REQ_set_socket_event,
......@@ -3802,6 +3815,7 @@ union generic_request
struct flush_file_request flush_file_request;
struct lock_file_request lock_file_request;
struct unlock_file_request unlock_file_request;
struct unmount_device_request unmount_device_request;
struct create_socket_request create_socket_request;
struct accept_socket_request accept_socket_request;
struct set_socket_event_request set_socket_event_request;
......@@ -4010,6 +4024,7 @@ union generic_reply
struct flush_file_reply flush_file_reply;
struct lock_file_reply lock_file_reply;
struct unlock_file_reply unlock_file_reply;
struct unmount_device_reply unmount_device_reply;
struct create_socket_reply create_socket_reply;
struct accept_socket_reply accept_socket_reply;
struct set_socket_event_reply set_socket_event_reply;
......@@ -4175,6 +4190,6 @@ union generic_reply
struct set_mailslot_info_reply set_mailslot_info_reply;
};
#define SERVER_PROTOCOL_VERSION 188
#define SERVER_PROTOCOL_VERSION 189
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
......@@ -137,6 +137,8 @@ static struct change *create_change_notification( struct fd *fd, int subtree, un
struct stat st;
int unix_fd = get_unix_fd( fd );
if (unix_fd == -1) return NULL;
if (fstat( unix_fd, &st ) == -1 || !S_ISDIR(st.st_mode))
{
set_error( STATUS_NOT_A_DIRECTORY );
......
......@@ -625,7 +625,7 @@ static void device_destroy( struct object *obj )
/* inode functions */
/* close all pending file descriptors in the closed list */
static void inode_close_pending( struct inode *inode )
static void inode_close_pending( struct inode *inode, int keep_unlinks )
{
struct list *ptr = list_head( &inode->closed );
......@@ -639,7 +639,7 @@ static void inode_close_pending( struct inode *inode )
close( fd->unix_fd );
fd->unix_fd = -1;
}
if (!fd->unlink) /* get rid of it unless there's an unlink pending on that file */
if (!keep_unlinks || !fd->unlink[0]) /* get rid of it unless there's an unlink pending on that file */
{
list_remove( ptr );
free( fd );
......@@ -968,7 +968,7 @@ static void remove_lock( struct file_lock *lock, int remove_unix )
list_remove( &lock->inode_entry );
list_remove( &lock->proc_entry );
if (remove_unix) remove_unix_locks( lock->fd, lock->start, lock->end );
if (list_empty( &inode->locks )) inode_close_pending( inode );
if (list_empty( &inode->locks )) inode_close_pending( inode, 1 );
lock->process = NULL;
wake_up( &lock->obj, 0 );
release_object( lock );
......@@ -1187,6 +1187,26 @@ void set_fd_events( struct fd *fd, int events )
}
}
/* prepare an fd for unmounting its corresponding device */
static inline void unmount_fd( struct fd *fd )
{
assert( fd->inode );
async_terminate_queue( &fd->read_q, STATUS_VOLUME_DISMOUNTED );
async_terminate_queue( &fd->write_q, STATUS_VOLUME_DISMOUNTED );
if (fd->poll_index != -1) set_fd_events( fd, -1 );
if (fd->unix_fd != -1) close( fd->unix_fd );
fd->unix_fd = -1;
fd->closed->unix_fd = -1;
fd->closed->unlink[0] = 0;
/* stop using Unix locks on this fd (existing locks have been removed by close) */
fd->fs_locks = 0;
}
/* allocate an fd object, without setting the unix fd yet */
struct fd *alloc_fd( const struct fd_ops *fd_user_ops, struct object *user )
{
......@@ -1379,6 +1399,7 @@ void *get_fd_user( struct fd *fd )
/* retrieve the unix fd for an object */
int get_unix_fd( struct fd *fd )
{
if (fd->unix_fd == -1) set_error( STATUS_VOLUME_DISMOUNTED );
return fd->unix_fd;
}
......@@ -1399,6 +1420,8 @@ int check_fd_events( struct fd *fd, int events )
{
struct pollfd pfd;
if (fd->unix_fd == -1) return POLLERR;
pfd.fd = fd->unix_fd;
pfd.events = events;
if (poll( &pfd, 1, 0 ) <= 0) return 0;
......@@ -1554,6 +1577,29 @@ void no_cancel_async( struct fd *fd )
set_error( STATUS_OBJECT_TYPE_MISMATCH );
}
/* close all Unix file descriptors on a device to allow unmounting it */
static void unmount_device( struct device *device )
{
unsigned int i;
struct inode *inode;
struct fd *fd;
for (i = 0; i < INODE_HASH_SIZE; i++)
{
LIST_FOR_EACH_ENTRY( inode, &device->inode_hash[i], struct inode, entry )
{
LIST_FOR_EACH_ENTRY( fd, &inode->open, struct fd, inode_entry )
{
unmount_fd( fd );
}
inode_close_pending( inode, 0 );
}
}
/* remove it from the hash table */
list_remove( &device->entry );
list_init( &device->entry );
}
/* same as get_handle_obj but retrieve the struct fd associated to the object */
static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handle,
unsigned int access )
......@@ -1595,18 +1641,31 @@ DECL_HANDLER(get_handle_fd)
if ((fd = get_handle_fd_obj( current->process, req->handle, req->access )))
{
int unix_fd = get_handle_unix_fd( current->process, req->handle, req->access );
if (unix_fd != -1) reply->fd = unix_fd;
else if (!get_error())
int unix_fd = get_unix_fd( fd );
if (unix_fd != -1)
{
assert( fd->unix_fd != -1 );
send_client_fd( current->process, fd->unix_fd, req->handle );
int cached_fd = get_handle_unix_fd( current->process, req->handle, req->access );
if (cached_fd != -1) reply->fd = cached_fd;
else if (!get_error()) send_client_fd( current->process, unix_fd, req->handle );
}
reply->flags = fd->fd_ops->get_file_info( fd );
release_object( fd );
}
}
/* get ready to unmount a Unix device */
DECL_HANDLER(unmount_device)
{
struct fd *fd;
if ((fd = get_handle_fd_obj( current->process, req->handle, 0 )))
{
if (fd->inode) unmount_device( fd->inode->device );
else set_error( STATUS_OBJECT_TYPE_MISMATCH );
release_object( fd );
}
}
/* create / reschedule an async I/O */
DECL_HANDLER(register_async)
{
......
......@@ -226,8 +226,13 @@ static int file_get_poll_events( struct fd *fd )
static int file_flush( struct fd *fd, struct event **event )
{
int ret = (fsync( get_unix_fd(fd) ) != -1);
if (!ret) file_set_error();
int ret = 0, unix_fd = get_unix_fd( fd );
if (unix_fd != -1)
{
ret = (fsync( unix_fd ) != -1);
if (!ret) file_set_error();
}
return ret;
}
......@@ -304,6 +309,8 @@ static int extend_file( struct file *file, file_pos_t new_size )
int unix_fd = get_file_unix_fd( file );
off_t size = new_size;
if (unix_fd == -1) return 0;
if (sizeof(new_size) > sizeof(size) && size != new_size)
{
set_error( STATUS_INVALID_PARAMETER );
......@@ -326,6 +333,8 @@ int grow_file( struct file *file, file_pos_t size )
struct stat st;
int unix_fd = get_file_unix_fd( file );
if (unix_fd == -1) return 0;
if (fstat( unix_fd, &st ) == -1)
{
file_set_error();
......
......@@ -196,7 +196,7 @@ static int get_image_params( struct mapping *mapping )
/* load the headers */
if (!(fd = mapping_get_fd( &mapping->obj ))) return 0;
unix_fd = get_unix_fd( fd );
if ((unix_fd = get_unix_fd( fd )) == -1) goto error;
if (pread( unix_fd, &dos, sizeof(dos), 0 ) != sizeof(dos)) goto error;
if (dos.e_magic != IMAGE_DOS_SIGNATURE) goto error;
pos = dos.e_lfanew;
......@@ -250,7 +250,7 @@ inline static int get_file_size( struct file *file, file_pos_t *size )
struct stat st;
int unix_fd = get_file_unix_fd( file );
if (fstat( unix_fd, &st ) == -1) return 0;
if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 0;
*size = st.st_size;
return 1;
}
......
......@@ -657,6 +657,12 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
@END
/* Get ready to unmount a Unix device */
@REQ(unmount_device)
obj_handle_t handle; /* handle to a file on the device */
@END
/* Create a socket */
@REQ(create_socket)
unsigned int access; /* wanted access rights */
......
......@@ -143,6 +143,7 @@ DECL_HANDLER(get_handle_fd);
DECL_HANDLER(flush_file);
DECL_HANDLER(lock_file);
DECL_HANDLER(unlock_file);
DECL_HANDLER(unmount_device);
DECL_HANDLER(create_socket);
DECL_HANDLER(accept_socket);
DECL_HANDLER(set_socket_event);
......@@ -352,6 +353,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_flush_file,
(req_handler)req_lock_file,
(req_handler)req_unlock_file,
(req_handler)req_unmount_device,
(req_handler)req_create_socket,
(req_handler)req_accept_socket,
(req_handler)req_set_socket_event,
......
......@@ -1077,6 +1077,11 @@ static void dump_unlock_file_request( const struct unlock_file_request *req )
fprintf( stderr, " count_high=%08x", req->count_high );
}
static void dump_unmount_device_request( const struct unmount_device_request *req )
{
fprintf( stderr, " handle=%p", req->handle );
}
static void dump_create_socket_request( const struct create_socket_request *req )
{
fprintf( stderr, " access=%08x,", req->access );
......@@ -3114,6 +3119,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_flush_file_request,
(dump_func)dump_lock_file_request,
(dump_func)dump_unlock_file_request,
(dump_func)dump_unmount_device_request,
(dump_func)dump_create_socket_request,
(dump_func)dump_accept_socket_request,
(dump_func)dump_set_socket_event_request,
......@@ -3320,6 +3326,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_flush_file_reply,
(dump_func)dump_lock_file_reply,
(dump_func)0,
(dump_func)0,
(dump_func)dump_create_socket_reply,
(dump_func)dump_accept_socket_reply,
(dump_func)0,
......@@ -3526,6 +3533,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"flush_file",
"lock_file",
"unlock_file",
"unmount_device",
"create_socket",
"accept_socket",
"set_socket_event",
......@@ -3755,6 +3763,7 @@ static const struct
{ "SUSPEND_COUNT_EXCEEDED", STATUS_SUSPEND_COUNT_EXCEEDED },
{ "TIMEOUT", STATUS_TIMEOUT },
{ "UNSUCCESSFUL", STATUS_UNSUCCESSFUL },
{ "VOLUME_DISMOUNTED", STATUS_VOLUME_DISMOUNTED },
{ "WAS_LOCKED", STATUS_WAS_LOCKED },
{ NULL, 0 }
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment