Coverage Report

Created: 2026-07-25 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/lib/g_lock.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   global locks based on dbwrap and messaging
4
   Copyright (C) 2009 by Volker Lendecke
5
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*/
19
20
#include "replace.h"
21
#include "system/filesys.h"
22
#include "lib/util/server_id.h"
23
#include "lib/util/debug.h"
24
#include "lib/util/talloc_stack.h"
25
#include "lib/util/samba_util.h"
26
#include "lib/util_path.h"
27
#include "dbwrap/dbwrap.h"
28
#include "dbwrap/dbwrap_open.h"
29
#include "dbwrap/dbwrap_watch.h"
30
#include "g_lock.h"
31
#include "util_tdb.h"
32
#include "../lib/util/tevent_ntstatus.h"
33
#include "messages.h"
34
#include "serverid.h"
35
36
struct g_lock_ctx {
37
  struct db_context *db;
38
  struct messaging_context *msg;
39
  enum dbwrap_lock_order lock_order;
40
  bool busy;
41
};
42
43
struct g_lock {
44
  struct server_id exclusive;
45
  size_t num_shared;
46
  uint8_t *shared;
47
  uint64_t unique_lock_epoch;
48
  uint64_t unique_data_epoch;
49
  size_t datalen;
50
  uint8_t *data;
51
};
52
53
static bool g_lock_parse(uint8_t *buf, size_t buflen, struct g_lock *lck)
54
0
{
55
0
  struct server_id exclusive;
56
0
  size_t num_shared, shared_len, data_len;
57
0
  uint64_t unique_lock_epoch;
58
0
  uint64_t unique_data_epoch;
59
60
0
  if (buflen < (SERVER_ID_BUF_LENGTH + /* exclusive */
61
0
          sizeof(uint64_t) +     /* unique_lock_epoch */
62
0
          sizeof(uint64_t) +     /* unique_data_epoch */
63
0
          sizeof(uint32_t))) {   /* num_shared */
64
0
    struct g_lock ret = {
65
0
      .exclusive.pid = 0,
66
0
      .unique_lock_epoch = generate_unique_u64(0),
67
0
      .unique_data_epoch = generate_unique_u64(0),
68
0
    };
69
0
    *lck = ret;
70
0
    return true;
71
0
  }
72
73
0
  server_id_get(&exclusive, buf);
74
0
  buf += SERVER_ID_BUF_LENGTH;
75
0
  buflen -= SERVER_ID_BUF_LENGTH;
76
77
0
  unique_lock_epoch = BVAL(buf, 0);
78
0
  buf += sizeof(uint64_t);
79
0
  buflen -= sizeof(uint64_t);
80
81
0
  unique_data_epoch = BVAL(buf, 0);
82
0
  buf += sizeof(uint64_t);
83
0
  buflen -= sizeof(uint64_t);
84
85
0
  num_shared = IVAL(buf, 0);
86
0
  buf += sizeof(uint32_t);
87
0
  buflen -= sizeof(uint32_t);
88
89
0
  if (num_shared > buflen/SERVER_ID_BUF_LENGTH) {
90
0
    DBG_DEBUG("num_shared=%zu, buflen=%zu\n",
91
0
        num_shared,
92
0
        buflen);
93
0
    return false;
94
0
  }
95
96
0
  shared_len = num_shared * SERVER_ID_BUF_LENGTH;
97
0
  data_len = buflen - shared_len;
98
99
0
  *lck = (struct g_lock) {
100
0
    .exclusive = exclusive,
101
0
    .num_shared = num_shared,
102
0
    .shared = num_shared == 0 ? NULL : buf,
103
0
    .unique_lock_epoch = unique_lock_epoch,
104
0
    .unique_data_epoch = unique_data_epoch,
105
0
    .datalen = data_len,
106
0
    .data = data_len == 0 ? NULL : buf + shared_len,
107
0
  };
108
109
0
  return true;
110
0
}
111
112
static void g_lock_get_shared(const struct g_lock *lck,
113
            size_t i,
114
            struct server_id *shared)
115
0
{
116
0
  if (i >= lck->num_shared) {
117
0
    abort();
118
0
  }
119
0
  server_id_get(shared, lck->shared + i*SERVER_ID_BUF_LENGTH);
120
0
}
121
122
static void g_lock_del_shared(struct g_lock *lck, size_t i)
123
0
{
124
0
  if (i >= lck->num_shared) {
125
0
    abort();
126
0
  }
127
0
  lck->num_shared -= 1;
128
0
  if (i < lck->num_shared) {
129
0
    memcpy(lck->shared + i*SERVER_ID_BUF_LENGTH,
130
0
           lck->shared + lck->num_shared*SERVER_ID_BUF_LENGTH,
131
0
           SERVER_ID_BUF_LENGTH);
132
0
  }
133
0
}
134
135
static NTSTATUS g_lock_store(
136
  struct db_record *rec,
137
  struct g_lock *lck,
138
  struct server_id *new_shared,
139
  const TDB_DATA *new_dbufs,
140
  size_t num_new_dbufs,
141
  int dbwrap_flags)
142
0
{
143
0
  uint8_t exclusive[SERVER_ID_BUF_LENGTH];
144
0
  uint8_t seqnum_buf[sizeof(uint64_t)*2];
145
0
  uint8_t sizebuf[sizeof(uint32_t)];
146
0
  uint8_t new_shared_buf[SERVER_ID_BUF_LENGTH];
147
148
0
  struct TDB_DATA dbufs[6 + num_new_dbufs];
149
150
0
  dbufs[0] = (TDB_DATA) {
151
0
    .dptr = exclusive, .dsize = sizeof(exclusive),
152
0
  };
153
0
  dbufs[1] = (TDB_DATA) {
154
0
    .dptr = seqnum_buf, .dsize = sizeof(seqnum_buf),
155
0
  };
156
0
  dbufs[2] = (TDB_DATA) {
157
0
    .dptr = sizebuf, .dsize = sizeof(sizebuf),
158
0
  };
159
0
  dbufs[3] = (TDB_DATA) {
160
0
    .dptr = lck->shared,
161
0
    .dsize = lck->num_shared * SERVER_ID_BUF_LENGTH,
162
0
  };
163
0
  dbufs[4] = (TDB_DATA) { 0 };
164
0
  dbufs[5] = (TDB_DATA) {
165
0
    .dptr = lck->data, .dsize = lck->datalen,
166
0
  };
167
168
0
  if (num_new_dbufs != 0) {
169
0
    memcpy(&dbufs[6],
170
0
           new_dbufs,
171
0
           num_new_dbufs * sizeof(TDB_DATA));
172
0
  }
173
174
0
  server_id_put(exclusive, lck->exclusive);
175
0
  SBVAL(seqnum_buf, 0, lck->unique_lock_epoch);
176
0
  SBVAL(seqnum_buf, 8, lck->unique_data_epoch);
177
178
0
  if (new_shared != NULL) {
179
0
    if (lck->num_shared >= UINT32_MAX) {
180
0
      return NT_STATUS_BUFFER_OVERFLOW;
181
0
    }
182
183
0
    server_id_put(new_shared_buf, *new_shared);
184
185
0
    dbufs[4] = (TDB_DATA) {
186
0
      .dptr = new_shared_buf,
187
0
      .dsize = sizeof(new_shared_buf),
188
0
    };
189
190
0
    lck->num_shared += 1;
191
0
  }
192
193
0
  SIVAL(sizebuf, 0, lck->num_shared);
194
195
0
  return dbwrap_record_storev(rec, dbufs, ARRAY_SIZE(dbufs), dbwrap_flags);
196
0
}
197
198
struct g_lock_ctx *g_lock_ctx_init_backend(
199
  TALLOC_CTX *mem_ctx,
200
  struct messaging_context *msg,
201
  struct db_context **backend)
202
0
{
203
0
  struct g_lock_ctx *result;
204
205
0
  result = talloc_zero(mem_ctx, struct g_lock_ctx);
206
0
  if (result == NULL) {
207
0
    return NULL;
208
0
  }
209
0
  result->msg = msg;
210
0
  result->lock_order = DBWRAP_LOCK_ORDER_NONE;
211
212
0
  result->db = db_open_watched(result, backend, msg);
213
0
  if (result->db == NULL) {
214
0
    DBG_WARNING("db_open_watched failed\n");
215
0
    TALLOC_FREE(result);
216
0
    return NULL;
217
0
  }
218
0
  return result;
219
0
}
220
221
void g_lock_set_lock_order(struct g_lock_ctx *ctx,
222
         enum dbwrap_lock_order lock_order)
223
0
{
224
0
  ctx->lock_order = lock_order;
225
0
}
226
227
struct g_lock_ctx *g_lock_ctx_init(TALLOC_CTX *mem_ctx,
228
           struct messaging_context *msg)
229
0
{
230
0
  char *db_path = NULL;
231
0
  struct db_context *backend = NULL;
232
0
  struct g_lock_ctx *ctx = NULL;
233
234
0
  db_path = lock_path(mem_ctx, "g_lock.tdb");
235
0
  if (db_path == NULL) {
236
0
    return NULL;
237
0
  }
238
239
0
  backend = db_open(
240
0
    mem_ctx,
241
0
    db_path,
242
0
    0,
243
0
    TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH|TDB_VOLATILE,
244
0
    O_RDWR|O_CREAT,
245
0
    0600,
246
0
    DBWRAP_LOCK_ORDER_3,
247
0
    DBWRAP_FLAG_NONE);
248
0
  TALLOC_FREE(db_path);
249
0
  if (backend == NULL) {
250
0
    DBG_WARNING("Could not open g_lock.tdb\n");
251
0
    return NULL;
252
0
  }
253
254
0
  ctx = g_lock_ctx_init_backend(mem_ctx, msg, &backend);
255
0
  return ctx;
256
0
}
257
258
static void g_lock_cleanup_dead(
259
  struct g_lock *lck,
260
  struct server_id *dead_blocker)
