예제 #1
0
int fsal_internal_proxy_fsal_path_2_utf8(fsal_path_t * ppath, utf8string * utf8str)
{
  char tmpstr[FSAL_MAX_PATH_LEN];
  fsal_status_t fsal_status;

  if(ppath == NULL || utf8str == NULL)
    return FALSE;

  fsal_status = FSAL_path2str(ppath, tmpstr, FSAL_MAX_NAME_LEN);
  if(fsal_status.major != ERR_FSAL_NO_ERROR)
    return FALSE;

  if(utf8str->utf8string_len == 0)
    {
      if((utf8str->utf8string_val = (char *)Mem_Alloc_Label(ppath->len,
                                                            "fsal_internal_proxy_fsal_path_2_utf8")) == NULL)
        return FALSE;
      else
        utf8str->utf8string_len = ppath->len;
    }

  if(str2utf8(tmpstr, utf8str) == -1)
    return FALSE;

  return TRUE;
}                               /* fsal_internal_proxy_fsal_path_2_utf8 */
예제 #2
0
/**
 *
 * gid2utf8: converts a gid to a utf8 string descriptor.
 *
 * Converts a gid to a utf8 string descriptor.
 *
 * @param gid     [IN]  the input gid
 * @param utf8str [OUT] computed UTF8 string descriptor
 *
 * @return the length of the utf8 buffer if succesfull, -1 if failed
 *
 */
int gid2utf8(gid_t gid, utf8string * utf8str)
{
  char buff[NFS4_MAX_DOMAIN_LEN];
  unsigned int len = 0;

  if(gid2str(gid, buff) == -1)
    return -1;

  len = strlen(buff);

  /* A matching gid was found */
  /* Do the conversion to uft8 format */
  if((utf8str->utf8string_val = (char *)Mem_Alloc_Label(len, "gid2utf8")) == NULL)
    return -1;
  else
    utf8str->utf8string_len = len;

  return str2utf8(buff, utf8str);
}                               /* gid2utf8 */
예제 #3
0
/**
 *
 * uid2utf8: converts a uid to a utf8 string descriptor.
 *
 * Converts a uid to a utf8 string descriptor.
 *
 * @param uid     [IN]  the input uid
 * @param utf8str [OUT] computed UTF8 string descriptor
 *
 * @return the length of the utf8 buffer if succesfull, -1 if failed
 *
 */
