Actually, it is possible to do it. Because it is possible to remove top level vdev from pool if space permits. So the trick is to:
- add a temp disk/file vdev to the pool with smaller size, but is enough to hold all existing data (including snapshots etc)
- remove the old vdev
- possibly re-partition old vdev to smaller size, or replace with a smaller disk
- add it back
- remove the temp disk.
All files should remain intact.
To illustrate the steps:
- Allocate the files
# fallocate -l 3G 3G_1.img
# fallocate -l 3G 3G_2.img
# fallocate -l 2G 2G_1.img
# fallocate -l 2G 2G_2.img
- Create zfs with the 2 3G files with mirror. (my directory is /var/snap/lxd/common/lxd/disks)
# zpool create test3g mirror /var/snap/lxd/common/lxd/disks/3G_1.img /var/snap/lxd/common/lxd/disks/3G_2.img
# zpool status test3g
pool: test3g
state: ONLINE
scan: none requested
config:
NAME STATE READ WRITE CKSUM
test3g ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
/var/snap/lxd/common/lxd/disks/3G_1.img ONLINE 0 0 0
/var/snap/lxd/common/lxd/disks/3G_2.img ONLINE 0 0 0
errors: No known data errors
# zpool list test3g
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
test3g 2.75G 111K 2.75G - - 0% 0% 1.00x ONLINE -
You can clearly see the test3g pool is 2.75G usable, it is in mirror.
- Let's try to create dummy file inside. This to simulate your existing data.
And you can verify your data is intact after the exercise.
# echo test > /test3g/test.txt
# cat /test3g/test.txt
test
#
- Now attach another mirror of smaller size (e.g. 2G)
# zpool add test3g mirror /var/snap/lxd/common/lxd/disks/2G_1.img /var/snap/lxd/common/lxd/disks/2G_2.img
# zpool status test3g
pool: test3g
state: ONLINE
scan: none requested
config:
NAME STATE READ WRITE CKSUM
test3g ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
/var/snap/lxd/common/lxd/disks/3G_1.img ONLINE 0 0 0
/var/snap/lxd/common/lxd/disks/3G_2.img ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
/var/snap/lxd/common/lxd/disks/2G_1.img ONLINE 0 0 0
/var/snap/lxd/common/lxd/disks/2G_2.img ONLINE 0 0 0
errors: No known data errors
# zpool list test3g
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
test3g 4.62G 156K 4.62G - - 0% 0% 1.00x ONLINE -
Now we have a striped mirror of 4.62GB usable.
- Let's remove the previous 3G parts.
# zpool remove test3g mirror-0
# zpool status
pool: default
state: ONLINE
scan: scrub repaired 0B in 0 days 00:06:45 with 0 errors on Fri May 21 15:20:30 2021
config:
NAME STATE READ WRITE CKSUM
default ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
/opt/lxc_image/default.img ONLINE 0 0 0
/var/snap/lxd/common/lxd/disks/default.img ONLINE 0 0 0
errors: No known data errors
pool: tank
state: ONLINE
scan: scrub repaired 0B in 0 days 00:00:10 with 0 errors on Tue May 18 19:42:56 2021
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
/var/snap/lxd/common/lxd/disks/tank.img ONLINE 0 0 0
/nfs-dual/zfs-images/tank.img ONLINE 0 0 0
errors: No known data errors
pool: test3g
state: ONLINE
scan: none requested
remove: Removal of vdev 0 copied 102K in 0h0m, completed on Fri May 21 15:33:19 2021
72 memory used for removed device mappings
config:
NAME STATE READ WRITE CKSUM
test3g ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
/var/snap/lxd/common/lxd/disks/2G_1.img ONLINE 0 0 0
/var/snap/lxd/common/lxd/disks/2G_2.img ONLINE 0 0 0
errors: No known data errors
# zpool list test3g
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
test3g 1.88G 142K 1.87G - - 0% 0% 1.00x ONLINE -
The space is down to 1.87G.
Note that this may take long depend on your data size, but it will complete OK.
Check the message above:
Removal of vdev 0 copied 102K in 0h0m, completed on Fri May 21 15:33:19 2021
You technically reduced the zpool size from 3G to 2G, without down time, without losing data.
- Let's verify the data is still there
# cat /test3g/test.txt
test
#
Yes of course.
Note that only the recent version of zfs supports this. Your mile may vary.
Thanks
Best
Shilin