updated the 3.0 branch from the head branch - ready for alpha18
[ira/wip.git] / source3 / smbd / oplock.c
index 23606f1d147f9ad42d05d0ad4492469ab972f803..14b243b36edeca15c8b549130d540b1f5da296ac 100644 (file)
@@ -72,34 +72,69 @@ BOOL oplock_message_waiting(fd_set *fds)
 
 ****************************************************************************/
 
-BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeout)
+BOOL receive_local_message( char *buffer, int buffer_len, int timeout)
 {
        struct sockaddr_in from;
-       int fromlen = sizeof(from);
+       socklen_t fromlen = sizeof(from);
        int32 msg_len = 0;
+       fd_set fds;
+       int selrtn = -1;
 
+       FD_ZERO(&fds);
        smb_read_error = 0;
 
-       if(timeout != 0) {
+       /*
+        * We need to check for kernel oplocks before going into the select
+        * here, as the EINTR generated by the linux kernel oplock may have
+        * already been eaten. JRA.
+        */
+
+       if (koplocks && koplocks->msg_waiting(&fds)) {
+               return koplocks->receive_message(&fds, buffer, buffer_len);
+       }
+
+       while (timeout > 0 && selrtn == -1) {
                struct timeval to;
-               int selrtn;
                int maxfd = oplock_sock;
+               time_t starttime = time(NULL);
 
-               if (koplocks && koplocks->notification_fd != -1) {
-                       FD_SET(koplocks->notification_fd, fds);
-                       maxfd = MAX(maxfd, koplocks->notification_fd);
-               }
+               FD_ZERO(&fds);
+               maxfd = setup_oplock_select_set(&fds);
 
                to.tv_sec = timeout / 1000;
                to.tv_usec = (timeout % 1000) * 1000;
 
-               selrtn = sys_select(maxfd+1,fds,NULL,NULL,&to);
+               DEBUG(5,("receive_local_message: doing select with timeout of %d ms\n", timeout));
+
+               selrtn = sys_select(maxfd+1,&fds,NULL,NULL,&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 (koplocks && koplocks->msg_waiting(&fds)) {
+                               return koplocks->receive_message(&fds, buffer, buffer_len);
+                       }
+
+                       /*
+                        * Linux 2.0.x seems to have a bug in that
+                        * it can return -1, EINTR with a timeout of zero.
+                        * Make sure we bail out here with a read timeout
+                        * if we got EINTR on a timeout of 1 or less.
+                        */
+
+                       if (timeout <= 1) {
+                               smb_read_error = READ_TIMEOUT;
+                               return False;
                        }
+
+                       /* Not a kernel interrupt - could be a SIGUSR1 message. We must restart. */
+                       /* We need to decrement the timeout here. */
+                       timeout -= ((time(NULL) - starttime)*1000);
+                       if (timeout < 0)
+                               timeout = 1;
+
+                       DEBUG(5,("receive_local_message: EINTR : new timeout %d ms\n", timeout));
+                       continue;
                }
 
                /* Check if error */
@@ -116,11 +151,11 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou
                }
        }
 
-       if (koplocks && koplocks->msg_waiting(fds)) {
-               return koplocks->receive_message(fds, buffer, buffer_len);
+       if (koplocks && koplocks->msg_waiting(&fds)) {
+               return koplocks->receive_message(&fds, buffer, buffer_len);
        }
 
-       if (!FD_ISSET(oplock_sock, fds))
+       if (!FD_ISSET(oplock_sock, &fds))
                return False;
 
        /*
@@ -131,7 +166,7 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou
        /*
         * Read a loopback udp message.
         */
-       msg_len = recvfrom(oplock_sock, &buffer[OPBRK_CMD_HEADER_LEN],
+       msg_len = sys_recvfrom(oplock_sock, &buffer[OPBRK_CMD_HEADER_LEN],
                                                buffer_len - OPBRK_CMD_HEADER_LEN, 0, (struct sockaddr *)&from, &fromlen);
 
        if(msg_len < 0) {
@@ -417,7 +452,7 @@ oplocks. Returning success.\n"));
                toaddr.sin_port = htons(from_port);
                toaddr.sin_family = AF_INET;
 
-               if(sendto( oplock_sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0,
+               if(sys_sendto( oplock_sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0,
                                (struct sockaddr *)&toaddr, sizeof(toaddr)) < 0) {
                        DEBUG(0,("process_local_message: sendto process %d failed. Errno was %s\n",
                                (int)remotepid, strerror(errno)));
@@ -930,7 +965,7 @@ dev = %x, inode = %.0f, file_id = %lu and no fsp found !\n",
             (unsigned int)dev, (double)inode, file_id );
        }
 
-       if(sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0,
+       if(sys_sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0,
                        (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0) {
                if( DEBUGLVL( 0 ) ) {
                        dbgtext( "request_oplock_break: failed when sending a oplock " );
@@ -967,16 +1002,8 @@ dev = %x, inode = %.0f, file_id = %lu and no fsp found !\n",
                char op_break_reply[OPBRK_CMD_HEADER_LEN+OPLOCK_BREAK_MSG_LEN];
                uint16 reply_from_port;
                char *reply_msg_start;
-               fd_set fds;
-
-               FD_ZERO(&fds);
-               FD_SET(oplock_sock,&fds);
-
-               if (koplocks && koplocks->notification_fd != -1) {
-                       FD_SET(koplocks->notification_fd, &fds);
-               }
 
-               if(receive_local_message(&fds, op_break_reply, sizeof(op_break_reply),
+               if(receive_local_message(op_break_reply, sizeof(op_break_reply),
                                time_left ? time_left * 1000 : 1) == False) {
                        if(smb_read_error == READ_TIMEOUT) {
                                if( DEBUGLVL( 0 ) ) {