!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/mm/   drwxr-xr-x
Free 318.34 GB of 458.09 GB (69.49%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     highmem.c (10.18 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 * High memory handling common code and variables.
 *
 * (C) 1999 Andrea Arcangeli, SuSE GmbH, andrea@suse.de
 *          Gerhard Wichert, Siemens AG, Gerhard.Wichert@pdb.siemens.de
 *
 *
 * Redesigned the x86 32-bit VM architecture to deal with
 * 64-bit physical space. With current x86 CPUs this
 * means up to 64 Gigabytes physical RAM.
 *
 * Rewrote high memory support to move the page cache into
 * high memory. Implemented permanent (schedulable) kmaps
 * based on Linus' idea.
 *
 * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
 */

#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>
#include <linux/swap.h>
#include <linux/slab.h>

/*
 * Virtual_count is not a pure "count".
 *  0 means that it is not mapped, and has not been mapped
 *    since a TLB flush - it is usable.
 *  1 means that there are no users, but it has been mapped
 *    since the last TLB flush - so we can't use it.
 *  n means that there are (n-1) current users of it.
 */
static int pkmap_count[LAST_PKMAP];
static unsigned int last_pkmap_nr;
static spinlock_t kmap_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;

pte_t * pkmap_page_table;

static DECLARE_WAIT_QUEUE_HEAD(pkmap_map_wait);

static void flush_all_zero_pkmaps(void)
{
    int i;

    flush_cache_all();

    for (i = 0; i < LAST_PKMAP; i++) {
        struct page *page;

        /*
         * zero means we don't have anything to do,
         * >1 means that it is still in use. Only
         * a count of 1 means that it is free but
         * needs to be unmapped
         */
        if (pkmap_count[i] != 1)
            continue;
        pkmap_count[i] = 0;

        /* sanity check */
        if (pte_none(pkmap_page_table[i]))
            BUG();

        /*
         * Don't need an atomic fetch-and-clear op here;
         * no-one has the page mapped, and cannot get at
         * its virtual address (and hence PTE) without first
         * getting the kmap_lock (which is held here).
         * So no dangers, even with speculative execution.
         */
        page = pte_page(pkmap_page_table[i]);
        pte_clear(&pkmap_page_table[i]);

        page->virtual = NULL;
    }
    flush_tlb_all();
}

static inline unsigned long map_new_virtual(struct page *page)
{
    unsigned long vaddr;
    int count;

start:
    count = LAST_PKMAP;
    /* Find an empty entry */
    for (;;) {
        last_pkmap_nr = (last_pkmap_nr + 1) & LAST_PKMAP_MASK;
        if (!last_pkmap_nr) {
            flush_all_zero_pkmaps();
            count = LAST_PKMAP;
        }
        if (!pkmap_count[last_pkmap_nr])
            break;    /* Found a usable entry */
        if (--count)
            continue;

        /*
         * Sleep for somebody else to unmap their entries
         */
        {
            DECLARE_WAITQUEUE(wait, current);

            current->state = TASK_UNINTERRUPTIBLE;
            add_wait_queue(&pkmap_map_wait, &wait);
            spin_unlock(&kmap_lock);
            schedule();
            remove_wait_queue(&pkmap_map_wait, &wait);
            spin_lock(&kmap_lock);

            /* Somebody else might have mapped it while we slept */
            if (page->virtual)
                return (unsigned long) page->virtual;

            /* Re-start */
            goto start;
        }
    }
    vaddr = PKMAP_ADDR(last_pkmap_nr);
    set_pte(&(pkmap_page_table[last_pkmap_nr]), mk_pte(page, kmap_prot));

    pkmap_count[last_pkmap_nr] = 1;
    page->virtual = (void *) vaddr;

    return vaddr;
}

void *kmap_high(struct page *page)
{
    unsigned long vaddr;

    /*
     * For highmem pages, we can't trust "virtual" until
     * after we have the lock.
     *
     * We cannot call this from interrupts, as it may block
     */
    spin_lock(&kmap_lock);
    vaddr = (unsigned long) page->virtual;
    if (!vaddr)
        vaddr = map_new_virtual(page);
    pkmap_count[PKMAP_NR(vaddr)]++;
    if (pkmap_count[PKMAP_NR(vaddr)] < 2)
        BUG();
    spin_unlock(&kmap_lock);
    return (void*) vaddr;
}

void kunmap_high(struct page *page)
{
    unsigned long vaddr;
    unsigned long nr;
    int need_wakeup;

    spin_lock(&kmap_lock);
    vaddr = (unsigned long) page->virtual;
    if (!vaddr)
        BUG();
    nr = PKMAP_NR(vaddr);

    /*
     * A count must never go down to zero
     * without a TLB flush!
     */
    need_wakeup = 0;
    switch (--pkmap_count[nr]) {
    case 0:
        BUG();
    case 1:
        /*
         * Avoid an unnecessary wake_up() function call.
         * The common case is pkmap_count[] == 1, but
         * no waiters.
         * The tasks queued in the wait-queue are guarded
         * by both the lock in the wait-queue-head and by
         * the kmap_lock.  As the kmap_lock is held here,
         * no need for the wait-queue-head's lock.  Simply
         * test if the queue is empty.
         */
        need_wakeup = waitqueue_active(&pkmap_map_wait);
    }
    spin_unlock(&kmap_lock);

    /* do wake-up, if needed, race-free outside of the spin lock */
    if (need_wakeup)
        wake_up(&pkmap_map_wait);
}

#define POOL_SIZE 32

/*
 * This lock gets no contention at all, normally.
 */
static spinlock_t emergency_lock = SPIN_LOCK_UNLOCKED;

int nr_emergency_pages;
static LIST_HEAD(emergency_pages);

int nr_emergency_bhs;
static LIST_HEAD(emergency_bhs);

/*
 * Simple bounce buffer support for highmem pages.
 * This will be moved to the block layer in 2.5.
 */

static inline void copy_from_high_bh (struct buffer_head *to,
             struct buffer_head *from)
{
    struct page *p_from;
    char *vfrom;

    p_from = from->b_page;

    vfrom = kmap_atomic(p_from, KM_USER0);
    memcpy(to->b_data, vfrom + bh_offset(from), to->b_size);
    kunmap_atomic(vfrom, KM_USER0);
}

static inline void copy_to_high_bh_irq (struct buffer_head *to,
             struct buffer_head *from)
{
    struct page *p_to;
    char *vto;
    unsigned long flags;

    p_to = to->b_page;
    __save_flags(flags);
    __cli();
    vto = kmap_atomic(p_to, KM_BOUNCE_READ);
    memcpy(vto + bh_offset(to), from->b_data, to->b_size);
    kunmap_atomic(vto, KM_BOUNCE_READ);
    __restore_flags(flags);
}

static inline void bounce_end_io (struct buffer_head *bh, int uptodate)
{
    struct page *page;
    struct buffer_head *bh_orig = (struct buffer_head *)(bh->b_private);
    unsigned long flags;

    bh_orig->b_end_io(bh_orig, uptodate);

    page = bh->b_page;

    spin_lock_irqsave(&emergency_lock, flags);
    if (nr_emergency_pages >= POOL_SIZE)
        __free_page(page);
    else {
        /*
         * We are abusing page->list to manage
         * the highmem emergency pool:
         */
        list_add(&page->list, &emergency_pages);
        nr_emergency_pages++;
    }
    
    if (nr_emergency_bhs >= POOL_SIZE) {
#ifdef HIGHMEM_DEBUG
        /* Don't clobber the constructed slab cache */
        init_waitqueue_head(&bh->b_wait);
#endif
        kmem_cache_free(bh_cachep, bh);
    } else {
        /*
         * Ditto in the bh case, here we abuse b_inode_buffers:
         */
        list_add(&bh->b_inode_buffers, &emergency_bhs);
        nr_emergency_bhs++;
    }
    spin_unlock_irqrestore(&emergency_lock, flags);
}

static __init int init_emergency_pool(void)
{
    struct sysinfo i;
        si_meminfo(&i);
        si_swapinfo(&i);
        
        if (!i.totalhigh)
            return 0;

    spin_lock_irq(&emergency_lock);
    while (nr_emergency_pages < POOL_SIZE) {
        struct page * page = alloc_page(GFP_ATOMIC);
        if (!page) {
            printk("couldn't refill highmem emergency pages");
            break;
        }
        list_add(&page->list, &emergency_pages);
        nr_emergency_pages++;
    }
    while (nr_emergency_bhs < POOL_SIZE) {
        struct buffer_head * bh = kmem_cache_alloc(bh_cachep, SLAB_ATOMIC);
        if (!bh) {
            printk("couldn't refill highmem emergency bhs");
            break;
        }
        list_add(&bh->b_inode_buffers, &emergency_bhs);
        nr_emergency_bhs++;
    }
    spin_unlock_irq(&emergency_lock);
    printk("allocated %d pages and %d bhs reserved for the highmem bounces\n",
           nr_emergency_pages, nr_emergency_bhs);

    return 0;
}

__initcall(init_emergency_pool);

static void bounce_end_io_write (struct buffer_head *bh, int uptodate)
{
    bounce_end_io(bh, uptodate);
}

static void bounce_end_io_read (struct buffer_head *bh, int uptodate)
{
    struct buffer_head *bh_orig = (struct buffer_head *)(bh->b_private);

    if (uptodate)
        copy_to_high_bh_irq(bh_orig, bh);
    bounce_end_io(bh, uptodate);
}

struct page *alloc_bounce_page (void)
{
    struct list_head *tmp;
    struct page *page;

    page = alloc_page(GFP_NOHIGHIO);
    if (page)
        return page;
    /*
     * No luck. First, kick the VM so it doesnt idle around while
     * we are using up our emergency rations.
     */
    wakeup_bdflush();

repeat_alloc:
    /*
     * Try to allocate from the emergency pool.
     */
    tmp = &emergency_pages;
    spin_lock_irq(&emergency_lock);
    if (!list_empty(tmp)) {
        page = list_entry(tmp->next, struct page, list);
        list_del(tmp->next);
        nr_emergency_pages--;
    }
    spin_unlock_irq(&emergency_lock);
    if (page)
        return page;

    /* we need to wait I/O completion */
    run_task_queue(&tq_disk);

    current->policy |= SCHED_YIELD;
    __set_current_state(TASK_RUNNING);
    schedule();
    goto repeat_alloc;
}

struct buffer_head *alloc_bounce_bh (void)
{
    struct list_head *tmp;
    struct buffer_head *bh;

    bh = kmem_cache_alloc(bh_cachep, SLAB_NOHIGHIO);
    if (bh)
        return bh;
    /*
     * No luck. First, kick the VM so it doesnt idle around while
     * we are using up our emergency rations.
     */
    wakeup_bdflush();

repeat_alloc:
    /*
     * Try to allocate from the emergency pool.
     */
    tmp = &emergency_bhs;
    spin_lock_irq(&emergency_lock);
    if (!list_empty(tmp)) {
        bh = list_entry(tmp->next, struct buffer_head, b_inode_buffers);
        list_del(tmp->next);
        nr_emergency_bhs--;
    }
    spin_unlock_irq(&emergency_lock);
    if (bh)
        return bh;

    /* we need to wait I/O completion */
    run_task_queue(&tq_disk);

    current->policy |= SCHED_YIELD;
    __set_current_state(TASK_RUNNING);
    schedule();
    goto repeat_alloc;
}

struct buffer_head * create_bounce(int rw, struct buffer_head * bh_orig)
{
    struct page *page;
    struct buffer_head *bh;

    if (!PageHighMem(bh_orig->b_page))
        return bh_orig;

    bh = alloc_bounce_bh();
    /*
     * This is wasteful for 1k buffers, but this is a stopgap measure
     * and we are being ineffective anyway. This approach simplifies
     * things immensly. On boxes with more than 4GB RAM this should
     * not be an issue anyway.
     */
    page = alloc_bounce_page();

    set_bh_page(bh, page, 0);

    bh->b_next = NULL;
    bh->b_blocknr = bh_orig->b_blocknr;
    bh->b_size = bh_orig->b_size;
    bh->b_list = -1;
    bh->b_dev = bh_orig->b_dev;
    bh->b_count = bh_orig->b_count;
    bh->b_rdev = bh_orig->b_rdev;
    bh->b_state = bh_orig->b_state;
#ifdef HIGHMEM_DEBUG
    bh->b_flushtime = jiffies;
    bh->b_next_free = NULL;
    bh->b_prev_free = NULL;
    /* bh->b_this_page */
    bh->b_reqnext = NULL;
    bh->b_pprev = NULL;
#endif
    /* bh->b_page */
    if (rw == WRITE) {
        bh->b_end_io = bounce_end_io_write;
        copy_from_high_bh(bh, bh_orig);
    } else
        bh->b_end_io = bounce_end_io_read;
    bh->b_private = (void *)bh_orig;
    bh->b_rsector = bh_orig->b_rsector;
#ifdef HIGHMEM_DEBUG
    memset(&bh->b_wait, -1, sizeof(bh->b_wait));
#endif

    return bh;
}


:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0293 ]--