summaryrefslogtreecommitdiff
path: root/source3/locking/locking.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/locking/locking.c')
-rw-r--r--source3/locking/locking.c171
1 files changed, 121 insertions, 50 deletions
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)