hjl / source-git / glibc

Forked from source-git/glibc 3 years ago
Clone

Blame support/support_descriptor_supports_holes.c

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