2012-01-23 10 views
18

में एक प्रक्रिया की पेज टेबल चलना मैं लिनक्स में एक प्रक्रिया के लिए पेज टेबल पर नेविगेट करने की कोशिश कर रहा हूं। एक कर्नेल मॉड्यूल में मैं निम्नलिखित समारोह का एहसास:लिनक्स

static struct page *walk_page_table(unsigned long addr) 
{ 
    pgd_t *pgd; 
    pte_t *ptep, pte; 
    pud_t *pud; 
    pmd_t *pmd; 

    struct page *page = NULL; 
    struct mm_struct *mm = current->mm; 

    pgd = pgd_offset(mm, addr); 
    if (pgd_none(*pgd) || pgd_bad(*pgd)) 
     goto out; 
    printk(KERN_NOTICE "Valid pgd"); 

    pud = pud_offset(pgd, addr); 
    if (pud_none(*pud) || pud_bad(*pud)) 
     goto out; 
    printk(KERN_NOTICE "Valid pud"); 

    pmd = pmd_offset(pud, addr); 
    if (pmd_none(*pmd) || pmd_bad(*pmd)) 
     goto out; 
    printk(KERN_NOTICE "Valid pmd"); 

    ptep = pte_offset_map(pmd, addr); 
    if (!ptep) 
     goto out; 
    pte = *ptep; 

    page = pte_page(pte); 
    if (page) 
     printk(KERN_INFO "page frame struct is @ %p", page); 

out: 
    return page; 
} 

इस समारोह ioctl और addr से कहा जाता है प्रक्रिया पता स्थान में एक आभासी पता है:

static int my_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long addr) 
{ 
    struct page *page = walk_page_table(addr); 
    ... 
    return 0; 
} 

अजीब बात यह है कि में ioctl बुला एक उपयोगकर्ता अंतरिक्ष प्रक्रिया, यह segfaults ... लेकिन ऐसा लगता है कि जिस तरह से मैं पेज टेबल प्रविष्टि की तलाश में हूं, वह सही है क्योंकि dmesg के साथ मैं प्रत्येक ioctl कॉल के लिए उदाहरण प्राप्त करता हूं:

[ 1721.437104] Valid pgd 
[ 1721.437108] Valid pud 
[ 1721.437108] Valid pmd 
[ 1721.437110] page frame struct is @ c17d9b80 

तो प्रक्रिया क्यों 'ioctl' कॉल को पूरा नहीं कर सकती है? शायद मुझे पेज टेबल पर नेविगेट करने से पहले कुछ लॉक करना होगा?

मैं कर्नेल 2.6.35-22 और तीन स्तर पृष्ठ तालिकाओं के साथ काम कर रहा हूं।

सभी को धन्यवाद!

+0

क्या यह संभव है कि ioctl syscall सफलतापूर्वक वापस आती है और कोड उसके बाद segfaulting है? –

+0

नहीं क्योंकि 'वापसी' से पहले ioctl syscall 'main' में अंतिम निर्देश है।अगर मैं 'ioctl' टिप्पणी करता हूं तो प्रक्रिया segfault नहीं है। – MirkoBanchi

+0

आपने उस भाग को क्यों छुपाया जहां आपने 'स्ट्रक्चर पेज' के पते का उपयोग किया था? क्या आप वाकई से अपने सेगफाल्ट नहीं आते हैं? क्या आपने इसे क्यूमु पर डीबग करने का प्रयास किया है? –

उत्तर

11
pte_unmap(ptep); 

लेबल आउट होने से ठीक पहले गायब है। इस तरह से कोड बदलने के लिए प्रयास करें:

... 
    page = pte_page(pte); 
    if (page) 
     printk(KERN_INFO "page frame struct is @ %p", page); 

    pte_unmap(ptep); 

out: 
+0

धन्यवाद। मुझे यकीन था कि कर्नेल को CONFIG_HIGHPTE के बिना संकलित किया गया था, जिसे परिभाषित किया गया था, इसलिए 'pte_offset_map' ने 'kmap' किया था। – MirkoBanchi

+0

