2015-04-01 4 views
6

के लिए मैं एक लिनक्स कर्नेल ड्राइवर लिख रहा हूं और प्रत्येक कार्य के लिए जो उपयोगकर्ताओं को डेटा भेजता है या उपयोगकर्ता स्पेस से डेटा भेजता है, मैं copy_to_user() और copy_from_user() का उपयोग कर रहा हूं। मेरा सवाल है: क्या मुझे इन कॉलों का उपयोग करने की ज़रूरत है यदि मैं सिर्फ एक मूल डेटा प्रकार की प्रतिलिपि बना रहा हूं जैसे कि u32 या int?copy_to_user() और copy_from_user() मूल डेटा प्रकार

+0

आप जो पूछ रहे हैं उसके बारे में कुछ भ्रम है। एक सैंपल फ़ंक्शन घोषणा, यह दर्शाती है कि क्या आप 'int' या 'int' पर पॉइंटर पास कर रहे हैं, यह सहायक होगा। अब तक पोस्ट किए गए दो उत्तरों आपके प्रश्न की दो अलग-अलग व्याख्याओं पर आधारित हैं। –

उत्तर

7

समारोह उपयोगकर्ता के अंतरिक्ष डेटा के लिए एक सूचक प्राप्त करता है, तो आप copy_from_user() उपयोग करने के लिए कर्नेल अंतरिक्ष (और इसके विपरीत) में उपयोगकर्ता अंतरिक्ष से उठाई-डेटा कॉपी करने के लिए है।

ध्यान दें कि पॉइंटर मान स्वयं मूल्य (सभी सी पैरामीटर की तरह) द्वारा पारित किया जाता है, इसलिए आपको copy_from_user() को पॉइंटर मान प्राप्त करने के लिए copy_from_user() डेटा को इंगित करने से पहले copy_from_user() करने की आवश्यकता नहीं है।

संख्यात्मक तर्क पॉइंटर तर्क के समान काम करते हैं; सी शर्तों में, वे दोनों scalars हैं। पैरामीटर के मान की प्रतिलिपि बनाने के लिए आपको copy_from_user() का उपयोग करने की आवश्यकता नहीं है; यह पहले से ही कॉपी किया गया है। आपको केवल उस डेटा की प्रतिलिपि बनाने के लिए इसका उपयोग करना होगा जो पास किए गए पॉइंटर द्वारा इंगित किया गया है।

तो यदि आपके पास int प्रकार का पैरामीटर है, तो आप इसका सीधे उपयोग कर सकते हैं। यदि आपका पैरामीटर int पर इंगित करता है, तो int ऑब्जेक्ट उपयोगकर्ता स्थान पर होगा, और आपको उस ऑब्जेक्ट के मान को कर्नेल स्पेस में कॉपी करने के लिए copy_to_user का उपयोग करने की आवश्यकता है।

+0

मैं आपसे असहमत हूं। मान लीजिए कि उपयोगकर्ता स्थान में एक पॉइंटर पेज गठबंधन नहीं है और आपको इसे पूरा करने के लिए पॉइंटर के दोनों हिस्सों को इकट्ठा करना होगा? कॉल करने के लिए पैरामीटर के रूप में उपयोगकर्ता से प्राप्त एकमात्र चीज उपयोगकर्ता सूचक है, लेकिन यदि यह किसी अन्य उपयोगकर्ता सूचक को इंगित करती है, तो वह पॉइंटर उपयोगकर्ता_copy के साथ अधिग्रहित किया जाना चाहिए। 64 बिट वातावरण में, उपयोगकर्ता सूचक 8 बाइट चौड़ा होता है, और इसे पृष्ठ सीमा में विभाजित किया जा सकता है, इसलिए आपको वर्चुअल पेज टेबल को उपयोगकर्ता स्थान से कर्नेल में अनुवाद करने के लिए acces करना होगा। इसके अलावा, उपयोगकर्ता स्पेस पेजों को बदल दिया जा सकता है, इसलिए इसके साथ सावधान रहें। –

+0

जब आप कहते हैं कि पॉइंटर पेज गठबंधन नहीं है, तो क्या आपका मतलब है कि पॉइंटर ऑब्जेक्ट को गलत तरीके से गलत किया गया है, या डेटा जो इंगित करता है? पॉइंटर्स स्केलर होते हैं और हमेशा मूल्य से गुजरते हैं। यदि सिस्टम कॉल में कहा गया है, तो 'शून्य * 'पैरामीटर, कर्नेल फ़ंक्शन जो सिस्टम कॉल को संभालता है उसे सूचक की * प्रति * प्राप्त होता है; कॉलर पक्ष पर पॉइंटर ऑब्जेक्ट का संरेखण अप्रासंगिक है। –

