/ 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 के कारण, लेकिन मुझे यकीन नहीं है कि इस व्यवहार का क्या कारण है? क्या तुम मुझे बता सकते हो?


हम। एक साझा (कॉपी-ऑन-राइट) शून्य पृष्ठ है, जिसका उपयोग तब किया जा सकता है जब उदाहरण के लिए एक विरल पृष्ठ को mmap () एड होने की आवश्यकता होती है। तो मुझे यकीन नहीं है कि विरल tmpfs फ़ाइल से किसी भी प्रकार के रीड को वास्तविक मेमोरी को आवंटित करने की आवश्यकता क्यों होगी। lwn.net/Articles/517465 । मुझे आश्चर्य है कि यह प्रत्यक्ष io का उपयोग करने के लिए लूप के रूपांतरण का कुछ दुष्प्रभाव था, लेकिन ऐसा लगता है कि जब आप tmpfs पर नए प्रकार के लूप का उपयोग करने का प्रयास करते हैं तो कोई अंतर नहीं होना चाहिए। spinics.net/lists/linux-fsdevel/msg60337.html
sourcejedi

शायद यह एक उत्तर मिल सकता है अगर यह एसओ पर था? बस एक विचार

1
/ Tmp के आउटपुट में पहले / बाद में अलग-अलग फाइलें हैं। क्या वह टाइपो है? पहले: 0 / tmp / sparse100 (अंत में एम के बिना) के बाद: 102400 / tmp / sparse100M (अनुगामी एम के साथ)।
योविस्मो

@YoMismo, हाँ एक केवल एक छोटे से टाइपो था
humanityANDpeace

जवाबों:


4

सबसे पहले आप इस तरह के मुद्दों के बारे में हैरान नहीं होते

यह सिर्फ सीमित नहीं है, tmpfsबल्कि NFSv4 के साथ एक चिंता का विषय है ।

यदि कोई अनुप्रयोग विरल फ़ाइल में 'छेद' पढ़ता है, तो फ़ाइल सिस्टम शून्य ब्लॉकों को "वास्तविक" ब्लॉक में शून्य से भर देता है, और उन्हें अनुप्रयोग में वापस कर देता है।

जब md5sumकिसी फ़ाइल को स्कैन करने का प्रयास किया जाता है, तो यह स्पष्ट रूप से अनुक्रमिक क्रम में ऐसा करने का विकल्प चुनता है , जो कि md5sum क्या करने का प्रयास कर रहा है, इसके आधार पर बहुत कुछ समझ में आता है।

जैसा कि फ़ाइल में मौलिक रूप से "छेद" होते हैं, यह अनुक्रमिक रीडिंग (कुछ स्थितियों में) फाइल को भरने के लिए ऑपरेशन की तरह लिखने पर एक कॉपी का कारण बनता है। इसके बाद fallocate()फाइलसिस्टम सपोर्ट में लागू किया जाता है या नहीं, इसके आसपास एक गहरा मुद्दा बन जाता है FALLOC_FL_PUNCH_HOLE

सौभाग्य से, न केवल इसका tmpfsसमर्थन करता है, बल्कि छिद्रों को वापस खोदने के लिए एक तंत्र है।

सीएलआई उपयोगिता का उपयोग करके 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जब आप ब्लॉक डिवाइस (क्रमिक रीडिंग का अनुरोध करते हैं) के खिलाफ फाइल स्तर पर काम करते हैं, तो आप सटीक अंतराल पर ट्रिपिंग कर रहे हैं कि कैसे syscall को काम करना चाहिए। हम इसे कार्रवाई में देख सकते हैं:md5sumfallocate()

कार्रवाई में, आपके उदाहरण का उपयोग करते हुए हम निम्नलिखित देखते हैं:

$ 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है कि विरल फाइलें और पंच_होल का समर्थन करता है। यही कारण है कि यह इतना भ्रामक है - इस tmpfs का समर्थन करता है , इसलिए एक लूप डिवाइस के माध्यम से पढ़ते समय स्पार्स छेद क्यों भरें और भरें? losetupफ़ाइल का आकार नहीं बदलता है, लेकिन यह एक ब्लॉक डिवाइस बनाता है, जो अधिकांश सिस्टम पर तब सामग्री के लिए स्कैन किया जाता है जैसे: क्या कोई विभाजन तालिका है? वहाँ UUID के साथ एक फाइल सिस्टम है? क्या मुझे / dev / डिस्क / बाय-यूआईडी / सिमलिंक बनाना चाहिए? और वे पढ़ते हैं पहले से ही विरल फ़ाइल के कुछ हिस्सों को आवंटित करने का कारण बनता है, क्योंकि कुछ रहस्यमय कारण से , tmpfs छेद को (कुछ) पढ़ता है।
25

1
क्या आप स्पष्ट कर सकते हैं " अनुक्रमिक रीडिंग (कुछ स्थितियों में) ऑपरेशन की तरह लिखने पर एक कॉपी का कारण बनता है ", कृपया? मैं यह समझने के लिए उत्सुक हूं कि एक रीड ऑपरेशन लिखने की कार्रवाई पर एक प्रतिलिपि कैसे ट्रिगर करेगा। धन्यवाद!
रोज़ा

यह गलत है। मेरे सिस्टम पर मैंने समान चरणों का पालन किया, हालांकि स्क्रिप्ट में मैन्युअल रूप से और नहीं। पहले मैंने ओपी की तरह ही 100 एम फाइल की। फिर मैंने केवल 10MB फ़ाइल के साथ चरणों को दोहराया। पहला परिणाम: ls -s sparse100M 102400 था। लेकिन 10MB फ़ाइल पर ls -s केवल 328 ब्लॉक था। ??
पैट्रिक टेलर

1
@PatrickTaylor ~ 328K यूयूआईडी स्कैनर द्वारा आने के बाद क्या उपयोग किया जाता है, इसके बारे में है, लेकिन आपने पूर्ण पढ़ने के लिए लूप डिवाइस को कैट / md5sum नहीं किया।
फ्रॉस्ट्सचुट्ज़

1
मैं लूप कर्नेल मॉड्यूल (में loop.c) के लिए स्रोत के माध्यम से खुदाई कर रहा था और देखा कि दो प्रासंगिक कार्य हैं : lo_read_simple& lo_read_transfer। निम्न स्तर के मेमोरी आवंटन में कुछ मामूली अंतर हैं ... lo_read_transferवास्तव में कॉल करने के दौरान slab.h( GFP_NOIO) से गैर-अवरुद्ध io ( ) का अनुरोध किया जाता है alloc_page()lo_read_simple()दूसरी ओर प्रदर्शन नहीं कर रहा है alloc_page()
ब्रायन रेडबर्ड ने
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.