Added an unmount_device request that invalidates all file descriptors

open on a given Unix device.
This commit is contained in:
Alexandre Julliard 2005-08-08 15:11:03 +00:00
parent 66868e532b
commit 964815bc42
8 changed files with 115 additions and 13 deletions

View File

@ -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 create_socket_request
{ {
struct request_header __header; struct request_header __header;
@ -3592,6 +3604,7 @@ enum request
REQ_flush_file, REQ_flush_file,
REQ_lock_file, REQ_lock_file,
REQ_unlock_file, REQ_unlock_file,
REQ_unmount_device,
REQ_create_socket, REQ_create_socket,
REQ_accept_socket, REQ_accept_socket,
REQ_set_socket_event, REQ_set_socket_event,
@ -3802,6 +3815,7 @@ union generic_request
struct flush_file_request flush_file_request; struct flush_file_request flush_file_request;
struct lock_file_request lock_file_request; struct lock_file_request lock_file_request;
struct unlock_file_request unlock_file_request; struct unlock_file_request unlock_file_request;
struct unmount_device_request unmount_device_request;
struct create_socket_request create_socket_request; struct create_socket_request create_socket_request;
struct accept_socket_request accept_socket_request; struct accept_socket_request accept_socket_request;
struct set_socket_event_request set_socket_event_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 flush_file_reply flush_file_reply;
struct lock_file_reply lock_file_reply; struct lock_file_reply lock_file_reply;
struct unlock_file_reply unlock_file_reply; struct unlock_file_reply unlock_file_reply;
struct unmount_device_reply unmount_device_reply;
struct create_socket_reply create_socket_reply; struct create_socket_reply create_socket_reply;
struct accept_socket_reply accept_socket_reply; struct accept_socket_reply accept_socket_reply;
struct set_socket_event_reply set_socket_event_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; 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 */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -137,6 +137,8 @@ static struct change *create_change_notification( struct fd *fd, int subtree, un
struct stat st; struct stat st;
int unix_fd = get_unix_fd( fd ); int unix_fd = get_unix_fd( fd );
if (unix_fd == -1) return NULL;
if (fstat( unix_fd, &st ) == -1 || !S_ISDIR(st.st_mode)) if (fstat( unix_fd, &st ) == -1 || !S_ISDIR(st.st_mode))
{ {
set_error( STATUS_NOT_A_DIRECTORY ); set_error( STATUS_NOT_A_DIRECTORY );

View File

@ -625,7 +625,7 @@ static void device_destroy( struct object *obj )
/* inode functions */ /* inode functions */
/* close all pending file descriptors in the closed list */ /* 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 ); struct list *ptr = list_head( &inode->closed );
@ -639,7 +639,7 @@ static void inode_close_pending( struct inode *inode )
close( fd->unix_fd ); close( fd->unix_fd );
fd->unix_fd = -1; 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 ); list_remove( ptr );
free( fd ); 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->inode_entry );
list_remove( &lock->proc_entry ); list_remove( &lock->proc_entry );
if (remove_unix) remove_unix_locks( lock->fd, lock->start, lock->end ); 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; lock->process = NULL;
wake_up( &lock->obj, 0 ); wake_up( &lock->obj, 0 );
release_object( lock ); 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 */ /* allocate an fd object, without setting the unix fd yet */
struct fd *alloc_fd( const struct fd_ops *fd_user_ops, struct object *user ) 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 */ /* retrieve the unix fd for an object */
int get_unix_fd( struct fd *fd ) int get_unix_fd( struct fd *fd )
{ {
if (fd->unix_fd == -1) set_error( STATUS_VOLUME_DISMOUNTED );
return fd->unix_fd; return fd->unix_fd;
} }
@ -1399,6 +1420,8 @@ int check_fd_events( struct fd *fd, int events )
{ {
struct pollfd pfd; struct pollfd pfd;
if (fd->unix_fd == -1) return POLLERR;
pfd.fd = fd->unix_fd; pfd.fd = fd->unix_fd;
pfd.events = events; pfd.events = events;
if (poll( &pfd, 1, 0 ) <= 0) return 0; 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 ); 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 */ /* 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, static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handle,
unsigned int access ) unsigned int access )
@ -1595,18 +1641,31 @@ DECL_HANDLER(get_handle_fd)
if ((fd = get_handle_fd_obj( current->process, req->handle, req->access ))) 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 ); int unix_fd = get_unix_fd( fd );
if (unix_fd != -1) reply->fd = unix_fd; if (unix_fd != -1)
else if (!get_error())
{ {
assert( fd->unix_fd != -1 ); int cached_fd = get_handle_unix_fd( current->process, req->handle, req->access );
send_client_fd( current->process, fd->unix_fd, req->handle ); 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 ); reply->flags = fd->fd_ops->get_file_info( fd );
release_object( 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 */ /* create / reschedule an async I/O */
DECL_HANDLER(register_async) DECL_HANDLER(register_async)
{ {

View File

@ -226,8 +226,13 @@ static int file_get_poll_events( struct fd *fd )
static int file_flush( struct fd *fd, struct event **event ) static int file_flush( struct fd *fd, struct event **event )
{ {
int ret = (fsync( get_unix_fd(fd) ) != -1); int ret = 0, unix_fd = get_unix_fd( fd );
if (!ret) file_set_error();
if (unix_fd != -1)
{
ret = (fsync( unix_fd ) != -1);
if (!ret) file_set_error();
}
return ret; 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 ); int unix_fd = get_file_unix_fd( file );
off_t size = new_size; off_t size = new_size;
if (unix_fd == -1) return 0;
if (sizeof(new_size) > sizeof(size) && size != new_size) if (sizeof(new_size) > sizeof(size) && size != new_size)
{ {
set_error( STATUS_INVALID_PARAMETER ); set_error( STATUS_INVALID_PARAMETER );
@ -326,6 +333,8 @@ int grow_file( struct file *file, file_pos_t size )
struct stat st; struct stat st;
int unix_fd = get_file_unix_fd( file ); int unix_fd = get_file_unix_fd( file );
if (unix_fd == -1) return 0;
if (fstat( unix_fd, &st ) == -1) if (fstat( unix_fd, &st ) == -1)
{ {
file_set_error(); file_set_error();

View File

@ -196,7 +196,7 @@ static int get_image_params( struct mapping *mapping )
/* load the headers */ /* load the headers */
if (!(fd = mapping_get_fd( &mapping->obj ))) return 0; 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 (pread( unix_fd, &dos, sizeof(dos), 0 ) != sizeof(dos)) goto error;
if (dos.e_magic != IMAGE_DOS_SIGNATURE) goto error; if (dos.e_magic != IMAGE_DOS_SIGNATURE) goto error;
pos = dos.e_lfanew; pos = dos.e_lfanew;
@ -250,7 +250,7 @@ inline static int get_file_size( struct file *file, file_pos_t *size )
struct stat st; struct stat st;
int unix_fd = get_file_unix_fd( file ); 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; *size = st.st_size;
return 1; return 1;
} }

View File

@ -657,6 +657,12 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
@END @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 */ /* Create a socket */
@REQ(create_socket) @REQ(create_socket)
unsigned int access; /* wanted access rights */ unsigned int access; /* wanted access rights */

View File

@ -143,6 +143,7 @@ DECL_HANDLER(get_handle_fd);
DECL_HANDLER(flush_file); DECL_HANDLER(flush_file);
DECL_HANDLER(lock_file); DECL_HANDLER(lock_file);
DECL_HANDLER(unlock_file); DECL_HANDLER(unlock_file);
DECL_HANDLER(unmount_device);
DECL_HANDLER(create_socket); DECL_HANDLER(create_socket);
DECL_HANDLER(accept_socket); DECL_HANDLER(accept_socket);
DECL_HANDLER(set_socket_event); 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_flush_file,
(req_handler)req_lock_file, (req_handler)req_lock_file,
(req_handler)req_unlock_file, (req_handler)req_unlock_file,
(req_handler)req_unmount_device,
(req_handler)req_create_socket, (req_handler)req_create_socket,
(req_handler)req_accept_socket, (req_handler)req_accept_socket,
(req_handler)req_set_socket_event, (req_handler)req_set_socket_event,

View File

@ -1077,6 +1077,11 @@ static void dump_unlock_file_request( const struct unlock_file_request *req )
fprintf( stderr, " count_high=%08x", req->count_high ); 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 ) static void dump_create_socket_request( const struct create_socket_request *req )
{ {
fprintf( stderr, " access=%08x,", req->access ); 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_flush_file_request,
(dump_func)dump_lock_file_request, (dump_func)dump_lock_file_request,
(dump_func)dump_unlock_file_request, (dump_func)dump_unlock_file_request,
(dump_func)dump_unmount_device_request,
(dump_func)dump_create_socket_request, (dump_func)dump_create_socket_request,
(dump_func)dump_accept_socket_request, (dump_func)dump_accept_socket_request,
(dump_func)dump_set_socket_event_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_flush_file_reply,
(dump_func)dump_lock_file_reply, (dump_func)dump_lock_file_reply,
(dump_func)0, (dump_func)0,
(dump_func)0,
(dump_func)dump_create_socket_reply, (dump_func)dump_create_socket_reply,
(dump_func)dump_accept_socket_reply, (dump_func)dump_accept_socket_reply,
(dump_func)0, (dump_func)0,
@ -3526,6 +3533,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"flush_file", "flush_file",
"lock_file", "lock_file",
"unlock_file", "unlock_file",
"unmount_device",
"create_socket", "create_socket",
"accept_socket", "accept_socket",
"set_socket_event", "set_socket_event",
@ -3755,6 +3763,7 @@ static const struct
{ "SUSPEND_COUNT_EXCEEDED", STATUS_SUSPEND_COUNT_EXCEEDED }, { "SUSPEND_COUNT_EXCEEDED", STATUS_SUSPEND_COUNT_EXCEEDED },
{ "TIMEOUT", STATUS_TIMEOUT }, { "TIMEOUT", STATUS_TIMEOUT },
{ "UNSUCCESSFUL", STATUS_UNSUCCESSFUL }, { "UNSUCCESSFUL", STATUS_UNSUCCESSFUL },
{ "VOLUME_DISMOUNTED", STATUS_VOLUME_DISMOUNTED },
{ "WAS_LOCKED", STATUS_WAS_LOCKED }, { "WAS_LOCKED", STATUS_WAS_LOCKED },
{ NULL, 0 } { NULL, 0 }
}; };