From 196028ab7b578526179d4fcff42a5d73ba07ccbb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 9 Jan 2009 14:02:18 +0100 Subject: s3:smbd: restructure kernel oplocks code This converts the irix oplocks code to use a fd event and removes the last special case for file descriptors for the main sys_select(). metze --- source3/smbd/globals.c | 13 +---- source3/smbd/globals.h | 9 +--- source3/smbd/oplock.c | 33 ++++--------- source3/smbd/oplock_irix.c | 118 ++++++++++++++++++++++++++++---------------- source3/smbd/oplock_linux.c | 36 +++++++++----- source3/smbd/process.c | 44 +++-------------- 6 files changed, 117 insertions(+), 136 deletions(-) (limited to 'source3/smbd') 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--; @@ -226,19 +226,6 @@ bool downgrade_oplock(files_struct *fsp) return ret; } -/**************************************************************************** - 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. */ @@ -726,20 +726,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. @@ -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 @@ -865,22 +849,6 @@ static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection * return NT_STATUS_RETRY; } - /* - * 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 @@ -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; } -- cgit