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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [mm/] [swapfile.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1634 jcastillo
/*
2
 *  linux/mm/swapfile.c
3
 *
4
 *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
5
 *  Swap reorganised 29.12.95, Stephen Tweedie
6
 */
7
 
8
#include <linux/config.h>
9
#include <linux/mm.h>
10
#include <linux/sched.h>
11
#include <linux/head.h>
12
#include <linux/kernel.h>
13
#include <linux/kernel_stat.h>
14
#include <linux/errno.h>
15
#include <linux/string.h>
16
#include <linux/stat.h>
17
#include <linux/swap.h>
18
#include <linux/fs.h>
19
#include <linux/swapctl.h>
20
#include <linux/blkdev.h> /* for blk_size */
21
#include <linux/shm.h>
22
 
23
#include <asm/dma.h>
24
#include <asm/system.h> /* for cli()/sti() */
25
#include <asm/segment.h> /* for memcpy_to/fromfs */
26
#include <asm/bitops.h>
27
#include <asm/pgtable.h>
28
 
29
int nr_swapfiles = 0;
30
static struct {
31
        int head;       /* head of priority-ordered swapfile list */
32
        int next;       /* swapfile to be used next */
33
} swap_list = {-1, -1};
34
 
35
struct swap_info_struct swap_info[MAX_SWAPFILES];
36
 
37
 
38
static inline int scan_swap_map(struct swap_info_struct *si)
39
{
40
        int offset;
41
        /*
42
         * We try to cluster swap pages by allocating them
43
         * sequentially in swap.  Once we've allocated
44
         * SWAP_CLUSTER_MAX pages this way, however, we resort to
45
         * first-free allocation, starting a new cluster.  This
46
         * prevents us from scattering swap pages all over the entire
47
         * swap partition, so that we reduce overall disk seek times
48
         * between swap pages.  -- sct */
49
        if (si->cluster_nr) {
50
                while (si->cluster_next <= si->highest_bit) {
51
                        offset = si->cluster_next++;
52
                        if (si->swap_map[offset])
53
                                continue;
54
                        if (test_bit(offset, si->swap_lockmap))
55
                                continue;
56
                        si->cluster_nr--;
57
                        goto got_page;
58
                }
59
        }
60
        si->cluster_nr = SWAP_CLUSTER_MAX;
61
        for (offset = si->lowest_bit; offset <= si->highest_bit ; offset++) {
62
                if (si->swap_map[offset])
63
                        continue;
64
                if (test_bit(offset, si->swap_lockmap))
65
                        continue;
66
                si->lowest_bit = offset;
67
got_page:
68
                si->swap_map[offset] = 1;
69
                nr_swap_pages--;
70
                if (offset == si->highest_bit)
71
                        si->highest_bit--;
72
                si->cluster_next = offset;
73
                return offset;
74
        }
75
        return 0;
76
}
77
 
78
unsigned long get_swap_page(void)
79
{
80
        struct swap_info_struct * p;
81
        unsigned long offset, entry;
82
        int type, wrapped = 0;
83
 
84
        type = swap_list.next;
85
        if (type < 0)
86
                return 0;
87
        if (nr_swap_pages == 0)
88
                return 0;
89
 
90
        while (1) {
91
                p = &swap_info[type];
92
                if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
93
                        offset = scan_swap_map(p);
94
                        if (offset) {
95
                                entry = SWP_ENTRY(type,offset);
96
                                type = swap_info[type].next;
97
                                if (type < 0 ||
98
                                        p->prio != swap_info[type].prio)
99
                                {
100
                                                swap_list.next = swap_list.head;
101
                                }
102
                                else
103
                                {
104
                                        swap_list.next = type;
105
                                }
106
                                return entry;
107
                        }
108
                }
109
                type = p->next;
110
                if (!wrapped) {
111
                        if (type < 0 || p->prio != swap_info[type].prio) {
112
                                type = swap_list.head;
113
                                wrapped = 1;
114
                        }
115
                } else if (type < 0) {
116
                        return 0;        /* out of swap space */
117
                }
118
        }
119
}
120
 
