svn commit: samba r13806 - in trunk/source: include locking smbd

jra at samba.org jra at samba.org
Fri Mar 3 05:14:28 GMT 2006


Author: jra
Date: 2006-03-03 05:14:27 +0000 (Fri, 03 Mar 2006)
New Revision: 13806

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

Log:
Ok, got the guts of the POSIX unlock logic coded up,
now to hook it up to the trans2 calls and code up the
blocking lock fixes.
Jeremy.

Modified:
   trunk/source/include/smb.h
   trunk/source/locking/brlock.c
   trunk/source/smbd/blocking.c


Changeset:
Modified: trunk/source/include/smb.h
===================================================================
--- trunk/source/include/smb.h	2006-03-03 03:57:34 UTC (rev 13805)
+++ trunk/source/include/smb.h	2006-03-03 05:14:27 UTC (rev 13806)
@@ -800,8 +800,10 @@
 #define FLAG_HIDE  	0x2000 /* options that should be hidden in SWAT */
 #define FLAG_DOS_STRING 0x4000 /* convert from UNIX to DOS codepage when reading this string. */
 
-/* passed to br lock code */
-enum brl_type {READ_LOCK, WRITE_LOCK, PENDING_LOCK};
+/* passed to br lock code - the UNLOCK_LOCK should never be stored into the tdb
+   and is used in calculating POSIX unlock ranges only. */
+
+enum brl_type {READ_LOCK, WRITE_LOCK, PENDING_LOCK, UNLOCK_LOCK};
 enum brl_flavour {WINDOWS_LOCK = 0, POSIX_LOCK = 1};
 
 struct byte_range_lock {

Modified: trunk/source/locking/brlock.c
===================================================================
--- trunk/source/locking/brlock.c	2006-03-03 03:57:34 UTC (rev 13805)
+++ trunk/source/locking/brlock.c	2006-03-03 05:14:27 UTC (rev 13806)
@@ -697,7 +697,6 @@
 
 static BOOL brl_unlock_windows(struct byte_range_lock *br_lck,
 		struct lock_struct *plock,
-		BOOL remove_pending_locks_only,
 		void (*pre_unlock_fn)(void *),
 		void *pre_unlock_data)
 {
@@ -712,6 +711,7 @@
 		if (lock->lock_type == WRITE_LOCK &&
 		    brl_same_context(&lock->context, &plock->context) &&
 		    lock->fnum == plock->fnum &&
+		    lock->lock_flav == WINDOWS_LOCK &&
 		    lock->start == plock->start &&
 		    lock->size == plock->size) {
 
@@ -736,23 +736,14 @@
 		lock = &locks[i];
 
 		/* Only remove our own locks that match in start, size, and flavour. */
-		if (!brl_same_context(&lock->context, &plock->context) ||
-					lock->fnum != plock->fnum ||
-					lock->lock_flav != WINDOWS_LOCK ||
-					lock->start != plock->start ||
-					lock->size != plock->size ) {
-			continue;
-		}
-
-		if (remove_pending_locks_only && lock->lock_type == PENDING_LOCK) {
-			/* Found this particular pending lock - delete it */
+		if (brl_same_context(&lock->context, &plock->context) &&
+					lock->fnum == plock->fnum &&
+					lock->lock_flav == WINDOWS_LOCK &&
+					lock->lock_type == PENDING_LOCK &&
+					lock->start == plock->start &&
+					lock->size == plock->size ) {
 			break;
 		}
-
-		if (lock->lock_type != PENDING_LOCK) {
-			/* Found it. */
-			break;
-		}
 	}
 
 	if (i == br_lck->num_locks) {
@@ -787,6 +778,7 @@
 		}
 	}
 
+	/* Actually delete the lock. */
 	if (i < br_lck->num_locks - 1) {
 		memmove(&locks[i], &locks[i+1], 
 			sizeof(*locks)*((br_lck->num_locks-1) - i));
@@ -803,14 +795,203 @@
 
 static BOOL brl_unlock_posix(struct byte_range_lock *br_lck,
 		struct lock_struct *plock,
-		BOOL remove_pending_locks_only,
 		void (*pre_unlock_fn)(void *),
 		void *pre_unlock_data)
 {
-	return False;
+	unsigned int i, j, count;
+	struct lock_struct *lock;
+	struct lock_struct *tp, *tp1;
+	struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+	BOOL overlap_found = False;
+
+	/* No zero-zero locks for POSIX. */
+	if (plock->start == 0 && plock->size == 0) {
+		return False;
+	}
+
+	/* Don't allow 64-bit lock wrap. */
+	if (plock->start + plock->size < plock->start ||
+			plock->start + plock->size < plock->size) {
+		return False;
+	}
+
+	/* The worst case scenario here is we have to split an
+	   existing POSIX lock range into two, so we need at most
+	   1 more entry. */
+
+	tp = SMB_MALLOC_ARRAY(struct lock_struct, (br_lck->num_locks + 1));
+	if (!tp) {
+		return False;
+	}
+
+	count = 0;
+	for (i = 0; i < br_lck->num_locks; i++) {
+		struct lock_struct tmp_lock[3];
+		BOOL lock_was_added = False;
+		unsigned int tmp_count;
+
+		lock = &locks[i];
+
+		/* Only remove our own locks */
+		if (!brl_same_context(&lock->context, &plock->context) ||
+					lock->lock_type == PENDING_LOCK ||
+					lock->fnum != plock->fnum ) {
+			memcpy(&tp[count], lock, sizeof(struct lock_struct));
+			count++;
+			continue;
+		}
+
+		/* Work out overlaps. */
+		tmp_count = brlock_posix_split_merge(&tmp_lock[0], &locks[i], plock, &lock_was_added);
+
+		if (tmp_count == 1) {
+			/* Ether the locks didn't overlap, or the unlock completely
+			   overlapped this lock. If it didn't overlap, then there's
+			   no change in the locks. */
+			if (tmp_lock[0].lock_type != UNLOCK_LOCK) {
+				SMB_ASSERT(tmp_lock[0].lock_type == locks[i].lock_type);
+				/* No change in this lock. */
+				memcpy(&tp[count], &tmp_lock[0], sizeof(struct lock_struct));
+				count++;
+			} else {
+				SMB_ASSERT(tmp_lock[0].lock_type == UNLOCK_LOCK);
+				overlap_found = True;
+			}
+			continue;
+		} else if (tmp_count == 2) {
+			/* The unlock overlapped an existing lock. Copy the truncated
+			   lock into the lock array. */
+			if (tmp_lock[0].lock_type != UNLOCK_LOCK) {
+				SMB_ASSERT(tmp_lock[0].lock_type == locks[i].lock_type);
+				SMB_ASSERT(tmp_lock[1].lock_type == UNLOCK_LOCK);
+				memcpy(&tp[count], &tmp_lock[0], sizeof(struct lock_struct));
+			} else {
+				SMB_ASSERT(tmp_lock[0].lock_type == UNLOCK_LOCK);
+				SMB_ASSERT(tmp_lock[1].lock_type == locks[i].lock_type);
+				memcpy(&tp[count], &tmp_lock[1], sizeof(struct lock_struct));
+			}
+			count++;
+			overlap_found = True;
+			continue;
+		} else {
+			/* tmp_count == 3 - (we split a lock range in two). */
+			SMB_ASSERT(tmp_lock[0].lock_type == locks[i].lock_type);
+			SMB_ASSERT(tmp_lock[1].lock_type == UNLOCK_LOCK);
+			SMB_ASSERT(tmp_lock[2].lock_type != locks[i].lock_type);
+
+			memcpy(&tp[count], &tmp_lock[0], sizeof(struct lock_struct));
+			count++;
+			memcpy(&tp[count], &tmp_lock[2], sizeof(struct lock_struct));
+			count++;
+			overlap_found = True;
+			/* Optimisation... */
+			/* We know we're finished here as we can't overlap any
+			   more POSIX locks. Copy the rest of the lock array. */
+			if (i < br_lck->num_locks - 1) {
+				memcpy(&tp[count], &locks[i+1], 
+					sizeof(*locks)*((br_lck->num_locks-1) - i));
+				count += ((br_lck->num_locks-1) - i);
+			}
+			break;
+		}
+	}
+
+	if (!overlap_found) {
+		/* Just ignore - no change. */
+		SAFE_FREE(tp);
+		return True;
+	}
+
+	/* Do any POSIX unlocks needed. */
+	if (pre_unlock_fn) {
+		(*pre_unlock_fn)(pre_unlock_data);
+	}
+
+	/* Realloc so we don't leak entries per unlock call. */
+	tp1 = (struct lock_struct *)SMB_REALLOC(tp, count * sizeof(*locks));
+	if (!tp1) {
+		return False;
+	}
+	br_lck->num_locks = count;
+	br_lck->lock_data = (void *)tp1;
+	br_lck->modified = True;
+
+	/* Send unlock messages to any pending waiters that overlap. */
+	locks = tp1;
+
+	for (j=0; j < br_lck->num_locks; j++) {
+		struct lock_struct *pend_lock = &locks[j];
+
+		/* Ignore non-pending locks. */
+		if (pend_lock->lock_type != PENDING_LOCK) {
+			continue;
+		}
+
+		/* We could send specific lock info here... */
+		if (brl_pending_overlap(lock, pend_lock)) {
+			DEBUG(10,("brl_unlock: sending unlock message to pid %s\n",
+				procid_str_static(&pend_lock->context.pid )));
+
+			become_root();
+			message_send_pid(pend_lock->context.pid,
+					MSG_SMB_UNLOCK,
+					NULL, 0, True);
+			unbecome_root();
+		}
+	}
+
+	return True;
 }
 
 /****************************************************************************
+ Remove a particular pending lock.
+****************************************************************************/
+
+BOOL brl_remove_pending_lock(struct byte_range_lock *br_lck,
+		uint16 smbpid,
+		struct process_id pid,
+		br_off start,
+		br_off size,
+		enum brl_flavour lock_flav)
+{
+	unsigned int i;
+	struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+	struct lock_context context;
+
+	context.smbpid = smbpid;
+	context.pid = pid;
+	context.tid = br_lck->fsp->conn->cnum;
+
+	for (i = 0; i < br_lck->num_locks; i++) {
+		struct lock_struct *lock = &locks[i];
+
+		if (brl_same_context(&lock->context, &context) &&
+				lock->fnum == br_lck->fsp->fnum &&
+				lock->lock_type == PENDING_LOCK &&
+				lock->lock_flav == lock_flav &&
+				lock->start == start &&
+				lock->size == size) {
+			break;
+		}
+	}
+
+	if (i == br_lck->num_locks) {
+		/* Didn't find it. */
+		return False;
+	}
+
+	if (i < br_lck->num_locks - 1) {
+		/* Found this particular pending lock - delete it */
+		memmove(&locks[i], &locks[i+1], 
+			sizeof(*locks)*((br_lck->num_locks-1) - i));
+	}
+
+	br_lck->num_locks -= 1;
+	br_lck->modified = True;
+	return True;
+}
+
+/****************************************************************************
  Unlock a range of bytes.
 ****************************************************************************/
 
@@ -832,19 +1013,17 @@
 	lock.start = start;
 	lock.size = size;
 	lock.fnum = br_lck->fsp->fnum;
-	lock.lock_type = READ_LOCK; /* We don't really care about this... */
+	lock.lock_type = UNLOCK_LOCK;
 	lock.lock_flav = lock_flav;
 
 	if (lock_flav == WINDOWS_LOCK) {
 		return brl_unlock_windows(br_lck,
 				&lock,
-				remove_pending_locks_only,
 				pre_unlock_fn,
 				pre_unlock_data);
 	} else {
 		return brl_unlock_posix(br_lck,
 				&lock,
-				remove_pending_locks_only,
 				pre_unlock_fn,
 				pre_unlock_data);
 	}

Modified: trunk/source/smbd/blocking.c
===================================================================
--- trunk/source/smbd/blocking.c	2006-03-03 03:57:34 UTC (rev 13805)
+++ trunk/source/smbd/blocking.c	2006-03-03 05:14:27 UTC (rev 13806)
@@ -565,15 +565,12 @@
 				DEBUG(10,("remove_pending_lock_requests_by_fid - removing request type %d for \
 file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
 
-				brl_unlock(br_lck,
+				brl_remove_pending_lock(br_lck,
 					blr->lock_pid,
 					procid_self(),
 					blr->offset,
 					blr->count,
-					blr->lock_flav,
-					True,
-					NULL,
-					NULL);
+					blr->lock_flav);
 				TALLOC_FREE(br_lck);
 
 			}
@@ -601,16 +598,12 @@
 				DEBUG(10,("remove_pending_lock_requests_by_mid - removing request type %d for \
 file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
 
-				brl_unlock(br_lck,
+				brl_remove_pending_lock(br_lck,
 					blr->lock_pid,
 					procid_self(),
 					blr->offset,
 					blr->count,
-					blr->lock_flav,
-					True,
-					NULL,
-					NULL);
-
+					blr->lock_flav);
 				TALLOC_FREE(br_lck);
 			}
 
@@ -706,16 +699,12 @@
 				DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n",
 					fsp->fnum, fsp->fsp_name ));
 
-				brl_unlock(br_lck,
+				brl_remove_pending_lock(br_lck,
 					blr->lock_pid,
 					procid_self(),
 					blr->offset,
 					blr->count,
-					blr->lock_flav,
-					True,
-					NULL,
-					NULL);
-
+					blr->lock_flav);
 				TALLOC_FREE(br_lck);
 			}
 
@@ -732,16 +721,12 @@
 			 */
 
 			if (br_lck) {
-				brl_unlock(br_lck,
+				brl_remove_pending_lock(br_lck,
 					blr->lock_pid,
 					procid_self(),
 					blr->offset,
 					blr->count,
-					WINDOWS_LOCK,
-					True,	
-					NULL,
-					NULL);
-
+					blr->lock_flav);
 				TALLOC_FREE(br_lck);
 			}
 
@@ -760,16 +745,12 @@
 			 */
 
 			if (br_lck) {
-				brl_unlock(br_lck,
+				brl_remove_pending_lock(br_lck,
 					blr->lock_pid,
 					procid_self(),
 					blr->offset,
 					blr->count,
-					blr->lock_flav,
-					True,
-					NULL,
-					NULL);
-
+					blr->lock_flav);
 				TALLOC_FREE(br_lck);
 			}
 
@@ -790,16 +771,12 @@
 			struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
 
 			if (br_lck) {
-				brl_unlock(br_lck,
+				brl_remove_pending_lock(br_lck,
 					blr->lock_pid,
 					procid_self(),
 					blr->offset,
 					blr->count,
-					blr->lock_flav,
-					True,
-					NULL,
-					NULL);
-
+					blr->lock_flav);
 				TALLOC_FREE(br_lck);
 			}
 



More information about the samba-cvs mailing list