示例#1
0
/* lookup
 * deprecated NULL parent && NULL path implies root handle
 */
static fsal_status_t lookup(struct fsal_obj_handle *parent,
			    const char *path, struct fsal_obj_handle **handle,
			    struct attrlist *attrs_out)
{
	fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR;
	int retval = 0;
	fsal_status_t status;
	struct gpfs_fsal_obj_handle *hdl;
	struct attrlist attrib;
	struct gpfs_file_handle *fh = alloca(sizeof(struct gpfs_file_handle));
	struct fsal_filesystem *fs;

	*handle = NULL;		/* poison it first */
	fs = parent->fs;
	if (!path)
		return fsalstat(ERR_FSAL_FAULT, 0);
	memset(fh, 0, sizeof(struct gpfs_file_handle));
	fh->handle_size = GPFS_MAX_FH_SIZE;
	if (!parent->obj_ops.handle_is(parent, DIRECTORY)) {
		LogCrit(COMPONENT_FSAL,
			"Parent handle is not a directory. hdl = 0x%p", parent);
		return fsalstat(ERR_FSAL_NOTDIR, 0);
	}

	if (parent->fsal != parent->fs->fsal) {
		LogDebug(COMPONENT_FSAL,
			 "FSAL %s operation for handle belonging to FSAL %s, return EXDEV",
			 parent->fsal->name, parent->fs->fsal->name);
		retval = EXDEV;
		goto hdlerr;
	}

	fsal_prepare_attrs(&attrib, ATTR_GPFS_ALLOC_HANDLE);

	if (attrs_out != NULL)
		attrib.mask |= attrs_out->mask;

	status = GPFSFSAL_lookup(op_ctx, parent, path, &attrib, fh, &fs);
	if (FSAL_IS_ERROR(status))
		return status;

	/* allocate an obj_handle and fill it up */
	hdl = alloc_handle(fh, fs, &attrib, NULL, op_ctx->fsal_export);

	if (attrs_out != NULL) {
		/* Copy the attributes to caller, passing ACL ref. */
		fsal_copy_attrs(attrs_out, &attrib, true);
	} else {
		/* Done with the attrs */
		fsal_release_attrs(&attrib);
	}

	*handle = &hdl->obj_handle;
	return fsalstat(ERR_FSAL_NO_ERROR, 0);

 hdlerr:
	fsal_error = posix2fsal_error(retval);
	return fsalstat(fsal_error, retval);
}
示例#2
0
/* create
 * create a regular file and set its attributes
 */
fsal_status_t create(struct fsal_obj_handle *dir_hdl,
		     const char *name, struct attrlist *attr_in,
		     struct fsal_obj_handle **handle,
		     struct attrlist *attrs_out)
{
	struct gpfs_fsal_obj_handle *hdl;
	fsal_status_t status;
	/* Use a separate attrlist to getch the actual attributes into */
	struct attrlist attrib;

	struct gpfs_file_handle *fh = alloca(sizeof(struct gpfs_file_handle));

	*handle = NULL;		/* poison it */
	if (!dir_hdl->obj_ops.handle_is(dir_hdl, DIRECTORY)) {
		LogCrit(COMPONENT_FSAL,
			"Parent handle is not a directory. hdl = 0x%p",
			dir_hdl);
		return fsalstat(ERR_FSAL_NOTDIR, 0);
	}
	memset(fh, 0, sizeof(struct gpfs_file_handle));
	fh->handle_size = GPFS_MAX_FH_SIZE;

	fsal_prepare_attrs(&attrib, ATTR_GPFS_ALLOC_HANDLE);

	if (attrs_out != NULL)
		attrib.mask |= attrs_out->mask;

	status =
	    GPFSFSAL_create(dir_hdl, name, op_ctx, attr_in->mode, fh, &attrib);
	if (FSAL_IS_ERROR(status))
		return status;

	/* allocate an obj_handle and fill it up */
	hdl = alloc_handle(fh, dir_hdl->fs, &attrib, NULL, op_ctx->fsal_export);

	if (attrs_out != NULL) {
		/* Copy the attributes to caller, passing ACL ref. */
		fsal_copy_attrs(attrs_out, &attrib, true);
	} else {
		/* Done with the attrs */
		fsal_release_attrs(&attrib);
	}

