Chuyển đổi tệp thưa thớt thành không thưa thớt tại chỗ


8

Trên Linux, được cung cấp một tệp thưa thớt, làm thế nào để làm cho nó không thưa thớt, tại chỗ?
Nó có thể được sao chép cùng cp --sparse=never ..., nhưng nếu tệp là 10G và lỗ là 2G (đó là không gian được phân bổ là 8G), làm thế nào để hệ thống tệp phân bổ 2G còn lại mà không sao chép 8G gốc sang tệp mới?

Câu trả lời:


11

Trên mặt của nó, nó đơn giản dd:

dd if=sparsefile of=sparsefile conv=notrunc bs=1M

Nó đọc toàn bộ tập tin và ghi lại toàn bộ nội dung vào nó.

Để chỉ tự viết lỗ, trước tiên bạn phải xác định các lỗ đó ở đâu. Bạn có thể làm điều đó bằng cách sử dụng một trong hai filefraghoặc hdparm:

filefrag:

# filefrag -e sparsefile
Filesystem type is: 58465342
File size of sparsefile is 10737418240 (2621440 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0.. 1048575:  187357696.. 188406271: 1048576:            
   1:  1572864.. 2621439:  200704128.. 201752703: 1048576:  188406272: last,eof
sparsefile: 2 extents found

hdparm:

# hdparm --fibmap sparsefile

sparsefile:
 filesystem blocksize 4096, begins at LBA 0; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0 1498861568 1507250175    8388608
  6442450944 1605633024 1614021631    8388608

Tệp ví dụ này, như bạn nói, có 10Gkích thước với một 2Glỗ. Nó có hai phạm vi, bao 0-1048575thứ nhất 1572864-2621439, thứ hai , có nghĩa là lỗ đó 1048576-1572864(trong các khối có kích thước 4k, như được hiển thị bởi filefrag). Thông tin được hiển thị hdparmlà giống nhau, chỉ hiển thị khác nhau (phạm vi đầu tiên bao gồm các cung từ 8388608512 byte bắt đầu từ 0 nên 0-4294967295byte của nó , do đó lỗ được tính 4294967296-6442450944bằng byte.

Lưu ý rằng dù sao bạn cũng có thể được hiển thị nhiều mức độ hơn nếu có bất kỳ phân mảnh nào. Thật không may, không có lệnh nào hiển thị các lỗ trực tiếp và tôi không biết một lỗ nào như vậy, vì vậy bạn phải suy ra nó từ các giá trị logic được hiển thị.

Bây giờ, lấp đầy 1048576-1572864lỗ hổng đó ddnhư được hiển thị ở trên, có thể được thực hiện bằng cách thêm các giá trị seek/ giống hệt (và giống hệt) skipcount. Lưu ý rằng bs=đã được điều chỉnh để sử dụng các 4klĩnh vực như được sử dụng filefragở trên. (Đối với bs=1M, bạn phải điều chỉnh các giá trị tìm kiếm / bỏ qua / đếm để phản ánh 1Mcác khối có kích thước).

dd if=sparsefile of=sparsefile conv=notrunc \
   bs=4k seek=1048576 skip=1048576 count=$((-1048576+1572864))

Mặc dù bạn có thể lấp đầy các lỗ /dev/zerothay vì đọc lỗ của chính tệp đó (cũng sẽ chỉ mang lại số 0), nhưng an toàn hơn là đọc từ sparsefiledù sao đi nữa vì vậy bạn sẽ không làm hỏng dữ liệu của mình trong trường hợp bạn bị sai lệch.

Trong các phiên bản mới hơn GNU dd, bạn có thể dính vào một khối lớn hơn và chỉ định tất cả các giá trị theo byte:

dd if=sparsefile of=sparsefile conv=notrunc bs=1M \
   iflag=skip_bytes,count_bytes oflag=seek_bytes \
   seek=4294967296 skip=4294967296 count=$((-4294967296+6442450944))

filefrag sau khi chạy nó:

# sync
# filefrag -e sparsefile 
Filesystem type is: 58465342
File size of sparsefile is 10737418240 (2621440 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0.. 1572863:  187357696.. 188930559: 1572864:            
   1:  1572864.. 2621439:  200704128.. 201752703: 1048576:  188930560: last,eof
sparsefile: 2 extents found

Do sự phân mảnh, nó vẫn còn hai phạm vi. Tuy nhiên, phần bù logic cho thấy lần này, không có lỗ hổng, vì vậy tệp không còn thưa thớt nữa.

Đương nhiên, ddgiải pháp này là cách tiếp cận rất thủ công cho mọi thứ. Nếu bạn cần điều này một cách thường xuyên, sẽ dễ dàng viết một chương trình nhỏ lấp đầy những khoảng trống như vậy. Nếu nó đã tồn tại như một công cụ tiêu chuẩn, tôi chưa nghe nói về nó.


Rốt cuộc, có một công cụ, fallocatedường như hoạt động, sau một thời trang:

fallocate -l $(stat --format="%s" sparsefile) sparsefile

Tuy nhiên, cuối cùng trong trường hợp XFS, trong khi nó phân bổ vùng vật lý cho tệp này, thì nó không thực sự bằng không. filefragcho thấy mức độ như được phân bổ, nhưng không được ghi nhận.

   2:        3..      15:    7628851..   7628863:     13:    7629020: unwritten

Điều này là không đủ nếu mục đích là có thể đọc dữ liệu chính xác trực tiếp từ thiết bị khối. Nó chỉ dự trữ không gian lưu trữ cần thiết cho việc viết trong tương lai.


1
Hoặc cat sparsefile 1<> sparsefile. Bạn có thể sử dụng fallocatetrên Linux để tránh phải ghi các byte NUL đó nếu tất cả những gì bạn muốn là không gian được phân bổ.
Stéphane Chazelas

@ StéphaneChazelas, cảm ơn, quên mất fallocate. Nó có --dig-holesnhưng không --fill-holes. Tuy nhiên, nó dường như hoạt động đủ tốt khi bạn chỉ định kích thước. Tôi sẽ chỉnh sửa câu trả lời của tôi.
frostschutz

Trên NFS hoặc ext3 fallocate không được hỗ trợ.
Ivan

Mới hơn fallocatecó một -zcái có thể được sử dụng trong Linux 3.14 trở lên trên ext4 và xfs (bạn cần chạy nó với -o-lcho tất cả các phần thưa thớt mà tôi cho là).
Stéphane Chazelas

@ StéphaneChazelas, yup, nhưng điều này -zkhông giữ dữ liệu của bạn nếu bạn dd
tình cờ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.