`dd 'จะถูกนำมาใช้เพื่อบล็อกขวาเปลี่ยนข้อมูลได้อย่างไร?


10

พิจารณาอุปกรณ์บล็อกดิบ 100MB เป็นตัวอย่างง่ายๆ นั่นคือ 204800 บล็อก 512 ไบต์แต่ละรายการรวมเป็น 102760448 ไบต์

ความท้าทายคือการเปลี่ยน 98MB แรก (200704 บล็อก) ดังนั้นจึงมีช่องว่าง 2MB (4096 บล็อก) ที่ด้านหน้า เมื่อต้องการทำสิ่งนี้ในสถานที่นั้นจะต้องไม่มีสิ่งใดถูกเขียนไปยังเซกเตอร์ที่ยังไม่ได้อ่าน วิธีหนึ่งในการบรรลุเป้าหมายนี้คือการแนะนำบัฟเฟอร์:

$ dd if=/dev/sdj2 count=200704 | mbuffer -s 512 -b 4096 -P 100 | dd of=/dev/sdj2 seek=4096

ความคาดหวังคือmbufferจะเก็บบล็อก 4096 ก่อนส่งผ่านสิ่งใดไปยังผู้เขียนดังนั้นให้แน่ใจว่าไม่มีสิ่งใดถูกเขียนไปยังพื้นที่ที่ไม่ได้ถูกอ่านและผู้เขียนล่าช้าผู้อ่านตามขนาดของบัฟเฟอร์ บัฟเฟอร์ควรอนุญาตให้ตัวอ่านและตัวเขียนทำงานเร็วที่สุดเท่าที่จะเป็นไปได้ภายในกลุ่มค่าเหล่านั้น

อย่างไรก็ตามดูเหมือนว่าจะไม่สามารถทำงานได้อย่างน่าเชื่อถือ ฉันได้ลองใช้อุปกรณ์จริง แต่มันก็ไม่สามารถใช้งานได้ในขณะที่การทดสอบกับไฟล์ทำงานบนกล่อง 64- บิตของฉัน แต่ไม่ได้อยู่ในกล่อง 32- บิตของฉัน

ก่อนอื่นให้เตรียม:

$ dd if=/dev/sdj2 count=200704 | md5sum
0f0727f6644dac7a6ec60ea98ffc6da9
$ dd if=/dev/sdj2 count=200704 of=testfile

สิ่งนี้ใช้ไม่ได้:

$ dd if=/dev/sdj2 count=200704 | mbuffer -s 512 -b 4096 -P 100 -H | dd of=/dev/sdj2 seek=4096
summary: 98.0 MiByte in  4.4sec - average of 22.0 MiB/s
md5 hash: 3cbf1ca59a250d19573285458e320ade

สิ่งนี้ใช้ได้กับระบบ 64- บิต แต่ไม่ได้อยู่ในระบบ 32- บิต:

$ dd if=testfile count=200704 | mbuffer -s 512 -b 4096 -P 100 -H | dd of=testfile seek=4096 conv=notrunc
summary: 98.0 MiByte in  0.9sec - average of  111 MiB/s
md5 hash: 0f0727f6644dac7a6ec60ea98ffc6da9

สิ่งนี้สามารถทำได้อย่างน่าเชื่อถือ?


บันทึก

ฉันได้อ่านคำถามอื่น ๆ เกี่ยวกับบัฟเฟอร์และมองไปที่pv, และbuffer mbufferฉันจะได้รับหลังเพื่อทำงานกับขนาดบัฟเฟอร์ที่ต้องการ

การใช้ที่เก็บข้อมูลแบบ Intermetiate เป็นวิธีการแก้ปัญหาที่เห็นได้ชัดว่าใช้งานได้จริง แต่ก็ไม่สามารถใช้งานได้จริงหากไม่มีความจุสำรองเพียงพอ

ทดสอบแพลตฟอร์มที่ใช้ Arch Linux ด้วยmbufferเวอร์ชัน 20140302


ผมไม่คิดว่ามันจะแก้ปัญหา แต่จากความอยากรู้ว่าทำไมการใช้งานmbufferที่ทั้งหมดหรือไม่ ทำไมไม่ลองddอ่านเนื้อหาทั้งหมดของอุปกรณ์บล็อกในคราวเดียวdd bs=102760448? แน่นอนไม่ทางใดก็ทางหนึ่งมันบัฟเฟอร์ใน RAM
Celada

@Celada - ตัวอย่าง 100MB เป็นเพียงตัวอย่าง ยกตัวอย่างเช่นการอ่าน 1TB ในครั้งเดียวจะไม่เป็นความคิดที่ดี
starfry

2
อ่าฉันเข้าใจแล้วขอบคุณ mbufferจริงควรบังคับให้สองddล้าหลังสำหรับครั้งแรกและคุณจะต้อง RAM พอที่จะ buffer ขนาดของการเปลี่ยนแปลงที่ น่าเสียดายที่ddไม่สนับสนุนการอ่านและการเขียนบล็อกตามลำดับย้อนหลังเนื่องจากจะช่วยขจัดปัญหาได้!
Celada

คุณไม่ได้ระบุว่าคุณคำนวณ md5sum ที่สองได้อย่างไร
psusi

@psusi md5 ตัวที่สองส่งออกโดย mbuffer ( -Hอาร์กิวเมนต์เปิดใช้งานคุณลักษณะนี้)
starfry

คำตอบ:


2

หากไม่มีบัฟเฟอร์คุณสามารถย้อนกลับได้ครั้งละหนึ่งบล็อก

for i in $(seq 100 -1 0)
do
    dd if=/dev/thing of=/dev/thing \
       bs=1M skip=$i seek=$(($i+2)) count=1
done

โปรดทราบว่าตัวอย่างนี้เป็นอันตรายเนื่องจากขาดการตรวจสอบข้อผิดพลาด

นอกจากนี้ยังช้าเนื่องจากปริมาณการddโทร หากคุณมีหน่วยความจำว่างคุณสามารถใช้บล็อคขนาดใหญ่ขึ้นได้

ด้วยกันชนระวังข้อผิดพลาด มันเป็นไม่เพียงพอที่จะรับประกัน prefill 100% สิ่งที่คุณต้องการคือการเติมขั้นต่ำตลอดทั้งกระบวนการ บัฟเฟอร์จะต้องไม่ลดลงด้านล่าง2Mเพราะมิฉะนั้นคุณจะเขียนทับข้อมูลที่ยังไม่ได้อ่านของคุณอีกครั้ง

ดังนั้นในขณะที่ในทางทฤษฎีคุณสามารถทำได้โดยไม่ต้องชนิดของบัฟเฟอร์และเพียงแค่ห่วงโซ่ใด ๆdd:

dd if=/dev/thing bs=1M | \
dd bs=1M iflag=fullblock | \
dd bs=1M iflag=fullblock | \
dd of=/dev/thing bs=1M seek=2

ในทางปฏิบัติสิ่งนี้ไม่สามารถทำงานได้อย่างน่าเชื่อถือเพราะไม่มีการรับประกันแรกddจัดการเพื่อเก็บข้อมูลการอ่านในขณะที่สุดท้ายdd(ด้วย2M"บัฟเฟอร์" ในระหว่าง) กำลังเขียนอยู่แล้ว

คุณสามารถเพิ่มโอกาสของคุณได้อย่างมากโดยการทำระหว่างบัฟเฟอร์ให้ใหญ่ขึ้น แต่ก็ไม่น่าเชื่อถือ

น่าเสียดายที่ฉันไม่รู้จักโปรแกรมบัฟเฟอร์ที่ดีพร้อมคุณสมบัติการเติมขั้นต่ำ คุณต้องการหนึ่งที่หยุดเอาท์พุทตราบใดที่มีน้อยกว่าความปลอดภัยของคุณภายในบัฟเฟอร์


ฉันยอมรับสิ่งนี้เพราะมันตอบคำถามเดิมโดยแสดงให้เห็นว่าddจะใช้อย่างไร ฉันคิดว่าอย่างไรก็ตามโซลูชันที่แท้จริงไม่ควรใช้ddแต่เลือกใช้สิ่งที่ออกแบบมาเพื่อให้ทำงานแบบย้อนกลับddrescueแทน ฉันอธิบายวิธีการทำเช่นนั้นในคำตอบ
starfry

1
@starfry: แน่นอนโปรแกรมที่เพิ่งจะเป็นทางออกที่ดี อย่างไรก็ตามฉันไม่แน่ใจเกี่ยวกับddrescueที่นี่ ไม่ใช่หากคาดว่าจะทำงานบนอุปกรณ์ต่าง ๆ และคุณต้องหลอกให้ยอมรับข้อโต้แย้งของคุณ มันอาจไม่ได้มีคุณสมบัติ "การบัฟเฟอร์ขั้นต่ำ" ภายในอย่างใดอย่างหนึ่ง (เนื่องจากมีอุปกรณ์ที่แตกต่างกันก็ไม่จำเป็นต้องใช้) ดังนั้นอีกครั้งมันอาจทำให้ข้อมูลของคุณเสียหาย คุณต้องตรวจสอบซอร์สโค้ดว่ามันถูกออกแบบมาสำหรับกรณีการใช้งานของคุณหรือไม่
frostschutz

1

คุณกำลังอ่าน 4096 บล็อกจากนั้นเขียน 4096 บล็อกเหล่านั้นไปยังบล็อก 4096 ถัดไปของดิสก์ดังนั้นจึงเขียนทับบล็อก 4096 ที่สองก่อนที่จะสามารถอ่านได้ คุณต้องอ่าน 8129 บล็อกเพื่อรับ 4096 อันที่สองก่อนเริ่มการเขียนใด ๆ จากนั้นคุณต้องเขียนเฉพาะ 4096 บล็อกก่อนที่จะอ่าน 4096 ถัดไป

คุณไม่ได้พูดถึงระบบไฟล์ประเภทนี้ ถ้ามันเป็นต่อ [234] และคุณมีรุ่นล่าสุดของ e2fsprogs e2image -ra -O 512 /dev/sdj2แล้วคุณสามารถใช้ นอกจากนี้ยังมีประโยชน์เพิ่มเติมของการเป็นคนฉลาดพอที่จะข้ามพื้นที่ว่างในไดรฟ์


นั่นทำให้รู้สึกเมื่ออ่านมันและฉันจะดูอีกครั้งตามที่ แต่มันไม่ได้อธิบายว่าทำไมมันจึงทำงานกับไฟล์ทดสอบ
starfry

ระบบไฟล์อีกครั้งคุณหมายถึงระบบไฟล์ที่มีไฟล์ทดสอบของฉันหรือไม่? ว่าext4แต่สำหรับสำเนาอุปกรณ์ป้องกันระบบแฟ้มใด ๆ ควรจะไม่เกี่ยวข้อง
starfry

@starfry วิธีเดียวที่ฉันรู้ว่าจะทำในลักษณะทั่วไปคือการใช้อัลกอริทึม Emmanuel แนะนำ (ทำงานย้อนหลังจากจุดสิ้นสุด) ซึ่งเป็นสิ่งที่ gparted
psusi

ขนาดบล็อกอีกครั้งฉันได้ลองบล็อกที่มีขนาดใหญ่กว่า (ฉันควรจะเขียนว่าในคำถาม) ฉันพบว่ามันไม่น่าเชื่อถือมากขึ้นแม้แต่บัฟเฟอร์เซกเตอร์ 64K ทางออกที่น่าเชื่อถือคือวิ่งถอยหลังสิ่งที่ddไม่ได้ทำ
starfry

1

โซลูชันที่เชื่อถือได้กำหนดให้คุณต้องแน่ใจว่าไม่มีสิ่งใดเขียนไปยังพื้นที่ที่อาจไม่ได้อ่านและวิธีเดียวที่จะบรรลุผลจริงคือการทำสำเนาในทิศทางตรงกันข้าม

ddrescueเครื่องมือที่สามารถทำงานในทิศทางกลับกัน แต่ก็ปฏิเสธที่จะทำงานกับ input และ output เป็นแบบเดียวกัน อย่างไรก็ตามมันเป็นไปได้ที่จะหลอกลวงโดยการทำซ้ำโหนดอุปกรณ์

ฉันทำการทดลองอย่างรวดเร็วและดูเหมือนว่าจะใช้งานได้ บรรทัดคำสั่งคือ:

$ ddrescue -f -R -s 200704s -o 4096s /dev/sdj11 /dev/sdj11_copy

ข้อโต้แย้งคือ

  • -f จำเป็นต้องบังคับให้เขียนลงในอุปกรณ์เอาต์พุตที่มีอยู่
  • -R บอกให้ทำงานในทิศทางตรงกันข้าม
  • -sบอกจำนวนอินพุตที่จะคัดลอก (ฉันใช้sคำต่อท้ายเพื่อระบุจำนวนของเซ็กเตอร์)
  • -oบอกให้พยายามส่งต่อไปยังอุปกรณ์เอาต์พุตก่อนเขียน (ระบุในเซกเตอร์อีกครั้งด้วยsคำต่อท้าย)
  • /dev/sdj11 เป็นอุปกรณ์บล็อคที่จะอ่าน
  • /dev/sdj11_copy เป็นอุปกรณ์บล็อคที่จะเขียน

ฉันสร้างขึ้น/dev/sdj11_copyด้วยเพื่อให้ตรงกับพารามิเตอร์ของmknod/dev/sdj11

ฉันได้ทำการทดสอบอย่างรวดเร็วเพียงบางอย่าง แต่ดูเหมือนว่าจะใช้งานได้ดีในการคัดลอกอุปกรณ์ดิบ มันไม่ทำงานกับไฟล์ (ฉันไม่สามารถหลอกให้เกินกว่าไฟล์ที่เหมือนกัน)

นี่ไม่ใช่คำตอบดั้งเดิมของฉันซึ่งถามว่าจะทำอย่างไรให้สำเร็จddแต่ฉันคิดว่าเมื่ออ่านคำตอบอื่น ๆ แล้วคำตอบก็คือddไม่สามารถทำได้


จะเกิดอะไรขึ้นหากddrescueพบบล็อกที่ไม่ดีในสถานการณ์นี้ หากมันข้ามไปยังพื้นที่อื่นของดิสก์ (เพื่อหลีกเลี่ยงบล็อกที่ไม่ดี) และทำการคัดลอกต่อไปจากที่นั่นมันจะเขียนทับส่วนอื่น ๆ ของข้อมูลของคุณอีกครั้ง หากไม่คาดว่าจะใช้งานกับอุปกรณ์เดียวกันได้ก็ไม่มีเหตุผลที่จะใช้มาตรการพิเศษเพื่อป้องกันกรณีที่ข้อมูลเสียหาย
frostschutz

ฉันยอมรับว่านี่เป็นปัญหาที่อาจเกิดขึ้น แต่ฉันไม่ได้ดูที่กรณีขอบเพราะฉันสามารถใช้ในการทำสิ่งที่ฉันต้องการ มีddrescueตัวเลือกในการ จำกัด ความพยายามในการกู้คืนข้อมูลที่ไม่ถูกต้อง แต่ฉันไม่ได้ใช้มัน
starfry

ความจริงที่ว่ามันปฏิเสธที่จะทำงานหากอินพุตและเอาต์พุตเหมือนกันอาจเป็นตัวบ่งชี้ที่ดีว่าไม่ปลอดภัย
psusi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.