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"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2009-01-08 14:03:45 +03:00
# include "smbd/globals.h"
2011-04-28 19:38:09 +04:00
# include "../lib/util/tevent_ntstatus.h"
2012-07-13 15:41:47 +04:00
# include "../lib/util/tevent_unix.h"
2012-07-18 00:24:51 +04:00
# include "lib/tevent_wait.h"
2005-06-28 02:53:56 +04:00
2015-11-12 20:20:05 +03:00
/****************************************************************************
Statics plus accessor functions .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-11-12 20:25:41 +03:00
static int outstanding_aio_calls ;
2015-11-12 20:20:05 +03:00
2015-11-12 20:25:41 +03:00
int get_outstanding_aio_calls ( void )
{
return outstanding_aio_calls ;
}
void increment_outstanding_aio_calls ( void )
{
outstanding_aio_calls + + ;
}
void decrement_outstanding_aio_calls ( void )
{
outstanding_aio_calls - - ;
}
2010-06-02 03:05:44 +04:00
/****************************************************************************
The buffer we keep around whilst an aio request is in process .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct aio_extra {
files_struct * fsp ;
2010-06-04 22:41:38 +04:00
struct smb_request * smbreq ;
2010-06-02 21:25:56 +04:00
DATA_BLOB outbuf ;
2010-06-02 03:05:44 +04:00
struct lock_struct lock ;
2012-07-06 17:05:02 +04:00
size_t nbyte ;
off_t offset ;
2010-06-08 03:25:18 +04:00
bool write_through ;
2010-06-02 03:05:44 +04:00
} ;
2012-07-12 21:57:47 +04:00
/****************************************************************************
Accessor function to return write_through state .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool aio_write_through_requested ( struct aio_extra * aio_ex )
{
return aio_ex - > write_through ;
}
2008-11-03 23:56:02 +03:00
static int aio_extra_destructor ( struct aio_extra * aio_ex )
{
2015-11-12 20:25:41 +03:00
decrement_outstanding_aio_calls ( ) ;
2008-11-03 23:56:02 +03:00
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-06-08 03:26:30 +04:00
static struct aio_extra * create_aio_extra ( TALLOC_CTX * mem_ctx ,
files_struct * fsp ,
size_t buflen )
2005-06-28 02:53:56 +04:00
{
2011-06-07 05:44:43 +04:00
struct aio_extra * aio_ex = talloc_zero ( mem_ctx , 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 . */
2010-06-08 03:26:30 +04:00
if ( buflen ) {
aio_ex - > outbuf = data_blob_talloc ( aio_ex , NULL , buflen ) ;
if ( ! aio_ex - > outbuf . data ) {
TALLOC_FREE ( aio_ex ) ;
return NULL ;
}
2005-06-28 02:53:56 +04:00
}
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 ;
2015-11-12 20:25:41 +03:00
increment_outstanding_aio_calls ( ) ;
2005-06-28 02:53:56 +04:00
return aio_ex ;
}
2012-07-06 11:37:57 +04:00
struct aio_req_fsp_link {
files_struct * fsp ;
struct tevent_req * req ;
} ;
static int aio_del_req_from_fsp ( struct aio_req_fsp_link * lnk )
{
unsigned i ;
files_struct * fsp = lnk - > fsp ;
struct tevent_req * req = lnk - > req ;
for ( i = 0 ; i < fsp - > num_aio_requests ; i + + ) {
if ( fsp - > aio_requests [ i ] = = req ) {
break ;
}
}
if ( i = = fsp - > num_aio_requests ) {
DEBUG ( 1 , ( " req %p not found in fsp %p \n " , req , fsp ) ) ;
return 0 ;
}
fsp - > num_aio_requests - = 1 ;
fsp - > aio_requests [ i ] = fsp - > aio_requests [ fsp - > num_aio_requests ] ;
2012-07-18 00:24:51 +04:00
if ( fsp - > num_aio_requests = = 0 ) {
tevent_wait_done ( fsp - > deferred_close ) ;
}
2012-07-06 11:37:57 +04:00
return 0 ;
}
2014-12-05 08:13:33 +03:00
bool aio_add_req_to_fsp ( files_struct * fsp , struct tevent_req * req )
2012-07-06 11:37:57 +04:00
{
size_t array_len ;
struct aio_req_fsp_link * lnk ;
lnk = talloc ( req , struct aio_req_fsp_link ) ;
if ( lnk = = NULL ) {
return false ;
}
array_len = talloc_array_length ( fsp - > aio_requests ) ;
if ( array_len < = fsp - > num_aio_requests ) {
struct tevent_req * * tmp ;
tmp = talloc_realloc (
fsp , fsp - > aio_requests , struct tevent_req * ,
fsp - > num_aio_requests + 1 ) ;
if ( tmp = = NULL ) {
TALLOC_FREE ( lnk ) ;
return false ;
}
fsp - > aio_requests = tmp ;
}
fsp - > aio_requests [ fsp - > num_aio_requests ] = req ;
fsp - > num_aio_requests + = 1 ;
lnk - > fsp = fsp ;
lnk - > req = req ;
talloc_set_destructor ( lnk , aio_del_req_from_fsp ) ;
return true ;
}
2012-07-02 14:46:03 +04:00
static void aio_pread_smb1_done ( struct tevent_req * req ) ;
2005-06-28 02:53:56 +04:00
/****************************************************************************
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 ,
2010-06-04 22:41:38 +04:00
struct smb_request * smbreq ,
2012-04-05 08:53:08 +04:00
files_struct * fsp , off_t startpos ,
2005-06-28 02:53:56 +04:00
size_t smb_maxcnt )
{
struct aio_extra * aio_ex ;
size_t bufsize ;
size_t min_aio_read_size = lp_aio_read_size ( SNUM ( conn ) ) ;
2012-07-02 14:46:03 +04:00
struct tevent_req * req ;
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 . */
2010-06-04 22:41:38 +04:00
if ( req_is_in_chain ( smbreq ) | | ( 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
}
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 */
2014-08-15 09:04:33 +04:00
bufsize = smb_size + 12 * 2 + smb_maxcnt + 1 /* padding byte */ ;
2005-06-28 02:53:56 +04:00
2010-06-08 03:26:30 +04:00
if ( ( aio_ex = create_aio_extra ( NULL , 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
}
2010-06-04 22:41:38 +04:00
construct_reply_common_req ( smbreq , ( char * ) aio_ex - > outbuf . data ) ;
2010-06-02 21:25:56 +04:00
srv_set_message ( ( char * ) aio_ex - > outbuf . data , 12 , 0 , True ) ;
SCVAL ( aio_ex - > outbuf . data , smb_vwv0 , 0xFF ) ; /* Never a chained reply. */
2014-08-15 09:04:33 +04:00
SCVAL ( smb_buf ( aio_ex - > outbuf . data ) , 0 , 0 ) ; /* padding byte */
2005-06-28 02:53:56 +04:00
2010-06-04 22:41:38 +04:00
init_strict_lock_struct ( fsp , ( uint64_t ) smbreq - > smbpid ,
2010-04-06 01:16:21 +04:00
( 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 ;
}
2012-07-06 17:05:02 +04:00
aio_ex - > nbyte = smb_maxcnt ;
aio_ex - > offset = startpos ;
2005-06-28 02:53:56 +04:00
2012-07-02 14:46:03 +04:00
req = SMB_VFS_PREAD_SEND ( aio_ex , fsp - > conn - > sconn - > ev_ctx ,
2014-08-15 09:04:33 +04:00
fsp ,
smb_buf ( aio_ex - > outbuf . data ) + 1 /* pad */ ,
2012-07-02 14:46:03 +04:00
smb_maxcnt , startpos ) ;
if ( req = = NULL ) {
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
}
2012-07-02 14:46:03 +04:00
tevent_req_set_callback ( req , aio_pread_smb1_done , aio_ex ) ;
2005-06-28 02:53:56 +04:00
2012-07-06 11:37:57 +04:00
if ( ! aio_add_req_to_fsp ( fsp , req ) ) {
DEBUG ( 1 , ( " Could not add req to fsp \n " ) ) ;
SMB_VFS_STRICT_UNLOCK ( conn , fsp , & aio_ex - > lock ) ;
TALLOC_FREE ( aio_ex ) ;
return NT_STATUS_RETRY ;
}
2010-06-04 22:41:38 +04:00
aio_ex - > smbreq = talloc_move ( aio_ex , & smbreq ) ;
2008-11-03 23:56:02 +03:00
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 ,
2010-06-04 22:41:38 +04:00
( unsigned int ) aio_ex - > smbreq - > 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
}
2012-07-02 14:46:03 +04:00
static void aio_pread_smb1_done ( struct tevent_req * req )
{
struct aio_extra * aio_ex = tevent_req_callback_data (
req , struct aio_extra ) ;
files_struct * fsp = aio_ex - > fsp ;
int outsize ;
char * outbuf = ( char * ) aio_ex - > outbuf . data ;
2014-08-15 09:04:33 +04:00
char * data = smb_buf ( outbuf ) + 1 /* padding byte */ ;
2012-07-02 14:46:03 +04:00
ssize_t nread ;
2016-02-26 12:54:01 +03:00
struct vfs_aio_state vfs_aio_state ;
2012-07-02 14:46:03 +04:00
2016-02-26 12:54:01 +03:00
nread = SMB_VFS_PREAD_RECV ( req , & vfs_aio_state ) ;
2012-07-02 14:46:03 +04:00
TALLOC_FREE ( req ) ;
DEBUG ( 10 , ( " pread_recv returned %d, err = %s \n " , ( int ) nread ,
2016-02-26 12:54:01 +03:00
( nread = = - 1 ) ? strerror ( vfs_aio_state . error ) : " no error " ) ) ;
2012-07-02 14:46:03 +04:00
if ( fsp = = NULL ) {
DEBUG ( 3 , ( " aio_pread_smb1_done: file closed whilst "
" aio outstanding (mid[%llu]). \n " ,
( unsigned long long ) aio_ex - > smbreq - > mid ) ) ;
TALLOC_FREE ( aio_ex ) ;
return ;
}
/* Unlock now we're done. */
SMB_VFS_STRICT_UNLOCK ( fsp - > conn , fsp , & aio_ex - > lock ) ;
if ( nread < 0 ) {
DEBUG ( 3 , ( " handle_aio_read_complete: file %s nread == %d. "
" Error = %s \n " , fsp_str_dbg ( fsp ) , ( int ) nread ,
2016-02-26 12:54:01 +03:00
strerror ( vfs_aio_state . error ) ) ) ;
2012-07-02 14:46:03 +04:00
2016-02-26 12:54:01 +03:00
ERROR_NT ( map_nt_error_from_unix ( vfs_aio_state . error ) ) ;
2012-07-02 14:46:03 +04:00
outsize = srv_set_message ( outbuf , 0 , 0 , true ) ;
} else {
2014-08-15 09:04:33 +04:00
outsize = srv_set_message ( outbuf , 12 ,
nread + 1 /* padding byte */ , false ) ;
2012-07-02 14:46:03 +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 ) ;
2012-07-06 17:05:02 +04:00
aio_ex - > fsp - > fh - > pos = aio_ex - > offset + nread ;
2012-07-02 14:46:03 +04:00
aio_ex - > fsp - > fh - > position_information = aio_ex - > fsp - > fh - > pos ;
DEBUG ( 3 , ( " handle_aio_read_complete file %s max=%d "
" nread=%d \n " , fsp_str_dbg ( fsp ) ,
2012-07-06 17:05:02 +04:00
( int ) aio_ex - > nbyte , ( int ) nread ) ) ;
2012-07-02 14:46:03 +04:00
}
smb_setlen ( outbuf , outsize - 4 ) ;
show_msg ( outbuf ) ;
2014-06-11 14:55:24 +04:00
if ( ! srv_send_smb ( aio_ex - > smbreq - > xconn , outbuf ,
2012-07-02 14:46:03 +04:00
true , aio_ex - > smbreq - > seqnum + 1 ,
IS_CONN_ENCRYPTED ( fsp - > conn ) , NULL ) ) {
exit_server_cleanly ( " handle_aio_read_complete: srv_send_smb "
" failed. " ) ;
}
DEBUG ( 10 , ( " handle_aio_read_complete: scheduled aio_read completed "
" for file %s, offset %.0f, len = %u \n " ,
2012-07-06 17:05:02 +04:00
fsp_str_dbg ( fsp ) , ( double ) aio_ex - > offset ,
2012-07-02 14:46:03 +04:00
( unsigned int ) nread ) ) ;
TALLOC_FREE ( aio_ex ) ;
}
2012-07-13 15:41:47 +04:00
struct pwrite_fsync_state {
struct tevent_context * ev ;
files_struct * fsp ;
bool write_through ;
ssize_t nwritten ;
} ;
static void pwrite_fsync_write_done ( struct tevent_req * subreq ) ;
static void pwrite_fsync_sync_done ( struct tevent_req * subreq ) ;
static struct tevent_req * pwrite_fsync_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct files_struct * fsp ,
const void * data ,
size_t n , off_t offset ,
bool write_through )
{
struct tevent_req * req , * subreq ;
struct pwrite_fsync_state * state ;
req = tevent_req_create ( mem_ctx , & state , struct pwrite_fsync_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > fsp = fsp ;
state - > write_through = write_through ;
subreq = SMB_VFS_PWRITE_SEND ( state , ev , fsp , data , n , offset ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , pwrite_fsync_write_done , req ) ;
return req ;
}
static void pwrite_fsync_write_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct pwrite_fsync_state * state = tevent_req_data (
req , struct pwrite_fsync_state ) ;
connection_struct * conn = state - > fsp - > conn ;
bool do_sync ;
2016-02-26 12:54:01 +03:00
struct vfs_aio_state vfs_aio_state ;
2012-07-13 15:41:47 +04:00
2016-02-26 12:54:01 +03:00
state - > nwritten = SMB_VFS_PWRITE_RECV ( subreq , & vfs_aio_state ) ;
2012-07-13 15:41:47 +04:00
TALLOC_FREE ( subreq ) ;
if ( state - > nwritten = = - 1 ) {
2016-02-26 12:54:01 +03:00
tevent_req_error ( req , vfs_aio_state . error ) ;
2012-07-13 15:41:47 +04:00
return ;
}
do_sync = ( lp_strict_sync ( SNUM ( conn ) ) & &
2014-02-04 06:09:12 +04:00
( lp_sync_always ( SNUM ( conn ) ) | | state - > write_through ) ) ;
2012-07-13 15:41:47 +04:00
if ( ! do_sync ) {
tevent_req_done ( req ) ;
return ;
}
subreq = SMB_VFS_FSYNC_SEND ( state , state - > ev , state - > fsp ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , pwrite_fsync_sync_done , req ) ;
}
static void pwrite_fsync_sync_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2016-02-26 12:54:01 +03:00
int ret ;
struct vfs_aio_state vfs_aio_state ;
2012-07-13 15:41:47 +04:00
2016-02-26 12:54:01 +03:00
ret = SMB_VFS_FSYNC_RECV ( subreq , & vfs_aio_state ) ;
2012-07-13 15:41:47 +04:00
TALLOC_FREE ( subreq ) ;
if ( ret = = - 1 ) {
2016-02-26 12:54:01 +03:00
tevent_req_error ( req , vfs_aio_state . error ) ;
2012-07-13 15:41:47 +04:00
return ;
}
tevent_req_done ( req ) ;
}
static ssize_t pwrite_fsync_recv ( struct tevent_req * req , int * perr )
{
struct pwrite_fsync_state * state = tevent_req_data (
req , struct pwrite_fsync_state ) ;
if ( tevent_req_is_unix_error ( req , perr ) ) {
return - 1 ;
}
return state - > nwritten ;
}
2012-07-02 14:46:03 +04:00
static void aio_pwrite_smb1_done ( struct tevent_req * req ) ;
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 ,
2010-06-04 22:41:38 +04:00
struct smb_request * smbreq ,
2011-05-05 21:41:59 +04:00
files_struct * fsp , const char * data ,
2012-04-05 08:53:08 +04:00
off_t startpos ,
2007-08-08 23:05:30 +04:00
size_t numtowrite )
2005-06-28 02:53:56 +04:00
{
struct aio_extra * aio_ex ;
2008-11-03 23:56:02 +03:00
size_t bufsize ;
2005-06-28 02:53:56 +04:00
size_t min_aio_write_size = lp_aio_write_size ( SNUM ( conn ) ) ;
2012-07-02 14:46:03 +04:00
struct tevent_req * req ;
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
}
2010-06-08 03:25:18 +04:00
/* Only do this on non-chained and non-chaining writes not using the
2007-02-10 16:15:58 +03:00
* write cache . */
2010-06-04 22:41:38 +04:00
if ( req_is_in_chain ( smbreq ) | | ( 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-11-03 23:56:02 +03:00
bufsize = smb_size + 6 * 2 ;
2010-06-08 03:26:30 +04:00
if ( ! ( aio_ex = create_aio_extra ( NULL , 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
}
2010-06-08 03:25:18 +04:00
aio_ex - > write_through = BITSETW ( smbreq - > vwv + 7 , 0 ) ;
2005-06-28 02:53:56 +04:00
2010-06-04 22:41:38 +04:00
construct_reply_common_req ( smbreq , ( char * ) aio_ex - > outbuf . data ) ;
2010-06-02 21:25:56 +04:00
srv_set_message ( ( char * ) aio_ex - > outbuf . data , 6 , 0 , True ) ;
SCVAL ( aio_ex - > outbuf . data , smb_vwv0 , 0xFF ) ; /* Never a chained reply. */
2005-06-28 02:53:56 +04:00
2010-06-04 22:41:38 +04:00
init_strict_lock_struct ( fsp , ( uint64_t ) smbreq - > smbpid ,
2010-04-06 01:16:21 +04:00
( 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 ;
}
2012-07-06 17:05:02 +04:00
aio_ex - > nbyte = numtowrite ;
aio_ex - > offset = startpos ;
2005-06-28 02:53:56 +04:00
2012-07-13 15:41:47 +04:00
req = pwrite_fsync_send ( aio_ex , fsp - > conn - > sconn - > ev_ctx , fsp ,
data , numtowrite , startpos ,
aio_ex - > write_through ) ;
2012-07-02 14:46:03 +04:00
if ( req = = NULL ) {
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
}
2012-07-02 14:46:03 +04:00
tevent_req_set_callback ( req , aio_pwrite_smb1_done , aio_ex ) ;
2008-11-02 23:52:16 +03:00
2012-07-06 11:37:57 +04:00
if ( ! aio_add_req_to_fsp ( fsp , req ) ) {
DEBUG ( 1 , ( " Could not add req to fsp \n " ) ) ;
SMB_VFS_STRICT_UNLOCK ( conn , fsp , & aio_ex - > lock ) ;
TALLOC_FREE ( aio_ex ) ;
return NT_STATUS_RETRY ;
}
2010-06-04 22:41:38 +04:00
aio_ex - > smbreq = talloc_move ( aio_ex , & smbreq ) ;
2008-11-03 23:56:02 +03:00
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
2014-02-04 06:09:12 +04:00
if ( ! aio_ex - > write_through & & ! lp_sync_always ( SNUM ( fsp - > conn ) )
2007-10-11 00:34:30 +04:00
& & fsp - > aio_write_behind ) {
/* Lie to the client and immediately claim we finished the
* write . */
2010-06-02 21:25:56 +04:00
SSVAL ( aio_ex - > outbuf . data , smb_vwv2 , numtowrite ) ;
SSVAL ( aio_ex - > outbuf . data , smb_vwv4 , ( numtowrite > > 16 ) & 1 ) ;
show_msg ( ( char * ) aio_ex - > outbuf . data ) ;
2014-06-11 14:55:24 +04:00
if ( ! srv_send_smb ( aio_ex - > smbreq - > xconn ,
2010-08-14 16:53:45 +04:00
( char * ) aio_ex - > outbuf . data ,
2010-06-04 22:41:38 +04:00
true , aio_ex - > smbreq - > seqnum + 1 ,
2009-02-09 10:10:34 +03:00
IS_CONN_ENCRYPTED ( fsp - > conn ) ,
2010-06-04 22:41:38 +04:00
& aio_ex - > smbreq - > pcd ) ) {
2010-08-14 00:51:29 +04:00
exit_server_cleanly ( " schedule_aio_write_and_X: "
" srv_send_smb failed. " ) ;
2007-10-11 00:34:30 +04:00
}
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 ,
2015-11-12 20:25:41 +03:00
( unsigned int ) aio_ex - > smbreq - > mid ,
get_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
}
2012-07-02 14:46:03 +04:00
static void aio_pwrite_smb1_done ( struct tevent_req * req )
{
struct aio_extra * aio_ex = tevent_req_callback_data (
req , struct aio_extra ) ;
files_struct * fsp = aio_ex - > fsp ;
char * outbuf = ( char * ) aio_ex - > outbuf . data ;
2012-07-06 17:05:02 +04:00
ssize_t numtowrite = aio_ex - > nbyte ;
2012-07-02 14:46:03 +04:00
ssize_t nwritten ;
int err ;
2012-07-13 15:41:47 +04:00
nwritten = pwrite_fsync_recv ( req , & err ) ;
2012-07-02 14:46:03 +04:00
TALLOC_FREE ( req ) ;
DEBUG ( 10 , ( " pwrite_recv returned %d, err = %s \n " , ( int ) nwritten ,
( nwritten = = - 1 ) ? strerror ( err ) : " no error " ) ) ;
if ( fsp = = NULL ) {
DEBUG ( 3 , ( " aio_pwrite_smb1_done: file closed whilst "
" aio outstanding (mid[%llu]). \n " ,
( unsigned long long ) aio_ex - > smbreq - > mid ) ) ;
TALLOC_FREE ( aio_ex ) ;
return ;
}
/* Unlock now we're done. */
SMB_VFS_STRICT_UNLOCK ( fsp - > conn , fsp , & aio_ex - > lock ) ;
2012-07-12 18:30:22 +04:00
mark_file_modified ( fsp ) ;
2012-07-02 14:46:03 +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 " ,
fsp_str_dbg ( fsp ) , strerror ( err ) ) ) ;
} else {
DEBUG ( 0 , ( " handle_aio_write_complete: "
" aio_write_behind failed ! File %s "
" is corrupt ! Wanted %u bytes but "
" only wrote %d \n " , fsp_str_dbg ( fsp ) ,
( unsigned int ) numtowrite ,
( int ) nwritten ) ) ;
}
} else {
DEBUG ( 10 , ( " handle_aio_write_complete: "
" aio_write_behind completed for file %s \n " ,
fsp_str_dbg ( fsp ) ) ) ;
}
/* TODO: should no return success in case of an error !!! */
TALLOC_FREE ( aio_ex ) ;
return ;
}
/* 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 ) {
DEBUG ( 3 , ( " handle_aio_write: file %s wanted %u bytes. "
" nwritten == %d. Error = %s \n " ,
fsp_str_dbg ( fsp ) , ( unsigned int ) numtowrite ,
( int ) nwritten , strerror ( err ) ) ) ;
ERROR_NT ( map_nt_error_from_unix ( err ) ) ;
srv_set_message ( outbuf , 0 , 0 , true ) ;
} else {
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 ) ;
}
DEBUG ( 3 , ( " handle_aio_write: %s, num=%d wrote=%d \n " ,
fsp_fnum_dbg ( fsp ) , ( int ) numtowrite , ( int ) nwritten ) ) ;
2012-07-06 17:05:02 +04:00
aio_ex - > fsp - > fh - > pos = aio_ex - > offset + nwritten ;
2012-07-02 14:46:03 +04:00
}
show_msg ( outbuf ) ;
2014-06-11 14:55:24 +04:00
if ( ! srv_send_smb ( aio_ex - > smbreq - > xconn , outbuf ,
2012-07-02 14:46:03 +04:00
true , aio_ex - > smbreq - > seqnum + 1 ,
IS_CONN_ENCRYPTED ( fsp - > conn ) ,
NULL ) ) {
exit_server_cleanly ( " handle_aio_write_complete: "
" srv_send_smb failed. " ) ;
}
DEBUG ( 10 , ( " handle_aio_write_complete: scheduled aio_write completed "
" for file %s, offset %.0f, requested %u, written = %u \n " ,
2012-07-06 17:05:02 +04:00
fsp_str_dbg ( fsp ) , ( double ) aio_ex - > offset ,
2012-07-02 14:46:03 +04:00
( unsigned int ) numtowrite , ( unsigned int ) nwritten ) ) ;
TALLOC_FREE ( aio_ex ) ;
}
2011-11-14 12:52:47 +04:00
bool cancel_smb2_aio ( struct smb_request * smbreq )
{
struct smbd_smb2_request * smb2req = smbreq - > smb2req ;
struct aio_extra * aio_ex = NULL ;
if ( smb2req ) {
aio_ex = talloc_get_type ( smbreq - > async_priv ,
struct aio_extra ) ;
}
if ( aio_ex = = NULL ) {
return false ;
}
if ( aio_ex - > fsp = = NULL ) {
return false ;
}
2012-07-06 11:37:57 +04:00
/*
* We let the aio request run . Setting fsp to NULL has the
* effect that the _done routines don ' t send anything out .
*/
2011-11-14 12:52:47 +04:00
2012-07-06 11:37:57 +04:00
aio_ex - > fsp = NULL ;
2011-11-14 12:52:47 +04:00
return true ;
}
2012-07-02 14:46:03 +04:00
static void aio_pread_smb2_done ( struct tevent_req * req ) ;
2010-06-11 00:20:37 +04:00
/****************************************************************************
Set up an aio request from a SMB2 read call .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS schedule_smb2_aio_read ( connection_struct * conn ,
struct smb_request * smbreq ,
files_struct * fsp ,
2010-12-15 03:32:10 +03:00
TALLOC_CTX * ctx ,
DATA_BLOB * preadbuf ,
2012-04-05 08:53:08 +04:00
off_t startpos ,
2010-06-11 00:20:37 +04:00
size_t smb_maxcnt )
{
struct aio_extra * aio_ex ;
size_t min_aio_read_size = lp_aio_read_size ( SNUM ( conn ) ) ;
2012-07-02 14:46:03 +04:00
struct tevent_req * req ;
2010-06-11 00:20:37 +04:00
if ( fsp - > base_fsp ! = NULL ) {
/* No AIO on streams yet */
DEBUG ( 10 , ( " AIO on streams not yet supported \n " ) ) ;
return NT_STATUS_RETRY ;
}
2014-05-01 21:58:51 +04:00
if ( fsp - > op = = NULL ) {
/* No AIO on internal opens. */
return NT_STATUS_RETRY ;
}
2010-06-11 00:20:37 +04:00
if ( ( ! min_aio_read_size | | ( smb_maxcnt < min_aio_read_size ) )
& & ! SMB_VFS_AIO_FORCE ( fsp ) ) {
/* Too small a read for aio request. */
DEBUG ( 10 , ( " smb2: read size (%u) too small "
" for minimum aio_read of %u \n " ,
( unsigned int ) smb_maxcnt ,
( unsigned int ) min_aio_read_size ) ) ;
return NT_STATUS_RETRY ;
}
/* Only do this on reads not using the write cache. */
if ( lp_write_cache_size ( SNUM ( conn ) ) ! = 0 ) {
return NT_STATUS_RETRY ;
}
2010-12-15 03:32:10 +03:00
/* Create the out buffer. */
* preadbuf = data_blob_talloc ( ctx , NULL , smb_maxcnt ) ;
if ( preadbuf - > data = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2010-06-11 00:20:37 +04:00
if ( ! ( aio_ex = create_aio_extra ( smbreq - > smb2req , fsp , 0 ) ) ) {
return NT_STATUS_NO_MEMORY ;
}
2013-12-06 02:57:54 +04:00
init_strict_lock_struct ( fsp , fsp - > op - > global - > open_persistent_id ,
2010-06-11 00:20:37 +04:00
( 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 ;
}
2012-07-06 17:05:02 +04:00
aio_ex - > nbyte = smb_maxcnt ;
aio_ex - > offset = startpos ;
2010-06-11 00:20:37 +04:00
2012-07-02 14:46:03 +04:00
req = SMB_VFS_PREAD_SEND ( aio_ex , fsp - > conn - > sconn - > ev_ctx , fsp ,
preadbuf - > data , smb_maxcnt , startpos ) ;
if ( req = = NULL ) {
DEBUG ( 0 , ( " smb2: SMB_VFS_PREAD_SEND failed. "
" Error %s \n " , strerror ( errno ) ) ) ;
2010-06-11 00:20:37 +04:00
SMB_VFS_STRICT_UNLOCK ( conn , fsp , & aio_ex - > lock ) ;
TALLOC_FREE ( aio_ex ) ;
return NT_STATUS_RETRY ;
}
2012-07-02 14:46:03 +04:00
tevent_req_set_callback ( req , aio_pread_smb2_done , aio_ex ) ;
2010-06-11 00:20:37 +04:00
2012-07-06 11:37:57 +04:00
if ( ! aio_add_req_to_fsp ( fsp , req ) ) {
DEBUG ( 1 , ( " Could not add req to fsp \n " ) ) ;
SMB_VFS_STRICT_UNLOCK ( conn , fsp , & aio_ex - > lock ) ;
TALLOC_FREE ( aio_ex ) ;
return NT_STATUS_RETRY ;
}
2010-06-11 00:20:37 +04:00
/* We don't need talloc_move here as both aio_ex and
* smbreq are children of smbreq - > smb2req . */
aio_ex - > smbreq = smbreq ;
2011-11-14 12:52:47 +04:00
smbreq - > async_priv = aio_ex ;
2010-06-11 00:20:37 +04:00
DEBUG ( 10 , ( " smb2: scheduled aio_read for file %s, "
" offset %.0f, len = %u (mid = %u) \n " ,
fsp_str_dbg ( fsp ) , ( double ) startpos , ( unsigned int ) smb_maxcnt ,
( unsigned int ) aio_ex - > smbreq - > mid ) ) ;
return NT_STATUS_OK ;
}
2012-07-02 14:46:03 +04:00
static void aio_pread_smb2_done ( struct tevent_req * req )
{
struct aio_extra * aio_ex = tevent_req_callback_data (
req , struct aio_extra ) ;
struct tevent_req * subreq = aio_ex - > smbreq - > smb2req - > subreq ;
files_struct * fsp = aio_ex - > fsp ;
NTSTATUS status ;
ssize_t nread ;
2016-02-26 12:54:01 +03:00
struct vfs_aio_state vfs_aio_state = { 0 } ;
2012-07-02 14:46:03 +04:00
2016-02-26 12:54:01 +03:00
nread = SMB_VFS_PREAD_RECV ( req , & vfs_aio_state ) ;
2012-07-02 14:46:03 +04:00
TALLOC_FREE ( req ) ;
DEBUG ( 10 , ( " pread_recv returned %d, err = %s \n " , ( int ) nread ,
2016-02-26 12:54:01 +03:00
( nread = = - 1 ) ? strerror ( vfs_aio_state . error ) : " no error " ) ) ;
2012-07-02 14:46:03 +04:00
if ( fsp = = NULL ) {
2015-04-16 23:28:25 +03:00
DEBUG ( 3 , ( " %s: request cancelled (mid[%ju]) \n " ,
__func__ , ( uintmax_t ) aio_ex - > smbreq - > mid ) ) ;
2012-07-02 14:46:03 +04:00
TALLOC_FREE ( aio_ex ) ;
2015-04-16 23:28:25 +03:00
tevent_req_nterror ( subreq , NT_STATUS_INTERNAL_ERROR ) ;
2012-07-02 14:46:03 +04:00
return ;
}
/* Unlock now we're done. */
SMB_VFS_STRICT_UNLOCK ( fsp - > conn , fsp , & aio_ex - > lock ) ;
/* Common error or success code processing for async or sync
read returns . */
2016-02-26 12:54:01 +03:00
status = smb2_read_complete ( subreq , nread , vfs_aio_state . error ) ;
2012-07-02 14:46:03 +04:00
if ( nread > 0 ) {
2012-07-06 17:05:02 +04:00
fsp - > fh - > pos = aio_ex - > offset + nread ;
2012-07-02 14:46:03 +04:00
fsp - > fh - > position_information = fsp - > fh - > pos ;
}
DEBUG ( 10 , ( " smb2: scheduled aio_read completed "
" for file %s, offset %.0f, len = %u "
" (errcode = %d, NTSTATUS = %s) \n " ,
fsp_str_dbg ( aio_ex - > fsp ) ,
2012-07-06 17:05:02 +04:00
( double ) aio_ex - > offset ,
2012-07-02 14:46:03 +04:00
( unsigned int ) nread ,
2016-02-26 12:54:01 +03:00
vfs_aio_state . error , nt_errstr ( status ) ) ) ;
2012-07-02 14:46:03 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( subreq , status ) ;
return ;
}
tevent_req_done ( subreq ) ;
}
2012-07-02 14:46:03 +04:00
static void aio_pwrite_smb2_done ( struct tevent_req * req ) ;
2010-06-11 00:20:37 +04:00
/****************************************************************************
Set up an aio request from a SMB2write call .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS schedule_aio_smb2_write ( connection_struct * conn ,
struct smb_request * smbreq ,
files_struct * fsp ,
uint64_t in_offset ,
DATA_BLOB in_data ,
bool write_through )
{
struct aio_extra * aio_ex = NULL ;
size_t min_aio_write_size = lp_aio_write_size ( SNUM ( conn ) ) ;
2012-07-02 14:46:03 +04:00
struct tevent_req * req ;
2010-06-11 00:20:37 +04:00
if ( fsp - > base_fsp ! = NULL ) {
/* No AIO on streams yet */
DEBUG ( 10 , ( " AIO on streams not yet supported \n " ) ) ;
return NT_STATUS_RETRY ;
}
2014-05-01 21:58:51 +04:00
if ( fsp - > op = = NULL ) {
/* No AIO on internal opens. */
return NT_STATUS_RETRY ;
}
2010-06-11 00:20:37 +04:00
if ( ( ! min_aio_write_size | | ( in_data . length < min_aio_write_size ) )
& & ! SMB_VFS_AIO_FORCE ( fsp ) ) {
/* Too small a write for aio request. */
DEBUG ( 10 , ( " smb2: write size (%u) too "
" small for minimum aio_write of %u \n " ,
( unsigned int ) in_data . length ,
( unsigned int ) min_aio_write_size ) ) ;
return NT_STATUS_RETRY ;
}
/* Only do this on writes not using the write cache. */
if ( lp_write_cache_size ( SNUM ( conn ) ) ! = 0 ) {
return NT_STATUS_RETRY ;
}
2013-03-18 23:00:25 +04:00
if ( smbreq - > unread_bytes ) {
/* Can't do async with recvfile. */
return NT_STATUS_RETRY ;
}
2010-06-11 00:20:37 +04:00
if ( ! ( aio_ex = create_aio_extra ( smbreq - > smb2req , fsp , 0 ) ) ) {
return NT_STATUS_NO_MEMORY ;
}
aio_ex - > write_through = write_through ;
2013-12-06 02:57:54 +04:00
init_strict_lock_struct ( fsp , fsp - > op - > global - > open_persistent_id ,
2010-06-11 00:20:37 +04:00
in_offset , ( uint64_t ) in_data . length , 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 ;
}
2012-07-06 17:05:02 +04:00
aio_ex - > nbyte = in_data . length ;
aio_ex - > offset = in_offset ;
2010-06-11 00:20:37 +04:00
2012-07-13 15:41:47 +04:00
req = pwrite_fsync_send ( aio_ex , fsp - > conn - > sconn - > ev_ctx , fsp ,
in_data . data , in_data . length , in_offset ,
write_through ) ;
2012-07-02 14:46:03 +04:00
if ( req = = NULL ) {
DEBUG ( 3 , ( " smb2: SMB_VFS_PWRITE_SEND failed. "
" Error %s \n " , strerror ( errno ) ) ) ;
2010-06-11 00:20:37 +04:00
SMB_VFS_STRICT_UNLOCK ( conn , fsp , & aio_ex - > lock ) ;
TALLOC_FREE ( aio_ex ) ;
return NT_STATUS_RETRY ;
}
2012-07-02 14:46:03 +04:00
tevent_req_set_callback ( req , aio_pwrite_smb2_done , aio_ex ) ;
2010-06-11 00:20:37 +04:00
2012-07-06 11:37:57 +04:00
if ( ! aio_add_req_to_fsp ( fsp , req ) ) {
DEBUG ( 1 , ( " Could not add req to fsp \n " ) ) ;
SMB_VFS_STRICT_UNLOCK ( conn , fsp , & aio_ex - > lock ) ;
TALLOC_FREE ( aio_ex ) ;
return NT_STATUS_RETRY ;
}
2010-06-11 00:20:37 +04:00
/* We don't need talloc_move here as both aio_ex and
* smbreq are children of smbreq - > smb2req . */
aio_ex - > smbreq = smbreq ;
2011-11-14 12:52:47 +04:00
smbreq - > async_priv = aio_ex ;
2010-06-11 00:20:37 +04: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 ) ;
/*
* We don ' t want to do write behind due to ownership
* issues of the request structs . Maybe add it if I
* figure those out . JRA .
*/
DEBUG ( 10 , ( " smb2: scheduled aio_write for file "
" %s, offset %.0f, len = %u (mid = %u) "
" outstanding_aio_calls = %d \n " ,
fsp_str_dbg ( fsp ) ,
( double ) in_offset ,
( unsigned int ) in_data . length ,
( unsigned int ) aio_ex - > smbreq - > mid ,
2015-11-12 20:25:41 +03:00
get_outstanding_aio_calls ( ) ) ) ;
2010-06-11 00:20:37 +04:00
return NT_STATUS_OK ;
}
2012-07-02 14:46:03 +04:00
static void aio_pwrite_smb2_done ( struct tevent_req * req )
{
struct aio_extra * aio_ex = tevent_req_callback_data (
req , struct aio_extra ) ;
2012-07-06 17:05:02 +04:00
ssize_t numtowrite = aio_ex - > nbyte ;
2012-07-02 14:46:03 +04:00
struct tevent_req * subreq = aio_ex - > smbreq - > smb2req - > subreq ;
files_struct * fsp = aio_ex - > fsp ;
NTSTATUS status ;
ssize_t nwritten ;
int err = 0 ;
2012-07-13 15:41:47 +04:00
nwritten = pwrite_fsync_recv ( req , & err ) ;
2012-07-02 14:46:03 +04:00
TALLOC_FREE ( req ) ;
DEBUG ( 10 , ( " pwrite_recv returned %d, err = %s \n " , ( int ) nwritten ,
( nwritten = = - 1 ) ? strerror ( err ) : " no error " ) ) ;
if ( fsp = = NULL ) {
2015-04-16 23:28:25 +03:00
DEBUG ( 3 , ( " %s: request cancelled (mid[%ju]) \n " ,
__func__ , ( uintmax_t ) aio_ex - > smbreq - > mid ) ) ;
2012-07-02 14:46:03 +04:00
TALLOC_FREE ( aio_ex ) ;
2015-04-16 23:28:25 +03:00
tevent_req_nterror ( subreq , NT_STATUS_INTERNAL_ERROR ) ;
2012-07-02 14:46:03 +04:00
return ;
}
/* Unlock now we're done. */
SMB_VFS_STRICT_UNLOCK ( fsp - > conn , fsp , & aio_ex - > lock ) ;
2013-06-20 20:27:39 +04:00
mark_file_modified ( fsp ) ;
2012-07-13 15:41:47 +04:00
status = smb2_write_complete_nosync ( subreq , nwritten , err ) ;
2012-07-02 14:46:03 +04:00
DEBUG ( 10 , ( " smb2: scheduled aio_write completed "
" for file %s, offset %.0f, requested %u, "
" written = %u (errcode = %d, NTSTATUS = %s) \n " ,
fsp_str_dbg ( fsp ) ,
2012-07-06 17:05:02 +04:00
( double ) aio_ex - > offset ,
2012-07-02 14:46:03 +04:00
( unsigned int ) numtowrite ,
( unsigned int ) nwritten ,
err , nt_errstr ( status ) ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( subreq , status ) ;
return ;
}
tevent_req_done ( subreq ) ;
}