OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o
-NOTIFY_OBJ = smbd/notify.o smbd/notify_hash.o
+NOTIFY_OBJ = smbd/notify.o smbd/notify_hash.o smbd/notify_kernel.o
SMBD_OBJ1 = smbd/server.o smbd/files.o smbd/chgpasswd.o smbd/connection.o \
smbd/dfree.o smbd/dir.o smbd/password.o smbd/conn.o smbd/fileio.o \
****************************************************************************/
BOOL init_change_notify(void)
{
- cnotify = hash_notify_init();
+#if HAVE_KERNEL_CHANGE_NOTIFY
+ cnotify = kernel_notify_init();
+#endif
+ if (!cnotify) cnotify = hash_notify_init();
if (!cnotify) {
DEBUG(0,("Failed to init change notify system\n"));
#define RT_SIGNAL_NOTIFY 34
#endif
+#ifndef F_SETSIG
+#define F_SETSIG 10
+#endif
+
+#ifndef F_NOTIFY
+#define F_NOTIFY 1026
+#endif
+
/****************************************************************************
This is the structure to keep the information needed to
determine if a directory has changed.
if (data->directory_handle != fd_pending) return False;
+ DEBUG(3,("kernel change notify on %s fd=%d\n", path, fd_pending));
+
close(fd_pending);
data->directory_handle = fd_pending = -1;
signals_processed++;
static void kernel_remove_notify(void *datap)
{
struct change_data *data = (struct change_data *)datap;
- if (data->directory_handle != -1) {
- if (data->directory_handle == fd_pending) {
- data->directory_handle = fd_pending = -1;
+ int fd = data->directory_handle;
+ if (fd != -1) {
+ if (fd == fd_pending) {
+ fd_pending = -1;
signals_processed++;
BlockSignals(False, RT_SIGNAL_NOTIFY);
}
- close(data->directory_handle);
+ close(fd);
}
free(data);
+ DEBUG(3,("removed kernel change notify fd=%d\n", fd));
}
int fd;
unsigned long kernel_flags;
- fd = dos_open(fsp->fsp_name, O_RDONLY, 0);
+ fd = dos_open(path, O_RDONLY, 0);
if (fd == -1) {
- DEBUG(3,("Failed to open directory %s for change notify\n", fsp->fsp_name));
+ DEBUG(3,("Failed to open directory %s for change notify\n", path));
return NULL;
}
}
kernel_flags = 0;
- if (flags & FILE_NOTIFY_CHANGE_FILE_NAME) kernel_flags |= DN_RENAME;
- if (flags & FILE_NOTIFY_CHANGE_DIR_NAME) kernel_flags |= DN_RENAME;
+ if (flags & FILE_NOTIFY_CHANGE_FILE_NAME) kernel_flags |= DN_RENAME|DN_DELETE;
+ if (flags & FILE_NOTIFY_CHANGE_DIR_NAME) kernel_flags |= DN_RENAME|DN_DELETE;
if (flags & FILE_NOTIFY_CHANGE_ATTRIBUTES) kernel_flags |= DN_MODIFY;
if (flags & FILE_NOTIFY_CHANGE_SIZE) kernel_flags |= DN_MODIFY;
if (flags & FILE_NOTIFY_CHANGE_LAST_WRITE) kernel_flags |= DN_MODIFY;
return NULL;
}
+ if (fcntl(fd, F_SETOWN, sys_getpid()) == -1) {
+ DEBUG(3,("Failed to set owner for change notify\n"));
+ return NULL;
+ }
+
data.directory_handle = fd;
+ DEBUG(3,("kernel change notify on %s (flags=0x%x) fd=%d\n",
+ path, (int)kernel_flags, fd));
+
return (void *)memdup(&data, sizeof(data));
}
+/****************************************************************************
+see if the kernel supports change notify
+****************************************************************************/
+static BOOL kernel_notify_available(void)
+{
+ int fd, ret;
+ fd = open("/tmp", O_RDONLY);
+ if (fd == -1) return False; /* uggh! */
+ ret = fcntl(fd, F_NOTIFY, 0);
+ close(fd);
+ return ret == 0 || errno != EINVAL;
+}
+
/****************************************************************************
setup kernel based change notify
static struct cnotify_fns cnotify;
struct sigaction act;
+ if (!kernel_notify_available()) return NULL;
+
act.sa_handler = NULL;
act.sa_sigaction = signal_handler;
act.sa_flags = SA_SIGINFO;
#define RT_SIGNAL_LEASE 33
#endif
+#ifndef F_SETSIG
+#define F_SETSIG 10
+#endif
+
/****************************************************************************
handle a LEASE signal, incrementing the signals_received and blocking the signal
****************************************************************************/
/****************************************************************************
try to gain a linux capability
-****************************************************************************/
-static void set_capability(unsigned capability)
+****************************************************************************/static void set_capability(unsigned capability)
{
#ifndef _LINUX_CAPABILITY_VERSION
#define _LINUX_CAPABILITY_VERSION 0x19980330
static int linux_setlease(int fd, int leasetype)
{
int ret;
+
+ if (fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE) == -1) {
+ DEBUG(3,("Failed to set signal handler for kernel lease\n"));
+ return -1;
+ }
+
ret = fcntl(fd, F_SETLEASE, leasetype);
if (ret == -1 && errno == EACCES) {
set_capability(CAP_LEASE);
dev = sbuf.st_dev;
inode = sbuf.st_ino;
- DEBUG(5,("receive_local_message: kernel oplock break request received for \
+ DEBUG(3,("receive_local_message: kernel oplock break request received for \
dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
/*
static BOOL linux_set_kernel_oplock(files_struct *fsp, int oplock_type)
{
if (linux_setlease(fsp->fd, F_WRLCK) == -1) {
- DEBUG(5,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
+ DEBUG(3,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
inode = %.0f. (%s)\n",
fsp->fsp_name, fsp->fd,
(unsigned int)fsp->dev, (double)fsp->inode, strerror(errno)));
return False;
}
- DEBUG(10,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f\n",
+ DEBUG(3,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f\n",
fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode));
return True;
memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode));
memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev));
- DEBUG(5,("kernel oplock break request for file dev = %x, inode = %.0f\n",
+ DEBUG(3,("kernel oplock break request for file dev = %x, inode = %.0f\n",
(unsigned int)*dev, (double)*inode));
return True;
koplocks.msg_waiting = linux_oplock_msg_waiting;
koplocks.notification_fd = -1;
+ DEBUG(3,("Linux kernel oplocks enabled\n"));
+
return &koplocks;
}