สิ่งใดที่สามารถอธิบายการจัดการไฟล์ที่กระจัดกระจายของ / in tmpfs นี้ได้


14

ในext4พาร์ติชันระบบแฟ้มของฉันฉันสามารถเรียกใช้รหัสต่อไปนี้:

fs="/mnt/ext4"

#create sparse 100M file on ${fs}
dd if=/dev/zero \
   of=${fs}/sparse100M conv=sparse seek=$((100*2*1024-1)) count=1 2> /dev/null

#show its actual used size before
echo "Before:"
ls ${fs}/sparse100M -s

#setting the sparse file up as loopback and run md5sum on loopback
losetup /dev/loop0 ${fs}/sparse100M 
md5sum /dev/loop0

#show its actual used size afterwards
echo "After:"
ls ${fs}/sparse100M -s

#release loopback and remove file
losetup -d /dev/loop0
rm ${fs}/sparse100M

ซึ่งให้ผลผลิต

Before:
0 sparse100M
2f282b84e7e608d5852449ed940bfc51  /dev/loop0
After:
0 sparse100M

ทำสิ่งเดียวกันกับ tmpfs เช่นเดียวกับ:

fs="/tmp"

อัตราผลตอบแทน

Before:
0 /tmp/sparse100M
2f282b84e7e608d5852449ed940bfc51  /dev/loop0
After:
102400 /tmp/sparse100M

ซึ่งโดยทั่วไปหมายความว่าสิ่งที่ฉันคาดว่าจะอ่านข้อมูลเพียงอย่างเดียวทำให้ไฟล์กระจัดกระจายเพื่อ "ระเบิดเหมือนบอลลูน"?

ฉันคาดหวังว่าเป็นเพราะการสนับสนุนที่สมบูรณ์แบบน้อยกว่าสำหรับไฟล์ที่กระจัดกระจายในtmpfsระบบไฟล์และโดยเฉพาะอย่างยิ่งเนื่องจาก FIEMAP ioctl ที่ขาดหายไป แต่ฉันไม่แน่ใจว่าอะไรเป็นสาเหตุของพฤติกรรมนี้ คุณบอกฉันได้ไหม?


ครวญเพลง มีเพจศูนย์ที่แชร์ (copy-on-write) ซึ่งสามารถใช้เมื่อจำเป็นต้องมีเพจแบบกระจายเป็น mmap () ed ดังนั้นฉันไม่แน่ใจว่าเหตุใดการอ่านประเภทใด ๆ จากไฟล์ tmpfs จะต้องมีการจัดสรรหน่วยความจำจริง lwn.net/Articles/517465 ฉันสงสัยว่านี่เป็นผลข้างเคียงของการแปลงลูปเพื่อใช้ direct io แต่ดูเหมือนว่าไม่ควรมีความแตกต่างเมื่อคุณพยายามใช้ลูปชนิดใหม่ใน tmpfs spinics.net/lists/linux-fsdevel/msg60337.html
sourcejedi

บางทีนี่อาจจะได้คำตอบถ้าอยู่บน SO? แค่คิด

1
เอาต์พุตของ / tmp มีไฟล์ต่างกันก่อน / หลัง นั่นคือการพิมพ์ผิด? ก่อน: 0 / tmp / sparse100 (ไม่มี M ที่ส่วนท้าย) หลัง: 102400 / tmp / sparse100M (พร้อมกับ M ต่อท้าย)
YoMismo

@YoMismo ใช่เพียงแค่พิมพ์ผิดเล็กน้อย
มนุษยชาติ

คำตอบ:


4

ก่อนอื่นคุณไม่ได้อยู่คนเดียวในการทำให้งงเกี่ยวกับปัญหาเหล่านี้

นี้ไม่ได้ จำกัด เพียงtmpfsแต่ได้รับความกังวลอ้างกับ NFSv4

หากแอปพลิเคชันอ่าน 'หลุม' ในไฟล์แบบกระจายระบบไฟล์จะแปลงบล็อกว่างเปล่าเป็นบล็อก "ของจริง" ที่เต็มไปด้วยเลขศูนย์และส่งกลับไปยังแอปพลิเคชัน

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

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

โชคดีที่ไม่เพียง แต่tmpfsรองรับสิ่งนี้ แต่ยังมีกลไกในการ "ขุด" หลุมกลับออกไป

การใช้ยูทิลิตี้ CLI ทำให้fallocateเราสามารถตรวจจับและขุดหลุมเหล่านี้ได้สำเร็จ

ตามman 1 fallocate:

-d, --dig-holes
      Detect and dig holes.  This makes the file sparse in-place, without
      using extra disk space.  The minimum size of the hole depends on
      filesystem I/O  block size (usually 4096 bytes).  Also, when using
      this option, --keep-size is implied.  If no range is specified by
      --offset and --length, then the entire file is analyzed for holes.

      You can think of this option as doing a "cp --sparse" and then
      renaming the destination file to the original, without the need for
      extra disk space.

      See --punch-hole for a list of supported filesystems.

fallocateทำงานในระดับไฟล์แม้ว่าและเมื่อคุณทำงานmd5sum กับอุปกรณ์บล็อก (ขอให้อ่านตามลำดับ) คุณกำลังสะดุดช่องว่างที่แน่นอนระหว่างวิธีที่fallocate()syscall ควรทำงาน เราสามารถเห็นสิ่งนี้ได้ในทางปฏิบัติ:

ในการดำเนินการโดยใช้ตัวอย่างของคุณเราเห็นดังต่อไปนี้:

$ fs=$(mktemp -d)
$ echo ${fs}
/tmp/tmp.ONTGAS8L06
$ dd if=/dev/zero of=${fs}/sparse100M conv=sparse seek=$((100*2*1024-1)) count=1 2>/dev/null
$ echo "Before:" "$(ls ${fs}/sparse100M -s)"
Before: 0 /tmp/tmp.ONTGAS8L06/sparse100M
$ sudo losetup /dev/loop0 ${fs}/sparse100M
$ sudo md5sum /dev/loop0
2f282b84e7e608d5852449ed940bfc51  /dev/loop0
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 102400 /tmp/tmp.ONTGAS8L06/sparse100M
$ fallocate -d ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 0 /tmp/tmp.ONTGAS8L06/sparse100M

ตอนนี้ ... ที่ตอบคำถามพื้นฐานของคุณ คำขวัญทั่วไปของฉันคือ "ทำให้ประหลาด" ดังนั้นฉันจึงขุดเพิ่มเติม ...

$ fs=$(mktemp -d)
$ echo ${fs}
/tmp/tmp.ZcAxvW32GY
$ dd if=/dev/zero of=${fs}/sparse100M conv=sparse seek=$((100*2*1024-1)) count=1 2>/dev/null
$ echo "Before:" "$(ls ${fs}/sparse100M -s)"
Before: 0 /tmp/tmp.ZcAxvW32GY/sparse100M
$ sudo losetup /dev/loop0 ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 1036 /tmp/tmp.ZcAxvW32GY/sparse100M
$ sudo md5sum ${fs}/sparse100M
2f282b84e7e608d5852449ed940bfc51  /tmp/tmp.ZcAxvW32GY/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 1036 /tmp/tmp.ZcAxvW32GY/sparse100M
$ fallocate -d ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 520 /tmp/tmp.ZcAxvW32GY/sparse100M
$ sudo md5sum ${fs}/sparse100M
2f282b84e7e608d5852449ed940bfc51  /tmp/tmp.ZcAxvW32GY/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 520 /tmp/tmp.ZcAxvW32GY/sparse100M
$ fallocate -d ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 516 /tmp/tmp.ZcAxvW32GY/sparse100M
$ fallocate -d ${fs}/sparse100M
$ sudo md5sum ${fs}/sparse100M
2f282b84e7e608d5852449ed940bfc51  /tmp/tmp.ZcAxvW32GY/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 512 /tmp/tmp.ZcAxvW32GY/sparse100M
$ fallocate -d ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 0 /tmp/tmp.ZcAxvW32GY/sparse100M
$ sudo md5sum ${fs}/sparse100M
2f282b84e7e608d5852449ed940bfc51  /tmp/tmp.ZcAxvW32GY/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 0 /tmp/tmp.ZcAxvW32GY/sparse100M

คุณจะเห็นว่าเป็นเพียงการกระทำของการดำเนินการlosetupเปลี่ยนแปลงขนาดของแฟ้มเบาบาง ดังนั้นสิ่งนี้จึงกลายเป็นการผสมผสานที่น่าสนใจของtmpfsกลไกกลไก HOLE_PUNCH fallocateและอุปกรณ์ตัดกัน


2
ขอบคุณสำหรับคำตอบ. ฉันรู้ว่าtmpfsรองรับไฟล์ที่กระจัดกระจายและ punch_hole นั่นคือสิ่งที่ทำให้เกิดความสับสน - tmpfs สนับสนุนสิ่งนี้ดังนั้นทำไมจึงต้องเติมช่องว่างเมื่ออ่านผ่านอุปกรณ์ลูป losetupไม่เปลี่ยนขนาดไฟล์ แต่สร้างอุปกรณ์บล็อกซึ่งในระบบส่วนใหญ่จะสแกนเนื้อหาเช่น: มีตารางพาร์ทิชันหรือไม่ มีระบบไฟล์พร้อม UUID หรือไม่ ฉันควรสร้าง / dev / disk / by-uuid / symlink แล้วหรือไม่ และการอ่านเหล่านั้นทำให้ส่วนต่าง ๆ ของไฟล์กระจัดกระจายได้รับการจัดสรรเพราะด้วยเหตุผลบางอย่างลึกลับ tmpfs เติมหลุมใน (บางส่วน) อ่าน
frostschutz

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

นี่มันแปลก ในระบบของฉันฉันทำตามขั้นตอนเดียวกันแม้ว่าด้วยตนเองและไม่ได้อยู่ในสคริปต์ ครั้งแรกที่ฉันทำไฟล์ 100M เช่นเดียวกับ OP จากนั้นฉันทำซ้ำขั้นตอนด้วยไฟล์ 10MB เท่านั้น ผลลัพธ์แรก: ls -s sparse100M คือ 102400 แต่ ls -s ในไฟล์ 10MB เป็นเพียง 328 บล็อก ??
Patrick Taylor

1
@PatrickTaylor ~ 328K เป็นเรื่องเกี่ยวกับสิ่งที่ใช้หลังจากสแกนเนอร์ UUID ที่มา แต่คุณไม่ได้ cat / md5sum อุปกรณ์ห่วงสำหรับการอ่านแบบเต็ม
frostschutz

1
ฉันถูกขุดผ่านแหล่งสำหรับโมดูลห่วงเคอร์เนล (ในloop.c) และเห็นว่ามีสองฟังก์ชั่นที่เกี่ยวข้อง : &lo_read_simple lo_read_transferมีความแตกต่างเล็กน้อยบางประการในวิธีการจัดสรรหน่วยความจำระดับต่ำ ... lo_read_transferจริง ๆ แล้วขอให้ไม่ปิดกั้น io จากslab.h( GFP_NOIO) ในขณะทำการalloc_page()โทร lo_read_simple()บนมืออื่น ๆ alloc_page()ที่ไม่ได้ดำเนินการ
Brian Redbeard
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.