+0

सरल डेटा प्रकारों (जैसे 'int *') के पॉइंटर्स के लिए, 'put_user' और' get_user' का भी उपयोग किया जा सकता है। – holgac

2

जब कोई उपयोगकर्ता कर्नेल स्पेस को डेटा पास करता है, तो यह डेटा कई पृष्ठों पर विभाजित किया जा सकता है, और ये पृष्ठ मेमोरी में भी बदल सकते हैं। इन मामलों में, आपको कर्नेल को पृष्ठ में स्वैप करने और उस पृष्ठ तक पहुंच प्राप्त करने की प्रतीक्षा करनी होगी जहां डेटा है। प्राथमिक डेटा प्रकारों (जैसे int या पॉइंटर्स) के मामले में यह भी सच है कि कुछ आर्किटेक्चर (विशेष रूप से x86 इंटेल) उपयोगकर्ता को डेटा संरेखित करने के लिए मजबूर नहीं करता है, इसलिए एक पूर्णांक को पृष्ठ सीमा के चारों ओर विभाजित किया जा सकता है। आपके पास पूर्णांक के पहले भाग तक पहुंच हो सकती है, लेकिन पूरी चीज तक पहुंचने से पहले मेमोरी मैनेजर द्वारा दूसरे को बदलने के लिए प्रतीक्षा करें।

आप सभी उपयोगकर्ता डेटा को उस संरचना में डालकर कुछ राउंडट्रिप्स सहेज सकते हैं जिनके पॉइंटर को कर्नेल में पास किया जाता है। आप एक ब्लॉक के रूप में यह copy_from_user कर सकते हैं और पहुंच को बचाने (और होने का खतरा में चल रहे कई बार अवरुद्ध)

तो, और एक निष्कर्ष के रूप में, , यहां तक ​​कि बुनियादी प्रकार के लिए कार्यों का उपयोग के रूप में उनमें से बहुत सारे हैं। कर्नेल मोड में चलते समय उपयोगकर्ता डेटा कहां हो सकता है इसके बारे में कुछ भी न मानें। आपके पास इसका उपयोग है, लेकिन उपयोगकर्ता डेटा के कर्नेल वर्चुअल पतों में उपयोगकर्ता मोड में देखे गए वर्चुअल पतों से कोई लेना देना नहीं है।

+0

लुइस: मुझे लगता है कि आपने ओपी का गलत व्याख्या किया है। सभी ओपी करने का प्रयास कर रहा है मूल डेटा प्रकार का एक मूल्य पास है। ओपी वास्तव में पूछ रहा है कि संदर्भ के बजाय मूल्य के आधार पर मूल डेटा पास करना संभव है या नहीं। जैसा कि @ किथ इंगित कर रहा था, आम तौर पर एक सूचक पास हो जाता है, और यह सूचक मूल्य से गुजरता है ताकि इसे सीधे एक्सेस किया जा सके। हालांकि यदि आप उपयोगकर्ता पॉइंटर को हटाना चाहते हैं, तो आपको कर्नेल में copy_from_user() या get_user() फ़ंक्शन का उपयोग करना होगा। –

+0

क्षमा करें, लेकिन जैसा कि वह कहता है: * यदि मैं सिर्फ एक मूल डेटा प्रकार की प्रतिलिपि बना रहा हूं जैसे कि u32 या int * अर्थ कॉपी करना, तो मुझे लगता है कि int संदर्भ द्वारा पारित किया गया है (उदाहरण के लिए कुछ मान वापस करने के लिए) बेशक अगर वह केवल कर्नेल के लिए मूल्य गुजर रहा है (लेकिन उपयोगकर्ता स्थान पर वापस नहीं) तो वह ऐसा कर सकता है। मैं ioctl पर सोच नहीं रहा हूं, जहां यह समझ में आता है। मान लीजिए कि वह 'int' करने की कोशिश कर रहा है; लिखो (एफसी, और ए, आकार का ए); '... –

+0

बेशक आप ** ** ** लिखने (2) ** में डेटा के रूप में कर्नेल स्पेस को पास पॉइंटर का उपयोग कर सकते हैं, लेकिन एक बनाने पर ज्यादा समझ नहीं है इस तरह चालक। वह कहता है * ... और हर समारोह के लिए ... * –

संबंधित मुद्दे