void badrange_forget()

in badrange.c [101:162]


void badrange_forget(struct badrange *badrange, phys_addr_t start,
		unsigned int len)
{
	struct list_head *badrange_list = &badrange->list;
	u64 clr_end = start + len - 1;
	struct badrange_entry *bre, *next;

	spin_lock(&badrange->lock);

	/*
	 * [start, clr_end] is the badrange interval being cleared.
	 * [bre->start, bre_end] is the badrange_list entry we're comparing
	 * the above interval against. The badrange list entry may need
	 * to be modified (update either start or length), deleted, or
	 * split into two based on the overlap characteristics
	 */

	list_for_each_entry_safe(bre, next, badrange_list, list) {
		u64 bre_end = bre->start + bre->length - 1;

		/* Skip intervals with no intersection */
		if (bre_end < start)
			continue;
		if (bre->start >  clr_end)
			continue;
		/* Delete completely overlapped badrange entries */
		if ((bre->start >= start) && (bre_end <= clr_end)) {
			list_del(&bre->list);
			kfree(bre);
			continue;
		}
		/* Adjust start point of partially cleared entries */
		if ((start <= bre->start) && (clr_end > bre->start)) {
			bre->length -= clr_end - bre->start + 1;
			bre->start = clr_end + 1;
			continue;
		}
		/* Adjust bre->length for partial clearing at the tail end */
		if ((bre->start < start) && (bre_end <= clr_end)) {
			/* bre->start remains the same */
			bre->length = start - bre->start;
			continue;
		}
		/*
		 * If clearing in the middle of an entry, we split it into
		 * two by modifying the current entry to represent one half of
		 * the split, and adding a new entry for the second half.
		 */
		if ((bre->start < start) && (bre_end > clr_end)) {
			u64 new_start = clr_end + 1;
			u64 new_len = bre_end - new_start + 1;

			/* Add new entry covering the right half */
			alloc_and_append_badrange_entry(badrange, new_start,
					new_len, GFP_NOWAIT);
			/* Adjust this entry to cover the left half */
			bre->length = start - bre->start;
			continue;
		}
	}
	spin_unlock(&badrange->lock);
}