261
0
{
262
0
  bool exclusive_died;
263
0
  struct server_id_buf tmp;
264
265
0
  if (dead_blocker == NULL) {
266
0
    return;
267
0
  }
268
269
0
  exclusive_died = server_id_equal(dead_blocker, &lck->exclusive);
270
271
0
  if (exclusive_died) {
272
0
    DBG_DEBUG("Exclusive holder %s died\n",
273
0
        server_id_str_buf(lck->exclusive, &tmp));
274
0
    lck->exclusive.pid = 0;
275
0
  }
276
277
0
  if (lck->num_shared != 0) {
278
0
    bool shared_died;
279
0
    struct server_id shared;
280
281
0
    g_lock_get_shared(lck, 0, &shared);
282
0
    shared_died = server_id_equal(dead_blocker, &shared);
283
284
0
    if (shared_died) {
285
0
      DBG_DEBUG("Shared holder %s died\n",
286
0
          server_id_str_buf(shared, &tmp));
287
0
      g_lock_del_shared(lck, 0);
288
0
    }
289
0
  }
290
0
}
291
292
static ssize_t g_lock_find_shared(
293
  struct g_lock *lck,
294
  const struct server_id *self)
295
0
{
296
0
  size_t i;
297
298
0
  for (i=0; i<lck->num_shared; i++) {
299
0
    struct server_id shared;
300
0
    bool same;
301
302
0
    g_lock_get_shared(lck, i, &shared);
303
304
0
    same = server_id_equal(self, &shared);
305
0
    if (same) {
306
0
      return i;
307
0
    }
308
0
  }
309
310
0
  return -1;
311
0
}
312
313
static void g_lock_cleanup_shared(struct g_lock *lck)
314
0
{
315
0
  size_t i;
316
0
  struct server_id check;
317
0
  bool exists;
318
319
0
  if (lck->num_shared == 0) {
320
0
    return;
321
0
  }
322
323
  /*
324
   * Read locks can stay around forever if the process dies. Do
325
   * a heuristic check for process existence: Check one random
326
   * process for existence. Hopefully this will keep runaway
327
   * read locks under control.
328
   */
329
0
  i = generate_random() % lck->num_shared;
330
0
  g_lock_get_shared(lck, i, &check);
331
332
0
  exists = serverid_exists(&check);
333
0
  if (!exists) {
334
0
    struct server_id_buf tmp;
335
0
    DBG_DEBUG("Shared locker %s died -- removing\n",
336
0
        server_id_str_buf(check, &tmp));
337
0
    g_lock_del_shared(lck, i);
338
0
  }
339
0
}
340
341
struct g_lock_lock_cb_state {
342
  struct g_lock_ctx *ctx;
343
  struct db_record *rec;
344
  struct g_lock *lck;
345
  struct server_id *new_shared;
346
  g_lock_lock_cb_fn_t cb_fn;
347
  void *cb_private;
348
  TALLOC_CTX *update_mem_ctx;
349
  TDB_DATA updated_data;
350
  bool existed;
351
  bool modified;
352
  bool unlock;
353
  int dbwrap_flags;
354
};
355
356
NTSTATUS g_lock_lock_cb_dump(struct g_lock_lock_cb_state *cb_state,
357
           void (*fn)(struct server_id exclusive,
358
          size_t num_shared,
359
          const struct server_id *shared,
360
          const uint8_t *data,
361
          size_t datalen,
362
          void *private_data),
363
           void *private_data)
364
0
{
365
0
  struct g_lock *lck = cb_state->lck;
366
367
  /* We allow a cb_fn only for G_LOCK_WRITE for now... */
368
0
  SMB_ASSERT(lck->num_shared == 0);
369
370
0
  fn(lck->exclusive,
371
0
     0, /* num_shared */
372
0
     NULL, /* shared */
373
0
     lck->data,
374
0
     lck->datalen,
375
0
     private_data);
376
377
0
  return NT_STATUS_OK;
378
0
}
379
380
NTSTATUS g_lock_lock_cb_writev(struct g_lock_lock_cb_state *cb_state,
381
             const TDB_DATA *dbufs,
382
             size_t num_dbufs,
383
             int flags)
384
0
{
385
0
  NTSTATUS status;
386
387
0
  status = dbwrap_merge_dbufs(&cb_state->updated_data,
388
0
            cb_state->update_mem_ctx,
389
0
            dbufs, num_dbufs);
390
0
  if (!NT_STATUS_IS_OK(status)) {
391
0
    return status;
392
0
  }
393
394
0
  cb_state->modified = true;
395
0
  cb_state->lck->data = cb_state->updated_data.dptr;
396
0
  cb_state->lck->datalen = cb_state->updated_data.dsize;
397
0
  cb_state->dbwrap_flags = flags;
398
399
0
  return NT_STATUS_OK;
400
0
}
401
402
void g_lock_lock_cb_unlock(struct g_lock_lock_cb_state *cb_state)
403
0
{
404
0
  cb_state->unlock = true;
405
0
}
406
407
struct g_lock_lock_cb_watch_data_state {
408
  struct tevent_context *ev;
409
  struct g_lock_ctx *ctx;
410
  TDB_DATA key;
411
  struct server_id blocker;
412
  bool blockerdead;
413
  uint64_t unique_lock_epoch;
414
  uint64_t unique_data_epoch;
415
  uint64_t watch_instance;
416
  NTSTATUS status;
417
};
418
419
static void g_lock_lock_cb_watch_data_done(struct tevent_req *subreq);
420
421
struct tevent_req *g_lock_lock_cb_watch_data_send(
422
  TALLOC_CTX *mem_ctx,
423
  struct tevent_context *ev,
424
  struct g_lock_lock_cb_state *cb_state,
425
  struct server_id blocker)
426
0
{
427
0
  struct tevent_req *req = NULL;
428
0
  struct g_lock_lock_cb_watch_data_state *state = NULL;
429
0
  struct tevent_req *subreq = NULL;
430
0
  TDB_DATA key = dbwrap_record_get_key(cb_state->rec);
431
432
0
  req = tevent_req_create(
433
0
    mem_ctx, &state, struct g_lock_lock_cb_watch_data_state);
434
0
  if (req == NULL) {
435
0
    return NULL;
436
0
  }
437
0
  state->ev = ev;
438
0
  state->ctx = cb_state->ctx;
439
0
  state->blocker = blocker;
440
441
0
  state->key = tdb_data_talloc_copy(state, key);
442
0
  if (tevent_req_nomem(state->key.dptr, req)) {
443
0
    return tevent_req_post(req, ev);
444
0
  }
445
446
0
  state->unique_lock_epoch = cb_state->lck->unique_lock_epoch;
447
0
  state->unique_data_epoch = cb_state->lck->unique_data_epoch;
448
449
0
  DBG_DEBUG("state->unique_data_epoch=%"PRIu64"\n", state->unique_data_epoch);
450
451
0
  subreq = dbwrap_watched_watch_send(
452
0
    state, state->ev, cb_state->rec, 0, state->blocker);
453
0
  if (tevent_req_nomem(subreq, req)) {
454
0
    return tevent_req_post(req, ev);
455
0
  }
456
0
  tevent_req_set_callback(subreq, g_lock_lock_cb_watch_data_done, req);
457
458
0
  return req;
459
0
}
460
461
static void g_lock_lock_cb_watch_data_done_fn(
462
  struct db_record *rec,
463
  TDB_DATA value,
464
  void *private_data)
465
0
{
466
0
  struct tevent_req *req = talloc_get_type_abort(
467
0
    private_data, struct tevent_req);
468
0
  struct g_lock_lock_cb_watch_data_state *state = tevent_req_data(
469
0
    req, struct g_lock_lock_cb_watch_data_state);
470
0
  struct tevent_req *subreq = NULL;
471
0
  struct g_lock lck;
472
0
  bool ok;
473
474
0
  ok = g_lock_parse(value.dptr, value.dsize, &lck);
475
0
  if (!ok) {
476
0
    dbwrap_watched_watch_remove_instance(rec, state->watch_instance);
477
0
    state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
478
0
    return;
479
0
  }
480
481
0
  if (lck.unique_data_epoch != state->unique_data_epoch) {
482
0
    dbwrap_watched_watch_remove_instance(rec, state->watch_instance);
483
0
    DBG_DEBUG("lck.unique_data_epoch=%"PRIu64", "
484
0
        "state->unique_data_epoch=%"PRIu64"\n",
485
0
        lck.unique_data_epoch,
486
0
        state->unique_data_epoch);
487
0
    state->status = NT_STATUS_OK;
488
0
    return;
489
0
  }
490
491
  /*
492
   * The lock epoch changed, so we better
493
   * remove ourself from the waiter list
494
   * (most likely the first position)
495
   * and re-add us at the end of the list.
496
   *
497
   * This gives other lock waiters a change
498
   * to make progress.
499
   *
500
   * Otherwise we'll keep our waiter instance alive,
501
   * keep waiting (most likely at first position).
502
   */
503
0
  if (lck.unique_lock_epoch != state->unique_lock_epoch) {
504
0
    dbwrap_watched_watch_remove_instance(rec, state->watch_instance);
505
0
    state->watch_instance = dbwrap_watched_watch_add_instance(rec);
506
0
    state->unique_lock_epoch = lck.unique_lock_epoch;
507
0
  }
508
509
0
  subreq = dbwrap_watched_watch_send(
510
0
    state, state->ev, rec, state->watch_instance, state->blocker);
511
0
  if (subreq == NULL) {
512
0
    dbwrap_watched_watch_remove_instance(rec, state->watch_instance);
513
0
    state->status = NT_STATUS_NO_MEMORY;
514
0
    return;
515
0
  }
516
0
  tevent_req_set_callback(subreq, g_lock_lock_cb_watch_data_done, req);
517
518
0
  state->status = NT_STATUS_EVENT_PENDING;
519
0
}
520
521
static void g_lock_lock_cb_watch_data_done(struct tevent_req *subreq)
522
0
{
523
0
  struct tevent_req *req = tevent_req_callback_data(
524
0
    subreq, struct tevent_req);
525
0
  struct g_lock_lock_cb_watch_data_state *state = tevent_req_data(
526
0
    req, struct g_lock_lock_cb_watch_data_state);
527
0
  NTSTATUS status;
528
0
  uint64_t instance = 0;
529
530
0
  status = dbwrap_watched_watch_recv(
531
0
    subreq, &instance, &state->blockerdead, &state->blocker);
532
0
  TALLOC_FREE(subreq);
533
0
  if (tevent_req_nterror(req, status)) {
534
0
    DBG_DEBUG("dbwrap_watched_watch_recv returned %s\n",
535
0
        nt_errstr(status));
536
0
    return;
537
0
  }
538
539
0
  state->watch_instance = instance;
540
541
0
  status = dbwrap_do_locked(
542
0
    state->ctx->db, state->key, g_lock_lock_cb_watch_data_done_fn, req);
543
0
  if (tevent_req_nterror(req, status)) {
544
0
    DBG_DEBUG("dbwrap_do_locked returned %s\n", nt_errstr(status));
545
0
    return;
546
0
  }
547
0
  if (NT_STATUS_EQUAL(state->status, NT_STATUS_EVENT_PENDING)) {
548
0
    return;
549
0
  }
550
0
  if (tevent_req_nterror(req, state->status)) {
551
0
    return;
552
0
  }
553
0
  tevent_req_done(req);
554
0
}
555
556
NTSTATUS g_lock_lock_cb_watch_data_recv(
557
  struct tevent_req *req,
558
  bool *blockerdead,
559
  struct server_id *blocker)
