"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "fsremap/src/io/extent_posix.cc" between
fstransform-0.9.3-src.tar.gz and fstransform-0.9.4.tar.gz

About: fstransform is a tool to change a file-system from one format to another, for example from jfs, xfs, or reiser to ext2, ext3, or ext4, in-place and without the need for backup.

extent_posix.cc  (fstransform-0.9.3-src):extent_posix.cc  (fstransform-0.9.4)
skipping to change at line 74 skipping to change at line 74
#include "extent_posix.hh" // for ff_read_extents_posix() */ #include "extent_posix.hh" // for ff_read_extents_posix() */
#include "util_posix.hh" // for ff_posix_ioctl(), ff_posix_size() */ #include "util_posix.hh" // for ff_posix_ioctl(), ff_posix_size() */
FT_IO_NAMESPACE_BEGIN FT_IO_NAMESPACE_BEGIN
/** /**
* retrieves file blocks allocation map (extents) for specified file descriptor * retrieves file blocks allocation map (extents) for specified file descriptor
* and appends them to ret_vector (with user_data = FC_DEFAULT_USER_DATA). * and appends them to ret_vector (with user_data = FC_DEFAULT_USER_DATA).
* in case of failure returns errno-compatible error code, and ret_vector conten ts will be UNDEFINED. * in case of failure returns errno-compatible error code, and ret_vector conten ts will be UNDEFINED.
* *
* must (and will) also check that device blocks count can be represented by ret * must (and will) also check that device size can be represented by ret_list,
_list,
* by calling ret_list.extent_set_range(block_size, block_count)
* *
* implementation: calls ioctl(FIBMAP) * implementation: calls ioctl(FIBMAP)
*/ */
static int ff_posix_fibmap(int fd, ft_uoff dev_length, fr_vector<ft_uoff> & ret_ list, ft_uoff & ret_block_size_bitmask) static int ff_posix_fibmap(int fd, ft_uoff dev_length, fr_vector<ft_uoff> & ret_ list, ft_uoff & ret_block_size_bitmask)
{ {
#ifdef FIBMAP #ifdef FIBMAP
ft_uoff file_length, file_block_count, dev_block_count; ft_uoff file_length, file_block_count, dev_block_count;
ft_uoff block_size, logical_uoff, physical_uoff, block_size_bitmask = ret_bl ft_uoff ioctl_n = 0, block_size = 0, logical_uoff, physical_uoff;
ock_size_bitmask;
ft_size extent_n = ret_list.size();
/* lower-level API ff_posix_ioctl(FIGETBSZ) and ff_posix_ioctl(FIBMAP) need these to be int */ /* lower-level API ff_posix_ioctl(FIGETBSZ) and ff_posix_ioctl(FIBMAP) need these to be int */
int err = 0, block_size_int, logical, physical; int err = 0, block_size_int, logical, physical;
do { do {
if ((err = ff_posix_ioctl(fd, FIGETBSZ, & block_size_int))) { if ((err = ff_posix_ioctl(fd, FIGETBSZ, & block_size_int))) {
err = ff_log(FC_ERROR, err, "ff_posix_fibmap(): error in ioctl(%d, F IGETBSZ)", fd); err = ff_log(FC_ERROR, err, "ff_posix_fibmap(): error in ioctl(%d, F IGETBSZ)", fd);
break; break;
} }
block_size = (ft_uoff) block_size_int; block_size = (ft_uoff) block_size_int;
// ft_uoff is expected to be unsigned and wider than int, // ft_uoff is expected to be wider than int,
// but explicitly checking for overflow is always safer than "expecting" // but explicitly checking for overflow is always safer than "expecting"
if (block_size < 0 || block_size_int != (int) block_size) { if ((int) block_size != block_size_int) {
/* overflow! give up. */ /* overflow! give up. */
err = ff_log(FC_ERROR, EFBIG, "ff_posix_fibmap(): error, block_size = %"FT_ULL" overflows type (ft_uoff)", (ft_ull) block_size_int); err = ff_log(FC_ERROR, EFBIG, "ff_posix_fibmap(): error, block_size = %" FT_ULL " overflows type (ft_uoff)", (ft_ull) block_size_int);
break; break;
} }
/* keep track of bits used by extents. needed to compute effective block
size */
block_size_bitmask |= block_size;
if ((err = ff_posix_size(fd, & file_length))) { if ((err = ff_posix_size(fd, & file_length))) {
err = ff_log(FC_ERROR, err, "ff_posix_fibmap(): error in stat(%d)", fd); err = ff_log(FC_ERROR, err, "ff_posix_fibmap(): error in stat(%d)", fd);
break; break;
} }
// number of blocks in the device // number of blocks in the device
dev_block_count = (dev_length + block_size - 1) / block_size; dev_block_count = (dev_length + block_size - 1) / block_size;
// number of blocks in the file // number of blocks in the file
skipping to change at line 125 skipping to change at line 124
// ioctl(FIBMAP) wants an (int logical) and returns an (int physical) // ioctl(FIBMAP) wants an (int logical) and returns an (int physical)
// in units of one block, so we must check for overflow! // in units of one block, so we must check for overflow!
int n = (int) file_block_count; int n = (int) file_block_count;
int m = (int) dev_block_count; int m = (int) dev_block_count;
if (m < 0 || dev_block_count != (ft_uoff) m if (m < 0 || dev_block_count != (ft_uoff) m
|| n < 0 || file_block_count != (ft_uoff) n) || n < 0 || file_block_count != (ft_uoff) n)
{ {
/* overflow! give up. */ /* overflow! give up. */
err = ff_log(FC_ERROR, EFBIG, "ff_posix_fibmap(): error, dev_block_c err = ff_log(FC_ERROR, EFBIG, "ff_posix_fibmap(): error, dev_block_c
ount = %"FT_ULL", file_block_count = %"FT_ULL" overflow type (int)", ount = %" FT_ULL ", file_block_count = %" FT_ULL " overflow type (int)",
fd, (ft_ull) dev_block_count, (ft_ull) file_block_count (ft_ull) dev_block_count, (ft_ull) file_block_count);
);
break; break;
} }
for (logical = 0; logical < n; logical++) { for (logical = 0; logical < n; logical++) {
physical = logical; physical = logical;
ioctl_n++;
if ((err = ff_posix_ioctl(fd, FIBMAP, & physical))) { if ((err = ff_posix_ioctl(fd, FIBMAP, & physical))) {
err = ff_log(FC_ERROR, err, "ff_posix_fibmap(): error in ioctl(% d, FIBMAP, %"FT_ULL")", fd, (ft_ull) logical); err = ff_log(FC_ERROR, err, "ff_posix_fibmap(): error in ioctl(% d, FIBMAP, %" FT_ULL ")", fd, (ft_ull) logical);
break; break;
} }
/* FIBMAP reports holes (i.e. unallocated blocks in the file) as phy sical == 0. ugly */ /* FIBMAP reports holes (i.e. unallocated blocks in the file) as phy sical == 0. ugly */
if (physical != 0) { if (physical != 0) {
physical_uoff = (ft_uoff) physical * block_size; physical_uoff = (ft_uoff) physical * block_size;
logical_uoff = (ft_uoff) logical * block_size; logical_uoff = (ft_uoff) logical * block_size;
/* keep track of bits used by extents. needed to compute effecti
ve block size */
ret_block_size_bitmask |= physical_uoff | logical_uoff;
/* this is painful... FIBMAP reports one block per call */ /* this is painful... FIBMAP reports one block per call */
ret_list.append(physical_uoff, logical_uoff, block_size, FC_DEFA ULT_USER_DATA); ret_list.append(physical_uoff, logical_uoff, block_size, FC_DEFA ULT_USER_DATA);
} }
} }
} while (0); } while (0);
if (err == 0) { if (err == 0) {
ff_log(FC_DEBUG, 0, "ioctl(%d, FIBMAP) succeeded", fd); static ft_ull log_count = 0;
ret_block_size_bitmask = block_size_bitmask;
if (log_count++ == 5)
ff_log(FC_DEBUG, 0, "decreasing to level TRACE any further DEBUG mes
sage 'ioctl(FIBMAP) successful'");
extent_n = ret_list.size() - extent_n;
ff_log(log_count < 5 ? FC_DEBUG : FC_TRACE, 0, "ioctl(%d, FIBMAP) succes
sful: retrieved %" FT_ULL " extent%s in %" FT_ULL " call%s",
fd, (ft_ull) extent_n, extent_n == 1 ? "" : "s", (ft_ull) ioctl_
n, ioctl_n == 1 ? "" : "s");
/* keep track of bits used by extents. needed to compute effective block
size */
ret_block_size_bitmask |= block_size;
} }
return err; return err;
#else #else
return ENOSYS; return ENOSYS;
#endif /* FIBMAP */ #endif /* FIBMAP */
} }
#ifdef FS_IOC_FIEMAP #ifdef FS_IOC_FIEMAP
static int ff_linux_fiemap_ioctl(int fd, ft_uoff file_length, ft_u32 extent_n, s static int ff_linux_fiemap(int fd, ft_uoff file_start, ft_uoff file_end, ft_u32
truct fiemap ** ret_k_map) { extent_n, struct fiemap * k_map)
struct fiemap * k_map; {
ft_size k_len = sizeof(struct fiemap) + extent_n * sizeof(struct fiemap_exte nt); ft_size k_len = sizeof(struct fiemap) + extent_n * sizeof(struct fiemap_exte nt);
int err = 0;
do { memset(k_map, 0, k_len);
k_map = (struct fiemap *) malloc(k_len);
if (k_map == NULL) {
err = ENOMEM; /* Out of memory */
/* do not mark the error as reported, this is just a DEBUG message *
/
ff_log(FC_DEBUG, 0, "malloc(%"FT_ULL") failed (%s), falling back on
ioctl(FIBMAP) ...", (ft_ull) k_len, strerror(err));
break;
}
memset(k_map, 0, k_len);
k_map->fm_start = 0L; k_map->fm_start = (ft_u64) file_start;
k_map->fm_length = (ft_u64) file_length; k_map->fm_length = (ft_u64) (file_end - file_start);
k_map->fm_flags = FIEMAP_FLAG_SYNC; k_map->fm_flags = FIEMAP_FLAG_SYNC;
k_map->fm_extent_count = extent_n; k_map->fm_extent_count = extent_n;
if ((err = ff_posix_ioctl(fd, FS_IOC_FIEMAP, k_map)) != 0) {
/* do not mark the error as reported, this is just a DEBUG message *
/
ff_log(FC_DEBUG, 0, "ioctl(%d, FS_IOC_FIEMAP, extents[%"FT_ULL"]) fa
iled (%s), falling back on ioctl(FIBMAP) ...", fd, (ft_ull) extent_n, strerror(e
rr));
}
} while (0);
if (err != 0) { int err = 0;
if (k_map != NULL) { if ((err = ff_posix_ioctl(fd, FS_IOC_FIEMAP, k_map)) != 0) {
free(k_map); static ft_ull log_count = 0;
k_map = NULL; if (log_count++ == 5)
} ff_log(FC_DEBUG, 0, "decreasing to level TRACE any further DEBUG mes
sage 'ioctl(FIEMAP) failed'");
/* do not mark the error as reported, this is just a DEBUG message */
ff_log(log_count < 5 ? FC_DEBUG : FC_TRACE, 0,
"ioctl(%d, FIEMAP, extents[%" FT_ULL "]) failed (%s), falling ba
ck on ioctl(FIBMAP) ...",
fd, (ft_ull) extent_n, strerror(err));
} }
* ret_k_map = k_map;
return err; return err;
} }
#endif /* FS_IOC_FIEMAP */ #endif /* FS_IOC_FIEMAP */
/* /*
* retrieves file blocks allocation map (extents) for specified file descriptor * retrieves file blocks allocation map (extents) for specified file descriptor
* and appends them to ret_vector (with user_data = FC_DEFAULT_USER_DATA). * and appends them to ret_vector (with user_data = FC_DEFAULT_USER_DATA).
* in case of failure returns errno-compatible error code and ret_vector content s will be UNCHANGED. * in case of failure returns errno-compatible error code and ret_vector content s will be UNCHANGED.
* *
* must (and will) also check that device blocks count can be represented by ret * must (and will) also check that device size can be represented by ret_list
_list,
* by calling ret_list.extent_set_range(block_size, block_count)
* *
* implementation: calls ioctl(FS_IOC_FIEMAP) * implementation: calls ioctl(FS_IOC_FIEMAP)
*/ */
static int ff_linux_fiemap(int fd, fr_vector<ft_uoff> & ret_list, ft_uoff & ret_ block_size_bitmask) static int ff_linux_fiemap(int fd, fr_vector<ft_uoff> & ret_list, ft_uoff & ret_ block_size_bitmask)
{ {
#ifdef FS_IOC_FIEMAP #ifdef FS_IOC_FIEMAP
struct fiemap * k_map = NULL; ft_uoff file_start = 0, file_size;
struct fiemap_extent * k_extent;
ft_uoff file_length, block_size_bitmask = ret_block_size_bitmask;
ft_u32 i, extent_n = 0;
int err; int err;
do { if ((err = ff_posix_size(fd, & file_size)) || file_size == 0)
if ((err = ff_posix_size(fd, & file_length)) || file_length == 0) return err;
break;
/* fr_vector<ft_uoff> tmp_list;
* first pass: call ioctl() and ask how many extents are needed
*
* second and further passes: allocate enough extents and call ioctl()
* with progressively larger buffers until we retrieve all extents
*/
while ((err = ff_linux_fiemap_ioctl(fd, file_length, extent_n, & k_map))
== 0) {
ft_u32 ret_extent_n = k_map->fm_mapped_extents;
if (ret_extent_n != 0 && extent_n != 0 && k_map->fm_extent_count != 0) {
k_extent = k_map->fm_extents;
if (k_extent[ret_extent_n - 1].fe_flags & FIEMAP_EXTENT_LAST) {
/* ok, we really got all the extents */
break;
}
}
/*
* no FIEMAP_EXTENT_LAST found, we did not get all the extents :(
*
* enlarge the array and try again.
* if extent_n == 0 (first pass), use kernel-suggested length k_map-
>fm_mapped_extents
* otherwise increase extent_n exponentially.
*/
free(k_map);
k_map = NULL;
if (extent_n == 0) { enum {
if ((extent_n = ret_extent_n) <= 1024) K_EXTENT_N = 1024,
extent_n = 1024; K_SIZEOF_FIEMAP = sizeof(struct fiemap) + K_EXTENT_N * sizeof(struct fie
} else if (ret_extent_n < extent_n) { map_extent)
ff_log(FC_WARN, 0, "ioctl(%d, FS_IOC_FIEMAP) is refusing to retu };
rn more than %"FT_ULL" extents in a single call, falling back on ioctl(FIBMAP) . char buf[K_SIZEOF_FIEMAP];
..", fd, (ft_ull) ret_extent_n); struct fiemap * k_map = (struct fiemap *) buf;
/* mark the error as reported, WARN is quite a severe level */ ft_uoff ioctl_n = 0, block_size_bitmask = ret_block_size_bitmask;
err = -ENOSYS; /* ioctl(FS_IOC_FIEMAP) not working as expected..
. */ // call ioctl() repeatedly until we retrieve all extents
break; while (ioctl_n++, (err = ff_linux_fiemap(fd, file_start, file_size, K_EXTENT
} else if (extent_n <= ((ft_u32)-1) >> 1) _N, k_map)) == 0) {
extent_n <<= 1;
else if (extent_n < (ft_u32)-1) ft_u32 i, extent_n = k_map->fm_mapped_extents;
extent_n = (ft_u32)-1; const struct fiemap_extent * extents = k_map->fm_extents;
else {
ff_log(FC_DEBUG, 0, "tried ioctl(%d, FS_IOC_FIEMAP) with [MAX_UI if (extent_n == 0) {
NT32_T-1] extents but it was not enough, falling back on ioctl(FIBMAP) ...", fd) /* we did not get any extent... bail out */
; ff_log(FC_WARN, 0, "ioctl(%d, FS_IOC_FIEMAP) is refusing to return a
/* do not mark the error as reported, this is just a DEBUG messa ny extent after file offset = %" FT_ULL
ge */ ", falling back on ioctl(FIBMAP) ...", fd, (ft_ull) file_sta
err = ENOMEM; /* Out of memory */ rt);
break; /* mark the error as reported, WARN is quite a severe level */
} err = -ENOSYS; /* ioctl(FS_IOC_FIEMAP) not working as expected... */
/* keep trying */ break;
} }
if (err)
const struct fiemap_extent & last_e = extents[extent_n - 1];
const ft_uoff new_file_start = (ft_uoff) last_e.fe_logical + (ft_uoff) l
ast_e.fe_length;
if (new_file_start <= file_start) {
ff_log(FC_WARN, 0, "ioctl(%d, FS_IOC_FIEMAP) returned extents ending
at %" FT_ULL ", i.e. _before_ start of requested range [%" FT_ULL ", %" FT_ULL
"]"
", falling back on ioctl(FIBMAP) ...", fd, (ft_ull) new_file
_start, (ft_ull) file_start, (ft_ull) file_size);
/* mark the error as reported, WARN is quite a severe level */
err = -ENOSYS; /* ioctl(FS_IOC_FIEMAP) not working as expected... */
break; break;
}
extent_n = k_map->fm_mapped_extents; tmp_list.reserve(tmp_list.size() + extent_n);
k_extent = k_map->fm_extents;
/*
* perform a first loop, checking for unsupported extents
* and computing an effective block size
*/
for (i = 0; i < extent_n; i++) { for (i = 0; i < extent_n; i++) {
ft_u32 flag = k_extent[i].fe_flags & (FIEMAP_EXTENT_UNKNOWN | FIEMAP const struct fiemap_extent & e = extents[i];
_EXTENT_ENCODED);
ft_u32 flag = e.fe_flags & (FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_EN
CODED);
if (flag) { if (flag) {
ff_log(FC_DEBUG, 0, "ioctl(%d, FIEMAP, extents[%"FT_ULL"]) retur ff_log(FC_DEBUG, 0, "ioctl(%d, FS_IOC_FIEMAP, extents[%" FT_ULL
ned unsupported %s%s%s extents, falling back on ioctl(FIBMAP) ...", "]) returned unsupported %s%s%s extents, falling back on ioctl(FIBMAP) ...",
fd, (ft_ull)extent_n, fd, (ft_ull) extent_n,
(flag & FIEMAP_EXTENT_UNKNOWN ? "UNKNOWN" : ""), (flag & FIEMAP_EXTENT_UNKNOWN ? "UNKNOWN" : ""),
(flag == (FIEMAP_EXTENT_UNKNOWN|FIEMAP_EXTENT_ENCODED) ? " + " : ""), (flag == (FIEMAP_EXTENT_UNKNOWN|FIEMAP_EXTENT_ENCODED) ? "+" : ""),
(flag & FIEMAP_EXTENT_ENCODED ? "ENCODED" : "") (flag & FIEMAP_EXTENT_ENCODED ? "ENCODED" : "")
); );
/* do not mark the error as reported, this is just a DEBUG messa ge */ // do not mark the error as reported, this is just a DEBUG messa ge
err = ENOSYS; err = ENOSYS;
break; break;
} }
/* keep track of bits used by all physical, logical and lengths. /*
* needed to check against block size */ * keep track of bits used by all physical, logical and lengths.
block_size_bitmask |= k_extent[i].fe_physical | k_extent[i].fe_logic * needed to check against block size
al | k_extent[i].fe_length; */
block_size_bitmask |= e.fe_physical | e.fe_logical | e.fe_length;
// save what we retrieved
tmp_list.append((ft_uoff) e.fe_physical,
(ft_uoff) e.fe_logical,
(ft_uoff) e.fe_length,
(e.fe_flags & FIEMAP_EXTENT_UNWRITTEN) ? FC_EXTENT_Z
EROED : FC_DEFAULT_USER_DATA);
} }
if (err != 0) if (err != 0 || (last_e.fe_flags & FIEMAP_EXTENT_LAST))
break; break;
ret_list.reserve(ret_list.size() + extent_n);
/* ok, no strange extents: we can now add them to ret_list */ // no FIEMAP_EXTENT_LAST found, we did not get all the extents. keep try
for (i = 0; i < extent_n; i++) { ing...
ret_list.append((ft_uoff) k_extent[i].fe_physical, if (new_file_start >= file_size)
(ft_uoff) k_extent[i].fe_logical, // should not happen, but not too dangerous
(ft_uoff) k_extent[i].fe_length, file_size = new_file_start + 1;
(k_extent[i].fe_flags & FIEMAP_EXTENT_UNWRITTEN) ? F file_start = new_file_start;
C_EXTENT_ZEROED : FC_DEFAULT_USER_DATA); }
} if (err != 0)
} while (0); return err;
if (k_map != NULL) ft_size extent_n = tmp_list.size();
free(k_map);
if (err == 0) { /* ok, no strange extents: we can now add them to ret_list */
ff_log(FC_DEBUG, 0, "ioctl(%d, FS_IOC_FIEMAP, extents[%"FT_ULL"]) succee ret_list.reserve(ret_list.size() + extent_n);
ded", fd, (ft_ull)extent_n); ret_list.append_all(tmp_list);
ret_block_size_bitmask = block_size_bitmask;
} static ft_ull log_count = 0;
if (log_count++ == 5)
ff_log(FC_DEBUG, 0, "decreasing to level TRACE any further DEBUG message
'ioctl(FIEMAP) successful'");
ff_log(log_count < 5 ? FC_DEBUG : FC_TRACE, 0, "ioctl(%d, FIEMAP) successful
: retrieved %" FT_ULL " extent%s in %" FT_ULL " call%s",
fd, (ft_ull) extent_n, extent_n == 1 ? "" : "s", (ft_ull) ioctl_n, i
octl_n == 1 ? "" : "s");
ret_block_size_bitmask = block_size_bitmask;
return err; return err;
#else #else
return ENOSYS; return ENOSYS;
#endif /* FS_IOC_FIEMAP */ #endif /* FS_IOC_FIEMAP */
} }
/** /**
* retrieves file blocks allocation map (extents) for specified file descriptor * retrieves file blocks allocation map (extents) for specified file descriptor
* and appends them to ret_vector (with user_data = FC_DEFAULT_USER_DATA) * and appends them to ret_vector (with user_data = FC_DEFAULT_USER_DATA) sorted by ->logical
* in case of failure returns errno-compatible error code, and ret_vector conten ts will be UNDEFINED. * in case of failure returns errno-compatible error code, and ret_vector conten ts will be UNDEFINED.
* *
* implementation: calls ioctl(FS_IOC_FIEMAP) and if it fails, tries with ioctl( FIBMAP) * implementation: calls ioctl(FS_IOC_FIEMAP) and if it fails, tries with ioctl( FIBMAP)
*/ */
int ff_read_extents_posix(int fd, ft_uoff dev_length, fr_vector<ft_uoff> & ret_l ist, ft_uoff & ret_block_size_bitmask) int ff_read_extents_posix(int fd, ft_uoff dev_length, fr_vector<ft_uoff> & ret_l ist, ft_uoff & ret_block_size_bitmask)
{ {
int err; int err;
do { do {
err = ff_linux_fiemap(fd, ret_list, ret_block_size_bitmask); err = ff_linux_fiemap(fd, ret_list, ret_block_size_bitmask);
if (err != 0) { if (err != 0) {
 End of changes. 37 change blocks. 
157 lines changed or deleted 138 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)