	*handle = &hdl->obj_handle;
	return fsalstat(ERR_FSAL_NO_ERROR, 0);
}
示例#3
0
int _9p_lcreate(struct _9p_request_data *req9p, u32 *plenout, char *preply)
{
	char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE;
	u16 *msgtag = NULL;
	u32 *fid = NULL;
	u32 *flags = NULL;
	u32 *mode = NULL;
	u32 *gid = NULL;
	u16 *name_len = NULL;
	char *name_str = NULL;

	struct _9p_fid *pfid = NULL;
	struct _9p_qid qid_newfile;
	u32 iounit = _9P_IOUNIT;

	struct fsal_obj_handle *pentry_newfile = NULL;
	char file_name[MAXNAMLEN+1];
	fsal_status_t fsal_status;
	fsal_openflags_t openflags = 0;

	struct attrlist sattr;
	fsal_verifier_t verifier;
	enum fsal_create_mode createmode = FSAL_UNCHECKED;

	/* Get data */
	_9p_getptr(cursor, msgtag, u16);

	_9p_getptr(cursor, fid, u32);
	_9p_getstr(cursor, name_len, name_str);
	_9p_getptr(cursor, flags, u32);
	_9p_getptr(cursor, mode, u32);
	_9p_getptr(cursor, gid, u32);

	LogDebug(COMPONENT_9P,
		 "TLCREATE: tag=%u fid=%u name=%.*s flags=0%o mode=0%o gid=%u",
		 (u32) *msgtag, *fid, *name_len, name_str, *flags, *mode,
		 *gid);

	if (*fid >= _9P_FID_PER_CONN)
		return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply);

	pfid = req9p->pconn->fids[*fid];

	/* Check that it is a valid fid */
	if (pfid == NULL || pfid->pentry == NULL) {
		LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid);
		return _9p_rerror(req9p, msgtag, EIO, plenout, preply);
	}

	_9p_init_opctx(pfid, req9p);
	if ((op_ctx->export_perms->options &
				 EXPORT_OPTION_WRITE_ACCESS) == 0)
		return _9p_rerror(req9p, msgtag, EROFS, plenout, preply);

	if (*name_len >= sizeof(file_name)) {
		LogDebug(COMPONENT_9P, "request with name too long (%u)",
			 *name_len);
		return _9p_rerror(req9p, msgtag, ENAMETOOLONG, plenout,
				  preply);
	}
	snprintf(file_name, sizeof(file_name), "%.*s", *name_len, name_str);

	_9p_openflags2FSAL(flags, &openflags);
	pfid->state->state_data.fid.share_access =
		_9p_openflags_to_share_access(flags);

	memset(&verifier, 0, sizeof(verifier));

	memset(&sattr, 0, sizeof(sattr));
	sattr.valid_mask = ATTR_MODE | ATTR_GROUP;
	sattr.mode = *mode;
	sattr.group = *gid;

	if (*flags & 0x10) {
		/* Filesize is already 0. */
		sattr.valid_mask |= ATTR_SIZE;
	}

	if (*flags & 0x1000) {
		/* If OEXCL, use FSAL_EXCLUSIVE_9P create mode
		 * so that we can pass the attributes specified
		 * above. Verifier is ignored for this create mode
		 * because we don't have to deal with retry.
		 */
		createmode = FSAL_EXCLUSIVE_9P;
	}

	fsal_status = fsal_open2(pfid->pentry,
				 pfid->state,
				 openflags,
				 createmode,
				 file_name,
				 &sattr,
				 verifier,
				 &pentry_newfile,
				 NULL);

	/* Release the attributes (may release an inherited ACL) */
	fsal_release_attrs(&sattr);

	if (FSAL_IS_ERROR(fsal_status))
		return _9p_rerror(req9p, msgtag,
				  _9p_tools_errno(fsal_status),
				  plenout, preply);

	/* put parent directory entry */
	pfid->pentry->obj_ops->put_ref(pfid->pentry);

	/* Build the qid */
	qid_newfile.type = _9P_QTFILE;
	qid_newfile.version = 0;
	qid_newfile.path = pentry_newfile->fileid;

	/* The fid will represent the new file now - we can't fail anymore */
	pfid->pentry = pentry_newfile;
	pfid->qid = qid_newfile;
	pfid->xattr = NULL;
	pfid->opens = 1;

	/* Build the reply */
	_9p_setinitptr(cursor, preply, _9P_RLCREATE);
	_9p_setptr(cursor, msgtag, u16);

	_9p_setqid(cursor, qid_newfile);
	_9p_setvalue(cursor, iounit, u32);

	_9p_setendptr(cursor, preply);
	_9p_checkbound(cursor, preply, plenout);

	LogDebug(COMPONENT_9P,
		 "RLCREATE: tag=%u fid=%u name=%.*s qid=(type=%u,version=%u,path=%llu) iounit=%u pentry=%p",
		 (u32) *msgtag, *fid, *name_len, name_str, qid_newfile.type,
		 qid_newfile.version, (unsigned long long)qid_newfile.path,
		 iounit, pfid->pentry);

	return 1;
}
示例#4
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 */
示例#5
0
int _9p_mkdir(struct _9p_request_data *req9p, u32 *plenout, char *preply)
{
	char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE;
	u16 *msgtag = NULL;
	u32 *fid = NULL;
	u32 *mode = NULL;
	u32 *gid = NULL;
	u16 *name_len = NULL;
	char *name_str = NULL;

	struct _9p_fid *pfid = NULL;
	struct _9p_qid qid_newdir;

	struct fsal_obj_handle *pentry_newdir = NULL;
	char dir_name[MAXNAMLEN+1];
	fsal_status_t fsal_status;
	struct attrlist sattr;

	/* Get data */
	_9p_getptr(cursor, msgtag, u16);

	_9p_getptr(cursor, fid, u32);
	_9p_getstr(cursor, name_len, name_str);
	_9p_getptr(cursor, mode, u32);
	_9p_getptr(cursor, gid, u32);

	LogDebug(COMPONENT_9P,
		 "TMKDIR: tag=%u fid=%u name=%.*s mode=0%o gid=%u",
		 (u32) *msgtag, *fid, *name_len, name_str, *mode, *gid);

	if (*fid >= _9P_FID_PER_CONN)
		return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply);

	pfid = req9p->pconn->fids[*fid];

	/* Check that it is a valid fid */
	if (pfid == NULL || pfid->pentry == NULL) {
		LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid);
		return _9p_rerror(req9p, msgtag, EIO, plenout, preply);
	}

	_9p_init_opctx(pfid, req9p);

	if ((op_ctx->export_perms->options &
				 EXPORT_OPTION_WRITE_ACCESS) == 0)
		return _9p_rerror(req9p, msgtag, EROFS, plenout, preply);

	if (*name_len >= sizeof(dir_name)) {
		LogDebug(COMPONENT_9P, "request with name too long (%u)",
			 *name_len);
		return _9p_rerror(req9p, msgtag, ENAMETOOLONG, plenout,
				  preply);
	}
	snprintf(dir_name, sizeof(dir_name), "%.*s", *name_len, name_str);

	fsal_prepare_attrs(&sattr, ATTR_MODE);

	sattr.mode = *mode;
	sattr.valid_mask = ATTR_MODE;

	/* Create the directory */
	/* BUGAZOMEU: @todo : the gid parameter is not used yet */
	fsal_status = fsal_create(pfid->pentry, dir_name, DIRECTORY, &sattr,
				  NULL, &pentry_newdir, NULL);

	/* Release the attributes (may release an inherited ACL) */
	fsal_release_attrs(&sattr);

	if (FSAL_IS_ERROR(fsal_status))
		return _9p_rerror(req9p, msgtag,
				  _9p_tools_errno(fsal_status), plenout,
				  preply);

	pentry_newdir->obj_ops.put_ref(pentry_newdir);

	/* Build the qid */
	qid_newdir.type = _9P_QTDIR;
	qid_newdir.version = 0;
	qid_newdir.path = pentry_newdir->fileid;

	/* Build the reply */
	_9p_setinitptr(cursor, preply, _9P_RMKDIR);
	_9p_setptr(cursor, msgtag, u16);

	_9p_setqid(cursor, qid_newdir);

	_9p_setendptr(cursor, preply);
	_9p_checkbound(cursor, preply, plenout);

	LogDebug(COMPONENT_9P,
		 "RMKDIR: tag=%u fid=%u name=%.*s qid=(type=%u,version=%u,path=%llu)",
		 (u32) *msgtag, *fid, *name_len, name_str, qid_newdir.type,
		 qid_newdir.version, (unsigned long long)qid_newdir.path);

	return 1;
}
示例#6
0
static void open4_ex(OPEN4args *arg,
		     compound_data_t *data,
		     OPEN4res *res_OPEN4,
		     nfs_client_id_t *clientid,
		     state_owner_t *owner,
		     state_t **file_state,
		     bool *new_state)
{
	/* Parent directory in which to open the file. */
	struct fsal_obj_handle *parent = NULL;
	/* The entry we associated with the desired file before open. */
	struct fsal_obj_handle *file_obj = NULL;
	/* Indicator that file_obj came from lookup. */
	bool looked_up_file_obj = false;
	/* The in_obj to pass to fsal_open2. */
	struct fsal_obj_handle *in_obj = NULL;
	/* The entry open associated with the file. */
	struct fsal_obj_handle *out_obj = NULL;
	fsal_openflags_t openflags = 0;
	fsal_openflags_t old_openflags = 0;
	enum fsal_create_mode createmode = FSAL_NO_CREATE;
	/* The filename to create */
	char *filename = NULL;
	/* The supplied calim type */
	open_claim_type4 claim = arg->claim.claim;
	fsal_verifier_t verifier;
	struct attrlist sattr;
	/* Status for fsal calls */
	fsal_status_t status = {0, 0};
	/* The open state for the file */
	bool state_lock_held = false;

	/* Make sure the attributes are initialized */
	memset(&sattr, 0, sizeof(sattr));

	/* Make sure... */
	*file_state = NULL;
	*new_state = false;

	/* Pre-process the claim type */
	switch (claim) {
	case CLAIM_NULL:
		/* Check parent */
		parent = data->current_obj;
		in_obj = parent;

		/* Parent must be a directory */
		if (parent->type != DIRECTORY) {
			if (parent->type == SYMBOLIC_LINK) {
				res_OPEN4->status = NFS4ERR_SYMLINK;
				goto out;
			} else {
				res_OPEN4->status = NFS4ERR_NOTDIR;
				goto out;
			}
		}

		/* Validate and convert the utf8 filename */
		res_OPEN4->status =
		    nfs4_utf8string2dynamic(&arg->claim.open_claim4_u.file,
					    UTF8_SCAN_ALL, &filename);

		if (res_OPEN4->status != NFS4_OK)
			goto out;

		/* Set the createmode if appropriate) */
		if (arg->openhow.opentype == OPEN4_CREATE) {
			open4_ex_create_args(arg, data, res_OPEN4, verifier,
					     &createmode, &sattr);

			if (res_OPEN4->status != NFS4_OK)
				goto out;
		}

		status = fsal_lookup(parent, filename, &file_obj, NULL);

		if (!FSAL_IS_ERROR(status)) {
			/* Check create situations. */
			if (arg->openhow.opentype == OPEN4_CREATE) {
				if (createmode >= FSAL_EXCLUSIVE) {
					/* Could be a replay, need to continue.
					 */
					LogFullDebug(COMPONENT_STATE,
						     "EXCLUSIVE open with existing file %s",
						     filename);
				} else if (createmode == FSAL_GUARDED) {
					/* This will be a failure no matter'
					 * what.
					 */
					looked_up_file_obj = true;
					res_OPEN4->status = NFS4ERR_EXIST;
					goto out;
				} else {
					/* FSAL_UNCHECKED, may be a truncate
					 * and we need to pass in the case
					 * of fsal_reopen2 case.
					 */
					if (FSAL_TEST_MASK(sattr.valid_mask,
							   ATTR_SIZE) &&
					    sattr.filesize == 0) {
						LogFullDebug(COMPONENT_STATE,
							     "Truncate");
						openflags |= FSAL_O_TRUNC;
					}
				}
			}

			/* We found the file by lookup, discard the filename
			 * and remember that we found the entry by lookup.
			 */
			looked_up_file_obj = true;
			gsh_free(filename);
			filename = NULL;
		} else if (status.major != ERR_FSAL_NOENT ||
			   arg->openhow.opentype != OPEN4_CREATE) {
			/* A real error occurred */
			res_OPEN4->status = nfs4_Errno_status(status);
			goto out;
		}

		break;

		/* Both of these just use the current filehandle. */
	case CLAIM_PREVIOUS:
		owner->so_owner.so_nfs4_owner.so_confirmed = true;
		if (!nfs4_check_deleg_reclaim(clientid, &data->currentFH)) {
			/* It must have been revoked. Can't reclaim.*/
			LogInfo(COMPONENT_NFS_V4, "Can't reclaim delegation");
			res_OPEN4->status = NFS4ERR_RECLAIM_BAD;
			goto out;
		}
		openflags |= FSAL_O_RECLAIM;
		file_obj = data->current_obj;
		break;

	case CLAIM_FH:
		file_obj = data->current_obj;
		break;

	case CLAIM_DELEGATE_PREV:
		/* FIXME: Remove this when we have full support
		 * for CLAIM_DELEGATE_PREV and delegpurge operations
		 */
		res_OPEN4->status = NFS4ERR_NOTSUPP;
		goto out;

	case CLAIM_DELEGATE_CUR:
		res_OPEN4->status = open4_claim_deleg(arg, data);
		if (res_OPEN4->status != NFS4_OK)
			goto out;
		openflags |= FSAL_O_RECLAIM;
		file_obj = data->current_obj;
		break;

	default:
		LogFatal(COMPONENT_STATE,
			 "Programming error.  Invalid claim after check.");
	}

	if ((arg->share_access & OPEN4_SHARE_ACCESS_READ) != 0)
		openflags |= FSAL_O_READ;

	if ((arg->share_access & OPEN4_SHARE_ACCESS_WRITE) != 0)
		openflags |= FSAL_O_WRITE;

	if ((arg->share_deny & OPEN4_SHARE_DENY_READ) != 0)
		openflags |= FSAL_O_DENY_READ;

	if ((arg->share_deny & OPEN4_SHARE_DENY_WRITE) != 0)
		openflags |= FSAL_O_DENY_WRITE_MAND;

	/* Check if file_obj a REGULAR_FILE */
	if (file_obj != NULL && file_obj->type != REGULAR_FILE) {
		LogDebug(COMPONENT_NFS_V4,
			 "Wrong file type expected REGULAR_FILE actual %s",
			 object_file_type_to_str(file_obj->type));

		if (file_obj->type == DIRECTORY) {
			res_OPEN4->status = NFS4ERR_ISDIR;
		} else {
			/* All special nodes must return NFS4ERR_SYMLINK for
			 * proper client behavior per this linux-nfs post:
			 * http://marc.info/?l=linux-nfs&m=131342421825436&w=2
			 */
			res_OPEN4->status = NFS4ERR_SYMLINK;
		}

		goto out;
	}

	if (file_obj != NULL) {
		/* Go ahead and take the state lock now. */
		PTHREAD_RWLOCK_wrlock(&file_obj->state_hdl->state_lock);
		state_lock_held = true;
		in_obj = file_obj;

		/* Check if any existing delegations conflict with this open.
		 * Delegation recalls will be scheduled if there is a conflict.
		 */
		if (state_deleg_conflict(file_obj,
					  (arg->share_access &
					   OPEN4_SHARE_ACCESS_WRITE) != 0)) {
			res_OPEN4->status = NFS4ERR_DELAY;
			goto out;
		}

		/* Check if there is already a state for this entry and owner.
		 */
		*file_state = nfs4_State_Get_Obj(file_obj, owner);

		if (isFullDebug(COMPONENT_STATE) && *file_state != NULL) {
			char str[LOG_BUFF_LEN] = "\0";
			struct display_buffer dspbuf = {sizeof(str), str, str};

			display_stateid(&dspbuf, *file_state);

			LogFullDebug(COMPONENT_STATE,
				     "Found existing state %s",
				     str);
		}

		/* Check if open from another export */
		if (*file_state != NULL &&
		    !state_same_export(*file_state, op_ctx->ctx_export)) {
			LogEvent(COMPONENT_STATE,
				 "Lock Owner Export Conflict, Lock held for export %"
				 PRIu16" request for export %"PRIu16,
				 state_export_id(*file_state),
				 op_ctx->ctx_export->export_id);
			res_OPEN4->status = NFS4ERR_INVAL;
			goto out;
		}
	}

	/* If that did not succeed, allocate a state from the FSAL. */
	if (*file_state == NULL) {
		*file_state = op_ctx->fsal_export->exp_ops.alloc_state(
							op_ctx->fsal_export,
							STATE_TYPE_SHARE,
							NULL);

		/* Remember we allocated a new state */
		*new_state = true;

		/* We are ready to perform the open (with possible create).
		 * in_obj has been set to the file itself or the parent.
		 * filename is NULL if in_obj is the file itself.
		 *
		 * Permission check has been done on directory if appropriate,
		 * otherwise fsal_open2 will do a directory permission
		 * check.
		 *
		 * fsal_open2 handles the permission check on the file
		 * itself and also handles all the share reservation stuff.
		 *
		 * fsal_open2 returns with a ref on out_obj, which should be
		 * passed to the state.
		 */
		LogFullDebug(COMPONENT_STATE,
			     "Calling open2 for %s", filename);

		status = fsal_open2(in_obj,
				    *file_state,
				    openflags,
				    createmode,
				    filename,
				    &sattr,
				    verifier,
				    &out_obj,
				    NULL);

		if (FSAL_IS_ERROR(status)) {
			res_OPEN4->status = nfs4_Errno_status(status);
			goto out;
		}
	} else if (createmode >= FSAL_EXCLUSIVE) {
		/* We have an EXCLUSIVE create with an existing
		 * state. We still need to verify it, but no need
		 * to call reopen2.
		 */
		LogFullDebug(COMPONENT_STATE, "Calling verify2 ");

		status = fsal_verify2(file_obj, verifier);

		if (FSAL_IS_ERROR(status)) {
			res_OPEN4->status = nfs4_Errno_status(status);
			goto out;
		}

		/* We need an extra reference below. */
		file_obj->obj_ops->get_ref(file_obj);
	} else {
		old_openflags =
			file_obj->obj_ops->status2(file_obj, *file_state);

		/* Open upgrade */
		LogFullDebug(COMPONENT_STATE, "Calling reopen2");

		status = fsal_reopen2(file_obj, *file_state,
				      openflags | old_openflags,
				      false);

		if (FSAL_IS_ERROR(status)) {
			res_OPEN4->status = nfs4_Errno_status(status);
			goto out;
		}

		/* We need an extra reference below. */
		file_obj->obj_ops->get_ref(file_obj);
	}

	if (file_obj == NULL) {
		/* We have a new cache inode entry, take the state lock. */
		file_obj = out_obj;
		PTHREAD_RWLOCK_wrlock(&file_obj->state_hdl->state_lock);
		state_lock_held = true;
	}

	/* Now the state_lock is held for sure and we have an extra LRU
	 * reference to file_obj, which is the opened file.
	 */

	if (*new_state) {
		/* The state data to be added */
		union state_data candidate_data;
		/* Tracking data for the open state */
		struct state_refer refer, *p_refer = NULL;
		state_status_t state_status;

		candidate_data.share.share_access =
		    arg->share_access & OPEN4_SHARE_ACCESS_BOTH;
		candidate_data.share.share_deny = arg->share_deny;
		candidate_data.share.share_access_prev =
			(1 << candidate_data.share.share_access);
		candidate_data.share.share_deny_prev =
			(1 << candidate_data.share.share_deny);

		LogFullDebug(COMPONENT_STATE,
			     "Creating new state access=%x deny=%x access_prev=%x deny_prev=%x",
			     candidate_data.share.share_access,
			     candidate_data.share.share_deny,
			     candidate_data.share.share_access_prev,
			     candidate_data.share.share_deny_prev);

		/* Record the sequence info */
		if (data->minorversion > 0) {
			memcpy(refer.session,
			       data->session->session_id,
			       sizeof(sessionid4));
			refer.sequence = data->sequence;
			refer.slot = data->slot;
			p_refer = &refer;
		}

		/* We need to register this state now. */
		state_status = state_add_impl(file_obj,
					      STATE_TYPE_SHARE,
					      &candidate_data,
					      owner,
					      file_state,
					      p_refer);

		if (state_status != STATE_SUCCESS) {
			/* state_add_impl failure closed and freed state.
			 * file_state will also be NULL at this point. Also
			 * release the ref on file_obj, since the state add
			 * failed.
			 */
			file_obj->obj_ops->put_ref(file_obj);
			res_OPEN4->status = nfs4_Errno_state(state_status);
			*new_state = false;
			goto out;
		}

		glist_init(&(*file_state)->state_data.share.share_lockstates);
	}

	res_OPEN4->status = open4_create_fh(data, file_obj, true);

	if (res_OPEN4->status != NFS4_OK) {
		if (*new_state) {
			/* state_del_locked will close the file. */
			state_del_locked(*file_state);
			*file_state = NULL;
			*new_state = false;
		} else {
			/*Do an open downgrade to the old open flags */
			status = file_obj->obj_ops->reopen2(file_obj,
							   *file_state,
							   old_openflags);
			if (FSAL_IS_ERROR(status)) {
				LogCrit(COMPONENT_NFS_V4,
					"Failed to allocate handle, reopen2 failed with %s",
					fsal_err_txt(status));
			}

			/* Need to release the state_lock before the put_ref
			 * call.
			 */
			PTHREAD_RWLOCK_unlock(&file_obj->state_hdl->state_lock);
			state_lock_held = false;

			/* Release the extra LRU reference on file_obj. */
			file_obj->obj_ops->put_ref(file_obj);
			goto out;
		}
	}

	/* Since open4_create_fh succeeded the LRU reference to file_obj was
	 * consumed by data->current_obj.
	 */

	if (!(*new_state)) {
		LogFullDebug(COMPONENT_STATE,
			     "Open upgrade old access=%x deny=%x access_prev=%x deny_prev=%x",
			     (*file_state)->state_data.share.share_access,
			     (*file_state)->state_data.share.share_deny,
			     (*file_state)->state_data.share.share_access_prev,
			     (*file_state)->state_data.share.share_deny_prev);

		LogFullDebug(COMPONENT_STATE,
			     "Open upgrade to access=%x deny=%x",
			     arg->share_access,
			     arg->share_deny);

		/* Update share_access and share_deny */
		(*file_state)->state_data.share.share_access |=
			arg->share_access & OPEN4_SHARE_ACCESS_BOTH;

		(*file_state)->state_data.share.share_deny |=
			arg->share_deny;

		/* Update share_access_prev and share_deny_prev */
		(*file_state)->state_data.share.share_access_prev |=
			(1 << (arg->share_access & OPEN4_SHARE_ACCESS_BOTH));

		(*file_state)->state_data.share.share_deny_prev |=
			(1 << arg->share_deny);

		LogFullDebug(COMPONENT_STATE,
			     "Open upgrade new access=%x deny=%x access_prev=%x deny_prev=%x",
			     (*file_state)->state_data.share.share_access,
			     (*file_state)->state_data.share.share_deny,
			     (*file_state)->state_data.share.share_access_prev,
			     (*file_state)->state_data.share.share_deny_prev);
	}

	do_delegation(arg, res_OPEN4, data, owner, *file_state, clientid);
 out:

	/* Release the attributes (may release an inherited ACL) */
	fsal_release_attrs(&sattr);

	if (state_lock_held)
		PTHREAD_RWLOCK_unlock(&file_obj->state_hdl->state_lock);

	if (filename)
		gsh_free(filename);

	if (res_OPEN4->status != NFS4_OK) {
		/* Cleanup state on error */
		if (*new_state)
			(*file_state)
				->state_exp->exp_ops.free_state(
					(*file_state)->state_exp, *file_state);
		else if (*file_state != NULL)
			dec_state_t_ref(*file_state);
		*file_state = NULL;
	}

	if (looked_up_file_obj) {
		/* We got file_obj via lookup, we need to unref it. */
		file_obj->obj_ops->put_ref(file_obj);
	}
}
示例#7
0
int nfs3_lookup(nfs_arg_t *arg, struct svc_req *req, nfs_res_t *res)
{
	struct fsal_obj_handle *obj_dir = NULL;
	struct fsal_obj_handle *obj_file = NULL;
	fsal_status_t fsal_status;
	char *name = NULL;
	int rc = NFS_REQ_OK;
	struct attrlist attrs;

	/* We have the option of not sending attributes, so set ATTR_RDATTR_ERR.
	 */
	fsal_prepare_attrs(&attrs, ATTRS_NFS3 | ATTR_RDATTR_ERR);

	if (isDebug(COMPONENT_NFSPROTO)) {
		char str[LEN_FH_STR];

		name = arg->arg_lookup3.what.name;

		nfs_FhandleToStr(req->rq_msg.cb_vers,
				 &(arg->arg_lookup3.what.dir),
				 NULL, str);
		LogDebug(COMPONENT_NFSPROTO,
			 "REQUEST PROCESSING: Calling nfs_Lookup handle: %s name: %s",
			 str, name);
	}

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

	obj_dir = nfs3_FhandleToCache(&arg->arg_lookup3.what.dir,
					&res->res_lookup3.status,
					&rc);

	if (obj_dir == NULL) {
		/* Status and rc have been set by nfs3_FhandleToCache */
		goto out;
	}

	name = arg->arg_lookup3.what.name;

	fsal_status = fsal_lookup(obj_dir, name, &obj_file, &attrs);

	if (FSAL_IS_ERROR(fsal_status)) {
		/* If we are here, there was an error */
		if (nfs_RetryableError(fsal_status.major)) {
			rc = NFS_REQ_DROP;
			goto out;
		}

		res->res_lookup3.status = nfs3_Errno_status(fsal_status);
		nfs_SetPostOpAttr(obj_dir,
				  &res->res_lookup3.LOOKUP3res_u.resfail.
					dir_attributes,
				  NULL);
	} else {
		/* Build FH */
		if (nfs3_FSALToFhandle(
			    true,
			    &res->res_lookup3.LOOKUP3res_u.resok.object,
			    obj_file,
			    op_ctx->ctx_export)) {
			/* Build entry attributes */
			nfs_SetPostOpAttr(obj_file,
					  &res->res_lookup3.LOOKUP3res_u.
						resok.obj_attributes,
					  &attrs);

			/* Build directory attributes */
			nfs_SetPostOpAttr(obj_dir,
					  &res->res_lookup3.
					     LOOKUP3res_u.resok.dir_attributes,
					  NULL);
			res->res_lookup3.status = NFS3_OK;
		} else {
			res->res_lookup3.status = NFS3ERR_BADHANDLE;
		}
	}

	rc = NFS_REQ_OK;

 out:

	/* Release the attributes. */
	fsal_release_attrs(&attrs);

	/* return references */
	if (obj_dir)
		obj_dir->obj_ops.put_ref(obj_dir);

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

	return rc;
}				/* nfs3_lookup */
示例#8
0
int _9p_setattr(struct _9p_request_data *req9p, u32 *plenout, char *preply)
{
	char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE;
	u16 *msgtag = NULL;
	u32 *fid = NULL;
	u32 *valid = NULL;
	u32 *mode = NULL;
	u32 *uid = NULL;
	u32 *gid = NULL;
	u64 *size = NULL;
	u64 *atime_sec = NULL;
	u64 *atime_nsec = NULL;
	u64 *mtime_sec = NULL;
	u64 *mtime_nsec = NULL;

	struct _9p_fid *pfid = NULL;

	struct attrlist fsalattr;
	fsal_status_t fsal_status;

	struct timeval t;

	/* Get data */
	_9p_getptr(cursor, msgtag, u16);
	_9p_getptr(cursor, fid, u32);

	_9p_getptr(cursor, valid, u32);
	_9p_getptr(cursor, mode, u32);
	_9p_getptr(cursor, uid, u32);
	_9p_getptr(cursor, gid, u32);
	_9p_getptr(cursor, size, u64);
	_9p_getptr(cursor, atime_sec, u64);
	_9p_getptr(cursor, atime_nsec, u64);
	_9p_getptr(cursor, mtime_sec, u64);
	_9p_getptr(cursor, mtime_nsec, u64);

	LogDebug(COMPONENT_9P,
		 "TSETATTR: tag=%u fid=%u valid=0x%x mode=0%o uid=%u gid=%u size=%"
		 PRIu64 " atime=(%llu|%llu) mtime=(%llu|%llu)", (u32) *msgtag,
		 *fid, *valid, *mode, *uid, *gid, *size,
		 (unsigned long long)*atime_sec,
		 (unsigned long long)*atime_nsec,
		 (unsigned long long)*mtime_sec,
		 (unsigned long long)*mtime_nsec);

	if (*fid >= _9P_FID_PER_CONN)
		return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply);

	pfid = req9p->pconn->fids[*fid];

	/* Check that it is a valid fid */
	if (pfid == NULL || pfid->pentry == NULL) {
		LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid);
		return _9p_rerror(req9p, msgtag, EIO, plenout, preply);
	}

	_9p_init_opctx(pfid, req9p);

	if ((op_ctx->export_perms->options &
				 EXPORT_OPTION_WRITE_ACCESS) == 0)
		return _9p_rerror(req9p, msgtag, EROFS, plenout, preply);

	/* If a "time" change is required, but not with the "_set" suffix,
	 * use gettimeofday */
	if (*valid &
	    (_9P_SETATTR_ATIME | _9P_SETATTR_CTIME | _9P_SETATTR_MTIME)) {
		if (gettimeofday(&t, NULL) == -1) {
			LogMajor(COMPONENT_9P,
				 "TSETATTR: tag=%u fid=%u ERROR !! gettimeofday returned -1 with errno=%u",
				 (u32) *msgtag, *fid, errno);
			return _9p_rerror(req9p, msgtag, errno,
					  plenout, preply);
		}
	}

	/* Let's do the job */
	memset((char *)&fsalattr, 0, sizeof(fsalattr));

	if (*valid & _9P_SETATTR_MODE) {
		FSAL_SET_MASK(fsalattr.mask, ATTR_MODE);
		fsalattr.mode = *mode;
	}

	if (*valid & _9P_SETATTR_UID) {
		FSAL_SET_MASK(fsalattr.mask, ATTR_OWNER);
		fsalattr.owner = *uid;
	}

	if (*valid & _9P_SETATTR_GID) {
		FSAL_SET_MASK(fsalattr.mask, ATTR_GROUP);
		fsalattr.group = *gid;
	}

	if (*valid & _9P_SETATTR_SIZE) {
		FSAL_SET_MASK(fsalattr.mask, ATTR_SIZE);
		fsalattr.filesize = *size;
	}

	if (*valid & _9P_SETATTR_ATIME) {
		FSAL_SET_MASK(fsalattr.mask, ATTR_ATIME);
		fsalattr.atime.tv_sec = t.tv_sec;
		fsalattr.atime.tv_nsec = t.tv_usec * 1000;
	}

	if (*valid & _9P_SETATTR_MTIME) {
		FSAL_SET_MASK(fsalattr.mask, ATTR_MTIME);
		fsalattr.mtime.tv_sec = t.tv_sec;
		fsalattr.mtime.tv_nsec = t.tv_usec * 1000;
	}

	if (*valid & _9P_SETATTR_CTIME) {
		FSAL_SET_MASK(fsalattr.mask, ATTR_CTIME);
		fsalattr.ctime.tv_sec = t.tv_sec;
		fsalattr.ctime.tv_nsec = t.tv_usec * 1000;
	}

	if (*valid & _9P_SETATTR_ATIME_SET) {
		FSAL_SET_MASK(fsalattr.mask, ATTR_ATIME);
		fsalattr.atime.tv_sec = *atime_sec;
		fsalattr.atime.tv_nsec = *atime_nsec;
	}

	if (*valid & _9P_SETATTR_MTIME_SET) {
		FSAL_SET_MASK(fsalattr.mask, ATTR_MTIME);
		fsalattr.mtime.tv_sec = *mtime_sec;
		fsalattr.mtime.tv_nsec = *mtime_nsec;
	}

	/* Now set the attr */
	fsal_status = fsal_setattr(pfid->pentry, false, pfid->state, &fsalattr);

	/* Release the attributes (may release an inherited ACL) */
	fsal_release_attrs(&fsalattr);

	if (FSAL_IS_ERROR(fsal_status))
		return _9p_rerror(req9p, msgtag,
				  _9p_tools_errno(fsal_status), plenout,
				  preply);

	/* Build the reply */
	_9p_setinitptr(cursor, preply, _9P_RSETATTR);
	_9p_setptr(cursor, msgtag, u16);

	_9p_setendptr(cursor, preply);
	_9p_checkbound(cursor, preply, plenout);

	LogDebug(COMPONENT_9P,
		 "RSETATTR: tag=%u fid=%u valid=0x%x mode=0%o uid=%u gid=%u size=%"
		 PRIu64 " atime=(%llu|%llu) mtime=(%llu|%llu)", (u32) *msgtag,
		 *fid, *valid, *mode, *uid, *gid, *size,
		 (unsigned long long)*atime_sec,
		 (unsigned long long)*atime_nsec,
		 (unsigned long long)*mtime_sec,
		 (unsigned long long)*mtime_nsec);

	/* _9p_stat_update(*pmsgtype, TRUE, &pwkrdata->stats._9p_stat_req); */
	return 1;
}
示例#9
0
/**
 * @brief create GPFS handle
 *
 * @param exp_hdl export handle
 * @param hdl_desc handle description
 * @param handle object handle
 * @return status
 *
 * Does what original FSAL_ExpandHandle did (sort of)
 * returns a ref counted handle to be later used in cache_inode etc.
 * NOTE! you must release this thing when done with it!
 * BEWARE! Thanks to some holes in the *AT syscalls implementation,
 * we cannot get an fd on an AF_UNIX socket, nor reliably on block or
 * character special devices.  Sorry, it just doesn't...
 * we could if we had the handle of the dir it is in, but this method
 * is for getting handles off the wire for cache entries that have LRU'd.
 * Ideas and/or clever hacks are welcome...
 */
