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 00044 00045 #include <stdio.h> 00046 #include <string.h> 00047 #include <pthread.h> 00048 #include "HashData.h" 00049 #include "HashTable.h" 00050 #include "log.h" 00051 #include "ganesha_rpc.h" 00052 #include "nfs4.h" 00053 #include "nfs_core.h" 00054 #include "sal_functions.h" 00055 #include "nfs_proto_functions.h" 00056 #include "nfs_proto_tools.h" 00057 #ifdef _PNFS_DS 00058 #include <stdlib.h> 00059 #include <unistd.h> 00060 #include "fsal_pnfs.h" 00061 #endif /* _PNFS_DS */ 00062 00063 #ifdef _PNFS_DS 00064 static int op_dsread(struct nfs_argop4 *op, 00065 compound_data_t * data, 00066 struct nfs_resop4 *resp); 00067 #endif /* _PNFS_DS */ 00068 00083 #define arg_READ4 op->nfs_argop4_u.opread 00084 #define res_READ4 resp->nfs_resop4_u.opread 00085 00086 int nfs4_op_read(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) 00087 { 00088 size_t size = 0; 00089 size_t read_size = 0; 00090 fsal_off_t offset = 0; 00091 fsal_boolean_t eof_met = FALSE; 00092 caddr_t bufferdata = NULL; 00093 cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; 00094 state_t * pstate_found = NULL; 00095 state_t * pstate_open = NULL; 00096 fsal_attrib_list_t attr; 00097 cache_entry_t * pentry = NULL; 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 /* Say we are managing NFS4_OP_READ */ 00105 resp->resop = NFS4_OP_READ; 00106 res_READ4.status = NFS4_OK; 00107 00108 /* 00109 * Do basic checks on a filehandle 00110 * Only files can be read 00111 */ 00112 res_READ4.status = nfs4_sanity_check_FH(data, REGULAR_FILE); 00113 if(res_READ4.status != NFS4_OK) 00114 return res_READ4.status; 00115 00116 /* If Filehandle points to a xattr object, manage it via the xattrs 00117 specific functions */ 00118 if(nfs4_Is_Fh_Xattr(&(data->currentFH))) 00119 return nfs4_op_read_xattr(op, data, resp); 00120 00121 #ifdef _PNFS_DS 00122 if((data->minorversion == 1) && 00123 (nfs4_Is_Fh_DSHandle(&data->currentFH))) 00124 { 00125 return(op_dsread(op, data, resp)); 00126 } 00127 #endif /* _PNFS_DS */ 00128 00129 /* Manage access type MDONLY */ 00130 if(( data->pexport->access_type == ACCESSTYPE_MDONLY ) || 00131 ( data->pexport->access_type == ACCESSTYPE_MDONLY_RO ) ) 00132 { 00133 res_READ4.status = NFS4ERR_DQUOT; 00134 return res_READ4.status; 00135 } 00136 00137 /* vnode to manage is the current one */ 00138 pentry = data->current_entry; 00139 00140 /* Check stateid correctness and get pointer to state 00141 * (also checks for special stateids) 00142 */ 00143 res_READ4.status = nfs4_Check_Stateid(&arg_READ4.stateid, 00144 pentry, 00145 &pstate_found, 00146 data, 00147 STATEID_SPECIAL_ANY, 00148 "READ"); 00149 if(res_READ4.status != NFS4_OK) 00150 return res_READ4.status; 00151 00152 /* NB: After this point, if pstate_found == NULL, then the stateid 00153 is all-0 or all-1 */ 00154 00155 if(pstate_found != NULL) 00156 { 00157 switch(pstate_found->state_type) 00158 { 00159 case STATE_TYPE_SHARE: 00160 pstate_open = pstate_found; 00161 // TODO FSF: need to check against existing locks 00162 break; 00163 00164 case STATE_TYPE_LOCK: 00165 pstate_open = pstate_found->state_data.lock.popenstate; 00166 // TODO FSF: should check that write is in range of an byte range lock... 00167 break; 00168 00169 case STATE_TYPE_DELEG: 00170 pstate_open = NULL; 00171 // TODO FSF: should check that this is a read delegation? 00172 break; 00173 00174 default: 00175 res_READ4.status = NFS4ERR_BAD_STATEID; 00176 LogDebug(COMPONENT_NFS_V4_LOCK, 00177 "READ with invalid statid of type %d", 00178 (int) pstate_found->state_type); 00179 return res_READ4.status; 00180 } 00181 00182 /* This is a read operation, this means that the file MUST have 00183 been opened for reading */ 00184 if(pstate_open != NULL && 00185 (pstate_open->state_data.share.share_access & 00186 OPEN4_SHARE_ACCESS_READ) == 0) 00187 { 00188 /* Even if file is open for write, the client may do 00189 * accidently read operation (caching). Because of this, 00190 * READ is allowed if not explicitely denied. See page 72 in 00191 * RFC3530 for more details */ 00192 00193 if (pstate_open->state_data.share.share_deny & OPEN4_SHARE_DENY_READ) 00194 { 00195 /* Bad open mode, return NFS4ERR_OPENMODE */ 00196 res_READ4.status = NFS4ERR_OPENMODE; 00197 LogDebug(COMPONENT_NFS_V4_LOCK, 00198 "READ state %p doesn't have OPEN4_SHARE_ACCESS_READ", 00199 pstate_found); 00200 return res_READ4.status; 00201 } 00202 } 00203 00213 switch( pstate_found->state_type ) 00214 { 00215 case STATE_TYPE_SHARE: 00216 if ((data->minorversion == 0) && 00217 ((pstate_found->state_powner->so_owner.so_nfs4_owner 00218 .so_confirmed) == FALSE)) 00219 { 00220 res_READ4.status = NFS4ERR_BAD_STATEID; 00221 return res_READ4.status; 00222 } 00223 break ; 00224 00225 case STATE_TYPE_LOCK: 00226 /* Nothing to do */ 00227 break ; 00228 00229 default: 00230 /* Sanity check: all other types are illegal. we should 00231 * not got that place (similar check above), anyway it 00232 * costs nothing to add this test */ 00233 res_READ4.status = NFS4ERR_BAD_STATEID; 00234 return res_READ4.status; 00235 break ; 00236 } 00237 } 00238 else 00239 { 00240 /* Special stateid, no open state, check to see if any share conflicts */ 00241 pstate_open = NULL; 00242 00243 pthread_rwlock_rdlock(&pentry->state_lock); 00244 anonymous = TRUE; 00245 00246 /* 00247 * Special stateid, no open state, check to see if any share conflicts 00248 * The stateid is all-0 or all-1 00249 */ 00250 res_READ4.status = nfs4_check_special_stateid(pentry,"READ", 00251 FATTR4_ATTR_READ); 00252 if(res_READ4.status != NFS4_OK) 00253 { 00254 pthread_rwlock_unlock(&pentry->state_lock); 00255 return res_READ4.status; 00256 } 00257 } 00258 00259 if (pstate_open == NULL) 00260 { 00261 if(cache_inode_access(pentry, 00262 FSAL_READ_ACCESS, 00263 data->pcontext, 00264 &cache_status) != CACHE_INODE_SUCCESS) 00265 { 00266 if (anonymous) 00267 { 00268 pthread_rwlock_unlock(&pentry->state_lock); 00269 } 00270 res_READ4.status = nfs4_Errno(cache_status); 00271 return res_READ4.status; 00272 } 00273 } 00274 /* Get the size and offset of the read operation */ 00275 offset = arg_READ4.offset; 00276 size = arg_READ4.count; 00277 00278 LogFullDebug(COMPONENT_NFS_V4, 00279 "NFS4_OP_READ: offset = %"PRIu64" length = %zu", 00280 offset, size); 00281 00282 if((data->pexport->options & EXPORT_OPTION_MAXOFFSETREAD) == 00283 EXPORT_OPTION_MAXOFFSETREAD) 00284 if((fsal_off_t) (offset + size) > data->pexport->MaxOffsetRead) 00285 { 00286 res_READ4.status = NFS4ERR_DQUOT; 00287 if (anonymous) 00288 { 00289 pthread_rwlock_unlock(&pentry->state_lock); 00290 } 00291 return res_READ4.status; 00292 } 00293 00294 /* Do not read more than FATTR4_MAXREAD */ 00295 if( size > data->pexport->MaxRead ) 00296 { 00297 /* the client asked for too much data, 00298 * this should normally not happen because 00299 * client will get FATTR4_MAXREAD value at mount time */ 00300 00301 LogFullDebug(COMPONENT_NFS_V4, 00302 "NFS4_OP_READ: read requested size = %zu read allowed size = %zu", 00303 size, data->pexport->MaxRead); 00304 size = data->pexport->MaxRead; 00305 } 00306 00307 /* If size == 0 , no I/O is to be made and everything is alright */ 00308 if(size == 0) 00309 { 00310 res_READ4.READ4res_u.resok4.eof = FALSE; /* end of file was not reached because READ occured, and a size = 0 can not lead to eof */ 00311 res_READ4.READ4res_u.resok4.data.data_len = 0; 00312 res_READ4.READ4res_u.resok4.data.data_val = NULL; 00313 00314 res_READ4.status = NFS4_OK; 00315 if (anonymous) 00316 { 00317 pthread_rwlock_unlock(&pentry->state_lock); 00318 } 00319 return res_READ4.status; 00320 } 00321 00322 /* Some work is to be done */ 00323 if((bufferdata = gsh_malloc_aligned(4096, size)) == NULL) 00324 { 00325 res_READ4.status = NFS4ERR_SERVERFAULT; 00326 if (anonymous) 00327 { 00328 pthread_rwlock_unlock(&pentry->state_lock); 00329 } 00330 return res_READ4.status; 00331 } 00332 if(data->pexport->options & EXPORT_OPTION_USE_DATACACHE) 00333 memset(bufferdata, 0, size); 00334 00335 if((cache_inode_rdwr(pentry, 00336 CACHE_INODE_READ, 00337 offset, 00338 size, 00339 &read_size, 00340 bufferdata, 00341 &eof_met, 00342 data->pcontext, 00343 CACHE_INODE_SAFE_WRITE_TO_FS, 00344 &cache_status) != CACHE_INODE_SUCCESS) || 00345 ((cache_inode_getattr(pentry, &attr, data->pcontext, 00346 &cache_status)) != CACHE_INODE_SUCCESS)) 00347 00348 { 00349 res_READ4.status = nfs4_Errno(cache_status); 00350 if (anonymous) 00351 { 00352 pthread_rwlock_unlock(&pentry->state_lock); 00353 } 00354 return res_READ4.status; 00355 } 00356 00357 res_READ4.READ4res_u.resok4.data.data_len = read_size; 00358 res_READ4.READ4res_u.resok4.data.data_val = bufferdata; 00359 00360 LogFullDebug(COMPONENT_NFS_V4, 00361 "NFS4_OP_READ: offset = %"PRIu64" read length = %zu eof=%u", 00362 offset, read_size, eof_met); 00363 00364 /* Is EOF met or not ? */ 00365 if( ( eof_met == TRUE ) || 00366 ( (offset + read_size) >= attr.filesize) ) 00367 res_READ4.READ4res_u.resok4.eof = TRUE; 00368 else 00369 res_READ4.READ4res_u.resok4.eof = FALSE; 00370 00371 /* Say it is ok */ 00372 res_READ4.status = NFS4_OK; 00373 if (anonymous) 00374 { 00375 pthread_rwlock_unlock(&pentry->state_lock); 00376 } 00377 00378 return res_READ4.status; 00379 } /* nfs4_op_read */ 00380 00391 void nfs4_op_read_Free(READ4res * resp) 00392 { 00393 if(resp->status == NFS4_OK) 00394 if(resp->READ4res_u.resok4.data.data_len != 0) 00395 gsh_free(resp->READ4res_u.resok4.data.data_val); 00396 return; 00397 } /* nfs4_op_read_Free */ 00398 00399 00400 #ifdef _PNFS_DS 00401 00413 static int op_dsread(struct nfs_argop4 *op, 00414 compound_data_t * data, 00415 struct nfs_resop4 *resp) 00416 { 00417 /* The FSAL file handle */ 00418 fsal_handle_t handle; 00419 struct fsal_handle_desc fh_desc; 00420 /* NFSv4 return code */ 00421 nfsstat4 nfs_status = 0; 00422 /* Buffer into which data is to be read */ 00423 caddr_t buffer = NULL; 00424 /* End of file flag */ 00425 fsal_boolean_t eof = FALSE; 00426 00427 /* Don't bother calling the FSAL if the read length is 0. */ 00428 00429 if(arg_READ4.count == 0) 00430 { 00431 res_READ4.READ4res_u.resok4.eof = FALSE; 00432 res_READ4.READ4res_u.resok4.data.data_len = 0; 00433 res_READ4.READ4res_u.resok4.data.data_val = NULL; 00434 res_READ4.status = NFS4_OK; 00435 return res_READ4.status; 00436 } 00437 00438 /* Construct the FSAL file handle */ 00439 00440 if ((nfs4_FhandleToFSAL(&data->currentFH, 00441 &fh_desc, 00442 data->pcontext)) == 0) 00443 { 00444 res_READ4.status = NFS4ERR_INVAL; 00445 return res_READ4.status; 00446 } 00447 memset(&handle, 0, sizeof(handle)); 00448 memcpy(&handle, fh_desc.start, fh_desc.len); 00449 00450 buffer = gsh_malloc_aligned(4096, arg_READ4.count); 00451 if (buffer == NULL) 00452 { 00453 res_READ4.status = NFS4ERR_SERVERFAULT; 00454 return res_READ4.status; 00455 } 00456 00457 res_READ4.READ4res_u.resok4.data.data_val = buffer; 00458 00459 if ((nfs_status 00460 = fsal_dsfunctions.DS_read(&handle, 00461 data->pcontext, 00462 &arg_READ4.stateid, 00463 arg_READ4.offset, 00464 arg_READ4.count, 00465 res_READ4.READ4res_u.resok4.data.data_val, 00466 &res_READ4.READ4res_u.resok4.data.data_len, 00467 &eof)) 00468 != NFS4_OK) 00469 { 00470 gsh_free(buffer); 00471 buffer = NULL; 00472 } 00473 00474 res_READ4.READ4res_u.resok4.eof = eof; 00475 00476 res_READ4.status = nfs_status; 00477 00478 return res_READ4.status; 00479 } 00480 00481 #endif /* _PNFS_DS */