int uid2utf8(uid_t uid, utf8string * utf8str)
{
  char buff[NFS4_MAX_DOMAIN_LEN];
  unsigned int len = 0;

  if(uid2str(uid, buff) == -1)
    return -1;

  len = strlen(buff);

  /* A matching uid was found, now do the conversion to utf8 */
  if((utf8str->utf8string_val = (char *)Mem_Alloc_Label(len, "uid2utf8")) == NULL)
    return -1;
  else
    utf8str->utf8string_len = len;

  return str2utf8(buff, utf8str);

}                               /* uid2utf8 */
예제 #4
0
cache_inode_status_t cache_inode_rdwr(cache_entry_t * pentry,
                                      cache_inode_io_direction_t read_or_write,
                                      fsal_seek_t * seek_descriptor,
                                      fsal_size_t buffer_size,
                                      fsal_size_t * pio_size,
                                      fsal_attrib_list_t * pfsal_attr,
                                      caddr_t buffer,
                                      fsal_boolean_t * p_fsal_eof,
                                      hash_table_t * ht,
                                      cache_inode_client_t * pclient,
                                      fsal_op_context_t * pcontext,
                                      uint64_t stable, 
				      cache_inode_status_t * pstatus)
{
  int statindex = 0;
  cache_content_io_direction_t io_direction;
  cache_content_status_t cache_content_status;
  fsal_status_t fsal_status;
  fsal_openflags_t openflags;
  fsal_size_t io_size;
  fsal_attrib_list_t post_write_attr;
  fsal_status_t fsal_status_getattr;
  struct stat buffstat;

  /* Set the return default to CACHE_INODE_SUCCESS */
  *pstatus = CACHE_INODE_SUCCESS;

  /* For now, only FSAL_SEEK_SET is supported */
  if(seek_descriptor->whence != FSAL_SEEK_SET)
    {
      LogCrit(COMPONENT_CACHE_INODE,
              "Implementation trouble: seek_descriptor was not a 'FSAL_SEEK_SET' cursor");
      *pstatus = CACHE_INODE_INVALID_ARGUMENT;
      return *pstatus;
    }

  io_size = buffer_size;

  LogDebug(COMPONENT_CACHE_INODE,
           "cache_inode_rdwr: INODE : IO Size = %llu fdsize =%zu seeksize=%zu",
           buffer_size, sizeof(fsal_file_t), sizeof(fsal_seek_t));

  /* stat */
  pclient->stat.nb_call_total += 1;
  if(read_or_write == CACHE_INODE_READ)
    {
      statindex = CACHE_INODE_READ_DATA;
      io_direction = CACHE_CONTENT_READ;
      openflags = FSAL_O_RDONLY;
      pclient->stat.func_stats.nb_call[CACHE_INODE_READ_DATA] += 1;
    }
  else
    {
      statindex = CACHE_INODE_WRITE_DATA;
      io_direction = CACHE_CONTENT_WRITE;
      openflags = FSAL_O_WRONLY;
      pclient->stat.func_stats.nb_call[CACHE_INODE_WRITE_DATA] += 1;
    }

  P_w(&pentry->lock);

  /* IO are done only on REGULAR_FILEs */
  if(pentry->internal_md.type != REGULAR_FILE)
    {
      *pstatus = CACHE_INODE_BAD_TYPE;
      V_w(&pentry->lock);

      /* stats */
      pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;

      return *pstatus;
    }

  /* Non absolute address within the file are not supported (we act only like pread/pwrite) */
  if(seek_descriptor->whence != FSAL_SEEK_SET)
    {
      *pstatus = CACHE_INODE_INVALID_ARGUMENT;
      V_w(&pentry->lock);

      /* stats */
      pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;

      return *pstatus;
    }

  /* Do we use stable or unstable storage ? */
  if(stable == FSAL_UNSAFE_WRITE_TO_GANESHA_BUFFER)
    {
      /* Data will be stored in memory and not flush to FSAL */

      /* If the unstable_data buffer allocated ? */
      if(pentry->object.file.unstable_data.buffer == NULL)
        {
          if((pentry->object.file.unstable_data.buffer =
              Mem_Alloc_Label(CACHE_INODE_UNSTABLE_BUFFERSIZE,
                              "Cache_Inode Unstable Buffer")) == NULL)
            {
              *pstatus = CACHE_INODE_MALLOC_ERROR;
              V_w(&pentry->lock);

              /* stats */
              pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;

              return *pstatus;
            }

          pentry->object.file.unstable_data.offset = seek_descriptor->offset;
          pentry->object.file.unstable_data.length = buffer_size;

          memcpy(pentry->object.file.unstable_data.buffer, buffer, buffer_size);

          /* Set mtime and ctime */
          cache_inode_set_time_current( &pentry->attributes.mtime ) ;  

          /* BUGAZOMEU : write operation must NOT modify file's ctime */
          pentry->attributes.ctime = pentry->attributes.mtime;

          *pio_size = buffer_size;
        }                       /* if( pentry->object.file.unstable_data.buffer == NULL ) */
      else
        {
          if((pentry->object.file.unstable_data.offset < seek_descriptor->offset) &&
             (buffer_size + seek_descriptor->offset < CACHE_INODE_UNSTABLE_BUFFERSIZE))
            {
              pentry->object.file.unstable_data.length =
                  buffer_size + seek_descriptor->offset;
              memcpy((char *)(pentry->object.file.unstable_data.buffer +
                              seek_descriptor->offset), buffer, buffer_size);

              /* Set mtime and ctime */
              cache_inode_set_time_current( &pentry->attributes.mtime ) ;

              /* BUGAZOMEU : write operation must NOT modify file's ctime */
              pentry->attributes.ctime = pentry->attributes.mtime;

              *pio_size = buffer_size;
            }
          else
            {
              /* Go back to regular situation */
              stable = FSAL_SAFE_WRITE_TO_FS;
            }
        }

    }
  /* if( stable == FALSE ) */
  if(stable == FSAL_SAFE_WRITE_TO_FS ||
     stable == FSAL_UNSAFE_WRITE_TO_FS_BUFFER)
    {
      /* Calls file content cache to operate on the cache */
      if(pentry->object.file.pentry_content != NULL)
        {
          /* Entry is data cached */
          cache_content_rdwr(pentry->object.file.pentry_content,
                             io_direction,
                             seek_descriptor,
                             &io_size,
                             pio_size,
                             buffer,
                             p_fsal_eof,
                             &buffstat,
                             (cache_content_client_t *) pclient->pcontent_client,
                             pcontext, &cache_content_status);

          /* If the entry under resync */
          if(cache_content_status == CACHE_CONTENT_LOCAL_CACHE_NOT_FOUND)
            {
              /* Data cache gc has removed this entry */
              if(cache_content_new_entry(pentry,
                                         NULL,
                                         (cache_content_client_t *)pclient->pcontent_client, 
                                         RENEW_ENTRY, pcontext,
                                         &cache_content_status) == NULL)
                {
                  /* Entry could not be recoverd, cache_content_status contains an error, let it be managed by the next block */
                  LogCrit(COMPONENT_CACHE_INODE,
                          "Read/Write Operation through cache failed with status %d (renew process failed)",
                          cache_content_status);

		  /* Will go to the end of the function on the error clause with cache_content_status describing the error */
                }
              else
                {
                  /* Entry was successfully renewed */
                  LogInfo(COMPONENT_CACHE_INODE,
                          "----> File Content Entry %p was successfully renewed",
                          pentry);

                  /* Try to access the content of the file again */
                  cache_content_rdwr(pentry->object.file.pentry_content,
                                     io_direction,
                                     seek_descriptor,
                                     &io_size,
                                     pio_size,
                                     buffer,
                                     p_fsal_eof,
                                     &buffstat,
                                     (cache_content_client_t *) pclient->pcontent_client,
                                     pcontext, &cache_content_status);

                  /* No management of cache_content_status in case of failure, this will be done
                   * within the next block */
                }

            }

          if(cache_content_status != CACHE_CONTENT_SUCCESS)
            {
              *pstatus = cache_content_error_convert(cache_content_status);

              V_w(&pentry->lock);

              LogCrit(COMPONENT_CACHE_INODE,
                      "Read/Write Operation through cache failed with status %d",
                      cache_content_status);

              /* stats */
              pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;

              return *pstatus;
            }

          LogFullDebug(COMPONENT_CACHE_INODE,
                       "cache_inode_rdwr: inode/dc: io_size=%llu, pio_size=%llu,  eof=%d, seek=%d.%"PRIu64,
                       io_size, *pio_size, *p_fsal_eof, seek_descriptor->whence,
                       seek_descriptor->offset);

          LogMidDebug(COMPONENT_CACHE_INODE,
                       "cache_inode_rdwr: INODE  AFTER : IO Size = %llu %llu",
                       io_size, *pio_size);

          /* Use information from the buffstat to update the file metadata */
          pentry->attributes.filesize = buffstat.st_size;
          pentry->attributes.spaceused =
              buffstat.st_blksize * buffstat.st_blocks;

        }
      else
        {
          /* No data cache entry, we operated directly on FSAL */
          pentry->attributes.asked_attributes = pclient->attrmask;

          /* We need to open if we don't have a cached
           * descriptor or our open flags differs.
           */
          if(cache_inode_open(pentry,
                              pclient,
                              openflags, pcontext, pstatus) != CACHE_INODE_SUCCESS)
            {
              V_w(&pentry->lock);

              /* stats */
              pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;

              return *pstatus;
            }

          /* Call FSAL_read or FSAL_write */

          if(read_or_write == CACHE_INODE_READ)
            {
#ifdef _USE_MFSL
              fsal_status = MFSL_read(&(pentry->object.file.open_fd.mfsl_fd),
                                      seek_descriptor,
                                      io_size,
                                      buffer,
                                      pio_size, p_fsal_eof, &pclient->mfsl_context, NULL);
#else
              fsal_status = FSAL_read(&(pentry->object.file.open_fd.fd),
                                      seek_descriptor,
                                      io_size, buffer, pio_size, p_fsal_eof);
#endif
            }
          else
            {
#ifdef _USE_MFSL
              fsal_status = MFSL_write(&(pentry->object.file.open_fd.mfsl_fd),
                                       seek_descriptor,
                                       io_size, buffer, pio_size, &pclient->mfsl_context, NULL);
#else
              fsal_status = FSAL_write(&(pentry->object.file.open_fd.fd),
                                       seek_descriptor, io_size, buffer, pio_size);
#endif

#if 0
              /* Alright, the unstable write is complete. Now if it was supposed to be a stable write
               * we can sync to the hard drive. */
              if(stable == FSAL_SAFE_WRITE_TO_FS)
                {
#ifdef _USE_MFSL
                  fsal_status = MFSL_commit(&(pentry->object.file.open_fd.mfsl_fd), NULL);
#else
                  fsal_status = FSAL_commit(&(pentry->object.file.open_fd.fd));
#endif
#endif

            }

          LogFullDebug(COMPONENT_FSAL,
                       "cache_inode_rdwr: FSAL IO operation returned %d, asked_size=%llu, effective_size=%llu",
                       fsal_status.major, (unsigned long long)io_size,
                       (unsigned long long)*pio_size);

          if(FSAL_IS_ERROR(fsal_status))
            {

              if(fsal_status.major == ERR_FSAL_DELAY)
                LogEvent(COMPONENT_CACHE_INODE,
                         "cache_inode_rdwr: FSAL_write returned EBUSY");
              else
                LogDebug(COMPONENT_CACHE_INODE,
                         "cache_inode_rdwr: fsal_status.major = %d",
                         fsal_status.major);

              if((fsal_status.major != ERR_FSAL_NOT_OPENED)
                 && (pentry->object.file.open_fd.fileno != 0))
                {

                  LogDebug(COMPONENT_CACHE_INODE,
                               "cache_inode_rdwr: CLOSING pentry %p: fd=%d",
                               pentry, pentry->object.file.open_fd.fileno);

#ifdef _USE_MFSL
                  MFSL_close(&(pentry->object.file.open_fd.mfsl_fd), &pclient->mfsl_context, NULL);
#else
                  FSAL_close(&(pentry->object.file.open_fd.fd));
#endif

                  *pstatus = cache_inode_error_convert(fsal_status);
                }
              else
                {
                  /* the fd has been close by another thread.
                   * return CACHE_INODE_FSAL_DELAY so the client will
                   * retry with a new fd.
                   */
                  *pstatus = CACHE_INODE_FSAL_DELAY;
                }

              pentry->object.file.open_fd.last_op = 0;
              pentry->object.file.open_fd.fileno = 0;

              V_w(&pentry->lock);

              /* stats */
              pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;

              return *pstatus;
            }

          LogFullDebug(COMPONENT_CACHE_INODE,
                       "cache_inode_rdwr: inode/direct: io_size=%llu, pio_size=%llu, eof=%d, seek=%d.%"PRIu64,
                       io_size, *pio_size, *p_fsal_eof, seek_descriptor->whence,
                       seek_descriptor->offset);

          if(cache_inode_close(pentry, pclient, pstatus) != CACHE_INODE_SUCCESS)
            {
              LogEvent(COMPONENT_CACHE_INODE,
                       "cache_inode_rdwr: cache_inode_close = %d", *pstatus);

              V_w(&pentry->lock);

              /* stats */
              pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;

              return *pstatus;
            }

          if(read_or_write == CACHE_INODE_WRITE)
            {
              /* Do a getattr in order to have update information on filesize
               * This query is done directly on FSAL (object is not data cached), and result
               * will be propagated to cache Inode */

              /* WARNING: This operation is to be done AFTER FSAL_close (some FSAL, like POSIX,
               * may not flush data until the file is closed */

              /*post_write_attr.asked_attributes =  pclient->attrmask ; */
              post_write_attr.asked_attributes = FSAL_ATTR_SIZE | FSAL_ATTR_SPACEUSED;
              fsal_status_getattr =
                  FSAL_getattrs(&(pentry->handle), pcontext,
                                &post_write_attr);

              /* if failed, the next block will handle the error */
              if(FSAL_IS_ERROR(fsal_status_getattr))
                fsal_status = fsal_status_getattr;
              else
                {
                  /* Update Cache Inode attributes */
                  pentry->attributes.filesize = post_write_attr.filesize;
                  pentry->attributes.spaceused = post_write_attr.spaceused;
                }
            }

        }

      /* IO was successfull (through cache content or not), we manually update the times in the attributes */

      switch (read_or_write)
        {
        case CACHE_INODE_READ:
          /* Set the atime */
          cache_inode_set_time_current( & pentry->attributes.atime ) ;
          break;

        case CACHE_INODE_WRITE:
          /* Set mtime and ctime */
          cache_inode_set_time_current( & pentry->attributes.mtime ) ;

          /* BUGAZOMEU : write operation must NOT modify file's ctime */
          pentry->attributes.ctime = pentry->attributes.mtime;

          break;
        }
    }

  /* if(stable == TRUE ) */
  /* Return attributes to caller */
  if(pfsal_attr != NULL)
    *pfsal_attr = pentry->attributes;

  *pstatus = CACHE_INODE_SUCCESS;

  /* stat */
  if(read_or_write == CACHE_INODE_READ)
    {
      *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient);

      if(*pstatus != CACHE_INODE_SUCCESS)
        pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_READ] += 1;
      else
        pclient->stat.func_stats.nb_success[CACHE_INODE_READ] += 1;
    }
  else
    {
      *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_SET, pclient);

      if(*pstatus != CACHE_INODE_SUCCESS)
        pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_WRITE] += 1;
      else
        pclient->stat.func_stats.nb_success[CACHE_INODE_WRITE] += 1;
    }

  V_w(&pentry->lock);

  return *pstatus;
}                               /* cache_inode_rdwr */
예제 #5
0
int _9p_readdir( _9p_request_data_t * preq9p, 
                 void  * pworker_data,
                 u32 * plenout, 
                 char * preply)
{
  char * cursor = preq9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE ;
  nfs_worker_data_t * pwkrdata = (nfs_worker_data_t *)pworker_data ;

  int rc = 0 ;
  u32 err = 0 ;

  u16 * msgtag = NULL ;
  u32 * fid    = NULL ;
  u64 * offset = NULL ;
  u32 * count  = NULL ;

  u32  dcount      = 0 ;
  u32  recsize     = 0 ;
  u16  name_len    = 0 ;
  
  char * name_str = NULL ;

  u8  * qid_type    = NULL ;
  u64 * qid_path    = NULL ;

  char * dcount_pos = NULL ;

  cache_inode_status_t cache_status;
  cache_inode_dir_entry_t **dirent_array = NULL;
  cache_inode_endofdir_t eod_met;
  cache_entry_t * pentry_dot_dot = NULL ;

  cache_inode_dir_entry_t dirent_dot     ;
  cache_inode_dir_entry_t dirent_dot_dot ;

  unsigned int cookie = 0;
  unsigned int end_cookie = 0;
  unsigned int estimated_num_entries = 0 ;
  unsigned int num_entries = 0 ;
  unsigned int delta = 0 ;
  int unlock = FALSE ;
  u64 i = 0LL ;

  if ( !preq9p || !pworker_data || !plenout || !preply )
   return -1 ;

  _9p_fid_t * pfid = NULL ;

  /* Get data */
  _9p_getptr( cursor, msgtag, u16 ) ; 
  _9p_getptr( cursor, fid,    u32 ) ; 
  _9p_getptr( cursor, offset, u64 ) ; 
  _9p_getptr( cursor, count,  u32 ) ; 
  
  LogDebug( COMPONENT_9P, "TREADDIR: tag=%u fid=%u offset=%llu count=%u",
            (u32)*msgtag, *fid, (unsigned long long)*offset, *count  ) ;

  if( *fid >= _9P_FID_PER_CONN )
    {
      err = ERANGE ;
      rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ;
      return rc ;
    }

   pfid = &preq9p->pconn->fids[*fid] ;

  /* Use Cache Inode to read the directory's content */
  cookie = (unsigned int)*offset ;
 
  /* For each entry, returns: 
   * qid     = 13 bytes 
   * offset  = 8 bytes
   * type    = 1 byte
   * namelen = 2 bytes
   * namestr = ~16 bytes (average size)
   * -------------------
   * total   = ~40 bytes (average size) per dentry */ 
  estimated_num_entries = (unsigned int)( *count / 40 ) ;  

  if((dirent_array = (cache_inode_dir_entry_t **) Mem_Alloc_Label(
          estimated_num_entries * sizeof(cache_inode_dir_entry_t*),
          "cache_inode_dir_entry_t in _9p_readdir")) == NULL)
    {
      err = EIO ;
      rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ;
      return rc ;
    }

  /* Is this the first request ? */
  if( *offset == 0 )
   {
      /* compute the parent entry */
      if( ( pentry_dot_dot = cache_inode_lookupp( pfid->pentry,
                                                  pwkrdata->ht,
                                                  &pwkrdata->cache_inode_client,
                                                  &pfid->fsal_op_context, 
                                                  &cache_status) ) == NULL )
        {
           err = _9p_tools_errno( cache_status ) ; ;
           rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ;
           return rc ;
        }

      /* Deal with "." and ".." */
      dirent_dot.pentry = pfid->pentry ;
      strcpy( dirent_dot.name.name, "." ) ;
      dirent_dot.name.len = strlen( dirent_dot.name.name ) ;
      dirent_array[0] = &dirent_dot ;

      dirent_dot_dot.pentry = pentry_dot_dot ;
      strcpy( dirent_dot_dot.name.name, ".." ) ;
      dirent_dot_dot.name.len = strlen( dirent_dot_dot.name.name ) ;
      dirent_array[1] = &dirent_dot_dot ;
 
      delta = 2 ;
   }
  else
   delta = 0 ;

  if( *offset == 2 )
   {
      /* offset == 2 as an input as one and only reason:
       *   - a former call with offset=0 was made and the dir was empty
       *   - '.' and '..' were returned and nothing else
       *   - the client makes a new call, expecting it to have empty return
       */
      num_entries = 0 ; /* Empty return */
      unlock = FALSE ;
   }
  else if(cache_inode_readdir( pfid->pentry,
                          pfid->pexport->cache_inode_policy,
                          cookie,
                          estimated_num_entries - delta,
                          &num_entries,
                          (uint64_t *)&end_cookie,
                          &eod_met,
                          &dirent_array[delta],
                          pwkrdata->ht,
                          &unlock,
                          &pwkrdata->cache_inode_client,
                          &pfid->fsal_op_context, 
                          &cache_status) != CACHE_INODE_SUCCESS)
    {
      if( unlock ) V_r( &pfid->pentry->lock ) ;

      err = _9p_tools_errno( cache_status ) ; ;
      rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ;
      return rc ;
    }

  /* Unlock the directory if needed */
  if( unlock ) V_r( &pfid->pentry->lock ) ;

  /* Never go behind _9P_MAXDIRCOUNT */
  if( num_entries > _9P_MAXDIRCOUNT ) num_entries = _9P_MAXDIRCOUNT ;


  /* Build the reply */
  _9p_setinitptr( cursor, preply, _9P_RREADDIR ) ;
  _9p_setptr( cursor, msgtag, u16 ) ;

  /* Remember dcount position for later use */
  _9p_savepos( cursor, dcount_pos, u32 ) ;

  /* fills in the dentry in 9P marshalling */
  for( i = 0 ; i < num_entries + delta ; i++ )
   {
     recsize = 0 ; 

     /* Build qid */
     switch( dirent_array[i]->pentry->internal_md.type )
      {
        case REGULAR_FILE:
          qid_path = (u64 *)&dirent_array[i]->pentry->object.file.attributes.fileid ;
          qid_type = &qid_type_file ;
	  break ;

        case CHARACTER_FILE:
        case BLOCK_FILE:
        case SOCKET_FILE:
        case FIFO_FILE:
          qid_path = (u64 *)&dirent_array[i]->pentry->object.special_obj.attributes.fileid ;
          qid_type = &qid_type_file ;
	  break ;

        case SYMBOLIC_LINK:
          qid_path = (u64 *)&dirent_array[i]->pentry->object.symlink->attributes.fileid ;
          qid_type = &qid_type_symlink;
	  break ;

        case DIRECTORY:
        case FS_JUNCTION:
          qid_path = (u64 *)&dirent_array[i]->pentry->object.dir.attributes.fileid ;
          qid_type = &qid_type_dir ;
	  break ;

        case UNASSIGNED:
        case RECYCLED:
        default:
          LogMajor( COMPONENT_9P, "implementation error, you should not see this message !!!!!!" ) ;
          err = EINVAL ;
          rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ;
          return rc ;
          break ;
      }

     /* Get dirent name information */
     name_str = dirent_array[i]->name.name ;
     name_len = dirent_array[i]->name.len ;
 
     /* Add 13 bytes in recsize for qid + 8 bytes for offset + 1 for type + 2 for strlen = 24 bytes*/
     recsize = 24 + name_len  ;

     /* Check if there is room left for another dentry */
     if( dcount + recsize > *count )
       break ; /* exit for loop */
     else
       dcount += recsize ;

     /* qid in 3 parts */
     _9p_setptr( cursor, qid_type, u8 ) ;
     _9p_setvalue( cursor, 0, u32 ) ; /* qid_version set to 0 to prevent the client from caching */
     _9p_setptr( cursor, qid_path, u64 ) ;
     
     /* offset */
     _9p_setvalue( cursor, i+cookie+1, u64 ) ;   

     /* Type (again ?) */
     _9p_setptr( cursor, qid_type, u8 ) ;

     /* name */
     _9p_setstr( cursor, name_len, name_str ) ;
  
     LogDebug( COMPONENT_9P, "RREADDIR dentry: recsize=%u dentry={ off=%llu,qid=(type=%u,version=%u,path=%llu),type=%u,name=%s,pentry=%p",
               recsize, (unsigned long long)i+cookie+1, *qid_type, 0, (unsigned long long)*qid_path, 
               *qid_type, name_str, dirent_array[i]->pentry ) ;
   } /* for( i = 0 , ... ) */

  if( !CACHE_INODE_KEEP_CONTENT( pfid->pentry->policy ) )
    cache_inode_release_dirent( dirent_array, num_entries, &pwkrdata->cache_inode_client ) ;
  Mem_Free((char *)dirent_array);

  
  /* Set buffsize in previously saved position */
  _9p_setvalue( dcount_pos, dcount, u32 ) ; 

  _9p_setendptr( cursor, preply ) ;
  _9p_checkbound( cursor, preply, plenout ) ;

  LogDebug( COMPONENT_9P, "RREADDIR: tag=%u fid=%u dcount=%u",
            (u32)*msgtag, *fid , dcount ) ;

  return 1 ;
}
예제 #6
0
int nfs4_op_readlink(struct nfs_argop4 *op,
                     compound_data_t * data, struct nfs_resop4 *resp)
{
  cache_inode_status_t cache_status;
  fsal_path_t symlink_path;

  char __attribute__ ((__unused__)) funcname[] = "nfs4_op_readlink";

  resp->resop = NFS4_OP_READLINK;
  res_READLINK4.status = NFS4_OK;

  /* If there is no FH */
  if(nfs4_Is_Fh_Empty(&(data->currentFH)))
    {
      res_READLINK4.status = NFS4ERR_NOFILEHANDLE;
      return NFS4ERR_NOFILEHANDLE;
    }

  /* If the filehandle is invalid */
  if(nfs4_Is_Fh_Invalid(&(data->currentFH)))
    {
      res_READLINK4.status = NFS4ERR_BADHANDLE;
      return NFS4ERR_BADHANDLE;
    }

  /* Tests if the Filehandle is expired (for volatile filehandle) */
  if(nfs4_Is_Fh_Expired(&(data->currentFH)))
    {
      res_READLINK4.status = NFS4ERR_FHEXPIRED;
      return NFS4ERR_FHEXPIRED;
    }

  /* You can readlink only on a link ... */
  if(data->current_filetype != SYMBOLIC_LINK)
    {
      /* As said on page 194 of RFC3530, return NFS4ERR_INVAL in this case */
      res_READLINK4.status = NFS4ERR_INVAL;
      return res_READLINK4.status;
    }

  /* Using cache_inode_readlink */
  if(cache_inode_readlink(data->current_entry,
                          &symlink_path,
                          data->ht,
                          data->pclient,
                          data->pcontext, &cache_status) == CACHE_INODE_SUCCESS)
    {
      /* Alloc read link */

      if((res_READLINK4.READLINK4res_u.resok4.link.utf8string_val =
          (char *)Mem_Alloc_Label(symlink_path.len, "nfs4_op_readlink")) == NULL)
        {
          res_READLINK4.status = NFS4ERR_INVAL;
          return res_READLINK4.status;
        }

      /* convert the fsal path to a utf8 string */
      if(str2utf8((char *)symlink_path.path, &res_READLINK4.READLINK4res_u.resok4.link)
         == -1)
        {
          res_READLINK4.status = NFS4ERR_INVAL;
          return res_READLINK4.status;
        }

      res_READLINK4.status = NFS4_OK;
      return res_READLINK4.status;
    }

  res_READLINK4.status = nfs4_Errno(cache_status);
  return res_READLINK4.status;
}                               /* nfs4_op_readlink */
예제 #7
0
int nlm_process_parameters(struct svc_req        * preq,
                           bool_t                  exclusive,
                           nlm4_lock             * alock,
                           state_lock_desc_t     * plock,
                           hash_table_t          * ht,
                           cache_entry_t        ** ppentry,
                           fsal_op_context_t     * pcontext,
                           cache_inode_client_t  * pclient,
                           care_t                  care,
                           state_nsm_client_t   ** ppnsm_client,
                           state_nlm_client_t   ** ppnlm_client,
                           state_owner_t        ** ppowner,
                           state_block_data_t   ** ppblock_data)
{
  cache_inode_fsal_data_t fsal_data;
  fsal_attrib_list_t      attr;
  cache_inode_status_t    cache_status;
  SVCXPRT                *ptr_svc = preq->rq_xprt;

  *ppnsm_client = NULL;
  *ppnlm_client = NULL;
  *ppowner      = NULL;

  /* Convert file handle into a cache entry */
  if(alock->fh.n_len > MAX_NETOBJ_SZ ||
     !nfs3_FhandleToFSAL((nfs_fh3 *) &alock->fh, &fsal_data.handle, pcontext))
    {
      /* handle is not valid */
      return NLM4_STALE_FH;
    }

  /* Now get the cached inode attributes */
  fsal_data.cookie = DIR_START;
  *ppentry = cache_inode_get(&fsal_data,
                             CACHE_INODE_JOKER_POLICY,
                             &attr,
                             ht,
                             pclient,
                             pcontext,
                             &cache_status);
  if(*ppentry == NULL)
    {
      /* handle is not valid */
      return NLM4_STALE_FH;
    }

  *ppnsm_client = get_nsm_client(care, ptr_svc, alock->caller_name);

  if(*ppnsm_client == NULL)
    {
      /* If NSM Client is not found, and we don't care (such as unlock),
       * just return GRANTED (the unlock must succeed, there can't be
       * any locks).
       */
      if(care != CARE_NOT)
        return NLM4_DENIED_NOLOCKS;
      else
        return NLM4_GRANTED;
    }

  *ppnlm_client = get_nlm_client(care, ptr_svc, *ppnsm_client, alock->caller_name);

  if(*ppnlm_client == NULL)
    {
      /* If NLM Client is not found, and we don't care (such as unlock),
       * just return GRANTED (the unlock must succeed, there can't be
       * any locks).
       */
      dec_nsm_client_ref(*ppnsm_client);

      if(care != CARE_NOT)
        return NLM4_DENIED_NOLOCKS;
      else
        return NLM4_GRANTED;
    }

  *ppowner = get_nlm_owner(care, *ppnlm_client, &alock->oh, alock->svid);

  if(*ppowner == NULL)
    {
      LogDebug(COMPONENT_NLM,
               "Could not get NLM Owner");
      dec_nsm_client_ref(*ppnsm_client);
      dec_nlm_client_ref(*ppnlm_client);
      *ppnlm_client = NULL;

      /* If owner is not found, and we don't care (such as unlock),
       * just return GRANTED (the unlock must succeed, there can't be
       * any locks).
       */
      if(care)
        return NLM4_DENIED_NOLOCKS;
      else
        return NLM4_GRANTED;
    }

  if(ppblock_data != NULL)
    {
      *ppblock_data = (state_block_data_t *) Mem_Alloc_Label(sizeof(**ppblock_data),
                                                             "NLM_Block_Data");
      /* Fill in the block data, if we don't get one, we will just proceed
       * without (which will mean the lock doesn't block.
       */
      if(*ppblock_data != NULL)
        {
          memset(*ppblock_data, 0, sizeof(**ppblock_data));
          if(copy_xprt_addr(&(*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_hostaddr, ptr_svc) == 0)
            {
              LogFullDebug(COMPONENT_NLM,
                           "copy_xprt_addr failed for Program %d, Version %d, Function %d",
                           (int)preq->rq_prog, (int)preq->rq_vers, (int)preq->rq_proc);
              Mem_Free(*ppblock_data);
              *ppblock_data = NULL;
              return NLM4_FAILED;
            }
          (*ppblock_data)->sbd_granted_callback = nlm_granted_callback;
          (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh.n_bytes =
            (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh_buf;
          (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh.n_len = alock->fh.n_len;
          memcpy((*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh_buf,
                 alock->fh.n_bytes,
                 alock->fh.n_len);
          /* FSF TODO: Ultimately I think the following will go away, we won't need the context, just the export */
          /* Copy credentials from pcontext */
          (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_credential = pcontext->credential;
        }
    }
  /* Fill in plock */
  plock->sld_type   = exclusive ? STATE_LOCK_W : STATE_LOCK_R;
  plock->sld_offset = alock->l_offset;
  plock->sld_length = alock->l_len;

  LogFullDebug(COMPONENT_NLM,
               "Parameters Processed");

  return -1;
}
예제 #8
0
SVCXPRT *Svcudp_bufcreate(register int sock, u_int sendsz, u_int recvsz)
{
  bool_t madesock = FALSE;
  register SVCXPRT *xprt;
  register struct Svcudp_data *su;
  struct sockaddr_in addr;
  unsigned long len = sizeof(struct sockaddr_in);

  if(sock == RPC_ANYSOCK)
    {
      if((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
        {
          perror("Svcudp_create: socket creation problem");
          return ((SVCXPRT *) NULL);
        }
      madesock = TRUE;
    }

  memset(&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;
  if(bindresvport(sock, &addr))
    {
      addr.sin_port = 0;
      (void)bind(sock, (struct sockaddr *)&addr, len);
    }

  if(getsockname(sock, (struct sockaddr *)&addr, (socklen_t *) & len) != 0)
    {
      perror("Svcudp_create - cannot getsockname");
      if(madesock)
        (void)close(sock);
      return ((SVCXPRT *) NULL);
    }

  xprt = (SVCXPRT *) Mem_Alloc_Label(sizeof(SVCXPRT), "SVCXPRT (UDP)");
  if(xprt == NULL)
    {
      return (NULL);
    }

  su = (struct Svcudp_data *)Mem_Alloc_Label(sizeof(*su), "struct Svcudp_data");

  if(su == NULL)
    {
      Mem_Free( xprt ) ;
      return (NULL);
    }

  su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4;
  if((rpc_buffer(xprt) = Mem_Alloc_Label(su->su_iosz, "UDP IO Buffer")) == NULL)
    {
      Mem_Free( su ) ;
      Mem_Free( xprt ) ;
      return (NULL);
    }

  xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE);
  xprt->xp_p2 = (caddr_t) su;
  xprt->xp_verf.oa_base = su->su_verfbody;
  xprt->xp_ops = &Svcudp_op;
  xprt->xp_port = ntohs(addr.sin_port);
  xprt->XP_SOCK = sock;

  Xprt_register(xprt);

  return (xprt);
}
예제 #9
0
cache_inode_status_t cache_inode_open_by_name(cache_entry_t * pentry_dir,
                                              fsal_name_t * pname,
                                              cache_entry_t * pentry_file,
                                              cache_inode_client_t * pclient,
                                              fsal_openflags_t openflags,
                                              fsal_op_context_t * pcontext,
                                              cache_inode_status_t * pstatus)
{
  fsal_status_t fsal_status;
  fsal_size_t save_filesize = 0;
  fsal_size_t save_spaceused = 0;
  fsal_time_t save_mtime = {
    .seconds = 0,
    .nseconds = 0
  };

  if((pentry_dir == NULL) || (pname == NULL) || (pentry_file == NULL) ||
     (pclient == NULL) || (pcontext == NULL) || (pstatus == NULL))
    return CACHE_INODE_INVALID_ARGUMENT;

  if((pentry_dir->internal_md.type != DIRECTORY))
    {
      *pstatus = CACHE_INODE_BAD_TYPE;
      return *pstatus;
    }

  if(pentry_file->internal_md.type != REGULAR_FILE)
    {
      *pstatus = CACHE_INODE_BAD_TYPE;
      return *pstatus;
    }

  /* Open file need to be closed, unless it is already open as read/write */
  if((pentry_file->object.file.open_fd.openflags != FSAL_O_RDWR) &&
     (pentry_file->object.file.open_fd.openflags != 0) &&
     (pentry_file->object.file.open_fd.fileno >= 0) &&
     (pentry_file->object.file.open_fd.openflags != openflags))
    {
#ifdef _USE_MFSL
      fsal_status =
          MFSL_close(&(pentry_file->object.file.open_fd.mfsl_fd), &pclient->mfsl_context, NULL);
#else
      fsal_status = FSAL_close(&(pentry_file->object.file.open_fd.fd));
#endif
      if(FSAL_IS_ERROR(fsal_status) && (fsal_status.major != ERR_FSAL_NOT_OPENED))
        {
          *pstatus = cache_inode_error_convert(fsal_status);

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_open_by_name: returning %d(%s) from FSAL_close",
                   *pstatus, cache_inode_err_str(*pstatus));

          return *pstatus;
        }

      pentry_file->object.file.open_fd.last_op = 0;
      pentry_file->object.file.open_fd.fileno = 0;
    }

  if(pentry_file->object.file.open_fd.last_op == 0
     || pentry_file->object.file.open_fd.fileno == 0)
    {
      LogDebug(COMPONENT_FSAL,
               "cache_inode_open_by_name: pentry %p: lastop=0", pentry_file);

      /* Keep coherency with the cache_content */
      if(pentry_file->object.file.pentry_content != NULL)
        {
          save_filesize = pentry_file->object.file.attributes.filesize;
          save_spaceused = pentry_file->object.file.attributes.spaceused;
          save_mtime = pentry_file->object.file.attributes.mtime;
        }

      /* opened file is not preserved yet */
#ifdef _USE_MFSL
      fsal_status = MFSL_open_by_name(&(pentry_dir->mobject),
                                      pname,
                                      pcontext,
                                      &pclient->mfsl_context,
                                      openflags,
                                      &pentry_file->object.file.open_fd.mfsl_fd,
                                      &(pentry_file->object.file.attributes),
#ifdef _USE_PNFS
                                      &pentry_file->object.file.pnfs_file ) ;
#else
                                      NULL );
#endif /* _USE_PNFS */

#else
      fsal_status = FSAL_open_by_name(&(pentry_dir->object.file.handle),
                                      pname,
                                      pcontext,
                                      openflags,
                                      &pentry_file->object.file.open_fd.fd,
                                      &(pentry_file->object.file.attributes));
#endif

      if(FSAL_IS_ERROR(fsal_status))
        {
          *pstatus = cache_inode_error_convert(fsal_status);

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_open_by_name: returning %d(%s) from FSAL_open_by_name",
                   *pstatus, cache_inode_err_str(*pstatus));

          return *pstatus;
        }

#ifdef _USE_PROXY

      /* If proxy if used, we should keep the name of the file to do FSAL_rcp if needed */
      if((pentry_file->object.file.pname =
          (fsal_name_t *) Mem_Alloc_Label(sizeof(fsal_name_t), "fsal_name_t")) == NULL)
        {
          *pstatus = CACHE_INODE_MALLOC_ERROR;

          return *pstatus;
        }

      pentry_file->object.file.pentry_parent_open = pentry_dir;
      pentry_file->object.file.pname->len = pname->len;
      memcpy((char *)(pentry_file->object.file.pname->name), (char *)(pname->name),
             FSAL_MAX_NAME_LEN);

#endif

      /* Keep coherency with the cache_content */
      if(pentry_file->object.file.pentry_content != NULL)
        {
          pentry_file->object.file.attributes.filesize = save_filesize;
          pentry_file->object.file.attributes.spaceused = save_spaceused;
          pentry_file->object.file.attributes.mtime = save_mtime;
        }

#ifdef _USE_MFSL
      pentry_file->object.file.open_fd.fileno =
          (int)FSAL_FILENO(&(pentry_file->object.file.open_fd.mfsl_fd.fsal_file));
#else
      pentry_file->object.file.open_fd.fileno =
          (int)FSAL_FILENO(&(pentry_file->object.file.open_fd.fd));
#endif
      pentry_file->object.file.open_fd.last_op = time(NULL);
      pentry_file->object.file.open_fd.openflags = openflags;

      LogDebug(COMPONENT_FSAL,
               "cache_inode_open_by_name: pentry %p: fd=%u",
               pentry_file, pentry_file->object.file.open_fd.fileno);

    }

  /* regular exit */
  pentry_file->object.file.open_fd.last_op = time(NULL);

  /* if file descriptor is too high, garbage collect FDs */
  if(pclient->use_fd_cache
     && (pentry_file->object.file.open_fd.fileno > pclient->max_fd))
    {
      if(cache_inode_gc_fd(pclient, pstatus) != CACHE_INODE_SUCCESS)
        {
          LogCrit(COMPONENT_CACHE_INODE_GC,
                  "FAILURE performing FD garbage collection");
          return *pstatus;
        }
    }

  *pstatus = CACHE_INODE_SUCCESS;
  return *pstatus;

}                               /* cache_inode_open_by_name */
예제 #10
0
int nfs3_Readdirplus(nfs_arg_t * parg,
                     exportlist_t * pexport,
                     fsal_op_context_t * pcontext,
                     cache_inode_client_t * pclient,
                     hash_table_t * ht, struct svc_req *preq, nfs_res_t * pres)
{
  static char __attribute__ ((__unused__)) funcName[] = "nfs3_Readdirplus";

  typedef char entry_name_array_item_t[FSAL_MAX_NAME_LEN];
  typedef char fh3_buffer_item_t[NFS3_FHSIZE];

  unsigned int delta = 0;
  cache_entry_t *dir_pentry = NULL;
  cache_entry_t *pentry_dot_dot = NULL;
  unsigned long dircount;
  unsigned long maxcount;
  fsal_attrib_list_t dir_attr;
  fsal_attrib_list_t entry_attr;
  uint64_t begin_cookie;
  uint64_t end_cookie;
  uint64_t cache_inode_cookie;
  cache_inode_dir_entry_t **dirent_array = NULL;
  cookieverf3 cookie_verifier;
  int rc;
  unsigned int i = 0;
  unsigned int num_entries;
  unsigned long space_used;
  unsigned long estimated_num_entries;
  unsigned long asked_num_entries;
  cache_inode_file_type_t dir_filetype;
  cache_inode_endofdir_t eod_met = UNASSIGNED_EOD;
  cache_inode_status_t cache_status;
  cache_inode_status_t cache_status_gethandle;
  fsal_handle_t *pfsal_handle = NULL;
  entry_name_array_item_t *entry_name_array = NULL;
  fh3_buffer_item_t *fh3_array = NULL;
  entryplus3 reference_entry;
  READDIRPLUS3resok reference_reply;
  int dir_pentry_unlock = FALSE;

  if(isDebug(COMPONENT_NFSPROTO) || isDebug(COMPONENT_NFS_READDIR))
    {
      char str[LEN_FH_STR];
      log_components_t component;
      sprint_fhandle3(str, &(parg->arg_readdirplus3.dir));
      if(isDebug(COMPONENT_NFSPROTO))
        component = COMPONENT_NFSPROTO;
      else
        component = COMPONENT_NFS_READDIR;
      LogDebug(component,
               "REQUEST PROCESSING: Calling nfs3_Readdirplus handle: %s", str);
    }

  /* to avoid setting it on each error case */
  pres->res_readdir3.READDIR3res_u.resfail.dir_attributes.attributes_follow = FALSE;

  dircount = parg->arg_readdirplus3.dircount;
  maxcount = parg->arg_readdirplus3.maxcount;
  begin_cookie = (unsigned int)parg->arg_readdirplus3.cookie;

  /* FIXME: This calculation over estimates the number of bytes that 
   * READDIRPLUS3resok will use on the wire by 4 bytes on x86_64. */
  space_used = sizeof(reference_reply.dir_attributes.attributes_follow) +
    sizeof(reference_reply.dir_attributes.post_op_attr_u.attributes) +
    sizeof(reference_reply.cookieverf) +
    sizeof(reference_reply.reply.eof);

  estimated_num_entries =
    (dircount - space_used + sizeof(entry3 *))
    / (sizeof(entry3) - sizeof(char *)*2);
  //  estimated_num_entries *= 4;
  LogFullDebug(COMPONENT_NFS_READDIR,
               "nfs3_Readdirplus: dircount=%lu  maxcount=%lu  begin_cookie=%"
               PRIu64" space_used=%lu  estimated_num_entries=%lu",
               dircount, maxcount, begin_cookie,
               space_used, estimated_num_entries);

  /* Is this a xattr FH ? */
  if(nfs3_Is_Fh_Xattr(&(parg->arg_readdirplus3.dir)))
    return nfs3_Readdirplus_Xattr(parg, pexport, pcontext, pclient, ht, preq, pres);

  /* Convert file handle into a vnode */
  if((dir_pentry = nfs_FhandleToCache(preq->rq_vers,
                                      NULL,
                                      &(parg->arg_readdirplus3.dir),
                                      NULL,
                                      NULL,
                                      &(pres->res_readdirplus3.status),
                                      NULL,
                                      &dir_attr, pcontext, pclient, ht, &rc)) == NULL)
    {
      /* return NFS_REQ_DROP ; */
      return rc;
    }

  /* Extract the filetype */
  dir_filetype = cache_inode_fsal_type_convert(dir_attr.type);

  /* Sanity checks -- must be a directory */

  if(dir_filetype != DIRECTORY)
    {
      pres->res_readdirplus3.status = NFS3ERR_NOTDIR;
      return NFS_REQ_OK;
    }

  /* switch */
  memset(cookie_verifier, 0, sizeof(cookieverf3));

  /*
   * If cookie verifier is used, then an non-trivial value is
   * returned to the client         This value is the mtime of
   * the directory. If verifier is unused (as in many NFS
   * Servers) then only a set of zeros is returned (trivial
   * value)
   */

  if(pexport->UseCookieVerifier)
    memcpy(cookie_verifier, &(dir_attr.mtime), sizeof(dir_attr.mtime));

  /*
   * nothing to do if != 0 because the area is already full of
   * zero
   */

  if(pexport->UseCookieVerifier && (begin_cookie != 0))
    {
      /*
       * Not the first call, so we have to check the cookie
       * verifier
       */
      if(memcmp(cookie_verifier, parg->arg_readdirplus3.cookieverf,
                NFS3_COOKIEVERFSIZE)
         != 0)
        {
          pres->res_readdirplus3.status = NFS3ERR_BAD_COOKIE;

          return NFS_REQ_OK;
        }
    }

  if((dirent_array =
      (cache_inode_dir_entry_t **) Mem_Alloc_Label(
          estimated_num_entries * sizeof(cache_inode_dir_entry_t*),
          "cache_inode_dir_entry_t in nfs3_Readdirplus")) == NULL)
    {
      pres->res_readdirplus3.status = NFS3ERR_IO;
      return NFS_REQ_DROP;
    }

  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = NULL;
  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE;

/** @todo  XXXX fix this--compare nfs4_op_readdir */

  /* How many entries will we retry from cache_inode ? */
  if(begin_cookie > 1)
    {
      asked_num_entries = estimated_num_entries;
      cache_inode_cookie = begin_cookie;
    }
  else
    {
      asked_num_entries = ((estimated_num_entries > 2) ? estimated_num_entries - 2 : 0);        /* Keep space for '.' and '..' */
      cache_inode_cookie = 0;
    }

  /* A definition that will be very useful to avoid very long names for variables */
#define RES_READDIRPLUS_REPLY pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply

  /* Call readdir */
  if(cache_inode_readdir(dir_pentry,
                         pexport->cache_inode_policy,
                         cache_inode_cookie,
                         asked_num_entries,
                         &num_entries,
                         &end_cookie,
                         &eod_met,
                         dirent_array,
                         ht,
                         &dir_pentry_unlock,
                         pclient,
                         pcontext,
                         &cache_status) == CACHE_INODE_SUCCESS)
    {
      LogFullDebug(COMPONENT_NFS_READDIR,
                   "Readdirplus3 -> Call to cache_inode_readdir( cookie=%"
                   PRIu64", asked=%lu ) -> num_entries = %u",
                   cache_inode_cookie, asked_num_entries, num_entries);

      if(eod_met == END_OF_DIR)
        {
          LogFullDebug(COMPONENT_NFS_READDIR,
                       "+++++++++++++++++++++++++++++++++++++++++> EOD MET ");
        }

      /* If nothing was found, return nothing, but if cookie=0, we should return . and .. */
      if((num_entries == 0) && (asked_num_entries != 0) && (begin_cookie > 1))
        {
          pres->res_readdirplus3.status = NFS3_OK;
          pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = NULL;
          pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = TRUE;

          nfs_SetPostOpAttr(pcontext, pexport,
                            dir_pentry,
                            NULL,
                            &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.
                              dir_attributes));

          memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf,
                 cookie_verifier, sizeof(cookieverf3));
        }
      else
        {
          /* Allocation of the structure for reply */
          entry_name_array =
              (entry_name_array_item_t *) Mem_Alloc_Label(estimated_num_entries *
                                                          (FSAL_MAX_NAME_LEN + 1),
                                                          "entry_name_array in nfs3_Readdirplus");

          if(entry_name_array == NULL)
            {
                /* after successful cache_inode_readdir, dir_pentry may be
                 * read locked */
                if (dir_pentry_unlock)
                    V_r(&dir_pentry->lock);
   
              if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) 
                cache_inode_release_dirent( dirent_array, num_entries, pclient ) ;
              Mem_Free((char *)dirent_array);
              return NFS_REQ_DROP;
            }

          pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries =
              (entryplus3 *) Mem_Alloc_Label(estimated_num_entries * sizeof(entryplus3),
                                             "READDIRPLUS3res_u.resok.reply.entries");

          if(pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries == NULL)
            {
                /* after successful cache_inode_readdir, dir_pentry may be
                 * read locked */
                if (dir_pentry_unlock)
                    V_r(&dir_pentry->lock);

              if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) 
               cache_inode_release_dirent( dirent_array, num_entries, pclient ) ;
              Mem_Free((char *)dirent_array);
              Mem_Free((char *)entry_name_array);
              return NFS_REQ_DROP;
            }

          /* Allocation of the file handles */
          fh3_array =
              (fh3_buffer_item_t *) Mem_Alloc_Label(estimated_num_entries * NFS3_FHSIZE,
                                                    "Filehandle V3 in nfs3_Readdirplus");

          if(fh3_array == NULL)
            {
                /* after successful cache_inode_readdir, dir_pentry may be
                 * read locked */
                if (dir_pentry_unlock)
                    V_r(&dir_pentry->lock);

              if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) 
                cache_inode_release_dirent( dirent_array, num_entries, pclient ) ;
              Mem_Free((char *)dirent_array);
              Mem_Free((char *)entry_name_array);

              return NFS_REQ_DROP;
            }

          delta = 0;

          /* manage . and .. */
          if(begin_cookie == 0)
            {
              /* Fill in '.' */
              if(estimated_num_entries > 0)
                {
                  if((pfsal_handle = cache_inode_get_fsal_handle(dir_pentry,
                                                                 &cache_status_gethandle))
                     == NULL)
                    {
                        /* after successful cache_inode_readdir, dir_pentry
                         * may be read locked */
                        if (dir_pentry_unlock)
                            V_r(&dir_pentry->lock);

                      if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) 
                        cache_inode_release_dirent( dirent_array, num_entries, pclient ) ;
                      Mem_Free((char *)dirent_array);
                      Mem_Free((char *)entry_name_array);
                      Mem_Free((char *)fh3_array);

                      pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle);
                      return NFS_REQ_OK;
                    }

                  FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext),
                                    FSAL_DIGEST_FILEID3,
                                    pfsal_handle,
                                    (caddr_t) & (RES_READDIRPLUS_REPLY.entries[0].
                                                 fileid));

                  RES_READDIRPLUS_REPLY.entries[0].name = entry_name_array[0];
                  strcpy(RES_READDIRPLUS_REPLY.entries[0].name, ".");

                  RES_READDIRPLUS_REPLY.entries[0].cookie = 1;

                  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0].
                      name_handle.post_op_fh3_u.handle.data.data_val =
                      (char *)fh3_array[0];

                  if(nfs3_FSALToFhandle
                     (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0].
                      name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0)
                    {
                        /* after successful cache_inode_readdir, dir_pentry may
                         * be read locked */
                        if (dir_pentry_unlock)
                            V_r(&dir_pentry->lock);

                      if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) 
                        cache_inode_release_dirent( dirent_array, num_entries, pclient ) ;
                      Mem_Free((char *)dirent_array);
                      Mem_Free((char *)entry_name_array);
                      Mem_Free((char *)fh3_array);

                      pres->res_readdirplus3.status = NFS3ERR_BADHANDLE;
                      return NFS_REQ_OK;
                    }

                  RES_READDIRPLUS_REPLY.entries[0].name_attributes.attributes_follow =
                      FALSE;
                  RES_READDIRPLUS_REPLY.entries[0].name_handle.handle_follows = FALSE;

		  entry_attr = dir_pentry->attributes;

                  /* Set PostPoFh3 structure */
                  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0].
                      name_handle.handle_follows = TRUE;
                  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0].
                      name_handle.post_op_fh3_u.handle.data.data_len =
                      sizeof(file_handle_v3_t);

                  nfs_SetPostOpAttr(pcontext, pexport,
                                    dir_pentry,
                                    &entry_attr,
                                    &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.
                                      reply.entries[0].name_attributes));

                  LogFullDebug(COMPONENT_NFS_READDIR,
                               "Readdirplus3 -> i=0 num_entries=%d space_used=%lu maxcount=%lu Name=. FileId=%016llx Cookie=%llu",
                               num_entries, space_used, maxcount,
                               RES_READDIRPLUS_REPLY.entries[0].fileid,
                               RES_READDIRPLUS_REPLY.entries[0].cookie);

                  delta += 1;
                }

            }

          /* Fill in '..' */
          if(begin_cookie <= 1)
            {
              if(estimated_num_entries > delta)
                {
                  if((pentry_dot_dot = cache_inode_lookupp_sw(dir_pentry,
							      ht,
							      pclient,
							      pcontext,
							      &cache_status_gethandle,
							      !dir_pentry_unlock)) ==
                     NULL)
                    {
                        /* after successful cache_inode_readdir, dir_pentry may
                         * be read locked */
                        if (dir_pentry_unlock)
                            V_r(&dir_pentry->lock);

                      if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) 
                        cache_inode_release_dirent( dirent_array, num_entries, pclient ) ;
                      Mem_Free((char *)dirent_array);
                      Mem_Free((char *)entry_name_array);
                      Mem_Free((char *)fh3_array);

                      pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle);
                      return NFS_REQ_OK;
                    }

                  if((pfsal_handle = cache_inode_get_fsal_handle(pentry_dot_dot,
                                                                 &cache_status_gethandle))
                     == NULL)
                    {
                        /* after successful cache_inode_readdir, dir_pentry may
                         * be read locked */
                        if (dir_pentry_unlock)
                            V_r(&dir_pentry->lock);

                      if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) 
                        cache_inode_release_dirent( dirent_array, num_entries, pclient ) ;
                      Mem_Free((char *)dirent_array);
                      Mem_Free((char *)entry_name_array);
                      Mem_Free((char *)fh3_array);

                      pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle);
                      return NFS_REQ_OK;
                    }

                  FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext),
                                    FSAL_DIGEST_FILEID3,
                                    pfsal_handle,
                                    (caddr_t) & (RES_READDIRPLUS_REPLY.entries[delta].
                                                 fileid));

                  RES_READDIRPLUS_REPLY.entries[delta].name = entry_name_array[delta];
                  strcpy(RES_READDIRPLUS_REPLY.entries[delta].name, "..");

                  /* Getting a file handle */
                  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta].
                      name_handle.post_op_fh3_u.handle.data.data_val =
                      (char *)fh3_array[delta];

                  if(nfs3_FSALToFhandle
                     (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta].
                      name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0)
                    {
                        /* after successful cache_inode_readdir, dir_pentry may
                         * be read locked */
                        if (dir_pentry_unlock)
                            V_r(&dir_pentry->lock);

                      if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) 
                        cache_inode_release_dirent( dirent_array, num_entries, pclient ) ;
                      Mem_Free((char *)dirent_array);
                      Mem_Free((char *)entry_name_array);
                      Mem_Free((char *)fh3_array);

                      pres->res_readdirplus3.status = NFS3ERR_BADHANDLE;
                      return NFS_REQ_OK;
                    }

                  RES_READDIRPLUS_REPLY.entries[delta].cookie = 2;

                  RES_READDIRPLUS_REPLY.entries[delta].name_attributes.attributes_follow =
                      FALSE;
                  RES_READDIRPLUS_REPLY.entries[delta].name_handle.handle_follows = FALSE;

		  entry_attr = pentry_dot_dot->attributes;

                  /* Set PostPoFh3 structure */
                  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta].
                      name_handle.handle_follows = TRUE;
                  pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta].
                      name_handle.post_op_fh3_u.handle.data.data_len =
                      sizeof(file_handle_v3_t);

                  nfs_SetPostOpAttr(pcontext, pexport,
                                    pentry_dot_dot,
                                    &entry_attr,
                                    &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.
                                      reply.entries[delta].name_attributes));

                  LogFullDebug(COMPONENT_NFS_READDIR,
                               "Readdirplus3 -> i=%d num_entries=%d space_used=%lu maxcount=%lu Name=.. FileId=%016llx Cookie=%llu",
                               delta, num_entries, space_used, maxcount,
                               RES_READDIRPLUS_REPLY.entries[delta].fileid,
                               RES_READDIRPLUS_REPLY.entries[delta].cookie);
                }
              RES_READDIRPLUS_REPLY.entries[0].nextentry =
                  &(RES_READDIRPLUS_REPLY.entries[delta]);

              if(num_entries > delta + 1)       /* not 0 ??? */
                RES_READDIRPLUS_REPLY.entries[delta].nextentry =
                    &(RES_READDIRPLUS_REPLY.entries[delta + 1]);
              else
                RES_READDIRPLUS_REPLY.entries[delta].nextentry = NULL;

              delta += 1;
            }

          /* if( begin_cookie == 0 ) */
          for(i = delta; i < num_entries + delta; i++)
            {
              unsigned long needed;

              /* maxcount is the size with the FH and attributes overhead,
	       * so entryplus3 is used instead of entry3. The data structures
	       * in nfs23.h have funny padding depending on the arch (32 or 64).
	       * We can't get an accurate estimate by simply using
	       * sizeof(entryplus3). */
	      /* FIXME: There is still a 4 byte over estimate here on x86_64. */

/** @todo Remove cookie offset calculation in readdir and readdirplus (obsoleted) */

              needed =
		sizeof(reference_entry)
		+ NFS3_FHSIZE
		+ ((strlen(dirent_array[i - delta]->name.name) + 3) & ~3);

	      /* if delta == 1 or 2, then "." and ".." have already been added
	       * to the readdirplus reply. */
	      if (i == delta) {
		needed += needed*delta /* size of a dir entry in reply */
		  - ((strlen(dirent_array[i - delta]->name.name) + 3) & ~3)*delta /* size of filename for current entry */
		  + 4*delta; /* size of "." and ".." filenames in reply */
	      }

              if((space_used += needed) > maxcount)
                {
		  /* If delta != 0, then we already added "." or ".." to the reply. */
                  if(i == delta && delta == 0)
                    {
                      /* Not enough room to make even a single reply */

                        /* after successful cache_inode_readdir, dir_pentry may
                         * be read locked */
                        if (dir_pentry_unlock)
                            V_r(&dir_pentry->lock);

                      if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) 
                        cache_inode_release_dirent( dirent_array, num_entries, pclient ) ;
                      Mem_Free((char *)dirent_array);
                      Mem_Free((char *)entry_name_array);
                      Mem_Free((char *)fh3_array);

                      pres->res_readdirplus3.status = NFS3ERR_TOOSMALL;

                      return NFS_REQ_OK;
                    }
                  break;        /* Make post traitement */
                }

              /*
               * Get information specific to this entry
               */
              if((pfsal_handle =
                  cache_inode_get_fsal_handle(dirent_array[i - delta]->pentry,
                                              &cache_status_gethandle)) == NULL)
                {
                    /* after successful cache_inode_readdir, dir_pentry may be
                     * read locked */
                    if (dir_pentry_unlock)
                        V_r(&dir_pentry->lock);

                  if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) 
                    cache_inode_release_dirent( dirent_array, num_entries, pclient ) ;
                  Mem_Free((char *)dirent_array);
                  Mem_Free((char *)entry_name_array);
                  Mem_Free((char *)fh3_array);

                  pres->res_readdirplus3.status =
                      nfs3_Errno(cache_status_gethandle);
                  return NFS_REQ_OK;
                }

              /* Now fill in the replyed entryplus3 list */
              FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext),
                                FSAL_DIGEST_FILEID3,
                                pfsal_handle,
                                (caddr_t) & (RES_READDIRPLUS_REPLY.entries[i].fileid));

              FSAL_name2str(&dirent_array[i - delta]->name, entry_name_array[i],
                            FSAL_MAX_NAME_LEN);
              RES_READDIRPLUS_REPLY.entries[i].name = entry_name_array[i];

              LogFullDebug(COMPONENT_NFS_READDIR,
                           "Readdirplus3 -> i=%u num_entries=%u delta=%u "
                           "num_entries + delta - 1=%u end_cookie=%"PRIu64,
                           i, num_entries, delta, num_entries + delta - 1,
                           end_cookie);
              if(i != num_entries + delta - 1)
                RES_READDIRPLUS_REPLY.entries[i].cookie =
                    dirent_array[i - delta]->cookie;
              else
                RES_READDIRPLUS_REPLY.entries[i].cookie = end_cookie;

              RES_READDIRPLUS_REPLY.entries[i].name_attributes.attributes_follow = FALSE;
              RES_READDIRPLUS_REPLY.entries[i].name_handle.handle_follows = FALSE;

	      entry_attr = dirent_array[i - delta]->pentry->attributes;

              pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle.post_op_fh3_u.handle.data.data_val = (char *)fh3_array[i];

              /* Compute the NFSv3 file handle */
              if(nfs3_FSALToFhandle
                 (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].
                  name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0)
                {
                    /* after successful cache_inode_readdir, dir_pentry may be
                     * read locked */
                    if (dir_pentry_unlock)
                        V_r(&dir_pentry->lock);

                  if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) 
                    cache_inode_release_dirent( dirent_array, num_entries, pclient ) ;
                  Mem_Free((char *)dirent_array);
                  Mem_Free((char *)entry_name_array);
                  Mem_Free((char *)fh3_array);

                  pres->res_readdirplus3.status = NFS3ERR_BADHANDLE;
                  return NFS_REQ_OK;
                }

              /* Set PostPoFh3 structure */
              pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle.handle_follows = TRUE;
              pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle.post_op_fh3_u.handle.data.data_len = sizeof(file_handle_v3_t);

              nfs_SetPostOpAttr(pcontext, pexport,
                                dirent_array[i - delta]->pentry,
                                &entry_attr,
                                &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_attributes));

              LogFullDebug(COMPONENT_NFS_READDIR,
                           "Readdirplus3 -> i=%d, num_entries=%d needed=%lu space_used=%lu maxcount=%lu Name=%s FileId=%016llx Cookie=%llu",
                           i, num_entries, needed, space_used, maxcount,
                           dirent_array[i - delta]->name.name,
                           RES_READDIRPLUS_REPLY.entries[i].fileid,
                           RES_READDIRPLUS_REPLY.entries[i].cookie);

              RES_READDIRPLUS_REPLY.entries[i].nextentry = NULL;
              if(i != 0)
                RES_READDIRPLUS_REPLY.entries[i - 1].nextentry =
                    &(RES_READDIRPLUS_REPLY.entries[i]);

            }

          pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE;
        }
       
      nfs_SetPostOpAttr(pcontext,
                        pexport,
                        dir_pentry,
                        &dir_attr,
                        &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.dir_attributes));

      memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf,
             cookie_verifier, sizeof(cookieverf3));

      pres->res_readdirplus3.status = NFS3_OK;

      if((eod_met == END_OF_DIR) && (i == num_entries + delta))
        {
          /* End of directory */
          LogFullDebug(COMPONENT_NFS_READDIR,
                       "============================================================> EOD MET !!!!!!");
          pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = TRUE;
        }
      else
        pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE;

      nfs_SetPostOpAttr(pcontext, pexport,
                        dir_pentry,
                        &dir_attr,
                        &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.dir_attributes));
      memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf, cookie_verifier,
             sizeof(cookieverf3));

      LogFullDebug(COMPONENT_NFS_READDIR,
                   "============================================================");

      /* after successful cache_inode_readdir, dir_pentry may be
       * read locked */
      if (dir_pentry_unlock)
          V_r(&dir_pentry->lock);

      /* Free the memory */
      if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) 
        cache_inode_release_dirent( dirent_array, num_entries, pclient ) ;
      Mem_Free((char *)dirent_array);

      return NFS_REQ_OK;
    }

  /* If we are here, there was an error */

  /* after successful cache_inode_readdir, dir_pentry may be
   * read locked */
  if (dir_pentry_unlock)
      V_r(&dir_pentry->lock);

  /* Free the memory */
  if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) )
    cache_inode_release_dirent( dirent_array, num_entries, pclient ) ;
  Mem_Free((char *)dirent_array);
  Mem_Free((char *)entry_name_array);
  Mem_Free((char *)fh3_array);

  /* Is this a retryable error */
  if(nfs_RetryableError(cache_status))
    return NFS_REQ_DROP;

  /* Set failed status */
  nfs_SetFailedStatus(pcontext, pexport,
                      NFS_V3,
                      cache_status,
                      NULL,
                      &pres->res_readdirplus3.status,
                      dir_pentry,
                      &(pres->res_readdirplus3.READDIRPLUS3res_u.resfail.dir_attributes),
                      NULL, NULL, NULL, NULL, NULL, NULL);

  return NFS_REQ_OK;
}                               /* nfs3_Readdirplus */
예제 #11
0
cache_inode_status_t cache_inode_open_by_name(cache_entry_t * pentry_dir,
                                              fsal_name_t * pname,
                                              cache_entry_t * pentry_file,
                                              cache_inode_client_t * pclient,
                                              fsal_openflags_t openflags,
                                              fsal_op_context_t * pcontext,
                                              cache_inode_status_t * pstatus)
{
  fsal_status_t fsal_status;
  fsal_size_t save_filesize = 0;
  fsal_size_t save_spaceused = 0;
  fsal_time_t save_mtime = {
    .seconds = 0,
    .nseconds = 0
  };

  if((pentry_dir == NULL) || (pname == NULL) || (pentry_file == NULL) ||
     (pclient == NULL) || (pcontext == NULL) || (pstatus == NULL))
    return CACHE_INODE_INVALID_ARGUMENT;

  if((pentry_dir->internal_md.type != DIRECTORY))
    {
      *pstatus = CACHE_INODE_BAD_TYPE;
      return *pstatus;
    }

  if(pentry_file->internal_md.type != REGULAR_FILE)
    {
      *pstatus = CACHE_INODE_BAD_TYPE;
      return *pstatus;
    }

  /* Open file need to be closed, unless it is already open as read/write */
  if((pentry_file->object.file.open_fd.openflags != FSAL_O_RDWR) &&
     (pentry_file->object.file.open_fd.openflags != 0) &&
     (pentry_file->object.file.open_fd.fileno != 0) &&
     (pentry_file->object.file.open_fd.openflags != openflags))
    {
#ifdef _USE_MFSL
      fsal_status =
          MFSL_close(&(pentry_file->object.file.open_fd.mfsl_fd), &pclient->mfsl_context, NULL);
#else
      fsal_status = FSAL_close(&(pentry_file->object.file.open_fd.fd));
#endif
      if(FSAL_IS_ERROR(fsal_status) && (fsal_status.major != ERR_FSAL_NOT_OPENED))
        {
          *pstatus = cache_inode_error_convert(fsal_status);

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_open_by_name: returning %d(%s) from FSAL_close",
                   *pstatus, cache_inode_err_str(*pstatus));

          return *pstatus;
        }

      pentry_file->object.file.open_fd.last_op = 0;
      pentry_file->object.file.open_fd.fileno = 0;
    }

  if(pentry_file->object.file.open_fd.last_op == 0
     || pentry_file->object.file.open_fd.fileno == 0)
    {
      LogFullDebug(COMPONENT_FSAL,
               "cache_inode_open_by_name: pentry %p: lastop=0", pentry_file);

      /* Keep coherency with the cache_content */
      if(pentry_file->object.file.pentry_content != NULL)
        {
          save_filesize = pentry_file->attributes.filesize;
          save_spaceused = pentry_file->attributes.spaceused;
          save_mtime = pentry_file->attributes.mtime;
        }

      /* opened file is not preserved yet */
#ifdef _USE_MFSL
      fsal_status = MFSL_open_by_name(&(pentry_dir->mobject),
                                      pname,
                                      pcontext,
                                      &pclient->mfsl_context,
                                      openflags,
                                      &pentry_file->object.file.open_fd.mfsl_fd,
                                      &(pentry_file->attributes),
                                      NULL );

#else
      fsal_status = FSAL_open_by_name(&(pentry_dir->handle),
                                      pname,
                                      pcontext,
                                      openflags,
                                      &pentry_file->object.file.open_fd.fd,
                                      &(pentry_file->attributes));
#endif

      if(FSAL_IS_ERROR(fsal_status))
        {
          *pstatus = cache_inode_error_convert(fsal_status);

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_open_by_name: returning %d(%s) from FSAL_open_by_name",
                   *pstatus, cache_inode_err_str(*pstatus));

          return *pstatus;
        }

