2012-03-15 15 views
14

के लिए loff_t * offp को समझना मैं एक डिवाइस ड्राइवर को डिज़ाइन कर रहा हूं जो बस एक वर्ण बफर को पढ़ता है और लिखता है। मेरा प्रश्न file_operations संरचना read और write में दो कार्यों के संबंध में है। मैं वास्तव में समझ नहीं पा रहा हूं कि loff_t *offp वास्तव में क्या है। मुझे पता है कि *offp दोनों पढ़ने और लिखने के संचालन के लिए फ़ाइल ऑफसेट का अर्थ फ़ाइल की वर्तमान पढ़ने/लेखन स्थिति है, हालांकि मुझे यह भी सुनिश्चित नहीं है कि डिवाइस फ़ाइल से लिखने या पढ़ने के लिए इसका क्या अर्थ है।file_operations

जो मैंने एकत्र किया है, और इस तरह से मैं अपने डिवाइस से लिख रहा हूं और पढ़ रहा हूं कि मैं एक ऐसी संरचना तैयार करता हूं जो मेरे डिवाइस का प्रतिनिधित्व करता है जिसे मैं my_char_struct कहता हूं जो दिखाया गया है।

struct my_char_structure{ 
    struct cdev my_cdev; 
    struct semaphore sem; 
    char *data; 
    ssize_t data_size; 
    unsigned int access_key; 
    unsigned long size; 
}; 

यह एक स्थिर संरचना है कि प्रारंभ और जब मेरे ड्राइवर insmod जैसे है की ओर इशारा कर रहा है।

static dev_t dev_num; 
static struct my_char_structure Dev; 

int start_mod(void){ 
    //Because we are dealing with a fictitious device, I want 
    //the driver to create my two devices with arbitrarily 
    //assigned major numbers. 
    struct my_char_structure *my_dev = &Dev; 
    int err; 

    alloc_chrdev_region(&dev_num, FIRST_MINOR, COUNT, DEVICE_NAME); 

    sema_init(&(my_dev->sem),1); 

    cdev_init(&(my_dev->my_cdev), &fops); 
    my_dev->my_cdev.owner = THIS_MODULE; 
    my_dev->my_cdev.ops = &fops;// fops is my file operations struct 

    err = cdev_add(&my_dev->my_cdev, dev_num, COUNT); 
    if(err<0) 
     printk(KERN_ALERT "There was an error %d.",err); 
    printk(KERN_ALERT " insmod to major number %d",MAJOR(dev_num)); 

    return 0; 
} 

module_init(start_mod); 

जब मेरे डिवाइस खुला है, मैं सिर्फ फ़ाइल है कि स्थिर संरचना है कि मैं module_init(start_mod) जैसे दौरान सेट कर लेते हैं को इंगित करने के लिए खुला के लिए एक सूचक बना ...

int dev_open(struct inode *in_node, struct file *filp){ 
    static struct my_char_structure *my_dev; 
    my_dev = container_of(in_node->i_cdev, struct my_char_structure, my_cdev); 
    printk(KERN_ALERT "The device number is %d",iminor(in_node)); 
    if(!my_dev) 
     printk(KERN_ALERT "something didn't work. my_dev not initialized."); 
    filp->private_data = my_dev; 
    return 0; 
} 

क्या मेरी पढ़ने और लिखने के तरीकों को संशोधित किया गया है कि प्रारंभिक संरचना देव, मैंने अपनी खुली फाइलों के साथ इंगित किया है। जो कुछ भी मैं copy_to_user मेरी संरचना से उपयोगकर्ता को डिवाइस पर लिखा गया है और जो कुछ भी मैं copy_from_user उपयोगकर्ता सोचता हूं कि वे लिख रहे हैं। लेकिन मेरी शुरुआती संरचना देव को बदलने से परे, फ़ाइल स्थिति या ऑफ़सेट का विचार तब तक समझ में नहीं आता है जब तक कि यह कुछ मनमानी संरचना या प्रकार के लिए कर्नेल के भीतर स्मृति को बफर करने के लिए सूचक को संदर्भित नहीं करता है। फ़ाइल ऑफसेट के लिए मेरे पास एकमात्र व्याख्या है ... क्या यह सही है? क्या यह loff_t *offp क्या है इसका संदर्भ है?

