Messages in this thread Patch in this message | | | Subject | [PATCH] Support for modules that use swap | From | (Eric W. Biederman) | Date | 23 May 1999 13:47:03 -0500 |
| |
The following patch allows shmfs (and possibly ipc/shm.c) to be built as modules by providing an interface to swap off, that you can add and remove functions from.
Eric
diff -uNrX linux-ignore-files linux-2.3.3.eb3/include/linux/shm.h linux-2.3.3.eb4/include/linux/shm.h --- linux-2.3.3.eb3/include/linux/shm.h Tue Feb 9 22:55:51 1999 +++ linux-2.3.3.eb4/include/linux/shm.h Thu May 20 20:24:17 1999 @@ -72,7 +72,6 @@ asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, unsigned long *addr); asmlinkage int sys_shmdt (char *shmaddr); asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); -extern void shm_unuse(unsigned long entry, unsigned long page); #endif /* __KERNEL__ */ diff -uNrX linux-ignore-files linux-2.3.3.eb3/include/linux/swap.h linux-2.3.3.eb4/include/linux/swap.h --- linux-2.3.3.eb3/include/linux/swap.h Tue May 18 01:09:31 1999 +++ linux-2.3.3.eb4/include/linux/swap.h Thu May 20 20:24:17 1999 @@ -125,6 +125,20 @@ asmlinkage int sys_swapoff(const char *); asmlinkage int sys_swapon(const char *, int); + +/* So that external drivers can use swap, swapoff */ +struct swap_unuse { + void (*unuse)(unsigned long entry, unsigned long page, void *arg); + int (*read_page_tables)(void *arg); + void (*swap_page_tables)(void *arg); + void *arg; + struct swap_unuse *prev; + struct swap_unuse *next; +}; + +extern void register_swap_unuse_function (struct swap_unuse *swap_unuse); +extern void unregister_swap_unuse_function (struct swap_unuse *swap_unuse); + /* * vm_ops not present page codes for shared memory. * diff -uNrX linux-ignore-files linux-2.3.3.eb3/ipc/shm.c linux-2.3.3.eb4/ipc/shm.c --- linux-2.3.3.eb3/ipc/shm.c Sun May 16 22:07:53 1999 +++ linux-2.3.3.eb4/ipc/shm.c Thu May 20 20:24:17 1999 @@ -41,6 +41,14 @@ static ulong swap_successes = 0; static ulong used_segs = 0; +static void shm_unuse(unsigned long entry, unsigned long page, void *arg); +static struct swap_unuse shm_swap_unuse = +{ + shm_unuse, + NULL, + NULL, NULL, NULL +}; + void __init shm_init (void) { int id; @@ -49,6 +57,7 @@ shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED; shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0; init_waitqueue_head(&shm_lock); + register_swap_unuse_function(&shm_swap_unuse); return; } @@ -748,7 +757,7 @@ /* * unuse_shm() search for an eventually swapped out shm page. */ -void shm_unuse(unsigned long entry, unsigned long page) +static void shm_unuse(unsigned long entry, unsigned long page, void *arg) { int i, n; diff -uNrX linux-ignore-files linux-2.3.3.eb3/mm/Makefile linux-2.3.3.eb4/mm/Makefile --- linux-2.3.3.eb3/mm/Makefile Tue May 12 14:17:54 1998 +++ linux-2.3.3.eb4/mm/Makefile Thu May 20 20:24:17 1999 @@ -12,4 +12,6 @@ vmalloc.o slab.o \ swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o +OX_OBJS := swap_syms.o + include $(TOPDIR)/Rules.make diff -uNrX linux-ignore-files linux-2.3.3.eb3/mm/swap_syms.c linux-2.3.3.eb4/mm/swap_syms.c --- linux-2.3.3.eb3/mm/swap_syms.c Wed Dec 31 18:00:00 1969 +++ linux-2.3.3.eb4/mm/swap_syms.c Thu May 20 20:24:17 1999 @@ -0,0 +1,16 @@ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/swap.h> + +/* Explicit swapping */ +EXPORT_SYMBOL(rw_swap_page); +EXPORT_SYMBOL(rw_swap_page_nocache); +EXPORT_SYMBOL(rw_swap_page_nolock); +EXPORT_SYMBOL(swap_free); +EXPORT_SYMBOL(get_swap_page); +EXPORT_SYMBOL(si_swapinfo); +EXPORT_SYMBOL(register_swap_unuse_function); +EXPORT_SYMBOL(unregister_swap_unuse_function); +EXPORT_SYMBOL(swapper_inode); diff -uNrX linux-ignore-files linux-2.3.3.eb3/mm/swapfile.c linux-2.3.3.eb4/mm/swapfile.c --- linux-2.3.3.eb3/mm/swapfile.c Tue May 18 01:09:31 1999 +++ linux-2.3.3.eb4/mm/swapfile.c Thu May 20 21:02:31 1999 @@ -279,19 +279,143 @@ return; } + +static void do_unuse_processes(unsigned long entry, unsigned long page, void *arg) +{ + struct task_struct *p; + + read_lock(&tasklist_lock); + for_each_task(p) + unuse_process(p->mm, entry, page); + read_unlock(&tasklist_lock); +} + +static struct swap_unuse unuse_processes = +{ + do_unuse_processes, + NULL, + NULL, + NULL, + &unuse_processes, + &unuse_processes +}; + +/* Don't add or remove unuse functions, or do another swapoff while a swapoff is in progress. + * It reduces some theoretical races. + */ +static int swap_off_lock = 0; +static DECLARE_WAIT_QUEUE_HEAD(swap_off_wait); + +static void swap_unuse(unsigned long entry, unsigned long page) +{ + + struct swap_unuse *swap_unuse, *next_unuse; + next_unuse = unuse_processes.next; + do { + swap_unuse = next_unuse; + next_unuse = next_unuse->next; + if (swap_unuse->unuse) { + swap_unuse->unuse(entry, page, swap_unuse->arg); + } + } while(swap_unuse != &unuse_processes); + return; +} + +static int read_page_tables(void) +{ + struct swap_unuse *swap_unuse, *next_unuse; + int error = 0; + next_unuse = unuse_processes.next; + do { + swap_unuse = next_unuse; + next_unuse = next_unuse->next; + if (swap_unuse->read_page_tables) { + error = swap_unuse->read_page_tables(swap_unuse->arg); + } + } while(!error && (swap_unuse != &unuse_processes)); + if (!error) { + return 0; + } + swap_unuse = swap_unuse->prev; + /* We couldn't swap the page tables so reenable swapping for them */ + while(swap_unuse != &unuse_processes) { + if (swap_unuse->swap_page_tables) { + swap_unuse->swap_page_tables(swap_unuse->arg); + } + swap_unuse = swap_unuse->prev; + } + return error; +} + +static void swap_page_tables(void) +{ + struct swap_unuse *swap_unuse, *next_unuse; + next_unuse = unuse_processes.next; + do { + swap_unuse = next_unuse; + next_unuse = next_unuse->next; + if (swap_unuse->swap_page_tables) { + swap_unuse->swap_page_tables(swap_unuse->arg); + } + } while(swap_unuse != &unuse_processes); + return; +} + +void register_swap_unuse_function (struct swap_unuse *swap_unuse) +{ + if (!swap_unuse) { + return; + } + while (swap_off_lock) { + sleep_on(&swap_off_wait); + } + swap_unuse->prev = &unuse_processes; + swap_unuse->next = unuse_processes.next; + unuse_processes.next->prev = swap_unuse; + unuse_processes.next = swap_unuse; +} + +void unregister_swap_unuse_function (struct swap_unuse *swap_unuse) +{ + struct swap_unuse *next; + if (!swap_unuse) { + return; + } + while (swap_off_lock) { + sleep_on(&swap_off_wait); + } + next = swap_unuse->next; + next->prev = swap_unuse->prev; + next->prev->next = next; + + swap_unuse->next = swap_unuse->prev = NULL; +} + /* - * We completely avoid races by reading each swap page in advance, - * and then search for the process using it. All the necessary + * We completely avoid races by: + * - reading & locking all of the page tables into memory, + * - reading each swap page in advance, and then search for page table entry using it. + * - when there are no more page table entries, letting the page tables swap again. + * + * All the necessary * page table adjustments can then be made atomically. */ static int try_to_unuse(unsigned int type) { struct swap_info_struct * si = &swap_info[type]; - struct task_struct *p; struct page *page_map; unsigned long entry, page; int i; + int err; + while(swap_off_lock) { + sleep_on(&swap_off_wait); + } + swap_off_lock = 1; + err = read_page_tables(); + if (err != 0) { + return err; + } while (1) { /* * Find a swap page in use and read it in. @@ -319,11 +443,7 @@ return -ENOMEM; } page = page_address(page_map); - read_lock(&tasklist_lock); - for_each_task(p) - unuse_process(p->mm, entry, page); - read_unlock(&tasklist_lock); - shm_unuse(entry, page); + swap_unuse(entry, page); /* Now get rid of the extra reference to the temporary page we've been using. */ if (PageSwapCache(page_map)) @@ -341,6 +461,9 @@ nr_swap_pages++; } } + swap_page_tables(); + swap_off_lock = 0; + wake_up(&swap_off_wait); return 0; } - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |