LCOV - code coverage report
Current view: top level - source4/ntvfs/common - brlock_tdb.c (source / functions) Hit Total Coverage
Test: coverage report for vadcx-master-patch-75612 fe003de8 Lines: 275 331 83.1 %
Date: 2024-02-29 22:57:05 Functions: 17 17 100.0 %

          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       54451 : static bool brl_invalid_lock_range(uint64_t start, uint64_t size)
      85             : {
      86       54451 :         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      189157 : 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      189157 :         brlh = talloc(mem_ctx, struct brl_handle);
     123      189157 :         if (brlh == NULL) {
     124           0 :                 return NULL;
     125             :         }
     126             : 
     127      189157 :         brlh->key = *file_key;
     128      189157 :         brlh->ntvfs = ntvfs;
     129      189157 :         ZERO_STRUCT(brlh->last_lock);
     130             : 
     131      189157 :         return brlh;
     132             : }
     133             : 
     134             : /*
     135             :   see if two locking contexts are equal
     136             : */
     137       65757 : static bool brl_tdb_same_context(struct lock_context *ctx1, struct lock_context *ctx2)
     138             : {
     139       65757 :         return (cluster_id_equal(&ctx1->server, &ctx2->server) &&
     140      164819 :                 ctx1->smbpid == ctx2->smbpid &&
     141       33305 :                 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       63776 : 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       63776 :         if (lck1->size != 0 &&
     156       63643 :             lck1->start == lck2->start &&
     157         871 :             lck1->size == lck2->size) {
     158         845 :                 return true;
     159             :         }
     160             :             
     161       62931 :         if (lck1->start >= (lck2->start+lck2->size) ||
     162       62379 :             lck2->start >= (lck1->start+lck1->size)) {
     163       62802 :                 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       64444 : static bool brl_tdb_conflict(struct lock_struct *lck1, 
     181             :                          struct lock_struct *lck2)
     182             : {
     183             :         /* pending locks don't conflict with anything */
     184       64444 :         if (lck1->lock_type >= PENDING_READ_LOCK ||
     185       64354 :             lck2->lock_type >= PENDING_READ_LOCK) {
     186         461 :                 return false;
     187             :         }
     188             : 
     189       63983 :         if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
     190         572 :                 return false;
     191             :         }
     192             : 
     193       63411 :         if (brl_tdb_same_context(&lck1->context, &lck2->context) &&
     194       31981 :             lck2->lock_type == READ_LOCK && lck1->ntvfs == lck2->ntvfs) {
     195         132 :                 return false;
     196             :         }
     197             : 
     198       63279 :         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         601 :             lock->context.ctx == brlh->last_lock.context.ctx &&
     277         601 :             lock->ntvfs == brlh->last_lock.ntvfs &&
     278         601 :             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        1992 : 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        1992 :         int count=0, i;
     302        1992 :         struct lock_struct lock, *locks=NULL;
     303           0 :         NTSTATUS status;
     304           0 :         struct db_record *locked;
     305             : 
     306        1992 :         kbuf.dptr = brlh->key.data;
     307        1992 :         kbuf.dsize = brlh->key.length;
     308             : 
     309        1992 :         if (brl_invalid_lock_range(start, size)) {
     310           4 :                 return NT_STATUS_INVALID_LOCK_RANGE;
     311             :         }
     312             : 
     313        1988 :         locked = dbwrap_fetch_locked(brl->db, brl, kbuf);
     314        1988 :         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        1988 :         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        1865 :         dbuf = dbwrap_record_get_value(locked);
     338             : 
     339        1865 :         lock.context.smbpid = smbpid;
     340        1865 :         lock.context.server = brl->server;
     341        1865 :         lock.context.ctx = brl;
     342        1865 :         lock.ntvfs = brlh->ntvfs;
     343        1865 :         lock.context.ctx = brl;
     344        1865 :         lock.start = start;
     345        1865 :         lock.size = size;
     346        1865 :         lock.lock_type = lock_type;
     347        1865 :         lock.notify_ptr = notify_ptr;
     348             : 
     349        1865 :         if (dbuf.dptr) {
     350             :                 /* there are existing locks - make sure they don't conflict */
     351        1566 :                 locks = (struct lock_struct *)dbuf.dptr;
     352        1566 :                 count = dbuf.dsize / sizeof(*locks);
     353       65100 :                 for (i=0; i<count; i++) {
     354       64444 :                         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         955 :         locks = talloc_array(locked, struct lock_struct, count+1);
     364         955 :         if (!locks) {
     365           0 :                 status = NT_STATUS_NO_MEMORY;
     366           0 :                 goto fail;
     367             :         }
     368         955 :         if (dbuf.dsize > 0) {
     369         656 :                 memcpy(locks, dbuf.dptr, dbuf.dsize);
     370             :         }
     371         955 :         locks[count] = lock;
     372             : 
     373         955 :         dbuf.dptr = (unsigned char *)locks;
     374         955 :         dbuf.dsize += sizeof(lock);
     375             : 
     376         955 :         status = dbwrap_record_store(locked, dbuf, TDB_REPLACE);
     377         955 :         if (!NT_STATUS_IS_OK(status)) {
     378           0 :                 goto fail;
     379             :         }
     380             : 
     381         955 :         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         955 :         if (lock_type >= PENDING_READ_LOCK) {
     387         111 :                 return NT_STATUS_LOCK_NOT_GRANTED;
     388             :         }
     389             : 
     390         844 :         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          47 : static void brl_tdb_notify_all(struct brl_context *brl,
     436             :                            struct lock_struct *locks, int count)
     437             : {
     438           0 :         int i;
     439         125 :         for (i=0;i<count;i++) {
     440          78 :                 if (locks->lock_type >= PENDING_READ_LOCK) {
     441           1 :                         brl_tdb_notify_unlock(brl, locks, count, &locks[i]);
     442             :                 }
     443             :         }
     444          47 : }
     445             : 
     446             : 
     447             : 
     448             : /*
     449             :  Unlock a range of bytes.
     450             : */
     451         690 : 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         690 :         struct lock_struct *locks, *lock = NULL;
     459           0 :         struct lock_context context;
     460           0 :         struct db_record *locked;
     461           0 :         NTSTATUS status;
     462             : 
     463         690 :         kbuf.dptr = brlh->key.data;
     464         690 :         kbuf.dsize = brlh->key.length;
     465             : 
     466         690 :         if (brl_invalid_lock_range(start, size)) {
     467           0 :                 return NT_STATUS_INVALID_LOCK_RANGE;
     468             :         }
     469             : 
     470         690 :         locked = dbwrap_fetch_locked(brl->db, brl, kbuf);
     471         690 :         if (!locked) {
     472           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     473             :         }
     474         690 :         dbuf = dbwrap_record_get_value(locked);
     475             : 
     476         690 :         context.smbpid = smbpid;
     477         690 :         context.server = brl->server;
     478         690 :         context.ctx = brl;
     479             : 
     480             :         /* there are existing locks - find a match */
     481         690 :         locks = (struct lock_struct *)dbuf.dptr;
     482         690 :         count = dbuf.dsize / sizeof(*locks);
     483             : 
     484        1475 :         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         690 :         if (i < count) goto found;
     495             : 
     496         620 :         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         108 : found:
     508         690 :         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         108 :         status = NT_STATUS_RANGE_NOT_LOCKED;
     540             : 
     541         108 :  fail:
     542         108 :         talloc_free(locked);
     543         108 :         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       51769 : 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       51769 :         kbuf.dptr = brlh->key.data;
     635       51769 :         kbuf.dsize = brlh->key.length;
     636             : 
     637       51769 :         if (brl_invalid_lock_range(start, size)) {
     638           2 :                 return NT_STATUS_INVALID_LOCK_RANGE;
     639             :         }
     640             : 
     641       51767 :         status = dbwrap_fetch(brl->db, brl, kbuf, &dbuf);
     642       51767 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     643       51660 :                 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         147 : static NTSTATUS brl_tdb_close(struct brl_context *brl,
     676             :                           struct brl_handle *brlh)
     677             : {
     678           0 :         TDB_DATA kbuf, dbuf;
     679         147 :         int count, i, dcount=0;
     680           0 :         struct lock_struct *locks;
     681           0 :         struct db_record *locked;
     682           0 :         NTSTATUS status;
     683             : 
     684         147 :         kbuf.dptr = brlh->key.data;
     685         147 :         kbuf.dsize = brlh->key.length;
     686             : 
     687         147 :         locked = dbwrap_fetch_locked(brl->db, brl, kbuf);
     688         147 :         if (!locked) {
     689           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     690             :         }
     691         147 :         dbuf = dbwrap_record_get_value(locked);
     692         147 :         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         147 :         locks = (struct lock_struct *)dbuf.dptr;
     699         147 :         count = dbuf.dsize / sizeof(*locks);
     700             : 
     701         516 :         for (i=0; i<count; i++) {
     702         369 :                 struct lock_struct *lock = &locks[i];
     703             : 
     704         369 :                 if (lock->context.ctx == brl &&
     705         340 :                     cluster_id_equal(&lock->context.server, &brl->server) &&
     706         340 :                     lock->ntvfs == brlh->ntvfs) {
     707             :                         /* found it - delete it */
     708         291 :                         if (count > 1 && i < count-1) {
     709         172 :                                 memmove(&locks[i], &locks[i+1], 
     710         172 :                                         sizeof(*locks)*((count-1) - i));
     711             :                         }
     712         291 :                         count--;
     713         291 :                         i--;
     714         291 :                         dcount++;
     715             :                 }
     716             :         }
     717             : 
     718         147 :         status = NT_STATUS_OK;
     719             : 
     720         147 :         if (count == 0) {
     721         100 :                 status = dbwrap_record_delete(locked);
     722          47 :         } 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          47 :                 brl_tdb_notify_all(brl, locks, count);
     727             : 
     728          47 :                 dbuf.dsize = count * sizeof(*locks);
     729             : 
     730          47 :                 status = dbwrap_record_store(locked, dbuf, TDB_REPLACE);
     731             :         }
     732         147 :         talloc_free(locked);
     733             : 
     734         147 :         return status;
     735             : }
     736             : 
     737       89176 : 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       89176 :         kbuf.dptr = brlh->key.data;
     744       89176 :         kbuf.dsize = brlh->key.length;
     745       89176 :         *count = 0;
     746             : 
     747       89176 :         status = dbwrap_fetch(brl->db, brl, kbuf, &dbuf);
     748       89176 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     749       89091 :                 return NT_STATUS_OK;
     750          85 :         } else if (!NT_STATUS_IS_OK(status)) {
     751           0 :                 return status;
     752             :         }
     753          85 :         *count = dbuf.dsize / sizeof(struct lock_struct);
     754             : 
     755          85 :         talloc_free(dbuf.dptr);
     756             : 
     757          85 :         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 : }

Generated by: LCOV version 1.14