धन्यवाद! मुझे " जैसे संदेश असंतुलन के साथ लौटाए गए संदेशों के साथ दुर्घटनाग्रस्त हो रही है"। अंत में pte_offset_map() में preempt_count() वृद्धि का पता लगाया! Pte_unmap को जोड़ने से यह सब ठीक हो गया। – kaiwan

5

/proc/<pid>/smaps फाइल सिस्टम पर देखो, तुम यूज़रस्पेस स्मृति देख सकते हैं:

cat smaps 
bfa60000-bfa81000 rw-p 00000000 00:00 0   [stack] 
Size:    136 kB 
Rss:     44 kB 

और कैसे यह छपा है fs/proc/task_mmu.c के माध्यम से है (कर्नेल स्रोत से):

http://lxr.linux.no/linux+v3.0.4/fs/proc/task_mmu.c

if (vma->vm_mm && !is_vm_hugetlb_page(vma)) 
       walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); 
       show_map_vma(m, vma.....); 
     seq_printf(m, 
        "Size:   %8lu kB\n" 
        "Rss:   %8lu kB\n" 
        "Pss:   %8lu kB\n" 

और आपका फ़ंक्शन कुछ हद तक walk_page_range() की तरह है। walk_page_range में देख() आप देख सकते हैं कि smaps_walk संरचना, जबकि यह चल रहा है बदलने के लिए नहीं होना चाहिए है:

http://lxr.linux.no/linux+v3.0.4/mm/pagewalk.c#L153 

For eg: 

       } 
201    if (walk->pgd_entry) 
202      err = walk->pgd_entry(pgd, addr, next, walk); 
203    if (!err && 
204     (walk->pud_entry || walk->pmd_entry || walk->pte_entry 

की पैदल दूरी पर बदलने के लिए थे, तो सब से ऊपर जाँच असंगत हो सकता है।

सभी ये सिर्फ मतलब है कि आप mmap_sem लॉक करने के लिए है कि जब पृष्ठ सारणी घूमना: अनलॉक द्वारा

if (!down_read_trylock(&mm->mmap_sem)) { 
      /* 
      * Activate page so shrink_inactive_list is unlikely to unmap 
      * its ptes while lock is dropped, so swapoff can make progress. 
      */ 
      activate_page(page); 
      unlock_page(page); 
      down_read(&mm->mmap_sem); 
      lock_page(page); 
    } 

और उसके बाद का पालन किया:

up_read(&mm->mmap_sem); 

और निश्चित रूप से, जब आप printk जारी () आपके कर्नेल मॉड्यूल के अंदर पेजेटेबल के, कर्नेल मॉड्यूल आपके इंसोड प्रक्रिया के प्रक्रिया संदर्भ में चल रहा है (बस "कॉम" प्रिंट करें और आप "insmod" देख सकते हैं) जिसका अर्थ है mmap_sem लॉक है, इसका मतलब यह भी है कि प्रक्रिया नहीं है चल रहा है, और इस प्रकार प्रक्रिया तक कोई कंसोल आउटपुट नहीं है पूरा (सभी प्रिंटक() आउटपुट केवल स्मृति में जाता है)।

तार्किक लगता है?

+0

धन्यवाद पीटर, मैंने पृष्ठ तालिकाओं को पढ़ने वाले पहले निर्देश से पहले 'mmap_sem' आयोजित करने का प्रयास किया लेकिन काम नहीं करता ... समान सेगमेंटेशन गलती त्रुटि। हालांकि जब मैं 'walk_page_table' कहता हूं' मैं प्रक्रिया के संदर्भ में नहीं हूं 'insmod': मैं इसे' my_ioctl' के अंदर बुलाता हूं, इसलिए मैं 'ioctl' syscall invoking प्रक्रिया के संदर्भ में हूं। क्या इससे कोई फर्क पड़ सकता है? – MirkoBanchi

+0

हां, यह एक फर्क पड़ता है। क्योंकि अलग-अलग प्रक्रिया में प्रति-प्रक्रिया अलग-अलग होती है - यदि आप गैर कर्नेल भाग चलते हैं। लेकिन जब कर्नेल पते की बात आती है तो सभी प्रक्रिया एक ही पेजेट करने योग्य होती है। –