s3:smbd/oplock: pass smbd_server_connection to onefs_init_kernel_oplocks()
[kai/samba.git] / source3 / smbd / oplock_onefs.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * Support for OneFS kernel oplocks
4  *
5  * Copyright (C) Volker Lendecke 2007
6  * Copyright (C) Tim Prouty, 2009
7  *
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.
12  *
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.
17  *
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/>.
20  */
21
22 #define DBGC_CLASS DBGC_LOCKING
23
24 #include "includes.h"
25
26 #if HAVE_ONEFS
27 #include "oplock_onefs.h"
28 #include "smbd/smbd.h"
29 #include "smbd/globals.h"
30
31 #include <ifs/ifs_syscalls.h>
32 #include <isi_ecs/isi_ecs_oplocks.h>
33 #include <sys/proc.h>
34
35 struct onefs_oplocks_context {
36         struct kernel_oplocks *ctx;
37         struct smbd_server_connection *sconn;
38         const struct oplocks_event_ops *onefs_ops;
39         int onefs_event_fd;
40         struct fd_event *read_fde;
41 };
42
43 enum onefs_callback_state {
44         ONEFS_OPEN_FILE,
45         ONEFS_WAITING_FOR_OPLOCK
46 };
47
48 struct onefs_callback_record {
49         struct onefs_callback_record *prev, *next;
50         uint64_t id;
51         enum onefs_callback_state state;
52         union {
53                 files_struct *fsp;      /* ONEFS_OPEN_FILE */
54                 uint64_t mid;           /* ONEFS_WAITING_FOR_OPLOCK */
55         } data;
56 };
57
58 /**
59  * Internal list of files (along with additional state) that have outstanding
60  * oplocks or requests for oplocks.
61  */
62 struct onefs_callback_record *callback_recs;
63
64 /**
65  * Convert a onefs_callback_record to a debug string using the dbg_ctx().
66  */
67 const char *onefs_cb_record_str_dbg(const struct onefs_callback_record *r)
68 {
69         char *result;
70
71         if (r == NULL) {
72                 result = talloc_strdup(talloc_tos(), "NULL callback record");
73                 return result;
74         }
75
76         switch (r->state) {
77         case ONEFS_OPEN_FILE:
78                 result = talloc_asprintf(talloc_tos(), "cb record %llu for "
79                                          "file %s", r->id,
80                                          fsp_str_dbg(r->data.fsp));
81         case ONEFS_WAITING_FOR_OPLOCK:
82                 result = talloc_asprintf(talloc_tos(), "cb record %llu for "
83                                          "pending mid %llu", r->id,
84                                          (unsigned long long)r->data.mid);
85                 break;
86         default:
87                 result = talloc_asprintf(talloc_tos(), "cb record %llu unknown "
88                                          "state %d", r->id, r->state);
89                 break;
90         }
91
92         return result;
93 }
94
95 /**
96  * Traverse the list of onefs_callback_records and print all entries.
97  */
98 static void debug_cb_records(const char *fn)
99 {
100         struct onefs_callback_record *rec;
101
102         if (DEBUGLEVEL < 10)
103                 return;
104
105         DEBUG(10, ("cb records (%s):\n", fn));
106
107         for (rec = callback_recs; rec; rec = rec->next) {
108                 DEBUGADD(10, ("%s\n", onefs_cb_record_str_dbg(rec)));
109         }
110 }
111
112 /**
113  * Find a callback record in the list of outstanding oplock operations.
114  *
115  * Once n ifs_createfile requests an oplock on a file, the kernel communicates
116  * with samba via the oplock event channel by sending events that reference an
117  * id.  This function maps that id to the onefs_callback_record that was
118  * created for it during the initial setup on open (onefs_oplock_wait_record).
119  * When a matching id is found in the onefs_callback_record list, the
120  * callback_type is checked to make sure the record is in in the correct
121  * state.
122  */
123 static struct onefs_callback_record *onefs_find_cb(uint64_t id,
124     enum onefs_callback_state expected_state)
125 {
126         struct onefs_callback_record *rec;
127
128         debug_cb_records("onefs_find_cb");
129
130         for (rec = callback_recs; rec; rec = rec->next) {
131                 if (rec->id == id) {
132                         DEBUG(10, ("found %s\n",
133                                    onefs_cb_record_str_dbg(rec)));
134                         break;
135                 }
136         }
137
138         if (rec == NULL) {
139                 DEBUG(5, ("Could not find callback record for id %llu\n", id));
140                 return NULL;
141         }
142
143         if (rec->state != expected_state) {
144                 DEBUG(0, ("Expected cb type %d, got %s", expected_state,
145                           onefs_cb_record_str_dbg(rec)));
146                 SMB_ASSERT(0);
147                 return NULL;
148         }
149
150         return rec;
151 }
152
153 /**
154  * Remove and free a callback record from the callback record list.
155  */
156 void destroy_onefs_callback_record(uint64_t id)
157 {
158         struct onefs_callback_record *rec;
159
160         debug_cb_records("destroy_onefs_callback_record");
161
162         if (id == 0) {
163                 DEBUG(10, ("destroy_onefs_callback_record: Nothing to "
164                            "destroy\n"));
165                 return;
166         }
167
168         for (rec = callback_recs; rec; rec = rec->next) {
169                 if (rec->id == id) {
170                         DLIST_REMOVE(callback_recs, rec);
171                         SAFE_FREE(rec);
172                         DEBUG(10, ("removed cb rec %llu\n", id));
173                         return;
174                 }
175         }
176
177         DEBUG(0, ("Could not find cb rec %llu to delete", id));
178         SMB_ASSERT(0);
179 }
180
181 /**
182  * Initialize a callback record and add it to the list of outstanding callback
183  * records.
184  *
185  * This is called in the open path before ifs_createfile so an id can be
186  * passed in.  Each callback record can be in one of two states:
187  *
188  *   1. WAITING_FOR_OPLOCK: This is the initial state for all callback
189  *   records.  If ifs_createfile can be completed syncronously without needing
190  *   to break any level I oplocks, the state is transitioned to OPEN_FILE.
191  *   Otherwise ifs_createfile will finish asynchronously and the open is
192  *   deferred.  When the necessary level I opocks have been broken, and the
193  *   open can be done, an event is sent by the kernel on the oplock event
194  *   channel, which is handled by semlock_available_handler.  At this point
195  *   the deferred open is retried.  Unless a level I oplock was acquired by
196  *   another client, ifs_createfile will now complete synchronously.
197  *
198  *   2. OPEN_FILE: Once ifs_createfile completes, the callback record is
199  *   transitioned to this state via onefs_set_oplock_callback.
200  */
201 uint64_t onefs_oplock_wait_record(uint64_t mid)
202 {
203         struct onefs_callback_record *result;
204         static uint64_t id_generator = 0;
205
206         if (!(result = SMB_MALLOC_P(struct onefs_callback_record))) {
207                 DEBUG(0, ("talloc failed\n"));
208                 return 0;
209         }
210
211         memset(result, '\0', sizeof(result));
212
213         id_generator += 1;
214         if (id_generator == 0) {
215                 /* Wow, that's a long-running smbd... */
216                 id_generator += 1;
217         }
218
219         result->id = id_generator;
220
221         result->state = ONEFS_WAITING_FOR_OPLOCK;
222         result->data.mid = mid;
223         DLIST_ADD(callback_recs, result);
224
225         DEBUG(10, ("New cb rec %llu created\n", result->id));
226
227         return result->id;
228 }
229
230 /**
231  * Transition the callback record state to OPEN_FILE.
232  *
233  * This is called after the file is opened and an fsp struct has been
234  * allocated.  The mid is dropped in favor of storing the fsp.
235  */
236 void onefs_set_oplock_callback(uint64_t id, files_struct *fsp)
237 {
238         struct onefs_callback_record *cb;
239         char *msg;
240
241         DEBUG(10, ("onefs_set_oplock_callback called for cb rec %llu\n", id));
242
243         if (!(cb = onefs_find_cb(id, ONEFS_WAITING_FOR_OPLOCK))) {
244                 if (asprintf(&msg, "Got invalid callback %lld\n", id) != -1) {
245                         smb_panic(msg);
246                 }
247                 smb_panic("Got invalid callback id\n");
248         }
249
250         /*
251          * Paranoia check
252          */
253         if (open_was_deferred(cb->data.mid)) {
254                 if (asprintf(&msg, "Trying to upgrade callback for deferred "
255                              "open mid=%llu\n", (unsigned long long)cb->data.mid) != -1) {
256                         smb_panic(msg);
257                 }
258                 smb_panic("Trying to upgrade callback for deferred open "
259                           "mid\n");
260         }
261
262         cb->state = ONEFS_OPEN_FILE;
263         cb->data.fsp = fsp;
264 }
265
266 /**
267  * Using a callback record, initialize a share mode entry to pass to
268  * share_mode_entry_to_message to send samba IPC messages.
269  */
270 static void init_share_mode_entry(struct share_mode_entry *sme,
271                                   struct onefs_callback_record *cb,
272                                   int op_type)
273 {
274         ZERO_STRUCT(*sme);
275
276         sme->pid = procid_self();
277         sme->op_type = op_type;
278         sme->id = cb->data.fsp->file_id;
279         sme->share_file_id = cb->data.fsp->fh->gen_id;
280 }
281
282 /**
283  * Callback when a break-to-none event is received from the kernel.
284  *
285  * On OneFS level 1 oplocks are always broken to level 2 first, therefore an
286  * async level 2 break message is always sent when breaking to none.  The
287  * downside of this is that OneFS currently has no way to express breaking
288  * directly from level 1 to none.
289  */
290 static void oplock_break_to_none_handler(uint64_t id)
291 {
292         struct onefs_callback_record *cb;
293         struct share_mode_entry sme;
294         char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
295
296         DEBUG(10, ("oplock_break_to_none_handler called for id %llu\n", id));
297
298         if (!(cb = onefs_find_cb(id, ONEFS_OPEN_FILE))) {
299                 DEBUG(3, ("oplock_break_to_none_handler: could not find "
300                           "callback id %llu\n", id));
301                 return;
302         }
303
304         DEBUG(10, ("oplock_break_to_none_handler called for file %s\n",
305                    fsp_str_dbg(cb->data.fsp)));
306
307         init_share_mode_entry(&sme, cb, FORCE_OPLOCK_BREAK_TO_NONE);
308         share_mode_entry_to_message(msg, &sme);
309         messaging_send_buf(smbd_messaging_context(),
310                            sme.pid,
311                            MSG_SMB_ASYNC_LEVEL2_BREAK,
312                            (uint8_t *)msg,
313                            MSG_SMB_SHARE_MODE_ENTRY_SIZE);
314
315         /*
316          * We could still receive an OPLOCK_REVOKED message, so keep the
317          * oplock_callback_id around.
318          */
319 }
320
321 /**
322  * Callback when a break-to-level2 event is received from the kernel.
323  *
324  * Breaks from level 1 to level 2.
325  */
326 static void oplock_break_to_level_two_handler(uint64_t id)
327 {
328         struct onefs_callback_record *cb;
329         struct share_mode_entry sme;
330         char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
331
332         DEBUG(10, ("oplock_break_to_level_two_handler called for id %llu\n",
333                    id));
334
335         if (!(cb = onefs_find_cb(id, ONEFS_OPEN_FILE))) {
336                 DEBUG(3, ("oplock_break_to_level_two_handler: could not find "
337                           "callback id %llu\n", id));
338                 return;
339         }
340
341         DEBUG(10, ("oplock_break_to_level_two_handler called for file %s\n",
342                    fsp_str_dbg(cb->data.fsp)));
343
344         init_share_mode_entry(&sme, cb, LEVEL_II_OPLOCK);
345         share_mode_entry_to_message(msg, &sme);
346         messaging_send_buf(smbd_messaging_context(),
347                           sme.pid,
348                           MSG_SMB_BREAK_REQUEST,
349                           (uint8_t *)msg,
350                           MSG_SMB_SHARE_MODE_ENTRY_SIZE);
351
352         /*
353          * We could still receive an OPLOCK_REVOKED or OPLOCK_BREAK_TO_NONE
354          * message, so keep the oplock_callback_id around.
355          */
356 }
357
358 /**
359  * Revoke an oplock from an unresponsive client.
360  *
361  * The kernel will send this message when it times out waiting for a level 1
362  * oplock break to be acknowledged by the client.  The oplock is then
363  * immediately removed.
364  */
365 static void oplock_revoked_handler(uint64_t id)
366 {
367         struct onefs_callback_record *cb;
368         files_struct *fsp = NULL;
369
370         DEBUG(10, ("oplock_revoked_handler called for id %llu\n", id));
371
372         if (!(cb = onefs_find_cb(id, ONEFS_OPEN_FILE))) {
373                 DEBUG(3, ("oplock_revoked_handler: could not find "
374                           "callback id %llu\n", id));
375                 return;
376         }
377
378         fsp = cb->data.fsp;
379
380         SMB_ASSERT(fsp->oplock_timeout == NULL);
381
382         DEBUG(0,("Level 1 oplock break failed for file %s. Forcefully "
383                  "revoking oplock\n", fsp_str_dbg(fsp)));
384
385         remove_oplock(fsp);
386
387         /*
388          * cb record is cleaned up in fsp ext data destructor on close, so
389          * leave it in the list.
390          */
391 }
392
393 /**
394  * Asynchronous ifs_createfile callback
395  *
396  * If ifs_createfile had to asynchronously break any oplocks, this function is
397  * called when the kernel sends an event that the open can be retried.
398  */
399 static void semlock_available_handler(uint64_t id)
400 {
401         struct onefs_callback_record *cb;
402
403         DEBUG(10, ("semlock_available_handler called: %llu\n", id));
404
405         if (!(cb = onefs_find_cb(id, ONEFS_WAITING_FOR_OPLOCK))) {
406                 DEBUG(5, ("semlock_available_handler: Did not find callback "
407                           "%llu\n", id));
408                 return;
409         }
410
411         DEBUG(10, ("Got semlock available for mid %llu\n",
412                 (unsigned long long)cb->data.mid));
413
414         /* Paranoia check */
415         if (!(open_was_deferred(cb->data.mid))) {
416                 char *msg;
417                 if (asprintf(&msg, "Semlock available on an open that wasn't "
418                              "deferred: %s\n",
419                               onefs_cb_record_str_dbg(cb)) != -1) {
420                         smb_panic(msg);
421                 }
422                 smb_panic("Semlock available on an open that wasn't "
423                           "deferred\n");
424         }
425
426         schedule_deferred_open_smb_message(cb->data.mid);
427
428         /* Cleanup the callback record since the open will be retried. */
429         destroy_onefs_callback_record(id);
430
431         return;
432 }
433
434 /**
435  * Asynchronous ifs_createfile failure callback
436  *
437  * If ifs_createfile had to asynchronously break any oplocks, but an error was
438  * encountered in the kernel, the open will be retried with the state->failed
439  * set to true.  This will prompt the open path to send an INTERNAL_ERROR
440  * error message to the client.
441  */
442 static void semlock_async_failure_handler(uint64_t id)
443 {
444         struct onefs_callback_record *cb;
445         struct deferred_open_record *state;
446
447         DEBUG(1, ("semlock_async_failure_handler called: %llu\n", id));
448
449         if (!(cb = onefs_find_cb(id, ONEFS_WAITING_FOR_OPLOCK))) {
450                 DEBUG(5, ("semlock_async_failure_handler: Did not find callback "
451                           "%llu\n", id));
452                 return;
453         }
454
455         DEBUG(1, ("Got semlock_async_failure message for mid %llu\n",
456                 (unsigned long long)cb->data.mid));
457
458         /* Paranoia check */
459         if (!(open_was_deferred(cb->data.mid))) {
460                 char *msg;
461                 if (asprintf(&msg, "Semlock failure on an open that wasn't "
462                              "deferred: %s\n",
463                               onefs_cb_record_str_dbg(cb)) != -1) {
464                         smb_panic(msg);
465                 }
466                 smb_panic("Semlock failure on an open that wasn't deferred\n");
467         }
468
469         /* Find the actual deferred open record. */
470         if (!get_open_deferred_message_state(cb->data.mid, NULL, &state)) {
471                 DEBUG(0, ("Could not find deferred request for "
472                           "mid %d\n", cb->data.mid));
473                 destroy_onefs_callback_record(id);
474                 return;
475         }
476
477         /* Update to failed so the client can be notified on retried open. */
478         state->failed = true;
479
480         /* Schedule deferred open for immediate retry. */
481         schedule_deferred_open_smb_message(cb->data.mid);
482
483         /* Cleanup the callback record here since the open will be retried. */
484         destroy_onefs_callback_record(id);
485
486         return;
487 }
488
489 /**
490  * OneFS acquires all oplocks via ifs_createfile, so this is a no-op.
491  */
492 static bool onefs_set_kernel_oplock(struct kernel_oplocks *_ctx,
493                                     files_struct *fsp, int oplock_type) {
494         return true;
495 }
496
497 /**
498  * Release the kernel oplock.
499  */
500 static void onefs_release_kernel_oplock(struct kernel_oplocks *_ctx,
501                                         files_struct *fsp, int oplock_type)
502 {
503         enum oplock_type oplock = onefs_samba_oplock_to_oplock(oplock_type);
504
505         DEBUG(10, ("onefs_release_kernel_oplock: Releasing %s to type %s\n",
506                    fsp_str_dbg(fsp), onefs_oplock_str(oplock)));
507
508         if (fsp->fh->fd == -1) {
509                 DEBUG(1, ("no fd\n"));
510                 return;
511         }
512
513         /* Downgrade oplock to either SHARED or NONE. */
514         if (ifs_oplock_downgrade(fsp->fh->fd, oplock)) {
515                 DEBUG(1,("ifs_oplock_downgrade failed: %s\n",
516                          strerror(errno)));
517         }
518 }
519
520 /**
521  * Wrap ifs_semlock_write so it is only called on operations that aren't
522  * already contended in the kernel.
523  */
524 static void onefs_semlock_write(int fd, enum level2_contention_type type,
525                                 enum semlock_operation semlock_op)
526 {
527         int ret;
528
529         switch (type) {
530         case LEVEL2_CONTEND_ALLOC_GROW:
531         case LEVEL2_CONTEND_POSIX_BRL:
532                 DEBUG(10, ("Taking %d write semlock for cmd %d on fd: %d\n",
533                            semlock_op, type, fd));
534                 ret = ifs_semlock_write(fd, semlock_op);
535                 if (ret) {
536                         DEBUG(0,("ifs_semlock_write failed taking %d write "
537                                  "semlock for cmd %d on fd: %d: %s",
538                                  semlock_op, type, fd, strerror(errno)));
539                 }
540                 break;
541         default:
542                 DEBUG(10, ("Skipping write semlock for cmd %d on fd: %d\n",
543                            type, fd));
544         }
545 }
546
547 /**
548  * Contend level 2 oplocks in the kernel and smbd.
549  *
550  * Taking a write semlock will contend all level 2 oplocks in all smbds across
551  * the cluster except the fsp's own level 2 oplock.  This lack of
552  * self-contention is a limitation of the current OneFS kernel oplocks
553  * implementation.  Luckily it is easy to contend our own level 2 oplock by
554  * checking the the fsp's oplock_type.  If it's a level2, send a break message
555  * to the client and remove the oplock.
556  */
557 static void onefs_contend_level2_oplocks_begin(files_struct *fsp,
558                                                enum level2_contention_type type)
559 {
560         /* Take care of level 2 kernel contention. */
561         onefs_semlock_write(fsp->fh->fd, type, SEMLOCK_LOCK);
562
563         /* Take care of level 2 self contention. */
564         if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
565                 break_level2_to_none_async(fsp);
566 }
567
568 /**
569  * Unlock the write semlock when the level 2 contending operation ends.
570  */
571 static void onefs_contend_level2_oplocks_end(files_struct *fsp,
572                                              enum level2_contention_type type)
573 {
574         /* Take care of level 2 kernel contention. */
575         onefs_semlock_write(fsp->fh->fd, type, SEMLOCK_UNLOCK);
576 }
577
578 /**
579  * Return string value of onefs oplock types.
580  */
581 const char *onefs_oplock_str(enum oplock_type onefs_oplock_type)
582 {
583         switch (onefs_oplock_type) {
584         case OPLOCK_NONE:
585                 return "OPLOCK_NONE";
586         case OPLOCK_EXCLUSIVE:
587                 return "OPLOCK_EXCLUSIVE";
588         case OPLOCK_BATCH:
589                 return "OPLOCK_BATCH";
590         case OPLOCK_SHARED:
591                 return "OPLOCK_SHARED";
592         default:
593                 break;
594         }
595         return "UNKNOWN";
596 }
597
598 /**
599  * Convert from onefs to samba oplock.
600  */
601 int onefs_oplock_to_samba_oplock(enum oplock_type onefs_oplock)
602 {
603         switch (onefs_oplock) {
604         case OPLOCK_NONE:
605                 return NO_OPLOCK;
606         case OPLOCK_EXCLUSIVE:
607                 return EXCLUSIVE_OPLOCK;
608         case OPLOCK_BATCH:
609                 return BATCH_OPLOCK;
610         case OPLOCK_SHARED:
611                 return LEVEL_II_OPLOCK;
612         default:
613                 DEBUG(0, ("unknown oplock type %d found\n", onefs_oplock));
614                 break;
615         }
616         return NO_OPLOCK;
617 }
618
619 /**
620  * Convert from samba to onefs oplock.
621  */
622 enum oplock_type onefs_samba_oplock_to_oplock(int samba_oplock_type)
623 {
624         if (BATCH_OPLOCK_TYPE(samba_oplock_type)) return OPLOCK_BATCH;
625         if (EXCLUSIVE_OPLOCK_TYPE(samba_oplock_type)) return OPLOCK_EXCLUSIVE;
626         if (LEVEL_II_OPLOCK_TYPE(samba_oplock_type)) return OPLOCK_SHARED;
627         return OPLOCK_NONE;
628 }
629
630 /**
631  * Oplock event handler.
632  *
633  * Call into the event system dispatcher to handle each event.
634  */
635 static void onefs_oplocks_read_fde_handler(struct event_context *ev,
636                                            struct fd_event *fde,
637                                            uint16_t flags,
638                                            void *private_data)
639 {
640         struct onefs_oplocks_context *ctx =
641             talloc_get_type(private_data, struct onefs_oplocks_context);
642
643         if (oplocks_event_dispatcher(ctx->onefs_ops)) {
644                 DEBUG(0, ("oplocks_event_dispatcher failed: %s\n",
645                           strerror(errno)));
646         }
647 }
648
649 /**
650  * Setup kernel oplocks
651  */
652 static const struct kernel_oplocks_ops onefs_koplocks_ops = {
653         .set_oplock                     = onefs_set_kernel_oplock,
654         .release_oplock                 = onefs_release_kernel_oplock,
655         .contend_level2_oplocks_begin   = onefs_contend_level2_oplocks_begin,
656         .contend_level2_oplocks_end     = onefs_contend_level2_oplocks_end,
657 };
658
659 static const struct oplocks_event_ops onefs_dispatch_ops = {
660         .oplock_break_to_none = oplock_break_to_none_handler,
661         .oplock_break_to_level_two = oplock_break_to_level_two_handler,
662         .oplock_revoked = oplock_revoked_handler,
663         .semlock_available = semlock_available_handler,
664         .semlock_async_failure = semlock_async_failure_handler,
665 };
666
667 struct kernel_oplocks *onefs_init_kernel_oplocks(struct smbd_server_connection *sconn)
668 {
669         struct kernel_oplocks *_ctx = NULL;
670         struct onefs_oplocks_context *ctx = NULL;
671         struct procoptions po = PROCOPTIONS_INIT;
672
673         DEBUG(10, ("onefs_init_kernel_oplocks called\n"));
674
675         /* Set the non-blocking proc flag */
676         po.po_flags_on |= P_NON_BLOCKING_SEMLOCK;
677         if (setprocoptions(&po) != 0) {
678                 DEBUG(0, ("setprocoptions failed: %s.\n", strerror(errno)));
679                 return NULL;
680         }
681
682         /* Setup the oplock contexts */
683         _ctx = talloc_zero(mem_ctx, struct kernel_oplocks);
684         if (!_ctx) {
685                 return NULL;
686         }
687
688         ctx = talloc_zero(_ctx, struct onefs_oplocks_context);
689         if (!ctx) {
690                 goto err_out;
691         }
692         ctx->sconn = sconn;
693
694         _ctx->ops = &onefs_koplocks_ops;
695         _ctx->flags = (KOPLOCKS_LEVEL2_SUPPORTED |
696                        KOPLOCKS_DEFERRED_OPEN_NOTIFICATION |
697                        KOPLOCKS_TIMEOUT_NOTIFICATION |
698                        KOPLOCKS_OPLOCK_BROKEN_NOTIFICATION);
699         _ctx->private_data = ctx;
700         ctx->ctx = _ctx;
701         ctx->onefs_ops = &onefs_dispatch_ops;
702
703         /* Register an kernel event channel for oplocks */
704         ctx->onefs_event_fd = oplocks_event_register();
705         if (ctx->onefs_event_fd == -1) {
706                 DEBUG(0, ("oplocks_event_register failed: %s\n",
707                            strerror(errno)));
708                 goto err_out;
709         }
710
711         DEBUG(10, ("oplock event_fd = %d\n", ctx->onefs_event_fd));
712
713         /* Register the oplock event_fd with samba's event system */
714         ctx->read_fde = event_add_fd(sconn->ev_ctx,
715                                      ctx,
716                                      ctx->onefs_event_fd,
717                                      EVENT_FD_READ,
718                                      onefs_oplocks_read_fde_handler,
719                                      ctx);
720         return _ctx;
721
722  err_out:
723         talloc_free(_ctx);
724         return NULL;
725 }
726
727 #else
728  void oplock_onefs_dummy(void);
729  void oplock_onefs_dummy(void) {}
730 #endif /* HAVE_ONEFS */