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

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