Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

mm/asyncd.c

Go to the documentation of this file.
00001 /*  $Id: asyncd.c,v 1.12.2.1 1999/11/16 06:29:36 davem Exp $
00002  *  The asyncd kernel daemon. This handles paging on behalf of 
00003  *  processes that receive page faults due to remote (async) memory
00004  *  accesses. 
00005  *
00006  *  Idea and skeleton code courtesy of David Miller (bless his cotton socks)
00007  *
00008  *  Implemented by tridge
00009  */
00010 
00011 #include <linux/mm.h>
00012 #include <linux/malloc.h>
00013 #include <linux/sched.h>
00014 #include <linux/kernel.h>
00015 #include <linux/kernel_stat.h>
00016 #include <linux/errno.h>
00017 #include <linux/string.h>
00018 #include <linux/stat.h>
00019 #include <linux/swap.h>
00020 #include <linux/fs.h>
00021 #include <linux/config.h>
00022 #include <linux/interrupt.h>
00023 
00024 #include <asm/dma.h>
00025 #include <asm/system.h> /* for cli()/sti() */
00026 #include <asm/segment.h> /* for memcpy_to/fromfs */
00027 #include <asm/bitops.h>
00028 #include <asm/pgtable.h>
00029 
00030 #define DEBUG 0
00031 
00032 #define WRITE_LIMIT 100
00033 #define LOOP_LIMIT 200
00034 
00035 static struct {
00036         int faults, read, write, success, failure, errors;
00037 } stats;
00038 
00039 /* 
00040  * The wait queue for waking up the async daemon:
00041  */
00042 static struct wait_queue * asyncd_wait = NULL;
00043 
00044 struct async_job {
00045         volatile struct async_job *next;
00046         int taskid;
00047         struct mm_struct *mm;
00048         unsigned long address;
00049         int write;
00050         void (*callback)(int,unsigned long,int,int);
00051 };
00052 
00053 static volatile struct async_job *async_queue = NULL;
00054 static volatile struct async_job *async_queue_end = NULL;
00055 
00056 static void add_to_async_queue(int taskid,
00057                                struct mm_struct *mm,
00058                                unsigned long address,
00059                                int write,
00060                                void (*callback)(int,unsigned long,int,int))
00061 {
00062         struct async_job *a = kmalloc(sizeof(*a),GFP_ATOMIC);
00063 
00064         if (!a) {
00065                 printk("ERROR: out of memory in asyncd\n");
00066                 a->callback(taskid,address,write,1);
00067                 return;
00068         }
00069 
00070         if (write)
00071                 stats.write++;
00072         else
00073                 stats.read++;
00074 
00075         a->next = NULL;
00076         a->taskid = taskid;
00077         a->mm = mm;
00078         a->address = address;
00079         a->write = write;
00080         a->callback = callback;
00081 
00082         if (!async_queue) {
00083                 async_queue = a;
00084         } else {
00085                 async_queue_end->next = a;
00086         }
00087         async_queue_end = a;
00088 }
00089 
00090 
00091 void async_fault(unsigned long address, int write, int taskid,
00092                  void (*callback)(int,unsigned long,int,int))
00093 {
00094         struct task_struct *tsk = task[taskid];
00095         struct mm_struct *mm = tsk->mm;
00096 
00097         stats.faults++;
00098 
00099 #if 0
00100         printk("paging in %x for task=%d\n",address,taskid);
00101 #endif
00102 
00103         add_to_async_queue(taskid, mm, address, write, callback);
00104         wake_up(&asyncd_wait);  
00105         mark_bh(TQUEUE_BH);
00106 }
00107 
00108 static int fault_in_page(int taskid,
00109                          struct vm_area_struct *vma,
00110                          unsigned address,int write)
00111 {
00112         static unsigned last_address;
00113         static int last_task, loop_counter;
00114         struct task_struct *tsk = task[taskid];
00115         pgd_t *pgd;
00116         pmd_t *pmd;
00117         pte_t *pte;
00118 
00119         if (!tsk || !tsk->mm)
00120                 return 1;
00121 
00122         if (!vma || (write && !(vma->vm_flags & VM_WRITE)))
00123           goto bad_area;
00124         if (vma->vm_start > address)
00125           goto bad_area;
00126 
00127         if (address == last_address && taskid == last_task) {
00128                 loop_counter++;
00129         } else {
00130                 loop_counter = 0;
00131                 last_address = address; 
00132                 last_task = taskid;
00133         }
00134 
00135         if (loop_counter == WRITE_LIMIT && !write) {
00136                 printk("MSC bug? setting write request\n");
00137                 stats.errors++;
00138                 write = 1;
00139         }
00140 
00141         if (loop_counter == LOOP_LIMIT) {
00142                 printk("MSC bug? failing request\n");
00143                 stats.errors++;
00144                 return 1;
00145         }
00146 
00147         pgd = pgd_offset(vma->vm_mm, address);
00148         pmd = pmd_alloc(pgd,address);
00149         if(!pmd)
00150                 goto no_memory;
00151         pte = pte_alloc(pmd, address);
00152         if(!pte)
00153                 goto no_memory;
00154         if(!pte_present(*pte)) {
00155                 int fault = handle_mm_fault(tsk, vma, address, write);
00156                 if (fault < 0)
00157                         goto no_memory;
00158                 goto finish_up;
00159         }
00160         set_pte(pte, pte_mkyoung(*pte));
00161         flush_tlb_page(vma, address);
00162         if(!write)
00163                 goto finish_up;
00164         if(pte_write(*pte)) {
00165                 set_pte(pte, pte_mkdirty(*pte));
00166                 flush_tlb_page(vma, address);
00167                 goto finish_up;
00168         }
00169         {
00170                 int fault = handle_mm_fault(tsk, vma, address, write);
00171                 if (fault < 0)
00172                         goto no_memory;
00173         }
00174 
00175         /* Fall through for do_wp_page */
00176 finish_up:
00177         stats.success++;
00178         return 0;
00179 
00180 no_memory:
00181         stats.failure++;
00182         force_sig(SIGKILL, tsk);
00183         return 1;
00184         
00185 bad_area:         
00186         stats.failure++;
00187         tsk->tss.sig_address = address;
00188         tsk->tss.sig_desc = SUBSIG_NOMAPPING;
00189         send_sig(SIGSEGV, tsk, 1);
00190         return 1;
00191 }
00192 
00193 
00194 /* Note the semaphore operations must be done here, and _not_
00195  * in async_fault().
00196  */
00197 static void run_async_queue(void)
00198 {
00199         int ret;
00200         unsigned flags;
00201 
00202         while (async_queue) {
00203                 volatile struct async_job *a;
00204                 struct mm_struct *mm;
00205                 struct vm_area_struct *vma;
00206 
00207                 save_flags(flags); cli();
00208                 a = async_queue;
00209                 async_queue = async_queue->next;
00210                 restore_flags(flags);
00211 
00212                 mm = a->mm;
00213 
00214                 down(&mm->mmap_sem);
00215                 vma = find_vma(mm, a->address);
00216                 ret = fault_in_page(a->taskid,vma,a->address,a->write);
00217 #if DEBUG
00218                 printk("fault_in_page(task=%d addr=%x write=%d) = %d\n",
00219                        a->taskid,a->address,a->write,ret);
00220 #endif
00221                 a->callback(a->taskid,a->address,a->write,ret);
00222                 up(&mm->mmap_sem);
00223                 kfree_s((void *)a,sizeof(*a));
00224         }
00225 }
00226 
00227 
00228 #if CONFIG_AP1000
00229 static void asyncd_info(void)
00230 {
00231         printk("CID(%d) faults: total=%d  read=%d  write=%d  success=%d fail=%d err=%d\n",
00232                mpp_cid(),stats.faults, stats.read, stats.write, stats.success,
00233                stats.failure, stats.errors);
00234 }
00235 #endif
00236 
00237 
00238 /*
00239  * The background async daemon.
00240  * Started as a kernel thread from the init process.
00241  */
00242 int asyncd(void *unused)
00243 {
00244         current->session = 1;
00245         current->pgrp = 1;
00246         sprintf(current->comm, "asyncd");
00247         sigfillset(&current->blocked); /* block all signals */
00248         recalc_sigpending(current);
00249   
00250         /* Give asyncd a realtime priority. */
00251         current->policy = SCHED_FIFO;
00252         current->priority = 32;  /* Fixme --- we need to standardise our
00253                                     namings for POSIX.4 realtime scheduling
00254                                     priorities.  */
00255   
00256         printk("Started asyncd\n");
00257 
00258 #if CONFIG_AP1000
00259         bif_add_debug_key('a',asyncd_info,"stats on asyncd");
00260 #endif
00261 
00262         while (1) {
00263                 unsigned flags;
00264 
00265                 save_flags(flags); cli();
00266 
00267                 while (!async_queue) {
00268                         spin_lock_irq(&current->sigmask_lock);
00269                         flush_signals(current);
00270                         spin_unlock_irq(&current->sigmask_lock);
00271                         interruptible_sleep_on(&asyncd_wait);
00272                 }
00273 
00274                 restore_flags(flags);
00275 
00276                 run_async_queue();
00277         }
00278 }
00279