HOW CONVERTFS WORKS ------------------- Convertfs is a cool idea by Serguei Tzukanov. This idea has been further discussed and developed by several people (including myself) on the bug-parted and ntfs-devel mailing lists, and #xfs IRC channel. It is available from here: http://tzukanov.narod.ru/convertfs Convertfs can be used to do in-place conversion and resize. It is quite linux-dependent, although there are probably analogous ways to do this on other operating systems. CONTENTS: --------- 1. The Basic Algorithm 2. In-place LVM conversion 3. File system resizing on top of LVM, without inode-renumbering 1. THE BASIC ALGORITHM ---------------------- Here's the basic algorithm: (1) mount the file system you wish to "convert" (or resize). (2) create a sparse file inside that file system, of the size you wish your new fs to be. This is done by seek(2)ing to the desired size, and write(2)ing something. (Note: in modern filesystems, this doesn't allocate (m)any blocks) (3) run mkfs on that sparse file, using the mkfs of the file system type you wish to convert to. (mkfs must not write blank 0's in free space) I'll call this new filesystem the "nested" file system. (4) mount the nested file system. (mount -o loopback ...) (5) mv(1) everything in the old file system to the nested one, except the nested file system itself ;) (6) unmount the nested filesystem (7) use the FIBMAP ioctl to find out where the blocks of the nested file system are. (Some of them will be unallocated). Store this somewhere. (8) unmount the old file system (9) move all blocks into their correct places, to "activate" the nested file system. That is, copy all the (allocated) blocks from the file containing the nested file system to their absolute positions. You can find these blocks from the output of part (7). This destroys the old file system, and creates the new one in-place. This algorithm executes in roughly O(N) time, where N is the size of the file system, since it must reconstruct the file system. 2. IN-PLACE LVM CONVERSION -------------------------- Here's an algorithm for converting a partition containing a file system to an LVM physical volume which contains a single logical volume containing the original file system, in place. It's a bit pie-in-the-sky, because it would probably require file systems to support having "holes" on the devices they store themselves on. But I think that's a really valuable thing. The algorithm: (1) Figure out how much metadata will be needed at the start of the partition. [Ask LVM somehow?] Anyway, call this number METADATA-SIZE (2) Mount the file system on the partition. (3) Create a file of size METADATA-SIZE (from step 1), and fill it with 0's. Call that file "start-copy". (4) Get the addresses of the blocks of the file "start-copy" via the FIBMAP ioctl. Store them somewhere. (5) Unmount the file system. (6) Copy the first METADATA-SIZE (from step 1) of the partition into "start-copy". We do this by copying to the appropriate blocks obtained from step 4. (7) Use the usual LVM utilities to create a physical volume, and a logical volume inside. Configure the logical volume to to cover the entire partition, except the first METADATA-SIZE blocks. (That is, the last blocks in the logical volume's address space should map to the last blocks in the physical volume). The first METADATA-SIZE blocks in the logical volume should be matched up with the blocks from the file start-copy, obtained through step 4. NOTE: Linux LVM version 1 doesn't support such fine-grained mapping, but Linux LVM version 2 does. At this stage, LVM and the file system should be functional, in theory. There's one dodgey thing we're doing here: the blocks from the file "super-block" are allocated twice: once for the file, and once for the first few blocks of the file system. This is kind-of ok, because we don't care about the 0's we "lost" when we overwrite "super-block". More importantly, LVM is mapping two different parts of the logical volume's address space to the same part of the physical volume! LVM might not like that. Also, if the file system gets corrupted, or perhaps if someone tries to write to "start-copy", the consequences might not be pretty. Anyway, I think the best solution to all of these problems is to allow address spaces to have holes. That is, we should be able to say that the part of the logical volume's address space containing the blocks of "start-copy" are not actually mapped anyway. File systems should be able to deal with this. If this is implemented, then all file system resize operations become trivial. [TODO: add a section on this] Anyway, this algorithm runs in roughly O(METADATA_SIZE) time. 3. FILE SYSTEM RESIZING ON TOP OF LVM, WITHOUT INODE-RENUMBERING ---------------------------------------------------------------- Once you have LVM (hint: use the algorithm from part 2) installed below your file system, you can grow it and shrink it without renumbering inodes! I'll describe the shrink algorithm here: (1) Mount your file system you want to shrink. (2) Create a file of the size that you want to shrink the file system by. (3) Write 0's (or whatever.. to ensure blocks get allocated). (4) Use the FIBMAP ioctl to find the blocks in this file. (5) Unmount the file system. (6) Map those blocks to "no-where" (eg: some magical /dev/zero)... you don't need them anymore. You just shrunk your file system's consumption. But, it's somewhat dangerous, for the same reasons algorithm 2 is, since the file system is making false assumptions about the underlying volume. Inode numbers weren't changed, since inodes weren't even touched :) This algorithm runs in roughly O(METADATA_SIZE + SHRINK_AMT) time.