From 289911bb4e7980bf42cc87305d3f94477c5f2b75 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 12 Apr 2006 04:42:40 +0000 Subject: r15048: 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. (This used to be commit ba0b8a218dfe1ef6cdf7de724fb30650301369dd) --- source4/lib/messaging/messaging.h | 1 + source4/librpc/idl/opendb.idl | 1 + source4/ntvfs/common/opendb.c | 105 ++++++++++++++++++++++++++++++-------- source4/ntvfs/posix/pvfs_open.c | 51 ++++++++++++------ source4/ntvfs/posix/vfs_posix.c | 4 +- 5 files changed, 122 insertions(+), 40 deletions(-) (limited to 'source4') diff --git a/source4/lib/messaging/messaging.h b/source4/lib/messaging/messaging.h index de65eb9ffe..86f5db2c17 100644 --- a/source4/lib/messaging/messaging.h +++ b/source4/lib/messaging/messaging.h @@ -32,5 +32,6 @@ struct messaging_context; #define MSG_PVFS_RETRY_OPEN 5 #define MSG_IRPC 6 #define MSG_PVFS_NOTIFY 7 +#define MSG_NTVFS_OPLOCK_BREAK 8 #endif diff --git a/source4/librpc/idl/opendb.idl b/source4/librpc/idl/opendb.idl index 3754d233f6..601c143bf2 100644 --- a/source4/librpc/idl/opendb.idl +++ b/source4/librpc/idl/opendb.idl @@ -21,6 +21,7 @@ interface opendb /* 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 { diff --git a/source4/ntvfs/common/opendb.c b/source4/ntvfs/common/opendb.c index 81a13857ab..fc981d5af6 100644 --- a/source4/ntvfs/common/opendb.c +++ b/source4/ntvfs/common/opendb.c @@ -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 @@ struct odb_lock { 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,8 +90,10 @@ _PUBLIC_ struct odb_context *odb_init(TALLOC_CTX *mem_ctx, uint32_t server, 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 @@ static NTSTATUS odb_push_record(struct odb_lock *lck, struct opendb_file *file) 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 @@ static NTSTATUS odb_push_record(struct odb_lock *lck, struct opendb_file *file) _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 @@ _PUBLIC_ NTSTATUS odb_open_file(struct odb_lock *lck, void *file_handle, 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 @@ _PUBLIC_ NTSTATUS odb_open_file(struct odb_lock *lck, void *file_handle, 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;iserver; + 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 @@ _PUBLIC_ NTSTATUS odb_close_file(struct odb_lock *lck, void *file_handle) /* find the entry, and delete it */ for (i=0;iserver == 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 @@ _PUBLIC_ NTSTATUS odb_close_file(struct odb_lock *lck, void *file_handle) /* send any pending notifications, removing them once sent */ for (i=0;imessaging_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 @@ _PUBLIC_ NTSTATUS odb_remove_pending(struct odb_lock *lck, void *private) /* find the entry, and delete it */ for (i=0;iserver == 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 @@ _PUBLIC_ NTSTATUS odb_can_open(struct odb_lock *lck, 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 @@ _PUBLIC_ NTSTATUS odb_can_open(struct odb_lock *lck, 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; diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 5afb538db7..0a2cab8747 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -313,7 +313,8 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, /* 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 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, } 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 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, 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 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, 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 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, 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 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, 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 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, 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 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, 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 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, 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 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, 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; diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c index c4d4d11c04..eddc49c919 100644 --- a/source4/ntvfs/posix/vfs_posix.c +++ b/source4/ntvfs/posix/vfs_posix.c @@ -178,9 +178,7 @@ static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs, 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; } -- cgit