s3-lsa: Fix static list of luids in our privileges implementation.
[Samba/ekacnet.git] / source3 / modules / onefs_cbrl.c
blob6d5d8c65ae728b3cc039172dee6fc57294294d02
1 /*
2 * Unix SMB/CIFS implementation.
3 * Support for OneFS system interfaces.
5 * Copyright (C) Zack Kirsch, 2009
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "onefs.h"
24 #include <ifs/ifs_syscalls.h>
25 #include <sys/isi_cifs_brl.h>
26 #include <isi_ecs/isi_ecs_cbrl.h>
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_LOCKING
31 static uint64_t onefs_get_new_id(void) {
32 static uint64_t id = 0;
34 id++;
36 return id;
39 enum onefs_cbrl_lock_state {ONEFS_CBRL_NONE, ONEFS_CBRL_ASYNC, ONEFS_CBRL_DONE,
40 ONEFS_CBRL_ERROR};
42 struct onefs_cbrl_blr_state {
43 uint64_t id;
44 enum onefs_cbrl_lock_state state;
47 static char *onefs_cbrl_blr_state_str(const struct blocking_lock_record *blr)
49 static fstring result;
50 struct onefs_cbrl_blr_state *bs;
52 SMB_ASSERT(blr);
54 bs = (struct onefs_cbrl_blr_state *)blr->blr_private;
56 if (bs == NULL) {
57 fstrcpy(result, "NULL CBRL BLR state - Posix lock?");
58 return result;
61 switch (bs->state) {
62 case ONEFS_CBRL_NONE:
63 fstr_sprintf(result, "CBRL BLR id=%llu: state=NONE", bs->id);
64 break;
65 case ONEFS_CBRL_ASYNC:
66 fstr_sprintf(result, "CBRL BLR id=%llu: state=ASYNC", bs->id);
67 break;
68 case ONEFS_CBRL_DONE:
69 fstr_sprintf(result, "CBRL BLR id=%llu: state=DONE", bs->id);
70 break;
71 case ONEFS_CBRL_ERROR:
72 fstr_sprintf(result, "CBRL BLR id=%llu: state=ERROR", bs->id);
73 break;
74 default:
75 fstr_sprintf(result, "CBRL BLR id=%llu: unknown state %d",
76 bs->id, bs->state);
77 break;
80 return result;
83 static void onefs_cbrl_enumerate_blq(const char *fn)
85 struct smbd_server_connection *sconn = smbd_server_conn;
86 struct blocking_lock_record *blr;
88 if (DEBUGLVL(10))
89 return;
91 DEBUG(10, ("CBRL BLR records (%s):\n", fn));
93 if (sconn->allow_smb2) {
94 struct smbd_smb2_request *smb2req;
95 for (smb2req = sconn->smb2.requests; smb2req; smb2req = nextreq) {
96 blr = get_pending_smb2req_blr(smb2req);
97 if (blr) {
98 DEBUGADD(10, ("%s\n", onefs_cbrl_blr_state_str(blr)));
101 } else {
102 for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = blr->next)
103 DEBUGADD(10, ("%s\n", onefs_cbrl_blr_state_str(blr)));
107 static struct blocking_lock_record *onefs_cbrl_find_blr(uint64_t id)
109 struct smbd_server_connection *sconn = smbd_server_conn;
110 struct blocking_lock_record *blr;
111 struct onefs_cbrl_blr_state *bs;
113 onefs_cbrl_enumerate_blq("onefs_cbrl_find_blr");
115 if (sconn->allow_smb2) {
116 struct smbd_smb2_request *smb2req;
117 for (smb2req = sconn->smb2.requests; smb2req; smb2req = nextreq) {
118 blr = get_pending_smb2req_blr(smb2req);
119 if (!blr) {
120 continue;
122 bs = (struct onefs_cbrl_blr_state *)blr->blr_private;
123 if (bs == NULL) {
124 continue;
126 if (bs->id == id) {
127 DEBUG(10, ("found %s\n",
128 onefs_cbrl_blr_state_str(blr)));
129 break;
131 } else {
132 for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = blr->next) {
133 bs = (struct onefs_cbrl_blr_state *)blr->blr_private;
135 /* We don't control all of the BLRs on the BLQ. */
136 if (bs == NULL)
137 continue;
139 if (bs->id == id) {
140 DEBUG(10, ("found %s\n",
141 onefs_cbrl_blr_state_str(blr)));
142 break;
147 if (blr == NULL) {
148 DEBUG(5, ("Could not find CBRL BLR for id %llu\n", id));
149 return NULL;
152 return blr;
155 static void onefs_cbrl_async_success(uint64_t id)
157 struct blocking_lock_record *blr;
158 struct onefs_cbrl_blr_state *bs;
159 uint16 num_locks;
161 DEBUG(10, ("CBRL async success!\n"));
163 /* Find BLR with id. Its okay not to find one (race with cancel) */
164 blr = onefs_cbrl_find_blr(id);
165 if (blr == NULL)
166 return;
168 bs = (struct onefs_cbrl_blr_state *)blr->blr_private;
169 SMB_ASSERT(bs);
170 SMB_ASSERT(bs->state == ONEFS_CBRL_ASYNC);
172 blr->lock_num++;
174 num_locks = SVAL(blr->req->vwv+7, 0);
176 if (blr->lock_num == num_locks)
177 bs->state = ONEFS_CBRL_DONE;
178 else
179 bs->state = ONEFS_CBRL_NONE;
181 /* Self contend our own level 2 oplock. The kernel handles
182 * contention of other opener's level 2 oplocks. */
183 contend_level2_oplocks_begin(blr->fsp,
184 LEVEL2_CONTEND_WINDOWS_BRL);
186 /* Process the queue, to try the next lock or finish up. */
187 process_blocking_lock_queue();
190 static void onefs_cbrl_async_failure(uint64_t id)
192 struct blocking_lock_record *blr;
193 struct onefs_cbrl_blr_state *bs;
195 DEBUG(10, ("CBRL async failure!\n"));
197 /* Find BLR with id. Its okay not to find one (race with cancel) */
198 blr = onefs_cbrl_find_blr(id);
199 if (blr == NULL)
200 return;
202 bs = (struct onefs_cbrl_blr_state *)blr->blr_private;
203 SMB_ASSERT(bs);
205 SMB_ASSERT(bs->state == ONEFS_CBRL_ASYNC);
206 bs->state = ONEFS_CBRL_ERROR;
208 /* Process the queue. It will end up trying to retake the same lock,
209 * see the error in onefs_cbrl_lock_windows() and fail. */
210 process_blocking_lock_queue();
213 static struct cbrl_event_ops cbrl_ops =
214 {.cbrl_async_success = onefs_cbrl_async_success,
215 .cbrl_async_failure = onefs_cbrl_async_failure};
217 static void onefs_cbrl_events_handler(struct event_context *ev,
218 struct fd_event *fde,
219 uint16_t flags,
220 void *private_data)
222 DEBUG(10, ("onefs_cbrl_events_handler\n"));
224 if (cbrl_event_dispatcher(&cbrl_ops)) {
225 DEBUG(0, ("cbrl_event_dispatcher failed: %s\n",
226 strerror(errno)));
230 static void onefs_init_cbrl(void)
232 static bool init_done = false;
233 static int cbrl_event_fd;
234 static struct fd_event *cbrl_fde;
236 if (init_done)
237 return;
239 DEBUG(10, ("onefs_init_cbrl\n"));
241 /* Register the event channel for CBRL. */
242 cbrl_event_fd = cbrl_event_register();
243 if (cbrl_event_fd == -1) {
244 DEBUG(0, ("cbrl_event_register failed: %s\n",
245 strerror(errno)));
246 return;
249 DEBUG(10, ("cbrl_event_fd = %d\n", cbrl_event_fd));
251 /* Register the CBRL event_fd with samba's event system */
252 cbrl_fde = event_add_fd(smbd_event_context(),
253 NULL,
254 cbrl_event_fd,
255 EVENT_FD_READ,
256 onefs_cbrl_events_handler,
257 NULL);
259 init_done = true;
260 return;
264 * Blocking PID. As far as I can tell, the blocking_pid is only used to tell
265 * whether a posix lock or a CIFS lock blocked us. If it was a posix lock,
266 * Samba polls every 10 seconds, which we don't want. -zkirsch
268 #define ONEFS_BLOCKING_PID 0xABCDABCD
271 * @param[in] br_lck Contains the fsp.
272 * @param[in] plock Lock request.
273 * @param[in] blocking_lock Only used for figuring out the error.
274 * @param[in,out] blr The BLR for the already-deferred operation.
276 NTSTATUS onefs_brl_lock_windows(vfs_handle_struct *handle,
277 struct byte_range_lock *br_lck,
278 struct lock_struct *plock,
279 bool blocking_lock,
280 struct blocking_lock_record *blr)
282 int fd = br_lck->fsp->fh->fd;
283 uint64_t id = 0;
284 enum cbrl_lock_type type;
285 bool async = false;
286 bool pending = false;
287 bool pending_async = false;
288 int error;
289 struct onefs_cbrl_blr_state *bs;
290 NTSTATUS status;
292 START_PROFILE(syscall_brl_lock);
294 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
295 SMB_ASSERT(plock->lock_type != UNLOCK_LOCK);
297 onefs_cbrl_enumerate_blq("onefs_brl_lock_windows");
299 /* Will only initialize the first time its called. */
300 onefs_init_cbrl();
302 switch (plock->lock_type) {
303 case WRITE_LOCK:
304 type = CBRL_LK_EX;
305 break;
306 case READ_LOCK:
307 type = CBRL_LK_SH;
308 break;
309 case PENDING_WRITE_LOCK:
310 /* Called when a blocking lock request is added - do an
311 * async lock. */
312 type = CBRL_LK_EX;
313 pending = true;
314 async = true;
315 break;
316 case PENDING_READ_LOCK:
317 /* Called when a blocking lock request is added - do an
318 * async lock. */
319 type = CBRL_LK_SH;
320 pending = true;
321 async = true;
322 break;
323 default:
324 /* UNLOCK_LOCK: should only be used for a POSIX_LOCK */
325 smb_panic("Invalid plock->lock_type passed in to "
326 "onefs_brl_lock_windows");
329 /* Figure out if we're actually doing the lock or a no-op. We need to
330 * do a no-op when process_blocking_lock_queue calls back into us.
332 * We know process_* is calling into us if a blr is passed in and
333 * pending is false. */
334 if (!pending && blr) {
335 /* Check the BLR state. */
336 bs = (struct onefs_cbrl_blr_state *)blr->blr_private;
337 SMB_ASSERT(bs);
339 /* ASYNC still in progress: The process_* calls will keep
340 * calling even if we haven't gotten the lock. Keep erroring
341 * without calling ifs_cbrl, or getting/setting an id. */
342 if (bs->state == ONEFS_CBRL_ASYNC) {
343 goto failure;
345 else if (bs->state == ONEFS_CBRL_ERROR) {
346 END_PROFILE(syscall_brl_lock);
347 return NT_STATUS_NO_MEMORY;
350 SMB_ASSERT(bs->state == ONEFS_CBRL_NONE);
351 async = true;
354 if (async) {
355 SMB_ASSERT(blocking_lock);
356 SMB_ASSERT(blr);
357 id = onefs_get_new_id();
360 DEBUG(10, ("Calling ifs_cbrl(LOCK)...\n"));
361 error = ifs_cbrl(fd, CBRL_OP_LOCK, type, plock->start,
362 plock->size, async, id, plock->context.smbpid, plock->context.tid,
363 plock->fnum);
364 if (!error) {
365 goto success;
366 } else if (errno == EWOULDBLOCK) {
367 SMB_ASSERT(!async);
368 } else if (errno == EINPROGRESS) {
369 SMB_ASSERT(async);
371 if (pending) {
372 /* Talloc a new BLR private state. */
373 blr->blr_private = talloc(blr, struct onefs_cbrl_blr_state);
374 pending_async = true;
377 /* Store the new id in the BLR private state. */
378 bs = (struct onefs_cbrl_blr_state *)blr->blr_private;
379 bs->id = id;
380 bs->state = ONEFS_CBRL_ASYNC;
381 } else {
382 DEBUG(0, ("onefs_brl_lock_windows failure: error=%d (%s).\n",
383 errno, strerror(errno)));
386 failure:
388 END_PROFILE(syscall_brl_lock);
390 /* Failure - error or async. */
391 plock->context.smbpid = (uint32) ONEFS_BLOCKING_PID;
393 if (pending_async)
394 status = NT_STATUS_OK;
395 else
396 status = brl_lock_failed(br_lck->fsp, plock, blocking_lock);
398 DEBUG(10, ("returning %s.\n", nt_errstr(status)));
399 return status;
401 success:
402 /* Self contend our own level 2 oplock. The kernel handles
403 * contention of other opener's level 2 oplocks. */
404 contend_level2_oplocks_begin(br_lck->fsp,
405 LEVEL2_CONTEND_WINDOWS_BRL);
407 END_PROFILE(syscall_brl_lock);
409 /* Success. */
410 onefs_cbrl_enumerate_blq("onefs_brl_unlock_windows");
411 DEBUG(10, ("returning NT_STATUS_OK.\n"));
412 return NT_STATUS_OK;
415 bool onefs_brl_unlock_windows(vfs_handle_struct *handle,
416 struct messaging_context *msg_ctx,
417 struct byte_range_lock *br_lck,
418 const struct lock_struct *plock)
420 int error;
421 int fd = br_lck->fsp->fh->fd;
423 START_PROFILE(syscall_brl_unlock);
425 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
426 SMB_ASSERT(plock->lock_type == UNLOCK_LOCK);
428 DEBUG(10, ("Calling ifs_cbrl(UNLOCK)...\n"));
429 error = ifs_cbrl(fd, CBRL_OP_UNLOCK, CBRL_LK_SH,
430 plock->start, plock->size, false, 0, plock->context.smbpid,
431 plock->context.tid, plock->fnum);
433 END_PROFILE(syscall_brl_unlock);
435 if (error) {
436 DEBUG(10, ("returning false.\n"));
437 return false;
440 /* For symmetry purposes, end our oplock contention even though its
441 * currently a no-op. */
442 contend_level2_oplocks_end(br_lck->fsp, LEVEL2_CONTEND_WINDOWS_BRL);
444 DEBUG(10, ("returning true.\n"));
445 return true;
447 /* Problem with storing things in TDB: I won't know what BRL to unlock in the TDB.
448 * - I could fake it?
449 * - I could send Samba a message with which lock is being unlocked?
450 * - I could *easily* make the "id" something you always pass in to
451 * lock, unlock or cancel -- it identifies a lock. Makes sense!
455 /* Default implementation only calls this on PENDING locks. */
456 bool onefs_brl_cancel_windows(vfs_handle_struct *handle,
457 struct byte_range_lock *br_lck,
458 struct lock_struct *plock,
459 struct blocking_lock_record *blr)
461 int error;
462 int fd = br_lck->fsp->fh->fd;
463 struct onefs_cbrl_blr_state *bs;
465 START_PROFILE(syscall_brl_cancel);
467 SMB_ASSERT(plock);
468 SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
469 SMB_ASSERT(blr);
471 onefs_cbrl_enumerate_blq("onefs_brl_cancel_windows");
473 bs = ((struct onefs_cbrl_blr_state *)blr->blr_private);
474 SMB_ASSERT(bs);
476 if (bs->state == ONEFS_CBRL_DONE || bs->state == ONEFS_CBRL_ERROR) {
477 /* No-op. */
478 DEBUG(10, ("State=%d, returning true\n", bs->state));
479 END_PROFILE(syscall_brl_cancel);
480 return true;
483 SMB_ASSERT(bs->state == ONEFS_CBRL_NONE ||
484 bs->state == ONEFS_CBRL_ASYNC);
486 /* A real cancel. */
487 DEBUG(10, ("Calling ifs_cbrl(CANCEL)...\n"));
488 error = ifs_cbrl(fd, CBRL_OP_CANCEL, CBRL_LK_UNSPEC, plock->start,
489 plock->size, false, bs->id, plock->context.smbpid,
490 plock->context.tid, plock->fnum);
492 END_PROFILE(syscall_brl_cancel);
494 if (error) {
495 DEBUG(10, ("returning false\n"));
496 bs->state = ONEFS_CBRL_ERROR;
497 return false;
500 bs->state = ONEFS_CBRL_DONE;
501 onefs_cbrl_enumerate_blq("onefs_brl_cancel_windows");
502 DEBUG(10, ("returning true\n"));
503 return true;
506 bool onefs_strict_lock(vfs_handle_struct *handle,
507 files_struct *fsp,
508 struct lock_struct *plock)
510 int error;
512 START_PROFILE(syscall_strict_lock);
514 SMB_ASSERT(plock->lock_type == READ_LOCK ||
515 plock->lock_type == WRITE_LOCK);
517 if (!lp_locking(handle->conn->params) ||
518 !lp_strict_locking(handle->conn->params)) {
519 END_PROFILE(syscall_strict_lock);
520 return True;
523 if (plock->lock_flav == POSIX_LOCK) {
524 END_PROFILE(syscall_strict_lock);
525 return SMB_VFS_NEXT_STRICT_LOCK(handle, fsp, plock);
528 if (plock->size == 0) {
529 END_PROFILE(syscall_strict_lock);
530 return True;
533 error = ifs_cbrl(fsp->fh->fd, CBRL_OP_LOCK,
534 plock->lock_type == READ_LOCK ? CBRL_LK_RD : CBRL_LK_WR,
535 plock->start, plock->size, 0, 0, plock->context.smbpid,
536 plock->context.tid, plock->fnum);
538 END_PROFILE(syscall_strict_lock);
540 return (error == 0);
543 void onefs_strict_unlock(vfs_handle_struct *handle,
544 files_struct *fsp,
545 struct lock_struct *plock)
547 START_PROFILE(syscall_strict_unlock);
549 SMB_ASSERT(plock->lock_type == READ_LOCK ||
550 plock->lock_type == WRITE_LOCK);
552 if (!lp_locking(handle->conn->params) ||
553 !lp_strict_locking(handle->conn->params)) {
554 END_PROFILE(syscall_strict_unlock);
555 return;
558 if (plock->lock_flav == POSIX_LOCK) {
559 SMB_VFS_NEXT_STRICT_UNLOCK(handle, fsp, plock);
560 END_PROFILE(syscall_strict_unlock);
561 return;
564 if (plock->size == 0) {
565 END_PROFILE(syscall_strict_unlock);
566 return;
569 if (fsp->fh) {
570 ifs_cbrl(fsp->fh->fd, CBRL_OP_UNLOCK,
571 plock->lock_type == READ_LOCK ? CBRL_LK_RD : CBRL_LK_WR,
572 plock->start, plock->size, 0, 0, plock->context.smbpid,
573 plock->context.tid, plock->fnum);
576 END_PROFILE(syscall_strict_unlock);
579 /* TODO Optimization: Abstract out brl_get_locks() in the Windows case.
580 * We'll malloc some memory or whatever (can't return NULL), but not actually
581 * touch the TDB. */
583 /* XXX brl_locktest: CBRL does not support calling this, but its only for
584 * strict locking. Add empty VOP? */
586 /* XXX brl_lockquery: CBRL does not support calling this for WINDOWS LOCKS, but
587 * its only called for POSIX LOCKS. Add empty VOP? */
589 /* XXX brl_close_fnum: CBRL will do this automatically. I think this is a NO-OP
590 * for us, we could add an empty VOP. */