Example #1
0
fsal_status_t vfs_write2(struct fsal_obj_handle *obj_hdl,
			 bool bypass,
			 struct state_t *state,
			 uint64_t offset,
			 size_t buffer_size,
			 void *buffer,
			 size_t *wrote_amount,
			 bool *fsal_stable,
			 struct io_info *info)
{
	ssize_t nb_written;
	fsal_status_t status;
	int retval = 0;
	int my_fd = -1;
	bool has_lock = false;
	bool need_fsync = false;
	bool closefd = false;
	fsal_openflags_t openflags = FSAL_O_WRITE;

	if (info != NULL) {
		/* Currently we don't support WRITE_PLUS */
		return fsalstat(ERR_FSAL_NOTSUPP, 0);
	}

	if (obj_hdl->fsal != obj_hdl->fs->fsal) {
		LogDebug(COMPONENT_FSAL,
			 "FSAL %s operation for handle belonging to FSAL %s, return EXDEV",
			 obj_hdl->fsal->name, obj_hdl->fs->fsal->name);
		return fsalstat(posix2fsal_error(EXDEV), EXDEV);
	}

	if (*fsal_stable)
		openflags |= FSAL_O_SYNC;

	/* Get a usable file descriptor */
	status = find_fd(&my_fd, obj_hdl, bypass, state, openflags,
			 &has_lock, &need_fsync, &closefd, false);

	if (FSAL_IS_ERROR(status)) {
		LogDebug(COMPONENT_FSAL,
			 "find_fd failed %s", msg_fsal_err(status.major));
		goto out;
	}

	fsal_set_credentials(op_ctx->creds);

	nb_written = pwrite(my_fd, buffer, buffer_size, offset);

	if (nb_written == -1) {
		retval = errno;
		status = fsalstat(posix2fsal_error(retval), retval);
		goto out;
	}

	*wrote_amount = nb_written;

	/* attempt stability if we aren't using an O_SYNC fd */
	if (need_fsync) {
		retval = fsync(my_fd);
		if (retval == -1) {
			retval = errno;
			status = fsalstat(posix2fsal_error(retval), retval);
		}
	}

 out:

	if (closefd)
		close(my_fd);

	if (has_lock)
		PTHREAD_RWLOCK_unlock(&obj_hdl->lock);

