source: trunk/kernel/libk/user_dir.c@ 627

Last change on this file since 627 was 619, checked in by alain, 8 years ago

1) Fix a bug in KSH : after the "load" command,

the [ksh] prompt is now printed after completion
of the loaded application.

2) Fix a bug in vmm_handle_cow() : the copy-on-write

use now a hal_remote_memcpy() to replicate the page content.


File size: 17.4 KB
RevLine 
[613]1/*
2 * user_dir.c - kernel DIR related operations implementation.
3 *
4 * Authors Alain Greiner (2016,2017,2018)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <kernel_config.h>
25#include <hal_kernel_types.h>
26#include <hal_irqmask.h>
27#include <hal_remote.h>
28#include <thread.h>
29#include <xlist.h>
30#include <scheduler.h>
31#include <remote_queuelock.h>
32#include <user_dir.h>
33
34
35/////////////////////////////////////////////
36xptr_t user_dir_from_ident( intptr_t ident )
37{
38 // get pointer on local process_descriptor
39 process_t * process = CURRENT_THREAD->process;
40
41 // get pointers on reference process
42 xptr_t ref_xp = process->ref_xp;
43 cxy_t ref_cxy = GET_CXY( ref_xp );
44 process_t * ref_ptr = GET_PTR( ref_xp );
45
46 // get extended pointers on open directories list and lock
47 xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->dir_root );
48 xptr_t lock_xp = XPTR( ref_cxy , &ref_ptr->dir_lock );
49
50 // get lock protecting open directories list
51 remote_queuelock_acquire( lock_xp );
52
53 // scan reference process dir list
54 xptr_t iter_xp;
55 xptr_t dir_xp;
56 cxy_t dir_cxy;
57 user_dir_t * dir_ptr;
58 intptr_t current;
59 bool_t found = false;
60
61 XLIST_FOREACH( root_xp , iter_xp )
62 {
63 dir_xp = XLIST_ELEMENT( iter_xp , user_dir_t , list );
64 dir_cxy = GET_CXY( dir_xp );
65 dir_ptr = GET_PTR( dir_xp );
66 current = (intptr_t)hal_remote_lpt( XPTR( dir_cxy , &dir_ptr->ident ) );
67 if( ident == current )
68 {
69 found = true;
70 break;
71 }
72 }
73
74 // relese lock protecting open directories list
75 remote_queuelock_release( lock_xp );
76
77 if( found == false ) return XPTR_NULL;
78 else return dir_xp;
79
80} // end user_dir_from_ident()
81
[614]82//////////////////////////////////////////////////
83user_dir_t * user_dir_create( vfs_inode_t * inode,
84 xptr_t ref_xp )
[613]85{
86 user_dir_t * dir; // local pointer on created user_dir_t
87 vseg_t * vseg; // local pointer on dirent array vseg
88 uint32_t vseg_size; // size of vseg in bytes
89 process_t * ref_ptr; // local pointer on reference process
90 cxy_t ref_cxy; // reference process cluster identifier
[614]91 pid_t ref_pid; // reference process PID
[613]92 xptr_t gpt_xp; // extended pointer on reference process GPT
93 uint32_t gpt_attributes; // attributes for all mapped gpt entries
94 uint32_t dirents_per_page; // number of dirent descriptors per page
95 xptr_t page_xp; // extended pointer on page descriptor
96 page_t * page; // local pointer on page descriptor
97 xptr_t base_xp; // extended pointer on physical page base
98 struct dirent * base; // local pointer on physical page base
99 uint32_t total_dirents; // total number of dirents in dirent array
100 uint32_t total_pages; // total number of pages for dirent array
101 vpn_t vpn; // first page in dirent array vseg
102 ppn_t ppn; // ppn of currently allocated physical page
103 uint32_t entries; // number of dirent actually comied in one page
104 uint32_t first_entry; // index of first dentry to copy in dirent array
105 bool_t done; // last entry found and copied when true
106 list_entry_t root; // root of temporary list of allocated pages
107 uint32_t page_id; // page index in list of physical pages
108 kmem_req_t req; // kmem request descriptor
109 error_t error;
110
[614]111 // get cluster, local pointer, and pid of reference user process
112 ref_cxy = GET_CXY( ref_xp );
113 ref_ptr = GET_PTR( ref_xp );
114 ref_pid = hal_remote_l32( XPTR( ref_cxy , &ref_ptr->pid ) );
[613]115
116#if DEBUG_USER_DIR
117uint32_t cycle = (uint32_t)hal_get_cycles();
118thread_t * this = CURRENT_THREAD;
119if( cycle > DEBUG_USER_DIR )
[614]120printk("\n[%s] thread[%x,%x] enter for inode (%x,%x) and process %x / cycle %d\n",
121__FUNCTION__, this->process->pid, this->trdid, local_cxy, inode, ref_pid, cycle );
[613]122#endif
123
124// check dirent size
125assert( ( sizeof(struct dirent) == 64), "sizeof(dirent) != 64\n");
126
127 // compute number of dirent per page
128 dirents_per_page = CONFIG_PPM_PAGE_SIZE >> 6;
129
130 // initialise temporary list of pages
131 list_root_init( &root );
132
133 // allocate memory for a local user_dir descriptor
134 req.type = KMEM_DIR;
135 req.flags = AF_ZERO;
136 dir = kmem_alloc( &req );
137
138 if( dir == NULL )
139 {
140 printk("\n[ERROR] in %s : cannot allocate user_dir_t in cluster %x\n",
141 __FUNCTION__, local_cxy );
142 return NULL;
143 }
144
145 // Build an initialize the dirent array as a list of physical pages.
146 // For each iteration in this while loop:
147 // - allocate one physical 4 Kbytes (64 dirent slots)
148 // - call the relevant FS specific function to scan the directory mapper,
149 // and copy up to 64 entries in the page.
150 // - register the page in a temporary list using the embedded page list_entry
151 // - exit when the last entry has been found (done == true).
152
153 // initialize loops variables
154 done = false;
155 total_dirents = 0;
156 total_pages = 0;
157 first_entry = 0;
158
159 while( done == false ) // loop on physical pages
160 {
161 // allocate one physical page
162 req.type = KMEM_PAGE;
163 req.size = 0;
164 req.flags = AF_ZERO;
165 page = kmem_alloc( &req );
166
167 if( page == NULL )
168 {
169 printk("\n[ERROR] in %s : cannot allocate page in cluster %x\n",
170 __FUNCTION__, ref_cxy );
171 goto user_dir_create_failure;
172 }
173
174 // get pointer on page base (array of dirents)
175 page_xp = XPTR( local_cxy , page );
176 base_xp = ppm_page2base( page_xp );
177 base = GET_PTR( base_xp );
178
179 // call the relevant FS specific function to copy up to 64 dirents in page
180 error = vfs_fs_get_user_dir( inode,
181 base,
182 dirents_per_page,
183 first_entry,
184 false, // don't create missing inodes
185 &entries,
186 &done );
187 if( error )
188 {
189 printk("\n[ERROR] in %s : cannot initialise dirent array in cluster %x\n",
190 __FUNCTION__, ref_cxy );
191 goto user_dir_create_failure;
192 }
193
194 // increment number of written dirents
195 total_dirents += entries;
196
197 // register page in temporary list
198 list_add_last( &root , &page->list );
199 total_pages++;
200
201 // set first_entry for next iteration
202 first_entry = total_dirents;
203
204 } // end while
205
[614]206#if DEBUG_USER_DIR
207if( cycle > DEBUG_USER_DIR )
208printk("\n[%s] thread[%x,%x] initialised dirent array / %d entries\n",
209__FUNCTION__, this->process->pid, this->trdid, total_dirents, cycle );
210#endif
211
[613]212 // compute required vseg size for a 64 bytes dirent
213 vseg_size = total_dirents << 6;
214
215 // create an ANON vseg and register it in reference process VSL
216 if( local_cxy == ref_cxy )
217 {
[614]218 vseg = vmm_create_vseg( ref_ptr,
[613]219 VSEG_TYPE_ANON,
220 0, // vseg base (unused)
221 vseg_size,
222 0, // file offset (unused)
223 0, // file_size (unused)
224 XPTR_NULL, // mapper (unused)
[614]225 local_cxy );
[613]226 }
227 else
228 {
229 rpc_vmm_create_vseg_client( ref_cxy,
230 ref_ptr,
231 VSEG_TYPE_ANON,
232 0, // vseg base (unused)
233 vseg_size,
234 0, // file offset (unused)
235 0, // file size (unused)
236 XPTR_NULL, // mapper (unused)
[614]237 local_cxy,
[613]238 &vseg );
239 }
[614]240
[613]241 if( vseg == NULL )
242 {
[614]243 printk("\n[ERROR] in %s : cannot create vseg for user_dir in cluster %x\n",
[613]244 __FUNCTION__, ref_cxy);
245 goto user_dir_create_failure;
246 }
247
[614]248#if DEBUG_USER_DIR
[613]249if( cycle > DEBUG_USER_DIR )
250printk("\n[%s] thread[%x,%x] allocated vseg ANON / base %x / size %x\n",
[614]251__FUNCTION__, this->process->pid, this->trdid, vseg->min, vseg->max - vseg->min );
[613]252#endif
253
254// check vseg size
255assert( (total_pages == hal_remote_l32( XPTR( ref_cxy , &vseg->vpn_size ) ) ),
256"unconsistent vseg size for dirent array" );
257
258 // build extended pointer on reference process GPT, PTE attributes and ppn
259 gpt_xp = XPTR( ref_cxy , &ref_ptr->vmm.gpt );
260 gpt_attributes = GPT_MAPPED |
261 GPT_SMALL |
262 GPT_READABLE |
263 GPT_CACHABLE |
264 GPT_USER ;
265
266 // get first vpn from vseg descriptor
267 vpn = hal_remote_l32( XPTR( ref_cxy , &vseg->vpn_base ) );
268
269 // scan the list of allocated physical pages to map
270 // all physical pages in the in the reference process GPT
271 page_id = 0;
272 while( list_is_empty( &root ) == false )
273 {
274 // get pointer on first page descriptor
275 page = LIST_FIRST( &root , page_t , list );
276
277 // compute ppn
278 ppn = ppm_page2ppn( XPTR( local_cxy , page ) );
279
280 error = hal_gpt_set_pte( gpt_xp,
281 vpn + page_id,
282 gpt_attributes,
283 ppn );
284 if( error )
285 {
286 printk("\n[ERROR] in %s : cannot map vpn %x in GPT\n",
287 __FUNCTION__, (vpn + page_id) );
[619]288
289 // delete the vseg
290 if( ref_cxy == local_cxy) vmm_delete_vseg( ref_pid, vpn<<CONFIG_PPM_PAGE_SHIFT );
291 else rpc_vmm_delete_vseg_client( ref_cxy, ref_pid, vpn<<CONFIG_PPM_PAGE_SHIFT );
292
[613]293 // release the user_dir descriptor
294 req.type = KMEM_DIR;
295 req.ptr = dir;
296 kmem_free( &req );
297 return NULL;
298 }
299
[614]300#if DEBUG_USER_DIR
[613]301if( cycle > DEBUG_USER_DIR )
302printk("\n[%s] thread[%x,%x] mapped vpn %x to ppn %x\n",
[614]303__FUNCTION__, this->process->pid, this->trdid, vpn + page_id, ppn );
[613]304#endif
305
306 // remove the page from temporary list
307 list_unlink( &page->list );
308
309 page_id++;
310
311 } // end map loop
312
313// check number of pages
314assert( (page_id == total_pages) , "unconsistent pages number\n" );
315
316 // initialise user_dir_t structure
317 dir->current = 0;
318 dir->entries = total_dirents;
319 dir->ident = (intptr_t)(vpn << CONFIG_PPM_PAGE_SHIFT);
320
321 // build extended pointers on root and lock of user_dir xlist in ref process
322 xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->dir_root );
323 xptr_t lock_xp = XPTR( ref_cxy , &ref_ptr->dir_lock );
324
325 // build extended pointer on list field in user_dir structure
326 xptr_t entry_xp = XPTR( local_cxy , &dir->list );
327
328 // get lock protecting open directories list
329 remote_queuelock_acquire( lock_xp );
330
331 // register user_dir_t in reference process
332 xlist_add_first( root_xp , entry_xp );
333
334 // release lock protecting open directorie list
335 remote_queuelock_release( lock_xp );
336
337#if DEBUG_USER_DIR
338cycle = (uint32_t)hal_get_cycles();
339if( cycle > DEBUG_USER_DIR )
340printk("\n[%s] thread[%x,%x] created user_dir (%x,%x) / %d entries / cycle %d\n",
[614]341__FUNCTION__, this->process->pid, this->trdid, local_cxy, dir, total_dirents, cycle );
[613]342#endif
343
344 return dir;
345
346user_dir_create_failure:
347
348 // release local user_dir_t structure
349 req.type = KMEM_DIR;
350 req.ptr = dir;
351 kmem_free( &req );
352
353 // release local physical pages
354 while( list_is_empty( &root ) == false )
355 {
356 page = LIST_FIRST( &root , page_t , list );
357 req.type = KMEM_PAGE;
358 req.ptr = page;
359 kmem_free( &req );
360 }
361
362 return NULL;
363
364} // end user_dir_create()
365
[614]366////////////////////////////////////////
367void user_dir_destroy( user_dir_t * dir,
368 xptr_t ref_xp )
[613]369{
[614]370 thread_t * this; // local pointer on calling thread
371 process_t * process; // local pointer on calling process
[613]372 cluster_t * cluster; // local pointer on local cluster
373 intptr_t ident; // user pointer on dirent array
[614]374 xptr_t ref_pid; // reference process PID
[613]375 cxy_t ref_cxy; // reference process cluster identifier
376 process_t * ref_ptr; // local pointer on reference process
377 xptr_t root_xp; // root of xlist
378 xptr_t lock_xp; // extended pointer on lock protecting xlist
379 xptr_t iter_xp; // iteratot in xlist
380 reg_t save_sr; // for critical section
381 cxy_t owner_cxy; // owner process cluster
382 lpid_t lpid; // process local index
383 rpc_desc_t rpc; // rpc descriptor
[619]384 uint32_t responses; // response counter
[613]385
[614]386 // get pointers on calling process & thread
[613]387 this = CURRENT_THREAD;
388 process = this->process;
389 cluster = LOCAL_CLUSTER;
390
[614]391 // get cluster, local pointer, and PID of reference user process
392 ref_cxy = GET_CXY( ref_xp );
393 ref_ptr = GET_PTR( ref_xp );
394 ref_pid = hal_remote_l32( XPTR( ref_cxy , &ref_ptr->pid ) );
395
[613]396#if DEBUG_USER_DIR
397uint32_t cycle = (uint32_t)hal_get_cycles();
398if( cycle > DEBUG_USER_DIR )
[614]399printk("\n[%s] thread[%x,%x] enter for user_dir (%x,%x) and process %x / cycle %d\n",
400__FUNCTION__, process->pid, this->trdid, local_cxy, dir, ref_pid, cycle );
[613]401#endif
402
403 // get user pointer on dirent array
404 ident = dir->ident;
405
406 // build extended pointer on lock protecting open directories list
407 lock_xp = XPTR( ref_cxy , &ref_ptr->dir_lock );
408
409 // get lock protecting open directories list
410 remote_queuelock_acquire( lock_xp );
411
412 // remove dir from reference process xlist
413 xlist_unlink( XPTR( local_cxy , &dir->list ) );
414
415 // release lock protecting open directories list
416 remote_queuelock_release( lock_xp );
417
418 // To delete all copies of the vseg containing the dirent array, the client thread
419 // send parallel RPCs to all clusters containing a client process copy (including
420 // the local cluster). It blocks and deschedules when all RPCs have been sent,
421 // to wait all RPC responses, and will be unblocked by the last RPC server thread.
422 // It allocates a - shared - RPC descriptor in the stack, because all parallel
423 // server threads use the same input arguments, and the same response field.
424
425 // get owner cluster identifier and process lpid
[614]426 owner_cxy = CXY_FROM_PID( ref_pid );
427 lpid = LPID_FROM_PID( ref_pid );
[613]428
429 // get root of list of copies and lock from owner cluster
430 root_xp = XPTR( owner_cxy , &cluster->pmgr.copies_root[lpid] );
431 lock_xp = XPTR( owner_cxy , &cluster->pmgr.copies_lock[lpid] );
432
433 // mask IRQs
434 hal_disable_irq( &save_sr);
435
436 // client thread blocks itself
437 thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_RPC );
438
[619]439 // initialize responses counter
440 responses = 0;
441
442 // initialize a shared RPC descriptor
443 // can be shared, because no out arguments
444 rpc.rsp = &responses;
[613]445 rpc.blocking = false;
446 rpc.index = RPC_VMM_DELETE_VSEG;
447 rpc.thread = this;
448 rpc.lid = this->core->lid;
[614]449 rpc.args[0] = ref_pid;
[613]450 rpc.args[1] = ident;
451
452 // take the lock protecting process copies
453 remote_queuelock_acquire( lock_xp );
454
455 // scan list of process copies
456 XLIST_FOREACH( root_xp , iter_xp )
457 {
458 // get extended pointer and cluster of process
459 xptr_t process_xp = XLIST_ELEMENT( iter_xp , process_t , copies_list );
460 cxy_t process_cxy = GET_CXY( process_xp );
461
462 // atomically increment responses counter
[619]463 hal_atomic_add( &responses , 1 );
[613]464
[619]465 // send RPC to target cluster
466 rpc_send( process_cxy , &rpc );
467 }
[613]468
469 // release the lock protecting process copies
470 remote_queuelock_release( lock_xp );
471
472 // client thread deschedule
[619]473 sched_yield("blocked on rpc_vmm_delete_vseg");
[613]474
475 // restore IRQs
476 hal_restore_irq( save_sr);
477
478 // release local user_dir_t structure
479 kmem_req_t req;
480 req.type = KMEM_DIR;
481 req.ptr = dir;
482 kmem_free( &req );
483
484#if DEBUG_USER_DIR
485cycle = (uint32_t)hal_get_cycles();
486if( cycle > DEBUG_USER_DIR )
487printk("\n[%s] thread[%x,%x] deleted user_dir (%x,%x) / cycle %d\n",
488__FUNCTION__, process->pid, this->trdid, local_cxy, dir, cycle );
489#endif
490
491} // end user_dir_destroy()
Note: See TracBrowser for help on using the repository browser.