560
0
{
561
0
  struct g_lock_lock_cb_watch_data_state *state = tevent_req_data(
562
0
    req, struct g_lock_lock_cb_watch_data_state);
563
0
  NTSTATUS status;
564
565
0
  if (tevent_req_is_nterror(req, &status)) {
566
0
    return status;
567
0
  }
568
0
  if (blockerdead != NULL) {
569
0
    *blockerdead = state->blockerdead;
570
0
  }
571
0
  if (blocker != NULL) {
572
0
    *blocker = state->blocker;
573
0
  }
574
575
0
  return NT_STATUS_OK;
576
0
}
577
578
void g_lock_lock_cb_wake_watchers(struct g_lock_lock_cb_state *cb_state)
579
0
{
580
0
  struct g_lock *lck = cb_state->lck;
581
582
0
  lck->unique_data_epoch = generate_unique_u64(lck->unique_data_epoch);
583
0
  cb_state->modified = true;
584
0
}
585
586
static NTSTATUS g_lock_lock_cb_run_and_store(struct g_lock_lock_cb_state *cb_state)
587
0
{
588
0
  struct g_lock *lck = cb_state->lck;
589
0
  NTSTATUS success_status = NT_STATUS_OK;
590
0
  NTSTATUS status;
591
592
0
  if (cb_state->cb_fn != NULL) {
593
594
0
    SMB_ASSERT(lck->num_shared == 0);
595
0
    SMB_ASSERT(cb_state->new_shared == NULL);
596
597
0
    if (cb_state->ctx->lock_order != DBWRAP_LOCK_ORDER_NONE) {
598
0
      const char *name = dbwrap_name(cb_state->ctx->db);
599
0
      dbwrap_lock_order_lock(name, cb_state->ctx->lock_order);
600
0
    }
601
602
0
    cb_state->ctx->busy = true;
603
0
    cb_state->cb_fn(cb_state, cb_state->cb_private);
604
0
    cb_state->ctx->busy = false;
605
606
0
    if (cb_state->ctx->lock_order != DBWRAP_LOCK_ORDER_NONE) {
607
0
      const char *name = dbwrap_name(cb_state->ctx->db);
608
0
      dbwrap_lock_order_unlock(name, cb_state->ctx->lock_order);
609
0
    }
610
0
  }
611
612
0
  if (cb_state->unlock) {
613
    /*
614
     * Unlocked should wake up watchers.
615
     *
616
     * We no longer need the lock, so
617
     * force a wakeup of the next watchers,
618
     * even if we don't do any update.
619
     */
620
0
    dbwrap_watched_watch_reset_alerting(cb_state->rec);
621
0
    dbwrap_watched_watch_force_alerting(cb_state->rec);
622
0
    if (!cb_state->modified) {
623
      /*
624
       * The record was not changed at
625
       * all, so we can also avoid
626
       * storing the lck.unique_lock_epoch
627
       * change
628
       */
629
0
      return NT_STATUS_WAS_UNLOCKED;
630
0
    }
631
0
    lck->exclusive = (struct server_id) { .pid = 0 };
632
0
    cb_state->new_shared = NULL;
633
634
0
    if (lck->datalen == 0) {
635
0
      if (!cb_state->existed) {
636
0
        return NT_STATUS_WAS_UNLOCKED;
637
0
      }
638
639
0
      status = dbwrap_record_delete(cb_state->rec);
640
0
      if (!NT_STATUS_IS_OK(status)) {
641
0
        DBG_WARNING("dbwrap_record_delete() failed: %s\n",
642
0
            nt_errstr(status));
643
0
        return status;
644
0
      }
645
0
      return NT_STATUS_WAS_UNLOCKED;
646
0
    }
647
648
0
    success_status = NT_STATUS_WAS_UNLOCKED;
649
0
  }
650
651
0
  status = g_lock_store(cb_state->rec,
652
0
            cb_state->lck,
653
0
            cb_state->new_shared,
654
0
            NULL,
655
0
            0,
656
0
            cb_state->dbwrap_flags);
657
0
  if (!NT_STATUS_IS_OK(status)) {
658
0
    DBG_WARNING("g_lock_store() failed: %s\n",
659
0
          nt_errstr(status));
660
0
    return status;
661
0
  }
662
663
0
  return success_status;
664
0
}
665
666
struct g_lock_lock_state {
667
  struct tevent_context *ev;
668
  struct g_lock_ctx *ctx;
669
  TDB_DATA key;
670
  enum g_lock_type type;
671
  bool retry;
672
  g_lock_lock_cb_fn_t cb_fn;
673
  void *cb_private;
674
};
675
676
struct g_lock_lock_fn_state {
677
  struct g_lock_lock_state *req_state;
678
  struct server_id *dead_blocker;
679
680
  struct tevent_req *watch_req;
681
  uint64_t watch_instance;
682
  NTSTATUS status;
683
};
684
685
static int g_lock_lock_state_destructor(struct g_lock_lock_state *s);
686
687
static NTSTATUS g_lock_trylock(
688
  struct db_record *rec,
689
  struct g_lock_lock_fn_state *state,
690
  TDB_DATA data,
691
  struct server_id *blocker)
