Changeset 612 for trunk


Ignore:
Timestamp:
Jan 11, 2019, 6:35:07 PM (3 years ago)
Author:
alain
Message:

Fix several bugs in vfs.c, fatfs.c, and devfs.c to support
the <.> and <..> directory entries.

Location:
trunk
Files:
22 edited

Legend:

Unmodified
Added
Removed
  • trunk/kernel/Makefile

    r611 r612  
    122122              build/libk/remote_fifo.o      \
    123123              build/libk/remote_mutex.o     \
    124               build/libk/remote_dir.o       \
    125124              build/libk/remote_sem.o       \
    126125              build/libk/remote_condvar.o   \
     
    128127              build/libk/memcpy.o           \
    129128              build/libk/htab.o             \
    130               build/libk/xhtab.o
     129              build/libk/xhtab.o            \
     130              build/libk/user_dir.o
    131131
    132132SYS_OBJS_0  = build/syscalls/sys_thread_exit.o     \
  • trunk/kernel/fs/devfs.c

    r610 r612  
    2727#include <hal_uspace.h>
    2828#include <printk.h>
     29#include <string.h>
    2930#include <chdev.h>
    3031#include <thread.h>
     
    102103                                     devfs_dev_inode_xp );
    103104
     105    // create dentries <.> and <..> in <dev>
     106    error |= vfs_add_special_dentries( *devfs_dev_inode_xp,
     107                                       root_inode_xp );
     108
    104109// check success
    105110assert( (error == 0) , "cannot create <dev>\n" );
     
    122127                                     devfs_external_inode_xp );
    123128
    124     assert( (error == 0) , "cannot create <external>\n" );
     129    // create dentries <.> and <..> in <external>
     130    error |= vfs_add_special_dentries( *devfs_external_inode_xp,
     131                                       *devfs_dev_inode_xp );
     132
     133// check success
     134assert( (error == 0) , "cannot create <external>\n" );
    125135
    126136#if DEBUG_DEVFS_INIT
     
    147157    uint32_t      channel;
    148158    xptr_t        unused_xp;    // required by add_child_in_parent()
     159    error_t       error;
    149160
    150161    // create "internal" directory
    151162    snprintf( node_name , 16 , "internal_%x" , local_cxy );
    152163
    153     vfs_add_child_in_parent( local_cxy,
    154                              INODE_TYPE_DIR,
    155                              FS_TYPE_DEVFS,
    156                              devfs_dev_inode_xp,
    157                              node_name,
    158                              &unused_xp,
    159                              devfs_internal_inode_xp );
     164    error = vfs_add_child_in_parent( local_cxy,
     165                                     INODE_TYPE_DIR,
     166                                     FS_TYPE_DEVFS,
     167                                     devfs_dev_inode_xp,
     168                                     node_name,
     169                                     &unused_xp,
     170                                     devfs_internal_inode_xp );
     171
     172    // create dentries <.> and <..> in <internal>
     173    error |= vfs_add_special_dentries( *devfs_internal_inode_xp,
     174                                       devfs_dev_inode_xp );
     175
     176// check success
     177assert( (error == 0) , "cannot create <external>\n" );
     178
    160179#if DEBUG_DEVFS_INIT
    161180uint32_t   cycle = (uint32_t)hal_get_cycles();
     
    173192        chdev_cxy = GET_CXY( chdev_xp );
    174193
    175 assert( (chdev_cxy == local_cxy ),
    176 "illegal MMC chdev_xp in cluster %x\n", local_cxy );
    177 
    178         vfs_add_child_in_parent( local_cxy,
    179                                  INODE_TYPE_DEV,
    180                                  FS_TYPE_DEVFS,
    181                                  *devfs_internal_inode_xp,
    182                                  chdev_ptr->name,
    183                                  &unused_xp,
    184                                  &inode_xp );
     194assert( (chdev_cxy == local_cxy ), "illegal MMC chdev in cluster %x\n", local_cxy );
     195
     196        error = vfs_add_child_in_parent( local_cxy,
     197                                         INODE_TYPE_DEV,
     198                                         FS_TYPE_DEVFS,
     199                                         *devfs_internal_inode_xp,
     200                                         chdev_ptr->name,
     201                                         &unused_xp,
     202                                         &inode_xp );
     203
     204assert( (error == 0) , "cannot create MMC inode\n" );
    185205
    186206        // update child inode "extend" field
     
    207227            chdev_cxy = GET_CXY( chdev_xp );
    208228
    209 assert( (chdev_cxy == local_cxy ),
    210 "illegal DMA[%d] chdev_xp in cluster %x\n", channel, local_cxy );
    211 
    212             vfs_add_child_in_parent( local_cxy,
    213                                      INODE_TYPE_DEV,
    214                                      FS_TYPE_DEVFS,
    215                                      *devfs_internal_inode_xp,
    216                                      chdev_ptr->name,
    217                                      &unused_xp,
    218                                      &inode_xp );
     229assert( (chdev_cxy == local_cxy ), "illegal DMA chdev in cluster %x\n", local_cxy );
     230
     231            error = vfs_add_child_in_parent( local_cxy,
     232                                             INODE_TYPE_DEV,
     233                                             FS_TYPE_DEVFS,
     234                                             *devfs_internal_inode_xp,
     235                                             chdev_ptr->name,
     236                                             &unused_xp,
     237                                             &inode_xp );
     238
     239assert( (error == 0) , "cannot create DMA inode\n" );
    219240
    220241            // update child inode "extend" field
     
    241262        if( chdev_cxy == local_cxy )
    242263        {
    243             vfs_add_child_in_parent( local_cxy,
    244                                      INODE_TYPE_DEV,
    245                                      FS_TYPE_DEVFS,
    246                                      devfs_external_inode_xp,
    247                                      chdev_ptr->name,
    248                                      &unused_xp,
    249                                      &inode_xp );
     264            error = vfs_add_child_in_parent( local_cxy,
     265                                             INODE_TYPE_DEV,
     266                                             FS_TYPE_DEVFS,
     267                                             devfs_external_inode_xp,
     268                                             chdev_ptr->name,
     269                                             &unused_xp,
     270                                             &inode_xp );
     271
     272assert( (error == 0) , "cannot create IOB inode\n" );
    250273
    251274            // update child inode "extend" field
     
    272295        if( chdev_cxy == local_cxy )
    273296        {
    274             vfs_add_child_in_parent( local_cxy,
    275                                      INODE_TYPE_DEV,
    276                                      FS_TYPE_DEVFS,
    277                                      devfs_external_inode_xp,
    278                                      chdev_ptr->name,
    279                                      &unused_xp,
    280                                      &inode_xp );
     297            error = vfs_add_child_in_parent( local_cxy,
     298                                             INODE_TYPE_DEV,
     299                                             FS_TYPE_DEVFS,
     300                                             devfs_external_inode_xp,
     301                                             chdev_ptr->name,
     302                                             &unused_xp,
     303                                             &inode_xp );
     304
     305assert( (error == 0) , "cannot create PIC inode\n" );
    281306
    282307            // update child inode "extend" field
     
    305330            if( chdev_cxy == local_cxy )
    306331            {
    307                 vfs_add_child_in_parent( local_cxy,
    308                                          INODE_TYPE_DEV,
    309                                          FS_TYPE_DEVFS,
    310                                          devfs_external_inode_xp,
    311                                          chdev_ptr->name,
    312                                          &unused_xp,
    313                                          &inode_xp );
     332                error = vfs_add_child_in_parent( local_cxy,
     333                                                 INODE_TYPE_DEV,
     334                                                 FS_TYPE_DEVFS,
     335                                                 devfs_external_inode_xp,
     336                                                 chdev_ptr->name,
     337                                                 &unused_xp,
     338                                                 &inode_xp );
     339
     340assert( (error == 0) , "cannot create TXT_RX inode\n" );
    314341
    315342                // update child inode "extend" field
     
    339366            if( chdev_cxy == local_cxy )
    340367            {
    341                 vfs_add_child_in_parent( local_cxy,
    342                                          INODE_TYPE_DEV,
    343                                          FS_TYPE_DEVFS,
    344                                          devfs_external_inode_xp,
    345                                          chdev_ptr->name,
    346                                          &unused_xp,
    347                                          &inode_xp );
     368                error = vfs_add_child_in_parent( local_cxy,
     369                                                 INODE_TYPE_DEV,
     370                                                 FS_TYPE_DEVFS,
     371                                                 devfs_external_inode_xp,
     372                                                 chdev_ptr->name,
     373                                                 &unused_xp,
     374                                                 &inode_xp );
     375
     376assert( (error == 0) , "cannot create TXT_TX inode\n" );
    348377
    349378                // update child inode "extend" field
     
    373402            if( chdev_cxy == local_cxy )
    374403            {
    375                 vfs_add_child_in_parent( local_cxy,
    376                                          INODE_TYPE_DEV,
    377                                          FS_TYPE_DEVFS,
    378                                          devfs_external_inode_xp,
    379                                          chdev_ptr->name,
    380                                          &unused_xp,
    381                                          &inode_xp );
     404                error = vfs_add_child_in_parent( local_cxy,
     405                                                 INODE_TYPE_DEV,
     406                                                 FS_TYPE_DEVFS,
     407                                                 devfs_external_inode_xp,
     408                                                 chdev_ptr->name,
     409                                                 &unused_xp,
     410                                                 &inode_xp );
     411
     412assert( (error == 0) , "cannot create IOC inode\n" );
    382413
    383414                // update child inode "extend" field
     
    407438            if( chdev_cxy == local_cxy )
    408439            {
    409                 vfs_add_child_in_parent( local_cxy,
    410                                          INODE_TYPE_DEV,
    411                                          FS_TYPE_DEVFS,
    412                                          devfs_external_inode_xp,
    413                                          chdev_ptr->name,
    414                                          &unused_xp,
    415                                          &inode_xp );
     440                error = vfs_add_child_in_parent( local_cxy,
     441                                                 INODE_TYPE_DEV,
     442                                                 FS_TYPE_DEVFS,
     443                                                 devfs_external_inode_xp,
     444                                                 chdev_ptr->name,
     445                                                 &unused_xp,
     446                                                 &inode_xp );
     447
     448assert( (error == 0) , "cannot create FBF inode\n" );
    416449
    417450                // update child inode "extend" field
     
    441474            if( chdev_cxy == local_cxy )
    442475            {
    443                 vfs_add_child_in_parent( local_cxy,
    444                                          INODE_TYPE_DEV,
    445                                          FS_TYPE_DEVFS,
    446                                          devfs_external_inode_xp,
    447                                          chdev_ptr->name,
    448                                          &unused_xp,
    449                                          &inode_xp );
     476                error = vfs_add_child_in_parent( local_cxy,
     477                                                 INODE_TYPE_DEV,
     478                                                 FS_TYPE_DEVFS,
     479                                                 devfs_external_inode_xp,
     480                                                 chdev_ptr->name,
     481                                                 &unused_xp,
     482                                                 &inode_xp );
     483
     484assert( (error == 0) , "cannot create NIC_RX inode\n" );
     485
     486                // update child inode "extend" field
     487                inode_cxy = GET_CXY( inode_xp );
     488                inode_ptr = GET_PTR( inode_xp );
     489                hal_remote_spt( XPTR( inode_cxy , &inode_ptr->extend ) , chdev_ptr );
     490 
    450491#if DEBUG_DEVFS_INIT
    451492cycle = (uint32_t)hal_get_cycles();
     
    469510            if( chdev_cxy == local_cxy )
    470511            {
    471                 vfs_add_child_in_parent( local_cxy,
    472                                          INODE_TYPE_DEV,
    473                                          FS_TYPE_DEVFS,
    474                                          devfs_external_inode_xp,
    475                                          chdev_ptr->name,
    476                                          &unused_xp,
    477                                          &inode_xp );
     512                error = vfs_add_child_in_parent( local_cxy,
     513                                                 INODE_TYPE_DEV,
     514                                                 FS_TYPE_DEVFS,
     515                                                 devfs_external_inode_xp,
     516                                                 chdev_ptr->name,
     517                                                 &unused_xp,
     518                                                 &inode_xp );
     519
     520assert( (error == 0) , "cannot create NIC_TX inode\n" );
    478521
    479522                // update child inode "extend" field
     
    620663}  // end devfs_user_move()
    621664
    622 
     665///////////////////////////////////////////////////////
     666error_t devfs_get_user_dir( struct vfs_inode_s * inode,
     667                            struct dirent      * array,
     668                            uint32_t             max_dirent,
     669                            uint32_t             min_dentry,
     670                            bool_t               detailed,
     671                            uint32_t           * entries,
     672                            bool_t             * done )
     673{
     674    xptr_t         xhtab_xp;    // extended pointer on inode xhtab (children dentries)
     675    xptr_t         dentry_xp;   // extended pointer on current dentry
     676    vfs_dentry_t * dentry_ptr;  // local pointer on current dentry
     677    uint32_t       dentry_id;   // dentry index in set of children dentry   
     678    uint32_t       dirent_id;   // dirent index in array of dirent
     679
     680// detailed argument unused
     681assert( (detailed == false) , "detailed argument not supported\n");
     682 
     683    // One loop to scan the target inode xhtab containing the set of dentries
     684    // exit loop if no more dentries, or dirent array full
     685
     686#if DEBUG_DEVFS_GET_USER_DIR
     687char       inode_name[CONFIG_VFS_MAX_NAME_LENGTH];
     688uint32_t   cycle = (uint32_t)hal_get_cycles();
     689thread_t * this  = CURRENT_THREAD;
     690vfs_inode_get_name( XPTR( local_cxy , inode ) , inode_name );
     691if( DEBUG_DEVFS_GET_USER_DIR < cycle )
     692printk("\n[%s]  thread[%x,%x] enter for inode <%s> / cycle %d\n",
     693__FUNCTION__, this->process->pid, this->trdid, inode_name , cycle );
     694#endif
     695
     696    // get extended pointer on inode xhtab
     697    xhtab_xp  = XPTR( local_cxy , &inode->children );
     698
     699    // initialize loop variables
     700    dentry_xp = xhtab_get_first( xhtab_xp );
     701    dentry_id = 0;
     702    dirent_id = 0;
     703
     704    while( (dentry_xp != XPTR_NULL ) && (dirent_id < max_dirent) )
     705    {
     706        if( dentry_id >= min_dentry )
     707        {
     708            // copy name into dirent array
     709            dentry_ptr = GET_PTR( dentry_xp );
     710            strcpy( array[dirent_id].d_name , dentry_ptr->name );
     711
     712            // increment dirent_id
     713            dirent_id++;
     714        }
     715         
     716        // update loop variables
     717        dentry_xp = xhtab_get_next( xhtab_xp );
     718        dentry_id++;
     719    }
     720
     721    // return results of scan
     722    *done    = (dentry_xp == XPTR_NULL);
     723    *entries = dirent_id;
     724
     725#if DEBUG_DEVFS_GET_USER_DIR
     726cycle = (uint32_t)hal_get_cycles();
     727if( DEBUG_DEVFS_GET_USER_DIR < cycle )
     728printk("\n[%s]  thread[%x,%x] exit for inode <%s> / %d entries / cycle %d\n",
     729__FUNCTION__, this->process->pid, this->trdid, inode_name, entries, cycle );
     730#endif
     731
     732    return 0;
     733   
     734}  // en devfs_get_user_dir()
     735
  • trunk/kernel/fs/devfs.h

    r598 r612  
    137137                     uint32_t size );
    138138
     139/******************************************************************************************
     140 * As the DEVFS is dynamically build in memory during kernel init, all relevant
     141 * information is contained in the Inode Tree. Therefore, this function simply
     142 * access the xhtab contained in the <inode> descriptor, to get the  dentries
     143 * to be copied in the dirent <array>.
     144 ******************************************************************************************
     145 * @ inode      : [in]  local pointer on directory inode.
     146 * @ array      : [in]  local pointer on array of dirents.
     147 * @ max_dirent : [in]  max number of slots in dirent array.
     148 * @ min_dentry : [in]  index of first dentry to be copied into array.
     149 * @ detailed   : [in]  dynamic inode creation if true.
     150 * @ entries    : [out] number of dentries actually copied into array.
     151 * @ done       : [out] Boolean true when last entry found.
     152 * @ return 0 if success / return -1 if failure.
     153 *****************************************************************************************/
     154error_t devfs_get_user_dir( struct vfs_inode_s * inode,
     155                            struct dirent      * array,
     156                            uint32_t             max_dirent,
     157                            uint32_t             min_dentry,
     158                            bool_t               detailed,
     159                            uint32_t           * entries,
     160                            bool_t             * done );
     161
    139162
    140163#endif  /* _DEVFS_H_ */
  • trunk/kernel/fs/fatfs.c

    r611 r612  
    13591359}  // end fatfs_remove_dentry
    13601360
    1361 ////////////////////////////////////////////////////////////////
    1362 error_t fatfs_child_init( vfs_inode_t * parent_inode,
     1361/////////////////////////////////////////////////////
     1362error_t fatfs_get_dentry( vfs_inode_t * parent_inode,
    13631363                          char        * name,
    13641364                          xptr_t        child_inode_xp )
     
    13681368    // - scan the directory entries in each 4 Kbytes page
    13691369
    1370 #if DEBUG_FATFS_CHILD_INIT
     1370#if DEBUG_FATFS_GET_DENTRY
    13711371char       parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
    13721372uint32_t   cycle = (uint32_t)hal_get_cycles();
    13731373thread_t * this  = CURRENT_THREAD;
    13741374vfs_inode_get_name( XPTR( local_cxy , parent_inode ) , parent_name );
    1375 if( DEBUG_FATFS_CHILD_INIT < cycle )
     1375if( DEBUG_FATFS_GET_DENTRY < cycle )
    13761376printk("\n[%s]  thread[%x,%x] enter for child <%s> in parent <%s> / cycle %d\n",
    13771377__FUNCTION__, this->process->pid, this->trdid, name , parent_name , cycle );
     
    14201420        base    = (uint8_t *)GET_PTR( base_xp );
    14211421
    1422 #if (DEBUG_FATFS_CHILD_INIT & 0x1)
    1423 if( DEBUG_FATFS_CHILD_INIT < cycle )
    1424 {
    1425     uint32_t * buf = (uint32_t *)base;
    1426     uint32_t line , word;
    1427     printk("\n[%s] First 16 dentries for <%s>\n",
    1428     __FUNCTION__ , parent_name );
    1429     for( line = 0 ; line < 16 ; line++ )
    1430     {
    1431         printk("%X : ", line );
    1432         for( word = 0 ; word < 8 ; word++ ) printk("%X ", buf[(line<<4) + word] );
    1433         printk("\n");
    1434     }
    1435 }
     1422#if (DEBUG_FATFS_GET_DENTRY & 0x1)
     1423if( DEBUG_FATFS_GET_DENTRY < cycle )
     1424mapper_display_page( mapper_xp , page_id , 256 , parent_name );
    14361425#endif
    14371426        // scan this page until end of directory, end of page, or name found
     
    15061495    {
    15071496
    1508 #if DEBUG_FATFS_CHILD_INIT
     1497#if DEBUG_FATFS_GET_DENTRY
    15091498cycle = (uint32_t)hal_get_cycles();
    1510 if( DEBUG_FATFS_CHILD_INIT < cycle )
     1499if( DEBUG_FATFS_GET_DENTRY < cycle )
    15111500printk("\n[%s]  thread[%x,%x] exit / child <%s> not found / cycle %d\n",
    15121501__FUNCTION__, this->process->pid, this->trdid, name, cycle );
     
    15441533    dentry_ptr->extend = (void *)(intptr_t)dentry_id;
    15451534
    1546 #if DEBUG_FATFS_CHILD_INIT
     1535#if DEBUG_FATFS_GET_DENTRY
    15471536cycle = (uint32_t)hal_get_cycles();
    1548 if( DEBUG_FATFS_CHILD_INIT < cycle )
     1537if( DEBUG_FATFS_GET_DENTRY < cycle )
    15491538printk("\n[%s]  thread[%x,%x] exit / child <%s> loaded in <%s> / cycle %d\n",
    15501539__FUNCTION__, this->process->pid, this->trdid, name, parent_name, cycle );
     
    15531542    return 0;
    15541543
    1555 }  // end fatfs_child_init()
     1544}  // end fatfs_get_dentry()
     1545
     1546///////////////////////////////////////////////////////
     1547error_t fatfs_get_user_dir( struct vfs_inode_s * inode,
     1548                            struct dirent      * array,
     1549                            uint32_t             max_dirent,
     1550                            uint32_t             min_dentry,
     1551                            bool_t               detailed,
     1552                            uint32_t           * entries,
     1553                            bool_t             * done )
     1554{
     1555    // Two embedded loops to scan the directory mapper:
     1556    // - scan the parent directory mapper pages starting always from page 0
     1557    // - scan the 32 bytes NORMAL/LFN directory entries in each page
     1558    // Only valid dentries are copied : dentry_id >= min_dentry && dirent_id < dirent_max
     1559
     1560#if DEBUG_FATFS_GET_USER_DIR
     1561char       inode_name[CONFIG_VFS_MAX_NAME_LENGTH];
     1562uint32_t   cycle = (uint32_t)hal_get_cycles();
     1563thread_t * this  = CURRENT_THREAD;
     1564vfs_inode_get_name( XPTR( local_cxy , inode ) , inode_name );
     1565if( DEBUG_FATFS_GET_USER_DIR < cycle )
     1566printk("\n[%s]  thread[%x,%x] enter for inode <%s> / cycle %d\n",
     1567__FUNCTION__, this->process->pid, this->trdid, inode_name , cycle );
     1568#endif
     1569
     1570    mapper_t * mapper    = inode->mapper;
     1571    xptr_t     mapper_xp = XPTR( local_cxy , mapper );
     1572
     1573// check mapper pointer
     1574assert( (mapper != NULL) , "mapper is NULL\n");
     1575   
     1576// TODO handle the detailed flag
     1577assert( (detailed == false), "detailed argument not supported/n");
     1578
     1579    char       cname[CONFIG_VFS_MAX_NAME_LENGTH];  // name extracter from each directory entry
     1580
     1581    char       lfn1[16];           // buffer for one partial cname
     1582    char       lfn2[16];           // buffer for one partial cname
     1583    char       lfn3[16];           // buffer for one partial cname
     1584    xptr_t     page_xp;            // extended pointer on page descriptor
     1585    xptr_t     base_xp;            // extended pointer on page base
     1586    uint8_t  * base;               // local pointer on page base
     1587    uint32_t   attr;               // directory entry ATTR field
     1588    uint32_t   ord;                // directory entry ORD field
     1589    uint32_t   seq;                // sequence index
     1590    uint32_t   lfn       = 0;      // LFN entries number
     1591    uint32_t   offset    = 0;      // byte offset in page
     1592    uint32_t   page_id   = 0;      // page index in mapper
     1593    uint32_t   dentry_id = 0;      // valid (i.e. copied) dentry index in mapper
     1594    uint32_t   dirent_id = 0;      // slot index in dirent array to initialize
     1595    bool_t     end       = false;  // true if end of directory found
     1596
     1597    // loop on mapper pages
     1598    while ( (end == false) && (dirent_id < max_dirent) )
     1599    {
     1600        // get one page from mapper
     1601        page_xp = mapper_remote_get_page( mapper_xp , page_id );
     1602
     1603        if( page_xp == XPTR_NULL) return -1;
     1604
     1605        // get page base
     1606        base_xp = ppm_page2base( page_xp );
     1607        base    = (uint8_t *)GET_PTR( base_xp );
     1608
     1609#if (DEBUG_FATFS_GET_USER_DIR & 0x1)
     1610if( DEBUG_FATFS_GET_USER_DIR < cycle )
     1611mapper_display_page( mapper_xp , page_id , 256 , inode_name );
     1612#endif
     1613        // loop on NORMAL/LFN (32 bytes) directory entries in this page
     1614        while( (end == false) && (offset < 4096) )
     1615        {
     1616            // compute condition to copy one dentry to dirent array
     1617            bool_t valid = (dentry_id >= min_dentry) && (dirent_id <  max_dirent );
     1618
     1619            attr = fatfs_get_record( DIR_ATTR , base + offset , 0 );   
     1620            ord  = fatfs_get_record( LDIR_ORD , base + offset , 0 );   
     1621
     1622            if (ord == NO_MORE_ENTRY)                 // no more entry => break
     1623            {
     1624                end = true;
     1625            }
     1626            else if ( ord == FREE_ENTRY )             // free entry => skip
     1627            {
     1628                offset = offset + 32;
     1629            }
     1630            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry
     1631            {
     1632                if( valid )
     1633                {
     1634                    // get partial cname
     1635                    seq = ord & 0x3;
     1636                    lfn = (seq > lfn) ? seq : lfn;   
     1637                    if      ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 );
     1638                    else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 );
     1639                    else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 );
     1640                }
     1641                offset = offset + 32;
     1642            }
     1643            else                                     // NORMAL entry
     1644            {
     1645                // increment dentry_id
     1646                dentry_id++;
     1647
     1648                if( valid )
     1649                {
     1650                    // build the complete cname
     1651                    if      ( lfn == 0 )
     1652                    {
     1653                        fatfs_get_name_from_short( base + offset , cname );
     1654                    }
     1655                    else if ( lfn == 1 )
     1656                    {
     1657                        strcpy( cname      , lfn1 );
     1658                    }   
     1659                    else if ( lfn == 2 )
     1660                    {
     1661                        strcpy( cname      , lfn1 );
     1662                        strcpy( cname + 13 , lfn2 );
     1663                    }
     1664                    else if ( lfn == 3 )
     1665                    {
     1666                        strcpy( cname      , lfn1 );
     1667                        strcpy( cname + 13 , lfn2 );
     1668                        strcpy( cname + 26 , lfn3 );
     1669                    }
     1670                   
     1671                    // copy cname into dirent array
     1672                    strcpy( array[dirent_id].d_name , cname );
     1673
     1674                    // increment dirent_id
     1675                    dirent_id++;
     1676                }
     1677                offset = offset + 32;
     1678                lfn    = 0;
     1679            }
     1680        }  // end loop on directory entries in page
     1681
     1682        page_id++;
     1683        offset = 0;
     1684
     1685    }  // end loop on pages
     1686
     1687    // return result of scan
     1688    *done    = end;
     1689    *entries = dirent_id;
     1690
     1691#if DEBUG_FATFS_GET_USER_DIR
     1692cycle = (uint32_t)hal_get_cycles();
     1693if( DEBUG_FATFS_GET_USER_DIR < cycle )
     1694printk("\n[%s]  thread[%x,%x] exit for inode <%s> / %d entries / cycle %d\n",
     1695__FUNCTION__, this->process->pid, this->trdid, inode_name, entries, cycle );
     1696#endif
     1697
     1698    return 0;
     1699
     1700}  // end fatfs_get_user_dir()
    15561701
    15571702///////////////////////////////////////////////
  • trunk/kernel/fs/fatfs.h

    r611 r612  
    114114#define NAME_MAX_SIZE           31
    115115
    116 /******* Directory Entry Structure (32 bytes) **********************************/
     116/******* SFN Directory Entry Structure (32 bytes) ******************************/
    117117//                            offset | length
    118118#define DIR_NAME                   0 , 11   // dir_entry name
     
    308308
    309309/*****************************************************************************************
    310  * This function implements the generic vfs_fs_child_init() function for the FATFS.
    311  *****************************************************************************************
    312  * It tries to initialise a new child (new inode/dentry couple in Inode Tree), identified
     310 * This function implements the generic vfs_fs_get_dentry() function for the FATFS.
     311 *****************************************************************************************
     312 * It initialises a new child (new inode/dentry couple in Inode Tree), identified
    313313 * by the <child_inode_xp> argument, from the parent directory mapper, identified by the
    314314 * <parent_inode> argument.
    315  * - It scan the parent mapper to find the <name> argument.
    316  * - it set the "type", "size", and "extend" fields in inode descriptor.
    317  * - it set the " extend" field in dentry descriptor.
     315 * It scan the parent mapper to find the <name> argument.
     316 * It set the "type", "size", and "extend" fields in inode descriptor.
     317 * It set the " extend" field in dentry descriptor.
    318318 * It must be called by a thread running in the cluster containing the parent inode.
    319319 *****************************************************************************************
     
    323323 * @ return 0 if success / return ENOENT if child not found.
    324324 ****************************************************************************************/
    325 error_t fatfs_child_init( struct vfs_inode_s * parent_inode,
     325error_t fatfs_get_dentry( struct vfs_inode_s * parent_inode,
    326326                          char               * name,
    327327                          xptr_t               child_inode_xp );
     328
     329/*****************************************************************************************
     330 * This function implements the generic vfs_fs_get_user_dir() function for the FATFS.
     331 *****************************************************************************************
     332 * It is called by the remote_dir_create() function to scan the mapper of a directory
     333 * identified by the <inode> argument and copy up to <max_dirent> valid dentries to a
     334 * local dirent array, defined by the <array> argument. The <min_dentry> argument defines
     335 * the index of the first dentry to copied to the target dirent array.
     336 * This function returns in the <entries> buffer the number of dentries actually written,
     337 * and signals in the <done> buffer when the last valid entry has been found.
     338 * If the <detailed> argument is true, a dentry/inode couple that does not exist in
     339 * the Inode Tree is dynamically created, and all dirent fiels are documented in the
     340 * dirent array. Otherwise, only the dentry name is documented.
     341 * It must be called by a thread running in the cluster containing the directory inode.
     342 *****************************************************************************************
     343 * @ inode      : [in]  local pointer on directory inode.
     344 * @ array      : [in]  local pointer on array of dirents.
     345 * @ max_dirent : [in]  max number of slots in dirent array.
     346 * @ min_dentry : [in]  index of first dentry to be copied into array.
     347 * @ detailed   : [in]  dynamic inode creation if true.
     348 * @ entries    : [out] number of dentries actually copied into array.
     349 * @ done       : [out] Boolean true when last entry found.
     350 * @ return 0 if success / return -1 if failure.
     351 ****************************************************************************************/
     352error_t fatfs_get_user_dir( struct vfs_inode_s * inode,
     353                            struct dirent      * array,
     354                            uint32_t             max_dirent,
     355                            uint32_t             min_dentry,
     356                            bool_t               detailed,
     357                            uint32_t           * entries,
     358                            bool_t             * done );
    328359
    329360/*****************************************************************************************
  • trunk/kernel/fs/vfs.c

    r611 r612  
    23502350                if( parent_cxy == local_cxy )
    23512351                {
    2352                     error = vfs_fs_child_init( parent_ptr,
     2352                    error = vfs_fs_get_dentry( parent_ptr,
    23532353                                               name,
    23542354                                               child_xp );
     
    23562356                else
    23572357                {
    2358                     rpc_vfs_fs_child_init_client( parent_cxy,
     2358                    rpc_vfs_fs_get_dentry_client( parent_cxy,
    23592359                                                  parent_ptr,
    23602360                                                  name,
     
    23672367                    if ( last && create )  // add a brand new dentry in parent
    23682368                    {
    2369                         error = vfs_new_child_init( parent_xp,               
    2370                                                     dentry_xp,
    2371                                                     child_xp );
     2369                        error = vfs_new_dentry_init( parent_xp,               
     2370                                                     dentry_xp,
     2371                                                     child_xp );
    23722372                        if ( error )
    23732373                        {
     
    25102510}  // end vfs_lookup()
    25112511
    2512 ///////////////////////////////////////////////
    2513 error_t vfs_new_child_init( xptr_t   parent_xp,
    2514                             xptr_t   dentry_xp,
    2515                             xptr_t   child_xp )
     2512////////////////////////////////////////////////
     2513error_t vfs_new_dentry_init( xptr_t   parent_xp,
     2514                             xptr_t   dentry_xp,
     2515                             xptr_t   child_xp )
    25162516{
    25172517    error_t     error;
     
    25992599    return 0;
    26002600
    2601 }  // end vfs_new_child_init()
     2601}  // end vfs_new_dentry_init()
    26022602
    26032603///////////////////////////////////////////////////
     
    26152615    vfs_dentry_t  * dentry_ptr;        // local pointer on dentry (used for . and ..)
    26162616
    2617     xptr_t          parents_root_xp;   // extended pointer on inode "parents" field
    2618     xptr_t          parents_entry_xp;  // extended pointer on dentry "parents" field
     2617    // xptr_t          parents_root_xp;   // extended pointer on inode "parents" field
     2618    // xptr_t          parents_entry_xp;  // extended pointer on dentry "parents" field
    26192619    xptr_t          children_xhtab_xp; // extended pointer on inode "children" field
    26202620    xptr_t          children_entry_xp; // extended pointer on dentry "children" field
     
    26282628vfs_inode_get_name( parent_xp , parent_name );
    26292629if( DEBUG_VFS_ADD_SPECIAL < cycle )
    2630 printk("\n[%s] thread[%x,%x] enter / child <%s> / parent <%s> / cycle %d\n",
     2630printk("\n[%s] thread[%x,%x] enter for child <%s> in parent <%s> / cycle %d\n",
    26312631__FUNCTION__, this->process->pid, this->trdid, child_name, parent_name, cycle );
    26322632#endif
     
    26862686    }
    26872687
    2688     // register <.> dentry in child_inode xlist of parents TODO faut-il ?
    2689     parents_root_xp  = XPTR( child_cxy , &child_ptr->parents );
    2690     parents_entry_xp = XPTR( child_cxy , &dentry_ptr->parents );
    2691     xlist_add_first( parents_root_xp , parents_entry_xp );
    2692     hal_remote_atomic_add( XPTR( child_cxy , &child_ptr->links ) , 1 );
     2688   
     2689    // don't register <.> dentry in child_inode xlist of parents
     2690    // parents_root_xp  = XPTR( child_cxy , &child_ptr->parents );
     2691    // parents_entry_xp = XPTR( child_cxy , &dentry_ptr->parents );
     2692    // xlist_add_first( parents_root_xp , parents_entry_xp );
     2693    // hal_remote_atomic_add( XPTR( child_cxy , &child_ptr->links ) , 1 );
    26932694
    26942695    // update "parent" and "child_xp" fields in <.> dentry
     
    27702771    }
    27712772
    2772     // register <..> dentry in parent_inode xlist of parents TODO faut-il ?
    2773     parents_root_xp  = XPTR( parent_cxy , &parent_ptr->parents );
    2774     parents_entry_xp = XPTR( child_cxy  , &dentry_ptr->parents );
    2775     xlist_add_first( parents_root_xp , parents_entry_xp );
    2776     hal_remote_atomic_add( XPTR( parent_cxy , &parent_ptr->links ) , 1 );
     2773    // don't register <..> dentry in parent_inode xlist of parents
     2774    // parents_root_xp  = XPTR( parent_cxy , &parent_ptr->parents );
     2775    // parents_entry_xp = XPTR( child_cxy  , &dentry_ptr->parents );
     2776    // xlist_add_first( parents_root_xp , parents_entry_xp );
     2777    // hal_remote_atomic_add( XPTR( parent_cxy , &parent_ptr->links ) , 1 );
    27772778
    27782779    // update "parent" and "child_xp" fields in <..> dentry
     
    28152816cycle = (uint32_t)hal_get_cycles();
    28162817if( DEBUG_VFS_ADD_SPECIAL < cycle )
    2817 printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
    2818 __FUNCTION__, this->process->pid, this->trdid, (uint32_t)hal_get_cycles() );
     2818printk("\n[%s] thread[%x,%x] exit for child <%s> in parent <%s> / cycle %d\n",
     2819__FUNCTION__, this->process->pid, this->trdid, child_name, parent_name, cycle );
    28192820#endif
    28202821
     
    31833184}  // end vfs_remove_child_from_parent()
    31843185
     3186
     3187
     3188
    31853189//////////////////////////////////////////////////////////////////////////////////////////
    31863190//    API used by VFS to access a specific FS 
     
    32513255    else if( fs_type == FS_TYPE_RAMFS )
    32523256    {
    3253         assert( false , "should not be called for RAMFS\n" );
     3257        error = 0;     // does nothing for RAMFS
    32543258    }
    32553259    else if( fs_type == FS_TYPE_DEVFS )
    32563260    {
    3257         assert( false , "should not be called for DEVFS\n" );
     3261        error = 0;     // does nothing for DEVFS
    32583262    }
    32593263    else
     
    32893293    else if( fs_type == FS_TYPE_RAMFS )
    32903294    {
    3291         assert( false , "should not be called for RAMFS\n" );
     3295        error = 0;     // does nothing for RAMFS
    32923296    }
    32933297    else if( fs_type == FS_TYPE_DEVFS )
    32943298    {
    3295         assert( false , "should not be called for DEVFS\n" );
     3299        error = 0;     // does nothing for DEVFS
    32963300    }
    32973301    else
     
    33053309
    33063310////////////////////////////////////////////////
    3307 error_t vfs_fs_child_init( vfs_inode_t * parent,
     3311error_t vfs_fs_get_dentry( vfs_inode_t * parent,
    33083312                           char        * name,
    33093313                           xptr_t        child_xp )
     
    33213325    if( fs_type == FS_TYPE_FATFS )
    33223326    {
    3323         error = fatfs_child_init( parent , name , child_xp );
     3327        error = fatfs_get_dentry( parent , name , child_xp );
    33243328    }
    33253329    else if( fs_type == FS_TYPE_RAMFS )
     
    33383342    return error;
    33393343
    3340 } // end vfs_fs_child_init()
    3341 
     3344} // end vfs_fs_get_dentry()
     3345
     3346///////////////////////////////////////////////////
     3347error_t vfs_fs_get_user_dir( vfs_inode_t   * inode,
     3348                             struct dirent * array,
     3349                             uint32_t        max_dirent,
     3350                             uint32_t        min_dentry,
     3351                             bool_t          detailed,
     3352                             uint32_t      * entries,
     3353                             bool_t        * done )
     3354{
     3355    error_t error = 0;
     3356
     3357// check arguments
     3358assert( (inode != NULL) , "parent pointer is NULL\n");
     3359assert( (array != NULL) , "child pointer is NULL\n");
     3360assert( (detailed == false) , "detailed argument not supported\n");
     3361
     3362    // check inode type
     3363    if( inode->type != INODE_TYPE_DIR )
     3364    {
     3365        printk("\n[ERROR] in %s : target inode is not a directory\n",
     3366        __FUNCTION__ );
     3367        return -1;
     3368    }
     3369
     3370    // get parent inode FS type
     3371    vfs_fs_type_t fs_type = inode->ctx->type;
     3372
     3373    // call relevant FS function
     3374    if( fs_type == FS_TYPE_FATFS )
     3375    {
     3376        error = fatfs_get_user_dir( inode,
     3377                                    array,
     3378                                    max_dirent,
     3379                                    min_dentry,
     3380                                    detailed,
     3381                                    entries,
     3382                                    done );
     3383    }
     3384    else if( fs_type == FS_TYPE_RAMFS )
     3385    {
     3386        assert( false , "should not be called for RAMFS\n" );
     3387    }
     3388    else if( fs_type == FS_TYPE_DEVFS )
     3389    {
     3390        error = devfs_get_user_dir( inode,
     3391                                    array,
     3392                                    max_dirent,
     3393                                    min_dentry,
     3394                                    detailed,
     3395                                    entries,
     3396                                    done );
     3397    }
     3398    else
     3399    {
     3400        assert( false , "undefined file system type\n" );
     3401    }
     3402
     3403    return error;
     3404
     3405}  // end vfs_fs_get_user_dir()
     3406 
    33423407////////////////////////////////////////////////
    33433408error_t vfs_fs_sync_inode( vfs_inode_t * inode )
  • trunk/kernel/fs/vfs.h

    r611 r612  
    467467
    468468
     469
    469470/******************************************************************************************
    470471 *        These functions access / modify the distributed VFS Inode Tree
     
    599600 * @ return 0 if success / -1 if failure.
    600601 *****************************************************************************************/
    601 error_t vfs_new_child_init( xptr_t   parent_xp,
    602                             xptr_t   dentry_xp,
    603                             xptr_t   child_xp );
    604 
    605 /******************************************************************************************
    606  * This function is called by the vfs_mkdir() function to create the two special dentries
    607  * <.> and <..> in a new directory identified by the <child_xp> argument. The parent
    608  * directory inode is defined by the <parent_xp> argument.
    609  * The two dentries are introduced in the Inode Tree. They are also introduced in the
    610  * in the child directory mapper, and the IOC device is updated.
     602error_t vfs_new_dentry_init( xptr_t   parent_xp,
     603                             xptr_t   dentry_xp,
     604                             xptr_t   child_xp );
     605
     606/******************************************************************************************
     607 * This function creates in the directory identified by the <child_xp> argument,
     608 * the two special dentries <.> and <..>. The parent directory inode is defined
     609 * by the <parent_xp> argument. The two dentries are introduced in the Inode Tree.
     610 * They are also introduced in the child directory mapper, and the IOC device is updated.
     611 * This function is called by all functions creating a brand new directory : vfs_mkdir(),
     612 * devfs_global_init(), and devfs_local_init().
    611613 ******************************************************************************************
    612614 * @ child_xp    : extended pointer on new directory inode.
     
    633635                                       uint32_t           fs_type,
    634636                                       struct process_s * process );
     637
    635638
    636639
     
    865868
    866869
    867 /******************************************************************************************
    868  *        These functions define the VFS "FS" API (to a specific File System)
     870
     871
     872/******************************************************************************************
     873 *        These functions define the VFS "FS" API to a specific File System
    869874 *****************************************************************************************/
    870875
     
    923928 * @ return 0 if success / return ENOENT if not found.
    924929 *****************************************************************************************/
    925 error_t vfs_fs_child_init( vfs_inode_t * parent,
     930error_t vfs_fs_get_dentry( vfs_inode_t * parent,
    926931                           char        * name,
    927932                           xptr_t        child_xp );
    928933
     934/******************************************************************************************
     935 * This function scan the mapper of an an existing parent inode directory, identified by
     936 * the <inode> argument and copy up to <max_dirent> valid dentries to a
     937 * local dirent array, defined by the <array> argument. The <min_dentry> argument defines
     938 * the index of the first dentry to copied to the target dirent array.
     939 * This function returns in the <entries> buffer the number of dentries actually written,
     940 * and signals in the <done> buffer when the last valid entry has been found.
     941 * If the <detailed> argument is true, a dentry/inode couple that does not exist in
     942 * the Inode Tree is dynamically created, and all dirent fiels are documented in the
     943 * dirent array. Otherwise, only the dentry name is documented.
     944 *
     945 * Depending on the file system type, it calls the relevant, FS specific function.
     946 * It must be called by a thread running in the cluster containing the parent inode.
     947 * This function does NOT take any lock.
     948 ******************************************************************************************
     949 * @ inode      : [in]  local pointer on directory inode.
     950 * @ array      : [in]  local pointer on array of dirents.
     951 * @ max_dirent : [in]  max number of slots in dirent array.
     952 * @ min_dentry : [in]  index of first dentry to be copied into array.
     953 * @ detailed   : [in]  dynamic inode creation if true.
     954 * @ entries    : [out] number of dentries actually copied into array.
     955 * @ done       : [out] Boolean true when last entry found.
     956 * @ return 0 if success / return -1 if failure.
     957 *****************************************************************************************/
     958error_t vfs_fs_get_user_dir( vfs_inode_t   * inode,
     959                             struct dirent * array,
     960                             uint32_t        max_dirent,
     961                             uint32_t        min_dentry,
     962                             bool_t          detailed,
     963                             uint32_t      * entries,
     964                             bool_t        * done );
     965 
    929966/*****************************************************************************************
    930967 * This function  updates the FS on the IOC device for a given inode identified by
  • trunk/kernel/kern/kernel_init.c

    r611 r612  
    33 *
    44 * Authors :  Mohamed Lamine Karaoui (2015)
    5  *            Alain Greiner  (2016,2017)
     5 *            Alain Greiner  (2016,2017,2018)
    66 *
    77 * Copyright (c) Sorbonne Universites
  • trunk/kernel/kern/process.h

    r611 r612  
    382382 * The "new" process keep the "old" process PID and PPID, all open files, and env variables,
    383383 * the vfs_root and vfs_cwd, but build a brand new memory image (new VMM from the new .elf).
    384  * It actually creates a "new" reference process descriptor, and copies all relevant
    385  * information from the "old" process descriptor to the "new" process descriptor.
    386  * It completes the "new" process descriptor, from information found in the <exec_info>
    387  * structure (defined in the process.h file), that must be built by the caller.
    388  * It creates and initializes the associated main thread. It finally destroys all copies
    389  * of the "old" process in all clusters, and destroys all old associated threads.
    390384 * It is executed in the local cluster, that becomes both the "owner" and the "reference"
    391385 * cluster for the "new" process.
  • trunk/kernel/kern/rpc.c

    r611 r612  
    2929#include <hal_special.h>
    3030#include <printk.h>
     31#include <user_dir.h>
    3132#include <remote_sem.h>
    3233#include <core.h>
     
    6667    &rpc_vfs_file_create_server,           // 14
    6768    &rpc_vfs_file_destroy_server,          // 15
    68     &rpc_vfs_fs_child_init_server,         // 16
     69    &rpc_vfs_fs_get_dentry_server,         // 16
    6970    &rpc_vfs_fs_add_dentry_server,         // 17
    7071    &rpc_vfs_fs_remove_dentry_server,      // 18
     
    102103    "VFS_FILE_CREATE",           // 14
    103104    "VFS_FILE_DESTROY",          // 15
    104     "VFS_FS_CHILD_INIT",         // 16
     105    "VFS_FS_GET_DENTRY",         // 16
    105106    "VFS_FS_ADD_DENTRY",         // 17
    106107    "VFS_FS_REMOVE_DENTRY",      // 18
     
    650651
    651652/////////////////////////////////////////////////////////////////////////////////////////
    652 // [4]      undefined slot
    653 /////////////////////////////////////////////////////////////////////////////////////////
    654 
    655 /////////////////////////////////////////////////////////////////////////////////////////
    656 // [5]      undefined slot
    657 /////////////////////////////////////////////////////////////////////////////////////////
     653// [4]      Marshaling functions attached to RPC_USER_DIR_CREATE (blocking)
     654/////////////////////////////////////////////////////////////////////////////////////////
     655
     656////////////////////////////////////////////////////
     657void rpc_user_dir_create_client( cxy_t          cxy,
     658                                 vfs_inode_t *  inode,
     659                                 user_dir_t  ** dir )
     660{
     661#if DEBUG_RPC_USER_DIR_CREATE
     662thread_t * this = CURRENT_THREAD;
     663uint32_t cycle = (uint32_t)hal_get_cycles();
     664if( cycle > DEBUG_RPC_USER_DIR_CREATE)
     665printk("\n[%s] thread[%x,%x] on core %d enter / cycle %d\n",
     666__FUNCTION__, this->process->pid, this->trdid, this->core->lid, cycle );
     667#endif
     668
     669    assert( (cxy != local_cxy) , "server cluster is not remote\n");
     670
     671    // initialise RPC descriptor header
     672    rpc_desc_t  rpc;
     673    rpc.index    = RPC_USER_DIR_CREATE;
     674    rpc.blocking = true;
     675    rpc.responses = 1;
     676
     677    // set input arguments in RPC descriptor
     678    rpc.args[0] = (uint64_t)(intptr_t)inode;
     679
     680    // register RPC request in remote RPC fifo
     681    rpc_send( cxy , &rpc );
     682
     683    // get output argument from RPC descriptor
     684    *dir = (user_dir_t *)(intptr_t)rpc.args[1];
     685
     686#if DEBUG_RPC_USER_DIR_CREATE
     687cycle = (uint32_t)hal_get_cycles();
     688if( cycle > DEBUG_RPC_USER_DIR_CREATE)
     689printk("\n[%s] thread[%x,%x] on core %d exit / cycle %d\n",
     690__FUNCTION__, this->process->pid, this->trdid, this->core->lid, cycle );
     691#endif
     692}
     693
     694////////////////////////////////////////////
     695void rpc_user_dir_create_server( xptr_t xp )
     696{
     697#if DEBUG_RPC_USER_DIR_CREATE
     698thread_t * this = CURRENT_THREAD;
     699uint32_t cycle = (uint32_t)hal_get_cycles();
     700if( cycle > DEBUG_RPC_USER_DIR_CREATE)
     701printk("\n[%s] thread[%x,%x] on core %d enter / cycle %d\n",
     702__FUNCTION__, this->process->pid, this->trdid, this->core->lid, cycle );
     703#endif
     704
     705    vfs_inode_t * inode;          // pointer on inode in server cluster
     706    user_dir_t  * dir;            // pointer on user_dir structure in server cluster
     707
     708    // get client cluster identifier and pointer on RPC descriptor
     709    cxy_t        client_cxy  = GET_CXY( xp );
     710    rpc_desc_t * desc        = GET_PTR( xp );
     711
     712    // get input argument from RPC descriptor
     713    inode = (vfs_inode_t *)(intptr_t)hal_remote_l64(XPTR(client_cxy , &desc->args[0]));
     714
     715    // call kernel function
     716    dir = user_dir_create( inode );
     717
     718    // set output argument into RPC descriptor
     719    hal_remote_s64( XPTR( client_cxy , &desc->args[1] ) , (intptr_t)dir );
     720
     721#if DEBUG_RPC_USER_DIR_CREATE
     722cycle = (uint32_t)hal_get_cycles();
     723if( cycle > DEBUG_RPC_USER_DIR_CREATE)
     724printk("\n[%s] thread[%x,%x] on core %d exit / cycle %d\n",
     725__FUNCTION__, this->process->pid, this->trdid, this->core->lid, cycle );
     726#endif
     727}
     728
     729/////////////////////////////////////////////////////////////////////////////////////////
     730// [5]      Marshaling functions attached to RPC_USER_DIR_DESTROY (blocking)
     731/////////////////////////////////////////////////////////////////////////////////////////
     732
     733////////////////////////////////////////////////////
     734void rpc_user_dir_destroy_client( cxy_t         cxy,
     735                                  user_dir_t  * dir )
     736{
     737#if DEBUG_RPC_USER_DIR_DESTROY
     738thread_t * this = CURRENT_THREAD;
     739uint32_t cycle = (uint32_t)hal_get_cycles();
     740if( cycle > DEBUG_RPC_USER_DIR_DESTROY)
     741printk("\n[%s] thread[%x,%x] on core %d enter / cycle %d\n",
     742__FUNCTION__, this->process->pid, this->trdid, this->core->lid, cycle );
     743#endif
     744
     745    assert( (cxy != local_cxy) , "server cluster is not remote\n");
     746
     747    // initialise RPC descriptor header
     748    rpc_desc_t  rpc;
     749    rpc.index    = RPC_USER_DIR_DESTROY;
     750    rpc.blocking = true;
     751    rpc.responses = 1;
     752
     753    // set input arguments in RPC descriptor
     754    rpc.args[0] = (uint64_t)(intptr_t)dir;
     755
     756    // register RPC request in remote RPC fifo
     757    rpc_send( cxy , &rpc );
     758
     759#if DEBUG_RPC_USER_DIR_DESTROY
     760cycle = (uint32_t)hal_get_cycles();
     761if( cycle > DEBUG_RPC_USER_DIR_DESTROY)
     762printk("\n[%s] thread[%x,%x] on core %d exit / cycle %d\n",
     763__FUNCTION__, this->process->pid, this->trdid, this->core->lid, cycle );
     764#endif
     765}
     766
     767/////////////////////////////////////////////
     768void rpc_user_dir_destroy_server( xptr_t xp )
     769{
     770#if DEBUG_RPC_USER_DIR_DESTROY
     771thread_t * this = CURRENT_THREAD;
     772uint32_t cycle = (uint32_t)hal_get_cycles();
     773if( cycle > DEBUG_RPC_USER_DIR_DESTROY)
     774printk("\n[%s] thread[%x,%x] on core %d enter / cycle %d\n",
     775__FUNCTION__, this->process->pid, this->trdid, this->core->lid, cycle );
     776#endif
     777
     778    user_dir_t * dir;            // pointer on user_dir structure in server cluster
     779
     780    // get client cluster identifier and pointer on RPC descriptor
     781    cxy_t        client_cxy  = GET_CXY( xp );
     782    rpc_desc_t * desc        = GET_PTR( xp );
     783
     784    // get input argument from RPC descriptor
     785    dir = (user_dir_t *)(intptr_t)hal_remote_l64(XPTR(client_cxy , &desc->args[0]));
     786
     787    // call kernel function
     788    user_dir_destroy( dir );
     789
     790#if DEBUG_RPC_USER_DIR_DESTROY
     791cycle = (uint32_t)hal_get_cycles();
     792if( cycle > DEBUG_RPC_USER_DIR_DESTROY)
     793printk("\n[%s] thread[%x,%x] on core %d exit / cycle %d\n",
     794__FUNCTION__, this->process->pid, this->trdid, this->core->lid, cycle );
     795#endif
     796}
    658797
    659798/////////////////////////////////////////////////////////////////////////////////////////
     
    731870    cxy_t        client_cxy  = GET_CXY( xp );
    732871    rpc_desc_t * desc        = GET_PTR( xp );
    733 
    734     // get pointer on attributes structure in client cluster from RPC descriptor
    735872
    736873    // get input arguments from RPC descriptor
     
    751888                                &attr_copy,
    752889                                &thread_ptr );
    753 
    754890    // set output arguments
    755891    thread_xp = XPTR( local_cxy , thread_ptr );
     
    14261562
    14271563/////////////////////////////////////////////////////////////////////////////////////////
    1428 // [16]      Marshaling functions attached to RPC_VFS_FS_CHILD_INIT  (blocking)
     1564// [16]      Marshaling functions attached to RPC_VFS_FS_GET_DENTRY  (blocking)
    14291565/////////////////////////////////////////////////////////////////////////////////////////
    14301566
    14311567/////////////////////////////////////////////////////////
    1432 void rpc_vfs_fs_child_init_client( cxy_t         cxy,
     1568void rpc_vfs_fs_get_dentry_client( cxy_t         cxy,
    14331569                                   vfs_inode_t * parent_inode,    // in
    14341570                                   char        * name,            // in
     
    14361572                                   error_t     * error )          // out
    14371573{
    1438 #if DEBUG_RPC_VFS_FS_CHILD_INIT
    1439 thread_t * this = CURRENT_THREAD;
    1440 uint32_t cycle = (uint32_t)hal_get_cycles();
    1441 if( cycle > DEBUG_RPC_VFS_FS_CHILD_INIT )
     1574#if DEBUG_RPC_VFS_FS_GET_DENTRY
     1575thread_t * this = CURRENT_THREAD;
     1576uint32_t cycle = (uint32_t)hal_get_cycles();
     1577if( cycle > DEBUG_RPC_VFS_FS_GET_DENTRY )
    14421578printk("\n[%s] thread[%x,%x] on core %d enter / cycle %d\n",
    14431579__FUNCTION__, this->process->pid, this->trdid, this->core->lid , cycle );
     
    14481584    // initialise RPC descriptor header
    14491585    rpc_desc_t  rpc;
    1450     rpc.index    = RPC_VFS_FS_CHILD_INIT;
     1586    rpc.index    = RPC_VFS_FS_GET_DENTRY;
    14511587    rpc.blocking = true;
    14521588    rpc.responses = 1;
     
    14631599    *error   = (error_t)rpc.args[3];
    14641600
    1465 #if DEBUG_RPC_VFS_FS_CHILD_INIT
    1466 cycle = (uint32_t)hal_get_cycles();
    1467 if( cycle > DEBUG_RPC_VFS_FS_CHILD_INIT )
     1601#if DEBUG_RPC_VFS_FS_GET_DENTRY
     1602cycle = (uint32_t)hal_get_cycles();
     1603if( cycle > DEBUG_RPC_VFS_FS_GET_DENTRY )
    14681604printk("\n[%s] thread[%x,%x] on core %d exit / cycle %d\n",
    14691605__FUNCTION__, this->process->pid, this->trdid, this->core->lid , cycle );
     
    14721608
    14731609//////////////////////////////////////////////
    1474 void rpc_vfs_fs_child_init_server( xptr_t xp )
    1475 {
    1476 #if DEBUG_RPC_VFS_FS_CHILD_INIT
    1477 thread_t * this = CURRENT_THREAD;
    1478 uint32_t cycle = (uint32_t)hal_get_cycles();
    1479 if( cycle > DEBUG_RPC_VFS_FS_CHILD_INIT )
     1610void rpc_vfs_fs_get_dentry_server( xptr_t xp )
     1611{
     1612#if DEBUG_RPC_VFS_FS_GET_DENTRY
     1613thread_t * this = CURRENT_THREAD;
     1614uint32_t cycle = (uint32_t)hal_get_cycles();
     1615if( cycle > DEBUG_RPC_VFS_FS_GET_DENTRY )
    14801616printk("\n[%s] thread[%x,%x] on core %d enter / cycle %d\n",
    14811617__FUNCTION__, this->process->pid, this->trdid, this->core->lid , cycle );
     
    15031639
    15041640    // call the kernel function
    1505     error = vfs_fs_child_init( parent , name_copy , child_xp );
     1641    error = vfs_fs_get_dentry( parent , name_copy , child_xp );
    15061642
    15071643    // set output argument
    15081644    hal_remote_s64( XPTR( client_cxy , &desc->args[3] ) , (uint64_t)error );
    15091645
    1510 #if DEBUG_RPC_VFS_FS_CHILD_INIT
    1511 cycle = (uint32_t)hal_get_cycles();
    1512 if( cycle > DEBUG_RPC_VFS_FS_CHILD_INIT )
     1646#if DEBUG_RPC_VFS_FS_GET_DENTRY
     1647cycle = (uint32_t)hal_get_cycles();
     1648if( cycle > DEBUG_RPC_VFS_FS_GET_DENTRY )
    15131649printk("\n[%s] thread[%x,%x] on core %d exit / cycle %d\n",
    15141650__FUNCTION__, this->process->pid, this->trdid, this->core->lid , cycle );
  • trunk/kernel/kern/rpc.h

    r611 r612  
    4040struct pthread_attr_s;
    4141struct remote_sem_s;
     42struct user_dir_s;
    4243struct fragment_s;
    4344struct vfs_inode_s;
     
    6364    RPC_UNDEFINED_2               = 2,     
    6465    RPC_PROCESS_MAKE_FORK         = 3,
    65     RPC_UNDEFINED_4               = 4,
    66     RPC_UNDEFINED_5               = 5,
     66    RPC_USER_DIR_CREATE           = 4,
     67    RPC_USER_DIR_DESTROY          = 5,
    6768    RPC_THREAD_USER_CREATE        = 6,
    6869    RPC_THREAD_KERNEL_CREATE      = 7,
     
    7677    RPC_VFS_FILE_CREATE           = 14,
    7778    RPC_VFS_FILE_DESTROY          = 15,
    78     RPC_VFS_FS_CHILD_INIT         = 16,
     79    RPC_VFS_FS_GET_DENTRY         = 16,
    7980    RPC_VFS_FS_ADD_DENTRY         = 17,
    8081    RPC_VFS_FS_REMOVE_DENTRY      = 18,
     
    226227
    227228/***********************************************************************************
    228  * [4] undefined slot
    229  **********************************************************************************/
    230 
    231 /***********************************************************************************
    232  * [5] undefined slot
    233  **********************************************************************************/
     229 * [4] The RPC_USER_DIR_CREATE allows a client thread to create an user_dir_t
     230 * structure and the associated array of dirents in a remote cluster containing
     231 * the target directory inode. It is called by the sys_opendir() function.
     232 ***********************************************************************************
     233 * @ cxy        : server cluster identifier.
     234 * @ inode      : [in]   local pointer on inode in server cluster.
     235 * @ dir        : [out]  local pointer on created user_dir structure.
     236 **********************************************************************************/
     237void rpc_user_dir_create_client( cxy_t                 cxy,
     238                                 struct vfs_inode_s  * inode,
     239                                 struct user_dir_s  ** dir );
     240
     241void rpc_user_dir_create_server( xptr_t xp );
     242
     243/***********************************************************************************
     244 * [5] The RPC_USER_DIR_DESTROY allows a client thread to delete an user_dir_t
     245 * structure and the associated array of dirents in a remote cluster containing
     246 * the target directory inode. It is called by the sys_closedir() function.
     247 ***********************************************************************************
     248 * @ cxy        : server cluster identifier.
     249 * @ dir        : [in]  local pointer on created user_dir structure.
     250 **********************************************************************************/
     251void rpc_user_dir_destroy_client( cxy_t               cxy,
     252                                  struct user_dir_s * dir );
     253
     254void rpc_user_dir_destroy_server( xptr_t xp );
    234255
    235256/***********************************************************************************
     
    402423
    403424/***********************************************************************************
    404  * [16] The RPC_VFS_FS_CHILD_INIT calls the vfs_fs_child_init_load_inode()
     425 * [16] The RPC_VFS_FS_GET_DENTRY calls the vfs_fs_get_dentry()
    405426 * function in a remote cluster containing a parent inode directory to scan the
    406427 * associated mapper, find a directory entry identified by its name, and update
    407  * both the child inode and the dentry.
     428 * both the - existing - child inode and dentry.
    408429 ***********************************************************************************
    409430 * @ cxy            : server cluster identifier
     
    413434 * @ error          : [out] error status (0 if success).
    414435 **********************************************************************************/
    415 void rpc_vfs_fs_child_init_client( cxy_t                cxy,
     436void rpc_vfs_fs_get_dentry_client( cxy_t                cxy,
    416437                                   struct vfs_inode_s * parent_inode,
    417438                                   char               * name,
     
    419440                                   error_t            * error );
    420441
    421 void rpc_vfs_fs_child_init_server( xptr_t xp );
     442void rpc_vfs_fs_get_dentry_server( xptr_t xp );
    422443
    423444/***********************************************************************************
  • trunk/kernel/kernel_config.h

    r611 r612  
    6262#define DEBUG_DEV_PIC                     0
    6363
    64 #define DEBUG_DEVFS_INIT                  0
     64#define DEBUG_DEVFS_INIT                  1
    6565#define DEBUG_DEVFS_MOVE                  0
    6666
     
    7474
    7575#define DEBUG_FATFS_ADD_DENTRY            0
    76 #define DEBUG_FATFS_CHILD_INIT            0
    7776#define DEBUG_FATFS_CLUSTER_ALLOC         0
    7877#define DEBUG_FATFS_CTX_INIT              0
    7978#define DEBUG_FATFS_FREE_CLUSTERS         0
    8079#define DEBUG_FATFS_GET_CLUSTER           0
     80#define DEBUG_FATFS_GET_DIRENT            1
     81#define DEBUG_FATFS_GET_USER_DIR          1
    8182#define DEBUG_FATFS_MOVE_PAGE             0
    8283#define DEBUG_FATFS_RELEASE_INODE         0
     
    127128
    128129#define DEBUG_QUEUELOCK_TYPE              0    // lock type (0 is undefined)
    129 
    130 #define DEBUG_REMOTE_DIR                  0
    131130
    132131#define DEBUG_RPC_CLIENT_GENERIC          0
     
    213212#define DEBUG_THREAD_USER_EXEC            0
    214213
     214#define DEBUG_USER_DIR                    1
     215
    215216#define DEBUG_VFS_ADD_CHILD               0
    216217#define DEBUG_VFS_ADD_SPECIAL             1
  • trunk/kernel/libk/list.h

    r610 r612  
    7878
    7979/***************************************************************************
    80  * This macro returns the first element of a rooted double linked list.
     80 * This macro returns t pointer on the first element of a list.
    8181 ***************************************************************************
    8282 * @ root     : pointer on the list root
     
    8989
    9090/***************************************************************************
    91  * This macro returns the last element of a rooted double linked list.
     91 * This macro returns a pointer on the last element of a list.
    9292 ***************************************************************************
    9393 * @ root     : pointer on the list root
  • trunk/kernel/libk/xhtab.c

    r610 r612  
    238238        remote_busylock_release( XPTR( xhtab_cxy , &xhtab_ptr->lock ) );
    239239
    240         return EINVAL;
     240        return -1;
    241241    }
    242242    else                          // insert item if not found
  • trunk/kernel/mm/kmem.c

    r611 r612  
    4040#include <fatfs.h>
    4141#include <ramfs.h>
    42 #include <remote_dir.h>
     42#include <user_dir.h>
    4343#include <remote_sem.h>
    4444#include <remote_barrier.h>
     
    101101    else if( type == KMEM_CONDVAR )       return sizeof( remote_condvar_t );
    102102    else if( type == KMEM_MUTEX )         return sizeof( remote_mutex_t );
    103     else if( type == KMEM_DIR )           return sizeof( remote_dir_t );
     103    else if( type == KMEM_DIR )           return sizeof( user_dir_t );
    104104
    105105        else if( type == KMEM_512_BYTES )     return 512;
  • trunk/kernel/mm/mapper.h

    r611 r612  
    3838
    3939/*******************************************************************************************
    40  * The mapper implements the kernel cache for a given file or directory.
     40 * The mapper implements the kernel cache for a given VFS file or directory.
    4141 * There is one mapper per file/dir. It is implemented as a three levels radix tree,
    4242 * entirely stored in the same cluster as the inode representing the file/dir.
     
    6161 * - In the present implementation the cache size for a given file increases on demand,
    6262 *   and the  allocated memory is only released when the mapper/inode is destroyed.
     63 *
     64 * TODO : the mapper being only used to implement the VFS cache(s), the mapper.c
     65 *        and mapper.h file should beerro trandfered to the vfs directory.
    6366 ******************************************************************************************/
    6467
  • trunk/kernel/mm/page.h

    r606 r612  
    3737/*************************************************************************************
    3838 * This  defines the flags that can be attached to a physical page.
    39  * TODO : the PG_BUFFER and PG_IO_ERR flags semantic is not defined [AG]
    4039 ************************************************************************************/
    4140
     
    4342#define PG_RESERVED         0x0002     // cannot be allocated by PPM
    4443#define PG_FREE             0x0004     // page can be allocated by PPM
    45 #define PG_IO_ERR           0x0010     // mapper signals access error    TODO ??? [AG]
    46 #define PG_BUFFER           0x0020     // used in blockio.c              TODO ??? [AG]
    4744#define PG_DIRTY            0x0040     // page has been written
    4845#define PG_COW          0x0080     // page is copy-on-write
  • trunk/kernel/syscalls/sys_closedir.c

    r611 r612  
    2828#include <thread.h>
    2929#include <process.h>
    30 #include <remote_dir.h>
     30#include <user_dir.h>
    3131#include <errno.h>
    3232#include <syscalls.h>
     
    3636int sys_closedir ( DIR * dirp )
    3737{
    38     xptr_t         dir_xp;       // extended pointer on remote_dir_t structure
     38    xptr_t         dir_xp;       // extended pointer on user_dir_t structure
     39    user_dir_t   * dir_ptr;      // lcal pointer on user_dir_t structure
     40    cxy_t          dir_cxy;      // cluster identifier (inode cluster)
    3941
    4042        thread_t  * this    = CURRENT_THREAD;  // client thread
     
    5153#endif
    5254 
    53     // get extended pointer on kernel remote_dir_t structure from dirp
    54     dir_xp  = remote_dir_from_ident( (intptr_t)dirp );
     55    // get extended pointer on kernel user_dir_t structure from dirp
     56    dir_xp  = user_dir_from_ident( (intptr_t)dirp );
    5557
    5658    if( dir_xp == XPTR_NULL )
     
    6567        }       
    6668
    67     // delete kernel remote_dir_t structure
    68     remote_dir_destroy( dir_xp );
     69    // get cluster and localpointer for user_dir_t structure
     70    dir_ptr = GET_PTR( dir_xp );
     71    dir_cxy = GET_CXY( dir_xp );
     72   
     73    // delete both user_dir_t structure and dirent array
     74    if( dir_cxy == local_cxy )
     75    {
     76        user_dir_destroy( dir_ptr );
     77    }
     78    else
     79    {
     80        rpc_user_dir_destroy_client( dir_cxy,
     81                                     dir_ptr );
     82    }
    6983
    7084    hal_fence();
  • trunk/kernel/syscalls/sys_display.c

    r611 r612  
    5252    else if( type == DISPLAY_DQDT              ) return "DQDT";
    5353    else if( type == DISPLAY_BUSYLOCKS         ) return "BUSYLOCKS";
     54    else if( type == DISPLAY_MAPPER            ) return "MAPPER";
     55    else                                         return "undefined";
    5456}
    5557#endif
  • trunk/kernel/syscalls/sys_opendir.c

    r611 r612  
    11/*
    2  * sys_opendir.c - Open a VFS directory.
     2 * sys_opendir.c - Open an user accessible VFS directory.
    33 *
    44 * Author        Alain Greiner (2016,2017,2018)
     
    2727#include <thread.h>
    2828#include <process.h>
    29 #include <remote_dir.h>
     29#include <user_dir.h>
    3030#include <printk.h>
    3131#include <errno.h>
     
    4545    cxy_t          inode_cxy;              // directory inode cluster
    4646    uint32_t       inode_type;             // to check directory inode type
    47     xptr_t         dir_xp;                 // extended pointer on remote_dir_t
    48     remote_dir_t * dir_ptr;                // local pointer on remote_dir_t
    49     cxy_t          dir_cxy;                // remote_dir_t cluster identifier
     47    user_dir_t   * dir_ptr;                // local pointer on user_dir_t
    5048    vseg_t       * vseg;                   // for user space checking
    5149    intptr_t       ident;                  // dirent array pointer in user space                 
     
    145143        }
    146144   
    147     // allocate, initialize, and register a new remote_dir_t structure
    148     // in the calling process reference cluster
    149     dir_xp  = remote_dir_create( inode_xp );
    150     dir_ptr = GET_PTR( dir_xp );
    151     dir_cxy = GET_CXY( dir_xp );
     145    // create a new user_dir_t structure in inode cluster
     146    // and get the user space pointer on dirent array
     147    if( inode_cxy == local_cxy )
     148    {
     149        dir_ptr = user_dir_create( inode_ptr );
     150    }
     151    else
     152    {
     153        rpc_user_dir_create_client( inode_cxy,
     154                                    inode_ptr,
     155                                    &dir_ptr );
     156    }
    152157
    153     if( dir_xp == XPTR_NULL )
     158    if( dir_ptr == NULL )
    154159        {
    155160
    156161#if DEBUG_SYSCALLS_ERROR
    157 printk("\n[ERROR] in %s / thread[%x,%x] : cannot create remote_dir for <%s>\n",
     162printk("\n[ERROR] in %s / thread[%x,%x] : cannot create user_dir for <%s>\n",
    158163__FUNCTION__ , process->pid , this->trdid , kbuf );
    159164#endif
     
    162167        }
    163168   
    164     // get ident from remote_dir structure
    165     ident = (intptr_t)hal_remote_lpt( XPTR( dir_cxy , &dir_ptr->ident ) );
     169    // get ident from user_dir structure
     170    ident = (intptr_t)hal_remote_lpt( XPTR( inode_cxy , &dir_ptr->ident ) );
    166171
    167172    // set ident value in user buffer
  • trunk/kernel/syscalls/sys_readdir.c

    r611 r612  
    3030#include <vfs.h>
    3131#include <process.h>
    32 #include <remote_dir.h>
     32#include <user_dir.h>
    3333#include <syscalls.h>
    3434#include <shared_syscalls.h>
     
    4040    error_t         error;
    4141    vseg_t        * vseg;               // for user space checking of buffer
    42     xptr_t          dir_xp;             // extended pointer on remote_dir_t structure
    43     remote_dir_t  * dir_ptr;            // local pointer on remote_dir_t structure
    44     cxy_t           dir_cxy;            // remote_dir_t stucture cluster identifier
     42    xptr_t          dir_xp;             // extended pointer on user_dir structure
     43    user_dir_t    * dir_ptr;            // local pointer on user_dir structure
     44    cxy_t           dir_cxy;            // user_dir stucture cluster identifier
    4545    struct dirent * direntp;            // dirent pointer in user space 
    4646    uint32_t        entries;            // total number of dirent entries
     
    7575        }       
    7676
    77     // get pointers on remote_dir_t structure from dirp
    78     dir_xp  = remote_dir_from_ident( (intptr_t)dirp );
     77    // get pointers on user_dir structure from dirp
     78    dir_xp  = user_dir_from_ident( (intptr_t)dirp );
    7979    dir_ptr = GET_PTR( dir_xp );
    8080    dir_cxy = GET_CXY( dir_xp );
     
    9191        }       
    9292
    93     // get "current" and "entries_nr" values from remote_dir_t structure
     93    // get "current" and "entries_nr" values from user_dir_t structure
    9494    current = hal_remote_l32( XPTR( dir_cxy , &dir_ptr->current ) );
    9595    entries = hal_remote_l32( XPTR( dir_cxy , &dir_ptr->entries ) );
     
    114114    hal_copy_to_uspace( buffer, &direntp , sizeof(void *) );
    115115
    116     // update current index in "remote_dir_t" structure
     116    // update current index in user_dir structure
    117117    hal_remote_atomic_add( XPTR( dir_cxy , &dir_ptr->current ) , 1 );
    118118
  • trunk/user/ksh/ksh.c

    r611 r612  
    758758    DIR            * dir;
    759759
    760         if (argc != 2 )
     760        if (argc > 2 )
    761761    {
    762762                printf("  usage: ls [path]\n");
     
    764764    else
    765765    {
    766 
    767 // handle case with no argument
    768 // TODO if ( argc == 1 ) path = ".";
     766        // handle case with no argument
    769767
    770768        // get target directory path
    771         pathname = argv[1];
     769        if ( argc == 1 ) strcpy( pathname , "." );
     770        else             pathname = argv[1];
    772771
    773772        // open target directory
     
    788787        while ( (entry = readdir(dir)) != NULL )
    789788            {
    790                     printf(" - %s\n", entry->d_name);
     789                    printf("%s\n", entry->d_name);
    791790            }
    792791
Note: See TracChangeset for help on using the changeset viewer.