svn commit: samba r15048 - in branches/SAMBA_4_0/source: lib/messaging librpc/idl ntvfs/common ntvfs/posix

tridge at samba.org tridge at samba.org
Wed Apr 12 04:42:41 GMT 2006


Author: tridge
Date: 2006-04-12 04:42:40 +0000 (Wed, 12 Apr 2006)
New Revision: 15048

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

Log:

started on the server side implementation of oplocks. The code is not
functional yet, I'm committing so it doesn't diverge too much from
other peoples work. It is disabled by default.

Modified:
   branches/SAMBA_4_0/source/lib/messaging/messaging.h
   branches/SAMBA_4_0/source/librpc/idl/opendb.idl
   branches/SAMBA_4_0/source/ntvfs/common/opendb.c
   branches/SAMBA_4_0/source/ntvfs/posix/pvfs_open.c
   branches/SAMBA_4_0/source/ntvfs/posix/vfs_posix.c


Changeset:
Modified: branches/SAMBA_4_0/source/lib/messaging/messaging.h
===================================================================
--- branches/SAMBA_4_0/source/lib/messaging/messaging.h	2006-04-12 00:07:40 UTC (rev 15047)
+++ branches/SAMBA_4_0/source/lib/messaging/messaging.h	2006-04-12 04:42:40 UTC (rev 15048)
@@ -32,5 +32,6 @@
 #define MSG_PVFS_RETRY_OPEN	5
 #define MSG_IRPC                6
 #define MSG_PVFS_NOTIFY		7
+#define MSG_NTVFS_OPLOCK_BREAK	8
 
 #endif

Modified: branches/SAMBA_4_0/source/librpc/idl/opendb.idl
===================================================================
--- branches/SAMBA_4_0/source/librpc/idl/opendb.idl	2006-04-12 00:07:40 UTC (rev 15047)
+++ branches/SAMBA_4_0/source/librpc/idl/opendb.idl	2006-04-12 04:42:40 UTC (rev 15048)
@@ -21,6 +21,7 @@
 		/* we need a per-entry delete on close, as well as a per-file
 		   one, to cope with strange semantics on open */
 		bool8 delete_on_close;
+		uint32 oplock_level;
 	} opendb_entry;
 
 	typedef struct {

Modified: branches/SAMBA_4_0/source/ntvfs/common/opendb.c
===================================================================
--- branches/SAMBA_4_0/source/ntvfs/common/opendb.c	2006-04-12 00:07:40 UTC (rev 15047)
+++ branches/SAMBA_4_0/source/ntvfs/common/opendb.c	2006-04-12 04:42:40 UTC (rev 15048)
@@ -47,11 +47,12 @@
 #include "lib/messaging/irpc.h"
 #include "librpc/gen_ndr/ndr_opendb.h"
 #include "smb.h"
+#include "ntvfs/ntvfs.h"
 
 struct odb_context {
 	struct tdb_wrap *w;
-	uint32_t server;
-	struct messaging_context *messaging_ctx;
+	struct ntvfs_context *ntvfs_ctx;
+	BOOL oplocks;
 };
 
 /*
@@ -68,8 +69,8 @@
   talloc_free(). We need the messaging_ctx to allow for pending open
   notifications.
 */
-_PUBLIC_ struct odb_context *odb_init(TALLOC_CTX *mem_ctx, uint32_t server, 
-				      struct messaging_context *messaging_ctx)
+_PUBLIC_ struct odb_context *odb_init(TALLOC_CTX *mem_ctx, 
+				      struct ntvfs_context *ntvfs_ctx)
 {
 	char *path;
 	struct odb_context *odb;
@@ -89,9 +90,11 @@
 		return NULL;
 	}
 
-	odb->server = server;
-	odb->messaging_ctx = messaging_ctx;
+	odb->ntvfs_ctx = ntvfs_ctx;
 
+	/* leave oplocks disabled by default until the code is working */
+	odb->oplocks = lp_parm_bool(-1, "opendb", "oplocks", False);
+
 	return odb;
 }
 
@@ -249,6 +252,16 @@
 	return NT_STATUS_OK;
 }
 