692
0
{
693
0
  struct g_lock_lock_state *req_state = state->req_state;
694
0
  struct server_id self = messaging_server_id(req_state->ctx->msg);
695
0
  enum g_lock_type type = req_state->type;
696
0
  bool retry = req_state->retry;
697
0
  struct g_lock lck = { .exclusive.pid = 0 };
698
0
  struct g_lock_lock_cb_state cb_state = {
699
0
    .ctx = req_state->ctx,
700
0
    .rec = rec,
701
0
    .lck = &lck,
702
0
    .cb_fn = req_state->cb_fn,
703
0
    .cb_private = req_state->cb_private,
704
0
    .existed = data.dsize != 0,
705
0
    .update_mem_ctx = talloc_tos(),
706
0
    .dbwrap_flags = dbwrap_record_get_flags(rec).persistent ?
707
0
      DBWRAP_STORE_PERSISTENT : 0,
708
0
  };
709
0
  struct server_id_buf tmp;
710
0
  NTSTATUS status;
711
0
  bool ok;
712
713
0
  ok = g_lock_parse(data.dptr, data.dsize, &lck);
714
0
  if (!ok) {
715
0
    dbwrap_watched_watch_remove_instance(rec, state->watch_instance);
716
0
    DBG_DEBUG("g_lock_parse failed\n");
717
0
    return NT_STATUS_INTERNAL_DB_CORRUPTION;
718
0
  }
719
720
0
  g_lock_cleanup_dead(&lck, state->dead_blocker);
721
722
0
  lck.unique_lock_epoch = generate_unique_u64(lck.unique_lock_epoch);
723
724
0
  if (lck.exclusive.pid != 0) {
725
0
    bool self_exclusive = server_id_equal(&self, &lck.exclusive);
726
727
0
    if (!self_exclusive) {
728
0
      bool exists = serverid_exists(&lck.exclusive);
729
0
      if (!exists) {
730
0
        lck.exclusive = (struct server_id) { .pid=0 };
731
0
        goto noexclusive;
732
0
      }
733
734
0
      DBG_DEBUG("%s has an exclusive lock\n",
735
0
          server_id_str_buf(lck.exclusive, &tmp));
736
737
0
      if (type == G_LOCK_DOWNGRADE) {
738
0
        struct server_id_buf tmp2;
739
740
0
        dbwrap_watched_watch_remove_instance(rec,
741
0
            state->watch_instance);
742
743
0
        DBG_DEBUG("%s: Trying to downgrade %s\n",
744
0
            server_id_str_buf(self, &tmp),
745
0
            server_id_str_buf(
746
0
              lck.exclusive, &tmp2));
747
0
        return NT_STATUS_NOT_LOCKED;
748
0
      }
749
750
0
      if (type == G_LOCK_UPGRADE) {
751
0
        ssize_t shared_idx;
752
753
0
        dbwrap_watched_watch_remove_instance(rec,
754
0
            state->watch_instance);
755
756
0
        shared_idx = g_lock_find_shared(&lck, &self);
757
758
0
        if (shared_idx == -1) {
759
0
          DBG_DEBUG("Trying to upgrade %s "
760
0
              "without "
761
0
              "existing shared lock\n",
762
0
              server_id_str_buf(
763
0
                self, &tmp));
764
0
          return NT_STATUS_NOT_LOCKED;
765
0
        }
766
767
        /*
768
         * We're trying to upgrade, and the
769
         * exclusive lock is taken by someone
770
         * else. This means that someone else
771
         * is waiting for us to give up our
772
         * shared lock. If we now also wait
773
         * for someone to give their shared
774
         * lock, we will deadlock.
775
         */
776
777
0
        DBG_DEBUG("Trying to upgrade %s while "
778
0
            "someone else is also "
779
0
            "trying to upgrade\n",
780
0
            server_id_str_buf(self, &tmp));
781
0
        return NT_STATUS_POSSIBLE_DEADLOCK;
782
0
      }
783
784
0
      DBG_DEBUG("Waiting for lck.exclusive=%s\n",
785
0
          server_id_str_buf(lck.exclusive, &tmp));
786
787
      /*
788
       * We will return NT_STATUS_LOCK_NOT_GRANTED
789
       * and need to monitor the record.
790
       *
791
       * If we don't have a watcher instance yet,
792
       * we should add one.
793
       */
794
0
      if (state->watch_instance == 0) {
795
0
        state->watch_instance =
796
0
          dbwrap_watched_watch_add_instance(rec);
797
0
      }
798
799
0
      *blocker = lck.exclusive;
800
0
      return NT_STATUS_LOCK_NOT_GRANTED;
801
0
    }
802
803
0
    if (type == G_LOCK_DOWNGRADE) {
804
0
      DBG_DEBUG("Downgrading %s from WRITE to READ\n",
805
0
          server_id_str_buf(self, &tmp));
806
807
0
      lck.exclusive = (struct server_id) { .pid = 0 };
808
0
      goto do_shared;
809
0
    }
810
811
0
    if (!retry) {
812
0
      dbwrap_watched_watch_remove_instance(rec,
813
0
            state->watch_instance);
814
815
0
      DBG_DEBUG("%s already locked by self\n",
816
0
          server_id_str_buf(self, &tmp));
817
0
      return NT_STATUS_WAS_LOCKED;
818
0
    }
819
820
0
    g_lock_cleanup_shared(&lck);
821
822
0
    if (lck.num_shared != 0) {
823
0
      g_lock_get_shared(&lck, 0, blocker);
824
825
0
      DBG_DEBUG("Continue waiting for shared lock %s\n",
826
0
          server_id_str_buf(*blocker, &tmp));
827
828
      /*
829
       * We will return NT_STATUS_LOCK_NOT_GRANTED
830
       * and need to monitor the record.
831
       *
832
       * If we don't have a watcher instance yet,
833
       * we should add one.
834
       */
835
0
      if (state->watch_instance == 0) {
836
0
        state->watch_instance =
837
0
          dbwrap_watched_watch_add_instance(rec);
838
0
      }
839
840
0
      return NT_STATUS_LOCK_NOT_GRANTED;
841
0
    }
842
843
    /*
844
     * Retry after a conflicting lock was released..
845
     * All pending readers are gone so we got the lock...
846
     */
847
0
    goto got_lock;
848
0
  }
849
850
0
noexclusive:
851
852
0
  if (type == G_LOCK_UPGRADE) {
853
0
    ssize_t shared_idx = g_lock_find_shared(&lck, &self);
854
855
0
    if (shared_idx == -1) {
856
0
      dbwrap_watched_watch_remove_instance(rec,
857
0
            state->watch_instance);
858
859
0
      DBG_DEBUG("Trying to upgrade %s without "
860
0
          "existing shared lock\n",
861
0
          server_id_str_buf(self, &tmp));
862
0
      return NT_STATUS_NOT_LOCKED;
863
0
    }
864
865
0
    g_lock_del_shared(&lck, shared_idx);
866
0
    type = G_LOCK_WRITE;
867
0
  }
868
869
0
  if (type == G_LOCK_WRITE) {
870
0
    ssize_t shared_idx = g_lock_find_shared(&lck, &self);
871
0
    int flags = dbwrap_record_get_flags(rec).persistent ?
872
0
      DBWRAP_STORE_PERSISTENT : 0;
873
874
0
    if (shared_idx != -1) {
875
0
      dbwrap_watched_watch_remove_instance(rec,
876
0
            state->watch_instance);
877
0
      DBG_DEBUG("Trying to writelock existing shared %s\n",
878
0
          server_id_str_buf(self, &tmp));
879
0
      return NT_STATUS_WAS_LOCKED;
880
0
    }
881
882
0
    lck.exclusive = self;
883
884
0
    g_lock_cleanup_shared(&lck);
885
886
0
    if (lck.num_shared == 0) {
887
      /*
888
       * If we store ourself as exclusive writer,
889
       * without any pending readers ...
890
       */
891
0
      goto got_lock;
892
0
    }
893
894
0
    if (state->watch_instance == 0) {
895
      /*
896
       * Here we have lck.num_shared != 0.
897
       *
898
       * We will return NT_STATUS_LOCK_NOT_GRANTED
899
       * below.
900
       *
901
       * And don't have a watcher instance yet!
902
       *
903
       * We add it here before g_lock_store()
904
       * in order to trigger just one
905
       * low level dbwrap_do_locked() call.
906
       */
907
0
      state->watch_instance =
908
0
        dbwrap_watched_watch_add_instance(rec);
909
0
    }
910
911
0
    status = g_lock_store(rec, &lck, NULL, NULL, 0, flags);
912
0
    if (!NT_STATUS_IS_OK(status)) {
913
0
      DBG_DEBUG("g_lock_store() failed: %s\n",
914
0
          nt_errstr(status));
915
0
      return status;
916
0
    }
917
918
0
    talloc_set_destructor(
919
0
      req_state, g_lock_lock_state_destructor);
920
921
0
    g_lock_get_shared(&lck, 0, blocker);
922
923
0
    DBG_DEBUG("Waiting for %zu shared locks, "
924
0
        "picking blocker %s\n",
925
0
        lck.num_shared,
926
0
        server_id_str_buf(*blocker, &tmp));
927
928
0
    return NT_STATUS_LOCK_NOT_GRANTED;
929
0
  }
930
931
0
do_shared:
932
933
0
  g_lock_cleanup_shared(&lck);
934
0
  cb_state.new_shared = &self;
935
0
  goto got_lock;
936
937
0
got_lock:
938
  /*
939
   * We got the lock we asked for, so we no
940
   * longer need to monitor the record.
941
   */
942
0
  dbwrap_watched_watch_remove_instance(rec, state->watch_instance);
943
944
0
  status = g_lock_lock_cb_run_and_store(&cb_state);
945
0
  if (!NT_STATUS_IS_OK(status) &&
946
0
      !NT_STATUS_EQUAL(status, NT_STATUS_WAS_UNLOCKED))
947
0
  {
948
0
    DBG_WARNING("g_lock_lock_cb_run_and_store() failed: %s\n",
949
0
          nt_errstr(status));
950
0
    return status;
951
0
  }
952
953
0
  talloc_set_destructor(req_state, NULL);
954
0
  return status;
955
0
}
956
957
static void g_lock_lock_fn(
958
  struct db_record *rec,
959
  TDB_DATA value,
960
  void *private_data)
961
0
{
962
0
  struct g_lock_lock_fn_state *state = private_data;
963
0
  struct server_id blocker = {0};
964
965
  /*
966
   * We're trying to get a lock and if we are
967
   * successful in doing that, we should not
968
   * wakeup any other waiters, all they would
969
   * find is that we're holding a lock they
970
   * are conflicting with.
971
   */
972
0
  dbwrap_watched_watch_skip_alerting(rec);
973
974
0
  state->status = g_lock_trylock(rec, state, value, &blocker);
975
0
  if (!NT_STATUS_IS_OK(state->status)) {
976
0
    DBG_DEBUG("g_lock_trylock returned %s\n",
977
0
        nt_errstr(state->status));
978
0
  }
979
0
  if (!NT_STATUS_EQUAL(state->status, NT_STATUS_LOCK_NOT_GRANTED)) {
980
0
    return;
981
0
  }
982
983
0
  state->watch_req = dbwrap_watched_watch_send(
984
0
    state->req_state, state->req_state->ev, rec, state->watch_instance, blocker);
985
0
  if (state->watch_req == NULL) {
986
0
    state->status = NT_STATUS_NO_MEMORY;
987
0
  }
988
0
}
989
990
static int g_lock_lock_state_destructor(struct g_lock_lock_state *s)
991
0
{
992
0
  NTSTATUS status = g_lock_unlock(s->ctx, s->key);
993
0
  if (!NT_STATUS_IS_OK(status)) {
994
0
    DBG_DEBUG("g_lock_unlock failed: %s\n", nt_errstr(status));
995
0
  }
996
0
  return 0;
997
0
}
998
999
static void g_lock_lock_retry(struct tevent_req *subreq);
1000
1001
struct tevent_req *g_lock_lock_send(TALLOC_CTX *mem_ctx,
1002
            struct tevent_context *ev,
1003
            struct g_lock_ctx *ctx,
1004
            TDB_DATA key,
1005
            enum g_lock_type type,
1006
            g_lock_lock_cb_fn_t cb_fn,
1007
            void *cb_private)
1008
0
{
1009
0
  struct tevent_req *req;
1010
0
  struct g_lock_lock_state *state;
1011
0
  struct g_lock_lock_fn_state fn_state;
1012
0
  NTSTATUS status;
1013
0
  bool ok;
1014
1015
0
  SMB_ASSERT(!ctx->busy);
1016
1017
0
  req = tevent_req_create(mem_ctx, &state, struct g_lock_lock_state);
1018
0
  if (req == NULL) {
1019
0
    return NULL;
1020
0
  }
1021
0
  state->ev = ev;
1022
0
  state->ctx = ctx;
1023
0
  state->key = key;
1024
0
  state->type = type;
1025
0
  state->cb_fn = cb_fn;
1026
0
  state->cb_private = cb_private;
1027
1028
0
  fn_state = (struct g_lock_lock_fn_state) {
1029
0
    .req_state = state,
1030
0
  };
1031
1032
  /*
1033
   * We allow a cb_fn only for G_LOCK_WRITE for now.
1034
   *
1035
   * It's all we currently need and it makes a few things
1036
   * easier to implement.
1037
   */
1038
0
  if (unlikely(cb_fn != NULL && type != G_LOCK_WRITE)) {
1039
0
    tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_6);
1040
0
    return tevent_req_post(req, ev);
1041
0
  }
1042
1043
0
  status = dbwrap_do_locked(ctx->db, key, g_lock_lock_fn, &fn_state);
1044
0
  if (tevent_req_nterror(req, status)) {
1045
0
    DBG_DEBUG("dbwrap_do_locked failed: %s\n",
1046
0
        nt_errstr(status));
1047
0
    return tevent_req_post(req, ev);
1048
0
  }
1049
1050
0
  if (NT_STATUS_IS_OK(fn_state.status)) {
1051
0
    tevent_req_done(req);
1052
0
    return tevent_req_post(req, ev);
1053
0
  }
1054
0
  if (!NT_STATUS_EQUAL(fn_state.status, NT_STATUS_LOCK_NOT_GRANTED)) {
1055
0
    tevent_req_nterror(req, fn_state.status);
1056
0
    return tevent_req_post(req, ev);
1057
0
  }