fsal_status_t gpfs_create_handle(struct fsal_export *exp_hdl,
				 struct gsh_buffdesc *hdl_desc,
				 struct fsal_obj_handle **handle,
				 struct attrlist *attrs_out)
{
	int retval = 0;
	fsal_status_t status;
	struct gpfs_fsal_obj_handle *hdl;
	struct gpfs_file_handle *fh;
	struct attrlist attrib;
	char *link_content = NULL;
	ssize_t retlink = PATH_MAX - 1;
	char link_buff[PATH_MAX];
	struct fsal_fsid__ fsid;
	struct fsal_filesystem *fs;
	struct gpfs_filesystem *gpfs_fs;

	*handle = NULL;		/* poison it first */
	if ((hdl_desc->len > (sizeof(struct gpfs_file_handle))))
		return fsalstat(ERR_FSAL_FAULT, 0);

	fh = alloca(hdl_desc->len);
	memcpy(fh, hdl_desc->addr, hdl_desc->len); /* struct aligned copy */

	gpfs_extract_fsid(fh, &fsid);

	fs = lookup_fsid(&fsid, GPFS_FSID_TYPE);

	if (fs == NULL) {
		LogInfo(COMPONENT_FSAL,
			"Could not find filesystem for fsid=0x%016"PRIx64
			".0x%016"PRIx64" from handle",
			fsid.major, fsid.minor);
		return fsalstat(ERR_FSAL_STALE, ESTALE);
	}

