summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/ntvfs/posix/pvfs_lock.c11
-rw-r--r--source4/ntvfs/posix/pvfs_oplock.c64
2 files changed, 68 insertions, 7 deletions
diff --git a/source4/ntvfs/posix/pvfs_lock.c b/source4/ntvfs/posix/pvfs_lock.c
index df85b2b775..0796286b7e 100644
--- a/source4/ntvfs/posix/pvfs_lock.c
+++ b/source4/ntvfs/posix/pvfs_lock.c
@@ -294,6 +294,10 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
return ntvfs_map_lock(ntvfs, req, lck);
}
+ if (lck->lockx.in.mode & LOCKING_ANDX_OPLOCK_RELEASE) {
+ return pvfs_oplock_release(ntvfs, req, lck);
+ }
+
f = pvfs_find_fd(pvfs, req, lck->lockx.in.file.ntvfs);
if (!f) {
return NT_STATUS_INVALID_HANDLE;
@@ -338,13 +342,6 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
return NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks);
}
- if (lck->lockx.in.mode & LOCKING_ANDX_OPLOCK_RELEASE) {
- DEBUG(0,("received unexpected oplock break\n"));
- talloc_free(pending);
- return NT_STATUS_NOT_IMPLEMENTED;
- }
-
-
/* the unlocks happen first */
locks = lck->lockx.in.locks;
diff --git a/source4/ntvfs/posix/pvfs_oplock.c b/source4/ntvfs/posix/pvfs_oplock.c
index 50b1478f13..eff9ae1f1d 100644
--- a/source4/ntvfs/posix/pvfs_oplock.c
+++ b/source4/ntvfs/posix/pvfs_oplock.c
@@ -134,3 +134,67 @@ NTSTATUS pvfs_setup_oplock(struct pvfs_file *f, uint32_t oplock_granted)
return NT_STATUS_OK;
}
+
+NTSTATUS pvfs_oplock_release(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req, union smb_lock *lck)
+{
+ 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;
+
+ f = pvfs_find_fd(pvfs, req, lck->lockx.in.file.ntvfs);
+ if (!f) {
+ 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);
+ 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;
+}