+/*
+  send an oplock break to a client
+*/
+static NTSTATUS odb_oplock_break_send(struct odb_context *odb, struct opendb_entry *e)
+{
+	/* tell the server handling this open file about the need to send the client
+	   a break */
+	return messaging_send_ptr(odb->ntvfs_ctx->msg_ctx, e->server, 
+				  MSG_NTVFS_OPLOCK_BREAK, e->file_handle);
+}
 
 /*
   register an open file in the open files database. This implements the share_access
@@ -260,7 +273,8 @@
 _PUBLIC_ NTSTATUS odb_open_file(struct odb_lock *lck, void *file_handle,
 				uint32_t stream_id, uint32_t share_access, 
 				uint32_t access_mask, BOOL delete_on_close,
-				const char *path)
+				const char *path, 
+				uint32_t oplock_level, uint32_t *oplock_granted)
 {
 	struct odb_context *odb = lck->odb;
 	struct opendb_entry e;
@@ -268,6 +282,10 @@
 	struct opendb_file file;
 	NTSTATUS status;
 
+	if (odb->oplocks == False) {
+		oplock_level = OPLOCK_NONE;
+	}
+
 	status = odb_pull_record(lck, &file);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
 		/* initialise a blank structure */
@@ -277,27 +295,70 @@
 		NT_STATUS_NOT_OK_RETURN(status);
 	}
 
-
-	if (file.delete_on_close || 
-	    (file.num_entries != 0 && delete_on_close)) {
-		/* while delete on close is set, no new opens are allowed */
-		return NT_STATUS_DELETE_PENDING;
-	}
-
 	/* see if it conflicts */
-	e.server          = odb->server;
+	e.server          = odb->ntvfs_ctx->server_id;
 	e.file_handle     = file_handle;
 	e.stream_id       = stream_id;
 	e.share_access    = share_access;
 	e.access_mask     = access_mask;
 	e.delete_on_close = delete_on_close;
+	e.oplock_level    = OPLOCK_NONE;
 		
+	/* see if anyone has an oplock, which we need to break */
 	for (i=0;i<file.num_entries;i++) {
+		if (file.entries[i].oplock_level == OPLOCK_BATCH) {
+			/* a batch oplock caches close calls, which
+			   means the client application might have
+			   already closed the file. We have to allow
+			   this close to propogate by sending a oplock
+			   break request and suspending this call
+			   until the break is acknowledged or the file
+			   is closed */
+			odb_oplock_break_send(odb, &file.entries[i]);
+			return NT_STATUS_OPLOCK_NOT_GRANTED;
+		}
+	}
+
+	if (file.delete_on_close || 
+	    (file.num_entries != 0 && delete_on_close)) {
+		/* while delete on close is set, no new opens are allowed */
+		return NT_STATUS_DELETE_PENDING;
+	}
+
+	/* check for sharing violations */
+	for (i=0;i<file.num_entries;i++) {
 		status = share_conflict(&file.entries[i], &e);
 		NT_STATUS_NOT_OK_RETURN(status);
 	}
 
-	/* it doesn't, so add it to the end */
+	/* we now know the open could succeed, but we need to check
+	   for any exclusive oplocks. We can't grant a second open
+	   till these are broken. Note that we check for batch oplocks
+	   before checking for sharing violations, and check for
+	   exclusive oplocks afterwards. */
+	for (i=0;i<file.num_entries;i++) {
+		if (file.entries[i].oplock_level == OPLOCK_EXCLUSIVE) {
+			odb_oplock_break_send(odb, &file.entries[i]);
+			return NT_STATUS_OPLOCK_NOT_GRANTED;
+		}
+	}
+
+	/*
+	  possibly grant an exclusive or batch oplock if this is the only client
+	  with the file open. We don't yet grant levelII oplocks.
+	*/
+	if (oplock_granted != NULL) {
+		if ((oplock_level == OPLOCK_BATCH ||
+		     oplock_level == OPLOCK_EXCLUSIVE) &&
+		    file.num_entries == 0) {
+			(*oplock_granted) = oplock_level;
+		} else {
+			(*oplock_granted) = OPLOCK_NONE;
+		}
+		e.oplock_level = (*oplock_granted);
+	}
+
+	/* it doesn't conflict, so add it to the end */
 	file.entries = talloc_realloc(lck, file.entries, struct opendb_entry, 
 				      file.num_entries+1);
 	NT_STATUS_HAVE_NO_MEMORY(file.entries);
