svn commit: samba r17153 - in branches/SAMBA_3_0_23/source/smbd: .

jra at samba.org jra at samba.org
Wed Jul 19 21:20:44 GMT 2006


Author: jra
Date: 2006-07-19 21:20:44 +0000 (Wed, 19 Jul 2006)
New Revision: 17153

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

Log:
Bring 3.0.23a up into line with the latest changes
in SAMBA_3_0. Fix kernel oplocks bug (efficiently).
Jerry - this needs merging for 3.0.23a.
Jeremy

Modified:
   branches/SAMBA_3_0_23/source/smbd/open.c


Changeset:
Modified: branches/SAMBA_3_0_23/source/smbd/open.c
===================================================================
--- branches/SAMBA_3_0_23/source/smbd/open.c	2006-07-19 21:03:03 UTC (rev 17152)
+++ branches/SAMBA_3_0_23/source/smbd/open.c	2006-07-19 21:20:44 UTC (rev 17153)
@@ -185,7 +185,8 @@
 			SMB_STRUCT_STAT *psbuf,
 			int flags,
 			mode_t unx_mode,
-			uint32 access_mask)
+			uint32 access_mask, /* client requested access mask. */
+			uint32 open_access_mask) /* what we're actually using in the open. */
 {
 	int accmode = (flags & O_ACCMODE);
 	int local_flags = flags;
@@ -239,7 +240,7 @@
 		local_flags = (flags & ~O_ACCMODE)|O_RDWR;
 	}
 
-	if ((access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||
+	if ((open_access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||
 	    (!file_existed && (local_flags & O_CREAT)) ||
 	    ((local_flags & O_TRUNC) == O_TRUNC) ) {
 
@@ -1112,6 +1113,7 @@
 	uint16 mid = get_current_mid();
 	struct timeval request_time = timeval_zero();
 	struct share_mode_lock *lck = NULL;
+	uint32 open_access_mask = access_mask;
 	NTSTATUS status;
 
 	if (conn->printer) {
@@ -1202,12 +1204,14 @@
 			/* If file exists replace/overwrite. If file doesn't
 			 * exist create. */
 			flags2 |= (O_CREAT | O_TRUNC);
+			open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */
 			break;
 
 		case FILE_OVERWRITE_IF:
 			/* If file exists replace/overwrite. If file doesn't
 			 * exist create. */
 			flags2 |= (O_CREAT | O_TRUNC);
+			open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */
 			break;
 
 		case FILE_OPEN:
@@ -1234,6 +1238,7 @@
 				return NULL;
 			}
 			flags2 |= O_TRUNC;
+			open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */
 			break;
 
 		case FILE_CREATE:
@@ -1286,7 +1291,10 @@
 
 	/* This is a nasty hack - must fix... JRA. */
 	if (access_mask == MAXIMUM_ALLOWED_ACCESS) {
-		access_mask = FILE_GENERIC_ALL;
+		open_access_mask = access_mask = FILE_GENERIC_ALL;
+		if (flags2 & O_TRUNC) {
+			open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */
+		}
 	}
 
 	/*
@@ -1351,7 +1359,7 @@
 	fsp->inode = psbuf->st_ino;
 	fsp->share_access = share_access;
 	fsp->fh->private_options = create_options;
-	fsp->access_mask = access_mask;
+	fsp->access_mask = open_access_mask; /* We change this to the requested access_mask after the open is done. */
 	/* Ensure no SAMBA_PRIVATE bits can be set. */
 	fsp->oplock_type = (oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK);
 
@@ -1382,6 +1390,7 @@
 			return NULL;
 		}
 
+		/* Use the client requested access mask here, not the one we open with. */
 		status = open_mode_check(conn, fname, lck,
 					 access_mask, share_access,
 					 create_options, &file_existed);
@@ -1417,6 +1426,8 @@
 			    (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
 			     NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
 				files_struct *fsp_dup;
+
+				/* Use the client requested access mask here, not the one we open with. */
 				fsp_dup = fcb_or_dos_open(conn, fname, dev,
 							  inode, access_mask,
 							  share_access,
@@ -1532,119 +1543,88 @@
 		 (unsigned int)flags, (unsigned int)flags2,
 		 (unsigned int)unx_mode));
 
-	/* Drop the lock before doing any real file access. Allows kernel
-	   oplock breaks to be processed. Handle any races after the open
-	   call when we re-acquire the lock. */
-
-	if (lck) {
-		TALLOC_FREE(lck);
-	}
-
 	/*
 	 * open_file strips any O_TRUNC flags itself.
 	 */
 
 	fsp_open = open_file(fsp,conn,fname,psbuf,flags|flags2,unx_mode,
-			     access_mask);
+				access_mask, open_access_mask);
 
 	if (!fsp_open) {
+		if (lck != NULL) {
+			TALLOC_FREE(lck);
+		}
 		file_free(fsp);
 		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) {
 
-	/*
-	 * 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
-	 * Nadav Danieli <nadavd at exanet.com>. JRA.
-	 */
+		/*
+		 * 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.
+		 */
 
-	dev = fsp->dev;
-	inode = fsp->inode;
+		/*
+		 * 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
+		 * Nadav Danieli <nadavd at exanet.com>. JRA.
+		 */
 
-	lck = get_share_mode_lock(NULL, dev, inode,
-				conn->connectpath,
-				fname);
+		dev = fsp->dev;
+		inode = fsp->inode;
 
-	if (lck == NULL) {
-		DEBUG(0, ("open_file_ntcreate: Could not get share mode lock for %s\n", fname));
-		fd_close(conn, fsp);
-		file_free(fsp);
-		set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION);
-		return NULL;
-	}
+		lck = get_share_mode_lock(NULL, dev, inode,
+					conn->connectpath,
+					fname);
 
-	/*
-	 * The share entry is again *locked*.....
-	 */
-
-	/* First pass - send break only on batch oplocks. */
-	if (delay_for_oplocks(lck, fsp, 1, oplock_request)) {
-		schedule_defer_open(lck, request_time);
-		fd_close(conn, fsp);
-		file_free(fsp);
-		TALLOC_FREE(lck);
-		set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION);
-		return NULL;
-	}
-
-	status = open_mode_check(conn, fname, lck,
-				 access_mask, share_access,
-				 create_options, &file_existed);
-
-	if (NT_STATUS_IS_OK(status)) {
-		/* We might be going to allow this open. Check oplock status again. */
-		/* Second pass - send break for both batch or exclusive oplocks. */
-		if (delay_for_oplocks(lck, fsp, 2, oplock_request)) {
-			schedule_defer_open(lck, request_time);
+		if (lck == NULL) {
+			DEBUG(0, ("open_file_ntcreate: Could not get share mode lock for %s\n", fname));
 			fd_close(conn, fsp);
 			file_free(fsp);
-			TALLOC_FREE(lck);
 			set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION);
 			return NULL;
 		}
-	}
 
-	if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
-		/* DELETE_PENDING is not deferred for a second */
-		fd_close(conn, fsp);
-		file_free(fsp);
-		TALLOC_FREE(lck);
-		set_saved_ntstatus(status);
-		return NULL;
-	}
+		status = open_mode_check(conn, fname, lck,
+					 access_mask, share_access,
+					 create_options, &file_existed);
 
