nfs-ganesha 1.4

cache_content_rdwr.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright CEA/DAM/DIF  (2008)
00005  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00006  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00007  *
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 3 of the License, or (at your option) any later version.
00013  * 
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  * 
00023  * ---------------------------------------
00024  */
00025 
00038 #ifdef HAVE_CONFIG_H
00039 #include "config.h"
00040 #endif
00041 
00042 #ifdef _SOLARIS
00043 #include "solaris_port.h"
00044 #endif                          /* _SOLARIS */
00045 
00046 #include "fsal.h"
00047 #include "LRU_List.h"
00048 #include "log.h"
00049 #include "HashData.h"
00050 #include "HashTable.h"
00051 #include "cache_inode.h"
00052 #include "cache_content.h"
00053 
00054 #include <unistd.h>
00055 #include <sys/types.h>
00056 #include <sys/stat.h>
00057 #include <fcntl.h>
00058 #include <sys/param.h>
00059 #include <time.h>
00060 #include <pthread.h>
00061 
00062 /* Missing prototypes */
00063 
00081 cache_content_status_t cache_content_open(cache_content_entry_t * pentry,
00082                                           cache_content_client_t * pclient,
00083                                           cache_content_status_t * pstatus)
00084 {
00085   int localfd;
00086 
00087   if((pentry == NULL) || (pstatus == NULL))
00088     return CACHE_CONTENT_INVALID_ARGUMENT;
00089 
00090   if(pclient->use_fd_cache == 0)
00091     pentry->local_fs_entry.opened_file.last_op = 0;     /* to force opening the file */
00092 
00093   if((pclient->use_fd_cache == 0) ||
00094      (time(NULL) - pentry->local_fs_entry.opened_file.last_op > pclient->retention))
00095     {
00096 
00097       if(pentry->local_fs_entry.opened_file.local_fd > 0)
00098         {
00099           close(pentry->local_fs_entry.opened_file.local_fd);
00100         }
00101 
00102       pentry->local_fs_entry.opened_file.local_fd = -1;
00103       pentry->local_fs_entry.opened_file.last_op = 0;
00104     }
00105 
00106   if(pentry->local_fs_entry.opened_file.last_op == 0)
00107     {
00108       /* Close file to be sure */
00109       if(pentry->local_fs_entry.opened_file.local_fd > 0)
00110         {
00111           close(pentry->local_fs_entry.opened_file.local_fd);
00112         }
00113 
00114       /* opened file is not preserved yet */
00115       if((localfd = open(pentry->local_fs_entry.cache_path_data, O_RDWR, 0750)) == -1)
00116         {
00117           if(errno == ENOENT)
00118             *pstatus = CACHE_CONTENT_LOCAL_CACHE_NOT_FOUND;
00119           else
00120             *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR;
00121 
00122           return *pstatus;
00123         }
00124 
00125       pentry->local_fs_entry.opened_file.local_fd = localfd;
00126     }
00127 
00128   /* Regular exit */
00129   pentry->local_fs_entry.opened_file.last_op = time(NULL);
00130 
00131   *pstatus = CACHE_CONTENT_SUCCESS;
00132   return *pstatus;
00133 
00134 }                               /* cache_content_open */
00135 
00152 cache_content_status_t cache_content_close(cache_content_entry_t * pentry,
00153                                            cache_content_client_t * pclient,
00154                                            cache_content_status_t * pstatus)
00155 {
00156   if((pentry == NULL) || (pstatus == NULL))
00157     return CACHE_CONTENT_INVALID_ARGUMENT;
00158 
00159   /* if nothing is opened, do nothing */
00160   if(pentry->local_fs_entry.opened_file.local_fd < 0)
00161     {
00162       *pstatus = CACHE_CONTENT_SUCCESS;
00163       return *pstatus;
00164     }
00165 
00166   if((pclient->use_fd_cache == 0) ||
00167      (time(NULL) - pentry->local_fs_entry.opened_file.last_op > pclient->retention) ||
00168      (pentry->local_fs_entry.opened_file.local_fd > pclient->max_fd))
00169     {
00170       close(pentry->local_fs_entry.opened_file.local_fd);
00171       pentry->local_fs_entry.opened_file.local_fd = -1;
00172       pentry->local_fs_entry.opened_file.last_op = 0;
00173     }
00174 
00175   *pstatus = CACHE_CONTENT_SUCCESS;
00176   return *pstatus;
00177 }                               /* cache_content_close */
00178 
00203 cache_content_status_t cache_content_rdwr(cache_content_entry_t * pentry,
00204                                           cache_inode_io_direction_t read_or_write,
00205                                           uint64_t offset,
00206                                           size_t * pio_size_in,
00207                                           size_t * pio_size_out,
00208                                           void *buffer,
00209                                           fsal_boolean_t * p_fsal_eof,
00210                                           struct stat * pbuffstat,
00211                                           cache_content_client_t * pclient,
00212                                           fsal_op_context_t * pcontext,
00213                                           cache_content_status_t * pstatus)
00214 {
00215   fsal_status_t fsal_status;
00216   fsal_path_t local_path;
00217   int statindex;
00218   size_t iosize_before;
00219   ssize_t iosize_after;
00220   struct stat buffstat;
00221   int rc;
00222   char c;
00223 
00224   *pstatus = CACHE_CONTENT_SUCCESS;
00225 
00226   /* Set the statindex variable */
00227   switch (read_or_write)
00228     {
00229     case CACHE_INODE_READ:
00230       statindex = CACHE_CONTENT_READ_ENTRY;
00231       break;
00232 
00233     case CACHE_INODE_WRITE:
00234       statindex = CACHE_CONTENT_WRITE_ENTRY;
00235       break;
00236 
00237     default:
00238       *pstatus = CACHE_CONTENT_INVALID_ARGUMENT;
00239       return *pstatus;
00240       break;
00241     }
00242 
00243   /* stat */
00244   pclient->stat.func_stats.nb_call[statindex] += 1;
00245 
00246   /* Convert the path to FSAL path */
00247   fsal_status =
00248       FSAL_str2path(pentry->local_fs_entry.cache_path_data, MAXPATHLEN, &local_path);
00249 
00250   if(FSAL_IS_ERROR(fsal_status))
00251     {
00252       *pstatus = CACHE_CONTENT_FSAL_ERROR;
00253 
00254       /* stat */
00255       pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;
00256 
00257       return *pstatus;
00258     }
00259 
00260   /* Parameters conversion */
00261   iosize_before = cache_content_fsal_size_convert(*pio_size_in, pstatus);
00262   if(*pstatus != CACHE_CONTENT_SUCCESS)
00263     {
00264       /* stat */
00265       pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;
00266 
00267       return *pstatus;
00268     }
00269 
00270   /* Open the local fd for reading */
00271   if(cache_content_open(pentry, pclient, pstatus) != CACHE_CONTENT_SUCCESS)
00272     {
00273       return *pstatus;
00274     }
00275 
00276   /* Perform the IO through the cache */
00277   if(read_or_write == CACHE_INODE_READ)
00278     {
00279       /* The file content was completely read before the IO. The read operation is fully done locally */
00280       if((iosize_after =
00281           pread(pentry->local_fs_entry.opened_file.local_fd, buffer, iosize_before,
00282                 offset)) == -1)
00283         {
00284           /* stat */
00285           pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;
00286 
00287           *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR;
00288           return *pstatus;
00289         }
00290 
00291       /* Get the eof */
00292       if(iosize_after == 0)
00293         *p_fsal_eof = TRUE;
00294       else
00295         {
00296           rc = pread(pentry->local_fs_entry.opened_file.local_fd, &c, 1,
00297                      offset + iosize_before);
00298           if(rc == 0)
00299             *p_fsal_eof = TRUE;
00300           else
00301             *p_fsal_eof = FALSE;
00302         }
00303     }
00304   else
00305     {
00306       /* The io is done on the cache before being flushed to the FSAL */
00307       if((iosize_after =
00308           pwrite(pentry->local_fs_entry.opened_file.local_fd, buffer, iosize_before,
00309                  offset)) == -1)
00310         {
00311           /* stat */
00312           pclient->stat.func_stats.nb_err_unrecover[statindex] += 1;
00313 
00314           *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR;
00315           return *pstatus;
00316         }
00317 
00318     }
00319 
00320   /* close the local fd */
00321   if(cache_content_close(pentry, pclient, pstatus) != CACHE_CONTENT_SUCCESS)
00322     return *pstatus;
00323 
00324   *pio_size_out = (fsal_size_t) iosize_after;
00325 
00326   /* Return the 'stat' as seen in the cache */
00327   if(stat(pentry->local_fs_entry.cache_path_data, &buffstat) == -1)
00328     {
00329       *pstatus = CACHE_CONTENT_LOCAL_CACHE_ERROR;
00330     }
00331   else
00332     {
00333       if(pbuffstat != NULL)
00334         *pbuffstat = buffstat;
00335     }
00336 
00337   return *pstatus;
00338 }                               /* cache_content_rdwr */