1058
1059
0
  if (tevent_req_nomem(fn_state.watch_req, req)) {
1060
0
    return tevent_req_post(req, ev);
1061
0
  }
1062
1063
0
  ok = tevent_req_set_endtime(
1064
0
    fn_state.watch_req,
1065
0
    state->ev,
1066
0
    timeval_current_ofs(5 + generate_random() % 5, 0));
1067
0
  if (!ok) {
1068
0
    tevent_req_oom(req);
1069
0
    return tevent_req_post(req, ev);
1070
0
  }
1071
0
  tevent_req_set_callback(fn_state.watch_req, g_lock_lock_retry, req);
1072
1073
0
  return req;
1074
0
}
1075
1076
static void g_lock_lock_retry(struct tevent_req *subreq)
1077
0
{
1078
0
  struct tevent_req *req = tevent_req_callback_data(
1079
0
    subreq, struct tevent_req);
1080
0
  struct g_lock_lock_state *state = tevent_req_data(
1081
0
    req, struct g_lock_lock_state);
1082
0
  struct g_lock_lock_fn_state fn_state;
1083
0
  struct server_id blocker = { .pid = 0 };
1084
0
  bool blockerdead = false;
1085
0
  NTSTATUS status;
1086
0
  uint64_t instance = 0;
1087
1088
0
  status = dbwrap_watched_watch_recv(subreq, &instance, &blockerdead, &blocker);
1089
0
  DBG_DEBUG("watch_recv returned %s\n", nt_errstr(status));
1090
0
  TALLOC_FREE(subreq);
1091
1092
0
  if (!NT_STATUS_IS_OK(status) &&
1093
0
      !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
1094
0
    tevent_req_nterror(req, status);
1095
0
    return;
1096
0
  }
1097
1098
0
  state->retry = true;
1099
1100
0
  fn_state = (struct g_lock_lock_fn_state) {
1101
0
    .req_state = state,
1102
0
    .dead_blocker = blockerdead ? &blocker : NULL,
1103
0
    .watch_instance = instance,
1104
0
  };
1105
1106
0
  status = dbwrap_do_locked(state->ctx->db, state->key,
1107
0
          g_lock_lock_fn, &fn_state);
1108
0
  if (tevent_req_nterror(req, status)) {
1109
0
    DBG_DEBUG("dbwrap_do_locked failed: %s\n",
1110
0
        nt_errstr(status));
1111
0
    return;
1112
0
  }
1113
1114
0
  if (NT_STATUS_IS_OK(fn_state.status)) {
1115
0
    tevent_req_done(req);
1116
0
    return;
1117
0
  }
1118
0
  if (!NT_STATUS_EQUAL(fn_state.status, NT_STATUS_LOCK_NOT_GRANTED)) {
1119
0
    tevent_req_nterror(req, fn_state.status);
1120
0
    return;
1121
0
  }
1122
1123
0
  if (tevent_req_nomem(fn_state.watch_req, req)) {
1124
0
    return;
1125
0
  }
1126
1127
0
  if (!tevent_req_set_endtime(
1128
0
        fn_state.watch_req, state->ev,
1129
0
        timeval_current_ofs(5 + generate_random() % 5, 0))) {
1130
0
    return;
1131
0
  }
1132
0
  tevent_req_set_callback(fn_state.watch_req, g_lock_lock_retry, req);
1133
0
}
1134
1135
NTSTATUS g_lock_lock_recv(struct tevent_req *req)
1136
0
{
1137
0
  struct g_lock_lock_state *state = tevent_req_data(
1138
0
    req, struct g_lock_lock_state);
1139
0
  struct g_lock_ctx *ctx = state->ctx;
1140
0
  NTSTATUS status;
1141
1142
0
  if (tevent_req_is_nterror(req, &status)) {
1143
0
    if (NT_STATUS_EQUAL(status, NT_STATUS_WAS_UNLOCKED)) {
1144
0
      return NT_STATUS_OK;
1145
0
    }
1146
0
    return status;
1147
0
  }
1148
1149
0
  if ((ctx->lock_order != DBWRAP_LOCK_ORDER_NONE) &&
1150
0
      ((state->type == G_LOCK_READ) ||
1151
0
       (state->type == G_LOCK_WRITE))) {
1152
0
    const char *name = dbwrap_name(ctx->db);
1153
0
    dbwrap_lock_order_lock(name, ctx->lock_order);
1154
0
  }
1155
1156
0
  return NT_STATUS_OK;
1157
0
}
1158
1159
struct g_lock_lock_simple_state {
1160
  struct g_lock_ctx *ctx;
1161
  struct server_id me;
1162
  enum g_lock_type type;
1163
  NTSTATUS status;
1164
  g_lock_lock_cb_fn_t cb_fn;
1165
  void *cb_private;
1166
};
1167
1168
static void g_lock_lock_simple_fn(
1169
  struct db_record *rec,
1170
  TDB_DATA value,
1171
  void *private_data)
1172
0
{
1173
0
  struct g_lock_lock_simple_state *state = private_data;
1174
0
  struct server_id_buf buf;
1175
0
  struct g_lock lck = { .exclusive.pid = 0 };
1176
0
  struct g_lock_lock_cb_state cb_state = {
1177
0
    .ctx = state->ctx,
1178
0
    .rec = rec,
1179
0
    .lck = &lck,
1180
0
    .cb_fn = state->cb_fn,
1181
0
    .cb_private = state->cb_private,
1182
0
    .existed = value.dsize != 0,
1183
0
    .update_mem_ctx = talloc_tos(),
1184
0
    .dbwrap_flags = dbwrap_record_get_flags(rec).persistent ?
1185
0
      DBWRAP_STORE_PERSISTENT : 0,
1186
0
  };
1187
0
  bool ok;
1188
1189
0
  ok = g_lock_parse(value.dptr, value.dsize, &lck);
1190
0
  if (!ok) {
1191
0
    DBG_DEBUG("g_lock_parse failed\n");
1192
0
    state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
1193
0
    return;
1194
0
  }
1195
1196
0
  if (lck.exclusive.pid != 0) {
1197
0
    DBG_DEBUG("locked by %s\n",
1198
0
        server_id_str_buf(lck.exclusive, &buf));
1199
0
    goto not_granted;
1200
0
  }
1201
1202
0
  if (state->type == G_LOCK_WRITE) {
1203
0
    if (lck.num_shared != 0) {
1204
0
      DBG_DEBUG("num_shared=%zu\n", lck.num_shared);
1205
0
      goto not_granted;
1206
0
    }
1207
0
    lck.exclusive = state->me;
1208
0
  } else if (state->type == G_LOCK_READ) {
1209
0
    g_lock_cleanup_shared(&lck);
1210
0
    cb_state.new_shared = &state->me;
1211
0
  } else {
1212
0
    smb_panic(__location__);
1213
0
  }
1214
1215
0
  lck.unique_lock_epoch = generate_unique_u64(lck.unique_lock_epoch);
1216
1217
  /*
1218
   * We are going to store us as owner,
1219
   * so we got what we were waiting for.
1220
   *
1221
   * So we no longer need to monitor the
1222
   * record.
1223
   */
1224
0
  dbwrap_watched_watch_skip_alerting(rec);
1225
1226
0
  state->status = g_lock_lock_cb_run_and_store(&cb_state);
1227
0
  if (!NT_STATUS_IS_OK(state->status) &&
1228
0
      !NT_STATUS_EQUAL(state->status, NT_STATUS_WAS_UNLOCKED))
1229
0
  {
1230
0
    DBG_WARNING("g_lock_lock_cb_run_and_store() failed: %s\n",
1231
0
          nt_errstr(state->status));
1232
0
    return;
1233
0
  }
1234
1235
0
  return;
1236
1237
0
not_granted:
1238
0
  state->status = NT_STATUS_LOCK_NOT_GRANTED;
1239
0
}
1240
1241
NTSTATUS g_lock_lock(struct g_lock_ctx *ctx, TDB_DATA key,
1242
         enum g_lock_type type, struct timeval timeout,
1243
         g_lock_lock_cb_fn_t cb_fn,
1244
         void *cb_private)
1245
0
{
1246
0
  TALLOC_CTX *frame;
1247
0
  struct tevent_context *ev;
1248
0
  struct tevent_req *req;
1249
0
  struct timeval end;
1250
0
  NTSTATUS status;
1251
1252
0
  SMB_ASSERT(!ctx->busy);
1253
1254
  /*
1255
   * We allow a cb_fn only for G_LOCK_WRITE for now.
1256
   *
1257
   * It's all we currently need and it makes a few things
1258
   * easier to implement.
1259
   */
1260
0
  if (unlikely(cb_fn != NULL && type != G_LOCK_WRITE)) {
1261
0
    return NT_STATUS_INVALID_PARAMETER_5;
1262
0
  }
1263
1264
0
  if ((type == G_LOCK_READ) || (type == G_LOCK_WRITE)) {
1265
    /*
1266
     * This is an abstraction violation: Normally we do
1267
     * the sync wrappers around async functions with full
1268
     * nested event contexts. However, this is used in
1269
     * very hot code paths, so avoid the event context
1270
     * creation for the good path where there's no lock
1271
     * contention. My benchmark gave a factor of 2
1272
     * improvement for lock/unlock.
1273
     */
1274
0
    struct g_lock_lock_simple_state state = {
1275
0
      .ctx = ctx,
1276
0
      .me = messaging_server_id(ctx->msg),
1277
0
      .type = type,
1278
0
      .cb_fn = cb_fn,
1279
0
      .cb_private = cb_private,
1280
0
    };
1281
0
    status = dbwrap_do_locked(
1282
0
      ctx->db, key, g_lock_lock_simple_fn, &state);
1283
0
    if (!NT_STATUS_IS_OK(status)) {
1284
0
      DBG_DEBUG("dbwrap_do_locked() failed: %s\n",
1285
0
          nt_errstr(status));
1286
0
      return status;
1287
0
    }
1288
1289
0
    DBG_DEBUG("status=%s, state.status=%s\n",
1290
0
        nt_errstr(status),
1291
0
        nt_errstr(state.status));
1292
1293
0
    if (NT_STATUS_IS_OK(state.status)) {
1294
0
      if (ctx->lock_order != DBWRAP_LOCK_ORDER_NONE) {
1295
0
        const char *name = dbwrap_name(ctx->db);
1296
0
        dbwrap_lock_order_lock(name, ctx->lock_order);
1297
0
      }
1298
0
      return NT_STATUS_OK;
1299
0
    }
1300
0
    if (NT_STATUS_EQUAL(state.status, NT_STATUS_WAS_UNLOCKED)) {
1301
      /* without dbwrap_lock_order_lock() */
1302
0
      return NT_STATUS_OK;
1303
0
    }
1304
0
    if (!NT_STATUS_EQUAL(
1305
0
          state.status, NT_STATUS_LOCK_NOT_GRANTED)) {
1306
0
      return state.status;
1307
0
    }
1308
1309
0
    if (timeval_is_zero(&timeout)) {
1310
0
      return NT_STATUS_LOCK_NOT_GRANTED;
1311
0
    }
1312
1313
    /*
1314
     * Fall back to the full g_lock_trylock logic,
1315
     * g_lock_lock_simple_fn() called above only covers
1316
     * the uncontended path.
1317
     */
1318
0
  }
1319
1320
0
  frame = talloc_stackframe();
1321
0
  status = NT_STATUS_NO_MEMORY;
1322
1323
0
  ev = samba_tevent_context_init(frame);
1324
0
  if (ev == NULL) {
1325
0
    goto fail;
1326
0
  }
1327
0
  req = g_lock_lock_send(frame, ev, ctx, key, type, cb_fn, cb_private);
1328
0
  if (req == NULL) {
1329
0
    goto fail;
1330
0
  }
1331
0
  end = timeval_current_ofs(timeout.tv_sec, timeout.tv_usec);
1332
0
  if (!tevent_req_set_endtime(req, ev, end)) {
1333
0
    goto fail;
1334
0
  }
1335
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1336
0
    goto fail;
1337
0
  }
