nfs-ganesha 1.4
|
00001 00032 #ifdef HAVE_CONFIG_H 00033 #include "config.h" 00034 #endif 00035 00036 #ifdef _SOLARIS 00037 #include "solaris_port.h" 00038 #endif 00039 00040 #include <stdio.h> 00041 #include <sys/types.h> 00042 #include <ctype.h> /* for having isalnum */ 00043 #include <stdlib.h> /* for having atoi */ 00044 #include <dirent.h> /* for having MAXNAMLEN */ 00045 #include <netdb.h> 00046 #include <netinet/in.h> 00047 #include <arpa/inet.h> 00048 #include <string.h> 00049 #include <pthread.h> 00050 #include <fcntl.h> 00051 #include <sys/file.h> /* for having FNDELAY */ 00052 #include <pwd.h> 00053 #include <grp.h> 00054 #include <pthread.h> 00055 #include "log.h" 00056 #include "ganesha_rpc.h" 00057 #include "HashData.h" 00058 #include "HashTable.h" 00059 #include "nfs_core.h" 00060 #include "nfs4.h" 00061 #include "fsal.h" 00062 #include "nfs_tools.h" 00063 #include "nfs_exports.h" 00064 #include "nfs_file_handle.h" 00065 #include "sal_functions.h" 00066 00067 size_t strnlen(const char *s, size_t maxlen); 00068 00069 hash_table_t *ht_state_id; 00070 00071 char all_zero[OTHERSIZE]; 00072 char all_one[OTHERSIZE]; 00073 #define seqid_all_one 0xFFFFFFFF 00074 00075 pthread_mutex_t StateIdMutex = PTHREAD_MUTEX_INITIALIZER; 00076 uint64_t state_id_counter; 00077 00078 int display_stateid_other(char * other, char * str) 00079 { 00080 uint32_t epoch = *((uint32_t *)other); 00081 uint64_t count = *((uint64_t *)(other + sizeof(uint32_t))); 00082 return sprintf(str, "epoch=0x%08x counter=0x%016llx", 00083 (unsigned int) epoch, (unsigned long long) count); 00084 } 00085 00086 int display_state_id_key(hash_buffer_t * pbuff, char *str) 00087 { 00088 return display_stateid_other(pbuff->pdata, str); 00089 } /* display_state_id_val */ 00090 00091 int display_state_id_val(hash_buffer_t * pbuff, char *str) 00092 { 00093 state_t *pstate = (state_t *) (pbuff->pdata); 00094 00095 return sprintf(str, 00096 "state %p is associated with pentry=%p type=%u seqid=%u", 00097 pstate, 00098 pstate->state_pentry, 00099 pstate->state_type, 00100 pstate->state_seqid); 00101 } /* display_state_id_val */ 00102 00103 int compare_state_id(hash_buffer_t * buff1, hash_buffer_t * buff2) 00104 { 00105 if(isFullDebug(COMPONENT_STATE)) 00106 { 00107 char str1[OTHERSIZE * 2 + 32], str2[OTHERSIZE * 2 + 32]; 00108 00109 display_stateid_other(buff1->pdata, str1); 00110 display_stateid_other(buff2->pdata, str2); 00111 00112 if(isDebug(COMPONENT_HASHTABLE)) 00113 LogFullDebug(COMPONENT_STATE, 00114 "{%s} vs {%s}", 00115 str1, str2); 00116 } 00117 00118 return memcmp(buff1->pdata, buff2->pdata, OTHERSIZE); 00119 } /* compare_state_id */ 00120 00121 inline uint32_t compute_stateid_hash_value(uint32_t * pstate) 00122 { 00123 return pstate[1] ^ pstate[2]; 00124 } 00125 00126 uint32_t state_id_value_hash_func(hash_parameter_t * p_hparam, 00127 hash_buffer_t * buffclef) 00128 { 00129 uint32_t val = compute_stateid_hash_value((uint32_t *) buffclef->pdata) % 00130 p_hparam->index_size; 00131 00132 if(isDebug(COMPONENT_HASHTABLE)) 00133 LogFullDebug(COMPONENT_STATE, "val = %"PRIu32, val); 00134 00135 return val; 00136 } 00137 00138 uint64_t state_id_rbt_hash_func(hash_parameter_t * p_hparam, 00139 hash_buffer_t * buffclef) 00140 { 00141 uint64_t val = compute_stateid_hash_value((uint32_t *) buffclef->pdata); 00142 00143 if(isDebug(COMPONENT_HASHTABLE)) 00144 LogFullDebug(COMPONENT_STATE, "rbt = %"PRIu64, val); 00145 00146 return val; 00147 } 00148 00160 int nfs4_Init_state_id(nfs_state_id_parameter_t param) 00161 { 00162 /* Init all_one */ 00163 memset(all_zero, 0, OTHERSIZE); 00164 memset(all_one, 0xFF, OTHERSIZE); 00165 00166 if((ht_state_id = HashTable_Init(¶m.hash_param)) == NULL) 00167 { 00168 LogCrit(COMPONENT_STATE, "Cannot init State Id cache"); 00169 return -1; 00170 } 00171 00172 return 0; 00173 } /* nfs_Init_client_id */ 00174 00184 void nfs4_BuildStateId_Other(char * other) 00185 { 00186 /* Use only 32 bits of server epoch */ 00187 uint32_t epoch = (uint32_t) ServerEpoch; 00188 memcpy(other, &epoch, sizeof(uint32_t)); 00189 00190 P(StateIdMutex); 00191 memcpy(other + sizeof(uint32_t), &state_id_counter, sizeof(uint64_t)); 00192 state_id_counter++; 00193 V(StateIdMutex); 00194 } 00195 00207 int nfs4_State_Set(char other[OTHERSIZE], state_t * pstate_data) 00208 { 00209 hash_buffer_t buffkey; 00210 hash_buffer_t buffval; 00211 00212 if((buffkey.pdata = gsh_malloc(OTHERSIZE)) == NULL) 00213 return 0; 00214 00215 LogFullDebug(COMPONENT_STATE, 00216 "Allocating stateid key %p", buffkey.pdata); 00217 00218 memcpy(buffkey.pdata, other, OTHERSIZE); 00219 buffkey.len = OTHERSIZE; 00220 00221 buffval.pdata = (caddr_t) pstate_data; 00222 buffval.len = sizeof(state_t); 00223 00224 if(HashTable_Test_And_Set(ht_state_id, 00225 &buffkey, 00226 &buffval, 00227 HASHTABLE_SET_HOW_SET_NO_OVERWRITE) != HASHTABLE_SUCCESS) 00228 { 00229 LogDebug(COMPONENT_STATE, 00230 "HashTable_Test_And_Set failed for key %p", 00231 buffkey.pdata); 00232 gsh_free(buffkey.pdata); 00233 return 0; 00234 } 00235 00236 return 1; 00237 } /* nfs4_State_Set */ 00238 00251 int nfs4_State_Get_Pointer(char other[OTHERSIZE], state_t * *pstate_data) 00252 { 00253 hash_buffer_t buffkey; 00254 hash_buffer_t buffval; 00255 int rc; 00256 00257 buffkey.pdata = (caddr_t) other; 00258 buffkey.len = OTHERSIZE; 00259 00260 rc = HashTable_Get(ht_state_id, &buffkey, &buffval); 00261 if(rc != HASHTABLE_SUCCESS) 00262 { 00263 LogDebug(COMPONENT_STATE, 00264 "HashTable_Get returned %d", rc); 00265 return 0; 00266 } 00267 00268 *pstate_data = (state_t *) buffval.pdata; 00269 00270 return 1; 00271 } /* nfs4_State_Get_Pointer */ 00272 00284 int nfs4_State_Del(char other[OTHERSIZE]) 00285 { 00286 hash_buffer_t buffkey, old_key, old_value; 00287 00288 buffkey.pdata = (caddr_t) other; 00289 buffkey.len = OTHERSIZE; 00290 00291 if(HashTable_Del(ht_state_id, &buffkey, &old_key, &old_value) == HASHTABLE_SUCCESS) 00292 { 00293 /* free the key that was stored in hash table */ 00294 LogFullDebug(COMPONENT_STATE, 00295 "Freeing stateid key %p", old_key.pdata); 00296 gsh_free(old_key.pdata); 00297 00298 /* State is managed in stuff alloc, no fre is needed for old_value.pdata */ 00299 00300 return 1; 00301 } 00302 else 00303 return 0; 00304 } /* nfs4_State_Del */ 00305 00317 int nfs4_Check_Stateid(stateid4 * pstate, 00318 cache_entry_t * pentry, 00319 state_t ** ppstate, 00320 compound_data_t * data, 00321 char flags, 00322 const char * tag) 00323 { 00324 uint32_t epoch = 0; 00325 state_t * pstate2; 00326 char str[OTHERSIZE * 2 + 1 + 6]; 00327 int32_t diff; 00328 00329 *ppstate = NULL; 00330 data->current_stateid_valid = FALSE; 00331 00332 if(pstate == NULL) 00333 return NFS4ERR_SERVERFAULT; 00334 00335 if(pentry == NULL) 00336 return NFS4ERR_SERVERFAULT; 00337 00338 if(pentry->type != REGULAR_FILE) 00339 return NFS4ERR_SERVERFAULT; 00340 00341 if(isDebug(COMPONENT_STATE)) 00342 { 00343 sprint_mem(str, (char *)pstate->other, OTHERSIZE); 00344 sprintf(str + OTHERSIZE * 2, ":%u", (unsigned int) pstate->seqid); 00345 } 00346 00347 /* Test for OTHER is all zeros */ 00348 if(memcmp(pstate->other, all_zero, OTHERSIZE) == 0) 00349 { 00350 if(pstate->seqid == 0 && (flags & STATEID_SPECIAL_ALL_0) != 0) 00351 { 00352 /* All 0 stateid */ 00353 LogDebug(COMPONENT_STATE, 00354 "Check %s stateid found special all 0 stateid", tag); 00355 /* TODO FSF: eventually this may want to return an actual state for 00356 * use in temporary locks for I/O. 00357 */ 00358 return NFS4_OK; 00359 } 00360 if(pstate->seqid == 1 && (flags & STATEID_SPECIAL_CURRENT) != 0) 00361 { 00362 /* Special current stateid */ 00363 LogDebug(COMPONENT_STATE, 00364 "Check %s stateid found special 'current' stateid", tag); 00365 /* Copy current stateid in and proceed to checks */ 00366 *pstate = data->current_stateid; 00367 } 00368 00369 LogDebug(COMPONENT_STATE, 00370 "Check %s stateid with OTHER all zeros, seqid %u unexpected", 00371 tag, (unsigned int) pstate->seqid); 00372 return NFS4ERR_BAD_STATEID; 00373 } 00374 00375 /* Test for OTHER is all ones */ 00376 if(memcmp(pstate->other, all_one, OTHERSIZE) == 0) 00377 { 00378 /* Test for special all ones stateid */ 00379 if(pstate->seqid == seqid_all_one && (flags & STATEID_SPECIAL_ALL_1) != 0) 00380 { 00381 /* All 1 stateid */ 00382 LogDebug(COMPONENT_STATE, 00383 "Check %s stateid found special all 1 stateid", tag); 00384 /* TODO FSF: eventually this may want to return an actual state for 00385 * use in temporary locks for I/O. 00386 */ 00387 return NFS4_OK; 00388 } 00389 00390 LogDebug(COMPONENT_STATE, 00391 "Check %s stateid with OTHER all ones, seqid %u unexpected", 00392 tag, (unsigned int) pstate->seqid); 00393 return NFS4ERR_BAD_STATEID; 00394 } 00395 00396 /* Check if stateid was made from this server instance */ 00397 memcpy(&epoch, pstate->other, sizeof(uint32_t)); 00398 00399 if(epoch != ServerEpoch) 00400 { 00401 LogDebug(COMPONENT_STATE, 00402 "Check %s stateid found stale stateid %s", tag, str); 00403 return NFS4ERR_STALE_STATEID; 00404 } 00405 00406 /* Try to get the related state */ 00407 if(!nfs4_State_Get_Pointer(pstate->other, &pstate2)) 00408 { 00409 /* State not found : return NFS4ERR_BAD_STATEID, RFC3530 page 129 */ 00410 LogDebug(COMPONENT_STATE, 00411 "Check %s stateid could not find state %s", tag, str); 00412 if(nfs_param.nfsv4_param.return_bad_stateid == TRUE) /* Dirty work-around for HPC environment */ 00413 return NFS4ERR_BAD_STATEID; 00414 else 00415 return NFS4_OK; 00416 } 00417 00418 /* Now, if this lease is not already reserved, reserve it */ 00419 if(data->preserved_clientid != pstate2->state_powner->so_owner.so_nfs4_owner.so_pclientid) 00420 { 00421 if(data->preserved_clientid != NULL) 00422 { 00423 /* We don't ever expect this to happen, but, just in case... 00424 * Update and release already reserved lease. 00425 */ 00426 P(data->preserved_clientid->cid_mutex); 00427 00428 update_lease(data->preserved_clientid); 00429 00430 V(data->preserved_clientid->cid_mutex); 00431 00432 data->preserved_clientid = NULL; 00433 } 00434 00435 /* Check if lease is expired and reserve it */ 00436 P(pstate2->state_powner->so_owner.so_nfs4_owner.so_pclientid->cid_mutex); 00437 00438 if(!reserve_lease(pstate2->state_powner->so_owner.so_nfs4_owner.so_pclientid)) 00439 { 00440 LogDebug(COMPONENT_STATE, 00441 "Returning NFS4ERR_EXPIRED"); 00442 00443 V(pstate2->state_powner->so_owner.so_nfs4_owner.so_pclientid->cid_mutex); 00444 00445 dec_client_id_ref(pstate2->state_powner->so_owner.so_nfs4_owner.so_pclientid); 00446 00447 return NFS4ERR_EXPIRED; 00448 } 00449 00450 data->preserved_clientid = pstate2->state_powner->so_owner.so_nfs4_owner.so_pclientid; 00451 00452 V(pstate2->state_powner->so_owner.so_nfs4_owner.so_pclientid->cid_mutex); 00453 } 00454 00455 /* Sanity check : Is this the right file ? */ 00456 if(pstate2->state_pentry != pentry) 00457 { 00458 LogDebug(COMPONENT_STATE, 00459 "Check %s stateid found stateid %s has wrong file", tag, str); 00460 return NFS4ERR_BAD_STATEID; 00461 } 00462 00463 /* Whether stateid.seqid may be zero depends on the state type 00464 exclusively, See RFC 5661 pp. 161,287-288. */ 00465 if((pstate2->state_type == STATE_TYPE_LAYOUT) || 00466 (pstate->seqid != 0)) 00467 { 00468 /* Check seqid in stateid */ 00472 diff = pstate->seqid - pstate2->state_seqid; 00473 if(diff < 0) 00474 { 00475 /* OLD_STATEID */ 00476 LogDebug(COMPONENT_STATE, 00477 "Check %s stateid found OLD stateid %s, expected seqid %u", 00478 tag, str, (unsigned int) pstate2->state_seqid); 00479 return NFS4ERR_OLD_STATEID; 00480 } 00481 else if(diff > 0) 00482 { 00483 /* BAD_STATEID */ 00484 LogDebug(COMPONENT_STATE, 00485 "Check %s stateid found BAD stateid %s, expected seqid %u", 00486 tag, str, (unsigned int) pstate2->state_seqid); 00487 return NFS4ERR_BAD_STATEID; 00488 } 00489 } 00490 00491 LogFullDebug(COMPONENT_STATE, 00492 "Check %s stateid found valid stateid %s - %p", 00493 tag, str, pstate2); 00494 00495 /* Copy stateid into current for later use */ 00496 data->current_stateid = *pstate; 00497 data->current_stateid.seqid = pstate2->state_seqid; 00498 data->current_stateid_valid = TRUE; 00499 00500 *ppstate = pstate2; 00501 return NFS4_OK; 00502 } /* nfs4_Check_Stateid */ 00503 00513 void nfs_State_PrintAll(void) 00514 { 00515 if(isFullDebug(COMPONENT_STATE)) 00516 HashTable_Log(COMPONENT_STATE, ht_state_id); 00517 } /* nfs_State_PrintAll */ 00518 00519 void update_stateid(state_t * pstate, 00520 stateid4 * presp, 00521 compound_data_t * data, 00522 const char * tag) 00523 { 00524 /* Increment state_seqid, handling wraparound */ 00525 pstate->state_seqid += 1; 00526 if(pstate->state_seqid == 0) 00527 pstate->state_seqid = 1; 00528 00529 /* Copy stateid into current for later use */ 00530 data->current_stateid.seqid = pstate->state_seqid; 00531 memcpy(data->current_stateid.other, pstate->stateid_other, OTHERSIZE); 00532 data->current_stateid_valid = TRUE; 00533 00534 /* Copy stateid into response */ 00535 presp->seqid = pstate->state_seqid; 00536 memcpy(presp->other, pstate->stateid_other, OTHERSIZE); 00537 00538 if(isFullDebug(COMPONENT_STATE)) 00539 { 00540 char str[OTHERSIZE * 2 + 1 + 6]; 00541 sprint_mem(str, (char *)pstate->stateid_other, OTHERSIZE); 00542 sprintf(str + OTHERSIZE * 2, ":%u", (unsigned int) pstate->state_seqid); 00543 LogDebug(COMPONENT_STATE, 00544 "Update %s stateid to %s for response", 00545 tag, str); 00546 } 00547 } 00548 00559 int nfs4_check_special_stateid(cache_entry_t *pentry, 00560 const char *tag, 00561 int access) 00562 { 00563 00564 struct glist_head * glist; 00565 state_t * pstate_iterate; 00566 int rc = NFS4_OK; 00567 00568 if(pentry == NULL) 00569 { 00570 rc = NFS4ERR_SERVERFAULT; 00571 return rc; 00572 } 00573 00574 /* Acquire lock to enter critical section on this entry */ 00575 pthread_rwlock_rdlock(&pentry->state_lock); 00576 00577 /* Iterate through file's state to look for conflicts */ 00578 glist_for_each(glist, &pentry->state_list) 00579 { 00580 pstate_iterate = glist_entry(glist, state_t, state_list); 00581 00582 switch(pstate_iterate->state_type) 00583 { 00584 case STATE_TYPE_SHARE: 00585 if((access == FATTR4_ATTR_READ) && 00586 (pstate_iterate->state_data.share.share_deny & OPEN4_SHARE_DENY_READ)) 00587 { 00588 /* Reading to this file is prohibited, file is read-denied */ 00589 rc = NFS4ERR_LOCKED; 00590 LogDebug(COMPONENT_NFS_V4_LOCK, 00591 "%s is denied by state %p", 00592 tag, 00593 pstate_iterate); 00594 goto ssid_out; 00595 } 00596 00597 if((access == FATTR4_ATTR_WRITE) && 00598 (pstate_iterate->state_data.share.share_deny & OPEN4_SHARE_DENY_WRITE)) 00599 { 00600 /* Writing to this file is prohibited, file is write-denied */ 00601 rc = NFS4ERR_LOCKED; 00602 LogDebug(COMPONENT_NFS_V4_LOCK, 00603 "%s is denied by state %p", 00604 tag, 00605 pstate_iterate); 00606 goto ssid_out; 00607 } 00608 00609 if((access == FATTR4_ATTR_READ_WRITE) && 00610 (pstate_iterate->state_data.share.share_deny & OPEN4_SHARE_DENY_BOTH)) 00611 { 00612 /* Reading and writing to this file is prohibited, file is rw-denied */ 00613 rc = NFS4ERR_LOCKED; 00614 LogDebug(COMPONENT_NFS_V4_LOCK, 00615 "%s is denied by state %p", 00616 tag, 00617 pstate_iterate); 00618 goto ssid_out; 00619 } 00620 00621 break; 00622 00623 case STATE_TYPE_LOCK: 00624 /* Skip, will check for conflicting locks later */ 00625 break; 00626 00627 case STATE_TYPE_DELEG: 00628 // TODO FSF: should check for conflicting delegations, may need to recall 00629 break; 00630 00631 case STATE_TYPE_LAYOUT: 00632 // TODO FSF: should check for conflicting layouts, may need to recall 00633 // Need to look at this even for NFS v4 WRITE since there may be NFS v4.1 users of the file 00634 break; 00635 00636 case STATE_TYPE_NONE: 00637 break; 00638 00639 default: 00640 break; 00641 } 00642 } 00643 // TODO FSF: need to check against existing locks 00644 00645 ssid_out: // Use this exit point if the lock was already acquired. 00646 pthread_rwlock_unlock(&pentry->state_lock); 00647 return rc; 00648 }