mirror of
https://github.com/samba-team/samba.git
synced 2025-02-28 01:58:17 +03:00
s3: smbd: kernel oplocks. Replace retry_open() with setup_kernel_oplock_poll_open().
If a O_NONBLOCK open fails with EWOULDBLOCK, this code changes smbd to do a retry open every second, until either the timeout or we get a successful open. If we're opening a file that has a kernel lease set by a non-smbd process, this is the best we can do. Prior to this, smbd would block on the second open on such a leased file (not using O_NONBLOCK) which freezes active clients. Regression test to follow. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13121 Signed-off-by: Jeremy Allison <jra@samba.org> Reviewed-by: Ralph Boehme <slow@samba.org>
This commit is contained in:
parent
a0f6ea8dec
commit
47c13fc10a
@ -2410,19 +2410,40 @@ static void defer_open_done(struct tevent_req *req)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reschedule an open for immediate execution
|
||||
* Actually attempt the kernel oplock polling open.
|
||||
*/
|
||||
|
||||
static void kernel_oplock_poll_open_timer(struct tevent_context *ev,
|
||||
struct tevent_timer *te,
|
||||
struct timeval current_time,
|
||||
void *private_data)
|
||||
{
|
||||
bool ok;
|
||||
struct smb_request *req = (struct smb_request *)private_data;
|
||||
|
||||
ok = schedule_deferred_open_message_smb(req->xconn, req->mid);
|
||||
if (!ok) {
|
||||
exit_server("schedule_deferred_open_message_smb failed");
|
||||
}
|
||||
DBG_DEBUG("kernel_oplock_poll_open_timer fired. Retying open !\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reschedule an open for 1 second from now, if not timed out.
|
||||
**/
|
||||
static void retry_open(struct timeval request_time,
|
||||
static void setup_kernel_oplock_poll_open(struct timeval request_time,
|
||||
struct smb_request *req,
|
||||
struct file_id id)
|
||||
{
|
||||
struct deferred_open_record *open_rec = NULL;
|
||||
bool ok;
|
||||
|
||||
DBG_DEBUG("request time [%s] mid [%" PRIu64 "] file_id [%s]\n",
|
||||
timeval_string(talloc_tos(), &request_time, false),
|
||||
req->mid,
|
||||
file_id_string_tos(&id));
|
||||
bool ok;
|
||||
struct deferred_open_record *open_rec = NULL;
|
||||
/* Maximum wait time. */
|
||||
struct timeval timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0);
|
||||
|
||||
if (request_timed_out(request_time, timeout)) {
|
||||
return;
|
||||
}
|
||||
|
||||
open_rec = deferred_open_record_create(false, false, id);
|
||||
if (open_rec == NULL) {
|
||||
@ -2431,17 +2452,30 @@ static void retry_open(struct timeval request_time,
|
||||
|
||||
ok = push_deferred_open_message_smb(req,
|
||||
request_time,
|
||||
timeval_set(0, 0),
|
||||
timeout,
|
||||
id,
|
||||
open_rec);
|
||||
if (!ok) {
|
||||
exit_server("push_deferred_open_message_smb failed");
|
||||
}
|
||||
|
||||
ok = schedule_deferred_open_message_smb(req->xconn, req->mid);
|
||||
if (!ok) {
|
||||
exit_server("schedule_deferred_open_message_smb failed");
|
||||
/*
|
||||
* As this timer event is owned by req, it will
|
||||
* disappear if req it talloc_freed.
|
||||
*/
|
||||
open_rec->te = tevent_add_timer(req->sconn->ev_ctx,
|
||||
req,
|
||||
timeval_current_ofs(1, 0),
|
||||
kernel_oplock_poll_open_timer,
|
||||
req);
|
||||
if (open_rec->te == NULL) {
|
||||
exit_server("tevent_add_timer failed");
|
||||
}
|
||||
|
||||
DBG_DEBUG("poll request time [%s] mid [%" PRIu64 "] file_id [%s]\n",
|
||||
timeval_string(talloc_tos(), &request_time, false),
|
||||
req->mid,
|
||||
file_id_string_tos(&id));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -3160,20 +3194,18 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
|
||||
flags2 &= ~(O_CREAT|O_TRUNC);
|
||||
}
|
||||
|
||||
if (first_open_attempt && lp_kernel_oplocks(SNUM(conn))) {
|
||||
if (lp_kernel_oplocks(SNUM(conn))) {
|
||||
/*
|
||||
* With kernel oplocks the open breaking an oplock
|
||||
* blocks until the oplock holder has given up the
|
||||
* oplock or closed the file. We prevent this by first
|
||||
* oplock or closed the file. We prevent this by always
|
||||
* trying to open the file with O_NONBLOCK (see "man
|
||||
* fcntl" on Linux). For the second try, triggered by
|
||||
* an oplock break response, we do not need this
|
||||
* anymore.
|
||||
* fcntl" on Linux).
|
||||
*
|
||||
* This is true under the assumption that only Samba
|
||||
* requests kernel oplocks. Once someone else like
|
||||
* NFSv4 starts to use that API, we will have to
|
||||
* modify this by communicating with the NFSv4 server.
|
||||
* If a process that doesn't use the smbd open files
|
||||
* database or communication methods holds a kernel
|
||||
* oplock we must periodically poll for available open
|
||||
* using O_NONBLOCK.
|
||||
*/
|
||||
flags2 |= O_NONBLOCK;
|
||||
}
|
||||
@ -3252,9 +3284,16 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
|
||||
|
||||
lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
|
||||
if (lck == NULL) {
|
||||
retry_open(request_time, req, fsp->file_id);
|
||||
DEBUG(10, ("No share mode lock found after "
|
||||
"EWOULDBLOCK, retrying sync\n"));
|
||||
/*
|
||||
* No oplock from Samba around. Set up a poll every 1
|
||||
* second to retry a non-blocking open until the time
|
||||
* expires.
|
||||
*/
|
||||
setup_kernel_oplock_poll_open(request_time,
|
||||
req,
|
||||
fsp->file_id);
|
||||
DBG_DEBUG("No Samba oplock around after EWOULDBLOCK. "
|
||||
"Retrying with poll\n");
|
||||
return NT_STATUS_SHARING_VIOLATION;
|
||||
}
|
||||
|
||||
@ -3275,14 +3314,15 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
|
||||
}
|
||||
|
||||
/*
|
||||
* No oplock from Samba around. Immediately retry with
|
||||
* a blocking open.
|
||||
* No oplock from Samba around. Set up a poll every 1
|
||||
* second to retry a non-blocking open until the time
|
||||
* expires.
|
||||
*/
|
||||
retry_open(request_time, req, fsp->file_id);
|
||||
setup_kernel_oplock_poll_open(request_time, req, fsp->file_id);
|
||||
|
||||
TALLOC_FREE(lck);
|
||||
DEBUG(10, ("No Samba oplock around after EWOULDBLOCK. "
|
||||
"Retrying sync\n"));
|
||||
DBG_DEBUG("No Samba oplock around after EWOULDBLOCK. "
|
||||
"Retrying with poll\n");
|
||||
return NT_STATUS_SHARING_VIOLATION;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user