1 /* $Id: asyncd.c,v 1.17 1999/08/14 03:51:44 anton 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>
25 #include <asm/system.h> /* for cli()/sti() */
26 #include <asm/segment.h> /* for memcpy_to/fromfs */
27 #include <asm/bitops.h>
28 #include <asm/pgtable.h>
32 #define WRITE_LIMIT 100
33 #define LOOP_LIMIT 200
36 int faults
, read
, write
, success
, failure
, errors
;
40 * The wait queue for waking up the async daemon:
42 static DECLARE_WAIT_QUEUE_HEAD(asyncd_wait
);
45 volatile struct async_job
*next
;
48 unsigned long address
;
50 void (*callback
)(int,unsigned long,int,int);
53 static volatile struct async_job
*async_queue
= NULL
;
54 static volatile struct async_job
*async_queue_end
= NULL
;
56 static void add_to_async_queue(int taskid
,
58 unsigned long address
,
60 void (*callback
)(int,unsigned long,int,int))
62 struct async_job
*a
= kmalloc(sizeof(*a
),GFP_ATOMIC
);
65 printk("ERROR: out of memory in asyncd\n");
66 a
->callback(taskid
,address
,write
,1);
80 a
->callback
= callback
;
85 async_queue_end
->next
= a
;
91 void async_fault(unsigned long address
, int write
, int taskid
,
92 void (*callback
)(int,unsigned long,int,int))
94 struct task_struct
*tsk
= task
[taskid
];
95 struct mm_struct
*mm
= tsk
->mm
;
100 printk("paging in %x for task=%d\n",address
,taskid
);
103 add_to_async_queue(taskid
, mm
, address
, write
, callback
);
104 wake_up(&asyncd_wait
);
108 static int fault_in_page(int taskid
,
109 struct vm_area_struct
*vma
,
110 unsigned address
,int write
)
112 static unsigned last_address
;
113 static int last_task
, loop_counter
;
114 struct task_struct
*tsk
= task
[taskid
];
119 if (!tsk
|| !tsk
->mm
)
122 if (!vma
|| (write
&& !(vma
->vm_flags
& VM_WRITE
)))
124 if (vma
->vm_start
> address
)
127 if (address
== last_address
&& taskid
== last_task
) {
131 last_address
= address
;
135 if (loop_counter
== WRITE_LIMIT
&& !write
) {
136 printk("MSC bug? setting write request\n");
141 if (loop_counter
== LOOP_LIMIT
) {
142 printk("MSC bug? failing request\n");
147 pgd
= pgd_offset(vma
->vm_mm
, address
);
148 pmd
= pmd_alloc(pgd
,address
);
151 pte
= pte_alloc(pmd
, address
);
154 if(!pte_present(*pte
)) {
155 handle_mm_fault(tsk
, vma
, address
, write
);
158 set_pte(pte
, pte_mkyoung(*pte
));
159 flush_tlb_page(vma
, address
);
162 if(pte_write(*pte
)) {
163 set_pte(pte
, pte_mkdirty(*pte
));
164 flush_tlb_page(vma
, address
);
167 handle_mm_fault(tsk
, vma
, address
, write
);
169 /* Fall through for do_wp_page */
181 tsk
->thread
.sig_address
= address
;
182 tsk
->thread
.sig_desc
= SUBSIG_NOMAPPING
;
183 send_sig(SIGSEGV
, tsk
, 1);
188 /* Note the semaphore operations must be done here, and _not_
191 static void run_async_queue(void)
196 while (async_queue
) {
197 volatile struct async_job
*a
;
198 struct mm_struct
*mm
;
199 struct vm_area_struct
*vma
;
201 save_flags(flags
); cli();
203 async_queue
= async_queue
->next
;
204 restore_flags(flags
);
209 vma
= find_vma(mm
, a
->address
);
210 ret
= fault_in_page(a
->taskid
,vma
,a
->address
,a
->write
);
212 printk("fault_in_page(task=%d addr=%x write=%d) = %d\n",
213 a
->taskid
,a
->address
,a
->write
,ret
);
215 a
->callback(a
->taskid
,a
->address
,a
->write
,ret
);
217 kfree_s((void *)a
,sizeof(*a
));
223 static void asyncd_info(void)
225 printk("CID(%d) faults: total=%d read=%d write=%d success=%d fail=%d err=%d\n",
226 mpp_cid(),stats
.faults
, stats
.read
, stats
.write
, stats
.success
,
227 stats
.failure
, stats
.errors
);
233 * The background async daemon.
234 * Started as a kernel thread from the init process.
236 int asyncd(void *unused
)
238 current
->session
= 1;
240 sprintf(current
->comm
, "asyncd");
241 sigfillset(¤t
->blocked
); /* block all signals */
242 recalc_sigpending(current
);
244 /* Give asyncd a realtime priority. */
245 current
->policy
= SCHED_FIFO
;
246 current
->priority
= 32; /* Fixme --- we need to standardise our
247 namings for POSIX.4 realtime scheduling
250 printk("Started asyncd\n");
253 bif_add_debug_key('a',asyncd_info
,"stats on asyncd");
259 save_flags(flags
); cli();
261 while (!async_queue
) {
262 spin_lock_irq(¤t
->sigmask_lock
);
263 flush_signals(current
);
264 spin_unlock_irq(¤t
->sigmask_lock
);
265 interruptible_sleep_on(&asyncd_wait
);
268 restore_flags(flags
);
276 static int __init
init_ap1000(void)
278 kernel_thread(asyncd
, NULL
, CLONE_FS
| CLONE_FILES
| CLONE_SIGHAND
);
282 module_init(init_ap1000
)