On 26 March 2012 02:13, Dan Shelton <[email protected]> wrote:
> Hello,
>
> are there plans to implement support for SEEK_HOLE (let lseek() seek
> to the next hole in a sparse file) and SEEK_DATA (let lseek() seek to
> the next place with real data, usually after a hole) in AST cp, mv and
> pax in the next 2-3 months? This has become VERY important to
> enterprise customers now that Linux+btrfs, GNU coreutils, Solaris,
> FreeBSD and others support this feature and that it is going to be
> included in the next iteration of the POSIX standard
> (http://man7.org/linux/man-pages/man2/lseek.2.html)
>
> I've forwarded an older email of Jeff Liu describing some internals at
> the end of this email about the GNU coreutils implementation as
> context.
>
> ---------- Forwarded message ----------
> From: Jeff Liu <[email protected]>
> Date: Fri, Aug 26, 2011 at 11:43 AM
> Subject: Re: [zfs-discuss] bug#8061: Introduce SEEK_DATA/SEEK_HOLE to
> extent_scan module
> To: [email protected]
> Cc: [email protected], [email protected],
> [email protected]
>
>
> Dear All,
>
> As the SEEK_HOLE/SEEK_DATA has been implemented on Btrfs in 3.1.0+ and
> Glibc, I have worked out a new version for your guys review.
>
> Changes:
> ======
> extent_scan.[c|h]:
> 1.  add a function pointer to "struct extent_scan":
> /* Scan method.  */
> bool (*extent_scan) (struct extent_scan *scan);
>
> 2. add  a structure item to indicate seek back issue maybe occurred:
> /* Failed to seek back to position 0 or not.  */
> bool seek_back_failed;
> If the file system support SEEK_HOLE, the file offset will pointed to
> somewhere > 0, so need to
> seek back to the beginning after support_seek_hole() checking for the
> proceeding extent scan.
>
> 3. rename extent_scan to fiemap_extent_scan.
>
> 4. add a new seek_extent_scan method.
>
> 5. add a new method to check SEEK stuff is supported or not.
> if the underlaying file system support SEEK_HOLE, assign
> seek_extent_scan to scan->extent_scan, or else, fiemap_extent_scan()
> will be assigned to it.
>
> copy.c:
> 1. pass src_total_size to extent_scan_init ().
> 2. for the first round extent scan,  we need to seek back to position
> 0 too, if the data extent is started at the beginning of source file.
>
> Tested:
> ======
> 1. make syntax-check.
> 2. verify a copied sparse file with 4697 extents on btrfs
> jeff@pibroch:~/gnu/coreutils$ python -c "f=open('/btrfs/sparse_test',
> 'w'); [(f.seek(x) or f.write(str(x))) for x in range(1, 1000000000,
> 99999)]; f.close()"
> jeff@pibroch:~/gnu/coreutils$ ./src/cp --sparse=always
> /btrfs/sparse_test /btrfs/sp.seek
> jeff@pibroch:~/gnu/coreutils$ cmp /btrfs/sparse_test /btrfs/sp.seek
> jeff@pibroch:~/gnu/coreutils$ echo $?
> 0
>
> Also, the previous patch was developed on Solaris ZFS,  but my test
> env was lost now. :(  so anyone can help testing it on ZFS would be
> appreciated!!
>
>
> From 5892744f977a06b5557042682c39fd007eec8030 Mon Sep 17 00:00:00 2001
> From: Jie Liu <[email protected]>
> Date: Fri, 26 Aug 2011 17:11:33 +0800
> Subject: [PATCH 1/1] copy: add SEEK_DATA/SEEK_HOLE support to extent_scan 
> module
>
> * src/extent_scan.h: introduce src_total_size to struct extent_info, we
>  need it for lseek(2) iteration, add seek_back_failed to indicate that the
>  seek back to position 0 failed in seek captical check or not, and it can
>  be used for further debugging IMHO.
>  add bool (*extent_scan) (struct extent_scan *scan) to switch the scan method.
> * src/extent_scan.c: implement a new seek_scan_read() through SEEK_DATA
>  and SEEK_HOLE.
> * src/copy.c: a few code changes according to the new extent call interface.
>
> Signed-off-by: Jie Liu <[email protected]>
> ---
>  src/copy.c        |   26 +++++++++-
>  src/extent-scan.c |  149 ++++++++++++++++++++++++++++++++++++++++++++++++++--
>  src/extent-scan.h |   16 +++++-
>  3 files changed, 183 insertions(+), 8 deletions(-)
>
> diff --git a/src/copy.c b/src/copy.c
> index bc4d7bd..c5e8714 100644
> --- a/src/copy.c
> +++ b/src/copy.c
> @@ -309,7 +309,18 @@ extent_copy (int src_fd, int dest_fd, char *buf,
> size_t buf_size,
>     We may need this at the end, for a final ftruncate.  */
>  off_t dest_pos = 0;
>
> -  extent_scan_init (src_fd, &scan);
> +  bool init_ok = extent_scan_init (src_fd, src_total_size, &scan);
> +  /* If the underlaying file system support SEEK_HOLE, but failed
> +     to seek back to position 0 after the initial seek checking,
> +     let extent copy failure in this case.  */
> +  if (! init_ok)
> +    {
> +      if (scan.seek_back_failed)
> +        error (0, errno,
> +          _("%s: extent_scan_init () failed, cannot seek back to position 
> 0"),
> +               quote (src_name));
> +      return false;
> +    }
>
>  *require_normal_copy = false;
>  bool wrote_hole_at_eof = true;
> @@ -356,6 +367,19 @@ extent_copy (int src_fd, int dest_fd, char *buf,
> size_t buf_size,
>
>          wrote_hole_at_eof = false;
>
> +          /* For the first round scan, if the data extent start at the
> +             beginning, and the current file pointer is not at position
> +             0, set it back first, otherwise, we'll read from undesired
> +             file offset.  */
> +          if (ext_start == 0 && lseek (src_fd, 0, SEEK_CUR) != 0)
> +            {
> +              if (lseek (src_fd, 0, SEEK_SET) < 0)
> +                {
> +                  error (0, errno, _("cannot lseek %s"), quote (src_name));
> +                  return false;
> +                }
> +            }
> +
>          if (hole_size)
>            {
>              if (lseek (src_fd, ext_start, SEEK_SET) < 0)
> diff --git a/src/extent-scan.c b/src/extent-scan.c
> index 37445b8..c835b63 100644
> --- a/src/extent-scan.c
> +++ b/src/extent-scan.c
> @@ -27,6 +27,12 @@
>  #include "fiemap.h"
>  #include "xstrtol.h"
>
> +#ifndef SEEK_DATA
> +# define SEEK_DATA 3  /* Seek to next data.  */
> +#endif
> +#ifndef SEEK_HOLE
> +# define SEEK_HOLE 4  /* Seek to next hole.  */
> +#endif
>
>  /* Work around Linux kernel issues on BTRFS and EXT4 before 2.6.39.
>   FIXME: remove in 2013, or whenever we're pretty confident
> @@ -65,10 +71,48 @@ extent_need_sync (void)
>  #endif
>  }
>
> +static bool
> +support_seek_hole (struct extent_scan *scan)
> +{
> +  off_t hole_pos;
> +
> +# ifdef _PC_MIN_HOLE_SIZE
> +  /* To determine if the underlaying file system support
> +     SEEK_HOLE, if not, fall back to fiemap extent scan or
> +     the standard copy.  */
> +  if (fpathconf (scan->fd, _PC_MIN_HOLE_SIZE) < 0)
> +      return false;
> +# endif
> +
> +  /* Inspired by STAR, If we have been compiled on an OS that
> +     supports SEEK_HOLE but run on an OS that does not support
> +     SEEK_HOLE, we get EINVAL.  If the underlying file system
> +     does not support the SEEK_HOLE call, we get ENOTSUP, fall
> +     back to the fiemap scan or standard copy in either case.  */
> +  hole_pos = lseek (scan->fd, (off_t) 0, SEEK_HOLE);
> +  if (hole_pos < 0)
> +    {
> +      if (errno == EINVAL || errno == ENOTSUP)
> +          return false;
> +    }
> +
> +  /* Seek back to position 0 first if we detected a real hole.  */
> +  if (hole_pos > 0)
> +    {
> +      if (lseek (scan->fd, (off_t) 0, SEEK_SET) != 0)
> +        {
> +          scan->seek_back_failed = true;
> +          return false;
> +        }
> +    }
> +
> +  return true;
> +}
> +
>  /* Allocate space for struct extent_scan, initialize the entries if
>   necessary and return it as the input argument of extent_scan_read().  */
> -extern void
> -extent_scan_init (int src_fd, struct extent_scan *scan)
> +extern bool
> +extent_scan_init (int src_fd, size_t src_total_size, struct extent_scan 
> *scan)
>  {
>  scan->fd = src_fd;
>  scan->ei_count = 0;
> @@ -76,17 +120,110 @@ extent_scan_init (int src_fd, struct extent_scan *scan)
>  scan->scan_start = 0;
>  scan->initial_scan_failed = false;
>  scan->hit_final_extent = false;
> -  scan->fm_flags = extent_need_sync () ? FIEMAP_FLAG_SYNC : 0;
> +  scan->seek_back_failed = false;
> +
> +  if (support_seek_hole (scan))
> +    {
> +      scan->src_total_size = src_total_size;
> +      scan->extent_scan = seek_extent_scan;
> +    }
> +  else
> +    {
> +      /* The underlying file system support SEEK_HOLE, but failed
> +         to seek back to position 0 after seek checking, Oops!  */
> +      if (scan->seek_back_failed)
> +        return false;
> +
> +      scan->extent_scan = fiemap_extent_scan;
> +      scan->fm_flags = extent_need_sync () ? FIEMAP_FLAG_SYNC : 0;
> +    }
> +
> +  return true;
> +}
> +
> +extern inline bool
> +extent_scan_read (struct extent_scan *scan)
> +{
> +  return scan->extent_scan (scan);
> +}
> +
> +extern bool
> +seek_extent_scan (struct extent_scan *scan)
> +{
> +  off_t data_pos, hole_pos;
> +  union { struct extent_info ei; char c[4096]; } extent_buf;
> +  struct extent_info *ext_info = &extent_buf.ei;
> +  enum { count = (sizeof extent_buf / sizeof *ext_info) };
> +  verify (count != 0);
> +
> +  memset (&extent_buf, 0, sizeof extent_buf);
> +
> +  unsigned int i = 0;
> +  /* If lseek(2) failed and the errno is set to ENXIO, for
> +     SEEK_DATA there are no more data regions past the supplied
> +     offset.  For SEEK_HOLE, there are no more holes past the
> +     supplied offset.  Set scan->hit_final_extent to true for
> +     either case.  */
> +  do {
> +    data_pos = lseek (scan->fd, scan->scan_start, SEEK_DATA);
> +    if (data_pos < 0)
> +      {
> +        if (errno == ENXIO)
> +          {
> +            scan->hit_final_extent = true;
> +            return true;
> +          }
> +        return false;
> +      }
> +
> +    /* We hit the final extent if the data offset is equal to
> +       the source file size.  */
> +    if (data_pos == scan->src_total_size)
> +      {
> +        scan->hit_final_extent = true;
> +        break;
> +      }
> +
> +    hole_pos = lseek (scan->fd, data_pos, SEEK_HOLE);
> +    if (hole_pos < 0)
> +      {
> +        if (errno != ENXIO)
> +          return false;
> +        else
> +          {
> +            scan->hit_final_extent = true;
> +            return true;
> +          }
> +      }
> +
> +    ext_info[i].ext_logical = data_pos;
> +    ext_info[i].ext_length = hole_pos - data_pos;
> +    scan->scan_start = hole_pos;
> +    ++i;
> +  } while (scan->scan_start < scan->src_total_size && i < count);
> +
> +  scan->ei_count = i;
> +  scan->ext_info = xnmalloc (scan->ei_count, sizeof (struct extent_info));
> +
> +  for (i = 0; i < scan->ei_count; i++)
> +    {
> +      assert (ext_info[i].ext_logical <= OFF_T_MAX);
> +
> +      scan->ext_info[i].ext_logical = ext_info[i].ext_logical;
> +      scan->ext_info[i].ext_length = ext_info[i].ext_length;
> +    }
> +
> +  return true;
>  }
>
> -#ifdef __linux__
> +#if defined __linux__
>  # ifndef FS_IOC_FIEMAP
>  #  define FS_IOC_FIEMAP _IOWR ('f', 11, struct fiemap)
>  # endif
>  /* Call ioctl(2) with FS_IOC_FIEMAP (available in linux 2.6.27) to
>   obtain a map of file extents excluding holes.  */
>  extern bool
> -extent_scan_read (struct extent_scan *scan)
> +fiemap_extent_scan (struct extent_scan *scan)
>  {
>  unsigned int si = 0;
>  struct extent_info *last_ei IF_LINT ( = scan->ext_info);
> @@ -212,7 +349,7 @@ extent_scan_read (struct extent_scan *scan)
>  }
>  #else
>  extern bool
> -extent_scan_read (struct extent_scan *scan ATTRIBUTE_UNUSED)
> +fiemap_extent_scan (struct extent_scan *scan ATTRIBUTE_UNUSED)
>  {
>  scan->initial_scan_failed = true;
>  errno = ENOTSUP;
> diff --git a/src/extent-scan.h b/src/extent-scan.h
> index 5b4ded5..e751810 100644
> --- a/src/extent-scan.h
> +++ b/src/extent-scan.h
> @@ -38,6 +38,9 @@ struct extent_scan
>  /* File descriptor of extent scan run against.  */
>  int fd;
>
> +  /* Source file size, i.e, (struct stat) &statbuf.st_size.  */
> +  size_t src_total_size;
> +
>  /* Next scan start offset.  */
>  off_t scan_start;
>
> @@ -47,6 +50,9 @@ struct extent_scan
>  /* How many extent info returned for a scan.  */
>  uint32_t ei_count;
>
> +  /* Failed to seek back to position 0 or not.  */
> +  bool seek_back_failed;
> +
>  /* If true, fall back to a normal copy, either set by the
>     failure of ioctl(2) for FIEMAP or lseek(2) with SEEK_DATA.  */
>  bool initial_scan_failed;
> @@ -54,14 +60,22 @@ struct extent_scan
>  /* If true, the total extent scan per file has been finished.  */
>  bool hit_final_extent;
>
> +  /* Scan method.  */
> +  bool (*extent_scan) (struct extent_scan *scan);
> +
>  /* Extent information: a malloc'd array of ei_count structs.  */
>  struct extent_info *ext_info;
>  };
>
> -void extent_scan_init (int src_fd, struct extent_scan *scan);
> +bool extent_scan_init (int src_fd, size_t src_total_size,
> +                       struct extent_scan *scan);
>
>  bool extent_scan_read (struct extent_scan *scan);
>
> +bool fiemap_extent_scan (struct extent_scan *scan);
> +
> +bool seek_extent_scan (struct extent_scan *scan);
> +
>  static inline void
>  extent_scan_free (struct extent_scan *scan)
>  {
> --
> 1.7.4.1
>
>
>
> Thanks,
> -Jeff
>
> On 04/19/2011 04:51 PM, Jeff liu wrote:
>>>
>>> Hi All,
>>>
>>> Please ignore the current patch, I will submit another patch with a few 
>>> fixes soon.
>>
>> Now the new patch set coming,
>>
>> In previous post, I have tried to change the extent_scan_init() interface by 
>> adding a new argument to indicate the source file size,
>> this will reduce the overhead of call fstat(2)  in extent_scan_read(), since 
>> the file size is definitely needed for SEEK* stuff, however, the file size 
>> is redundant for FIEMAP.
>> so I changed my idea to keep extent_scan_init() as before,  instead, to 
>> retrieve the file size in extent_scan_read() when launching the first scan, 
>> one benefit is, there is nothing need to
>> be modified in extent_copy() for this patch.
>>
>> Tests:
>> ====
>> A new test sparse-lseek was introduced in this post, it make use of the 
>> sparse file generation function in Perl, and do `cmp` against the target 
>> copied file.
>> I have also took a look at the `sdb` utility shipped with ZFS, but did not 
>> found any interesting stuff can be used for this test.
>>
>> Test run passed on my environment as below,
>>
>> bash-3.00# make check TESTS=cp/sparse-lseek VERBOSE=yes
>> make  check-TESTS
>> make[1]: Entering directory `/coreutils/tests'
>> make[2]: Entering directory `/coreutils/tests'
>> PASS: cp/sparse-lseek
>> =============
>> 1 test passed
>> =============
>> make[2]: Leaving directory `/coreutils/tests'
>> make[1]: Leaving directory `/coreutils/tests'
>>   GEN    vc_exe_in_TESTS
>> No differences encountered
>>
>> Manual tests:
>> ===========
>> 1. Ensure trailing blanks, test 0 size sparse file, non-sparse file,  sparse 
>> file with hole start and hole end.
>> 2. make syntax-check failed, I have no idea of this issue at the moment,  I 
>> also tried to run make distcheck, looks the package building, install and 
>> uninstall procedures all passed,
>> but it also failed at the final stage, am I missing something here?
>>
>> The logs which were shown as following,
>> bash-3.00# make syntax-check
>> GFDL_version
>> awk: syntax error near line 1
>> awk: bailing out near line 1
>> make: *** [sc_GFDL_version.z] Error 2
>>
>> make distcheck:
>> ==============
>> ......
>> make[1]: Entering directory `/coreutils'
>>   GEN    check-ls-dircolors
>> make my-distcheck
>> make[2]: Entering directory `/coreutils'
>> make syntax-check
>> make[3]: Entering directory `/coreutils'
>> GFDL_version
>> awk: syntax error near line 1
>> awk: bailing out near line 1
>> make[3]: *** [sc_GFDL_version.z] Error 2
>> make[3]: Leaving directory `/coreutils'
>> make[2]: *** [my-distcheck] Error 2
>> make[2]: Leaving directory `/coreutils'
>> make[1]: *** [distcheck-hook] Error 2
>> make[1]: Leaving directory `/coreutils'
>> make: *** [distcheck] Error 1
>>
>>
>>
>> Below is the revised patch,
>>
>>  From 4f966c1fe6226f3f711faae120cd8bea78e722b8 Mon Sep 17 00:00:00 2001
>> From: Jie Liu<[email protected]>
>> Date: Tue, 19 Apr 2011 15:24:50 -0700
>> Subject: [PATCH 1/1] copy: add SEEK_DATA/SEEK_HOLE support to extent_scan 
>> module
>>
>> * src/extent_scan.h: introduce src_total_size to struct extent_info, we
>>   need it for lseek(2) iteration.
>> * src/extent_scan.c: implement a new extent_scan_read() through SEEK_DATA
>>   and SEEK_HOLE if those stuff are supported.
>> * tests/cp/sparse-lseek: add a new test for lseek(2) extent copy.
>>
>> Signed-off-by: Jie Liu<[email protected]>
>> ---
>>  src/extent-scan.c     |  119 
>> +++++++++++++++++++++++++++++++++++++++++++++++++
>>  src/extent-scan.h     |    5 ++
>>  tests/Makefile.am     |    1 +
>>  tests/cp/sparse-lseek |   56 +++++++++++++++++++++++
>>  4 files changed, 181 insertions(+), 0 deletions(-)
>>  create mode 100755 tests/cp/sparse-lseek
>>
>> diff --git a/src/extent-scan.c b/src/extent-scan.c
>> index da7eb9d..a54eca0 100644
>> --- a/src/extent-scan.c
>> +++ b/src/extent-scan.c
>> @@ -17,7 +17,9 @@
>>     Written by Jie Liu ([email protected]).  */
>>
>>  #include<config.h>
>> +#include<fcntl.h>
>>  #include<sys/types.h>
>> +#include<sys/stat.h>
>>  #include<sys/ioctl.h>
>>  #include<sys/utsname.h>
>>  #include<assert.h>
>> @@ -71,6 +73,9 @@ extent_scan_init (int src_fd, struct extent_scan *scan)
>>    scan->initial_scan_failed = false;
>>    scan->hit_final_extent = false;
>>    scan->fm_flags = extent_need_sync () ? FIEMAP_FLAG_SYNC : 0;
>> +#if defined (SEEK_DATA)&&  defined (SEEK_HOLE)
>> +  scan->src_total_size = 0;
>> +#endif
>>  }
>>
>>  #ifdef __linux__
>> @@ -204,6 +209,120 @@ extent_scan_read (struct extent_scan *scan)
>>
>>    return true;
>>  }
>> +#elif defined (SEEK_HOLE)&&  defined (SEEK_DATA)
>> +extern bool
>> +extent_scan_read (struct extent_scan *scan)
>> +{
>> +  off_t data_pos, hole_pos;
>> +  union { struct extent_info ei; char c[4096]; } extent_buf;
>> +  struct extent_info *ext_info =&extent_buf.ei;
>> +  enum { count = (sizeof extent_buf / sizeof *ext_info) };
>> +  verify (count != 0);
>> +
>> +  memset (&extent_buf, 0, sizeof extent_buf);
>> +
>> +  if (scan->scan_start == 0)
>> +    {
>> +# ifdef _PC_MIN_HOLE_SIZE
>> +      /* To determine if the underlaying file system support
>> +         SEEK_HOLE.  If not, fall back to the standard copy.  */
>> +      if (fpathconf (scan->fd, _PC_MIN_HOLE_SIZE)<  0)
>> +        {
>> +          scan->initial_scan_failed = true;
>> +          return false;
>> +        }
>> +# endif
>> +
>> +      /* If we have been compiled on an OS that supports SEEK_HOLE
>> +         but run on an OS that does not support SEEK_HOLE, we get
>> +         EINVAL.  If the underlying file system does not support the
>> +         SEEK_HOLE call, we get ENOTSUP, setting initial_scan_failed
>> +         to true to fall back to the standard copy in either case.  */
>> +      hole_pos = lseek (scan->fd, (off_t) 0, SEEK_HOLE);
>> +      if (hole_pos<  0)
>> +        {
>> +          if (errno == EINVAL || errno == ENOTSUP)
>> +            scan->initial_scan_failed = true;
>> +          return false;
>> +        }
>> +
>> +      /* Seek back to position 0 first.  */
>> +      if (hole_pos>  0)
>> +        {
>> +          if (lseek (scan->fd, (off_t) 0, SEEK_SET)<  0)
>> +            return false;
>> +        }
>> +
>> +      struct stat sb;
>> +      if (fstat (scan->fd,&sb)<  0)
>> +        return false;
>> +
>> +      /* This is definitely not a sparse file, we treat it as a big extent. 
>>  */
>> +      if (hole_pos>= sb.st_size)
>> +        {
>> +          scan->ei_count = 1;
>> +          scan->ext_info = xnmalloc (scan->ei_count, sizeof (struct 
>> extent_info));
>> +          scan->ext_info[0].ext_logical = 0;
>> +          scan->ext_info[0].ext_length = sb.st_size;
>> +          scan->hit_final_extent = true;
>> +          return true;
>> +        }
>> +      scan->src_total_size = sb.st_size;
>> +    }
>> +
>> +  unsigned int i = 0;
>> +  /* If lseek(2) failed and the errno is set to ENXIO, for
>> +     SEEK_DATA there are no more data regions past the supplied
>> +     offset.  For SEEK_HOLE, there are no more holes past the
>> +     supplied offset.  Set scan->hit_final_extent to true in
>> +     either case.  */
>> +  while (scan->scan_start<  scan->src_total_size&&  i<  count)
>> +    {
>> +      data_pos = lseek (scan->fd, scan->scan_start, SEEK_DATA);
>> +      if (data_pos<  0)
>> +        {
>> +          if (errno == ENXIO)
>> +            {
>> +              scan->hit_final_extent = true;
>> +              break;
>> +            }
>> +          return false;
>> +        }
>> +
>> +      hole_pos = lseek (scan->fd, data_pos, SEEK_HOLE);
>> +      if (hole_pos<  0)
>> +        {
>> +          if (errno == ENXIO)
>> +            {
>> +              scan->hit_final_extent = true;
>> +              hole_pos = scan->src_total_size;
>> +              if (data_pos<  hole_pos)
>> +                goto preserve_ext_info;
>> +              break;
>> +            }
>> +          return false;
>> +        }
>> +
>> +preserve_ext_info:
>> +      ext_info[i].ext_logical = data_pos;
>> +      ext_info[i].ext_length = hole_pos - data_pos;
>> +      scan->scan_start = hole_pos;
>> +      ++i;
>> +    }
>> +
>> +  scan->ei_count = i;
>> +  scan->ext_info = xnmalloc (scan->ei_count, sizeof (struct extent_info));
>> +
>> +  for (i = 0; i<  scan->ei_count; i++)
>> +    {
>> +      assert (ext_info[i].ext_logical<= OFF_T_MAX);
>> +
>> +      scan->ext_info[i].ext_logical = ext_info[i].ext_logical;
>> +      scan->ext_info[i].ext_length = ext_info[i].ext_length;
>> +    }
>> +
>> +  return (lseek (scan->fd, (off_t) 0, SEEK_SET)<  0) ? false : true;
>> +}
>>  #else
>>  extern bool
>>  extent_scan_read (struct extent_scan *scan ATTRIBUTE_UNUSED)
>> diff --git a/src/extent-scan.h b/src/extent-scan.h
>> index 5b4ded5..4fc05c6 100644
>> --- a/src/extent-scan.h
>> +++ b/src/extent-scan.h
>> @@ -38,6 +38,11 @@ struct extent_scan
>>    /* File descriptor of extent scan run against.  */
>>    int fd;
>>
>> +# if defined (SEEK_DATA)&&  defined (SEEK_HOLE)
>> +  /* Source file size, i.e, (struct stat)&statbuf.st_size.  */
>> +  size_t src_total_size;
>> +#endif
>> +
>>    /* Next scan start offset.  */
>>    off_t scan_start;
>>
>> diff --git a/tests/Makefile.am b/tests/Makefile.am
>> index 685eb52..6c596b9 100644
>> --- a/tests/Makefile.am
>> +++ b/tests/Makefile.am
>> @@ -28,6 +28,7 @@ root_tests =                                  \
>>    cp/cp-mv-enotsup-xattr                      \
>>    cp/capability                                       \
>>    cp/sparse-fiemap                            \
>> +  cp/sparse-lseek                               \
>>    dd/skip-seek-past-dev                               \
>>    install/install-C-root                      \
>>    ls/capability                                       \
>> diff --git a/tests/cp/sparse-lseek b/tests/cp/sparse-lseek
>> new file mode 100755
>> index 0000000..5b8f2c1
>> --- /dev/null
>> +++ b/tests/cp/sparse-lseek
>> @@ -0,0 +1,56 @@
>> +#!/bin/sh
>> +# Test cp --sparse=always through lseek(SEEK_DATA/SEEK_HOLE) copy
>> +
>> +# Copyright (C) 2010-2011 Free Software Foundation, Inc.
>> +
>> +# This program is free software: you can redistribute it and/or modify
>> +# it under the terms of the GNU General Public License as published by
>> +# the Free Software Foundation, either version 3 of the License, or
>> +# (at your option) any later version.
>> +
>> +# This program 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 General Public License for more details.
>> +
>> +# You should have received a copy of the GNU General Public License
>> +# along with this program.  If not, see<http://www.gnu.org/licenses/>.
>> +
>> +. "${srcdir=.}/init.sh"; path_prepend_ ../src
>> +print_ver_ cp
>> +$PERL -e 1 || skip_test_ 'you lack perl'
>> +
>> +zfsdisk=diskX
>> +zfspool=seektest
>> +
>> +require_root_
>> +
>> +cwd=$PWD
>> +cleanup_() { zpool destroy $zfspool; }
>> +
>> +skip=0
>> +mkfile 128m "$cwd/$zfsdisk" || skip=1
>> +
>> +# Check if the seektest pool is already exists
>> +zpool list $zfspool 2>/dev/null&&
>> +  skip_test_ "$zfspool already exists"
>> +
>> +# Create pool and verify if it is mounted automatically
>> +zpool create $zfspool "$cwd/$zfsdisk" || skip=1
>> +zpool list $zfspool>/dev/null || skip=1
>> +
>> +test $skip = 1&&  skip_test_ "insufficient ZFS support"
>> +
>> +for i in $(seq 1 2 21); do
>> +  for j in 1 2 31 100; do
>> +    $PERL -e 'BEGIN { $n = '$i' * 1024; *F = *STDOUT }' \
>> +          -e 'for (1..'$j') { sysseek (*F, $n, 1)' \
>> +          -e '&&  syswrite (*F, chr($_)x$n) or die "$!"}'>  /$zfspool/j1 || 
>> fail=1
>> +
>> +    cp --sparse=always /$zfspool/j1 /$zfspool/j2 || fail=1
>> +    cmp /$zfspool/j1 /$zfspool/j2 || fail=1
>> +    test $fail = 1&&  break 2
>> +  done
>> +done
>> +
>> +Exit $fail

Per http://austingroupbugs.net/view.php?id=415 SEEK_HOLE/_DATA will be
in Issue 8 of the standard.

_______________________________________________
ast-users mailing list
[email protected]
https://mailman.research.att.com/mailman/listinfo/ast-users

Reply via email to