1 /* extent-scan.c -- core functions for scanning extents
2 Copyright (C) 2010 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 Written by Jie Liu (jeff.liu@oracle.com). */
21 #include <sys/types.h>
22 #include <sys/ioctl.h>
26 #include "extent-scan.h"
32 /* Allocate space for struct extent_scan, initialize the entries if
33 necessary and return it as the input argument of extent_scan_read(). */
35 extent_scan_init (int src_fd
, struct extent_scan
*scan
)
40 scan
->initial_scan_failed
= false;
41 scan
->hit_final_extent
= false;
45 # ifndef FS_IOC_FIEMAP
46 # define FS_IOC_FIEMAP _IOWR ('f', 11, struct fiemap)
48 /* Call ioctl(2) with FS_IOC_FIEMAP (available in linux 2.6.27) to
49 obtain a map of file extents excluding holes. */
51 extent_scan_read (struct extent_scan
*scan
)
53 union { struct fiemap f
; char c
[4096]; } fiemap_buf
;
54 struct fiemap
*fiemap
= &fiemap_buf
.f
;
55 struct fiemap_extent
*fm_extents
= &fiemap
->fm_extents
[0];
56 enum { count
= (sizeof fiemap_buf
- sizeof *fiemap
) / sizeof *fm_extents
};
59 /* This is required at least to initialize fiemap->fm_start,
60 but also serves (in mid 2010) to appease valgrind, which
61 appears not to know the semantics of the FIEMAP ioctl. */
62 memset (&fiemap_buf
, 0, sizeof fiemap_buf
);
64 fiemap
->fm_start
= scan
->scan_start
;
65 fiemap
->fm_flags
= FIEMAP_FLAG_SYNC
;
66 fiemap
->fm_extent_count
= count
;
67 fiemap
->fm_length
= FIEMAP_MAX_OFFSET
- scan
->scan_start
;
69 /* Fall back to the standard copy if call ioctl(2) failed for the
71 if (ioctl (scan
->fd
, FS_IOC_FIEMAP
, fiemap
) < 0)
73 if (scan
->scan_start
== 0)
74 scan
->initial_scan_failed
= true;
78 /* If 0 extents are returned, then more get_extent_table() are not needed. */
79 if (fiemap
->fm_mapped_extents
== 0)
81 scan
->hit_final_extent
= true;
85 scan
->ei_count
= fiemap
->fm_mapped_extents
;
86 scan
->ext_info
= xnmalloc (scan
->ei_count
, sizeof (struct extent_info
));
89 for (i
= 0; i
< scan
->ei_count
; i
++)
91 assert (fm_extents
[i
].fe_logical
<= OFF_T_MAX
);
93 scan
->ext_info
[i
].ext_logical
= fm_extents
[i
].fe_logical
;
94 scan
->ext_info
[i
].ext_length
= fm_extents
[i
].fe_length
;
95 scan
->ext_info
[i
].ext_flags
= fm_extents
[i
].fe_flags
;
99 if (scan
->ext_info
[i
].ext_flags
& FIEMAP_EXTENT_LAST
)
101 scan
->hit_final_extent
= true;
105 scan
->scan_start
= fm_extents
[i
].fe_logical
+ fm_extents
[i
].fe_length
;
111 extent_scan_read (struct extent_scan
*scan ATTRIBUTE_UNUSED
)