Example #1
0
File: utils.c Project: acapola/lofe
void align_size_offset(size_t size, off_t offset, size_t *aligned_size, off_t *aligned_offset) {
	*aligned_offset = align_start(offset);
	off_t end_offset = offset + size;
	off_t aligned_end_offset = align_end(end_offset);
	*aligned_size = (size_t)(aligned_end_offset - *aligned_offset);
}
Example #2
0
/*
 * this is pretty ugly, but it is used to find a free spot in the
 * tree for a new iommu allocation.  We start from a given
 * hint and try to find an aligned range of a given size.
 *
 * Send the slot pointer, and we'll update it with the location
 * we found.
 *
 * This will return -EAGAIN if we found a good spot but someone
 * raced in and allocated it before we could.  This gives the
 * caller the chance to update their hint.
 *
 * This will return -EEXIST if we couldn't find anything at all
 *
 * returns 0 if all went well, or some other negative error
 * if things went badly.
 */
int skiplist_insert_hole(struct sl_list *list, unsigned long hint,
			 unsigned long limit,
			 unsigned long size, unsigned long align,
			 struct sl_slot *slot,
			 gfp_t gfp_mask)
{
	unsigned long last_end = 0;
	struct sl_node *p;
	struct sl_leaf *leaf;
	int i;
	int ret = -EEXIST;
	int preload_token;
	int pending_level;

	preload_token = skiplist_preload(list, gfp_mask);
	if (preload_token < 0) {
		return preload_token;
	}
	pending_level = pending_insert_level(preload_token);

	/* step one, lets find our hint */
	rcu_read_lock();
again:

	last_end = max(last_end, hint);
	last_end = align_start(last_end, align);
	slot->key = align_start(hint, align);
	slot->size = size;
	leaf = __skiplist_lookup_leaf(list, &p, hint, 1);
	if (!p)
		p = list->head;

	if (leaf && !verify_key_in_leaf(leaf, hint, size)) {
		goto again;
	}

again_lock:
	sl_lock_node(p);
	if (sl_node_dead(p)) {
		sl_unlock_node(p);
		goto again;
	}

	if (p != list->head) {
		leaf = sl_entry(p);
		/*
		 * the leaf we found was past the hint,
		 * go back one
		 */
		if (sl_max_key(leaf) > hint) {
			struct sl_node *locked = p;
			p = p->ptrs[0].prev;
			sl_unlock_node(locked);
			goto again_lock;
		}
		last_end = align_start(sl_max_key(sl_entry(p)), align);
	}

	/*
	 * now walk at level 0 and find a hole.  We could use lockless walks
	 * if we wanted to bang more on the insertion code, but this
	 * instead holds the lock on each node as we inspect it
	 *
	 * This is a little sloppy, insert will return -eexist if we get it
	 * wrong.
	 */
	while(1) {
		leaf = sl_next_leaf(list, p, 0);
		if (!leaf)
			break;

		/* p and leaf are locked */
		sl_lock_node(&leaf->node);
		if (last_end > sl_max_key(leaf))
			goto next;

		for (i = 0; i < leaf->nr; i++) {
			if (last_end > leaf->keys[i])
				continue;
			if (leaf->keys[i] - last_end >= size) {

				if (last_end + size > limit) {
					sl_unlock_node(&leaf->node);
					goto out_rcu;
				}

				sl_unlock_node(p);
				slot->key = last_end;
				slot->size = size;
				goto try_insert;
			}
			last_end = leaf->keys[i] + leaf->ptrs[i]->size;
			last_end = align_start(last_end, align);
			if (last_end + size > limit) {
				sl_unlock_node(&leaf->node);
				goto out_rcu;
			}
		}
next:
		sl_unlock_node(p);
		p = &leaf->node;
	}

	if (last_end + size <= limit) {
		sl_unlock_node(p);
		slot->key = last_end;
		slot->size = size;
		goto try_insert;
	}

out_rcu:
	/* we've failed */
	sl_unlock_node(p);
	rcu_read_unlock();
	preempt_enable();

	return ret;

try_insert:
	/*
	 * if the pending_level is zero or there is room in the
	 * leaf, we're ready to insert.  This is true most of the
	 * time, and we won't have to drop our lock and give others
	 * the chance to race in and steal our spot.
	 */
	if (leaf && (pending_level == 0 || leaf->nr < SKIP_KEYS_PER_NODE) &&
	    !sl_node_dead(&leaf->node) && (slot->key >= sl_min_key(leaf) &&
	    slot->key + slot->size <= sl_max_key(leaf))) {
		ret = find_or_add_key(list, slot->key, size, leaf, slot,
				      preload_token, NULL);
		rcu_read_unlock();
		goto out;
	}
	/*
	 * no such luck, drop our lock and try the insert the
	 * old fashioned way
	 */
	if (leaf)
		sl_unlock_node(&leaf->node);

	rcu_read_unlock();
	ret = skiplist_insert(list, slot, preload_token, NULL);

out:
	/*
	 * if we get an EEXIST here, it just means we lost the race.
	 * return eagain to the caller so they can update the hint
	 */
	if (ret == -EEXIST)
		ret = -EAGAIN;

	preempt_enable();
	return ret;
}