Explorar o código

defect 974
checkpoint service segfaults during synchronization because iteration item
is deleted and iteration continues in unsafe fashion.


git-svn-id: http://svn.fedorahosted.org/svn/corosync/trunk@850 fd59a12c-fef9-0310-b244-a6a79926bd2f

Steven Dake %!s(int64=20) %!d(string=hai) anos
pai
achega
ff8e494243
Modificáronse 1 ficheiros con 50 adicións e 22 borrados
  1. 50 22
      exec/ckpt.c

+ 50 - 22
exec/ckpt.c

@@ -165,6 +165,7 @@ void checkpoint_release (struct saCkptCheckpoint *checkpoint);
 void timer_function_retention (void *data);
 void timer_function_retention (void *data);
 unsigned int abstime_to_msec (SaTimeT time);
 unsigned int abstime_to_msec (SaTimeT time);
 void timer_function_section_expire (void *data);
 void timer_function_section_expire (void *data);
+void clean_checkpoint_list(struct list_head* head);
 
 
 static int recovery_checkpoint_open(SaNameT *checkpointName,
 static int recovery_checkpoint_open(SaNameT *checkpointName,
 									SaCkptCheckpointCreationAttributesT *ckptAttributes,
 									SaCkptCheckpointCreationAttributesT *ckptAttributes,
@@ -1027,10 +1028,13 @@ static void ckpt_recovery_process_members_exit(struct in_addr *left_list,
 
 
 			checkpoint = list_entry (checkpoint_list,
 			checkpoint = list_entry (checkpoint_list,
 				struct saCkptCheckpoint, list);			
 				struct saCkptCheckpoint, list);			
+			assert (checkpoint > 0);
 			index = processor_index_find(member, checkpoint->ckpt_refcount);			
 			index = processor_index_find(member, checkpoint->ckpt_refcount);			
-			if (index == -1) {
+			if (index < 0) {
+				checkpoint_list = checkpoint_list->next;
 				continue;
 				continue;
 			}		
 			}		
+			assert ( index < PROCESSOR_COUNT_MAX);
 			/*
 			/*
 			 * Decrement
 			 * Decrement
 			 * 
 			 * 
@@ -1044,35 +1048,59 @@ static void ckpt_recovery_process_members_exit(struct in_addr *left_list,
 				log_printf (LOG_LEVEL_ERROR, "ckpt_recovery_process_members_exit: refCount for %s = %d.\n",
 				log_printf (LOG_LEVEL_ERROR, "ckpt_recovery_process_members_exit: refCount for %s = %d.\n",
 												&checkpoint->name.value,checkpoint->referenceCount);			
 												&checkpoint->name.value,checkpoint->referenceCount);			
 				assert(0);
 				assert(0);
-			}						
+			}		
 			checkpoint->ckpt_refcount[index].count = 0;
 			checkpoint->ckpt_refcount[index].count = 0;
 			memset((char*)&checkpoint->ckpt_refcount[index].addr, 0, sizeof(struct in_addr));			
 			memset((char*)&checkpoint->ckpt_refcount[index].addr, 0, sizeof(struct in_addr));			
-			
-			/*
-			 * If checkpoint has been unlinked and this is the last reference, delete it
-			 */
-			if (checkpoint->unlinked && checkpoint->referenceCount == 0) {
-				log_printf (LOG_LEVEL_DEBUG, "ckpt_recovery_process_members_exit: Unlinking checkpoint %s.\n",
-												&checkpoint->name.value);		
-				checkpoint_release (checkpoint);
-			} else
-			if ((checkpoint->expired == 0) && (checkpoint->referenceCount == 0)) {
-				log_printf (LOG_LEVEL_DEBUG, "ckpt_recovery_process_members_exit: Starting timer to release checkpoint %s.\n",
-												&checkpoint->name.value);
-				poll_timer_delete (aisexec_poll_handle, checkpoint->retention_timer);
-
-				poll_timer_add (aisexec_poll_handle,
-					checkpoint->checkpointCreationAttributes.retentionDuration / 1000000,
-					checkpoint,
-					timer_function_retention,
-					&checkpoint->retention_timer);
-			}
 		}
 		}
 		member++;
 		member++;
 	}
 	}
+
+	clean_checkpoint_list(&checkpoint_list_head);
+	
 	return;
 	return;
 }
 }
 
 
+void clean_checkpoint_list(struct list_head *head) 
+{
+	struct list_head *checkpoint_list;
+	struct saCkptCheckpoint *checkpoint;
+
+	if (list_empty(head)) {
+		log_printf (LOG_LEVEL_NOTICE, "clean_checkpoint_list: List is empty \n");
+		return;
+	}
+
+	checkpoint_list = head->next;
+        while (checkpoint_list != head) {
+		checkpoint = list_entry (checkpoint_list,
+                                struct saCkptCheckpoint, list);
+                assert (checkpoint > 0);
+
+		/*
+		* If checkpoint has been unlinked and this is the last reference, delete it
+		*/
+		 if (checkpoint->unlinked && checkpoint->referenceCount == 0) {
+			log_printf (LOG_LEVEL_NOTICE,"clean_checkpoint_list: deallocating checkpoint %s.\n",
+                                                                                                &checkpoint->name.value);
+			checkpoint_list = checkpoint_list->next;
+			checkpoint_release (checkpoint);
+			continue;
+			
+		} 
+		else if ((checkpoint->expired == 0) && (checkpoint->referenceCount == 0)) {
+			log_printf (LOG_LEVEL_NOTICE, "clean_checkpoint_list: Starting timer to release checkpoint %s.\n",
+				&checkpoint->name.value);
+			poll_timer_delete (aisexec_poll_handle, checkpoint->retention_timer);
+			poll_timer_add (aisexec_poll_handle,
+				checkpoint->checkpointCreationAttributes.retentionDuration / 1000000,
+				checkpoint,
+				timer_function_retention,
+				&checkpoint->retention_timer);
+		}
+		checkpoint_list = checkpoint_list->next;
+        }
+}
+
 static int ckpt_confchg_fn (
 static int ckpt_confchg_fn (
 	enum totem_configuration_type configuration_type,
 	enum totem_configuration_type configuration_type,
 	struct in_addr *member_list, int member_list_entries,
 	struct in_addr *member_list, int member_list_entries,