write(struct file *filp, const char __user *buff, size_t count, loff_t *offp) 
read(struct file *filp, char __user *buff, size_t count, loff_t *offp) 

क्या loff_t है * offp शुरू में करने के लिए सेट कुछ file_operation इस तरह पढ़ने/लिखने के रूप में कहा जाता है और मैं व्यक्तिगत रूप से *offp सेट नहीं था जब (मेरी समझ दी सही है),?

यदि अंतिम फ़ाइल_ऑपरेशन ऑफपी = some_arbitrary_address (क्योंकि मैंने इसे बताया है) में, यह है कि इस ऑपरेशन को फिर से कहने पर ऑफप सेट किया जाएगा?

क्या होता है यदि मेरे पास अन्य file_opens संचालन चल रहा है, तो क्या यह आखिरी फ़ाइल_ऑपरेशन के रूप में छोड़ा जाएगा, या यह उस फ़ाइल_ओपन ऑपरेशन का एक टैब रखेगा जो इसे इस्तेमाल करता है और

एक चार डिवाइस की अवधारणा मेरे लिए बहुत सारणी है जब ऐसा लगता है कि डिवाइस स्वयं फ़ाइल की तरह जानकारी भी संग्रहीत नहीं करता है, बल्कि इसके ड्राइवर को जानकारी बचाता है। मुझे उम्मीद है कि मैंने अपनी धुंधली व्याख्या की है और मैं कुछ भी साफ़ कर दूंगा जो मुझे अस्पष्ट लगता है।

उत्तर

19

"loff_t" की स्थिति "लंबे समय से ऑफसेट", यानी, एक की तलाश है कि off_t, off64_t की पागल विविधता को एकीकृत, और इतने पर है, ताकि चालकों सिर्फ loff_t उपयोग कर सकते हैं और इसके बारे में चिंता नहीं है।

पॉइंटर स्वयं, जब आप ड्राइवर में जाते हैं, तो उपयोगकर्ता द्वारा प्रदान किए गए ऑफसेट को इंगित करता है (माना जाता है कि यह उपयोगकर्ता कोड ड्राइवर पहुंच कर रहा है-तकनीकी रूप से कर्नेल अपना स्वयं का प्रदान कर सकता है, लेकिन उपयोगकर्ता केस एक है के बारे में सोचने के लिए) lseek या llseek या lseek64, आदि के माध्यम से, और फिर सामान्य पढ़ने और लिखने के संचालन के माध्यम से।एक नियमित ऑन-डिस्क फ़ाइल के मामले पर विचार करें: जब आप पहली बार open फ़ाइल करते हैं, तो आप (उपयोगकर्ता के रूप में) कर्नेल को डेटा संरचना प्रदान करने के लिए प्राप्त करते हैं जो फ़ाइल में आपकी वर्तमान स्थिति का ट्रैक रखता है, ताकि यदि आप read या write कुछ बाइट्स, अगले read या write जहां से आपने छोड़ा था वहां से उठाता है।

इसके अलावा, अगर आप dup फ़ाइल वर्णनकर्ता, या आदेशों के अनुक्रम चल के मामले में अलग (जैसे) fork और exec बराबर करते हैं, कि तलाश स्थिति सभी इनहेरीट प्रक्रियाओं के द्वारा साझा किया जाता है। इसलिए, सुरक्षा प्रॉम्प्ट पर, आदेश:

(prog1; prog2; prog3) > outputfile 

ताकि उत्पादन कि prog2 लिखते तुरंत prog1 से उत्पादन के बाद फ़ाइल में चला जाता है dup तीन कार्यक्रमों के लिए वर्णनकर्ता, एक आउटपुट फ़ाइल बनाता है तो, है, और prog3 से आउटपुट अन्य दो-सब का पालन करता है क्योंकि सभी तीन अलग-अलग प्रक्रियाएं समान आंतरिक loff_t के साथ समान अंतर्निहित कर्नेल डेटा संरचना साझा करती हैं।