	if (fs->fsal != exp_hdl->fsal) {
		LogInfo(COMPONENT_FSAL,
			"Non GPFS filesystem fsid=0x%016"PRIx64
			".0x%016"PRIx64" from handle",
			fsid.major, fsid.minor);
		return fsalstat(ERR_FSAL_STALE, ESTALE);
	}

	gpfs_fs = fs->private_data;

	fsal_prepare_attrs(&attrib, ATTR_GPFS_ALLOC_HANDLE);

	if (attrs_out != NULL)
		attrib.mask |= attrs_out->mask;

	status = GPFSFSAL_getattrs(exp_hdl, gpfs_fs, op_ctx, fh, &attrib);
	if (FSAL_IS_ERROR(status))
		return status;

	if (attrib.type == SYMBOLIC_LINK) {	/* I could lazy eval this... */

		status = fsal_readlink_by_handle(gpfs_fs->root_fd, fh,
						 link_buff, &retlink);
		if (FSAL_IS_ERROR(status))
			return status;

		if (retlink < 0 || retlink == PATH_MAX) {
			retval = errno;
			if (retlink == PATH_MAX)
				retval = ENAMETOOLONG;
			return fsalstat(posix2fsal_error(retval), retval);
		}
		link_buff[retlink] = '\0';
		link_content = link_buff;
	}

	hdl = alloc_handle(fh, fs, &attrib, link_content, exp_hdl);

	if (attrs_out != NULL) {
		/* Copy the attributes to caller, passing ACL ref. */
		fsal_copy_attrs(attrs_out, &attrib, true);
	} else {
		/* Done with the attrs */
		fsal_release_attrs(&attrib);
	}

	*handle = &hdl->obj_handle;

	return status;
}
示例#10
0
int nfs4_op_verify(struct nfs_argop4 *op, compound_data_t *data,
		   struct nfs_resop4 *resp)
{
	VERIFY4args * const arg_VERIFY4 = &op->nfs_argop4_u.opverify;
	VERIFY4res * const res_VERIFY4 = &resp->nfs_resop4_u.opverify;
	fattr4 file_attr4;
	int rc = 0;
	struct attrlist attrs;

	resp->resop = NFS4_OP_VERIFY;
	res_VERIFY4->status = NFS4_OK;

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

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

	/* Get only attributes that are allowed to be read */
	if (!nfs4_Fattr_Check_Access
	    (&arg_VERIFY4->obj_attributes, FATTR4_ATTR_READ)) {
		res_VERIFY4->status = NFS4ERR_INVAL;
		return res_VERIFY4->status;
	}

	/* Ask only for supported attributes */
	if (!nfs4_Fattr_Supported(&arg_VERIFY4->obj_attributes)) {
		res_VERIFY4->status = NFS4ERR_ATTRNOTSUPP;
		return res_VERIFY4->status;
	}

	fsal_prepare_attrs(&attrs, 0);

	res_VERIFY4->status =
		bitmap4_to_attrmask_t(&arg_VERIFY4->obj_attributes.attrmask,
				      &attrs.mask);

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

	res_VERIFY4->status =
		file_To_Fattr(data, attrs.mask, &attrs, &file_attr4,
			      &arg_VERIFY4->obj_attributes.attrmask);

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

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

	rc = nfs4_Fattr_cmp(&(arg_VERIFY4->obj_attributes), &file_attr4);

	if (rc == true)
		res_VERIFY4->status = NFS4_OK;
	else if (rc == -1)
		res_VERIFY4->status = NFS4ERR_INVAL;
	else
		res_VERIFY4->status = NFS4ERR_NOT_SAME;

	nfs4_Fattr_Free(&file_attr4);
	return res_VERIFY4->status;
}				/* nfs4_op_verify */
示例#11
0
static int nfs4_read(struct nfs_argop4 *op, compound_data_t *data,
		    struct nfs_resop4 *resp, fsal_io_direction_t io,
		    struct io_info *info)
{
	READ4args * const arg_READ4 = &op->nfs_argop4_u.opread;
	READ4res * const res_READ4 = &resp->nfs_resop4_u.opread;
	uint64_t size = 0;
	size_t read_size = 0;
	uint64_t offset = 0;
	bool eof_met = false;
	void *bufferdata = NULL;
	fsal_status_t fsal_status = {0, 0};
	state_t *state_found = NULL;
	state_t *state_open = NULL;
	struct fsal_obj_handle *obj = NULL;
	bool sync = false;
	bool anonymous_started = false;
	state_owner_t *owner = NULL;
	bool bypass = false;
	uint64_t MaxRead = atomic_fetch_uint64_t(&op_ctx->ctx_export->MaxRead);
	uint64_t MaxOffsetRead =
			atomic_fetch_uint64_t(
				&op_ctx->ctx_export->MaxOffsetRead);

	/* Say we are managing NFS4_OP_READ */
	resp->resop = NFS4_OP_READ;
	res_READ4->status = NFS4_OK;

	/* Do basic checks on a filehandle Only files can be read */

	if ((data->minorversion > 0)
	    && nfs4_Is_Fh_DSHandle(&data->currentFH)) {
		if (io == FSAL_IO_READ)
			return op_dsread(op, data, resp);
		else
			return op_dsread_plus(op, data, resp, info);
	}

	res_READ4->status = nfs4_sanity_check_FH(data, REGULAR_FILE, true);
	if (res_READ4->status != NFS4_OK)
		return res_READ4->status;

	obj = data->current_obj;
	/* Check stateid correctness and get pointer to state (also
	   checks for special stateids) */

	res_READ4->status =
	    nfs4_Check_Stateid(&arg_READ4->stateid, obj, &state_found, data,
			       STATEID_SPECIAL_ANY, 0, false, "READ");
	if (res_READ4->status != NFS4_OK)
		return res_READ4->status;

	/* NB: After this point, if state_found == NULL, then the
	   stateid is all-0 or all-1 */

	if (state_found != NULL) {
		struct state_deleg *sdeleg;

		if (info)
			info->io_advise = state_found->state_data.io_advise;
		switch (state_found->state_type) {
		case STATE_TYPE_SHARE:
			state_open = state_found;
			/* Note this causes an extra refcount, but it
			 * simplifies logic below.
			 */
			inc_state_t_ref(state_open);
			/**
			 * @todo FSF: need to check against existing locks
			 */
			break;

		case STATE_TYPE_LOCK:
			state_open = state_found->state_data.lock.openstate;
			inc_state_t_ref(state_open);
			/**
			 * @todo FSF: should check that write is in
			 * range of an byte range lock...
			 */
			break;

		case STATE_TYPE_DELEG:
			/* Check if the delegation state allows READ */
			sdeleg = &state_found->state_data.deleg;
			if (!(sdeleg->sd_type & OPEN_DELEGATE_READ) ||
				(sdeleg->sd_state != DELEG_GRANTED)) {
				/* Invalid delegation for this operation. */
				LogDebug(COMPONENT_STATE,
					"Delegation type:%d state:%d",
					sdeleg->sd_type,
					sdeleg->sd_state);
				res_READ4->status = NFS4ERR_BAD_STATEID;
				goto out;
			}

			state_open = NULL;
			break;

		default:
			res_READ4->status = NFS4ERR_BAD_STATEID;
			LogDebug(COMPONENT_NFS_V4_LOCK,
				 "READ with invalid statid of type %d",
				 state_found->state_type);
			goto out;
		}

		/* This is a read operation, this means that the file
		   MUST have been opened for reading */
		if (state_open != NULL
		    && (state_open->state_data.share.
			share_access & OPEN4_SHARE_ACCESS_READ) == 0) {
			/* Even if file is open for write, the client
			 * may do accidently read operation (caching).
			 * Because of this, READ is allowed if not
			 * explicitly denied.  See page 112 in RFC 7530
			 * for more details.
			 */

			if (state_open->state_data.share.
			    share_deny & OPEN4_SHARE_DENY_READ) {
				/* Bad open mode, return NFS4ERR_OPENMODE */
				res_READ4->status = NFS4ERR_OPENMODE;

				if (isDebug(COMPONENT_NFS_V4_LOCK)) {
					char str[LOG_BUFF_LEN] = "\0";
					struct display_buffer dspbuf = {
							sizeof(str), str, str};
					display_stateid(&dspbuf, state_found);
					LogDebug(COMPONENT_NFS_V4_LOCK,
						 "READ %s doesn't have OPEN4_SHARE_ACCESS_READ",
						 str);
				}
				goto out;
			}
		}

		/**
		 * @todo : this piece of code looks a bit suspicious
		 *  (see Rong's mail)
		 *
		 * @todo: ACE: This works for now.  How do we want to
		 * handle owner confirmation across NFSv4.0/NFSv4.1?
		 * Do we want to mark every NFSv4.1 owner
		 * pre-confirmed, or make the check conditional on
		 * minorversion like we do here?
		 */
		switch (state_found->state_type) {
		case STATE_TYPE_SHARE:
			if (data->minorversion == 0 &&
			    !state_owner_confirmed(state_found)) {
				res_READ4->status = NFS4ERR_BAD_STATEID;
				goto out;
			}
			break;
		case STATE_TYPE_LOCK:
		case STATE_TYPE_DELEG:
			break;
		default:
			/* Sanity check: all other types are illegal.
			 * we should not got that place (similar check
			 * above), anyway it costs nothing to add this
			 * test */
			res_READ4->status = NFS4ERR_BAD_STATEID;
			goto out;
		}
	} else {
		/* Special stateid, no open state, check to see if any
		   share conflicts */
		state_open = NULL;

		/* Special stateid, no open state, check to see if any share
		 * conflicts The stateid is all-0 or all-1
		 */
		bypass = arg_READ4->stateid.seqid != 0;
		res_READ4->status = nfs4_Errno_state(
				state_share_anonymous_io_start(
					obj,
					OPEN4_SHARE_ACCESS_READ,
					arg_READ4->stateid.seqid != 0
						? SHARE_BYPASS_READ
						: SHARE_BYPASS_NONE));

		if (res_READ4->status != NFS4_OK)
			goto out;

		anonymous_started = true;
	}

	/* Need to permission check the read. */
	fsal_status = obj->obj_ops.test_access(obj, FSAL_READ_ACCESS,
					       NULL, NULL, true);

	if (fsal_status.major == ERR_FSAL_ACCESS) {
		/* Test for execute permission */
		fsal_status = fsal_access(obj,
				  FSAL_MODE_MASK_SET(FSAL_X_OK) |
				  FSAL_ACE4_MASK_SET
				  (FSAL_ACE_PERM_EXECUTE));
	}

	if (FSAL_IS_ERROR(fsal_status)) {
		res_READ4->status = nfs4_Errno_status(fsal_status);
		goto done;
	}

	/* Get the size and offset of the read operation */
	offset = arg_READ4->offset;
	size = arg_READ4->count;

	if (MaxOffsetRead < UINT64_MAX) {
		LogFullDebug(COMPONENT_NFS_V4,
			     "Read offset=%" PRIu64
			     " size=%" PRIu64 " MaxOffSet=%" PRIu64,
			     offset, size,
			     MaxOffsetRead);

		if ((offset + size) > MaxOffsetRead) {
			LogEvent(COMPONENT_NFS_V4,
				 "A client tryed to violate max file size %"
				 PRIu64 " for exportid #%hu",
				 MaxOffsetRead,
				 op_ctx->ctx_export->export_id);
			res_READ4->status = NFS4ERR_FBIG;
			goto done;
		}
	}

	if (size > MaxRead) {
		/* the client asked for too much data, this should normally
		   not happen because client will get FATTR4_MAXREAD value
		   at mount time */

		if (info == NULL ||
		    info->io_content.what != NFS4_CONTENT_HOLE) {
			LogFullDebug(COMPONENT_NFS_V4,
				     "read requested size = %"PRIu64
				     " read allowed size = %" PRIu64,
				     size, MaxRead);
			size = MaxRead;
		}
	}

	/* If size == 0, no I/O is to be made and everything is
	   alright */
	if (size == 0) {
		/* A size = 0 can not lead to EOF */
		res_READ4->READ4res_u.resok4.eof = false;
		res_READ4->READ4res_u.resok4.data.data_len = 0;
		res_READ4->READ4res_u.resok4.data.data_val = NULL;
		res_READ4->status = NFS4_OK;
		goto done;
	}

	/* Some work is to be done */
	bufferdata = gsh_malloc_aligned(4096, size);

	if (!anonymous_started && data->minorversion == 0) {
		owner = get_state_owner_ref(state_found);
		if (owner != NULL) {
			op_ctx->clientid =
				&owner->so_owner.so_nfs4_owner.so_clientid;
		}
	}

	if (obj->fsal->m_ops.support_ex(obj)) {
		/* Call the new fsal_read2 */
		fsal_status = fsal_read2(obj, bypass, state_found, offset, size,
					 &read_size, bufferdata, &eof_met,
					 info);
	} else {
		/* Call legacy fsal_rdwr */
		fsal_status = fsal_rdwr(obj, io, offset, size, &read_size,
					bufferdata, &eof_met, &sync, info);
	}

	if (FSAL_IS_ERROR(fsal_status)) {
		res_READ4->status = nfs4_Errno_status(fsal_status);
		gsh_free(bufferdata);
		res_READ4->READ4res_u.resok4.data.data_val = NULL;
		goto done;
	}

	if (!eof_met) {
		/** @todo FSF: add a config option for this behavior?
		 */
		/* Need to check against filesize for ESXi clients */
		struct attrlist attrs;

		fsal_prepare_attrs(&attrs, ATTR_SIZE);

		if (!FSAL_IS_ERROR(obj->obj_ops.getattrs(obj, &attrs)))
			eof_met = (offset + read_size) >= attrs.filesize;

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

	if (!anonymous_started && data->minorversion == 0)
		op_ctx->clientid = NULL;

	res_READ4->READ4res_u.resok4.data.data_len = read_size;
	res_READ4->READ4res_u.resok4.data.data_val = bufferdata;

	LogFullDebug(COMPONENT_NFS_V4,
		     "NFS4_OP_READ: offset = %" PRIu64
		     " read length = %zu eof=%u", offset, read_size, eof_met);

	/* Is EOF met or not ? */
	res_READ4->READ4res_u.resok4.eof = eof_met;

	/* Say it is ok */
	res_READ4->status = NFS4_OK;

 done:

	if (anonymous_started)
		state_share_anonymous_io_done(obj, OPEN4_SHARE_ACCESS_READ);

	server_stats_io_done(size, read_size,
			     (res_READ4->status == NFS4_OK) ? true : false,
			     false);

 out:

	if (owner != NULL)
		dec_state_owner_ref(owner);

	if (state_found != NULL)
		dec_state_t_ref(state_found);

	if (state_open != NULL)
		dec_state_t_ref(state_open);

	return res_READ4->status;
}				/* nfs4_op_read */
示例#12
0
/**
 *  @brief Create a symbolic link.
 *
 * @param dir_hdl Handle of the parent dir where the link is to be created.
 * @param linkname Name of the link to be created.
 * @param linkcontent Content of the link to be created.
 * @param op_ctx Authentication context for the operation (user,...).
 * @param accessmode Mode of the link to be created.
 *                  It has no sense in POSIX filesystems.
 * @param gpfs_fh Pointer to the handle of the created symlink.
 * @param link_attr Attributes of the newly created symlink.
 *                 As input, it defines the attributes that the caller
 *                 wants to retrieve (by positioning flags into this structure)
 *                 and the output is built considering this input
 *                 (it fills the structure according to the flags it contains).
 *                 May be NULL.
 *
 * @return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t
GPFSFSAL_symlink(struct fsal_obj_handle *dir_hdl, const char *linkname,
		 const char *linkcontent, const struct req_op_context *op_ctx,
		 uint32_t accessmode, struct gpfs_file_handle *gpfs_fh,
		 struct attrlist *link_attr)
{

	int rc, errsv;
	fsal_status_t status;
	int fd;
	struct gpfs_fsal_obj_handle *gpfs_hdl;
	struct gpfs_filesystem *gpfs_fs;

	/* note : link_attr is optional. */
	if (!dir_hdl || !op_ctx || !gpfs_fh || !linkname
	    || !linkcontent)
		return fsalstat(ERR_FSAL_FAULT, 0);

	gpfs_hdl =
	    container_of(dir_hdl, struct gpfs_fsal_obj_handle, obj_handle);

	gpfs_fs = dir_hdl->fs->private_data;

	/* Tests if symlinking is allowed by configuration. */

	if (!op_ctx->fsal_export->exp_ops.
	    fs_supports(op_ctx->fsal_export,
			fso_symlink_support))
		return fsalstat(ERR_FSAL_NOTSUPP, 0);

	status = fsal_internal_handle2fd(gpfs_fs->root_fd, gpfs_hdl->handle,
					 &fd, O_RDONLY | O_DIRECTORY, 0);

	if (FSAL_IS_ERROR(status))
		return status;

	/* build symlink path */

	/* create the symlink on the filesystem using the credentials
	 * for proper ownership assignment.
	 */

	fsal_set_credentials(op_ctx->creds);

	rc = symlinkat(linkcontent, fd, linkname);
	errsv = errno;

	fsal_restore_ganesha_credentials();

	if (rc) {
		close(fd);
		return fsalstat(posix2fsal_error(errsv), errsv);
	}

	/* now get the associated handle, while there is a race, there is
	   also a race lower down  */
	status = fsal_internal_get_handle_at(fd, linkname, gpfs_fh);

	if (FSAL_IS_ERROR(status)) {
		close(fd);
		return status;
	}

	/* get attributes */
	status = GPFSFSAL_getattrs(op_ctx->fsal_export, gpfs_fs,
				   op_ctx, gpfs_fh,
				   link_attr);

	if (!FSAL_IS_ERROR(status) && link_attr->type != SYMBOLIC_LINK) {
		/* We could wind up not failing the creation of the symlink
		 * and the only way we know is that the object type isn't
		 * a symlink.
		 */
		fsal_release_attrs(link_attr);
		status = fsalstat(ERR_FSAL_EXIST, 0);
	}

	close(fd);
	return status;
}
示例#13
0
/**
 * read_dirents
 * read the directory and call through the callback function for
 * each entry.
 * @param dir_hdl [IN] the directory to read
 * @param whence [IN] where to start (next)
 * @param dir_state [IN] pass thru of state to callback
 * @param cb [IN] callback function
 * @param eof [OUT] eof marker true == end of dir
 */
static fsal_status_t read_dirents(struct fsal_obj_handle *dir_hdl,
				  fsal_cookie_t *whence, void *dir_state,
				  fsal_readdir_cb cb, attrmask_t attrmask,
				  bool *eof)
{
	fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR;
	int retval = 0;
	struct gpfs_fsal_obj_handle *myself;
	int dirfd;
	fsal_status_t status;
	off_t seekloc = 0;
	int bpos, cnt, nread;
	struct dirent64 *dentry;
	char buf[BUF_SIZE];
	struct gpfs_filesystem *gpfs_fs;

	if (whence != NULL)
		seekloc = (off_t) *whence;

	myself = container_of(dir_hdl, struct gpfs_fsal_obj_handle, obj_handle);
	gpfs_fs = dir_hdl->fs->private_data;

	status = fsal_internal_handle2fd_at(gpfs_fs->root_fd, myself->handle,
					    &dirfd, O_RDONLY | O_DIRECTORY, 0);
	if (dirfd < 0)
		return status;

	seekloc = lseek(dirfd, seekloc, SEEK_SET);
	if (seekloc < 0) {
		retval = errno;
		fsal_error = posix2fsal_error(retval);
		goto done;
	}
	cnt = 0;
	do {
		nread = syscall(SYS_getdents64, dirfd, buf, BUF_SIZE);
		if (nread < 0) {
			retval = errno;
			fsal_error = posix2fsal_error(retval);
			goto done;
		}
		if (nread == 0)
			break;
		for (bpos = 0; bpos < nread;) {
			struct fsal_obj_handle *hdl;
			struct attrlist attrs;
			bool cb_rc;

			dentry = (struct dirent64 *)(buf + bpos);
			if (strcmp(dentry->d_name, ".") == 0
			    || strcmp(dentry->d_name, "..") == 0)
				goto skip;	/* must skip '.' and '..' */

			fsal_prepare_attrs(&attrs, attrmask);

			status = lookup(dir_hdl, dentry->d_name, &hdl, &attrs);
			if (FSAL_IS_ERROR(status)) {
				fsal_error = status.major;
				goto done;
			}

			/* callback to cache inode */
			cb_rc = cb(dentry->d_name, hdl, &attrs, dir_state,
				   (fsal_cookie_t) dentry->d_off);

			fsal_release_attrs(&attrs);

			if (!cb_rc)
				goto done;
 skip:
			bpos += dentry->d_reclen;
			cnt++;
		}
	} while (nread > 0);

	*eof = true;
 done:
	close(dirfd);

	return fsalstat(fsal_error, retval);
}
示例#14
0
/** makesymlink
 *  Note that we do not set mode bits on symlinks for Linux/POSIX
 *  They are not really settable in the kernel and are not checked
 *  anyway (default is 0777) because open uses that target's mode
 */
