svn commit: samba r15401 - in trunk/source: include locking

jra at samba.org jra at samba.org
Wed May 3 02:13:52 GMT 2006


Author: jra
Date: 2006-05-03 02:13:51 +0000 (Wed, 03 May 2006)
New Revision: 15401

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

Log:
Fix for bug #3587. Dead entries can be left in the locking
db. Make this db self-cleaning on first read of entry after
open, and also on smbstatus -b call. Needs more testing when
I get back from Boston but passes valgrind at first look.
Jeremy.

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


Changeset:
Modified: trunk/source/include/smb.h
===================================================================
--- trunk/source/include/smb.h	2006-05-02 20:15:47 UTC (rev 15400)
+++ trunk/source/include/smb.h	2006-05-03 02:13:51 UTC (rev 15401)
@@ -444,6 +444,7 @@
 	BOOL is_directory;
 	BOOL is_stat;
 	BOOL aio_write_behind;
+	BOOL lockdb_clean;
 	char *fsp_name;
  	FAKE_FILE_HANDLE *fake_file_handle;
 } files_struct;

Modified: trunk/source/locking/brlock.c
===================================================================
--- trunk/source/locking/brlock.c	2006-05-02 20:15:47 UTC (rev 15400)
+++ trunk/source/locking/brlock.c	2006-05-03 02:13:51 UTC (rev 15401)
@@ -1269,13 +1269,62 @@
 {
 	struct lock_struct *locks;
 	struct lock_key *key;
-	int i;
+	unsigned int i;
+	unsigned int num_locks = 0;
+	unsigned int num_valid_entries = 0;
 
 	BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state;
 
 	locks = (struct lock_struct *)dbuf.dptr;
 	key = (struct lock_key *)kbuf.dptr;
 
+	num_locks = dbuf.dsize/sizeof(*locks);
+
+	/* Ensure the lock db is clean of invalid processes. */
+
+	for (i = 0; i < num_locks; i++) {
+		struct lock_struct *lock_data = &locks[i];
+		if (!process_exists(lock_data->context.pid)) {
+			/* This process no longer exists - mark this
+			   entry as invalid by zeroing it. */
+			ZERO_STRUCTP(lock_data);
+		} else {
+			num_valid_entries++;
+		}
+	}
+
+	if (num_valid_entries != num_locks) {
+		struct lock_struct *new_lock_data = NULL;
+
+		if (num_valid_entries) {
+			new_lock_data = SMB_MALLOC_ARRAY(struct lock_struct, num_valid_entries);
+			if (!new_lock_data) {
+				DEBUG(3, ("malloc fail\n"));
+				return 0;
+			}
+			num_valid_entries = 0;
+			for (i = 0; i < num_locks; i++) {
+				struct lock_struct *lock_data = &locks[i];
+				if (lock_data->context.smbpid &&
+						lock_data->context.tid) {
+					/* Valid (nonzero) entry - copy it. */
+					memcpy(&new_lock_data[num_valid_entries],
+						lock_data, sizeof(struct lock_struct));
+					num_valid_entries++;
+				}
+			}
+		}
+		SAFE_FREE(dbuf.dptr);
+		dbuf.dptr = (void *)new_lock_data;
+		dbuf.dsize = (num_valid_entries) * sizeof(*locks);
+
+		if (dbuf.dsize) {
+			tdb_store(ttdb, kbuf, dbuf, TDB_REPLACE);
+		} else {
+			tdb_delete(ttdb, kbuf);
+		}
+	}
+
 	for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
 		traverse_callback(key->device,
 				  key->inode,
@@ -1375,6 +1424,58 @@
 	br_lck->lock_data = (void *)data.dptr;
 	br_lck->num_locks = data.dsize / sizeof(struct lock_struct);
 
+	if (!fsp->lockdb_clean) {
+
+		/* This is the first time we've accessed this. */
+		/* Go through and ensure all entries exist - remove any that don't. */
+		/* Makes the lockdb self cleaning at low cost. */
+		unsigned int num_valid_entries = 0;
+		unsigned int i;
+
+		for (i = 0; i < br_lck->num_locks; i++) {
+			struct lock_struct *lock_data = &((struct lock_struct *)br_lck->lock_data)[i];
+			if (!process_exists(lock_data->context.pid)) {
+				/* This process no longer exists - mark this
+				   entry as invalid by zeroing it. */
+				ZERO_STRUCTP(lock_data);
+			} else {
+				num_valid_entries++;
+			}
+		}
+
+		if (num_valid_entries != br_lck->num_locks) {
+			struct lock_struct *new_lock_data = NULL;
+
+			if (num_valid_entries) {
+				new_lock_data = SMB_MALLOC_ARRAY(struct lock_struct, num_valid_entries);
+				if (!new_lock_data) {
+					DEBUG(3, ("malloc fail\n"));
+					tdb_chainunlock(tdb, key);
+					SAFE_FREE(br_lck->lock_data);
+					SAFE_FREE(br_lck);
+					return NULL;
+				}
+				num_valid_entries = 0;
+				for (i = 0; i < br_lck->num_locks; i++) {
+					struct lock_struct *lock_data = &((struct lock_struct *)br_lck->lock_data)[i];
+					if (lock_data->context.smbpid &&
+							lock_data->context.tid) {
+						/* Valid (nonzero) entry - copy it. */
+						memcpy(&new_lock_data[num_valid_entries],
+							lock_data, sizeof(struct lock_struct));
+						num_valid_entries++;
+					}
+				}
+			}
+			SAFE_FREE(br_lck->lock_data);
+			br_lck->lock_data = (void *)new_lock_data;
+			br_lck->num_locks = num_valid_entries;
+		}
+
+		/* Mark the lockdb as "clean" as seen from this open file. */
+		fsp->lockdb_clean = True;
+	}
+
 	if (DEBUGLEVEL >= 10) {
 		unsigned int i;
 		struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;



More information about the samba-cvs mailing list