OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [mm/] [page_io.c] - Diff between revs 1765 and 1782

Only display areas with differences | Details | Blame | View Log

Rev 1765 Rev 1782
/*
/*
 *  linux/mm/page_io.c
 *  linux/mm/page_io.c
 *
 *
 *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
 *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
 *
 *
 *  Swap reorganised 29.12.95,
 *  Swap reorganised 29.12.95,
 *  Asynchronous swapping added 30.12.95. Stephen Tweedie
 *  Asynchronous swapping added 30.12.95. Stephen Tweedie
 *  Removed race in async swapping. 14.4.1996. Bruno Haible
 *  Removed race in async swapping. 14.4.1996. Bruno Haible
 */
 */
 
 
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/head.h>
#include <linux/head.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/kernel_stat.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/stat.h>
#include <linux/swap.h>
#include <linux/swap.h>
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/locks.h>
#include <linux/locks.h>
#include <linux/swapctl.h>
#include <linux/swapctl.h>
 
 
#include <asm/dma.h>
#include <asm/dma.h>
#include <asm/system.h> /* for cli()/sti() */
#include <asm/system.h> /* for cli()/sti() */
#include <asm/segment.h> /* for memcpy_to/fromfs */
#include <asm/segment.h> /* for memcpy_to/fromfs */
#include <asm/bitops.h>
#include <asm/bitops.h>
#include <asm/pgtable.h>
#include <asm/pgtable.h>
 
 
static struct wait_queue * lock_queue = NULL;
static struct wait_queue * lock_queue = NULL;
 
 
/*
/*
 * Reads or writes a swap page.
 * Reads or writes a swap page.
 * wait=1: start I/O and wait for completion. wait=0: start asynchronous I/O.
 * wait=1: start I/O and wait for completion. wait=0: start asynchronous I/O.
 *
 *
 * Important prevention of race condition: The first thing we do is set a lock
 * Important prevention of race condition: The first thing we do is set a lock
 * on this swap page, which lasts until I/O completes. This way a
 * on this swap page, which lasts until I/O completes. This way a
 * write_swap_page(entry) immediately followed by a read_swap_page(entry)
 * write_swap_page(entry) immediately followed by a read_swap_page(entry)
 * on the same entry will first complete the write_swap_page(). Fortunately,
 * on the same entry will first complete the write_swap_page(). Fortunately,
 * not more than one write_swap_page() request can be pending per entry. So
 * not more than one write_swap_page() request can be pending per entry. So
 * all races the caller must catch are: multiple read_swap_page() requests
 * all races the caller must catch are: multiple read_swap_page() requests
 * on the same entry.
 * on the same entry.
 */
 */
