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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [mm/] [page_io.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  linux/mm/page_io.c
3
 *
4
 *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
5
 *
6
 *  Swap reorganised 29.12.95,
7
 *  Asynchronous swapping added 30.12.95. Stephen Tweedie
8
 *  Removed race in async swapping. 14.4.1996. Bruno Haible
9
 */
10
 
11
#include <linux/mm.h>
12
#include <linux/sched.h>
13
#include <linux/head.h>
14
#include <linux/kernel.h>
15
#include <linux/kernel_stat.h>
16
#include <linux/errno.h>
17
#include <linux/string.h>
18
#include <linux/stat.h>
19
#include <linux/swap.h>
20
#include <linux/fs.h>
21
#include <linux/locks.h>
22
#include <linux/swapctl.h>
23
 
24
#include <asm/dma.h>
25
#include <asm/system.h> /* for cli()/sti() */
26
#include <asm/segment.h> /* for memcpy_to/fromfs */
27
#include <asm/bitops.h>
28
#include <asm/pgtable.h>
29
 
30
static struct wait_queue * lock_queue = NULL;
31
 
32
/*
33
 * Reads or writes a swap page.
34
 * wait=1: start I/O and wait for completion. wait=0: start asynchronous I/O.
35
 *
36
 * Important prevention of race condition: The first thing we do is set a lock
37
 * on this swap page, which lasts until I/O completes. This way a
38
 * write_swap_page(entry) immediately followed by a read_swap_page(entry)
39
 * on the same entry will first complete the write_swap_page(). Fortunately,
40
 * not more than one write_swap_page() request can be pending per entry. So
41
 * all races the caller must catch are: multiple read_swap_page() requests
42
 * on the same entry.
43
 */
44
void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
45
{
46
        unsigned long type, offset;
47
        struct swap_info_struct * p;
48
        struct page *page;
49
 
50
        type = SWP_TYPE(entry);
51
        if (type >= nr_swapfiles) {
52
                printk("Internal error: bad swap-device\n");
53
                return;
54
        }
55
        p = &swap_info[type];
56
        offset = SWP_OFFSET(entry);
57
        if (offset >= p->max) {
58
                printk("rw_swap_page: weirdness\n");
59
                return;
60
        }
61
        if (p->swap_map && !p->swap_map[offset]) {
62
                printk("Hmm.. Trying to use unallocated swap (%08lx)\n", entry);
63
                return;
64
        }
65
        if (!(p->flags & SWP_USED)) {
66
                printk("Trying to swap to unused swap-device\n");
67
                return;
68
        }
69
        /* Make sure we are the only process doing I/O with this swap page. */
70
        while (set_bit(offset,p->swap_lockmap)) {
71
                run_task_queue(&tq_disk);
72
                sleep_on(&lock_queue);
73
        }
74
        if (rw == READ)
75
                kstat.pswpin++;
76
        else
77
                kstat.pswpout++;
78
        page = mem_map + MAP_NR(buf);
79
        atomic_inc(&page->count);
80
        wait_on_page(page);
81
        if (p->swap_device) {
82
                if (!wait) {
83
                        set_bit(PG_free_after, &page->flags);
84
                        set_bit(PG_decr_after, &page->flags);
85
                        set_bit(PG_swap_unlock_after, &page->flags);
86
                        page->swap_unlock_entry = entry;
87
                        atomic_inc(&nr_async_pages);
88
                }
89
                ll_rw_page(rw,p->swap_device,offset,buf);
90
                /*
91
                 * NOTE! We don't decrement the page count if we
92
                 * don't wait - that will happen asynchronously
93
                 * when the IO completes.
94
                 */
95
                if (!wait)
96
                        return;
97
                wait_on_page(page);
98
        } else if (p->swap_file) {
99
                struct inode *swapf = p->swap_file;
100
                unsigned int zones[PAGE_SIZE/512];
101
                int i;
102
                if (swapf->i_op->bmap == NULL
103
                        && swapf->i_op->smap != NULL){
104
                        /*
105
                                With MsDOS, we use msdos_smap which return
106
                                a sector number (not a cluster or block number).
107
                                It is a patch to enable the UMSDOS project.
108
                                Other people are working on better solution.
109
 
110
                                It sounds like ll_rw_swap_file defined
111
                                it operation size (sector size) based on
112
                                PAGE_SIZE and the number of block to read.
113
                                So using bmap or smap should work even if
114
                                smap will require more blocks.
115
                        */
116
                        int j;
117
                        unsigned int block = offset << 3;
118
 
119
                        for (i=0, j=0; j< PAGE_SIZE ; i++, j += 512){
120
                                if (!(zones[i] = swapf->i_op->smap(swapf,block++))) {
121
                                        printk("rw_swap_page: bad swap file\n");
122
                                        return;
123
                                }
124
                        }
125
                }else{
126
                        int j;
127
                        unsigned int block = offset
128
                                << (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
129
 
130
                        for (i=0, j=0; j< PAGE_SIZE ; i++, j +=swapf->i_sb->s_blocksize)
131
                                if (!(zones[i] = bmap(swapf,block++))) {
132
                                        printk("rw_swap_page: bad swap file\n");
133
                                }
134
                }
135
                ll_rw_swap_file(rw,swapf->i_dev, zones, i,buf);
136
        } else
137
                printk("rw_swap_page: no swap file or device\n");
138
        atomic_dec(&page->count);
139
        if (offset && !clear_bit(offset,p->swap_lockmap))
140
                printk("rw_swap_page: lock already cleared\n");
141
        wake_up(&lock_queue);
142
}
143
 
144
/* This is run when asynchronous page I/O has completed. */
145
void swap_after_unlock_page (unsigned long entry)
146
{
147
        unsigned long type, offset;
148
        struct swap_info_struct * p;
149
 
150
        type = SWP_TYPE(entry);
151
        if (type >= nr_swapfiles) {
152
                printk("swap_after_unlock_page: bad swap-device\n");
153
                return;
154
        }
155
        p = &swap_info[type];
156
        offset = SWP_OFFSET(entry);
157
        if (offset >= p->max) {
158
                printk("swap_after_unlock_page: weirdness\n");
159
                return;
160
        }
161
        if (!clear_bit(offset,p->swap_lockmap))
162
                printk("swap_after_unlock_page: lock already cleared\n");
163
        wake_up(&lock_queue);
164
}
165
 
166
/*
167
 * Swap partitions are now read via brw_page.  ll_rw_page is an
168
 * asynchronous function now --- we must call wait_on_page afterwards
169
 * if synchronous IO is required.
170
 */
171
void ll_rw_page(int rw, kdev_t dev, unsigned long offset, char * buffer)
172
{
173
        int block = offset;
174
        struct page *page;
175
 
176
        switch (rw) {
177
                case READ:
178
                        break;
179
                case WRITE:
180
                        if (is_read_only(dev)) {
181
                                printk("Can't page to read-only device %s\n",
182
                                        kdevname(dev));
183
                                return;
184
                        }
185
                        break;
186
                default:
187
                        panic("ll_rw_page: bad block dev cmd, must be R/W");
188
        }
189
        page = mem_map + MAP_NR(buffer);
190
        if (set_bit(PG_locked, &page->flags))
191
                panic ("ll_rw_page: page already locked");
192
        brw_page(rw, page, dev, &block, PAGE_SIZE, 0);
193
}

powered by: WebSVN 2.1.0

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