svn commit: samba r9586 - in trunk/source/smbd: .

vlendec at samba.org vlendec at samba.org
Wed Aug 24 14:13:59 GMT 2005


Author: vlendec
Date: 2005-08-24 14:13:58 +0000 (Wed, 24 Aug 2005)
New Revision: 9586

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=9586

Log:
I *hate* code duplication... :-)

This changes the handling of the race condition where two smbd's detect that a
file does not exist and try to create it, and the share mode requests create a
violation or other error from the open_mode_check.

Volker

Modified:
   trunk/source/smbd/open.c


Changeset:
Modified: trunk/source/smbd/open.c
===================================================================
--- trunk/source/smbd/open.c	2005-08-24 13:27:24 UTC (rev 9585)
+++ trunk/source/smbd/open.c	2005-08-24 14:13:58 UTC (rev 9586)
@@ -707,6 +707,15 @@
 	SAFE_FREE(de_array);
 }
 
+static BOOL request_timed_out(struct timeval request_time,
+			      struct timeval timeout)
+{
+	struct timeval now, end_time;
+	GetTimeOfDay(&now);
+	end_time = timeval_sum(&request_time, &timeout);
+	return (timeval_compare(&end_time, &now) < 0);
+}
+
 /****************************************************************************
  Handle the 1 second delay in returning a SHARING_VIOLATION error.
 ****************************************************************************/
@@ -720,17 +729,6 @@
 	pid_t mypid = sys_getpid();
 	deferred_open_entry *de_array = NULL;
 	int num_de_entries, i;
-	struct timeval now, end_time;
-
-	GetTimeOfDay(&now);
-	end_time = timeval_sum(&request_time, &timeout);
-
-	if (timeval_compare(&end_time, &now) < 0) {
-		/* Request already timed out */
-		DEBUG(10, ("Request timed out\n"));
-		return;
-	}
-
 	/* Paranoia check */
 
 	num_de_entries = get_deferred_opens(state->dev, state->inode, &de_array);
@@ -1347,12 +1345,15 @@
 
 		if (delay_for_oplocks(fsp)) {
 			struct deferred_open_record state;
+			struct timeval timeout;
 
 			if (delayed_for_oplocks) {
 				DEBUG(0, ("Trying to delay for oplocks twice\n"));
 				exit_server("exiting");
 			}
 
+			timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0);
+
 			/* 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
@@ -1363,9 +1364,10 @@
 			state.dev = dev;
 			state.inode = inode;
 
-			defer_open(request_time, 
-				   timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0),
-				   fname, &state);
+			if (!request_timed_out(request_time, timeout)) {
+				defer_open(request_time, timeout,
+					   fname, &state);
+			}
 
 			unlock_share_entry(dev, inode);
 			return NULL;
@@ -1444,14 +1446,22 @@
 			 * cope with the braindead 1 second delay.
 			 */
 
-			if (!internal_only_open && lp_defer_sharing_violations()) {
+			if (!internal_only_open &&
+			    lp_defer_sharing_violations()) {
+				struct timeval timeout;
 				struct deferred_open_record state;
+
+				timeout = timeval_set(0, SHARING_VIOLATION_USEC_WAIT);
+
 				state.delayed_for_oplocks = False;
 				state.dev = dev;
 				state.inode = inode;
-				defer_open(request_time,
-					   timeval_set(0, SHARING_VIOLATION_USEC_WAIT),
-					   fname, &state);
+
+				if (!request_timed_out(request_time,
+						       timeout)) {
+					defer_open(request_time, timeout,
+						   fname, &state);
+				}
 			}
 
 			unlock_share_entry(dev, inode);
@@ -1514,16 +1524,17 @@
 		return NULL;
 	}
 
-	/*
-	 * Deal with the race condition where two smbd's detect the file
-	 * doesn't exist and do the create at the same time. One of them will
-	 * win and set a share mode, the other (ie. this one) should check if
-	 * the requested share mode for this create is allowed.
-	 */
-
 	if (!file_existed) { 
 
 		/*
+		 * Deal with the race condition where two smbd's detect the
+		 * file doesn't exist and do the create at the same time. One
+		 * of them will win and set a share mode, the other (ie. this
+		 * one) should check if the requested share mode for this
+		 * create is allowed.
+		 */
+
+		/*
 		 * Now the file exists and fsp is successfully opened,
 		 * fsp->dev and fsp->inode are valid and should replace the
 		 * dev=0,inode=0 from a non existent file. Spotted by
@@ -1539,63 +1550,26 @@
 					 access_mask, share_access,
 					 create_options, &file_existed);
 
-		if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
-			set_saved_ntstatus(status);
+		if (!NT_STATUS_IS_OK(status)) {
+			struct deferred_open_record state;
+
 			unlock_share_entry(dev, inode);
 			fd_close(conn, fsp);
 			file_free(fsp);
-			return NULL;
-		}
 
-		if (!NT_STATUS_IS_OK(status)) {
+			state.delayed_for_oplocks = False;
+			state.dev = dev;
+			state.inode = inode;
 
-			SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION));
+			/* Do it all over again immediately. In the second
+			 * round we will find that the file existed and handle
+			 * the DELETE_PENDING and FCB cases correctly. No need
+			 * to duplicate the code here. Essentially this is a
+			 * "goto top of this function", but don't tell
+			 * anybody... */
 
-			/* Check if this can be done with the deny_dos and fcb
-			 * calls. */
-			if (create_options &
-			    (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
-			     NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
-				files_struct *fsp_dup;
-				fsp_dup = fcb_or_dos_open(conn, fname, dev, inode,
-							  access_mask, share_access,
-							  create_options);
-				if (fsp_dup) {
-					unlock_share_entry(dev, inode);
-					fd_close(conn, fsp);
-					file_free(fsp);
-					if (pinfo) {
-						*pinfo = FILE_WAS_OPENED;
-					}
-					conn->num_files_open++;
-					return fsp_dup;
-				}
-
-				/* 
-				 * If we're returning a share violation,
-				 * ensure we cope with the braindead 1 second
-				 * delay.
-				 */
-
-				if (lp_defer_sharing_violations()) {
-					struct deferred_open_record state;
-					state.delayed_for_oplocks = False;
-					state.dev = dev;
-					state.inode = inode;
-					defer_open(request_time,
-						   timeval_set(0, SHARING_VIOLATION_USEC_WAIT),
-						   fname, &state);
-				}
-			}
-
-			unlock_share_entry_fsp(fsp);
-			fd_close(conn,fsp);
-			file_free(fsp);
-			/*
-			 * We have detected a sharing violation here, so
-			 * return the correct code.
-			 */
-			set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION);
+			defer_open(request_time, timeval_zero(),
+				   fname, &state);
 			return NULL;
 		}
 



More information about the samba-cvs mailing list