TL; DR: यदि लिनक्स कर्नेल एक आई / ओ लिखता है , तो क्या यह पता लगाने के लिए आवेदन का कोई तरीका है?
मुझे पता है कि आपके पास fsync()स्थायित्व के लिए फ़ाइल (और इसकी मूल निर्देशिका) है । सवाल यह है कि यदि कर्नेल गंदे बफ़र्स को खो देता है जो कि I / O त्रुटि के कारण लंबित हैं , तो एप्लिकेशन इसे कैसे पता लगा सकता है और पुनर्प्राप्त या निरस्त कर सकता है?
डेटाबेस एप्लिकेशन आदि के बारे में सोचें, जहां लिखने और स्थायित्व लिखने का क्रम महत्वपूर्ण हो सकता है।
खोया लिखा? कैसे?
लिनक्स कर्नेल की ब्लॉक लेयर कुछ परिस्थितियों में आई / ओ अनुरोधों को खो देती है जो त्रुटि के साथ सफलतापूर्वक सबमिट किए जाते हैं write(), pwrite()आदि:
Buffer I/O error on device dm-0, logical block 12345
lost page write due to I/O error on dm-0
(देखें end_buffer_write_sync(...)और end_buffer_async_write(...)मेंfs/buffer.c )।
नए कर्नेल पर त्रुटि के बजाय "खोया async पेज लिखना" होगा , जैसे:
Buffer I/O error on dev dm-0, logical block 12345, lost async page write
चूंकि एप्लिकेशन की write()त्रुटि के बिना पहले ही वापस आ चुका है, इसलिए आवेदन में त्रुटि की रिपोर्ट करने का कोई तरीका नहीं है।
उनका पता लगा रहे हैं?
मैं कर्नेल स्रोतों से परिचित नहीं हूं, लेकिन मुझे लगता है कि यह AS_EIOबफर पर सेट होता है जो कि लिखने में विफल रहा है, अगर यह एक async लेखन कर रहा है:
set_bit(AS_EIO, &page->mapping->flags);
set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
SetPageError(page);
लेकिन यह मेरे लिए अस्पष्ट है कि क्या या कैसे इस बारे में एप्लिकेशन को पता चल सकता है जब उसने बाद में fsync()डिस्क पर इसकी पुष्टि करने के लिए फाइल की है।
ऐसा लग रहा है wait_on_page_writeback_range(...)मेंmm/filemap.c से हो सकता है do_sync_mapping_range(...)मेंfs/sync.c है जिसके द्वारा कहा जाता है बारी है sys_sync_file_range(...)। -EIOयदि एक या अधिक बफ़र्स नहीं लिखे जा सकते हैं तो यह वापस आ जाता है।
यदि, जैसा कि मैं अनुमान लगा रहा हूं, यह fsync()परिणाम के लिए प्रचारित करता है , तो अगर ऐप पैन करता है और बाहर निकलता है अगर इसे I / O त्रुटि मिलती है fsync()और फिर से शुरू होने पर अपने काम को फिर से करने का तरीका जानता है, तो यह पर्याप्त सुरक्षा होना चाहिए?
वहाँ शायद के लिए ऐप को जानने का कोई तरीका नहीं है जो बाइट ऑफसेट खो पृष्ठों के लिए एक फ़ाइल के अनुरूप अगर यह जानता है कि कैसे, लेकिन तो यह उन्हें फिर से लिखने सकते में ऐप्स को पिछली बार सफल के बाद से सभी अपने लंबित काम को दोहराता है, तो fsync()फ़ाइल की, और कहा कि पुनर्लेखन किसी भी गंदे कर्नेल बफ़र्स को फाइल के खिलाफ लिखने के लिए खो दिया गया है, जो कि खोए गए पृष्ठों पर किसी भी I / O त्रुटि झंडे को साफ करना चाहिए और अगले fsync()को पूरा करने की अनुमति देना चाहिए - सही है?
क्या तब कोई अन्य, हानिरहित, परिस्थितियां ऐसी fsync()हो सकती हैं, -EIOजहां से बाहर निकलना और काम को फिर से करना बहुत अधिक कठोर होगा?
क्यों?
बेशक ऐसी त्रुटियां नहीं होनी चाहिए। इस मामले में त्रुटि dm-multipathड्राइवर की चूक के बीच एक दुर्भाग्यपूर्ण बातचीत से उत्पन्न हुई और सैन द्वारा उपयोग किए जाने वाले अर्थ कोड पतले-प्रावधान वाले भंडारण को आवंटित करने में विफलता की रिपोर्ट करने के लिए। लेकिन यह एकमात्र परिस्थिति नहीं है जहां वे हो सकते हैं - मैंने इसके लिए पतली प्रावधानित LVM से रिपोर्ट भी देखी है, उदाहरण के लिए, libvirt, Docker, और बहुत कुछ। एक डेटाबेस की तरह एक महत्वपूर्ण एप्लिकेशन को इस तरह की त्रुटियों से निपटने की कोशिश करनी चाहिए, बजाय आँख बंद करके ले जाने के जैसे कि सब ठीक है।
यदि कर्नेल को लगता है कि कर्नेल घबराहट के साथ मरने के बिना लिखना खोना ठीक है, तो अनुप्रयोगों को सामना करने का एक तरीका खोजना होगा।
व्यावहारिक प्रभाव यह है कि मुझे एक ऐसा मामला मिला जहां एक SAN के साथ एक बहुपथ समस्या का कारण खो गया जो लिखता है कि डेटाबेस भ्रष्टाचार के कारण उतरा क्योंकि DBMS को पता नहीं था कि उसके लेखन विफल हो गए थे। मज़ा नहीं।