void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
{
{
        unsigned long type, offset;
        unsigned long type, offset;
        struct swap_info_struct * p;
        struct swap_info_struct * p;
        struct page *page;
        struct page *page;
 
 
        type = SWP_TYPE(entry);
        type = SWP_TYPE(entry);
        if (type >= nr_swapfiles) {
        if (type >= nr_swapfiles) {
                printk("Internal error: bad swap-device\n");
                printk("Internal error: bad swap-device\n");
                return;
                return;
        }
        }
        p = &swap_info[type];
        p = &swap_info[type];
        offset = SWP_OFFSET(entry);
        offset = SWP_OFFSET(entry);
        if (offset >= p->max) {
        if (offset >= p->max) {
                printk("rw_swap_page: weirdness\n");
                printk("rw_swap_page: weirdness\n");
                return;
                return;
        }
        }
        if (p->swap_map && !p->swap_map[offset]) {
        if (p->swap_map && !p->swap_map[offset]) {
                printk("Hmm.. Trying to use unallocated swap (%08lx)\n", entry);
                printk("Hmm.. Trying to use unallocated swap (%08lx)\n", entry);
                return;
                return;
        }
        }
        if (!(p->flags & SWP_USED)) {
        if (!(p->flags & SWP_USED)) {
                printk("Trying to swap to unused swap-device\n");
                printk("Trying to swap to unused swap-device\n");
                return;
                return;
        }
        }
        /* Make sure we are the only process doing I/O with this swap page. */
        /* Make sure we are the only process doing I/O with this swap page. */
        while (set_bit(offset,p->swap_lockmap)) {
        while (set_bit(offset,p->swap_lockmap)) {
                run_task_queue(&tq_disk);
                run_task_queue(&tq_disk);
                sleep_on(&lock_queue);
                sleep_on(&lock_queue);
        }
        }
        if (rw == READ)
        if (rw == READ)
                kstat.pswpin++;
                kstat.pswpin++;
        else
        else
                kstat.pswpout++;
                kstat.pswpout++;
        page = mem_map + MAP_NR(buf);
        page = mem_map + MAP_NR(buf);
        atomic_inc(&page->count);
        atomic_inc(&page->count);
        wait_on_page(page);
        wait_on_page(page);
        if (p->swap_device) {
        if (p->swap_device) {
                if (!wait) {
                if (!wait) {
                        set_bit(PG_free_after, &page->flags);
                        set_bit(PG_free_after, &page->flags);
                        set_bit(PG_decr_after, &page->flags);
                        set_bit(PG_decr_after, &page->flags);
                        set_bit(PG_swap_unlock_after, &page->flags);
                        set_bit(PG_swap_unlock_after, &page->flags);
                        page->swap_unlock_entry = entry;
                        page->swap_unlock_entry = entry;
                        atomic_inc(&nr_async_pages);
                        atomic_inc(&nr_async_pages);
                }
                }
                ll_rw_page(rw,p->swap_device,offset,buf);
                ll_rw_page(rw,p->swap_device,offset,buf);
                /*
                /*
                 * NOTE! We don't decrement the page count if we
                 * NOTE! We don't decrement the page count if we
                 * don't wait - that will happen asynchronously
                 * don't wait - that will happen asynchronously
                 * when the IO completes.
                 * when the IO completes.
                 */
                 */
                if (!wait)
                if (!wait)
                        return;
                        return;
                wait_on_page(page);
                wait_on_page(page);
        } else if (p->swap_file) {
        } else if (p->swap_file) {
                struct inode *swapf = p->swap_file;
                struct inode *swapf = p->swap_file;
                unsigned int zones[PAGE_SIZE/512];
                unsigned int zones[PAGE_SIZE/512];
                int i;
                int i;
                if (swapf->i_op->bmap == NULL
                if (swapf->i_op->bmap == NULL
                        && swapf->i_op->smap != NULL){
                        && swapf->i_op->smap != NULL){
                        /*
                        /*
                                With MsDOS, we use msdos_smap which return
                                With MsDOS, we use msdos_smap which return
                                a sector number (not a cluster or block number).
                                a sector number (not a cluster or block number).
                                It is a patch to enable the UMSDOS project.
                                It is a patch to enable the UMSDOS project.
                                Other people are working on better solution.
                                Other people are working on better solution.
 
 
                                It sounds like ll_rw_swap_file defined
                                It sounds like ll_rw_swap_file defined
                                it operation size (sector size) based on
                                it operation size (sector size) based on
                                PAGE_SIZE and the number of block to read.
                                PAGE_SIZE and the number of block to read.
                                So using bmap or smap should work even if
                                So using bmap or smap should work even if
                                smap will require more blocks.
                                smap will require more blocks.
                        */
                        */
                        int j;
                        int j;
                        unsigned int block = offset << 3;
                        unsigned int block = offset << 3;
 
 
                        for (i=0, j=0; j< PAGE_SIZE ; i++, j += 512){
                        for (i=0, j=0; j< PAGE_SIZE ; i++, j += 512){
                                if (!(zones[i] = swapf->i_op->smap(swapf,block++))) {
                                if (!(zones[i] = swapf->i_op->smap(swapf,block++))) {
                                        printk("rw_swap_page: bad swap file\n");
                                        printk("rw_swap_page: bad swap file\n");
                                        return;
                                        return;
                                }
                                }
                        }
                        }
                }else{
                }else{
                        int j;
                        int j;
                        unsigned int block = offset
                        unsigned int block = offset
                                << (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
                                << (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
 
 
                        for (i=0, j=0; j< PAGE_SIZE ; i++, j +=swapf->i_sb->s_blocksize)
                        for (i=0, j=0; j< PAGE_SIZE ; i++, j +=swapf->i_sb->s_blocksize)
                                if (!(zones[i] = bmap(swapf,block++))) {
                                if (!(zones[i] = bmap(swapf,block++))) {
                                        printk("rw_swap_page: bad swap file\n");
                                        printk("rw_swap_page: bad swap file\n");
                                }
                                }
                }
                }
                ll_rw_swap_file(rw,swapf->i_dev, zones, i,buf);
                ll_rw_swap_file(rw,swapf->i_dev, zones, i,buf);
        } else
        } else
                printk("rw_swap_page: no swap file or device\n");
                printk("rw_swap_page: no swap file or device\n");
        atomic_dec(&page->count);
        atomic_dec(&page->count);
        if (offset && !clear_bit(offset,p->swap_lockmap))
        if (offset && !clear_bit(offset,p->swap_lockmap))
                printk("rw_swap_page: lock already cleared\n");
                printk("rw_swap_page: lock already cleared\n");
        wake_up(&lock_queue);
        wake_up(&lock_queue);
}
}
 
 
/* This is run when asynchronous page I/O has completed. */
/* This is run when asynchronous page I/O has completed. */
void swap_after_unlock_page (unsigned long entry)
void swap_after_unlock_page (unsigned long entry)
{
{
        unsigned long type, offset;
        unsigned long type, offset;
        struct swap_info_struct * p;
        struct swap_info_struct * p;
 
 
        type = SWP_TYPE(entry);
        type = SWP_TYPE(entry);
        if (type >= nr_swapfiles) {
        if (type >= nr_swapfiles) {
                printk("swap_after_unlock_page: bad swap-device\n");
                printk("swap_after_unlock_page: bad swap-device\n");
                return;
                return;
        }
        }
        p = &swap_info[type];
        p = &swap_info[type];
        offset = SWP_OFFSET(entry);
        offset = SWP_OFFSET(entry);
        if (offset >= p->max) {
        if (offset >= p->max) {
                printk("swap_after_unlock_page: weirdness\n");
                printk("swap_after_unlock_page: weirdness\n");
                return;
                return;
        }
        }
        if (!clear_bit(offset,p->swap_lockmap))
        if (!clear_bit(offset,p->swap_lockmap))
                printk("swap_after_unlock_page: lock already cleared\n");
                printk("swap_after_unlock_page: lock already cleared\n");
        wake_up(&lock_queue);
        wake_up(&lock_queue);
}
}
 
 
/*
/*
 * Swap partitions are now read via brw_page.  ll_rw_page is an
 * Swap partitions are now read via brw_page.  ll_rw_page is an
 * asynchronous function now --- we must call wait_on_page afterwards
 * asynchronous function now --- we must call wait_on_page afterwards
 * if synchronous IO is required.
 * if synchronous IO is required.
 */
 */
void ll_rw_page(int rw, kdev_t dev, unsigned long offset, char * buffer)
void ll_rw_page(int rw, kdev_t dev, unsigned long offset, char * buffer)
{
{
        int block = offset;
        int block = offset;
        struct page *page;
        struct page *page;
 
 
        switch (rw) {
        switch (rw) {
                case READ:
                case READ:
                        break;
                        break;
                case WRITE:
                case WRITE:
                        if (is_read_only(dev)) {
                        if (is_read_only(dev)) {
                                printk("Can't page to read-only device %s\n",
                                printk("Can't page to read-only device %s\n",
                                        kdevname(dev));
                                        kdevname(dev));
                                return;
                                return;
                        }
                        }
                        break;
                        break;
                default:
                default:
                        panic("ll_rw_page: bad block dev cmd, must be R/W");
                        panic("ll_rw_page: bad block dev cmd, must be R/W");
        }
        }
        page = mem_map + MAP_NR(buffer);
        page = mem_map + MAP_NR(buffer);
        if (set_bit(PG_locked, &page->flags))
        if (set_bit(PG_locked, &page->flags))
                panic ("ll_rw_page: page already locked");
                panic ("ll_rw_page: page already locked");
        brw_page(rw, page, dev, &block, PAGE_SIZE, 0);
        brw_page(rw, page, dev, &block, PAGE_SIZE, 0);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.