#!/usr/bin/perl -w
#
# $Header: $
#

$| = 1;
($prog = $0) =~ s/.*\///;

use POSIX qw(ceil);

# The one (and only) argument to this script is the autofs(5) key
die "$prog: illegal argument count!\n" unless (scalar(@ARGV) == 1);
our $key = shift(@ARGV);

# Key processing: a valid specification is a non-negative request size
# followed optionally by 'KB', 'MB', or 'GB' (case insensitive).  Not
# specifying a unit of the request size implies a request for that many
# nr_hugepages; otherwise this value is (best fit) caculated from the given
# kernel's hugepagesize.
our $req_size = undef;
our $req_unit = undef;
if ($key =~ /^(\d+)([kmg]b)?$/i) {
   chomp $key;
   $req_size = $1;
   $req_unit = uc($2) if (defined $2);
} else {
   die "$prog: malformed key: $key\n";
}
die "$prog: request size must be non-negative: $key!\n"
   unless ($req_size >= 0);

# Avoid a second mount in $mnt_pt; you must wait 'til automount expires it
our $mnt_pt = '/huge';
die "$prog: $!\n." unless (opendir(MNT, $mnt_pt));
our @Mounts = grep { $_ !~ /^\.{1,2}$/ } readdir(MNT);
closedir(MNT);
die "$prog: mount(s) already exist in $mnt_pt!\n" if (scalar @Mounts);

# Translate the request size into nr_hugepages
if (defined $req_unit) {
   $req_size *= 1024 if ($req_unit eq 'MB');		# Mbytes -> Kbytes
   $req_size *= 1024*1024 if ($req_unit eq 'GB');	# Gbytes -> Kbytes
   my $hugepg_size = undef;
   my $hugepg_unit = undef;
   open (MEMINFO, '/proc/meminfo')
      || die "$prog: unable to open /proc/meminfo for reading: $!.\n";
   while (defined (my $line = <MEMINFO>)) {
      if ($line =~ /^hugepagesize:\s+(\d+)\s+([km]b)$/i) {
	 $hugepg_size = $1;
	 $hugepg_unit = uc($2);
	 last;
      }
   }
   close MEMINFO;
   die "$prog: unable to determine kernel's hugepagesize!\n"
      unless (defined($hugepg_size) && defined($hugepg_unit));
   $hugepg_size *= 1024 if ($hugepg_unit eq 'MB');	# Mbytes -> Kbytes
   our $nr_hugepages = ceil($req_size/$hugepg_size);	# round up
} else {
   our $nr_hugepages = $req_size;
}

# HTLB settings
open (NR, '+</proc/sys/vm/nr_hugepages')
   || die "$prog: unable to open /proc/sys/vm/nr_hugepages for r/w: $!.\n";
print NR $nr_hugepages;		# request nr_hugepages
seek (NR, 0, 0);		# seek to beginning
chomp(my $nr = <NR>);		# system reserved $nr nr_hugepages
close NR;
warn "$prog: got $nr of requested $nr_hugepages nr_hugepages!\n"
   if ($nr != $nr_hugepages);

# Success: mount "value"
print STDOUT '-fstype=hugetlbfs,rw,uid=$UID,gid=$GID,mode=700 nodev' . "\n";
exit 0;
