nfs-ganesha 1.4
|
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 */