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 "cache_inode_lru.h" 00058 00072 #define arg_OPEN4 op->nfs_argop4_u.opopen 00073 #define res_OPEN4 resp->nfs_resop4_u.opopen 00074 00075 int nfs41_op_open(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) 00076 { 00077 cache_entry_t * pentry_parent = NULL; 00078 cache_entry_t * pentry_lookup = NULL; 00079 cache_entry_t * pentry_newfile = NULL; 00080 fsal_handle_t * pnewfsal_handle = NULL; 00081 fsal_attrib_list_t attr_parent; 00082 fsal_attrib_list_t attr; 00083 fsal_attrib_list_t attr_newfile; 00084 fsal_attrib_list_t sattr; 00085 fsal_openflags_t openflags = 0; 00086 cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; 00087 state_status_t state_status; 00088 int retval; 00089 fsal_name_t filename; 00090 bool_t AttrProvided = FALSE; 00091 bool_t ReuseState = FALSE; 00092 fsal_accessmode_t mode = 0600; 00093 nfs_fh4 newfh4; 00094 struct alloc_file_handle_v4 new_handle; 00095 state_data_t candidate_data; 00096 state_type_t candidate_type; 00097 state_t * pfile_state = NULL; 00098 state_t * pstate_iterate; 00099 state_nfs4_owner_name_t owner_name; 00100 state_owner_t * powner = NULL; 00101 const char * tag = "OPEN"; 00102 const char * cause = "OOPS"; 00103 const char * cause2 = ""; 00104 struct glist_head * glist; 00105 #ifdef _USE_QUOTA 00106 fsal_status_t fsal_status ; 00107 #endif 00108 00109 LogDebug(COMPONENT_STATE, 00110 "Entering NFS v4.1 OPEN handler -----------------------------------------------------"); 00111 00112 newfh4.nfs_fh4_val = (caddr_t) &new_handle; 00113 newfh4.nfs_fh4_len = sizeof(struct alloc_file_handle_v4); 00114 00115 fsal_accessflags_t write_access = FSAL_WRITE_ACCESS; 00116 fsal_accessflags_t read_access = FSAL_READ_ACCESS; 00117 00118 resp->resop = NFS4_OP_OPEN; 00119 res_OPEN4.status = NFS4_OK; 00120 00121 uint32_t tmp_attr[2]; 00122 00123 cache_inode_create_arg_t create_arg = { 00124 .newly_created_dir = FALSE 00125 }; 00126 00127 memset(&create_arg, 0, sizeof(create_arg)); 00128 00129 /* 00130 * Do basic checks on a filehandle 00131 */ 00132 res_OPEN4.status = nfs4_sanity_check_FH(data, 0LL); 00133 if(res_OPEN4.status != NFS4_OK) 00134 goto out; 00135 00136 /* This can't be done on the pseudofs */ 00137 if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) 00138 { 00139 res_OPEN4.status = NFS4ERR_ROFS; 00140 LogDebug(COMPONENT_STATE, 00141 "NFS41 OPEN returning NFS4ERR_ROFS"); 00142 goto out; 00143 } 00144 00145 /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */ 00146 if(nfs4_Is_Fh_Xattr(&(data->currentFH))) { 00147 res_OPEN4.status = nfs4_op_open_xattr(op, data, resp); 00148 goto out; 00149 } 00150 00151 /* If data->current_entry is empty, repopulate it */ 00152 if(data->current_entry == NULL) 00153 { 00154 if((data->current_entry = nfs_FhandleToCache(NFS_V4, 00155 NULL, 00156 NULL, 00157 &(data->currentFH), 00158 NULL, 00159 NULL, 00160 &(res_OPEN4.status), 00161 &attr, 00162 data->pcontext, 00163 &retval)) == NULL) 00164 { 00165 res_OPEN4.status = NFS4ERR_RESOURCE; 00166 LogDebug(COMPONENT_STATE, 00167 "NFS41 OPEN returning NFS4ERR_RESOURCE after trying to repopulate cache"); 00168 goto out; 00169 } 00170 } 00171 00172 /* Set parent */ 00173 pentry_parent = data->current_entry; 00174 00175 /* First switch is based upon claim type */ 00176 switch (arg_OPEN4.claim.claim) 00177 { 00178 case CLAIM_DELEGATE_CUR: 00179 case CLAIM_DELEGATE_PREV: 00180 /* Check for name length */ 00181 if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len > FSAL_MAX_NAME_LEN) 00182 { 00183 res_OPEN4.status = NFS4ERR_NAMETOOLONG; 00184 LogDebug(COMPONENT_STATE, 00185 "NFS41 OPEN returning NFS4ERR_NAMETOOLONG for CLAIM_DELEGATE"); 00186 goto out; 00187 } 00188 00189 /* get the filename from the argument, it should not be empty */ 00190 if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len == 0) 00191 { 00192 res_OPEN4.status = NFS4ERR_INVAL; 00193 LogDebug(COMPONENT_STATE, 00194 "NFS41 OPEN returning NFS4ERR_INVAL for CLAIM_DELEGATE"); 00195 goto out; 00196 } 00197 00198 res_OPEN4.status = NFS4ERR_NOTSUPP; 00199 LogDebug(COMPONENT_STATE, 00200 "NFS41 OPEN returning NFS4ERR_NOTSUPP for CLAIM_DELEGATE"); 00201 goto out; 00202 00203 case CLAIM_NULL: 00204 cause = "CLAIM_NULL"; 00205 00206 /* Is this open_owner known? If so, get it so we can use replay cache */ 00207 convert_nfs4_open_owner(&arg_OPEN4.owner, 00208 &owner_name, 00209 data->psession->clientid); 00210 00211 if(!nfs4_owner_Get_Pointer(&owner_name, &powner)) 00212 { 00213 LogFullDebug(COMPONENT_STATE, 00214 "OPEN new owner"); 00215 } 00216 else 00217 { 00218 if(isFullDebug(COMPONENT_STATE)) 00219 { 00220 char str[HASHTABLE_DISPLAY_STRLEN]; 00221 00222 display_nfs4_owner(powner, str); 00223 00224 LogFullDebug(COMPONENT_STATE, 00225 "A previously known open_owner is used:%p %s arg_OPEN4.seqid=%u", 00226 powner, str, arg_OPEN4.seqid); 00227 } 00228 } 00229 00230 /* Check for name length */ 00231 if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len > FSAL_MAX_NAME_LEN) 00232 { 00233 res_OPEN4.status = NFS4ERR_NAMETOOLONG; 00234 goto out; 00235 } 00236 00237 /* get the filename from the argument, it should not be empty */ 00238 if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len == 0) 00239 { 00240 res_OPEN4.status = NFS4ERR_INVAL; 00241 cause2 = " (empty filename)"; 00242 goto out; 00243 } 00244 00245 /* Check if asked attributes are correct */ 00246 if(arg_OPEN4.openhow.openflag4_u.how.mode == GUARDED4 || 00247 arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4) 00248 { 00249 if(!nfs4_Fattr_Supported 00250 (&arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs)) 00251 { 00252 res_OPEN4.status = NFS4ERR_ATTRNOTSUPP; 00253 goto out; 00254 } 00255 00256 /* Do not use READ attr, use WRITE attr */ 00257 if(!nfs4_Fattr_Check_Access 00258 (&arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs, 00259 FATTR4_ATTR_WRITE)) 00260 { 00261 res_OPEN4.status = NFS4ERR_INVAL; 00262 cause2 = " (bad attr)"; 00263 goto out; 00264 } 00265 } 00266 00267 /* Check if filename is correct */ 00268 if((cache_status = 00269 cache_inode_error_convert(FSAL_buffdesc2name 00270 ((fsal_buffdesc_t *) & arg_OPEN4.claim.open_claim4_u. 00271 file, &filename))) != CACHE_INODE_SUCCESS) 00272 { 00273 res_OPEN4.status = nfs4_Errno(cache_status); 00274 cause2 = " FSAL_buffdesc2name"; 00275 goto out; 00276 } 00277 00278 /* Check parent */ 00279 pentry_parent = data->current_entry; 00280 00281 /* Parent must be a directory */ 00282 if(pentry_parent->type != DIRECTORY) 00283 { 00284 /* Parent object is not a directory... */ 00285 if(pentry_parent->type == SYMBOLIC_LINK) 00286 res_OPEN4.status = NFS4ERR_SYMLINK; 00287 else 00288 res_OPEN4.status = NFS4ERR_NOTDIR; 00289 00290 cause2 = " (parent not directory)"; 00291 goto out; 00292 } 00293 00294 /* What kind of open is it ? */ 00295 LogFullDebug(COMPONENT_STATE, 00296 "OPEN: Claim type = %d Open Type = %d Share Deny = %d Share Access = %d ", 00297 arg_OPEN4.claim.claim, 00298 arg_OPEN4.openhow.opentype, 00299 arg_OPEN4.share_deny, 00300 arg_OPEN4.share_access); 00301 00302 /* It this a known client id ? */ 00303 LogDebug(COMPONENT_STATE, 00304 "OPEN Client id = %llx", 00305 (unsigned long long)arg_OPEN4.owner.clientid); 00306 00307 /* Is this open_owner known ? */ 00308 if(powner == NULL) 00309 { 00310 /* This open owner is not known yet, allocated and set up a new one */ 00311 powner = create_nfs4_owner(&owner_name, 00312 data->psession->pclientid_record, 00313 STATE_OPEN_OWNER_NFSV4, 00314 NULL, 00315 1); /* NFSv4.1 specific, initial seqid is 1 */ 00316 00317 if(powner == NULL) 00318 { 00319 res_OPEN4.status = NFS4ERR_RESOURCE; 00320 LogDebug(COMPONENT_STATE, 00321 "NFS41 OPEN returning NFS4ERR_RESOURCE for CLAIM_NULL (could not create NFS41 Owner"); 00322 goto out; 00323 } 00324 } 00325 00326 /* Status of parent directory before the operation */ 00327 if(cache_inode_getattr(pentry_parent, 00328 &attr_parent, 00329 data->pcontext, 00330 &cache_status) != CACHE_INODE_SUCCESS) 00331 { 00332 res_OPEN4.status = nfs4_Errno(cache_status); 00333 cause2 = " cache_inode_getattr"; 00334 goto out; 00335 } 00336 00337 res_OPEN4.OPEN4res_u.resok4.cinfo.before 00338 = cache_inode_get_changeid4(pentry_parent); 00339 00340 /* CLient may have provided fattr4 to set attributes at creation time */ 00341 if(arg_OPEN4.openhow.openflag4_u.how.mode == GUARDED4 || 00342 arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4) 00343 { 00344 if(arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs.attrmask. 00345 bitmap4_len != 0) 00346 { 00347 /* Convert fattr4 so nfs4_sattr */ 00348 res_OPEN4.status = 00349 nfs4_Fattr_To_FSAL_attr(&sattr, 00350 &(arg_OPEN4.openhow.openflag4_u.how. 00351 createhow4_u.createattrs)); 00352 00353 if(res_OPEN4.status != NFS4_OK) 00354 { 00355 cause2 = " (nfs4_Fattr_To_FSAL_attr failed)"; 00356 goto out; 00357 } 00358 00359 AttrProvided = TRUE; 00360 } 00361 } 00362 00363 /* Second switch is based upon "openhow" */ 00364 switch (arg_OPEN4.openhow.opentype) 00365 { 00366 case OPEN4_CREATE: 00367 /* a new file is to be created */ 00368 #ifdef _USE_QUOTA 00369 /* if quota support is active, then we should check is the FSAL allows inode creation or not */ 00370 fsal_status = FSAL_check_quota( data->pexport->fullpath, 00371 FSAL_QUOTA_INODES, 00372 FSAL_OP_CONTEXT_TO_UID( data->pcontext ) ) ; 00373 if( FSAL_IS_ERROR( fsal_status ) ) 00374 { 00375 res_OPEN4.status = NFS4ERR_DQUOT ; 00376 return res_OPEN4.status; 00377 } 00378 #endif /* _USE_QUOTA */ 00379 00380 if(arg_OPEN4.openhow.openflag4_u.how.mode == EXCLUSIVE4) 00381 cause = "OPEN4_CREATE EXCLUSIVE"; 00382 else 00383 cause = "OPEN4_CREATE"; 00384 00385 /* Does a file with this name already exist ? */ 00386 pentry_lookup = cache_inode_lookup(pentry_parent, 00387 &filename, 00388 &attr_newfile, 00389 data->pcontext, 00390 &cache_status); 00391 00392 if(cache_status != CACHE_INODE_NOT_FOUND) 00393 { 00394 /* if open is UNCHECKED, return NFS4_OK (RFC3530 page 172) */ 00395 if(arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4 00396 && (cache_status == CACHE_INODE_SUCCESS)) 00397 { 00398 /* If the file is opened for write, OPEN4 while deny share write access, 00399 * in this case, check caller has write access to the file */ 00400 if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE) 00401 { 00402 if(cache_inode_access(pentry_lookup, 00403 write_access, 00404 data->pcontext, 00405 &cache_status) != CACHE_INODE_SUCCESS) 00406 { 00407 res_OPEN4.status = NFS4ERR_ACCESS; 00408 goto out; 00409 } 00410 openflags = FSAL_O_WRONLY; 00411 } 00412 00413 /* Same check on read: check for readability of a file before opening it for read */ 00414 if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ) 00415 { 00416 if(cache_inode_access(pentry_lookup, 00417 read_access, 00418 data->pcontext, 00419 &cache_status) != CACHE_INODE_SUCCESS) 00420 { 00421 res_OPEN4.status = NFS4ERR_ACCESS; 00422 goto out; 00423 } 00424 openflags = FSAL_O_RDONLY; 00425 } 00426 00427 if(AttrProvided == TRUE) /* Set the attribute if provided */ 00428 { 00429 if(cache_inode_setattr(pentry_lookup, 00430 &sattr, 00431 data->pcontext, 00432 &cache_status) != CACHE_INODE_SUCCESS) 00433 { 00434 res_OPEN4.status = nfs4_Errno(cache_status); 00435 cause2 = " cache_inode_setattr"; 00436 goto out; 00437 } 00438 00439 res_OPEN4.OPEN4res_u.resok4.attrset = 00440 arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs. 00441 attrmask; 00442 } 00443 else 00444 res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 0; 00445 00446 /* Same check on write */ 00447 if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE) 00448 { 00449 if(cache_inode_access(pentry_lookup, 00450 write_access, 00451 data->pcontext, 00452 &cache_status) != CACHE_INODE_SUCCESS) 00453 { 00454 res_OPEN4.status = NFS4ERR_ACCESS; 00455 cause2 = " cache_inode_access"; 00456 goto out; 00457 } 00458 openflags = FSAL_O_RDWR; 00459 } 00460 00461 /* Set the state for the related file */ 00462 00463 /* Prepare state management structure */ 00464 candidate_type = STATE_TYPE_SHARE; 00465 candidate_data.share.share_deny = arg_OPEN4.share_deny; 00466 candidate_data.share.share_access = arg_OPEN4.share_access; 00467 00468 if(state_add(pentry_lookup, 00469 candidate_type, 00470 &candidate_data, 00471 powner, 00472 data->pcontext, 00473 &pfile_state, 00474 &state_status) != STATE_SUCCESS) 00475 { 00476 res_OPEN4.status = nfs4_Errno_state(state_status); 00477 cause2 = " (state_add failed)"; 00478 goto out; 00479 } 00480 /* Attach this open to an export */ 00481 pfile_state->state_pexport = data->pexport; 00482 P(data->pexport->exp_state_mutex); 00483 glist_add_tail(&data->pexport->exp_state_list, 00484 &pfile_state->state_export_list); 00485 V(data->pexport->exp_state_mutex); 00486 00487 init_glist(&pfile_state->state_data.share.share_lockstates); 00488 00489 /* Attach this open to an export */ 00490 pfile_state->state_pexport = data->pexport; 00491 P(data->pexport->exp_state_mutex); 00492 glist_add_tail(&data->pexport->exp_state_list, &pfile_state->state_export_list); 00493 V(data->pexport->exp_state_mutex); 00494 00495 /* Open the file */ 00496 if(cache_inode_open(pentry_lookup, 00497 openflags, 00498 data->pcontext, 00499 0, 00500 &cache_status) != CACHE_INODE_SUCCESS) 00501 { 00502 // TODO FSF: huh???? 00503 res_OPEN4.status = NFS4ERR_SHARE_DENIED; 00504 res_OPEN4.status = NFS4ERR_ACCESS; 00505 cause2 = " cache_inode_open"; 00506 goto out; 00507 } 00508 00509 res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 3; 00510 if((res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val = 00511 gsh_calloc(res_OPEN4.OPEN4res_u.resok4.attrset. 00512 bitmap4_len, sizeof(uint32_t))) == NULL) 00513 { 00514 res_OPEN4.status = NFS4ERR_RESOURCE; 00515 res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 0; 00516 cause2 = " (allocation of bitmap failed)"; 00517 goto out; 00518 } 00519 00520 res_OPEN4.OPEN4res_u.resok4.cinfo.after 00521 = cache_inode_get_changeid4(pentry_parent); 00522 res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = FALSE; 00523 00524 /* No delegation */ 00525 res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type = 00526 OPEN_DELEGATE_NONE; 00527 00528 res_OPEN4.OPEN4res_u.resok4.rflags = OPEN4_RESULT_LOCKTYPE_POSIX; 00529 00530 /* Now produce the filehandle to this file */ 00531 pnewfsal_handle = &pentry_lookup->handle; 00532 00533 /* Building a new fh */ 00534 if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data)) 00535 { 00536 res_OPEN4.status = NFS4ERR_SERVERFAULT; 00537 cause2 = " (nfs4_FSALToFhandle failed)"; 00538 goto out; 00539 } 00540 00541 /* This new fh replaces the current FH */ 00542 data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len; 00543 memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val, 00544 newfh4.nfs_fh4_len); 00545 00546 data->current_entry = pentry_lookup; 00547 if (cache_inode_lru_ref(data->current_entry, 00548 0) 00549 != CACHE_INODE_SUCCESS) 00550 { 00551 LogFatal(COMPONENT_CACHE_INODE_LRU, 00552 "Inconsistency found in LRU management."); 00553 } 00554 data->current_filetype = REGULAR_FILE; 00555 00556 /* regular exit */ 00557 goto out_success; 00558 } 00559 00560 /* if open is EXCLUSIVE, but verifier is the same, return NFS4_OK (RFC3530 page 173) */ 00561 if(arg_OPEN4.openhow.openflag4_u.how.mode == EXCLUSIVE4) 00562 { 00563 if((pentry_lookup != NULL) 00564 && (pentry_lookup->type == REGULAR_FILE)) 00565 { 00566 pthread_rwlock_rdlock(&pentry_lookup->state_lock); 00567 glist_for_each(glist, &pentry_lookup->state_list) 00568 { 00569 pstate_iterate = glist_entry(glist, state_t, state_list); 00570 00571 /* Check is open_owner is the same */ 00572 if((pstate_iterate->state_type == STATE_TYPE_SHARE) 00573 && !memcmp(arg_OPEN4.owner.owner.owner_val, 00574 pstate_iterate->state_powner->so_owner_val, 00575 pstate_iterate->state_powner->so_owner_len) 00576 && !memcmp(pstate_iterate->state_data.share. 00577 share_oexcl_verifier, 00578 arg_OPEN4.openhow.openflag4_u.how. 00579 createhow4_u.createverf, NFS4_VERIFIER_SIZE)) 00580 { 00581 00582 /* A former open EXCLUSIVE with same owner and verifier was found, resend it */ 00583 memset(&(res_OPEN4.OPEN4res_u.resok4.cinfo.after), 0, 00584 sizeof(changeid4)); 00585 res_OPEN4.OPEN4res_u.resok4.cinfo.after = 00586 cache_inode_get_changeid4(pentry_parent); 00587 res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = FALSE; 00588 00589 /* No delegation */ 00590 res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type = 00591 OPEN_DELEGATE_NONE; 00592 00593 res_OPEN4.OPEN4res_u.resok4.rflags = 00594 OPEN4_RESULT_LOCKTYPE_POSIX; 00595 00596 /* Now produce the filehandle to this file */ 00597 pnewfsal_handle = &pentry_lookup->handle; 00598 00599 /* Building a new fh */ 00600 if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data)) 00601 { 00602 res_OPEN4.status = NFS4ERR_SERVERFAULT; 00603 cause2 = " nfs4_FSALToFhandle failed"; 00604 pthread_rwlock_unlock(&pentry_lookup 00605 ->state_lock); 00606 goto out; 00607 } 00608 00609 /* This new fh replaces the current FH */ 00610 data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len; 00611 memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val, 00612 newfh4.nfs_fh4_len); 00613 00614 data->current_entry = pentry_lookup; 00615 if (cache_inode_lru_ref(data->current_entry, 0) 00616 != CACHE_INODE_SUCCESS) 00617 { 00618 LogFatal(COMPONENT_CACHE_INODE_LRU, 00619 "Inconsistency found in LRU " 00620 "management."); 00621 } 00622 data->current_filetype = REGULAR_FILE; 00623 00624 pthread_rwlock_unlock(&pentry_lookup 00625 ->state_lock); 00626 /* regular exit */ 00627 goto out_success; 00628 } 00629 } 00630 } 00631 } 00632 00633 /* Managing GUARDED4 mode */ 00634 if(cache_status != CACHE_INODE_SUCCESS) 00635 res_OPEN4.status = nfs4_Errno(cache_status); 00636 else 00637 res_OPEN4.status = NFS4ERR_EXIST; /* File already exists */ 00638 00639 cause2 = "GUARDED4"; 00640 goto out; 00641 } 00642 00643 /* if( cache_status != CACHE_INODE_NOT_FOUND ), if file already exists basically */ 00644 LogFullDebug(COMPONENT_STATE, 00645 " OPEN open.how = %d", 00646 arg_OPEN4.openhow.openflag4_u.how.mode); 00647 00648 /* Create the file, if we reach this point, it does not exist, we can create it */ 00649 if((pentry_newfile = cache_inode_create(pentry_parent, 00650 &filename, 00651 REGULAR_FILE, 00652 mode, 00653 &create_arg, 00654 &attr_newfile, 00655 data->pcontext, &cache_status)) == NULL) 00656 { 00657 /* If the file already exists, this is not an error if open mode is UNCHECKED */ 00658 if(cache_status != CACHE_INODE_ENTRY_EXISTS) 00659 { 00660 res_OPEN4.status = nfs4_Errno(cache_status); 00661 cause2 = " UNCHECKED cache_inode_create"; 00662 goto out; 00663 } 00664 else 00665 { 00666 /* If this point is reached, then the file already 00667 exists, cache_status == CACHE_INODE_ENTRY_EXISTS 00668 and pentry_newfile == NULL This probably means 00669 EXCLUSIVE4 mode is used and verifier 00670 matches. pentry_newfile is then set to 00671 pentry_lookup */ 00672 pentry_newfile = pentry_lookup; 00673 } 00674 } 00675 00676 /* Prepare state management structure */ 00677 candidate_type = STATE_TYPE_SHARE; 00678 candidate_data.share.share_deny = arg_OPEN4.share_deny; 00679 candidate_data.share.share_access = arg_OPEN4.share_access; 00680 00681 /* If file is opened under mode EXCLUSIVE4, open verifier 00682 should be kept to detect non vicious double open */ 00683 if(arg_OPEN4.openhow.openflag4_u.how.mode == EXCLUSIVE4) 00684 { 00685 strncpy(candidate_data.share.share_oexcl_verifier, 00686 arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createverf, 00687 NFS4_VERIFIER_SIZE); 00688 } 00689 00690 if(state_add(pentry_newfile, 00691 candidate_type, 00692 &candidate_data, 00693 powner, 00694 data->pcontext, 00695 &pfile_state, &state_status) != STATE_SUCCESS) 00696 { 00697 res_OPEN4.status = nfs4_Errno_state(state_status); 00698 cause2 = " state_add failed"; 00699 goto out; 00700 } 00701 00702 /* Attach this open to an export */ 00703 pfile_state->state_pexport = data->pexport; 00704 P(data->pexport->exp_state_mutex); 00705 glist_add_tail(&data->pexport->exp_state_list, 00706 &pfile_state->state_export_list); 00707 V(data->pexport->exp_state_mutex); 00708 00709 init_glist(&pfile_state->state_data.share.share_lockstates); 00710 00711 /* Attach this open to an export */ 00712 pfile_state->state_pexport = data->pexport; 00713 P(data->pexport->exp_state_mutex); 00714 glist_add_tail(&data->pexport->exp_state_list, &pfile_state->state_export_list); 00715 V(data->pexport->exp_state_mutex); 00716 00717 cache_status = CACHE_INODE_SUCCESS; 00718 00719 if(AttrProvided == TRUE) /* Set the attribute if provided */ 00720 { 00721 if((cache_status = cache_inode_setattr(pentry_newfile, 00722 &sattr, 00723 data->pcontext, 00724 &cache_status)) != 00725 CACHE_INODE_SUCCESS) 00726 { 00727 res_OPEN4.status = nfs4_Errno(cache_status); 00728 cause2 = " cache_inode_setattr"; 00729 goto out; 00730 } 00731 00732 } 00733 00734 /* Set the openflags variable */ 00735 if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE) 00736 openflags |= FSAL_O_RDONLY; 00737 if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_READ) 00738 openflags |= FSAL_O_WRONLY; 00739 if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE) 00740 openflags = FSAL_O_RDWR; 00741 if(arg_OPEN4.share_access != 0) 00742 openflags = FSAL_O_RDWR; /* @todo : BUGAZOMEU : Something better later */ 00743 00744 /* Open the file */ 00745 if(cache_inode_open(pentry_newfile, 00746 openflags, 00747 data->pcontext, 00748 0, 00749 &cache_status) != CACHE_INODE_SUCCESS) 00750 { 00751 res_OPEN4.status = NFS4ERR_ACCESS; 00752 cause2 = " cache_inode_open"; 00753 goto out; 00754 } 00755 00756 break; 00757 00758 case OPEN4_NOCREATE: 00759 /* It was not a creation, but a regular open */ 00760 cause = "OPEN4_NOCREATE"; 00761 00762 /* The filehandle to the new file replaces the current filehandle */ 00763 if(pentry_newfile == NULL) 00764 { 00765 if((pentry_newfile = cache_inode_lookup(pentry_parent, 00766 &filename, 00767 &attr_newfile, 00768 data->pcontext, 00769 &cache_status)) == NULL) 00770 { 00771 res_OPEN4.status = nfs4_Errno(cache_status); 00772 cause2 = " cache_inode_lookup"; 00773 goto out; 00774 } 00775 } 00776 00777 /* OPEN4 is to be done on a file */ 00778 if(pentry_newfile->type != REGULAR_FILE) 00779 { 00780 if(pentry_newfile->type == DIRECTORY) 00781 { 00782 res_OPEN4.status = NFS4ERR_ISDIR; 00783 goto out; 00784 } 00785 else if(pentry_newfile->type == SYMBOLIC_LINK) 00786 { 00787 res_OPEN4.status = NFS4ERR_SYMLINK; 00788 goto out; 00789 } 00790 else 00791 { 00792 res_OPEN4.status = NFS4ERR_INVAL; 00793 cause2 = " (not REGULAR_FILE)"; 00794 goto out; 00795 } 00796 } 00797 00798 /* If the file is opened for write, OPEN4 while deny share write access, 00799 * in this case, check caller has write access to the file */ 00800 if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE) 00801 { 00802 if(cache_inode_access(pentry_newfile, 00803 write_access, 00804 data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) 00805 { 00806 res_OPEN4.status = NFS4ERR_ACCESS; 00807 cause2 = " OPEN4_SHARE_DENY_WRITE cache_inode_access"; 00808 goto out; 00809 } 00810 openflags = FSAL_O_WRONLY; 00811 } 00812 00813 /* Same check on read: check for readability of a file before opening it for read */ 00814 if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ) 00815 { 00816 if(cache_inode_access(pentry_newfile, 00817 read_access, 00818 data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) 00819 { 00820 res_OPEN4.status = NFS4ERR_ACCESS; 00821 cause2 = " OPEN4_SHARE_ACCESS_READ cache_inode_access"; 00822 goto out; 00823 } 00824 openflags = FSAL_O_RDONLY; 00825 } 00826 00827 /* Same check on write */ 00828 if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE) 00829 { 00830 if(cache_inode_access(pentry_newfile, 00831 write_access, 00832 data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) 00833 { 00834 res_OPEN4.status = NFS4ERR_ACCESS; 00835 cause2 = " OPEN4_SHARE_ACCESS_WRITE cache_inode_access"; 00836 goto out; 00837 } 00838 openflags = FSAL_O_RDWR; 00839 } 00840 00841 /* Try to find if the same open_owner already has acquired a 00842 stateid for this file */ 00843 pthread_rwlock_wrlock(&pentry_newfile->state_lock); 00844 glist_for_each(glist, &pentry_newfile->state_list) 00845 { 00846 pstate_iterate = glist_entry(glist, state_t, state_list); 00847 00848 // TODO FSF: currently only care about share types 00849 if(pstate_iterate->state_type != STATE_TYPE_SHARE) 00850 continue; 00851 00852 /* Check is open_owner is the same */ 00853 if((pstate_iterate->state_powner->so_owner.so_nfs4_owner.so_clientid == arg_OPEN4.owner.clientid) && 00854 ((pstate_iterate->state_powner->so_owner_len == arg_OPEN4.owner.owner.owner_len) && 00855 (!memcmp(arg_OPEN4.owner.owner.owner_val, 00856 pstate_iterate->state_powner->so_owner_val, 00857 pstate_iterate->state_powner->so_owner_len)))) 00858 { 00859 /* We'll be re-using the found state */ 00860 pfile_state = pstate_iterate; 00861 ReuseState = TRUE; 00862 } 00863 else 00864 { 00865 /* This is a different owner, check for possible conflicts */ 00866 if((pstate_iterate->state_data.share.share_access & OPEN4_SHARE_ACCESS_WRITE) 00867 && (arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE)) 00868 { 00869 res_OPEN4.status = NFS4ERR_SHARE_DENIED; 00870 cause2 = " (OPEN4_SHARE_DENY_WRITE)"; 00871 pthread_rwlock_unlock(&pentry_newfile->state_lock); 00872 goto out; 00873 } 00874 } 00875 00876 /* In all cases opening in read access a read denied file or write access to a write denied file 00877 * should fail, even if the owner is the same, see discussion in 14.2.16 and 8.9 00878 */ 00879 00880 /* deny read access on read denied file */ 00881 if((pstate_iterate->state_data.share.share_deny & OPEN4_SHARE_DENY_READ) 00882 && (arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ)) 00883 { 00884 res_OPEN4.status = NFS4ERR_SHARE_DENIED; 00885 cause2 = " (OPEN4_SHARE_ACCESS_READ)"; 00886 pthread_rwlock_unlock(&pentry_newfile->state_lock); 00887 goto out; 00888 } 00889 00890 /* deny write access on write denied file */ 00891 if((pstate_iterate->state_data.share.share_deny & OPEN4_SHARE_DENY_WRITE) 00892 && (arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE)) 00893 { 00894 res_OPEN4.status = NFS4ERR_SHARE_DENIED; 00895 cause2 = " (OPEN4_SHARE_ACCESS_WRITE)"; 00896 pthread_rwlock_unlock(&pentry_newfile->state_lock); 00897 goto out; 00898 } 00899 } 00900 00901 if(pfile_state == NULL) 00902 { 00903 /* Set the state for the related file */ 00904 /* Prepare state management structure */ 00905 candidate_type = STATE_TYPE_SHARE; 00906 candidate_data.share.share_deny = arg_OPEN4.share_deny; 00907 candidate_data.share.share_access = arg_OPEN4.share_access; 00908 00909 if(state_add_impl(pentry_newfile, 00910 candidate_type, 00911 &candidate_data, 00912 powner, 00913 data->pcontext, 00914 &pfile_state, 00915 &state_status) != STATE_SUCCESS) 00916 { 00917 res_OPEN4.status = nfs4_Errno_state(state_status); 00918 cause2 = " (state_add failed)"; 00919 pthread_rwlock_unlock(&pentry_newfile->state_lock); 00920 goto out; 00921 } 00922 00923 /* Attach this open to an export */ 00924 pfile_state->state_pexport = data->pexport; 00925 P(data->pexport->exp_state_mutex); 00926 glist_add_tail(&data->pexport->exp_state_list, 00927 &pfile_state->state_export_list); 00928 V(data->pexport->exp_state_mutex); 00929 init_glist(&pfile_state->state_data.share.share_lockstates); 00930 00931 /* Attach this open to an export */ 00932 pfile_state->state_pexport = data->pexport; 00933 P(data->pexport->exp_state_mutex); 00934 glist_add_tail(&data->pexport->exp_state_list, &pfile_state->state_export_list); 00935 V(data->pexport->exp_state_mutex); 00936 } 00937 else 00938 { 00939 /* Check if open from another export */ 00940 if(pfile_state->state_pexport != data->pexport) 00941 { 00942 LogEvent(COMPONENT_STATE, 00943 "Lock Owner Export Conflict, Lock held for export %d (%s), request for export %d (%s)", 00944 pfile_state->state_pexport->id, 00945 pfile_state->state_pexport->fullpath, 00946 data->pexport->id, 00947 data->pexport->fullpath); 00948 return STATE_INVALID_ARGUMENT; 00949 } 00950 } 00951 pthread_rwlock_unlock(&pentry_newfile->state_lock); 00952 00953 /* Open the file */ 00954 if(cache_inode_open(pentry_newfile, 00955 openflags, 00956 data->pcontext, 00957 0, 00958 &cache_status) != CACHE_INODE_SUCCESS) 00959 { 00960 res_OPEN4.status = NFS4ERR_ACCESS; 00961 cause2 = " cache_inode_open"; 00962 goto out; 00963 } 00964 break; 00965 00966 default: 00967 cause = "INVALID OPEN TYPE"; 00968 res_OPEN4.status = NFS4ERR_INVAL; 00969 goto out; 00970 } /* switch( arg_OPEN4.openhow.opentype ) */ 00971 00972 break; 00973 00974 case CLAIM_PREVIOUS: 00975 // TODO FSF: doesn't this need to do something to re-establish state? 00976 cause = "CLAIM_PREVIOUS"; 00977 powner = NULL; 00978 break; 00979 00980 default: 00981 /* Invalid claim type */ 00982 cause = "INVALID CLAIM"; 00983 res_OPEN4.status = NFS4ERR_INVAL; 00984 goto out; 00985 } /* switch( arg_OPEN4.claim.claim ) */ 00986 00987 /* Now produce the filehandle to this file */ 00988 pnewfsal_handle = &pentry_newfile->handle; 00989 00990 /* Building a new fh */ 00991 if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data)) 00992 { 00993 res_OPEN4.status = NFS4ERR_SERVERFAULT; 00994 cause2 = " (nfs4_FSALToFhandle failed)"; 00995 goto out; 00996 } 00997 00998 /* This new fh replaces the current FH */ 00999 data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len; 01000 memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val, newfh4.nfs_fh4_len); 01001 01002 data->current_entry = pentry_newfile; 01003 if (cache_inode_lru_ref(data->current_entry, 0) 01004 != CACHE_INODE_SUCCESS) 01005 { 01006 LogFatal(COMPONENT_CACHE_INODE_LRU, 01007 "Inconsistency found in LRU management."); 01008 } 01009 data->current_filetype = REGULAR_FILE; 01010 01011 /* Status of parent directory after the operation */ 01012 if((cache_status = cache_inode_getattr(pentry_parent, 01013 &attr_parent, 01014 data->pcontext, 01015 &cache_status)) != CACHE_INODE_SUCCESS) 01016 { 01017 res_OPEN4.status = nfs4_Errno(cache_status); 01018 cause2 = " cache_inode_getattr"; 01019 goto out; 01020 } 01021 01022 res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 3; 01023 if((res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val = 01024 gsh_calloc(res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len, 01025 sizeof(uint32_t))) == NULL) 01026 { 01027 res_OPEN4.status = NFS4ERR_SERVERFAULT; 01028 res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 0; 01029 cause2 = " (allocation of attr failed)"; 01030 goto out; 01031 } 01032 01033 if(arg_OPEN4.openhow.opentype == OPEN4_CREATE) 01034 { 01035 tmp_attr[0] = FATTR4_SIZE; 01036 tmp_attr[1] = FATTR4_MODE; 01037 nfs4_list_to_bitmap4(&(res_OPEN4.OPEN4res_u.resok4.attrset), 2, tmp_attr); 01038 } 01039 01040 res_OPEN4.OPEN4res_u.resok4.cinfo.after 01041 = cache_inode_get_changeid4(pentry_parent); 01042 res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = FALSE; 01043 01044 /* No delegation */ 01045 res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type = OPEN_DELEGATE_NONE; 01046 01047 res_OPEN4.OPEN4res_u.resok4.rflags = OPEN4_RESULT_LOCKTYPE_POSIX; 01048 01049 out_success: 01050 01051 LogFullDebug(COMPONENT_STATE, "NFS41 OPEN returning NFS4_OK"); 01052 01053 /* regular exit */ 01054 res_OPEN4.status = NFS4_OK; 01055 01056 /* Handle stateid/seqid for success */ 01057 update_stateid(pfile_state, 01058 &res_OPEN4.OPEN4res_u.resok4.stateid, 01059 data, 01060 tag); 01061 01062 /* If we are re-using stateid, then release extra reference to open owner */ 01063 if(ReuseState) 01064 dec_state_owner_ref(powner); 01065 01066 out: 01067 01068 if(res_OPEN4.status != NFS4_OK) 01069 { 01070 const char *cause3 = "", *cause4 = ""; 01071 01072 if(cache_status != CACHE_INODE_SUCCESS) 01073 { 01074 cause3 = " returned "; 01075 cause4 = cache_inode_err_str(cache_status); 01076 } 01077 01078 LogDebug(COMPONENT_STATE, 01079 "NFS41 OPEN returning %s for %s%s%s%s", 01080 nfsstat4_to_str(res_OPEN4.status), 01081 cause, cause2, cause3, cause4); 01082 01083 /* Clean up if we have an error exit */ 01084 if(pfile_state != NULL && !ReuseState) 01085 { 01086 /* Need to destroy open owner and state */ 01087 if(state_del(pfile_state, 01088 &state_status) != STATE_SUCCESS) 01089 LogDebug(COMPONENT_NFS_V4_LOCK, 01090 "state_del failed with status %s", 01091 state_err_str(state_status)); 01092 } 01093 else if(powner != NULL) 01094 { 01095 /* Need to release the open owner */ 01096 dec_state_owner_ref(powner); 01097 } 01098 } 01099 01100 /* return cache entry references */ 01101 if (pentry_parent) 01102 cache_inode_put(pentry_parent); 01103 01104 if (pentry_lookup) 01105 cache_inode_put(pentry_lookup); 01106 01107 if (pentry_newfile) 01108 cache_inode_put(pentry_newfile); 01109 01110 return res_OPEN4.status; 01111 } /* nfs41_op_open */ 01112 01123 void nfs41_op_open_Free(OPEN4res * resp) 01124 { 01125 gsh_free(resp->OPEN4res_u.resok4.attrset.bitmap4_val); 01126 resp->OPEN4res_u.resok4.attrset.bitmap4_len = 0; 01127 01128 return; 01129 } /* nfs41_op_open_Free */