121
void swap_free(unsigned long entry)
122
{
123
        struct swap_info_struct * p;
124
        unsigned long offset, type;
125
 
126
        if (!entry)
127
                return;
128
        type = SWP_TYPE(entry);
129
        if (type & SHM_SWP_TYPE)
130
                return;
131
        if (type >= nr_swapfiles) {
132
                printk("Trying to free nonexistent swap-page\n");
133
                return;
134
        }
135
        p = & swap_info[type];
136
        offset = SWP_OFFSET(entry);
137
        if (offset >= p->max) {
138
                printk("swap_free: weirdness\n");
139
                return;
140
        }
141
        if (!(p->flags & SWP_USED)) {
142
                printk("Trying to free swap from unused swap-device\n");
143
                return;
144
        }
145
        if (offset < p->lowest_bit)
146
                p->lowest_bit = offset;
147
        if (offset > p->highest_bit)
148
                p->highest_bit = offset;
149
        if (!p->swap_map[offset])
150
                printk("swap_free: swap-space map null (entry %08lx)\n",entry);
151
        else if (p->swap_map[offset] == SWAP_MAP_RESERVED)
152
                printk("swap_free: swap-space reserved (entry %08lx)\n",entry);
153
        else if (!--p->swap_map[offset])
154
                        nr_swap_pages++;
155
        if (p->prio > swap_info[swap_list.next].prio) {
156
            swap_list.next = swap_list.head;
157
        }
158
}
159
 
160
/*
161
 * Trying to stop swapping from a file is fraught with races, so
162
 * we repeat quite a bit here when we have to pause. swapoff()
163
 * isn't exactly timing-critical, so who cares (but this is /really/
164
 * inefficient, ugh).
165
 *
166
 * We return 1 after having slept, which makes the process start over
167
 * from the beginning for this process..
168
 */
169
static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address,
170
        pte_t *dir, unsigned int type, unsigned long page)
171
{
172
        pte_t pte = *dir;
173
 
174
        if (pte_none(pte))
175
                return 0;
176
        if (pte_present(pte)) {
177
                unsigned long page_nr = MAP_NR(pte_page(pte));
178
                if (page_nr >= MAP_NR(high_memory))
179
                        return 0;
180
                if (!in_swap_cache(page_nr))
181
                        return 0;
182
                if (SWP_TYPE(in_swap_cache(page_nr)) != type)
183
                        return 0;
184
                delete_from_swap_cache(page_nr);
185
                set_pte(dir, pte_mkdirty(pte));
186
                return 0;
187
        }
188
        if (SWP_TYPE(pte_val(pte)) != type)
189
                return 0;
190
        read_swap_page(pte_val(pte), (char *) page);
191
        if (pte_val(*dir) != pte_val(pte)) {
192
                free_page(page);
193
                return 1;
194
        }
195
        set_pte(dir, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))));
196
        flush_tlb_page(vma, address);
197
        ++vma->vm_mm->rss;
198
        swap_free(pte_val(pte));
199
        return 1;
200
}
201
 
202
static inline int unuse_pmd(struct vm_area_struct * vma, pmd_t *dir,
203
        unsigned long address, unsigned long size, unsigned long offset,
204
        unsigned int type, unsigned long page)
205
{
206
        pte_t * pte;
207
        unsigned long end;
208
 
209
        if (pmd_none(*dir))
210
                return 0;
211
        if (pmd_bad(*dir)) {
212
                printk("unuse_pmd: bad pmd (%08lx)\n", pmd_val(*dir));
213
                pmd_clear(dir);
214
                return 0;
215
        }
216
        pte = pte_offset(dir, address);
217
        offset += address & PMD_MASK;
218
        address &= ~PMD_MASK;
219
        end = address + size;
220
        if (end > PMD_SIZE)
221
                end = PMD_SIZE;
222
        do {
223
                if (unuse_pte(vma, offset+address-vma->vm_start, pte, type, page))
224
                        return 1;
225
                address += PAGE_SIZE;
226
                pte++;
227
        } while (address < end);
228
        return 0;
229
}
230
 
231
static inline int unuse_pgd(struct vm_area_struct * vma, pgd_t *dir,
232
        unsigned long address, unsigned long size,
233
        unsigned int type, unsigned long page)