static fsal_status_t makesymlink(struct fsal_obj_handle *dir_hdl,
				 const char *name, const char *link_path,
				 struct attrlist *attr_in,
				 struct fsal_obj_handle **handle,
				 struct attrlist *attrs_out)
{
	fsal_status_t status;
	struct gpfs_fsal_obj_handle *hdl;
	struct gpfs_file_handle *fh = alloca(sizeof(struct gpfs_file_handle));
	/* Use a separate attrlist to getch the actual attributes into */
	struct attrlist attrib;

	*handle = NULL;		/* poison it first */
	if (!dir_hdl->obj_ops.handle_is(dir_hdl, DIRECTORY)) {
		LogCrit(COMPONENT_FSAL,
			"Parent handle is not a directory. hdl = 0x%p",
			dir_hdl);
		return fsalstat(ERR_FSAL_NOTDIR, 0);
	}
	memset(fh, 0, sizeof(struct gpfs_file_handle));
	fh->handle_size = GPFS_MAX_FH_SIZE;

	fsal_prepare_attrs(&attrib, ATTR_GPFS_ALLOC_HANDLE);

	if (attrs_out != NULL)
		attrib.mask |= attrs_out->mask;

	status = GPFSFSAL_symlink(dir_hdl, name, link_path, op_ctx,
				  attr_in->mode, fh, &attrib);
	if (FSAL_IS_ERROR(status))
		return status;

	/* allocate an obj_handle and fill it up */
	hdl = alloc_handle(fh, dir_hdl->fs, &attrib, link_path,
			   op_ctx->fsal_export);

	if (attrs_out != NULL) {
		/* Copy the attributes to caller, passing ACL ref. */
		fsal_copy_attrs(attrs_out, &attrib, true);
	} else {
		/* Done with the attrs */
		fsal_release_attrs(&attrib);
	}
	*handle = &hdl->obj_handle;

	/* We handled the mode above. */
	FSAL_UNSET_MASK(attr_in->mask, ATTR_MODE);

	if (attr_in->mask) {
		/* Now per support_ex API, if there are any other attributes
		 * set, go ahead and get them set now.
		 */
		status = (*handle)->obj_ops.setattr2(*handle, false, NULL,
						     attr_in);
		if (FSAL_IS_ERROR(status)) {
			/* Release the handle we just allocated. */
			LogFullDebug(COMPONENT_FSAL,
				     "setattr2 status=%s",
				      fsal_err_txt(status));
			(*handle)->obj_ops.release(*handle);
			*handle = NULL;
		}
	} else {
		status = fsalstat(ERR_FSAL_NO_ERROR, 0);

		if (attrs_out != NULL) {
			/* Make sure ATTR_RDATTR_ERR is cleared on success. */
			attrs_out->mask &= ~ATTR_RDATTR_ERR;
		}
	}
	FSAL_SET_MASK(attr_in->mask, ATTR_MODE);

	return status;
}
示例#15
0
/**
 * @brief Set attributes on an object
 *
 * This function sets attributes on an object.  Which attributes are
 * set is determined by attrib_set->mask. The FSAL must manage bypass
 * or not of share reservations, and a state may be passed.
 *
 * @param[in] obj_hdl    File on which to operate
 * @param[in] state      state_t to use for this operation
 * @param[in] attrib_set Attributes to set
 *
 * @return FSAL status.
 */
fsal_status_t vfs_setattr2(struct fsal_obj_handle *obj_hdl,
			   bool bypass,
			   struct state_t *state,
			   struct attrlist *attrib_set)
{
	struct vfs_fsal_obj_handle *myself;
	fsal_status_t status = {0, 0};
	int retval = 0;
	fsal_openflags_t openflags = FSAL_O_ANY;
	bool has_lock = false;
	bool need_fsync = false;
	bool closefd = false;
	int my_fd;
	const char *func;

	/* apply umask, if mode attribute is to be changed */
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE))
		attrib_set->mode &=
		    ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export);

	myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle);

	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 != NULL
				? obj_hdl->fs->fsal->name
				: "(none)");
		return fsalstat(posix2fsal_error(EXDEV), EXDEV);
	}

#ifdef ENABLE_VFS_DEBUG_ACL
#ifdef ENABLE_RFC_ACL
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE) &&
	    !FSAL_TEST_MASK(attrib_set->mask, ATTR_ACL)) {
		/* Set ACL from MODE */
		struct attrlist attrs;

		fsal_prepare_attrs(&attrs, ATTR_ACL);

		status = obj_hdl->obj_ops.getattrs(obj_hdl, &attrs);

		if (FSAL_IS_ERROR(status))
			return status;

		status = fsal_mode_to_acl(attrib_set, attrs.acl);

		/* Done with the attrs */
		fsal_release_attrs(&attrs);
	} else {
		/* If ATTR_ACL is set, mode needs to be adjusted no matter what.
		 * See 7530 s 6.4.1.3 */
		if (!FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE))
			attrib_set->mode = myself->mode;
		status = fsal_acl_to_mode(attrib_set);
	}

	if (FSAL_IS_ERROR(status))
		return status;
#endif /* ENABLE_RFC_ACL */
#endif

	/* This is yet another "you can't get there from here".  If this object
	 * is a socket (AF_UNIX), an fd on the socket s useless _period_.
	 * If it is for a symlink, without O_PATH, you will get an ELOOP error
	 * and (f)chmod doesn't work for a symlink anyway - not that it matters
	 * because access checking is not done on the symlink but the final
	 * target.
	 * AF_UNIX sockets are also ozone material.  If the socket is already
	 * active listeners et al, you can manipulate the mode etc.  If it is
	 * just sitting there as in you made it with a mknod.
	 * (one of those leaky abstractions...)
	 * or the listener forgot to unlink it, it is lame duck.
	 */

	/* Test if size is being set, make sure file is regular and if so,
	 * require a read/write file descriptor.
	 */
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_SIZE)) {
		if (obj_hdl->type != REGULAR_FILE) {
			LogFullDebug(COMPONENT_FSAL,
				     "Setting size on non-regular file");
			return fsalstat(ERR_FSAL_INVAL, EINVAL);
		}
		openflags = FSAL_O_RDWR;
	}

	/* Get a usable file descriptor. Share conflict is only possible if
	 * size is being set.
	 */
	status = find_fd(&my_fd, obj_hdl, bypass, state, openflags,
			 &has_lock, &need_fsync, &closefd, false);

	if (FSAL_IS_ERROR(status)) {
		if (obj_hdl->type == SYMBOLIC_LINK &&
		    status.major == ERR_FSAL_PERM) {
			/* You cannot open_by_handle (XFS) a symlink and it
			 * throws an EPERM error for it.  open_by_handle_at
			 * does not throw that error for symlinks so we play a
			 * game here.  Since there is not much we can do with
			 * symlinks anyway, say that we did it
			 * but don't actually do anything.
			 * If you *really* want to tweek things
			 * like owners, get a modern linux kernel...
			 */
			status = fsalstat(ERR_FSAL_NO_ERROR, 0);
		}
		LogFullDebug(COMPONENT_FSAL,
			     "find_fd status=%s",
			     fsal_err_txt(status));
		goto out;
	}

	/** TRUNCATE **/
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_SIZE)) {
		retval = ftruncate(my_fd, attrib_set->filesize);
		if (retval != 0) {
			/** @todo FSF: is this still necessary?
			 *
			 * XXX ESXi volume creation pattern reliably
			 * reached this point in the past, however now that we
			 * only use the already open file descriptor if it is
			 * open read/write, this may no longer fail.
			 * If there is some other error from ftruncate, then
			 * we will needlessly retry, but without more detail
			 * of the original failure, we can't be sure.
			 * Fortunately permission checking is done by
			 * Ganesha before calling here, so we won't get an
			 * EACCES since this call is done as root. We could
			 * get EFBIG, EPERM, or EINVAL.
			 */
			/** @todo FSF: re-open if we really still need this
			 */

			retval = ftruncate(my_fd, attrib_set->filesize);
			if (retval != 0) {
				func = "truncate";
				goto fileerr;
			}
		}
	}

	/** CHMOD **/
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE)) {
		/* The POSIX chmod call doesn't affect the symlink object, but
		 * the entry it points to. So we must ignore it.
		 */
		if (obj_hdl->type != SYMBOLIC_LINK) {
			if (vfs_unopenable_type(obj_hdl->type))
				retval = fchmodat(
					my_fd,
					myself->u.unopenable.name,
					fsal2unix_mode(attrib_set->mode),
					0);
			else
				retval = fchmod(
					my_fd,
					fsal2unix_mode(attrib_set->mode));

			if (retval != 0) {
				func = "chmod";
				goto fileerr;
			}
		}
	}

	/**  CHOWN  **/
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_OWNER | ATTR_GROUP)) {
		uid_t user = FSAL_TEST_MASK(attrib_set->mask, ATTR_OWNER)
		    ? (int)attrib_set->owner : -1;
		gid_t group = FSAL_TEST_MASK(attrib_set->mask, ATTR_GROUP)
		    ? (int)attrib_set->group : -1;

		if (vfs_unopenable_type(obj_hdl->type))
			retval = fchownat(my_fd, myself->u.unopenable.name,
					  user, group, AT_SYMLINK_NOFOLLOW);
		else if (obj_hdl->type == SYMBOLIC_LINK)
			retval = fchownat(my_fd, "", user, group,
					  AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH);
		else
			retval = fchown(my_fd, user, group);

		if (retval) {
			func = "chown";
			goto fileerr;
		}
	}

	/**  UTIME  **/
	if (FSAL_TEST_MASK(attrib_set->mask, ATTRS_SET_TIME)) {
		struct timespec timebuf[2];

		if (obj_hdl->type == SYMBOLIC_LINK)
			goto out; /* Setting time on symlinks is illegal */
		/* Atime */
		if (FSAL_TEST_MASK(attrib_set->mask, ATTR_ATIME_SERVER)) {
			timebuf[0].tv_sec = 0;
			timebuf[0].tv_nsec = UTIME_NOW;
		} else if (FSAL_TEST_MASK(attrib_set->mask, ATTR_ATIME)) {
			timebuf[0] = attrib_set->atime;
		} else {
			timebuf[0].tv_sec = 0;
			timebuf[0].tv_nsec = UTIME_OMIT;
		}

		/* Mtime */
		if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MTIME_SERVER)) {
			timebuf[1].tv_sec = 0;
			timebuf[1].tv_nsec = UTIME_NOW;
		} else if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MTIME)) {
			timebuf[1] = attrib_set->mtime;
		} else {
			timebuf[1].tv_sec = 0;
			timebuf[1].tv_nsec = UTIME_OMIT;
		}
		if (vfs_unopenable_type(obj_hdl->type))
			retval = vfs_utimesat(my_fd, myself->u.unopenable.name,
					      timebuf, AT_SYMLINK_NOFOLLOW);
		else
			retval = vfs_utimes(my_fd, timebuf);
		if (retval != 0) {
			func = "utimes";
			goto fileerr;
		}
	}

	/** SUBFSAL **/
	if (myself->sub_ops && myself->sub_ops->setattrs) {
		status = myself->sub_ops->setattrs(
					myself,
					my_fd,
					attrib_set->mask, attrib_set);
		if (FSAL_IS_ERROR(status))
			goto out;
	}

	errno = 0;

 fileerr:

	retval = errno;

	if (retval != 0) {
		LogDebug(COMPONENT_FSAL,
			 "%s returned %s",
			 func, strerror(retval));
	}

	status = fsalstat(posix2fsal_error(retval), retval);

 out:

	if (closefd)
		close(my_fd);

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

	return status;
}
示例#16
0
int nfs4_op_setattr(struct nfs_argop4 *op, compound_data_t *data,
		    struct nfs_resop4 *resp)
{
	SETATTR4args * const arg_SETATTR4 = &op->nfs_argop4_u.opsetattr;
	SETATTR4res * const res_SETATTR4 = &resp->nfs_resop4_u.opsetattr;
	struct attrlist sattr;
	fsal_status_t fsal_status = {0, 0};
	const char *tag = "SETATTR";
	state_t *state_found = NULL;
	state_t *state_open = NULL;
	struct fsal_obj_handle *obj = NULL;
	bool anonymous_started = false;

