Source in file:
int convert(size_t impnum, struct partition *imported, size_t expnum, struct partition *exported, size_t spcnum, struct space *free_space, int badblock_check, PROGRESS_PARAM, ERR_PARAM)
Converts partitions from beginning state (imported partitions) to destination state (exported partitions).
The convert() is divided into a few other functions, some less important of
them are also in the same file and are named
gc_* functions or
Logs some constants and sizes of some important structures, checks if
they aren't too large, they are limited by the size of block (
There are some GConv services that may be now initizalized. These are
for uniq device handles, device intervals, swapping program generator
(translation tables), for details see
gc_services_1(). Provided by
Note: There are many such initializations and these are bound by
dependencies, therefore there are defined macros
GSC_DONE() and argument is level (number of group). These init and done
calls are described in
gc_services_*() functions in pairs and are
written in init-order, done-order is backward.
struct partition in imported and
exported partitions and filled its items, e.g. unique filehandle, flag
if is inited, location on virtual device etc.
The level of checking is badblock_check, checks for badblocks (read only, read/write test or disabled) each imported and exported partition, adds badblocks into a list.
All areas (imported and exported partitions and free space), uses
device interval functions (
devint.h), adds these in list and
devint_checks() checks if given partitions are correct
(e.g. exported partitions can't intersect), sorts these and sets up
location on virtual device in each partition and free space.
This is accelerating feature. If may be changed superblock only
(there isn't any influence to structure of filesystem) then is called
fc_superblock(). If it is unsuccessful
then it continues in common way. The last action is syncing devices.
Function gc_initfs(), sets up using cache and calls
each imported partition and sets up attribute
gd_init (means partition
is initialized). (attribute
pt_cache_on can be changed in
GConv initialization system is described together above (first
level of GConv services). Initialized various caches - cache for
converting current (real) and destination (new) addresses on the virtual
device (n2r), cache of the tree (tc), minicache for caching status of
blocks (for very fast access, see
map_status.c) (mc), support of
creating the tree (trt), giving free blocks (free) and cache for
exported partitions (ec). For details see
this is called in macro
This is initialization of the third level of GConv services.
Currently here is creating the tree only. For this the
Imported partition have attribute
pt_ronly, if attribute is set
then the partition can't be modified in anyway (includes unused blocks).
Marks all whole imported partitions, follows marking all remaining free blocks (as free blocks).
Filesystem specific data (e.g. bootsector) can be passed through this
struct partition contains item
is initizalized in
fc_init(). This is passed to exported partition
if imported and exported partition have the same filesystem type,
otherwise this is NULL. See function
fc_mkfs() for each exported partition, except partitions
converted by call
fc_superblock() above, sets up attribute that
partition is initilized. Follows putting found badblocks to lists of
All blocks of files in imported partitions, which can be passed to
exported partition as are, are marked (ALIGN flag). This minimizes
number of moves (of blocks). Provided by function
All files from imported filesystem are moved into destination
partitions. In current version files from i-th imported partition are
moved to i-th exported partition. Moving is virtual only and files stay
their locations. The metadata of exported filesystems are built only.
Provided by function
move_files() (found in
Close all imported and exported partitions, used call
for imported and
fc_fsdone() for exported partitions, freed all
GConv internal data in struct partition. See function
Swapping program must be stored on device in free blocks. Function
make_transchain() computes number and reserves them.
At first the function
make_transchain() reserves some blocks and
make_translating_tables() which writes swapping
program in run-length encoding) into these reserved reserved blocks.
The swapping program is a sequence of swap operations which permutate
blocks to have all exported partition on their real destination location
(the goal of the general conversion).
Calls done functions for all these services. These functions free used memory etc. If any partition isn't closed than close it (this can happen if an error occured).
If all actions were successful then would be called final permutation
algorithm. This algorithm is implemented in
This is critical section and can't be interrupted. Illegal interruption
can cause lose your data.
Closes the first level GConv services and sync devices.
Source in file:
int move_files(size_t n, struct partition *imported, size_t m, struct partition *exported, PROGRESS_PARAM, ERR_PARAM)
Moves all files from imported filesystems to exported filesystems, in current version all files from i-th imported filesystem are moved to i-th exported filesystem. We plan selecting destination exported partition for files in future versions because joining and splitting operations require this.
align_files() is simpler than this, browses
directory structure of each imported filesystem and for each file browses
all blocks. For each extent calls
fc_align() (in destination exported
partition), function returns subextent (or empty extent) which can stay its
Support for hardlinks and their duplicating is initialized
dupl_init()). Checks if passed parameters
are correct. Sums blocks of all imported partitions (for computing
progress). And follows main loop, actions are realized for all partitions
which must be rebuilt (not solved by
The main loop consists of following, used call-sequece of filesystem calls corresponds with description in filesystem API documentation.
fc_open_rootdir() in both cases, fills given structures to
their root directories, prepares filesystems for browsing/creating
filesystem directory structures
this loop browse through filesystem in imported partition, stack is represented as linklist, current directory is head of linklist, the loop is repeated while this stack isn't empty
fc_nextentry() returns next entry (behind given), this
function is just one which gives entry, therefore returns first entry
for just opened directory, returns zero if success
all entries in current directory are browsed and created, rests to
close this directory in imported and also exported filesystem by
fc_close_dir, and change current directory upper "cd ..", entry
corresponding to directory which was just browsed, putting entries into
this directory finished, must be called
entry found, must be created in exported filesystem, differenced by type of this entry (directory, regular files, devices etc.)
if the entry is regular file and has at least two hardlinks, try
to find out another correspoding entry in imported filesystem, used
if such entry found then find correspoding entry in exported
hardlink_gettemple(), create hardlink in exported
fc_hardlink_create() - if returned request to
duplicate data of hardlink then add this into queue by
create new entry in exported filesystem as a copy of passed original
entry from imported filesystem, used
discern cases if entry is directory, regular file or other.
open this directory in imported filesytem and also just created
directory in exported filesystem, in both used
fc_open_subdir(), add these on tops of browsing stacks
link this file with corresponding blocks - it is "virtual
copying", it works with numbers (exactly extents) of blocks
relatively to start of exported partition, blocks are assigned to
this file (considering possibility of use original blocks),
their numbers are linked with original numbers in GConv internal
structures - in the Tree, required for permutating of blocks,
for linking is used
entrydata_iterate() which iterates calls
proc_movedata() for all blocks of entry
if file is hardlink (first occurance) then this entry must be
hardlinks_addtemple() (to hardlink other links
e.g. device, pipe or softlink, it doesn't need putting data or
any other actions, all required actions are done in
duplicate all hardlinks which are requested to be duplicated, were
follows freeing resources used for duplicates and hardlinks by
Source in file:
int entrydata_iterate(struct partition *imported, struct entry_info *imp_entry, struct partition *exported, struct entry_info *exp_entry, int (*proc)(struct block_list *list_glob, struct block_list *list_exp, struct partition *exported, struct entry_info *exp_entry, ERR_PARAM), ERR_PARAM)
Its task is to pass all (extents of) blocks of entry in imported partition to given function to do something with these blocks in exported partition, e.g. decide about destination location of this entry and link source and destination numbers of blocks for later permutating of blocks.
Function consists of double loop, gets blocks from source entry
imp_entry, these blocks are relative to to start of
partition. Blocks are renumbered to be relative to start of the virtual
device (it contains everything) by
extents_globalize(). Blocks are
passed to given function (from argument)
exp_entry which can consider
exported partition and
converts blocks to be relative to start of
exported partition or marks
that are outside (used constant
INVALID_BLOCK as first block). Such
list can be fragmented, function
join_blocklist() joins all
neighbouring extents which can be joined (satisfying logical order). The
most important action is call passed
proc function with these lists to
do something like linking, aligning etc.
The last action is to free used resources by
Note: exception for
exp_entry == NULL is used in aligning
Source in file:
int proc_movedata(struct block_list *list_glob, struct block_list *list_exp, struct partition *exported, struct entry_info *exp_entry, ERR_PARAM)
proc_duplicate() are very
similar to this and don't need detailed description.
Consists of single loop which iterates through all passed blocks and does following actions:
filesystem can have problems with locating new entry, but I prefer to
use blocks outside files in imported partition, therefore it must give
such blocks to exported partition (exported partition has infomartion only
about own already created files), used
now I pass blocks which must be copied in exported partition, so
fc_putdata() must decide about their future location
some free blocks were used, must be removed from list used in
offer_blocks() function, function
original and destination numbers of blocks must be linked, this is
required for later permutating, by function
cut satisfied blocks because there is possible particular success in
fc_putdata() function, used
Source in file:
block_t bread(struct partition *part, const struct extent *blocks, void *buf, ERR_PARAM)
block_t bwrite(struct partition *part, const struct extent *blocks, const void *buf, ERR_PARAM)
Part of API, unify interface for logical access to partitions. Therefore these are usable for both imported and exported partitions. Even in special accelerated functions.
pt_direct_access is set then functions bread() and bwrite()
access to device directly, used
this method is intended for accelerated actions like mkfs or zeroing
pt_imported is set for imported partition, if cache (for
imported partitions) is enabled then is used by
otherwise is used
device_read(). Note that write to imported
partition is not permitted.
exported partition exists virtually only (on the virtual device in its
destination state), simply used function
linnew_write() which are intended for reading/writing to virtual device
in its destination state and use exported cache, their description follows.
bwrite() function are entirely block-oriented (unit
BASIC_BLOCK), but there are written byte-oriented extensions
bwrite1(), but are emulated by
current implementation of GConv is not better way how does it.
Source in file:
int linnew_read(const struct extent *ext, void *buf, ERR_PARAM)
int linnew_write(const struct extent *ext, const void *buf, ERR_PARAM)
Provide read and write operation with the virtual device in its destination
state. Functions are intended namely for accessing to exported partitions
and are used in
Functions consist of loop, which is repeated until action is done. Rest of
given extent is converted from destination to current addressing of the
virtual device in each iteration, used
new2real(). Rests differ for
read and write. Read is very simple use of exported cache
expcache_read(). Note: block which wasn't already written contains
zeroes. Write is very similar to read, it uses also exported cache
expcache_write() and blocks are allocated during the first write by
alloc_realblock() and also these must be linked with current
destination, e.g. for filesystem metadata.
Source in file:
int crazy_algorithm(PROGRESS_PARAM, ERR_PARAM)
The function does modification of all partition which are consireder for
conversion. The functionality is very simple, works in single for-cycle for
all blocks. In i-th iteration of the for-cycle function
returns number of another block and these two blocks may be swapped or
second one may be copied on first one (depends on returned
flag). If such action is required (means that second one differs with
INVALID_BLOCK) then function
crazy_swap() is used to do it. The
crazy_swap() is buffered and such buffering makes this simple idea
Note: simplicity is very important to be possible to implement journaling in feature versions, and to be sure that this critical code is without bugs.