234
{
235
        pmd_t * pmd;
236
        unsigned long offset, end;
237
 
238
        if (pgd_none(*dir))
239
                return 0;
240
        if (pgd_bad(*dir)) {
241
                printk("unuse_pgd: bad pgd (%08lx)\n", pgd_val(*dir));
242
                pgd_clear(dir);
243
                return 0;
244
        }
245
        pmd = pmd_offset(dir, address);
246
        offset = address & PGDIR_MASK;
247
        address &= ~PGDIR_MASK;
248
        end = address + size;
249
        if (end > PGDIR_SIZE)
250
                end = PGDIR_SIZE;
251
        do {
252
                if (unuse_pmd(vma, pmd, address, end - address, offset, type, page))
253
                        return 1;
254
                address = (address + PMD_SIZE) & PMD_MASK;
255
                pmd++;
256
        } while (address < end);
257
        return 0;
258
}
259
 
260
static int unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir,
261
        unsigned long start, unsigned long end,
262
        unsigned int type, unsigned long page)
263
{
264
        while (start < end) {
265
                if (unuse_pgd(vma, pgdir, start, end - start, type, page))
266
                        return 1;
267
                start = (start + PGDIR_SIZE) & PGDIR_MASK;
268
                pgdir++;
269
        }
270
        return 0;
271
}
272
 
273
static int unuse_process(struct mm_struct * mm, unsigned int type, unsigned long page)
274
{
275
        struct vm_area_struct* vma;
276
 
277
        /*
278
         * Go through process' page directory.
279
         */
280
        if (!mm || mm == &init_mm)
281
                return 0;
282
        vma = mm->mmap;
283
        while (vma) {
284
                pgd_t * pgd = pgd_offset(mm, vma->vm_start);
285
                if (unuse_vma(vma, pgd, vma->vm_start, vma->vm_end, type, page))
286
                        return 1;
287
                vma = vma->vm_next;
288
        }
289
        return 0;
290
}
291
 
292
/*
293
 * To avoid races, we repeat for each process after having
294
 * swapped something in. That gets rid of a few pesky races,
295
 * and "swapoff" isn't exactly timing critical.
296
 */
297
static int try_to_unuse(unsigned int type)
298
{
299
        int nr;
300
        unsigned long page = get_free_page(GFP_KERNEL);
301
 
302
        if (!page)
303
                return -ENOMEM;
304
        nr = 0;
305
        while (nr < NR_TASKS) {
306
                struct task_struct * p = task[nr];
307
                if (p) {
308
                        if (unuse_process(p->mm, type, page)) {
309
                                page = get_free_page(GFP_KERNEL);
310
                                if (!page)
311
                                        return -ENOMEM;
312
                                continue;
313
                        }
314
                }
315
                nr++;
316
        }
317
        free_page(page);
318
#ifdef CONFIG_SYSVIPC   
319
        shm_unuse(type);
320
#endif
321
        return 0;
322
}
323
 
324
asmlinkage int sys_swapoff(const char * specialfile)
325
{
326
        struct swap_info_struct * p;
327
        struct inode * inode;
328
        struct file filp;
329
        int i, type, prev;
330
        int err;
331
 
332
        if (!suser())
333
                return -EPERM;
334
        err = namei(specialfile,&inode);
335
        if (err)
336
                return err;
337
        prev = -1;
338
        for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
339
                p = swap_info + type;
340
                if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
341
                        if (p->swap_file) {
342
                                if (p->swap_file == inode)
343
                                  break;
344
                        } else {
345
                                if (S_ISBLK(inode->i_mode)
346
                                    && (p->swap_device == inode->i_rdev))
347
                                  break;
348
                        }
349
                }
350
                prev = type;
351
        }
352
        if (type < 0){
353
                iput(inode);
354
                return -EINVAL;
355
        }
356
        if (prev < 0) {
357
                swap_list.head = p->next;
358
        } else {
359
                swap_info[prev].next = p->next;
360
        }
361
        if (type == swap_list.next) {
362
                /* just pick something that's safe... */
363
                swap_list.next = swap_list.head;
364
        }
365
        p->flags = SWP_USED;
366
        err = try_to_unuse(type);