	resp->resop = NFS4_OP_SETATTR;
	res_SETATTR4->status = NFS4_OK;

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

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

	/* Don't allow attribute change while we are in grace period.
	 * Required for delegation reclaims and may be needed for other
	 * reclaimable states as well.
	 */
	if (nfs_in_grace()) {
		res_SETATTR4->status = NFS4ERR_GRACE;
		return res_SETATTR4->status;
	}

	/* Get only attributes that are allowed to be read */
	if (!nfs4_Fattr_Check_Access
	    (&arg_SETATTR4->obj_attributes, FATTR4_ATTR_WRITE)) {
		res_SETATTR4->status = NFS4ERR_INVAL;
		return res_SETATTR4->status;
	}

	/* Ask only for supported attributes */
	if (!nfs4_Fattr_Supported(&arg_SETATTR4->obj_attributes)) {
		res_SETATTR4->status = NFS4ERR_ATTRNOTSUPP;
		return res_SETATTR4->status;
	}

	/* Convert the fattr4 in the request to a fsal sattr structure */
	res_SETATTR4->status =
		nfs4_Fattr_To_FSAL_attr(&sattr,
					&arg_SETATTR4->obj_attributes,
					data);

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

	/* Trunc may change Xtime so we have to start with trunc and
	 * finish by the mtime and atime
	 */
	if ((FSAL_TEST_MASK(sattr.mask, ATTR_SIZE))
	     || (FSAL_TEST_MASK(sattr.mask, ATTR4_SPACE_RESERVED))) {
		/* Setting the size of a directory is prohibited */
		if (data->current_filetype == DIRECTORY) {
			res_SETATTR4->status = NFS4ERR_ISDIR;
			return res_SETATTR4->status;
		}

		/* Object should be a file */
		if (data->current_obj->type != REGULAR_FILE) {
			res_SETATTR4->status = NFS4ERR_INVAL;
			return res_SETATTR4->status;
		}

		obj = data->current_obj;

		/* Check stateid correctness and get pointer to state */
		res_SETATTR4->status =
		    nfs4_Check_Stateid(&arg_SETATTR4->stateid,
				       data->current_obj,
				       &state_found,
				       data,
				       STATEID_SPECIAL_ANY,
				       0,
				       false,
				       tag);

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

		/* NB: After this point, if state_found == NULL, then
		 * the stateid is all-0 or all-1
		 */
		if (state_found != NULL) {
			switch (state_found->state_type) {
			case STATE_TYPE_SHARE:
				state_open = state_found;
				/* Note this causes an extra refcount, but it
				 * simplifies logic below.
				 */
				inc_state_t_ref(state_open);
				break;

			case STATE_TYPE_LOCK:
				state_open =
				    state_found->state_data.lock.openstate;
				inc_state_t_ref(state_open);
				break;

			case STATE_TYPE_DELEG:
				state_open = NULL;
				break;

			default:
				res_SETATTR4->status = NFS4ERR_BAD_STATEID;
				return res_SETATTR4->status;
			}

			/* This is a size operation, this means that
			 * the file MUST have been opened for writing
			 */
			if (state_open != NULL &&
			    (state_open->state_data.share.share_access &
			     OPEN4_SHARE_ACCESS_WRITE) == 0) {
				/* Bad open mode, return NFS4ERR_OPENMODE */
				res_SETATTR4->status = NFS4ERR_OPENMODE;
				return res_SETATTR4->status;
			}
		} else {
			/* Special stateid, no open state, check to
			 * see if any share conflicts
			 */
			state_open = NULL;

			/* Special stateid, no open state, check to see if
			 * any share conflicts The stateid is all-0 or all-1
			 */
			res_SETATTR4->status = nfs4_Errno_state(
				state_share_anonymous_io_start(
					obj,
					OPEN4_SHARE_ACCESS_WRITE,
					SHARE_BYPASS_NONE));

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

			anonymous_started = true;
		}
	}

	const time_t S_NSECS = 1000000000UL;
	/* Set the atime and mtime (ctime is not setable) */

	/* A carry into seconds considered invalid */
	if (sattr.atime.tv_nsec >= S_NSECS) {
		res_SETATTR4->status = NFS4ERR_INVAL;
		goto done;
	}

	if (sattr.mtime.tv_nsec >= S_NSECS) {
		res_SETATTR4->status = NFS4ERR_INVAL;
		goto done;
	}

	/* If owner or owner_group are set, and the credential was
	 * squashed, then we must squash the set owner and owner_group.
	 */
	squash_setattr(&sattr);

	/* If a SETATTR comes with an open stateid, and size is being
	 * set, then the open MUST be for write (checked above), so
	 * is_open_write is simple at this stage, it's just a check that
	 * we have an open owner.
	 */
	fsal_status = fsal_setattr(data->current_obj,
				   false,
				   state_found,
				   &sattr);

	/* Release the attributes (may release an explicit or inherited ACL) */
	fsal_release_attrs(&sattr);

	if (FSAL_IS_ERROR(fsal_status)) {
		res_SETATTR4->status = nfs4_Errno_status(fsal_status);
		goto done;
	}

	/* Set the replyed structure */
	res_SETATTR4->attrsset = arg_SETATTR4->obj_attributes.attrmask;

	/* Exit with no error */
	res_SETATTR4->status = NFS4_OK;

 done:

	if (anonymous_started)
		state_share_anonymous_io_done(obj, OPEN4_SHARE_ACCESS_WRITE);

	if (state_found != NULL)
		dec_state_t_ref(state_found);

	if (state_open != NULL)
		dec_state_t_ref(state_open);

	return res_SETATTR4->status;
}				/* nfs4_op_setattr */
示例#17
0
fsal_status_t vfs_open2(struct fsal_obj_handle *obj_hdl,
			struct state_t *state,
			fsal_openflags_t openflags,
			enum fsal_create_mode createmode,
			const char *name,
			struct attrlist *attrib_set,
			fsal_verifier_t verifier,
			struct fsal_obj_handle **new_obj,
			struct attrlist *attrs_out,
			bool *caller_perm_check)
{
	int posix_flags = 0;
	int fd, dir_fd;
	int retval = 0;
	mode_t unix_mode;
	fsal_status_t status = {0, 0};
	struct vfs_fd *my_fd = NULL;
	struct vfs_fsal_obj_handle *myself, *hdl = NULL;
	struct stat stat;
	vfs_file_handle_t *fh = NULL;
	bool truncated;
	bool created = false;

	if (state != NULL)
		my_fd = (struct vfs_fd *)(state + 1);

	myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle);

	LogAttrlist(COMPONENT_FSAL, NIV_FULL_DEBUG,
		    "attrib_set ", attrib_set, false);

	fsal2posix_openflags(openflags, &posix_flags);

	truncated = (posix_flags & O_TRUNC) != 0;

	LogFullDebug(COMPONENT_FSAL,
		     truncated ? "Truncate" : "No truncate");

	if (createmode >= FSAL_EXCLUSIVE) {
		/* Now fixup attrs for verifier if exclusive create */
		set_common_verifier(attrib_set, verifier);
	}

	if (name == NULL) {
		/* This is an open by handle */
		struct vfs_fsal_obj_handle *myself;

		myself = container_of(obj_hdl,
				      struct vfs_fsal_obj_handle,
				      obj_handle);

		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 (state != NULL) {
			/* Prepare to take the share reservation, but only if we
			 * are called with a valid state (if state is NULL the
			 * caller is a stateless create such as NFS v3 CREATE).
			 */

			/* This can block over an I/O operation. */
			PTHREAD_RWLOCK_wrlock(&obj_hdl->lock);

			/* Check share reservation conflicts. */
			status = check_share_conflict(&myself->u.file.share,
						      openflags,
						      false);

			if (FSAL_IS_ERROR(status)) {
				PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
				return status;
			}

			/* Take the share reservation now by updating the
			 * counters.
			 */
			update_share_counters(&myself->u.file.share,
					      FSAL_O_CLOSED,
					      openflags);

			PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
		} else {
			/* We need to use the global fd to continue, and take
			 * the lock to protect it.
			 */
			my_fd = &hdl->u.file.fd;
			PTHREAD_RWLOCK_wrlock(&obj_hdl->lock);
		}

		status = vfs_open_my_fd(myself, openflags, posix_flags, my_fd);

		if (FSAL_IS_ERROR(status)) {
			if (state == NULL) {
				/* Release the lock taken above, and return
				 * since there is nothing to undo.
				 */
				PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
				return status;
			} else {
				/* Error - need to release the share */
				goto undo_share;
			}
		}

		if (createmode >= FSAL_EXCLUSIVE || truncated) {
			/* Refresh the attributes */
			struct stat stat;

			retval = fstat(my_fd->fd, &stat);

			if (retval == 0) {
				LogFullDebug(COMPONENT_FSAL,
					     "New size = %" PRIx64,
					     stat.st_size);
			} else {
				if (errno == EBADF)
					errno = ESTALE;
				status = fsalstat(posix2fsal_error(errno),
						  errno);
			}

			/* Now check verifier for exclusive, but not for
			 * FSAL_EXCLUSIVE_9P.
			 */
			if (!FSAL_IS_ERROR(status) &&
			    createmode >= FSAL_EXCLUSIVE &&
			    createmode != FSAL_EXCLUSIVE_9P &&
			    !check_verifier_stat(&stat, verifier)) {
				/* Verifier didn't match, return EEXIST */
				status =
				    fsalstat(posix2fsal_error(EEXIST), EEXIST);
			}
		}

		if (state == NULL) {
			/* If no state, release the lock taken above and return
			 * status.
			 */
			PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
			return status;
		}

		if (!FSAL_IS_ERROR(status)) {
			/* Return success. */
			return status;
		}

		(void) vfs_close_my_fd(my_fd);

 undo_share:

		/* Can only get here with state not NULL and an error */

		/* On error we need to release our share reservation
		 * and undo the update of the share counters.
		 * This can block over an I/O operation.
		 */
		PTHREAD_RWLOCK_wrlock(&obj_hdl->lock);

		update_share_counters(&myself->u.file.share,
				      openflags,
				      FSAL_O_CLOSED);

		PTHREAD_RWLOCK_unlock(&obj_hdl->lock);

		return status;
	}

	/* In this path where we are opening by name, we can't check share
	 * reservation yet since we don't have an object_handle yet. If we
	 * indeed create the object handle (there is no race with another
	 * open by name), then there CAN NOT be a share conflict, otherwise
	 * the share conflict will be resolved when the object handles are
	 * merged.
	 */

