Add support for swap partitions > 128MB; derived from patch-2.1.117. Large swap partitions require a version of mkswap that supports the new-style (v1) swap area. --- include/linux/swap.h.DIST Fri May 31 16:28:19 2002 +++ include/linux/swap.h Thu Jun 19 13:05:42 2003 @@ -7,6 +7,23 @@ #define MAX_SWAPFILES 8 +union swap_header { + struct + { + char reserved[PAGE_SIZE - 10]; + char magic[10]; + } magic; + struct + { + char bootbits[1024]; /* Space for disklabel etc. */ + unsigned int version; + unsigned int last_page; + unsigned int nr_badpages; + unsigned int padding[125]; + unsigned int badpages[1]; + } info; +}; + #ifdef __KERNEL__ #include @@ -16,12 +33,15 @@ #define SWAP_CLUSTER_MAX 32 +#define SWAP_MAP_MAX 0x7fff +#define SWAP_MAP_BAD 0x8000 + struct swap_info_struct { unsigned int flags; kdev_t swap_device; char *swap_filename; struct inode * swap_file; - unsigned char * swap_map; + unsigned short * swap_map; unsigned char * swap_lockmap; unsigned int lowest_bit; unsigned int highest_bit; --- mm/swap_state.c.DIST Fri May 31 16:28:19 2002 +++ mm/swap_state.c Thu Jun 19 14:06:46 2003 @@ -106,7 +106,16 @@ printk("swap_duplicate: trying to duplicate unused page\n"); return; } - p->swap_map[offset]++; + if (p->swap_map[offset] < SWAP_MAP_MAX) + p->swap_map[offset]++; + else { + static int overflow = 0; + if (overflow++ < 5) + printk(KERN_WARNING + "swap_duplicate: entry %08lx map count=%d\n", + entry, p->swap_map[offset]); + p->swap_map[offset] = SWAP_MAP_MAX; + } return; } --- mm/swapfile.c.DIST Fri May 31 16:28:19 2002 +++ mm/swapfile.c Thu Jun 19 14:42:03 2003 @@ -153,9 +153,10 @@ p->highest_bit = offset; if (!p->swap_map[offset]) debug("swap_free: swap-space map bad", 0); - else + else if (p->swap_map[offset] < SWAP_MAP_MAX) { if (!--p->swap_map[offset]) nr_swap_pages++; + } if (p->prio > swap_info[swap_list.next].prio) { swap_list.next = swap_list.head; } @@ -402,7 +403,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; @@ -430,7 +431,7 @@ usedswap = 0; for (j = 0; j < ptr->max; ++j) switch (ptr->swap_map[j]) { - case 128: + case SWAP_MAP_BAD: case 0: continue; default: @@ -454,10 +455,14 @@ unsigned int type; int i, j, prev; int error = -EPERM; - char *tmp; struct file filp; static int least_priority = 0; - + union swap_header *swap_header = 0; + int swap_header_version; + int lock_map_size = PAGE_SIZE; + int nr_good_pages = 0; + char tmp_lock_map = 0; + lock_kernel(); if (!suser()) goto out; @@ -521,54 +526,114 @@ } } else if (!S_ISREG(swap_inode->i_mode)) goto bad_swap; - p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER); - if (!p->swap_lockmap) { + swap_header = (void *) __get_free_page(GFP_USER); + if (!swap_header) { 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_lock_map; + read_swap_page(SWP_ENTRY(type,0), (char *) swap_header); + p->swap_lockmap = 0; + + if (!memcmp("SWAP-SPACE",swap_header->magic.magic,10)) + swap_header_version = 1; + else if (!memcmp("SWAPSPACE2",swap_header->magic.magic,10)) + swap_header_version = 2; + else { printk("Unable to find swap-space signature\n"); error = -EINVAL; goto bad_swap; } - memset(p->swap_lockmap+PAGE_SIZE-10,0,10); - j = 0; - p->lowest_bit = 0; - p->highest_bit = 0; - for (i = 1 ; i < 8*PAGE_SIZE ; i++) { - if (test_bit(i,p->swap_lockmap)) { - if (!p->lowest_bit) - p->lowest_bit = i; - p->highest_bit = i; - p->max = i+1; - j++; + + switch (swap_header_version) { + case 1: + memset(((char *) swap_header)+PAGE_SIZE-10,0,10); + j = 0; + p->lowest_bit = 0; + p->highest_bit = 0; + for (i = 1 ; i < 8*PAGE_SIZE ; i++) { + if (test_bit(i,(char *) swap_header)) { + if (!p->lowest_bit) + p->lowest_bit = i; + p->highest_bit = i; + p->max = i+1; + j++; + } + } + nr_good_pages = j; + p->swap_map = vmalloc(p->max * sizeof(short)); + if (!p->swap_map) { + error = -ENOMEM; + goto bad_swap; + } + for (i = 1 ; i < p->max ; i++) { + if (test_bit(i,(char *) swap_header)) + p->swap_map[i] = 0; + else + p->swap_map[i] = SWAP_MAP_BAD; + } + break; + + case 2: + /* Check the swap header's sub-version and the size of + the swap file and bad block lists */ + if (swap_header->info.version != 1) { + printk("Unable to handle swap header version %d\n", + swap_header->info.version); + error = -EINVAL; + goto bad_swap; + } + + p->lowest_bit = 1; + p->highest_bit = swap_header->info.last_page - 1; + p->max = swap_header->info.last_page; + + if (p->max >= 0x7fffffffL/PAGE_SIZE || + (void *) &swap_header->info.badpages[swap_header->info.nr_badpages-1] >= (void *) swap_header->magic.magic) { + error = -EINVAL; + goto bad_swap; + } + + /* OK, set up the swap map and apply the bad block list */ + if (!(p->swap_map = vmalloc (p->max * sizeof(short)))) { + error = -ENOMEM; + goto bad_swap; + } + + error = 0; + memset(p->swap_map, 0, p->max * sizeof(short)); + for (i=0; iinfo.nr_badpages; i++) { + int page = swap_header->info.badpages[i]; + if (page <= 0 || page >= swap_header->info.last_page) + error = -EINVAL; + else + p->swap_map[page] = SWAP_MAP_BAD; } + nr_good_pages = swap_header->info.last_page - i; + lock_map_size = (p->max + 7) / 8; + if (error) + goto bad_swap; + break; } - if (!j) { + + if (!nr_good_pages) { printk("Empty swap-file\n"); error = -EINVAL; goto bad_swap; } - p->swap_map = (unsigned char *) vmalloc(p->max); - if (!p->swap_map) { + p->swap_map[0] = SWAP_MAP_BAD; + if (!(p->swap_lockmap = vmalloc (lock_map_size))) { error = -ENOMEM; goto bad_swap; } - for (i = 1 ; i < p->max ; i++) { - if (test_bit(i,p->swap_lockmap)) - p->swap_map[i] = 0; - else - p->swap_map[i] = 0x80; - } - p->swap_map[0] = 0x80; - memset(p->swap_lockmap,0,PAGE_SIZE); + memset(p->swap_lockmap,0,lock_map_size); p->flags = SWP_WRITEOK; - p->pages = j; - nr_swap_pages += j; + p->pages = nr_good_pages; + nr_swap_pages += nr_good_pages; printk("Adding Swap: %dk swap-space (priority %d)\n", - j<<(PAGE_SHIFT-10), p->prio); + nr_good_pages<<(PAGE_SHIFT-10), p->prio); /* insert swap space into swap_list: */ prev = -1; @@ -579,12 +644,6 @@ prev = i; } p->next = i; - if (!getname(specialfile, &tmp)) { - if ((p->swap_filename = - (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL) - strcpy(p->swap_filename, tmp); - putname(tmp); - } if (prev < 0) { swap_list.head = swap_list.next = p - swap_info; } else { @@ -596,8 +655,10 @@ if(filp.f_op && filp.f_op->release) filp.f_op->release(filp.f_inode,&filp); bad_swap_2: - free_page((long) p->swap_lockmap); - vfree(p->swap_map); + if (p->swap_lockmap) + vfree(p->swap_lockmap); + if (p->swap_map) + vfree(p->swap_map); iput(p->swap_file); p->swap_device = 0; p->swap_file = NULL; @@ -605,6 +666,8 @@ p->swap_lockmap = NULL; p->flags = 0; out: + if (swap_header) + free_page((long) swap_header); unlock_kernel(); return error; } @@ -619,7 +682,7 @@ continue; for (j = 0; j < swap_info[i].max; ++j) switch (swap_info[i].swap_map[j]) { - case 128: + case SWAP_MAP_BAD: continue; case 0: ++val->freeswap;