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 License 00011 * as published by the Free Software Foundation; either version 3 of 00012 * the License, or (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, but 00015 * 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 00022 * 02110-1301 USA 00023 * 00024 * --------------------------------------- 00025 */ 00026 00035 #ifdef HAVE_CONFIG_H 00036 #include "config.h" 00037 #endif 00038 00039 #ifdef _SOLARIS 00040 #include "solaris_port.h" 00041 #endif /* _SOLARIS */ 00042 00043 #include <unistd.h> 00044 #include <sys/types.h> 00045 #include <sys/param.h> 00046 #include <time.h> 00047 #include <pthread.h> 00048 #include <string.h> 00049 00050 #include "log.h" 00051 #include "HashData.h" 00052 #include "HashTable.h" 00053 #include "fsal.h" 00054 #include "nfs_core.h" 00055 #include "nfs4.h" 00056 #include "sal_functions.h" 00057 #ifdef _USE_NLM 00058 #include "nlm_util.h" 00059 #endif 00060 #include "cache_inode_lru.h" 00061 00062 /* 00063 * state_lock_entry_t locking rule: 00064 * The value is always updated/read with nlm_lock_entry->lock held 00065 * If we have nlm_lock_list mutex held we can read it safely, because the 00066 * value is always updated while walking the list with pentry->state_lock held. 00067 * The updation happens as below: 00068 * pthread_rwlock_wrlock(&pentry->state_mutex) 00069 * pthread_mutex_lock(lock_entry->sle_mutex) 00070 * update the lock_entry value 00071 * ........ 00072 * The value is ref counted with nlm_lock_entry->sle_ref_count so that a 00073 * parallel cancel/unlock won't endup freeing the datastructure. The last 00074 * release on the data structure ensure that it is freed. 00075 */ 00076 00077 /* The following constant defines the number of errors we will accept 00078 * before giving up in state recovery routines. These routines need to 00079 * terminate at some point. 00080 */ 00081 #define STATE_ERR_MAX 100 00082 00083 #ifdef _DEBUG_MEMLEAKS 00084 static struct glist_head state_all_locks; 00085 pthread_mutex_t all_locks_mutex = PTHREAD_MUTEX_INITIALIZER; 00086 #endif 00087 00088 #ifdef _USE_BLOCKING_LOCKS 00089 00090 /* List of all locks blocked in FSAL */ 00091 struct glist_head state_blocked_locks; 00092 00093 /* List of all async blocking locks notified by FSAL but not processed */ 00094 struct glist_head state_notified_locks; 00095 00096 /* Mutex to protect above lists */ 00097 pthread_mutex_t blocked_locks_mutex = PTHREAD_MUTEX_INITIALIZER; 00098 00099 #endif 00100 00101 state_owner_t unknown_owner; 00102 00103 #ifdef _USE_BLOCKING_LOCKS 00104 hash_table_t *ht_lock_cookies; 00105 00106 state_status_t state_lock_init(state_status_t * pstatus, 00107 hash_parameter_t cookie_param) 00108 #else 00109 state_status_t state_lock_init(state_status_t * pstatus) 00110 #endif 00111 { 00112 *pstatus = STATE_SUCCESS; 00113 00114 memset(&unknown_owner, 0, sizeof(unknown_owner)); 00115 strcpy(unknown_owner.so_owner_val, "ganesha_unknown_owner"); 00116 unknown_owner.so_type = STATE_LOCK_OWNER_UNKNOWN; 00117 unknown_owner.so_refcount = 1; 00118 unknown_owner.so_owner_len = strlen(unknown_owner.so_owner_val); 00119 00120 init_glist(&unknown_owner.so_lock_list); 00121 00122 if(pthread_mutex_init(&unknown_owner.so_mutex, NULL) == -1) 00123 { 00124 *pstatus = STATE_INIT_ENTRY_FAILED; 00125 return *pstatus; 00126 } 00127 00128 #ifdef _USE_BLOCKING_LOCKS 00129 ht_lock_cookies = HashTable_Init(&cookie_param); 00130 if(ht_lock_cookies == NULL) 00131 { 00132 LogCrit(COMPONENT_STATE, 00133 "Cannot init NLM Client cache"); 00134 *pstatus = STATE_INIT_ENTRY_FAILED; 00135 return *pstatus; 00136 } 00137 #endif 00138 00139 #ifdef _DEBUG_MEMLEAKS 00140 init_glist(&state_all_locks); 00141 #endif 00142 00143 #ifdef _USE_BLOCKING_LOCKS 00144 init_glist(&state_blocked_locks); 00145 init_glist(&state_notified_locks); 00146 00147 *pstatus = state_async_init(); 00148 #endif 00149 00150 state_owner_pool = pool_init("NFSv4 state owners", 00151 sizeof(state_owner_t), 00152 pool_basic_substrate, 00153 NULL, NULL, NULL); 00154 state_nfs4_owner_name_pool = pool_init("Owner names", 00155 sizeof(state_nfs4_owner_name_t), 00156 pool_basic_substrate, 00157 NULL, NULL, NULL); 00158 state_v4_pool = pool_init("NFSv4 files states", 00159 sizeof(state_t), 00160 pool_basic_substrate, 00161 NULL, NULL, NULL); 00162 return *pstatus; 00163 } 00164 00165 bool_t lock_owner_is_nlm(state_lock_entry_t * lock_entry) 00166 { 00167 #ifdef _USE_NLM 00168 return lock_entry->sle_owner->so_type == STATE_LOCK_OWNER_NLM; 00169 #else 00170 return FALSE; 00171 #endif 00172 } 00173 00174 state_status_t do_lock_op(cache_entry_t * pentry, 00175 fsal_op_context_t * pcontext, 00176 exportlist_t * pexport, 00177 fsal_lock_op_t lock_op, 00178 state_owner_t * powner, 00179 fsal_lock_param_t * plock, 00180 state_owner_t ** holder, /* owner that holds conflicting lock */ 00181 fsal_lock_param_t * conflict, /* description of conflicting lock */ 00182 bool_t overlap); /* hint that lock overlaps */ 00183 00184 /****************************************************************************** 00185 * 00186 * Functions to display various aspects of a lock 00187 * 00188 ******************************************************************************/ 00189 static inline uint64_t lock_end(fsal_lock_param_t *plock) 00190 { 00191 if(plock->lock_length == 0) 00192 return UINT64_MAX; 00193 else 00194 return plock->lock_start + plock->lock_length - 1; 00195 } 00196 00197 const char *str_lockt(fsal_lock_t ltype) 00198 { 00199 switch(ltype) 00200 { 00201 case FSAL_LOCK_R: return "READ "; 00202 case FSAL_LOCK_W: return "WRITE"; 00203 case FSAL_NO_LOCK: return "NO LOCK"; 00204 default: return "?????"; 00205 } 00206 return "????"; 00207 } 00208 00209 const char *str_blocking(state_blocking_t blocking) 00210 { 00211 switch(blocking) 00212 { 00213 case STATE_NON_BLOCKING: return "NON_BLOCKING "; 00214 case STATE_NLM_BLOCKING: return "NLM_BLOCKING "; 00215 case STATE_NFSV4_BLOCKING: return "NFSV4_BLOCKING"; 00216 case STATE_GRANTING: return "GRANTING "; 00217 case STATE_CANCELED: return "CANCELED "; 00218 } 00219 return "unknown "; 00220 } 00221 00222 const char *str_blocked(state_blocking_t blocked) 00223 { 00224 switch(blocked) 00225 { 00226 case STATE_NON_BLOCKING: return "GRANTED "; 00227 case STATE_NLM_BLOCKING: return "NLM_BLOCKING "; 00228 case STATE_NFSV4_BLOCKING: return "NFSV4_BLOCKING"; 00229 case STATE_GRANTING: return "GRANTING "; 00230 case STATE_CANCELED: return "CANCELED "; 00231 } 00232 return "unknown "; 00233 } 00234 00235 /****************************************************************************** 00236 * 00237 * Function to compare lock parameters 00238 * 00239 ******************************************************************************/ 00240 00241 /* This is not complete, it doesn't check the owner's IP address...*/ 00242 static inline int different_lock(fsal_lock_param_t *lock1, fsal_lock_param_t *lock2) 00243 { 00244 return (lock1->lock_type != lock2->lock_type) || 00245 (lock1->lock_start != lock2->lock_start) || 00246 (lock1->lock_length != lock2->lock_length); 00247 } 00248 00249 /****************************************************************************** 00250 * 00251 * Functions to log locks in various ways 00252 * 00253 ******************************************************************************/ 00254 static void LogEntry(const char *reason, 00255 state_lock_entry_t *ple) 00256 { 00257 if(isFullDebug(COMPONENT_STATE)) 00258 { 00259 char owner[HASHTABLE_DISPLAY_STRLEN]; 00260 00261 DisplayOwner(ple->sle_owner, owner); 00262 00263 LogFullDebug(COMPONENT_STATE, 00264 "%s Entry: %p pentry=%p, fileid=%"PRIu64", export=%u, type=%s, start=0x%llx, end=0x%llx, blocked=%s/%p, state=%p, refcount=%d, owner={%s}", 00265 reason, ple, 00266 ple->sle_pentry, (uint64_t)ple->sle_pentry->attributes.fileid, 00267 (unsigned int) ple->sle_pexport->id, 00268 str_lockt(ple->sle_lock.lock_type), 00269 (unsigned long long) ple->sle_lock.lock_start, 00270 (unsigned long long) lock_end(&ple->sle_lock), 00271 str_blocked(ple->sle_blocked), 00272 ple->sle_block_data, 00273 ple->sle_state, 00274 ple->sle_ref_count, 00275 owner); 00276 } 00277 } 00278 00279 static bool_t LogList(const char * reason, 00280 cache_entry_t * pentry, 00281 struct glist_head * list) 00282 { 00283 if(isFullDebug(COMPONENT_STATE)) 00284 { 00285 struct glist_head * glist; 00286 state_lock_entry_t * found_entry; 00287 00288 if(glist_empty(list)) 00289 { 00290 if(pentry != NULL) 00291 LogFullDebug(COMPONENT_STATE, 00292 "%s for %p is empty", 00293 reason, pentry); 00294 else 00295 LogFullDebug(COMPONENT_STATE, 00296 "%s is empty", 00297 reason); 00298 return TRUE; 00299 } 00300 00301 00302 glist_for_each(glist, list) 00303 { 00304 found_entry = glist_entry(glist, state_lock_entry_t, sle_list); 00305 LogEntry(reason, found_entry); 00306 if(found_entry->sle_pentry == NULL) 00307 break; 00308 } 00309 } 00310 00311 return FALSE; 00312 } 00313 00314 #ifdef _USE_BLOCKING_LOCKS 00315 static bool_t LogBlockedList(const char * reason, 00316 cache_entry_t * pentry, 00317 struct glist_head * list) 00318 { 00319 if(isFullDebug(COMPONENT_STATE)) 00320 { 00321 struct glist_head * glist; 00322 state_lock_entry_t * found_entry; 00323 state_block_data_t * block_entry; 00324 00325 if(glist_empty(list)) 00326 { 00327 if(pentry != NULL) 00328 LogFullDebug(COMPONENT_STATE, 00329 "%s for %p is empty", 00330 reason, pentry); 00331 else 00332 LogFullDebug(COMPONENT_STATE, 00333 "%s is empty", 00334 reason); 00335 return TRUE; 00336 } 00337 00338 00339 glist_for_each(glist, list) 00340 { 00341 block_entry = glist_entry(glist, state_block_data_t, sbd_list); 00342 found_entry = block_entry->sbd_lock_entry; 00343 LogEntry(reason, found_entry); 00344 if(found_entry->sle_pentry == NULL) 00345 break; 00346 } 00347 } 00348 00349 return FALSE; 00350 } 00351 #endif /* _USE_BLOCKING_LOCKS */ 00352 00353 void LogLock(log_components_t component, 00354 log_levels_t debug, 00355 const char * reason, 00356 cache_entry_t * pentry, 00357 fsal_op_context_t * pcontext, 00358 state_owner_t * powner, 00359 fsal_lock_param_t * plock) 00360 { 00361 if(isLevel(component, debug)) 00362 { 00363 char owner[HASHTABLE_DISPLAY_STRLEN]; 00364 00365 if(powner != NULL) 00366 DisplayOwner(powner, owner); 00367 else 00368 sprintf(owner, "NONE"); 00369 00370 LogAtLevel(component, debug, 00371 "%s Lock: pentry=%p, fileid=%"PRIu64", type=%s, start=0x%llx, end=0x%llx, owner={%s}", 00372 reason, pentry, (uint64_t)pentry->attributes.fileid, 00373 str_lockt(plock->lock_type), 00374 (unsigned long long) plock->lock_start, 00375 (unsigned long long) lock_end(plock), 00376 owner); 00377 } 00378 } 00379 00380 void LogLockDesc(log_components_t component, 00381 log_levels_t debug, 00382 const char * reason, 00383 cache_entry_t * pentry, 00384 void * powner, 00385 fsal_lock_param_t * plock) 00386 { 00387 LogAtLevel(component, debug, 00388 "%s Lock: pentry=%p, powner=%p, type=%s, start=0x%llx, end=0x%llx", 00389 reason, 00390 pentry, 00391 powner, 00392 str_lockt(plock->lock_type), 00393 (unsigned long long) plock->lock_start, 00394 (unsigned long long) lock_end(plock)); 00395 } 00396 00397 void dump_all_locks(const char * label) 00398 { 00399 #ifdef _DEBUG_MEMLEAKS 00400 struct glist_head *glist; 00401 00402 P(all_locks_mutex); 00403 00404 if(glist_empty(&state_all_locks)) 00405 { 00406 LogFullDebug(COMPONENT_STATE, "All Locks are freed"); 00407 V(all_locks_mutex); 00408 return; 00409 } 00410 00411 glist_for_each(glist, &state_all_locks) 00412 LogEntry(label, glist_entry(glist, state_lock_entry_t, sle_all_locks)); 00413 00414 V(all_locks_mutex); 00415 #else 00416 return; 00417 #endif 00418 } 00419 00420 /****************************************************************************** 00421 * 00422 * Functions to manage lock entries and lock list 00423 * 00424 ******************************************************************************/ 00425 static state_lock_entry_t *create_state_lock_entry(cache_entry_t * pentry, 00426 fsal_op_context_t * pcontext, 00427 exportlist_t * pexport, 00428 state_blocking_t blocked, 00429 state_owner_t * powner, 00430 state_t * pstate, 00431 fsal_lock_param_t * plock) 00432 { 00433 state_lock_entry_t *new_entry; 00434 00435 new_entry = gsh_malloc(sizeof(*new_entry)); 00436 if(!new_entry) 00437 return NULL; 00438 00439 LogFullDebug(COMPONENT_STATE, 00440 "new_entry = %p", new_entry); 00441 00442 memset(new_entry, 0, sizeof(*new_entry)); 00443 00444 if(pthread_mutex_init(&new_entry->sle_mutex, NULL) == -1) 00445 { 00446 gsh_free(new_entry); 00447 return NULL; 00448 } 00449 00450 new_entry->sle_ref_count = 1; 00451 new_entry->sle_pentry = pentry; 00452 new_entry->sle_blocked = blocked; 00453 new_entry->sle_owner = powner; 00454 new_entry->sle_state = pstate; 00455 new_entry->sle_block_data = NULL; /* will be filled in later if necessary */ 00456 new_entry->sle_lock = *plock; 00457 new_entry->sle_pexport = pexport; 00458 00459 #ifdef _USE_NLM 00460 if(powner->so_type == STATE_LOCK_OWNER_NLM) 00461 { 00462 /* Add to list of locks owned by client that powner belongs to */ 00463 P(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client->ssc_mutex); 00464 00465 glist_add_tail(&powner->so_owner.so_nlm_owner.so_client->slc_nsm_client->ssc_lock_list, 00466 &new_entry->sle_client_locks); 00467 00468 inc_nsm_client_ref_locked(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client); 00469 00470 /* Add to list of locks owned by export */ 00471 P(pexport->exp_state_mutex); 00472 glist_add_tail(&pexport->exp_lock_list, 00473 &new_entry->sle_export_locks); 00474 V(pexport->exp_state_mutex); 00475 } 00476 #endif 00477 /* Add to list of locks owned by powner */ 00478 P(powner->so_mutex); 00479 00480 if(powner->so_type == STATE_LOCK_OWNER_NFSV4 && pstate != NULL) 00481 { 00482 glist_add_tail(&pstate->state_data.lock.state_locklist, 00483 &new_entry->sle_state_locks); 00484 } 00485 00486 glist_add_tail(&powner->so_lock_list, &new_entry->sle_owner_locks); 00487 00488 inc_state_owner_ref_locked(powner); 00489 00490 #ifdef _DEBUG_MEMLEAKS 00491 P(all_locks_mutex); 00492 00493 glist_add_tail(&state_all_locks, &new_entry->sle_all_locks); 00494 00495 V(all_locks_mutex); 00496 #endif 00497 00498 return new_entry; 00499 } 00500 00501 inline state_lock_entry_t *state_lock_entry_t_dup(fsal_op_context_t * pcontext, 00502 state_lock_entry_t * orig_entry) 00503 { 00504 return create_state_lock_entry(orig_entry->sle_pentry, 00505 pcontext, 00506 orig_entry->sle_pexport, 00507 orig_entry->sle_blocked, 00508 orig_entry->sle_owner, 00509 orig_entry->sle_state, 00510 &orig_entry->sle_lock); 00511 } 00512 00513 void lock_entry_inc_ref(state_lock_entry_t *lock_entry) 00514 { 00515 P(lock_entry->sle_mutex); 00516 lock_entry->sle_ref_count++; 00517 LogEntry("Increment refcount", lock_entry); 00518 V(lock_entry->sle_mutex); 00519 } 00520 00521 void lock_entry_dec_ref(state_lock_entry_t *lock_entry) 00522 { 00523 bool_t to_free = FALSE; 00524 00525 P(lock_entry->sle_mutex); 00526 00527 lock_entry->sle_ref_count--; 00528 00529 LogEntry("Decrement refcount", lock_entry); 00530 00531 if(!lock_entry->sle_ref_count) 00532 { 00533 /* 00534 * We should already be removed from the lock_list 00535 * So we can free the lock_entry without any locking 00536 */ 00537 to_free = TRUE; 00538 } 00539 00540 V(lock_entry->sle_mutex); 00541 00542 if(to_free) 00543 { 00544 LogEntry("Freeing", lock_entry); 00545 00546 #ifdef _USE_BLOCKING_LOCKS 00547 /* Release block data if present */ 00548 if(lock_entry->sle_block_data != NULL) 00549 { 00550 memset(lock_entry->sle_block_data, 0, sizeof(*(lock_entry->sle_block_data))); 00551 gsh_free(lock_entry->sle_block_data); 00552 } 00553 #endif 00554 #ifdef _DEBUG_MEMLEAKS 00555 P(all_locks_mutex); 00556 glist_del(&lock_entry->sle_all_locks); 00557 V(all_locks_mutex); 00558 #endif 00559 00560 memset(lock_entry, 0, sizeof(*lock_entry)); 00561 gsh_free(lock_entry); 00562 } 00563 } 00564 00565 static void remove_from_locklist(state_lock_entry_t * lock_entry) 00566 { 00567 state_owner_t * powner = lock_entry->sle_owner; 00568 00569 LogEntry("Removing", lock_entry); 00570 00571 /* 00572 * If some other thread is holding a reference to this nlm_lock_entry 00573 * don't free the structure. But drop from the lock list 00574 */ 00575 if(powner != NULL) 00576 { 00577 #ifdef _USE_NLM 00578 if(powner->so_type == STATE_LOCK_OWNER_NLM) 00579 { 00580 /* Remove from list of locks owned by client that powner belongs to */ 00581 P(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client->ssc_mutex); 00582 00583 glist_del(&lock_entry->sle_client_locks); 00584 00585 dec_nsm_client_ref_locked(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client); 00586 00587 /* Remove from list of locks owned by export */ 00588 P(lock_entry->sle_pexport->exp_state_mutex); 00589 glist_del(&lock_entry->sle_export_locks); 00590 V(lock_entry->sle_pexport->exp_state_mutex); 00591 } 00592 #endif 00593 00594 /* Remove from list of locks owned by powner */ 00595 P(powner->so_mutex); 00596 00597 if(powner->so_type == STATE_LOCK_OWNER_NFSV4) 00598 { 00599 glist_del(&lock_entry->sle_state_locks); 00600 } 00601 00602 glist_del(&lock_entry->sle_owner_locks); 00603 00604 dec_state_owner_ref_locked(powner); 00605 } 00606 00607 lock_entry->sle_owner = NULL; 00608 glist_del(&lock_entry->sle_list); 00609 lock_entry_dec_ref(lock_entry); 00610 } 00611 00612 static state_lock_entry_t *get_overlapping_entry(cache_entry_t * pentry, 00613 fsal_op_context_t * pcontext, 00614 state_owner_t * powner, 00615 fsal_lock_param_t * plock) 00616 { 00617 struct glist_head *glist; 00618 state_lock_entry_t *found_entry = NULL; 00619 uint64_t found_entry_end, plock_end = lock_end(plock); 00620 00621 glist_for_each(glist, &pentry->object.file.lock_list) 00622 { 00623 found_entry = glist_entry(glist, state_lock_entry_t, sle_list); 00624 00625 LogEntry("Checking", found_entry); 00626 00627 /* Skip blocked or cancelled locks */ 00628 if(found_entry->sle_blocked == STATE_NLM_BLOCKING || 00629 found_entry->sle_blocked == STATE_NFSV4_BLOCKING || 00630 found_entry->sle_blocked == STATE_CANCELED) 00631 continue; 00632 00633 found_entry_end = lock_end(&found_entry->sle_lock); 00634 00635 if((found_entry_end >= plock->lock_start) && 00636 (found_entry->sle_lock.lock_start <= plock_end)) 00637 { 00638 /* lock overlaps see if we can allow 00639 * allow if neither lock is exclusive or the owner is the same 00640 */ 00641 if((found_entry->sle_lock.lock_type == FSAL_LOCK_W || 00642 plock->lock_type == FSAL_LOCK_W) && 00643 different_owners(found_entry->sle_owner, powner) 00644 ) 00645 { 00646 /* found a conflicting lock, return it */ 00647 return found_entry; 00648 } 00649 } 00650 } 00651 00652 return NULL; 00653 } 00654 00655 /* We need to iterate over the full lock list and remove 00656 * any mapping entry. And l_offset = 0 and sle_lock.lock_length = 0 lock_entry 00657 * implies remove all entries 00658 */ 00659 static void merge_lock_entry(cache_entry_t * pentry, 00660 fsal_op_context_t * pcontext, 00661 state_lock_entry_t * lock_entry) 00662 { 00663 state_lock_entry_t * check_entry; 00664 state_lock_entry_t * check_entry_right; 00665 uint64_t check_entry_end; 00666 uint64_t lock_entry_end; 00667 struct glist_head * glist; 00668 struct glist_head * glistn; 00669 00670 /* lock_entry might be STATE_NON_BLOCKING or STATE_GRANTING */ 00671 00672 glist_for_each_safe(glist, glistn, &pentry->object.file.lock_list) 00673 { 00674 check_entry = glist_entry(glist, state_lock_entry_t, sle_list); 00675 00676 /* Skip entry being merged - it could be in the list */ 00677 if(check_entry == lock_entry) 00678 continue; 00679 00680 if(different_owners(check_entry->sle_owner, lock_entry->sle_owner)) 00681 continue; 00682 00683 /* Only merge fully granted locks */ 00684 if(check_entry->sle_blocked != STATE_NON_BLOCKING) 00685 continue; 00686 00687 check_entry_end = lock_end(&check_entry->sle_lock); 00688 lock_entry_end = lock_end(&lock_entry->sle_lock); 00689 00690 if((check_entry_end + 1) < lock_entry->sle_lock.lock_start) 00691 /* nothing to merge */ 00692 continue; 00693 00694 if((lock_entry_end + 1) < check_entry->sle_lock.lock_start) 00695 /* nothing to merge */ 00696 continue; 00697 00698 /* Need to handle locks of different types differently, may split an old lock. 00699 * If new lock totally overlaps old lock, the new lock will replace the old 00700 * lock so no special work to be done. 00701 */ 00702 if((check_entry->sle_lock.lock_type != lock_entry->sle_lock.lock_type) && 00703 ((lock_entry_end < check_entry_end) || 00704 (check_entry->sle_lock.lock_start < lock_entry->sle_lock.lock_start))) 00705 { 00706 if(lock_entry_end < check_entry_end && 00707 check_entry->sle_lock.lock_start < lock_entry->sle_lock.lock_start) 00708 { 00709 /* Need to split old lock */ 00710 check_entry_right = state_lock_entry_t_dup(pcontext, check_entry); 00711 if(check_entry_right == NULL) 00712 { 00713 // TODO FSF: OOPS.... 00714 // Leave old lock in place, it may cause false conflicts, but should eventually be released 00715 LogMajor(COMPONENT_STATE, 00716 "Memory allocation failure during lock upgrade/downgrade"); 00717 continue; 00718 } 00719 glist_add_tail(&pentry->object.file.lock_list, &(check_entry_right->sle_list)); 00720 } 00721 else 00722 { 00723 /* No split, just shrink, make the logic below work on original lock */ 00724 check_entry_right = check_entry; 00725 } 00726 if(lock_entry_end < check_entry_end) 00727 { 00728 /* Need to shrink old lock from beginning (right lock if split) */ 00729 LogEntry("Merge shrinking right", check_entry_right); 00730 check_entry_right->sle_lock.lock_start = lock_entry_end + 1; 00731 check_entry_right->sle_lock.lock_length = check_entry_end - lock_entry_end; 00732 LogEntry("Merge shrunk right", check_entry_right); 00733 continue; 00734 } 00735 if(check_entry->sle_lock.lock_start < lock_entry->sle_lock.lock_start) 00736 { 00737 /* Need to shrink old lock from end (left lock if split) */ 00738 LogEntry("Merge shrinking left", check_entry); 00739 check_entry->sle_lock.lock_length = lock_entry->sle_lock.lock_start - check_entry->sle_lock.lock_start; 00740 LogEntry("Merge shrunk left", check_entry); 00741 continue; 00742 } 00743 /* Done splitting/shrinking old lock */ 00744 continue; 00745 } 00746 00747 /* check_entry touches or overlaps lock_entry, expand lock_entry */ 00748 if(lock_entry_end < check_entry_end) 00749 /* Expand end of lock_entry */ 00750 lock_entry_end = check_entry_end; 00751 00752 if(check_entry->sle_lock.lock_start < lock_entry->sle_lock.lock_start) 00753 /* Expand start of lock_entry */ 00754 lock_entry->sle_lock.lock_start = check_entry->sle_lock.lock_start; 00755 00756 /* Compute new lock length */ 00757 lock_entry->sle_lock.lock_length = lock_entry_end - lock_entry->sle_lock.lock_start + 1; 00758 00759 /* Remove merged entry */ 00760 LogEntry("Merged", lock_entry); 00761 LogEntry("Merging removing", check_entry); 00762 remove_from_locklist(check_entry); 00763 } 00764 } 00765 00766 static void free_list(struct glist_head * list) 00767 { 00768 state_lock_entry_t *found_entry; 00769 struct glist_head *glist, *glistn; 00770 00771 glist_for_each_safe(glist, glistn, list) 00772 { 00773 found_entry = glist_entry(glist, state_lock_entry_t, sle_list); 00774 00775 remove_from_locklist(found_entry); 00776 } 00777 } 00778 00779 /* Subtract a lock from a lock entry, placing any remaining bits into the split list. */ 00780 static bool_t subtract_lock_from_entry(cache_entry_t * pentry, 00781 fsal_op_context_t * pcontext, 00782 state_lock_entry_t * found_entry, 00783 fsal_lock_param_t * plock, 00784 struct glist_head * split_list, 00785 struct glist_head * remove_list, 00786 state_status_t * pstatus) 00787 { 00788 uint64_t found_entry_end = lock_end(&found_entry->sle_lock); 00789 uint64_t plock_end = lock_end(plock); 00790 state_lock_entry_t *found_entry_left = NULL; 00791 state_lock_entry_t *found_entry_right = NULL; 00792 00793 *pstatus = STATE_SUCCESS; 00794 00795 if(plock_end < found_entry->sle_lock.lock_start) 00796 /* nothing to split */ 00797 return FALSE; 00798 00799 if(found_entry_end < plock->lock_start) 00800 /* nothing to split */ 00801 return FALSE; 00802 00803 if((plock->lock_start <= found_entry->sle_lock.lock_start) && 00804 plock_end >= found_entry_end) 00805 { 00806 /* Fully overlap */ 00807 LogEntry("Remove Complete", found_entry); 00808 goto complete_remove; 00809 } 00810 00811 LogEntry("Split", found_entry); 00812 00813 /* Delete the old entry and add one or two new entries */ 00814 if(plock->lock_start > found_entry->sle_lock.lock_start) 00815 { 00816 found_entry_left = state_lock_entry_t_dup(pcontext, found_entry); 00817 if(found_entry_left == NULL) 00818 { 00819 free_list(split_list); 00820 *pstatus = STATE_MALLOC_ERROR; 00821 return FALSE; 00822 } 00823 00824 found_entry_left->sle_lock.lock_length = plock->lock_start - found_entry->sle_lock.lock_start; 00825 LogEntry("Left split", found_entry_left); 00826 glist_add_tail(split_list, &(found_entry_left->sle_list)); 00827 } 00828 00829 if(plock_end < found_entry_end) 00830 { 00831 found_entry_right = state_lock_entry_t_dup(pcontext, found_entry); 00832 if(found_entry_right == NULL) 00833 { 00834 free_list(split_list); 00835 *pstatus = STATE_MALLOC_ERROR; 00836 return FALSE; 00837 } 00838 00839 found_entry_right->sle_lock.lock_start = plock_end + 1; 00840 found_entry_right->sle_lock.lock_length = found_entry_end - plock_end; 00841 LogEntry("Right split", found_entry_right); 00842 glist_add_tail(split_list, &(found_entry_right->sle_list)); 00843 } 00844 00845 complete_remove: 00846 00847 /* Remove the lock from the list it's on and put it on the remove_list */ 00848 glist_del(&found_entry->sle_list); 00849 glist_add_tail(remove_list, &(found_entry->sle_list)); 00850 00851 return TRUE; 00852 } 00853 00854 /* Subtract a lock from a list of locks, possibly splitting entries in the list. */ 00855 static bool_t subtract_lock_from_list(cache_entry_t * pentry, 00856 fsal_op_context_t * pcontext, 00857 state_owner_t * powner, 00858 state_t * pstate, 00859 fsal_lock_param_t * plock, 00860 state_status_t * pstatus, 00861 struct glist_head * list) 00862 { 00863 state_lock_entry_t *found_entry; 00864 struct glist_head split_lock_list, remove_list; 00865 struct glist_head *glist, *glistn; 00866 bool_t rc = FALSE; 00867 00868 init_glist(&split_lock_list); 00869 init_glist(&remove_list); 00870 00871 *pstatus = STATE_SUCCESS; 00872 glist_for_each_safe(glist, glistn, list) 00873 { 00874 found_entry = glist_entry(glist, state_lock_entry_t, sle_list); 00875 00876 if(powner != NULL && different_owners(found_entry->sle_owner, powner)) 00877 continue; 00878 00879 /* Only care about granted locks */ 00880 if(found_entry->sle_blocked != STATE_NON_BLOCKING) 00881 continue; 00882 00883 00884 #ifdef _USE_NLM 00885 /* Skip locks owned by this NLM state. 00886 * This protects NLM locks from the current iteration of an NLM 00887 * client from being released by SM_NOTIFY. 00888 */ 00889 if(pstate != NULL && 00890 lock_owner_is_nlm(found_entry) && 00891 found_entry->sle_state == pstate) 00892 continue; 00893 #endif 00894 00895 /* 00896 * We have matched owner. 00897 * Even though we are taking a reference to found_entry, we 00898 * don't inc the ref count because we want to drop the lock entry. 00899 */ 00900 rc |= subtract_lock_from_entry(pentry, 00901 pcontext, 00902 found_entry, 00903 plock, 00904 &split_lock_list, 00905 &remove_list, 00906 pstatus); 00907 if(*pstatus != STATE_SUCCESS) 00908 { 00909 /* We ran out of memory while splitting, deal with it outside loop */ 00910 break; 00911 } 00912 } 00913 00914 if(*pstatus != STATE_SUCCESS) 00915 { 00916 /* We ran out of memory while splitting. split_lock_list has been freed. 00917 * For each entry on the remove_list, put it back on the list. 00918 */ 00919 LogDebug(COMPONENT_STATE, 00920 "Failed %s", 00921 state_err_str(*pstatus)); 00922 glist_for_each_safe(glist, glistn, &remove_list) 00923 { 00924 found_entry = glist_entry(glist, state_lock_entry_t, sle_list); 00925 glist_del(&found_entry->sle_list); 00926 glist_add_tail(list, &(found_entry->sle_list)); 00927 } 00928 } 00929 else 00930 { 00931 /* free the enttries on the remove_list*/ 00932 free_list(&remove_list); 00933 00934 /* now add the split lock list */ 00935 glist_add_list_tail(list, &split_lock_list); 00936 } 00937 00938 LogFullDebug(COMPONENT_STATE, 00939 "List of all locks for pentry=%p returning %d", 00940 pentry, (int) rc); 00941 00942 return rc; 00943 } 00944 00945 static state_status_t subtract_list_from_list(cache_entry_t * pentry, 00946 fsal_op_context_t * pcontext, 00947 struct glist_head * target, 00948 struct glist_head * source, 00949 state_status_t * pstatus) 00950 { 00951 state_lock_entry_t *found_entry; 00952 struct glist_head *glist, *glistn; 00953 00954 *pstatus = STATE_SUCCESS; 00955 00956 glist_for_each_safe(glist, glistn, source) 00957 { 00958 found_entry = glist_entry(glist, state_lock_entry_t, sle_list); 00959 00960 subtract_lock_from_list(pentry, 00961 pcontext, 00962 NULL, 00963 NULL, 00964 &found_entry->sle_lock, 00965 pstatus, 00966 target); 00967 if(*pstatus != STATE_SUCCESS) 00968 break; 00969 } 00970 00971 return *pstatus; 00972 } 00973 00974 /****************************************************************************** 00975 * 00976 * Implement hash table to hash blocked lock entries by cookie 00977 * 00978 ******************************************************************************/ 00979 00980 #ifdef _USE_BLOCKING_LOCKS 00981 static void grant_blocked_locks(cache_entry_t * pentry, 00982 fsal_op_context_t * pcontext); 00983 00984 int display_lock_cookie_key(hash_buffer_t * pbuff, char *str) 00985 { 00986 return DisplayOpaqueValue((char *)pbuff->pdata, pbuff->len, str); 00987 } 00988 00989 int display_lock_cookie_entry(state_cookie_entry_t * he, char * str) 00990 { 00991 char *tmp = str; 00992 00993 tmp += sprintf(tmp, "%p: cookie ", he); 00994 tmp += DisplayOpaqueValue(he->sce_pcookie, he->sce_cookie_size, tmp); 00995 tmp += sprintf(tmp, " entry {%p fileid=%"PRIu64"} lock {", 00996 he->sce_pentry, 00997 (uint64_t)he->sce_pentry->attributes.fileid); 00998 if(he->sce_lock_entry != NULL) 00999 { 01000 tmp += sprintf(tmp, "%p owner {", he->sce_lock_entry); 01001 01002 tmp += DisplayOwner(he->sce_lock_entry->sle_owner, tmp); 01003 01004 tmp += sprintf(tmp, "} type=%s start=0x%llx end=0x%llx blocked=%s}", 01005 str_lockt(he->sce_lock_entry->sle_lock.lock_type), 01006 (unsigned long long) he->sce_lock_entry->sle_lock.lock_start, 01007 (unsigned long long) lock_end(&he->sce_lock_entry->sle_lock), 01008 str_blocked(he->sce_lock_entry->sle_blocked)); 01009 } 01010 else 01011 { 01012 tmp += sprintf(tmp, "<NULL>}"); 01013 } 01014 01015 return tmp - str; 01016 } 01017 01018 int display_lock_cookie_val(hash_buffer_t * pbuff, char *str) 01019 { 01020 return display_lock_cookie_entry((state_cookie_entry_t *)pbuff->pdata, str); 01021 } 01022 01023 int compare_lock_cookie_key(hash_buffer_t * buff1, hash_buffer_t * buff2) 01024 { 01025 if(isFullDebug(COMPONENT_STATE) && isDebug(COMPONENT_HASHTABLE)) 01026 { 01027 char str1[HASHTABLE_DISPLAY_STRLEN]; 01028 char str2[HASHTABLE_DISPLAY_STRLEN]; 01029 01030 display_lock_cookie_key(buff1, str1); 01031 display_lock_cookie_key(buff2, str2); 01032 LogFullDebug(COMPONENT_STATE, 01033 "{%s} vs {%s}", str1, str2); 01034 } 01035 01036 if(buff1->pdata == buff2->pdata) 01037 return 0; 01038 01039 if(buff1->len != buff2->len) 01040 return 1; 01041 01042 if(buff1->pdata == NULL || buff2->pdata == NULL) 01043 return 1; 01044 01045 return memcmp(buff1->pdata, buff2->pdata, buff1->len); 01046 } 01047 01048 uint32_t lock_cookie_value_hash_func(hash_parameter_t * p_hparam, 01049 hash_buffer_t * buffclef) 01050 { 01051 unsigned int sum = 0; 01052 unsigned int i; 01053 unsigned long res; 01054 unsigned char *pdata = (unsigned char *) buffclef->pdata; 01055 01056 /* Compute the sum of all the characters */ 01057 for(i = 0; i < buffclef->len; i++) 01058 sum +=(unsigned char) pdata[i]; 01059 01060 res = (unsigned long) sum + 01061 (unsigned long) buffclef->len; 01062 01063 if(isDebug(COMPONENT_HASHTABLE)) 01064 LogFullDebug(COMPONENT_STATE, 01065 "value = %lu", res % p_hparam->index_size); 01066 01067 return (unsigned long)(res % p_hparam->index_size); 01068 } 01069 01070 uint64_t lock_cookie_rbt_hash_func(hash_parameter_t * p_hparam, 01071 hash_buffer_t * buffclef) 01072 { 01073 unsigned int sum = 0; 01074 unsigned int i; 01075 unsigned long res; 01076 unsigned char *pdata = (unsigned char *) buffclef->pdata; 01077 01078 /* Compute the sum of all the characters */ 01079 for(i = 0; i < buffclef->len; i++) 01080 sum +=(unsigned char) pdata[i]; 01081 01082 res = (unsigned long) sum + 01083 (unsigned long) buffclef->len; 01084 01085 if(isDebug(COMPONENT_HASHTABLE)) 01086 LogFullDebug(COMPONENT_STATE, "rbt = %lu", res); 01087 01088 return res; 01089 } 01090 01091 void free_cookie(state_cookie_entry_t * p_cookie_entry, 01092 bool_t unblock) 01093 { 01094 char str[HASHTABLE_DISPLAY_STRLEN]; 01095 void * pcookie = p_cookie_entry->sce_pcookie; 01096 01097 if(isFullDebug(COMPONENT_STATE)) 01098 display_lock_cookie_entry(p_cookie_entry, str); 01099 01100 /* Since the cookie is not in the hash table, we can just free the memory */ 01101 LogFullDebug(COMPONENT_STATE, 01102 "Free Lock Cookie {%s}", 01103 str); 01104 01105 /* If block data is still attached to lock entry, remove it */ 01106 if(p_cookie_entry->sce_lock_entry != NULL && unblock) 01107 { 01108 if(p_cookie_entry->sce_lock_entry->sle_block_data != NULL) 01109 p_cookie_entry->sce_lock_entry->sle_block_data->sbd_blocked_cookie = NULL; 01110 01111 lock_entry_dec_ref(p_cookie_entry->sce_lock_entry); 01112 } 01113 01114 /* Free the memory for the cookie and the cookie entry */ 01115 memset(pcookie, 0, p_cookie_entry->sce_cookie_size); 01116 memset(p_cookie_entry, 0, sizeof(*p_cookie_entry)); 01117 01118 gsh_free(pcookie); 01119 gsh_free(p_cookie_entry); 01120 } 01121 01122 state_status_t state_add_grant_cookie(cache_entry_t * pentry, 01123 fsal_op_context_t * pcontext, 01124 void * pcookie, 01125 int cookie_size, 01126 state_lock_entry_t * lock_entry, 01127 state_cookie_entry_t ** ppcookie_entry, 01128 state_status_t * pstatus) 01129 { 01130 hash_buffer_t buffkey, buffval; 01131 state_cookie_entry_t * hash_entry; 01132 char str[HASHTABLE_DISPLAY_STRLEN]; 01133 01134 *ppcookie_entry = NULL; 01135 01136 if(lock_entry->sle_block_data == NULL || pcookie == NULL || cookie_size == 0) 01137 { 01138 /* Something's wrong with this entry */ 01139 *pstatus = STATE_INCONSISTENT_ENTRY; 01140 return *pstatus; 01141 } 01142 01143 if(isFullDebug(COMPONENT_STATE)) 01144 DisplayOpaqueValue(pcookie, cookie_size, str); 01145 01146 hash_entry = gsh_malloc(sizeof(*hash_entry)); 01147 if(hash_entry == NULL) 01148 { 01149 LogFullDebug(COMPONENT_STATE, 01150 "KEY {%s} NO MEMORY", 01151 str); 01152 *pstatus = STATE_MALLOC_ERROR; 01153 return *pstatus; 01154 } 01155 01156 memset(hash_entry, 0, sizeof(*hash_entry)); 01157 01158 buffkey.pdata = gsh_malloc(cookie_size); 01159 if(buffkey.pdata == NULL) 01160 { 01161 LogFullDebug(COMPONENT_STATE, 01162 "KEY {%s} NO MEMORY", 01163 str); 01164 gsh_free(hash_entry); 01165 *pstatus = STATE_MALLOC_ERROR; 01166 return *pstatus; 01167 } 01168 01169 hash_entry->sce_pentry = pentry; 01170 hash_entry->sce_lock_entry = lock_entry; 01171 hash_entry->sce_pcookie = buffkey.pdata; 01172 hash_entry->sce_cookie_size = cookie_size; 01173 01174 memcpy(buffkey.pdata, pcookie, cookie_size); 01175 buffkey.len = cookie_size; 01176 buffval.pdata = (void *)hash_entry; 01177 buffval.len = sizeof(*hash_entry); 01178 01179 if(isFullDebug(COMPONENT_STATE)) 01180 display_lock_cookie_entry(hash_entry, str); 01181 01182 01183 if(HashTable_Test_And_Set 01184 (ht_lock_cookies, &buffkey, &buffval, 01185 HASHTABLE_SET_HOW_SET_NO_OVERWRITE) != HASHTABLE_SUCCESS) 01186 { 01187 gsh_free(hash_entry); 01188 LogFullDebug(COMPONENT_STATE, 01189 "Lock Cookie {%s} HASH TABLE ERROR", 01190 str); 01191 *pstatus = STATE_HASH_TABLE_ERROR; 01192 return *pstatus; 01193 } 01194 01195 /* Increment lock entry reference count and link it to the cookie */ 01196 lock_entry_inc_ref(lock_entry); 01197 lock_entry->sle_block_data->sbd_blocked_cookie = hash_entry; 01198 01199 LogFullDebug(COMPONENT_STATE, 01200 "Lock Cookie {%s} Added", 01201 str); 01202 01203 switch(lock_entry->sle_block_data->sbd_grant_type) 01204 { 01205 case STATE_GRANT_NONE: 01206 /* Shouldn't get here */ 01207 *pstatus = STATE_INCONSISTENT_ENTRY; 01208 break; 01209 01210 case STATE_GRANT_FSAL_AVAILABLE: 01211 /* Now that we are sure we can continue, try to acquire the FSAL lock */ 01212 /* If we get STATE_LOCK_BLOCKED we need to return... */ 01213 *pstatus = do_lock_op(pentry, 01214 pcontext, 01215 lock_entry->sle_pexport, 01216 FSAL_OP_LOCKB, 01217 lock_entry->sle_owner, 01218 &lock_entry->sle_lock, 01219 NULL, 01220 NULL, 01221 FALSE); 01222 break; 01223 01224 case STATE_GRANT_INTERNAL: 01225 /* Now that we are sure we can continue, acquire the FSAL lock */ 01226 /* If we get STATE_LOCK_BLOCKED we need to return... */ 01227 *pstatus = do_lock_op(pentry, 01228 pcontext, 01229 lock_entry->sle_pexport, 01230 FSAL_OP_LOCK, 01231 lock_entry->sle_owner, 01232 &lock_entry->sle_lock, 01233 NULL, 01234 NULL, 01235 FALSE); 01236 break; 01237 01238 case STATE_GRANT_FSAL: 01239 /* No need to go to FSAL for lock */ 01240 *pstatus = STATE_SUCCESS; 01241 break; 01242 } 01243 01244 if(*pstatus != STATE_SUCCESS) 01245 { 01246 /* lock will be returned to right blocking type if it is still blocking 01247 * we could lose a block if we failed for any other reason 01248 */ 01249 if(*pstatus == STATE_LOCK_BLOCKED) 01250 LogDebug(COMPONENT_STATE, 01251 "Unable to lock FSAL for %s lock, error=%s", 01252 str_blocked(lock_entry->sle_blocked), 01253 state_err_str(*pstatus)); 01254 else 01255 LogMajor(COMPONENT_STATE, 01256 "Unable to lock FSAL for %s lock, error=%s", 01257 str_blocked(lock_entry->sle_blocked), 01258 state_err_str(*pstatus)); 01259 01260 LogEntry("Entry", lock_entry); 01261 01262 /* And release the cookie without unblocking the lock. 01263 * grant_blocked_locks() will decide whether to keep or free the block. 01264 */ 01265 free_cookie(hash_entry, FALSE); 01266 01267 return *pstatus; 01268 } 01269 01270 *ppcookie_entry = hash_entry; 01271 return *pstatus; 01272 } 01273 01274 state_status_t state_cancel_grant(fsal_op_context_t * pcontext, 01275 state_cookie_entry_t * cookie_entry, 01276 state_status_t * pstatus) 01277 { 01278 /* We had acquired an FSAL lock, need to release it. */ 01279 *pstatus = do_lock_op(cookie_entry->sce_pentry, 01280 pcontext, 01281 cookie_entry->sce_lock_entry->sle_pexport, 01282 FSAL_OP_UNLOCK, 01283 cookie_entry->sce_lock_entry->sle_owner, 01284 &cookie_entry->sce_lock_entry->sle_lock, 01285 NULL, /* no conflict expected */ 01286 NULL, 01287 FALSE); 01288 01289 if(*pstatus != STATE_SUCCESS) 01290 LogMajor(COMPONENT_STATE, 01291 "Unable to unlock FSAL for canceled GRANTED lock, error=%s", 01292 state_err_str(*pstatus)); 01293 01294 /* And release the cookie and unblock lock (because lock will be removed) */ 01295 free_cookie(cookie_entry, TRUE); 01296 01297 return *pstatus; 01298 } 01299 01300 state_status_t state_find_grant(void * pcookie, 01301 int cookie_size, 01302 state_cookie_entry_t ** ppcookie_entry, 01303 state_status_t * pstatus) 01304 { 01305 hash_buffer_t buffkey; 01306 hash_buffer_t buffval; 01307 hash_buffer_t buffused_key; 01308 char str[HASHTABLE_DISPLAY_STRLEN]; 01309 01310 buffkey.pdata = (caddr_t) pcookie; 01311 buffkey.len = cookie_size; 01312 01313 if(isFullDebug(COMPONENT_STATE) && isDebug(COMPONENT_HASHTABLE)) 01314 { 01315 display_lock_cookie_key(&buffkey, str); 01316 LogFullDebug(COMPONENT_STATE, 01317 "KEY {%s}", str); 01318 } 01319 01320 if(HashTable_Get_and_Del(ht_lock_cookies, &buffkey, &buffval, &buffused_key) != HASHTABLE_SUCCESS) 01321 { 01322 LogFullDebug(COMPONENT_STATE, 01323 "KEY {%s} NOTFOUND", str); 01324 *pstatus = STATE_BAD_COOKIE; 01325 return *pstatus; 01326 } 01327 01328 *ppcookie_entry = (state_cookie_entry_t *) buffval.pdata; 01329 01330 if(isFullDebug(COMPONENT_STATE) && isDebug(COMPONENT_HASHTABLE)) 01331 { 01332 char str[HASHTABLE_DISPLAY_STRLEN]; 01333 01334 display_lock_cookie_entry(*ppcookie_entry, str); 01335 LogFullDebug(COMPONENT_STATE, 01336 "Found Lock Cookie {%s}", str); 01337 } 01338 01339 *pstatus = STATE_SUCCESS; 01340 return *pstatus; 01341 } 01342 01343 void grant_blocked_lock_immediate(cache_entry_t * pentry, 01344 fsal_op_context_t * pcontext, 01345 state_lock_entry_t * lock_entry) 01346 { 01347 state_cookie_entry_t * pcookie = NULL; 01348 state_status_t state_status; 01349 01350 /* Try to clean up blocked lock. */ 01351 if(lock_entry->sle_block_data != NULL) 01352 { 01353 if(lock_entry->sle_block_data->sbd_blocked_cookie != NULL) 01354 { 01355 /* Cookie is attached, try to get it */ 01356 pcookie = lock_entry->sle_block_data->sbd_blocked_cookie; 01357 01358 if(state_find_grant(pcookie->sce_pcookie, 01359 pcookie->sce_cookie_size, 01360 &pcookie, 01361 &state_status) == STATE_SUCCESS) 01362 { 01363 /* We've got the cookie, free the cookie and the blocked lock */ 01364 free_cookie(pcookie, TRUE); 01365 } 01366 else 01367 { 01368 /* Otherwise, another thread has the cookie, let it do it's business. */ 01369 return; 01370 } 01371 } 01372 else 01373 { 01374 /* We have block data but no cookie, so we can just free the block data */ 01375 memset(lock_entry->sle_block_data, 0, sizeof(*lock_entry->sle_block_data)); 01376 gsh_free(lock_entry->sle_block_data); 01377 lock_entry->sle_block_data = NULL; 01378 } 01379 } 01380 01381 /* Mark lock as granted */ 01382 lock_entry->sle_blocked = STATE_NON_BLOCKING; 01383 01384 /* Merge any touching or overlapping locks into this one. */ 01385 LogEntry("Granted immediate, merging locks for", lock_entry); 01386 01387 merge_lock_entry(pentry, pcontext, lock_entry); 01388 LogEntry("Immediate Granted entry", lock_entry); 01389 01390 /* A lock downgrade could unblock blocked locks */ 01391 grant_blocked_locks(pentry, pcontext); 01392 } 01393 01394 void state_complete_grant(fsal_op_context_t * pcontext, 01395 state_cookie_entry_t * cookie_entry) 01396 { 01397 state_lock_entry_t * lock_entry; 01398 cache_entry_t * pentry; 01399 01400 lock_entry = cookie_entry->sce_lock_entry; 01401 pentry = cookie_entry->sce_pentry; 01402 01403 /* This routine does not call cache_inode_inc_pin_ref() because there MUST be 01404 * at least one lock present for there to be a cookie_entry to even allow this 01405 * routine to be called, and therefor the cache entry MUST be pinned. 01406 */ 01407 01408 pthread_rwlock_wrlock(&pentry->state_lock); 01409 01410 /* We need to make sure lock is ready to be granted */ 01411 if(lock_entry->sle_blocked == STATE_GRANTING) 01412 { 01413 /* Mark lock as granted */ 01414 lock_entry->sle_blocked = STATE_NON_BLOCKING; 01415 01416 /* Merge any touching or overlapping locks into this one. */ 01417 LogEntry("Granted, merging locks for", lock_entry); 01418 merge_lock_entry(pentry, pcontext, lock_entry); 01419 01420 LogEntry("Granted entry", lock_entry); 01421 01422 /* A lock downgrade could unblock blocked locks */ 01423 grant_blocked_locks(pentry, pcontext); 01424 } 01425 01426 /* Free cookie and unblock lock. 01427 * If somehow the lock was unlocked/canceled while the GRANT 01428 * was in progress, this will completely clean up the lock. 01429 */ 01430 free_cookie(cookie_entry, TRUE); 01431 01432 /* In case all locks have wound up free, we must release the pin reference. */ 01433 if(glist_empty(&pentry->object.file.lock_list)) 01434 cache_inode_dec_pin_ref(pentry); 01435 01436 pthread_rwlock_unlock(&pentry->state_lock); 01437 } 01438 01439 void try_to_grant_lock(state_lock_entry_t * lock_entry) 01440 { 01441 granted_callback_t call_back; 01442 state_blocking_t blocked; 01443 state_status_t status; 01444 01445 /* Try to grant if not cancelled and has block data */ 01446 if(lock_entry->sle_blocked != STATE_CANCELED && 01447 lock_entry->sle_block_data != NULL) 01448 { 01449 call_back = lock_entry->sle_block_data->sbd_granted_callback; 01450 /* 01451 * Mark the lock_entry as provisionally granted and make the granted 01452 * call back. The granted call back is responsible for acquiring a 01453 * reference to the lock entry if needed. 01454 */ 01455 blocked = lock_entry->sle_blocked; 01456 lock_entry->sle_blocked = STATE_GRANTING; 01457 if(lock_entry->sle_block_data->sbd_grant_type == STATE_GRANT_NONE) 01458 lock_entry->sle_block_data->sbd_grant_type = STATE_GRANT_INTERNAL; 01459 01460 if(call_back(lock_entry->sle_pentry, 01461 lock_entry, 01462 &status) == STATE_LOCK_BLOCKED) 01463 { 01464 /* The lock is still blocked, restore it's type and leave it in the list */ 01465 lock_entry->sle_blocked = blocked; 01466 return; 01467 } 01468 01469 if(status == STATE_SUCCESS) 01470 return; 01471 } 01472 01473 /* There was no call back data, the call back failed, or the block was cancelled. 01474 * Remove lock from list. 01475 */ 01476 LogEntry("Removing blocked entry", lock_entry); 01477 remove_from_locklist(lock_entry); 01478 } 01479 01480 void process_blocked_lock_upcall(state_block_data_t * block_data) 01481 { 01482 state_lock_entry_t * lock_entry = block_data->sbd_lock_entry; 01483 cache_entry_t * pentry = lock_entry->sle_pentry; 01484 01485 /* This routine does not call cache_inode_inc_pin_ref() because there MUST be 01486 * at least one lock present for there to be a block_data to even allow this 01487 * routine to be called, and therefor the cache entry MUST be pinned. 01488 */ 01489 01490 pthread_rwlock_wrlock(&pentry->state_lock); 01491 01492 try_to_grant_lock(lock_entry); 01493 01494 /* In case all locks have wound up free, we must release the pin reference. */ 01495 if(glist_empty(&pentry->object.file.lock_list)) 01496 cache_inode_dec_pin_ref(pentry); 01497 01498 pthread_rwlock_unlock(&pentry->state_lock); 01499 } 01500 01501 static void grant_blocked_locks(cache_entry_t * pentry, 01502 fsal_op_context_t * pcontext) 01503 { 01504 state_lock_entry_t * found_entry; 01505 struct glist_head * glist, * glistn; 01506 fsal_staticfsinfo_t * pstatic = pcontext->export_context->fe_static_fs_info; 01507 01508 /* If FSAL supports async blocking locks, allow it to grant blocked locks. */ 01509 if(pstatic->lock_support_async_block) 01510 return; 01511 01512 glist_for_each_safe(glist, glistn, &pentry->object.file.lock_list) 01513 { 01514 found_entry = glist_entry(glist, state_lock_entry_t, sle_list); 01515 01516 if(found_entry->sle_blocked != STATE_NLM_BLOCKING && 01517 found_entry->sle_blocked != STATE_NFSV4_BLOCKING) 01518 continue; 01519 01520 /* Found a blocked entry for this file, see if we can place the lock. */ 01521 if(get_overlapping_entry(pentry, 01522 pcontext, 01523 found_entry->sle_owner, 01524 &found_entry->sle_lock) != NULL) 01525 continue; 01526 01527 /* Found an entry that might work, try to grant it. */ 01528 try_to_grant_lock(found_entry); 01529 } 01530 } 01531 01532 state_status_t cancel_blocked_lock(cache_entry_t * pentry, 01533 fsal_op_context_t * pcontext, 01534 state_lock_entry_t * lock_entry) 01535 { 01536 state_cookie_entry_t * pcookie = NULL; 01537 state_status_t state_status; 01538 01539 /* Mark lock as canceled */ 01540 LogEntry("Cancelling blocked", lock_entry); 01541 lock_entry->sle_blocked = STATE_CANCELED; 01542 01543 /* Unlocking the entire region will remove any FSAL locks we held, whether 01544 * from fully granted locks, or from blocking locks that were in the process 01545 * of being granted. 01546 */ 01547 01548 /* Try to clean up blocked lock if a cookie is present */ 01549 if(lock_entry->sle_block_data != NULL && 01550 lock_entry->sle_block_data->sbd_blocked_cookie != NULL) 01551 { 01552 /* Cookie is attached, try to get it */ 01553 pcookie = lock_entry->sle_block_data->sbd_blocked_cookie; 01554 01555 if(state_find_grant(pcookie->sce_pcookie, 01556 pcookie->sce_cookie_size, 01557 &pcookie, 01558 &state_status) == STATE_SUCCESS) 01559 { 01560 /* We've got the cookie, free the cookie and the blocked lock */ 01561 free_cookie(pcookie, TRUE); 01562 } 01563 /* otherwise, another thread has the cookie, let it do it's business, 01564 * which won't be much, since we've already marked the lock CANCELED. 01565 */ 01566 } 01567 else 01568 { 01569 /* Otherwise, if block data is present, it will be freed when the lock 01570 * entry is freed. If the cookie is held, the refcount it holds will 01571 * prevent the lock entry from being released until the cookie is 01572 * freed. 01573 */ 01574 01575 /* Since a cookie was not found, the lock must still be in a state 01576 * of needing cancelling. 01577 */ 01578 state_status = do_lock_op(pentry, 01579 pcontext, 01580 lock_entry->sle_pexport, 01581 FSAL_OP_CANCEL, 01582 lock_entry->sle_owner, 01583 &lock_entry->sle_lock, 01584 NULL, /* no conflict expected */ 01585 NULL, 01586 FALSE); /* overlap not relevant */ 01587 01588 if(state_status != STATE_SUCCESS) 01589 { 01590 /* Unable to cancel, assume that granted upcall is on it's way. */ 01591 LogEntry("Unable to cancel (grant upcall expected)", lock_entry); 01592 return STATE_SUCCESS; 01593 } 01594 } 01595 01596 /* Remove the lock from the lock list*/ 01597 LogEntry("Removing", lock_entry); 01598 remove_from_locklist(lock_entry); 01599 01600 return state_status; 01601 } 01602 01623 void cancel_blocked_locks_range(cache_entry_t * pentry, 01624 fsal_op_context_t * pcontext, 01625 state_owner_t * powner, 01626 state_t * pstate, 01627 fsal_lock_param_t * plock) 01628 { 01629 struct glist_head * glist, * glistn; 01630 state_lock_entry_t * found_entry = NULL; 01631 uint64_t found_entry_end, plock_end = lock_end(plock); 01632 01633 glist_for_each_safe(glist, glistn, &pentry->object.file.lock_list) 01634 { 01635 found_entry = glist_entry(glist, state_lock_entry_t, sle_list); 01636 01637 /* Skip locks not owned by owner */ 01638 if(powner != NULL && different_owners(found_entry->sle_owner, powner)) 01639 continue; 01640 01641 /* Skip locks owned by this NLM state. 01642 * This protects NLM locks from the current iteration of an NLM 01643 * client from being released by SM_NOTIFY. 01644 */ 01645 if(pstate != NULL && 01646 lock_owner_is_nlm(found_entry) && 01647 found_entry->sle_state == pstate) 01648 continue; 01649 01650 /* Skip granted locks */ 01651 if(found_entry->sle_blocked == STATE_NON_BLOCKING) 01652 continue; 01653 01654 LogEntry("Checking", found_entry); 01655 01656 found_entry_end = lock_end(&found_entry->sle_lock); 01657 01658 if((found_entry_end >= plock->lock_start) && 01659 (found_entry->sle_lock.lock_start <= plock_end)) 01660 { 01661 /* lock overlaps, cancel it. */ 01662 (void) cancel_blocked_lock(pentry, pcontext, found_entry); 01663 } 01664 } 01665 } 01666 01667 state_status_t state_release_grant(fsal_op_context_t * pcontext, 01668 state_cookie_entry_t * cookie_entry, 01669 state_status_t * pstatus) 01670 { 01671 state_lock_entry_t * lock_entry; 01672 cache_entry_t * pentry; 01673 01674 *pstatus = STATE_SUCCESS; 01675 01676 lock_entry = cookie_entry->sce_lock_entry; 01677 pentry = cookie_entry->sce_pentry; 01678 01679 /* This routine does not call cache_inode_inc_pin_ref() because there MUST be 01680 * at least one lock present for there to be a cookie_entry to even allow this 01681 * routine to be called, and therefor the cache entry MUST be pinned. 01682 */ 01683 01684 pthread_rwlock_wrlock(&pentry->state_lock); 01685 01686 /* We need to make sure lock is only "granted" once... 01687 * It's (remotely) possible that due to latency, we might end up processing 01688 * two GRANTED_RSP calls at the same time. 01689 */ 01690 if(lock_entry->sle_blocked == STATE_GRANTING) 01691 { 01692 /* Mark lock as canceled */ 01693 lock_entry->sle_blocked = STATE_CANCELED; 01694 01695 /* Remove the lock from the lock list. 01696 * Will not free yet because of cookie reference to lock entry. 01697 */ 01698 LogEntry("Release Grant Removing", lock_entry); 01699 remove_from_locklist(lock_entry); 01700 01701 /* We had acquired an FSAL lock, need to release it. */ 01702 *pstatus = do_lock_op(pentry, 01703 pcontext, 01704 lock_entry->sle_pexport, 01705 FSAL_OP_UNLOCK, 01706 lock_entry->sle_owner, 01707 &lock_entry->sle_lock, 01708 NULL, /* no conflict expected */ 01709 NULL, 01710 FALSE); 01711 01712 if(*pstatus != STATE_SUCCESS) 01713 LogMajor(COMPONENT_STATE, 01714 "Unable to unlock FSAL for released GRANTED lock, error=%s", 01715 state_err_str(*pstatus)); 01716 } 01717 01718 /* Free the cookie and unblock the lock. 01719 * This will release our final reference on the lock entry and should free it. 01720 * (Unless another thread has a reference for some reason. 01721 */ 01722 free_cookie(cookie_entry, TRUE); 01723 01724 /* Check to see if we can grant any blocked locks. */ 01725 grant_blocked_locks(pentry, pcontext); 01726 01727 /* In case all locks have wound up free, we must release the pin reference. */ 01728 if(glist_empty(&pentry->object.file.lock_list)) 01729 cache_inode_dec_pin_ref(pentry); 01730 01731 pthread_rwlock_unlock(&pentry->state_lock); 01732 01733 return *pstatus; 01734 } 01735 #endif 01736 01737 /****************************************************************************** 01738 * 01739 * Functions to interract with FSAL 01740 * 01741 ******************************************************************************/ 01742 inline const char *fsal_lock_op_str(fsal_lock_op_t op) 01743 { 01744 switch(op) 01745 { 01746 case FSAL_OP_LOCKT: return "FSAL_OP_LOCKT "; 01747 case FSAL_OP_LOCK: return "FSAL_OP_LOCK "; 01748 case FSAL_OP_LOCKB: return "FSAL_OP_LOCKB "; 01749 case FSAL_OP_UNLOCK: return "FSAL_OP_UNLOCK"; 01750 case FSAL_OP_CANCEL: return "FSAL_OP_CANCEL"; 01751 } 01752 return "unknown"; 01753 } 01754 01774 state_status_t do_unlock_no_owner(cache_entry_t * pentry, 01775 fsal_op_context_t * pcontext, 01776 exportlist_t * pexport, 01777 fsal_lock_param_t * plock) 01778 { 01779 state_lock_entry_t * unlock_entry; 01780 struct glist_head fsal_unlock_list; 01781 struct glist_head * glist, *glistn; 01782 state_lock_entry_t * found_entry; 01783 fsal_status_t fsal_status; 01784 state_status_t status = STATE_SUCCESS, t_status; 01785 fsal_lock_param_t * punlock; 01786 01787 unlock_entry = create_state_lock_entry(pentry, 01788 pcontext, 01789 pexport, 01790 STATE_NON_BLOCKING, 01791 &unknown_owner, /* no real owner */ 01792 NULL, /* no real state */ 01793 plock); 01794 01795 if(unlock_entry == NULL) 01796 return STATE_MALLOC_ERROR; 01797 01798 init_glist(&fsal_unlock_list); 01799 01800 glist_add_tail(&fsal_unlock_list, &unlock_entry->sle_list); 01801 01802 LogEntry("Generating FSAL Unlock List", unlock_entry); 01803 01804 if(subtract_list_from_list(pentry, 01805 pcontext, 01806 &fsal_unlock_list, 01807 &pentry->object.file.lock_list, 01808 &status) != STATE_SUCCESS) 01809 { 01810 /* We ran out of memory while trying to build the unlock list. 01811 * We have already released the locks from cache inode lock list. 01812 */ 01813 // TODO FSF: what do we do now? 01814 LogMajor(COMPONENT_STATE, 01815 "Error %s while trying to create unlock list", 01816 state_err_str(status)); 01817 } 01818 01819 glist_for_each_safe(glist, glistn, &fsal_unlock_list) 01820 { 01821 found_entry = glist_entry(glist, state_lock_entry_t, sle_list); 01822 punlock = &found_entry->sle_lock; 01823 01824 LogEntry("FSAL Unlock", found_entry); 01825 01826 fsal_status = FSAL_lock_op(cache_inode_fd(pentry), 01827 &pentry->handle, 01828 pcontext, 01829 NULL, 01830 FSAL_OP_UNLOCK, 01831 *punlock, 01832 NULL); 01833 01834 t_status = state_error_convert(fsal_status); 01835 01836 LogFullDebug(COMPONENT_STATE, 01837 "FSAL_lock_op returned %s", 01838 state_err_str(t_status)); 01839 01840 if(t_status != STATE_SUCCESS) 01841 { 01842 // TODO FSF: what do we do now? 01843 LogMajor(COMPONENT_STATE, 01844 "Error %s while trying to do FSAL Unlock", 01845 state_err_str(status)); 01846 status = t_status; 01847 } 01848 01849 remove_from_locklist(found_entry); 01850 } 01851 01852 return status; 01853 } 01854 01855 state_status_t do_lock_op(cache_entry_t * pentry, 01856 fsal_op_context_t * pcontext, 01857 exportlist_t * pexport, 01858 fsal_lock_op_t lock_op, 01859 state_owner_t * powner, 01860 fsal_lock_param_t * plock, 01861 state_owner_t ** holder, /* owner that holds conflicting lock */ 01862 fsal_lock_param_t * conflict, /* description of conflicting lock */ 01863 bool_t overlap) /* hint that lock overlaps */ 01864 { 01865 fsal_status_t fsal_status; 01866 state_status_t status = STATE_SUCCESS; 01867 fsal_lock_param_t conflicting_lock; 01868 fsal_staticfsinfo_t * pstatic = pcontext->export_context->fe_static_fs_info; 01869 01870 /* Quick exit if: 01871 * Locks are not supported by FSAL 01872 * Async blocking locks are not supported and this is a cancel 01873 * Async blocking locks are not supported and this lock overlaps 01874 * Lock owners are not supported and hint tells us that lock fully overlaps a 01875 * lock we already have (no need to make another FSAL call in that case) 01876 */ 01877 if(!pstatic->lock_support || 01878 (!pstatic->lock_support_async_block && lock_op == FSAL_OP_CANCEL) || 01879 (!pstatic->lock_support_async_block && overlap) || 01880 (!pstatic->lock_support_owner && overlap)) 01881 return STATE_SUCCESS; 01882 01883 LogLock(COMPONENT_STATE, NIV_FULL_DEBUG, 01884 fsal_lock_op_str(lock_op), pentry, pcontext, powner, plock); 01885 01886 memset(&conflicting_lock, 0, sizeof(conflicting_lock)); 01887 01888 if(pstatic->lock_support_owner || lock_op != FSAL_OP_UNLOCK) 01889 { 01890 if(lock_op == FSAL_OP_LOCKB && !pstatic->lock_support_async_block) 01891 lock_op = FSAL_OP_LOCK; 01892 01893 fsal_status = FSAL_lock_op(cache_inode_fd(pentry), 01894 &pentry->handle, 01895 pcontext, 01896 pstatic->lock_support_owner ? powner : NULL, 01897 lock_op, 01898 *plock, 01899 &conflicting_lock); 01900 01901 status = state_error_convert(fsal_status); 01902 01903 LogFullDebug(COMPONENT_STATE, 01904 "FSAL_lock_op returned %s", 01905 state_err_str(status)); 01906 01907 if(status == STATE_LOCK_BLOCKED && lock_op != FSAL_OP_LOCKB) 01908 { 01909 /* This is an unexpected return code, make sure caller reports an error */ 01910 LogMajor(COMPONENT_STATE, 01911 "FSAL returned unexpected STATE_LOCK_BLOCKED result"); 01912 status = STATE_FSAL_ERROR; 01913 } 01914 } 01915 else 01916 { 01917 status = do_unlock_no_owner(pentry, pcontext, pexport, plock); 01918 } 01919 01920 if(status == STATE_LOCK_CONFLICT) 01921 { 01922 if(holder != NULL) 01923 { 01924 *holder = &unknown_owner; 01925 inc_state_owner_ref(&unknown_owner); 01926 } 01927 if(conflict != NULL) 01928 { 01929 *conflict = conflicting_lock; 01930 } 01931 } 01932 01933 return status; 01934 } 01935 01936 void copy_conflict(state_lock_entry_t * found_entry, 01937 state_owner_t ** holder, /* owner that holds conflicting lock */ 01938 fsal_lock_param_t * conflict) /* description of conflicting lock */ 01939 { 01940 if(found_entry == NULL) 01941 return; 01942 01943 if(holder != NULL) 01944 { 01945 *holder = found_entry->sle_owner; 01946 inc_state_owner_ref(found_entry->sle_owner); 01947 } 01948 if(conflict != NULL) 01949 *conflict = found_entry->sle_lock; 01950 } 01951 01952 /****************************************************************************** 01953 * 01954 * Primary lock interface functions 01955 * 01956 ******************************************************************************/ 01957 01967 state_status_t state_test(cache_entry_t * pentry, 01968 fsal_op_context_t * pcontext, 01969 exportlist_t * pexport, 01970 state_owner_t * powner, 01971 fsal_lock_param_t * plock, 01972 state_owner_t ** holder, /* owner that holds conflicting lock */ 01973 fsal_lock_param_t * conflict, /* description of conflicting lock */ 01974 state_status_t * pstatus) 01975 { 01976 state_lock_entry_t * found_entry; 01977 cache_inode_status_t cache_status; 01978 01979 LogLock(COMPONENT_STATE, NIV_FULL_DEBUG, 01980 "TEST", 01981 pentry, pcontext, powner, plock); 01982 01983 cache_status = cache_inode_inc_pin_ref(pentry); 01984 01985 if(cache_status != CACHE_INODE_SUCCESS) 01986 { 01987 *pstatus = cache_inode_status_to_state_status(cache_status); 01988 LogDebug(COMPONENT_STATE, 01989 "Could not pin file"); 01990 return *pstatus; 01991 } 01992 01993 if(cache_inode_open(pentry, FSAL_O_RDWR, pcontext, 0, &cache_status) != CACHE_INODE_SUCCESS) 01994 { 01995 *pstatus = cache_inode_status_to_state_status(cache_status); 01996 LogFullDebug(COMPONENT_STATE, 01997 "Could not open file"); 01998 01999 cache_inode_dec_pin_ref(pentry); 02000 02001 return *pstatus; 02002 } 02003 02004 pthread_rwlock_rdlock(&pentry->state_lock); 02005 02006 found_entry = get_overlapping_entry(pentry, pcontext, powner, plock); 02007 02008 if(found_entry != NULL) 02009 { 02010 /* found a conflicting lock, return it */ 02011 LogEntry("Found conflict", found_entry); 02012 copy_conflict(found_entry, holder, conflict); 02013 *pstatus = STATE_LOCK_CONFLICT; 02014 } 02015 else 02016 { 02017 /* Prepare to make call to FSAL for this lock */ 02018 *pstatus = do_lock_op(pentry, 02019 pcontext, 02020 pexport, 02021 FSAL_OP_LOCKT, 02022 powner, 02023 plock, 02024 holder, 02025 conflict, 02026 FALSE); 02027 02028 if(*pstatus != STATE_SUCCESS && 02029 *pstatus != STATE_LOCK_CONFLICT) 02030 { 02031 LogMajor(COMPONENT_STATE, 02032 "Got error from FSAL lock operation, error=%s", 02033 state_err_str(*pstatus)); 02034 } 02035 if(*pstatus == STATE_SUCCESS) 02036 LogFullDebug(COMPONENT_STATE, 02037 "No Conflict"); 02038 else 02039 LogLock(COMPONENT_STATE, NIV_FULL_DEBUG, 02040 "Conflict from FSAL", 02041 pentry, pcontext, *holder, conflict); 02042 } 02043 02044 if(isFullDebug(COMPONENT_STATE) && isFullDebug(COMPONENT_MEMLEAKS)) 02045 LogList("Lock List", pentry, &pentry->object.file.lock_list); 02046 02047 pthread_rwlock_unlock(&pentry->state_lock); 02048 02049 cache_inode_dec_pin_ref(pentry); 02050 02051 return *pstatus; 02052 } 02053 02061 state_status_t state_lock(cache_entry_t * pentry, 02062 fsal_op_context_t * pcontext, 02063 exportlist_t * pexport, 02064 state_owner_t * powner, 02065 state_t * pstate, 02066 state_blocking_t blocking, 02067 state_block_data_t * block_data, 02068 fsal_lock_param_t * plock, 02069 state_owner_t ** holder, /* owner that holds conflicting lock */ 02070 fsal_lock_param_t * conflict, /* description of conflicting lock */ 02071 state_status_t * pstatus) 02072 { 02073 bool_t allow = TRUE, overlap = FALSE; 02074 struct glist_head * glist; 02075 state_lock_entry_t * found_entry; 02076 uint64_t found_entry_end; 02077 uint64_t plock_end = lock_end(plock); 02078 cache_inode_status_t cache_status; 02079 fsal_staticfsinfo_t * pstatic = pcontext->export_context->fe_static_fs_info; 02080 fsal_lock_op_t lock_op; 02081 02082 cache_status = cache_inode_inc_pin_ref(pentry); 02083 02084 if(cache_status != CACHE_INODE_SUCCESS) 02085 { 02086 *pstatus = cache_inode_status_to_state_status(cache_status); 02087 LogDebug(COMPONENT_STATE, 02088 "Could not pin file"); 02089 return *pstatus; 02090 } 02091 02092 if(cache_inode_open(pentry, FSAL_O_RDWR, pcontext, 0, &cache_status) != CACHE_INODE_SUCCESS) 02093 { 02094 cache_inode_dec_pin_ref(pentry); 02095 *pstatus = cache_inode_status_to_state_status(cache_status); 02096 LogFullDebug(COMPONENT_STATE, 02097 "Could not open file"); 02098 return *pstatus; 02099 } 02100 02101 pthread_rwlock_wrlock(&pentry->state_lock); 02102 02103 #ifdef _USE_BLOCKING_LOCKS 02104 02105 if(blocking != STATE_NON_BLOCKING) 02106 { 02107 /* 02108 * First search for a blocked request. Client can ignore the blocked 02109 * request and keep sending us new lock request again and again. So if 02110 * we have a mapping blocked request return that 02111 */ 02112 glist_for_each(glist, &pentry->object.file.lock_list) 02113 { 02114 found_entry = glist_entry(glist, state_lock_entry_t, sle_list); 02115 02116 if(different_owners(found_entry->sle_owner, powner)) 02117 continue; 02118 02119 /* Need to reject lock request if this lock owner already has a lock 02120 * on this file via a different export. 02121 */ 02122 if(found_entry->sle_pexport != pexport) 02123 { 02124 pthread_rwlock_unlock(&pentry->state_lock); 02125 02126 cache_inode_dec_pin_ref(pentry); 02127 02128 LogEvent(COMPONENT_STATE, 02129 "Lock Owner Export Conflict, Lock held for export %d (%s), request for export %d (%s)", 02130 found_entry->sle_pexport->id, 02131 found_entry->sle_pexport->fullpath, 02132 pexport->id, 02133 pexport->fullpath); 02134 LogEntry("Found lock entry belonging to another export", found_entry); 02135 *pstatus = STATE_INVALID_ARGUMENT; 02136 return *pstatus; 02137 } 02138 02139 if(found_entry->sle_blocked != blocking) 02140 continue; 02141 02142 if(different_lock(&found_entry->sle_lock, plock)) 02143 continue; 02144 02145 pthread_rwlock_unlock(&pentry->state_lock); 02146 02147 cache_inode_dec_pin_ref(pentry); 02148 02149 /* 02150 * We have matched all atribute of the existing lock. 02151 * Just return with blocked status. Client may be polling. 02152 */ 02153 LogEntry("Found blocked", found_entry); 02154 *pstatus = STATE_LOCK_BLOCKED; 02155 return *pstatus; 02156 } 02157 } 02158 #endif 02159 02160 glist_for_each(glist, &pentry->object.file.lock_list) 02161 { 02162 found_entry = glist_entry(glist, state_lock_entry_t, sle_list); 02163 02164 /* Need to reject lock request if this lock owner already has a lock 02165 * on this file via a different export. 02166 */ 02167 if(found_entry->sle_pexport != pexport && 02168 !different_owners(found_entry->sle_owner, powner)) 02169 { 02170 pthread_rwlock_unlock(&pentry->state_lock); 02171 02172 cache_inode_dec_pin_ref(pentry); 02173 02174 LogEvent(COMPONENT_STATE, 02175 "Lock Owner Export Conflict, Lock held for export %d (%s), request for export %d (%s)", 02176 found_entry->sle_pexport->id, 02177 found_entry->sle_pexport->fullpath, 02178 pexport->id, 02179 pexport->fullpath); 02180 02181 LogEntry("Found lock entry belonging to another export", found_entry); 02182 02183 *pstatus = STATE_INVALID_ARGUMENT; 02184 return *pstatus; 02185 } 02186 02187 /* Don't skip blocked locks for fairness */ 02188 02189 found_entry_end = lock_end(&found_entry->sle_lock); 02190 02191 if((found_entry_end >= plock->lock_start) && 02192 (found_entry->sle_lock.lock_start <= plock_end)) 02193 { 02194 /* lock overlaps see if we can allow 02195 * allow if neither lock is exclusive or the owner is the same 02196 */ 02197 if((found_entry->sle_lock.lock_type == FSAL_LOCK_W || 02198 plock->lock_type == FSAL_LOCK_W) && 02199 different_owners(found_entry->sle_owner, powner)) 02200 { 02201 /* Found a conflicting lock, break out of loop. 02202 * Also indicate overlap hint. 02203 */ 02204 LogEntry("Conflicts with", found_entry); 02205 LogList("Locks", pentry, &pentry->object.file.lock_list); 02206 copy_conflict(found_entry, holder, conflict); 02207 allow = FALSE; 02208 overlap = TRUE; 02209 break; 02210 } 02211 } 02212 02213 if(found_entry_end >= plock_end && 02214 found_entry->sle_lock.lock_start <= plock->lock_start && 02215 found_entry->sle_lock.lock_type == plock->lock_type && 02216 (found_entry->sle_blocked == STATE_NON_BLOCKING || 02217 found_entry->sle_blocked == STATE_GRANTING)) 02218 { 02219 /* Found an entry that entirely overlaps the new entry 02220 * (and due to the preceding test does not prevent 02221 * granting this lock - therefore there can't be any 02222 * other locks that would prevent granting this lock 02223 */ 02224 if(!different_owners(found_entry->sle_owner, powner)) 02225 { 02226 #ifdef _USE_BLOCKING_LOCKS 02227 /* The lock actually has the same owner, we're done, 02228 * other than dealing with a lock in GRANTING state. 02229 */ 02230 if(found_entry->sle_blocked == STATE_GRANTING) 02231 { 02232 /* Need to handle completion of granting of this lock 02233 * because a GRANT was in progress. 02234 * This could be a client retrying a blocked lock 02235 * due to mis-trust of server. If the client 02236 * also accepts the GRANT_MSG with a GRANT_RESP, 02237 * that will be just fine. 02238 */ 02239 grant_blocked_lock_immediate(pentry, 02240 pcontext, 02241 found_entry); 02242 } 02243 #endif 02244 pthread_rwlock_unlock(&pentry->state_lock); 02245 02246 cache_inode_dec_pin_ref(pentry); 02247 02248 LogEntry("Found existing", found_entry); 02249 02250 *pstatus = STATE_SUCCESS; 02251 return *pstatus; 02252 } 02253 02254 /* Found a compatible lock with a different lock owner that 02255 * fully overlaps, set hint. 02256 */ 02257 LogEntry("state_lock Found overlapping", found_entry); 02258 overlap = TRUE; 02259 } 02260 } 02261 02262 /* Decide how to proceed */ 02263 if(pstatic->lock_support_async_block && blocking == STATE_NLM_BLOCKING) 02264 { 02265 /* FSAL supports blocking locks, and this is an NLM blocking lock request, 02266 * request blocking lock from FSAL. 02267 */ 02268 lock_op = FSAL_OP_LOCKB; 02269 } 02270 else if(allow || blocking == STATE_NLM_BLOCKING) 02271 { 02272 /* No conflict found in Ganesha, or NLM blocking lock when FSAL doesn't 02273 * support blocking locks. In either case, proceed with non-blocking 02274 * request to FSAL. 02275 */ 02276 lock_op = FSAL_OP_LOCK; 02277 } 02278 else 02279 { 02280 /* Can't do async blocking lock in FSAL and have a conflict. 02281 * Return it. 02282 */ 02283 pthread_rwlock_unlock(&pentry->state_lock); 02284 02285 cache_inode_dec_pin_ref(pentry); 02286 02287 *pstatus = STATE_LOCK_CONFLICT; 02288 return *pstatus; 02289 } 02290 02291 /* We have already returned if: 02292 * + we have found an identical blocking lock 02293 * + we have found an entirely overlapping lock with the same lock owner 02294 * + this was not a supported blocking lock and we found a conflict 02295 * 02296 * So at this point, we are either going to do one of the following (all 02297 * descriptions below assume no problems occur): 02298 * 02299 * (1) FSAL supports async blocking locks, we know there is a conflict, and 02300 * this is a supported blocking lock request 02301 * 02302 * Make FSAL_OP_LOCKB call anyway, we will rely on FSAL to grant blocking 02303 * locks. We will return the conflict we know about rather than what the 02304 * FSAL returns. Insert blocking lock into queue. 02305 * 02306 * (2) FSAL supports async blocking locks, we don't know about any conflict, 02307 * and this is a supported blocking lock request 02308 * 02309 * Make FSAL_OP_LOCKB call, if it indicates block, insert blocking lock 02310 * into queue, and return the conflict the FSAL indicates. If FSAL grants 02311 * lock, then return granted lock and insert into lock list, otherwise 02312 * insert blocking lock into queue. 02313 * 02314 * (3) FSAL doesn't support async blocking locks, this is a supported blocking 02315 * lock and we know there is a conflict 02316 * 02317 * Insert blocking lock into queue, we will grant lock when possible. 02318 * 02319 * (4) FSAL doesn't support async blocking locks and we don't know about any 02320 * conflict 02321 * 02322 * Make FSAL_OP_LOCK call, if it indicates conflict, return that. Even if 02323 * this is a supported blocking lock call, there is no way to block. If 02324 * lock is granted, return that and insert lock into list. 02325 * 02326 * (5) FSAL supports async blocking locks, we don't know about any conflict, 02327 * and this is not a supported blocking lock request 02328 * 02329 * Make FSAL_OP_LOCK call, if it indicates conflict, return that. If 02330 * lock is granted, return that and insert lock into list. 02331 */ 02332 02333 /* Create the new lock entry. 02334 * Provisionally mark this lock as granted. 02335 */ 02336 found_entry = create_state_lock_entry(pentry, 02337 pcontext, 02338 pexport, 02339 STATE_NON_BLOCKING, 02340 powner, 02341 pstate, 02342 plock); 02343 if(!found_entry) 02344 { 02345 pthread_rwlock_unlock(&pentry->state_lock); 02346 02347 cache_inode_dec_pin_ref(pentry); 02348 02349 *pstatus = STATE_MALLOC_ERROR; 02350 return *pstatus; 02351 } 02352 02353 /* If no conflict in lock list, or FSAL supports async blocking locks, 02354 * make FSAL call. Don't ask for conflict if we know about a conflict. 02355 */ 02356 if(allow || pstatic->lock_support_async_block) 02357 { 02358 /* Prepare to make call to FSAL for this lock */ 02359 *pstatus = do_lock_op(pentry, 02360 pcontext, 02361 pexport, 02362 lock_op, 02363 powner, 02364 plock, 02365 allow ? holder : NULL, 02366 allow ? conflict : NULL, 02367 overlap); 02368 } 02369 else 02370 *pstatus = STATE_LOCK_BLOCKED; 02371 02372 if(*pstatus == STATE_SUCCESS) 02373 { 02374 /* Merge any touching or overlapping locks into this one */ 02375 LogEntry("FSAL lock acquired, merging locks for", found_entry); 02376 02377 merge_lock_entry(pentry, pcontext, found_entry); 02378 02379 /* Insert entry into lock list */ 02380 LogEntry("New", found_entry); 02381 02382 /* if the list is empty to start with; increment the pin ref count 02383 * before adding it to the list 02384 */ 02385 if(glist_empty(&pentry->object.file.lock_list)) 02386 cache_inode_inc_pin_ref(pentry); 02387 02388 glist_add_tail(&pentry->object.file.lock_list, &found_entry->sle_list); 02389 02390 #ifdef _USE_BLOCKING_LOCKS 02391 /* A lock downgrade could unblock blocked locks */ 02392 grant_blocked_locks(pentry, pcontext); 02393 #endif 02394 /* Don't need to unpin, we know there is state on file. */ 02395 } 02396 else if(*pstatus == STATE_LOCK_CONFLICT) 02397 { 02398 LogEntry("Conflict in FSAL for", found_entry); 02399 02400 /* Discard lock entry */ 02401 remove_from_locklist(found_entry); 02402 } 02403 #ifdef _USE_BLOCKING_LOCKS 02404 else if(*pstatus == STATE_LOCK_BLOCKED) 02405 { 02406 /* Mark entry as blocking and attach block_data */ 02407 found_entry->sle_block_data = block_data; 02408 found_entry->sle_blocked = blocking; 02409 block_data->sbd_lock_entry = found_entry; 02410 02411 /* Insert entry into lock list */ 02412 LogEntry("FSAL block for", found_entry); 02413 02414 /* if the list is empty to start with; increment the pin ref count 02415 * before adding it to the list 02416 */ 02417 if(glist_empty(&pentry->object.file.lock_list)) 02418 cache_inode_inc_pin_ref(pentry); 02419 02420 glist_add_tail(&pentry->object.file.lock_list, &found_entry->sle_list); 02421 02422 pthread_rwlock_unlock(&pentry->state_lock); 02423 02424 cache_inode_dec_pin_ref(pentry); 02425 02426 P(blocked_locks_mutex); 02427 02428 glist_add_tail(&state_blocked_locks, &block_data->sbd_list); 02429 02430 V(blocked_locks_mutex); 02431 02432 return *pstatus; 02433 } 02434 #endif /* _USE_BLOCKING_LOCKS */ 02435 else 02436 { 02437 LogMajor(COMPONENT_STATE, 02438 "Unable to lock FSAL, error=%s", 02439 state_err_str(*pstatus)); 02440 02441 /* Discard lock entry */ 02442 remove_from_locklist(found_entry); 02443 } 02444 02445 pthread_rwlock_unlock(&pentry->state_lock); 02446 02447 cache_inode_dec_pin_ref(pentry); 02448 02449 return *pstatus; 02450 } 02451 02457 state_status_t state_unlock(cache_entry_t * pentry, 02458 fsal_op_context_t * pcontext, 02459 exportlist_t * pexport, 02460 state_owner_t * powner, 02461 state_t * pstate, 02462 fsal_lock_param_t * plock, 02463 state_status_t * pstatus) 02464 { 02465 bool_t empty = FALSE; 02466 cache_inode_status_t cache_status; 02467 02468 cache_status = cache_inode_inc_pin_ref(pentry); 02469 02470 if(cache_status != CACHE_INODE_SUCCESS) 02471 { 02472 *pstatus = cache_inode_status_to_state_status(cache_status); 02473 LogDebug(COMPONENT_STATE, 02474 "Could not pin file"); 02475 return *pstatus; 02476 } 02477 02478 if(pentry->type != REGULAR_FILE) 02479 { 02480 LogLock(COMPONENT_STATE, NIV_DEBUG, 02481 "Bad Unlock", 02482 pentry, pcontext, powner, plock); 02483 *pstatus = STATE_BAD_TYPE; 02484 return *pstatus; 02485 } 02486 02487 /* We need to iterate over the full lock list and remove 02488 * any mapping entry. And sle_lock.lock_start = 0 and sle_lock.lock_length = 0 nlm_lock 02489 * implies remove all entries 02490 */ 02491 pthread_rwlock_wrlock(&pentry->state_lock); 02492 02493 /* If lock list is empty, there really isn't any work for us to do. */ 02494 if(glist_empty(&pentry->object.file.lock_list)) 02495 { 02496 pthread_rwlock_unlock(&pentry->state_lock); 02497 02498 cache_inode_dec_pin_ref(pentry); 02499 LogDebug(COMPONENT_STATE, 02500 "Unlock success on file with no locks"); 02501 02502 *pstatus = STATE_SUCCESS; 02503 return *pstatus; 02504 } 02505 02506 LogFullDebug(COMPONENT_STATE, 02507 "----------------------------------------------------------------------"); 02508 LogLock(COMPONENT_STATE, NIV_FULL_DEBUG, 02509 "Subtracting", 02510 pentry, pcontext, powner, plock); 02511 LogFullDebug(COMPONENT_STATE, 02512 "----------------------------------------------------------------------"); 02513 02514 #ifdef _USE_BLOCKING_LOCKS 02515 /* First cancel any blocking locks that might overlap the unlocked range. */ 02516 cancel_blocked_locks_range(pentry, 02517 pcontext, 02518 powner, 02519 pstate, 02520 plock); 02521 #endif 02522 02523 /* Release the lock from cache inode lock list for pentry */ 02524 subtract_lock_from_list(pentry, 02525 pcontext, 02526 powner, 02527 pstate, 02528 plock, 02529 pstatus, 02530 &pentry->object.file.lock_list); 02531 02532 if(*pstatus != STATE_SUCCESS) 02533 { 02534 /* The unlock has not taken affect (other than canceling any blocking locks. */ 02535 LogMajor(COMPONENT_STATE, 02536 "Unable to remove lock from list for unlock, error=%s", 02537 state_err_str(*pstatus)); 02538 02539 pthread_rwlock_unlock(&pentry->state_lock); 02540 02541 cache_inode_dec_pin_ref(pentry); 02542 02543 return *pstatus; 02544 } 02545 02546 /* If the lock list has become zero; decrement the pin ref count pt placed */ 02547 if(glist_empty(&pentry->object.file.lock_list)) 02548 cache_inode_dec_pin_ref(pentry); 02549 02550 02551 /* Unlocking the entire region will remove any FSAL locks we held, whether 02552 * from fully granted locks, or from blocking locks that were in the process 02553 * of being granted. 02554 */ 02555 *pstatus = do_lock_op(pentry, 02556 pcontext, 02557 pexport, 02558 FSAL_OP_UNLOCK, 02559 powner, 02560 plock, 02561 NULL, /* no conflict expected */ 02562 NULL, 02563 FALSE); 02564 02565 if(*pstatus != STATE_SUCCESS) 02566 LogMajor(COMPONENT_STATE, 02567 "Unable to unlock FSAL, error=%s", 02568 state_err_str(*pstatus)); 02569 02570 LogFullDebug(COMPONENT_STATE, 02571 "----------------------------------------------------------------------"); 02572 LogLock(COMPONENT_STATE, NIV_FULL_DEBUG, 02573 "Done", pentry, pcontext, powner, plock); 02574 LogFullDebug(COMPONENT_STATE, 02575 "----------------------------------------------------------------------"); 02576 02577 if(isFullDebug(COMPONENT_STATE) && 02578 isFullDebug(COMPONENT_MEMLEAKS) && 02579 plock->lock_start == 0 && plock->lock_length == 0) 02580 empty = LogList("Lock List", pentry, &pentry->object.file.lock_list); 02581 02582 #ifdef _USE_BLOCKING_LOCKS 02583 grant_blocked_locks(pentry, pcontext); 02584 #endif 02585 02586 pthread_rwlock_unlock(&pentry->state_lock); 02587 02588 cache_inode_dec_pin_ref(pentry); 02589 02590 if(isFullDebug(COMPONENT_STATE) && 02591 isFullDebug(COMPONENT_MEMLEAKS) && 02592 plock->lock_start == 0 && plock->lock_length == 0 && 02593 empty) 02594 dump_all_locks("All locks (after unlock)"); 02595 02596 return *pstatus; 02597 } 02598 02599 #ifdef _USE_BLOCKING_LOCKS 02600 02606 state_status_t state_cancel(cache_entry_t * pentry, 02607 fsal_op_context_t * pcontext, 02608 exportlist_t * pexport, 02609 state_owner_t * powner, 02610 fsal_lock_param_t * plock, 02611 state_status_t * pstatus) 02612 { 02613 struct glist_head * glist; 02614 state_lock_entry_t * found_entry; 02615 cache_inode_status_t cache_status; 02616 02617 if(pentry->type != REGULAR_FILE) 02618 { 02619 LogLock(COMPONENT_STATE, NIV_DEBUG, 02620 "Bad Cancel", 02621 pentry, pcontext, powner, plock); 02622 *pstatus = STATE_BAD_TYPE; 02623 return *pstatus; 02624 } 02625 02626 *pstatus = STATE_NOT_FOUND; 02627 02628 cache_status = cache_inode_inc_pin_ref(pentry); 02629 02630 if(cache_status != CACHE_INODE_SUCCESS) 02631 { 02632 *pstatus = cache_inode_status_to_state_status(cache_status); 02633 LogDebug(COMPONENT_STATE, 02634 "Could not pin file"); 02635 return *pstatus; 02636 } 02637 02638 pthread_rwlock_wrlock(&pentry->state_lock); 02639 02640 /* If lock list is empty, there really isn't any work for us to do. */ 02641 if(glist_empty(&pentry->object.file.lock_list)) 02642 { 02643 pthread_rwlock_unlock(&pentry->state_lock); 02644 02645 cache_inode_dec_pin_ref(pentry); 02646 LogDebug(COMPONENT_STATE, 02647 "Cancel success on file with no locks"); 02648 02649 *pstatus = STATE_SUCCESS; 02650 return *pstatus; 02651 } 02652 02653 glist_for_each(glist, &pentry->object.file.lock_list) 02654 { 02655 found_entry = glist_entry(glist, state_lock_entry_t, sle_list); 02656 02657 if(different_owners(found_entry->sle_owner, powner)) 02658 continue; 02659 02660 /* Can not cancel a lock once it is granted */ 02661 if(found_entry->sle_blocked == STATE_NON_BLOCKING) 02662 continue; 02663 02664 if(different_lock(&found_entry->sle_lock, plock)) 02665 continue; 02666 02667 /* Cancel the blocked lock */ 02668 *pstatus = cancel_blocked_lock(pentry, pcontext, found_entry); 02669 02670 /* Check to see if we can grant any blocked locks. */ 02671 grant_blocked_locks(pentry, pcontext); 02672 02673 break; 02674 } 02675 02676 /* If the lock list has become zero; decrement the pin ref count pt placed */ 02677 if(glist_empty(&pentry->object.file.lock_list)) 02678 cache_inode_dec_pin_ref(pentry); 02679 02680 pthread_rwlock_unlock(&pentry->state_lock); 02681 02682 cache_inode_dec_pin_ref(pentry); 02683 02684 return *pstatus; 02685 } 02686 #endif 02687 02688 #ifdef _USE_NLM 02689 02697 state_status_t state_nlm_notify(state_nsm_client_t * pnsmclient, 02698 state_t * pstate, 02699 state_status_t * pstatus) 02700 { 02701 state_owner_t * powner; 02702 state_lock_entry_t * found_entry; 02703 exportlist_t * pexport; 02704 fsal_lock_param_t lock; 02705 cache_entry_t * pentry; 02706 int errcnt = 0; 02707 struct glist_head newlocks; 02708 fsal_op_context_t fsal_context; 02709 fsal_status_t fsal_status; 02710 state_nlm_share_t * found_share; 02711 02712 if(isFullDebug(COMPONENT_STATE)) 02713 { 02714 char client[HASHTABLE_DISPLAY_STRLEN]; 02715 02716 display_nsm_client(pnsmclient, client); 02717 02718 LogFullDebug(COMPONENT_STATE, 02719 "state_nlm_notify for %s", client); 02720 } 02721 02722 init_glist(&newlocks); 02723 02724 /* First remove byte range locks. 02725 * Only accept so many errors before giving up. 02726 */ 02727 while(errcnt < STATE_ERR_MAX) 02728 { 02729 P(pnsmclient->ssc_mutex); 02730 02731 /* We just need to find any file this client has locks on. 02732 * We pick the first lock the client holds, and use it's file. 02733 */ 02734 found_entry = glist_first_entry(&pnsmclient->ssc_lock_list, 02735 state_lock_entry_t, 02736 sle_client_locks); 02737 02738 /* If we don't find any entries, then we are done. */ 02739 if(found_entry == NULL) 02740 { 02741 V(pnsmclient->ssc_mutex); 02742 break; 02743 } 02744 02745 /* Get a reference so the lock entry will still be valid when we release the ssc_mutex */ 02746 lock_entry_inc_ref(found_entry); 02747 02748 /* Remove from the client lock list */ 02749 glist_del(&found_entry->sle_client_locks); 02750 02751 if(found_entry->sle_state == pstate) 02752 { 02753 /* This is a new lock acquired since the client rebooted, retain it. */ 02754 LogEntry("Don't release new lock", found_entry); 02755 glist_add_tail(&newlocks, &found_entry->sle_client_locks); 02756 V(pnsmclient->ssc_mutex); 02757 continue; 02758 } 02759 02760 LogEntry("Release client locks based on", found_entry); 02761 02762 /* Move this entry to the end of the list (this will help if errors occur) */ 02763 glist_add_tail(&pnsmclient->ssc_lock_list, &found_entry->sle_client_locks); 02764 02765 V(pnsmclient->ssc_mutex); 02766 02767 /* Extract the cache inode entry from the lock entry and release the lock entry */ 02768 pentry = found_entry->sle_pentry; 02769 powner = found_entry->sle_owner; 02770 pexport = found_entry->sle_pexport; 02771 02772 pthread_rwlock_wrlock(&pentry->state_lock); 02773 02774 lock_entry_dec_ref(found_entry); 02775 02776 pthread_rwlock_unlock(&pentry->state_lock); 02777 02778 /* Make lock that covers the whole file - type doesn't matter for unlock */ 02779 lock.lock_type = FSAL_LOCK_R; 02780 lock.lock_start = 0; 02781 lock.lock_length = 0; 02782 02783 /* construct the fsal context based on the export and root credential */ 02784 fsal_status = FSAL_GetClientContext(&fsal_context, 02785 &pexport->FS_export_context, 02786 0, 02787 0, 02788 NULL, 02789 0); 02790 if(FSAL_IS_ERROR(fsal_status)) 02791 { 02792 /* log error here , and continue? */ 02793 LogDebug(COMPONENT_STATE, 02794 "FSAL_GetClientConext failed"); 02795 continue; 02796 } 02797 02798 /* Make sure we hold an lru ref to the cache inode while calling unlock */ 02799 if(cache_inode_lru_ref(pentry, 0) != CACHE_INODE_SUCCESS) 02800 LogCrit(COMPONENT_STATE, 02801 "Ugliness - cache_inode_lru_ref has returned non-success"); 02802 02803 /* Remove all locks held by this NLM Client on the file */ 02804 if(state_unlock(pentry, 02805 &fsal_context, 02806 pexport, 02807 powner, 02808 pstate, 02809 &lock, 02810 pstatus) != STATE_SUCCESS) 02811 { 02812 /* Increment the error count and try the next lock, with any luck 02813 * the memory pressure which is causing the problem will resolve itself. 02814 */ 02815 LogFullDebug(COMPONENT_STATE, 02816 "state_unlock returned %s", 02817 state_err_str(*pstatus)); 02818 errcnt++; 02819 } 02820 02821 /* Release the lru ref to the cache inode we held while calling unlock */ 02822 cache_inode_lru_unref(pentry, 0); 02823 } 02824 02825 /* Now remove NLM_SHARE reservations. 02826 * Only accept so many errors before giving up. 02827 */ 02828 while(errcnt < STATE_ERR_MAX) 02829 { 02830 P(pnsmclient->ssc_mutex); 02831 02832 /* We just need to find any file this client has locks on. 02833 * We pick the first lock the client holds, and use it's file. 02834 */ 02835 found_share = glist_first_entry(&pnsmclient->ssc_share_list, 02836 state_nlm_share_t, 02837 sns_share_per_client); 02838 02839 /* If we don't find any entries, then we are done. */ 02840 if(found_share == NULL) 02841 { 02842 V(pnsmclient->ssc_mutex); 02843 break; 02844 } 02845 02846 /* Extract the cache inode entry from the share */ 02847 pentry = found_share->sns_pentry; 02848 powner = found_share->sns_powner; 02849 pexport = found_share->sns_pexport; 02850 02851 /* get a reference to the owner */ 02853 #ifdef FSF 02854 inc_state_owner_ref_locked(powner); 02855 #endif 02856 02857 V(pnsmclient->ssc_mutex); 02858 02859 /* construct the fsal context based on the export and root credential */ 02860 fsal_status = FSAL_GetClientContext(&fsal_context, 02861 &pexport->FS_export_context, 02862 0, 02863 0, 02864 NULL, 02865 0); 02866 if(FSAL_IS_ERROR(fsal_status)) 02867 { 02868 #ifdef FSF 02869 dec_state_owner_ref_locked(powner); 02870 #endif 02871 02872 /* log error here , and continue? */ 02873 LogDebug(COMPONENT_STATE, 02874 "FSAL_GetClientConext failed"); 02875 continue; 02876 } 02877 02878 /* Remove all shares held by this NSM Client and Owner on the file */ 02879 if(state_nlm_unshare(pentry, 02880 &fsal_context, 02881 OPEN4_SHARE_ACCESS_NONE, 02882 OPEN4_SHARE_DENY_NONE, 02883 powner, 02884 pstatus) != STATE_SUCCESS) 02885 { 02886 /* Increment the error count and try the next share, with any luck 02887 * the memory pressure which is causing the problem will resolve itself. 02888 */ 02889 LogFullDebug(COMPONENT_STATE, 02890 "state_nlm_unshare returned %s", 02891 state_err_str(*pstatus)); 02892 errcnt++; 02893 } 02894 02895 #ifdef FSF 02896 dec_state_owner_ref_locked(powner); 02897 #endif 02898 } 02899 02900 /* Put locks from current client incarnation onto end of list */ 02901 P(pnsmclient->ssc_mutex); 02902 glist_add_list_tail(&pnsmclient->ssc_lock_list, &newlocks); 02903 V(pnsmclient->ssc_mutex); 02904 LogFullDebug(COMPONENT_STATE, "DONE"); 02905 02906 return *pstatus; 02907 } 02908 #endif 02909 02915 state_status_t state_owner_unlock_all(fsal_op_context_t * pcontext, 02916 state_owner_t * powner, 02917 state_t * pstate, 02918 state_status_t * pstatus) 02919 { 02920 state_lock_entry_t * found_entry; 02921 exportlist_t * pexport; 02922 fsal_lock_param_t lock; 02923 cache_entry_t * pentry; 02924 int errcnt = 0; 02925 02926 /* Only accept so many errors before giving up. */ 02927 while(errcnt < STATE_ERR_MAX) 02928 { 02929 P(powner->so_mutex); 02930 02931 /* We just need to find any file this owner has locks on. 02932 * We pick the first lock the owner holds, and use it's file. 02933 */ 02934 found_entry = glist_first_entry(&powner->so_lock_list, state_lock_entry_t, sle_owner_locks); 02935 02936 /* If we don't find any entries, then we are done. */ 02937 if((found_entry == NULL) || (found_entry->sle_state != pstate)) 02938 { 02939 V(powner->so_mutex); 02940 break; 02941 } 02942 02943 lock_entry_inc_ref(found_entry); 02944 02945 /* Move this entry to the end of the list (this will help if errors occur) */ 02946 glist_del(&found_entry->sle_owner_locks); 02947 glist_add_tail(&powner->so_lock_list, &found_entry->sle_owner_locks); 02948 02949 V(powner->so_mutex); 02950 02951 /* Extract the cache inode entry from the lock entry and release the lock entry */ 02952 pentry = found_entry->sle_pentry; 02953 pexport = found_entry->sle_pexport; 02954 02955 pthread_rwlock_wrlock(&pentry->state_lock); 02956 02957 lock_entry_dec_ref(found_entry); 02958 02959 pthread_rwlock_unlock(&pentry->state_lock); 02960 02961 /* Make lock that covers the whole file - type doesn't matter for unlock */ 02962 lock.lock_type = FSAL_LOCK_R; 02963 lock.lock_start = 0; 02964 lock.lock_length = 0; 02965 02966 /* Make sure we hold an lru ref to the cache inode while calling unlock */ 02967 if(cache_inode_lru_ref(pentry, 0) != CACHE_INODE_SUCCESS) 02968 LogCrit(COMPONENT_STATE, 02969 "Ugliness - cache_inode_lru_ref has returned non-success"); 02970 02971 /* Remove all locks held by this owner on the file */ 02972 if(state_unlock(pentry, 02973 pcontext, 02974 pexport, 02975 powner, 02976 pstate, 02977 &lock, 02978 pstatus) != STATE_SUCCESS) 02979 { 02980 /* Increment the error count and try the next lock, with any luck 02981 * the memory pressure which is causing the problem will resolve itself. 02982 */ 02983 LogDebug(COMPONENT_STATE, 02984 "state_unlock failed %s", 02985 state_err_str(*pstatus)); 02986 errcnt++; 02987 } 02988 02989 /* Release the lru ref to the cache inode we held while calling unlock */ 02990 cache_inode_lru_unref(pentry, 0); 02991 } 02992 return *pstatus; 02993 } 02994 02995 #ifdef _USE_BLOCKING_LOCKS 02996 02997 void find_blocked_lock_upcall(cache_entry_t * pentry, 02998 void * powner, 02999 fsal_lock_param_t * plock, 03000 state_grant_type_t grant_type) 03001 { 03002 state_lock_entry_t * found_entry; 03003 struct glist_head * glist; 03004 state_block_data_t * pblock; 03005 03006 P(blocked_locks_mutex); 03007 03008 glist_for_each(glist, &state_blocked_locks) 03009 { 03010 pblock = glist_entry(glist, state_block_data_t, sbd_list); 03011 03012 found_entry = pblock->sbd_lock_entry; 03013 03014 /* Check if for same file */ 03015 if(found_entry->sle_pentry != pentry) 03016 continue; 03017 03018 /* Check if for same owner */ 03019 if(found_entry->sle_owner != powner) 03020 continue; 03021 03022 /* Check if same lock */ 03023 if(different_lock(&found_entry->sle_lock, plock)) 03024 continue; 03025 03026 /* Put lock on list of locks granted by FSAL */ 03027 glist_del(&pblock->sbd_list); 03028 glist_add_tail(&state_notified_locks, &pblock->sbd_list); 03029 pblock->sbd_grant_type = grant_type; 03030 03031 LogEntry("Blocked Lock found", found_entry); 03032 03033 V(blocked_locks_mutex); 03034 03035 signal_async_work(); 03036 03037 return; 03038 } /* glist_for_each_safe */ 03039 03040 if(isFullDebug(COMPONENT_STATE) && 03041 isFullDebug(COMPONENT_MEMLEAKS)) 03042 LogBlockedList("Blocked Lock List", NULL, &state_blocked_locks); 03043 03044 V(blocked_locks_mutex); 03045 03046 if(isFullDebug(COMPONENT_STATE) && 03047 isFullDebug(COMPONENT_MEMLEAKS)) 03048 { 03049 pthread_rwlock_rdlock(&pentry->state_lock); 03050 03051 LogList("File Lock List", pentry, &pentry->object.file.lock_list); 03052 03053 pthread_rwlock_unlock(&pentry->state_lock); 03054 } 03055 03056 /* We must be out of sync with FSAL, this is fatal */ 03057 LogLockDesc(COMPONENT_STATE, NIV_MAJOR, 03058 "Blocked Lock Not Found for", pentry, powner, plock); 03059 LogFatal(COMPONENT_STATE, "Locks out of sync with FSAL"); 03060 } 03061 03067 void grant_blocked_lock_upcall(cache_entry_t * pentry, 03068 void * powner, 03069 fsal_lock_param_t * plock) 03070 { 03071 LogLockDesc(COMPONENT_STATE, NIV_DEBUG, 03072 "Grant Upcall for", pentry, powner, plock); 03073 03074 find_blocked_lock_upcall(pentry, powner, plock, STATE_GRANT_FSAL); 03075 } 03076 03082 void available_blocked_lock_upcall(cache_entry_t * pentry, 03083 void * powner, 03084 fsal_lock_param_t * plock) 03085 { 03086 LogLockDesc(COMPONENT_STATE, NIV_DEBUG, 03087 "Available Upcall for", pentry, powner, plock); 03088 03089 find_blocked_lock_upcall(pentry, powner, plock, STATE_GRANT_FSAL_AVAILABLE); 03090 } 03091 03092 #endif 03093 03094 void state_lock_wipe(cache_entry_t * pentry) 03095 { 03096 if(glist_empty(&pentry->object.file.lock_list)) 03097 return; 03098 03099 free_list(&pentry->object.file.lock_list); 03100 03101 cache_inode_dec_pin_ref(pentry); 03102 }