static int mem_config()

in drivers/mconsole_kern.c [289:380]


static int mem_config(char *str, char **error_out)
{
	unsigned long long diff;
	int err = -EINVAL, i, add;
	char *ret;

	if (str[0] != '=') {
		*error_out = "Expected '=' after 'mem'";
		goto out;
	}

	str++;
	if (str[0] == '-')
		add = 0;
	else if (str[0] == '+') {
		add = 1;
	}
	else {
		*error_out = "Expected increment to start with '-' or '+'";
		goto out;
	}

	str++;
	diff = memparse(str, &ret);
	if (*ret != '\0') {
		*error_out = "Failed to parse memory increment";
		goto out;
	}

	diff /= PAGE_SIZE;

	mutex_lock(&plug_mem_mutex);
	for (i = 0; i < diff; i++) {
		struct unplugged_pages *unplugged;
		void *addr;

		if (add) {
			if (list_empty(&unplugged_pages))
				break;

			unplugged = list_entry(unplugged_pages.next,
					       struct unplugged_pages, list);
			if (unplug_index > 0)
				addr = unplugged->pages[--unplug_index];
			else {
				list_del(&unplugged->list);
				addr = unplugged;
				unplug_index = UNPLUGGED_PER_PAGE;
			}

			free_page((unsigned long) addr);
			unplugged_pages_count--;
		}
		else {
			struct page *page;

			page = alloc_page(GFP_ATOMIC);
			if (page == NULL)
				break;

			unplugged = page_address(page);
			if (unplug_index == UNPLUGGED_PER_PAGE) {
				list_add(&unplugged->list, &unplugged_pages);
				unplug_index = 0;
			}
			else {
				struct list_head *entry = unplugged_pages.next;
				addr = unplugged;

				unplugged = list_entry(entry,
						       struct unplugged_pages,
						       list);
				err = os_drop_memory(addr, PAGE_SIZE);
				if (err) {
					printk(KERN_ERR "Failed to release "
					       "memory - errno = %d\n", err);
					*error_out = "Failed to release memory";
					goto out_unlock;
				}
				unplugged->pages[unplug_index++] = addr;
			}

			unplugged_pages_count++;
		}
	}

	err = 0;
out_unlock:
	mutex_unlock(&plug_mem_mutex);
out:
	return err;
}