mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +03:00
totally rewrote the async signal, notification and oplock notification
handling in Samba. This was needed due to several limitations and races in the previous code - as a side effect the new code is much cleaner :) in summary: - changed sys_select() to avoid a signal/select race condition. It is a rare race but once we have signals doing notification and oplocks it is important. - changed our main processing loop to take advantage of the new sys_select semantics - split the notify code into implementaion dependent and general parts. Added the following structure that defines an implementation: struct cnotify_fns { void * (*register_notify)(connection_struct *conn, char *path, uint32 flags); BOOL (*check_notify)(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *data, time_t t); void (*remove_notify)(void *data); }; then I wrote two implementations, one using hash/poll (like our old code) and the other using the new Linux kernel change notify. It should be easy to add other change notify implementations by creating a sructure of the above type. - fixed a bug in change notify where we were returning the wrong error code. - rewrote the core change notify code to be much simpler - moved to real-time signals for leases and change notify Amazingly, it all seems to work. I was very surprised!
This commit is contained in:
parent
abf06fa90b
commit
44766c39e0
@ -108,7 +108,7 @@ LIB_OBJ = lib/charcnv.o lib/charset.o lib/debug.o lib/fault.o \
|
||||
lib/util_unistr.o lib/util_file.o \
|
||||
lib/util.o lib/util_sock.o lib/util_sec.o smbd/ssl.o \
|
||||
lib/talloc.o lib/hash.o lib/substitute.o lib/fsusage.o \
|
||||
lib/ms_fnmatch.o lib/util_seaccess.o \
|
||||
lib/ms_fnmatch.o lib/util_seaccess.o lib/select.o \
|
||||
$(TDB_OBJ)
|
||||
|
||||
UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \
|
||||
@ -159,10 +159,12 @@ PROFILE_OBJ = profile/profile.o
|
||||
|
||||
OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o
|
||||
|
||||
NOTIFY_OBJ = smbd/notify.o smbd/notify_hash.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 \
|
||||
smbd/ipc.o smbd/lanman.o smbd/mangle.o smbd/negprot.o \
|
||||
smbd/message.o smbd/nttrans.o smbd/notify.o smbd/pipes.o \
|
||||
smbd/message.o smbd/nttrans.o smbd/pipes.o \
|
||||
smbd/reply.o smbd/trans2.o smbd/uid.o \
|
||||
smbd/dosmode.o smbd/filename.o smbd/open.o smbd/close.o smbd/blocking.o \
|
||||
smbd/vfs.o smbd/vfs-wrap.o smbd/statcache.o \
|
||||
@ -180,7 +182,7 @@ MSDFS_OBJ = msdfs/msdfs.o
|
||||
SMBD_OBJ = $(SMBD_OBJ1) $(MSDFS_OBJ) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \
|
||||
$(RPC_SERVER_OBJ) $(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) \
|
||||
$(LOCKING_OBJ) $(PASSDB_OBJ) $(PRINTING_OBJ) $(PROFILE_OBJ) $(LIB_OBJ) \
|
||||
$(PRINTBACKEND_OBJ) $(QUOTAOBJS) $(OPLOCK_OBJ)
|
||||
$(PRINTBACKEND_OBJ) $(QUOTAOBJS) $(OPLOCK_OBJ) $(NOTIFY_OBJ)
|
||||
|
||||
|
||||
NMBD_OBJ1 = nmbd/asyncdns.o nmbd/nmbd.o nmbd/nmbd_become_dmb.o \
|
||||
|
2
source/configure
vendored
2
source/configure
vendored
@ -4680,7 +4680,7 @@ else
|
||||
fi
|
||||
done
|
||||
|
||||
for ac_func in initgroups select rdchk getgrnam getgrent pathconf
|
||||
for ac_func in initgroups select poll rdchk getgrnam getgrent pathconf
|
||||
do
|
||||
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
|
||||
echo "configure:4687: checking for $ac_func" >&5
|
||||
|
@ -361,7 +361,7 @@ AC_CHECK_FUNCS(waitpid getcwd strdup strtoul strerror chown chmod chroot)
|
||||
AC_CHECK_FUNCS(fstat strchr utime utimes getrlimit fsync bzero memset)
|
||||
AC_CHECK_FUNCS(memmove vsnprintf snprintf setsid glob strpbrk pipe crypt16 getauthuid)
|
||||
AC_CHECK_FUNCS(strftime sigprocmask sigblock sigaction innetgr setnetgrent getnetgrent endnetgrent)
|
||||
AC_CHECK_FUNCS(initgroups select rdchk getgrnam getgrent pathconf)
|
||||
AC_CHECK_FUNCS(initgroups select poll rdchk getgrnam getgrent pathconf)
|
||||
AC_CHECK_FUNCS(setpriv setgidx setuidx setgroups sysconf mktime rename ftruncate stat64 fstat64)
|
||||
AC_CHECK_FUNCS(lstat64 fopen64 atexit grantpt dup2 lseek64 ftruncate64 readdir64)
|
||||
AC_CHECK_FUNCS(fseek64 fseeko64 ftell64 ftello64 setluid yp_get_default_domain getpwanam)
|
||||
|
@ -544,6 +544,9 @@
|
||||
/* Define if you have the pipe function. */
|
||||
#undef HAVE_PIPE
|
||||
|
||||
/* Define if you have the poll function. */
|
||||
#undef HAVE_POLL
|
||||
|
||||
/* Define if you have the pread function. */
|
||||
#undef HAVE_PREAD
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#define ERROR_INVALID_PARAMETER (87)
|
||||
#define ERROR_INSUFFICIENT_BUFFER (122)
|
||||
#define STATUS_1804 (1804)
|
||||
#define STATUS_NOTIFY_ENUM_DIR (0x10C)
|
||||
|
||||
|
||||
/* these are the NT error codes less than 1000. They are here for when
|
||||
@ -514,5 +515,4 @@
|
||||
#define NT_STATUS_TOO_MANY_LINKS (0xC0000000 | 613)
|
||||
#define NT_STATUS_QUOTA_LIST_INCONSISTENT (0xC0000000 | 614)
|
||||
#define NT_STATUS_FILE_IS_OFFLINE (0xC0000000 | 615)
|
||||
#define NT_STATUS_NOTIFY_ENUM_DIR (0xC0000000 | 0x10C)
|
||||
#define NT_STATUS_NO_SUCH_JOB (0xC0000000 | 0xEDE) /* scheduler */
|
||||
|
@ -183,6 +183,12 @@ void pidfile_create(char *name);
|
||||
|
||||
char *rep_inet_ntoa(struct in_addr ip);
|
||||
|
||||
/*The following definitions come from lib/select.c */
|
||||
|
||||
void sys_select_signal(void);
|
||||
int sys_select(int maxfd, fd_set *fds,struct timeval *tval);
|
||||
int sys_select_intr(int maxfd, fd_set *fds,struct timeval *tval);
|
||||
|
||||
/*The following definitions come from lib/signal.c */
|
||||
|
||||
void BlockSignals(BOOL block,int signum);
|
||||
@ -212,9 +218,6 @@ void standard_sub_vsnum(char *str, user_struct *vuser, int snum);
|
||||
|
||||
/*The following definitions come from lib/system.c */
|
||||
|
||||
int sys_select(int maxfd, fd_set *fds,struct timeval *tval);
|
||||
int sys_select(int maxfd, fd_set *fds,struct timeval *tval);
|
||||
int sys_select_intr(int maxfd, fd_set *fds,struct timeval *tval);
|
||||
int sys_usleep(long usecs);
|
||||
int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf);
|
||||
int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf);
|
||||
@ -3251,9 +3254,16 @@ BOOL disk_quotas(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT
|
||||
void remove_pending_change_notify_requests_by_fid(files_struct *fsp);
|
||||
void remove_pending_change_notify_requests_by_mid(int mid);
|
||||
void remove_pending_change_notify_requests_by_filename(files_struct *fsp);
|
||||
BOOL process_pending_change_notify_queue(time_t t);
|
||||
BOOL change_notifies_pending(void);
|
||||
BOOL process_pending_change_notify_queue(time_t t);
|
||||
BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn, uint32 flags);
|
||||
BOOL init_change_notify(void);
|
||||
#endif
|
||||
|
||||
/*The following definitions come from smbd/notify_hash.c */
|
||||
|
||||
#if OLD_NTDOMAIN
|
||||
struct cnotify_fns *hash_notify_init(void) ;
|
||||
#endif
|
||||
|
||||
/*The following definitions come from smbd/nttrans.c */
|
||||
@ -3301,6 +3311,18 @@ BOOL attempt_close_oplocked_file(files_struct *fsp);
|
||||
BOOL init_oplocks(void);
|
||||
#endif
|
||||
|
||||
/*The following definitions come from smbd/oplock_irix.c */
|
||||
|
||||
#if OLD_NTDOMAIN
|
||||
struct kernel_oplocks *irix_init_kernel_oplocks(void) ;
|
||||
#endif
|
||||
|
||||
/*The following definitions come from smbd/oplock_linux.c */
|
||||
|
||||
#if OLD_NTDOMAIN
|
||||
struct kernel_oplocks *linux_init_kernel_oplocks(void) ;
|
||||
#endif
|
||||
|
||||
/*The following definitions come from smbd/password.c */
|
||||
|
||||
#if OLD_NTDOMAIN
|
||||
|
@ -1636,6 +1636,16 @@ struct kernel_oplocks {
|
||||
|
||||
#define CMD_REPLY 0x8000
|
||||
|
||||
/* this structure defines the functions for doing change notify in
|
||||
various implementations */
|
||||
struct cnotify_fns {
|
||||
void * (*register_notify)(connection_struct *conn, char *path, uint32 flags);
|
||||
BOOL (*check_notify)(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *data, time_t t);
|
||||
void (*remove_notify)(void *data);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#include "smb_macros.h"
|
||||
|
||||
/* A netbios name structure. */
|
||||
|
@ -132,6 +132,8 @@ void sig_usr2( int sig )
|
||||
|
||||
DEBUG( 0, ( "Got SIGUSR2; set debug level to %d.\n", DEBUGLEVEL ) );
|
||||
|
||||
sys_select_signal();
|
||||
|
||||
#if !defined(HAVE_SIGACTION)
|
||||
CatchSignal( SIGUSR2, SIGNAL_CAST sig_usr2 );
|
||||
#endif
|
||||
@ -154,6 +156,8 @@ void sig_usr1( int sig )
|
||||
|
||||
DEBUG( 0, ( "Got SIGUSR1; set debug level to %d.\n", DEBUGLEVEL ) );
|
||||
|
||||
sys_select_signal();
|
||||
|
||||
#if !defined(HAVE_SIGACTION)
|
||||
CatchSignal( SIGUSR1, SIGNAL_CAST sig_usr1 );
|
||||
#endif
|
||||
|
@ -39,115 +39,6 @@ extern int DEBUGLEVEL;
|
||||
*/
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
this replaces the normal select() system call
|
||||
return if some data has arrived on one of the file descriptors
|
||||
return -1 means error
|
||||
********************************************************************/
|
||||
#ifndef HAVE_SELECT
|
||||
static int pollfd(int fd)
|
||||
{
|
||||
int r=0;
|
||||
|
||||
#ifdef HAS_RDCHK
|
||||
r = rdchk(fd);
|
||||
#elif defined(TCRDCHK)
|
||||
(void)ioctl(fd, TCRDCHK, &r);
|
||||
#else
|
||||
(void)ioctl(fd, FIONREAD, &r);
|
||||
#endif
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
||||
int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
|
||||
{
|
||||
fd_set fds2;
|
||||
int counter=0;
|
||||
int found=0;
|
||||
|
||||
FD_ZERO(&fds2);
|
||||
|
||||
while (1)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<maxfd;i++) {
|
||||
if (FD_ISSET(i,fds) && pollfd(i)>0) {
|
||||
found++;
|
||||
FD_SET(i,&fds2);
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
memcpy((void *)fds,(void *)&fds2,sizeof(fds2));
|
||||
return(found);
|
||||
}
|
||||
|
||||
if (tval && tval->tv_sec < counter) return(0);
|
||||
sleep(1);
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !NO_SELECT */
|
||||
int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
|
||||
{
|
||||
#ifdef USE_POLL
|
||||
struct pollfd pfd[256];
|
||||
int i;
|
||||
int maxpoll;
|
||||
int timeout;
|
||||
int pollrtn;
|
||||
|
||||
maxpoll = 0;
|
||||
for( i = 0; i < maxfd; i++) {
|
||||
if(FD_ISSET(i,fds)) {
|
||||
struct pollfd *pfdp = &pfd[maxpoll++];
|
||||
pfdp->fd = i;
|
||||
pfdp->events = POLLIN;
|
||||
pfdp->revents = 0;
|
||||
}
|
||||
}
|
||||
|
||||
timeout = (tval != NULL) ? (tval->tv_sec * 1000) + (tval->tv_usec/1000) :
|
||||
-1;
|
||||
errno = 0;
|
||||
pollrtn = poll( &pfd[0], maxpoll, timeout);
|
||||
|
||||
FD_ZERO(fds);
|
||||
|
||||
for( i = 0; i < maxpoll; i++)
|
||||
if( pfd[i].revents & POLLIN )
|
||||
FD_SET(pfd[i].fd,fds);
|
||||
|
||||
return pollrtn;
|
||||
#else /* USE_POLL */
|
||||
|
||||
struct timeval t2;
|
||||
int selrtn;
|
||||
|
||||
if (tval) memcpy((void *)&t2,(void *)tval,sizeof(t2));
|
||||
errno = 0;
|
||||
selrtn = select(maxfd,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
|
||||
|
||||
return(selrtn);
|
||||
}
|
||||
#endif /* USE_POLL */
|
||||
#endif /* NO_SELECT */
|
||||
|
||||
/*******************************************************************
|
||||
similar to sys_select() but catch EINTR and continue
|
||||
this is what sys_select() used to do in Samba
|
||||
********************************************************************/
|
||||
int sys_select_intr(int maxfd, fd_set *fds,struct timeval *tval)
|
||||
{
|
||||
int ret;
|
||||
do {
|
||||
ret = sys_select(maxfd, fds, tval);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
A wrapper for usleep in case we don't have one.
|
||||
|
@ -3,8 +3,8 @@
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 3.0
|
||||
change notify handling
|
||||
Copyright (C) Jeremy Allison 1994-1998
|
||||
Copyright (C) Andrew Tridgell 2000
|
||||
Copyright (C) Jeremy Allison 1994-1998
|
||||
|
||||
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
|
||||
@ -25,320 +25,120 @@
|
||||
|
||||
extern int DEBUGLEVEL;
|
||||
|
||||
/****************************************************************************
|
||||
This is the structure to keep the information needed to
|
||||
determine if a directory has changed.
|
||||
*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
time_t modify_time; /* Info from the directory we're monitoring. */
|
||||
time_t status_time; /* Info from the directory we're monitoring. */
|
||||
time_t total_time; /* Total time of all directory entries - don't care if it wraps. */
|
||||
unsigned int num_entries; /* Zero or the number of files in the directory. */
|
||||
} change_hash_data;
|
||||
static struct cnotify_fns *cnotify;
|
||||
|
||||
/****************************************************************************
|
||||
This is the structure to queue to implement NT change
|
||||
notify. It consists of smb_size bytes stored from the
|
||||
transact command (to keep the mid, tid etc around).
|
||||
Plus the fid to examine and the time to check next.
|
||||
Plus the fid to examine and notify private data
|
||||
*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
ubi_slNode msg_next;
|
||||
files_struct *fsp;
|
||||
connection_struct *conn;
|
||||
uint32 flags;
|
||||
time_t next_check_time;
|
||||
change_hash_data change_data;
|
||||
char request_buf[smb_size];
|
||||
} change_notify_buf;
|
||||
struct change_notify {
|
||||
struct change_notify *next, *prev;
|
||||
files_struct *fsp;
|
||||
connection_struct *conn;
|
||||
uint32 flags;
|
||||
char request_buf[smb_size];
|
||||
void *change_data;
|
||||
};
|
||||
|
||||
static ubi_slList change_notify_queue = { NULL, (ubi_slNodePtr)&change_notify_queue, 0};
|
||||
static struct change_notify *change_notify_list;
|
||||
|
||||
/****************************************************************************
|
||||
Setup the common parts of the return packet and send it.
|
||||
*****************************************************************************/
|
||||
|
||||
static void change_notify_reply_packet(char *inbuf, int error_class, uint32 error_code)
|
||||
static void change_notify_reply_packet(char *inbuf, uint32 error_code)
|
||||
{
|
||||
char outbuf[smb_size+38];
|
||||
char outbuf[smb_size+38];
|
||||
|
||||
memset(outbuf, '\0', sizeof(outbuf));
|
||||
construct_reply_common(inbuf, outbuf);
|
||||
memset(outbuf, '\0', sizeof(outbuf));
|
||||
construct_reply_common(inbuf, outbuf);
|
||||
|
||||
/*
|
||||
* If we're returning a 'too much in the directory changed' we need to
|
||||
* set this is an NT error status flags. If we don't then the (probably
|
||||
* untested) code in the NT redirector has a bug in that it doesn't re-issue
|
||||
* the change notify.... Ah - I *love* it when I get so deeply into this I
|
||||
* can even determine how MS failed to test stuff and why.... :-). JRA.
|
||||
*/
|
||||
/*
|
||||
* If we're returning a 'too much in the directory changed' we need to
|
||||
* set this is an NT error status flags. If we don't then the (probably
|
||||
* untested) code in the NT redirector has a bug in that it doesn't re-issue
|
||||
* the change notify.... Ah - I *love* it when I get so deeply into this I
|
||||
* can even determine how MS failed to test stuff and why.... :-). JRA.
|
||||
*/
|
||||
|
||||
SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
|
||||
ERROR(0,error_code);
|
||||
|
||||
if(error_class == 0) /* NT Error. */
|
||||
SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
|
||||
/*
|
||||
* Seems NT needs a transact command with an error code
|
||||
* in it. This is a longer packet than a simple error.
|
||||
*/
|
||||
set_message(outbuf,18,0,False);
|
||||
|
||||
ERROR(error_class,error_code);
|
||||
|
||||
/*
|
||||
* Seems NT needs a transact command with an error code
|
||||
* in it. This is a longer packet than a simple error.
|
||||
*/
|
||||
set_message(outbuf,18,0,False);
|
||||
|
||||
send_smb(smbd_server_fd(),outbuf);
|
||||
send_smb(smbd_server_fd(),outbuf);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Create the hash we will use to determine if the contents changed.
|
||||
remove an entry from the list and free it, also closing any
|
||||
directory handle if necessary
|
||||
Notice the horrible stuff we have to do because this is a singly linked list.
|
||||
*****************************************************************************/
|
||||
|
||||
static BOOL create_directory_notify_hash( change_notify_buf *cnbp, change_hash_data *change_data)
|
||||
static void change_notify_remove(struct change_notify *cnbp)
|
||||
{
|
||||
SMB_STRUCT_STAT st;
|
||||
files_struct *fsp = cnbp->fsp;
|
||||
|
||||
memset((char *)change_data, '\0', sizeof(change_data));
|
||||
|
||||
/*
|
||||
* Store the current timestamp on the directory we are monitoring.
|
||||
*/
|
||||
|
||||
if(dos_stat(fsp->fsp_name, &st) < 0) {
|
||||
DEBUG(0,("create_directory_notify_hash: Unable to stat name = %s. \
|
||||
Error was %s\n", fsp->fsp_name, strerror(errno) ));
|
||||
return False;
|
||||
}
|
||||
|
||||
change_data->modify_time = st.st_mtime;
|
||||
change_data->status_time = st.st_ctime;
|
||||
|
||||
/*
|
||||
* If we are to watch for changes that are only stored
|
||||
* in inodes of files, not in the directory inode, we must
|
||||
* scan the directory and produce a unique identifier with
|
||||
* which we can determine if anything changed. We use the
|
||||
* modify and change times from all the files in the
|
||||
* directory, added together (ignoring wrapping if it's
|
||||
* larger than the max time_t value).
|
||||
*/
|
||||
|
||||
if(cnbp->flags & (FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE)) {
|
||||
pstring full_name;
|
||||
char *p;
|
||||
char *fname;
|
||||
size_t remaining_len;
|
||||
size_t fullname_len;
|
||||
void *dp = OpenDir(cnbp->conn, fsp->fsp_name, True);
|
||||
|
||||
if(dp == NULL) {
|
||||
DEBUG(0,("create_directory_notify_hash: Unable to open directory = %s. \
|
||||
Error was %s\n", fsp->fsp_name, strerror(errno) ));
|
||||
return False;
|
||||
}
|
||||
|
||||
change_data->num_entries = 0;
|
||||
|
||||
pstrcpy(full_name, fsp->fsp_name);
|
||||
pstrcat(full_name, "/");
|
||||
|
||||
fullname_len = strlen(full_name);
|
||||
remaining_len = sizeof(full_name) - fullname_len - 1;
|
||||
p = &full_name[fullname_len];
|
||||
|
||||
while ((fname = ReadDirName(dp))) {
|
||||
if(strequal(fname, ".") || strequal(fname, ".."))
|
||||
continue;
|
||||
|
||||
change_data->num_entries++;
|
||||
safe_strcpy( p, fname, remaining_len);
|
||||
|
||||
memset(&st, '\0', sizeof(st));
|
||||
|
||||
/*
|
||||
* Do the stat - but ignore errors.
|
||||
*/
|
||||
|
||||
if(dos_stat(full_name, &st) < 0) {
|
||||
DEBUG(5,("create_directory_notify_hash: Unable to stat content file = %s. \
|
||||
Error was %s\n", fsp->fsp_name, strerror(errno) ));
|
||||
}
|
||||
change_data->total_time += (st.st_mtime + st.st_ctime);
|
||||
}
|
||||
|
||||
CloseDir(dp);
|
||||
}
|
||||
|
||||
return True;
|
||||
cnotify->remove_notify(cnbp->change_data);
|
||||
DLIST_REMOVE(change_notify_list, cnbp);
|
||||
ZERO_STRUCTP(cnbp);
|
||||
free(cnbp);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Delete entries by fnum from the change notify pending queue.
|
||||
*****************************************************************************/
|
||||
|
||||
void remove_pending_change_notify_requests_by_fid(files_struct *fsp)
|
||||
{
|
||||
change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
|
||||
change_notify_buf *prev = NULL;
|
||||
struct change_notify *cnbp, *next;
|
||||
|
||||
while(cnbp != NULL) {
|
||||
if(cnbp->fsp->fnum == fsp->fnum) {
|
||||
free((char *)ubi_slRemNext( &change_notify_queue, prev));
|
||||
cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
|
||||
continue;
|
||||
}
|
||||
|
||||
prev = cnbp;
|
||||
cnbp = (change_notify_buf *)ubi_slNext(cnbp);
|
||||
}
|
||||
for (cnbp=change_notify_list; cnbp; cnbp=next) {
|
||||
next=cnbp->next;
|
||||
if (cnbp->fsp->fnum == fsp->fnum) {
|
||||
change_notify_remove(cnbp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Delete entries by mid from the change notify pending queue. Always send reply.
|
||||
*****************************************************************************/
|
||||
|
||||
void remove_pending_change_notify_requests_by_mid(int mid)
|
||||
{
|
||||
change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
|
||||
change_notify_buf *prev = NULL;
|
||||
struct change_notify *cnbp, *next;
|
||||
|
||||
while(cnbp != NULL) {
|
||||
if(SVAL(cnbp->request_buf,smb_mid) == mid) {
|
||||
change_notify_reply_packet(cnbp->request_buf,0,0xC0000000 |NT_STATUS_CANCELLED);
|
||||
free((char *)ubi_slRemNext( &change_notify_queue, prev));
|
||||
cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
|
||||
continue;
|
||||
}
|
||||
|
||||
prev = cnbp;
|
||||
cnbp = (change_notify_buf *)ubi_slNext(cnbp);
|
||||
}
|
||||
for (cnbp=change_notify_list; cnbp; cnbp=next) {
|
||||
next=cnbp->next;
|
||||
if(SVAL(cnbp->request_buf,smb_mid) == mid) {
|
||||
change_notify_reply_packet(cnbp->request_buf,NT_STATUS_CANCELLED);
|
||||
change_notify_remove(cnbp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Delete entries by filename and cnum from the change notify pending queue.
|
||||
Always send reply.
|
||||
*****************************************************************************/
|
||||
|
||||
void remove_pending_change_notify_requests_by_filename(files_struct *fsp)
|
||||
{
|
||||
change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
|
||||
change_notify_buf *prev = NULL;
|
||||
struct change_notify *cnbp, *next;
|
||||
|
||||
while(cnbp != NULL) {
|
||||
/*
|
||||
* We know it refers to the same directory if the connection number and
|
||||
* the filename are identical.
|
||||
*/
|
||||
if((cnbp->fsp->conn == fsp->conn) && strequal(cnbp->fsp->fsp_name,fsp->fsp_name)) {
|
||||
change_notify_reply_packet(cnbp->request_buf,0,0xC0000000 |NT_STATUS_CANCELLED);
|
||||
free((char *)ubi_slRemNext( &change_notify_queue, prev));
|
||||
cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
|
||||
continue;
|
||||
}
|
||||
|
||||
prev = cnbp;
|
||||
cnbp = (change_notify_buf *)ubi_slNext(cnbp);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Process the change notify queue. Note that this is only called as root.
|
||||
Returns True if there are still outstanding change notify requests on the
|
||||
queue.
|
||||
*****************************************************************************/
|
||||
|
||||
BOOL process_pending_change_notify_queue(time_t t)
|
||||
{
|
||||
change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
|
||||
change_notify_buf *prev = NULL;
|
||||
|
||||
if(cnbp == NULL)
|
||||
return False;
|
||||
|
||||
if(cnbp->next_check_time >= t)
|
||||
return True;
|
||||
|
||||
/*
|
||||
* It's time to check. Go through the queue and see if
|
||||
* the timestamps changed.
|
||||
*/
|
||||
|
||||
while((cnbp != NULL) && (cnbp->next_check_time <= t)) {
|
||||
change_hash_data change_data;
|
||||
connection_struct *conn = cnbp->conn;
|
||||
uint16 vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID :
|
||||
SVAL(cnbp->request_buf,smb_uid);
|
||||
|
||||
ZERO_STRUCT(change_data);
|
||||
|
||||
/*
|
||||
* Ensure we don't have any old chain_fsp values
|
||||
* sitting around....
|
||||
*/
|
||||
chain_size = 0;
|
||||
file_chain_reset();
|
||||
|
||||
if(!become_user(conn,vuid)) {
|
||||
DEBUG(0,("process_pending_change_notify_queue: Unable to become user vuid=%d.\n",
|
||||
vuid ));
|
||||
/*
|
||||
* Remove the entry and return an error to the client.
|
||||
*/
|
||||
change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
|
||||
free((char *)ubi_slRemNext( &change_notify_queue, prev));
|
||||
cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!become_service(conn,True)) {
|
||||
DEBUG(0,("process_pending_change_notify_queue: Unable to become service Error was %s.\n", strerror(errno) ));
|
||||
/*
|
||||
* Remove the entry and return an error to the client.
|
||||
*/
|
||||
change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
|
||||
free((char *)ubi_slRemNext( &change_notify_queue, prev));
|
||||
cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
|
||||
unbecome_user();
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!create_directory_notify_hash( cnbp, &change_data)) {
|
||||
DEBUG(0,("process_pending_change_notify_queue: Unable to create change data for \
|
||||
directory %s\n", cnbp->fsp->fsp_name ));
|
||||
/*
|
||||
* Remove the entry and return an error to the client.
|
||||
*/
|
||||
change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
|
||||
free((char *)ubi_slRemNext( &change_notify_queue, prev));
|
||||
cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
|
||||
unbecome_user();
|
||||
continue;
|
||||
}
|
||||
|
||||
if(memcmp( (char *)&cnbp->change_data, (char *)&change_data, sizeof(change_data))) {
|
||||
/*
|
||||
* Remove the entry and return a change notify to the client.
|
||||
*/
|
||||
DEBUG(5,("process_pending_change_notify_queue: directory name = %s changed.\n",
|
||||
cnbp->fsp->fsp_name ));
|
||||
change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR);
|
||||
free((char *)ubi_slRemNext( &change_notify_queue, prev));
|
||||
cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
|
||||
unbecome_user();
|
||||
continue;
|
||||
}
|
||||
|
||||
unbecome_user();
|
||||
|
||||
/*
|
||||
* Move to the next in the list.
|
||||
*/
|
||||
prev = cnbp;
|
||||
cnbp = (change_notify_buf *)ubi_slNext(cnbp);
|
||||
}
|
||||
|
||||
return (cnbp != NULL);
|
||||
for (cnbp=change_notify_list; cnbp; cnbp=next) {
|
||||
next=cnbp->next;
|
||||
/*
|
||||
* We know it refers to the same directory if the connection number and
|
||||
* the filename are identical.
|
||||
*/
|
||||
if((cnbp->fsp->conn == fsp->conn) && strequal(cnbp->fsp->fsp_name,fsp->fsp_name)) {
|
||||
change_notify_reply_packet(cnbp->request_buf,NT_STATUS_CANCELLED);
|
||||
change_notify_remove(cnbp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -346,22 +146,44 @@ directory %s\n", cnbp->fsp->fsp_name ));
|
||||
****************************************************************************/
|
||||
BOOL change_notifies_pending(void)
|
||||
{
|
||||
change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
|
||||
return (cnbp != NULL);
|
||||
return (change_notify_list != NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Now queue an entry on the notify change stack. We timestamp
|
||||
* the entry we are adding so that we know when to scan next.
|
||||
Process the change notify queue. Note that this is only called as root.
|
||||
Returns True if there are still outstanding change notify requests on the
|
||||
queue.
|
||||
*****************************************************************************/
|
||||
BOOL process_pending_change_notify_queue(time_t t)
|
||||
{
|
||||
struct change_notify *cnbp, *next;
|
||||
uint16 vuid;
|
||||
|
||||
for (cnbp=change_notify_list; cnbp; cnbp=next) {
|
||||
next=cnbp->next;
|
||||
|
||||
vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(cnbp->request_buf,smb_uid);
|
||||
|
||||
if (cnotify->check_notify(cnbp->conn, vuid, cnbp->fsp->fsp_name, cnbp->flags, cnbp->change_data, t)) {
|
||||
change_notify_reply_packet(cnbp->request_buf,STATUS_NOTIFY_ENUM_DIR);
|
||||
change_notify_remove(cnbp);
|
||||
}
|
||||
}
|
||||
|
||||
return (change_notify_list != NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Now queue an entry on the notify change list.
|
||||
* We only need to save smb_size bytes from this incoming packet
|
||||
* as we will always by returning a 'read the directory yourself'
|
||||
* error.
|
||||
****************************************************************************/
|
||||
BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn, uint32 flags)
|
||||
{
|
||||
change_notify_buf *cnbp;
|
||||
struct change_notify *cnbp;
|
||||
|
||||
if((cnbp = (change_notify_buf *)malloc(sizeof(change_notify_buf))) == NULL) {
|
||||
if((cnbp = (struct change_notify *)malloc(sizeof(*cnbp))) == NULL) {
|
||||
DEBUG(0,("call_nt_transact_notify_change: malloc fail !\n" ));
|
||||
return -1;
|
||||
}
|
||||
@ -371,23 +193,34 @@ BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn,
|
||||
memcpy(cnbp->request_buf, inbuf, smb_size);
|
||||
cnbp->fsp = fsp;
|
||||
cnbp->conn = conn;
|
||||
cnbp->next_check_time = time(NULL) + lp_change_notify_timeout();
|
||||
cnbp->flags = flags;
|
||||
cnbp->change_data = cnotify->register_notify(conn, fsp->fsp_name, flags);
|
||||
|
||||
if (!create_directory_notify_hash(cnbp, &cnbp->change_data)) {
|
||||
free((char *)cnbp);
|
||||
if (!cnbp->change_data) {
|
||||
free(cnbp);
|
||||
return False;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adding to the tail enables us to check only
|
||||
* the head when scanning for change, as this entry
|
||||
* is forced to have the first timeout expiration.
|
||||
*/
|
||||
|
||||
ubi_slAddTail(&change_notify_queue, cnbp);
|
||||
|
||||
DLIST_ADD(change_notify_list, cnbp);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
initialise the change notify subsystem
|
||||
****************************************************************************/
|
||||
BOOL init_change_notify(void)
|
||||
{
|
||||
cnotify = hash_notify_init();
|
||||
|
||||
if (!cnotify) {
|
||||
DEBUG(0,("Failed to init change notify system\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
#undef OLD_NTDOMAIN
|
||||
|
184
source/smbd/notify_hash.c
Normal file
184
source/smbd/notify_hash.c
Normal file
@ -0,0 +1,184 @@
|
||||
#define OLD_NTDOMAIN 1
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 3.0
|
||||
change notify handling - hash based implementation
|
||||
Copyright (C) Jeremy Allison 1994-1998
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
extern int DEBUGLEVEL;
|
||||
|
||||
|
||||
struct change_data {
|
||||
time_t last_check_time; /* time we last checked this entry */
|
||||
time_t modify_time; /* Info from the directory we're monitoring. */
|
||||
time_t status_time; /* Info from the directory we're monitoring. */
|
||||
time_t total_time; /* Total time of all directory entries - don't care if it wraps. */
|
||||
unsigned int num_entries; /* Zero or the number of files in the directory. */
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Create the hash we will use to determine if the contents changed.
|
||||
*****************************************************************************/
|
||||
static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
|
||||
struct change_data *data)
|
||||
{
|
||||
SMB_STRUCT_STAT st;
|
||||
pstring full_name;
|
||||
char *p;
|
||||
char *fname;
|
||||
size_t remaining_len;
|
||||
size_t fullname_len;
|
||||
void *dp;
|
||||
|
||||
ZERO_STRUCTP(data);
|
||||
|
||||
if(dos_stat(path, &st) == -1) return False;
|
||||
|
||||
data->modify_time = st.st_mtime;
|
||||
data->status_time = st.st_ctime;
|
||||
|
||||
/*
|
||||
* If we are to watch for changes that are only stored
|
||||
* in inodes of files, not in the directory inode, we must
|
||||
* scan the directory and produce a unique identifier with
|
||||
* which we can determine if anything changed. We use the
|
||||
* modify and change times from all the files in the
|
||||
* directory, added together (ignoring wrapping if it's
|
||||
* larger than the max time_t value).
|
||||
*/
|
||||
|
||||
if (!(flags & (FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE))) return True;
|
||||
|
||||
dp = OpenDir(conn, path, True);
|
||||
if (dp == NULL) return False;
|
||||
|
||||
data->num_entries = 0;
|
||||
|
||||
pstrcpy(full_name, path);
|
||||
pstrcat(full_name, "/");
|
||||
|
||||
fullname_len = strlen(full_name);
|
||||
remaining_len = sizeof(full_name) - fullname_len - 1;
|
||||
p = &full_name[fullname_len];
|
||||
|
||||
while ((fname = ReadDirName(dp))) {
|
||||
if(strequal(fname, ".") || strequal(fname, "..")) continue;
|
||||
|
||||
data->num_entries++;
|
||||
safe_strcpy(p, fname, remaining_len);
|
||||
|
||||
ZERO_STRUCT(st);
|
||||
|
||||
/*
|
||||
* Do the stat - but ignore errors.
|
||||
*/
|
||||
dos_stat(full_name, &st);
|
||||
data->total_time += (st.st_mtime + st.st_ctime);
|
||||
}
|
||||
|
||||
CloseDir(dp);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
register a change notify request
|
||||
*****************************************************************************/
|
||||
static void *hash_register_notify(connection_struct *conn, char *path, uint32 flags)
|
||||
{
|
||||
struct change_data data;
|
||||
|
||||
if (!notify_hash(conn, path, flags, &data)) return NULL;
|
||||
|
||||
data.last_check_time = time(NULL);
|
||||
|
||||
return (void *)memdup(&data, sizeof(data));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
check if a change notify should be issued
|
||||
*****************************************************************************/
|
||||
static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t)
|
||||
{
|
||||
struct change_data *data = (struct change_data *)datap;
|
||||
struct change_data data2;
|
||||
|
||||
if (t < data->last_check_time + lp_change_notify_timeout()) return False;
|
||||
|
||||
if (!become_user(conn,vuid)) return True;
|
||||
if (!become_service(conn,True)) {
|
||||
unbecome_user();
|
||||
return True;
|
||||
}
|
||||
|
||||
if (!notify_hash(conn, path, flags, &data2) ||
|
||||
data2.modify_time != data->modify_time ||
|
||||
data2.status_time != data->status_time ||
|
||||
data2.total_time != data->total_time ||
|
||||
data2.num_entries != data->num_entries) {
|
||||
unbecome_user();
|
||||
return True;
|
||||
}
|
||||
|
||||
data->last_check_time = t;
|
||||
unbecome_user();
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
remove a change notify data structure
|
||||
*****************************************************************************/
|
||||
static void hash_remove_notify(void *datap)
|
||||
{
|
||||
free(datap);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
setup hash based change notify
|
||||
****************************************************************************/
|
||||
struct cnotify_fns *hash_notify_init(void)
|
||||
{
|
||||
static struct cnotify_fns cnotify;
|
||||
|
||||
cnotify.register_notify = hash_register_notify;
|
||||
cnotify.check_notify = hash_check_notify;
|
||||
cnotify.remove_notify = hash_remove_notify;
|
||||
|
||||
return &cnotify;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
|
||||
change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR);
|
||||
|
||||
chain_size = 0;
|
||||
file_chain_reset();
|
||||
|
||||
uint16 vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID :
|
||||
SVAL(cnbp->request_buf,smb_uid);
|
||||
*/
|
||||
|
||||
#undef OLD_NTDOMAIN
|
170
source/smbd/notify_kernel.c
Normal file
170
source/smbd/notify_kernel.c
Normal file
@ -0,0 +1,170 @@
|
||||
#define OLD_NTDOMAIN 1
|
||||
/*
|
||||
Unix SMB/Netbios implementation.
|
||||
Version 3.0
|
||||
change notify handling - linux kernel based implementation
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#if HAVE_KERNEL_CHANGE_NOTIFY
|
||||
|
||||
extern int DEBUGLEVEL;
|
||||
static int fd_pending;
|
||||
static unsigned signals_received;
|
||||
static unsigned signals_processed;
|
||||
|
||||
#ifndef DN_ACCESS
|
||||
#define DN_ACCESS 0x00000001 /* File accessed in directory */
|
||||
#define DN_MODIFY 0x00000002 /* File modified in directory */
|
||||
#define DN_CREATE 0x00000004 /* File created in directory */
|
||||
#define DN_DELETE 0x00000008 /* File removed from directory */
|
||||
#define DN_RENAME 0x00000010 /* File renamed in directory */
|
||||
#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef RT_SIGNAL_NOTIFY
|
||||
#define RT_SIGNAL_NOTIFY 34
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
This is the structure to keep the information needed to
|
||||
determine if a directory has changed.
|
||||
*****************************************************************************/
|
||||
struct change_data {
|
||||
int directory_handle;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
the signal handler for change notify
|
||||
*****************************************************************************/
|
||||
static void signal_handler(int signal, siginfo_t *info, void *unused)
|
||||
{
|
||||
BlockSignals(True, signal);
|
||||
fd_pending = info->si_fd;
|
||||
signals_received++;
|
||||
sys_select_signal();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
check if a change notify should be issued
|
||||
*****************************************************************************/
|
||||
static BOOL kernel_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t)
|
||||
{
|
||||
struct change_data *data = (struct change_data *)datap;
|
||||
|
||||
if (data->directory_handle != fd_pending) return False;
|
||||
|
||||
close(fd_pending);
|
||||
data->directory_handle = fd_pending = -1;
|
||||
signals_processed++;
|
||||
BlockSignals(False, RT_SIGNAL_NOTIFY);
|
||||
return True;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
remove a change notify data structure
|
||||
*****************************************************************************/
|
||||
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;
|
||||
signals_processed++;
|
||||
BlockSignals(False, RT_SIGNAL_NOTIFY);
|
||||
}
|
||||
close(data->directory_handle);
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
register a change notify request
|
||||
*****************************************************************************/
|
||||
static void *kernel_register_notify(connection_struct *conn, char *path, uint32 flags)
|
||||
{
|
||||
struct change_data data;
|
||||
int fd;
|
||||
unsigned long kernel_flags;
|
||||
|
||||
fd = dos_open(fsp->fsp_name, O_RDONLY, 0);
|
||||
|
||||
if (fd == -1) {
|
||||
DEBUG(3,("Failed to open directory %s for change notify\n", fsp->fsp_name));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fcntl(fd, F_SETSIG, RT_SIGNAL_NOTIFY) == -1) {
|
||||
DEBUG(3,("Failed to set signal handler for change notify\n"));
|
||||
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_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;
|
||||
if (flags & FILE_NOTIFY_CHANGE_LAST_ACCESS) kernel_flags |= DN_ACCESS;
|
||||
if (flags & FILE_NOTIFY_CHANGE_CREATION) kernel_flags |= DN_CREATE;
|
||||
|
||||
if (fcntl(fd, F_NOTIFY, kernel_flags) == -1) {
|
||||
DEBUG(3,("Failed to set async flag for change notify\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data.directory_handle = fd;
|
||||
|
||||
return (void *)memdup(&data, sizeof(data));
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
setup kernel based change notify
|
||||
****************************************************************************/
|
||||
struct cnotify_fns *kernel_notify_init(void)
|
||||
{
|
||||
static struct cnotify_fns cnotify;
|
||||
struct sigaction act;
|
||||
|
||||
act.sa_handler = NULL;
|
||||
act.sa_sigaction = signal_handler;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(RT_SIGNAL_NOTIFY, &act, NULL) != 0) {
|
||||
DEBUG(0,("Failed to setup RT_SIGNAL_NOTIFY handler\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cnotify.register_notify = kernel_register_notify;
|
||||
cnotify.check_notify = kernel_check_notify;
|
||||
cnotify.remove_notify = kernel_remove_notify;
|
||||
|
||||
return &cnotify;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
void notify_kernel_dummy(void) {}
|
||||
#endif /* HAVE_KERNEL_CHANGE_NOTIFY */
|
||||
|
||||
#undef OLD_NTDOMAIN
|
@ -71,44 +71,47 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou
|
||||
smb_read_error = 0;
|
||||
|
||||
if(timeout != 0) {
|
||||
struct timeval to;
|
||||
int selrtn;
|
||||
int maxfd = oplock_sock;
|
||||
struct timeval to;
|
||||
int selrtn;
|
||||
int maxfd = oplock_sock;
|
||||
|
||||
if (koplocks && koplocks->notification_fd != -1) {
|
||||
FD_SET(koplocks->notification_fd, fds);
|
||||
}
|
||||
if (koplocks && koplocks->notification_fd != -1) {
|
||||
FD_SET(koplocks->notification_fd, fds);
|
||||
maxfd = MAX(maxfd, koplocks->notification_fd);
|
||||
}
|
||||
|
||||
to.tv_sec = timeout / 1000;
|
||||
to.tv_usec = (timeout % 1000) * 1000;
|
||||
to.tv_sec = timeout / 1000;
|
||||
to.tv_usec = (timeout % 1000) * 1000;
|
||||
|
||||
selrtn = sys_select(maxfd+1,fds,&to);
|
||||
selrtn = sys_select(maxfd+1,fds,&to);
|
||||
|
||||
if (selrtn == -1 && errno == EINTR) {
|
||||
/* could be a kernel oplock interrupt */
|
||||
if (koplocks && koplocks->msg_waiting(fds)) {
|
||||
return koplocks->receive_message(fds, buffer, buffer_len);
|
||||
}
|
||||
}
|
||||
if (selrtn == -1 && errno == EINTR) {
|
||||
/* could be a kernel oplock interrupt */
|
||||
if (koplocks && koplocks->msg_waiting(fds)) {
|
||||
return koplocks->receive_message(fds, buffer, buffer_len);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if error */
|
||||
if(selrtn == -1) {
|
||||
/* something is wrong. Maybe the socket is dead? */
|
||||
smb_read_error = READ_ERROR;
|
||||
return False;
|
||||
}
|
||||
/* Check if error */
|
||||
if(selrtn == -1) {
|
||||
/* something is wrong. Maybe the socket is dead? */
|
||||
smb_read_error = READ_ERROR;
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Did we timeout ? */
|
||||
if (selrtn == 0) {
|
||||
smb_read_error = READ_TIMEOUT;
|
||||
return False;
|
||||
}
|
||||
/* Did we timeout ? */
|
||||
if (selrtn == 0) {
|
||||
smb_read_error = READ_TIMEOUT;
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
if (koplocks && koplocks->msg_waiting(fds)) {
|
||||
return koplocks->receive_message(fds, buffer, buffer_len);
|
||||
}
|
||||
|
||||
if (!FD_ISSET(oplock_sock, fds)) return False;
|
||||
|
||||
/*
|
||||
* From here down we deal with the smbd <--> smbd
|
||||
* oplock break protocol only.
|
||||
|
@ -218,16 +218,16 @@ static BOOL irix_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *in
|
||||
{
|
||||
/* Ensure that the msg length is correct. */
|
||||
if(msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) {
|
||||
DEBUG(0,("process_local_message: incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, \
|
||||
should be %d).\n", msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN));
|
||||
DEBUG(0,("incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, should be %d).\n",
|
||||
msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN));
|
||||
return False;
|
||||
}
|
||||
|
||||
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,("process_local_message: kernel oplock break request for \
|
||||
file dev = %x, inode = %.0f\n", (unsigned int)*dev, (double)*inode));
|
||||
DEBUG(5,("kernel oplock break request for file dev = %x, inode = %.0f\n",
|
||||
(unsigned int)*dev, (double)*inode));
|
||||
|
||||
return True;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ extern int DEBUGLEVEL;
|
||||
|
||||
static unsigned signals_received;
|
||||
static unsigned signals_processed;
|
||||
static int fd_pending; /* the fd of the current pending SIGIO */
|
||||
static int fd_pending; /* the fd of the current pending signal */
|
||||
|
||||
#ifndef F_SETLEASE
|
||||
#define F_SETLEASE 1024
|
||||
@ -43,14 +43,19 @@ static int fd_pending; /* the fd of the current pending SIGIO */
|
||||
#define CAP_LEASE 28
|
||||
#endif
|
||||
|
||||
#ifndef RT_SIGNAL_LEASE
|
||||
#define RT_SIGNAL_LEASE 33
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
handle a SIGIO, incrementing the signals_received and blocking SIGIO
|
||||
handle a LEASE signal, incrementing the signals_received and blocking the signal
|
||||
****************************************************************************/
|
||||
static void sigio_handler(int signal, siginfo_t *info, void *unused)
|
||||
static void signal_handler(int signal, siginfo_t *info, void *unused)
|
||||
{
|
||||
BlockSignals(True, signal);
|
||||
fd_pending = info->si_fd;
|
||||
signals_received++;
|
||||
BlockSignals(True, SIGIO);
|
||||
sys_select_signal();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -150,7 +155,7 @@ dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
|
||||
/* now we can receive more signals */
|
||||
fd_pending = -1;
|
||||
signals_processed++;
|
||||
BlockSignals(False, SIGIO);
|
||||
BlockSignals(False, RT_SIGNAL_LEASE);
|
||||
|
||||
return True;
|
||||
}
|
||||
@ -213,16 +218,16 @@ static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *i
|
||||
{
|
||||
/* Ensure that the msg length is correct. */
|
||||
if (msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) {
|
||||
DEBUG(0,("process_local_message: incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, \
|
||||
should be %d).\n", msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN));
|
||||
DEBUG(0,("incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, should be %d).\n",
|
||||
msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN));
|
||||
return False;
|
||||
}
|
||||
|
||||
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,("process_local_message: kernel oplock break request for \
|
||||
file dev = %x, inode = %.0f\n", (unsigned int)*dev, (double)*inode));
|
||||
DEBUG(5,("kernel oplock break request for file dev = %x, inode = %.0f\n",
|
||||
(unsigned int)*dev, (double)*inode));
|
||||
|
||||
return True;
|
||||
}
|
||||
@ -264,10 +269,10 @@ struct kernel_oplocks *linux_init_kernel_oplocks(void)
|
||||
}
|
||||
|
||||
act.sa_handler = NULL;
|
||||
act.sa_sigaction = sigio_handler;
|
||||
act.sa_sigaction = signal_handler;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(SIGIO, &act, NULL) != 0) {
|
||||
DEBUG(0,("Failed to setup SIGIO handler\n"));
|
||||
if (sigaction(RT_SIGNAL_LEASE, &act, NULL) != 0) {
|
||||
DEBUG(0,("Failed to setup RT_SIGNAL_LEASE handler\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,30 @@ static BOOL push_message(ubi_slList *list_head, char *buf, int msg_len)
|
||||
|
||||
BOOL push_oplock_pending_smb_message(char *buf, int msg_len)
|
||||
{
|
||||
return push_message(&smb_oplock_queue, buf, msg_len);
|
||||
return push_message(&smb_oplock_queue, buf, msg_len);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
do all async processing in here. This includes UDB oplock messages, kernel
|
||||
oplock messages, change notify events etc.
|
||||
****************************************************************************/
|
||||
static void async_processing(fd_set *fds, char *buffer, int buffer_len)
|
||||
{
|
||||
/* check for oplock messages (both UDP and kernel) */
|
||||
if (receive_local_message(fds, buffer, buffer_len, 0)) {
|
||||
process_local_message(buffer, buffer_len);
|
||||
}
|
||||
|
||||
/* check for async change notify events */
|
||||
process_pending_change_notify_queue(0);
|
||||
|
||||
/* check for sighup processing */
|
||||
if (reload_after_sighup) {
|
||||
unbecome_user();
|
||||
DEBUG(1,("Reloading services after SIGHUP\n"));
|
||||
reload_services(False);
|
||||
reload_after_sighup = False;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -115,7 +138,7 @@ BOOL push_oplock_pending_smb_message(char *buf, int msg_len)
|
||||
|
||||
If a local udp message has been pushed onto the
|
||||
queue (this can only happen during oplock break
|
||||
processing) return this first.
|
||||
processing) call async_processing()
|
||||
|
||||
If a pending smb message has been pushed onto the
|
||||
queue (this can only happen during oplock break
|
||||
@ -131,8 +154,7 @@ BOOL push_oplock_pending_smb_message(char *buf, int msg_len)
|
||||
The timeout is in milli seconds
|
||||
****************************************************************************/
|
||||
|
||||
static BOOL receive_message_or_smb(char *buffer, int buffer_len,
|
||||
int timeout, BOOL *got_smb)
|
||||
static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
|
||||
{
|
||||
fd_set fds;
|
||||
int selrtn;
|
||||
@ -141,30 +163,28 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len,
|
||||
|
||||
smb_read_error = 0;
|
||||
|
||||
*got_smb = False;
|
||||
|
||||
/*
|
||||
* Check to see if we already have a message on the smb queue.
|
||||
* If so - copy and return it.
|
||||
*/
|
||||
|
||||
if(ubi_slCount(&smb_oplock_queue) != 0) {
|
||||
if(ubi_slCount(&smb_oplock_queue) != 0) {
|
||||
pending_message_list *msg = (pending_message_list *)ubi_slRemHead(&smb_oplock_queue);
|
||||
memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len));
|
||||
|
||||
/* Free the message we just copied. */
|
||||
free((char *)msg->msg_buf);
|
||||
free((char *)msg);
|
||||
*got_smb = True;
|
||||
|
||||
DEBUG(5,("receive_message_or_smb: returning queued smb message.\n"));
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Setup the select read fd set.
|
||||
*/
|
||||
|
||||
again:
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(smbd_server_fd(),&fds);
|
||||
maxfd = setup_oplock_select_set(&fds);
|
||||
@ -175,16 +195,16 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len,
|
||||
selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,timeout>0?&to:NULL);
|
||||
|
||||
/* if we get EINTR then maybe we have received an oplock
|
||||
signal - treat this as select returning 1. This is ugly, but
|
||||
is the best we can do until the oplock code knows more about
|
||||
signals */
|
||||
signal - treat this as select returning 1. This is ugly, but
|
||||
is the best we can do until the oplock code knows more about
|
||||
signals */
|
||||
if (selrtn == -1 && errno == EINTR) {
|
||||
FD_ZERO(&fds);
|
||||
selrtn = 1;
|
||||
async_processing(&fds, buffer, buffer_len);
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* Check if error */
|
||||
if(selrtn == -1 && errno != EINTR) {
|
||||
if (selrtn == -1) {
|
||||
/* something is wrong. Maybe the socket is dead? */
|
||||
smb_read_error = READ_ERROR;
|
||||
return False;
|
||||
@ -195,13 +215,13 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len,
|
||||
smb_read_error = READ_TIMEOUT;
|
||||
return False;
|
||||
}
|
||||
|
||||
if (FD_ISSET(smbd_server_fd(),&fds)) {
|
||||
*got_smb = True;
|
||||
return receive_smb(smbd_server_fd(), buffer, 0);
|
||||
} else {
|
||||
return receive_local_message(&fds, buffer, buffer_len, 0);
|
||||
|
||||
if (!FD_ISSET(smbd_server_fd(),&fds) || selrtn > 1) {
|
||||
async_processing(&fds, buffer, buffer_len);
|
||||
if (!FD_ISSET(smbd_server_fd(),&fds)) goto again;
|
||||
}
|
||||
|
||||
return receive_smb(smbd_server_fd(), buffer, 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -210,30 +230,16 @@ Get the next SMB packet, doing the local message processing automatically.
|
||||
|
||||
BOOL receive_next_smb(char *inbuf, int bufsize, int timeout)
|
||||
{
|
||||
BOOL got_smb = False;
|
||||
BOOL ret;
|
||||
BOOL got_keepalive;
|
||||
BOOL ret;
|
||||
|
||||
do
|
||||
{
|
||||
ret = receive_message_or_smb(inbuf,bufsize,timeout,&got_smb);
|
||||
do {
|
||||
ret = receive_message_or_smb(inbuf,bufsize,timeout);
|
||||
|
||||
got_keepalive = (ret && (CVAL(inbuf,0) == 0x85));
|
||||
} while (ret && got_keepalive);
|
||||
|
||||
if(ret && !got_smb)
|
||||
{
|
||||
/* Deal with oplock break requests from other smbd's. */
|
||||
process_local_message(inbuf, bufsize);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ret && (CVAL(inbuf,0) == 0x85))
|
||||
{
|
||||
/* Keepalive packet. */
|
||||
got_smb = False;
|
||||
}
|
||||
|
||||
}
|
||||
while(ret && !got_smb);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -270,13 +276,12 @@ void respond_to_all_remaining_local_messages(void)
|
||||
* Keep doing receive_local_message with a 1 ms timeout until
|
||||
* we have no more messages.
|
||||
*/
|
||||
|
||||
while(receive_local_message(&fds, buffer, sizeof(buffer), 1)) {
|
||||
/* Deal with oplock break requests from other smbd's. */
|
||||
process_local_message(buffer, sizeof(buffer));
|
||||
/* Deal with oplock break requests from other smbd's. */
|
||||
process_local_message(buffer, sizeof(buffer));
|
||||
|
||||
FD_ZERO(&fds);
|
||||
(void)setup_oplock_select_set(&fds);
|
||||
FD_ZERO(&fds);
|
||||
(void)setup_oplock_select_set(&fds);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -1008,98 +1013,80 @@ machine %s in domain %s.\n", global_myname, global_myworkgroup ));
|
||||
|
||||
void smbd_process(void)
|
||||
{
|
||||
extern int smb_echo_count;
|
||||
time_t last_timeout_processing_time = time(NULL);
|
||||
unsigned int num_smbs = 0;
|
||||
extern int smb_echo_count;
|
||||
time_t last_timeout_processing_time = time(NULL);
|
||||
unsigned int num_smbs = 0;
|
||||
|
||||
InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
|
||||
OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
|
||||
if ((InBuffer == NULL) || (OutBuffer == NULL))
|
||||
return;
|
||||
InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
|
||||
OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
|
||||
if ((InBuffer == NULL) || (OutBuffer == NULL))
|
||||
return;
|
||||
|
||||
InBuffer += SMB_ALIGNMENT;
|
||||
OutBuffer += SMB_ALIGNMENT;
|
||||
InBuffer += SMB_ALIGNMENT;
|
||||
OutBuffer += SMB_ALIGNMENT;
|
||||
|
||||
max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
|
||||
max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
|
||||
|
||||
/* re-initialise the timezone */
|
||||
TimeInit();
|
||||
/* re-initialise the timezone */
|
||||
TimeInit();
|
||||
|
||||
while (True)
|
||||
{
|
||||
int deadtime = lp_deadtime()*60;
|
||||
BOOL got_smb = False;
|
||||
int select_timeout = setup_select_timeout();
|
||||
while (True) {
|
||||
int deadtime = lp_deadtime()*60;
|
||||
int select_timeout = setup_select_timeout();
|
||||
int num_echos;
|
||||
|
||||
if (deadtime <= 0)
|
||||
deadtime = DEFAULT_SMBD_TIMEOUT;
|
||||
if (deadtime <= 0)
|
||||
deadtime = DEFAULT_SMBD_TIMEOUT;
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
/* free up temporary memory */
|
||||
lp_talloc_free();
|
||||
|
||||
/* free up temporary memory */
|
||||
lp_talloc_free();
|
||||
while (!receive_message_or_smb(InBuffer,BUFFER_SIZE,select_timeout)) {
|
||||
if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
|
||||
return;
|
||||
num_smbs = 0; /* Reset smb counter. */
|
||||
}
|
||||
|
||||
/*
|
||||
* If reload_after_sighup == True then we got a SIGHUP
|
||||
* and are being asked to reload. Fix from <branko.cibej@hermes.si>
|
||||
*/
|
||||
if (reload_after_sighup) {
|
||||
/* become root */
|
||||
unbecome_user();
|
||||
DEBUG(1,("Reloading services after SIGHUP\n"));
|
||||
reload_services(False);
|
||||
reload_after_sighup = False;
|
||||
}
|
||||
/*
|
||||
* Ensure we do timeout processing if the SMB we just got was
|
||||
* only an echo request. This allows us to set the select
|
||||
* timeout in 'receive_message_or_smb()' to any value we like
|
||||
* without worrying that the client will send echo requests
|
||||
* faster than the select timeout, thus starving out the
|
||||
* essential processing (change notify, blocking locks) that
|
||||
* the timeout code does. JRA.
|
||||
*/
|
||||
num_echos = smb_echo_count;
|
||||
|
||||
while(!receive_message_or_smb(InBuffer,BUFFER_SIZE,select_timeout,&got_smb))
|
||||
{
|
||||
if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
|
||||
return;
|
||||
num_smbs = 0; /* Reset smb counter. */
|
||||
}
|
||||
process_smb(InBuffer, OutBuffer);
|
||||
|
||||
if(got_smb) {
|
||||
/*
|
||||
* Ensure we do timeout processing if the SMB we just got was
|
||||
* only an echo request. This allows us to set the select
|
||||
* timeout in 'receive_message_or_smb()' to any value we like
|
||||
* without worrying that the client will send echo requests
|
||||
* faster than the select timeout, thus starving out the
|
||||
* essential processing (change notify, blocking locks) that
|
||||
* the timeout code does. JRA.
|
||||
*/
|
||||
int num_echos = smb_echo_count;
|
||||
if (smb_echo_count != num_echos) {
|
||||
if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
|
||||
return;
|
||||
num_smbs = 0; /* Reset smb counter. */
|
||||
}
|
||||
|
||||
process_smb(InBuffer, OutBuffer);
|
||||
num_smbs++;
|
||||
|
||||
if(smb_echo_count != num_echos) {
|
||||
if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
|
||||
return;
|
||||
num_smbs = 0; /* Reset smb counter. */
|
||||
}
|
||||
|
||||
num_smbs++;
|
||||
|
||||
/*
|
||||
* If we are getting smb requests in a constant stream
|
||||
* with no echos, make sure we attempt timeout processing
|
||||
* every select_timeout milliseconds - but only check for this
|
||||
* every 200 smb requests.
|
||||
*/
|
||||
|
||||
if((num_smbs % 200) == 0) {
|
||||
time_t new_check_time = time(NULL);
|
||||
if(last_timeout_processing_time - new_check_time >= (select_timeout/1000)) {
|
||||
if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
|
||||
return;
|
||||
num_smbs = 0; /* Reset smb counter. */
|
||||
last_timeout_processing_time = new_check_time; /* Reset time. */
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
process_local_message(InBuffer, BUFFER_SIZE);
|
||||
}
|
||||
/*
|
||||
* If we are getting smb requests in a constant stream
|
||||
* with no echos, make sure we attempt timeout processing
|
||||
* every select_timeout milliseconds - but only check for this
|
||||
* every 200 smb requests.
|
||||
*/
|
||||
|
||||
if ((num_smbs % 200) == 0) {
|
||||
time_t new_check_time = time(NULL);
|
||||
if(last_timeout_processing_time - new_check_time >= (select_timeout/1000)) {
|
||||
if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
|
||||
return;
|
||||
num_smbs = 0; /* Reset smb counter. */
|
||||
last_timeout_processing_time = new_check_time; /* Reset time. */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef OLD_NTDOMAIN
|
||||
|
@ -350,12 +350,7 @@ static void sig_hup(int sig)
|
||||
BlockSignals(True,SIGHUP);
|
||||
DEBUG(0,("Got SIGHUP\n"));
|
||||
|
||||
/*
|
||||
* Fix from <branko.cibej@hermes.si> here.
|
||||
* We used to reload in the signal handler - this
|
||||
* is a *BIG* no-no.
|
||||
*/
|
||||
|
||||
sys_select_signal();
|
||||
reload_after_sighup = True;
|
||||
BlockSignals(False,SIGHUP);
|
||||
}
|
||||
@ -758,6 +753,11 @@ static void usage(char *pname)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Setup change notify */
|
||||
if (!init_change_notify()) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
smbd_process();
|
||||
|
||||
exit_server("normal exit");
|
||||
|
Loading…
Reference in New Issue
Block a user