वही डिवाइस ड्राइवर फ़ाइलों पर लागू होता है। जब आपके पढ़ने और लिखने के कार्यों को बुलाया जाता है, तो आपको उपयोगकर्ता द्वारा प्रदान की गई "वर्तमान ऑफ़सेट" प्राप्त होती है, और आप इसे आवश्यकतानुसार अपडेट कर सकते हैं (और चाहिए) ... मान लीजिए कि कोई ज़रूरत है (उदाहरण के लिए, आप उपयोगकर्ताओं को प्रदान करना चाहते हैं एक नियमित फ़ाइल की उपस्थिति, जिसमें तथ्य है कि ऑफसेट्स को पढ़ने और लिखने के रूप में जाना जाता है)। यदि डिवाइस ऑफ़सेट ऑफ़सेट के कुछ तार्किक अनुप्रयोग हैं, तो आप इसका उपयोग यहां कर सकते हैं।

बेशक, डिवाइस ड्राइवरों के लिए बहुत कुछ है, यही कारण है कि इस सामान (q.v.) पर पूरी पुस्तक-अध्याय हैं। :-)

+1

तो जब मैं ऑफसेट को ऑफसेट + = बाइट्स_read/लिखने के लिए बदलता हूं, तो उपयोगकर्ता सूचक बदल जाता है, लेकिन यह स्वचालित रूप से ऐसा नहीं करता है? मुझे लगता है कि यह मेरे लिए कुछ चीजों को साफ़ करता है। मैं लिनक्स डिवाइस ड्राइवर 3 संस्करण संस्करण पढ़ रहा था कि हर कोई एक परिचय के रूप में पढ़ता है और इसमें यह चित्र था जहां ऑफसेट पॉइंटर कुछ अजीब कर्नेल अबास्ट्रक्शन (बेहतर शब्द की कमी के लिए) का संदर्भ दे रहा था जिसे उन्होंने फ़ाइल स्थिति कहा था। मदद के लिए धन्यवाद, इस तरह की चीजों को साफ़ करता है :) –

+2

हां। (संभवतः आपका मतलब '* offp + = nbytes' है।) जो वैरिएबल आप बदल रहे हैं वह वास्तव में कर्नेल-स्पेस चीज है, लेकिन यह * उपयोगकर्ता की तलाश-ऑफसेट का प्रतिनिधित्व करता है। (या, कुछ मामलों में, ऑफसेट को 'प्रीड' या 'पिरिट' कॉल, या यहां तक ​​कि कुछ और, लेकिन अक्सर, उपयोगकर्ता का 'lseek' ऑफसेट' प्रदान किया जाता है।) "अजीब कर्नेल अबास्ट्रक्शन", जैसा कि आप इसे कहते हैं, क्या है '(prog1; prog2)> आउटपुट' काम करता है। संयोग से, * बीएसडी कर्नेल में, 'uiomove' नामक एक फ़ंक्शन है जो स्वचालित रूप से आपके लिए "उपयोगकर्ता I/O ऑफ़सेट" अपडेट करता है; लिनक्स बस दूसरी तरफ चला गया। – torek

0

Torek's answer उत्कृष्ट है। बस थोड़ा अतिरिक्त विवरण/संदर्भ जोड़ना ... पहले के लिनक्स कर्नेल (2.6.28) से, यहां सिस्टम कॉल में ऑफसेट का ऑफसेट है ... यह ऑफसेट को उपयोगकर्ता स्पेस से ऑफसेट करने से पहले अस्थायी चर में कॉपी करता है कर्नेल ड्राइवर-आमंत्रण तंत्र में, और फिर इसे उपयोगकर्ता फ़ाइल में वापस कॉपी करता है। इस प्रकार चालक को ऑफसेट देखता है, इसके उपयोगकर्ता दृश्य से decoupled है, और उन स्थितियों को सुविधाजनक बनाता है जहां सिस्टम कॉल में इसे ऑफसेट करते हैं, इसलिए कोई SEGVIO नहीं होता है।

SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd, loff_t __user *, offset, size_t, count) 
{ 
    loff_t pos; 
    ssize_t ret; 

    if (offset) { 
     if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t)))) 
      return -EFAULT; 
     ret = do_sendfile(out_fd, in_fd, &pos, count, 0); 
     if (unlikely(put_user(pos, offset))) 
      return -EFAULT; 
     return ret; 
    } 

    return do_sendfile(out_fd, in_fd, NULL, count, 0); 
} 

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

  • कोई संबंधित समस्या नहीं^_^