/**
 *
 * cache_content_crash_recover: recovers the data cache and the associated inode after a crash.
 *
 * @param pclient [IN]  ressource allocated by the client for the nfs management.
 * @pstatus [OUT] returned status.
 *
 * @return CACHE_CONTENT_SUCCESS is successful.
 *
 */
cache_content_status_t cache_content_crash_recover(unsigned short exportid,
                                                   unsigned int index,
                                                   unsigned int mod,
                                                   cache_content_client_t * pclient_data,
                                                   cache_inode_client_t * pclient_inode,
                                                   hash_table_t * ht,
                                                   fsal_op_context_t * pcontext,
                                                   cache_content_status_t * pstatus)
{
  DIR *cache_directory;
  cache_content_dirinfo_t export_directory;

  char cache_exportdir[MAXPATHLEN];
  char fullpath[MAXPATHLEN];

  struct dirent *direntp;
  struct dirent dirent_export;

  int found_export_id;
  u_int64_t inum;

  off_t size_in_cache;

  cache_entry_t inode_entry;
  cache_entry_t *pentry = NULL;
  cache_content_entry_t *pentry_content = NULL;
  cache_inode_status_t cache_inode_status;
  cache_content_status_t cache_content_status;

  fsal_attrib_list_t fsal_attr;
  cache_inode_fsal_data_t fsal_data;

  *pstatus = CACHE_CONTENT_SUCCESS;

  /* Open the cache directory */
  if((cache_directory = opendir(pclient_data->cache_dir)) == NULL)
    {
      *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR;
      return *pstatus;
    }
  /* read the cache directory */
  while((direntp = readdir(cache_directory)) != NULL)
    {

      /* . and .. are of no interest */
      if(!strcmp(direntp->d_name, ".") || !strcmp(direntp->d_name, ".."))
        continue;

      if((found_export_id = cache_content_get_export_id(direntp->d_name)) >= 0)
        {
          LogEvent(COMPONENT_CACHE_CONTENT,
                            "Directory cache for Export ID %d has been found",
                            found_export_id);
          snprintf(cache_exportdir, MAXPATHLEN, "%s/%s", pclient_data->cache_dir,
                   direntp->d_name);

          if(cache_content_local_cache_opendir(cache_exportdir, &(export_directory)) ==
             FALSE)
            {
              *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR;
              closedir(cache_directory);
              return *pstatus;
            }

          /* Reads the directory content (a single thread for the moment) */

          while(cache_content_local_cache_dir_iter
                (&export_directory, &dirent_export, index, mod))
            {
              /* . and .. are of no interest */
              if(!strcmp(dirent_export.d_name, ".")
                 || !strcmp(dirent_export.d_name, ".."))
                continue;

              if((inum = cache_content_get_inum(dirent_export.d_name)) > 0)
                {
                  LogEvent(COMPONENT_CACHE_CONTENT,
                                    "Cache entry for File ID %llx has been found", inum);

                  /* Get the content of the file */
                  sprintf(fullpath, "%s/%s/%s", pclient_data->cache_dir, direntp->d_name,
                          dirent_export.d_name);

                  if((cache_inode_status = cache_inode_reload_content(fullpath,
                                                                      &inode_entry)) !=
                     CACHE_INODE_SUCCESS)
                    {
                      LogMajor(COMPONENT_CACHE_CONTENT,
                                        "File Content Cache record for File ID %llx is unreadable",
                                        inum);
                      continue;
                    }
                  else
                    LogMajor(COMPONENT_CACHE_CONTENT,
                                      "File Content Cache record for File ID %llx : READ OK",
                                      inum);

                  /* Populating the cache_inode... */
                  fsal_data.handle = inode_entry.object.file.handle;
                  fsal_data.cookie = 0;

                  if((pentry = cache_inode_get(&fsal_data,
                                               &fsal_attr,
                                               ht,
                                               pclient_inode,
                                               pcontext, &cache_inode_status)) == NULL)
                    {
                      LogCrit(COMPONENT_CACHE_CONTENT,
                                   "Error adding cached inode for file ID %llx, error=%d",
                                   inum, cache_inode_status);
                      continue;
                    }
                  else
                    LogEvent(COMPONENT_CACHE_CONTENT,
                                      "Cached inode added successfully for file ID %llx",
                                      inum);

                  /* Get the size from the cache */
                  if((size_in_cache =
                      cache_content_recover_size(cache_exportdir, inum)) == -1)
                    {
                      LogCrit(COMPONENT_CACHE_CONTENT,
                                   "Error when recovering size for file ID %llx", inum);
                    }
                  else
                    pentry->object.file.attributes.filesize = (fsal_size_t) size_in_cache;

                  /* Adding the cached entry to the data cache */
                  if((pentry_content = cache_content_new_entry(pentry,
                                                               NULL,
                                                               pclient_data,
                                                               RECOVER_ENTRY,
                                                               pcontext,
                                                               &cache_content_status)) ==
                     NULL)
                    {
                      LogCrit(COMPONENT_CACHE_CONTENT,
                                   "Error adding cached data for file ID %llx, error=%d",
                                   inum, cache_inode_status);
                      continue;
                    }
                  else
                    LogEvent(COMPONENT_CACHE_CONTENT,
                                      "Cached data added successfully for file ID %llx",
                                      inum);

                  if((cache_content_status =
                      cache_content_valid(pentry_content, CACHE_CONTENT_OP_GET,
                                          pclient_data)) != CACHE_CONTENT_SUCCESS)
                    {
                      *pstatus = cache_content_status;
                      return *pstatus;
                    }

                }

            }                   /*  while( ( dirent_export = readdir( export_directory ) ) != NULL ) */

          /* Close the export cache directory */
          cache_content_local_cache_closedir(&export_directory);

        }                       /* if( ( found_export_id = cache_content_get_export_id( direntp->d_name ) ) > 0 ) */
    }                           /* while( ( direntp = readdir( cache_directory ) ) != NULL ) */

  /* Close the cache directory */
  closedir(cache_directory);

  return *pstatus;
}                               /* cache_content_crash_recover */
Ejemplo n.º 2
0
/**
 *
 * cache_content_rdwr: Reads/Writes through the cache layer.
 *
 * Reads/Writes through the cache layer.
 * This routine should be called only from the cache_inode layer. 
 *
 * 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 read_or_write   [IN] a flag of type cache_content_io_direction_t to tell if a read or write is to be done. 
 * @param seek_descriptor [IN] absolute position (in the FSAL file) where the IO will be done.
 * @param pio_size_in     [IN] requested io size
 * @param pio_size_out    [OUT] the size of the io that was successfully made.
 * @param pbuffstat       [OUT] the 'stat' of entry in the data cache after the operation
 * @param buffer write:[IN] read:[OUT] the buffer for the data.
 * @param pclient         [IN]  ressource allocated by the client for the nfs management.
 * @param pcontext        [IN] fsal credentials for the operation.
 * @pstatus               [OUT] returned status.
 *
 * @return CACHE_CONTENT_SUCCESS is successful .
 *
 */
