Esempio n. 1
0
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;
}
Esempio n. 2
0
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 */
Esempio n. 3
0
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 */
Esempio n. 4
0
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;
}
Esempio n. 5
0
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 */
Esempio n. 6
0
/**
 * @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 */