#ifdef _USE_PROXY

      /* If proxy if used, we should keep the name of the file to do FSAL_rcp if needed */
      if((pentry_file->object.file.pname =
          (fsal_name_t *) Mem_Alloc_Label(sizeof(fsal_name_t), "fsal_name_t")) == NULL)
        {
          *pstatus = CACHE_INODE_MALLOC_ERROR;

          return *pstatus;
        }

      pentry_file->object.file.pentry_parent_open = pentry_dir;
      pentry_file->object.file.pname->len = pname->len;
      memcpy((char *)(pentry_file->object.file.pname->name), (char *)(pname->name),
             FSAL_MAX_NAME_LEN);

#endif

      /* Keep coherency with the cache_content */
      if(pentry_file->object.file.pentry_content != NULL)
        {
          pentry_file->attributes.filesize = save_filesize;
          pentry_file->attributes.spaceused = save_spaceused;
          pentry_file->attributes.mtime = save_mtime;
        }

#ifdef _USE_MFSL
      pentry_file->object.file.open_fd.fileno =
          (int)FSAL_FILENO(&(pentry_file->object.file.open_fd.mfsl_fd.fsal_file));
#else
      pentry_file->object.file.open_fd.fileno =
          (int)FSAL_FILENO(&(pentry_file->object.file.open_fd.fd));
