Added an unmount_device request that invalidates all file descriptors
open on a given Unix device.
This commit is contained in:
parent
66868e532b
commit
964815bc42
|
@ -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 */
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
75
server/fd.c
75
server/fd.c
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue