X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fsmbd%2Foplock_linux.c;h=f796e8c9b817be15d9dea98f20a0d29ea2b4bef1;hb=641a2dea812faf628146145e3d04e411e7d19485;hp=8087167ff44a5d568004cc696f4973486541b390;hpb=1fcd85e8b9235301c7bc6c4c0878e73ddcbd4b16;p=kai%2Fsamba.git diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c index 8087167ff44..f796e8c9b81 100644 --- a/source3/smbd/oplock_linux.c +++ b/source3/smbd/oplock_linux.c @@ -2,23 +2,25 @@ Unix SMB/CIFS implementation. kernel oplock processing for Linux Copyright (C) Andrew Tridgell 2000 - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ #define DBGC_CLASS DBGC_LOCKING #include "includes.h" +#include "system/filesys.h" +#include "smbd/smbd.h" #include "smbd/globals.h" #if HAVE_KERNEL_OPLOCKS_LINUX @@ -43,19 +45,6 @@ #define F_SETSIG 10 #endif -/**************************************************************************** - Handle a LEASE signal, incrementing the signals_received and blocking the signal. -****************************************************************************/ - -static void signal_handler(int sig, siginfo_t *info, void *unused) -{ - if (oplock_signals_received < FD_PENDING_SIZE - 1) { - fd_pending_array[oplock_signals_received] = (SIG_ATOMIC_T)info->si_fd; - oplock_signals_received++; - } /* Else signal is lost. */ - sys_select_signal(RT_SIGNAL_LEASE); -} - /* * public function to get linux lease capability. Needed by some VFS modules (eg. gpfs.c) */ @@ -101,24 +90,27 @@ int linux_setlease(int fd, int leasetype) * oplock break protocol. ****************************************************************************/ -static files_struct *linux_oplock_receive_message(struct kernel_oplocks *ctx) +static void linux_oplock_signal_handler(struct tevent_context *ev_ctx, + struct tevent_signal *se, + int signum, int count, + void *_info, void *private_data) { - int fd; + struct kernel_oplocks *ctx = + talloc_get_type_abort(private_data, + struct kernel_oplocks); + struct smbd_server_connection *sconn = + talloc_get_type_abort(ctx->private_data, + struct smbd_server_connection); + siginfo_t *info = (siginfo_t *)_info; + int fd = info->si_fd; files_struct *fsp; - BlockSignals(True, RT_SIGNAL_LEASE); - fd = fd_pending_array[0]; - fsp = file_find_fd(fd); - fd_pending_array[0] = (SIG_ATOMIC_T)-1; - if (oplock_signals_received > 1) - memmove(CONST_DISCARD(void *, &fd_pending_array[0]), - CONST_DISCARD(void *, &fd_pending_array[1]), - sizeof(SIG_ATOMIC_T)*(oplock_signals_received-1)); - oplock_signals_received--; - /* now we can receive more signals */ - BlockSignals(False, RT_SIGNAL_LEASE); - - return fsp; + fsp = file_find_fd(sconn, fd); + if (fsp == NULL) { + DEBUG(0,("linux_oplock_signal_handler: failed to find fsp for file fd=%d (file was closed ?)\n", fd )); + return; + } + break_kernel_oplock(sconn->msg_ctx, fsp); } /**************************************************************************** @@ -131,7 +123,7 @@ static bool linux_set_kernel_oplock(struct kernel_oplocks *ctx, if ( SMB_VFS_LINUX_SETLEASE(fsp, F_WRLCK) == -1) { DEBUG(3,("linux_set_kernel_oplock: Refused oplock on file %s, " "fd = %d, file_id = %s. (%s)\n", - fsp->fsp_name, fsp->fh->fd, + fsp_str_dbg(fsp), fsp->fh->fd, file_id_string_tos(&fsp->file_id), strerror(errno))); return False; @@ -139,7 +131,7 @@ static bool linux_set_kernel_oplock(struct kernel_oplocks *ctx, DEBUG(3,("linux_set_kernel_oplock: got kernel oplock on file %s, " "file_id = %s gen_id = %lu\n", - fsp->fsp_name, file_id_string_tos(&fsp->file_id), + fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id), fsp->fh->gen_id)); return True; @@ -150,7 +142,7 @@ static bool linux_set_kernel_oplock(struct kernel_oplocks *ctx, ****************************************************************************/ static void linux_release_kernel_oplock(struct kernel_oplocks *ctx, - files_struct *fsp) + files_struct *fsp, int oplock_type) { if (DEBUGLVL(10)) { /* @@ -160,7 +152,8 @@ static void linux_release_kernel_oplock(struct kernel_oplocks *ctx, int state = fcntl(fsp->fh->fd, F_GETLEASE, 0); dbgtext("linux_release_kernel_oplock: file %s, file_id = %s " "gen_id = %lu has kernel oplock state " - "of %x.\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id), + "of %x.\n", fsp_str_dbg(fsp), + file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, state ); } @@ -172,22 +165,13 @@ static void linux_release_kernel_oplock(struct kernel_oplocks *ctx, dbgtext("linux_release_kernel_oplock: Error when " "removing kernel oplock on file " ); dbgtext("%s, file_id = %s, gen_id = %lu. " - "Error was %s\n", fsp->fsp_name, + "Error was %s\n", fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, strerror(errno) ); } } } -/**************************************************************************** - See if a oplock message is waiting. -****************************************************************************/ - -static bool linux_oplock_msg_waiting(struct kernel_oplocks *ctx) -{ - return oplock_signals_received != 0; -} - /**************************************************************************** See if the kernel supports oplocks. ****************************************************************************/ @@ -208,43 +192,43 @@ static bool linux_oplocks_available(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 + .set_oplock = linux_set_kernel_oplock, + .release_oplock = linux_release_kernel_oplock, + .contend_level2_oplocks_begin = NULL, + .contend_level2_oplocks_end = NULL, }; -struct kernel_oplocks *linux_init_kernel_oplocks(TALLOC_CTX *mem_ctx) +struct kernel_oplocks *linux_init_kernel_oplocks(struct smbd_server_connection *sconn) { - struct sigaction act; struct kernel_oplocks *ctx; + struct tevent_signal *se; if (!linux_oplocks_available()) { DEBUG(3,("Linux kernel oplocks not available\n")); return NULL; } - ctx = talloc_zero(mem_ctx, struct kernel_oplocks); + ctx = talloc_zero(sconn, 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; - act.sa_sigaction = signal_handler; - act.sa_flags = SA_SIGINFO; - sigemptyset( &act.sa_mask ); - if (sigaction(RT_SIGNAL_LEASE, &act, NULL) != 0) { - DEBUG(0,("Failed to setup RT_SIGNAL_LEASE handler\n")); + ctx->private_data = sconn; + + se = tevent_add_signal(sconn->ev_ctx, + ctx, + RT_SIGNAL_LEASE, SA_SIGINFO, + linux_oplock_signal_handler, + ctx); + if (!se) { + DEBUG(0,("Failed to setup RT_SIGNAL_LEASE handler")); + TALLOC_FREE(ctx); return NULL; } - /* the signal can start off blocked due to a bug in bash */ - BlockSignals(False, RT_SIGNAL_LEASE); + ctx->private_data = se; DEBUG(3,("Linux kernel oplocks enabled\n"));