#endif
      pentry_file->object.file.open_fd.last_op = time(NULL);
      pentry_file->object.file.open_fd.openflags = openflags;

      LogFullDebug(COMPONENT_FSAL,
               "cache_inode_open_by_name: pentry %p: fd=%u",
               pentry_file, pentry_file->object.file.open_fd.fileno);

    }

  /* regular exit */
  pentry_file->object.file.open_fd.last_op = time(NULL);

  /* if file descriptor is too high, garbage collect FDs */
  if(pclient->use_fd_cache
     && (pentry_file->object.file.open_fd.fileno > pclient->max_fd))
    {
      if(cache_inode_gc_fd(pclient, pstatus) != CACHE_INODE_SUCCESS)
        {
          LogCrit(COMPONENT_CACHE_INODE_GC,
                  "FAILURE performing FD garbage collection");
          return *pstatus;
        }
    }

  *pstatus = CACHE_INODE_SUCCESS;
  return *pstatus;

}                               /* cache_inode_open_by_name */

/**
 *
 * cache_inode_close: closes the local fd in the FSAL.
 *
 * Closes the local fd in the FSAL.
 *
 * No lock management is done in this layer: the related pentry in the cache inode layer is
 * locked and will prevent from concurent accesses.
 *
 * @param pentry  [IN] entry in file content layer whose content is to be accessed.
 * @param pclient [IN]  ressource allocated by the client for the nfs management.
 * @pstatus       [OUT] returned status.
 *
 * @return CACHE_CONTENT_SUCCESS is successful .
 *
 */
