nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=8:tabstop=8: 00003 * 00004 * Copyright CEA/DAM/DIF (2008) 00005 * contributeur : Philippe DENIEL philippe.deniel@cea.fr 00006 * Thomas LEIBOVICI thomas.leibovici@cea.fr 00007 * 00008 * 00009 * This program is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 3 of the License, or (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 * 00023 * --------------------------------------- 00024 */ 00025 00037 #ifdef HAVE_CONFIG_H 00038 #include "config.h" 00039 #endif 00040 00041 #ifdef _SOLARIS 00042 #include "solaris_port.h" 00043 #endif 00044 00045 #include <stdio.h> 00046 #include <string.h> 00047 #include <pthread.h> 00048 #include "HashData.h" 00049 #include "HashTable.h" 00050 #include "log.h" 00051 #include "ganesha_rpc.h" 00052 #include "nfs4.h" 00053 #include "nfs_core.h" 00054 #include "sal_functions.h" 00055 #include "nfs_proto_functions.h" 00056 #include "nfs_proto_tools.h" 00057 #include "nlm_list.h" 00058 00076 #define arg_LOCK4 op->nfs_argop4_u.oplock 00077 #define res_LOCK4 resp->nfs_resop4_u.oplock 00078 00079 int nfs41_op_lock(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) 00080 { 00081 state_status_t state_status; 00082 state_data_t candidate_data; 00083 state_type_t candidate_type; 00084 int rc = 0; 00085 state_t * plock_state; /* state for the lock */ 00086 state_t * pstate_open; /* state for the open owner */ 00087 state_owner_t * plock_owner; 00088 state_owner_t * popen_owner; 00089 state_owner_t * conflict_owner = NULL; 00090 state_nfs4_owner_name_t owner_name; 00091 fsal_lock_param_t lock_desc, conflict_desc; 00092 state_blocking_t blocking = STATE_NON_BLOCKING; 00093 const char * tag = "LOCK"; 00094 00095 LogDebug(COMPONENT_NFS_V4_LOCK, 00096 "Entering NFS v4.1 LOCK handler -----------------------------------------------------"); 00097 00098 /* Initialize to sane starting values */ 00099 resp->resop = NFS4_OP_LOCK; 00100 res_LOCK4.status = NFS4_OK; 00101 00102 /* 00103 * Do basic checks on a filehandle 00104 * Lock is done only on a file 00105 */ 00106 res_LOCK4.status = nfs4_sanity_check_FH(data, REGULAR_FILE); 00107 if(res_LOCK4.status != NFS4_OK) 00108 return res_LOCK4.status; 00109 00110 /* Convert lock parameters to internal types */ 00111 switch(arg_LOCK4.locktype) 00112 { 00113 case READ_LT: 00114 lock_desc.lock_type = FSAL_LOCK_R; 00115 blocking = STATE_NON_BLOCKING; 00116 break; 00117 00118 case WRITE_LT: 00119 lock_desc.lock_type = FSAL_LOCK_W; 00120 blocking = STATE_NON_BLOCKING; 00121 break; 00122 00123 case READW_LT: 00124 lock_desc.lock_type = FSAL_LOCK_R; 00125 blocking = STATE_NFSV4_BLOCKING; 00126 break; 00127 00128 case WRITEW_LT: 00129 lock_desc.lock_type = FSAL_LOCK_W; 00130 blocking = STATE_NFSV4_BLOCKING; 00131 break; 00132 } 00133 00134 lock_desc.lock_start = arg_LOCK4.offset; 00135 00136 if(arg_LOCK4.length != STATE_LOCK_OFFSET_EOF) 00137 lock_desc.lock_length = arg_LOCK4.length; 00138 else 00139 lock_desc.lock_length = 0; 00140 00141 if(arg_LOCK4.locker.new_lock_owner) 00142 { 00143 /* New lock owner, Find the open owner */ 00144 tag = "LOCK (new owner)"; 00145 00146 /* Check stateid correctness and get pointer to state */ 00147 if((rc = nfs4_Check_Stateid(&arg_LOCK4.locker.locker4_u.open_owner.open_stateid, 00148 data->current_entry, 00149 &pstate_open, 00150 data, 00151 STATEID_SPECIAL_FOR_LOCK, 00152 tag)) != NFS4_OK) 00153 { 00154 res_LOCK4.status = rc; 00155 LogDebug(COMPONENT_NFS_V4_LOCK, 00156 "LOCK failed nfs4_Check_Stateid for open owner"); 00157 return res_LOCK4.status; 00158 } 00159 00160 popen_owner = pstate_open->state_powner; 00161 plock_state = NULL; 00162 plock_owner = NULL; 00163 00164 LogLock(COMPONENT_NFS_V4_LOCK, NIV_FULL_DEBUG, 00165 "LOCK New lock owner from open owner", 00166 data->current_entry, 00167 data->pcontext, 00168 popen_owner, 00169 &lock_desc); 00170 00171 /* An open state has been found. Check its type */ 00172 if(pstate_open->state_type != STATE_TYPE_SHARE) 00173 { 00174 res_LOCK4.status = NFS4ERR_BAD_STATEID; 00175 LogDebug(COMPONENT_NFS_V4_LOCK, 00176 "LOCK failed open stateid is not a SHARE"); 00177 return res_LOCK4.status; 00178 } 00179 00180 /* Is this lock_owner known ? */ 00181 convert_nfs4_lock_owner(&arg_LOCK4.locker.locker4_u.open_owner.lock_owner, 00182 &owner_name, data->psession->clientid); 00183 } 00184 else 00185 { 00186 /* Existing lock owner 00187 * Find the lock stateid 00188 * From that, get the open_owner 00189 */ 00190 tag = "LOCK (existing owner)"; 00191 00192 /* There was code here before to handle all-0 stateid, but that 00193 * really doesn't apply - when we handle temporary locks for 00194 * I/O operations (which is where we will see all-0 or all-1 00195 * stateid, those will not come in through nfs4_op_lock. 00196 */ 00197 00198 /* Check stateid correctness and get pointer to state */ 00199 if((rc = nfs4_Check_Stateid(&arg_LOCK4.locker.locker4_u.lock_owner.lock_stateid, 00200 data->current_entry, 00201 &plock_state, 00202 data, 00203 STATEID_SPECIAL_FOR_LOCK, 00204 tag)) != NFS4_OK) 00205 { 00206 res_LOCK4.status = rc; 00207 LogDebug(COMPONENT_NFS_V4_LOCK, 00208 "LOCK failed nfs4_Check_Stateid for existing lock owner"); 00209 return res_LOCK4.status; 00210 } 00211 00212 /* Check if lock state belongs to same export */ 00213 if(plock_state->state_pexport != data->pexport) 00214 { 00215 LogEvent(COMPONENT_STATE, 00216 "Lock Owner Export Conflict, Lock held for export %d (%s), request for export %d (%s)", 00217 plock_state->state_pexport->id, 00218 plock_state->state_pexport->fullpath, 00219 data->pexport->id, 00220 data->pexport->fullpath); 00221 res_LOCK4.status = STATE_INVALID_ARGUMENT; 00222 return res_LOCK4.status; 00223 } 00224 00225 /* An lock state has been found. Check its type */ 00226 if(plock_state->state_type != STATE_TYPE_LOCK) 00227 { 00228 res_LOCK4.status = NFS4ERR_BAD_STATEID; 00229 LogDebug(COMPONENT_NFS_V4_LOCK, 00230 "LOCK failed existing lock owner, state type is not LOCK"); 00231 return res_LOCK4.status; 00232 } 00233 00234 /* Get the old lockowner. We can do the following 'cast', in NFSv4 lock_owner4 and open_owner4 00235 * are different types but with the same definition*/ 00236 plock_owner = plock_state->state_powner; 00237 popen_owner = plock_owner->so_owner.so_nfs4_owner.so_related_owner; 00238 pstate_open = plock_state->state_data.lock.popenstate; 00239 00240 LogLock(COMPONENT_NFS_V4_LOCK, NIV_FULL_DEBUG, 00241 "LOCK Existing lock owner", 00242 data->current_entry, 00243 data->pcontext, 00244 plock_owner, 00245 &lock_desc); 00246 } /* if( arg_LOCK4.locker.new_lock_owner ) */ 00247 00248 /* Lock length should not be 0 */ 00249 if(arg_LOCK4.length == 0LL) 00250 { 00251 res_LOCK4.status = NFS4ERR_INVAL; 00252 LogDebug(COMPONENT_NFS_V4_LOCK, 00253 "LOCK failed length == 0"); 00254 00255 return res_LOCK4.status; 00256 } 00257 00258 /* Check for range overflow. 00259 * Comparing beyond 2^64 is not possible int 64 bits precision, 00260 * but off+len > 2^64-1 is equivalent to len > 2^64-1 - off 00261 */ 00262 if(lock_desc.lock_length > (STATE_LOCK_OFFSET_EOF - lock_desc.lock_start)) 00263 { 00264 res_LOCK4.status = NFS4ERR_INVAL; 00265 LogDebug(COMPONENT_NFS_V4_LOCK, 00266 "LOCK failed length overflow"); 00267 00268 return res_LOCK4.status; 00269 } 00270 00271 /* check if open state has correct access for type of lock. 00272 * Don't need to check for conflicting states since this open 00273 * state assures there are no conflicting states. 00274 */ 00275 if(((arg_LOCK4.locktype == WRITE_LT || arg_LOCK4.locktype == WRITEW_LT) && 00276 ((pstate_open->state_data.share.share_access & OPEN4_SHARE_ACCESS_WRITE) == 0)) || 00277 ((arg_LOCK4.locktype == READ_LT || arg_LOCK4.locktype == READW_LT) && 00278 ((pstate_open->state_data.share.share_access & OPEN4_SHARE_ACCESS_READ) == 0))) 00279 { 00280 /* The open state doesn't allow access based on the type of lock */ 00281 LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG, 00282 "LOCK failed, SHARE doesn't allow access", 00283 data->current_entry, 00284 data->pcontext, 00285 plock_owner, 00286 &lock_desc); 00287 00288 res_LOCK4.status = NFS4ERR_OPENMODE; 00289 return res_LOCK4.status; 00290 } 00291 00292 /* 00293 * do grace period checking 00294 */ 00295 if (nfs_in_grace() && !arg_LOCK4.reclaim) 00296 { 00297 LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG, 00298 "LOCK failed, non-reclaim while in grace", 00299 data->current_entry, 00300 data->pcontext, 00301 plock_owner, 00302 &lock_desc); 00303 res_LOCK4.status = NFS4ERR_GRACE; 00304 return res_LOCK4.status; 00305 } 00306 00307 if (nfs_in_grace() && arg_LOCK4.reclaim && 00308 !data->psession->pclientid_record->cid_allow_reclaim) 00309 { 00310 LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG, 00311 "LOCK failed, invalid reclaim while in grace", 00312 data->current_entry, 00313 data->pcontext, 00314 plock_owner, 00315 &lock_desc); 00316 res_LOCK4.status = NFS4ERR_NO_GRACE; 00317 return res_LOCK4.status; 00318 } 00319 00320 if (!nfs_in_grace() && arg_LOCK4.reclaim) 00321 { 00322 LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG, 00323 "LOCK failed, reclaim while not in grace", 00324 data->current_entry, 00325 data->pcontext, 00326 plock_owner, 00327 &lock_desc); 00328 res_LOCK4.status = NFS4ERR_NO_GRACE; 00329 return res_LOCK4.status; 00330 } 00331 00332 if(arg_LOCK4.locker.new_lock_owner) 00333 { 00334 /* A lock owner is always associated with a previously made open 00335 * which has itself a previously made stateid 00336 */ 00337 00338 if(nfs4_owner_Get_Pointer(&owner_name, &plock_owner)) 00339 { 00340 /* Lock owner already exists. */ 00341 if(plock_owner->so_owner.so_nfs4_owner.so_related_owner == NULL) 00342 { 00343 /* Attach open owner to lock owner now that we know it. */ 00344 inc_state_owner_ref(popen_owner); 00345 plock_owner->so_owner.so_nfs4_owner.so_related_owner = popen_owner; 00346 } 00347 else if(plock_owner->so_owner.so_nfs4_owner.so_related_owner != popen_owner) 00348 { 00349 res_LOCK4.status = NFS4ERR_INVAL; 00350 LogDebug(COMPONENT_NFS_V4_LOCK, 00351 "LOCK failed related owner %p doesn't match open owner %p", 00352 plock_owner->so_owner.so_nfs4_owner.so_related_owner, 00353 popen_owner); 00354 return res_LOCK4.status; 00355 } 00356 } 00357 else 00358 { 00359 /* This lock owner is not known yet, allocated and set up a new one */ 00360 plock_owner = create_nfs4_owner(&owner_name, 00361 data->psession->pclientid_record, 00362 STATE_LOCK_OWNER_NFSV4, 00363 popen_owner, 00364 0); 00365 00366 if(plock_owner == NULL) 00367 { 00368 res_LOCK4.status = NFS4ERR_RESOURCE; 00369 00370 LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG, 00371 "LOCK failed to create new lock owner", 00372 data->current_entry, 00373 data->pcontext, 00374 popen_owner, 00375 &lock_desc); 00376 00377 return res_LOCK4.status; 00378 } 00379 } 00380 00381 /* Prepare state management structure */ 00382 memset(&candidate_type, 0, sizeof(candidate_type)); 00383 candidate_type = STATE_TYPE_LOCK; 00384 candidate_data.lock.popenstate = pstate_open; 00385 00386 /* Add the lock state to the lock table */ 00387 if(state_add(data->current_entry, 00388 candidate_type, 00389 &candidate_data, 00390 plock_owner, 00391 data->pcontext, 00392 &plock_state, &state_status) != STATE_SUCCESS) 00393 { 00394 res_LOCK4.status = NFS4ERR_RESOURCE; 00395 00396 LogLock(COMPONENT_NFS_V4_LOCK, NIV_DEBUG, 00397 "LOCK failed to add new stateid", 00398 data->current_entry, 00399 data->pcontext, 00400 plock_owner, 00401 &lock_desc); 00402 00403 dec_state_owner_ref(plock_owner); 00404 00405 return res_LOCK4.status; 00406 } 00407 00408 init_glist(&plock_state->state_data.lock.state_locklist); 00409 00410 /* Attach this lock to an export */ 00411 plock_state->state_pexport = data->pexport; 00412 P(data->pexport->exp_state_mutex); 00413 glist_add_tail(&data->pexport->exp_state_list, &plock_state->state_export_list); 00414 V(data->pexport->exp_state_mutex); 00415 00416 /* Add lock state to the list of lock states belonging to the open state */ 00417 glist_add_tail(&pstate_open->state_data.share.share_lockstates, 00418 &plock_state->state_data.lock.state_sharelist); 00419 } /* if( arg_LOCK4.locker.new_lock_owner ) */ 00420 00421 /* Now we have a lock owner and a stateid. 00422 * Go ahead and push lock into SAL (and FSAL). 00423 */ 00424 if(state_lock(data->current_entry, 00425 data->pcontext, 00426 data->pexport, 00427 plock_owner, 00428 plock_state, 00429 blocking, 00430 NULL, /* No block data for now */ 00431 &lock_desc, 00432 &conflict_owner, 00433 &conflict_desc, 00434 &state_status) != STATE_SUCCESS) 00435 { 00436 if(state_status == STATE_LOCK_CONFLICT) 00437 { 00438 /* A conflicting lock from a different lock_owner, returns NFS4ERR_DENIED */ 00439 Process_nfs4_conflict(&res_LOCK4.LOCK4res_u.denied, 00440 conflict_owner, 00441 &conflict_desc); 00442 } 00443 00444 LogDebug(COMPONENT_NFS_V4_LOCK, 00445 "LOCK failed with status %s", 00446 state_err_str(state_status)); 00447 00448 res_LOCK4.status = nfs4_Errno_state(state_status); 00449 00450 if(arg_LOCK4.locker.new_lock_owner) 00451 { 00452 /* Need to destroy lock owner and state */ 00453 if(state_del(plock_state, 00454 &state_status) != STATE_SUCCESS) 00455 LogDebug(COMPONENT_NFS_V4_LOCK, 00456 "state_del failed with status %s", 00457 state_err_str(state_status)); 00458 } 00459 00460 return res_LOCK4.status; 00461 } 00462 00463 res_LOCK4.status = NFS4_OK; 00464 00465 /* Handle stateid/seqid for success */ 00466 update_stateid(plock_state, 00467 &res_LOCK4.LOCK4res_u.resok4.lock_stateid, 00468 data, 00469 tag); 00470 00471 LogFullDebug(COMPONENT_NFS_V4_LOCK, 00472 "LOCK state_seqid = %u, plock_state = %p", 00473 plock_state->state_seqid, 00474 plock_state); 00475 00476 LogLock(COMPONENT_NFS_V4_LOCK, NIV_FULL_DEBUG, 00477 "LOCK applied", 00478 data->current_entry, 00479 data->pcontext, 00480 plock_owner, 00481 &lock_desc); 00482 00483 return res_LOCK4.status; 00484 00485 } /* nfs41_op_lock */ 00486 00497 void nfs41_op_lock_Free(LOCK4res * resp) 00498 { 00499 if(resp->status == NFS4ERR_DENIED) 00500 Release_nfs4_denied(&resp->LOCK4res_u.denied); 00501 return; 00502 } /* nfs41_op_lock_Free */