summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/include/proto.h5
-rw-r--r--source3/include/smb.h12
-rw-r--r--source3/locking/brlock.c359
-rw-r--r--source3/locking/locking.c171
4 files changed, 469 insertions, 78 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index db50e12ab6..79ebe331ad 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -816,6 +816,8 @@ BOOL brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
uint16 smbpid, pid_t pid, uint16 tid,
br_off start, br_off size,
enum brl_type lock_type);
+struct unlock_list *brl_unlock_list(TALLOC_CTX *ctx, struct unlock_list *ulhead,
+ pid_t pid, SMB_DEV_T dev, SMB_INO_T ino);
BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
uint16 smbpid, pid_t pid, uint16 tid,
br_off start, br_off size);
@@ -824,11 +826,11 @@ BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino,
br_off start, br_off size,
enum brl_type lock_type);
void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum);
+struct unlock_list *brl_getlocklist( TALLOC_CTX *ctx, SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum);
int brl_forall(BRLOCK_FN(fn));
/*The following definitions come from locking/locking.c */
-void locking_close_file(files_struct *fsp);
BOOL is_locked(files_struct *fsp,connection_struct *conn,
SMB_BIG_UINT count,SMB_BIG_UINT offset,
enum brl_type lock_type);
@@ -838,6 +840,7 @@ BOOL do_lock(files_struct *fsp,connection_struct *conn,
BOOL do_unlock(files_struct *fsp,connection_struct *conn,
SMB_BIG_UINT count,SMB_BIG_UINT offset,
int *eclass,uint32 *ecode);
+void locking_close_file(files_struct *fsp);
BOOL locking_init(int read_only);
BOOL locking_end(void);
BOOL lock_share_entry(connection_struct *conn,
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 5147a567b4..1559143418 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -519,6 +519,18 @@ struct uid_cache {
uid_t list[UID_CACHE_SIZE];
};
+/*
+ * Structure used when splitting a lock range
+ * into a POSIX lock range. Doubly linked list.
+ */
+
+struct unlock_list {
+ struct unlock_list *next;
+ struct unlock_list *prev;
+ SMB_BIG_UINT start;
+ SMB_BIG_UINT size;
+};
+
typedef struct
{
char *name;
diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
index 71fc45854a..68daa7e0bb 100644
--- a/source3/locking/brlock.c
+++ b/source3/locking/brlock.c
@@ -2,7 +2,10 @@
Unix SMB/Netbios implementation.
Version 3.0
byte range locking code
- Copyright (C) Andrew Tridgell 1992-1998
+ Updated to handle range splits/merges.
+
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Jeremy Allison 1992-2000
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +22,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* this module implements a tdb based byte range locking service,
+/* This module implements a tdb based byte range locking service,
replacing the fcntl() based byte range locking previously
used. This allows us to provide the same semantics as NT */
@@ -27,18 +30,20 @@
extern int DEBUGLEVEL;
-/* this contains elements that differentiate locks. The smbpid is a
+/* This contains elements that differentiate locks. The smbpid is a
client supplied pid, and is essentially the locking context for
this client */
+
struct lock_context {
uint16 smbpid;
uint16 tid;
pid_t pid;
};
-/* the data in brlock records is an unsorted linear array of these
+/* The data in brlock records is an unsorted linear array of these
records. It is unnecessary to store the count as tdb provides the
size of the record */
+
struct lock_struct {
struct lock_context context;
br_off start;
@@ -47,19 +52,21 @@ struct lock_struct {
enum brl_type lock_type;
};
-/* the key used in the brlock database */
+/* The key used in the brlock database. */
+
struct lock_key {
SMB_DEV_T device;
SMB_INO_T inode;
};
-/* the open brlock.tdb database */
-static TDB_CONTEXT *tdb;
+/* The open brlock.tdb database. */
+static TDB_CONTEXT *tdb;
/****************************************************************************
-see if two locking contexts are equal
+ See if two locking contexts are equal.
****************************************************************************/
+
static BOOL brl_same_context(struct lock_context *ctx1,
struct lock_context *ctx2)
{
@@ -69,8 +76,9 @@ static BOOL brl_same_context(struct lock_context *ctx1,
}
/****************************************************************************
-see if lock2 can be added when lock1 is in place
+ See if lock2 can be added when lock1 is in place.
****************************************************************************/
+
static BOOL brl_conflict(struct lock_struct *lck1,
struct lock_struct *lck2)
{
@@ -88,8 +96,9 @@ static BOOL brl_conflict(struct lock_struct *lck1,
/****************************************************************************
-open up the brlock.tdb database
+ Open up the brlock.tdb database.
****************************************************************************/
+
void brl_init(int read_only)
{
if (tdb) return;
@@ -102,8 +111,9 @@ void brl_init(int read_only)
/****************************************************************************
-lock a range of bytes
+ Lock a range of bytes.
****************************************************************************/
+
BOOL brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
uint16 smbpid, pid_t pid, uint16 tid,
br_off start, br_off size,
@@ -160,10 +170,238 @@ BOOL brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
return False;
}
+/****************************************************************************
+ Create a list of lock ranges that don't overlap a given range. Used in calculating
+ POSIX lock unlocks. This is a difficult function that requires ASCII art to
+ understand it :-).
+****************************************************************************/
+
+struct unlock_list *brl_unlock_list(TALLOC_CTX *ctx, struct unlock_list *ulhead,
+ pid_t pid, SMB_DEV_T dev, SMB_INO_T ino)
+{
+ struct lock_key key;
+ TDB_DATA kbuf, dbuf;
+ struct lock_struct *locks;
+ int num_locks, i;
+
+ /*
+ * Setup the key for this fetch.
+ */
+ key.device = dev;
+ key.inode = ino;
+ kbuf.dptr = (char *)&key;
+ kbuf.dsize = sizeof(key);
+
+ dbuf.dptr = NULL;
+
+ tdb_lockchain(tdb, kbuf);
+ dbuf = tdb_fetch(tdb, kbuf);
+
+ if (!dbuf.dptr) {
+ tdb_unlockchain(tdb, kbuf);
+ return ulhead;
+ }
+
+ locks = (struct lock_struct *)dbuf.dptr;
+ num_locks = dbuf.dsize / sizeof(*locks);
+
+ /*
+ * Check the current lock list on this dev/inode pair.
+ * Quit if the list is deleted.
+ */
+
+ for (i=0; i<num_locks && ulhead; i++) {
+
+ struct lock_struct *lock = &locks[i];
+ struct unlock_list *ul_curr;
+
+ /* If it's not this process, ignore it. */
+ if (lock->context.pid != pid)
+ continue;
+
+ /*
+ * Walk the unlock list, checking for overlaps. Note that
+ * the unlock list can expand within this loop if the current
+ * range being examined needs to be split.
+ */
+
+ for (ul_curr = ulhead; ul_curr;) {
+
+ DEBUG(10,("brl_unlock_list: curr: start=%.0f,size=%.0f \
+lock: start=%.0f,size=%.0f\n", (double)ul_curr->start, (double)ul_curr->size,
+ (double)lock->start, (double)lock->size ));
+
+ if ( (ul_curr->start >= (lock->start + lock->size)) ||
+ (lock->start > (ul_curr->start + ul_curr->size))) {
+
+ /* No overlap with this lock - leave this range alone. */
+/*********************************************
+ +---------+
+ | ul_curr |
+ +---------+
+ +-------+
+ | lock |
+ +-------+
+OR....
+ +---------+
+ | ul_curr |
+ +---------+
+**********************************************/
+
+ DEBUG(10,("brl_unlock_list: no overlap case.\n" ));
+
+ ul_curr = ul_curr->next;
+
+ } else if ( (ul_curr->start >= lock->start) &&
+ (ul_curr->start + ul_curr->size <= lock->start + lock->size) ) {
+
+ /*
+ * This unlock is completely overlapped by this existing lock range
+ * and thus should have no effect (not be unlocked). Delete it from the list.
+ */
+/*********************************************
+ +---------+
+ | ul_curr |
+ +---------+
+ +---------------------------+
+ | lock |
+ +---------------------------+
+**********************************************/
+ /* Save the next pointer */
+ struct unlock_list *ul_next = ul_curr->next;
+
+ DEBUG(10,("brl_unlock_list: delete case.\n" ));
+
+ DLIST_REMOVE(ulhead, ul_curr);
+ if(ulhead == NULL)
+ break; /* No more list... */
+
+ ul_curr = ul_next;
+
+ } else if ( (ul_curr->start >= lock->start) &&
+ (ul_curr->start < lock->start + lock->size) &&
+ (ul_curr->start + ul_curr->size > lock->start + lock->size) ) {
+
+ /*
+ * This unlock overlaps the existing lock range at the high end.
+ * Truncate by moving start to existing range end and reducing size.
+ */
+/*********************************************
+ +---------------+
+ | ul_curr |
+ +---------------+
+ +---------------+
+ | lock |
+ +---------------+
+BECOMES....
+ +-------+
+ |ul_curr|
+ +-------+
+**********************************************/
+
+ ul_curr->size = (ul_curr->start + ul_curr->size) - (lock->start + lock->size);
+ ul_curr->start = lock->start + lock->size;
+
+ DEBUG(10,("brl_unlock_list: truncate high case: start=%.0f,size=%.0f\n",
+ (double)ul_curr->start, (double)ul_curr->size ));
+
+ ul_curr = ul_curr->next;
+
+ } else if ( (ul_curr->start < lock->start) &&
+ (ul_curr->start + ul_curr->size > lock->start) ) {
+
+ /*
+ * This unlock overlaps the existing lock range at the low end.
+ * Truncate by reducing size.
+ */
+/*********************************************
+ +---------------+
+ | ul_curr |
+ +---------------+
+ +---------------+
+ | lock |
+ +---------------+
+BECOMES....
+ +-------+
+ |ul_curr|
+ +-------+
+**********************************************/
+
+ ul_curr->size = lock->start - ul_curr->start;
+
+ DEBUG(10,("brl_unlock_list: truncate low case: start=%.0f,size=%.0f\n",
+ (double)ul_curr->start, (double)ul_curr->size ));
+
+ ul_curr = ul_curr->next;
+
+ } else if ( (ul_curr->start < lock->start) &&
+ (ul_curr->start + ul_curr->size > lock->start + lock->size) ) {
+ /*
+ * Worst case scenario. Unlock request completely overlaps an existing
+ * lock range. Split the request into two, push the new (upper) request
+ * into the dlink list, and continue with the entry after ul_new (as we
+ * know that ul_new will not overlap with this lock).
+ */
+/*********************************************
+ +---------------------------+
+ | ul_curr |
+ +---------------------------+
+ +---------+
+ | lock |
+ +---------+
+BECOMES.....
+ +-------+ +---------+
+ |ul_curr| |ul_new |
+ +-------+ +---------+
+**********************************************/
+ struct unlock_list *ul_new = (struct unlock_list *)talloc(ctx,
+ sizeof(struct unlock_list));
+
+ if(ul_new == NULL) {
+ DEBUG(0,("brl_unlock_list: talloc fail.\n"));
+ return NULL; /* The talloc_destroy takes care of cleanup. */
+ }
+
+ ZERO_STRUCTP(ul_new);
+ ul_new->start = lock->start + lock->size;
+ ul_new->size = ul_curr->start + ul_curr->size - ul_new->start;
+
+ /* Add into the dlink list after the ul_curr point - NOT at ulhead. */
+ DLIST_ADD(ul_curr, ul_new);
+
+ /* Truncate the ul_curr. */
+ ul_curr->size = lock->start - ul_curr->start;
+
+ DEBUG(10,("brl_unlock_list: split case: curr: start=%.0f,size=%.0f \
+new: start=%.0f,size=%.0f\n", (double)ul_curr->start, (double)ul_curr->size,
+ (double)ul_new->start, (double)ul_new->size ));
+
+ ul_curr = ul_new->next;
+
+ } else {
+
+ /*
+ * This logic case should never happen. Ensure this is the
+ * case by forcing an abort.... Remove in production.
+ */
+
+ smb_panic("brl_unlock_list: logic flaw in cases...\n");
+ }
+ } /* end for ( ul_curr = ulhead; ul_curr;) */
+ } /* end for (i=0; i<num_locks && ul_head; i++) */
+
+ tdb_unlockchain(tdb, kbuf);
+
+ if (dbuf.dptr)
+ free(dbuf.dptr);
+
+ return ulhead;
+}
/****************************************************************************
-unlock a range of bytes
+ Unlock a range of bytes.
****************************************************************************/
+
BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
uint16 smbpid, pid_t pid, uint16 tid,
br_off start, br_off size)
@@ -194,10 +432,13 @@ BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
locks = (struct lock_struct *)dbuf.dptr;
count = dbuf.dsize / sizeof(*locks);
for (i=0; i<count; i++) {
- if (brl_same_context(&locks[i].context, &context) &&
- locks[i].fnum == fnum &&
- locks[i].start == start &&
- locks[i].size == size) {
+
+ struct lock_struct *lock = &locks[i];
+
+ if (brl_same_context(&lock->context, &context) &&
+ lock->fnum == fnum &&
+ lock->start == start &&
+ lock->size == size) {
/* found it - delete it */
if (count == 1) {
tdb_delete(tdb, kbuf);
@@ -224,11 +465,10 @@ BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
return False;
}
-
-
/****************************************************************************
-test if we could add a lock if we wanted to
+ Test if we could add a lock if we wanted to.
****************************************************************************/
+
BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino,
uint16 smbpid, pid_t pid, uint16 tid,
br_off start, br_off size,
@@ -278,10 +518,10 @@ BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino,
return False;
}
-
/****************************************************************************
-remove any locks associated with a open file
+ Remove any locks associated with a open file.
****************************************************************************/
+
void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
{
struct lock_key key;
@@ -305,9 +545,11 @@ void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
locks = (struct lock_struct *)dbuf.dptr;
count = dbuf.dsize / sizeof(*locks);
for (i=0; i<count; i++) {
- if (locks[i].context.tid == tid &&
- locks[i].context.pid == pid &&
- locks[i].fnum == fnum) {
+ struct lock_struct *lock = &locks[i];
+
+ if (lock->context.tid == tid &&
+ lock->context.pid == pid &&
+ lock->fnum == fnum) {
/* found it - delete it */
if (count > 1 && i < count-1) {
memmove(&locks[i], &locks[i+1],
@@ -330,11 +572,73 @@ void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
tdb_unlockchain(tdb, kbuf);
}
+/****************************************************************************
+ Return a lock list associated with an open file.
+****************************************************************************/
+
+struct unlock_list *brl_getlocklist( TALLOC_CTX *ctx, SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
+{
+ struct lock_key key;
+ TDB_DATA kbuf, dbuf;
+ int i, count;
+ struct lock_struct *locks;
+ struct unlock_list *ulist = NULL;
+
+ key.device = dev;
+ key.inode = ino;
+ kbuf.dptr = (char *)&key;
+ kbuf.dsize = sizeof(key);
+
+ dbuf.dptr = NULL;
+
+ tdb_lockchain(tdb, kbuf);
+ dbuf = tdb_fetch(tdb, kbuf);
+
+ if (!dbuf.dptr) {
+ tdb_unlockchain(tdb, kbuf);
+ return NULL;
+ }
+
+ /* There are existing locks - allocate an entry for each one. */
+ locks = (struct lock_struct *)dbuf.dptr;
+ count = dbuf.dsize / sizeof(*locks);
+
+ for (i=0; i<count; i++) {
+ struct lock_struct *lock = &locks[i];
+
+ if (lock->context.tid == tid &&
+ lock->context.pid == pid &&
+ lock->fnum == fnum) {
+
+ struct unlock_list *ul_new = (struct unlock_list *)talloc(ctx,
+ sizeof(struct unlock_list));
+
+ if(ul_new == NULL) {
+ DEBUG(0,("brl_getlocklist: talloc fail.\n"));
+ return NULL; /* The talloc_destroy takes care of cleanup. */
+ }
+
+ ZERO_STRUCTP(ul_new);
+ ul_new->start = lock->start;
+ ul_new->size = lock->size;
+
+ DLIST_ADD(ulist, ul_new);
+ }
+ }
+
+ if (dbuf.dptr)
+ free(dbuf.dptr);
+ tdb_unlockchain(tdb, kbuf);
+
+ return ulist;
+}
+
/****************************************************************************
-traverse the whole database with this function, calling traverse_callback
-on each lock
+ Traverse the whole database with this function, calling traverse_callback
+ on each lock.
****************************************************************************/
+
static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
{
struct lock_struct *locks;
@@ -357,8 +661,9 @@ static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *st
}
/*******************************************************************
- Call the specified function on each lock in the database
+ Call the specified function on each lock in the database.
********************************************************************/
+
int brl_forall(BRLOCK_FN(fn))
{
if (!tdb) return 0;
diff --git a/source3/locking/locking.c b/source3/locking/locking.c
index a73af8fd07..811dfbc101 100644
--- a/source3/locking/locking.c
+++ b/source3/locking/locking.c
@@ -381,29 +381,6 @@ static BOOL release_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG
}
/****************************************************************************
- Remove any locks on this fd. Called from file_close().
-****************************************************************************/
-
-void locking_close_file(files_struct *fsp)
-{
- if (!lp_locking(SNUM(fsp->conn)))
- return;
-
- if(lp_posix_locking(SNUM(fsp->conn))) {
- /*
- * We need to release all POSIX locks we have on this
- * fd.
- */
- }
-
- /*
- * Now release all the tdb locks.
- */
-
- brl_close(fsp->dev, fsp->inode, getpid(), fsp->conn->cnum, fsp->fnum);
-}
-
-/****************************************************************************
Utility function called to see if a file region is locked.
****************************************************************************/
@@ -502,52 +479,146 @@ BOOL do_unlock(files_struct *fsp,connection_struct *conn,
int *eclass,uint32 *ecode)
{
BOOL ok = False;
+ TALLOC_CTX *ul_ctx = NULL;
+ struct unlock_list *ulist = NULL;
+ struct unlock_list *ul = NULL;
+ pid_t pid;
if (!lp_locking(SNUM(conn)))
return(True);
+ if (!OPEN_FSP(fsp) || !fsp->can_lock || (fsp->conn != conn)) {
+ *eclass = ERRDOS;
+ *ecode = ERRlock;
+ return False;
+ }
+
DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for file %s\n",
(double)offset, (double)count, fsp->fsp_name ));
-
- if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn)) {
-
- if(lp_posix_locking(SNUM(conn))) {
-
-#if 0
- /*
- * The following call calculates if there are any
- * overlapping read locks held by this process on
- * other fd's open on the same file and truncates
- * any overlapping range and returns the value in
- * the non_overlap_XXX variables. Thus the POSIX
- * unlock may not be done on the same region as
- * the brl_lock. JRA.
- */
- brl_unlock_list(fsp->dev, fsp->inode, fsp->fnum,
-#endif
-
- /*
- * Release the POSIX lock on this range.
- */
+ /*
+ * Remove the existing lock record from the tdb lockdb
+ * before looking at POSIX locks. If this record doesn't
+ * match then don't bother looking to remove POSIX locks.
+ */
- (void)release_posix_lock(fsp, offset, count);
- fsp->num_posix_locks--;
- }
+ pid = getpid();
- ok = brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
- global_smbpid, getpid(), conn->cnum, offset, count);
- }
+ ok = brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
+ global_smbpid, pid, conn->cnum, offset, count);
if (!ok) {
*eclass = ERRDOS;
*ecode = ERRlock;
return False;
}
+
+ if (!lp_posix_locking(SNUM(conn)))
+ return True;
+
+ if ((ul_ctx = talloc_init()) == NULL) {
+ DEBUG(0,("do_unlock: unable to init talloc context.\n"));
+ return True; /* Not a fatal error. */
+ }
+
+ if ((ul = (struct unlock_list *)talloc(ul_ctx, sizeof(struct unlock_list))) == NULL) {
+ DEBUG(0,("do_unlock: unable to talloc unlock list.\n"));
+ talloc_destroy(ul_ctx);
+ return True; /* Not a fatal error. */
+ }
+
+ /*
+ * Create the initial list entry containing the
+ * lock we want to remove.
+ */
+
+ ZERO_STRUCTP(ul);
+ ul->start = offset;
+ ul->size = count;
+
+ DLIST_ADD(ulist, ul);
+
+ /*
+ * The following call calculates if there are any
+ * overlapping read locks held by this process on
+ * other fd's open on the same file and creates a
+ * list of unlock ranges that will allow other
+ * POSIX lock ranges to remain on the file whilst the
+ * unlocks are performed.
+ */
+
+ ulist = brl_unlock_list(ul_ctx, ulist, pid, fsp->dev, fsp->inode);
+
+ /*
+ * Release the POSIX locks on the list of ranges returned.
+ */
+
+ for(; ulist; ulist = ulist->next)
+ (void)release_posix_lock(fsp, ulist->start, ulist->size);
+
+ talloc_destroy(ul_ctx);
+
+ /*
+ * We treat this as one unlock request for POSIX accounting purposes even
+ * if it may have been split into multiple smaller POSIX unlock ranges.
+ */
+
+ fsp->num_posix_locks--;
+
return True; /* Did unlock */
}
/****************************************************************************
+ Remove any locks on this fd. Called from file_close().
+****************************************************************************/
+
+void locking_close_file(files_struct *fsp)
+{
+ pid_t pid = getpid();
+
+ if (!lp_locking(SNUM(fsp->conn)))
+ return;
+
+ if(lp_posix_locking(SNUM(fsp->conn))) {
+
+ TALLOC_CTX *ul_ctx = NULL;
+ struct unlock_list *ul = NULL;
+ int eclass;
+ uint32 ecode;
+
+ if ((ul_ctx = talloc_init()) == NULL) {
+ DEBUG(0,("locking_close_file: unable to init talloc context.\n"));
+ return;
+ }
+
+ /*
+ * We need to release all POSIX locks we have on this
+ * fd. Get all our existing locks from the tdb locking database.
+ */
+
+ ul = brl_getlocklist(ul_ctx, fsp->dev, fsp->inode, pid, fsp->conn->cnum, fsp->fnum);
+
+ /*
+ * Now unlock all of them. This will remove the brl entry also
+ * for each lock.
+ */
+
+ for(; ul; ul = ul->next)
+ do_unlock(fsp,fsp->conn,ul->size,ul->start,&eclass,&ecode);
+
+ talloc_destroy(ul_ctx);
+
+ } else {
+
+ /*
+ * Just release all the tdb locks, no need to release individually.
+ */
+
+ brl_close(fsp->dev, fsp->inode, pid, fsp->conn->cnum, fsp->fnum);
+ }
+}
+
+/****************************************************************************
Initialise the locking functions.
****************************************************************************/
BOOL locking_init(int read_only)