cache_inode_status_t cache_inode_close(cache_entry_t * pentry,
                                       cache_inode_client_t * pclient,
                                       cache_inode_status_t * pstatus)
{
  fsal_status_t fsal_status;

  if((pentry == NULL) || (pclient == NULL) || (pstatus == NULL))
    return CACHE_CONTENT_INVALID_ARGUMENT;

  if(pentry->internal_md.type != REGULAR_FILE)
    {
      *pstatus = CACHE_INODE_BAD_TYPE;
      return *pstatus;
    }

  /* if nothing is opened, do nothing */
  if(pentry->object.file.open_fd.fileno < 0)
    {
      *pstatus = CACHE_INODE_SUCCESS;
      return *pstatus;
    }

  /* if locks are held in the file, do not close */
  if( cache_inode_file_holds_state( pentry ) )
    {
      *pstatus = CACHE_INODE_SUCCESS; /** @todo : PhD : May be CACHE_INODE_STATE_CONFLICTS would be better ? */
      return *pstatus;
    }

  if((pclient->use_fd_cache == 0) ||
     (time(NULL) - pentry->object.file.open_fd.last_op > pclient->retention) ||
     (pentry->object.file.open_fd.fileno > (int)(pclient->max_fd)))
    {

      LogFullDebug(COMPONENT_CACHE_INODE,
               "cache_inode_close: pentry %p, fileno = %d, lastop=%d ago",
               pentry, pentry->object.file.open_fd.fileno,
               (int)(time(NULL) - pentry->object.file.open_fd.last_op));

#ifdef _USE_MFSL
      fsal_status = MFSL_close(&(pentry->object.file.open_fd.mfsl_fd), &pclient->mfsl_context, NULL);
#else
      fsal_status = FSAL_close(&(pentry->object.file.open_fd.fd));
#endif

      pentry->object.file.open_fd.fileno = 0;
      pentry->object.file.open_fd.last_op = 0;

      if(FSAL_IS_ERROR(fsal_status) && (fsal_status.major != ERR_FSAL_NOT_OPENED))
        {
          *pstatus = cache_inode_error_convert(fsal_status);

          LogDebug(COMPONENT_CACHE_INODE,
                   "cache_inode_close: returning %d(%s) from FSAL_close",
                   *pstatus, cache_inode_err_str(*pstatus));

          return *pstatus;
        }
    }
#ifdef _USE_PROXY
  /* If proxy if used, free the name if needed */
  if(pentry->object.file.pname != NULL)
    {
      Mem_Free((char *)(pentry->object.file.pname));
      pentry->object.file.pname = NULL;
    }
  pentry->object.file.pentry_parent_open = NULL;
#endif

  *pstatus = CACHE_CONTENT_SUCCESS;

  return *pstatus;
}                               /* cache_content_close */
예제 #12
0
/*
 * Duplicate xprt from original to copy.
 */