#ifdef ENABLE_VFS_DEBUG_ACL
	if (createmode != FSAL_NO_CREATE) {
		/* Need to ammend attributes for inherited ACL, these will be
		 * set later. We also need to test for permission to create
		 * since there might be an ACL.
		 */
		struct attrlist attrs;
		fsal_accessflags_t access_type;

		access_type = FSAL_MODE_MASK_SET(FSAL_W_OK) |
			FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE);
		status = obj_hdl->obj_ops.test_access(obj_hdl, access_type,
						      NULL, NULL, false);

		if (FSAL_IS_ERROR(status))
			return status;

		fsal_prepare_attrs(&attrs, ATTR_ACL);

		status = obj_hdl->obj_ops.getattrs(obj_hdl, &attrs);

		if (FSAL_IS_ERROR(status))
			return status;

		status.major = fsal_inherit_acls(attrib_set, attrs.acl,
						 FSAL_ACE_FLAG_FILE_INHERIT);

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

		if (FSAL_IS_ERROR(status))
			return status;
	}
#endif /* ENABLE_VFS_DEBUG_ACL */

	if (createmode != FSAL_NO_CREATE) {
		/* Now add in O_CREAT and O_EXCL. */
		posix_flags |= O_CREAT;

		/* And if we are at least FSAL_GUARDED, do an O_EXCL create. */
		if (createmode >= FSAL_GUARDED)
			posix_flags |= O_EXCL;

		/* Fetch the mode attribute to use in the openat system call. */
		unix_mode = fsal2unix_mode(attrib_set->mode) &
		    ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export);

		/* Don't set the mode if we later set the attributes */
		FSAL_UNSET_MASK(attrib_set->mask, ATTR_MODE);
	}

	if (createmode == FSAL_UNCHECKED && (attrib_set->mask != 0)) {
		/* If we have FSAL_UNCHECKED and want to set more attributes
		 * than the mode, we attempt an O_EXCL create first, if that
		 * succeeds, then we will be allowed to set the additional
		 * attributes, otherwise, we don't know we created the file
		 * and this can NOT set the attributes.
		 */
		posix_flags |= O_EXCL;
	}

	dir_fd = vfs_fsal_open(myself, O_PATH | O_NOACCESS, &status.major);

	if (dir_fd < 0)
		return fsalstat(status.major, -dir_fd);

	/** @todo: not sure what this accomplishes... */
	retval = vfs_stat_by_handle(dir_fd, &stat);

	if (retval < 0) {
		retval = errno;
		status = fsalstat(posix2fsal_error(retval), retval);
		goto direrr;
	}

	/* Become the user because we are creating an object in this dir.
	 */
	if (createmode != FSAL_NO_CREATE)
		fsal_set_credentials(op_ctx->creds);

	if ((posix_flags & O_CREAT) != 0)
		fd = openat(dir_fd, name, posix_flags, unix_mode);
	else
		fd = openat(dir_fd, name, posix_flags);

	if (fd == -1 && errno == EEXIST && createmode == FSAL_UNCHECKED) {
		/* We tried to create O_EXCL to set attributes and failed.
		 * Remove O_EXCL and retry. We still try O_CREAT again just in
		 * case file disappears out from under us.
		 *
		 * Note that because we have dropped O_EXCL, later on we will
		 * not assume we created the file, and thus will not set
		 * additional attributes. We don't need to separately track
		 * the condition of not wanting to set attributes.
		 */
		posix_flags &= ~O_EXCL;
		fd = openat(dir_fd, name, posix_flags, unix_mode);
	}

	/* Preserve errno */
	retval = errno;

	/* If we were creating, restore credentials now. */
	if (createmode != FSAL_NO_CREATE)
		fsal_restore_ganesha_credentials();

	if (fd < 0) {
		status = fsalstat(posix2fsal_error(retval), retval);
		goto direrr;
	}

	/* Remember if we were responsible for creating the file.
	 * Note that in an UNCHECKED retry we MIGHT have re-created the
	 * file and won't remember that. Oh well, so in that rare case we
	 * leak a partially created file if we have a subsequent error in here.
	 * Also notify caller to do permission check if we DID NOT create the
	 * file. Note it IS possible in the case of a race between an UNCHECKED
	 * open and an external unlink, we did create the file, but we will
	 * still force a permission check. Of course that permission check
	 * SHOULD succeed since we also won't set the mode the caller requested
	 * and the default file create permissions SHOULD allow the owner
	 * read/write.
	 */
	created = (posix_flags & O_EXCL) != 0;
	*caller_perm_check = !created;

	vfs_alloc_handle(fh);

	retval = vfs_name_to_handle(dir_fd, obj_hdl->fs, name, fh);

	if (retval < 0) {
		retval = errno;
		status = fsalstat(posix2fsal_error(retval), retval);
		goto fileerr;
	}

	retval = fstat(fd, &stat);

	if (retval < 0) {
		retval = errno;
		status = fsalstat(posix2fsal_error(retval), retval);
		goto fileerr;
	}

	/* allocate an obj_handle and fill it up */
	hdl = alloc_handle(dir_fd, fh, obj_hdl->fs, &stat, myself->handle, name,
			   op_ctx->fsal_export);

	if (hdl == NULL) {
		status = fsalstat(posix2fsal_error(ENOMEM), ENOMEM);
		goto fileerr;
	}

	/* If we didn't have a state above, use the global fd. At this point,
	 * since we just created the global fd, no one else can have a
	 * reference to it, and thus we can mamnipulate unlocked which is
	 * handy since we can then call setattr2 which WILL take the lock
	 * without a double locking deadlock.
	 */
	if (my_fd == NULL)
		my_fd = &hdl->u.file.fd;

	my_fd->fd = fd;
	my_fd->openflags = openflags;

	*new_obj = &hdl->obj_handle;

	if (created && attrib_set->mask != 0) {
		/* Set attributes using our newly opened file descriptor as the
		 * share_fd if there are any left to set (mode and truncate
		 * have already been handled).
		 *
		 * Note that we only set the attributes if we were responsible
		 * for creating the file and we have attributes to set.
		 *
		 * Note if we have ENABLE_VFS_DEBUG_ACL an inherited ACL might
		 * be part of the attributes we are setting here.
		 */
		status = (*new_obj)->obj_ops.setattr2(*new_obj,
						      false,
						      state,
						      attrib_set);

		if (FSAL_IS_ERROR(status)) {
			/* Release the handle we just allocated. */
			(*new_obj)->obj_ops.release(*new_obj);
			*new_obj = NULL;
			goto fileerr;
		}

		if (attrs_out != NULL) {
			status = (*new_obj)->obj_ops.getattrs(*new_obj,
							      attrs_out);
			if (FSAL_IS_ERROR(status) &&
			    (attrs_out->mask & ATTR_RDATTR_ERR) == 0) {
				/* Get attributes failed and caller expected
				 * to get the attributes. Otherwise continue
				 * with attrs_out indicating ATTR_RDATTR_ERR.
				 */
				goto fileerr;
			}
		}
	} else if (attrs_out != NULL) {
		/* Since we haven't set any attributes other than what was set
		 * on create (if we even created), just use the stat results
		 * we used to create the fsal_obj_handle.
		 */
		posix2fsal_attributes(&stat, attrs_out);

		/* Make sure ATTR_RDATTR_ERR is cleared on success. */
		attrs_out->mask &= ~ATTR_RDATTR_ERR;
	}

	close(dir_fd);

	if (state != NULL) {
		/* Prepare to take the share reservation, but only if we are
		 * called with a valid state (if state is NULL the caller is
		 * a stateless create such as NFS v3 CREATE).
		 */

		/* This can block over an I/O operation. */
		PTHREAD_RWLOCK_wrlock(&(*new_obj)->lock);

		/* Take the share reservation now by updating the counters. */
		update_share_counters(&hdl->u.file.share,
				      FSAL_O_CLOSED,
				      openflags);

		PTHREAD_RWLOCK_unlock(&(*new_obj)->lock);
	}

	return fsalstat(ERR_FSAL_NO_ERROR, 0);

 fileerr:

	close(fd);

	/* Delete the file if we actually created it. */
	if (created)
		unlinkat(dir_fd, name, 0);

 direrr:

	close(dir_fd);
	return fsalstat(posix2fsal_error(retval), retval);
}
示例#18
0
/**
 *  @param exp_hdl Handle
 *  @param path Path
 *  @param handle Reference to handle
 *
 *  modelled on old api except we don't stuff attributes.
 *  @return Status of operation
 */
fsal_status_t gpfs_lookup_path(struct fsal_export *exp_hdl,
			       const char *path,
			       struct fsal_obj_handle **handle,
			       struct attrlist *attrs_out)
{
	fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR;
	fsal_status_t fsal_status;
	int retval = 0;
	int dir_fd;
	struct fsal_filesystem *fs;
	struct gpfs_fsal_obj_handle *hdl;
	struct attrlist attributes;
	gpfsfsal_xstat_t buffxstat;
	struct gpfs_file_handle *fh = alloca(sizeof(struct gpfs_file_handle));
	struct fsal_fsid__ fsid;
	struct gpfs_fsal_export *gpfs_export;

	memset(fh, 0, sizeof(struct gpfs_file_handle));
	fh->handle_size = GPFS_MAX_FH_SIZE;

	*handle = NULL;	/* poison it */

	dir_fd = open_dir_by_path_walk(-1, path, &buffxstat.buffstat);

	fsal_prepare_attrs(&attributes, ATTR_GPFS_ALLOC_HANDLE);

	if (attrs_out != NULL)
		attributes.mask |= attrs_out->mask;

	if (dir_fd < 0) {
		LogCrit(COMPONENT_FSAL,
			"Could not open directory for path %s",
			path);
		retval = -dir_fd;
		goto errout;
	}

	fsal_status = fsal_internal_fd2handle(dir_fd, fh);
	if (FSAL_IS_ERROR(fsal_status))
		goto fileerr;

	gpfs_export = container_of(exp_hdl, struct gpfs_fsal_export, export);

	fsal_status = fsal_get_xstat_by_handle(dir_fd, fh, &buffxstat,
					       NULL, false,
					       (attributes.mask & ATTR_ACL)
									!= 0);
	if (FSAL_IS_ERROR(fsal_status))
		goto fileerr;
	fsal_status = gpfsfsal_xstat_2_fsal_attributes(&buffxstat, &attributes,
						       gpfs_export->use_acl);
	LogFullDebug(COMPONENT_FSAL,
		     "fsid=0x%016"PRIx64".0x%016"PRIx64,
		     attributes.fsid.major,
		     attributes.fsid.minor);
	if (FSAL_IS_ERROR(fsal_status))
		goto fileerr;

	close(dir_fd);

	gpfs_extract_fsid(fh, &fsid);

	fs = lookup_fsid(&fsid, GPFS_FSID_TYPE);

	if (fs == NULL) {
		LogInfo(COMPONENT_FSAL,
			"Could not find file system for path %s",
			path);
		retval = ENOENT;
		goto errout;
	}

	if (fs->fsal != exp_hdl->fsal) {
		LogInfo(COMPONENT_FSAL,
			"File system for path %s did not belong to FSAL %s",
			path, exp_hdl->fsal->name);
		retval = EACCES;
		goto errout;
	}

	LogDebug(COMPONENT_FSAL,
		 "filesystem %s for path %s",
		 fs->path, path);

	/* Make sure ATTR_RDATTR_ERR is cleared on success. */
	attributes.mask &= ~ATTR_RDATTR_ERR;

	/* allocate an obj_handle and fill it up */
	hdl = alloc_handle(fh, fs, &attributes, NULL, exp_hdl);

	if (attrs_out != NULL) {
		/* Copy the attributes to caller, passing ACL ref. */
		fsal_copy_attrs(attrs_out, &attributes, true);
	} else {
		/* Done with the attrs */
		fsal_release_attrs(&attributes);
	}

	*handle = &hdl->obj_handle;
	return fsalstat(ERR_FSAL_NO_ERROR, 0);

 fileerr:
	retval = errno;
	close(dir_fd);

 errout:

	/* Done with attributes */
	fsal_release_attrs(&attributes);

	fsal_error = posix2fsal_error(retval);
	return fsalstat(fsal_error, retval);
}