367
        if (err) {
368
                iput(inode);
369
                /* re-insert swap space back into swap_list */
370
                for (prev = -1, i = swap_list.head; i >= 0; prev = i, i = swap_info[i].next)
371
                        if (p->prio >= swap_info[i].prio)
372
                                break;
373
                p->next = i;
374
                if (prev < 0)
375
                        swap_list.head = swap_list.next = p - swap_info;
376
                else
377
                        swap_info[prev].next = p - swap_info;
378
                p->flags = SWP_WRITEOK;
379
                return err;
380
        }
381
        if(p->swap_device){
382
                memset(&filp, 0, sizeof(filp));
383
                filp.f_inode = inode;
384
                filp.f_mode = 3; /* read write */
385
                /* open it again to get fops */
386
                if( !blkdev_open(inode, &filp) &&
387
                   filp.f_op && filp.f_op->release){
388
                        filp.f_op->release(inode,&filp);
389
                        filp.f_op->release(inode,&filp);
390
                }
391
        }
392
        iput(inode);
393
 
394
        nr_swap_pages -= p->pages;
395
        iput(p->swap_file);
396
        p->swap_file = NULL;
397
        p->swap_device = 0;
398
        vfree(p->swap_map);
399
        p->swap_map = NULL;
400
        free_page((long) p->swap_lockmap);
401
        p->swap_lockmap = NULL;
402
        p->flags = 0;
403
        return 0;
404
}
405
 
406
/*
407
 * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
408
 *
409
 * The swapon system call
410
 */
411
asmlinkage int sys_swapon(const char * specialfile, int swap_flags)
412
{
413
        struct swap_info_struct * p;
414
        struct inode * swap_inode;
415
        unsigned int type;
416
        int i, j, prev;
417
        int error;
418
        struct file filp;
419
        static int least_priority = 0;
420
 
421
        memset(&filp, 0, sizeof(filp));
422
        if (!suser())
423
                return -EPERM;
424
        p = swap_info;
425
        for (type = 0 ; type < nr_swapfiles ; type++,p++)
426
                if (!(p->flags & SWP_USED))
427
                        break;
428
        if (type >= MAX_SWAPFILES)
429
                return -EPERM;
430
        if (type >= nr_swapfiles)
431
                nr_swapfiles = type+1;
432
        p->flags = SWP_USED;
433
        p->swap_file = NULL;
434
        p->swap_device = 0;
435
        p->swap_map = NULL;
436
        p->swap_lockmap = NULL;
437
        p->lowest_bit = 0;
438
        p->highest_bit = 0;
439
        p->cluster_nr = 0;
440
        p->max = 1;
441
        p->next = -1;
442
        if (swap_flags & SWAP_FLAG_PREFER) {
443
                p->prio =
444
                  (swap_flags & SWAP_FLAG_PRIO_MASK)>>SWAP_FLAG_PRIO_SHIFT;
445
        } else {
446
                p->prio = --least_priority;
447
        }
448
        error = namei(specialfile,&swap_inode);
449
        if (error)
450
                goto bad_swap_2;
451
        p->swap_file = swap_inode;
452
        error = -EBUSY;
453
        if (swap_inode->i_count != 1)
454
                goto bad_swap_2;
455
        error = -EINVAL;
456
 
457
        if (S_ISBLK(swap_inode->i_mode)) {
458
                p->swap_device = swap_inode->i_rdev;
459
                set_blocksize(p->swap_device, PAGE_SIZE);
460
 
461
                filp.f_inode = swap_inode;
462
                filp.f_mode = 3; /* read write */
463
                error = blkdev_open(swap_inode, &filp);
464
                p->swap_file = NULL;
465
                iput(swap_inode);
466
                if(error)
467
                        goto bad_swap_2;
468
                error = -ENODEV;
469
                if (!p->swap_device ||
470
                    (blk_size[MAJOR(p->swap_device)] &&
471
                     !blk_size[MAJOR(p->swap_device)][MINOR(p->swap_device)]))
472
                        goto bad_swap;
473
                error = -EBUSY;
474
                for (i = 0 ; i < nr_swapfiles ; i++) {
475
                        if (i == type)
476
                                continue;
477
                        if (p->swap_device == swap_info[i].swap_device)
478
                                goto bad_swap;
479
                }
480
        } else if (!S_ISREG(swap_inode->i_mode))
481
                goto bad_swap;
482
        p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER);
