source: trunk/kernel/syscalls/sys_readdir.c @ 625

Last change on this file since 625 was 625, checked in by alain, 6 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

File size: 4.2 KB
Line 
1/*
2 * sys_readdir.c - Copy one entry from an open VFS directory to an user buffer.
3 *
4 * Author    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_uspace.h>
27#include <hal_vmm.h>
28#include <errno.h>
29#include <thread.h>
30#include <printk.h>
31#include <vfs.h>
32#include <process.h>
33#include <user_dir.h>
34#include <syscalls.h>
35#include <shared_syscalls.h>
36
37///////////////////////////////////////
38int sys_readdir( DIR            * dirp,
39                 struct dirent ** buffer )
40{
41    error_t         error;
42    vseg_t        * vseg;               // for user space checking of buffer
43    xptr_t          dir_xp;             // extended pointer on user_dir structure
44    user_dir_t    * dir_ptr;            // local pointer on user_dir structure
45    cxy_t           dir_cxy;            // user_dir stucture cluster identifier
46    struct dirent * direntp;            // dirent pointer in user space 
47    uint32_t        entries;            // total number of dirent entries
48    uint32_t        current;            // current dirent index
49
50        thread_t  * this    = CURRENT_THREAD;  // client thread
51        process_t * process = this->process;   // client process
52
53#if (DEBUG_SYS_READDIR || CONFIG_INSTRUMENTATION_SYSCALLS)
54uint64_t     tm_start = hal_get_cycles();
55#endif
56
57#if DEBUG_SYS_READDIR
58if( DEBUG_SYS_READDIR < tm_start )
59printk("\n[%s] thread[%x,%x] enter / dirp %x / cycle %d\n",
60__FUNCTION__, process->pid, this->trdid, dirp, (uint32_t)tm_start );
61#endif
62 
63    // check buffer in user space
64    error = vmm_get_vseg( process , (intptr_t)buffer, &vseg );
65
66        if( error )
67        {
68
69#if DEBUG_SYSCALLS_ERROR
70printk("\n[ERROR] in %s / thread[%x,%x] : user buffer %x unmapped\n",
71__FUNCTION__ , process->pid , this->trdid, buffer );
72hal_vmm_display( process , false );
73#endif
74                this->errno = EINVAL;
75                return -1;
76        }       
77
78    // get pointers on user_dir structure from dirp
79    dir_xp  = user_dir_from_ident( (intptr_t)dirp );
80    dir_ptr = GET_PTR( dir_xp );
81    dir_cxy = GET_CXY( dir_xp );
82
83    if( dir_xp == XPTR_NULL )
84        {
85
86#if DEBUG_SYSCALLS_ERROR
87printk("\n[ERROR] in %s / thread[%x,%x] : dirp %x not registered\n",
88__FUNCTION__ , process->pid , this->trdid, dirp );
89#endif
90                this->errno = EBADF;
91                return -1;
92        }       
93
94    // get "current" and "entries_nr" values from user_dir_t structure
95    current = hal_remote_l32( XPTR( dir_cxy , &dir_ptr->current ) );
96    entries = hal_remote_l32( XPTR( dir_cxy , &dir_ptr->entries ) );
97
98    // check "current" index
99    if( current >= entries )
100    {
101        this->errno = 0;
102        return -1;
103    }
104
105    // compute dirent pointer in user space
106    direntp = (struct dirent *)dirp + current;
107
108#if (DEBUG_SYS_READDIR & 1)
109if( DEBUG_SYS_READDIR < tm_start )
110printk("\n[%s] entries = %d / current = %d / direntp = %x\n",
111__FUNCTION__, entries, current, direntp );
112#endif
113
114    // copy dirent pointer to user buffer
115    hal_copy_to_uspace( buffer, &direntp , sizeof(void *) );
116
117    // update current index in user_dir structure
118    hal_remote_atomic_add( XPTR( dir_cxy , &dir_ptr->current ) , 1 );
119
120    hal_fence();
121
122#if (DEBUG_SYS_READDIR || CONFIG_INSTRUMENTATION_SYSCALLS)
123uint64_t     tm_end = hal_get_cycles();
124#endif
125
126#if DEBUG_SYS_READDIR
127if( DEBUG_SYS_READDIR < tm_end )
128printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
129__FUNCTION__, process->pid, this->trdid, (uint32_t)tm_end );
130#endif
131 
132#if CONFIG_INSTRUMENTATION_SYSCALLS
133hal_atomic_add( &syscalls_cumul_cost[SYS_READDIR] , tm_end - tm_start );
134hal_atomic_add( &syscalls_occurences[SYS_READDIR] , 1 );
135#endif
136
137        return 0;
138
139}  // end sys_readdir()
Note: See TracBrowser for help on using the repository browser.