source: trunk/kernel/syscalls/sys_opendir.c @ 624

Last change on this file since 624 was 624, checked in by alain, 5 years ago

Fix several bugs to use the instruction MMU in kernel mode
in replacement of the instruction address extension register,
and remove the "kentry" segment.

This version is running on the tsar_generic_iob" platform.

One interesting bug: the cp0_ebase defining the kernel entry point
(for interrupts, exceptions and syscalls) must be initialized
early in kernel_init(), because the VFS initialisation done by
kernel_ini() uses RPCs, and RPCs uses Inter-Processor-Interrup.

File size: 6.1 KB
Line 
1/*
2 * sys_opendir.c - Open an user accessible VFS directory.
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 <thread.h>
28#include <process.h>
29#include <user_dir.h>
30#include <printk.h>
31#include <errno.h>
32#include <vseg.h>
33#include <vfs.h>
34#include <syscalls.h>
35#include <shared_syscalls.h>
36
37///////////////////////////////////
38int sys_opendir ( char *  pathname,
39                  DIR  ** dirp )
40{
41    error_t        error;
42    xptr_t         root_inode_xp;          // extended pointer on path root inode
43    xptr_t         inode_xp;               // extended pointer on directory inode
44    vfs_inode_t  * inode_ptr;              // local pointer on directory inode
45    cxy_t          inode_cxy;              // directory inode cluster
46    uint32_t       inode_type;             // to check directory inode type
47    user_dir_t   * dir_ptr;                // local pointer on user_dir_t
48    vseg_t       * vseg;                   // for user space checking
49    intptr_t       ident;                  // dirent array pointer in user space                 
50    char          kbuf[CONFIG_VFS_MAX_PATH_LENGTH];
51       
52        thread_t     * this    = CURRENT_THREAD;  // client thread
53        process_t    * process = this->process;   // client process
54
55#if (DEBUG_SYS_OPENDIR || CONFIG_INSTRUMENTATION_SYSCALLS)
56uint64_t     tm_start = hal_get_cycles();
57#endif
58
59    // check DIR buffer in user space
60    error = vmm_get_vseg( process , (intptr_t)dirp, &vseg );
61
62        if( error )
63        {
64
65#if DEBUG_SYSCALLS_ERROR
66printk("\n[ERROR] in %s / thread[%x,%x] : DIR buffer %x unmapped\n",
67__FUNCTION__ , process->pid , this->trdid, dirp );
68hal_vmm_display( process , false );
69#endif
70                this->errno = EINVAL;
71                return -1;
72        }       
73
74    // check pathname length
75    if( hal_strlen_from_uspace( pathname ) >= CONFIG_VFS_MAX_PATH_LENGTH )
76    {
77
78#if DEBUG_SYSCALLS_ERROR
79printk("\n[ERROR] in %s / thread[%x,%x] : pathname too long\n",
80 __FUNCTION__ , process->pid , this->trdid );
81#endif
82        this->errno = ENFILE;
83        return -1;
84    }
85
86    // copy pathname in kernel space
87    hal_strcpy_from_uspace( kbuf , pathname , CONFIG_VFS_MAX_PATH_LENGTH );
88
89#if DEBUG_SYS_OPENDIR
90if( DEBUG_SYS_OPENDIR < tm_start )
91printk("\n[%s] thread[%x,%x] enter for directory <%s> / cycle %d\n",
92__FUNCTION__, process->pid, this->trdid, kbuf, (uint32_t)tm_start );
93#endif
94
95    // compute root inode for pathname
96    if( kbuf[0] == '/' )                        // absolute path
97    {
98        // use extended pointer on VFS root inode
99        root_inode_xp = process->vfs_root_xp;
100    }
101    else                                        // relative path
102    {
103        // get cluster and local pointer on reference process
104        xptr_t      ref_xp  = process->ref_xp;
105        process_t * ref_ptr = (process_t *)GET_PTR( ref_xp );
106        cxy_t       ref_cxy = GET_CXY( ref_xp );
107
108        // use extended pointer on CWD inode
109        root_inode_xp = hal_remote_l64( XPTR( ref_cxy , &ref_ptr->cwd_xp ) );
110    }
111
112    // get extended pointer on directory inode
113    error = vfs_lookup( root_inode_xp,
114                        kbuf,
115                        0,
116                        &inode_xp,
117                        NULL );
118    if( error )
119        {
120
121#if DEBUG_SYSCALLS_ERROR
122printk("\n[ERROR] in %s / thread[%x,%x] : cannot found directory <%s>\n",
123__FUNCTION__ , process->pid , this->trdid , kbuf );
124#endif
125                this->errno = ENFILE;
126                return -1;
127        }
128   
129    // check inode type
130    inode_ptr  = GET_PTR( inode_xp );
131    inode_cxy  = GET_CXY( inode_xp );
132    inode_type = hal_remote_l32( XPTR( inode_cxy , &inode_ptr->type ) );
133
134    if( inode_type != INODE_TYPE_DIR )
135        {
136
137#if DEBUG_SYSCALLS_ERROR
138printk("\n[ERROR] in %s / thread[%x,%x] : cannot found directory <%s>\n",
139__FUNCTION__ , process->pid , this->trdid , kbuf );
140#endif
141                this->errno = ENFILE;
142                return -1;
143        }
144   
145    // create a new user_dir_t structure in target directory inode cluster
146    // map it in the reference user process VMM (in a new ANON vseg)
147    // an get the local pointer on the created user_dir_t structure
148    if( inode_cxy == local_cxy )
149    {
150        dir_ptr = user_dir_create( inode_ptr,
151                                   process->ref_xp );
152    }
153    else
154    {
155        rpc_user_dir_create_client( inode_cxy,
156                                    inode_ptr,
157                                    process->ref_xp,
158                                    &dir_ptr );
159    }
160
161    if( dir_ptr == NULL )
162        {
163
164#if DEBUG_SYSCALLS_ERROR
165printk("\n[ERROR] in %s / thread[%x,%x] : cannot create user_dir for <%s>\n",
166__FUNCTION__ , process->pid , this->trdid , kbuf );
167#endif
168                this->errno = ENFILE;
169                return -1;
170        }
171   
172    // get ident from user_dir structure
173    ident = (intptr_t)hal_remote_lpt( XPTR( inode_cxy , &dir_ptr->ident ) );
174
175    // set ident value in user buffer
176    hal_copy_to_uspace( dirp , &ident , sizeof(intptr_t) );
177
178    hal_fence();
179
180#if (DEBUG_SYS_OPENDIR || CONFIG_INSTRUMENTATION_SYSCALLS)
181uint64_t     tm_end = hal_get_cycles();
182#endif
183
184#if DEBUG_SYS_OPENDIR
185if( DEBUG_SYS_OPENDIR < tm_end )
186printk("\n[%s] thread[%x,%x] exit for directory <%s> / cycle %d\n",
187__FUNCTION__, process->pid, this->trdid, kbuf, (uint32_t)tm_end );
188#endif
189 
190#if CONFIG_INSTRUMENTATION_SYSCALLS
191hal_atomic_add( &syscalls_cumul_cost[SYS_OPENDIR] , tm_end - tm_start );
192hal_atomic_add( &syscalls_occurences[SYS_OPENDIR] , 1 );
193#endif
194
195        return 0;
196
197}  // end sys_opendir()
Note: See TracBrowser for help on using the repository browser.