1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-25 23:21:54 +03:00

Fix issue with aio where r/w lock wasn't kept across aio read operations.

Change schedule_aio_read_and_X/schedule_aio_write_and_X to
return NTSTATUS. Move the grant and release of the lock into
the aio code.

Jeremy
This commit is contained in:
Jeremy Allison 2010-04-05 14:16:21 -07:00
parent 2754a8e2b6
commit c75184b8a1
3 changed files with 110 additions and 51 deletions

View File

@ -6047,11 +6047,11 @@ struct regval_ctr *svcctl_fetch_regvalues( const char *name, NT_USER_TOKEN *toke
/* The following definitions come from smbd/aio.c */ /* The following definitions come from smbd/aio.c */
bool schedule_aio_read_and_X(connection_struct *conn, NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
struct smb_request *req, struct smb_request *req,
files_struct *fsp, SMB_OFF_T startpos, files_struct *fsp, SMB_OFF_T startpos,
size_t smb_maxcnt); size_t smb_maxcnt);
bool schedule_aio_write_and_X(connection_struct *conn, NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
struct smb_request *req, struct smb_request *req,
files_struct *fsp, char *data, files_struct *fsp, char *data,
SMB_OFF_T startpos, SMB_OFF_T startpos,

View File

@ -81,6 +81,7 @@ struct aio_extra {
files_struct *fsp; files_struct *fsp;
struct smb_request *req; struct smb_request *req;
char *outbuf; char *outbuf;
struct lock_struct lock;
int (*handle_completion)(struct aio_extra *ex, int errcode); int (*handle_completion)(struct aio_extra *ex, int errcode);
}; };
@ -145,7 +146,7 @@ static struct aio_extra *find_aio_ex(uint16 mid)
Set up an aio request from a SMBreadX call. Set up an aio request from a SMBreadX call.
*****************************************************************************/ *****************************************************************************/
bool schedule_aio_read_and_X(connection_struct *conn, NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
struct smb_request *req, struct smb_request *req,
files_struct *fsp, SMB_OFF_T startpos, files_struct *fsp, SMB_OFF_T startpos,
size_t smb_maxcnt) size_t smb_maxcnt)
@ -159,7 +160,7 @@ bool schedule_aio_read_and_X(connection_struct *conn,
if (fsp->base_fsp != NULL) { if (fsp->base_fsp != NULL) {
/* No AIO on streams yet */ /* No AIO on streams yet */
DEBUG(10, ("AIO on streams not yet supported\n")); DEBUG(10, ("AIO on streams not yet supported\n"));
return false; return NT_STATUS_RETRY;
} }
if ((!min_aio_read_size || (smb_maxcnt < min_aio_read_size)) if ((!min_aio_read_size || (smb_maxcnt < min_aio_read_size))
@ -169,20 +170,20 @@ bool schedule_aio_read_and_X(connection_struct *conn,
"for minimum aio_read of %u\n", "for minimum aio_read of %u\n",
(unsigned int)smb_maxcnt, (unsigned int)smb_maxcnt,
(unsigned int)min_aio_read_size )); (unsigned int)min_aio_read_size ));
return False; return NT_STATUS_RETRY;
} }
/* Only do this on non-chained and non-chaining reads not using the /* Only do this on non-chained and non-chaining reads not using the
* write cache. */ * write cache. */
if (req_is_in_chain(req) || (lp_write_cache_size(SNUM(conn)) != 0)) { if (req_is_in_chain(req) || (lp_write_cache_size(SNUM(conn)) != 0)) {
return False; return NT_STATUS_RETRY;
} }
if (outstanding_aio_calls >= aio_pending_size) { if (outstanding_aio_calls >= aio_pending_size) {
DEBUG(10,("schedule_aio_read_and_X: Already have %d aio " DEBUG(10,("schedule_aio_read_and_X: Already have %d aio "
"activities outstanding.\n", "activities outstanding.\n",
outstanding_aio_calls )); outstanding_aio_calls ));
return False; return NT_STATUS_RETRY;
} }
/* The following is safe from integer wrap as we've already checked /* The following is safe from integer wrap as we've already checked
@ -195,7 +196,7 @@ bool schedule_aio_read_and_X(connection_struct *conn,
if ((aio_ex = create_aio_extra(fsp, bufsize)) == NULL) { if ((aio_ex = create_aio_extra(fsp, bufsize)) == NULL) {
DEBUG(10,("schedule_aio_read_and_X: malloc fail.\n")); DEBUG(10,("schedule_aio_read_and_X: malloc fail.\n"));
return False; return NT_STATUS_NO_MEMORY;
} }
aio_ex->handle_completion = handle_aio_read_complete; aio_ex->handle_completion = handle_aio_read_complete;
@ -203,6 +204,16 @@ bool schedule_aio_read_and_X(connection_struct *conn,
srv_set_message(aio_ex->outbuf, 12, 0, True); srv_set_message(aio_ex->outbuf, 12, 0, True);
SCVAL(aio_ex->outbuf,smb_vwv0,0xFF); /* Never a chained reply. */ SCVAL(aio_ex->outbuf,smb_vwv0,0xFF); /* Never a chained reply. */
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;
}
a = &aio_ex->acb; a = &aio_ex->acb;
/* Now set up the aio record for the read call. */ /* Now set up the aio record for the read call. */
@ -219,8 +230,9 @@ bool schedule_aio_read_and_X(connection_struct *conn,
if (ret == -1) { if (ret == -1) {
DEBUG(0,("schedule_aio_read_and_X: aio_read failed. " DEBUG(0,("schedule_aio_read_and_X: aio_read failed. "
"Error %s\n", strerror(errno) )); "Error %s\n", strerror(errno) ));
SMB_VFS_STRICT_UNLOCK(conn, fsp, &aio_ex->lock);
TALLOC_FREE(aio_ex); TALLOC_FREE(aio_ex);
return False; return NT_STATUS_RETRY;
} }
outstanding_aio_calls++; outstanding_aio_calls++;
@ -231,14 +243,14 @@ bool schedule_aio_read_and_X(connection_struct *conn,
fsp_str_dbg(fsp), (double)startpos, (unsigned int)smb_maxcnt, fsp_str_dbg(fsp), (double)startpos, (unsigned int)smb_maxcnt,
(unsigned int)aio_ex->req->mid )); (unsigned int)aio_ex->req->mid ));
return True; return NT_STATUS_OK;
} }
/**************************************************************************** /****************************************************************************
Set up an aio request from a SMBwriteX call. Set up an aio request from a SMBwriteX call.
*****************************************************************************/ *****************************************************************************/
bool schedule_aio_write_and_X(connection_struct *conn, NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
struct smb_request *req, struct smb_request *req,
files_struct *fsp, char *data, files_struct *fsp, char *data,
SMB_OFF_T startpos, SMB_OFF_T startpos,
@ -254,7 +266,7 @@ bool schedule_aio_write_and_X(connection_struct *conn,
if (fsp->base_fsp != NULL) { if (fsp->base_fsp != NULL) {
/* No AIO on streams yet */ /* No AIO on streams yet */
DEBUG(10, ("AIO on streams not yet supported\n")); DEBUG(10, ("AIO on streams not yet supported\n"));
return false; return NT_STATUS_RETRY;
} }
if ((!min_aio_write_size || (numtowrite < min_aio_write_size)) if ((!min_aio_write_size || (numtowrite < min_aio_write_size))
@ -264,13 +276,13 @@ bool schedule_aio_write_and_X(connection_struct *conn,
"small for minimum aio_write of %u\n", "small for minimum aio_write of %u\n",
(unsigned int)numtowrite, (unsigned int)numtowrite,
(unsigned int)min_aio_write_size )); (unsigned int)min_aio_write_size ));
return False; return NT_STATUS_RETRY;
} }
/* Only do this on non-chained and non-chaining reads not using the /* Only do this on non-chained and non-chaining reads not using the
* write cache. */ * write cache. */
if (req_is_in_chain(req) || (lp_write_cache_size(SNUM(conn)) != 0)) { if (req_is_in_chain(req) || (lp_write_cache_size(SNUM(conn)) != 0)) {
return False; return NT_STATUS_RETRY;
} }
if (outstanding_aio_calls >= aio_pending_size) { if (outstanding_aio_calls >= aio_pending_size) {
@ -283,7 +295,7 @@ bool schedule_aio_write_and_X(connection_struct *conn,
fsp_str_dbg(fsp), (double)startpos, fsp_str_dbg(fsp), (double)startpos,
(unsigned int)numtowrite, (unsigned int)numtowrite,
(unsigned int)req->mid )); (unsigned int)req->mid ));
return False; return NT_STATUS_RETRY;
} }
/* Ensure aio is initialized. */ /* Ensure aio is initialized. */
@ -293,7 +305,7 @@ bool schedule_aio_write_and_X(connection_struct *conn,
if (!(aio_ex = create_aio_extra(fsp, bufsize))) { if (!(aio_ex = create_aio_extra(fsp, bufsize))) {
DEBUG(0,("schedule_aio_write_and_X: malloc fail.\n")); DEBUG(0,("schedule_aio_write_and_X: malloc fail.\n"));
return False; return NT_STATUS_NO_MEMORY;
} }
aio_ex->handle_completion = handle_aio_write_complete; aio_ex->handle_completion = handle_aio_write_complete;
@ -301,6 +313,16 @@ bool schedule_aio_write_and_X(connection_struct *conn,
srv_set_message(aio_ex->outbuf, 6, 0, True); srv_set_message(aio_ex->outbuf, 6, 0, True);
SCVAL(aio_ex->outbuf,smb_vwv0,0xFF); /* Never a chained reply. */ SCVAL(aio_ex->outbuf,smb_vwv0,0xFF); /* Never a chained reply. */
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;
}
a = &aio_ex->acb; a = &aio_ex->acb;
/* Now set up the aio record for the write call. */ /* Now set up the aio record for the write call. */
@ -317,8 +339,9 @@ bool schedule_aio_write_and_X(connection_struct *conn,
if (ret == -1) { if (ret == -1) {
DEBUG(3,("schedule_aio_wrote_and_X: aio_write failed. " DEBUG(3,("schedule_aio_wrote_and_X: aio_write failed. "
"Error %s\n", strerror(errno) )); "Error %s\n", strerror(errno) ));
SMB_VFS_STRICT_UNLOCK(conn, fsp, &aio_ex->lock);
TALLOC_FREE(aio_ex); TALLOC_FREE(aio_ex);
return False; return NT_STATUS_RETRY;
} }
outstanding_aio_calls++; outstanding_aio_calls++;
@ -352,10 +375,9 @@ bool schedule_aio_write_and_X(connection_struct *conn,
fsp_str_dbg(fsp), (double)startpos, (unsigned int)numtowrite, fsp_str_dbg(fsp), (double)startpos, (unsigned int)numtowrite,
(unsigned int)aio_ex->req->mid, outstanding_aio_calls )); (unsigned int)aio_ex->req->mid, outstanding_aio_calls ));
return True; return NT_STATUS_OK;
} }
/**************************************************************************** /****************************************************************************
Complete the read and return the data or error back to the client. Complete the read and return the data or error back to the client.
Returns errno or zero if all ok. Returns errno or zero if all ok.
@ -511,6 +533,7 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex, int errcode)
static bool handle_aio_completed(struct aio_extra *aio_ex, int *perr) static bool handle_aio_completed(struct aio_extra *aio_ex, int *perr)
{ {
files_struct *fsp = NULL;
int err; int err;
if(!aio_ex) { if(!aio_ex) {
@ -518,14 +541,21 @@ static bool handle_aio_completed(struct aio_extra *aio_ex, int *perr)
return false; return false;
} }
fsp = aio_ex->fsp;
/* Ensure the operation has really completed. */ /* Ensure the operation has really completed. */
err = SMB_VFS_AIO_ERROR(aio_ex->fsp, &aio_ex->acb); err = SMB_VFS_AIO_ERROR(fsp, &aio_ex->acb);
if (err == EINPROGRESS) { if (err == EINPROGRESS) {
DEBUG(10,( "handle_aio_completed: operation mid %u still in " DEBUG(10,( "handle_aio_completed: operation mid %u still in "
"process for file %s\n", "process for file %s\n",
aio_ex->req->mid, fsp_str_dbg(aio_ex->fsp))); aio_ex->req->mid, fsp_str_dbg(aio_ex->fsp)));
return False; return False;
} else if (err == ECANCELED) { }
/* Unlock now we're done. */
SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &aio_ex->lock);
if (err == ECANCELED) {
/* If error is ECANCELED then don't return anything to the /* If error is ECANCELED then don't return anything to the
* client. */ * client. */
DEBUG(10,( "handle_aio_completed: operation mid %u" DEBUG(10,( "handle_aio_completed: operation mid %u"
@ -696,6 +726,9 @@ void cancel_aio_by_fsp(files_struct *fsp)
for( aio_ex = aio_list_head; aio_ex; aio_ex = aio_ex->next) { for( aio_ex = aio_list_head; aio_ex; aio_ex = aio_ex->next) {
if (aio_ex->fsp == fsp) { if (aio_ex->fsp == fsp) {
/* Unlock now we're done. */
SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &aio_ex->lock);
/* Don't delete the aio_extra record as we may have /* Don't delete the aio_extra record as we may have
completed and don't yet know it. Just do the completed and don't yet know it. Just do the
aio_cancel call and return. */ aio_cancel call and return. */
@ -707,21 +740,21 @@ void cancel_aio_by_fsp(files_struct *fsp)
} }
#else #else
bool schedule_aio_read_and_X(connection_struct *conn, NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
struct smb_request *req, struct smb_request *req,
files_struct *fsp, SMB_OFF_T startpos, files_struct *fsp, SMB_OFF_T startpos,
size_t smb_maxcnt) size_t smb_maxcnt)
{ {
return False; return NT_STATUS_RETRY;
} }
bool schedule_aio_write_and_X(connection_struct *conn, NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
struct smb_request *req, struct smb_request *req,
files_struct *fsp, char *data, files_struct *fsp, char *data,
SMB_OFF_T startpos, SMB_OFF_T startpos,
size_t numtowrite) size_t numtowrite)
{ {
return False; return NT_STATUS_RETRY;
} }
void cancel_aio_by_fsp(files_struct *fsp) void cancel_aio_by_fsp(files_struct *fsp)

View File

@ -3698,9 +3698,23 @@ void reply_read_and_X(struct smb_request *req)
} }
if (!big_readX && if (!big_readX) {
schedule_aio_read_and_X(conn, req, fsp, startpos, smb_maxcnt)) { NTSTATUS status = schedule_aio_read_and_X(conn,
goto out; req,
fsp,
startpos,
smb_maxcnt);
if (NT_STATUS_IS_OK(status)) {
/* Read scheduled - we're done. */
goto out;
}
if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
/* Real error - report to client. */
END_PROFILE(SMBreadX);
reply_nterror(req, status);
return;
}
/* NT_STATUS_RETRY - fall back to sync read. */
} }
smbd_lock_socket(smbd_server_conn); smbd_lock_socket(smbd_server_conn);
@ -4320,6 +4334,7 @@ void reply_write_and_X(struct smb_request *req)
unsigned int smblen; unsigned int smblen;
char *data; char *data;
NTSTATUS status; NTSTATUS status;
int saved_errno = 0;
START_PROFILE(SMBwriteX); START_PROFILE(SMBwriteX);
@ -4414,16 +4429,6 @@ void reply_write_and_X(struct smb_request *req)
#endif /* LARGE_SMB_OFF_T */ #endif /* LARGE_SMB_OFF_T */
} }
init_strict_lock_struct(fsp, (uint32)req->smbpid,
(uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
&lock);
if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
END_PROFILE(SMBwriteX);
return;
}
/* X/Open SMB protocol says that, unlike SMBwrite /* X/Open SMB protocol says that, unlike SMBwrite
if the length is zero then NO truncation is if the length is zero then NO truncation is
done, just a write of zero. To truncate a file, done, just a write of zero. To truncate a file,
@ -4432,24 +4437,49 @@ void reply_write_and_X(struct smb_request *req)
if(numtowrite == 0) { if(numtowrite == 0) {
nwritten = 0; nwritten = 0;
} else { } else {
if (req->unread_bytes == 0) {
status = schedule_aio_write_and_X(conn,
req,
fsp,
data,
startpos,
numtowrite);
if ((req->unread_bytes == 0) && if (NT_STATUS_IS_OK(status)) {
schedule_aio_write_and_X(conn, req, fsp, data, startpos, /* write scheduled - we're done. */
numtowrite)) { goto out;
goto strict_unlock; }
if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
/* Real error - report to client. */
reply_nterror(req, status);
goto out;
}
/* NT_STATUS_RETRY - fall through to sync write. */
}
init_strict_lock_struct(fsp, (uint32)req->smbpid,
(uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
&lock);
if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
goto out;
} }
nwritten = write_file(req,fsp,data,startpos,numtowrite); nwritten = write_file(req,fsp,data,startpos,numtowrite);
saved_errno = errno;
SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
} }
if(nwritten < 0) { if(nwritten < 0) {
reply_nterror(req, map_nt_error_from_unix(errno)); reply_nterror(req, map_nt_error_from_unix(saved_errno));
goto strict_unlock; goto out;
} }
if((nwritten == 0) && (numtowrite != 0)) { if((nwritten == 0) && (numtowrite != 0)) {
reply_nterror(req, NT_STATUS_DISK_FULL); reply_nterror(req, NT_STATUS_DISK_FULL);
goto strict_unlock; goto out;
} }
reply_outbuf(req, 6, 0); reply_outbuf(req, 6, 0);
@ -4469,18 +4499,14 @@ void reply_write_and_X(struct smb_request *req)
DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n", DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
fsp_str_dbg(fsp), nt_errstr(status))); fsp_str_dbg(fsp), nt_errstr(status)));
reply_nterror(req, status); reply_nterror(req, status);
goto strict_unlock; goto out;
} }
SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
END_PROFILE(SMBwriteX); END_PROFILE(SMBwriteX);
chain_reply(req); chain_reply(req);
return; return;
strict_unlock: out:
SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
END_PROFILE(SMBwriteX); END_PROFILE(SMBwriteX);
return; return;
} }