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 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 );
|
||||
|
|
75
server/fd.c
75
server/fd.c
|
@ -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 }
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue