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 00043 00044 #include <stdio.h> 00045 #include <string.h> 00046 #include <pthread.h> 00047 #include "HashData.h" 00048 #include "HashTable.h" 00049 #include "log.h" 00050 #include "ganesha_rpc.h" 00051 #include "nfs4.h" 00052 #include "nfs_core.h" 00053 #include "sal_functions.h" 00054 #include "nfs_proto_functions.h" 00055 #include "nfs_proto_tools.h" 00056 #ifdef _PNFS_DS 00057 #include "fsal_pnfs.h" 00058 #endif /* _PNFS_DS */ 00059 00060 #ifdef _PNFS_DS 00061 static int op_dswrite(struct nfs_argop4 *op, 00062 compound_data_t * data, 00063 struct nfs_resop4 *resp); 00064 #endif /* _PNFS_DS */ 00065 00079 #define arg_WRITE4 op->nfs_argop4_u.opwrite 00080 #define res_WRITE4 resp->nfs_resop4_u.opwrite 00081 00082 int nfs4_op_write(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) 00083 { 00084 fsal_size_t size; 00085 fsal_size_t written_size; 00086 fsal_off_t offset; 00087 fsal_boolean_t eof_met; 00088 cache_inode_stability_t stability = CACHE_INODE_SAFE_WRITE_TO_FS; 00089 caddr_t bufferdata; 00090 stable_how4 stable_how; 00091 state_t * pstate_found = NULL; 00092 state_t * pstate_open; 00093 cache_inode_status_t cache_status; 00094 cache_entry_t * pentry = NULL; 00095 #ifdef _USE_QUOTA 00096 fsal_status_t fsal_status ; 00097 #endif 00098 /* This flag is set to true in the case of an anonymous read so that 00099 we know to release the state lock afterward. The state lock does 00100 not need to be held during a non-anonymous read, since the open 00101 state itself prevents a conflict. */ 00102 bool_t anonymous = FALSE; 00103 00104 /* Lock are not supported */ 00105 resp->resop = NFS4_OP_WRITE; 00106 res_WRITE4.status = NFS4_OK; 00107 00108 /* 00109 * Do basic checks on a filehandle 00110 * Only files can be written 00111 */ 00112 res_WRITE4.status = nfs4_sanity_check_FH(data, REGULAR_FILE); 00113 if(res_WRITE4.status != NFS4_OK) 00114 return res_WRITE4.status; 00115 00116 #ifdef _USE_QUOTA 00117 /* if quota support is active, then we should check is the FSAL allows inode creation or not */ 00118 fsal_status = FSAL_check_quota( data->pexport->fullpath, 00119 FSAL_QUOTA_BLOCKS, 00120 FSAL_OP_CONTEXT_TO_UID( data->pcontext ) ) ; 00121 if( FSAL_IS_ERROR( fsal_status ) ) 00122 { 00123 res_WRITE4.status = NFS4ERR_DQUOT ; 00124 return res_WRITE4.status; 00125 } 00126 #endif /* _USE_QUOTA */ 00127 00128 /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */ 00129 if(nfs4_Is_Fh_Xattr(&(data->currentFH))) 00130 return nfs4_op_write_xattr(op, data, resp); 00131 00132 #ifdef _PNFS_DS 00133 if((data->minorversion == 1) && 00134 (nfs4_Is_Fh_DSHandle(&data->currentFH))) 00135 { 00136 return(op_dswrite(op, data, resp)); 00137 } 00138 #endif /* _PNFS_DS */ 00139 00140 /* Manage access type */ 00141 switch( data->pexport->access_type ) 00142 { 00143 case ACCESSTYPE_MDONLY: 00144 case ACCESSTYPE_MDONLY_RO: 00145 res_WRITE4.status = NFS4ERR_DQUOT; 00146 return res_WRITE4.status; 00147 break ; 00148 00149 case ACCESSTYPE_RO: 00150 res_WRITE4.status = NFS4ERR_ROFS ; 00151 return res_WRITE4.status; 00152 break ; 00153 00154 default: 00155 break ; 00156 } /* switch( data->pexport->access_type ) */ 00157 00158 /* vnode to manage is the current one */ 00159 pentry = data->current_entry; 00160 00161 /* Check stateid correctness and get pointer to state 00162 * (also checks for special stateids) 00163 */ 00164 res_WRITE4.status = nfs4_Check_Stateid(&arg_WRITE4.stateid, 00165 pentry, 00166 &pstate_found, 00167 data, 00168 STATEID_SPECIAL_ANY, 00169 "WRITE"); 00170 if(res_WRITE4.status != NFS4_OK) 00171 return res_WRITE4.status; 00172 00173 /* NB: After this points, if pstate_found == NULL, then the stateid is all-0 or all-1 */ 00174 00175 if(pstate_found != NULL) 00176 { 00177 switch(pstate_found->state_type) 00178 { 00179 case STATE_TYPE_SHARE: 00180 pstate_open = pstate_found; 00181 // TODO FSF: need to check against existing locks 00182 break; 00183 00184 case STATE_TYPE_LOCK: 00185 pstate_open = pstate_found->state_data.lock.popenstate; 00186 // TODO FSF: should check that write is in range of an exclusive lock... 00187 break; 00188 00189 case STATE_TYPE_DELEG: 00190 #ifdef _USE_NFS4_1 00191 case STATE_TYPE_LAYOUT: 00192 #endif /* _USE_NFS4_1 */ 00193 pstate_open = NULL; 00194 // TODO FSF: should check that this is a write delegation? 00195 break; 00196 00197 default: 00198 res_WRITE4.status = NFS4ERR_BAD_STATEID; 00199 LogDebug(COMPONENT_NFS_V4_LOCK, 00200 "WRITE with invalid stateid of type %d", 00201 (int) pstate_found->state_type); 00202 return res_WRITE4.status; 00203 } 00204 00205 /* This is a write operation, this means that the file MUST have been opened for writing */ 00206 if(pstate_open != NULL && 00207 (pstate_open->state_data.share.share_access & OPEN4_SHARE_ACCESS_WRITE) == 0) 00208 { 00209 /* Bad open mode, return NFS4ERR_OPENMODE */ 00210 res_WRITE4.status = NFS4ERR_OPENMODE; 00211 LogDebug(COMPONENT_NFS_V4_LOCK, 00212 "WRITE state %p doesn't have OPEN4_SHARE_ACCESS_WRITE", 00213 pstate_found); 00214 return res_WRITE4.status; 00215 } 00216 } 00217 else 00218 { 00219 /* Special stateid, no open state, check to see if any share conflicts */ 00220 pstate_open = NULL; 00221 00222 pthread_rwlock_rdlock(&pentry->state_lock); 00223 anonymous = TRUE; 00224 00225 /* 00226 * Special stateid, no open state, check to see if any share conflicts 00227 * The stateid is all-0 or all-1 00228 */ 00229 res_WRITE4.status = nfs4_check_special_stateid(pentry,"WRITE", 00230 FATTR4_ATTR_WRITE); 00231 if(res_WRITE4.status != NFS4_OK) 00232 { 00233 pthread_rwlock_unlock(&pentry->state_lock); 00234 return res_WRITE4.status; 00235 } 00236 } 00237 00238 if (pstate_open == NULL) 00239 { 00240 if(cache_inode_access(pentry, 00241 FSAL_WRITE_ACCESS, 00242 data->pcontext, 00243 &cache_status) != CACHE_INODE_SUCCESS) 00244 { 00245 res_WRITE4.status = nfs4_Errno(cache_status);; 00246 pthread_rwlock_unlock(&pentry->state_lock); 00247 return res_WRITE4.status; 00248 } 00249 } 00250 00251 /* Get the characteristics of the I/O to be made */ 00252 offset = arg_WRITE4.offset; 00253 size = arg_WRITE4.data.data_len; 00254 stable_how = arg_WRITE4.stable; 00255 LogFullDebug(COMPONENT_NFS_V4, 00256 "NFS4_OP_WRITE: offset = %"PRIu64" length = %zu stable = %d", 00257 offset, size, stable_how); 00258 00259 if((data->pexport->options & EXPORT_OPTION_MAXOFFSETWRITE) == 00260 EXPORT_OPTION_MAXOFFSETWRITE) 00261 if((fsal_off_t) (offset + size) > data->pexport->MaxOffsetWrite) 00262 { 00263 res_WRITE4.status = NFS4ERR_DQUOT; 00264 if (anonymous) 00265 { 00266 pthread_rwlock_unlock(&pentry->state_lock); 00267 } 00268 return res_WRITE4.status; 00269 } 00270 00271 /* The size to be written should not be greater than FATTR4_MAXWRITESIZE because this value is asked 00272 * by the client at mount time, but we check this by security */ 00273 00274 if( size > data->pexport->MaxWrite ) 00275 { 00276 /* 00277 * The client asked for too much data, we 00278 * must restrict him 00279 */ 00280 00281 LogFullDebug(COMPONENT_NFS_V4, 00282 "NFS4_OP_WRITE: write requested size = %"PRIu64" write allowed size = %"PRIu64, 00283 size, data->pexport->MaxWrite); 00284 00285 size = data->pexport->MaxWrite; 00286 } 00287 00288 /* Where are the data ? */ 00289 bufferdata = arg_WRITE4.data.data_val; 00290 00291 LogFullDebug(COMPONENT_NFS_V4, 00292 "NFS4_OP_WRITE: offset = %"PRIu64" length = %zu", 00293 offset, size); 00294 00295 /* if size == 0 , no I/O) are actually made and everything is alright */ 00296 if(size == 0) 00297 { 00298 res_WRITE4.WRITE4res_u.resok4.count = 0; 00299 res_WRITE4.WRITE4res_u.resok4.committed = FILE_SYNC4; 00300 00301 memcpy(res_WRITE4.WRITE4res_u.resok4.writeverf, NFS4_write_verifier, 00302 sizeof(verifier4)); 00303 00304 res_WRITE4.status = NFS4_OK; 00305 if (anonymous) 00306 { 00307 pthread_rwlock_unlock(&pentry->state_lock); 00308 } 00309 return res_WRITE4.status; 00310 } 00311 00312 if(arg_WRITE4.stable == UNSTABLE4) 00313 { 00314 stability = CACHE_INODE_UNSAFE_WRITE_TO_FS_BUFFER; 00315 } 00316 else 00317 { 00318 stability = CACHE_INODE_SAFE_WRITE_TO_FS; 00319 } 00320 00321 if(cache_inode_rdwr(pentry, 00322 CACHE_INODE_WRITE, 00323 offset, 00324 size, 00325 &written_size, 00326 bufferdata, 00327 &eof_met, 00328 data->pcontext, 00329 stability, 00330 &cache_status) != CACHE_INODE_SUCCESS) 00331 { 00332 LogDebug(COMPONENT_NFS_V4, 00333 "cache_inode_rdwr returned %s", 00334 cache_inode_err_str(cache_status)); 00335 res_WRITE4.status = nfs4_Errno(cache_status); 00336 if (anonymous) 00337 { 00338 pthread_rwlock_unlock(&pentry->state_lock); 00339 } 00340 return res_WRITE4.status; 00341 } 00342 00343 /* Set the returned value */ 00344 if(stability == CACHE_INODE_SAFE_WRITE_TO_FS) 00345 res_WRITE4.WRITE4res_u.resok4.committed = FILE_SYNC4; 00346 else 00347 res_WRITE4.WRITE4res_u.resok4.committed = UNSTABLE4; 00348 00349 res_WRITE4.WRITE4res_u.resok4.count = written_size; 00350 memcpy(res_WRITE4.WRITE4res_u.resok4.writeverf, NFS4_write_verifier, sizeof(verifier4)); 00351 00352 res_WRITE4.status = NFS4_OK; 00353 00354 if (anonymous) 00355 { 00356 pthread_rwlock_unlock(&pentry->state_lock); 00357 } 00358 00359 return res_WRITE4.status; 00360 } /* nfs4_op_write */ 00361 00372 void nfs4_op_write_Free(WRITE4res * resp) 00373 { 00374 /* Nothing to be done */ 00375 return; 00376 } /* nfs4_op_write_Free */ 00377 00378 #ifdef _PNFS_DS 00379 00391 static int op_dswrite(struct nfs_argop4 *op, 00392 compound_data_t * data, 00393 struct nfs_resop4 *resp) 00394 { 00395 /* FSAL file handle */ 00396 fsal_handle_t handle; 00397 /* NFSv4 return code */ 00398 nfsstat4 nfs_status = 0; 00399 struct fsal_handle_desc fh_desc; 00400 00401 /* Construct the FSAL file handle */ 00402 00403 if ((nfs4_FhandleToFSAL(&data->currentFH, 00404 &fh_desc, 00405 data->pcontext)) == 0) 00406 { 00407 res_WRITE4.status = NFS4ERR_INVAL; 00408 return res_WRITE4.status; 00409 } 00410 00411 memset((caddr_t) &handle, 0, sizeof(handle)); 00412 memcpy((caddr_t) &handle, fh_desc.start, fh_desc.len); 00413 nfs_status 00414 = fsal_dsfunctions.DS_write(&handle, 00415 data->pcontext, 00416 &arg_WRITE4.stateid, 00417 arg_WRITE4.offset, 00418 arg_WRITE4.data.data_len, 00419 arg_WRITE4.data.data_val, 00420 arg_WRITE4.stable, 00421 &res_WRITE4.WRITE4res_u.resok4.count, 00422 &res_WRITE4.WRITE4res_u.resok4.writeverf, 00423 &res_WRITE4.WRITE4res_u.resok4.committed); 00424 00425 res_WRITE4.status = nfs_status; 00426 return res_WRITE4.status; 00427 } 00428 #endif /* _PNFS_DS */