Blame support/support_descriptor_supports_holes.c

Packit Service 12b0ed
/* Test for file system hole support.
Packit Service 12b0ed
   Copyright (C) 2018 Free Software Foundation, Inc.
Packit Service 12b0ed
   This file is part of the GNU C Library.
Packit Service 12b0ed
Packit Service 12b0ed
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 12b0ed
   modify it under the terms of the GNU Lesser General Public
Packit Service 12b0ed
   License as published by the Free Software Foundation; either
Packit Service 12b0ed
   version 2.1 of the License, or (at your option) any later version.
Packit Service 12b0ed
Packit Service 12b0ed
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 12b0ed
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 12b0ed
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 12b0ed
   Lesser General Public License for more details.
Packit Service 12b0ed
Packit Service 12b0ed
   You should have received a copy of the GNU Lesser General Public
Packit Service 12b0ed
   License along with the GNU C Library; if not, see
Packit Service 12b0ed
   <http://www.gnu.org/licenses/>.  */
Packit Service 12b0ed
Packit Service 12b0ed
#include <stdbool.h>
Packit Service 12b0ed
#include <support.h>
Packit Service 12b0ed
#include <support/check.h>
Packit Service 12b0ed
#include <sys/stat.h>
Packit Service 12b0ed
#include <xunistd.h>
Packit Service 12b0ed
Packit Service 12b0ed
int
Packit Service 12b0ed
support_descriptor_supports_holes (int fd)
Packit Service 12b0ed
{
Packit Service 12b0ed
  enum
Packit Service 12b0ed
    {
Packit Service 12b0ed
      /* Write offset for the enlarged file.  This value is arbitrary
Packit Service 12b0ed
         and hopefully large enough to trigger the creation of holes.
Packit Service 12b0ed
         We cannot use the file system block size as a reference here
Packit Service 12b0ed
         because it is incorrect for network file systems.  */
Packit Service 12b0ed
      write_offset = 16 * 1024 * 1024,
Packit Service 12b0ed
Packit Service 12b0ed
      /* Our write may add this number of additional blocks (see
Packit Service 12b0ed
         block_limit below).  */
Packit Service 12b0ed
      block_headroom = 8,
Packit Service 12b0ed
    };
Packit Service 12b0ed
Packit Service 12b0ed
  struct stat64 st;
Packit Service 12b0ed
  xfstat (fd, &st);
Packit Service 12b0ed
  if (!S_ISREG (st.st_mode))
Packit Service 12b0ed
    FAIL_EXIT1 ("descriptor %d does not refer to a regular file", fd);
Packit Service 12b0ed
  if (st.st_size != 0)
Packit Service 12b0ed
    FAIL_EXIT1 ("descriptor %d does not refer to an empty file", fd);
Packit Service 12b0ed
  if (st.st_blocks > block_headroom)
Packit Service 12b0ed
    FAIL_EXIT1 ("descriptor %d refers to a pre-allocated file (%lld blocks)",
Packit Service 12b0ed
                fd, (long long int) st.st_blocks);
Packit Service 12b0ed
Packit Service 12b0ed
  /* Write a single byte at the start of the file to compute the block
Packit Service 12b0ed
     usage for a single byte.  */
Packit Service 12b0ed
  xlseek (fd, 0, SEEK_SET);
Packit Service 12b0ed
  char b = '@';
Packit Service 12b0ed
  xwrite (fd, &b, 1);
Packit Service 12b0ed
  /* Attempt to bypass delayed allocation.  */
Packit Service 12b0ed
  TEST_COMPARE (fsync (fd), 0);
Packit Service 12b0ed
  xfstat (fd, &st);
Packit Service 12b0ed
Packit Service 12b0ed
  /* This limit is arbitrary.  The file system needs to store
Packit Service 12b0ed
     somewhere that data exists at the write offset, and this may
Packit Service 12b0ed
     moderately increase the number of blocks used by the file, in
Packit Service 12b0ed
     proportion to the initial block count, but not in proportion to
Packit Service 12b0ed
     the write offset.  */
Packit Service 12b0ed
  unsigned long long int block_limit = 2 * st.st_blocks + block_headroom;
Packit Service 12b0ed
Packit Service 12b0ed
  /* Write a single byte at 16 megabytes.  */
Packit Service 12b0ed
  xlseek (fd, write_offset, SEEK_SET);
Packit Service 12b0ed
  xwrite (fd, &b, 1);
Packit Service 12b0ed
  /* Attempt to bypass delayed allocation.  */
Packit Service 12b0ed
  TEST_COMPARE (fsync (fd), 0);
Packit Service 12b0ed
  xfstat (fd, &st);
Packit Service 12b0ed
  bool supports_holes = st.st_blocks <= block_limit;
Packit Service 12b0ed
Packit Service 12b0ed
  /* Also check that extending the file does not fill up holes.  */
Packit Service 12b0ed
  xftruncate (fd, 2 * write_offset);
Packit Service 12b0ed
  /* Attempt to bypass delayed allocation.  */
Packit Service 12b0ed
  TEST_COMPARE (fsync (fd), 0);
Packit Service 12b0ed
  xfstat (fd, &st);
Packit Service 12b0ed
  supports_holes = supports_holes && st.st_blocks <= block_limit;
Packit Service 12b0ed
Packit Service 12b0ed
  /* Return to a zero-length file.  */
Packit Service 12b0ed
  xftruncate (fd, 0);
Packit Service 12b0ed
  xlseek (fd, 0, SEEK_SET);
Packit Service 12b0ed
Packit Service 12b0ed
  return supports_holes;
Packit Service 12b0ed
}