1338
0
  status = g_lock_lock_recv(req);
1339
0
 fail:
1340
0
  TALLOC_FREE(frame);
1341
0
  return status;
1342
0
}
1343
1344
struct g_lock_unlock_state {
1345
  struct server_id self;
1346
  NTSTATUS status;
1347
};
1348
1349
static void g_lock_unlock_fn(
1350
  struct db_record *rec,
1351
  TDB_DATA value,
1352
  void *private_data)
1353
0
{
1354
0
  struct g_lock_unlock_state *state = private_data;
1355
0
  int flags = dbwrap_record_get_flags(rec).persistent ?
1356
0
    DBWRAP_STORE_PERSISTENT : 0;
1357
0
  struct server_id_buf tmp1, tmp2;
1358
0
  struct g_lock lck;
1359
0
  size_t i;
1360
0
  bool ok, exclusive;
1361
1362
0
  ok = g_lock_parse(value.dptr, value.dsize, &lck);
1363
0
  if (!ok) {
1364
0
    DBG_DEBUG("g_lock_parse() failed\n");
1365
0
    state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
1366
0
    return;
1367
0
  }
1368
1369
0
  exclusive = server_id_equal(&state->self, &lck.exclusive);
1370
1371
0
  for (i=0; i<lck.num_shared; i++) {
1372
0
    struct server_id shared;
1373
0
    g_lock_get_shared(&lck, i, &shared);
1374
0
    if (server_id_equal(&state->self, &shared)) {
1375
0
      break;
1376
0
    }
1377
0
  }
1378
1379
0
  if (i < lck.num_shared) {
1380
0
    if (exclusive) {
1381
0
      DBG_DEBUG("%s both exclusive and shared (%zu)\n",
1382
0
          server_id_str_buf(state->self, &tmp1),
1383
0
          i);
1384
0
      state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
1385
0
      return;
1386
0
    }
1387
0
    g_lock_del_shared(&lck, i);
1388
0
  } else {
1389
0
    if (!exclusive) {
1390
0
      DBG_DEBUG("Lock not found, self=%s, lck.exclusive=%s, "
1391
0
          "num_shared=%zu\n",
1392
0
          server_id_str_buf(state->self, &tmp1),
1393
0
          server_id_str_buf(lck.exclusive, &tmp2),
1394
0
          lck.num_shared);
1395
0
      state->status = NT_STATUS_NOT_FOUND;
1396
0
      return;
1397
0
    }
1398
0
    lck.exclusive = (struct server_id) { .pid = 0 };
1399
0
  }
1400
1401
0
  if ((lck.exclusive.pid == 0) &&
1402
0
      (lck.num_shared == 0) &&
1403
0
      (lck.datalen == 0)) {
1404
0
    state->status = dbwrap_record_delete(rec);
1405
0
    return;
1406
0
  }
1407
1408
0
  if (!exclusive && lck.exclusive.pid != 0) {
1409
    /*
1410
     * We only had a read lock and there's
1411
     * someone waiting for an exclusive lock.
1412
     *
1413
     * Don't alert the exclusive lock waiter
1414
     * if there are still other read lock holders.
1415
     */
1416
0
    g_lock_cleanup_shared(&lck);
1417
0
    if (lck.num_shared != 0) {
1418
0
      dbwrap_watched_watch_skip_alerting(rec);
1419
0
    }
1420
0
  }
1421
1422
0
  lck.unique_lock_epoch = generate_unique_u64(lck.unique_lock_epoch);
1423
1424
0
  state->status = g_lock_store(rec, &lck, NULL, NULL, 0, flags);
1425
0
}
1426
1427
NTSTATUS g_lock_unlock(struct g_lock_ctx *ctx, TDB_DATA key)
1428
0
{
1429
0
  struct g_lock_unlock_state state = {
1430
0
    .self = messaging_server_id(ctx->msg),
1431
0
  };
1432
0
  NTSTATUS status;
1433
1434
0
  SMB_ASSERT(!ctx->busy);
1435
1436
0
  status = dbwrap_do_locked(ctx->db, key, g_lock_unlock_fn, &state);
1437
0
  if (!NT_STATUS_IS_OK(status)) {
1438
0
    DBG_WARNING("dbwrap_do_locked failed: %s\n",
1439
0
          nt_errstr(status));
1440
0
    return status;
1441
0
  }
1442
0
  if (!NT_STATUS_IS_OK(state.status)) {
1443
0
    DBG_WARNING("g_lock_unlock_fn failed: %s\n",
1444
0
          nt_errstr(state.status));
1445
0
    return state.status;
1446
0
  }
1447
1448
0
  if (ctx->lock_order != DBWRAP_LOCK_ORDER_NONE) {
1449
0
    const char *name = dbwrap_name(ctx->db);
1450
0
    dbwrap_lock_order_unlock(name, ctx->lock_order);
1451
0
  }
1452
1453
0
  return NT_STATUS_OK;
1454
0
}
1455
1456
struct g_lock_writev_data_state {
1457
  TDB_DATA key;
1458
  struct server_id self;
1459
  const TDB_DATA *dbufs;
1460
  size_t num_dbufs;
1461
  NTSTATUS status;
1462
  int dbwrap_flags;
1463
};
1464
1465
static void g_lock_writev_data_fn(
1466
  struct db_record *rec,
1467
  TDB_DATA value,
1468
  void *private_data)
1469
0
{
1470
0
  struct g_lock_writev_data_state *state = private_data;
1471
0
  struct g_lock lck;
1472
0
  bool exclusive;
1473
0
  bool ok;
1474
1475
  /*
1476
   * We're holding an exclusive write lock.
1477
   *
1478
   * Now we're updating the content of the record.
1479
   *
1480
   * We should not wakeup any other waiters, all they
1481
   * would find is that we're still holding a lock they
1482
   * are conflicting with.
1483
   */
1484
0
  dbwrap_watched_watch_skip_alerting(rec);
1485
1486
0
  ok = g_lock_parse(value.dptr, value.dsize, &lck);
1487
0
  if (!ok) {
1488
0
    DBG_DEBUG("g_lock_parse for %s failed\n",
1489
0
        tdb_data_dbg(state->key));
1490
0
    state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
1491
0
    return;
1492
0
  }
1493
1494
0
  exclusive = server_id_equal(&state->self, &lck.exclusive);
1495
1496
  /*
1497
   * Make sure we're really exclusive. We are marked as
1498
   * exclusive when we are waiting for an exclusive lock
1499
   */
1500
0
  exclusive &= (lck.num_shared == 0);
1501
1502
0
  if (!exclusive) {
1503
0
    struct server_id_buf buf1, buf2;
1504
0
    DBG_DEBUG("Not locked by us: self=%s, lck.exclusive=%s, "
1505
0
        "lck.num_shared=%zu\n",
1506
0
        server_id_str_buf(state->self, &buf1),
1507
0
        server_id_str_buf(lck.exclusive, &buf2),
1508
0
        lck.num_shared);
1509
0
    state->status = NT_STATUS_NOT_LOCKED;
1510
0
    return;
1511
0
  }
1512
1513
0
  lck.unique_data_epoch = generate_unique_u64(lck.unique_data_epoch);
1514
0
  lck.data = NULL;
1515
0
  lck.datalen = 0;
1516
1517
0
  state->status = g_lock_store(rec,
1518
0
             &lck,
1519
0
             NULL,
1520
0
             state->dbufs,
1521
0
             state->num_dbufs,
1522
0
             state->dbwrap_flags);
1523
0
}
1524
1525
NTSTATUS g_lock_writev_data(
1526
  struct g_lock_ctx *ctx,
1527
  TDB_DATA key,
1528
  const TDB_DATA *dbufs,
1529
  size_t num_dbufs,
1530
  int flags)