@@ -325,7 +386,7 @@
 				      file.num_pending+1);
 	NT_STATUS_HAVE_NO_MEMORY(file.pending);
 
-	file.pending[file.num_pending].server = odb->server;
+	file.pending[file.num_pending].server = odb->ntvfs_ctx->server_id;
 	file.pending[file.num_pending].notify_ptr = private;
 
 	file.num_pending++;
@@ -350,7 +411,7 @@
 	/* find the entry, and delete it */
 	for (i=0;i<file.num_entries;i++) {
 		if (file_handle == file.entries[i].file_handle &&
-		    odb->server == file.entries[i].server) {
+		    odb->ntvfs_ctx->server_id == file.entries[i].server) {
 			if (file.entries[i].delete_on_close) {
 				file.delete_on_close = True;
 			}
@@ -369,7 +430,7 @@
 
 	/* send any pending notifications, removing them once sent */
 	for (i=0;i<file.num_pending;i++) {
-		messaging_send_ptr(odb->messaging_ctx, file.pending[i].server, 
+		messaging_send_ptr(odb->ntvfs_ctx->msg_ctx, file.pending[i].server, 
 				   MSG_PVFS_RETRY_OPEN, 
 				   file.pending[i].notify_ptr);
 	}
@@ -397,7 +458,7 @@
 	/* find the entry, and delete it */
 	for (i=0;i<file.num_pending;i++) {
 		if (private == file.pending[i].notify_ptr &&
-		    odb->server == file.pending[i].server) {
+		    odb->ntvfs_ctx->server_id == file.pending[i].server) {
 			if (i < file.num_pending-1) {
 				memmove(file.pending+i, file.pending+i+1, 
 					(file.num_pending - (i+1)) * 
@@ -525,7 +586,7 @@
 		return NT_STATUS_DELETE_PENDING;
 	}
 
-	e.server       = odb->server;
+	e.server       = odb->ntvfs_ctx->server_id;
 	e.file_handle  = NULL;
 	e.stream_id    = 0;
 	e.share_access = share_access;
@@ -536,7 +597,7 @@
 		if (!NT_STATUS_IS_OK(status)) {
 			/* note that we discard the error code
 			   here. We do this as unless we are actually
-			   doing an open (which comes via a sdifferent
+			   doing an open (which comes via a different
 			   function), we need to return a sharing
 			   violation */
 			return NT_STATUS_SHARING_VIOLATION;

Modified: branches/SAMBA_4_0/source/ntvfs/posix/pvfs_open.c
===================================================================
--- branches/SAMBA_4_0/source/ntvfs/posix/pvfs_open.c	2006-04-12 00:07:40 UTC (rev 15047)
+++ branches/SAMBA_4_0/source/ntvfs/posix/pvfs_open.c	2006-04-12 04:42:40 UTC (rev 15048)
@@ -313,7 +313,8 @@
 		
 		/* see if we are allowed to open at the same time as existing opens */
 		status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
-				       share_access, access_mask, del_on_close, name->full_name);
+				       share_access, access_mask, del_on_close, 
+				       name->full_name, OPLOCK_NONE, NULL);
 
 		if (!NT_STATUS_IS_OK(status)) {
 			idr_remove(pvfs->files.idtree, f->fnum);
@@ -369,7 +370,8 @@
 		}
 
 		status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
-				       share_access, access_mask, del_on_close, name->full_name);
+				       share_access, access_mask, del_on_close, 
+				       name->full_name, OPLOCK_NONE, NULL);
 
 		if (!NT_STATUS_IS_OK(status)) {
 			goto cleanup_delete;
@@ -563,6 +565,7 @@
 	uint32_t attrib;
 	BOOL del_on_close;
 	struct pvfs_filename *parent;
+	uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
 
 	if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
 	    (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
@@ -678,8 +681,17 @@
 		del_on_close = False;
 	}
 
+	if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
+		oplock_level = OPLOCK_NONE;
+	} else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
+		oplock_level = OPLOCK_BATCH;
+	} else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
+		oplock_level = OPLOCK_EXCLUSIVE;
+	}
+
 	status = odb_open_file(lck, f->handle, name->stream_id,
-			       share_access, access_mask, del_on_close, name->full_name);
+			       share_access, access_mask, del_on_close, 
+			       name->full_name, oplock_level, &oplock_granted);
 	talloc_free(lck);
 	if (!NT_STATUS_IS_OK(status)) {
 		/* bad news, we must have hit a race - we don't delete the file
@@ -690,6 +702,10 @@
 		return status;
 	}
 
+	if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
+		oplock_granted = OPLOCK_BATCH;
+	}
+
 	f->fnum              = fnum;
 	f->session_info      = req->session_info;
 	f->smbpid            = req->smbpid;
@@ -718,12 +734,7 @@
 	talloc_set_destructor(f, pvfs_fnum_destructor);
 	talloc_set_destructor(f->handle, pvfs_handle_destructor);
 
-	
-	if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
-		io->generic.out.oplock_level  = OPLOCK_BATCH;
-	} else {
-		io->generic.out.oplock_level  = OPLOCK_NONE;
-	}
+	io->generic.out.oplock_level  = oplock_granted;
 	io->generic.out.file.fnum     = f->fnum;
 	io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
 	io->generic.out.create_time   = name->dos.create_time;
@@ -994,6 +1005,7 @@
 	uint32_t share_access;
 	uint32_t access_mask;
 	BOOL stream_existed, stream_truncate=False;
+	uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
 
 	/* use the generic mapping code to avoid implementing all the
 	   different open calls. */
@@ -1174,9 +1186,18 @@
 	talloc_set_destructor(f, pvfs_fnum_destructor);
 	talloc_set_destructor(f->handle, pvfs_handle_destructor);
 
+	if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
+		oplock_level = OPLOCK_NONE;
+	} else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
+		oplock_level = OPLOCK_BATCH;
+	} else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
+		oplock_level = OPLOCK_EXCLUSIVE;
+	}
+
 	/* see if we are allowed to open at the same time as existing opens */
 	status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
