aboutsummaryrefslogblamecommitdiffstats
path: root/litmus/reservations/alloc.c
blob: 1f93f223f504c3e624f4d2221ff55cec86020c7e (plain) (tree)














































































































































                                                                                    
#include <linux/slab.h>
#include <asm/uaccess.h>

#include <litmus/rt_param.h>

#include <litmus/reservations/alloc.h>
#include <litmus/reservations/polling.h>
#include <litmus/reservations/table-driven.h>


long alloc_polling_reservation(
	int res_type,
	struct reservation_config *config,
	struct reservation **_res)
{
	struct polling_reservation *pres;
	int use_edf  = config->priority == LITMUS_NO_PRIORITY;
	int periodic =  res_type == PERIODIC_POLLING;

	if (config->polling_params.budget >
	    config->polling_params.period) {
		printk(KERN_ERR "invalid polling reservation (%u): "
		       "budget > period\n", config->id);
		return -EINVAL;
	}
	if (config->polling_params.budget >
	    config->polling_params.relative_deadline
	    && config->polling_params.relative_deadline) {
		printk(KERN_ERR "invalid polling reservation (%u): "
		       "budget > deadline\n", config->id);
		return -EINVAL;
	}
	if (config->polling_params.offset >
	    config->polling_params.period) {
		printk(KERN_ERR "invalid polling reservation (%u): "
		       "offset > period\n", config->id);
		return -EINVAL;
	}

	/* XXX: would be nice to use a core-local allocation. */
	pres = kzalloc(sizeof(*pres), GFP_KERNEL);
	if (!pres)
		return -ENOMEM;

	polling_reservation_init(pres, use_edf, periodic,
		config->polling_params.budget,
		config->polling_params.period,
		config->polling_params.relative_deadline,
		config->polling_params.offset);
	pres->res.id = config->id;
	if (!use_edf)
		pres->res.priority = config->priority;

	*_res = &pres->res;
	return 0;
}


#define MAX_INTERVALS 1024

long alloc_table_driven_reservation(
	struct reservation_config *config,
	struct reservation **_res)
{
	struct table_driven_reservation *td_res = NULL;
	struct lt_interval *slots = NULL;
	size_t slots_size;
	unsigned int i, num_slots;
	long err = -EINVAL;
	void *mem;

	if (!config->table_driven_params.num_intervals) {
		printk(KERN_ERR "invalid table-driven reservation (%u): "
		       "no intervals\n", config->id);
		return -EINVAL;
	}

	if (config->table_driven_params.num_intervals > MAX_INTERVALS) {
		printk(KERN_ERR "invalid table-driven reservation (%u): "
		       "too many intervals (max: %d)\n", config->id, MAX_INTERVALS);
		return -EINVAL;
	}

	num_slots = config->table_driven_params.num_intervals;
	slots_size = sizeof(slots[0]) * num_slots;

	mem = kzalloc(sizeof(*td_res) + slots_size, GFP_KERNEL);
	if (!mem) {
		return -ENOMEM;
	} else {
		slots  = mem + sizeof(*td_res);
		td_res = mem;
		err = copy_from_user(slots,
			config->table_driven_params.intervals, slots_size);
	}

	if (!err) {
		/* sanity checks */
		for (i = 0; !err && i < num_slots; i++)
			if (slots[i].end <= slots[i].start) {
				printk(KERN_ERR
				       "invalid table-driven reservation (%u): "
				       "invalid interval %u => [%llu, %llu]\n",
				       config->id, i,
				       slots[i].start, slots[i].end);
				err = -EINVAL;
			}

		for (i = 0; !err && i + 1 < num_slots; i++)
			if (slots[i + 1].start <= slots[i].end) {
				printk(KERN_ERR
				       "invalid table-driven reservation (%u): "
				       "overlapping intervals %u, %u\n",
				       config->id, i, i + 1);
				err = -EINVAL;
			}

		if (slots[num_slots - 1].end >
			config->table_driven_params.major_cycle_length) {
			printk(KERN_ERR
				"invalid table-driven reservation (%u): last "
				"interval ends past major cycle %llu > %llu\n",
				config->id,
				slots[num_slots - 1].end,
				config->table_driven_params.major_cycle_length);
			err = -EINVAL;
		}
	}

	if (err) {
		kfree(td_res);
	} else {
		table_driven_reservation_init(td_res,
			config->table_driven_params.major_cycle_length,
			slots, num_slots);
		td_res->res.id = config->id;
		td_res->res.priority = config->priority;
		*_res = &td_res->res;
	}

	return err;
}