svn commit: samba r13804 - in trunk/source/locking: .

jra at samba.org jra at samba.org
Fri Mar 3 03:00:52 GMT 2006


Author: jra
Date: 2006-03-03 03:00:52 +0000 (Fri, 03 Mar 2006)
New Revision: 13804

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=13804

Log:
Add in support for lock splits/merges on POSIX
flavour setlock. Now to add support for unlock.
Jeremy.

Modified:
   trunk/source/locking/brlock.c
   trunk/source/locking/locking.c


Changeset:
Modified: trunk/source/locking/brlock.c
===================================================================
--- trunk/source/locking/brlock.c	2006-03-03 02:29:48 UTC (rev 13803)
+++ trunk/source/locking/brlock.c	2006-03-03 03:00:52 UTC (rev 13804)
@@ -124,9 +124,11 @@
 static BOOL brl_conflict(struct lock_struct *lck1, 
 			 struct lock_struct *lck2)
 {
+	/* Ignore PENDING locks. */
 	if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
 		return False;
 
+	/* Read locks never conflict. */
 	if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
 		return False;
 	}
@@ -139,6 +141,39 @@
 	return brl_overlap(lck1, lck2);
 } 
 
+/****************************************************************************
+ See if lock2 can be added when lock1 is in place - when both locks are POSIX
+ flavour.
+****************************************************************************/
+
+static BOOL brl_conflict_posix(struct lock_struct *lck1, 
+			 struct lock_struct *lck2)
+{
+#if defined(DEVELOPER)
+	SMB_ASSERT(lck1->lock_flav == POSIX_LOCK);
+	SMB_ASSERT(lck2->lock_flav == POSIX_LOCK);
+#endif
+
+	/* Ignore PENDING locks. */
+	if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
+		return False;
+
+	/* Read locks never conflict. */
+	if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
+		return False;
+	}
+
+	/* Locks on the same context on the same fnum con't conflict. */
+	if (brl_same_context(&lck1->context, &lck2->context) &&
+			(lck1->fnum == lck2->fnum)) {
+		return False;
+	}
+
+	/* One is read, the other write, context or fnum are different,
+	   do the overlap ? */
+	return brl_overlap(lck1, lck2);
+} 
+
 #if ZERO_ZERO
 static BOOL brl_conflict1(struct lock_struct *lck1, 
 			 struct lock_struct *lck2)
