summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/globals.c13
-rw-r--r--source3/smbd/globals.h9
-rw-r--r--source3/smbd/oplock.c33
-rw-r--r--source3/smbd/oplock_irix.c118
-rw-r--r--source3/smbd/oplock_linux.c36
-rw-r--r--source3/smbd/process.c44
6 files changed, 117 insertions, 136 deletions
diff --git a/source3/smbd/globals.c b/source3/smbd/globals.c
index 6fcf18da09..c5681223f9 100644
--- a/source3/smbd/globals.c
+++ b/source3/smbd/globals.c
@@ -175,20 +175,13 @@ char *LastDir = NULL;
#if HAVE_KERNEL_OPLOCKS_LINUX
SIG_ATOMIC_T oplock_signals_received = 0;
SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE];
-struct kernel_oplocks linux_koplocks;
-#endif
-
-#if HAVE_KERNEL_OPLOCKS_IRIX
-int oplock_pipe_write = -1;
-int oplock_pipe_read = -1;
-struct kernel_oplocks irix_koplocks;
#endif
/* Current number of oplocks we have outstanding. */
int32_t exclusive_oplocks_open = 0;
int32_t level_II_oplocks_open = 0;
bool global_client_failed_oplock_break = false;
-const struct kernel_oplocks *koplocks = NULL;
+struct kernel_oplocks *koplocks = NULL;
struct notify_mid_map *notify_changes_by_mid = NULL;
@@ -215,9 +208,5 @@ void smbd_init_globals(void)
#if HAVE_KERNEL_OPLOCKS_LINUX
ZERO_STRUCT(fd_pending_array);
- ZERO_STRUCT(linux_koplocks);
-#endif
-#if HAVE_KERNEL_OPLOCKS_IRIX
- ZERO_STRUCT(irix_koplocks);
#endif
}
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 157089f37c..2c4f8b5821 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -188,20 +188,13 @@ extern char *LastDir;
extern SIG_ATOMIC_T oplock_signals_received;
#define FD_PENDING_SIZE 100
extern SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE];
-extern struct kernel_oplocks linux_koplocks;
-#endif
-
-#if HAVE_KERNEL_OPLOCKS_IRIX
-extern int oplock_pipe_write;
-extern int oplock_pipe_read;
-extern struct kernel_oplocks irix_koplocks;
#endif
/* Current number of oplocks we have outstanding. */
extern int32_t exclusive_oplocks_open;
extern int32_t level_II_oplocks_open;
extern bool global_client_failed_oplock_break;
-extern const struct kernel_oplocks *koplocks;
+extern struct kernel_oplocks *koplocks;
extern struct notify_mid_map *notify_changes_by_mid;
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 3fd5afef22..e4b5016538 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -36,9 +36,9 @@ int32 get_number_of_exclusive_open_oplocks(void)
Return True if an oplock message is pending.
****************************************************************************/
-bool oplock_message_waiting(fd_set *fds)
+bool oplock_message_waiting(void)
{
- if (koplocks && koplocks->msg_waiting(fds)) {
+ if (koplocks && koplocks->ops->msg_waiting(koplocks)) {
return True;
}
@@ -52,7 +52,7 @@ bool oplock_message_waiting(fd_set *fds)
we're calling this in a shutting down state.
****************************************************************************/
-void process_kernel_oplocks(struct messaging_context *msg_ctx, fd_set *pfds)
+void process_kernel_oplocks(struct messaging_context *msg_ctx)
{
/*
* We need to check for kernel oplocks before going into the select
@@ -64,11 +64,11 @@ void process_kernel_oplocks(struct messaging_context *msg_ctx, fd_set *pfds)
return;
}
- while (koplocks->msg_waiting(pfds)) {
+ while (koplocks->ops->msg_waiting(koplocks)) {
files_struct *fsp;
char msg[MSG_SMB_KERNEL_BREAK_SIZE];
- fsp = koplocks->receive_message(pfds);
+ fsp = koplocks->ops->receive_message(koplocks);
if (fsp == NULL) {
DEBUG(3, ("Kernel oplock message announced, but none "
@@ -99,7 +99,7 @@ bool set_file_oplock(files_struct *fsp, int oplock_type)
if ((fsp->oplock_type != NO_OPLOCK) &&
(fsp->oplock_type != FAKE_LEVEL_II_OPLOCK) &&
koplocks &&
- !koplocks->set_oplock(fsp, oplock_type)) {
+ !koplocks->ops->set_oplock(koplocks, fsp, oplock_type)) {
return False;
}
@@ -129,7 +129,7 @@ void release_file_oplock(files_struct *fsp)
if ((fsp->oplock_type != NO_OPLOCK) &&
(fsp->oplock_type != FAKE_LEVEL_II_OPLOCK) &&
koplocks) {
- koplocks->release_oplock(fsp);
+ koplocks->ops->release_oplock(koplocks, fsp);
}
if (fsp->oplock_type == LEVEL_II_OPLOCK) {
@@ -161,7 +161,7 @@ void release_file_oplock(files_struct *fsp)
static void downgrade_file_oplock(files_struct *fsp)
{
if (koplocks) {
- koplocks->release_oplock(fsp);
+ koplocks->ops->release_oplock(koplocks, fsp);
}
fsp->oplock_type = LEVEL_II_OPLOCK;
exclusive_oplocks_open--;
@@ -227,19 +227,6 @@ bool downgrade_oplock(files_struct *fsp)
}
/****************************************************************************
- Return the fd (if any) used for receiving oplock notifications.
-****************************************************************************/
-
-int oplock_notify_fd(void)
-{
- if (koplocks) {
- return koplocks->notification_fd;
- }
-
- return -1;
-}
-
-/****************************************************************************
Set up an oplock break message.
****************************************************************************/
@@ -914,9 +901,9 @@ bool init_oplocks(struct messaging_context *msg_ctx)
if (lp_kernel_oplocks()) {
#if HAVE_KERNEL_OPLOCKS_IRIX
- koplocks = irix_init_kernel_oplocks();
+ koplocks = irix_init_kernel_oplocks(talloc_autofree_context());
#elif HAVE_KERNEL_OPLOCKS_LINUX
- koplocks = linux_init_kernel_oplocks();
+ koplocks = linux_init_kernel_oplocks(talloc_autofree_context());
#endif
}
diff --git a/source3/smbd/oplock_irix.c b/source3/smbd/oplock_irix.c
index 496b0b72ea..0cfa960425 100644
--- a/source3/smbd/oplock_irix.c
+++ b/source3/smbd/oplock_irix.c
@@ -23,6 +23,14 @@
#if HAVE_KERNEL_OPLOCKS_IRIX
+struct irix_oplocks_context {
+ struct kernel_oplocks *ctx;
+ int write_fd;
+ int read_fd;
+ struct fd_event *read_fde;
+ bool pending;
+};
+
/****************************************************************************
Test to see if IRIX kernel oplocks work.
****************************************************************************/
@@ -100,22 +108,27 @@ static bool irix_oplocks_available(void)
* oplock break protocol.
****************************************************************************/
-static files_struct *irix_oplock_receive_message(fd_set *fds)
+static files_struct *irix_oplock_receive_message(struct kernel_oplocks *_ctx)
{
+ struct irix_oplocks_context *ctx = talloc_get_type(_ctx->private_data,
+ struct irix_oplocks_context);
oplock_stat_t os;
char dummy;
struct file_id fileid;
files_struct *fsp;
- /* Ensure we only get one call per select fd set. */
- FD_CLR(oplock_pipe_read, fds);
+ /*
+ * TODO: is it correct to assume we only get one
+ * oplock break, for each byte we read from the pipe?
+ */
+ ctx->pending = false;
/*
* Read one byte of zero to clear the
* kernel break notify message.
*/
- if(read(oplock_pipe_read, &dummy, 1) != 1) {
+ if(read(ctx->read_fd, &dummy, 1) != 1) {
DEBUG(0,("irix_oplock_receive_message: read of kernel "
"notification failed. Error was %s.\n",
strerror(errno) ));
@@ -128,7 +141,7 @@ static files_struct *irix_oplock_receive_message(fd_set *fds)
* request outstanding.
*/
- if(sys_fcntl_ptr(oplock_pipe_read, F_OPLKSTAT, &os) < 0) {
+ if(sys_fcntl_ptr(ctx->read_fd, F_OPLKSTAT, &os) < 0) {
DEBUG(0,("irix_oplock_receive_message: fcntl of kernel "
"notification failed. Error was %s.\n",
strerror(errno) ));
@@ -170,9 +183,13 @@ static files_struct *irix_oplock_receive_message(fd_set *fds)
Attempt to set an kernel oplock on a file.
****************************************************************************/
-static bool irix_set_kernel_oplock(files_struct *fsp, int oplock_type)
+static bool irix_set_kernel_oplock(struct kernel_oplocks *_ctx,
+ files_struct *fsp, int oplock_type)
{
- if (sys_fcntl_long(fsp->fh->fd, F_OPLKREG, oplock_pipe_write) == -1) {
+ struct irix_oplocks_context *ctx = talloc_get_type(_ctx->private_data,
+ struct irix_oplocks_context);
+
+ if (sys_fcntl_long(fsp->fh->fd, F_OPLKREG, ctx->write_fd) == -1) {
if(errno != EAGAIN) {
DEBUG(0,("irix_set_kernel_oplock: Unable to get "
"kernel oplock on file %s, file_id %s "
@@ -204,7 +221,8 @@ static bool irix_set_kernel_oplock(files_struct *fsp, int oplock_type)
Release a kernel oplock on a file.
****************************************************************************/
-static void irix_release_kernel_oplock(files_struct *fsp)
+static void irix_release_kernel_oplock(struct kernel_oplocks *_ctx,
+ files_struct *fsp)
{
if (DEBUGLVL(10)) {
/*
@@ -234,63 +252,77 @@ static void irix_release_kernel_oplock(files_struct *fsp)
}
}
-/****************************************************************************
- See if there is a message waiting in this fd set.
- Note that fds MAY BE NULL ! If so we must do our own select.
-****************************************************************************/
-
-static bool irix_oplock_msg_waiting(fd_set *fds)
+static bool irix_oplock_msg_waiting(struct kernel_oplocks *_ctx)
{
- int selrtn;
- fd_set myfds;
- struct timeval to;
-
- if (oplock_pipe_read == -1)
- return False;
-
- if (fds) {
- return FD_ISSET(oplock_pipe_read, fds);
- }
-
- /* Do a zero-time select. We just need to find out if there
- * are any outstanding messages. We use sys_select_intr as
- * we need to ignore any signals. */
+ struct irix_oplocks_context *ctx = talloc_get_type(_ctx->private_data,
+ struct irix_oplocks_context);
+ return ctx->pending;
+}
- FD_ZERO(&myfds);
- FD_SET(oplock_pipe_read, &myfds);
+static void irix_oplocks_read_fde_handler(struct event_context *ev,
+ struct fd_event *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct irix_oplocks_context *ctx = talloc_get_type(private_data,
+ struct irix_oplocks_context);
- to = timeval_set(0, 0);
- selrtn = sys_select_intr(oplock_pipe_read+1,&myfds,NULL,NULL,&to);
- return (selrtn == 1) ? True : False;
+ ctx->pending = true;
+ process_kernel_oplocks(smbd_messaging_context());
+ ctx->pending = false;
}
/****************************************************************************
Setup kernel oplocks.
****************************************************************************/
-struct kernel_oplocks *irix_init_kernel_oplocks(void)
+static const struct kernel_oplocks_ops irix_koplocks = {
+ .receive_message = irix_oplock_receive_message,
+ .set_oplock = irix_set_kernel_oplock,
+ .release_oplock = irix_release_kernel_oplock,
+ .msg_waiting = irix_oplock_msg_waiting
+};
+
+struct kernel_oplocks *irix_init_kernel_oplocks(TALLOC_CTX *mem_ctx)
{
+ struct kernel_oplocks *_ctx;
+ struct irix_oplocks_context *ctx;
int pfd[2];
if (!irix_oplocks_available())
return NULL;
+ _ctx = talloc_zero(mem_ctx, struct kernel_oplocks);
+ if (!_ctx) {
+ return NULL;
+ }
+
+ ctx = talloc_zero(_ctx, struct irix_oplocks_context);
+ if (!ctx) {
+ talloc_free(_ctx);
+ return NULL;
+ }
+ _ctx->ops = &irix_koplocks;
+ _ctx->private_data = ctx;
+ ctx->ctx = _ctx;
+
if(pipe(pfd) != 0) {
+ talloc_free(_ctx);
DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. "
"Error was %s\n", strerror(errno) ));
return False;
}
- oplock_pipe_read = pfd[0];
- oplock_pipe_write = pfd[1];
-
- irix_koplocks.receive_message = irix_oplock_receive_message;
- irix_koplocks.set_oplock = irix_set_kernel_oplock;
- irix_koplocks.release_oplock = irix_release_kernel_oplock;
- irix_koplocks.msg_waiting = irix_oplock_msg_waiting;
- irix_koplocks.notification_fd = oplock_pipe_read;
+ ctx->read_fd = pfd[0];
+ ctx->write_fd = pfd[1];
- return &irix_koplocks;
+ ctx->read_fde = event_add_fd(smbd_event_context(),
+ ctx,
+ ctx->read_fd,
+ EVENT_FD_READ,
+ irix_oplocks_read_fde_handler,
+ ctx);
+ return _ctx;
}
#else
void oplock_irix_dummy(void);
diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c
index cb37a81fb9..8087167ff4 100644
--- a/source3/smbd/oplock_linux.c
+++ b/source3/smbd/oplock_linux.c
@@ -101,7 +101,7 @@ int linux_setlease(int fd, int leasetype)
* oplock break protocol.
****************************************************************************/
-static files_struct *linux_oplock_receive_message(fd_set *fds)
+static files_struct *linux_oplock_receive_message(struct kernel_oplocks *ctx)
{
int fd;
files_struct *fsp;
@@ -125,7 +125,8 @@ static files_struct *linux_oplock_receive_message(fd_set *fds)
Attempt to set an kernel oplock on a file.
****************************************************************************/
-static bool linux_set_kernel_oplock(files_struct *fsp, int oplock_type)
+static bool linux_set_kernel_oplock(struct kernel_oplocks *ctx,
+ files_struct *fsp, int oplock_type)
{
if ( SMB_VFS_LINUX_SETLEASE(fsp, F_WRLCK) == -1) {
DEBUG(3,("linux_set_kernel_oplock: Refused oplock on file %s, "
@@ -148,7 +149,8 @@ static bool linux_set_kernel_oplock(files_struct *fsp, int oplock_type)
Release a kernel oplock on a file.
****************************************************************************/
-static void linux_release_kernel_oplock(files_struct *fsp)
+static void linux_release_kernel_oplock(struct kernel_oplocks *ctx,
+ files_struct *fsp)
{
if (DEBUGLVL(10)) {
/*
@@ -181,7 +183,7 @@ static void linux_release_kernel_oplock(files_struct *fsp)
See if a oplock message is waiting.
****************************************************************************/
-static bool linux_oplock_msg_waiting(fd_set *fds)
+static bool linux_oplock_msg_waiting(struct kernel_oplocks *ctx)
{
return oplock_signals_received != 0;
}
@@ -205,15 +207,31 @@ static bool linux_oplocks_available(void)
Setup kernel oplocks.
****************************************************************************/
-struct kernel_oplocks *linux_init_kernel_oplocks(void)
+static const struct kernel_oplocks_ops linux_koplocks = {
+ .receive_message = linux_oplock_receive_message,
+ .set_oplock = linux_set_kernel_oplock,
+ .release_oplock = linux_release_kernel_oplock,
+ .msg_waiting = linux_oplock_msg_waiting
+};
+
+struct kernel_oplocks *linux_init_kernel_oplocks(TALLOC_CTX *mem_ctx)
{
struct sigaction act;
+ struct kernel_oplocks *ctx;
if (!linux_oplocks_available()) {
DEBUG(3,("Linux kernel oplocks not available\n"));
return NULL;
}
+ ctx = talloc_zero(mem_ctx, struct kernel_oplocks);
+ if (!ctx) {
+ DEBUG(0,("Linux Kernel oplocks talloc_Zero failed\n"));
+ return NULL;
+ }
+
+ ctx->ops = &linux_koplocks;
+
ZERO_STRUCT(act);
act.sa_handler = NULL;
@@ -225,18 +243,12 @@ struct kernel_oplocks *linux_init_kernel_oplocks(void)
return NULL;
}
- linux_koplocks.receive_message = linux_oplock_receive_message;
- linux_koplocks.set_oplock = linux_set_kernel_oplock;
- linux_koplocks.release_oplock = linux_release_kernel_oplock;
- linux_koplocks.msg_waiting = linux_oplock_msg_waiting;
- linux_koplocks.notification_fd = -1;
-
/* the signal can start off blocked due to a bug in bash */
BlockSignals(False, RT_SIGNAL_LEASE);
DEBUG(3,("Linux kernel oplocks enabled\n"));
- return &linux_koplocks;
+ return ctx;
}
#else
void oplock_linux_dummy(void);
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 7847505f7c..78e66e4620 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -700,13 +700,13 @@ struct idle_event *event_add_idle(struct event_context *event_ctx,
notify events etc.
****************************************************************************/
-static void async_processing(fd_set *pfds)
+static void async_processing(void)
{
DEBUG(10,("async_processing: Doing async processing.\n"));
process_aio_queue();
- process_kernel_oplocks(smbd_messaging_context(), pfds);
+ process_kernel_oplocks(smbd_messaging_context());
/* Do the aio check again after receive_local_message as it does a
select and may have eaten our signal. */
@@ -727,20 +727,6 @@ static void async_processing(fd_set *pfds)
}
/****************************************************************************
- Add a fd to the set we will be select(2)ing on.
-****************************************************************************/
-
-static int select_on_fd(int fd, int maxfd, fd_set *fds)
-{
- if (fd != -1) {
- FD_SET(fd, fds);
- maxfd = MAX(maxfd, fd);
- }
-
- return maxfd;
-}
-
-/****************************************************************************
Do a select on an two fd's - with timeout.
If a local udp message has been pushed onto the
@@ -794,9 +780,9 @@ static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection *
* This is hideously complex - *MUST* be simplified for 3.0 ! JRA.
*/
- if (oplock_message_waiting(&r_fds)) {
+ if (oplock_message_waiting()) {
DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n"));
- async_processing(&r_fds);
+ async_processing();
/*
* After async processing we must go and do the select again, as
* the state of the flag in fds for the server file descriptor is
@@ -827,8 +813,6 @@ static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection *
int sav;
START_PROFILE(smbd_idle);
- maxfd = select_on_fd(oplock_notify_fd(), maxfd, &r_fds);
-
selrtn = sys_select(maxfd+1,&r_fds,&w_fds,NULL,&to);
sav = errno;
@@ -845,7 +829,7 @@ static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection *
is the best we can do until the oplock code knows more about
signals */
if (selrtn == -1 && errno == EINTR) {
- async_processing(&r_fds);
+ async_processing();
/*
* After async processing we must go and do the select again, as
* the state of the flag in fds for the server file descriptor is
@@ -866,22 +850,6 @@ static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection *
}
/*
- * Ensure we process oplock break messages by preference.
- * This is IMPORTANT ! Otherwise we can starve other processes
- * sending us an oplock break message. JRA.
- */
-
- if (oplock_message_waiting(&r_fds)) {
- async_processing(&r_fds);
- /*
- * After async processing we must go and do the select again, as
- * the state of the flag in fds for the server file descriptor is
- * indeterminate - we may have done I/O on it in the oplock processing. JRA.
- */
- return NT_STATUS_RETRY;
- }
-
- /*
* We've just woken up from a protentially long select sleep.
* Ensure we process local messages as we need to synchronously
* process any messages from other smbd's to avoid file rename race
@@ -935,7 +903,7 @@ void respond_to_all_remaining_local_messages(void)
return;
}
- process_kernel_oplocks(smbd_messaging_context(), NULL);
+ process_kernel_oplocks(smbd_messaging_context());
return;
}