1531
0
{
1532
0
  struct g_lock_writev_data_state state = {
1533
0
    .key = key,
1534
0
    .self = messaging_server_id(ctx->msg),
1535
0
    .dbufs = dbufs,
1536
0
    .num_dbufs = num_dbufs,
1537
0
    .dbwrap_flags = flags,
1538
0
  };
1539
0
  NTSTATUS status;
1540
1541
0
  SMB_ASSERT(!ctx->busy);
1542
1543
0
  status = dbwrap_do_locked(
1544
0
    ctx->db, key, g_lock_writev_data_fn, &state);
1545
0
  if (!NT_STATUS_IS_OK(status)) {
1546
0
    DBG_WARNING("dbwrap_do_locked failed: %s\n",
1547
0
          nt_errstr(status));
1548
0
    return status;
1549
0
  }
1550
0
  if (!NT_STATUS_IS_OK(state.status)) {
1551
0
    DBG_WARNING("g_lock_writev_data_fn failed: %s\n",
1552
0
          nt_errstr(state.status));
1553
0
    return state.status;
1554
0
  }
1555
1556
0
  return NT_STATUS_OK;
1557
0
}
1558
1559
NTSTATUS g_lock_write_data(struct g_lock_ctx *ctx, TDB_DATA key,
1560
         const uint8_t *buf, size_t buflen)
1561
0
{
1562
0
  TDB_DATA dbuf = {
1563
0
    .dptr = discard_const_p(uint8_t, buf),
1564
0
    .dsize = buflen,
1565
0
  };
1566
0
  return g_lock_writev_data(ctx, key, &dbuf, 1, 0);
1567
0
}
1568
1569
struct g_lock_locks_state {
1570
  int (*fn)(TDB_DATA key, void *private_data);
1571
  void *private_data;
1572
};
1573
1574
static int g_lock_locks_fn(struct db_record *rec, void *priv)
1575
0
{
1576
0
  TDB_DATA key;
1577
0
  struct g_lock_locks_state *state = (struct g_lock_locks_state *)priv;
1578
1579
0
  key = dbwrap_record_get_key(rec);
1580
0
  return state->fn(key, state->private_data);
1581
0
}
1582
1583
int g_lock_locks_read(struct g_lock_ctx *ctx,
1584
          int (*fn)(TDB_DATA key, void *private_data),
1585
          void *private_data)
1586
0
{
1587
0
  struct g_lock_locks_state state;
1588
0
  NTSTATUS status;
1589
0
  int count;
1590
1591
0
  SMB_ASSERT(!ctx->busy);
1592
1593
0
  state.fn = fn;
1594
0
  state.private_data = private_data;
1595
1596
0
  status = dbwrap_traverse_read(ctx->db,
1597
0
              g_lock_locks_fn,
1598
0
              &state,
1599
0
              &count);
1600
0
  if (!NT_STATUS_IS_OK(status)) {
1601
0
    return -1;
1602
0
  }
1603
0
  return count;
1604
0
}
1605
1606
int g_lock_locks(struct g_lock_ctx *ctx,
1607
     int (*fn)(TDB_DATA key, void *private_data),
1608
     void *private_data)
1609
0
{
1610
0
  struct g_lock_locks_state state;
1611
0
  NTSTATUS status;
1612
0
  int count;
1613
1614
0
  SMB_ASSERT(!ctx->busy);
1615
1616
0
  state.fn = fn;
1617
0
  state.private_data = private_data;
1618
1619
0
  status = dbwrap_traverse(ctx->db, g_lock_locks_fn, &state, &count);
1620
0
  if (!NT_STATUS_IS_OK(status)) {
1621
0
    return -1;
1622
0
  }
1623
0
  return count;
1624
0
}
1625
1626
struct g_lock_dump_state {
1627
  TALLOC_CTX *mem_ctx;
1628
  TDB_DATA key;
1629
  void (*fn)(struct server_id exclusive,
1630
       size_t num_shared,
1631
       const struct server_id *shared,
1632
       const uint8_t *data,
1633
       size_t datalen,
1634
       void *private_data);
1635
  void *private_data;
1636
  NTSTATUS status;
1637
  enum dbwrap_req_state req_state;
1638
};
1639
1640
static void g_lock_dump_fn(TDB_DATA key, TDB_DATA data,
1641
         void *private_data)
1642
0
{
1643
0
  struct g_lock_dump_state *state = private_data;
1644
0
  struct g_lock lck = (struct g_lock) { .exclusive.pid = 0 };
1645
0
  struct server_id *shared = NULL;
1646
0
  size_t i;
1647
0
  bool ok;
1648
1649
0
  ok = g_lock_parse(data.dptr, data.dsize, &lck);
1650
0
  if (!ok) {
1651
0
    DBG_DEBUG("g_lock_parse failed for %s\n",
1652
0
        tdb_data_dbg(state->key));
1653
0
    state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
1654
0
    return;
1655
0
  }
1656
1657
0
  if (lck.num_shared > 0) {
1658
0
    shared = talloc_array(
1659
0
      state->mem_ctx, struct server_id, lck.num_shared);
1660
0
    if (shared == NULL) {
1661
0
      DBG_DEBUG("talloc failed\n");
1662
0
      state->status = NT_STATUS_NO_MEMORY;
1663
0
      return;
1664
0
    }
1665
0
  }
1666
1667
0
  for (i=0; i<lck.num_shared; i++) {
1668
0
    g_lock_get_shared(&lck, i, &shared[i]);
1669
0
  }
1670
1671
0
  state->fn(lck.exclusive,
1672
0
      lck.num_shared,
1673
0
      shared,
1674
0
      lck.data,
1675
0
      lck.datalen,
1676
0
      state->private_data);
1677
1678
0
  TALLOC_FREE(shared);
1679
1680
0
  state->status = NT_STATUS_OK;
1681
0
}
1682
1683
NTSTATUS g_lock_dump(struct g_lock_ctx *ctx, TDB_DATA key,
1684
         void (*fn)(struct server_id exclusive,
1685
        size_t num_shared,
1686
        const struct server_id *shared,
1687
        const uint8_t *data,
1688
        size_t datalen,
1689
        void *private_data),
1690
         void *private_data)
1691
0
{
1692
0
  struct g_lock_dump_state state = {
1693
0
    .mem_ctx = ctx, .key = key,
1694
0
    .fn = fn, .private_data = private_data
1695
0
  };
1696
0
  NTSTATUS status;
1697
1698
0
  SMB_ASSERT(!ctx->busy);
1699
1700
0
  status = dbwrap_parse_record(ctx->db, key, g_lock_dump_fn, &state);
1701
0
  if (!NT_STATUS_IS_OK(status)) {
1702
0
    DBG_DEBUG("dbwrap_parse_record returned %s\n",
1703
0
        nt_errstr(status));
1704
0
    return status;
1705
0
  }
1706
0
  if (!NT_STATUS_IS_OK(state.status)) {
1707
0
    DBG_DEBUG("g_lock_dump_fn returned %s\n",
1708
0
        nt_errstr(state.status));
1709
0
    return state.status;
1710
0
  }
1711
0
  return NT_STATUS_OK;
1712
0
}
1713
1714
static void g_lock_dump_done(struct tevent_req *subreq);
1715
1716
struct tevent_req *g_lock_dump_send(
1717
  TALLOC_CTX *mem_ctx,
1718
  struct tevent_context *ev,
1719
  struct g_lock_ctx *ctx,
1720
  TDB_DATA key,
1721
  void (*fn)(struct server_id exclusive,
1722
       size_t num_shared,
1723
       const struct server_id *shared,
1724
       const uint8_t *data,
1725
       size_t datalen,
1726
       void *private_data),
1727
  void *private_data)
1728
0
{
1729
0
  struct tevent_req *req = NULL, *subreq = NULL;
1730
0
  struct g_lock_dump_state *state = NULL;
1731
1732
0
  SMB_ASSERT(!ctx->busy);
1733
1734
0
  req = tevent_req_create(mem_ctx, &state, struct g_lock_dump_state);
1735
0
  if (req == NULL) {
1736
0
    return NULL;
1737
0
  }
1738
0
  state->mem_ctx = state;
1739
0
  state->key = key;
1740
0
  state->fn = fn;
1741
0
  state->private_data = private_data;
1742
1743
0
  SMB_ASSERT(!ctx->busy);
1744
1745
0
  subreq = dbwrap_parse_record_send(
1746
0
    state,
1747
0
    ev,
1748
0
    ctx->db,
1749
0
    key,
1750
0
    g_lock_dump_fn,
1751
0
    state,
1752
0
    &state->req_state);
1753
0
  if (tevent_req_nomem(subreq, req)) {
1754
0
    return tevent_req_post(req, ev);
1755
0
  }
1756
0
  tevent_req_set_callback(subreq, g_lock_dump_done, req);
1757
0
  return req;
1758
0
}
1759
1760
static void g_lock_dump_done(struct tevent_req *subreq)
1761
0
{
1762
0
  struct tevent_req *req = tevent_req_callback_data(
1763
0
    subreq, struct tevent_req);
1764
0
  struct g_lock_dump_state *state = tevent_req_data(
1765
0
    req, struct g_lock_dump_state);
1766
0
  NTSTATUS status;
1767
1768
0
  status = dbwrap_parse_record_recv(subreq);
1769
0
  TALLOC_FREE(subreq);
1770
0
  if (tevent_req_nterror(req, status) ||
1771
0
      tevent_req_nterror(req, state->status)) {
1772
0
    return;
1773
0
  }
1774
0
  tevent_req_done(req);
1775
0
}
1776
1777
NTSTATUS g_lock_dump_recv(struct tevent_req *req)
1778
0
{
1779
0
  return tevent_req_simple_recv_ntstatus(req);
1780
0
}
1781
1782
int g_lock_seqnum(struct g_lock_ctx *ctx)
1783
0
{
1784
0
  return dbwrap_get_seqnum(ctx->db);
1785
0
}
1786
1787
struct g_lock_watch_data_state {
1788
  struct tevent_context *ev;
1789
  struct g_lock_ctx *ctx;
1790
  TDB_DATA key;
1791
  struct server_id blocker;
1792
  bool blockerdead;
1793
  uint64_t unique_lock_epoch;
1794
  uint64_t unique_data_epoch;
1795
  uint64_t watch_instance;
1796
  NTSTATUS status;
1797
};
1798
1799
static void g_lock_watch_data_done(struct tevent_req *subreq);
1800
1801
static void g_lock_watch_data_send_fn(
1802
  struct db_record *rec,
1803
  TDB_DATA value,
1804
  void *private_data)