@@ -287,9 +322,10 @@
 {
 	unsigned int i;
 	struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
-	char *tp;
+	struct lock_struct *tp;
 
 	for (i=0; i < br_lck->num_locks; i++) {
+		/* Do any Windows or POSIX locks conflict ? */
 		if (brl_conflict(&locks[i], plock)) {
 			NTSTATUS status = brl_lock_failed(plock);;
 			/* Did we block ourselves ? */
@@ -307,34 +343,292 @@
 	}
 
 	/* no conflicts - add it to the list of locks */
-	tp = SMB_REALLOC(locks, (br_lck->num_locks + 1) * sizeof(*locks));
+	tp = (struct lock_struct *)SMB_REALLOC(locks, (br_lck->num_locks + 1) * sizeof(*locks));
 	if (!tp) {
 		return NT_STATUS_NO_MEMORY;
 	} else {
-		locks = (struct lock_struct *)tp;
+		locks = tp;
 		memcpy(&locks[br_lck->num_locks], plock, sizeof(struct lock_struct));
 		br_lck->num_locks += 1;
 		br_lck->lock_data = (void *)locks;
 		br_lck->modified = True;
 	}
 
-#if ZERO_ZERO
-	/* sort the lock list */
-	qsort(br_lck->lock_data, (size_t)br_lck->num_locks, sizeof(lock), lock_compare);
-#endif
-
 	return NT_STATUS_OK;
 }
 
 /****************************************************************************
+ Cope with POSIX range splits and merges.
+****************************************************************************/
+
+static unsigned int brlock_posix_split_merge(struct lock_struct *lck_arr,
+						struct lock_struct *ex,
+						struct lock_struct *plock,
+						BOOL *lock_was_added)
+{
+	BOOL lock_types_differ = (ex->lock_type != plock->lock_type);
+
+	/* We can't merge non-conplicting locks on different context
+		or not on the same fnum */
+
+	if (!brl_same_context(&ex->context, &plock->context) || (ex->fnum != plock->fnum)) {
+		/* Just copy. */
+		memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+		return 1;
+	}
+
+	/* We now know we have the same context and fnum. */
+
+	/* Did we overlap ? */
+
+/*********************************************
+                                             +---------+
+                                             | ex      |
+                                             +---------+
+                                +-------+
+                                | plock |
+                                +-------+
+OR....
+             +---------+
+             |  ex     |
+             +---------+
+**********************************************/
+
+	if ( (ex->start >= (plock->start + plock->size)) ||
+			(plock->start >= (ex->start + ex->size))) {
+		/* No overlap with this lock - copy existing. */
+		memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+		return 1;
+	}
+
+/*********************************************
+                +---------+
+                |  ex     |
+                +---------+
+        +---------------------------+
+        |       plock               | -> replace with plock.
+        +---------------------------+
+**********************************************/
+
+	if ( (ex->start >= plock->start) &&
+			(ex->start + ex->size <= plock->start + plock->size) ) {
+		memcpy(&lck_arr[0], plock, sizeof(struct lock_struct));
+		*lock_was_added = True;
+		return 1;
+	}
+
+/*********************************************
+                +---------------+
+                |  ex           |
+                +---------------+
+        +---------------+
+        |   plock       |
+        +---------------+
+BECOMES....
+        +---------------+-------+
+        |   plock       | ex    | - different lock types.
+        +---------------+-------+
+OR....
+        +---------------+-------+
+        |   ex                  | - same lock type.
+        +---------------+-------+
+**********************************************/
+
+	if ( (ex->start >= plock->start) &&
+				(ex->start < plock->start + plock->size) &&
+				(ex->start + ex->size > plock->start + plock->size) ) {
+
+		*lock_was_added = True;
+
+		/* If the lock types are the same, we merge, if different, we
+		   add the new lock before the old. */
+
+		if (lock_types_differ) {
+			/* Add new. */
+			memcpy(&lck_arr[0], plock, sizeof(struct lock_struct));
+			memcpy(&lck_arr[1], ex, sizeof(struct lock_struct));
+			/* Adjust existing start and size. */
+			lck_arr[1].start = plock->start + plock->size;
+			lck_arr[1].size = (ex->start + ex->size) - (plock->start + plock->size);
+			return 2;
+		} else {
+			/* Merge. */
+			memcpy(&lck_arr[0], plock, sizeof(struct lock_struct));
+			/* Set new start and size. */
+			lck_arr[0].start = plock->start;
+			lck_arr[0].size = (ex->start + ex->size) - plock->start;
+			return 1;
+		}
+	}
+
+/*********************************************
+   +---------------+
+   |  ex           |
+   +---------------+
+           +---------------+
+           |   plock       |
+           +---------------+
+BECOMES....
+   +-------+---------------+
+   | ex    |   plock       | - different lock types
+   +-------+---------------+
+
+OR
+   +-------+---------------+
+   | ex                    | - same lock type.
+   +-------+---------------+
+
+**********************************************/
+
+	if ( (ex->start < plock->start) &&
+			(ex->start + ex->size > plock->start) &&
+			(ex->start + ex->size <= plock->start + plock->size) ) {
+
+		*lock_was_added = True;
+
+		/* If the lock types are the same, we merge, if different, we
+		   add the new lock after the old. */
+
+		if (lock_types_differ) {
+			memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+			memcpy(&lck_arr[1], plock, sizeof(struct lock_struct));
+			/* Adjust existing size. */
+			lck_arr[0].size = plock->start - ex->start;
+			return 2;
+		} else {
+			/* Merge. */
+			memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+			/* Adjust existing size. */
+			lck_arr[0].size = (plock->start + plock->size) - ex->start;
+			return 1;
+		}
+	}
+
+/*********************************************
+        +---------------------------+
+        |        ex                 |
+        +---------------------------+
+                +---------+
+                |  plock  |
+                +---------+
+BECOMES.....
+        +-------+---------+---------+
+        | ex    |  plock  | ex      | - different lock types.
+        +-------+---------+---------+
+OR
+        +---------------------------+
+        |        ex                 | - same lock type.
+        +---------------------------+
+**********************************************/
+
+	if ( (ex->start < plock->start) && (ex->start + ex->size > plock->start + plock->size) ) {
+		*lock_was_added = True;
+
+		if (lock_types_differ) {
+
+			/* We have to split ex into two locks here. */
+
+			memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+			memcpy(&lck_arr[1], plock, sizeof(struct lock_struct));
+			memcpy(&lck_arr[2], ex, sizeof(struct lock_struct));
+
+			/* Adjust first existing size. */
+			lck_arr[0].size = plock->start - ex->start;
+
+			/* Adjust second existing start and size. */
+			lck_arr[2].start = plock->start + plock->size;
+			lck_arr[2].size = (ex->start + ex->size) - (plock->start + plock->size);
+			return 3;
+		} else {
+			/* Just eat plock. */
+			memcpy(&lck_arr[0], ex, sizeof(struct lock_struct));
+			return 1;
+		}
+	}
+
+	/* Never get here. */
+	smb_panic("brlock_posix_split_merge\n");
+	return 0;
+}
+
+/****************************************************************************
  Lock a range of bytes - POSIX lock semantics.
+ We must cope with range splits and merges.
 ****************************************************************************/
 
 static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck,
-			struct lock_struct *plock)
+			struct lock_struct *plock,
+			BOOL *my_lock_ctx)
 {
-	/* Placeholder until I fix this. */
-	return NT_STATUS_LOCK_NOT_GRANTED;
+	unsigned int i, count;
+	struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+	struct lock_struct *tp, *tp1;
+	BOOL lock_was_added = False;
+
+	/* No zero-zero locks for POSIX. */
+	if (plock->start == 0 && plock->size == 0) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	/* Don't allow 64-bit lock wrap. */
+	if (plock->start + plock->size < plock->start ||
+			plock->start + plock->size < plock->size) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	/* The worst case scenario here is we have to split an
+	   existing POSIX lock range into two, and add our lock,
+	   so we need at most 2 more entries. */
+
+	tp = SMB_MALLOC_ARRAY(struct lock_struct, (br_lck->num_locks + 2));
+	if (!tp) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	
+	count = 0;
+	for (i=0; i < br_lck->num_locks; i++) {
+		if (locks[i].lock_flav == WINDOWS_LOCK) {
+			/* Do any Windows flavour locks conflict ? */
+			if (brl_conflict(&locks[i], plock)) {
+				/* Did we block ourselves ? */
+				if (brl_same_context(&locks[i].context, &plock->context)) {
+					*my_lock_ctx = True;
+				}
+				/* No games with error messages. */
+				SAFE_FREE(tp);
+				return NT_STATUS_FILE_LOCK_CONFLICT;
+			}
+			/* Just copy the Windows lock into the new array. */
+			memcpy(&tp[count], &locks[i], sizeof(struct lock_struct));
+			count++;
+		} else {
+			/* POSIX conflict semantics are different. */
+			if (brl_conflict_posix(&locks[i], plock)) {
+				/* Can't block ourselves with POSIX locks. */
+				/* No games with error messages. */
+				SAFE_FREE(tp);
+				return NT_STATUS_FILE_LOCK_CONFLICT;
+			}
+
+			/* Work out overlaps. */
+			count += brlock_posix_split_merge(&tp[count], &locks[i], plock, &lock_was_added);
+		}
+	}
+
+	if (!lock_was_added) {
+		memcpy(&tp[count], plock, sizeof(struct lock_struct));
+		count++;
+	}
+
+	/* Realloc so we don't leak entries per lock call. */
+	tp1 = (struct lock_struct *)SMB_REALLOC(tp, count * sizeof(*locks));
+	if (!tp1) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	br_lck->num_locks = count;
+	br_lck->lock_data = (void *)tp1;
+	br_lck->modified = True;
+	return NT_STATUS_OK;
 }
 
 /****************************************************************************
@@ -350,6 +644,7 @@
 		enum brl_flavour lock_flav,
 		BOOL *my_lock_ctx)
 {
+	NTSTATUS ret;
 	struct lock_struct lock;
 
 	*my_lock_ctx = False;
@@ -370,10 +665,17 @@
 	lock.lock_flav = lock_flav;
 
 	if (lock_flav == WINDOWS_LOCK) {
-		return brl_lock_windows(br_lck, &lock, my_lock_ctx);
+		ret = brl_lock_windows(br_lck, &lock, my_lock_ctx);
 	} else {
-		return brl_lock_posix(br_lck, &lock);
+		ret = brl_lock_posix(br_lck, &lock, my_lock_ctx);
 	}
+
+#if ZERO_ZERO
+	/* sort the lock list */
+	qsort(br_lck->lock_data, (size_t)br_lck->num_locks, sizeof(lock), lock_compare);
+#endif
+
+	return ret;
 }
 
 /****************************************************************************

Modified: trunk/source/locking/locking.c
===================================================================
--- trunk/source/locking/locking.c	2006-03-03 02:29:48 UTC (rev 13803)
+++ trunk/source/locking/locking.c	2006-03-03 03:00:52 UTC (rev 13804)
@@ -2,7 +2,7 @@
    Unix SMB/CIFS implementation.
    Locking functions
    Copyright (C) Andrew Tridgell 1992-2000
-   Copyright (C) Jeremy Allison 1992-2000
+   Copyright (C) Jeremy Allison 1992-2006
    Copyright (C) Volker Lendecke 2005
    
    This program is free software; you can redistribute it and/or modify
@@ -33,6 +33,7 @@
    rewrtten completely to use new tdb code. Tridge, Dec '99
 
    Added POSIX locking support. Jeremy Allison (jeremy at valinux.com), Apr. 2000.
+   Added Unix Extensions POSIX locking support. Jeremy Allison Mar 2006.
 */
 
 #include "includes.h"



More information about the samba-cvs mailing list