-	if (!NT_STATUS_IS_OK(status)) {
-		struct deferred_open_record state;
+		if (!NT_STATUS_IS_OK(status)) {
+			struct deferred_open_record state;
 
-		fd_close(conn, fsp);
-		file_free(fsp);
+			fd_close(conn, fsp);
+			file_free(fsp);
 
-		state.delayed_for_oplocks = False;
-		state.dev = dev;
-		state.inode = inode;
+			state.delayed_for_oplocks = False;
+			state.dev = dev;
+			state.inode = inode;
 
-		/* 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... */
+			/* 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... */
 
-		defer_open(lck, request_time, timeval_zero(),
-			   &state);
-		TALLOC_FREE(lck);
-		return NULL;
+			defer_open(lck, request_time, timeval_zero(),
+				   &state);
+			TALLOC_FREE(lck);
+			return NULL;
+		}
+
+		/*
+		 * We exit this block with the share entry *locked*.....
+		 */
+
 	}
 
+	SMB_ASSERT(lck != NULL);
+
 	/* note that we ignore failure for the following. It is
            basically a hack for NFS, and NFS will never set one of
            these only read them. Nobody but Samba can ever set a deny
@@ -1685,7 +1665,7 @@
 
 	if (file_existed) {
 		/* stat opens on existing files don't get oplocks. */
-		if (is_stat_open(fsp->access_mask)) {
+		if (is_stat_open(open_access_mask)) {
 			fsp->oplock_type = NO_OPLOCK;
 		}
 
@@ -1828,7 +1808,7 @@
 
 	/* note! we must use a non-zero desired access or we don't get
            a real file descriptor. Oh what a twisted web we weave. */
-	fsp_open = open_file(fsp,conn,fname,psbuf,O_WRONLY,0,FILE_WRITE_DATA);
+	fsp_open = open_file(fsp,conn,fname,psbuf,O_WRONLY,0,FILE_WRITE_DATA,FILE_WRITE_DATA);
 
 	/* 
 	 * This is not a user visible file open.



More information about the samba-cvs mailing list