示例#1
0
int nfs4_op_putrootfh(struct nfs_argop4 *op, compound_data_t *data,
		      struct nfs_resop4 *resp)
{
	fsal_status_t status = {0, 0};
	struct fsal_obj_handle *file_obj;

	PUTROOTFH4res * const res_PUTROOTFH4 = &resp->nfs_resop4_u.opputrootfh;

	/* First of all, set the reply to zero to make sure
	 * it contains no parasite information
	 */
	memset(resp, 0, sizeof(struct nfs_resop4));
	resp->resop = NFS4_OP_PUTROOTFH;

	/* Release any old export reference */
	if (op_ctx->ctx_export != NULL)
		put_gsh_export(op_ctx->ctx_export);

	op_ctx->ctx_export = NULL;
	op_ctx->fsal_export = NULL;

	/* Clear out current entry for now */
	set_current_entry(data, NULL);

	/* Get the root export of the Pseudo FS */
	op_ctx->ctx_export = get_gsh_export_by_pseudo("/", true);

	if (op_ctx->ctx_export == NULL) {
		LogCrit(COMPONENT_EXPORT,
			"Could not get export for Pseudo Root");

		res_PUTROOTFH4->status = NFS4ERR_NOENT;
		return res_PUTROOTFH4->status;
	}

	op_ctx->fsal_export = op_ctx->ctx_export->fsal_export;

	/* Build credentials */
	res_PUTROOTFH4->status = nfs4_export_check_access(data->req);

	/* Test for access error (export should not be visible). */
	if (res_PUTROOTFH4->status == NFS4ERR_ACCESS) {
		/* Client has no access at all */
		LogDebug(COMPONENT_EXPORT,
			 "Client doesn't have access to Pseudo Root");
		return res_PUTROOTFH4->status;
	}

	if (res_PUTROOTFH4->status != NFS4_OK) {
		LogMajor(COMPONENT_EXPORT,
			 "Failed to get FSAL credentials Pseudo Root");
		return res_PUTROOTFH4->status;
	}

	/* Get the Pesudo Root inode of the mounted on export */
	status = nfs_export_get_root_entry(op_ctx->ctx_export, &file_obj);
	if (FSAL_IS_ERROR(status)) {
		LogCrit(COMPONENT_EXPORT,
			"Could not get root inode for Pseudo Root");

		res_PUTROOTFH4->status = nfs4_Errno_status(status);
		return res_PUTROOTFH4->status;
	}

	LogMidDebug(COMPONENT_EXPORT,
		    "Root node %p", data->current_obj);

	set_current_entry(data, file_obj);

	/* Put our ref */
	file_obj->obj_ops.put_ref(file_obj);

	/* Convert it to a file handle */
	if (!nfs4_FSALToFhandle(data->currentFH.nfs_fh4_val == NULL,
				&data->currentFH,
				data->current_obj,
				op_ctx->ctx_export)) {
		LogCrit(COMPONENT_EXPORT,
			"Could not get handle for Pseudo Root");

		res_PUTROOTFH4->status = NFS4ERR_SERVERFAULT;
		return res_PUTROOTFH4->status;
	}

	LogHandleNFS4("NFS4 PUTROOTFH CURRENT FH: ", &data->currentFH);

	res_PUTROOTFH4->status = NFS4_OK;
	return res_PUTROOTFH4->status;
}				/* nfs4_op_putrootfh */
示例#2
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 */
示例#3
0
/**
 * @brief NFS4_OP_LOOKUPP
 *
 * This function implements the NFS4_OP_LOOKUPP operation, which looks
 * up the parent of the supplied directory.
 *
 * @param[in]     op   Arguments for nfs4_op
 * @param[in,out] data Compound request's data
 * @param[out]    resp Results for nfs4_op
 *
 * @return per RFC5661, p. 369
 *
 */
int nfs4_op_lookupp(struct nfs_argop4 *op, compound_data_t *data,
		    struct nfs_resop4 *resp)
{
	LOOKUPP4res * const res_LOOKUPP4 = &resp->nfs_resop4_u.oplookupp;
	struct fsal_obj_handle *dir_obj = NULL;
	struct fsal_obj_handle *file_obj;
	struct fsal_obj_handle *root_obj;
	fsal_status_t status;
	struct gsh_export *original_export = op_ctx->ctx_export;

	resp->resop = NFS4_OP_LOOKUPP;
	res_LOOKUPP4->status = NFS4_OK;

	/* Do basic checks on a filehandle */
	res_LOOKUPP4->status = nfs4_sanity_check_FH(data, DIRECTORY, false);

	if (res_LOOKUPP4->status != NFS4_OK)
		return res_LOOKUPP4->status;

	/* Preparing for cache_inode_lookup ".." */
	file_obj = NULL;
	dir_obj = data->current_obj;

	/* If Filehandle points to the root of the current export, then backup
	 * through junction into the containing export.
	 */
	if (data->current_obj->type != DIRECTORY)
		goto not_junction;

	PTHREAD_RWLOCK_rdlock(&original_export->lock);

	status = nfs_export_get_root_entry(original_export, &root_obj);
	if (FSAL_IS_ERROR(status)) {
		res_LOOKUPP4->status = nfs4_Errno_status(status);
		PTHREAD_RWLOCK_unlock(&original_export->lock);
		return res_LOOKUPP4->status;
	}

	if (data->current_obj == root_obj) {
		struct gsh_export *parent_exp = NULL;

		/* Handle reverse junction */
		LogDebug(COMPONENT_EXPORT,
			 "Handling reverse junction from Export_Id %d Path %s Parent=%p",
			 original_export->export_id,
			 original_export->fullpath,
			 original_export->exp_parent_exp);

		if (original_export->exp_parent_exp == NULL) {
			/* lookupp on the root on the pseudofs should return
			 * NFS4ERR_NOENT (RFC3530, page 166)
			 */
			PTHREAD_RWLOCK_unlock(&original_export->lock);
			res_LOOKUPP4->status = NFS4ERR_NOENT;
			return res_LOOKUPP4->status;
		}

		PTHREAD_RWLOCK_unlock(&original_export->lock);

		/* Clear out data->current entry outside lock
		 * so if it cascades into cleanup, we aren't holding
		 * an export lock that would cause trouble.
		 */
		set_current_entry(data, NULL);

		/* We need to protect accessing the parent information
		 * with the export lock. We use the current export's lock
		 * which is plenty, the parent can't go away without
		 * grabbing the current export's lock to clean out the
		 * parent information.
		 */
		PTHREAD_RWLOCK_rdlock(&original_export->lock);

		/* Get the junction inode into dir_obj and parent_exp
		 * for reference.
		 */
		dir_obj = original_export->exp_junction_obj;
		parent_exp = original_export->exp_parent_exp;

		/* Check if there is a problem with the export and try and
		 * get a reference to the parent export.
		 */
		if (dir_obj == NULL || parent_exp == NULL ||
		    !export_ready(parent_exp)) {
			/* Export is in the process of dying */
			PTHREAD_RWLOCK_unlock(&original_export->lock);
			LogCrit(COMPONENT_EXPORT,
				"Reverse junction from Export_Id %d Path %s Parent=%p is stale",
				original_export->export_id,
				original_export->fullpath,
				parent_exp);
			res_LOOKUPP4->status = NFS4ERR_STALE;
			return res_LOOKUPP4->status;
		}

		get_gsh_export_ref(parent_exp);

		dir_obj->obj_ops.get_ref(dir_obj);

		/* Set up dir_obj as current obj with an LRU reference
		 * while still holding the lock.
		 */
		set_current_entry(data, dir_obj);

		/* Put our ref */
		dir_obj->obj_ops.put_ref(dir_obj);

		/* Stash parent export in opctx while still holding the lock.
		 */
		op_ctx->ctx_export = parent_exp;
		op_ctx->fsal_export = op_ctx->ctx_export->fsal_export;

		/* Now we are safely transitioned to the parent export and can
		 * release the lock.
		 */
		PTHREAD_RWLOCK_unlock(&original_export->lock);

		/* Release old export reference that was held by opctx. */
		put_gsh_export(original_export);

		/* Build credentials */
		res_LOOKUPP4->status = nfs4_export_check_access(data->req);

		/* Test for access error (export should not be visible). */
		if (res_LOOKUPP4->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 Path %s with NFS4ERR_NOENT",
				 parent_exp->export_id,
				 parent_exp->fullpath);
			res_LOOKUPP4->status = NFS4ERR_NOENT;
			return res_LOOKUPP4->status;
		}
	} else {
		/* Release the lock taken above */
		PTHREAD_RWLOCK_unlock(&original_export->lock);
	}

	/* Return our ref from above */
	root_obj->obj_ops.put_ref(root_obj);

not_junction:

	status = fsal_lookupp(dir_obj, &file_obj, NULL);

	if (file_obj != NULL) {
		/* Convert it to a file handle */
		if (!nfs4_FSALToFhandle(false, &data->currentFH,
						file_obj,
						op_ctx->ctx_export)) {
			res_LOOKUPP4->status = NFS4ERR_SERVERFAULT;
			file_obj->obj_ops.put_ref(file_obj);
			return res_LOOKUPP4->status;
		}

		/* Keep the pointer within the compound data */
		set_current_entry(data, file_obj);

		/* Put our ref */
		file_obj->obj_ops.put_ref(file_obj);

		/* Return successfully */
		res_LOOKUPP4->status = NFS4_OK;
	} else {
		/* Unable to look up parent for some reason.
		 * Return error.
		 */
		set_current_entry(data, NULL);
		res_LOOKUPP4->status = nfs4_Errno_status(status);
	}

	return res_LOOKUPP4->status;
}				/* nfs4_op_lookupp */