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 00037 #ifdef HAVE_CONFIG_H 00038 #include "config.h" 00039 #endif 00040 00041 #ifdef _SOLARIS 00042 #include "solaris_port.h" 00043 #endif /* _SOLARIS */ 00044 00045 #include "fsal.h" 00046 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_inode_lru.h" 00053 #include "nfs_core.h" 00054 00055 #include <unistd.h> 00056 #include <sys/types.h> 00057 #include <sys/stat.h> 00058 #include <sys/param.h> 00059 #include <time.h> 00060 #include <pthread.h> 00061 #include <assert.h> 00062 00085 cache_inode_status_t 00086 cache_inode_rdwr(cache_entry_t *entry, 00087 cache_inode_io_direction_t io_direction, 00088 uint64_t offset, 00089 size_t io_size, 00090 size_t *bytes_moved, 00091 void *buffer, 00092 bool_t *eof, 00093 fsal_op_context_t *context, 00094 cache_inode_stability_t stable, 00095 cache_inode_status_t *status) 00096 { 00097 /* Error return from FSAL calls */ 00098 fsal_status_t fsal_status = {0, 0}; 00099 /* Required open mode to successfully read or write */ 00100 fsal_openflags_t openflags = FSAL_O_CLOSED; 00101 fsal_openflags_t loflags; 00102 /* TRUE if we have taken the content lock on 'entry' */ 00103 bool_t content_locked = FALSE; 00104 /* TRUE if we have taken the attribute lock on 'entry' */ 00105 bool_t attributes_locked = FALSE; 00106 /* TRUE if we opened a previously closed FD */ 00107 bool_t opened = FALSE; 00108 /* We need this until Jim Lieb redoes the FSAL interface. But 00109 there's no reason to make users of cache_inode deal with it. */ 00110 fsal_seek_t seek_descriptor = { 00111 .whence = FSAL_SEEK_SET, 00112 .offset = offset 00113 }; 00114 00115 /* Set flags for a read or write, as appropriate */ 00116 if (io_direction == CACHE_INODE_READ) { 00117 openflags = FSAL_O_RDONLY; 00118 } else { 00119 openflags = FSAL_O_WRONLY; 00120 if (stable == CACHE_INODE_SAFE_WRITE_TO_FS) 00121 openflags |= FSAL_O_SYNC; 00122 } 00123 00124 /* IO is done only on REGULAR_FILEs */ 00125 if (entry->type != REGULAR_FILE) { 00126 *status = CACHE_INODE_BAD_TYPE; 00127 goto out; 00128 } 00129 00130 if (stable == CACHE_INODE_UNSAFE_WRITE_TO_GANESHA_BUFFER) { 00131 /* Write to memory */ 00132 pthread_rwlock_wrlock(&entry->content_lock); 00133 content_locked = TRUE; 00134 00135 /* Is the unstable_data buffer allocated? */ 00136 if ((entry->object.file.unstable_data.buffer == NULL) && 00137 (io_size <= CACHE_INODE_UNSTABLE_BUFFERSIZE)) { 00138 if ((entry->object.file.unstable_data.buffer = 00139 gsh_malloc(CACHE_INODE_UNSTABLE_BUFFERSIZE)) == NULL) { 00140 *status = CACHE_INODE_MALLOC_ERROR; 00141 goto out; 00142 } 00143 00144 entry->object.file.unstable_data.offset = offset; 00145 entry->object.file.unstable_data.length = io_size; 00146 00147 memcpy(entry->object.file.unstable_data.buffer, 00148 buffer, io_size); 00149 00150 pthread_rwlock_wrlock(&entry->attr_lock); 00151 attributes_locked = TRUE; 00152 cache_inode_set_time_current(&entry->attributes.mtime); 00153 *bytes_moved = io_size; 00154 } else { 00155 if ((entry->object.file.unstable_data.offset < offset) && 00156 (io_size + offset < CACHE_INODE_UNSTABLE_BUFFERSIZE)) { 00157 entry->object.file.unstable_data.length = 00158 io_size + offset; 00159 memcpy(entry->object.file.unstable_data.buffer + 00160 offset, buffer, io_size); 00161 00162 pthread_rwlock_wrlock(&entry->attr_lock); 00163 attributes_locked = TRUE; 00164 cache_inode_set_time_current(&entry->attributes.mtime); 00165 *bytes_moved = io_size; 00166 } else { 00167 /* Go back to stable writes */ 00168 stable = CACHE_INODE_SAFE_WRITE_TO_FS; 00169 } 00170 } 00171 if (content_locked) { 00172 pthread_rwlock_unlock(&entry->content_lock); 00173 content_locked = FALSE; 00174 } 00175 if (attributes_locked) { 00176 pthread_rwlock_unlock(&entry->attr_lock); 00177 attributes_locked = FALSE; 00178 } 00179 } 00180 00181 if (stable == CACHE_INODE_SAFE_WRITE_TO_FS || 00182 stable == CACHE_INODE_UNSAFE_WRITE_TO_FS_BUFFER) { 00183 /* Write through the FSAL. We need a write lock only 00184 if we need to open or close a file descriptor. */ 00185 pthread_rwlock_rdlock(&entry->content_lock); 00186 content_locked = TRUE; 00187 loflags = entry->object.file.open_fd.openflags; 00188 if ((!cache_inode_fd(entry)) || 00189 (loflags && loflags != FSAL_O_RDWR && loflags != openflags)) { 00190 pthread_rwlock_unlock(&entry->content_lock); 00191 pthread_rwlock_wrlock(&entry->content_lock); 00192 loflags = entry->object.file.open_fd.openflags; 00193 if ((!cache_inode_fd(entry)) || 00194 (loflags && loflags != FSAL_O_RDWR && 00195 loflags != openflags)) { 00196 if (cache_inode_open(entry, 00197 openflags, 00198 context, 00199 CACHE_INODE_FLAG_CONTENT_HAVE | 00200 CACHE_INODE_FLAG_CONTENT_HOLD, 00201 status) != CACHE_INODE_SUCCESS) { 00202 goto out; 00203 } 00204 opened = TRUE; 00205 } 00206 } 00207 00208 /* Call FSAL_read or FSAL_write */ 00209 if (io_direction == CACHE_INODE_READ) { 00210 fsal_status 00211 = FSAL_read(&(entry->object.file.open_fd.fd), 00212 &seek_descriptor, 00213 io_size, 00214 buffer, 00215 bytes_moved, 00216 eof); 00217 } else { 00218 fsal_status 00219 = FSAL_write(&(entry->object.file.open_fd.fd), 00220 context, 00221 &seek_descriptor, 00222 io_size, 00223 buffer, 00224 bytes_moved); 00225 00226 /* Alright, the unstable write is complete. Now if it was 00227 supposed to be a stable write we can sync to the hard 00228 drive. */ 00229 00230 if (stable == CACHE_INODE_SAFE_WRITE_TO_FS && 00231 !(entry->object.file.open_fd.openflags & FSAL_O_SYNC)) { 00232 fsal_status 00233 = FSAL_commit(&(entry->object.file.open_fd.fd), 00234 offset, io_size); 00235 } 00236 } 00237 00238 LogFullDebug(COMPONENT_FSAL, 00239 "cache_inode_rdwr: FSAL IO operation returned " 00240 "%d, asked_size=%zu, effective_size=%zu", 00241 fsal_status.major, io_size, *bytes_moved); 00242 00243 if (FSAL_IS_ERROR(fsal_status)) { 00244 if (fsal_status.major == ERR_FSAL_DELAY) { 00245 LogEvent(COMPONENT_CACHE_INODE, 00246 "cache_inode_rdwr: FSAL_write " 00247 " returned EBUSY"); 00248 } else { 00249 LogDebug(COMPONENT_CACHE_INODE, 00250 "cache_inode_rdwr: fsal_status.major = %d", 00251 fsal_status.major); 00252 } 00253 00254 *bytes_moved = 0; 00255 *status = cache_inode_error_convert(fsal_status); 00256 00257 if (fsal_status.major == ERR_FSAL_STALE) { 00258 cache_inode_kill_entry(entry); 00259 goto out; 00260 } 00261 00262 if ((fsal_status.major != ERR_FSAL_NOT_OPENED) 00263 && (entry->object.file.open_fd.openflags 00264 != FSAL_O_CLOSED)) { 00265 cache_inode_status_t cstatus; 00266 LogFullDebug(COMPONENT_CACHE_INODE, 00267 "cache_inode_rdwr: CLOSING entry %p", 00268 entry); 00269 pthread_rwlock_unlock(&entry->content_lock); 00270 pthread_rwlock_wrlock(&entry->content_lock); 00271 cache_inode_close(entry, 00272 (CACHE_INODE_FLAG_REALLYCLOSE | 00273 CACHE_INODE_FLAG_CONTENT_HAVE | 00274 CACHE_INODE_FLAG_CONTENT_HOLD), 00275 &cstatus); 00276 00277 if (cstatus != CACHE_INODE_SUCCESS) { 00278 LogCrit(COMPONENT_CACHE_INODE_LRU, 00279 "Error closing file in cache_inode_rdwr: %d.", 00280 cstatus); 00281 } 00282 } 00283 00284 goto out; 00285 } 00286 00287 LogFullDebug(COMPONENT_CACHE_INODE, 00288 "cache_inode_rdwr: inode/direct: io_size=%zu, " 00289 "bytes_moved=%zu, offset=%"PRIu64, 00290 io_size, *bytes_moved, offset); 00291 00292 if (opened) { 00293 if (cache_inode_close(entry, 00294 CACHE_INODE_FLAG_CONTENT_HAVE | 00295 CACHE_INODE_FLAG_CONTENT_HOLD, 00296 status) != CACHE_INODE_SUCCESS) { 00297 LogEvent(COMPONENT_CACHE_INODE, 00298 "cache_inode_rdwr: cache_inode_close = %d", 00299 *status); 00300 goto out; 00301 } 00302 } 00303 00304 if (content_locked) { 00305 pthread_rwlock_unlock(&entry->content_lock); 00306 content_locked = FALSE; 00307 } 00308 } 00309 00310 pthread_rwlock_wrlock(&entry->attr_lock); 00311 attributes_locked = TRUE; 00312 if (io_direction == CACHE_INODE_WRITE) { 00313 if ((*status = cache_inode_refresh_attrs(entry, 00314 context)) 00315 != CACHE_INODE_SUCCESS) { 00316 goto out; 00317 } 00318 } else { 00319 cache_inode_set_time_current(&entry->attributes.atime); 00320 } 00321 pthread_rwlock_unlock(&entry->attr_lock); 00322 attributes_locked = FALSE; 00323 00324 *status = CACHE_INODE_SUCCESS; 00325 00326 out: 00327 00328 if (content_locked) { 00329 pthread_rwlock_unlock(&entry->content_lock); 00330 content_locked = FALSE; 00331 } 00332 00333 if (attributes_locked) { 00334 pthread_rwlock_unlock(&entry->attr_lock); 00335 attributes_locked = FALSE; 00336 } 00337 00338 return *status; 00339 } /* cache_inode_rdwr */