/*
* libhugetlbfs - Easy use of Linux hugepages
* Copyright (C) 20015 Mike Kravetz, Oracle Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define _GNU_SOURCE
#include <linux/falloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <linux/falloc.h>
#include <hugetlbfs.h>
#include "hugetests.h"
#define P "fallocate-align"
#define DESC \
"* Test alignment of fallocate arguments. fallocate will take *\n"\
"* non-huge page aligned offsets and addresses. However, *\n"\
"* operations are only performed on huge pages. This is different *\n"\
"* that than fallocate behavior in "normal" filesystems. *"
int main(int argc, char *argv[])
{
long hpage_size;
int fd;
int err;
unsigned long free_before, free_after;
test_init(argc, argv);
hpage_size = check_hugepagesize();
fd = hugetlbfs_unlinked_fd();
if (fd < 0)
FAIL("hugetlbfs_unlinked_fd()");
free_before = get_huge_page_counter(hpage_size, HUGEPAGES_FREE);
/*
* First preallocate file with with just 1 byte. Allocation sizes
* are rounded up, so we should get an entire huge page.
*/
err = fallocate(fd, 0, 0, 1);
if (err) {
if (errno == EOPNOTSUPP)
IRRELEVANT();
if (err)
FAIL("fallocate(): %s", strerror(errno));
}
free_after = get_huge_page_counter(hpage_size, HUGEPAGES_FREE);
if (free_before - free_after != 1)
FAIL("fallocate 1 byte did not preallocate entire huge page\n");
/*
* Now punch a hole with just 1 byte. On hole punch, sizes are
* rounded down. So, this operation should not create a hole.
*/
err = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
0, 1);
if (err)
FAIL("fallocate(FALLOC_FL_PUNCH_HOLE): %s", strerror(errno));
free_after = get_huge_page_counter(hpage_size, HUGEPAGES_FREE);
if (free_after == free_before)
FAIL("fallocate hole punch 1 byte free'ed a huge page\n");
/*
* Now punch a hole with of 2 * hpage_size - 1 byte. This size
* should be rounded down to a single huge page and the hole created.
*/
err = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
0, (2 * hpage_size) - 1);
if (err)
FAIL("fallocate(FALLOC_FL_PUNCH_HOLE): %s", strerror(errno));
free_after = get_huge_page_counter(hpage_size, HUGEPAGES_FREE);
if (free_after != free_before)
FAIL("fallocate hole punch 2 * hpage_size - 1 byte did not free huge page\n");
/*
* Perform a preallocate operation with offset 1 and size of
* hpage_size. The offset should be rounded down and the
* size rounded up to preallocate two huge pages.
*/
err = fallocate(fd, 0, 1, hpage_size);
if (err)
FAIL("fallocate(): %s", strerror(errno));
free_after = get_huge_page_counter(hpage_size, HUGEPAGES_FREE);
if (free_before - free_after != 2)
FAIL("fallocate 1 byte offset, huge page size did not preallocate two huge pages\n");
/*
* The hole punch code will only delete 'whole' huge pags that are
* in the specified range. The offset is rounded up, and (offset
* + size) is rounded down to determine the huge pages to be deleted.
* In this case, after rounding the range is (hpage_size, hpage_size).
* So, no pages should be deleted.
*/
err = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
1, hpage_size);
if (err)
FAIL("fallocate(FALLOC_FL_PUNCH_HOLE): %s", strerror(errno));
free_after = get_huge_page_counter(hpage_size, HUGEPAGES_FREE);
if (free_before - free_after != 2)
FAIL("fallocate hole punch 1 byte offset, huge page size incorrectly deleted a huge page\n");
/*
* To delete both huge pages, the range passed to hole punch must
* overlap the allocated pages
*/
err = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
0, 2 * hpage_size);
if (err)
FAIL("fallocate(FALLOC_FL_PUNCH_HOLE): %s", strerror(errno));
free_after = get_huge_page_counter(hpage_size, HUGEPAGES_FREE);
if (free_after != free_before)
FAIL("fallocate hole punch did not delete two huge pages\n");
PASS();
}