Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : generic byte range locking code - tdb backend
5 :
6 : Copyright (C) Andrew Tridgell 1992-2006
7 : Copyright (C) Jeremy Allison 1992-2000
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : /* This module implements a tdb based byte range locking service,
24 : replacing the fcntl() based byte range locking previously
25 : used. This allows us to provide the same semantics as NT */
26 :
27 : #include "includes.h"
28 : #include "system/filesys.h"
29 : #include "messaging/messaging.h"
30 : #include "lib/messaging/irpc.h"
31 : #include "libcli/libcli.h"
32 : #include "cluster/cluster.h"
33 : #include "ntvfs/common/brlock.h"
34 : #include "ntvfs/ntvfs.h"
35 : #include "param/param.h"
36 : #include "dbwrap/dbwrap.h"
37 :
38 : /*
39 : in this module a "DATA_BLOB *file_key" is a blob that uniquely identifies
40 : a file. For a local posix filesystem this will usually be a combination
41 : of the device and inode numbers of the file, but it can be anything
42 : that uniquely identifies a file for locking purposes, as long
43 : as it is applied consistently.
44 : */
45 :
46 : /* this struct is typically attached to tcon */
47 : struct brl_context {
48 : struct db_context *db;
49 : struct server_id server;
50 : struct imessaging_context *imessaging_ctx;
51 : };
52 :
53 : /*
54 : the lock context contains the elements that define whether one
55 : lock is the same as another lock
56 : */
57 : struct lock_context {
58 : struct server_id server;
59 : uint32_t smbpid;
60 : struct brl_context *ctx;
61 : };
62 :
63 : /* The data in brlock records is an unsorted linear array of these
64 : records. It is unnecessary to store the count as tdb provides the
65 : size of the record */
66 : struct lock_struct {
67 : struct lock_context context;
68 : struct ntvfs_handle *ntvfs;
69 : uint64_t start;
70 : uint64_t size;
71 : enum brl_type lock_type;
72 : void *notify_ptr;
73 : };
74 :
75 : /* this struct is attached to on oprn file handle */
76 : struct brl_handle {
77 : DATA_BLOB key;
78 : struct ntvfs_handle *ntvfs;
79 : struct lock_struct last_lock;
80 : };
81 :
82 : /* see if we have wrapped locks, which are no longer allowed (windows
83 : * changed this in win7 */
84 54300 : static bool brl_invalid_lock_range(uint64_t start, uint64_t size)
85 : {
86 54300 : return (size > 1 && (start + size < start));
87 : }
88 :
89 : /*
90 : Open up the brlock.tdb database. Close it down using
91 : talloc_free(). We need the imessaging_ctx to allow for
92 : pending lock notifications.
93 : */
94 1328 : static struct brl_context *brl_tdb_init(TALLOC_CTX *mem_ctx, struct server_id server,
95 : struct loadparm_context *lp_ctx,
96 : struct imessaging_context *imessaging_ctx)
97 : {
98 0 : struct brl_context *brl;
99 :
100 1328 : brl = talloc(mem_ctx, struct brl_context);
101 1328 : if (brl == NULL) {
102 0 : return NULL;
103 : }
104 :
105 1328 : brl->db = cluster_db_tmp_open(brl, lp_ctx, "brlock", TDB_DEFAULT);
106 1328 : if (brl->db == NULL) {
107 0 : talloc_free(brl);
108 0 : return NULL;
109 : }
110 :
111 1328 : brl->server = server;
112 1328 : brl->imessaging_ctx = imessaging_ctx;
113 :
114 1328 : return brl;
115 : }
116 :
117 189155 : static struct brl_handle *brl_tdb_create_handle(TALLOC_CTX *mem_ctx, struct ntvfs_handle *ntvfs,
118 : DATA_BLOB *file_key)
119 : {
120 0 : struct brl_handle *brlh;
121 :
122 189155 : brlh = talloc(mem_ctx, struct brl_handle);
123 189155 : if (brlh == NULL) {
124 0 : return NULL;
125 : }
126 :
127 189155 : brlh->key = *file_key;
128 189155 : brlh->ntvfs = ntvfs;
129 189155 : ZERO_STRUCT(brlh->last_lock);
130 :
131 189155 : return brlh;
132 : }
133 :
134 : /*
135 : see if two locking contexts are equal
136 : */
137 65771 : static bool brl_tdb_same_context(struct lock_context *ctx1, struct lock_context *ctx2)
138 : {
139 65771 : return (cluster_id_equal(&ctx1->server, &ctx2->server) &&
140 164845 : ctx1->smbpid == ctx2->smbpid &&
141 33303 : ctx1->ctx == ctx2->ctx);
142 : }
143 :
144 : /*
145 : see if lck1 and lck2 overlap
146 :
147 : lck1 is the existing lock. lck2 is the new lock we are
148 : looking at adding
149 : */
150 63788 : static bool brl_tdb_overlap(struct lock_struct *lck1,
151 : struct lock_struct *lck2)
152 : {
153 : /* this extra check is not redundant - it copes with locks
154 : that go beyond the end of 64 bit file space */
155 63788 : if (lck1->size != 0 &&
156 63655 : lck1->start == lck2->start &&
157 873 : lck1->size == lck2->size) {
158 845 : return true;
159 : }
160 :
161 62943 : if (lck1->start >= (lck2->start+lck2->size) ||
162 62393 : lck2->start >= (lck1->start+lck1->size)) {
163 62814 : return false;
164 : }
165 :
166 : /* we have a conflict. Now check to see if lck1 really still
167 : * exists, which involves checking if the process still
168 : * exists. We leave this test to last as its the most
169 : * expensive test, especially when we are clustered */
170 : /* TODO: need to do this via a server_id_exists() call, which
171 : * hasn't been written yet. When clustered this will need to
172 : * call into ctdb */
173 :
174 129 : return true;
175 : }
176 :
177 : /*
178 : See if lock2 can be added when lock1 is in place.
179 : */
180 64470 : static bool brl_tdb_conflict(struct lock_struct *lck1,
181 : struct lock_struct *lck2)
182 : {
183 : /* pending locks don't conflict with anything */
184 64470 : if (lck1->lock_type >= PENDING_READ_LOCK ||
185 64380 : lck2->lock_type >= PENDING_READ_LOCK) {
186 461 : return false;
187 : }
188 :
189 64009 : if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
190 584 : return false;
191 : }
192 :
193 63425 : if (brl_tdb_same_context(&lck1->context, &lck2->context) &&
194 31979 : lck2->lock_type == READ_LOCK && lck1->ntvfs == lck2->ntvfs) {
195 134 : return false;
196 : }
197 :
198 63291 : return brl_tdb_overlap(lck1, lck2);
199 : }
200 :
201 :
202 : /*
203 : Check to see if this lock conflicts, but ignore our own locks on the
204 : same fnum only.
205 : */
206 730 : static bool brl_tdb_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2)
207 : {
208 : /* pending locks don't conflict with anything */
209 730 : if (lck1->lock_type >= PENDING_READ_LOCK ||
210 730 : lck2->lock_type >= PENDING_READ_LOCK) {
211 0 : return false;
212 : }
213 :
214 730 : if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK)
215 213 : return false;
216 :
217 : /*
218 : * note that incoming write calls conflict with existing READ
219 : * locks even if the context is the same. JRA. See LOCKTEST7
220 : * in smbtorture.
221 : */
222 517 : if (brl_tdb_same_context(&lck1->context, &lck2->context) &&
223 101 : lck1->ntvfs == lck2->ntvfs &&
224 90 : (lck2->lock_type == READ_LOCK || lck1->lock_type == WRITE_LOCK)) {
225 52 : return false;
226 : }
227 :
228 465 : return brl_tdb_overlap(lck1, lck2);
229 : }
230 :
231 :
232 : /*
233 : amazingly enough, w2k3 "remembers" whether the last lock failure
234 : is the same as this one and changes its error code. I wonder if any
235 : app depends on this?
236 : */
237 910 : static NTSTATUS brl_tdb_lock_failed(struct brl_handle *brlh, struct lock_struct *lock)
238 : {
239 : /*
240 : * this function is only called for non pending lock!
241 : */
242 :
243 : /* in SMB2 mode always return NT_STATUS_LOCK_NOT_GRANTED! */
244 910 : if (lock->ntvfs->ctx->protocol >= PROTOCOL_SMB2_02) {
245 95 : return NT_STATUS_LOCK_NOT_GRANTED;
246 : }
247 :
248 : /*
249 : * if the notify_ptr is non NULL,
250 : * it means that we're at the end of a pending lock
251 : * and the real lock is requested after the timeout went by
252 : * In this case we need to remember the last_lock and always
253 : * give FILE_LOCK_CONFLICT
254 : */
255 815 : if (lock->notify_ptr) {
256 61 : brlh->last_lock = *lock;
257 61 : return NT_STATUS_FILE_LOCK_CONFLICT;
258 : }
259 :
260 : /*
261 : * amazing the little things you learn with a test
262 : * suite. Locks beyond this offset (as a 64 bit
263 : * number!) always generate the conflict error code,
264 : * unless the top bit is set
265 : */
266 754 : if (lock->start >= 0xEF000000 && (lock->start >> 63) == 0) {
267 39 : brlh->last_lock = *lock;
268 39 : return NT_STATUS_FILE_LOCK_CONFLICT;
269 : }
270 :
271 : /*
272 : * if the current lock matches the last failed lock on the file handle
273 : * and starts at the same offset, then FILE_LOCK_CONFLICT should be returned
274 : */
275 715 : if (cluster_id_equal(&lock->context.server, &brlh->last_lock.context.server) &&
276 593 : lock->context.ctx == brlh->last_lock.context.ctx &&
277 593 : lock->ntvfs == brlh->last_lock.ntvfs &&
278 593 : lock->start == brlh->last_lock.start) {
279 99 : return NT_STATUS_FILE_LOCK_CONFLICT;
280 : }
281 :
282 616 : brlh->last_lock = *lock;
283 616 : return NT_STATUS_LOCK_NOT_GRANTED;
284 : }
285 :
286 : /*
287 : Lock a range of bytes. The lock_type can be a PENDING_*_LOCK, in
288 : which case a real lock is first tried, and if that fails then a
289 : pending lock is created. When the pending lock is triggered (by
290 : someone else closing an overlapping lock range) a messaging
291 : notification is sent, identified by the notify_ptr
292 : */
293 2000 : static NTSTATUS brl_tdb_lock(struct brl_context *brl,
294 : struct brl_handle *brlh,
295 : uint32_t smbpid,
296 : uint64_t start, uint64_t size,
297 : enum brl_type lock_type,
298 : void *notify_ptr)
299 : {
300 0 : TDB_DATA kbuf, dbuf;
301 2000 : int count=0, i;
302 2000 : struct lock_struct lock, *locks=NULL;
303 0 : NTSTATUS status;
304 0 : struct db_record *locked;
305 :
306 2000 : kbuf.dptr = brlh->key.data;
307 2000 : kbuf.dsize = brlh->key.length;
308 :
309 2000 : if (brl_invalid_lock_range(start, size)) {
310 4 : return NT_STATUS_INVALID_LOCK_RANGE;
311 : }
312 :
313 1996 : locked = dbwrap_fetch_locked(brl->db, brl, kbuf);
314 1996 : if (!locked) {
315 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
316 : }
317 :
318 : /* if this is a pending lock, then with the chainlock held we
319 : try to get the real lock. If we succeed then we don't need
320 : to make it pending. This prevents a possible race condition
321 : where the pending lock gets created after the lock that is
322 : preventing the real lock gets removed */
323 1996 : if (lock_type >= PENDING_READ_LOCK) {
324 234 : enum brl_type rw = (lock_type==PENDING_READ_LOCK? READ_LOCK : WRITE_LOCK);
325 :
326 : /* here we need to force that the last_lock isn't overwritten */
327 234 : lock = brlh->last_lock;
328 234 : status = brl_tdb_lock(brl, brlh, smbpid, start, size, rw, NULL);
329 234 : brlh->last_lock = lock;
330 :
331 234 : if (NT_STATUS_IS_OK(status)) {
332 123 : talloc_free(locked);
333 123 : return NT_STATUS_OK;
334 : }
335 : }
336 :
337 1873 : dbuf = dbwrap_record_get_value(locked);
338 :
339 1873 : lock.context.smbpid = smbpid;
340 1873 : lock.context.server = brl->server;
341 1873 : lock.context.ctx = brl;
342 1873 : lock.ntvfs = brlh->ntvfs;
343 1873 : lock.context.ctx = brl;
344 1873 : lock.start = start;
345 1873 : lock.size = size;
346 1873 : lock.lock_type = lock_type;
347 1873 : lock.notify_ptr = notify_ptr;
348 :
349 1873 : if (dbuf.dptr) {
350 : /* there are existing locks - make sure they don't conflict */
351 1574 : locks = (struct lock_struct *)dbuf.dptr;
352 1574 : count = dbuf.dsize / sizeof(*locks);
353 65134 : for (i=0; i<count; i++) {
354 64470 : if (brl_tdb_conflict(&locks[i], &lock)) {
355 910 : status = brl_tdb_lock_failed(brlh, &lock);
356 910 : goto fail;
357 : }
358 : }
359 : }
360 :
361 : /* no conflicts - add it to the list of locks */
362 : /* FIXME: a dbwrap_record_append() would help here! */
363 963 : locks = talloc_array(locked, struct lock_struct, count+1);
364 963 : if (!locks) {
365 0 : status = NT_STATUS_NO_MEMORY;
366 0 : goto fail;
367 : }
368 963 : if (dbuf.dsize > 0) {
369 664 : memcpy(locks, dbuf.dptr, dbuf.dsize);
370 : }
371 963 : locks[count] = lock;
372 :
373 963 : dbuf.dptr = (unsigned char *)locks;
374 963 : dbuf.dsize += sizeof(lock);
375 :
376 963 : status = dbwrap_record_store(locked, dbuf, TDB_REPLACE);
377 963 : if (!NT_STATUS_IS_OK(status)) {
378 0 : goto fail;
379 : }
380 :
381 963 : talloc_free(locked);
382 :
383 : /* the caller needs to know if the real lock was granted. If
384 : we have reached here then it must be a pending lock that
385 : was granted, so tell them the lock failed */
386 963 : if (lock_type >= PENDING_READ_LOCK) {
387 111 : return NT_STATUS_LOCK_NOT_GRANTED;
388 : }
389 :
390 852 : return NT_STATUS_OK;
391 :
392 910 : fail:
393 910 : talloc_free(locked);
394 910 : return status;
395 : }
396 :
397 :
398 : /*
399 : we are removing a lock that might be holding up a pending lock. Scan for pending
400 : locks that cover this range and if we find any then notify the server that it should
401 : retry the lock
402 : */
403 384 : static void brl_tdb_notify_unlock(struct brl_context *brl,
404 : struct lock_struct *locks, int count,
405 : struct lock_struct *removed_lock)
406 : {
407 0 : int i, last_notice;
408 :
409 : /* the last_notice logic is to prevent stampeding on a lock
410 : range. It prevents us sending hundreds of notifies on the
411 : same range of bytes. It doesn't prevent all possible
412 : stampedes, but it does prevent the most common problem */
413 384 : last_notice = -1;
414 :
415 21455 : for (i=0;i<count;i++) {
416 21100 : if (locks[i].lock_type >= PENDING_READ_LOCK &&
417 29 : brl_tdb_overlap(&locks[i], removed_lock)) {
418 22 : if (last_notice != -1 && brl_tdb_overlap(&locks[i], &locks[last_notice])) {
419 3 : continue;
420 : }
421 19 : if (locks[i].lock_type == PENDING_WRITE_LOCK) {
422 15 : last_notice = i;
423 : }
424 19 : imessaging_send_ptr(brl->imessaging_ctx, locks[i].context.server,
425 19 : MSG_BRL_RETRY, locks[i].notify_ptr);
426 : }
427 : }
428 384 : }
429 :
430 :
431 : /*
432 : send notifications for all pending locks - the file is being closed by this
433 : user
434 : */
435 55 : static void brl_tdb_notify_all(struct brl_context *brl,
436 : struct lock_struct *locks, int count)
437 : {
438 0 : int i;
439 155 : for (i=0;i<count;i++) {
440 100 : if (locks->lock_type >= PENDING_READ_LOCK) {
441 1 : brl_tdb_notify_unlock(brl, locks, count, &locks[i]);
442 : }
443 : }
444 55 : }
445 :
446 :
447 :
448 : /*
449 : Unlock a range of bytes.
450 : */
451 684 : static NTSTATUS brl_tdb_unlock(struct brl_context *brl,
452 : struct brl_handle *brlh,
453 : uint32_t smbpid,
454 : uint64_t start, uint64_t size)
455 : {
456 0 : TDB_DATA kbuf, dbuf;
457 0 : int count, i;
458 684 : struct lock_struct *locks, *lock = NULL;
459 0 : struct lock_context context;
460 0 : struct db_record *locked;
461 0 : NTSTATUS status;
462 :
463 684 : kbuf.dptr = brlh->key.data;
464 684 : kbuf.dsize = brlh->key.length;
465 :
466 684 : if (brl_invalid_lock_range(start, size)) {
467 0 : return NT_STATUS_INVALID_LOCK_RANGE;
468 : }
469 :
470 684 : locked = dbwrap_fetch_locked(brl->db, brl, kbuf);
471 684 : if (!locked) {
472 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
473 : }
474 684 : dbuf = dbwrap_record_get_value(locked);
475 :
476 684 : context.smbpid = smbpid;
477 684 : context.server = brl->server;
478 684 : context.ctx = brl;
479 :
480 : /* there are existing locks - find a match */
481 684 : locks = (struct lock_struct *)dbuf.dptr;
482 684 : count = dbuf.dsize / sizeof(*locks);
483 :
484 1469 : for (i=0; i<count; i++) {
485 1317 : lock = &locks[i];
486 1317 : if (brl_tdb_same_context(&lock->context, &context) &&
487 957 : lock->ntvfs == brlh->ntvfs &&
488 912 : lock->start == start &&
489 601 : lock->size == size &&
490 593 : lock->lock_type == WRITE_LOCK) {
491 532 : break;
492 : }
493 : }
494 684 : if (i < count) goto found;
495 :
496 614 : for (i=0; i<count; i++) {
497 512 : lock = &locks[i];
498 512 : if (brl_tdb_same_context(&lock->context, &context) &&
499 266 : lock->ntvfs == brlh->ntvfs &&
500 241 : lock->start == start &&
501 55 : lock->size == size &&
502 51 : lock->lock_type < PENDING_READ_LOCK) {
503 50 : break;
504 : }
505 : }
506 :
507 102 : found:
508 684 : if (i < count) {
509 : /* found it - delete it */
510 582 : if (count == 1) {
511 199 : status = dbwrap_record_delete(locked);
512 199 : if (!NT_STATUS_IS_OK(status)) {
513 0 : goto fail;
514 : }
515 : } else {
516 383 : struct lock_struct removed_lock = *lock;
517 383 : if (i < count-1) {
518 307 : memmove(&locks[i], &locks[i+1],
519 307 : sizeof(*locks)*((count-1) - i));
520 : }
521 383 : count--;
522 :
523 : /* send notifications for any relevant pending locks */
524 383 : brl_tdb_notify_unlock(brl, locks, count, &removed_lock);
525 :
526 383 : dbuf.dsize = count * sizeof(*locks);
527 :
528 383 : status = dbwrap_record_store(locked, dbuf, TDB_REPLACE);
529 383 : if (!NT_STATUS_IS_OK(status)) {
530 0 : goto fail;
531 : }
532 : }
533 :
534 582 : talloc_free(locked);
535 582 : return NT_STATUS_OK;
536 : }
537 :
538 : /* we didn't find it */
539 102 : status = NT_STATUS_RANGE_NOT_LOCKED;
540 :
541 102 : fail:
542 102 : talloc_free(locked);
543 102 : return status;
544 : }
545 :
546 :
547 : /*
548 : remove a pending lock. This is called when the caller has either
549 : given up trying to establish a lock or when they have succeeded in
550 : getting it. In either case they no longer need to be notified.
551 : */
552 82 : static NTSTATUS brl_tdb_remove_pending(struct brl_context *brl,
553 : struct brl_handle *brlh,
554 : void *notify_ptr)
555 : {
556 0 : TDB_DATA kbuf, dbuf;
557 0 : int count, i;
558 0 : struct lock_struct *locks;
559 0 : NTSTATUS status;
560 0 : struct db_record *locked;
561 :
562 82 : kbuf.dptr = brlh->key.data;
563 82 : kbuf.dsize = brlh->key.length;
564 :
565 82 : locked = dbwrap_fetch_locked(brl->db, brl, kbuf);
566 82 : if (!locked) {
567 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
568 : }
569 :
570 82 : dbuf = dbwrap_record_get_value(locked);
571 82 : if (!dbuf.dptr) {
572 0 : talloc_free(locked);
573 0 : return NT_STATUS_RANGE_NOT_LOCKED;
574 : }
575 :
576 : /* there are existing locks - find a match */
577 82 : locks = (struct lock_struct *)dbuf.dptr;
578 82 : count = dbuf.dsize / sizeof(*locks);
579 :
580 390 : for (i=0; i<count; i++) {
581 390 : struct lock_struct *lock = &locks[i];
582 :
583 390 : if (lock->lock_type >= PENDING_READ_LOCK &&
584 82 : lock->notify_ptr == notify_ptr &&
585 82 : cluster_id_equal(&lock->context.server, &brl->server)) {
586 : /* found it - delete it */
587 82 : if (count == 1) {
588 0 : status = dbwrap_record_delete(locked);
589 0 : if (!NT_STATUS_IS_OK(status)) {
590 0 : goto fail;
591 : }
592 : } else {
593 82 : if (i < count-1) {
594 21 : memmove(&locks[i], &locks[i+1],
595 21 : sizeof(*locks)*((count-1) - i));
596 : }
597 82 : count--;
598 82 : dbuf.dsize = count * sizeof(*locks);
599 82 : status = dbwrap_record_store(locked, dbuf,
600 : TDB_REPLACE);
601 82 : if (!NT_STATUS_IS_OK(status)) {
602 0 : goto fail;
603 : }
604 : }
605 :
606 82 : talloc_free(locked);
607 82 : return NT_STATUS_OK;
608 : }
609 : }
610 :
611 : /* we didn't find it */
612 0 : status = NT_STATUS_RANGE_NOT_LOCKED;
613 :
614 0 : fail:
615 0 : talloc_free(locked);
616 0 : return status;
617 : }
618 :
619 :
620 : /*
621 : Test if we are allowed to perform IO on a region of an open file
622 : */
623 51616 : static NTSTATUS brl_tdb_locktest(struct brl_context *brl,
624 : struct brl_handle *brlh,
625 : uint32_t smbpid,
626 : uint64_t start, uint64_t size,
627 : enum brl_type lock_type)
628 : {
629 0 : TDB_DATA kbuf, dbuf;
630 0 : int count, i;
631 0 : struct lock_struct lock, *locks;
632 0 : NTSTATUS status;
633 :
634 51616 : kbuf.dptr = brlh->key.data;
635 51616 : kbuf.dsize = brlh->key.length;
636 :
637 51616 : if (brl_invalid_lock_range(start, size)) {
638 2 : return NT_STATUS_INVALID_LOCK_RANGE;
639 : }
640 :
641 51614 : status = dbwrap_fetch(brl->db, brl, kbuf, &dbuf);
642 51614 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
643 51507 : return NT_STATUS_OK;
644 107 : } else if (!NT_STATUS_IS_OK(status)) {
645 0 : return status;
646 : }
647 :
648 107 : lock.context.smbpid = smbpid;
649 107 : lock.context.server = brl->server;
650 107 : lock.context.ctx = brl;
651 107 : lock.ntvfs = brlh->ntvfs;
652 107 : lock.start = start;
653 107 : lock.size = size;
654 107 : lock.lock_type = lock_type;
655 :
656 : /* there are existing locks - make sure they don't conflict */
657 107 : locks = (struct lock_struct *)dbuf.dptr;
658 107 : count = dbuf.dsize / sizeof(*locks);
659 :
660 798 : for (i=0; i<count; i++) {
661 730 : if (brl_tdb_conflict_other(&locks[i], &lock)) {
662 39 : talloc_free(dbuf.dptr);
663 39 : return NT_STATUS_FILE_LOCK_CONFLICT;
664 : }
665 : }
666 :
667 68 : talloc_free(dbuf.dptr);
668 68 : return NT_STATUS_OK;
669 : }
670 :
671 :
672 : /*
673 : Remove any locks associated with a open file.
674 : */
675 155 : static NTSTATUS brl_tdb_close(struct brl_context *brl,
676 : struct brl_handle *brlh)
677 : {
678 0 : TDB_DATA kbuf, dbuf;
679 155 : int count, i, dcount=0;
680 0 : struct lock_struct *locks;
681 0 : struct db_record *locked;
682 0 : NTSTATUS status;
683 :
684 155 : kbuf.dptr = brlh->key.data;
685 155 : kbuf.dsize = brlh->key.length;
686 :
687 155 : locked = dbwrap_fetch_locked(brl->db, brl, kbuf);
688 155 : if (!locked) {
689 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
690 : }
691 155 : dbuf = dbwrap_record_get_value(locked);
692 155 : if (!dbuf.dptr) {
693 0 : talloc_free(locked);
694 0 : return NT_STATUS_OK;
695 : }
696 :
697 : /* there are existing locks - remove any for this fnum */
698 155 : locks = (struct lock_struct *)dbuf.dptr;
699 155 : count = dbuf.dsize / sizeof(*locks);
700 :
701 554 : for (i=0; i<count; i++) {
702 399 : struct lock_struct *lock = &locks[i];
703 :
704 399 : if (lock->context.ctx == brl &&
705 354 : cluster_id_equal(&lock->context.server, &brl->server) &&
706 354 : lock->ntvfs == brlh->ntvfs) {
707 : /* found it - delete it */
708 299 : if (count > 1 && i < count-1) {
709 174 : memmove(&locks[i], &locks[i+1],
710 174 : sizeof(*locks)*((count-1) - i));
711 : }
712 299 : count--;
713 299 : i--;
714 299 : dcount++;
715 : }
716 : }
717 :
718 155 : status = NT_STATUS_OK;
719 :
720 155 : if (count == 0) {
721 100 : status = dbwrap_record_delete(locked);
722 55 : } else if (dcount != 0) {
723 : /* tell all pending lock holders for this file that
724 : they have a chance now. This is a bit indiscriminant,
725 : but works OK */
726 55 : brl_tdb_notify_all(brl, locks, count);
727 :
728 55 : dbuf.dsize = count * sizeof(*locks);
729 :
730 55 : status = dbwrap_record_store(locked, dbuf, TDB_REPLACE);
731 : }
732 155 : talloc_free(locked);
733 :
734 155 : return status;
735 : }
736 :
737 89170 : static NTSTATUS brl_tdb_count(struct brl_context *brl, struct brl_handle *brlh,
738 : int *count)
739 : {
740 0 : TDB_DATA kbuf, dbuf;
741 0 : NTSTATUS status;
742 :
743 89170 : kbuf.dptr = brlh->key.data;
744 89170 : kbuf.dsize = brlh->key.length;
745 89170 : *count = 0;
746 :
747 89170 : status = dbwrap_fetch(brl->db, brl, kbuf, &dbuf);
748 89170 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
749 89081 : return NT_STATUS_OK;
750 89 : } else if (!NT_STATUS_IS_OK(status)) {
751 0 : return status;
752 : }
753 89 : *count = dbuf.dsize / sizeof(struct lock_struct);
754 :
755 89 : talloc_free(dbuf.dptr);
756 :
757 89 : return NT_STATUS_OK;
758 : }
759 :
760 : static const struct brlock_ops brlock_tdb_ops = {
761 : .brl_init = brl_tdb_init,
762 : .brl_create_handle = brl_tdb_create_handle,
763 : .brl_lock = brl_tdb_lock,
764 : .brl_unlock = brl_tdb_unlock,
765 : .brl_remove_pending = brl_tdb_remove_pending,
766 : .brl_locktest = brl_tdb_locktest,
767 : .brl_close = brl_tdb_close,
768 : .brl_count = brl_tdb_count
769 : };
770 :
771 :
772 4 : void brl_tdb_init_ops(void)
773 : {
774 4 : brlock_set_ops(&brlock_tdb_ops);
775 4 : }
|