patch-2.1.19 linux/arch/sparc64/mm/asyncd.c
Next file: linux/arch/sparc64/mm/extable.c
Previous file: linux/arch/sparc64/mm/Makefile
Back to the patch index
Back to the overall index
- Lines: 273
- Date:
Mon Dec 30 11:59:59 1996
- Orig file:
v2.1.18/linux/arch/sparc64/mm/asyncd.c
- Orig date:
Thu Jan 1 02:00:00 1970
diff -u --recursive --new-file v2.1.18/linux/arch/sparc64/mm/asyncd.c linux/arch/sparc64/mm/asyncd.c
@@ -0,0 +1,272 @@
+/* $Id: asyncd.c,v 1.1 1996/12/26 10:24:24 davem Exp $
+ * The asyncd kernel daemon. This handles paging on behalf of
+ * processes that receive page faults due to remote (async) memory
+ * accesses.
+ *
+ * Idea and skeleton code courtesy of David Miller (bless his cotton socks)
+ *
+ * Implemented by tridge
+ */
+
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/swap.h>
+#include <linux/fs.h>
+#include <linux/config.h>
+#include <linux/interrupt.h>
+
+#include <asm/dma.h>
+#include <asm/system.h> /* for cli()/sti() */
+#include <asm/segment.h> /* for memcpy_to/fromfs */
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+
+#define DEBUG 0
+
+#define WRITE_LIMIT 100
+#define LOOP_LIMIT 200
+
+static struct {
+ int faults, read, write, success, failure, errors;
+} stats;
+
+/*
+ * The wait queue for waking up the async daemon:
+ */
+static struct wait_queue * asyncd_wait = NULL;
+
+struct async_job {
+ volatile struct async_job *next;
+ int taskid;
+ struct mm_struct *mm;
+ unsigned long address;
+ int write;
+ void (*callback)(int,unsigned long,int,int);
+};
+
+static volatile struct async_job *async_queue = NULL;
+static volatile struct async_job *async_queue_end = NULL;
+
+static void add_to_async_queue(int taskid,
+ struct mm_struct *mm,
+ unsigned long address,
+ int write,
+ void (*callback)(int,unsigned long,int,int))
+{
+ struct async_job *a = kmalloc(sizeof(*a),GFP_ATOMIC);
+
+ if (!a) {
+ printk("ERROR: out of memory in asyncd\n");
+ a->callback(taskid,address,write,1);
+ return;
+ }
+
+ if (write)
+ stats.write++;
+ else
+ stats.read++;
+
+ a->next = NULL;
+ a->taskid = taskid;
+ a->mm = mm;
+ a->address = address;
+ a->write = write;
+ a->callback = callback;
+
+ if (!async_queue) {
+ async_queue = a;
+ } else {
+ async_queue_end->next = a;
+ }
+ async_queue_end = a;
+}
+
+
+void async_fault(unsigned long address, int write, int taskid,
+ void (*callback)(int,unsigned long,int,int))
+{
+ struct task_struct *tsk = task[taskid];
+ struct mm_struct *mm = tsk->mm;
+
+ stats.faults++;
+
+#if 0
+ printk("paging in %x for task=%d\n",address,taskid);
+#endif
+
+ add_to_async_queue(taskid, mm, address, write, callback);
+ wake_up(&asyncd_wait);
+ mark_bh(TQUEUE_BH);
+}
+
+static int fault_in_page(int taskid,
+ struct vm_area_struct *vma,
+ unsigned address,int write)
+{
+ static unsigned last_address;
+ static int last_task, loop_counter;
+ struct task_struct *tsk = task[taskid];
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ if (!tsk || !tsk->mm)
+ return 1;
+
+ if (!vma || (write && !(vma->vm_flags & VM_WRITE)))
+ goto bad_area;
+ if (vma->vm_start > address)
+ goto bad_area;
+
+ if (address == last_address && taskid == last_task) {
+ loop_counter++;
+ } else {
+ loop_counter = 0;
+ last_address = address;
+ last_task = taskid;
+ }
+
+ if (loop_counter == WRITE_LIMIT && !write) {
+ printk("MSC bug? setting write request\n");
+ stats.errors++;
+ write = 1;
+ }
+
+ if (loop_counter == LOOP_LIMIT) {
+ printk("MSC bug? failing request\n");
+ stats.errors++;
+ return 1;
+ }
+
+ pgd = pgd_offset(vma->vm_mm, address);
+ pmd = pmd_alloc(pgd,address);
+ if(!pmd)
+ goto no_memory;
+ pte = pte_alloc(pmd, address);
+ if(!pte)
+ goto no_memory;
+ if(!pte_present(*pte)) {
+ do_no_page(tsk, vma, address, write);
+ goto finish_up;
+ }
+ set_pte(pte, pte_mkyoung(*pte));
+ flush_tlb_page(vma, address);
+ if(!write)
+ goto finish_up;
+ if(pte_write(*pte)) {
+ set_pte(pte, pte_mkdirty(*pte));
+ flush_tlb_page(vma, address);
+ goto finish_up;
+ }
+ do_wp_page(tsk, vma, address, write);
+
+ /* Fall through for do_wp_page */
+finish_up:
+ stats.success++;
+ update_mmu_cache(vma, address, *pte);
+ return 0;
+
+no_memory:
+ stats.failure++;
+ oom(tsk);
+ return 1;
+
+bad_area:
+ stats.failure++;
+ tsk->tss.sig_address = address;
+ tsk->tss.sig_desc = SUBSIG_NOMAPPING;
+ send_sig(SIGSEGV, tsk, 1);
+ return 1;
+}
+
+
+/* Note the semaphore operations must be done here, and _not_
+ * in async_fault().
+ */
+static void run_async_queue(void)
+{
+ int ret;
+ unsigned flags;
+
+ while (async_queue) {
+ volatile struct async_job *a;
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+
+ save_flags(flags); cli();
+ a = async_queue;
+ async_queue = async_queue->next;
+ restore_flags(flags);
+
+ mm = a->mm;
+
+ down(&mm->mmap_sem);
+ vma = find_vma(mm, a->address);
+ ret = fault_in_page(a->taskid,vma,a->address,a->write);
+#if DEBUG
+ printk("fault_in_page(task=%d addr=%x write=%d) = %d\n",
+ a->taskid,a->address,a->write,ret);
+#endif
+ a->callback(a->taskid,a->address,a->write,ret);
+ up(&mm->mmap_sem);
+ kfree_s((void *)a,sizeof(*a));
+ }
+}
+
+
+#if CONFIG_AP1000
+static void asyncd_info(void)
+{
+ printk("CID(%d) faults: total=%d read=%d write=%d success=%d fail=%d err=%d\n",
+ mpp_cid(),stats.faults, stats.read, stats.write, stats.success,
+ stats.failure, stats.errors);
+}
+#endif
+
+
+/*
+ * The background async daemon.
+ * Started as a kernel thread from the init process.
+ */
+int asyncd(void *unused)
+{
+ current->session = 1;
+ current->pgrp = 1;
+ sprintf(current->comm, "asyncd");
+ current->blocked = ~0UL; /* block all signals */
+
+ /* Give asyncd a realtime priority. */
+ current->policy = SCHED_FIFO;
+ current->priority = 32; /* Fixme --- we need to standardise our
+ namings for POSIX.4 realtime scheduling
+ priorities. */
+
+ printk("Started asyncd\n");
+
+#if CONFIG_AP1000
+ bif_add_debug_key('a',asyncd_info,"stats on asyncd");
+#endif
+
+ while (1) {
+ unsigned flags;
+
+ save_flags(flags); cli();
+
+ while (!async_queue) {
+ current->signal = 0;
+ interruptible_sleep_on(&asyncd_wait);
+ }
+
+ restore_flags(flags);
+
+ run_async_queue();
+ }
+}
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov