nfs-ganesha 1.4
|
00001 /* vim:expandtab:shiftwidth=8:tabstop=8: 00002 * 00003 * Copyright CEA/DAM/DIF (2008) 00004 * contributeur : Philippe DENIEL philippe.deniel@cea.fr 00005 * Thomas LEIBOVICI thomas.leibovici@cea.fr 00006 * 00007 * 00008 * This program is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public License 00010 * as published by the Free Software Foundation; either version 3 of 00011 * the License, or (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, but 00014 * WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00021 * 02110-1301 USA 00022 * 00023 * --------------------------------------- 00024 */ 00025 00034 #ifdef HAVE_CONFIG_H 00035 #include "config.h" 00036 #endif 00037 00038 #ifdef _SOLARIS 00039 #include "solaris_port.h" 00040 #endif /* _SOLARIS */ 00041 00042 #include <unistd.h> 00043 #include <sys/types.h> 00044 #include <sys/param.h> 00045 #include <time.h> 00046 #include <pthread.h> 00047 #include <string.h> 00048 00049 #include "LRU_List.h" 00050 #include "log.h" 00051 #include "HashData.h" 00052 #include "HashTable.h" 00053 #include "nfs_core.h" 00054 #include "nfs4.h" 00055 #include "fsal.h" 00056 #include "sal_functions.h" 00057 #include "cache_inode_lru.h" 00058 00072 int state_conflict(state_t * pstate, 00073 state_type_t state_type, 00074 state_data_t * pstate_data) 00075 { 00076 if(pstate == NULL || pstate_data == NULL) 00077 return TRUE; 00078 00079 switch (state_type) 00080 { 00081 case STATE_TYPE_NONE: 00082 return FALSE; /* STATE_NONE conflicts with nobody */ 00083 00084 case STATE_TYPE_SHARE: 00085 if(pstate->state_type == STATE_TYPE_SHARE) 00086 { 00087 if((pstate->state_data.share.share_access & pstate_data->share.share_deny) || 00088 (pstate->state_data.share.share_deny & pstate_data->share.share_access)) 00089 return TRUE; 00090 } 00091 return FALSE; 00092 00093 case STATE_TYPE_LOCK: 00094 return FALSE; /* lock conflict is managed in the NFS request */ 00095 00096 case STATE_TYPE_LAYOUT: 00097 return FALSE; 00099 case STATE_TYPE_DELEG: 00100 /* Not yet implemented for now, answer TRUE to avoid weird behavior */ 00101 return TRUE; 00102 } 00103 00104 return TRUE; 00105 } /* state_conflict */ 00106 00126 state_status_t state_add_impl(cache_entry_t * pentry, 00127 state_type_t state_type, 00128 state_data_t * pstate_data, 00129 state_owner_t * powner_input, 00130 fsal_op_context_t * pcontext, 00131 state_t ** ppstate, 00132 state_status_t * pstatus) 00133 { 00134 state_t * pnew_state = NULL; 00135 state_t * piter_state = NULL; 00136 char debug_str[OTHERSIZE * 2 + 1]; 00137 struct glist_head * glist; 00138 cache_inode_status_t cache_status; 00139 bool_t got_pinned = FALSE; 00140 00141 if(glist_empty(&pentry->state_list)) 00142 { 00143 cache_status = cache_inode_inc_pin_ref(pentry); 00144 00145 if(cache_status != CACHE_INODE_SUCCESS) 00146 { 00147 *pstatus = cache_inode_status_to_state_status(cache_status); 00148 LogDebug(COMPONENT_STATE, 00149 "Could not pin file"); 00150 return *pstatus; 00151 } 00152 00153 got_pinned = TRUE; 00154 } 00155 00156 pnew_state = pool_alloc(state_v4_pool, NULL); 00157 00158 if(pnew_state == NULL) 00159 { 00160 LogDebug(COMPONENT_STATE, 00161 "Can't allocate a new file state from cache pool"); 00162 00163 /* stat */ 00164 *pstatus = STATE_MALLOC_ERROR; 00165 00166 if(got_pinned) 00167 cache_inode_dec_pin_ref(pentry); 00168 00169 return *pstatus; 00170 } 00171 00172 memset(pnew_state, 0, sizeof(*pnew_state)); 00173 00174 /* Browse the state's list */ 00175 glist_for_each(glist, &pentry->state_list) 00176 { 00177 piter_state = glist_entry(glist, state_t, state_list); 00178 00179 if(state_conflict(piter_state, state_type, pstate_data)) 00180 { 00181 LogDebug(COMPONENT_STATE, 00182 "new state conflicts with another state for pentry %p", 00183 pentry); 00184 00185 /* stat */ 00186 pool_free(state_v4_pool, pnew_state); 00187 00188 *pstatus = STATE_STATE_CONFLICT; 00189 00190 if(got_pinned) 00191 cache_inode_dec_pin_ref(pentry); 00192 00193 return *pstatus; 00194 } 00195 } 00196 00197 /* Add the stateid.other, this will increment state_id_counter */ 00198 nfs4_BuildStateId_Other(pnew_state->stateid_other); 00199 00200 /* Set the type and data for this state */ 00201 memcpy(&(pnew_state->state_data), pstate_data, sizeof(state_data_t)); 00202 pnew_state->state_type = state_type; 00203 pnew_state->state_seqid = 0; /* will be incremented to 1 later */ 00204 pnew_state->state_pentry = pentry; 00205 pnew_state->state_powner = powner_input; 00206 00207 if (isDebug(COMPONENT_STATE)) 00208 sprint_mem(debug_str, (char *)pnew_state->stateid_other, OTHERSIZE); 00209 00210 init_glist(&pnew_state->state_list); 00211 init_glist(&pnew_state->state_owner_list); 00212 00213 /* Add the state to the related hashtable */ 00214 if(!nfs4_State_Set(pnew_state->stateid_other, pnew_state)) 00215 { 00216 LogDebug(COMPONENT_STATE, 00217 "Can't create a new state id %s for the pentry %p (F)", 00218 debug_str, pentry); 00219 00220 pool_free(state_v4_pool, pnew_state); 00221 00222 /* Return STATE_MALLOC_ERROR since most likely the nfs4_State_Set failed 00223 * to allocate memory. 00224 */ 00225 *pstatus = STATE_MALLOC_ERROR; 00226 00227 if(got_pinned) 00228 cache_inode_dec_pin_ref(pentry); 00229 00230 return *pstatus; 00231 } 00232 00233 /* Add state to list for cache entry */ 00234 glist_add_tail(&pentry->state_list, &pnew_state->state_list); 00235 00236 P(powner_input->so_mutex); 00237 glist_add_tail(&powner_input->so_owner.so_nfs4_owner.so_state_list, 00238 &pnew_state->state_owner_list); 00239 V(powner_input->so_mutex); 00240 00241 /* Copy the result */ 00242 *ppstate = pnew_state; 00243 00244 LogFullDebug(COMPONENT_STATE, 00245 "Add State: %s", debug_str); 00246 00247 /* Regular exit */ 00248 *pstatus = STATE_SUCCESS; 00249 return *pstatus; 00250 } /* state_add */ 00251 00252 00270 state_status_t state_add(cache_entry_t * pentry, 00271 state_type_t state_type, 00272 state_data_t * pstate_data, 00273 state_owner_t * powner_input, 00274 fsal_op_context_t * pcontext, 00275 state_t ** ppstate, 00276 state_status_t * pstatus) 00277 { 00278 /* Ensure that states are are associated only with the appropriate 00279 owners */ 00280 00281 if (((state_type == STATE_TYPE_SHARE) && 00282 (powner_input->so_type != STATE_OPEN_OWNER_NFSV4)) || 00283 ((state_type == STATE_TYPE_LOCK) && 00284 (powner_input->so_type != STATE_LOCK_OWNER_NFSV4)) || 00285 (((state_type == STATE_TYPE_DELEG) || 00286 (state_type == STATE_TYPE_LAYOUT)) && 00287 (powner_input->so_type != STATE_CLIENTID_OWNER_NFSV4))) 00288 { 00289 return (*pstatus = STATE_BAD_TYPE); 00290 } 00291 00292 pthread_rwlock_wrlock(&pentry->state_lock); 00293 state_add_impl(pentry, state_type, pstate_data, powner_input, 00294 pcontext, ppstate, pstatus); 00295 pthread_rwlock_unlock(&pentry->state_lock); 00296 00297 return *pstatus; 00298 } /* state_add */ 00299 00300 state_status_t state_del_locked(state_t * pstate, 00301 cache_entry_t * pentry) 00302 { 00303 char debug_str[OTHERSIZE * 2 + 1]; 00304 00305 if (isDebug(COMPONENT_STATE)) 00306 sprint_mem(debug_str, (char *)pstate->stateid_other, OTHERSIZE); 00307 00308 LogFullDebug(COMPONENT_STATE, "Deleting state %s", debug_str); 00309 00310 /* Remove the entry from the HashTable */ 00311 if(!nfs4_State_Del(pstate->stateid_other)) 00312 { 00313 LogDebug(COMPONENT_STATE, "Could not delete state %s", debug_str); 00314 00315 return STATE_STATE_ERROR; 00316 } 00317 00318 /* Remove from list of states owned by owner */ 00319 00320 /* Release the state owner reference */ 00321 if(pstate->state_powner != NULL) 00322 { 00323 P(pstate->state_powner->so_mutex); 00324 glist_del(&pstate->state_owner_list); 00325 V(pstate->state_powner->so_mutex); 00326 dec_state_owner_ref(pstate->state_powner); 00327 } 00328 00329 /* Remove from the list of states for a particular cache entry */ 00330 glist_del(&pstate->state_list); 00331 00332 /* Remove from the list of lock states for a particular open state */ 00333 if(pstate->state_type == STATE_TYPE_LOCK) 00334 glist_del(&pstate->state_data.lock.state_sharelist); 00335 00336 /* Remove from list of states for a particular export */ 00337 P(pstate->state_pexport->exp_state_mutex); 00338 glist_del(&pstate->state_export_list); 00339 V(pstate->state_pexport->exp_state_mutex); 00340 00341 pool_free(state_v4_pool, pstate); 00342 00343 LogFullDebug(COMPONENT_STATE, "Deleted state %s", debug_str); 00344 00345 if(glist_empty(&pentry->state_list)) 00346 cache_inode_dec_pin_ref(pentry); 00347 00348 return STATE_SUCCESS; 00349 } 00350 00363 state_status_t state_del(state_t * pstate, 00364 state_status_t * pstatus) 00365 { 00366 cache_entry_t *entry = pstate->state_pentry; 00367 00368 pthread_rwlock_wrlock(&entry->state_lock); 00369 00370 *pstatus = state_del_locked(pstate, pstate->state_pentry); 00371 00372 pthread_rwlock_unlock(&entry->state_lock); 00373 00374 return *pstatus; 00375 } /* state_del */ 00376 00377 void state_nfs4_state_wipe(cache_entry_t * pentry) 00378 { 00379 struct glist_head * glist, *glistn; 00380 state_t * pstate = NULL; 00381 00382 if(glist_empty(&pentry->state_list)) 00383 return; 00384 00385 glist_for_each_safe(glist, glistn, &pentry->state_list) 00386 { 00387 pstate = glist_entry(glist, state_t, state_list); 00388 state_del_locked(pstate, pentry); 00389 } 00390 00391 return; 00392 } 00393 00402 void release_lockstate(state_owner_t * plock_owner) 00403 { 00404 state_status_t state_status; 00405 struct glist_head * glist, * glistn; 00406 00407 glist_for_each_safe(glist, glistn, &plock_owner->so_owner.so_nfs4_owner.so_state_list) 00408 { 00409 state_t * pstate_found = glist_entry(glist, 00410 state_t, 00411 state_owner_list); 00412 00413 /* Make sure we hold an lru ref to the cache inode while calling state_del */ 00414 if(cache_inode_lru_ref(pstate_found->state_pentry, 00415 0) != CACHE_INODE_SUCCESS) 00416 LogCrit(COMPONENT_CLIENTID, 00417 "Ugliness - cache_inode_lru_ref has returned non-success"); 00418 00419 if(state_del(pstate_found, 00420 &state_status) != STATE_SUCCESS) 00421 { 00422 LogDebug(COMPONENT_CLIENTID, 00423 "release_lockstate failed to release stateid error %s", 00424 state_err_str(state_status)); 00425 } 00426 00427 /* Release the lru ref to the cache inode we held while calling state_del */ 00428 cache_inode_lru_unref(pstate_found->state_pentry, 00429 0); 00430 } 00431 00432 /* Release the reference to the lock owner that keeps it in the hash table */ 00433 dec_state_owner_ref(plock_owner); 00434 } 00435 00444 void release_openstate(state_owner_t * popen_owner) 00445 { 00446 state_status_t state_status; 00447 struct glist_head * glist, * glistn; 00448 00449 glist_for_each_safe(glist, glistn, &popen_owner->so_owner.so_nfs4_owner.so_state_list) 00450 { 00451 fsal_op_context_t fsal_context; 00452 fsal_status_t fsal_status; 00453 00454 state_t * pstate_found = glist_entry(glist, 00455 state_t, 00456 state_owner_list); 00457 00458 cache_entry_t * pentry = pstate_found->state_pentry; 00459 cache_inode_status_t cache_status; 00460 00461 /* Make sure we hold an lru ref to the cache inode while calling state_del */ 00462 if(cache_inode_lru_ref(pentry, 00463 0) != CACHE_INODE_SUCCESS) 00464 LogCrit(COMPONENT_CLIENTID, 00465 "Ugliness - cache_inode_lru_ref has returned non-success"); 00466 00467 pthread_rwlock_wrlock(&pentry->state_lock); 00468 /* Construct the fsal context based on the export and root credential */ 00469 fsal_status = FSAL_GetClientContext(&fsal_context, 00470 &pstate_found->state_pexport->FS_export_context, 00471 0, 00472 0, 00473 NULL, 00474 0); 00475 00476 if(FSAL_IS_ERROR(fsal_status)) 00477 { 00478 /* log error here , and continue? */ 00479 LogEvent(COMPONENT_CLIENTID, 00480 "FSAL_GetClientConext failed"); 00481 } 00482 else if(pstate_found->state_type == STATE_TYPE_SHARE) 00483 { 00484 if(state_share_remove(pstate_found->state_pentry, 00485 &fsal_context, 00486 popen_owner, 00487 pstate_found, 00488 &state_status) != STATE_SUCCESS) 00489 { 00490 LogEvent(COMPONENT_CLIENTID, 00491 "EXPIRY failed to release share stateid error %s", 00492 state_err_str(state_status)); 00493 } 00494 } 00495 00496 if((state_status 00497 = state_del_locked(pstate_found, 00498 pentry)) != STATE_SUCCESS) 00499 { 00500 LogDebug(COMPONENT_CLIENTID, 00501 "EXPIRY failed to release stateid error %s", 00502 state_err_str(state_status)); 00503 } 00504 00505 /* Close the file in FSAL through the cache inode */ 00506 cache_inode_close(pentry, 00507 0, 00508 &cache_status); 00509 00510 pthread_rwlock_unlock(&pentry->state_lock); 00511 00512 /* Release the lru ref to the cache inode we held while calling state_del */ 00513 cache_inode_lru_unref(pentry, 00514 0); 00515 } 00516 00517 /* Release the reference to the open owner that keeps it in the hash table */ 00518 dec_state_owner_ref(popen_owner); 00519 }