[patch] large swap areas

Sylvain Pion (Sylvain.Pion@sophia.inria.fr)
Mon, 23 Feb 1998 21:29:50 +0100


--0F1p//8PRICkK4MW
Content-Type: text/plain; charset=us-ascii

Hi,

I've made a patch to handle large swap spaces (larger than the ~128MB limit).
It features some compatibility with the older swap space format. I don't
know the new limit, but at least 1GB seems to work on x86. The corresponding
patch to mkswap.c (from util-linux-2.7.1) is appended too.

Also in this patch, kswapd_setup() and init_swap_timer() are made
__initfunc() (I'm not sure if it's ok).

This is my first kernel patch, so comments are welcome.

-- 
Sylvain

--0F1p//8PRICkK4MW Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=large_swap_patch-2188

diff -ur linux-2.1.88-voyager/mm/swapfile.c linux/mm/swapfile.c --- linux-2.1.88-voyager/mm/swapfile.c Thu Jan 22 21:46:00 1998 +++ linux/mm/swapfile.c Sun Feb 22 15:30:26 1998 @@ -445,7 +445,7 @@ p->swap_device = 0; vfree(p->swap_map); p->swap_map = NULL; - free_page((long) p->swap_lockmap); + vfree(p->swap_lockmap); p->swap_lockmap = NULL; p->flags = 0; err = 0; @@ -499,13 +499,14 @@ */ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) { - struct swap_info_struct * p; + struct swap_info_struct * p, * q; struct dentry * swap_dentry; unsigned int type; - int i, j, prev; + int i, j, prev, nr_sig_pages; int error = -EPERM; struct file filp; static int least_priority = 0; + char * tmp_page = NULL; lock_kernel(); if (!suser()) @@ -543,6 +544,14 @@ p->swap_file = swap_dentry; error = -EINVAL; + /* Check if already used (shouldn't it be locked ?) */ + for (i = swap_list.head; i >= 0; i = swap_info[i].next) { + q = swap_info + i; + if (((q->flags & SWP_USED) == SWP_USED) && + (q->swap_file) && (q->swap_file == swap_dentry)) + goto bad_swap_2; + } + if (S_ISBLK(swap_dentry->d_inode->i_mode)) { p->swap_device = swap_dentry->d_inode->i_rdev; set_blocksize(p->swap_device, PAGE_SIZE); @@ -566,23 +575,39 @@ } } else if (!S_ISREG(swap_dentry->d_inode->i_mode)) goto bad_swap; - p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER); - if (!p->swap_lockmap) { + tmp_page = (unsigned char *) get_free_page(GFP_USER); + if (!tmp_page) { printk("Unable to start swapping: out of memory :-)\n"); error = -ENOMEM; goto bad_swap; } - read_swap_page(SWP_ENTRY(type,0), (char *) p->swap_lockmap); - if (memcmp("SWAP-SPACE",p->swap_lockmap+PAGE_SIZE-10,10)) { + p->swap_lockmap = tmp_page; + read_swap_page(SWP_ENTRY(type,0), (char *) tmp_page); + p->swap_lockmap = NULL; + if (memcmp("SWAP-SPACE",tmp_page+PAGE_SIZE-10,10)) { printk("Unable to find swap-space signature\n"); error = -EINVAL; goto bad_swap; } - memset(p->swap_lockmap+PAGE_SIZE-10,0,10); + for (nr_sig_pages = 0 ; (nr_sig_pages<8*PAGE_SIZE) && + (!test_bit(nr_sig_pages,tmp_page)) ; nr_sig_pages++); + p->swap_lockmap = (unsigned char *) vmalloc(PAGE_SIZE*nr_sig_pages); + if (!p->swap_lockmap) { + printk("Unable to start swapping: out of memory :-)\n"); + error = -ENOMEM; + goto bad_swap; + } + *p->swap_lockmap = 0; + p->max = nr_sig_pages; + for(i = 0 ; i < nr_sig_pages ; i++) { + read_swap_page(SWP_ENTRY(type,i), tmp_page); + memmove((i*PAGE_SIZE - (i>0?10:0)) + (char *) p->swap_lockmap, + tmp_page, PAGE_SIZE); + } j = 0; p->lowest_bit = 0; p->highest_bit = 0; - for (i = 1 ; i < 8*PAGE_SIZE ; i++) { + for (i = 1 ; i < 8*PAGE_SIZE*nr_sig_pages-10 ; i++) { if (test_bit(i,p->swap_lockmap)) { if (!p->lowest_bit) p->lowest_bit = i; @@ -608,7 +633,7 @@ p->swap_map[i] = 0x80; } p->swap_map[0] = 0x80; - memset(p->swap_lockmap,0,PAGE_SIZE); + memset(p->swap_lockmap,0,PAGE_SIZE*nr_sig_pages); p->flags = SWP_WRITEOK; p->pages = j; nr_swap_pages += j; @@ -635,7 +660,7 @@ if(filp.f_op && filp.f_op->release) filp.f_op->release(filp.f_dentry->d_inode,&filp); bad_swap_2: - free_page((long) p->swap_lockmap); + vfree(p->swap_lockmap); vfree(p->swap_map); dput(p->swap_file); p->swap_device = 0; @@ -644,6 +669,7 @@ p->swap_lockmap = NULL; p->flags = 0; out: + free_page((long)tmp_page); unlock_kernel(); return error; } diff -ur linux-2.1.88-voyager/mm/vmscan.c linux/mm/vmscan.c --- linux-2.1.88-voyager/mm/vmscan.c Thu Jan 22 21:48:16 1998 +++ linux/mm/vmscan.c Mon Feb 23 20:43:35 1998 @@ -22,6 +22,7 @@ #include <linux/smp_lock.h> #include <linux/slab.h> #include <linux/dcache.h> +#include <linux/init.h> #include <asm/bitops.h> #include <asm/pgtable.h> @@ -421,7 +422,7 @@ * may be printed in the middle of another driver's init * message). It looks very bad when that happens. */ -void kswapd_setup(void) +__initfunc(void kswapd_setup(void)) { int i; char *revision="$Revision: 1.23 $", *s, *e; @@ -432,6 +433,8 @@ else s = revision, i = -1; printk ("Starting kswapd v%.*s\n", i, s); + + init_swap_timer(); } #define MAX_SWAP_FAIL 3 @@ -459,8 +462,6 @@ namings for POSIX.4 realtime scheduling priorities. */ - init_swap_timer(); - while (1) { int fail; @@ -531,7 +532,7 @@ * Initialise the swap timer */ -void init_swap_timer(void) +__initfunc(void init_swap_timer(void)) { timer_table[SWAP_TIMER].expires = 0; timer_table[SWAP_TIMER].fn = swap_tick;

--0F1p//8PRICkK4MW Content-Type: text/plain Content-Disposition: attachment; filename="patch_mkswap.c"

--- mkswap.c.orig Sun Jul 6 02:11:03 1997 +++ mkswap.c Mon Feb 23 20:36:22 1998 @@ -8,15 +8,17 @@ /* * 20.12.91 - time began. Got VM working yesterday by doing this by hand. * - * Usuage: mkswap [-c] device [size-in-blocks] + * Usage: mkswap [-c] device [size-in-blocks] * - * -c for readablility checking (use it unless you are SURE!) + * -c for readability checking (use it unless you are SURE!) * * The device may be a block device or a image of one, but this isn't * enforced (but it's not much fun on a character device :-). * * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995. + * + * Patch from Sylvain.Pion@sophia.inria.fr to support large swap areas. */ #include <stdio.h> @@ -27,14 +29,7 @@ #include <sys/ioctl.h> #include <sys/stat.h> #include <asm/page.h> - -#define BLKGETSIZE 0x1260 - -#ifndef __linux__ -# define volatile -#endif - -#define TEST_BUFFER_PAGES 8 +#include <linux/fs.h> static char * program_name = "mkswap"; static char * device_name = NULL; @@ -42,8 +37,8 @@ static long PAGES = 0; static int check = 0; static int badpages = 0; - -static int signature_page[PAGE_SIZE/sizeof(int)]; +static int nr_sig_pages = 1; +static int * signature_page; static void bit_set (unsigned int *addr, unsigned int nr) { @@ -66,12 +61,8 @@ return (r & m) != 0; } -/* - * Volatile to let gcc know that this doesn't return. When trying - * to compile this under minix, volatile gives a warning, as - * exit() isn't defined as volatile under minix. - */ -volatile void fatal_error(const char * fmt_string) +void fatal_error(const char * fmt_string) __attribute__ ((noreturn)); +void fatal_error(const char * fmt_string) { fprintf(stderr,fmt_string,program_name,device_name); exit(1); @@ -82,11 +73,10 @@ void check_blocks(void) { - unsigned int current_page; + unsigned int current_page = 0; int do_seek = 1; static char buffer[PAGE_SIZE]; - current_page = 0; while (current_page < PAGES) { if (!check) { bit_set(signature_page,current_page++); @@ -161,9 +151,8 @@ { char * tmp; struct stat statbuf; - int goodpages; + int goodpages, i; - memset(signature_page,0,PAGE_SIZE); if (argc && *argv) program_name = *argv; while (argc-- > 1) { @@ -185,8 +174,7 @@ PAGES = get_size(device_name) / PAGE_SIZE; } if (!device_name) { - fprintf(stderr, - "%s: error: Nowhere to set up swap on?\n", + fprintf(stderr, "%s: error: Nowhere to set up swap on?\n", program_name); usage(); } @@ -194,12 +182,13 @@ fprintf(stderr, "%s: error: swap area needs to be at least %ldkB\n", program_name, 10 * PAGE_SIZE / 1024); - usage(); + die(""); } if (PAGES > 8 * (PAGE_SIZE - 10)) { - PAGES = 8 * (PAGE_SIZE - 10); - fprintf(stderr, "%s: warning: truncating swap area to %ldkB\n", - program_name, PAGES * PAGE_SIZE / 1024); + nr_sig_pages = 2 + (PAGES - 8 * (PAGE_SIZE - 10) -1) / (8 * PAGE_SIZE); + fprintf(stderr, + "%s: warning: large swap area (%d signature pages)\n", + program_name, nr_sig_pages); } DEV = open(device_name,O_RDWR); if (DEV < 0 || fstat(DEV, &statbuf) < 0) { @@ -210,9 +199,15 @@ check=0; else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) die("Will not try to make swapdevice on '%s'"); + signature_page = calloc( nr_sig_pages, PAGE_SIZE); check_blocks(); + memmove(((char *)signature_page)+PAGE_SIZE, + ((char *)signature_page)+PAGE_SIZE-10, + (nr_sig_pages-1)*PAGE_SIZE); if (!bit_test_and_clear(signature_page,0)) - die("fatal: first page unreadable"); + die("Fatal: first page unreadable"); + for (i=0; i<nr_sig_pages; i++) + bit_test_and_clear(signature_page,i); goodpages = PAGES - badpages - 1; if (goodpages <= 0) die("Unable to set up swap-space: unreadable"); @@ -220,8 +215,10 @@ goodpages*PAGE_SIZE); strncpy((char*)signature_page+PAGE_SIZE-10, "SWAP-SPACE", 10); if (lseek(DEV, 0, SEEK_SET)) - die("unable to rewind swap-device"); - if (PAGE_SIZE != write(DEV, signature_page, PAGE_SIZE)) - die("unable to write signature page"); + die("Unable to rewind swap-device"); + if ((PAGE_SIZE*nr_sig_pages) != write(DEV, signature_page, PAGE_SIZE * nr_sig_pages)) + die("Unable to write signature page(s)"); + free(signature_page); + sync(); return 0; }

--0F1p//8PRICkK4MW--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu