16

I'm currently doing cp -aR to copy data from my (99% full) 1TB ext4 formatted disk to a new LVM-with-ext4-on-it disk. It's taking forever.

Is there any way to attempt to "convert" the disk in place? I'm on EC2 so backing up takes minutes.

Or alternatively, is there any way that might be faster than cp to directly copy the ext4 filesystem onto the LVM disk?

4 Answers 4

28

I wrote blocks (née lvmify) which does this conversion in-place. It works by shrinking the filesystem a bit, moving the start of the filesystem to the end of the partition, and copying an LVM superblock (preconfigured with the right PV/LV/VG) in its place.

9
  • this sounds really interesting! I am thinking on backuping my 500GB to the other partition (that is already lvm) just to give it a try! May 27, 2014 at 0:01
  • 1
    @Gabriel, will this work on live fs? I mean do I need to unmount the FS, and then it does it in-place, or will it even work on a r/w mounted root FS?
    – Gavriel
    Jun 7, 2015 at 11:20
  • 1
    @AmrMostafa: "Pretty" solid? I have this thing about my file systems, I need them to be rock solid... :-) Jul 13, 2015 at 15:09
  • 3
    Ubuntu Trusty+ users will find it hard to install the required python 3.3.. only 3.4 is available and blocks hasn't been updated since Dec 2014 :/
    – bksunday
    Jan 29, 2016 at 16:17
  • 2
    Despite the fact that it was updated 5 ears ago, it steel working. Confirmed on NVMe SSD, GPT partition scheme. Note: better use Python 3.6.
    – Anthony
    Aug 26, 2018 at 11:19
1

I'm unsure about how to convert the disk live, but I think rsync will be a better and safer way to copy your data over. It'll allow you to resume and keep the data intact in the event the transfer stops.

I did find a similar process completed by someone adding an external drive to their local system as an LVM. There's not a whole lot of information, but I think it will be enough to get your started:

"So today I discovered the awesome that is LVM. Installing Debian, I selected "LVM - Use entire disk". But the main drive was a slow and small 5200rpm laptop drive. Today I inserted my spare 1.5TB drive and booted up. Wanted the system on this bigger faster drive instead.

LVM approach: add /dev/sdc to the volume group, then run "pvmove /dev/sda". This moves all data from sda to other drives (only sdc available). No need to reboot, no need to unmount. While I'm writing this, the data is being moved.

Later, do "vgreduce megatron /dev/sda" to remove the slow drive from the volume group and voila. Data moved. (megatron is the name of the volume group and of my computer). This might be old news to many but I just thought this was really cool :)"

Granted this was done locally, but I think with additional research, you maybe be able to accomlpish this.

source

1

No method exists to do such an LVM conversion "on the fly."

LVM actually resides under your filesystem to expand it across multiple physical devices, or stripe or mirror it, etc. The final step in creating a logical volume is to lay a file system on top of it. Here are examples from RHEL6.

What you will need to do is back up or archive the data on that device, then destroy existing filesystem, create a logical volume, and re-lay a filesystem on top. If this is a root filesystem on a linux OS, consider doing a reinstallation. It may be faster.

For faster copies, I'm fond of dd, but I don't use it often. Making a mistake with dd is dangerous. One thing you can try is tar czv <source fs> | (cd <destination fs>; tar x) which will transfer a compressed tar file on the fly.

Good luck!

5
  • 3
    Using compression in the tar operation makes no sense at all. The only place the data will be compressed is in-memory as it's piped; it's then immediately uncompressed again before it gets written to disk. Only now, the operation generates multiple times as much CPU load because it's both compressing and uncompressing, uselessly, on the fly. Also, for any operation like this involving entire filesystems, you're going to want at least tar cSf - | tar xvpf - to handle sparse files & permissions. Possibly --selinux too (if the destination volume will subsequently replace the source).
    – FeRD
    Oct 9, 2013 at 7:05
  • That's a good point if your source and destination devices are on the same host or if you don't have CPU cycles to spare. Those are points to consider case by case. I do like the "S" and "p" switches and the "--selinux" argument.
    – dafydd
    Oct 10, 2013 at 13:15
  • Mmm, well, if anyone's cloning a filesystem by piping an on-the-fly tar operation over a network link, then (a) they're a braver soul than I, but (b) you might NOT want -p unless the hosts share usernames/UIDs (though the manpage reminds me that -p is the default for GNU tar when run as root), and --selinux is fraught with even more peril — probably better to just do a restorecon -Rv (or -Rp) over the whole thing once it's mounted in the correct (final) location.
    – FeRD
    Oct 13, 2013 at 8:43
  • dd is the proper tool for this operation since you're copying a partition. dd will make an exact copy on the new partition, then you change the fstab to load from the new partition instead of the old. Once you're done moving all the partitions off the old drive, you can destroy the filesystem and add the drive to the LVM physical disks group, and then use the space to expand the partitions however you wish.
    – Jeter-work
    Nov 20, 2017 at 20:07
  • "No method exists" is plain wrong, see accepted answer and my "manual lvmify" answer. Feb 18, 2022 at 9:31
1

Manual lvmify:

  1. Shrink filesystem by 8 MiB (if the length is a multiple of 4 MiB shrinking by 4 MiB is enough; if not sure shrink a bit more and expand filesystem to maximum size after step 7) or increase the size of the partition to a multiple of 4 MiB and having 1 free 4 MiB block at the end.
  2. Copy the first 4 MiB to the location of the last 4 MiB aligned block, e.g. with a 17 MiB disk that's at 12 MiB (toy example for simplicity, see illustration below).
  3. Create PV with --dataalignment 4M
  4. Create VG
  5. Create LV with --extents 1, -Zn and PV specification /dev/sdX:1234 where sdX is your disk (add the partition number if used) and 1234 the last extent number, i.e. number of available extents - 1. In the example, we have 3 extents (4 MiB header, 12 MiB usable space, 1 MiB trailing space) and the index of the last extent is 2.
  6. Grow LV (lvextend) to full size, e.g. with -l+100%FREE
  7. Check plausibility of the data in the new LV. Steps 5+6 can be repeated with corrected numbers after removing the LV. (Assuming no journal replay damaged the data.)

Illustration (toy example with 17 MiB disk):

Meta| PV usable | trailing data
+---+---+---+---+-+
| 0 | 1 | 2 | 3 | |
+---+---+---+---+-+
  |           ^
   \----------/ copy

Shrinking filesystem to 3 extents (12 MiB).
LV extents: 0 (was 3), 1, 2

Ideas for testing this approach before touching important data:

  • Create a sparse file and a loop device (or use a VM), fill the first and last 20 MiB or so with random data (or sequential block numbers), get the md5sum of the relevant data (excluding the area we overwrite in step 2 and the trailing data), follow steps, check that md5sum of LV contents matches earlier md5sum
  • Create a device snapshot (100 MiB backing storage should be plenty, this can be on a tmpfs), e.g. following https://gist.github.com/jowagner/b36024636140ddf453c12eaf6e590b5d, and work on the writeable snapshot for testing.

If you are not 100% sure like me whether dd seek= does the right thing for step 2 here a few lines of code that I used:

dev_name = 'dev/sdX'
dev_size = 24000272007168  # put size in bytes here
pe_size = 4096 * 1024
n_extents = dev_size // pe_size
f = open(dev_name, 'r+b')
f.seek(0)
block = f.read(pe_size)
assert len(block) == pe_size
f.seek(pe_size*(n_extents-1))
f.write(block)
f.close()
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.