1805
0
{
1806
0
  struct tevent_req *req = talloc_get_type_abort(
1807
0
    private_data, struct tevent_req);
1808
0
  struct g_lock_watch_data_state *state = tevent_req_data(
1809
0
    req, struct g_lock_watch_data_state);
1810
0
  struct tevent_req *subreq = NULL;
1811
0
  struct g_lock lck;
1812
0
  bool ok;
1813
1814
0
  ok = g_lock_parse(value.dptr, value.dsize, &lck);
1815
0
  if (!ok) {
1816
0
    state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
1817
0
    return;
1818
0
  }
1819
0
  state->unique_lock_epoch = lck.unique_lock_epoch;
1820
0
  state->unique_data_epoch = lck.unique_data_epoch;
1821
1822
0
  DBG_DEBUG("state->unique_data_epoch=%"PRIu64"\n", state->unique_data_epoch);
1823
1824
0
  subreq = dbwrap_watched_watch_send(
1825
0
    state, state->ev, rec, 0, state->blocker);
1826
0
  if (subreq == NULL) {
1827
0
    state->status = NT_STATUS_NO_MEMORY;
1828
0
    return;
1829
0
  }
1830
0
  tevent_req_set_callback(subreq, g_lock_watch_data_done, req);
1831
1832
0
  state->status = NT_STATUS_EVENT_PENDING;
1833
0
}
1834
1835
struct tevent_req *g_lock_watch_data_send(
1836
  TALLOC_CTX *mem_ctx,
1837
  struct tevent_context *ev,
1838
  struct g_lock_ctx *ctx,
1839
  TDB_DATA key,
1840
  struct server_id blocker)
1841
0
{
1842
0
  struct tevent_req *req = NULL;
1843
0
  struct g_lock_watch_data_state *state = NULL;
1844
0
  NTSTATUS status;
1845
1846
0
  SMB_ASSERT(!ctx->busy);
1847
1848
0
  req = tevent_req_create(
1849
0
    mem_ctx, &state, struct g_lock_watch_data_state);
1850
0
  if (req == NULL) {
1851
0
    return NULL;
1852
0
  }
1853
0
  state->ev = ev;
1854
0
  state->ctx = ctx;
1855
0
  state->blocker = blocker;
1856
1857
0
  state->key = tdb_data_talloc_copy(state, key);
1858
0
  if (tevent_req_nomem(state->key.dptr, req)) {
1859
0
    return tevent_req_post(req, ev);
1860
0
  }
1861
1862
0
  status = dbwrap_do_locked(
1863
0
    ctx->db, key, g_lock_watch_data_send_fn, req);
1864
0
  if (tevent_req_nterror(req, status)) {
1865
0
    DBG_DEBUG("dbwrap_do_locked returned %s\n", nt_errstr(status));
1866
0
    return tevent_req_post(req, ev);
1867
0
  }
1868
1869
0
  if (NT_STATUS_EQUAL(state->status, NT_STATUS_EVENT_PENDING)) {
1870
0
    return req;
1871
0
  }
1872
0
  if (tevent_req_nterror(req, state->status)) {
1873
0
    return tevent_req_post(req, ev);
1874
0
  }
1875
0
  tevent_req_done(req);
1876
0
  return tevent_req_post(req, ev);
1877
0
}
1878
1879
static void g_lock_watch_data_done_fn(
1880
  struct db_record *rec,
1881
  TDB_DATA value,
1882
  void *private_data)
1883
0
{
1884
0
  struct tevent_req *req = talloc_get_type_abort(
1885
0
    private_data, struct tevent_req);
1886
0
  struct g_lock_watch_data_state *state = tevent_req_data(
1887
0
    req, struct g_lock_watch_data_state);
1888
0
  struct tevent_req *subreq = NULL;
1889
0
  struct g_lock lck;
1890
0
  bool ok;
1891
1892
0
  ok = g_lock_parse(value.dptr, value.dsize, &lck);
1893
0
  if (!ok) {
1894
0
    dbwrap_watched_watch_remove_instance(rec, state->watch_instance);
1895
0
    state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
1896
0
    return;
1897
0
  }
1898
1899
0
  if (lck.unique_data_epoch != state->unique_data_epoch) {
1900
0
    dbwrap_watched_watch_remove_instance(rec, state->watch_instance);
1901
0
    DBG_DEBUG("lck.unique_data_epoch=%"PRIu64", "
1902
0
        "state->unique_data_epoch=%"PRIu64"\n",
1903
0
        lck.unique_data_epoch,
1904
0
        state->unique_data_epoch);
1905
0
    state->status = NT_STATUS_OK;
1906
0
    return;
1907
0
  }
1908
1909
  /*
1910
   * The lock epoch changed, so we better
1911
   * remove ourself from the waiter list
1912
   * (most likely the first position)
1913
   * and re-add us at the end of the list.
1914
   *
1915
   * This gives other lock waiters a change
1916
   * to make progress.
1917
   *
1918
   * Otherwise we'll keep our waiter instance alive,
1919
   * keep waiting (most likely at first position).
1920
   */
1921
0
  if (lck.unique_lock_epoch != state->unique_lock_epoch) {
1922
0
    dbwrap_watched_watch_remove_instance(rec, state->watch_instance);
1923
0
    state->watch_instance = dbwrap_watched_watch_add_instance(rec);
1924
0
    state->unique_lock_epoch = lck.unique_lock_epoch;
1925
0
  }
1926
1927
0
  subreq = dbwrap_watched_watch_send(
1928
0
    state, state->ev, rec, state->watch_instance, state->blocker);
1929
0
  if (subreq == NULL) {
1930
0
    dbwrap_watched_watch_remove_instance(rec, state->watch_instance);
1931
0
    state->status = NT_STATUS_NO_MEMORY;
1932
0
    return;
1933
0
  }
1934
0
  tevent_req_set_callback(subreq, g_lock_watch_data_done, req);
1935
1936
0
  state->status = NT_STATUS_EVENT_PENDING;
1937
0
}
1938
1939
static void g_lock_watch_data_done(struct tevent_req *subreq)
1940
0
{
1941
0
  struct tevent_req *req = tevent_req_callback_data(
1942
0
    subreq, struct tevent_req);
1943
0
  struct g_lock_watch_data_state *state = tevent_req_data(
1944
0
    req, struct g_lock_watch_data_state);
1945
0
  NTSTATUS status;
1946
0
  uint64_t instance = 0;
1947
1948
0
  status = dbwrap_watched_watch_recv(
1949
0
    subreq, &instance, &state->blockerdead, &state->blocker);
1950
0
  TALLOC_FREE(subreq);
1951
0
  if (tevent_req_nterror(req, status)) {
1952
0
    DBG_DEBUG("dbwrap_watched_watch_recv returned %s\n",
1953
0
        nt_errstr(status));
1954
0
    return;
1955
0
  }
1956
1957
0
  state->watch_instance = instance;
1958
1959
0
  status = dbwrap_do_locked(
1960
0
    state->ctx->db, state->key, g_lock_watch_data_done_fn, req);
1961
0
  if (tevent_req_nterror(req, status)) {
1962
0
    DBG_DEBUG("dbwrap_do_locked returned %s\n", nt_errstr(status));
1963
0
    return;
1964
0
  }
1965
0
  if (NT_STATUS_EQUAL(state->status, NT_STATUS_EVENT_PENDING)) {
1966
0
    return;
1967
0
  }
1968
0
  if (tevent_req_nterror(req, state->status)) {
1969
0
    return;
1970
0
  }
1971
0
  tevent_req_done(req);
1972
0
}
1973
1974
NTSTATUS g_lock_watch_data_recv(
1975
  struct tevent_req *req,
1976
  bool *blockerdead,
1977
  struct server_id *blocker)
1978
0
{
1979
0
  struct g_lock_watch_data_state *state = tevent_req_data(
1980
0
    req, struct g_lock_watch_data_state);
1981
0
  NTSTATUS status;
1982
1983
0
  if (tevent_req_is_nterror(req, &status)) {
1984
0
    return status;
1985
0
  }
1986
0
  if (blockerdead != NULL) {
1987
0
    *blockerdead = state->blockerdead;
1988
0
  }
1989
0
  if (blocker != NULL) {
1990
0
    *blocker = state->blocker;
1991
0
  }
1992
1993
0
  return NT_STATUS_OK;
1994
0
}
1995
1996
static void g_lock_wake_watchers_fn(
1997
  struct db_record *rec,
1998
  TDB_DATA value,
1999
  void *private_data)
2000
0
{
2001
0
  struct g_lock lck = { .exclusive.pid = 0 };
2002
0
  int flags = dbwrap_record_get_flags(rec).persistent ?
2003
0
    DBWRAP_STORE_PERSISTENT : 0;
2004
0
  NTSTATUS status;
2005
0
  bool ok;
2006
2007
0
  ok = g_lock_parse(value.dptr, value.dsize, &lck);
2008
0
  if (!ok) {
2009
0
    DBG_WARNING("g_lock_parse failed\n");
2010
0
    return;
2011
0
  }
2012
2013
0
  lck.unique_data_epoch = generate_unique_u64(lck.unique_data_epoch);
2014
2015
0
  status = g_lock_store(rec, &lck, NULL, NULL, 0, flags);
2016
0
  if (!NT_STATUS_IS_OK(status)) {
2017
0
    DBG_WARNING("g_lock_store failed: %s\n", nt_errstr(status));
2018
0
    return;
2019
0
  }
2020
0
}
2021
2022
void g_lock_wake_watchers(struct g_lock_ctx *ctx, TDB_DATA key)
2023
0
{
2024
0
  NTSTATUS status;
2025
2026
0
  SMB_ASSERT(!ctx->busy);
2027
2028
0
  status = dbwrap_do_locked(ctx->db, key, g_lock_wake_watchers_fn, NULL);
2029
0
  if (!NT_STATUS_IS_OK(status)) {
2030
0
    DBG_DEBUG("dbwrap_do_locked returned %s\n",
2031
0
        nt_errstr(status));
2032
0
  }
2033
0
}
2034
2035
NTSTATUS g_lock_wipe(struct g_lock_ctx *ctx, struct dbwrap_wipe_flags flags)
2036
0
{
2037
0
  int ret;
2038
2039
0
  ret = dbwrap_wipe(ctx->db, flags);
2040
0
  if (ret != 0) {
2041
0
    return NT_STATUS_INTERNAL_DB_ERROR;
2042
0
  }
2043
0
  return NT_STATUS_OK;
2044
0
}