1 /* $Id: asyncd.c,v 1.12 2000/01/21 11:39:13 jj Exp $
2 * The asyncd kernel daemon. This handles paging on behalf of
3 * processes that receive page faults due to remote (async) memory
6 * Idea and skeleton code courtesy of David Miller (bless his cotton socks)
8 * Implemented by tridge
12 #include <linux/malloc.h>
13 #include <linux/sched.h>
14 #include <linux/kernel.h>
15 #include <linux/kernel_stat.h>
16 #include <linux/errno.h>
17 #include <linux/string.h>
18 #include <linux/stat.h>
19 #include <linux/swap.h>
21 #include <linux/config.h>
22 #include <linux/interrupt.h>
23 #include <linux/signal.h>
26 #include <asm/system.h> /* for cli()/sti() */
27 #include <asm/segment.h> /* for memcpy_to/fromfs */
28 #include <asm/bitops.h>
29 #include <asm/pgalloc.h>
30 #include <asm/pgtable.h>
34 #define WRITE_LIMIT 100
35 #define LOOP_LIMIT 200
38 int faults
, read
, write
, success
, failure
, errors
;
42 * The wait queue for waking up the async daemon:
44 static DECLARE_WAIT_QUEUE_HEAD(asyncd_wait
);
47 volatile struct async_job
*next
;
50 unsigned long address
;
52 void (*callback
)(int,unsigned long,int,int);
55 static volatile struct async_job
*async_queue
= NULL
;
56 static volatile struct async_job
*async_queue_end
= NULL
;
58 static void add_to_async_queue(int taskid
,
60 unsigned long address
,
62 void (*callback
)(int,unsigned long,int,int))
64 struct async_job
*a
= kmalloc(sizeof(*a
),GFP_ATOMIC
);
67 printk("ERROR: out of memory in asyncd\n");
68 a
->callback(taskid
,address
,write
,1);
82 a
->callback
= callback
;
87 async_queue_end
->next
= a
;
93 void async_fault(unsigned long address
, int write
, int taskid
,
94 void (*callback
)(int,unsigned long,int,int))
96 #warning Need some fixing here... -DaveM
97 struct task_struct
*tsk
= current
/* XXX task[taskid] */;
98 struct mm_struct
*mm
= tsk
->mm
;
103 printk("paging in %x for task=%d\n",address
,taskid
);
106 add_to_async_queue(taskid
, mm
, address
, write
, callback
);
107 wake_up(&asyncd_wait
);
111 static int fault_in_page(int taskid
,
112 struct vm_area_struct
*vma
,
113 unsigned long address
, int write
)
115 static unsigned last_address
;
116 static int last_task
, loop_counter
;
118 #warning Need some fixing here... -DaveM
119 struct task_struct
*tsk
= current
/* XXX task[taskid] */;
124 if (!tsk
|| !tsk
->mm
)
127 if (!vma
|| (write
&& !(vma
->vm_flags
& VM_WRITE
)))
129 if (vma
->vm_start
> address
)
132 if (address
== last_address
&& taskid
== last_task
) {
136 last_address
= address
;
140 if (loop_counter
== WRITE_LIMIT
&& !write
) {
141 printk("MSC bug? setting write request\n");
146 if (loop_counter
== LOOP_LIMIT
) {
147 printk("MSC bug? failing request\n");
152 pgd
= pgd_offset(vma
->vm_mm
, address
);
153 pmd
= pmd_alloc(pgd
,address
);
156 pte
= pte_alloc(pmd
, address
);
159 if(!pte_present(*pte
)) {
160 handle_mm_fault(tsk
, vma
, address
, write
);
163 set_pte(pte
, pte_mkyoung(*pte
));
164 flush_tlb_page(vma
, address
);
167 if(pte_write(*pte
)) {
168 set_pte(pte
, pte_mkdirty(*pte
));
169 flush_tlb_page(vma
, address
);
172 handle_mm_fault(tsk
, vma
, address
, write
);
174 /* Fall through for do_wp_page */
186 info
.si_signo
= SIGSEGV
;
188 info
.si_code
= SEGV_MAPERR
;
189 info
.si_addr
= (void *)address
;
191 send_sig_info(SIGSEGV
, &info
, tsk
);
196 /* Note the semaphore operations must be done here, and _not_
199 static void run_async_queue(void)
204 while (async_queue
) {
205 volatile struct async_job
*a
;
206 struct mm_struct
*mm
;
207 struct vm_area_struct
*vma
;
209 save_flags(flags
); cli();
211 async_queue
= async_queue
->next
;
212 restore_flags(flags
);
217 vma
= find_vma(mm
, a
->address
);
218 ret
= fault_in_page(a
->taskid
,vma
,a
->address
,a
->write
);
220 printk("fault_in_page(task=%d addr=%x write=%d) = %d\n",
221 a
->taskid
,a
->address
,a
->write
,ret
);
223 a
->callback(a
->taskid
,a
->address
,a
->write
,ret
);
225 kfree_s((void *)a
,sizeof(*a
));
231 static void asyncd_info(void)
233 printk("CID(%d) faults: total=%d read=%d write=%d success=%d fail=%d err=%d\n",
234 mpp_cid(),stats
.faults
, stats
.read
, stats
.write
, stats
.success
,
235 stats
.failure
, stats
.errors
);
241 * The background async daemon.
242 * Started as a kernel thread from the init process.
244 int asyncd(void *unused
)
246 current
->session
= 1;
248 sprintf(current
->comm
, "asyncd");
250 sigfillset(¤t
->blocked
); /* block all signals */
251 recalc_sigpending(current
);
253 /* Give asyncd a realtime priority. */
254 current
->policy
= SCHED_FIFO
;
255 current
->priority
= 32; /* Fixme --- we need to standardise our
256 namings for POSIX.4 realtime scheduling
259 printk("Started asyncd\n");
262 bif_add_debug_key('a',asyncd_info
,"stats on asyncd");
268 save_flags(flags
); cli();
270 while (!async_queue
) {
271 spin_lock(¤t
->sigmask_lock
);
272 flush_signals(current
);
273 spin_unlock(¤t
->sigmask_lock
);
274 interruptible_sleep_on(&asyncd_wait
);
275 __sti(); cli(); /* acquire gloabl_irq_lock */
278 restore_flags(flags
);