Blame hugeadm.c

Packit Service b439df
/***************************************************************************
Packit Service b439df
 *   User front end for using huge pages Copyright (C) 2008, IBM           *
Packit Service b439df
 *                                                                         *
Packit Service b439df
 *   This program is free software; you can redistribute it and/or modify  *
Packit Service b439df
 *   it under the terms of the Lesser GNU General Public License as        *
Packit Service b439df
 *   published by the Free Software Foundation; either version 2.1 of the  *
Packit Service b439df
 *   License, or at your option) any later version.                        *
Packit Service b439df
 *                                                                         *
Packit Service b439df
 *   This program is distributed in the hope that it will be useful,       *
Packit Service b439df
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
Packit Service b439df
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
Packit Service b439df
 *   GNU Lesser General Public License for more details.                   *
Packit Service b439df
 *                                                                         *
Packit Service b439df
 *   You should have received a copy of the Lesser GNU General Public      *
Packit Service b439df
 *   License along with this program; if not, write to the                 *
Packit Service b439df
 *   Free Software Foundation, Inc.,                                       *
Packit Service b439df
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
Packit Service b439df
 ***************************************************************************/
Packit Service b439df
Packit Service b439df
/*
Packit Service b439df
 * hugeadm is designed to make an administrators life simpler, to automate
Packit Service b439df
 * and simplify basic system configuration as it relates to hugepages.  It
Packit Service b439df
 * is designed to help with pool and mount configuration.
Packit Service b439df
 */
Packit Service b439df
Packit Service b439df
#include <stdlib.h>
Packit Service b439df
#include <stdio.h>
Packit Service b439df
#include <errno.h>
Packit Service b439df
#include <string.h>
Packit Service b439df
#include <limits.h>
Packit Service b439df
#include <mntent.h>
Packit Service b439df
#include <unistd.h>
Packit Service b439df
#include <grp.h>
Packit Service b439df
#include <pwd.h>
Packit Service b439df
#include <fcntl.h>
Packit Service b439df
Packit Service b439df
#include <sys/stat.h>
Packit Service b439df
#include <sys/types.h>
Packit Service b439df
#include <sys/mount.h>
Packit Service b439df
#include <sys/swap.h>
Packit Service b439df
#include <sys/wait.h>
Packit Service b439df
Packit Service b439df
#define _GNU_SOURCE /* for getopt_long */
Packit Service b439df
#include <unistd.h>
Packit Service b439df
#include <getopt.h>
Packit Service b439df
Packit Service b439df
#define KB (1024)
Packit Service b439df
#define MB (1024*KB)
Packit Service b439df
#define GB (1024*MB)
Packit Service b439df
Packit Service b439df
#define REPORT_UTIL "hugeadm"
Packit Service b439df
#define REPORT(level, prefix, format, ...)                                    \
Packit Service b439df
	do {                                                                  \
Packit Service b439df
		if (verbose_level >= level)                                   \
Packit Service b439df
			fprintf(stderr, "hugeadm:" prefix ": " format,       \
Packit Service b439df
				##__VA_ARGS__);                               \
Packit Service b439df
	} while (0);
Packit Service b439df
Packit Service b439df
#include "libhugetlbfs_internal.h"
Packit Service b439df
#include "hugetlbfs.h"
Packit Service b439df
Packit Service b439df
extern int optind;
Packit Service b439df
extern char *optarg;
Packit Service b439df
Packit Service b439df
#define OPTION(opts, text)	fprintf(stderr, " %-25s  %s\n", opts, text)
Packit Service b439df
#define CONT(text) 		fprintf(stderr, " %-25s  %s\n", "", text)
Packit Service b439df
Packit Service b439df
#define MOUNT_DIR "/var/lib/hugetlbfs"
Packit Service b439df
#define OPT_MAX 4096
Packit Service b439df
Packit Service b439df
#define PROCMOUNTS "/proc/mounts"
Packit Service b439df
#define PROCHUGEPAGES_MOVABLE "/proc/sys/vm/hugepages_treat_as_movable"
Packit Service b439df
#define PROCMINFREEKBYTES "/proc/sys/vm/min_free_kbytes"
Packit Service b439df
#define PROCSHMMAX "/proc/sys/kernel/shmmax"
Packit Service b439df
#define PROCHUGETLBGROUP "/proc/sys/vm/hugetlb_shm_group"
Packit Service b439df
#define PROCZONEINFO "/proc/zoneinfo"
Packit Service b439df
#define FS_NAME "hugetlbfs"
Packit Service b439df
#define MIN_COL 20
Packit Service b439df
#define MAX_SIZE_MNTENT (64 + PATH_MAX + 32 + 128 + 2 * sizeof(int))
Packit Service b439df
#define FORMAT_LEN 20
Packit Service b439df
Packit Service b439df
#define MEM_TOTAL "MemTotal:"
Packit Service b439df
#define SWAP_FREE "SwapFree:"
Packit Service b439df
#define SWAP_TOTAL "SwapTotal:"
Packit Service b439df
Packit Service b439df
#define ALWAYS		  "always"
Packit Service b439df
#define MADVISE		  "madvise"
Packit Service b439df
#define NEVER		  "never"
Packit Service b439df
#define TRANS_ENABLE	  "/sys/kernel/mm/transparent_hugepage/enabled"
Packit Service b439df
#define KHUGE_SCAN_PAGES  "/sys/kernel/mm/transparent_hugepage/khugepaged/pages_to_scan"
Packit Service b439df
#define KHUGE_SCAN_SLEEP  "/sys/kernel/mm/transparent_hugepage/khugepaged/scan_sleep_millisecs"
Packit Service b439df
#define KHUGE_ALLOC_SLEEP "/sys/kernel/mm/transparent_hugepage/khugepaged/alloc_sleep_millisecs"
Packit Service b439df
Packit Service b439df
void print_usage()
Packit Service b439df
{
Packit Service b439df
	fprintf(stderr, "hugeadm [options]\n");
Packit Service b439df
	fprintf(stderr, "options:\n");
Packit Service b439df
Packit Service b439df
	OPTION("--list-all-mounts", "List all current hugetlbfs mount points");
Packit Service b439df
	OPTION("--pool-list", "List all pools");
Packit Service b439df
	OPTION("--hard", "specified with --pool-pages-min to make");
Packit Service b439df
	CONT("multiple attempts at adjusting the pool size to the");
Packit Service b439df
	CONT("specified count on failure");
Packit Service b439df
	OPTION("--pool-pages-min <size|DEFAULT>:[+|-]<pagecount|memsize<G|M|K>>", "");
Packit Service b439df
	CONT("Adjust pool 'size' lower bound");
Packit Service b439df
	OPTION("--obey-mempolicy", "Obey the NUMA memory policy when");
Packit Service b439df
	CONT("adjusting the pool 'size' lower bound");
Packit Service b439df
	OPTION("--thp-always", "Enable transparent huge pages always");
Packit Service b439df
	OPTION("--thp-madvise", "Enable transparent huge pages with madvise");
Packit Service b439df
	OPTION("--thp-never", "Disable transparent huge pages");
Packit Service b439df
	OPTION("--thp-khugepaged-pages <pages to scan>", "Number of pages that khugepaged");
Packit Service b439df
	CONT("should scan on each pass");
Packit Service b439df
	OPTION("--thp-khugepaged-scan-sleep <milliseconds>", "Time in ms to sleep between");
Packit Service b439df
	CONT("khugepaged passes");
Packit Service 65d968
	OPTION("--thp-khugepaged-alloc-sleep <milliseconds>", "Time in ms for khugepaged");
Packit Service b439df
	CONT("to wait if there was a huge page allocation failure");
Packit Service b439df
	OPTION("--pool-pages-max <size|DEFAULT>:[+|-]<pagecount|memsize<G|M|K>>", "");
Packit Service b439df
	CONT("Adjust pool 'size' upper bound");
Packit Service b439df
	OPTION("--set-recommended-min_free_kbytes", "");
Packit Service b439df
	CONT("Sets min_free_kbytes to a recommended value to improve availability of");
Packit Service b439df
	CONT("huge pages at runtime");
Packit Service b439df
	OPTION("--set-recommended-shmmax", "Sets shmmax to a recommended value to");
Packit Service b439df
	CONT("maximise the size possible for shared memory pools");
Packit Service b439df
	OPTION("--set-shm-group <gid|groupname>", "Sets hugetlb_shm_group to the");
Packit Service b439df
	CONT("specified group, which has permission to use hugetlb shared memory pools");
Packit Service b439df
	OPTION("--add-temp-swap[=count]", "Specified with --pool-pages-min to create");
Packit Service b439df
	CONT("temporary swap space for the duration of the pool resize. Default swap");
Packit Service b439df
	CONT("size is 5 huge pages. Optional arg sets size to 'count' huge pages");
Packit Service b439df
	OPTION("--add-ramdisk-swap", "Specified with --pool-pages-min to create");
Packit Service b439df
	CONT("swap space on ramdisks. By default, swap is removed after the resize.");
Packit Service b439df
	OPTION("--persist", "Specified with --add-temp-swap or --add-ramdisk-swap");
Packit Service b439df
	CONT("options to make swap space persist after the resize.");
Packit Service b439df
	OPTION("--enable-zone-movable", "Use ZONE_MOVABLE for huge pages");
Packit Service b439df
	OPTION("--disable-zone-movable", "Do not use ZONE_MOVABLE for huge pages");
Packit Service b439df
	OPTION("--create-mounts", "Creates a mount point for each available");
Packit Service b439df
	CONT("huge page size on this system under /var/lib/hugetlbfs");
Packit Service b439df
	OPTION("--create-user-mounts <user>", "");
Packit Service b439df
	CONT("Creates a mount point for each available huge");
Packit Service b439df
	CONT("page size under /var/lib/hugetlbfs/<user>");
Packit Service b439df
	CONT("usable by user <user>");
Packit Service b439df
	OPTION("--create-group-mounts <group>", "");
Packit Service b439df
	CONT("Creates a mount point for each available huge");
Packit Service b439df
	CONT("page size under /var/lib/hugetlbfs/<group>");
Packit Service b439df
	CONT("usable by group <group>");
Packit Service b439df
	OPTION("--create-global-mounts", "");
Packit Service b439df
	CONT("Creates a mount point for each available huge");
Packit Service b439df
	CONT("page size under /var/lib/hugetlbfs/global");
Packit Service b439df
	CONT("usable by anyone");
Packit Service b439df
Packit Service b439df
	OPTION("--max-size <size<G|M|K>>", "Limit the filesystem size of a new mount point");
Packit Service b439df
	OPTION("--max-inodes <number>", "Limit the number of inodes on a new mount point");
Packit Service b439df
Packit Service b439df
	OPTION("--page-sizes", "Display page sizes that a configured pool");
Packit Service b439df
	OPTION("--page-sizes-all",
Packit Service b439df
			"Display page sizes support by the hardware");
Packit Service b439df
	OPTION("--dry-run", "Print the equivalent shell commands for what");
Packit Service b439df
	CONT("the specified options would have done without");
Packit Service b439df
	CONT("taking any action");
Packit Service b439df
Packit Service b439df
	OPTION("--explain", "Gives a overview of the status of the system");
Packit Service b439df
	CONT("with respect to huge page availability");
Packit Service b439df
Packit Service b439df
	OPTION("--verbose <level>, -v", "Increases/sets tracing levels");
Packit Service b439df
	OPTION("--help, -h", "Prints this message");
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
int opt_dry_run = 0;
Packit Service b439df
int opt_hard = 0;
Packit Service b439df
int opt_movable = -1;
Packit Service b439df
int opt_set_recommended_minfreekbytes = 0;
Packit Service b439df
int opt_set_recommended_shmmax = 0;
Packit Service b439df
int opt_set_hugetlb_shm_group = 0;
Packit Service b439df
int opt_temp_swap = 0;
Packit Service b439df
int opt_ramdisk_swap = 0;
Packit Service b439df
int opt_swap_persist = 0;
Packit Service b439df
int opt_obey_mempolicy = 0;
Packit Service b439df
unsigned long opt_limit_mount_size = 0;
Packit Service b439df
int opt_limit_mount_inodes = 0;
Packit Service b439df
int verbose_level = VERBOSITY_DEFAULT;
Packit Service b439df
char ramdisk_list[PATH_MAX] = "";
Packit Service b439df
Packit Service b439df
void setup_environment(char *var, char *val)
Packit Service b439df
{
Packit Service b439df
	if (opt_dry_run) {
Packit Service b439df
		printf("%s='%s'\n", var, val);
Packit Service b439df
		return;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	setenv(var, val, 1);
Packit Service b439df
	DEBUG("%s='%s'\n", var, val);
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
/* Enable/disable allocation of hugepages from ZONE_MOVABLE */
Packit Service b439df
void setup_zone_movable(int able)
Packit Service b439df
{
Packit Service b439df
	if (opt_dry_run) {
Packit Service b439df
		printf("echo %d > %s\n", able, PROCHUGEPAGES_MOVABLE);
Packit Service b439df
		return;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	DEBUG("Setting %s to %d\n", PROCHUGEPAGES_MOVABLE, able);
Packit Service b439df
Packit Service b439df
	/* libhugetlbfs reports any error that occurs */
Packit Service b439df
	file_write_ulong(PROCHUGEPAGES_MOVABLE, (unsigned long)able);
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void verbose_init(void)
Packit Service b439df
{
Packit Service b439df
	char *env;
Packit Service b439df
Packit Service b439df
	env = getenv("HUGETLB_VERBOSE");
Packit Service b439df
	if (env)
Packit Service b439df
		verbose_level = atoi(env);
Packit Service b439df
	env = getenv("HUGETLB_DEBUG");
Packit Service b439df
	if (env)
Packit Service b439df
		verbose_level = VERBOSITY_MAX;
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void verbose(char *which)
Packit Service b439df
{
Packit Service b439df
	int new_level;
Packit Service b439df
Packit Service b439df
	if (which) {
Packit Service b439df
		new_level = atoi(which);
Packit Service b439df
		if (new_level < 0 || new_level > 99) {
Packit Service b439df
			ERROR("%d: verbosity out of range 0-99\n",
Packit Service b439df
				new_level);
Packit Service b439df
			exit(EXIT_FAILURE);
Packit Service b439df
		}
Packit Service b439df
	} else {
Packit Service b439df
		new_level = verbose_level + 1;
Packit Service b439df
		if (new_level == 100) {
Packit Service b439df
			WARNING("verbosity limited to 99\n");
Packit Service b439df
			new_level--;
Packit Service b439df
		}
Packit Service b439df
	}
Packit Service b439df
	verbose_level = new_level;
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void verbose_expose(void)
Packit Service b439df
{
Packit Service b439df
	char level[3];
Packit Service b439df
Packit Service b439df
	if (verbose_level == 99) {
Packit Service b439df
		setup_environment("HUGETLB_DEBUG", "yes");
Packit Service b439df
	}
Packit Service b439df
	snprintf(level, sizeof(level), "%d", verbose_level);
Packit Service b439df
	setup_environment("HUGETLB_VERBOSE", level);
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
/*
Packit Service b439df
 * getopts return values for options which are long only.
Packit Service b439df
 */
Packit Service b439df
#define LONG_POOL		('p' << 8)
Packit Service b439df
#define LONG_POOL_LIST		(LONG_POOL|'l')
Packit Service b439df
#define LONG_POOL_MIN_ADJ	(LONG_POOL|'m')
Packit Service b439df
#define LONG_POOL_MAX_ADJ	(LONG_POOL|'M')
Packit Service b439df
#define LONG_POOL_MEMPOL	(LONG_POOL|'p')
Packit Service b439df
Packit Service b439df
#define LONG_SET_RECOMMENDED_MINFREEKBYTES	('k' << 8)
Packit Service b439df
#define LONG_SET_RECOMMENDED_SHMMAX		('x' << 8)
Packit Service b439df
#define LONG_SET_HUGETLB_SHM_GROUP		('R' << 8)
Packit Service b439df
Packit Service b439df
#define LONG_MOVABLE		('z' << 8)
Packit Service b439df
#define LONG_MOVABLE_ENABLE	(LONG_MOVABLE|'e')
Packit Service b439df
#define LONG_MOVABLE_DISABLE	(LONG_MOVABLE|'d')
Packit Service b439df
Packit Service b439df
#define LONG_HARD		('h' << 8)
Packit Service b439df
#define LONG_SWAP		('s' << 8)
Packit Service b439df
#define LONG_SWAP_DISK		(LONG_SWAP|'d')
Packit Service b439df
#define LONG_SWAP_RAMDISK	(LONG_SWAP|'r')
Packit Service b439df
#define LONG_SWAP_PERSIST	(LONG_SWAP|'p')
Packit Service b439df
Packit Service b439df
#define LONG_PAGE	('P' << 8)
Packit Service b439df
#define LONG_PAGE_SIZES	(LONG_PAGE|'s')
Packit Service b439df
#define LONG_PAGE_AVAIL	(LONG_PAGE|'a')
Packit Service b439df
Packit Service b439df
#define LONG_MOUNTS			('m' << 8)
Packit Service b439df
#define LONG_CREATE_MOUNTS		(LONG_MOUNTS|'C')
Packit Service b439df
#define LONG_CREATE_USER_MOUNTS		(LONG_MOUNTS|'U')
Packit Service b439df
#define LONG_CREATE_GROUP_MOUNTS	(LONG_MOUNTS|'g')
Packit Service b439df
#define LONG_CREATE_GLOBAL_MOUNTS	(LONG_MOUNTS|'G')
Packit Service b439df
#define LONG_LIST_ALL_MOUNTS		(LONG_MOUNTS|'A')
Packit Service b439df
Packit Service b439df
#define LONG_LIMITS			('l' << 8)
Packit Service b439df
#define LONG_LIMIT_SIZE			(LONG_LIMITS|'S')
Packit Service b439df
#define LONG_LIMIT_INODES		(LONG_LIMITS|'I')
Packit Service b439df
Packit Service b439df
#define LONG_EXPLAIN	('e' << 8)
Packit Service b439df
Packit Service b439df
#define LONG_TRANS			('t' << 8)
Packit Service b439df
#define LONG_TRANS_ALWAYS		(LONG_TRANS|'a')
Packit Service b439df
#define LONG_TRANS_MADVISE		(LONG_TRANS|'m')
Packit Service b439df
#define LONG_TRANS_NEVER		(LONG_TRANS|'n')
Packit Service b439df
Packit Service b439df
#define LONG_KHUGE			('K' << 8)
Packit Service b439df
#define LONG_KHUGE_PAGES		(LONG_KHUGE|'p')
Packit Service b439df
#define LONG_KHUGE_SCAN			(LONG_KHUGE|'s')
Packit Service b439df
#define LONG_KHUGE_ALLOC		(LONG_KHUGE|'a')
Packit Service b439df
Packit Service b439df
#define MAX_POOLS	32
Packit Service b439df
Packit Service b439df
static int cmpsizes(const void *p1, const void *p2)
Packit Service b439df
{
Packit Service b439df
	return ((struct hpage_pool *)p1)->pagesize >
Packit Service b439df
			((struct hpage_pool *)p2)->pagesize;
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void pool_list(void)
Packit Service b439df
{
Packit Service b439df
	struct hpage_pool pools[MAX_POOLS];
Packit Service b439df
	int pos;
Packit Service b439df
	int cnt;
Packit Service b439df
Packit Service b439df
	cnt = hpool_sizes(pools, MAX_POOLS);
Packit Service b439df
	if (cnt < 0) {
Packit Service b439df
		ERROR("unable to obtain pools list");
Packit Service b439df
		exit(EXIT_FAILURE);
Packit Service b439df
	}
Packit Service b439df
	qsort(pools, cnt, sizeof(pools[0]), cmpsizes);
Packit Service b439df
Packit Service b439df
	printf("%10s %8s %8s %8s %8s\n",
Packit Service b439df
		"Size", "Minimum", "Current", "Maximum", "Default");
Packit Service b439df
	for (pos = 0; cnt--; pos++) {
Packit Service b439df
		printf("%10ld %8ld %8ld %8ld %8s\n", pools[pos].pagesize,
Packit Service b439df
			pools[pos].minimum, pools[pos].size,
Packit Service b439df
			pools[pos].maximum, (pools[pos].is_default) ? "*" : "");
Packit Service b439df
	}
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
struct mount_list
Packit Service b439df
{
Packit Service b439df
	struct mntent entry;
Packit Service b439df
	char data[MAX_SIZE_MNTENT];
Packit Service b439df
	struct mount_list *next;
Packit Service b439df
};
Packit Service b439df
Packit Service b439df
void print_mounts(struct mount_list *current, int longest)
Packit Service b439df
{
Packit Service b439df
	char format_str[FORMAT_LEN];
Packit Service b439df
Packit Service b439df
	snprintf(format_str, FORMAT_LEN, "%%-%ds %%s\n", longest);
Packit Service b439df
	printf(format_str, "Mount Point", "Options");
Packit Service b439df
	while (current) {
Packit Service b439df
		printf(format_str, current->entry.mnt_dir,
Packit Service b439df
				   current->entry.mnt_opts);
Packit Service b439df
		current = current->next;
Packit Service b439df
	}
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
/*
Packit Service b439df
 * collect_active_mounts returns a list of active hugetlbfs
Packit Service b439df
 * mount points, and, if longest is not NULL, the number of
Packit Service b439df
 * characters in the longest mount point to ease output
Packit Service b439df
 * formatting.  Caller is expected to free the list of mounts.
Packit Service b439df
 */
Packit Service b439df
struct mount_list *collect_active_mounts(int *longest)
Packit Service b439df
{
Packit Service b439df
	FILE *mounts;
Packit Service b439df
	struct mount_list *list, *current, *previous = NULL;
Packit Service b439df
	int length;
Packit Service b439df
Packit Service b439df
	/* First try /proc/mounts, then /etc/mtab */
Packit Service b439df
	mounts = setmntent(PROCMOUNTS, "r");
Packit Service b439df
	if (!mounts) {
Packit Service b439df
		mounts = setmntent(MOUNTED, "r");
Packit Service b439df
		if (!mounts) {
Packit Service b439df
			ERROR("unable to open %s or %s for reading",
Packit Service b439df
				PROCMOUNTS, MOUNTED);
Packit Service b439df
			exit(EXIT_FAILURE);
Packit Service b439df
		}
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	list = malloc(sizeof(struct mount_list));
Packit Service b439df
	if (!list) {
Packit Service b439df
		ERROR("out of memory");
Packit Service b439df
		exit(EXIT_FAILURE);
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	list->next = NULL;
Packit Service b439df
	current = list;
Packit Service b439df
	while (getmntent_r(mounts, &(current->entry), current->data, MAX_SIZE_MNTENT)) {
Packit Service b439df
		if (strcasecmp(current->entry.mnt_type, FS_NAME) == 0) {
Packit Service b439df
			length = strlen(current->entry.mnt_dir);
Packit Service b439df
			if (longest && length > *longest)
Packit Service b439df
				*longest = length;
Packit Service b439df
Packit Service b439df
			current->next = malloc(sizeof(struct mount_list));
Packit Service b439df
			if (!current->next) {
Packit Service b439df
				ERROR("out of memory");
Packit Service b439df
				exit(EXIT_FAILURE);
Packit Service b439df
			}
Packit Service b439df
			previous = current;
Packit Service b439df
			current = current->next;
Packit Service b439df
			current->next = NULL;
Packit Service b439df
		}
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	endmntent(mounts);
Packit Service b439df
Packit Service b439df
	if (previous) {
Packit Service b439df
		free(previous->next);
Packit Service b439df
		previous->next = NULL;
Packit Service b439df
		return list;
Packit Service b439df
	}
Packit Service b439df
	return NULL;
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void mounts_list_all(void)
Packit Service b439df
{
Packit Service b439df
	struct mount_list *list, *previous;
Packit Service b439df
	int longest = MIN_COL;
Packit Service b439df
Packit Service b439df
	list = collect_active_mounts(&longest);
Packit Service b439df
Packit Service b439df
	if (!list) {
Packit Service b439df
		ERROR("No hugetlbfs mount points found\n");
Packit Service b439df
		return;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	print_mounts(list, longest);
Packit Service b439df
Packit Service b439df
	while (list) {
Packit Service b439df
		previous = list;
Packit Service b439df
		list = list->next;
Packit Service b439df
		free(previous);
Packit Service b439df
	}
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
int make_dir(char *path, mode_t mode, uid_t uid, gid_t gid)
Packit Service b439df
{
Packit Service b439df
	struct passwd *pwd;
Packit Service b439df
	struct group *grp;
Packit Service b439df
Packit Service b439df
	if (opt_dry_run) {
Packit Service b439df
		pwd = getpwuid(uid);
Packit Service b439df
		grp = getgrgid(gid);
Packit Service b439df
		printf("if [ ! -e %s ]\n", path);
Packit Service b439df
		printf("then\n");
Packit Service b439df
		printf(" mkdir %s\n", path);
Packit Service b439df
		printf(" chown %s:%s %s\n", pwd->pw_name, grp->gr_name, path);
Packit Service b439df
		printf(" chmod %o %s\n", mode, path);
Packit Service b439df
		printf("fi\n");
Packit Service b439df
		return 0;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	if (mkdir(path, mode)) {
Packit Service b439df
		if (errno != EEXIST) {
Packit Service b439df
			ERROR("Unable to create dir %s, error: %s\n",
Packit Service b439df
				path, strerror(errno));
Packit Service b439df
			return 1;
Packit Service b439df
		}
Packit Service b439df
	} else {
Packit Service b439df
		if (chown(path, uid, gid)) {
Packit Service b439df
			ERROR("Unable to change ownership of %s, error: %s\n",
Packit Service b439df
				path, strerror(errno));
Packit Service b439df
			return 1;
Packit Service b439df
		}
Packit Service b439df
Packit Service b439df
		if (chmod(path, mode)) {
Packit Service b439df
			ERROR("Unable to change permission on %s, error: %s\n",
Packit Service b439df
				path, strerror(errno));
Packit Service b439df
			return 1;
Packit Service b439df
		}
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	return 0;
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
/**
Packit Service b439df
 * ensure_dir will build the entire directory structure up to and
Packit Service b439df
 * including path, all directories built will be owned by
Packit Service b439df
 * user:group and permissions will be set to mode.
Packit Service b439df
 */
Packit Service b439df
int ensure_dir(char *path, mode_t mode, uid_t uid, gid_t gid)
Packit Service b439df
{
Packit Service b439df
	char *idx;
Packit Service b439df
Packit Service b439df
	if (!path || strlen(path) == 0)
Packit Service b439df
		return 0;
Packit Service b439df
Packit Service b439df
	idx = strchr(path + 1, '/');
Packit Service b439df
Packit Service b439df
	do {
Packit Service b439df
		if (idx)
Packit Service b439df
			*idx = '\0';
Packit Service b439df
Packit Service b439df
		if (make_dir(path, mode, uid, gid))
Packit Service b439df
			return 1;
Packit Service b439df
Packit Service b439df
		if (idx) {
Packit Service b439df
			*idx = '/';
Packit Service b439df
			idx++;
Packit Service b439df
		}
Packit Service b439df
	} while ((idx = strchr(idx, '/')) != NULL);
Packit Service b439df
Packit Service b439df
	if (make_dir(path, mode, uid, gid))
Packit Service b439df
		return 1;
Packit Service b439df
Packit Service b439df
	return 0;
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
int check_if_already_mounted(struct mount_list *list, char *path)
Packit Service b439df
{
Packit Service b439df
	while (list) {
Packit Service b439df
		if (!strcmp(list->entry.mnt_dir, path))
Packit Service b439df
			return 1;
Packit Service b439df
		list = list->next;
Packit Service b439df
	}
Packit Service b439df
	return 0;
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
int mount_dir(char *path, char *options, mode_t mode, uid_t uid, gid_t gid)
Packit Service b439df
{
Packit Service b439df
	struct passwd *pwd;
Packit Service b439df
	struct group *grp;
Packit Service b439df
	struct mntent entry;
Packit Service b439df
	FILE *mounts;
Packit Service b439df
        char dummy;
Packit Service b439df
        int useMtab;
Packit Service b439df
Packit Service b439df
	struct mount_list *list, *previous;
Packit Service b439df
Packit Service b439df
	list = collect_active_mounts(NULL);
Packit Service b439df
Packit Service b439df
	if (list && check_if_already_mounted(list, path)) {
Packit Service b439df
		WARNING("Directory %s is already mounted.\n", path);
Packit Service b439df
Packit Service b439df
		while (list) {
Packit Service b439df
			previous = list;
Packit Service b439df
			list = list->next;
Packit Service b439df
			free(previous);
Packit Service b439df
		}
Packit Service b439df
		return 0;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	while (list) {
Packit Service b439df
		previous = list;
Packit Service b439df
		list = list->next;
Packit Service b439df
		free(previous);
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	if (opt_dry_run) {
Packit Service b439df
		pwd = getpwuid(uid);
Packit Service b439df
		grp = getgrgid(gid);
Packit Service b439df
		printf("mount -t %s none %s -o %s\n", FS_NAME,
Packit Service b439df
			path, options);
Packit Service b439df
		printf("chown %s:%s %s\n", pwd->pw_name, grp->gr_name,
Packit Service b439df
			path);
Packit Service b439df
		printf("chmod %o %s\n", mode, path);
Packit Service b439df
	} else {
Packit Service b439df
		if (mount("none", path, FS_NAME, 0, options)) {
Packit Service b439df
			ERROR("Unable to mount %s, error: %s\n",
Packit Service b439df
				path, strerror(errno));
Packit Service b439df
			return 1;
Packit Service b439df
		}
Packit Service b439df
Packit Service b439df
          /* Check if mtab is a symlink */
Packit Service b439df
          useMtab = (readlink(MOUNTED, &dummy, 1) < 0);
Packit Service b439df
          if (useMtab) {
Packit Service b439df
			mounts = setmntent(MOUNTED, "a+");
Packit Service b439df
			if (mounts) {
Packit Service b439df
				entry.mnt_fsname = FS_NAME;
Packit Service b439df
				entry.mnt_dir = path;
Packit Service b439df
				entry.mnt_type = FS_NAME;
Packit Service b439df
				entry.mnt_opts = options;
Packit Service b439df
				entry.mnt_freq = 0;
Packit Service b439df
				entry.mnt_passno = 0;
Packit Service b439df
				if (addmntent(mounts, &entry))
Packit Service b439df
					WARNING("Unable to add entry %s to %s, error: %s\n",
Packit Service b439df
						path, MOUNTED, strerror(errno));
Packit Service b439df
				endmntent(mounts);
Packit Service b439df
			} else {
Packit Service b439df
				WARNING("Unable to open %s, error: %s\n",
Packit Service b439df
					MOUNTED, strerror(errno));
Packit Service b439df
			}
Packit Service b439df
		}
Packit Service b439df
Packit Service b439df
		if (chown(path, uid, gid)) {
Packit Service b439df
			ERROR("Unable to change ownership of %s, error: %s\n",
Packit Service b439df
				path, strerror(errno));
Packit Service b439df
			return 1;
Packit Service b439df
		}
Packit Service b439df
Packit Service b439df
		if (chmod(path, mode)) {
Packit Service b439df
			ERROR("Unable to set permissions on %s, error: %s\n",
Packit Service b439df
				path, strerror(errno));
Packit Service b439df
			return 1;
Packit Service b439df
		}
Packit Service b439df
	}
Packit Service b439df
	return 0;
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void scale_size(char *buf, unsigned long pagesize)
Packit Service b439df
{
Packit Service b439df
	if(pagesize >= GB)
Packit Service b439df
		snprintf(buf, OPT_MAX, "%luGB", pagesize / GB);
Packit Service b439df
	else if(pagesize >= MB)
Packit Service b439df
		snprintf(buf, OPT_MAX, "%luMB", pagesize / MB);
Packit Service b439df
	else
Packit Service b439df
		snprintf(buf, OPT_MAX, "%luKB", pagesize / KB);
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void create_mounts(char *user, char *group, char *base, mode_t mode)
Packit Service b439df
{
Packit Service b439df
	struct hpage_pool pools[MAX_POOLS];
Packit Service b439df
	char path[PATH_MAX];
Packit Service b439df
	char options[OPT_MAX];
Packit Service b439df
	char limits[OPT_MAX];
Packit Service b439df
	char scaled[OPT_MAX];
Packit Service b439df
	int cnt, pos;
Packit Service b439df
	struct passwd *pwd;
Packit Service b439df
	struct group *grp;
Packit Service b439df
	uid_t uid = 0;
Packit Service b439df
	gid_t gid = 0;
Packit Service b439df
Packit Service b439df
	if (geteuid() != 0) {
Packit Service b439df
		ERROR("Mounts can only be created by root\n");
Packit Service b439df
		exit(EXIT_FAILURE);
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	if (user) {
Packit Service b439df
		pwd = getpwnam(user);
Packit Service b439df
		if (!pwd) {
Packit Service b439df
			ERROR("Could not find specified user %s\n", user);
Packit Service b439df
			exit(EXIT_FAILURE);
Packit Service b439df
		}
Packit Service b439df
		uid = pwd->pw_uid;
Packit Service b439df
	} else if (group) {
Packit Service b439df
		grp = getgrnam(group);
Packit Service b439df
		if (!grp) {
Packit Service b439df
			ERROR("Could not find specified group %s\n", group);
Packit Service b439df
			exit(EXIT_FAILURE);
Packit Service b439df
		}
Packit Service b439df
		gid = grp->gr_gid;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	if (ensure_dir(base,
Packit Service b439df
		S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, 0, 0))
Packit Service b439df
		exit(EXIT_FAILURE);
Packit Service b439df
Packit Service b439df
	cnt = hpool_sizes(pools, MAX_POOLS);
Packit Service b439df
	if (cnt < 0) {
Packit Service b439df
		ERROR("Unable to obtain pools list\n");
Packit Service b439df
		exit(EXIT_FAILURE);
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	for (pos=0; cnt--; pos++) {
Packit Service b439df
		scaled[0] = 0;
Packit Service b439df
		scale_size(scaled, pools[pos].pagesize);
Packit Service b439df
		if (user)
Packit Service b439df
			snprintf(path, PATH_MAX, "%s/%s/pagesize-%s",
Packit Service b439df
				base, user, scaled);
Packit Service b439df
		else if (group)
Packit Service b439df
			snprintf(path, PATH_MAX, "%s/%s/pagesize-%s",
Packit Service b439df
				base, group, scaled);
Packit Service b439df
		else
Packit Service b439df
			snprintf(path, PATH_MAX, "%s/pagesize-%s",
Packit Service b439df
				base, scaled);
Packit Service b439df
Packit Service b439df
		snprintf(options, OPT_MAX, "pagesize=%ld",
Packit Service b439df
				pools[pos].pagesize);
Packit Service b439df
Packit Service b439df
		/* Yes, this could be cleverer */
Packit Service b439df
		if (opt_limit_mount_size && opt_limit_mount_inodes)
Packit Service b439df
			snprintf(limits, OPT_MAX, ",size=%lu,nr_inodes=%d",
Packit Service b439df
				opt_limit_mount_size, opt_limit_mount_inodes);
Packit Service b439df
		else {
Packit Service b439df
			if (opt_limit_mount_size)
Packit Service b439df
				snprintf(limits, OPT_MAX, ",size=%lu",
Packit Service b439df
					opt_limit_mount_size);
Packit Service b439df
			if (opt_limit_mount_inodes)
Packit Service b439df
				snprintf(limits, OPT_MAX, ",nr_inodes=%d",
Packit Service b439df
					opt_limit_mount_inodes);
Packit Service b439df
		}
Packit Service b439df
Packit Service b439df
		/* Append limits if specified */
Packit Service b439df
		if (limits[0] != 0) {
Packit Service b439df
			size_t maxlen = OPT_MAX - strlen(options);
Packit Service b439df
			if (maxlen > strlen(limits))
Packit Service b439df
				strcat(options, limits);
Packit Service b439df
			else
Packit Service b439df
				WARNING("String limitations met, cannot append limitations onto mount options string. Increase OPT_MAX");
Packit Service b439df
		}
Packit Service b439df
Packit Service b439df
		if (ensure_dir(path, mode, uid, gid))
Packit Service b439df
			exit(EXIT_FAILURE);
Packit Service b439df
Packit Service b439df
		if (mount_dir(path, options, mode, uid, gid))
Packit Service b439df
			exit(EXIT_FAILURE);
Packit Service b439df
	}
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
/**
Packit Service b439df
 * show_mem shouldn't change the behavior of any of its
Packit Service b439df
 * callers, it only prints a message to the user showing the
Packit Service b439df
 * total amount of memory in the system (in megabytes).
Packit Service b439df
 */
Packit Service b439df
void show_mem()
Packit Service b439df
{
Packit Service b439df
	long mem_total;
Packit Service b439df
Packit Service b439df
	mem_total = read_meminfo(MEM_TOTAL);
Packit Service b439df
	printf("Total System Memory: %ld MB\n\n", mem_total / 1024);
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
/**
Packit Service b439df
 * check_swap shouldn't change the behavior of any of its
Packit Service b439df
 * callers, it only prints a message to the user if something
Packit Service b439df
 * is being done that might fail without swap available.  i.e.
Packit Service b439df
 * resizing a huge page pool
Packit Service b439df
 */
Packit Service b439df
void check_swap()
Packit Service b439df
{
Packit Service b439df
	long swap_sz;
Packit Service b439df
	long swap_total;
Packit Service b439df
Packit Service b439df
	swap_total = read_meminfo(SWAP_TOTAL);
Packit Service b439df
	if (swap_total <= 0) {
Packit Service b439df
		WARNING("There is no swap space configured, resizing hugepage pool may fail\n");
Packit Service b439df
		WARNING("Use --add-temp-swap option to temporarily add swap during the resize\n");
Packit Service b439df
		return;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	swap_sz = read_meminfo(SWAP_FREE);
Packit Service b439df
	/* meminfo keeps values in kb, but we use bytes for hpage sizes */
Packit Service b439df
	swap_sz *= 1024;
Packit Service b439df
	if (swap_sz <= gethugepagesize()) {
Packit Service b439df
		WARNING("There is very little swap space free, resizing hugepage pool may fail\n");
Packit Service b439df
		WARNING("Use --add-temp-swap option to temporarily add swap during the resize\n");
Packit Service b439df
	}
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
#define ZONEINFO_LINEBUF 1024
Packit Service b439df
long recommended_minfreekbytes(void)
Packit Service b439df
{
Packit Service b439df
	FILE *f;
Packit Service b439df
	char buf[ZONEINFO_LINEBUF];
Packit Service b439df
	int nr_zones = 0;
Packit Service b439df
	long recommended_min;
Packit Service b439df
	long pageblock_kbytes = kernel_default_hugepage_size() / 1024;
Packit Service b439df
Packit Service b439df
	/* Detect the number of zones in the system */
Packit Service b439df
	f = fopen(PROCZONEINFO, "r");
Packit Service b439df
	if (f == NULL) {
Packit Service b439df
		WARNING("Unable to open " PROCZONEINFO);
Packit Service b439df
		return 0;
Packit Service b439df
	}
Packit Service b439df
	while (fgets(buf, ZONEINFO_LINEBUF, f) != NULL) {
Packit Service b439df
		if (strncmp(buf, "Node ", 5) == 0)
Packit Service b439df
			nr_zones++;
Packit Service b439df
	}
Packit Service b439df
	fclose(f);
Packit Service b439df
Packit Service b439df
	/* Make sure at least 2 pageblocks are free for MIGRATE_RESERVE */
Packit Service b439df
	recommended_min = pageblock_kbytes * nr_zones * 2;
Packit Service b439df
Packit Service b439df
	/*
Packit Service b439df
	 * Make sure that on average at least two pageblocks are almost free
Packit Service b439df
	 * of another type, one for a migratetype to fall back to and a
Packit Service b439df
	 * second to avoid subsequent fallbacks of other types There are 3
Packit Service b439df
	 * MIGRATE_TYPES we care about.
Packit Service b439df
	 */
Packit Service b439df
	recommended_min += pageblock_kbytes * nr_zones * 3 * 3;
Packit Service b439df
	return recommended_min;
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void set_recommended_minfreekbytes(void)
Packit Service b439df
{
Packit Service b439df
	long recommended_min = recommended_minfreekbytes();
Packit Service b439df
Packit Service b439df
	if (opt_dry_run) {
Packit Service b439df
		printf("echo \"%ld\" > %s\n", recommended_min,
Packit Service b439df
			PROCMINFREEKBYTES);
Packit Service b439df
		return;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	DEBUG("Setting min_free_kbytes to %ld\n", recommended_min);
Packit Service b439df
	file_write_ulong(PROCMINFREEKBYTES, (unsigned long)recommended_min);
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
/*
Packit Service b439df
 * check_minfreekbytes does not alter the value of min_free_kbytes. It just
Packit Service b439df
 * reports what the current value is and what it should be
Packit Service b439df
 */
Packit Service b439df
void check_minfreekbytes(void)
Packit Service b439df
{
Packit Service b439df
	long min_free_kbytes = file_read_ulong(PROCMINFREEKBYTES, NULL);
Packit Service b439df
	long recommended_min = recommended_minfreekbytes();
Packit Service b439df
Packit Service b439df
	/* There should be at least one pageblock free per zone in the system */
Packit Service b439df
	if (recommended_min > min_free_kbytes) {
Packit Service b439df
		printf("\n");
Packit Service b439df
		printf("The " PROCMINFREEKBYTES " of %ld is too small. To maximiuse efficiency\n", min_free_kbytes);
Packit Service b439df
		printf("of fragmentation avoidance, there should be at least one huge page free per zone\n");
Packit Service b439df
		printf("in the system which minimally requires a min_free_kbytes value of %ld\n", recommended_min);
Packit Service b439df
	}
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
unsigned long long recommended_shmmax(void)
Packit Service b439df
{
Packit Service b439df
	struct hpage_pool pools[MAX_POOLS];
Packit Service b439df
	unsigned long long recommended_shmmax = 0;
Packit Service b439df
	int pos, cnt;
Packit Service b439df
Packit Service b439df
	cnt = hpool_sizes(pools, MAX_POOLS);
Packit Service b439df
	if (cnt < 0) {
Packit Service b439df
		ERROR("unable to obtain pools list");
Packit Service b439df
		exit(EXIT_FAILURE);
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	for (pos = 0; cnt--; pos++)
Packit Service b439df
		recommended_shmmax += ((unsigned long long)pools[pos].maximum *
Packit Service b439df
							pools[pos].pagesize);
Packit Service b439df
Packit Service b439df
	return recommended_shmmax;
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void set_recommended_shmmax(void)
Packit Service b439df
{
Packit Service b439df
	int ret;
Packit Service b439df
	unsigned long max_recommended = -1UL;
Packit Service b439df
	unsigned long long recommended = recommended_shmmax();
Packit Service b439df
Packit Service b439df
	if (recommended == 0) {
Packit Service b439df
		printf("\n");
Packit Service b439df
		WARNING("We can only set a recommended shmmax when huge pages are configured!\n");
Packit Service b439df
		return;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	if (recommended > max_recommended)
Packit Service b439df
		recommended = max_recommended;
Packit Service b439df
Packit Service b439df
	DEBUG("Setting shmmax to %llu\n", recommended);
Packit Service b439df
	ret = file_write_ulong(PROCSHMMAX, (unsigned long)recommended);
Packit Service b439df
Packit Service b439df
	if (!ret) {
Packit Service b439df
		INFO("To make shmmax settings persistent, add the following line to /etc/sysctl.conf:\n");
Packit Service b439df
		INFO("  kernel.shmmax = %llu\n", recommended);
Packit Service b439df
	}
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void check_shmmax(void)
Packit Service b439df
{
Packit Service b439df
	long current_shmmax = file_read_ulong(PROCSHMMAX, NULL);
Packit Service b439df
	long recommended = recommended_shmmax();
Packit Service b439df
Packit Service b439df
	if (current_shmmax != recommended) {
Packit Service b439df
		printf("\n");
Packit Service b439df
		printf("A " PROCSHMMAX " value of %ld bytes may be sub-optimal. To maximise\n", current_shmmax);
Packit Service b439df
		printf("shared memory usage, this should be set to the size of the largest shared memory\n");
Packit Service b439df
		printf("segment size you want to be able to use. Alternatively, set it to a size matching\n");
Packit Service b439df
		printf("the maximum possible allocation size of all huge pages. This can be done\n");
Packit Service b439df
		printf("automatically, using the --set-recommended-shmmax option.\n");
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	if (recommended == 0) {
Packit Service b439df
		printf("\n");
Packit Service b439df
		WARNING("We can't make a shmmax recommendation until huge pages are configured!\n");
Packit Service b439df
		return;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	printf("\n");
Packit Service b439df
	printf("The recommended shmmax for your currently allocated huge pages is %ld bytes.\n", recommended);
Packit Service b439df
	printf("To make shmmax settings persistent, add the following line to /etc/sysctl.conf:\n");
Packit Service b439df
	printf("  kernel.shmmax = %ld\n", recommended);
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void set_hugetlb_shm_group(gid_t gid, char *group)
Packit Service b439df
{
Packit Service b439df
	int ret;
Packit Service b439df
Packit Service b439df
	DEBUG("Setting hugetlb_shm_group to %d (%s)\n", gid, group);
Packit Service b439df
	ret = file_write_ulong(PROCHUGETLBGROUP, (unsigned long)gid);
Packit Service b439df
Packit Service b439df
	if (!ret) {
Packit Service b439df
		INFO("To make hugetlb_shm_group settings persistent, add the following line to /etc/sysctl.conf:\n");
Packit Service b439df
		INFO("  vm.hugetlb_shm_group = %d\n", gid);
Packit Service b439df
	}
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
/* heisted from shadow-utils/libmisc/list.c::is_on_list() */
Packit Service b439df
static int user_in_group(char *const *list, const char *member)
Packit Service b439df
{
Packit Service b439df
	while (*list != NULL) {
Packit Service b439df
		if (strcmp(*list, member) == 0) {
Packit Service b439df
			return 1;
Packit Service b439df
		}
Packit Service b439df
		list++;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	return 0;
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void check_user(void)
Packit Service b439df
{
Packit Service b439df
	uid_t uid;
Packit Service b439df
	gid_t gid;
Packit Service b439df
	struct passwd *pwd;
Packit Service b439df
	struct group *grp;
Packit Service b439df
Packit Service b439df
	gid = (gid_t)file_read_ulong(PROCHUGETLBGROUP, NULL);
Packit Service b439df
	grp = getgrgid(gid);
Packit Service b439df
	if (!grp) {
Packit Service b439df
		printf("\n");
Packit Service b439df
		WARNING("Group ID %d in hugetlb_shm_group doesn't appear to be a valid group!\n", gid);
Packit Service b439df
		return;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	uid = getuid();
Packit Service b439df
	pwd = getpwuid(uid);
Packit Service b439df
Packit Service b439df
	/* Don't segfault if user does not have a passwd entry. */
Packit Service b439df
	if (!pwd) {
Packit Service b439df
		printf("\n");
Packit Service b439df
		WARNING("User uid %d is not in the password file!\n", uid);
Packit Service b439df
		return;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	if (gid != pwd->pw_gid && !user_in_group(grp->gr_mem, pwd->pw_name) && uid != 0) {
Packit Service b439df
		printf("\n");
Packit Service b439df
		WARNING("User %s (uid: %d) is not a member of the hugetlb_shm_group %s (gid: %d)!\n", pwd->pw_name, uid, grp->gr_name, gid);
Packit Service b439df
	} else {
Packit Service b439df
		printf("\n");
Packit Service b439df
		printf("To make your hugetlb_shm_group settings persistent, add the following line to /etc/sysctl.conf:\n");
Packit Service b439df
		printf("  vm.hugetlb_shm_group = %d\n", gid);
Packit Service b439df
	}
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void add_temp_swap(long page_size)
Packit Service b439df
{
Packit Service b439df
	char path[PATH_MAX];
Packit Service b439df
	char file[PATH_MAX];
Packit Service b439df
	char mkswap_cmd[PATH_MAX];
Packit Service b439df
	FILE *f;
Packit Service b439df
	char *buf;
Packit Service b439df
	long swap_size;
Packit Service b439df
	long pid;
Packit Service b439df
	int ret;
Packit Service b439df
	int num_pages;
Packit Service b439df
Packit Service b439df
	if (geteuid() != 0) {
Packit Service b439df
		ERROR("Swap can only be manipulated by root\n");
Packit Service b439df
		exit(EXIT_FAILURE);
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	pid = getpid();
Packit Service b439df
	snprintf(path, PATH_MAX, "%s/swap/temp", MOUNT_DIR);
Packit Service b439df
	snprintf(file, PATH_MAX, "%s/swapfile-%ld", path, pid);
Packit Service b439df
Packit Service b439df
	/* swapsize is 5 hugepages */
Packit Service b439df
	if (opt_temp_swap == -1)
Packit Service b439df
		num_pages = 5;
Packit Service b439df
	else
Packit Service b439df
		num_pages = opt_temp_swap;
Packit Service b439df
	swap_size = num_pages * page_size;
Packit Service b439df
Packit Service b439df
	if (ensure_dir(path, S_IRWXU | S_IRGRP | S_IXGRP, 0, 0))
Packit Service b439df
		exit(EXIT_FAILURE);
Packit Service b439df
Packit Service b439df
	if (opt_dry_run) {
Packit Service b439df
		printf("dd bs=1024 count=%ld if=/dev/zero of=%s\n",
Packit Service b439df
			swap_size / 1024, file);
Packit Service b439df
		printf("mkswap %s\nswapon %s\n", file, file);
Packit Service b439df
		return;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	f = fopen(file, "wx");
Packit Service b439df
	if (!f) {
Packit Service b439df
		WARNING("Couldn't open %s: %s\n", file, strerror(errno));
Packit Service b439df
		opt_temp_swap = 0;
Packit Service b439df
		return;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	buf = malloc(swap_size);
Packit Service b439df
	memset(buf, 0, swap_size);
Packit Service b439df
	fwrite(buf, sizeof(char), swap_size, f);
Packit Service b439df
	free(buf);
Packit Service b439df
	fclose(f);
Packit Service b439df
Packit Service b439df
	snprintf(mkswap_cmd, PATH_MAX, "mkswap %s", file);
Packit Service b439df
	ret = system(mkswap_cmd);
Packit Service b439df
	if (WIFSIGNALED(ret)) {
Packit Service b439df
		WARNING("Call to mkswap failed\n");
Packit Service b439df
		opt_temp_swap = 0;
Packit Service b439df
		return;
Packit Service b439df
	} else if (WIFEXITED(ret)) {
Packit Service b439df
		ret = WEXITSTATUS(ret);
Packit Service b439df
		if (ret) {
Packit Service b439df
			WARNING("Call to mkswap failed\n");
Packit Service b439df
			opt_temp_swap = 0;
Packit Service b439df
			return;
Packit Service b439df
		}
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	DEBUG("swapon %s\n", file);
Packit Service b439df
	if (swapon(file, 0)) {
Packit Service b439df
		WARNING("swapon on %s failed: %s\n", file, strerror(errno));
Packit Service b439df
		opt_temp_swap = 0;
Packit Service b439df
	}
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void rem_temp_swap() {
Packit Service b439df
	char file[PATH_MAX];
Packit Service b439df
	long pid;
Packit Service b439df
Packit Service b439df
	pid = getpid();
Packit Service b439df
	snprintf(file, PATH_MAX, "%s/swap/temp/swapfile-%ld", MOUNT_DIR, pid);
Packit Service b439df
Packit Service b439df
	if (opt_dry_run) {
Packit Service b439df
		printf("swapoff %s\nrm -f %s\n", file, file);
Packit Service b439df
		return;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	if (swapoff(file))
Packit Service b439df
		WARNING("swapoff on %s failed: %s\n", file, strerror(errno));
Packit Service b439df
	remove(file);
Packit Service b439df
	DEBUG("swapoff %s\n", file);
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void add_ramdisk_swap(long page_size) {
Packit Service b439df
	char ramdisk[PATH_MAX];
Packit Service b439df
	char mkswap_cmd[PATH_MAX];
Packit Service b439df
	int disk_num=0;
Packit Service b439df
	int count = 0;
Packit Service b439df
	long ramdisk_size;
Packit Service b439df
	int ret;
Packit Service b439df
	int fd;
Packit Service b439df
Packit Service b439df
	snprintf(ramdisk, PATH_MAX, "/dev/ram%i", disk_num);
Packit Service b439df
	fd = open(ramdisk, O_RDONLY);
Packit Service b439df
	ioctl(fd, BLKGETSIZE, &ramdisk_size);
Packit Service b439df
	close(fd);
Packit Service b439df
Packit Service b439df
	ramdisk_size = ramdisk_size * 512;
Packit Service b439df
	count = (page_size/ramdisk_size) + 1;
Packit Service b439df
Packit Service b439df
	if (count > 1) {
Packit Service b439df
		INFO("Swap will be initialized on multiple ramdisks because\n\
Packit Service b439df
		ramdisk size is less than huge page size. To avoid\n\
Packit Service b439df
		this in the future, use kernel command line parameter\n\
Packit Service b439df
		ramdisk_size=N, to set ramdisk size to N blocks.\n");
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	while (count > 0) {
Packit Service b439df
		snprintf(ramdisk, PATH_MAX, "/dev/ram%i", disk_num);
Packit Service b439df
		if (access(ramdisk, F_OK) != 0){
Packit Service b439df
			break;
Packit Service b439df
		}
Packit Service b439df
		disk_num++;
Packit Service b439df
Packit Service b439df
		if (opt_dry_run) {
Packit Service b439df
			printf("mkswap %s\nswapon %s\n", ramdisk, ramdisk);
Packit Service b439df
		} else {
Packit Service b439df
			snprintf(mkswap_cmd, PATH_MAX, "mkswap %s", ramdisk);
Packit Service b439df
			ret = system(mkswap_cmd);
Packit Service b439df
			if (WIFSIGNALED(ret)) {
Packit Service b439df
				WARNING("Call to mkswap failed\n");
Packit Service b439df
				continue;
Packit Service b439df
			} else if (WIFEXITED(ret)) {
Packit Service b439df
				ret = WEXITSTATUS(ret);
Packit Service b439df
				if (ret) {
Packit Service b439df
					WARNING("Call to mkswap failed\n");
Packit Service b439df
					continue;
Packit Service b439df
				}
Packit Service b439df
			}
Packit Service b439df
			DEBUG("swapon %s\n", ramdisk);
Packit Service b439df
			if (swapon(ramdisk, 0)) {
Packit Service b439df
				WARNING("swapon on %s failed: %s\n", ramdisk, strerror(errno));
Packit Service b439df
				opt_temp_swap = 0;
Packit Service b439df
				continue;
Packit Service b439df
			}
Packit Service b439df
		}
Packit Service b439df
		count--;
Packit Service b439df
		strcat(ramdisk_list, " ");
Packit Service b439df
		strcat(ramdisk_list, ramdisk);
Packit Service b439df
	}
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void rem_ramdisk_swap(){
Packit Service b439df
	char *ramdisk;
Packit Service b439df
	char *iter = NULL;
Packit Service b439df
Packit Service b439df
	ramdisk = strtok_r(ramdisk_list, " ", &iter);
Packit Service b439df
	while (ramdisk != NULL) {
Packit Service b439df
		if (opt_dry_run) {
Packit Service b439df
			printf("swapoff %s\n", ramdisk);
Packit Service b439df
		} else {
Packit Service b439df
			DEBUG("swapoff %s\n", ramdisk);
Packit Service b439df
			if (swapoff(ramdisk)) {
Packit Service b439df
				WARNING("swapoff on %s failed: %s\n", ramdisk, strerror(errno));
Packit Service b439df
				continue;
Packit Service b439df
			}
Packit Service b439df
		}
Packit Service b439df
		ramdisk = strtok_r(NULL, " ", &iter);
Packit Service b439df
	}
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void set_trans_opt(const char *file, const char *value)
Packit Service b439df
{
Packit Service b439df
	FILE *f;
Packit Service b439df
Packit Service b439df
	if (geteuid() != 0) {
Packit Service b439df
                ERROR("Transparent huge page options can only be set by root\n");
Packit Service b439df
                exit(EXIT_FAILURE);
Packit Service b439df
        }
Packit Service b439df
Packit Service b439df
	if (opt_dry_run) {
Packit Service b439df
		printf("echo '%s' > %s\n", value, file);
Packit Service b439df
		return;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	f = fopen(file, "w");
Packit Service b439df
	if (!f) {
Packit Service b439df
		ERROR("Couldn't open %s: %s\n", file, strerror(errno));
Packit Service b439df
		return;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	fprintf(f, "%s", value);
Packit Service b439df
	fclose(f);
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
enum {
Packit Service b439df
	POOL_MIN,
Packit Service b439df
	POOL_MAX,
Packit Service b439df
	POOL_BOTH,
Packit Service b439df
};
Packit Service b439df
Packit Service b439df
static long value_adjust(char *adjust_str, long base, long page_size)
Packit Service b439df
{
Packit Service b439df
	long long adjust;
Packit Service b439df
	char *iter;
Packit Service b439df
Packit Service b439df
	/* Convert and validate the adjust. */
Packit Service b439df
	errno = 0;
Packit Service b439df
	adjust = strtol(adjust_str, &iter, 0);
Packit Service b439df
	/* Catch strtol errors and sizes that overflow the native word size */
Packit Service b439df
	if (errno || adjust_str == iter) {
Packit Service b439df
		if (errno == ERANGE)
Packit Service b439df
			errno = EOVERFLOW;
Packit Service b439df
		else
Packit Service b439df
			errno = EINVAL;
Packit Service b439df
		ERROR("%s: invalid adjustment\n", adjust_str);
Packit Service b439df
		exit(EXIT_FAILURE);
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	/* size_to_smaller_unit() only works with positive values */
Packit Service b439df
	if (adjust_str[0] == '-')
Packit Service b439df
		adjust = -adjust;
Packit Service b439df
Packit Service b439df
	switch (*iter) {
Packit Service b439df
	case 'G':
Packit Service b439df
	case 'g':
Packit Service b439df
		adjust = size_to_smaller_unit(adjust);
Packit Service b439df
	case 'M':
Packit Service b439df
	case 'm':
Packit Service b439df
		adjust = size_to_smaller_unit(adjust);
Packit Service b439df
	case 'K':
Packit Service b439df
	case 'k':
Packit Service b439df
		adjust = size_to_smaller_unit(adjust);
Packit Service b439df
		adjust = adjust / page_size;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	/* if previously negative, make negative again */
Packit Service b439df
	if (adjust_str[0] == '-')
Packit Service b439df
		adjust = -adjust;
Packit Service b439df
Packit Service b439df
	if (adjust_str[0] != '+' && adjust_str[0] != '-')
Packit Service b439df
		base = 0;
Packit Service b439df
Packit Service b439df
	/* Ensure we neither go negative nor exceed LONG_MAX. */
Packit Service b439df
	if (adjust < 0 && -adjust > base) {
Packit Service b439df
		adjust = -base;
Packit Service b439df
	}
Packit Service b439df
	if (adjust > 0 && (base + adjust) < base) {
Packit Service b439df
		adjust = LONG_MAX - base;
Packit Service b439df
	}
Packit Service b439df
	base += adjust;
Packit Service b439df
Packit Service b439df
	DEBUG("Returning page count of %ld\n", base);
Packit Service b439df
Packit Service b439df
	return base;
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
Packit Service b439df
void pool_adjust(char *cmd, unsigned int counter)
Packit Service b439df
{
Packit Service b439df
	struct hpage_pool pools[MAX_POOLS];
Packit Service b439df
	int pos;
Packit Service b439df
	int cnt;
Packit Service b439df
Packit Service b439df
	char *iter = NULL;
Packit Service b439df
	char *page_size_str = NULL;
Packit Service b439df
	char *adjust_str = NULL;
Packit Service b439df
	long page_size;
Packit Service b439df
Packit Service b439df
	unsigned long min;
Packit Service b439df
	unsigned long min_orig;
Packit Service b439df
	unsigned long max;
Packit Service b439df
	unsigned long last_pool_value;
Packit Service b439df
Packit Service b439df
	/* Extract the pagesize and adjustment. */
Packit Service b439df
	page_size_str = strtok_r(cmd, ":", &iter);
Packit Service b439df
	if (page_size_str)
Packit Service b439df
		adjust_str = strtok_r(NULL, ":", &iter);
Packit Service b439df
Packit Service b439df
	if (!page_size_str || !adjust_str) {
Packit Service b439df
		ERROR("%s: invalid resize specification\n", cmd);
Packit Service b439df
		exit(EXIT_FAILURE);
Packit Service b439df
	}
Packit Service b439df
	INFO("page_size<%s> adjust<%s> counter<%d>\n",
Packit Service b439df
					page_size_str, adjust_str, counter);
Packit Service b439df
Packit Service b439df
	/* Convert and validate the page_size. */
Packit Service b439df
	if (strcmp(page_size_str, "DEFAULT") == 0)
Packit Service b439df
		page_size = kernel_default_hugepage_size();
Packit Service b439df
	else
Packit Service b439df
		page_size = parse_page_size(page_size_str);
Packit Service b439df
Packit Service b439df
	DEBUG("Working with page_size of %ld\n", page_size);
Packit Service b439df
Packit Service b439df
	cnt = hpool_sizes(pools, MAX_POOLS);
Packit Service b439df
	if (cnt < 0) {
Packit Service b439df
		ERROR("unable to obtain pools list");
Packit Service b439df
		exit(EXIT_FAILURE);
Packit Service b439df
	}
Packit Service b439df
	for (pos = 0; cnt--; pos++) {
Packit Service b439df
		if (pools[pos].pagesize == page_size)
Packit Service b439df
			break;
Packit Service b439df
	}
Packit Service b439df
	if (cnt < 0) {
Packit Service b439df
		ERROR("%s: unknown page size\n", page_size_str);
Packit Service b439df
		exit(EXIT_FAILURE);
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	min_orig = min = pools[pos].minimum;
Packit Service b439df
	max = pools[pos].maximum;
Packit Service b439df
Packit Service b439df
	if (counter == POOL_BOTH) {
Packit Service b439df
		min = value_adjust(adjust_str, min, page_size);
Packit Service b439df
		max = min;
Packit Service b439df
	} else if (counter == POOL_MIN) {
Packit Service b439df
		min = value_adjust(adjust_str, min, page_size);
Packit Service b439df
		if (min > max)
Packit Service b439df
			max = min;
Packit Service b439df
	} else {
Packit Service b439df
		max = value_adjust(adjust_str, max, page_size);
Packit Service b439df
		if (max < min)
Packit Service b439df
			min = max;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	INFO("%ld, %ld -> %ld, %ld\n", pools[pos].minimum, pools[pos].maximum,
Packit Service b439df
		min, max);
Packit Service b439df
Packit Service b439df
	if ((pools[pos].maximum - pools[pos].minimum) < (max - min)) {
Packit Service b439df
		INFO("setting HUGEPAGES_OC to %ld\n", (max - min));
Packit Service b439df
		set_huge_page_counter(page_size, HUGEPAGES_OC, (max - min));
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	if (opt_hard)
Packit Service b439df
		cnt = 5;
Packit Service b439df
	else
Packit Service b439df
		cnt = -1;
Packit Service b439df
Packit Service b439df
	if (min > min_orig) {
Packit Service b439df
		if (opt_temp_swap)
Packit Service b439df
			add_temp_swap(page_size);
Packit Service b439df
		if (opt_ramdisk_swap)
Packit Service b439df
			add_ramdisk_swap(page_size);
Packit Service b439df
		check_swap();
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	if (opt_obey_mempolicy && get_huge_page_counter(page_size,
Packit Service b439df
				HUGEPAGES_TOTAL_MEMPOL) < 0) {
Packit Service b439df
		opt_obey_mempolicy = 0;
Packit Service b439df
		WARNING("Counter for NUMA huge page allocations is not found, continuing with normal pool adjustment\n");
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	INFO("setting HUGEPAGES_TOTAL%s to %ld\n",
Packit Service b439df
		opt_obey_mempolicy ? "_MEMPOL" : "", min);
Packit Service b439df
	set_huge_page_counter(page_size,
Packit Service b439df
		opt_obey_mempolicy ? HUGEPAGES_TOTAL_MEMPOL : HUGEPAGES_TOTAL,
Packit Service b439df
		min);
Packit Service b439df
	get_pool_size(page_size, &pools[pos]);
Packit Service b439df
Packit Service b439df
	/* If we fail to make an allocation, retry if user requests */
Packit Service b439df
	last_pool_value = pools[pos].minimum;
Packit Service b439df
	while ((pools[pos].minimum != min) && (cnt > 0)) {
Packit Service b439df
		/* Make note if progress is being made and sleep for IO */
Packit Service b439df
		if (last_pool_value == pools[pos].minimum)
Packit Service b439df
			cnt--;
Packit Service b439df
		else
Packit Service b439df
			cnt = 5;
Packit Service b439df
		sleep(6);
Packit Service b439df
Packit Service b439df
		last_pool_value = pools[pos].minimum;
Packit Service b439df
		INFO("Retrying allocation HUGEPAGES_TOTAL%s to %ld current %ld\n", opt_obey_mempolicy ? "_MEMPOL" : "", min, pools[pos].minimum);
Packit Service b439df
		set_huge_page_counter(page_size,
Packit Service b439df
			opt_obey_mempolicy ?
Packit Service b439df
				HUGEPAGES_TOTAL_MEMPOL :
Packit Service b439df
				HUGEPAGES_TOTAL,
Packit Service b439df
			min);
Packit Service b439df
		get_pool_size(page_size, &pools[pos]);
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	if (min > min_orig && !opt_swap_persist) {
Packit Service b439df
		if (opt_temp_swap)
Packit Service b439df
			rem_temp_swap();
Packit Service b439df
		else if (opt_ramdisk_swap)
Packit Service b439df
			rem_ramdisk_swap();
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	/*
Packit Service b439df
	 * HUGEPAGES_TOTAL is not guarenteed to check to exactly the figure
Packit Service b439df
	 * requested should there be insufficient pages.  Check the new
Packit Service b439df
	 * value and adjust HUGEPAGES_OC accordingly.
Packit Service b439df
	 */
Packit Service b439df
	if (pools[pos].minimum != min) {
Packit Service b439df
		WARNING("failed to set pool minimum to %ld became %ld\n",
Packit Service b439df
			min, pools[pos].minimum);
Packit Service b439df
		min = pools[pos].minimum;
Packit Service b439df
	}
Packit Service b439df
	if (pools[pos].maximum != max) {
Packit Service b439df
		INFO("setting HUGEPAGES_OC to %ld\n", (max - min));
Packit Service b439df
		set_huge_page_counter(page_size, HUGEPAGES_OC, (max - min));
Packit Service b439df
	}
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void page_sizes(int all)
Packit Service b439df
{
Packit Service b439df
	struct hpage_pool pools[MAX_POOLS];
Packit Service b439df
	int pos;
Packit Service b439df
	int cnt;
Packit Service b439df
Packit Service b439df
	cnt = hpool_sizes(pools, MAX_POOLS);
Packit Service b439df
	if (cnt < 0) {
Packit Service b439df
		ERROR("unable to obtain pools list");
Packit Service b439df
		exit(EXIT_FAILURE);
Packit Service b439df
	}
Packit Service b439df
	qsort(pools, cnt, sizeof(pools[0]), cmpsizes);
Packit Service b439df
Packit Service b439df
	for (pos = 0; cnt--; pos++) {
Packit Service b439df
		if (all || (pools[pos].maximum &&
Packit Service b439df
		    hugetlbfs_find_path_for_size(pools[pos].pagesize)))
Packit Service b439df
			printf("%ld\n", pools[pos].pagesize);
Packit Service b439df
	}
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
void explain()
Packit Service b439df
{
Packit Service b439df
	show_mem();
Packit Service b439df
	mounts_list_all();
Packit Service b439df
	printf("\nHuge page pools:\n");
Packit Service b439df
	pool_list();
Packit Service b439df
	printf("\nHuge page sizes with configured pools:\n");
Packit Service b439df
	page_sizes(0);
Packit Service b439df
	check_minfreekbytes();
Packit Service b439df
	check_shmmax();
Packit Service b439df
	check_swap();
Packit Service b439df
	check_user();
Packit Service b439df
	printf("\nNote: Permanent swap space should be preferred when dynamic "
Packit Service b439df
		"huge page pools are used.\n");
Packit Service b439df
}
Packit Service b439df
Packit Service b439df
int main(int argc, char** argv)
Packit Service b439df
{
Packit Service b439df
	int ops;
Packit Service b439df
	int has_hugepages = kernel_has_hugepages();
Packit Service b439df
Packit Service b439df
	char opts[] = "+hdv";
Packit Service b439df
	char base[PATH_MAX];
Packit Service b439df
	char *opt_min_adj[MAX_POOLS], *opt_max_adj[MAX_POOLS];
Packit Service b439df
	char *opt_user_mounts = NULL, *opt_group_mounts = NULL;
Packit Service b439df
	int opt_list_mounts = 0, opt_pool_list = 0, opt_create_mounts = 0;
Packit Service b439df
	int opt_global_mounts = 0, opt_pgsizes = 0, opt_pgsizes_all = 0;
Packit Service b439df
	int opt_explain = 0, minadj_count = 0, maxadj_count = 0;
Packit Service b439df
	int opt_trans_always = 0, opt_trans_never = 0, opt_trans_madvise = 0;
Packit Service b439df
	int opt_khuge_pages = 0, opt_khuge_scan = 0, opt_khuge_alloc = 0;
Packit Service b439df
	int ret = 0, index = 0;
Packit Service b439df
	char *khuge_pages = NULL, *khuge_alloc = NULL, *khuge_scan = NULL;
Packit Service b439df
	gid_t opt_gid = 0;
Packit Service b439df
	struct group *opt_grp = NULL;
Packit Service b439df
	int group_invalid = 0;
Packit Service b439df
	struct option long_opts[] = {
Packit Service b439df
		{"help",       no_argument, NULL, 'h'},
Packit Service b439df
		{"verbose",    required_argument, NULL, 'v' },
Packit Service b439df
Packit Service b439df
		{"list-all-mounts", no_argument, NULL, LONG_LIST_ALL_MOUNTS},
Packit Service b439df
		{"pool-list", no_argument, NULL, LONG_POOL_LIST},
Packit Service b439df
		{"pool-pages-min", required_argument, NULL, LONG_POOL_MIN_ADJ},
Packit Service b439df
		{"pool-pages-max", required_argument, NULL, LONG_POOL_MAX_ADJ},
Packit Service b439df
		{"obey-mempolicy", no_argument, NULL, LONG_POOL_MEMPOL},
Packit Service b439df
		{"thp-always", no_argument, NULL, LONG_TRANS_ALWAYS},
Packit Service b439df
		{"thp-madvise", no_argument, NULL, LONG_TRANS_MADVISE},
Packit Service b439df
		{"thp-never", no_argument, NULL, LONG_TRANS_NEVER},
Packit Service b439df
		{"thp-khugepaged-pages", required_argument, NULL, LONG_KHUGE_PAGES},
Packit Service b439df
		{"thp-khugepaged-scan-sleep", required_argument, NULL, LONG_KHUGE_SCAN},
Packit Service b439df
		{"thp-khugepaged-alloc-sleep", required_argument, NULL, LONG_KHUGE_ALLOC},
Packit Service b439df
		{"set-recommended-min_free_kbytes", no_argument, NULL, LONG_SET_RECOMMENDED_MINFREEKBYTES},
Packit Service b439df
		{"set-recommended-shmmax", no_argument, NULL, LONG_SET_RECOMMENDED_SHMMAX},
Packit Service b439df
		{"set-shm-group", required_argument, NULL, LONG_SET_HUGETLB_SHM_GROUP},
Packit Service b439df
		{"enable-zone-movable", no_argument, NULL, LONG_MOVABLE_ENABLE},
Packit Service b439df
		{"disable-zone-movable", no_argument, NULL, LONG_MOVABLE_DISABLE},
Packit Service b439df
		{"hard", no_argument, NULL, LONG_HARD},
Packit Service b439df
		{"add-temp-swap", optional_argument, NULL, LONG_SWAP_DISK},
Packit Service b439df
		{"add-ramdisk-swap", no_argument, NULL, LONG_SWAP_RAMDISK},
Packit Service b439df
		{"persist", no_argument, NULL, LONG_SWAP_PERSIST},
Packit Service b439df
		{"create-mounts", no_argument, NULL, LONG_CREATE_MOUNTS},
Packit Service b439df
		{"create-user-mounts", required_argument, NULL, LONG_CREATE_USER_MOUNTS},
Packit Service b439df
		{"create-group-mounts", required_argument, NULL, LONG_CREATE_GROUP_MOUNTS},
Packit Service b439df
		{"create-global-mounts", no_argument, NULL, LONG_CREATE_GLOBAL_MOUNTS},
Packit Service b439df
Packit Service b439df
		{"max-size", required_argument, NULL, LONG_LIMIT_SIZE},
Packit Service b439df
		{"max-inodes", required_argument, NULL, LONG_LIMIT_INODES},
Packit Service b439df
Packit Service b439df
		{"page-sizes", no_argument, NULL, LONG_PAGE_SIZES},
Packit Service b439df
		{"page-sizes-all", no_argument, NULL, LONG_PAGE_AVAIL},
Packit Service b439df
		{"dry-run", no_argument, NULL, 'd'},
Packit Service b439df
		{"explain", no_argument, NULL, LONG_EXPLAIN},
Packit Service b439df
Packit Service b439df
		{0},
Packit Service b439df
	};
Packit Service b439df
Packit Service b439df
	hugetlbfs_setup_debug();
Packit Service b439df
	setup_mounts();
Packit Service b439df
	verbose_init();
Packit Service b439df
Packit Service b439df
	ops = 0;
Packit Service b439df
	while (ret != -1) {
Packit Service b439df
		ret = getopt_long(argc, argv, opts, long_opts, &index);
Packit Service b439df
		switch (ret) {
Packit Service b439df
		case -1:
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case '?':
Packit Service b439df
			print_usage();
Packit Service b439df
			exit(EXIT_FAILURE);
Packit Service b439df
Packit Service b439df
		case 'h':
Packit Service b439df
			print_usage();
Packit Service b439df
			exit(EXIT_SUCCESS);
Packit Service b439df
Packit Service b439df
		case 'v':
Packit Service b439df
			verbose(optarg);
Packit Service b439df
			continue;
Packit Service b439df
Packit Service b439df
		case 'd':
Packit Service b439df
			opt_dry_run = 1;
Packit Service b439df
			continue;
Packit Service b439df
Packit Service b439df
		default:
Packit Service b439df
			/* All other commands require hugepage support. */
Packit Service b439df
			if (! has_hugepages) {
Packit Service b439df
				ERROR("kernel does not support huge pages\n");
Packit Service b439df
				exit(EXIT_FAILURE);
Packit Service b439df
			}
Packit Service b439df
		}
Packit Service b439df
		switch (ret) {
Packit Service b439df
		case -1:
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_HARD:
Packit Service b439df
			opt_hard = 1;
Packit Service b439df
			continue;
Packit Service b439df
Packit Service b439df
		case LONG_SWAP_DISK:
Packit Service b439df
			if (optarg)
Packit Service b439df
				opt_temp_swap = atoi(optarg);
Packit Service b439df
			else
Packit Service b439df
				opt_temp_swap = -1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_SWAP_RAMDISK:
Packit Service b439df
			opt_ramdisk_swap = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_SWAP_PERSIST:
Packit Service b439df
			opt_swap_persist = 1;
Packit Service b439df
Packit Service b439df
		case LONG_LIST_ALL_MOUNTS:
Packit Service b439df
			opt_list_mounts = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_POOL_LIST:
Packit Service b439df
			opt_pool_list = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_POOL_MIN_ADJ:
Packit Service b439df
			if (minadj_count == MAX_POOLS) {
Packit Service b439df
				WARNING("Attempting to adjust an invalid "
Packit Service b439df
					"pool or a pool multiple times, "
Packit Service b439df
					"ignoring request: '%s'\n", optarg);
Packit Service b439df
			} else {
Packit Service b439df
				opt_min_adj[minadj_count++] = optarg;
Packit Service b439df
			}
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_POOL_MEMPOL:
Packit Service b439df
			opt_obey_mempolicy = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_TRANS_ALWAYS:
Packit Service b439df
			opt_trans_always = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_TRANS_MADVISE:
Packit Service b439df
			opt_trans_madvise = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_TRANS_NEVER:
Packit Service b439df
			opt_trans_never = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_KHUGE_PAGES:
Packit Service b439df
			opt_khuge_pages = 1;
Packit Service b439df
			khuge_pages = optarg;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_KHUGE_SCAN:
Packit Service b439df
			opt_khuge_scan = 1;
Packit Service b439df
			khuge_scan = optarg;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_KHUGE_ALLOC:
Packit Service b439df
			opt_khuge_alloc = 1;
Packit Service b439df
			khuge_alloc = optarg;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_POOL_MAX_ADJ:
Packit Service b439df
			if (! kernel_has_overcommit()) {
Packit Service b439df
				ERROR("kernel does not support overcommit, "
Packit Service b439df
					"max cannot be adjusted\n");
Packit Service b439df
				exit(EXIT_FAILURE);
Packit Service b439df
			}
Packit Service b439df
Packit Service b439df
			if (maxadj_count == MAX_POOLS) {
Packit Service b439df
				WARNING("Attempting to adjust an invalid "
Packit Service b439df
					"pool or a pool multiple times, "
Packit Service b439df
					"ignoring request: '%s'\n", optarg);
Packit Service b439df
			} else {
Packit Service b439df
				opt_max_adj[maxadj_count++] = optarg;
Packit Service b439df
			}
Packit Service b439df
                        break;
Packit Service b439df
Packit Service b439df
		case LONG_MOVABLE_ENABLE:
Packit Service b439df
			opt_movable = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_SET_RECOMMENDED_MINFREEKBYTES:
Packit Service b439df
			opt_set_recommended_minfreekbytes = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_SET_RECOMMENDED_SHMMAX:
Packit Service b439df
			opt_set_recommended_shmmax = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_SET_HUGETLB_SHM_GROUP:
Packit Service b439df
			opt_grp = getgrnam(optarg);
Packit Service b439df
			if (!opt_grp) {
Packit Service b439df
				opt_gid = atoi(optarg);
Packit Service b439df
				if (opt_gid == 0 && strcmp(optarg, "0"))
Packit Service b439df
					group_invalid = 1;
Packit Service b439df
				opt_grp = getgrgid(opt_gid);
Packit Service b439df
				if (!opt_grp)
Packit Service b439df
					group_invalid = 1;
Packit Service b439df
			} else {
Packit Service b439df
				opt_gid = opt_grp->gr_gid;
Packit Service b439df
			}
Packit Service b439df
			if (group_invalid) {
Packit Service b439df
				ERROR("Invalid group specification (%s)\n", optarg);
Packit Service b439df
				exit(EXIT_FAILURE);
Packit Service b439df
			}
Packit Service b439df
			opt_set_hugetlb_shm_group = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_MOVABLE_DISABLE:
Packit Service b439df
			opt_movable = 0;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_CREATE_MOUNTS:
Packit Service b439df
			opt_create_mounts = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_CREATE_USER_MOUNTS:
Packit Service b439df
			opt_user_mounts = optarg;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_CREATE_GROUP_MOUNTS:
Packit Service b439df
			opt_group_mounts = optarg;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_CREATE_GLOBAL_MOUNTS:
Packit Service b439df
			opt_global_mounts = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_LIMIT_SIZE:
Packit Service b439df
			/* Not a pagesize, but the conversions the same */
Packit Service b439df
			opt_limit_mount_size = parse_page_size(optarg);
Packit Service b439df
			if (!opt_limit_mount_size)
Packit Service b439df
				WARNING("Mount max size specification 0, invalid or overflowed\n");
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_LIMIT_INODES:
Packit Service b439df
			opt_limit_mount_inodes = atoi(optarg);
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_PAGE_SIZES:
Packit Service b439df
			opt_pgsizes = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_PAGE_AVAIL:
Packit Service b439df
			opt_pgsizes_all = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		case LONG_EXPLAIN:
Packit Service b439df
			opt_explain = 1;
Packit Service b439df
			break;
Packit Service b439df
Packit Service b439df
		default:
Packit Service b439df
			WARNING("unparsed option %08x\n", ret);
Packit Service b439df
			ret = -1;
Packit Service b439df
			break;
Packit Service b439df
		}
Packit Service b439df
		if (ret != -1)
Packit Service b439df
			ops++;
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	verbose_expose();
Packit Service b439df
Packit Service b439df
	if (opt_list_mounts)
Packit Service b439df
		mounts_list_all();
Packit Service b439df
Packit Service b439df
	if (opt_pool_list)
Packit Service b439df
		pool_list();
Packit Service b439df
Packit Service b439df
	if (opt_movable != -1)
Packit Service b439df
		setup_zone_movable(opt_movable);
Packit Service b439df
Packit Service b439df
	if (opt_trans_always)
Packit Service b439df
		set_trans_opt(TRANS_ENABLE, ALWAYS);
Packit Service b439df
Packit Service b439df
	if (opt_trans_madvise)
Packit Service b439df
		set_trans_opt(TRANS_ENABLE, MADVISE);
Packit Service b439df
Packit Service b439df
	if (opt_trans_never)
Packit Service b439df
		set_trans_opt(TRANS_ENABLE, NEVER);
Packit Service b439df
Packit Service b439df
	if (opt_khuge_pages)
Packit Service b439df
		set_trans_opt(KHUGE_SCAN_PAGES, khuge_pages);
Packit Service b439df
Packit Service b439df
	if (opt_khuge_alloc)
Packit Service b439df
		set_trans_opt(KHUGE_ALLOC_SLEEP, khuge_alloc);
Packit Service b439df
Packit Service b439df
	if (opt_khuge_scan)
Packit Service b439df
		set_trans_opt(KHUGE_SCAN_SLEEP, khuge_scan);
Packit Service b439df
Packit Service b439df
	if (opt_set_recommended_minfreekbytes)
Packit Service b439df
		set_recommended_minfreekbytes();
Packit Service b439df
Packit Service b439df
	if (opt_set_recommended_shmmax)
Packit Service b439df
		set_recommended_shmmax();
Packit Service b439df
Packit Service b439df
	if (opt_set_hugetlb_shm_group)
Packit Service b439df
		set_hugetlb_shm_group(opt_gid, opt_grp->gr_name);
Packit Service b439df
Packit Service b439df
	while (--minadj_count >= 0) {
Packit Service b439df
		if (! kernel_has_overcommit())
Packit Service b439df
			pool_adjust(opt_min_adj[minadj_count], POOL_BOTH);
Packit Service b439df
		else
Packit Service b439df
			pool_adjust(opt_min_adj[minadj_count], POOL_MIN);
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	while (--maxadj_count >=0)
Packit Service b439df
			pool_adjust(opt_max_adj[maxadj_count], POOL_MAX);
Packit Service b439df
Packit Service b439df
	if (opt_create_mounts) {
Packit Service b439df
		snprintf(base, PATH_MAX, "%s", MOUNT_DIR);
Packit Service b439df
		create_mounts(NULL, NULL, base, S_IRWXU | S_IRWXG);
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
Packit Service b439df
	if (opt_user_mounts != NULL) {
Packit Service b439df
		snprintf(base, PATH_MAX, "%s/user", MOUNT_DIR);
Packit Service b439df
		create_mounts(opt_user_mounts, NULL, base, S_IRWXU);
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	if (opt_group_mounts) {
Packit Service b439df
		snprintf(base, PATH_MAX, "%s/group", MOUNT_DIR);
Packit Service b439df
		create_mounts(NULL, opt_group_mounts, base, S_IRWXG);
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	if (opt_global_mounts) {
Packit Service b439df
		snprintf(base, PATH_MAX, "%s/global", MOUNT_DIR);
Packit Service b439df
		create_mounts(NULL, NULL, base, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX );
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	if (opt_pgsizes)
Packit Service b439df
		page_sizes(0);
Packit Service b439df
Packit Service b439df
	if (opt_pgsizes_all)
Packit Service b439df
		page_sizes(1);
Packit Service b439df
Packit Service b439df
	if (opt_explain)
Packit Service b439df
		explain();
Packit Service b439df
Packit Service b439df
	index = optind;
Packit Service b439df
Packit Service b439df
	if ((argc - index) != 0 || ops == 0) {
Packit Service b439df
		print_usage();
Packit Service b439df
		exit(EXIT_FAILURE);
Packit Service b439df
	}
Packit Service b439df
Packit Service b439df
	exit(EXIT_SUCCESS);
Packit Service b439df
}