1
0
mirror of https://github.com/samba-team/samba.git synced 2025-08-26 01:49:31 +03:00

pvfs_open: retry pvfs_open() after an EGAIN or EWOULDBLOCK from open()

In case a unix application as an oplock or share mode on
a file we need to retry periodicly as there's no way
to get a notification from the kernel when the oplock
is released.

metze
(This used to be commit 4d40f3a026)
This commit is contained in:
Stefan Metzmacher
2008-03-12 14:02:11 +01:00
parent 454e9bed04
commit 50243cdbbd

View File

@ -858,7 +858,13 @@ NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
/* setup a pending lock */
status = odb_open_file_pending(lck, r);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
/*
* maybe only a unix application
* has the file open
*/
data_blob_free(&r->odb_locking_key);
} else if (!NT_STATUS_IS_OK(status)) {
return status;
}
@ -891,8 +897,14 @@ static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
enum pvfs_wait_notice reason)
{
union smb_open *io = talloc_get_type(_io, union smb_open);
struct timeval *final_timeout = NULL;
NTSTATUS status;
if (private_data) {
final_timeout = talloc_get_type(private_data,
struct timeval);
}
/* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
just a bug in their server, but we better do the same */
if (reason == PVFS_WAIT_CANCEL) {
@ -900,6 +912,16 @@ static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
}
if (reason == PVFS_WAIT_TIMEOUT) {
if (final_timeout &&
!timeval_expired(final_timeout)) {
/*
* we need to retry periodictly
* after an EAGAIN as there's
* no way the kernel tell us
* an oplock is released.
*/
goto retry;
}
/* if it timed out, then give the failure
immediately */
talloc_free(r);
@ -908,6 +930,7 @@ static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
return;
}
retry:
talloc_free(r);
/* try the open again, which could trigger another retry setup
@ -1027,6 +1050,7 @@ static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
struct pvfs_state *pvfs = ntvfs->private_data;
NTSTATUS status;
struct timeval end_time;
struct timeval *final_timeout = NULL;
if (io->generic.in.create_options &
(NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
@ -1047,12 +1071,28 @@ static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
} else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
end_time = timeval_add(&req->statistics.request_time,
pvfs->oplock_break_timeout, 0);
} else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
/*
* we got EAGAIN which means a unix application
* has an oplock or share mode
*
* we retry every 4/5 of the sharing violation delay
* to see if the unix application
* has released the oplock or share mode.
*/
final_timeout = talloc(req, struct timeval);
NT_STATUS_HAVE_NO_MEMORY(final_timeout);
*final_timeout = timeval_add(&req->statistics.request_time,
pvfs->oplock_break_timeout,
0);
end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
end_time = timeval_min(final_timeout, &end_time);
} else {
return NT_STATUS_INTERNAL_ERROR;
}
return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
pvfs_retry_open_sharing);
return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
final_timeout, pvfs_retry_open_sharing);
}
/*
@ -1305,8 +1345,18 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
/* do the actual open */
fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
if (fd == -1) {
status = pvfs_map_errno(f->pvfs, errno);
/*
* STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
*/
if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
}
talloc_free(lck);
return pvfs_map_errno(f->pvfs, errno);
return status;
}
f->handle->fd = fd;