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 00036 #ifdef HAVE_CONFIG_H 00037 #include "config.h" 00038 #endif 00039 00040 #ifdef _SOLARIS 00041 #include "solaris_port.h" 00042 #endif /* _SOLARIS */ 00043 00044 #include "fsal.h" 00045 00046 #include "LRU_List.h" 00047 #include "log.h" 00048 #include "HashData.h" 00049 #include "HashTable.h" 00050 #include "cache_inode.h" 00051 #include "nfs_core.h" 00052 00053 #include <unistd.h> 00054 #include <sys/types.h> 00055 #include <sys/stat.h> 00056 #include <sys/param.h> 00057 #include <time.h> 00058 #include <pthread.h> 00059 #include <assert.h> 00060 00076 cache_inode_status_t 00077 cache_inode_commit(cache_entry_t *entry, 00078 uint64_t offset, 00079 size_t count, 00080 cache_inode_stability_t stability, 00081 fsal_op_context_t *context, 00082 cache_inode_status_t *status) 00083 { 00084 /* Number of bytes actually written */ 00085 size_t bytes_moved = 0; 00086 /* Descriptor for unstable data */ 00087 cache_inode_unstable_data_t *udata = NULL; 00088 /* Error return from FSAL operations*/ 00089 fsal_status_t fsal_status = {0, 0}; 00090 /* True if the content_lock is held */ 00091 bool_t content_locked = FALSE; 00092 /* True if we opened our own file descriptor */ 00093 bool_t opened = FALSE; 00094 00095 if ((uint64_t)count > ~(uint64_t)offset) 00096 return NFS4ERR_INVAL; 00097 00098 pthread_rwlock_rdlock(&entry->content_lock); 00099 content_locked = TRUE; 00100 00101 /* Just in case the variable holds something funny when we're 00102 called. */ 00103 *status = CACHE_INODE_SUCCESS; 00104 00105 /* If we aren't using the Ganesha write buffer, then we're using 00106 the filesystem write buffer so execute a normal fsal_commit() 00107 call. */ 00108 if (stability == CACHE_INODE_UNSAFE_WRITE_TO_FS_BUFFER) { 00109 if (!is_open_for_write(entry)) { 00110 pthread_rwlock_unlock(&entry->content_lock); 00111 pthread_rwlock_wrlock(&entry->content_lock); 00112 if (!is_open_for_write(entry)) { 00113 if (cache_inode_open(entry, 00114 FSAL_O_WRONLY, 00115 context, 00116 CACHE_INODE_FLAG_CONTENT_HAVE | 00117 CACHE_INODE_FLAG_CONTENT_HOLD, 00118 status) != CACHE_INODE_SUCCESS) { 00119 goto out; 00120 } 00121 opened = TRUE; 00122 } 00123 } 00124 00125 fsal_status = FSAL_commit(&(entry->object.file.open_fd.fd), 00126 offset, 00127 count); 00128 if (FSAL_IS_ERROR(fsal_status)) { 00129 LogMajor(COMPONENT_CACHE_INODE, 00130 "cache_inode_rdwr: fsal_commit() failed: " 00131 "fsal_status.major = %d", fsal_status.major); 00132 00133 *status = cache_inode_error_convert(fsal_status); 00134 if (fsal_status.major == ERR_FSAL_STALE) { 00135 cache_inode_kill_entry(entry); 00136 goto out; 00137 } 00138 /* Close the FD if we opened it. No need to catch an 00139 additional error form a close? */ 00140 if (opened) { 00141 cache_inode_close(entry, 00142 CACHE_INODE_FLAG_CONTENT_HAVE | 00143 CACHE_INODE_FLAG_CONTENT_HOLD, 00144 status); 00145 opened = FALSE; 00146 } 00147 goto out; 00148 } 00149 /* Close the FD if we opened it. */ 00150 if (opened) { 00151 if (cache_inode_close(entry, 00152 CACHE_INODE_FLAG_CONTENT_HAVE | 00153 CACHE_INODE_FLAG_CONTENT_HOLD, 00154 status) != 00155 CACHE_INODE_SUCCESS) { 00156 LogEvent(COMPONENT_CACHE_INODE, 00157 "cache_inode_commit: cache_inode_close = %d", 00158 *status); 00159 } 00160 } 00161 } else { 00162 /* Ok, it looks like we're using the Ganesha write 00163 * buffer. This means we will either be writing to the 00164 * buffer, or writing a stable write to the file system if 00165 * the buffer is already full. */ 00166 udata = &entry->object.file.unstable_data; 00167 if (udata->buffer == NULL) { 00168 *status = CACHE_INODE_SUCCESS; 00169 goto out; 00170 } 00171 if (count == 0 || count == 0xFFFFFFFFL) { 00172 /* Count = 0 means "flush all data to permanent storage */ 00173 pthread_rwlock_unlock(&entry->content_lock); 00174 content_locked = FALSE; 00175 *status = cache_inode_rdwr(entry, 00176 CACHE_INODE_WRITE, 00177 offset, 00178 udata->length, 00179 &bytes_moved, 00180 udata->buffer, 00181 NULL, 00182 context, 00183 CACHE_INODE_SAFE_WRITE_TO_FS, 00184 status); 00185 if (status != CACHE_INODE_SUCCESS) { 00186 goto out; 00187 } 00188 gsh_free(udata->buffer); 00189 udata->buffer = NULL; 00190 } else { 00191 if (offset < udata->offset) { 00192 *status = CACHE_INODE_INVALID_ARGUMENT; 00193 goto out; 00194 } 00195 00196 cache_inode_rdwr(entry, 00197 CACHE_INODE_WRITE, 00198 offset, 00199 count, 00200 &bytes_moved, 00201 (udata->buffer + 00202 offset - udata->offset), 00203 NULL, 00204 context, 00205 CACHE_INODE_SAFE_WRITE_TO_FS, 00206 status); 00207 } 00208 } 00209 00210 out: 00211 00212 if (content_locked) { 00213 pthread_rwlock_unlock(&entry->content_lock); 00214 } 00215 00216 return *status; 00217 }