e30070a9f75df75884e82b1f81e7894a38a4a408
[ira/wip.git] / source3 / modules / onefs_cbrl.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * Support for OneFS system interfaces.
4  *
5  * Copyright (C) Zack Kirsch, 2009
6  *
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.
11  *
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.
16  *
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/>.
19  */
20
21 #include "includes.h"
22 #include "onefs.h"
23
24 #include <ifs/ifs_syscalls.h>
25 #include <sys/isi_cifs_brl.h>
26 #include <isi_ecs/isi_ecs_cbrl.h>
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_LOCKING
30
31 extern struct blocking_lock_record *blocking_lock_queue;
32
33 static uint64_t onefs_get_new_id(void) {
34         static uint64_t id = 0;
35
36         id++;
37
38         return id;
39 }
40
41 enum onefs_cbrl_lock_state {ONEFS_CBRL_NONE, ONEFS_CBRL_ASYNC, ONEFS_CBRL_DONE,
42         ONEFS_CBRL_ERROR};
43
44 struct onefs_cbrl_blr_state {
45         uint64_t id;
46         enum onefs_cbrl_lock_state state;
47 };
48
49 static char *onefs_cbrl_blr_state_str(const struct blocking_lock_record *blr)
50 {
51         static fstring result;
52         struct onefs_cbrl_blr_state *bs;
53
54         SMB_ASSERT(blr);
55
56         bs = (struct onefs_cbrl_blr_state *)blr->blr_private;
57
58         if (bs == NULL) {
59                 fstrcpy(result, "NULL CBRL BLR state - Posix lock?");
60                 return result;
61         }
62
63         switch (bs->state) {
64         case ONEFS_CBRL_NONE:
65                 fstr_sprintf(result, "CBRL BLR id=%llu: state=NONE", bs->id);
66                 break;
67         case ONEFS_CBRL_ASYNC:
68                 fstr_sprintf(result, "CBRL BLR id=%llu: state=ASYNC", bs->id);
69                 break;
70         case ONEFS_CBRL_DONE:
71                 fstr_sprintf(result, "CBRL BLR id=%llu: state=DONE", bs->id);
72                 break;
73         case ONEFS_CBRL_ERROR:
74                 fstr_sprintf(result, "CBRL BLR id=%llu: state=ERROR", bs->id);
75                 break;
76         default:
77                 fstr_sprintf(result, "CBRL BLR id=%llu: unknown state %d",
78                     bs->id, bs->state);
79                 break;
80         }
81
82         return result;
83 }
84
85 static void onefs_cbrl_enumerate_blq(const char *fn)
86 {
87         struct blocking_lock_record *blr;
88
89         if (DEBUGLVL(10))
90                 return;
91
92         DEBUG(10, ("CBRL BLR records (%s):\n", fn));
93
94         for (blr = blocking_lock_queue; blr; blr = blr->next)
95                 DEBUGADD(10, ("%s\n", onefs_cbrl_blr_state_str(blr)));
96 }
97
98 static struct blocking_lock_record *onefs_cbrl_find_blr(uint64_t id)
99 {
100         struct blocking_lock_record *blr;
101         struct onefs_cbrl_blr_state *bs;
102
103         onefs_cbrl_enumerate_blq("onefs_cbrl_find_blr");
104
105         for (blr = blocking_lock_queue; blr; blr = blr->next) {
106                 bs = (struct onefs_cbrl_blr_state *)blr->blr_private;
107
108                 /* We don't control all of the BLRs on the BLQ. */
109                 if (bs == NULL)
110                         continue;
111
112                 if (bs->id == id) {
113                         DEBUG(10, ("found %s\n",
114                             onefs_cbrl_blr_state_str(blr)));
115                         break;
116                 }
117         }
118
119         if (blr == NULL) {
120                 DEBUG(5, ("Could not find CBRL BLR for id %llu\n", id));
121                 return NULL;
122         }
123
124         return blr;
125 }
126
127 static void onefs_cbrl_async_success(uint64_t id)
128 {
129         struct blocking_lock_record *blr;
130         struct onefs_cbrl_blr_state *bs;
131         uint16 num_locks;
132
133         DEBUG(10, ("CBRL async success!\n"));
134
135         /* Find BLR with id. Its okay not to find one (race with cancel) */
136         blr = onefs_cbrl_find_blr(id);
137         if (blr == NULL)
138                 return;
139
140         bs = (struct onefs_cbrl_blr_state *)blr->blr_private;
141         SMB_ASSERT(bs);
142         SMB_ASSERT(bs->state == ONEFS_CBRL_ASYNC);
143
144         blr->lock_num++;
145
146         num_locks = SVAL(blr->req->vwv+7, 0);
147
148         if (blr->lock_num == num_locks)
149                 bs->state = ONEFS_CBRL_DONE;
150         else
151                 bs->state = ONEFS_CBRL_NONE;
152
153         /* Process the queue, to try the next lock or finish up. */
154         process_blocking_lock_queue();
155 }
156
157 static void onefs_cbrl_async_failure(uint64_t id)
158 {
159         struct blocking_lock_record *blr;
160         struct onefs_cbrl_blr_state *bs;
161
162         DEBUG(10, ("CBRL async failure!\n"));
163
164         /* Find BLR with id. Its okay not to find one (race with cancel) */
165         blr = onefs_cbrl_find_blr(id);
166         if (blr == NULL)
167                 return;
168
169         bs = (struct onefs_cbrl_blr_state *)blr->blr_private;
170         SMB_ASSERT(bs);
171
172         SMB_ASSERT(bs->state == ONEFS_CBRL_ASYNC);
173         bs->state = ONEFS_CBRL_ERROR;
174
175         /* Process the queue. It will end up trying to retake the same lock,
176          * see the error in onefs_cbrl_lock_windows() and fail. */
177         process_blocking_lock_queue();
178 }
179
180 static struct cbrl_event_ops cbrl_ops =
181     {.cbrl_async_success = onefs_cbrl_async_success,
182      .cbrl_async_failure = onefs_cbrl_async_failure};
183  
184 static void onefs_cbrl_events_handler(struct event_context *ev,
185                                         struct fd_event *fde,
186                                         uint16_t flags,
187                                         void *private_data)
188 {
189         DEBUG(10, ("onefs_cbrl_events_handler\n"));
190
191         if (cbrl_event_dispatcher(&cbrl_ops)) {
192                 DEBUG(0, ("cbrl_event_dispatcher failed: %s\n",
193                         strerror(errno)));
194         }
195 }
196
197 static void onefs_init_cbrl(void)
198 {
199         static bool init_done = false;
200         static int cbrl_event_fd;
201         static struct fd_event *cbrl_fde;
202
203         if (init_done)
204                 return;
205
206         DEBUG(10, ("onefs_init_cbrl\n"));
207
208         /* Register the event channel for CBRL. */
209         cbrl_event_fd = cbrl_event_register();
210         if (cbrl_event_fd == -1) {
211                 DEBUG(0, ("cbrl_event_register failed: %s\n",
212                         strerror(errno)));
213                 return;
214         }
215
216         DEBUG(10, ("cbrl_event_fd = %d\n", cbrl_event_fd));
217
218         /* Register the oplock event_fd with samba's event system */
219         cbrl_fde = event_add_fd(smbd_event_context(),
220                                      NULL,
221                                      cbrl_event_fd,
222                                      EVENT_FD_READ,
223                                      onefs_cbrl_events_handler,
224                                      NULL);
225
226         init_done = true;
227         return;
228 }
229
230 /**
231  * Blocking PID. As far as I can tell, the blocking_pid is only used to tell
232  * whether a posix lock or a CIFS lock blocked us. If it was a posix lock,
233  * Samba polls every 10 seconds, which we don't want. -zkirsch
234  */
235 #define ONEFS_BLOCKING_PID 0xABCDABCD
236
237 /**
238  * @param[in]     br_lck        Contains the fsp.
239  * @param[in]     plock         Lock request.
240  * @param[in]     blocking_lock Only used for figuring out the error.
241  * @param[in,out] blr           The BLR for the already-deferred operation.
242  */
243 NTSTATUS onefs_brl_lock_windows(vfs_handle_struct *handle,
244                                 struct byte_range_lock *br_lck,
245                                 struct lock_struct *plock,
246                                 bool blocking_lock,
247                                 struct blocking_lock_record *blr)
248 {
249         int fd = br_lck->fsp->fh->fd;
250         uint64_t id = 0;
251         enum cbrl_lock_type type;
252         bool async = false;
253         bool pending = false;
254         bool pending_async = false;
255         int error;
256         struct onefs_cbrl_blr_state *bs;
257         NTSTATUS status;
258
259         START_PROFILE(syscall_brl_lock);
260
261         SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
262         SMB_ASSERT(plock->lock_type != UNLOCK_LOCK);
263
264         onefs_cbrl_enumerate_blq("onefs_brl_lock_windows");
265
266         /* Will only initialize the first time its called. */
267         onefs_init_cbrl();
268
269         switch (plock->lock_type) {
270                 case WRITE_LOCK:
271                         type = CBRL_LK_EX;
272                         break;
273                 case READ_LOCK:
274                         type = CBRL_LK_SH;
275                         break;
276                 case PENDING_WRITE_LOCK:
277                         /* Called when a blocking lock request is added - do an
278                          * async lock. */
279                         type = CBRL_LK_EX;
280                         pending = true;
281                         async = true;
282                         break;
283                 case PENDING_READ_LOCK:
284                         /* Called when a blocking lock request is added - do an
285                          * async lock. */
286                         type = CBRL_LK_SH;
287                         pending = true;
288                         async = true;
289                         break;
290                 default:
291                         /* UNLOCK_LOCK: should only be used for a POSIX_LOCK */
292                         smb_panic("Invalid plock->lock_type passed in to "
293                             "onefs_brl_lock_windows");
294         }
295
296         /* Figure out if we're actually doing the lock or a no-op. We need to
297          * do a no-op when process_blocking_lock_queue calls back into us.
298          *
299          * We know process_* is calling into us if a blr is passed in and
300          * pending is false. */
301         if (!pending && blr) {
302                 /* Check the BLR state. */
303                 bs = (struct onefs_cbrl_blr_state *)blr->blr_private;
304                 SMB_ASSERT(bs);
305
306                 /* ASYNC still in progress: The process_* calls will keep
307                  * calling even if we haven't gotten the lock. Keep erroring
308                  * without calling ifs_cbrl, or getting/setting an id. */
309                 if (bs->state == ONEFS_CBRL_ASYNC) {
310                         goto failure;
311                 }
312                 else if (bs->state == ONEFS_CBRL_ERROR) {
313                         END_PROFILE(syscall_brl_lock);
314                         return NT_STATUS_NO_MEMORY;
315                 }
316
317                 SMB_ASSERT(bs->state == ONEFS_CBRL_NONE);
318                 async = true;
319         }
320
321         if (async) {
322                 SMB_ASSERT(blocking_lock);
323                 SMB_ASSERT(blr);
324                 id = onefs_get_new_id();
325         }
326
327         DEBUG(10, ("Calling ifs_cbrl(LOCK)..."));
328         error = ifs_cbrl(fd, CBRL_OP_LOCK, type, plock->start,
329             plock->size, async, id, plock->context.smbpid, plock->context.tid,
330             plock->fnum);
331         if (!error) {
332                 goto success;
333         } else if (errno == EWOULDBLOCK) {
334                 SMB_ASSERT(!async);
335         } else if (errno == EINPROGRESS) {
336                 SMB_ASSERT(async);
337
338                 if (pending) {
339                         /* Talloc a new BLR private state. */
340                         blr->blr_private = talloc(blr, struct onefs_cbrl_blr_state);
341                         pending_async = true;
342                 }
343
344                 /* Store the new id in the BLR private state. */
345                 bs = (struct onefs_cbrl_blr_state *)blr->blr_private;
346                 bs->id = id;
347                 bs->state = ONEFS_CBRL_ASYNC;
348         } else {
349                 DEBUG(0, ("onefs_brl_lock_windows failure: error=%d (%s).\n",
350                         errno, strerror(errno)));
351         }
352
353 failure:
354
355         END_PROFILE(syscall_brl_lock);
356
357         /* Failure - error or async. */
358         plock->context.smbpid = (uint32) ONEFS_BLOCKING_PID;
359
360         if (pending_async)
361                 status = NT_STATUS_OK;
362         else
363                 status = brl_lock_failed(br_lck->fsp, plock, blocking_lock);
364
365         DEBUG(10, ("returning %s.\n", nt_errstr(status)));
366         return status;
367
368 success:
369
370         END_PROFILE(syscall_brl_lock);
371
372         /* Success. */
373         onefs_cbrl_enumerate_blq("onefs_brl_unlock_windows");
374         DEBUG(10, ("returning NT_STATUS_OK.\n"));
375         return NT_STATUS_OK;
376 }
377
378 bool onefs_brl_unlock_windows(vfs_handle_struct *handle,
379                               struct messaging_context *msg_ctx,
380                               struct byte_range_lock *br_lck,
381                               const struct lock_struct *plock)
382 {
383         int error;
384         int fd = br_lck->fsp->fh->fd;
385
386         START_PROFILE(syscall_brl_unlock);
387
388         SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
389         SMB_ASSERT(plock->lock_type == UNLOCK_LOCK);
390
391         DEBUG(10, ("Calling ifs_cbrl(UNLOCK)..."));
392         error = ifs_cbrl(fd, CBRL_OP_UNLOCK, CBRL_LK_SH,
393             plock->start, plock->size, false, 0, plock->context.smbpid,
394             plock->context.tid, plock->fnum);
395
396         END_PROFILE(syscall_brl_unlock);
397
398         if (error) {
399                 DEBUG(10, ("returning false.\n"));
400                 return false;
401         }
402
403         DEBUG(10, ("returning true.\n"));
404         return true;
405
406         /* Problem with storing things in TDB: I won't know what BRL to unlock in the TDB.
407          *  - I could fake it?
408          *  - I could send Samba a message with which lock is being unlocked?
409          *  - I could *easily* make the "id" something you always pass in to
410          *  lock, unlock or cancel -- it identifies a lock. Makes sense!
411          */
412 }
413
414 /* Default implementation only calls this on PENDING locks. */
415 bool onefs_brl_cancel_windows(vfs_handle_struct *handle,
416                               struct byte_range_lock *br_lck,
417                               struct lock_struct *plock,
418                               struct blocking_lock_record *blr)
419 {
420         int error;
421         int fd = br_lck->fsp->fh->fd;
422         struct onefs_cbrl_blr_state *bs;
423
424         START_PROFILE(syscall_brl_cancel);
425
426         SMB_ASSERT(plock);
427         SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
428         SMB_ASSERT(blr);
429
430         onefs_cbrl_enumerate_blq("onefs_brl_cancel_windows");
431
432         bs = ((struct onefs_cbrl_blr_state *)blr->blr_private);
433         SMB_ASSERT(bs);
434
435         if (bs->state == ONEFS_CBRL_DONE || bs->state == ONEFS_CBRL_ERROR) {
436                 /* No-op. */
437                 DEBUG(10, ("State=%d, returning true\n", bs->state));
438                 END_PROFILE(syscall_brl_cancel);
439                 return true;
440         }
441
442         SMB_ASSERT(bs->state == ONEFS_CBRL_NONE ||
443             bs->state == ONEFS_CBRL_ASYNC);
444
445         /* A real cancel. */
446         DEBUG(10, ("Calling ifs_cbrl(CANCEL)..."));
447         error = ifs_cbrl(fd, CBRL_OP_CANCEL, CBRL_LK_UNSPEC, plock->start,
448             plock->size, false, bs->id, plock->context.smbpid,
449             plock->context.tid, plock->fnum);
450
451         END_PROFILE(syscall_brl_cancel);
452
453         if (error) {
454                 DEBUG(10, ("returning false\n"));
455                 bs->state = ONEFS_CBRL_ERROR;
456                 return false;
457         }
458
459         bs->state = ONEFS_CBRL_DONE;
460         onefs_cbrl_enumerate_blq("onefs_brl_cancel_windows");
461         DEBUG(10, ("returning true\n"));
462         return true;
463 }
464
465 bool onefs_strict_lock(vfs_handle_struct *handle,
466                         files_struct *fsp,
467                         struct lock_struct *plock)
468 {
469         int error;
470
471         START_PROFILE(syscall_strict_lock);
472
473         SMB_ASSERT(plock->lock_type == READ_LOCK ||
474             plock->lock_type == WRITE_LOCK);
475
476         if (!lp_locking(handle->conn->params) ||
477             !lp_strict_locking(handle->conn->params)) {
478                 END_PROFILE(syscall_strict_lock);
479                 return True;
480         }
481
482         if (plock->lock_flav == POSIX_LOCK) {
483                 END_PROFILE(syscall_strict_lock);
484                 return SMB_VFS_NEXT_STRICT_LOCK(handle, fsp, plock);
485         }
486
487         if (plock->size == 0) {
488                 END_PROFILE(syscall_strict_lock);
489                 return True;
490         }
491
492         error = ifs_cbrl(fsp->fh->fd, CBRL_OP_LOCK,
493             plock->lock_type == READ_LOCK ? CBRL_LK_RD : CBRL_LK_WR,
494             plock->start, plock->size, 0, 0, plock->context.smbpid,
495             plock->context.tid, plock->fnum);
496
497         END_PROFILE(syscall_strict_lock);
498
499         return (error == 0);
500 }
501
502 void onefs_strict_unlock(vfs_handle_struct *handle,
503                         files_struct *fsp,
504                         struct lock_struct *plock)
505 {
506         START_PROFILE(syscall_strict_unlock);
507
508         SMB_ASSERT(plock->lock_type == READ_LOCK ||
509             plock->lock_type == WRITE_LOCK);
510
511         if (!lp_locking(handle->conn->params) ||
512             !lp_strict_locking(handle->conn->params)) {
513                 END_PROFILE(syscall_strict_unlock);
514                 return;
515         }
516
517         if (plock->lock_flav == POSIX_LOCK) {
518                 SMB_VFS_NEXT_STRICT_UNLOCK(handle, fsp, plock);
519                 END_PROFILE(syscall_strict_unlock);
520                 return;
521         }
522
523         if (plock->size == 0) {
524                 END_PROFILE(syscall_strict_unlock);
525                 return;
526         }
527
528         if (fsp->fh) {
529                 ifs_cbrl(fsp->fh->fd, CBRL_OP_UNLOCK,
530                     plock->lock_type == READ_LOCK ? CBRL_LK_RD : CBRL_LK_WR,
531                     plock->start, plock->size, 0, 0, plock->context.smbpid,
532                     plock->context.tid, plock->fnum);
533         }
534
535         END_PROFILE(syscall_strict_unlock);
536 }
537
538 /* TODO Optimization: Abstract out brl_get_locks() in the Windows case.
539  * We'll malloc some memory or whatever (can't return NULL), but not actually
540  * touch the TDB. */
541
542 /* XXX brl_locktest: CBRL does not support calling this, but its only for
543  * strict locking. Add empty VOP? */
544
545 /* XXX brl_lockquery: CBRL does not support calling this for WINDOWS LOCKS, but
546  * its only called for POSIX LOCKS. Add empty VOP? */
547
548 /* XXX brl_close_fnum: CBRL will do this automatically. I think this is a NO-OP
549  * for us, we could add an empty VOP. */
550