2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - oplock handling
6 Copyright (C) Stefan Metzmacher 2008
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "lib/messaging/messaging.h"
24 #include "lib/messaging/irpc.h"
25 #include "vfs_posix.h"
29 struct pvfs_file_handle *handle;
30 struct pvfs_file *file;
32 struct messaging_context *msg_ctx;
36 receive oplock breaks and forward them to the client
38 static void pvfs_oplock_break(struct pvfs_oplock *opl, uint8_t level)
41 struct pvfs_file *f = opl->file;
42 struct pvfs_file_handle *h = opl->handle;
43 struct pvfs_state *pvfs = h->pvfs;
45 DEBUG(10,("pvfs_oplock_break: sending oplock break level %d for '%s' %p\n",
46 level, h->name->original_name, h));
47 status = ntvfs_send_oplock_break(pvfs->ntvfs, f->ntvfs, level);
48 if (!NT_STATUS_IS_OK(status)) {
49 DEBUG(0,("pvfs_oplock_break: sending oplock break failed: %s\n",
54 static void pvfs_oplock_break_dispatch(struct messaging_context *msg,
55 void *private_data, uint32_t msg_type,
56 struct server_id src, DATA_BLOB *data)
58 struct pvfs_oplock *opl = talloc_get_type(private_data,
60 struct opendb_oplock_break opb;
64 /* we need to check that this one is for us. See
65 messaging_send_ptr() for the other side of this.
67 if (data->length == sizeof(struct opendb_oplock_break)) {
68 struct opendb_oplock_break *p;
69 p = (struct opendb_oplock_break *)data->data;
72 DEBUG(0,("%s: ignore oplock break with length[%u]\n",
73 __location__, data->length));
76 if (opb.file_handle != opl->handle) {
81 * maybe we should use ntvfs_setup_async()
83 pvfs_oplock_break(opl, opb.level);
86 static int pvfs_oplock_destructor(struct pvfs_oplock *opl)
88 messaging_deregister(opl->msg_ctx, MSG_NTVFS_OPLOCK_BREAK, opl);
92 NTSTATUS pvfs_setup_oplock(struct pvfs_file *f, uint32_t oplock_granted)
95 struct pvfs_oplock *opl;
96 uint32_t level = OPLOCK_NONE;
98 f->handle->oplock = NULL;
100 switch (oplock_granted) {
101 case EXCLUSIVE_OPLOCK_RETURN:
102 level = OPLOCK_EXCLUSIVE;
104 case BATCH_OPLOCK_RETURN:
105 level = OPLOCK_BATCH;
107 case LEVEL_II_OPLOCK_RETURN:
108 level = OPLOCK_LEVEL_II;
112 if (level == OPLOCK_NONE) {
116 opl = talloc(f->handle, struct pvfs_oplock);
117 NT_STATUS_HAVE_NO_MEMORY(opl);
119 opl->handle = f->handle;
122 opl->msg_ctx = f->pvfs->ntvfs->ctx->msg_ctx;
124 status = messaging_register(opl->msg_ctx,
126 MSG_NTVFS_OPLOCK_BREAK,
127 pvfs_oplock_break_dispatch);
128 NT_STATUS_NOT_OK_RETURN(status);
131 talloc_set_destructor(opl, pvfs_oplock_destructor);
133 f->handle->oplock = opl;
138 NTSTATUS pvfs_oplock_release(struct ntvfs_module_context *ntvfs,
139 struct ntvfs_request *req, union smb_lock *lck)
141 struct pvfs_state *pvfs = ntvfs->private_data;
143 struct pvfs_file_handle *h;
144 struct odb_lock *olck;
145 uint8_t oplock_break;
148 f = pvfs_find_fd(pvfs, req, lck->lockx.in.file.ntvfs);
150 return NT_STATUS_INVALID_HANDLE;
156 return NT_STATUS_FILE_IS_A_DIRECTORY;
159 if (!h->have_opendb_entry) {
160 return NT_STATUS_FOOBAR;
164 return NT_STATUS_FOOBAR;
167 olck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
169 DEBUG(0,("Unable to lock opendb for oplock update\n"));
170 return NT_STATUS_FOOBAR;
173 oplock_break = (lck->lockx.in.mode >> 8) & 0xFF;
174 if (oplock_break == OPLOCK_BREAK_TO_NONE) {
175 h->oplock->level = OPLOCK_NONE;
176 } else if (oplock_break == OPLOCK_BREAK_TO_LEVEL_II) {
177 h->oplock->level = OPLOCK_LEVEL_II;
179 /* fallback to level II in case of a invalid value */
180 DEBUG(1,("unexpected oplock break level[0x%02X]\n", oplock_break));
181 h->oplock->level = OPLOCK_LEVEL_II;
183 status = odb_update_oplock(olck, h, h->oplock->level);
184 if (!NT_STATUS_IS_OK(status)) {
185 DEBUG(0,("Unable to update oplock level for '%s' - %s\n",
186 h->name->full_name, nt_errstr(status)));
193 /* after a break to none, we no longer have an oplock attached */
194 if (h->oplock->level == OPLOCK_NONE) {
195 talloc_free(h->oplock);