-			       share_access, access_mask, False, name->full_name);
+			       share_access, access_mask, False, name->full_name,
+			       oplock_level, &oplock_granted);
 
 	/* on a sharing violation we need to retry when the file is closed by 
 	   the other user, or after 1 second */
@@ -1190,6 +1211,10 @@
 		return status;
 	}
 
+	if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
+		oplock_granted = OPLOCK_BATCH;
+	}
+
 	f->handle->have_opendb_entry = True;
 
 	if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
@@ -1252,11 +1277,7 @@
 	    
 	talloc_free(lck);
 
-	if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
-		io->generic.out.oplock_level  = OPLOCK_BATCH;
-	} else {
-		io->generic.out.oplock_level  = OPLOCK_NONE;
-	}
+	io->generic.out.oplock_level  = oplock_granted;
 	io->generic.out.file.fnum     = f->fnum;
 	io->generic.out.create_action = stream_existed?
 		NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;

Modified: branches/SAMBA_4_0/source/ntvfs/posix/vfs_posix.c
===================================================================
--- branches/SAMBA_4_0/source/ntvfs/posix/vfs_posix.c	2006-04-12 00:07:40 UTC (rev 15047)
+++ branches/SAMBA_4_0/source/ntvfs/posix/vfs_posix.c	2006-04-12 04:42:40 UTC (rev 15048)
@@ -178,9 +178,7 @@
 		return NT_STATUS_INTERNAL_DB_CORRUPTION;
 	}
 
-	pvfs->odb_context = odb_init(pvfs, 
-				     pvfs->ntvfs->ctx->server_id,  
-				     pvfs->ntvfs->ctx->msg_ctx);
+	pvfs->odb_context = odb_init(pvfs, pvfs->ntvfs->ctx);
 	if (pvfs->odb_context == NULL) {
 		return NT_STATUS_INTERNAL_DB_CORRUPTION;
 	}



More information about the samba-cvs mailing list