SVCXPRT *Svcxprt_copy(SVCXPRT *xprt_copy, SVCXPRT *xprt_orig)
{
  if(xprt_copy)
    FreeXprt(xprt_copy);

  xprt_copy = (SVCXPRT *) Mem_Alloc(sizeof(SVCXPRT));
  if(xprt_copy == NULL)
    goto fail_no_xprt;

  LogFullDebug(COMPONENT_RPC,
               "Svcxprt_copy copying xprt_orig=%p to xprt_copy=%p",
               xprt_orig, xprt_copy);
  memcpy(xprt_copy, xprt_orig, sizeof(SVCXPRT));
  xprt_copy->xp_p1 = NULL;
  xprt_copy->xp_p2 = NULL;

  if(xprt_orig->xp_ops == &Svcudp_op)
    {
      if(Su_data(xprt_orig))
        {
          struct Svcudp_data *su_o = Su_data(xprt_orig), *su_c;
          su_c = (struct Svcudp_data *) Mem_Alloc(sizeof(*su_c));
          if(!su_c)
            goto fail;
          Su_data_set(xprt_copy) = (void *) su_c;
          memcpy(su_c, su_o, sizeof(*su_c));

          rpc_buffer(xprt_copy) = Mem_Alloc_Label(su_c->su_iosz, "UDP IO Buffer");
          if(!rpc_buffer(xprt_copy))
            goto fail;
          xdrmem_create(&(su_c->su_xdrs), rpc_buffer(xprt_copy), su_c->su_iosz, XDR_DECODE);
          if(xprt_orig->xp_verf.oa_base == su_o->su_verfbody)
            xprt_copy->xp_verf.oa_base = su_c->su_verfbody;
          else
            xprt_copy->xp_verf.oa_base = xprt_orig->xp_verf.oa_base;
          xprt_copy->xp_verf.oa_flavor = xprt_orig->xp_verf.oa_flavor;
          xprt_copy->xp_verf.oa_length = xprt_orig->xp_verf.oa_length;
        }
      else
        goto fail;
    }
  else if (xprt_orig->xp_ops == &Svctcp_op)
    {
      struct tcp_conn *cd_o = (struct tcp_conn *)xprt_orig->xp_p1, *cd_c;
      cd_c = (struct tcp_conn *) Mem_Alloc(sizeof(*cd_c));
      if(!cd_c)
        goto fail;
      memcpy(cd_c, cd_o, sizeof(*cd_c));
      xprt_copy->xp_p1 = (void *) cd_c;
      xdrrec_create(&(cd_c->xdrs), 32768, 32768, (caddr_t) xprt_copy, Readtcp, Writetcp);
      if(xprt_orig->xp_verf.oa_base == cd_o->verf_body)
        xprt_copy->xp_verf.oa_base = cd_c->verf_body;
      else
        xprt_copy->xp_verf.oa_base = xprt_orig->xp_verf.oa_base;
      xprt_copy->xp_verf.oa_flavor = xprt_orig->xp_verf.oa_flavor;
      xprt_copy->xp_verf.oa_length = xprt_orig->xp_verf.oa_length;
    }
  else if (xprt_orig->xp_ops == &Svctcp_rendezvous_op)
    {
      goto fail;
    }
  else
    {
      LogDebug(COMPONENT_RPC,
               "Attempt to copy unknown xprt %p",
               xprt_orig);
      Mem_Free(xprt_copy);
      goto fail_no_xprt;
    }

  return xprt_copy;

 fail:
  FreeXprt(xprt_copy);
 fail_no_xprt:
  /* Let caller know about failure */
  LogCrit(COMPONENT_RPC,
          "Failed to copy xprt");
  svcerr_systemerr(xprt_orig);
  return NULL;
}
예제 #13
0
fsal_status_t VFSFSAL_rcp(fsal_handle_t * filehandle,      /* IN */
                       fsal_op_context_t * p_context,   /* IN */
                       fsal_path_t * p_local_path,      /* IN */
                       fsal_rcpflag_t transfer_opt      /* IN */
    )
{

  int local_fd;
  int local_flags;
  int errsv;

  fsal_file_t fs_fd;
  fsal_openflags_t fs_flags;

  fsal_status_t st = FSAL_STATUS_NO_ERROR;

  /* default buffer size for RCP: 10MB */
#define RCP_BUFFER_SIZE 10485760
  caddr_t IObuffer;

  int to_local = FALSE;
  int to_fs = FALSE;

  int eof = FALSE;

  ssize_t local_size;
  fsal_size_t fs_size;

  /* sanity checks. */

  if(!filehandle || !p_context || !p_local_path)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rcp);

  to_local = ((transfer_opt & FSAL_RCP_FS_TO_LOCAL) == FSAL_RCP_FS_TO_LOCAL);
  to_fs = ((transfer_opt & FSAL_RCP_LOCAL_TO_FS) == FSAL_RCP_LOCAL_TO_FS);

  if(to_local)
    LogFullDebug(COMPONENT_FSAL,
                 "FSAL_rcp: FSAL -> local file (%s)", p_local_path->path);

  if(to_fs)
    LogFullDebug(COMPONENT_FSAL,
                 "FSAL_rcp: local file -> FSAL (%s)", p_local_path->path);

  /* must give the sens of transfert (exactly one) */

  if((!to_local && !to_fs) || (to_local && to_fs))
    Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_rcp);

  /* first, open local file with the correct flags */

  if(to_fs)
    {
      local_flags = O_RDONLY;
    }
  else
    {
      local_flags = O_WRONLY | O_TRUNC;

      if((transfer_opt & FSAL_RCP_LOCAL_CREAT) == FSAL_RCP_LOCAL_CREAT)
        local_flags |= O_CREAT;

      if((transfer_opt & FSAL_RCP_LOCAL_EXCL) == FSAL_RCP_LOCAL_EXCL)
        local_flags |= O_EXCL;

    }

  if(isFullDebug(COMPONENT_FSAL))
    {
      char msg[1024];

      msg[0] = '\0';

      if((local_flags & O_RDONLY) == O_RDONLY)
        strcat(msg, "O_RDONLY ");

      if((local_flags & O_WRONLY) == O_WRONLY)
        strcat(msg, "O_WRONLY ");

      if((local_flags & O_TRUNC) == O_TRUNC)
        strcat(msg, "O_TRUNC ");

      if((local_flags & O_CREAT) == O_CREAT)
        strcat(msg, "O_CREAT ");

      if((local_flags & O_EXCL) == O_EXCL)
        strcat(msg, "O_EXCL ");

      LogFullDebug(COMPONENT_FSAL, "Openning local file %s with flags: %s",
                   p_local_path->path, msg);
    }

  local_fd = open(p_local_path->path, local_flags);
  errsv = errno;

  if(local_fd == -1)
    {
      Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rcp);
    }

  /* call FSAL_open with the correct flags */

  if(to_fs)
    {
      fs_flags = FSAL_O_WRONLY | FSAL_O_TRUNC;

      /* invalid flags for local to filesystem */

      if(((transfer_opt & FSAL_RCP_LOCAL_CREAT) == FSAL_RCP_LOCAL_CREAT)
         || ((transfer_opt & FSAL_RCP_LOCAL_EXCL) == FSAL_RCP_LOCAL_EXCL))
        {
          /* clean & return */
          close(local_fd);
          Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_rcp);
        }
    }
  else
    {
      fs_flags = FSAL_O_RDONLY;
    }

  if(isFullDebug(COMPONENT_FSAL))
    {
      char msg[1024];

      msg[0] = '\0';

      if((fs_flags & FSAL_O_RDONLY) == FSAL_O_RDONLY)
        strcat(msg, "FSAL_O_RDONLY ");

      if((fs_flags & FSAL_O_WRONLY) == FSAL_O_WRONLY)
        strcat(msg, "FSAL_O_WRONLY ");

      if((fs_flags & FSAL_O_TRUNC) == FSAL_O_TRUNC)
        strcat(msg, "FSAL_O_TRUNC ");

      LogFullDebug(COMPONENT_FSAL, "Openning FSAL file with flags: %s", msg);
    }


  st = FSAL_open(filehandle, p_context, fs_flags, &fs_fd, NULL);

  if(FSAL_IS_ERROR(st))
    {
      /* clean & return */
      close(local_fd);
      Return(st.major, st.minor, INDEX_FSAL_rcp);
    }
  LogFullDebug(COMPONENT_FSAL,
               "Allocating IO buffer of size %llu",
               (unsigned long long)RCP_BUFFER_SIZE);

  /* Allocates buffer */

  IObuffer = (caddr_t) Mem_Alloc_Label(RCP_BUFFER_SIZE,
                                       "IO Buffer");

  if(IObuffer == NULL)
    {
      /* clean & return */
      close(local_fd);
      FSAL_close(&fs_fd);
      Return(ERR_FSAL_NOMEM, Mem_Errno, INDEX_FSAL_rcp);
    }

  /* read/write loop */

  while(!eof)
    {
      /* initialize error code */
      st = FSAL_STATUS_NO_ERROR;

      LogFullDebug(COMPONENT_FSAL, "Read a block from source");

      /* read */

      if(to_fs)                 /* from local filesystem */
        {
          LogFullDebug(COMPONENT_FSAL,
                       "Read a block from local file system");
          local_size = read(local_fd, IObuffer, RCP_BUFFER_SIZE);

          if(local_size == -1)
            {
              st.major = ERR_FSAL_IO;
              st.minor = errno;
              break;            /* exit loop */
            }

          eof = (local_size == 0);
          if(!eof)
            {
              LogFullDebug(COMPONENT_FSAL,
                           "Write a block (%llu bytes) to FSAL",
                            (unsigned long long)local_size);

              st = FSAL_write(&fs_fd, NULL, local_size, IObuffer, &fs_size);
              if(FSAL_IS_ERROR(st))
                {
                  LogFullDebug(COMPONENT_FSAL,
                               "Error writing to FSAL");
                  break;          /* exit loop */
                }
            }
          else
            {
              LogFullDebug(COMPONENT_FSAL,
                           "End of file on local file system");
            }
        }
      else                      /* from FSAL filesystem */
        {
          LogFullDebug(COMPONENT_FSAL,
                       "Read a block from FSAL");
          fs_size = 0;
          st = FSAL_read(&fs_fd, NULL, RCP_BUFFER_SIZE, IObuffer, &fs_size, &eof);

          if(FSAL_IS_ERROR(st))
            break;              /* exit loop */

          if(fs_size > 0)
            {
              LogFullDebug(COMPONENT_FSAL,
                           "Write a block (%llu bytes) to local file system",
                            (unsigned long long)fs_size);

              local_size = write(local_fd, IObuffer, fs_size);

              if(local_size == -1)
                {
                  st.major = ERR_FSAL_IO;
                  st.minor = errno;
                  break;        /* exit loop */
                }
            }
          else
            {
              LogFullDebug(COMPONENT_FSAL,
                           "End of file on FSAL");
              break;
            }

          LogFullDebug(COMPONENT_FSAL, "Size read from source: %llu",
                       (unsigned long long)fs_size);
        }
    }                           /* while !eof */

  /* Clean */

  Mem_Free(IObuffer);
  close(local_fd);
  FSAL_close(&fs_fd);

  /* return status. */

  Return(st.major, st.minor, INDEX_FSAL_rcp);

}
예제 #14
0
int nfs_Mkdir(nfs_arg_t * parg,
              exportlist_t * pexport,
              fsal_op_context_t * pcontext,
              cache_inode_client_t * pclient,
              hash_table_t * ht, struct svc_req *preq, nfs_res_t * pres)
{
  static char __attribute__ ((__unused__)) funcName[] = "nfs_Mkdir";

  char *str_dir_name = NULL;
  fsal_accessmode_t mode = 0;
  cache_entry_t *dir_pentry = NULL;
  cache_entry_t *parent_pentry = NULL;
  int rc = 0;
  fsal_attrib_list_t parent_attr;
  fsal_attrib_list_t attr;
  fsal_attrib_list_t *ppre_attr;
  fsal_attrib_list_t attr_parent_after;
  cache_inode_file_type_t parent_filetype;
  fsal_handle_t *pfsal_handle;
  fsal_name_t dir_name;
  cache_inode_status_t cache_status = CACHE_INODE_SUCCESS;
  cache_inode_status_t cache_status_lookup;

  if(isDebug(COMPONENT_NFSPROTO))
    {
      char str[LEN_FH_STR];

      switch (preq->rq_vers)
        {
        case NFS_V2:
          str_dir_name = parg->arg_mkdir2.where.name;
          break;
        case NFS_V3:
          str_dir_name = parg->arg_mkdir3.where.name;
          break;
        }

      nfs_FhandleToStr(preq->rq_vers,
                       &(parg->arg_mkdir2.where.dir),
                       &(parg->arg_mkdir3.where.dir),
                       NULL,
                       str);
      LogDebug(COMPONENT_NFSPROTO,
               "REQUEST PROCESSING: Calling nfs_Mkdir handle: %s name: %s",
               str, str_dir_name);
    }

  if(preq->rq_vers == NFS_V3)
    {
      /* to avoid setting it on each error case */
      pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc.before.attributes_follow = FALSE;
      pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc.after.attributes_follow = FALSE;
      ppre_attr = NULL;
    }

  if((parent_pentry = nfs_FhandleToCache(preq->rq_vers,
                                         &(parg->arg_mkdir2.where.dir),
                                         &(parg->arg_mkdir3.where.dir),
                                         NULL,
                                         &(pres->res_dirop2.status),
                                         &(pres->res_mkdir3.status),
                                         NULL,
                                         &parent_attr,
                                         pcontext, pclient, ht, &rc)) == NULL)
    {
      /* Stale NFS FH ? */
      return rc;
    }

  /* get directory attributes before action (for V3 reply) */
  ppre_attr = &parent_attr;

  /* Extract the filetype */
  parent_filetype = cache_inode_fsal_type_convert(parent_attr.type);

  /*
   * Sanity checks: 
   */
  if(parent_filetype != DIRECTORY)
    {
      switch (preq->rq_vers)
        {
        case NFS_V2:
          pres->res_dirop2.status = NFSERR_NOTDIR;
          break;

        case NFS_V3:
          pres->res_mkdir3.status = NFS3ERR_NOTDIR;
          break;
        }

      return NFS_REQ_OK;
    }

  switch (preq->rq_vers)
    {
    case NFS_V2:
      str_dir_name = parg->arg_mkdir2.where.name;

      if(parg->arg_mkdir2.attributes.mode != (unsigned int)-1)
        {
          mode = (fsal_accessmode_t) parg->arg_mkdir2.attributes.mode;
        }
      else
        {
          mode = (fsal_accessmode_t) 0;
        }
      break;

    case NFS_V3:
      str_dir_name = parg->arg_mkdir3.where.name;

      if(parg->arg_mkdir3.attributes.mode.set_it == TRUE)
        mode = (fsal_accessmode_t) parg->arg_mkdir3.attributes.mode.set_mode3_u.mode;
      else
        mode = (fsal_accessmode_t) 0;
      break;
    }

  //if(str_dir_name == NULL || strlen(str_dir_name) == 0)
  if(str_dir_name == NULL || *str_dir_name == '\0' )
    {
      if(preq->rq_vers == NFS_V2)
        pres->res_dirop2.status = NFSERR_IO;
      if(preq->rq_vers == NFS_V3)
        pres->res_mkdir3.status = NFS3ERR_INVAL;
    }
  else
    {
      /* Make the directory */
      if((cache_status = cache_inode_error_convert(FSAL_str2name(str_dir_name,
                                                                 FSAL_MAX_NAME_LEN,
                                                                 &dir_name))) ==
         CACHE_INODE_SUCCESS)
        {
          /*
           * Lookup file to see if it exists.  If so, use it.  Otherwise
           * create a new one.  
           */
          dir_pentry = cache_inode_lookup( parent_pentry,
                                           &dir_name,
                                           pexport->cache_inode_policy,
                                           &attr,
                                           ht, 
                                           pclient, 
                                           pcontext, 
                                           &cache_status_lookup);

          if(cache_status_lookup == CACHE_INODE_NOT_FOUND)
            {
              /* Create the directory */
              if((dir_pentry = cache_inode_create(parent_pentry,
                                                  &dir_name,
                                                  DIRECTORY,
                                                  pexport->cache_inode_policy,
                                                  mode,
                                                  NULL,
                                                  &attr,
                                                  ht,
                                                  pclient,
                                                  pcontext, &cache_status)) != NULL)
                {
                  /*
                   * Get the FSAL handle for this entry 
                   */
                  pfsal_handle = cache_inode_get_fsal_handle(dir_pentry, &cache_status);

                  if(cache_status == CACHE_INODE_SUCCESS)
                    {
                      switch (preq->rq_vers)
                        {
                        case NFS_V2:
                          /* Build file handle */
                          if(!nfs2_FSALToFhandle
                             (&(pres->res_dirop2.DIROP2res_u.diropok.file), pfsal_handle,
                              pexport))
                            pres->res_dirop2.status = NFSERR_IO;
                          else
                            {
                              /*
                               * Build entry
                               * attributes 
                               */
                              if(nfs2_FSALattr_To_Fattr(pexport, &attr,
                                                        &(pres->res_dirop2.DIROP2res_u.
                                                          diropok.attributes)) == 0)
                                pres->res_dirop2.status = NFSERR_IO;
                              else
                                pres->res_dirop2.status = NFS_OK;
                            }
                          break;

                        case NFS_V3:
                          /* Build file handle */
                          if((pres->res_mkdir3.MKDIR3res_u.resok.obj.post_op_fh3_u.
                              handle.data.data_val = Mem_Alloc_Label(NFS3_FHSIZE,
                                                                     "Filehandle V3 in nfs3_mkdir")) == NULL)
                            {
                              pres->res_mkdir3.status = NFS3ERR_IO;
                              return NFS_REQ_OK;
                            }

                          if(nfs3_FSALToFhandle
                             (&pres->res_mkdir3.MKDIR3res_u.resok.obj.post_op_fh3_u.
                              handle, pfsal_handle, pexport) == 0)
                            {
                              Mem_Free((char *)pres->res_mkdir3.MKDIR3res_u.resok.obj.
                                       post_op_fh3_u.handle.data.data_val);
                              pres->res_mkdir3.status = NFS3ERR_INVAL;
                              return NFS_REQ_OK;
                            }
                          else
                            {
                              /* Set Post Op Fh3 structure */
                              pres->res_mkdir3.MKDIR3res_u.resok.obj.handle_follows =
                                  TRUE;
                              pres->res_mkdir3.MKDIR3res_u.resok.obj.post_op_fh3_u.handle.
                                  data.data_len = sizeof(file_handle_v3_t);

                              /*
                               * Build entry
                               * attributes 
                               */
                              nfs_SetPostOpAttr(pcontext, pexport,
                                                dir_pentry,
                                                &attr,
                                                &(pres->res_mkdir3.MKDIR3res_u.resok.
                                                  obj_attributes));

                              /* Get the attributes of the parent after the operation */
                              cache_inode_get_attributes(parent_pentry,
                                                         &attr_parent_after);

                              /*
                               * Build Weak Cache
                               * Coherency data 
                               */
                              nfs_SetWccData(pcontext, pexport,
                                             parent_pentry,
                                             ppre_attr,
                                             &attr_parent_after,
                                             &(pres->res_mkdir3.MKDIR3res_u.resok.
                                               dir_wcc));

                              pres->res_mkdir3.status = NFS3_OK;
                            }

                          break;
                        }
                      return NFS_REQ_OK;
                    }
                }
            }                   /* If( cache_status_lookup == CACHE_INODE_NOT_FOUND ) */
          else
            {
              /* object already exists or failure during lookup */
              if(cache_status_lookup == CACHE_INODE_SUCCESS)
                {
                  /* Trying to create a file that already exists */
                  cache_status = CACHE_INODE_ENTRY_EXISTS;

                  switch (preq->rq_vers)
                    {
                    case NFS_V2:
                      pres->res_dirop2.status = NFSERR_EXIST;
                      break;

                    case NFS_V3:
                      pres->res_mkdir3.status = NFS3ERR_EXIST;
                      break;
                    }
                }
              else
                {
                  /* Server fault */
                  cache_status = cache_status_lookup;

                  switch (preq->rq_vers)
                    {
                    case NFS_V2:
                      pres->res_dirop2.status = NFSERR_IO;
                      break;

                    case NFS_V3:
                      pres->res_mkdir3.status = NFS3ERR_INVAL;
                      break;
                    }
                }

              nfs_SetFailedStatus(pcontext, pexport,
                                  preq->rq_vers,
                                  cache_status,
                                  &pres->res_dirop2.status,
                                  &pres->res_mkdir3.status,
                                  NULL, NULL,
                                  parent_pentry,
                                  ppre_attr,
                                  &(pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc),
                                  NULL, NULL, NULL);

              return NFS_REQ_OK;
            }
        }
    }

  /* If we are here, there was an error */
  if(nfs_RetryableError(cache_status))
    {
      return NFS_REQ_DROP;

    }
  nfs_SetFailedStatus(pcontext, pexport,
                      preq->rq_vers,
                      cache_status,
                      &pres->res_dirop2.status,
                      &pres->res_mkdir3.status,
                      NULL, NULL,
                      parent_pentry,
                      ppre_attr,
                      &(pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc), NULL, NULL, NULL);

  return NFS_REQ_OK;

}