2005-06-28 02:53:56 +04:00
/*
Unix SMB / Netbios implementation .
Version 3.0
async_io read handling using POSIX async io .
Copyright ( C ) Jeremy Allison 2005.
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2005-06-28 02:53:56 +04:00
( 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
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-06-28 02:53:56 +04:00
*/
# include "includes.h"
2009-01-08 14:03:45 +03:00
# include "smbd/globals.h"
2005-06-28 02:53:56 +04:00
# if defined(WITH_AIO)
/* The signal we'll use to signify aio done. */
# ifndef RT_SIGNAL_AIO
2008-09-16 05:45:10 +04:00
# define RT_SIGNAL_AIO (SIGRTMIN+3)
# endif
# ifndef HAVE_STRUCT_SIGEVENT_SIGEV_VALUE_SIVAL_PTR
# ifdef HAVE_STRUCT_SIGEVENT_SIGEV_VALUE_SIGVAL_PTR
# define sival_int sigval_int
# define sival_ptr sigval_ptr
# endif
2005-06-28 02:53:56 +04:00
# endif
2010-04-02 03:47:59 +04:00
/****************************************************************************
Initialize the signal handler for aio read / write .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void smbd_aio_signal_handler ( struct tevent_context * ev_ctx ,
struct tevent_signal * se ,
int signum , int count ,
void * _info , void * private_data )
{
siginfo_t * info = ( siginfo_t * ) _info ;
unsigned int mid = ( unsigned int ) info - > si_value . sival_int ;
smbd_aio_complete_mid ( mid ) ;
}
static void initialize_async_io_handler ( void )
{
if ( aio_signal_event ) {
return ;
}
aio_signal_event = tevent_add_signal ( smbd_event_context ( ) ,
smbd_event_context ( ) ,
RT_SIGNAL_AIO , SA_SIGINFO ,
smbd_aio_signal_handler ,
NULL ) ;
if ( ! aio_signal_event ) {
exit_server ( " Failed to setup RT_SIGNAL_AIO handler " ) ;
}
/* tevent supports 100 signal with SA_SIGINFO */
aio_pending_size = 100 ;
}
2005-06-28 02:53:56 +04:00
/****************************************************************************
The buffer we keep around whilst an aio request is in process .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct aio_extra {
struct aio_extra * next , * prev ;
SMB_STRUCT_AIOCB acb ;
files_struct * fsp ;
2008-11-03 23:56:02 +03:00
struct smb_request * req ;
2005-06-28 02:53:56 +04:00
char * outbuf ;
2010-04-06 01:16:21 +04:00
struct lock_struct lock ;
2009-10-13 17:48:19 +04:00
int ( * handle_completion ) ( struct aio_extra * ex , int errcode ) ;
2005-06-28 02:53:56 +04:00
} ;
2009-10-13 17:48:19 +04:00
static int handle_aio_read_complete ( struct aio_extra * aio_ex , int errcode ) ;
static int handle_aio_write_complete ( struct aio_extra * aio_ex , int errcode ) ;
2008-11-03 23:56:02 +03:00
static int aio_extra_destructor ( struct aio_extra * aio_ex )
{
DLIST_REMOVE ( aio_list_head , aio_ex ) ;
return 0 ;
}
2005-06-28 02:53:56 +04:00
/****************************************************************************
Create the extended aio struct we must keep around for the lifetime
2008-11-03 23:56:02 +03:00
of the aio call .
2005-06-28 02:53:56 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-11-03 23:56:02 +03:00
static struct aio_extra * create_aio_extra ( files_struct * fsp , size_t buflen )
2005-06-28 02:53:56 +04:00
{
2008-11-03 21:59:11 +03:00
struct aio_extra * aio_ex = TALLOC_ZERO_P ( NULL , struct aio_extra ) ;
2005-06-28 02:53:56 +04:00
if ( ! aio_ex ) {
return NULL ;
}
2008-11-03 21:59:11 +03:00
2005-06-28 02:53:56 +04:00
/* The output buffer stored in the aio_ex is the start of
the smb return buffer . The buffer used in the acb
is the start of the reply data portion of that buffer . */
2008-11-03 23:56:02 +03:00
aio_ex - > outbuf = TALLOC_ARRAY ( aio_ex , char , buflen ) ;
2005-06-28 02:53:56 +04:00
if ( ! aio_ex - > outbuf ) {
2008-11-03 21:59:11 +03:00
TALLOC_FREE ( aio_ex ) ;
2005-06-28 02:53:56 +04:00
return NULL ;
}
DLIST_ADD ( aio_list_head , aio_ex ) ;
2008-11-03 23:56:02 +03:00
talloc_set_destructor ( aio_ex , aio_extra_destructor ) ;
2005-06-28 02:53:56 +04:00
aio_ex - > fsp = fsp ;
return aio_ex ;
}
/****************************************************************************
2008-11-03 19:49:38 +03:00
Given the mid find the extended aio struct containing it .
2005-06-28 02:53:56 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct aio_extra * find_aio_ex ( uint16 mid )
{
struct aio_extra * p ;
for ( p = aio_list_head ; p ; p = p - > next ) {
2008-11-03 23:56:02 +03:00
if ( mid = = p - > req - > mid ) {
2005-06-28 02:53:56 +04:00
return p ;
}
}
return NULL ;
}
/****************************************************************************
We can have these many aio buffers in flight .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/****************************************************************************
Set up an aio request from a SMBreadX call .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-04-06 01:16:21 +04:00
NTSTATUS schedule_aio_read_and_X ( connection_struct * conn ,
2007-08-11 20:28:10 +04:00
struct smb_request * req ,
2005-06-28 02:53:56 +04:00
files_struct * fsp , SMB_OFF_T startpos ,
size_t smb_maxcnt )
{
struct aio_extra * aio_ex ;
SMB_STRUCT_AIOCB * a ;
size_t bufsize ;
size_t min_aio_read_size = lp_aio_read_size ( SNUM ( conn ) ) ;
2008-11-02 23:52:16 +03:00
int ret ;
2005-06-28 02:53:56 +04:00
2008-02-24 02:01:07 +03:00
if ( fsp - > base_fsp ! = NULL ) {
/* No AIO on streams yet */
DEBUG ( 10 , ( " AIO on streams not yet supported \n " ) ) ;
2010-04-06 01:16:21 +04:00
return NT_STATUS_RETRY ;
2008-02-24 02:01:07 +03:00
}
2008-01-30 13:11:27 +03:00
if ( ( ! min_aio_read_size | | ( smb_maxcnt < min_aio_read_size ) )
& & ! SMB_VFS_AIO_FORCE ( fsp ) ) {
2005-06-28 02:53:56 +04:00
/* Too small a read for aio request. */
DEBUG ( 10 , ( " schedule_aio_read_and_X: read size (%u) too small "
" for minimum aio_read of %u \n " ,
( unsigned int ) smb_maxcnt ,
( unsigned int ) min_aio_read_size ) ) ;
2010-04-06 01:16:21 +04:00
return NT_STATUS_RETRY ;
2005-06-28 02:53:56 +04:00
}
2007-02-10 16:15:58 +03:00
/* Only do this on non-chained and non-chaining reads not using the
* write cache . */
2009-01-31 01:44:21 +03:00
if ( req_is_in_chain ( req ) | | ( lp_write_cache_size ( SNUM ( conn ) ) ! = 0 ) ) {
2010-04-06 01:16:21 +04:00
return NT_STATUS_RETRY ;
2005-06-28 02:53:56 +04:00
}
2008-02-24 13:32:22 +03:00
if ( outstanding_aio_calls > = aio_pending_size ) {
2007-02-10 16:15:58 +03:00
DEBUG ( 10 , ( " schedule_aio_read_and_X: Already have %d aio "
" activities outstanding. \n " ,
2005-06-28 02:53:56 +04:00
outstanding_aio_calls ) ) ;
2010-04-06 01:16:21 +04:00
return NT_STATUS_RETRY ;
2005-06-28 02:53:56 +04:00
}
2007-08-11 20:28:10 +04:00
/* The following is safe from integer wrap as we've already checked
smb_maxcnt is 128 k or less . Wct is 12 for read replies */
bufsize = smb_size + 12 * 2 + smb_maxcnt ;
2005-06-28 02:53:56 +04:00
2010-04-02 03:47:59 +04:00
/* Ensure aio is initialized. */
initialize_async_io_handler ( ) ;
2008-11-03 23:56:02 +03:00
if ( ( aio_ex = create_aio_extra ( fsp , bufsize ) ) = = NULL ) {
2005-06-28 02:53:56 +04:00
DEBUG ( 10 , ( " schedule_aio_read_and_X: malloc fail. \n " ) ) ;
2010-04-06 01:16:21 +04:00
return NT_STATUS_NO_MEMORY ;
2005-06-28 02:53:56 +04:00
}
2008-11-03 23:56:02 +03:00
aio_ex - > handle_completion = handle_aio_read_complete ;
2005-06-28 02:53:56 +04:00
2008-11-03 22:16:09 +03:00
construct_reply_common_req ( req , aio_ex - > outbuf ) ;
2008-01-04 23:56:23 +03:00
srv_set_message ( aio_ex - > outbuf , 12 , 0 , True ) ;
2005-06-28 02:53:56 +04:00
SCVAL ( aio_ex - > outbuf , smb_vwv0 , 0xFF ) ; /* Never a chained reply. */
2010-04-06 01:16:21 +04:00
init_strict_lock_struct ( fsp , ( uint32 ) req - > smbpid ,
( uint64_t ) startpos , ( uint64_t ) smb_maxcnt , READ_LOCK ,
& aio_ex - > lock ) ;
/* Take the lock until the AIO completes. */
if ( ! SMB_VFS_STRICT_LOCK ( conn , fsp , & aio_ex - > lock ) ) {
TALLOC_FREE ( aio_ex ) ;
return NT_STATUS_FILE_LOCK_CONFLICT ;
}
2005-06-28 02:53:56 +04:00
a = & aio_ex - > acb ;
/* Now set up the aio record for the read call. */
2008-11-03 22:07:11 +03:00
2005-07-13 04:26:52 +04:00
a - > aio_fildes = fsp - > fh - > fd ;
2005-06-28 02:53:56 +04:00
a - > aio_buf = smb_buf ( aio_ex - > outbuf ) ;
a - > aio_nbytes = smb_maxcnt ;
a - > aio_offset = startpos ;
a - > aio_sigevent . sigev_notify = SIGEV_SIGNAL ;
a - > aio_sigevent . sigev_signo = RT_SIGNAL_AIO ;
2008-11-03 23:56:02 +03:00
a - > aio_sigevent . sigev_value . sival_int = req - > mid ;
2005-06-28 02:53:56 +04:00
2008-11-02 23:52:16 +03:00
ret = SMB_VFS_AIO_READ ( fsp , a ) ;
if ( ret = = - 1 ) {
2007-02-10 16:15:58 +03:00
DEBUG ( 0 , ( " schedule_aio_read_and_X: aio_read failed. "
" Error %s \n " , strerror ( errno ) ) ) ;
2010-04-06 01:16:21 +04:00
SMB_VFS_STRICT_UNLOCK ( conn , fsp , & aio_ex - > lock ) ;
2008-11-03 21:59:11 +03:00
TALLOC_FREE ( aio_ex ) ;
2010-04-06 01:16:21 +04:00
return NT_STATUS_RETRY ;
2005-06-28 02:53:56 +04:00
}
2009-10-01 02:20:09 +04:00
outstanding_aio_calls + + ;
2008-11-03 23:56:02 +03:00
aio_ex - > req = talloc_move ( aio_ex , & req ) ;
2007-02-10 16:15:58 +03:00
DEBUG ( 10 , ( " schedule_aio_read_and_X: scheduled aio_read for file %s, "
" offset %.0f, len = %u (mid = %u) \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) , ( double ) startpos , ( unsigned int ) smb_maxcnt ,
2008-11-03 23:56:02 +03:00
( unsigned int ) aio_ex - > req - > mid ) ) ;
2005-06-28 02:53:56 +04:00
2010-04-06 01:16:21 +04:00
return NT_STATUS_OK ;
2005-06-28 02:53:56 +04:00
}
/****************************************************************************
Set up an aio request from a SMBwriteX call .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-04-06 01:16:21 +04:00
NTSTATUS schedule_aio_write_and_X ( connection_struct * conn ,
2007-08-08 23:05:30 +04:00
struct smb_request * req ,
files_struct * fsp , char * data ,
SMB_OFF_T startpos ,
size_t numtowrite )
2005-06-28 02:53:56 +04:00
{
struct aio_extra * aio_ex ;
SMB_STRUCT_AIOCB * a ;
2008-11-03 23:56:02 +03:00
size_t bufsize ;
2008-11-02 14:20:47 +03:00
bool write_through = BITSETW ( req - > vwv + 7 , 0 ) ;
2005-06-28 02:53:56 +04:00
size_t min_aio_write_size = lp_aio_write_size ( SNUM ( conn ) ) ;
2008-11-02 23:52:16 +03:00
int ret ;
2005-06-28 02:53:56 +04:00
2008-02-24 02:01:07 +03:00
if ( fsp - > base_fsp ! = NULL ) {
/* No AIO on streams yet */
DEBUG ( 10 , ( " AIO on streams not yet supported \n " ) ) ;
2010-04-06 01:16:21 +04:00
return NT_STATUS_RETRY ;
2008-02-24 02:01:07 +03:00
}
2008-01-30 13:11:27 +03:00
if ( ( ! min_aio_write_size | | ( numtowrite < min_aio_write_size ) )
& & ! SMB_VFS_AIO_FORCE ( fsp ) ) {
2005-06-28 02:53:56 +04:00
/* Too small a write for aio request. */
2007-02-10 16:15:58 +03:00
DEBUG ( 10 , ( " schedule_aio_write_and_X: write size (%u) too "
" small for minimum aio_write of %u \n " ,
2005-06-28 02:53:56 +04:00
( unsigned int ) numtowrite ,
( unsigned int ) min_aio_write_size ) ) ;
2010-04-06 01:16:21 +04:00
return NT_STATUS_RETRY ;
2005-06-28 02:53:56 +04:00
}
2007-02-10 16:15:58 +03:00
/* Only do this on non-chained and non-chaining reads not using the
* write cache . */
2009-01-31 01:44:21 +03:00
if ( req_is_in_chain ( req ) | | ( lp_write_cache_size ( SNUM ( conn ) ) ! = 0 ) ) {
2010-04-06 01:16:21 +04:00
return NT_STATUS_RETRY ;
2005-06-28 02:53:56 +04:00
}
2008-02-24 13:32:22 +03:00
if ( outstanding_aio_calls > = aio_pending_size ) {
2007-02-10 16:15:58 +03:00
DEBUG ( 3 , ( " schedule_aio_write_and_X: Already have %d aio "
" activities outstanding. \n " ,
2005-06-28 02:53:56 +04:00
outstanding_aio_calls ) ) ;
2007-02-10 16:15:58 +03:00
DEBUG ( 10 , ( " schedule_aio_write_and_X: failed to schedule "
" aio_write for file %s, offset %.0f, len = %u "
" (mid = %u) \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) , ( double ) startpos ,
2007-02-10 16:15:58 +03:00
( unsigned int ) numtowrite ,
2007-08-08 23:05:30 +04:00
( unsigned int ) req - > mid ) ) ;
2010-04-06 01:16:21 +04:00
return NT_STATUS_RETRY ;
2005-06-28 02:53:56 +04:00
}
2010-04-02 03:47:59 +04:00
/* Ensure aio is initialized. */
initialize_async_io_handler ( ) ;
2008-11-03 23:56:02 +03:00
bufsize = smb_size + 6 * 2 ;
if ( ! ( aio_ex = create_aio_extra ( fsp , bufsize ) ) ) {
2005-06-28 02:53:56 +04:00
DEBUG ( 0 , ( " schedule_aio_write_and_X: malloc fail. \n " ) ) ;
2010-04-06 01:16:21 +04:00
return NT_STATUS_NO_MEMORY ;
2005-06-28 02:53:56 +04:00
}
2008-11-03 23:56:02 +03:00
aio_ex - > handle_completion = handle_aio_write_complete ;
2005-06-28 02:53:56 +04:00
2008-11-03 23:56:02 +03:00
construct_reply_common_req ( req , aio_ex - > outbuf ) ;
srv_set_message ( aio_ex - > outbuf , 6 , 0 , True ) ;
2005-06-28 02:53:56 +04:00
SCVAL ( aio_ex - > outbuf , smb_vwv0 , 0xFF ) ; /* Never a chained reply. */
2010-04-06 01:16:21 +04:00
init_strict_lock_struct ( fsp , ( uint32 ) req - > smbpid ,
( uint64_t ) startpos , ( uint64_t ) numtowrite , WRITE_LOCK ,
& aio_ex - > lock ) ;
/* Take the lock until the AIO completes. */
if ( ! SMB_VFS_STRICT_LOCK ( conn , fsp , & aio_ex - > lock ) ) {
TALLOC_FREE ( aio_ex ) ;
return NT_STATUS_FILE_LOCK_CONFLICT ;
}
2005-06-28 02:53:56 +04:00
a = & aio_ex - > acb ;
/* Now set up the aio record for the write call. */
2008-11-03 22:07:11 +03:00
2005-07-13 04:26:52 +04:00
a - > aio_fildes = fsp - > fh - > fd ;
2008-11-03 23:56:02 +03:00
a - > aio_buf = data ;
2005-06-28 02:53:56 +04:00
a - > aio_nbytes = numtowrite ;
a - > aio_offset = startpos ;
a - > aio_sigevent . sigev_notify = SIGEV_SIGNAL ;
a - > aio_sigevent . sigev_signo = RT_SIGNAL_AIO ;
2008-11-03 23:56:02 +03:00
a - > aio_sigevent . sigev_value . sival_int = req - > mid ;
2005-06-28 02:53:56 +04:00
2008-11-02 23:52:16 +03:00
ret = SMB_VFS_AIO_WRITE ( fsp , a ) ;
if ( ret = = - 1 ) {
2007-02-10 16:15:58 +03:00
DEBUG ( 3 , ( " schedule_aio_wrote_and_X: aio_write failed. "
" Error %s \n " , strerror ( errno ) ) ) ;
2010-04-06 01:16:21 +04:00
SMB_VFS_STRICT_UNLOCK ( conn , fsp , & aio_ex - > lock ) ;
2008-11-03 21:59:11 +03:00
TALLOC_FREE ( aio_ex ) ;
2010-04-06 01:16:21 +04:00
return NT_STATUS_RETRY ;
2005-06-28 02:53:56 +04:00
}
2008-11-02 23:52:16 +03:00
2009-10-01 02:20:09 +04:00
outstanding_aio_calls + + ;
2008-11-03 23:56:02 +03:00
aio_ex - > req = talloc_move ( aio_ex , & req ) ;
2009-02-03 22:56:35 +03:00
/* This should actually be improved to span the write. */
contend_level2_oplocks_begin ( fsp , LEVEL2_CONTEND_WRITE ) ;
contend_level2_oplocks_end ( fsp , LEVEL2_CONTEND_WRITE ) ;
2008-02-19 17:53:57 +03:00
2007-10-11 00:34:30 +04:00
if ( ! write_through & & ! lp_syncalways ( SNUM ( fsp - > conn ) )
& & fsp - > aio_write_behind ) {
/* Lie to the client and immediately claim we finished the
* write . */
SSVAL ( aio_ex - > outbuf , smb_vwv2 , numtowrite ) ;
SSVAL ( aio_ex - > outbuf , smb_vwv4 , ( numtowrite > > 16 ) & 1 ) ;
show_msg ( aio_ex - > outbuf ) ;
2008-01-04 23:56:23 +03:00
if ( ! srv_send_smb ( smbd_server_fd ( ) , aio_ex - > outbuf ,
2009-03-09 11:47:59 +03:00
true , aio_ex - > req - > seqnum + 1 ,
2009-02-09 10:10:34 +03:00
IS_CONN_ENCRYPTED ( fsp - > conn ) ,
2009-09-29 08:36:15 +04:00
& aio_ex - > req - > pcd ) ) {
2008-01-04 23:56:23 +03:00
exit_server_cleanly ( " handle_aio_write: srv_send_smb "
2007-10-11 00:34:30 +04:00
" failed. " ) ;
}
DEBUG ( 10 , ( " schedule_aio_write_and_X: scheduled aio_write "
2009-07-11 01:50:37 +04:00
" behind for file %s \n " , fsp_str_dbg ( fsp ) ) ) ;
2007-10-11 00:34:30 +04:00
}
2005-06-28 02:53:56 +04:00
2007-02-10 16:15:58 +03:00
DEBUG ( 10 , ( " schedule_aio_write_and_X: scheduled aio_write for file "
" %s, offset %.0f, len = %u (mid = %u) "
" outstanding_aio_calls = %d \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) , ( double ) startpos , ( unsigned int ) numtowrite ,
2008-11-03 23:56:02 +03:00
( unsigned int ) aio_ex - > req - > mid , outstanding_aio_calls ) ) ;
2005-06-28 02:53:56 +04:00
2010-04-06 01:16:21 +04:00
return NT_STATUS_OK ;
2005-06-28 02:53:56 +04:00
}
/****************************************************************************
Complete the read and return the data or error back to the client .
Returns errno or zero if all ok .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-10-13 17:48:19 +04:00
static int handle_aio_read_complete ( struct aio_extra * aio_ex , int errcode )
2005-06-28 02:53:56 +04:00
{
int outsize ;
char * outbuf = aio_ex - > outbuf ;
char * data = smb_buf ( outbuf ) ;
ssize_t nread = SMB_VFS_AIO_RETURN ( aio_ex - > fsp , & aio_ex - > acb ) ;
if ( nread < 0 ) {
/* We're relying here on the fact that if the fd is
closed then the aio will complete and aio_return
will return an error . Hopefully this is
true . . . . JRA . */
2009-10-13 17:48:19 +04:00
DEBUG ( 3 , ( " handle_aio_read_complete: file %s nread == %d. "
2007-02-10 16:15:58 +03:00
" Error = %s \n " ,
2009-10-14 00:28:57 +04:00
fsp_str_dbg ( aio_ex - > fsp ) , ( int ) nread , strerror ( errcode ) ) ) ;
2005-06-28 02:53:56 +04:00
2009-10-14 00:28:57 +04:00
ERROR_NT ( map_nt_error_from_unix ( errcode ) ) ;
2008-01-04 23:56:23 +03:00
outsize = srv_set_message ( outbuf , 0 , 0 , true ) ;
2005-06-28 02:53:56 +04:00
} else {
2008-01-04 23:56:23 +03:00
outsize = srv_set_message ( outbuf , 12 , nread , False ) ;
2005-06-28 02:53:56 +04:00
SSVAL ( outbuf , smb_vwv2 , 0xFFFF ) ; /* Remaining - must be * -1. */
SSVAL ( outbuf , smb_vwv5 , nread ) ;
SSVAL ( outbuf , smb_vwv6 , smb_offset ( data , outbuf ) ) ;
SSVAL ( outbuf , smb_vwv7 , ( ( nread > > 16 ) & 1 ) ) ;
SSVAL ( smb_buf ( outbuf ) , - 2 , nread ) ;
2008-02-19 15:27:08 +03:00
aio_ex - > fsp - > fh - > pos = aio_ex - > acb . aio_offset + nread ;
aio_ex - > fsp - > fh - > position_information = aio_ex - > fsp - > fh - > pos ;
2007-02-10 16:15:58 +03:00
DEBUG ( 3 , ( " handle_aio_read_complete file %s max=%d "
" nread=%d \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( aio_ex - > fsp ) ,
2007-07-25 22:53:16 +04:00
( int ) aio_ex - > acb . aio_nbytes , ( int ) nread ) ) ;
2005-06-28 02:53:56 +04:00
}
2008-01-04 23:56:23 +03:00
smb_setlen ( outbuf , outsize - 4 ) ;
2005-06-28 02:53:56 +04:00
show_msg ( outbuf ) ;
2008-01-04 23:56:23 +03:00
if ( ! srv_send_smb ( smbd_server_fd ( ) , outbuf ,
2009-03-09 11:47:59 +03:00
true , aio_ex - > req - > seqnum + 1 ,
2009-02-09 10:10:34 +03:00
IS_CONN_ENCRYPTED ( aio_ex - > fsp - > conn ) , NULL ) ) {
2008-01-04 23:56:23 +03:00
exit_server_cleanly ( " handle_aio_read_complete: srv_send_smb "
2007-02-10 16:15:58 +03:00
" failed. " ) ;
2005-06-28 02:53:56 +04:00
}
2007-02-10 16:15:58 +03:00
DEBUG ( 10 , ( " handle_aio_read_complete: scheduled aio_read completed "
" for file %s, offset %.0f, len = %u \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( aio_ex - > fsp ) , ( double ) aio_ex - > acb . aio_offset ,
2007-02-10 16:15:58 +03:00
( unsigned int ) nread ) ) ;
2005-06-28 02:53:56 +04:00
2009-10-14 00:28:57 +04:00
return errcode ;
2005-06-28 02:53:56 +04:00
}
/****************************************************************************
Complete the write and return the data or error back to the client .
2009-10-13 17:48:19 +04:00
Returns error code or zero if all ok .
2005-06-28 02:53:56 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-10-13 17:48:19 +04:00
static int handle_aio_write_complete ( struct aio_extra * aio_ex , int errcode )
2005-06-28 02:53:56 +04:00
{
files_struct * fsp = aio_ex - > fsp ;
char * outbuf = aio_ex - > outbuf ;
ssize_t numtowrite = aio_ex - > acb . aio_nbytes ;
ssize_t nwritten = SMB_VFS_AIO_RETURN ( fsp , & aio_ex - > acb ) ;
2007-10-11 00:34:30 +04:00
if ( fsp - > aio_write_behind ) {
if ( nwritten ! = numtowrite ) {
if ( nwritten = = - 1 ) {
DEBUG ( 5 , ( " handle_aio_write_complete: "
" aio_write_behind failed ! File %s "
" is corrupt ! Error %s \n " ,
2009-10-13 17:48:19 +04:00
fsp_str_dbg ( fsp ) , strerror ( errcode ) ) ) ;
2007-10-11 00:34:30 +04:00
} else {
DEBUG ( 0 , ( " handle_aio_write_complete: "
" aio_write_behind failed ! File %s "
" is corrupt ! Wanted %u bytes but "
2009-07-11 01:50:37 +04:00
" only wrote %d \n " , fsp_str_dbg ( fsp ) ,
2007-10-11 00:34:30 +04:00
( unsigned int ) numtowrite ,
( int ) nwritten ) ) ;
2009-10-14 00:28:57 +04:00
errcode = EIO ;
2007-10-11 00:34:30 +04:00
}
} else {
DEBUG ( 10 , ( " handle_aio_write_complete: "
" aio_write_behind completed for file %s \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) ) ) ;
2007-10-11 00:34:30 +04:00
}
2009-10-13 17:48:19 +04:00
/* TODO: should no return 0 in case of an error !!! */
2007-10-11 00:34:30 +04:00
return 0 ;
}
2005-06-28 02:53:56 +04:00
/* We don't need outsize or set_message here as we've already set the
fixed size length when we set up the aio call . */
if ( nwritten = = - 1 ) {
2007-02-10 16:15:58 +03:00
DEBUG ( 3 , ( " handle_aio_write: file %s wanted %u bytes. "
" nwritten == %d. Error = %s \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) , ( unsigned int ) numtowrite ,
2009-10-14 00:03:39 +04:00
( int ) nwritten , strerror ( errcode ) ) ) ;
2005-06-28 02:53:56 +04:00
2009-10-14 00:28:57 +04:00
ERROR_NT ( map_nt_error_from_unix ( errcode ) ) ;
2008-01-04 23:56:23 +03:00
srv_set_message ( outbuf , 0 , 0 , true ) ;
2005-06-28 02:53:56 +04:00
} else {
2008-11-05 21:19:17 +03:00
bool write_through = BITSETW ( aio_ex - > req - > vwv + 7 , 0 ) ;
2007-06-15 23:24:04 +04:00
NTSTATUS status ;
2005-06-28 02:53:56 +04:00
SSVAL ( outbuf , smb_vwv2 , nwritten ) ;
SSVAL ( outbuf , smb_vwv4 , ( nwritten > > 16 ) & 1 ) ;
if ( nwritten < ( ssize_t ) numtowrite ) {
SCVAL ( outbuf , smb_rcls , ERRHRD ) ;
SSVAL ( outbuf , smb_err , ERRdiskfull ) ;
}
2007-02-10 16:15:58 +03:00
DEBUG ( 3 , ( " handle_aio_write: fnum=%d num=%d wrote=%d \n " ,
fsp - > fnum , ( int ) numtowrite , ( int ) nwritten ) ) ;
2007-06-15 23:24:04 +04:00
status = sync_file ( fsp - > conn , fsp , write_through ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-10-14 00:28:57 +04:00
errcode = errno ;
ERROR_BOTH ( map_nt_error_from_unix ( errcode ) ,
2007-12-27 21:56:44 +03:00
ERRHRD , ERRdiskfull ) ;
2008-01-04 23:56:23 +03:00
srv_set_message ( outbuf , 0 , 0 , true ) ;
2007-06-15 23:24:04 +04:00
DEBUG ( 5 , ( " handle_aio_write: sync_file for %s returned %s \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) , nt_errstr ( status ) ) ) ;
2007-06-15 23:24:04 +04:00
}
2008-02-19 15:27:08 +03:00
aio_ex - > fsp - > fh - > pos = aio_ex - > acb . aio_offset + nwritten ;
2005-06-28 02:53:56 +04:00
}
show_msg ( outbuf ) ;
2009-03-09 11:47:59 +03:00
if ( ! srv_send_smb ( smbd_server_fd ( ) , outbuf ,
true , aio_ex - > req - > seqnum + 1 ,
IS_CONN_ENCRYPTED ( fsp - > conn ) ,
2009-02-09 10:10:34 +03:00
NULL ) ) {
2008-01-04 23:56:23 +03:00
exit_server_cleanly ( " handle_aio_write: srv_send_smb failed. " ) ;
2005-06-28 02:53:56 +04:00
}
2007-02-10 16:15:58 +03:00
DEBUG ( 10 , ( " handle_aio_write_complete: scheduled aio_write completed "
" for file %s, offset %.0f, requested %u, written = %u \n " ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) , ( double ) aio_ex - > acb . aio_offset ,
2007-02-10 16:15:58 +03:00
( unsigned int ) numtowrite , ( unsigned int ) nwritten ) ) ;
2005-06-28 02:53:56 +04:00
2009-10-14 00:28:57 +04:00
return errcode ;
2005-06-28 02:53:56 +04:00
}
/****************************************************************************
2007-02-10 16:15:58 +03:00
Handle any aio completion . Returns True if finished ( and sets * perr if err
was non - zero ) , False if not .
2005-06-28 02:53:56 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool handle_aio_completed ( struct aio_extra * aio_ex , int * perr )
2005-06-28 02:53:56 +04:00
{
2010-04-06 01:16:21 +04:00
files_struct * fsp = NULL ;
2005-06-28 02:53:56 +04:00
int err ;
2008-09-16 05:45:10 +04:00
if ( ! aio_ex ) {
DEBUG ( 3 , ( " handle_aio_completed: Non-existing aio_ex passed \n " ) ) ;
return false ;
}
2010-04-06 01:16:21 +04:00
fsp = aio_ex - > fsp ;
2005-06-28 02:53:56 +04:00
/* Ensure the operation has really completed. */
2010-04-06 01:16:21 +04:00
err = SMB_VFS_AIO_ERROR ( fsp , & aio_ex - > acb ) ;
2009-10-13 17:48:19 +04:00
if ( err = = EINPROGRESS ) {
2007-02-10 16:15:58 +03:00
DEBUG ( 10 , ( " handle_aio_completed: operation mid %u still in "
" process for file %s \n " ,
2009-07-11 01:50:37 +04:00
aio_ex - > req - > mid , fsp_str_dbg ( aio_ex - > fsp ) ) ) ;
2005-06-28 02:53:56 +04:00
return False ;
2010-04-06 01:16:21 +04:00
}
/* Unlock now we're done. */
SMB_VFS_STRICT_UNLOCK ( fsp - > conn , fsp , & aio_ex - > lock ) ;
if ( err = = ECANCELED ) {
2009-10-13 17:48:19 +04:00
/* If error is ECANCELED then don't return anything to the
* client . */
DEBUG ( 10 , ( " handle_aio_completed: operation mid %u "
" canceled \n " , aio_ex - > req - > mid ) ) ;
return True ;
}
2005-06-28 02:53:56 +04:00
2009-10-13 17:48:19 +04:00
err = aio_ex - > handle_completion ( aio_ex , err ) ;
2005-06-28 02:53:56 +04:00
if ( err ) {
* perr = err ; /* Only save non-zero errors. */
}
return True ;
}
/****************************************************************************
Handle any aio completion inline .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-01-22 20:04:17 +03:00
void smbd_aio_complete_mid ( unsigned int mid )
2005-06-28 02:53:56 +04:00
{
2009-01-22 20:04:17 +03:00
files_struct * fsp = NULL ;
struct aio_extra * aio_ex = find_aio_ex ( mid ) ;
2005-06-28 02:53:56 +04:00
int ret = 0 ;
2009-10-01 02:20:09 +04:00
outstanding_aio_calls - - ;
2009-01-22 20:04:17 +03:00
DEBUG ( 10 , ( " smbd_aio_complete_mid: mid[%u] \n " , mid ) ) ;
2005-06-28 02:53:56 +04:00
2009-01-22 20:04:17 +03:00
if ( ! aio_ex ) {
DEBUG ( 3 , ( " smbd_aio_complete_mid: Can't find record to "
" match mid %u. \n " , mid ) ) ;
return ;
2005-06-28 02:53:56 +04:00
}
2009-01-22 20:04:17 +03:00
fsp = aio_ex - > fsp ;
if ( fsp = = NULL ) {
/* file was closed whilst I/O was outstanding. Just
* ignore . */
DEBUG ( 3 , ( " smbd_aio_complete_mid: file closed whilst "
" aio outstanding (mid[%u]). \n " , mid ) ) ;
return ;
}
2005-06-28 02:53:56 +04:00
2009-01-22 20:04:17 +03:00
if ( ! handle_aio_completed ( aio_ex , & ret ) ) {
return ;
}
2005-06-28 02:53:56 +04:00
2009-01-22 20:04:17 +03:00
TALLOC_FREE ( aio_ex ) ;
}
2005-06-28 02:53:56 +04:00
2007-10-11 00:34:30 +04:00
/****************************************************************************
We ' re doing write behind and the client closed the file . Wait up to 30
seconds ( my arbitrary choice ) for the aio to complete . Return 0 if all writes
completed , errno to return if not .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define SMB_TIME_FOR_AIO_COMPLETE_WAIT 29
int wait_for_aio_completion ( files_struct * fsp )
{
struct aio_extra * aio_ex ;
const SMB_STRUCT_AIOCB * * aiocb_list ;
int aio_completion_count = 0 ;
time_t start_time = time ( NULL ) ;
int seconds_left ;
for ( seconds_left = SMB_TIME_FOR_AIO_COMPLETE_WAIT ;
seconds_left > = 0 ; ) {
int err = 0 ;
int i ;
struct timespec ts ;
aio_completion_count = 0 ;
for ( aio_ex = aio_list_head ; aio_ex ; aio_ex = aio_ex - > next ) {
if ( aio_ex - > fsp = = fsp ) {
aio_completion_count + + ;
}
}
if ( ! aio_completion_count ) {
return 0 ;
}
DEBUG ( 3 , ( " wait_for_aio_completion: waiting for %d aio events "
" to complete. \n " , aio_completion_count ) ) ;
aiocb_list = SMB_MALLOC_ARRAY ( const SMB_STRUCT_AIOCB * ,
aio_completion_count ) ;
if ( ! aiocb_list ) {
return ENOMEM ;
}
for ( i = 0 , aio_ex = aio_list_head ;
aio_ex ;
aio_ex = aio_ex - > next ) {
if ( aio_ex - > fsp = = fsp ) {
aiocb_list [ i + + ] = & aio_ex - > acb ;
}
}
/* Now wait up to seconds_left for completion. */
ts . tv_sec = seconds_left ;
ts . tv_nsec = 0 ;
DEBUG ( 10 , ( " wait_for_aio_completion: %d events, doing a wait "
" of %d seconds. \n " ,
aio_completion_count , seconds_left ) ) ;
err = SMB_VFS_AIO_SUSPEND ( fsp , aiocb_list ,
aio_completion_count , & ts ) ;
DEBUG ( 10 , ( " wait_for_aio_completion: returned err = %d, "
" errno = %s \n " , err , strerror ( errno ) ) ) ;
2008-11-03 22:07:11 +03:00
2007-10-11 00:34:30 +04:00
if ( err = = - 1 & & errno = = EAGAIN ) {
DEBUG ( 0 , ( " wait_for_aio_completion: aio_suspend timed "
" out waiting for %d events after a wait of "
" %d seconds \n " , aio_completion_count ,
seconds_left ) ) ;
/* Timeout. */
cancel_aio_by_fsp ( fsp ) ;
SAFE_FREE ( aiocb_list ) ;
return EIO ;
}
/* One or more events might have completed - process them if
* so . */
for ( i = 0 ; i < aio_completion_count ; i + + ) {
uint16 mid = aiocb_list [ i ] - > aio_sigevent . sigev_value . sival_int ;
aio_ex = find_aio_ex ( mid ) ;
if ( ! aio_ex ) {
DEBUG ( 0 , ( " wait_for_aio_completion: mid %u "
" doesn't match an aio record \n " ,
( unsigned int ) mid ) ) ;
continue ;
}
if ( ! handle_aio_completed ( aio_ex , & err ) ) {
continue ;
}
2008-11-03 21:59:11 +03:00
TALLOC_FREE ( aio_ex ) ;
2007-10-11 00:34:30 +04:00
}
SAFE_FREE ( aiocb_list ) ;
seconds_left = SMB_TIME_FOR_AIO_COMPLETE_WAIT
- ( time ( NULL ) - start_time ) ;
}
/* We timed out - we don't know why. Return ret if already an error,
* else EIO . */
DEBUG ( 10 , ( " wait_for_aio_completion: aio_suspend timed out waiting "
" for %d events \n " ,
aio_completion_count ) ) ;
return EIO ;
}
2005-06-28 02:53:56 +04:00
/****************************************************************************
Cancel any outstanding aio requests . The client doesn ' t care about the reply .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void cancel_aio_by_fsp ( files_struct * fsp )
{
struct aio_extra * aio_ex ;
for ( aio_ex = aio_list_head ; aio_ex ; aio_ex = aio_ex - > next ) {
if ( aio_ex - > fsp = = fsp ) {
2010-04-06 01:16:21 +04:00
/* Unlock now we're done. */
SMB_VFS_STRICT_UNLOCK ( fsp - > conn , fsp , & aio_ex - > lock ) ;
2007-02-10 16:15:58 +03:00
/* Don't delete the aio_extra record as we may have
completed and don ' t yet know it . Just do the
aio_cancel call and return . */
2008-01-08 14:20:51 +03:00
SMB_VFS_AIO_CANCEL ( fsp , & aio_ex - > acb ) ;
2007-02-10 16:15:58 +03:00
aio_ex - > fsp = NULL ; /* fsp will be closed when we
* return . */
2005-06-28 02:53:56 +04:00
}
}
}
2009-01-22 20:04:17 +03:00
# else
2010-04-06 01:16:21 +04:00
NTSTATUS schedule_aio_read_and_X ( connection_struct * conn ,
2007-08-11 20:28:10 +04:00
struct smb_request * req ,
2005-06-28 02:53:56 +04:00
files_struct * fsp , SMB_OFF_T startpos ,
size_t smb_maxcnt )
{
2010-04-06 01:16:21 +04:00
return NT_STATUS_RETRY ;
2005-06-28 02:53:56 +04:00
}
2010-04-06 01:16:21 +04:00
NTSTATUS schedule_aio_write_and_X ( connection_struct * conn ,
2007-08-08 23:05:30 +04:00
struct smb_request * req ,
files_struct * fsp , char * data ,
SMB_OFF_T startpos ,
size_t numtowrite )
2005-06-28 02:53:56 +04:00
{
2010-04-06 01:16:21 +04:00
return NT_STATUS_RETRY ;
2005-06-28 02:53:56 +04:00
}
void cancel_aio_by_fsp ( files_struct * fsp )
{
}
2007-10-19 04:40:25 +04:00
int wait_for_aio_completion ( files_struct * fsp )
2007-10-11 00:34:30 +04:00
{
2007-10-19 04:40:25 +04:00
return ENOSYS ;
2007-10-11 00:34:30 +04:00
}
2009-01-22 20:04:17 +03:00
void smbd_aio_complete_mid ( unsigned int mid ) ;
2005-06-28 02:53:56 +04:00
# endif