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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DBGC_CLASS DBGC_LOCKING
#include "includes.h"
+#include "system/filesys.h"
+#include "smbd/smbd.h"
+#include "smbd/globals.h"
#if HAVE_KERNEL_OPLOCKS_IRIX
-static int oplock_pipe_write = -1;
-static int oplock_pipe_read = -1;
+struct irix_oplocks_context {
+ struct kernel_oplocks *ctx;
+ struct smbd_server_connection *sconn;
+ int write_fd;
+ int read_fd;
+ struct tevent_fd *read_fde;
+ bool pending;
+};
/****************************************************************************
Test to see if IRIX kernel oplocks work.
****************************************************************************/
-static BOOL irix_oplocks_available(void)
+static bool irix_oplocks_available(void)
{
int fd;
int pfd[2];
- pstring tmpname;
+ TALLOC_CTX *ctx = talloc_stackframe();
+ char *tmpname = NULL;
set_effective_capability(KERNEL_OPLOCK_CAPABILITY);
- slprintf(tmpname,sizeof(tmpname)-1, "%s/koplock.%d", lp_lockdir(),
- (int)sys_getpid());
+ tmpname = talloc_asprintf(ctx,
+ "%s/koplock.%d",
+ lp_lock_directory(),
+ (int)getpid());
+ if (!tmpname) {
+ TALLOC_FREE(ctx);
+ return False;
+ }
if(pipe(pfd) != 0) {
DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error "
"was %s\n",
strerror(errno) ));
+ TALLOC_FREE(ctx);
return False;
}
- if((fd = sys_open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) {
+ if((fd = open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) {
DEBUG(0,("check_kernel_oplocks: Unable to open temp test file "
"%s. Error was %s\n",
tmpname, strerror(errno) ));
unlink( tmpname );
close(pfd[0]);
close(pfd[1]);
+ TALLOC_FREE(ctx);
return False;
}
unlink(tmpname);
+ TALLOC_FREE(ctx);
+
if(sys_fcntl_long(fd, F_OPLKREG, pfd[1]) == -1) {
DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not "
"available on this machine. Disabling kernel oplock "
return True;
}
+/*
+ * This is bad because the file_id should always be created through the vfs
+ * layer! Unfortunately, a conn struct isn't available here.
+ */
+static struct file_id file_id_create_dev(SMB_DEV_T dev, SMB_INO_T inode)
+{
+ struct file_id key;
+
+ /* the ZERO_STRUCT ensures padding doesn't break using the key as a
+ * blob */
+ ZERO_STRUCT(key);
+
+ key.devid = dev;
+ key.inode = inode;
+
+ return key;
+}
+
/****************************************************************************
* Deal with the IRIX kernel <--> smbd
* oplock break protocol.
****************************************************************************/
-static files_struct *irix_oplock_receive_message(fd_set *fds)
+static files_struct *irix_oplock_receive_message(struct kernel_oplocks *_ctx)
{
- extern int smb_read_error;
+ 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) ));
- smb_read_error = READ_ERROR;
return NULL;
}
* 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) ));
*/
return NULL;
}
- smb_read_error = READ_ERROR;
return NULL;
}
/*
* We only have device and inode info here - we have to guess that this
* is the first fsp open with this dev,ino pair.
+ *
+ * NOTE: this doesn't work if any VFS modules overloads
+ * the file_id_create() hook!
*/
- if ((fsp = file_find_di_first(
- file_id_create((SMB_DEV_T)os.os_dev,
- (SMB_INO_T)os.os_ino))) == NULL) {
+ fileid = file_id_create_dev((SMB_DEV_T)os.os_dev,
+ (SMB_INO_T)os.os_ino);
+ if ((fsp = file_find_di_first(ctx->sconn, fileid)) == NULL) {
DEBUG(0,("irix_oplock_receive_message: unable to find open "
"file with dev = %x, inode = %.0f\n",
(unsigned int)os.os_dev, (double)os.os_ino ));
DEBUG(5,("irix_oplock_receive_message: kernel oplock break request "
"received for file_id %s gen_id = %ul",
- file_id_static_string(&fsp->file_id),
+ file_id_string_tos(&fsp->file_id),
fsp->fh->gen_id ));
return fsp;
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 "
"gen_id = %ul. Error was %s\n",
- fsp->fsp_name, file_id_static_string(&fsp->file_id),
+ fsp_str_dbg(fsp),
+ file_id_string_tos(&fsp->file_id),
fsp->fh->gen_id,
strerror(errno) ));
} else {
DEBUG(5,("irix_set_kernel_oplock: Refused oplock on "
- "file %s, fd = %d, file_id = 5s, "
+ "file %s, fd = %d, file_id = %s, "
"gen_id = %ul. Another process had the file "
"open.\n",
- fsp->fsp_name, fsp->fh->fd,
- file_id_static_string(&fsp->file_id),
+ fsp_str_dbg(fsp), fsp->fh->fd,
+ file_id_string_tos(&fsp->file_id),
fsp->fh->gen_id ));
}
return False;
DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, file_id = %s "
"gen_id = %ul\n",
- fsp->fsp_name, file_id_static_string(&fsp->file_id),
+ fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id),
fsp->fh->gen_id));
return True;
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, int oplock_type)
{
if (DEBUGLVL(10)) {
/*
int state = sys_fcntl_long(fsp->fh->fd, F_OPLKACK, -1);
dbgtext("irix_release_kernel_oplock: file %s, file_id = %s"
"gen_id = %ul, has kernel oplock state "
- "of %x.\n", fsp->fsp_name, file_id_static_string(&fsp->file_id),
+ "of %x.\n", fsp_str_dbg(fsp),
+ file_id_string_tos(&fsp->file_id),
fsp->fh->gen_id, state );
}
"removing kernel oplock on file " );
dbgtext("%s, file_id = %s gen_id = %ul. "
"Error was %s\n",
- fsp->fsp_name, file_id_static_string(&fsp->file_id),
+ fsp_str_dbg(fsp),
+ file_id_string_tos(&fsp->file_id),
fsp->fh->gen_id,
strerror(errno) );
}
}
}
-/****************************************************************************
- 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 void irix_oplocks_read_fde_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
{
- 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. */
-
- FD_ZERO(&myfds);
- FD_SET(oplock_pipe_read, &myfds);
+ struct irix_oplocks_context *ctx = talloc_get_type(private_data,
+ struct irix_oplocks_context);
+ files_struct *fsp;
- to = timeval_set(0, 0);
- selrtn = sys_select_intr(oplock_pipe_read+1,&myfds,NULL,NULL,&to);
- return (selrtn == 1) ? True : False;
+ fsp = irix_oplock_receive_message(ctx->ctx);
+ break_kernel_oplock(ctx->sconn->msg_ctx, fsp);
}
/****************************************************************************
Setup kernel oplocks.
****************************************************************************/
-struct kernel_oplocks *irix_init_kernel_oplocks(void)
+static const struct kernel_oplocks_ops irix_koplocks = {
+ .set_oplock = irix_set_kernel_oplock,
+ .release_oplock = irix_release_kernel_oplock,
+ .contend_level2_oplocks_begin = NULL,
+ .contend_level2_oplocks_end = NULL,
+};
+
+struct kernel_oplocks *irix_init_kernel_oplocks(struct smbd_server_connection *sconn)
{
+ struct kernel_oplocks *_ctx;
+ struct irix_oplocks_context *ctx;
int pfd[2];
- static struct kernel_oplocks koplocks;
if (!irix_oplocks_available())
return NULL;
+ _ctx = talloc_zero(sconn, 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;
+ ctx->sconn = sconn;
+
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];
-
- koplocks.receive_message = irix_oplock_receive_message;
- koplocks.set_oplock = irix_set_kernel_oplock;
- koplocks.release_oplock = irix_release_kernel_oplock;
- koplocks.msg_waiting = irix_oplock_msg_waiting;
- koplocks.notification_fd = oplock_pipe_read;
+ ctx->read_fd = pfd[0];
+ ctx->write_fd = pfd[1];
- return &koplocks;
+ ctx->read_fde = tevent_add_fd(sconn->ev_ctx,
+ ctx,
+ ctx->read_fd,
+ TEVENT_FD_READ,
+ irix_oplocks_read_fde_handler,
+ ctx);
+ return _ctx;
}
#else
void oplock_irix_dummy(void);