Пример #1
0
/*ARGSUSED7*/
static int
xmem_create(struct vnode *dvp, char *nm, struct vattr *vap,
	enum vcexcl exclusive, int mode, struct vnode **vpp, struct cred *cred,
	int flag)
{
	struct xmemnode *parent;
	struct xmount *xm;
	struct xmemnode *self;
	int error;
	struct xmemnode *oldxp;

again:
	parent = (struct xmemnode *)VTOXN(dvp);
	xm = (struct xmount *)VTOXM(dvp);
	self = NULL;
	error = 0;
	oldxp = NULL;

	if (vap->va_type == VREG && (vap->va_mode & VSVTX)) {
		/* Must be privileged to set sticky bit */
		if (secpolicy_vnode_stky_modify(cred) != 0)
			vap->va_mode &= ~VSVTX;
	} else if (vap->va_type == VNON) {
		return (EINVAL);
	}

	/*
	 * Null component name is a synonym for directory being searched.
	 */
	if (*nm == '\0') {
		VN_HOLD(dvp);
		oldxp = parent;
	} else {
		error = xdirlookup(parent, nm, &oldxp, cred);
	}

	if (error == 0) {	/* name found */
		ASSERT(oldxp);

		rw_enter(&oldxp->xn_rwlock, RW_WRITER);

		/*
		 * if create/read-only an existing
		 * directory, allow it
		 */
		if (exclusive == EXCL)
			error = EEXIST;
		else if ((oldxp->xn_type == VDIR) && (mode & VWRITE))
			error = EISDIR;
		else {
			error = xmem_xaccess(oldxp, mode, cred);
		}

		if (error) {
			rw_exit(&oldxp->xn_rwlock);
			xmemnode_rele(oldxp);
			return (error);
		}
		*vpp = XNTOV(oldxp);
		if ((*vpp)->v_type == VREG && (vap->va_mask & AT_SIZE) &&
		    vap->va_size == 0) {
			rw_enter(&oldxp->xn_contents, RW_WRITER);
			(void) xmemnode_trunc(xm, oldxp, 0);
			rw_exit(&oldxp->xn_contents);
		}
		rw_exit(&oldxp->xn_rwlock);
		if (IS_DEVVP(*vpp)) {
			struct vnode *newvp;

			newvp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type,
			    cred);
			VN_RELE(*vpp);
			*vpp = newvp;
		}
		return (0);
	}

	if (error != ENOENT)
		return (error);

	rw_enter(&parent->xn_rwlock, RW_WRITER);
	error = xdirenter(xm, parent, nm, DE_CREATE,
	    (struct xmemnode *)NULL, (struct xmemnode *)NULL,
	    vap, &self, cred);
	rw_exit(&parent->xn_rwlock);

	if (error) {
		if (self)
			xmemnode_rele(self);

		if (error == EEXIST) {
			/*
			 * This means that the file was created sometime
			 * after we checked and did not find it and when
			 * we went to create it.
			 * Since creat() is supposed to truncate a file
			 * that already exits go back to the begining
			 * of the function. This time we will find it
			 * and go down the xmem_trunc() path
			 */
			goto again;
		}
		return (error);
	}

	*vpp = XNTOV(self);

	if (IS_DEVVP(*vpp)) {
		struct vnode *newvp;

		newvp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type,
		    cred);
		VN_RELE(*vpp);
		*vpp = newvp;
	}

	return (0);
}
Пример #2
0
/* ARGSUSED7 */
int				/* ERRNO if error, 0 if successful. */
sam_create_ino(
	sam_node_t *pip,	/* pointer to parent directory inode. */
	char *cp,		/* pointer to the component name to create. */
	vattr_t *vap,		/* vattr ptr for type & mode information. */
	vcexcl_t ex,		/* exclusive create flag. */
	int mode,		/* file mode information. */
	vnode_t **vpp,		/* pointer pointer to returned vnode. */
	cred_t *credp,		/* credentials pointer. */
	int filemode)		/* open file mode */
{
	int error = 0;
	sam_node_t *ip;
	struct sam_name name;	/* If no entry, slot info is returned here */
	int trans_size;
	int issync;
	int truncflag = 0;
	int terr = 0;
#ifdef LQFS_TODO_LOCKFS
	struct ulockfs *ulp;
#endif /* LQFS_TODO_LOCKFS */

	/*
	 * Cannot set sticky bit unless superuser.
	 */
	if ((vap->va_mode & VSVTX) && secpolicy_vnode_stky_modify(credp)) {
		vap->va_mode &= ~VSVTX;
	}

lookup_name:

#ifdef LQFS_TODO_LOCKFS
	error = qfs_lockfs_begin(pip->mp, &ulp, ULOCKFS_CREATE_MASK);
	if (error) {
		return (error);
	}

	if (ulp) {
#endif /* LQFS_TODO_LOCKFS */
		/* Start LQFS create transaction */
		trans_size = (int)TOP_CREATE_SIZE(pip);
		TRANS_BEGIN_CSYNC(pip->mp, issync, TOP_CREATE, trans_size);
#ifdef LQFS_TODO_LOCKFS
	}
#endif /* LQFS_TODO_LOCKFS */

	RW_LOCK_OS(&pip->data_rwl, RW_WRITER);
	name.operation = SAM_CREATE;
	if ((error = sam_lookup_name(pip, cp, &ip, &name, credp)) == ENOENT) {
		if (((error = sam_create_name(pip, cp, &ip, &name,
		    vap, credp)) != 0) &&
		    IS_SAM_ENOSPC(error)) {
			RW_UNLOCK_OS(&pip->data_rwl, RW_WRITER);
			/*
			 * Temporarily end LQFS create transaction
			 */
#ifdef LQFS_TODO_LOCKFS
			if (ulp) {
#endif /* LQFS_TODO_LOCKFS */
				TRANS_END_CSYNC(pip->mp, terr, issync,
				    TOP_CREATE, trans_size);
#ifdef LQFS_TODO_LOCKFS
			}
#endif /* LQFS_TODO_LOCKFS */
			error = sam_wait_space(pip, error);
			if (error == 0) {
				error = terr;
			}
			if (error) {
				return (error);
			}
			goto lookup_name;
		}
		RW_UNLOCK_OS(&pip->data_rwl, RW_WRITER);

	} else if (error == 0) {	/* If entry already exists. */
		RW_UNLOCK_OS(&pip->data_rwl, RW_WRITER);
		error = EEXIST;

		if (ex == NONEXCL) {	/* If non-exclusive create */
			if ((S_ISDIR(ip->di.mode) ||
			    S_ISATTRDIR(ip->di.mode)) &&
			    (mode & S_IWRITE)) {
				/* Cannot create over an existing dir. */
				error = EISDIR;
			} else if (SAM_PRIVILEGE_INO(ip->di.version,
			    ip->di.id.ino)) {
				/* Cannot create over privileged inodes */
				error = EPERM;
			} else if (mode) {	/* Check mode if set */
				error = sam_access_ino(ip, mode, FALSE, credp);
			} else {
				error = 0;
			}
			if ((error == 0) && S_ISREG(ip->di.mode) &&
			    (vap->va_mask & AT_SIZE) && (vap->va_size == 0)) {
				/*
				 * If logging, do the truncate after the
				 * LQFS create transaction is logged.
				 */
				if (TRANS_ISTRANS(ip->mp)) {
					truncflag++;
				} else {
					RW_LOCK_OS(&ip->inode_rwl, RW_WRITER);
					error = sam_clear_file(ip, 0,
					    STALE_ARCHIVE, credp);
					RW_UNLOCK_OS(&ip->inode_rwl, RW_WRITER);
				}
				if (error == 0) {
					VNEVENT_CREATE_OS(SAM_ITOV(ip), NULL);
				}
			}
		}
		/*
		 * Cannot do the following as it caused a stale of
		 * offline copies.
		 */
#if	0
		if ((error == 0) && ((mode & O_CREAT) == 0)) {
			TRANS_INODE(ip->mp, ip);
			sam_mark_ino(ip, SAM_UPDATED|SAM_CHANGED);
		}
#endif
		if (error) {
			VN_RELE(SAM_ITOV(ip));	/* Decrement v_count if error */
		}
	} else {
		RW_UNLOCK_OS(&pip->data_rwl, RW_WRITER);
	}
#ifdef LQFS_TODO_LOCKFS
	if (ulp) {
#endif /* LQFS_TODO_LOCKFS */
		TRANS_END_CSYNC(pip->mp, terr, issync, TOP_CREATE, trans_size);
		/*
		 * If we haven't had a more interesting failure
		 * already, then anything that might've happened
		 * here should be reported.
		 */
		if (error == 0) {
			error = terr;
		}
#ifdef LQFS_TODO_LOCKFS
	}
#endif /* LQFS_TODO_LOCKFS */

	if (!error && truncflag) {
		(void) TRANS_ITRUNC(ip, (u_offset_t)0, STALE_ARCHIVE, credp);
	}

#ifdef LQFS_TODO_LOCKFS
	if (ulp) {
		qfs_lockfs_end(ulp);
	}
#endif /* LQFS_TODO_LOCKFS */

	if (error == 0) {
		*vpp = SAM_ITOV(ip);
		TRACE(T_SAM_CREATE_RET, SAM_ITOV(pip), (sam_tr_t)* vpp,
		    ip->di.id.ino, error);
	}
	return (error);
}