2004-10-18 11:40:17 +04:00
/*
Unix SMB / CIFS implementation .
POSIX NTVFS backend - async request wait routines
Copyright ( C ) Andrew Tridgell 2004
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2004-11-05 10:24:25 +03:00
# include "includes.h"
2005-02-03 14:56:03 +03:00
# include "lib/events/events.h"
2004-11-04 14:28:38 +03:00
# include "dlinklist.h"
2004-10-18 11:40:17 +04:00
# include "vfs_posix.h"
2005-01-30 03:54:57 +03:00
# include "smbd/service_stream.h"
2005-06-05 10:53:07 +04:00
# include "lib/messaging/irpc.h"
2004-10-18 11:40:17 +04:00
/* the context for a single wait instance */
struct pvfs_wait {
2004-11-04 14:28:38 +03:00
struct pvfs_wait * next , * prev ;
struct pvfs_state * pvfs ;
2004-11-05 05:22:07 +03:00
void ( * handler ) ( void * , enum pvfs_wait_notice ) ;
2004-10-18 11:40:17 +04:00
void * private ;
int msg_type ;
2004-10-27 07:15:42 +04:00
struct messaging_context * msg_ctx ;
2004-10-18 11:40:17 +04:00
struct event_context * ev ;
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req ;
2004-11-05 05:22:07 +03:00
enum pvfs_wait_notice reason ;
2004-10-18 11:40:17 +04:00
} ;
2004-10-18 17:27:22 +04:00
/*
called from the ntvfs layer when we have requested setup of an async
call . this ensures that async calls runs with the right state of
previous ntvfs handlers in the chain ( such as security context )
*/
NTSTATUS pvfs_async_setup ( struct ntvfs_module_context * ntvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req , void * private )
2004-10-18 17:27:22 +04:00
{
struct pvfs_wait * pwait = private ;
2004-11-05 05:22:07 +03:00
pwait - > handler ( pwait - > private , pwait - > reason ) ;
2004-10-18 17:27:22 +04:00
return NT_STATUS_OK ;
}
2004-10-18 11:40:17 +04:00
/*
receive a completion message for a wait
*/
2004-10-27 07:15:42 +04:00
static void pvfs_wait_dispatch ( struct messaging_context * msg , void * private , uint32_t msg_type ,
2005-01-30 03:54:57 +03:00
uint32_t src , DATA_BLOB * data )
2004-10-18 11:40:17 +04:00
{
struct pvfs_wait * pwait = private ;
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req ;
2004-10-18 11:40:17 +04:00
2004-11-03 13:09:48 +03:00
/* we need to check that this one is for us. See
messaging_send_ptr ( ) for the other side of this .
*/
2004-10-18 11:40:17 +04:00
if ( data - > length ! = sizeof ( void * ) | |
* ( void * * ) data - > data ! = pwait - > private ) {
return ;
}
2004-11-05 05:22:07 +03:00
pwait - > reason = PVFS_WAIT_EVENT ;
2004-10-18 17:27:22 +04:00
req = pwait - > req ;
/* the extra reference here is to ensure that the req
structure is not destroyed when the async request reply is
sent , which would cause problems with the other ntvfs
modules above us */
talloc_increase_ref_count ( req ) ;
ntvfs_async_setup ( pwait - > req , pwait ) ;
talloc_free ( req ) ;
2004-10-18 11:40:17 +04:00
}
/*
receive a timeout on a message wait
*/
2004-11-03 13:09:48 +03:00
static void pvfs_wait_timeout ( struct event_context * ev ,
2005-02-03 05:35:52 +03:00
struct timed_event * te , struct timeval t , void * private )
2004-10-18 11:40:17 +04:00
{
2005-02-03 05:35:52 +03:00
struct pvfs_wait * pwait = talloc_get_type ( private , struct pvfs_wait ) ;
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req = pwait - > req ;
2004-10-18 17:27:22 +04:00
2004-11-05 05:22:07 +03:00
pwait - > reason = PVFS_WAIT_TIMEOUT ;
2004-10-18 17:27:22 +04:00
talloc_increase_ref_count ( req ) ;
ntvfs_async_setup ( pwait - > req , pwait ) ;
talloc_free ( req ) ;
2004-10-18 11:40:17 +04:00
}
/*
destroy a pending wait
*/
2006-05-24 11:35:06 +04:00
static int pvfs_wait_destructor ( struct pvfs_wait * pwait )
2004-10-18 11:40:17 +04:00
{
2006-03-29 17:31:30 +04:00
if ( pwait - > msg_type ! = - 1 ) {
messaging_deregister ( pwait - > msg_ctx , pwait - > msg_type , pwait ) ;
}
2004-11-04 14:28:38 +03:00
DLIST_REMOVE ( pwait - > pvfs - > wait_list , pwait ) ;
2004-10-18 11:40:17 +04:00
return 0 ;
}
/*
setup a request to wait on a message of type msg_type , with a
timeout ( given as an expiry time )
the return value is a handle . To stop waiting talloc_free this
handle .
2006-03-29 17:31:30 +04:00
if msg_type = = - 1 then no message is registered , and it is assumed
that the caller handles any messaging setup needed
2004-10-18 11:40:17 +04:00
*/
2006-03-10 17:31:17 +03:00
void * pvfs_wait_message ( struct pvfs_state * pvfs ,
struct ntvfs_request * req ,
2004-10-18 11:40:17 +04:00
int msg_type ,
2004-11-03 13:09:48 +03:00
struct timeval end_time ,
2004-11-05 05:22:07 +03:00
void ( * fn ) ( void * , enum pvfs_wait_notice ) ,
2004-10-18 11:40:17 +04:00
void * private )
{
struct pvfs_wait * pwait ;
2005-01-27 10:08:20 +03:00
pwait = talloc ( pvfs , struct pvfs_wait ) ;
2004-10-18 11:40:17 +04:00
if ( pwait = = NULL ) {
return NULL ;
}
pwait - > private = private ;
pwait - > handler = fn ;
2006-03-15 20:28:46 +03:00
pwait - > msg_ctx = pvfs - > ntvfs - > ctx - > msg_ctx ;
pwait - > ev = pvfs - > ntvfs - > ctx - > event_ctx ;
2004-10-18 11:40:17 +04:00
pwait - > msg_type = msg_type ;
2004-11-07 13:05:35 +03:00
pwait - > req = talloc_reference ( pwait , req ) ;
2004-11-04 14:28:38 +03:00
pwait - > pvfs = pvfs ;
2004-10-18 11:40:17 +04:00
2006-03-21 14:39:48 +03:00
if ( ! timeval_is_zero ( & end_time ) ) {
/* setup a timer */
event_add_timed ( pwait - > ev , pwait , end_time , pvfs_wait_timeout , pwait ) ;
}
2004-10-18 11:40:17 +04:00
/* register with the messaging subsystem for this message
type */
2006-03-29 17:31:30 +04:00
if ( msg_type ! = - 1 ) {
messaging_register ( pwait - > msg_ctx ,
pwait ,
msg_type ,
pvfs_wait_dispatch ) ;
}
2004-10-18 11:40:17 +04:00
/* tell the main smb server layer that we will be replying
asynchronously */
2004-10-29 01:48:53 +04:00
req - > async_states - > state | = NTVFS_ASYNC_STATE_ASYNC ;
2004-10-18 11:40:17 +04:00
2004-11-04 14:28:38 +03:00
DLIST_ADD ( pvfs - > wait_list , pwait ) ;
2004-10-18 11:40:17 +04:00
/* make sure we cleanup the timer and message handler */
talloc_set_destructor ( pwait , pvfs_wait_destructor ) ;
return pwait ;
}
2004-11-04 14:28:38 +03:00
/*
cancel an outstanding async request
*/
2006-03-10 17:31:17 +03:00
NTSTATUS pvfs_cancel ( struct ntvfs_module_context * ntvfs , struct ntvfs_request * req )
2004-11-04 14:28:38 +03:00
{
struct pvfs_state * pvfs = ntvfs - > private_data ;
struct pvfs_wait * pwait ;
2006-03-16 21:54:19 +03:00
2004-11-04 14:28:38 +03:00
for ( pwait = pvfs - > wait_list ; pwait ; pwait = pwait - > next ) {
2006-07-11 22:15:42 +04:00
if ( pwait - > req = = req ) {
2004-11-05 05:22:07 +03:00
/* trigger a cancel on the request */
pwait - > reason = PVFS_WAIT_CANCEL ;
ntvfs_async_setup ( pwait - > req , pwait ) ;
2004-11-04 14:28:38 +03:00
return NT_STATUS_OK ;
}
}
2005-07-04 09:08:27 +04:00
return NT_STATUS_DOS ( ERRDOS , ERRcancelviolation ) ;
2004-11-04 14:28:38 +03:00
}