483
        if (!p->swap_lockmap) {
484
                printk("Unable to start swapping: out of memory :-)\n");
485
                error = -ENOMEM;
486
                goto bad_swap;
487
        }
488
        read_swap_page(SWP_ENTRY(type,0), (char *) p->swap_lockmap);
489
        if (memcmp("SWAP-SPACE",p->swap_lockmap+PAGE_SIZE-10,10)) {
490
                printk("Unable to find swap-space signature\n");
491
                error = -EINVAL;
492
                goto bad_swap;
493
        }
494
        memset(p->swap_lockmap+PAGE_SIZE-10,0,10);
495
        j = 0;
496
        p->lowest_bit = 0;
497
        p->highest_bit = 0;
498
        for (i = 1 ; i < 8*PAGE_SIZE ; i++) {
499
                if (test_bit(i,p->swap_lockmap)) {
500
                        if (!p->lowest_bit)
501
                                p->lowest_bit = i;
502
                        p->highest_bit = i;
503
                        p->max = i+1;
504
                        j++;
505
                }
506
        }
507
        if (!j) {
508
                printk("Empty swap-file\n");
509
                error = -EINVAL;
510
                goto bad_swap;
511
        }
512
        p->swap_map = (unsigned short *) vmalloc(p->max * sizeof(short));
513
        if (!p->swap_map) {
514
                error = -ENOMEM;
515
                goto bad_swap;
516
        }
517
        for (i = 1 ; i < p->max ; i++) {
518
                if (test_bit(i,p->swap_lockmap))
519
                        p->swap_map[i] = 0;
520
                else
521
                        p->swap_map[i] = SWAP_MAP_RESERVED;
522
        }
523
        p->swap_map[0] = SWAP_MAP_RESERVED;
524
        memset(p->swap_lockmap,0,PAGE_SIZE);
525
        p->flags = SWP_WRITEOK;
526
        p->pages = j;
527
        nr_swap_pages += j;
528
        printk("Adding Swap: %dk swap-space (priority %d)\n",
529
               j<<(PAGE_SHIFT-10), p->prio);
530
 
531
        /* insert swap space into swap_list: */
532
        prev = -1;
533
        for (i = swap_list.head; i >= 0; i = swap_info[i].next) {
534
                if (p->prio >= swap_info[i].prio) {
535
                        break;
536
                }
537
                prev = i;
538
        }
539
        p->next = i;
540
        if (prev < 0) {
541
                swap_list.head = swap_list.next = p - swap_info;
542
        } else {
543
                swap_info[prev].next = p - swap_info;
544
        }
545
        return 0;
546
bad_swap:
547
        if(filp.f_op && filp.f_op->release)
548
                filp.f_op->release(filp.f_inode,&filp);
549
bad_swap_2:
550
        free_page((long) p->swap_lockmap);
551
        vfree(p->swap_map);
552
        iput(p->swap_file);
553
        p->swap_device = 0;
554
        p->swap_file = NULL;
555
        p->swap_map = NULL;
556
        p->swap_lockmap = NULL;
557
        p->flags = 0;
558
        return error;
559
}
560
 
561
void si_swapinfo(struct sysinfo *val)
562
{
563
        unsigned int i, j;
564
 
565
        val->freeswap = val->totalswap = 0;
566
        for (i = 0; i < nr_swapfiles; i++) {
567
                if ((swap_info[i].flags & SWP_WRITEOK) != SWP_WRITEOK)
568
                        continue;
569
                for (j = 0; j < swap_info[i].max; ++j)
570
                        switch (swap_info[i].swap_map[j]) {
571
                                case SWAP_MAP_RESERVED:
572
                                        continue;
573
                                case 0:
574
                                        ++val->freeswap;
575
                                default:
576
                                        ++val->totalswap;
577
                        }
578
        }
579
        val->freeswap <<= PAGE_SHIFT;
580
        val->totalswap <<= PAGE_SHIFT;
581
        return;
582
}
583
 

powered by: WebSVN 2.1.0

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