cache_content_status_t cache_content_rdwr(cache_content_entry_t * pentry,
                                          cache_content_io_direction_t read_or_write,
                                          fsal_seek_t * seek_descriptor,
                                          fsal_size_t * pio_size_in,
                                          fsal_size_t * pio_size_out,
                                          caddr_t buffer,
                                          fsal_boolean_t * p_fsal_eof,
                                          struct stat * pbuffstat,
                                          cache_content_client_t * pclient,
                                          fsal_op_context_t * pcontext,
                                          cache_content_status_t * pstatus)
{
  fsal_handle_t *pfsal_handle = NULL;
  fsal_status_t fsal_status;
  cache_inode_status_t cache_inode_status;
  cache_content_status_t cache_content_status;
  fsal_path_t local_path;
  int statindex;
  off_t offset;
  size_t iosize_before;
  ssize_t iosize_after;
  struct stat buffstat;
  int rc;
  char c;

  *pstatus = CACHE_CONTENT_SUCCESS;

  LogFullDebug(COMPONENT_CACHE_CONTENT,
                    "---> DATA : IO Size IN = %llu fdsize=%zu seeksize=%zu",
                    *pio_size_in, sizeof(fsal_file_t), sizeof(fsal_seek_t));

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

  /* Set the statindex variable */
  switch (read_or_write)
    {
    case CACHE_CONTENT_READ:
      statindex = CACHE_CONTENT_READ_ENTRY;
      break;

    case CACHE_CONTENT_WRITE:
      statindex = CACHE_CONTENT_WRITE_ENTRY;
      break;

    default:
      *pstatus = CACHE_CONTENT_INVALID_ARGUMENT;
      return *pstatus;
      break;
    }

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

  /* Get the fsal handle */
  if((pfsal_handle =
      cache_inode_get_fsal_handle(pentry->pentry_inode, &cache_inode_status)) == NULL)
    {
      *pstatus = CACHE_CONTENT_BAD_CACHE_INODE_ENTRY;

      LogMajor(COMPONENT_CACHE_CONTENT,
                        "cache_content_rdwr: cannot get handle");
      /* stat */
      pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;

      return *pstatus;
    }

  /* Convert the path to FSAL path */
  fsal_status =
      FSAL_str2path(pentry->local_fs_entry.cache_path_data, MAXPATHLEN, &local_path);

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

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

      return *pstatus;
    }

  /* Parameters conversion */
  offset = cache_content_fsal_seek_convert(*seek_descriptor, pstatus);
  if(*pstatus != CACHE_CONTENT_SUCCESS)
    {
      /* stat */
      pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;

      return *pstatus;
    }

  iosize_before = cache_content_fsal_size_convert(*pio_size_in, pstatus);
  if(*pstatus != CACHE_CONTENT_SUCCESS)
    {
      /* stat */
      pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;

      return *pstatus;
    }

  /* Open the local fd for reading */
  if(cache_content_open(pentry, pclient, pstatus) != CACHE_CONTENT_SUCCESS)
    {
      return *pstatus;
    }

  /* Perform the IO through the cache */
  if(read_or_write == CACHE_CONTENT_READ)
    {
      /* The file content was completely read before the IO. The read operation is fully done locally */
      if((iosize_after =
          pread(pentry->local_fs_entry.opened_file.local_fd, buffer, iosize_before,
                offset)) == -1)
        {
          /* stat */
          pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;

          *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR;
          return *pstatus;
        }

      if((cache_content_status =
          cache_content_valid(pentry, CACHE_CONTENT_OP_GET,
                              pclient)) != CACHE_CONTENT_SUCCESS)
        {
          *pstatus = cache_content_status;
          return *pstatus;
        }

      /* Get the eof */
      if(iosize_after == 0)
        *p_fsal_eof = TRUE;
      else
        {
          rc = pread(pentry->local_fs_entry.opened_file.local_fd, &c, 1,
                     offset + iosize_before);
          if(rc == 0)
            *p_fsal_eof = TRUE;
          else
            *p_fsal_eof = FALSE;
        }
    }
  else
    {
      /* The io is done on the cache before being flushed to the FSAL */
      if((iosize_after =
          pwrite(pentry->local_fs_entry.opened_file.local_fd, buffer, iosize_before,
                 offset)) == -1)
        {
          /* stat */
          pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;

          *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR;
          return *pstatus;
        }

      if((cache_content_status =
          cache_content_valid(pentry, CACHE_CONTENT_OP_SET,
                              pclient)) != CACHE_CONTENT_SUCCESS)
        {
          *pstatus = cache_content_status;
          return *pstatus;
        }

      /* p_fsal_eof has no meaning here, it is unused */
    }

  /* close the local fd */
  if(cache_content_close(pentry, pclient, pstatus) != CACHE_CONTENT_SUCCESS)
    return *pstatus;

  *pio_size_out = (fsal_size_t) iosize_after;

  /* Return the 'stat' as seen in the cache */
  if(stat(pentry->local_fs_entry.cache_path_data, &buffstat) == -1)
    {
      *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR;
    }
  else
    {
      if(pbuffstat != NULL)
        *pbuffstat = buffstat;
    }

  return *pstatus;
}                               /* cache_content_rdwr */