Author: vlendec Date: 2005-08-02 23:52:43 +0000 (Tue, 02 Aug 2005) New Revision: 8962
WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=8962 Log: Add oplock break failure handling Modified: trunk/source/include/local.h trunk/source/include/smb.h trunk/source/smbd/open.c trunk/source/smbd/oplock.c trunk/source/smbd/process.c Changeset: Modified: trunk/source/include/local.h =================================================================== --- trunk/source/include/local.h 2005-08-02 23:43:50 UTC (rev 8961) +++ trunk/source/include/local.h 2005-08-02 23:52:43 UTC (rev 8962) @@ -233,9 +233,6 @@ /* Number of microseconds to wait before a sharing violation. */ #define SHARING_VIOLATION_USEC_WAIT 950000 -/* Number of microseconds to wait before an oplock break */ -#define OPLOCK_BREAK_USEC_WAIT 30000000 - #define MAX_LDAP_REPLICATION_SLEEP_TIME 5000 /* In milliseconds. */ #endif Modified: trunk/source/include/smb.h =================================================================== --- trunk/source/include/smb.h 2005-08-02 23:43:50 UTC (rev 8961) +++ trunk/source/include/smb.h 2005-08-02 23:52:43 UTC (rev 8962) @@ -443,6 +443,7 @@ time_t last_write_time; int oplock_type; int sent_oplock_break; + struct timed_event *oplock_timeout; BOOL level2_around; int num_waiting_for_level2_inform; Modified: trunk/source/smbd/open.c =================================================================== --- trunk/source/smbd/open.c 2005-08-02 23:43:50 UTC (rev 8961) +++ trunk/source/smbd/open.c 2005-08-02 23:52:43 UTC (rev 8962) @@ -1593,7 +1593,13 @@ /* delay_for_oplocks might delete the fsp */ open_time = fsp->open_time; if (delay_for_oplocks(fsp, second_try)) { - defer_open(&open_time, OPLOCK_BREAK_USEC_WAIT, + /* Normally the smbd we asked should respond within + * OPLOCK_BREAK_TIMEOUT seconds regardless of whether + * the client did, give twice the timeout as a safety + * measure here in case the other smbd is stuck + * somewhere else. */ + defer_open(&open_time, + (OPLOCK_BREAK_TIMEOUT*2) * 1000000, fname, dev, inode); return NULL; } Modified: trunk/source/smbd/oplock.c =================================================================== --- trunk/source/smbd/oplock.c 2005-08-02 23:43:50 UTC (rev 8961) +++ trunk/source/smbd/oplock.c 2005-08-02 23:52:43 UTC (rev 8962) @@ -1018,6 +1018,18 @@ return True; } +static void oplock_timeout_handler(struct timed_event *te, + const struct timeval *now, + void *private_data) +{ + files_struct *fsp = private_data; + + DEBUG(0, ("Oplock break failed -- replying anyway\n")); + global_client_failed_oplock_break = True; + remove_oplock(fsp); + reply_to_oplock_break_requests(fsp); +} + static void process_oplock_break_message(int msg_type, pid_t src, void *buf, size_t len) { @@ -1115,6 +1127,20 @@ ADD_TO_ARRAY(NULL, struct share_mode_entry, *msg, &fsp->pending_break_messages, &fsp->num_pending_break_messages); + + if (fsp->oplock_timeout != NULL) { + DEBUG(0, ("Logic problem -- have an oplock event hanging " + "around\n")); + } + + fsp->oplock_timeout = + add_timed_event(NULL, + timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0), + oplock_timeout_handler, fsp); + + if (fsp->oplock_timeout == NULL) { + DEBUG(0, ("Could not add oplock timeout handler\n")); + } } static void process_kernel_oplock_break(int msg_type, pid_t src, @@ -1187,6 +1213,10 @@ SAFE_FREE(fsp->pending_break_messages); fsp->num_pending_break_messages = 0; + if (fsp->oplock_timeout != NULL) { + talloc_free(fsp->oplock_timeout); + fsp->oplock_timeout = NULL; + } return; } Modified: trunk/source/smbd/process.c =================================================================== --- trunk/source/smbd/process.c 2005-08-02 23:43:50 UTC (rev 8961) +++ trunk/source/smbd/process.c 2005-08-02 23:52:43 UTC (rev 8962) @@ -274,6 +274,7 @@ static int timed_event_destructor(void *p) { struct timed_event *te = talloc_get_type_abort(p, struct timed_event); + DEBUG(10, ("Destroying timed event\n")); DLIST_REMOVE(timed_events, te); return 0; } @@ -325,13 +326,15 @@ if (timed_events == NULL) { /* No syscall if there are no events */ + DEBUG(10, ("run_events: No events\n")); return; } GetTimeOfDay(&now); - if (timeval_compare(&timed_events->when, &now) < 0) { + if (timeval_compare(&now, &timed_events->when) < 0) { /* Nothing to do yet */ + DEBUG(10, ("run_events: Nothing to do\n")); return; } @@ -339,26 +342,21 @@ return; } -static int timed_events_timeout(void) +struct timeval timed_events_timeout(void) { struct timeval now, timeout; if (timed_events == NULL) { - return -1; + return timeval_set(SMBD_SELECT_TIMEOUT, 0); } now = timeval_current(); timeout = timeval_until(&now, &timed_events->when); - /* We need that additional millisecond here. Select() under Linux - * seems to return a bit early, and due to a second - * setup_select_timeout in timeout_processing and - * receive_message_or_smb interpreting a zero timeout as "wait - * indefinitely" we could end up with processing the event *very* - * late. This can probably change once we don't use milliseconds but - * struct timevals everywhere. -- vl */ + DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)timeout.tv_sec, + (int)timeout.tv_usec)); - return (timeout.tv_sec * 1000) + ((timeout.tv_usec+999) / 1000) + 1; + return timeout; } struct idle_event { @@ -481,17 +479,17 @@ { fd_set fds; int selrtn; - struct timeval to; - struct timeval *pto; + struct timeval to = timeval_set(SMBD_SELECT_TIMEOUT, 0); int maxfd; smb_read_error = 0; again: - to.tv_sec = timeout / 1000; - to.tv_usec = (timeout % 1000) * 1000; - pto = timeout > 0 ? &to : NULL; + if (timeout >= 0) { + to.tv_sec = timeout / 1000; + to.tv_usec = (timeout % 1000) * 1000; + } /* * Note that this call must be before processing any SMB @@ -540,9 +538,8 @@ /* Make a more accurate select timeout. */ to.tv_sec = tdif / 1000000; to.tv_usec = tdif % 1000000; - pto = &to; DEBUG(10,("receive_message_or_smb: select with timeout of [%u.%06u]\n", - (unsigned int)pto->tv_sec, (unsigned int)pto->tv_usec )); + (unsigned int)to.tv_sec, (unsigned int)to.tv_usec )); } } @@ -581,11 +578,19 @@ */ goto again; } + + { + struct timeval tmp = timed_events_timeout(); + to = timeval_min(&to, &tmp); + if (timeval_is_zero(&to)) { + return True; + } + } FD_SET(smbd_server_fd(),&fds); maxfd = setup_oplock_select_set(&fds); - selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,NULL,NULL,pto); + selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,NULL,NULL,&to); /* if we get EINTR then maybe we have received an oplock signal - treat this as select returning 1. This is ugly, but @@ -1431,16 +1436,13 @@ select_timeout *= 1000; t = change_notify_timeout(); + DEBUG(10, ("change_notify_timeout: %d\n", t)); if (t != -1) select_timeout = MIN(select_timeout, t*1000); if (print_notify_messages_pending()) select_timeout = MIN(select_timeout, 1000); - t = timed_events_timeout(); - if (t != -1) - select_timeout = MIN(select_timeout, t); - return select_timeout; } @@ -1792,7 +1794,7 @@ clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size); #endif - while (!receive_message_or_smb(InBuffer,BUFFER_SIZE+LARGE_WRITEX_HDR_SIZE,select_timeout)) { + while (!receive_message_or_smb(InBuffer,BUFFER_SIZE+LARGE_WRITEX_HDR_SIZE,-1)) { if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time)) return; num_smbs = 0; /* Reset smb counter. */