	fsal_restore_ganesha_credentials();
	return status;
}
Example #2
0
int nfs3_readdir(nfs_arg_t *arg, struct svc_req *req, nfs_res_t *res)
{
	struct fsal_obj_handle *dir_obj = NULL;
	struct fsal_obj_handle *parent_dir_obj = NULL;
	unsigned long count = 0;
	uint64_t cookie = 0;
	uint64_t fsal_cookie = 0;
	cookieverf3 cookie_verifier;
	unsigned int num_entries = 0;
	unsigned long estimated_num_entries = 0;
	object_file_type_t dir_filetype = 0;
	bool eod_met = false;
	fsal_status_t fsal_status = {0, 0};
	fsal_status_t fsal_status_gethandle = {0, 0};
	int rc = NFS_REQ_OK;
	struct nfs3_readdir_cb_data tracker = { NULL };
	bool use_cookie_verifier = op_ctx_export_has_option(
					EXPORT_OPTION_USE_COOKIE_VERIFIER);

	if (isDebug(COMPONENT_NFSPROTO) || isDebug(COMPONENT_NFS_READDIR)) {
		char str[LEN_FH_STR];
		log_components_t component;

		nfs_FhandleToStr(req->rq_vers,
				 &(arg->arg_readdir3.dir),
				 NULL,
				 str);

		if (isDebug(COMPONENT_NFSPROTO))
			component = COMPONENT_NFSPROTO;
		else
			component = COMPONENT_NFS_READDIR;

		LogDebug(component,
			 "REQUEST PROCESSING: Calling nfs_Readdir handle: %s",
			 str);
	}

	READDIR3resok * const RES_READDIR3_OK =
	    &res->res_readdir3.READDIR3res_u.resok;

	/* to avoid setting it on each error case */
	res->res_readdir3.READDIR3res_u.resfail.dir_attributes.
	    attributes_follow = FALSE;

	/* Look up object for filehandle */
	dir_obj = nfs3_FhandleToCache(&(arg->arg_readdir3.dir),
					&(res->res_readdir3.status),
					&rc);
	if (dir_obj == NULL) {
		/* Status and rc have been set by nfs3_FhandleToCache */
		goto out;
	}

	/* Extract the filetype */
	dir_filetype = dir_obj->type;
	/* Sanity checks -- must be a directory */
	if (dir_filetype != DIRECTORY) {
		res->res_readdir3.status = NFS3ERR_NOTDIR;

		rc = NFS_REQ_OK;
		goto out;
	}

	/* Parse out request arguments and decide how many entries we
	 * want.  For NFSv3, deal with the cookie verifier.
	 */

	count = arg->arg_readdir3.count;
	cookie = arg->arg_readdir3.cookie;
	estimated_num_entries =
	    MIN(count / (sizeof(entry3) - sizeof(char *)), 120);
	LogFullDebug(COMPONENT_NFS_READDIR,
		     "---> nfs3_readdir: count=%lu  cookie=%" PRIu64
		     " estimated_num_entries=%lu",
		     count, cookie, estimated_num_entries);
	if (estimated_num_entries == 0) {
		res->res_readdir3.status = NFS3ERR_TOOSMALL;
		rc = NFS_REQ_OK;
		goto out;
	}

	/* To make or check the cookie verifier */
	memset(cookie_verifier, 0, sizeof(cookieverf3));

	/* If cookie verifier is used, then a
	 * non-trivial value is returned to the
	 * client.
	 *
	 * This value is the ctime of the directory. If verifier is
	 * unused (as in many NFS Servers) then only a set of zeros
	 * is returned (trivial value).
	 */
	if (use_cookie_verifier) {
		struct attrlist attrs;

		fsal_prepare_attrs(&attrs, ATTR_CTIME);

		fsal_status = dir_obj->obj_ops.getattrs(dir_obj, &attrs);

		if (FSAL_IS_ERROR(fsal_status)) {
			res->res_readdir3.status =
						nfs3_Errno_status(fsal_status);
			LogFullDebug(COMPONENT_NFS_READDIR,
				     "getattrs returned %s",
				     msg_fsal_err(fsal_status.major));
			goto out;
		}

		memcpy(cookie_verifier,
		       &attrs.ctime.tv_sec,
		       sizeof(attrs.ctime.tv_sec));

		/* Done with the attrs */
		fsal_release_attrs(&attrs);
	}

	if (cookie != 0 && use_cookie_verifier) {
		/* Not the first call, so we have to check the cookie
		 * verifier
		 */
		if (memcmp(cookie_verifier,
			   arg->arg_readdir3.cookieverf,
			   NFS3_COOKIEVERFSIZE) != 0) {
			res->res_readdir3.status = NFS3ERR_BAD_COOKIE;
			rc = NFS_REQ_OK;
			goto out;
		}
	}

	tracker.entries = gsh_calloc(estimated_num_entries, sizeof(entry3));
	tracker.total_entries = estimated_num_entries;
	tracker.mem_left = count - sizeof(READDIR3resok);
	tracker.count = 0;
	tracker.error = NFS3_OK;

	/* Adjust the cookie we supply to fsal */
	if (cookie > 2) {	/* it is not the cookie for "." nor ".." */
		fsal_cookie = cookie;
	} else {
		fsal_cookie = 0;
	}

	/* Fills "."  */
	if (cookie == 0) {
		res->res_readdir3.status = nfs_readdir_dot_entry(dir_obj, ".",
					 1, nfs3_readdir_callback, &tracker);

		if (res->res_readdir3.status != NFS3_OK) {
			rc = NFS_REQ_OK;
			goto out;
		}
	}

	/* Fills ".." */
	if ((cookie <= 1) && (estimated_num_entries > 1)) {
		/* Get parent pentry */
		fsal_status_gethandle = fsal_lookupp(dir_obj,
						     &parent_dir_obj,
						     NULL);

		if (parent_dir_obj == NULL) {
			res->res_readdir3.status =
			    nfs3_Errno_status(fsal_status_gethandle);
			rc = NFS_REQ_OK;
			goto out;
		}

		res->res_readdir3.status = nfs_readdir_dot_entry(parent_dir_obj,
				"..", 2, nfs3_readdir_callback, &tracker);

		if (res->res_readdir3.status != NFS3_OK) {
			rc = NFS_REQ_OK;
			goto out;
		}

		parent_dir_obj->obj_ops.put_ref(parent_dir_obj);
		parent_dir_obj = NULL;
	}

	/* Call readdir */
	fsal_status = fsal_readdir(dir_obj, fsal_cookie, &num_entries, &eod_met,
				   0,	/* no attr */
				   nfs3_readdir_callback, &tracker);

	if (FSAL_IS_ERROR(fsal_status)) {
		if (nfs_RetryableError(fsal_status.major)) {
			rc = NFS_REQ_DROP;
			goto out;
		}

		res->res_readdir3.status = nfs3_Errno_status(fsal_status);
		nfs_SetPostOpAttr(dir_obj,
				  &res->res_readdir3.READDIR3res_u.resfail.
					dir_attributes,
				  NULL);
		goto out;
	}

	if (tracker.error != NFS3_OK) {
		res->res_readdir3.status = tracker.error;
		nfs_SetPostOpAttr(dir_obj,
				  &res->res_readdir3.READDIR3res_u.resfail.
					dir_attributes,
				  NULL);
		goto out;
	}

	LogFullDebug(COMPONENT_NFS_READDIR,
		     "-- Readdir -> Call to fsal_readdir(cookie=%"
		     PRIu64 ")",
		     fsal_cookie);

	if ((num_entries == 0) && (cookie > 1)) {
		RES_READDIR3_OK->reply.entries = NULL;
		RES_READDIR3_OK->reply.eof = TRUE;
	} else {
		RES_READDIR3_OK->reply.entries = tracker.entries;
		RES_READDIR3_OK->reply.eof = eod_met;
	}
	nfs_SetPostOpAttr(dir_obj, &RES_READDIR3_OK->dir_attributes, NULL);
	memcpy(RES_READDIR3_OK->cookieverf, cookie_verifier,
	       sizeof(cookieverf3));
	res->res_readdir3.status = NFS3_OK;

	rc = NFS_REQ_OK;

 out:
	/* return references */
	if (dir_obj)
		dir_obj->obj_ops.put_ref(dir_obj);

	if (parent_dir_obj)
		parent_dir_obj->obj_ops.put_ref(parent_dir_obj);

	/* Deallocate memory in the event of an error */
	if (((res->res_readdir3.status != NFS3_OK) || (rc != NFS_REQ_OK) ||
	    ((num_entries == 0) && (cookie > 1))) &&
	    (tracker.entries != NULL)) {
		free_entry3s(tracker.entries);
		RES_READDIR3_OK->reply.entries = NULL;
	}

	return rc;
}				/* nfs3_readdir */
Example #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 */
Example #4
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;
}
Example #5
0
/**
 * @brief Delete the unecessary directories from pseudo FS
 *
 * @param pseudopath [IN] full path of the node
 * @param entry [IN] cache entry for the last directory in the path
 *
 * If this entry is present is pseudo FSAL, and is unnecessary, then remove it.
 * Check recursively if the parent entry is needed.
 *
 * The pseudopath is deconstructed in place to create the subsequently shorter
 * pseudo paths.
 *
 * When called the first time, entry is the mount point of an export that has
 * been unmounted from the PseudoFS. By definition, it is NOT the root of a
 * PseudoFS. Also, the PseudoFS root filesystem is NOT mounted and thus this
 * function will not be called for it. The req_op_context references the
 * export for the PseudoFS entry is within. Note that the caller is
 * responsible for checking if it is an FSAL_PSEUDO export (we only clean up
 * directories in FSAL_PSEUDO filesystems).
 */
void cleanup_pseudofs_node(char *pseudopath,
			   struct fsal_obj_handle *obj)
{
	struct fsal_obj_handle *parent_obj;
	char *pos = pseudopath + strlen(pseudopath) - 1;
	char *name;
	fsal_status_t fsal_status;

	/* Strip trailing / from pseudopath */
	while (*pos == '/')
		pos--;

	/* Replace first trailing / if any with NUL */
	pos[1] = '\0';

	/* Find the previous slash.
	 * We will NEVER back up PAST the root, so no need to check
	 * for walking off the beginning of the string.
	 */
	while (*pos != '/')
		pos--;

	/* Remember the element name for remove */
	name = pos + 1;

	LogDebug(COMPONENT_EXPORT,
		 "Checking if pseudo node %s is needed", pseudopath);

	fsal_status = fsal_lookupp(obj, &parent_obj, NULL);

	if (FSAL_IS_ERROR(fsal_status)) {
		/* Truncate the pseudopath to be the path to the parent */
		*pos = '\0';
		LogCrit(COMPONENT_EXPORT,
			"Could not find cache entry for parent directory %s",
			pseudopath);
		return;
	}

	fsal_status = fsal_remove(parent_obj, name);

	if (FSAL_IS_ERROR(fsal_status)) {
		LogCrit(COMPONENT_EXPORT,
			"Removing pseudo node %s failed with %s",
			pseudopath, msg_fsal_err(fsal_status.major));
		goto out;
	}

	/* Before recursing the check the parent, get export lock for looking at
	 * exp_root_obj so we can check if we have reached the root of
	 * the mounted on export.
	 */
	PTHREAD_RWLOCK_rdlock(&op_ctx->ctx_export->lock);

	if (parent_obj == op_ctx->ctx_export->exp_root_obj) {
		LogDebug(COMPONENT_EXPORT,
			 "Reached root of PseudoFS %s",
			 op_ctx->ctx_export->pseudopath);

		PTHREAD_RWLOCK_unlock(&op_ctx->ctx_export->lock);
		goto out;
	}

	PTHREAD_RWLOCK_unlock(&op_ctx->ctx_export->lock);

	/* Truncate the pseudopath to be the path to the parent */
	*pos = '\0';

	/* check if the parent directory is needed */
	cleanup_pseudofs_node(pseudopath, parent_obj);

out:
	parent_obj->obj_ops.put_ref(parent_obj);
	return;
}