From af0d863ce78a4afb1e2add837613a665d54031eb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 4 Mar 2008 14:10:13 +0100 Subject: pvfs_oplock: move pvfs_oplock_release() parts into a helper function metze (This used to be commit 2b8934e4ab2dd9673928a6c9a291aedac1ebaa95) --- source4/ntvfs/posix/pvfs_oplock.c | 99 ++++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 43 deletions(-) (limited to 'source4/ntvfs') diff --git a/source4/ntvfs/posix/pvfs_oplock.c b/source4/ntvfs/posix/pvfs_oplock.c index cf30ddbc59..b830ad2adc 100644 --- a/source4/ntvfs/posix/pvfs_oplock.c +++ b/source4/ntvfs/posix/pvfs_oplock.c @@ -32,6 +32,58 @@ struct pvfs_oplock { struct messaging_context *msg_ctx; }; +static NTSTATUS pvfs_oplock_release_internal(struct pvfs_file_handle *h, + uint8_t oplock_break) +{ + struct odb_lock *olck; + NTSTATUS status; + + if (h->fd == -1) { + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + + if (!h->have_opendb_entry) { + return NT_STATUS_FOOBAR; + } + + if (!h->oplock) { + return NT_STATUS_FOOBAR; + } + + olck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); + if (olck == NULL) { + DEBUG(0,("Unable to lock opendb for oplock update\n")); + return NT_STATUS_FOOBAR; + } + + if (oplock_break == OPLOCK_BREAK_TO_NONE) { + h->oplock->level = OPLOCK_NONE; + } else if (oplock_break == OPLOCK_BREAK_TO_LEVEL_II) { + h->oplock->level = OPLOCK_LEVEL_II; + } else { + /* fallback to level II in case of a invalid value */ + DEBUG(1,("unexpected oplock break level[0x%02X]\n", oplock_break)); + h->oplock->level = OPLOCK_LEVEL_II; + } + status = odb_update_oplock(olck, h, h->oplock->level); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Unable to update oplock level for '%s' - %s\n", + h->name->full_name, nt_errstr(status))); + talloc_free(olck); + return status; + } + + talloc_free(olck); + + /* after a break to none, we no longer have an oplock attached */ + if (h->oplock->level == OPLOCK_NONE) { + talloc_free(h->oplock); + h->oplock = NULL; + } + + return NT_STATUS_OK; +} + /* receive oplock breaks and forward them to the client */ @@ -140,8 +192,6 @@ NTSTATUS pvfs_oplock_release(struct ntvfs_module_context *ntvfs, { struct pvfs_state *pvfs = ntvfs->private_data; struct pvfs_file *f; - struct pvfs_file_handle *h; - struct odb_lock *olck; uint8_t oplock_break; NTSTATUS status; @@ -150,52 +200,15 @@ NTSTATUS pvfs_oplock_release(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_HANDLE; } - h = f->handle; - - if (h->fd == -1) { - return NT_STATUS_FILE_IS_A_DIRECTORY; - } - - if (!h->have_opendb_entry) { - return NT_STATUS_FOOBAR; - } - - if (!h->oplock) { - return NT_STATUS_FOOBAR; - } - - olck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); - if (olck == NULL) { - DEBUG(0,("Unable to lock opendb for oplock update\n")); - return NT_STATUS_FOOBAR; - } - oplock_break = (lck->lockx.in.mode >> 8) & 0xFF; - if (oplock_break == OPLOCK_BREAK_TO_NONE) { - h->oplock->level = OPLOCK_NONE; - } else if (oplock_break == OPLOCK_BREAK_TO_LEVEL_II) { - h->oplock->level = OPLOCK_LEVEL_II; - } else { - /* fallback to level II in case of a invalid value */ - DEBUG(1,("unexpected oplock break level[0x%02X]\n", oplock_break)); - h->oplock->level = OPLOCK_LEVEL_II; - } - status = odb_update_oplock(olck, h, h->oplock->level); + + status = pvfs_oplock_release_internal(f->handle, oplock_break); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Unable to update oplock level for '%s' - %s\n", - h->name->full_name, nt_errstr(status))); - talloc_free(olck); + DEBUG(0,("%s: failed to release the oplock[0x%02X]: %s\n", + __FUNCTION__, oplock_break, nt_errstr(status))); return status; } - talloc_free(olck); - - /* after a break to none, we no longer have an oplock attached */ - if (h->oplock->level == OPLOCK_NONE) { - talloc_free(h->oplock); - h->oplock = NULL; - } - return NT_STATUS_OK; } -- cgit From 1f5301c1d2182993d8f8cdaa65763408faff080d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 4 Mar 2008 14:11:53 +0100 Subject: pvfs_oplock: only a break level2 oplocks... It seems that I've tested this in the wrong way before. metze (This used to be commit 21772fa33d772a9df6ff04a0ed1b0d8f4f533295) --- source4/ntvfs/posix/pvfs_oplock.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'source4/ntvfs') diff --git a/source4/ntvfs/posix/pvfs_oplock.c b/source4/ntvfs/posix/pvfs_oplock.c index b830ad2adc..3f581e5443 100644 --- a/source4/ntvfs/posix/pvfs_oplock.c +++ b/source4/ntvfs/posix/pvfs_oplock.c @@ -218,7 +218,7 @@ NTSTATUS pvfs_break_level2_oplocks(struct pvfs_file *f) struct odb_lock *olck; NTSTATUS status; - if (h->oplock && h->oplock->level == OPLOCK_EXCLUSIVE) { + if (h->oplock && h->oplock->level != OPLOCK_LEVEL_II) { return NT_STATUS_OK; } @@ -228,16 +228,6 @@ NTSTATUS pvfs_break_level2_oplocks(struct pvfs_file *f) return NT_STATUS_FOOBAR; } - if (h->oplock && h->oplock->level == OPLOCK_BATCH) { - status = odb_update_oplock(olck, h, OPLOCK_LEVEL_II); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Unable to update oplock level for '%s' - %s\n", - h->name->full_name, nt_errstr(status))); - talloc_free(olck); - return status; - } - } - status = odb_break_oplocks(olck); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Unable to break level2 oplocks to none for '%s' - %s\n", -- cgit From eb26c896a2523c8d635b5b34c21a0c43e20d10b6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 4 Mar 2008 14:16:17 +0100 Subject: pvfs_oplock: auto release oplocks after a timeout Remember that we sent an oplock break to a client and don't resend. If the filesystem layer tries to send a new break and the client has not released after a former oplock break after the timeout interval, we need to auto release the oplock. metze (This used to be commit bfb0888578677856b2b6b72471f542d0d5d7b838) --- source4/ntvfs/posix/pvfs_oplock.c | 67 +++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 6 deletions(-) (limited to 'source4/ntvfs') diff --git a/source4/ntvfs/posix/pvfs_oplock.c b/source4/ntvfs/posix/pvfs_oplock.c index 3f581e5443..dfa3697af7 100644 --- a/source4/ntvfs/posix/pvfs_oplock.c +++ b/source4/ntvfs/posix/pvfs_oplock.c @@ -22,6 +22,7 @@ #include "includes.h" #include "lib/messaging/messaging.h" #include "lib/messaging/irpc.h" +#include "system/time.h" #include "vfs_posix.h" @@ -29,6 +30,8 @@ struct pvfs_oplock { struct pvfs_file_handle *handle; struct pvfs_file *file; uint32_t level; + struct timeval break_to_level_II; + struct timeval break_to_none; struct messaging_context *msg_ctx; }; @@ -93,13 +96,65 @@ static void pvfs_oplock_break(struct pvfs_oplock *opl, uint8_t level) struct pvfs_file *f = opl->file; struct pvfs_file_handle *h = opl->handle; struct pvfs_state *pvfs = h->pvfs; + struct timeval cur = timeval_current(); + struct timeval *last = NULL; + struct timeval end; - DEBUG(10,("pvfs_oplock_break: sending oplock break level %d for '%s' %p\n", - level, h->name->original_name, h)); - status = ntvfs_send_oplock_break(pvfs->ntvfs, f->ntvfs, level); + switch (level) { + case OPLOCK_BREAK_TO_LEVEL_II: + last = &opl->break_to_level_II; + break; + case OPLOCK_BREAK_TO_NONE: + last = &opl->break_to_none; + break; + } + + if (!last) { + DEBUG(0,("%s: got unexpected level[0x%02X]\n", + __FUNCTION__, level)); + return; + } + + if (timeval_is_zero(last)) { + /* + * this is the first break we for this level + * remember the time + */ + *last = cur; + + DEBUG(0,("%s: sending oplock break level %d for '%s' %p\n", + __FUNCTION__, level, h->name->original_name, h)); + status = ntvfs_send_oplock_break(pvfs->ntvfs, f->ntvfs, level); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("%s: sending oplock break failed: %s\n", + __FUNCTION__, nt_errstr(status))); + } + return; + } + + end = timeval_add(last, pvfs->oplock_break_timeout, 0); + + if (timeval_compare(&cur, &end) < 0) { + /* + * If it's not expired just ignore the break + * as we already sent the break request to the client + */ + DEBUG(0,("%s: do not resend oplock break level %d for '%s' %p\n", + __FUNCTION__, level, h->name->original_name, h)); + return; + } + + /* + * If the client did not send a release within the + * oplock break timeout time frame we auto release + * the oplock + */ + DEBUG(0,("%s: auto release oplock level %d for '%s' %p\n", + __FUNCTION__, level, h->name->original_name, h)); + status = pvfs_oplock_release_internal(h, level); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("pvfs_oplock_break: sending oplock break failed: %s\n", - nt_errstr(status))); + DEBUG(0,("%s: failed to auto release the oplock[0x%02X]: %s\n", + __FUNCTION__, level, nt_errstr(status))); } } @@ -165,7 +220,7 @@ NTSTATUS pvfs_setup_oplock(struct pvfs_file *f, uint32_t oplock_granted) return NT_STATUS_OK; } - opl = talloc(f->handle, struct pvfs_oplock); + opl = talloc_zero(f->handle, struct pvfs_oplock); NT_STATUS_HAVE_NO_MEMORY(opl); opl->handle = f->handle; -- cgit From 87f2925252b910f2f403bdbb3f9158202cb7a2c5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 6 Mar 2008 15:14:08 +0100 Subject: ntvfs: pass down the client capabilities into the ntvfs layer Note that we don't use any protocol specific values here. For now only NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS is defined others should be defined, when we find out that the ntvfs layer needs to know about it. metze (This used to be commit cc42cd5f6753ca582677fa6f403f0419eec5ab10) --- source4/ntvfs/ntvfs.h | 16 ++++++++++++++++ source4/ntvfs/ntvfs_base.c | 2 ++ source4/ntvfs/ntvfs_util.c | 1 + 3 files changed, 19 insertions(+) (limited to 'source4/ntvfs') diff --git a/source4/ntvfs/ntvfs.h b/source4/ntvfs/ntvfs.h index a708dbff51..7a2edc7e2c 100644 --- a/source4/ntvfs/ntvfs.h +++ b/source4/ntvfs/ntvfs.h @@ -181,6 +181,14 @@ struct ntvfs_context { enum protocol_types protocol; + /* + * client capabilities + * this field doesn't use protocol specific + * values! + */ +#define NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS 0x0000000000000001LLU + uint64_t client_caps; + /* * linked list of module contexts */ @@ -257,6 +265,14 @@ struct ntvfs_request { /* the smb pid is needed for locking contexts */ uint16_t smbpid; + /* + * client capabilities + * this field doesn't use protocol specific + * values! + * see NTVFS_CLIENT_CAP_* + */ + uint64_t client_caps; + /* some statictics for the management tools */ struct { /* the system time when the request arrived */ diff --git a/source4/ntvfs/ntvfs_base.c b/source4/ntvfs/ntvfs_base.c index f5a24f23a0..35becabcf9 100644 --- a/source4/ntvfs/ntvfs_base.c +++ b/source4/ntvfs/ntvfs_base.c @@ -153,6 +153,7 @@ _PUBLIC_ bool ntvfs_interface_differs(const struct ntvfs_critical_sizes *const i */ NTSTATUS ntvfs_init_connection(TALLOC_CTX *mem_ctx, struct share_config *scfg, enum ntvfs_type type, enum protocol_types protocol, + uint64_t ntvfs_client_caps, struct event_context *ev, struct messaging_context *msg, struct loadparm_context *lp_ctx, struct server_id server_id, struct ntvfs_context **_ctx) @@ -168,6 +169,7 @@ NTSTATUS ntvfs_init_connection(TALLOC_CTX *mem_ctx, struct share_config *scfg, e ctx = talloc_zero(mem_ctx, struct ntvfs_context); NT_STATUS_HAVE_NO_MEMORY(ctx); ctx->protocol = protocol; + ctx->client_caps = ntvfs_client_caps; ctx->type = type; ctx->config = talloc_steal(ctx, scfg); ctx->event_ctx = ev; diff --git a/source4/ntvfs/ntvfs_util.c b/source4/ntvfs/ntvfs_util.c index 7432ac2c13..ebe8008edd 100644 --- a/source4/ntvfs/ntvfs_util.c +++ b/source4/ntvfs/ntvfs_util.c @@ -42,6 +42,7 @@ _PUBLIC_ struct ntvfs_request *ntvfs_request_create(struct ntvfs_context *ctx, T req->async_states = NULL; req->session_info = session_info; req->smbpid = smbpid; + req->client_caps = ctx->client_caps; req->statistics.request_time = request_time; async = talloc(req, struct ntvfs_async_state); -- cgit From 0339ae5ad82c248b43afa9431b13cda536b18fd6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 6 Mar 2008 15:34:37 +0100 Subject: pvfs_open: fix crash/leak in case pvfs_setup_oplock() fails metze (This used to be commit 5563238782e825f64a22b5f9e0a7deb687f50b19) --- source4/ntvfs/posix/pvfs_open.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'source4/ntvfs') diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index adf4c1ac18..792e35cd14 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -696,21 +696,20 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, DLIST_ADD(pvfs->files.list, f); + /* setup a destructor to avoid file descriptor leaks on + abnormal termination */ + talloc_set_destructor(f, pvfs_fnum_destructor); + talloc_set_destructor(f->handle, pvfs_handle_destructor); + if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) { oplock_granted = OPLOCK_BATCH; } else if (oplock_granted != OPLOCK_NONE) { status = pvfs_setup_oplock(f, oplock_granted); if (!NT_STATUS_IS_OK(status)) { - talloc_free(lck); return status; } } - /* setup a destructor to avoid file descriptor leaks on - abnormal termination */ - talloc_set_destructor(f, pvfs_fnum_destructor); - talloc_set_destructor(f->handle, pvfs_handle_destructor); - io->generic.out.oplock_level = oplock_granted; io->generic.out.file.ntvfs = f->ntvfs; io->generic.out.create_action = NTCREATEX_ACTION_CREATED; -- cgit From b7db5f7cb57eca4bf28fd8238e5f958a6038158e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 6 Mar 2008 15:47:27 +0100 Subject: opendb: add allow_level_II_oplock parameter to odb_open_file() Not all clients support a fallback to level II oplocks. metze (This used to be commit 146f1fe0b67ca0805f0e71358abc57da0c0579a9) --- source4/ntvfs/common/opendb.c | 4 +++- source4/ntvfs/common/opendb.h | 1 + source4/ntvfs/common/opendb_tdb.c | 32 +++++++++++++++++++++----------- 3 files changed, 25 insertions(+), 12 deletions(-) (limited to 'source4/ntvfs') diff --git a/source4/ntvfs/common/opendb.c b/source4/ntvfs/common/opendb.c index 6c1a9c070a..a7e5458aaf 100644 --- a/source4/ntvfs/common/opendb.c +++ b/source4/ntvfs/common/opendb.c @@ -98,11 +98,13 @@ _PUBLIC_ NTSTATUS odb_open_file(struct odb_lock *lck, uint32_t stream_id, uint32_t share_access, uint32_t access_mask, bool delete_on_close, uint32_t open_disposition, bool break_to_none, + bool allow_level_II_oplock, uint32_t oplock_level, uint32_t *oplock_granted) { return ops->odb_open_file(lck, file_handle, path, stream_id, share_access, access_mask, delete_on_close, open_disposition, - break_to_none, oplock_level, oplock_granted); + break_to_none, allow_level_II_oplock, + oplock_level, oplock_granted); } diff --git a/source4/ntvfs/common/opendb.h b/source4/ntvfs/common/opendb.h index 69a7f718ba..1c7f815dea 100644 --- a/source4/ntvfs/common/opendb.h +++ b/source4/ntvfs/common/opendb.h @@ -30,6 +30,7 @@ struct opendb_ops { uint32_t stream_id, uint32_t share_access, uint32_t access_mask, bool delete_on_close, uint32_t open_disposition, bool break_to_none, + bool allow_level_II_oplock, uint32_t oplock_level, uint32_t *oplock_granted); NTSTATUS (*odb_open_file_pending)(struct odb_lock *lck, void *private); NTSTATUS (*odb_close_file)(struct odb_lock *lck, void *file_handle, diff --git a/source4/ntvfs/common/opendb_tdb.c b/source4/ntvfs/common/opendb_tdb.c index 47b35f594c..0736af3d1e 100644 --- a/source4/ntvfs/common/opendb_tdb.c +++ b/source4/ntvfs/common/opendb_tdb.c @@ -344,7 +344,8 @@ static NTSTATUS odb_tdb_open_can_internal(struct odb_context *odb, break request and suspending this call until the break is acknowledged or the file is closed */ - if (break_to_none) { + if (break_to_none || + !file->entries[i].allow_level_II_oplock) { oplock_return = OPLOCK_BREAK_TO_NONE; } odb_oplock_break_send(odb, &file->entries[i], @@ -391,7 +392,8 @@ static NTSTATUS odb_tdb_open_can_internal(struct odb_context *odb, * send an oplock break to the holder of the * oplock and tell caller to retry later */ - if (break_to_none) { + if (break_to_none || + !file->entries[i].allow_level_II_oplock) { oplock_return = OPLOCK_BREAK_TO_NONE; } odb_oplock_break_send(odb, &file->entries[i], @@ -418,6 +420,7 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, uint32_t stream_id, uint32_t share_access, uint32_t access_mask, bool delete_on_close, uint32_t open_disposition, bool break_to_none, + bool allow_level_II_oplock, uint32_t oplock_level, uint32_t *oplock_granted) { struct odb_context *odb = lck->odb; @@ -447,13 +450,14 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, NT_STATUS_NOT_OK_RETURN(status); /* see if it conflicts */ - 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; + 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.allow_level_II_oplock = allow_level_II_oplock; + e.oplock_level = OPLOCK_NONE; /* possibly grant an exclusive, batch or level2 oplock @@ -466,17 +470,23 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, if (file.num_entries == 0) { e.oplock_level = OPLOCK_EXCLUSIVE; *oplock_granted = EXCLUSIVE_OPLOCK_RETURN; - } else { + } else if (allow_level_II_oplock) { e.oplock_level = OPLOCK_LEVEL_II; *oplock_granted = LEVEL_II_OPLOCK_RETURN; + } else { + e.oplock_level = OPLOCK_NONE; + *oplock_granted = NO_OPLOCK_RETURN; } } else if (oplock_level == OPLOCK_BATCH) { if (file.num_entries == 0) { e.oplock_level = OPLOCK_BATCH; *oplock_granted = BATCH_OPLOCK_RETURN; - } else { + } else if (allow_level_II_oplock) { e.oplock_level = OPLOCK_LEVEL_II; *oplock_granted = LEVEL_II_OPLOCK_RETURN; + } else { + e.oplock_level = OPLOCK_NONE; + *oplock_granted = NO_OPLOCK_RETURN; } } else if (oplock_level == OPLOCK_LEVEL_II) { e.oplock_level = OPLOCK_LEVEL_II; -- cgit From ef4ae2597d0c198f42a5144ccd49716f0cb5796b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 6 Mar 2008 15:48:31 +0100 Subject: pvfs_open: pass down allow_level_II_oplock to odb_open_file() metze (This used to be commit 7c9b269b0742d435055e21f7e6cc945c21c7e332) --- source4/ntvfs/posix/pvfs_open.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'source4/ntvfs') diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 792e35cd14..47b44b9634 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -293,7 +293,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, status = odb_open_file(lck, f->handle, name->full_name, name->stream_id, share_access, access_mask, del_on_close, io->generic.in.open_disposition, - false, OPLOCK_NONE, NULL); + false, false, OPLOCK_NONE, NULL); if (!NT_STATUS_IS_OK(status)) { talloc_free(lck); @@ -347,7 +347,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, status = odb_open_file(lck, f->handle, name->full_name, name->stream_id, share_access, access_mask, del_on_close, io->generic.in.open_disposition, - false, OPLOCK_NONE, NULL); + false, false, OPLOCK_NONE, NULL); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; @@ -544,6 +544,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, bool del_on_close; struct pvfs_filename *parent; uint32_t oplock_level = OPLOCK_NONE, oplock_granted; + bool allow_level_II_oplock = false; if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) && (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) { @@ -658,10 +659,15 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, oplock_level = OPLOCK_EXCLUSIVE; } + if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) { + allow_level_II_oplock = true; + } + status = odb_open_file(lck, f->handle, name->full_name, name->stream_id, share_access, access_mask, del_on_close, io->generic.in.open_disposition, - false, oplock_level, &oplock_granted); + false, allow_level_II_oplock, + 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 @@ -1047,6 +1053,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, bool del_on_close; bool stream_existed, stream_truncate=false; uint32_t oplock_level = OPLOCK_NONE, oplock_granted; + bool allow_level_II_oplock = false; /* use the generic mapping code to avoid implementing all the different open calls. */ @@ -1241,11 +1248,16 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, oplock_level = OPLOCK_EXCLUSIVE; } + if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) { + allow_level_II_oplock = true; + } + /* see if we are allowed to open at the same time as existing opens */ status = odb_open_file(lck, f->handle, name->full_name, name->stream_id, share_access, access_mask, del_on_close, io->generic.in.open_disposition, - false, oplock_level, &oplock_granted); + false, allow_level_II_oplock, + oplock_level, &oplock_granted); /* * on a sharing violation we need to retry when the file is closed by -- cgit