static int nfs4_mds_putfh(compound_data_t *data) { struct file_handle_v4 *v4_handle = (struct file_handle_v4 *)data->currentFH.nfs_fh4_val; struct gsh_export *exporting; struct fsal_export *export; struct gsh_buffdesc fh_desc; struct fsal_obj_handle *new_hdl; fsal_status_t fsal_status = { 0, 0 }; bool changed = true; LogFullDebug(COMPONENT_FILEHANDLE, "NFS4 Handle flags 0x%X export id %d", v4_handle->fhflags1, ntohs(v4_handle->id.exports)); LogFullDebugOpaque(COMPONENT_FILEHANDLE, "NFS4 FSAL Handle %s", LEN_FH_STR, v4_handle->fsopaque, v4_handle->fs_len); /* Find any existing export by the "id" from the handle, * before releasing the old export (to prevent thrashing). */ exporting = get_gsh_export(ntohs(v4_handle->id.exports)); if (exporting == NULL) { LogInfoAlt(COMPONENT_DISPATCH, COMPONENT_EXPORT, "NFS4 Request from client (%s) has invalid export identifier %d", op_ctx->client ? op_ctx->client->hostaddr_str : "unknown", ntohs(v4_handle->id.exports)); return NFS4ERR_STALE; } /* If old CurrentFH had a related export, release reference. */ if (op_ctx->ctx_export != NULL) { changed = ntohs(v4_handle->id.exports) != op_ctx->ctx_export->export_id; put_gsh_export(op_ctx->ctx_export); } /* If old CurrentFH had a related server, release reference. */ if (op_ctx->fsal_pnfs_ds != NULL) { pnfs_ds_put(op_ctx->fsal_pnfs_ds); op_ctx->fsal_pnfs_ds = NULL; } /* Clear out current entry for now */ set_current_entry(data, NULL); /* update _ctx fields needed by nfs4_export_check_access */ op_ctx->ctx_export = exporting; op_ctx->fsal_export = export = exporting->fsal_export; if (changed) { int status; status = nfs4_export_check_access(data->req); if (status != NFS4_OK) { LogFullDebug(COMPONENT_FILEHANDLE, "Export check access failed %s", nfsstat4_to_str(status)); return status; } } fh_desc.len = v4_handle->fs_len; fh_desc.addr = &v4_handle->fsopaque; /* adjust the handle opaque into a cache key */ fsal_status = export->exp_ops.wire_to_host(export, FSAL_DIGEST_NFSV4, &fh_desc, v4_handle->fhflags1); if (FSAL_IS_ERROR(fsal_status)) { LogFullDebug(COMPONENT_FILEHANDLE, "wire_to_host failed %s", msg_fsal_err(fsal_status.major)); return nfs4_Errno_status(fsal_status); } fsal_status = export->exp_ops.create_handle(export, &fh_desc, &new_hdl, NULL); if (FSAL_IS_ERROR(fsal_status)) { LogDebug(COMPONENT_FILEHANDLE, "could not get create_handle object error %s", msg_fsal_err(fsal_status.major)); return nfs4_Errno_status(fsal_status); } /* Set the current entry using the ref from get */ set_current_entry(data, new_hdl); /* Put our ref */ new_hdl->obj_ops->put_ref(new_hdl); LogFullDebug(COMPONENT_FILEHANDLE, "File handle is of type %s(%d)", object_file_type_to_str(data->current_filetype), data->current_filetype); return NFS4_OK; }
int nfs4_op_open(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { /* Shorter alias for OPEN4 arguments */ OPEN4args * const arg_OPEN4 = &(op->nfs_argop4_u.opopen); /* Shorter alias for OPEN4 response */ OPEN4res * const res_OPEN4 = &(resp->nfs_resop4_u.opopen); /* The handle from which the change_info4 is to be * generated. Every mention of change_info4 in RFC5661 * speaks of the parent directory of the file being opened. * However, with CLAIM_FH, CLAIM_DELEG_CUR_FH, and * CLAIM_DELEG_PREV_FH, there is no way to derive the parent * directory from the file handle. It is Unclear what the * correct behavior is. In our implementation, we take the * change_info4 of whatever filehandle is current when the * OPEN operation is invoked. */ struct fsal_obj_handle *obj_change = NULL; /* The found client record */ nfs_client_id_t *clientid = NULL; /* The found or created state owner for this open */ state_owner_t *owner = NULL; /* The supplied calim type */ open_claim_type4 claim = arg_OPEN4->claim.claim; /* The open state for the file */ state_t *file_state = NULL; /* True if the state was newly created */ bool new_state = false; int retval; LogDebug(COMPONENT_STATE, "Entering NFS v4 OPEN handler -----------------------------"); /* What kind of open is it ? */ LogFullDebug(COMPONENT_STATE, "OPEN: Claim type = %d, Open Type = %d, Share Deny = %d, Share Access = %d ", arg_OPEN4->claim.claim, arg_OPEN4->openhow.opentype, arg_OPEN4->share_deny, arg_OPEN4->share_access); resp->resop = NFS4_OP_OPEN; res_OPEN4->status = NFS4_OK; res_OPEN4->OPEN4res_u.resok4.rflags = 0; /* Check export permissions if OPEN4_CREATE */ if ((arg_OPEN4->openhow.opentype == OPEN4_CREATE) && ((op_ctx->export_perms->options & EXPORT_OPTION_MD_WRITE_ACCESS) == 0)) { res_OPEN4->status = NFS4ERR_ROFS; LogDebug(COMPONENT_NFS_V4, "Status of OP_OPEN due to export permissions = %s", nfsstat4_to_str(res_OPEN4->status)); return res_OPEN4->status; } /* Check export permissions if OPEN4_SHARE_ACCESS_WRITE */ if (((arg_OPEN4->share_access & OPEN4_SHARE_ACCESS_WRITE) != 0) && ((op_ctx->export_perms->options & EXPORT_OPTION_WRITE_ACCESS) == 0)) { res_OPEN4->status = NFS4ERR_ROFS; LogDebug(COMPONENT_NFS_V4, "Status of OP_OPEN due to export permissions = %s", nfsstat4_to_str(res_OPEN4->status)); return res_OPEN4->status; } /* Do basic checks on a filehandle */ res_OPEN4->status = nfs4_sanity_check_FH(data, NO_FILE_TYPE, false); if (res_OPEN4->status != NFS4_OK) return res_OPEN4->status; if (data->current_obj == NULL) { /* This should be impossible, as PUTFH fills in the * current entry and previous checks weed out handles * in the PseudoFS and DS handles. */ res_OPEN4->status = NFS4ERR_SERVERFAULT; LogCrit(COMPONENT_NFS_V4, "Impossible condition in compound data at %s:%u.", __FILE__, __LINE__); goto out3; } /* It this a known client id? */ LogDebug(COMPONENT_STATE, "OPEN Client id = %" PRIx64, arg_OPEN4->owner.clientid); retval = nfs_client_id_get_confirmed( data->minorversion == 0 ? arg_OPEN4->owner.clientid : data->session->clientid, &clientid); if (retval != CLIENT_ID_SUCCESS) { res_OPEN4->status = clientid_error_to_nfsstat(retval); LogDebug(COMPONENT_NFS_V4, "nfs_client_id_get_confirmed failed"); return res_OPEN4->status; } /* Check if lease is expired and reserve it */ PTHREAD_MUTEX_lock(&clientid->cid_mutex); if (data->minorversion == 0 && !reserve_lease(clientid)) { PTHREAD_MUTEX_unlock(&clientid->cid_mutex); res_OPEN4->status = NFS4ERR_EXPIRED; LogDebug(COMPONENT_NFS_V4, "Lease expired"); goto out3; } PTHREAD_MUTEX_unlock(&clientid->cid_mutex); /* Get the open owner */ if (!open4_open_owner(op, data, resp, clientid, &owner)) { LogDebug(COMPONENT_NFS_V4, "open4_open_owner failed"); goto out2; } /* Do the claim check here, so we can save the result in the * owner for NFSv4.0. */ res_OPEN4->status = open4_validate_claim(data, claim, clientid); if (res_OPEN4->status != NFS4_OK) { LogDebug(COMPONENT_NFS_V4, "open4_validate_claim failed"); goto out; } /* After this point we know we have only CLAIM_NULL, * CLAIM_FH, or CLAIM_PREVIOUS, and that our grace period and * minor version are appropriate for the claim specified. */ if ((arg_OPEN4->openhow.opentype == OPEN4_CREATE) && (claim != CLAIM_NULL)) { res_OPEN4->status = NFS4ERR_INVAL; LogDebug(COMPONENT_NFS_V4, "OPEN4_CREATE but not CLAIM_NULL"); goto out2; } /* So we still have a reference even after we repalce the * current FH. */ obj_change = data->current_obj; obj_change->obj_ops->get_ref(obj_change); /* Update the change info for entry_change. */ res_OPEN4->OPEN4res_u.resok4.cinfo.before = fsal_get_changeid4(obj_change); /* Check if share_access does not have any access set, or has * invalid bits that are set. check that share_deny doesn't * have any invalid bits set. */ if (!(arg_OPEN4->share_access & OPEN4_SHARE_ACCESS_BOTH) || (data->minorversion == 0 && arg_OPEN4->share_access & ~OPEN4_SHARE_ACCESS_BOTH) || (arg_OPEN4->share_access & (~OPEN4_SHARE_ACCESS_WANT_DELEG_MASK & ~OPEN4_SHARE_ACCESS_BOTH)) || (arg_OPEN4->share_deny & ~OPEN4_SHARE_DENY_BOTH)) { res_OPEN4->status = NFS4ERR_INVAL; LogDebug(COMPONENT_NFS_V4, "Invalid SHARE_ACCESS or SHARE_DENY"); goto out; } /* Utilize the extended FSAL APU functionality to perform the open. */ open4_ex(arg_OPEN4, data, res_OPEN4, clientid, owner, &file_state, &new_state); if (res_OPEN4->status != NFS4_OK) goto out; memset(&res_OPEN4->OPEN4res_u.resok4.attrset, 0, sizeof(struct bitmap4)); if (arg_OPEN4->openhow.openflag4_u.how.mode == EXCLUSIVE4 || arg_OPEN4->openhow.openflag4_u.how.mode == EXCLUSIVE4_1) { struct bitmap4 *bits = &res_OPEN4->OPEN4res_u.resok4.attrset; set_attribute_in_bitmap(bits, FATTR4_TIME_ACCESS); set_attribute_in_bitmap(bits, FATTR4_TIME_MODIFY); } /* If server use OPEN_CONFIRM4, set the correct flag, * but not for 4.1 */ if (owner->so_owner.so_nfs4_owner.so_confirmed == false) res_OPEN4->OPEN4res_u.resok4.rflags |= OPEN4_RESULT_CONFIRM; res_OPEN4->OPEN4res_u.resok4.rflags |= OPEN4_RESULT_LOCKTYPE_POSIX; LogFullDebug(COMPONENT_STATE, "NFS4 OPEN returning NFS4_OK"); /* regular exit */ res_OPEN4->status = NFS4_OK; /* Update change_info4 */ res_OPEN4->OPEN4res_u.resok4.cinfo.after = fsal_get_changeid4(obj_change); res_OPEN4->OPEN4res_u.resok4.cinfo.atomic = FALSE; /* Handle open stateid/seqid for success */ update_stateid(file_state, &res_OPEN4->OPEN4res_u.resok4.stateid, data, open_tag); out: if (res_OPEN4->status != NFS4_OK) { LogDebug(COMPONENT_STATE, "failed with status %s", nfsstat4_to_str(res_OPEN4->status)); } /* Save the response in the open owner. * obj_change is either the parent directory or for a CLAIM_PREV is * the entry itself. In either case, it's the right entry to use in * saving the request results. */ if (data->minorversion == 0) { Copy_nfs4_state_req(owner, arg_OPEN4->seqid, op, obj_change, resp, open_tag); } out2: /* Update the lease before exit */ if (data->minorversion == 0) { PTHREAD_MUTEX_lock(&clientid->cid_mutex); update_lease(clientid); PTHREAD_MUTEX_unlock(&clientid->cid_mutex); } if (file_state != NULL) dec_state_t_ref(file_state); /* Clean up if we have an error exit */ if ((file_state != NULL) && new_state && (res_OPEN4->status != NFS4_OK)) { /* Need to destroy open owner and state */ state_del(file_state); } if (obj_change) obj_change->obj_ops->put_ref(obj_change); if (owner != NULL) { /* Need to release the open owner for this call */ dec_state_owner_ref(owner); } out3: dec_client_id_ref(clientid); return res_OPEN4->status; } /* nfs4_op_open */
int nfs4_op_lookup(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { /* Convenient alias for the arguments */ LOOKUP4args * const arg_LOOKUP4 = &op->nfs_argop4_u.oplookup; /* Convenient alias for the response */ LOOKUP4res * const res_LOOKUP4 = &resp->nfs_resop4_u.oplookup; /* The name to look up */ char *name = NULL; /* The directory in which to look up the name */ struct fsal_obj_handle *dir_obj = NULL; /* The name found */ struct fsal_obj_handle *file_obj = NULL; /* Status code from fsal */ fsal_status_t status = {0, 0}; resp->resop = NFS4_OP_LOOKUP; res_LOOKUP4->status = NFS4_OK; /* Do basic checks on a filehandle */ res_LOOKUP4->status = nfs4_sanity_check_FH(data, DIRECTORY, false); if (res_LOOKUP4->status != NFS4_OK) { /* for some reason lookup is picky. Just not being * dir is not enough. We want to know it is a symlink */ if (res_LOOKUP4->status == NFS4ERR_NOTDIR && data->current_filetype == SYMBOLIC_LINK) res_LOOKUP4->status = NFS4ERR_SYMLINK; goto out; } /* Validate and convert the UFT8 objname to a regular string */ res_LOOKUP4->status = nfs4_utf8string2dynamic(&arg_LOOKUP4->objname, UTF8_SCAN_ALL, &name); if (res_LOOKUP4->status != NFS4_OK) goto out; LogDebug(COMPONENT_NFS_V4, "name=%s", name); /* Do the lookup in the FSAL */ file_obj = NULL; dir_obj = data->current_obj; /* Sanity check: dir_obj should be ACTUALLY a directory */ status = fsal_lookup(dir_obj, name, &file_obj, NULL); if (FSAL_IS_ERROR(status)) { res_LOOKUP4->status = nfs4_Errno_status(status); goto out; } if (file_obj->type == DIRECTORY) { PTHREAD_RWLOCK_rdlock(&file_obj->state_hdl->state_lock); if (file_obj->state_hdl->dir.junction_export != NULL) { /* Handle junction */ struct fsal_obj_handle *obj = NULL; /* Attempt to get a reference to the export across the * junction. */ if (!export_ready( file_obj->state_hdl->dir.junction_export)) { /* If we could not get a reference, return * stale. Release state_lock */ LogDebug(COMPONENT_EXPORT, "NFS4ERR_STALE on LOOKUP of %s", name); res_LOOKUP4->status = NFS4ERR_STALE; PTHREAD_RWLOCK_unlock( &file_obj->state_hdl->state_lock); goto out; } get_gsh_export_ref( file_obj->state_hdl->dir.junction_export); /* Release any old export reference */ if (op_ctx->ctx_export != NULL) put_gsh_export(op_ctx->ctx_export); /* Stash the new export in the compound data. */ op_ctx->ctx_export = file_obj->state_hdl->dir.junction_export; op_ctx->fsal_export = op_ctx->ctx_export->fsal_export; PTHREAD_RWLOCK_unlock(&file_obj->state_hdl->state_lock); /* Build credentials */ res_LOOKUP4->status = nfs4_export_check_access(data->req); /* Test for access error (export should not be visible). */ if (res_LOOKUP4->status == NFS4ERR_ACCESS) { /* If return is NFS4ERR_ACCESS then this client * doesn't have access to this export, return * NFS4ERR_NOENT to hide it. It was not visible * in READDIR response. */ LogDebug(COMPONENT_EXPORT, "NFS4ERR_ACCESS Hiding Export_Id %d Pseudo %s with NFS4ERR_NOENT", op_ctx->ctx_export->export_id, op_ctx->ctx_export->pseudopath); res_LOOKUP4->status = NFS4ERR_NOENT; goto out; } if (res_LOOKUP4->status == NFS4ERR_WRONGSEC) { /* LogInfo already documents why */ goto out; } if (res_LOOKUP4->status != NFS4_OK) { /* Should never get here, * nfs4_export_check_access can only return * NFS4_OK, NFS4ERR_ACCESS or NFS4ERR_WRONGSEC. */ LogMajor(COMPONENT_EXPORT, "PSEUDO FS JUNCTION TRAVERSAL: Failed with %s for %s, id=%d", nfsstat4_to_str(res_LOOKUP4->status), op_ctx->ctx_export->pseudopath, op_ctx->ctx_export->export_id); goto out; } status = nfs_export_get_root_entry(op_ctx->ctx_export, &obj); if (FSAL_IS_ERROR(status)) { LogMajor(COMPONENT_EXPORT, "PSEUDO FS JUNCTION TRAVERSAL: Failed to get root for %s, id=%d, status = %s", op_ctx->ctx_export->pseudopath, op_ctx->ctx_export->export_id, msg_fsal_err(status.major)); res_LOOKUP4->status = nfs4_Errno_status(status); goto out; } LogDebug(COMPONENT_EXPORT, "PSEUDO FS JUNCTION TRAVERSAL: Crossed to %s, id=%d for name=%s", op_ctx->ctx_export->pseudopath, op_ctx->ctx_export->export_id, name); file_obj->obj_ops->put_ref(file_obj); file_obj = obj; } else { PTHREAD_RWLOCK_unlock(&file_obj->state_hdl->state_lock); } } /* Convert it to a file handle */ if (!nfs4_FSALToFhandle(false, &data->currentFH, file_obj, op_ctx->ctx_export)) { res_LOOKUP4->status = NFS4ERR_SERVERFAULT; goto out; } /* Keep the pointer within the compound data */ set_current_entry(data, file_obj); /* Put our ref */ file_obj->obj_ops->put_ref(file_obj); file_obj = NULL; /* Return successfully */ res_LOOKUP4->status = NFS4_OK; out: /* Release reference on file_obj if we didn't utilze it. */ if (file_obj) file_obj->obj_ops->put_ref(file_obj); gsh_free(name); return res_LOOKUP4->status; } /* nfs4_op_lookup */
int nfs4_op_seek(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { SEEK4args * const arg_SEEK = &op->nfs_argop4_u.opseek; SEEK4res * const res_SEEK = &resp->nfs_resop4_u.opseek; fsal_status_t fsal_status = { 0, 0 }; state_t *state_found = NULL; struct fsal_obj_handle *obj = NULL; struct io_info info; /* Say we are managing NFS4_OP_SEEK */ resp->resop = NFS4_OP_SEEK; if (data->minorversion < 2) { res_SEEK->sr_status = NFS4ERR_NOTSUPP; goto done; } res_SEEK->sr_status = NFS4_OK; /* Do basic checks on a filehandle Only files can be set */ res_SEEK->sr_status = nfs4_sanity_check_FH(data, REGULAR_FILE, true); if (res_SEEK->sr_status != NFS4_OK) goto done; obj = data->current_obj; /* Check stateid correctness and get pointer to state (also checks for special stateids) */ res_SEEK->sr_status = nfs4_Check_Stateid(&arg_SEEK->sa_stateid, obj, &state_found, data, STATEID_SPECIAL_ANY, 0, false, "SEEK"); if (res_SEEK->sr_status != NFS4_OK) goto done; if (state_found != NULL) { info.io_advise = state_found->state_data.io_advise; info.io_content.what = arg_SEEK->sa_what; if (arg_SEEK->sa_what == NFS4_CONTENT_DATA || arg_SEEK->sa_what == NFS4_CONTENT_HOLE) { info.io_content.hole.di_offset = arg_SEEK->sa_offset; } else info.io_content.adb.adb_offset = arg_SEEK->sa_offset; fsal_status = obj->obj_ops.seek(obj, &info); if (FSAL_IS_ERROR(fsal_status)) { res_SEEK->sr_status = NFS4ERR_NXIO; goto done; } res_SEEK->sr_resok4.sr_eof = info.io_eof; res_SEEK->sr_resok4.sr_offset = info.io_content.hole.di_offset; } done: LogDebug(COMPONENT_NFS_V4, "Status %s type %d offset %" PRIu64, nfsstat4_to_str(res_SEEK->sr_status), arg_SEEK->sa_what, arg_SEEK->sa_offset); if (state_found != NULL) dec_state_t_ref(state_found); return res_SEEK->sr_status; }
int nfs4_op_io_advise(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { IO_ADVISE4args * const arg_IO_ADVISE = &op->nfs_argop4_u.opio_advise; IO_ADVISE4res * const res_IO_ADVISE = &resp->nfs_resop4_u.opio_advise; fsal_status_t fsal_status = { 0, 0 }; struct io_hints hints; state_t *state_found = NULL; struct fsal_obj_handle *obj = NULL; /* Say we are managing NFS4_OP_IO_ADVISE */ resp->resop = NFS4_OP_IO_ADVISE; res_IO_ADVISE->iaa_status = NFS4_OK; hints.hints = 0; hints.offset = 0; hints.count = 0; if (data->minorversion < 2) { res_IO_ADVISE->iaa_status = NFS4ERR_NOTSUPP; goto done; } /* Do basic checks on a filehandle Only files can be set */ res_IO_ADVISE->iaa_status = nfs4_sanity_check_FH(data, REGULAR_FILE, true); if (res_IO_ADVISE->iaa_status != NFS4_OK) goto done; obj = data->current_obj; /* Check stateid correctness and get pointer to state (also checks for special stateids) */ res_IO_ADVISE->iaa_status = nfs4_Check_Stateid(&arg_IO_ADVISE->iaa_stateid, obj, &state_found, data, STATEID_SPECIAL_ANY, 0, false, "IO_ADVISE"); if (res_IO_ADVISE->iaa_status != NFS4_OK) goto done; if (state_found && obj) { hints.hints = arg_IO_ADVISE->iaa_hints.map[0]; hints.offset = arg_IO_ADVISE->iaa_offset; hints.count = arg_IO_ADVISE->iaa_count; fsal_status = obj->obj_ops.io_advise(obj, &hints); if (FSAL_IS_ERROR(fsal_status)) { res_IO_ADVISE->iaa_status = NFS4ERR_NOTSUPP; goto done; } /* save hints to use with other operations */ state_found->state_data.io_advise = hints.hints; res_IO_ADVISE->iaa_status = NFS4_OK; res_IO_ADVISE->iaa_hints.bitmap4_len = 1; res_IO_ADVISE->iaa_hints.map[0] = hints.hints; } done: LogDebug(COMPONENT_NFS_V4, "Status %s hints 0x%X offset %" PRIu64 " count %" PRIu64, nfsstat4_to_str(res_IO_ADVISE->iaa_status), hints.hints, hints.offset, hints.count); if (state_found != NULL) dec_state_t_ref(state_found); return res_IO_ADVISE->iaa_status; } /* nfs4_op_io_advise */
/** * @brief the NFS4_OP_SEQUENCE operation * * @param[in] op nfs4_op arguments * @param[in,out] data Compound request's data * @param[out] resp nfs4_op results * * @return per RFC5661, p. 374 * * @see nfs4_Compound * */ int nfs4_op_sequence(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { SEQUENCE4args * const arg_SEQUENCE4 = &op->nfs_argop4_u.opsequence; SEQUENCE4res * const res_SEQUENCE4 = &resp->nfs_resop4_u.opsequence; nfs41_session_t *session; resp->resop = NFS4_OP_SEQUENCE; res_SEQUENCE4->sr_status = NFS4_OK; if (data->minorversion == 0) { res_SEQUENCE4->sr_status = NFS4ERR_INVAL; return res_SEQUENCE4->sr_status; } /* OP_SEQUENCE is always the first operation of the request */ if (data->oppos != 0) { res_SEQUENCE4->sr_status = NFS4ERR_SEQUENCE_POS; return res_SEQUENCE4->sr_status; } if (!nfs41_Session_Get_Pointer(arg_SEQUENCE4->sa_sessionid, &session)) { if (nfs_in_grace()) { memcpy(res_SEQUENCE4->SEQUENCE4res_u.sr_resok4. sr_sessionid, arg_SEQUENCE4->sa_sessionid, NFS4_SESSIONID_SIZE); res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_sequenceid = arg_SEQUENCE4->sa_sequenceid; res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_slotid = arg_SEQUENCE4->sa_slotid; res_SEQUENCE4->SEQUENCE4res_u.sr_resok4. sr_highest_slotid = NFS41_NB_SLOTS - 1; res_SEQUENCE4->SEQUENCE4res_u.sr_resok4. sr_target_highest_slotid = arg_SEQUENCE4->sa_slotid; res_SEQUENCE4->SEQUENCE4res_u.sr_resok4. sr_status_flags = SEQ4_STATUS_RESTART_RECLAIM_NEEDED; LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "SEQUENCE returning status %s flags 0x%X", nfsstat4_to_str(res_SEQUENCE4->sr_status), res_SEQUENCE4->SEQUENCE4res_u.sr_resok4. sr_status_flags); } else { res_SEQUENCE4->sr_status = NFS4ERR_BADSESSION; LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "SEQUENCE returning status %s", nfsstat4_to_str(res_SEQUENCE4->sr_status)); } return res_SEQUENCE4->sr_status; } /* session->refcount +1 */ LogDebug(COMPONENT_SESSIONS, "SEQUENCE session=%p", session); /* Check if lease is expired and reserve it */ pthread_mutex_lock(&session->clientid_record->cid_mutex); if (!reserve_lease(session->clientid_record)) { pthread_mutex_unlock(&session->clientid_record->cid_mutex); dec_session_ref(session); res_SEQUENCE4->sr_status = NFS4ERR_EXPIRED; LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "SEQUENCE returning status %s", nfsstat4_to_str(res_SEQUENCE4->sr_status)); return res_SEQUENCE4->sr_status; } data->preserved_clientid = session->clientid_record; pthread_mutex_unlock(&session->clientid_record->cid_mutex); /* Check is slot is compliant with ca_maxrequests */ if (arg_SEQUENCE4->sa_slotid >= session->fore_channel_attrs.ca_maxrequests) { dec_session_ref(session); res_SEQUENCE4->sr_status = NFS4ERR_BADSLOT; LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "SEQUENCE returning status %s", nfsstat4_to_str(res_SEQUENCE4->sr_status)); return res_SEQUENCE4->sr_status; } /* By default, no DRC replay */ data->use_drc = false; pthread_mutex_lock(&session->slots[arg_SEQUENCE4->sa_slotid].lock); if (session->slots[arg_SEQUENCE4->sa_slotid].sequence + 1 != arg_SEQUENCE4->sa_sequenceid) { if (session->slots[arg_SEQUENCE4->sa_slotid].sequence == arg_SEQUENCE4->sa_sequenceid) { #if IMPLEMENT_CACHETHIS /** @todo * * Ganesha always caches result anyway so ignore * cachethis */ if (session->slots[arg_SEQUENCE4->sa_slotid] .cache_used) { #endif /* Replay operation through the DRC */ data->use_drc = true; data->cached_res = &session->slots[arg_SEQUENCE4->sa_slotid]. cached_result; LogFullDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "Use sesson slot %" PRIu32 "=%p for DRC", arg_SEQUENCE4->sa_slotid, data->cached_res); pthread_mutex_unlock(&session-> slots[arg_SEQUENCE4->sa_slotid].lock); dec_session_ref(session); res_SEQUENCE4->sr_status = NFS4_OK; return res_SEQUENCE4->sr_status; #if IMPLEMENT_CACHETHIS } else { /* Illegal replay */ pthread_mutex_unlock(&session-> slots[arg_SEQUENCE4->sa_slotid].lock); dec_session_ref(session); res_SEQUENCE4->sr_status = NFS4ERR_RETRY_UNCACHED_REP; LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "SEQUENCE returning status %s", nfsstat4_to_str(res_SEQUENCE4-> sr_status)); return res_SEQUENCE4->sr_status; } #endif } pthread_mutex_unlock(&session-> slots[arg_SEQUENCE4->sa_slotid].lock); dec_session_ref(session); res_SEQUENCE4->sr_status = NFS4ERR_SEQ_MISORDERED; LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "SEQUENCE returning status %s", nfsstat4_to_str(res_SEQUENCE4->sr_status)); return res_SEQUENCE4->sr_status; } /* Keep memory of the session in the COMPOUND's data */ data->session = session; /* Record the sequenceid and slotid in the COMPOUND's data */ data->sequence = arg_SEQUENCE4->sa_sequenceid; data->slot = arg_SEQUENCE4->sa_slotid; /* Update the sequence id within the slot */ session->slots[arg_SEQUENCE4->sa_slotid].sequence += 1; memcpy(res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_sessionid, arg_SEQUENCE4->sa_sessionid, NFS4_SESSIONID_SIZE); res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_sequenceid = session->slots[arg_SEQUENCE4->sa_slotid].sequence; res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_slotid = arg_SEQUENCE4->sa_slotid; res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_highest_slotid = NFS41_NB_SLOTS - 1; res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_target_highest_slotid = arg_SEQUENCE4->sa_slotid; /* Maybe not the best choice */ res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_status_flags = 0; if (nfs_rpc_get_chan(session->clientid_record, 0) == NULL) { res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_status_flags |= SEQ4_STATUS_CB_PATH_DOWN; } #if IMPLEMENT_CACHETHIS /* Ganesha always caches result anyway so ignore cachethis */ if (arg_SEQUENCE4->sa_cachethis) { #endif data->cached_res = &session->slots[arg_SEQUENCE4->sa_slotid].cached_result; session->slots[arg_SEQUENCE4->sa_slotid].cache_used = true; LogFullDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "Use sesson slot %" PRIu32 "=%p for DRC", arg_SEQUENCE4->sa_slotid, data->cached_res); #if IMPLEMENT_CACHETHIS } else { data->cached_res = NULL; session->slots[arg_SEQUENCE4->sa_slotid].cache_used = false; LogFullDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "Don't use sesson slot %" PRIu32 "=NULL for DRC", arg_SEQUENCE4->sa_slotid); } #endif pthread_mutex_unlock(&session->slots[arg_SEQUENCE4->sa_slotid].lock); /* If we were successful, stash the clientid in the request * context. */ data->req_ctx->clientid = &data->session->clientid; res_SEQUENCE4->sr_status = NFS4_OK; return res_SEQUENCE4->sr_status; } /* nfs41_op_sequence */