Esempio n. 1
0
/*
 * union_mkdir(struct vnode *a_dvp, struct vnode **a_vpp,
 *		struct componentname *a_cnp, struct vattr *a_vap)
 */
static int
union_mkdir(struct vop_old_mkdir_args *ap)
{
	struct union_node *dun = VTOUNION(ap->a_dvp);
	struct componentname *cnp = ap->a_cnp;
	struct thread *td = cnp->cn_td;
	struct vnode *upperdvp;
	int error = EROFS;

	if ((upperdvp = union_lock_upper(dun, td)) != NULLVP) {
		struct vnode *vp;

		error = VOP_MKDIR(upperdvp, &vp, cnp, ap->a_vap);
		union_unlock_upper(upperdvp, td);

		if (error == 0) {
			vn_unlock(vp);
			UDEBUG(("ALLOCVP-2 FROM %p REFS %d\n", vp, vp->v_sysref.refcnt));
			error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount,
				ap->a_dvp, NULLVP, cnp, vp, NULLVP, 1);
			UDEBUG(("ALLOCVP-2B FROM %p REFS %d\n", *ap->a_vpp, vp->v_sysref.refcnt));
		}
	}
	return (error);
}
Esempio n. 2
0
int
smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
    int flags, cred_t *cr, vsecattr_t *vsap)
{
	int error;
	int option_flags = 0;
	xvattr_t xvattr;
	vattr_t *vap;
	char *np = name;
	char namebuf[MAXNAMELEN];

	if (flags & SMB_IGNORE_CASE)
		option_flags = FIGNORECASE;

	attr->sa_vattr.va_mask = 0;

	if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) {
		smb_vop_setup_xvattr(attr, &xvattr);
		vap = &xvattr.xva_vattr;
	} else {
		smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask);
		vap = &attr->sa_vattr;
	}

	if (flags & SMB_CATIA) {
		np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
		if (strchr(np, '/') != NULL)
			return (EILSEQ);
	}

	error = VOP_MKDIR(dvp, np, vap, vpp, cr, &smb_ct, option_flags, vsap);

	return (error);
}
Esempio n. 3
0
int
RUMP_VOP_MKDIR(struct vnode *dvp,
    struct vnode **vpp,
    struct componentname *cnp,
    struct vattr *vap)
{
	int error;

	rump_schedule();
	error = VOP_MKDIR(dvp, vpp, cnp, vap);
	rump_unschedule();

	return error;
}
Esempio n. 4
0
/*
 * Does most of the work for mkdir.
 */
int
vfs_mkdir(char *path)
{
	struct vnode *parent;
	char name[NAME_MAX+1];
	int result;

	result = vfs_lookparent(path, &parent, name, sizeof(name));
	if (result) {
		return result;
	}

	result = VOP_MKDIR(parent, name);

	VOP_DECREF(parent);

	return result;
}
Esempio n. 5
0
static int
unionfs_mkdir(void *v)
{
	struct vop_mkdir_args *ap = v;
	int		error;
	struct unionfs_node *dunp;
	struct componentname *cnp;
	struct vnode   *udvp;
	struct vnode   *uvp;
	struct vattr	va;

	UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: enter\n");

	error = EROFS;
	dunp = VTOUNIONFS(ap->a_dvp);
	cnp = ap->a_cnp;
	udvp = dunp->un_uppervp;

	if (udvp != NULLVP) {
		/* check opaque */
		if (!(cnp->cn_flags & ISWHITEOUT)) {
			error = VOP_GETATTR(udvp, &va, cnp->cn_cred);
			if (error != 0)
				return (error);
			if (va.va_flags & OPAQUE) 
				cnp->cn_flags |= ISWHITEOUT;
		}

		if ((error = VOP_MKDIR(udvp, &uvp, cnp, ap->a_vap)) == 0) {
			error = unionfs_nodeget(ap->a_dvp->v_mount, uvp, NULLVP,
			    ap->a_dvp, ap->a_vpp, cnp);
			if (error) {
				vput(uvp);
			} else {
				vrele(uvp);
			}
		}
	}

	UNIONFS_INTERNAL_DEBUG("unionfs_mkdir: leave (%d)\n", error);

	return (error);
}
Esempio n. 6
0
static void
prof_getattr(struct sdev_node *dir, char *name, struct vnode *gdv,
    struct vattr *vap, struct vnode **avpp, int *no_fs_perm)
{
	struct vnode *advp;

	/* get attribute from shadow, if present; else get default */
	advp = dir->sdev_attrvp;
	if (advp && VOP_LOOKUP(advp, name, avpp, NULL, 0, NULL, kcred,
	    NULL, NULL, NULL) == 0) {
		(void) VOP_GETATTR(*avpp, vap, 0, kcred, NULL);
	} else if (gdv == NULL || gdv->v_type == VDIR) {
		/* always create shadow directory */
		*vap = sdev_vattr_dir;
		if (advp && VOP_MKDIR(advp, name, &sdev_vattr_dir,
		    avpp, kcred, NULL, 0, NULL) != 0) {
			*avpp = NULLVP;
			sdcmn_err10(("prof_getattr: failed to create "
			    "shadow directory %s/%s\n", dir->sdev_path, name));
		}
	} else {
		/*
		 * get default permission from devfs
		 * Before calling devfs_get_defattr, we need to get
		 * the realvp (the dv_node). If realvp is not a dv_node,
		 * devfs_get_defattr() will return a system-wide default
		 * attr for device nodes.
		 */
		struct vnode *rvp;
		if (VOP_REALVP(gdv, &rvp, NULL) != 0)
			rvp = gdv;
		devfs_get_defattr(rvp, vap, no_fs_perm);
		*avpp = NULLVP;
	}

	/* ignore dev_t and vtype from backing store */
	if (gdv) {
		vap->va_type = gdv->v_type;
		vap->va_rdev = gdv->v_rdev;
	}
}
Esempio n. 7
0
static int
auto_mkdir(
	vnode_t *dvp,
	char *nm,
	vattr_t *va,
	vnode_t **vpp,
	cred_t *cred,
	caller_context_t *ct,
	int flags,
	vsecattr_t *vsecp)
{
	vnode_t *newvp;
	int error;

	AUTOFS_DPRINT((4, "auto_mkdir dvp %p nm %s\n", (void *)dvp, nm));

	if (error = auto_trigger_mount(dvp, cred, &newvp))
		goto done;

	if (newvp != NULL) {
		/*
		 * Node is now mounted on.
		 */
		if (vn_is_readonly(newvp))
			error = EROFS;
		else
			error = VOP_MKDIR(newvp, nm, va, vpp, cred, ct,
			    flags, vsecp);
		VN_RELE(newvp);
	} else
		error = ENOSYS;

done:
	AUTOFS_DPRINT((5, "auto_mkdir: error=%d\n", error));
	return (error);
}
Esempio n. 8
0
static int
zfs_replay_create(zfsvfs_t *zfsvfs, lr_create_t *lr, boolean_t byteswap)
{
	char *name = NULL;		/* location determined later */
	char *link;			/* symlink content follows name */
	znode_t *dzp;
	vnode_t *vp = NULL;
	xvattr_t xva;
	int vflg = 0;
	size_t lrsize = sizeof (lr_create_t);
	lr_attr_t *lrattr;
	void *start;
	size_t xvatlen;
	uint64_t txtype;
	struct componentname cn;
	int error;

	txtype = (lr->lr_common.lrc_txtype & ~TX_CI);
	if (byteswap) {
		byteswap_uint64_array(lr, sizeof (*lr));
		if (txtype == TX_CREATE_ATTR || txtype == TX_MKDIR_ATTR)
			zfs_replay_swap_attrs((lr_attr_t *)(lr + 1));
	}


	if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
		return (error);

	xva_init(&xva);
	zfs_init_vattr(&xva.xva_vattr, AT_TYPE | AT_MODE | AT_UID | AT_GID,
	    lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, lr->lr_foid);

	/*
	 * All forms of zfs create (create, mkdir, mkxattrdir, symlink)
	 * eventually end up in zfs_mknode(), which assigns the object's
	 * creation time and generation number.  The generic VOP_CREATE()
	 * doesn't have either concept, so we smuggle the values inside
	 * the vattr's otherwise unused va_ctime and va_nblocks fields.
	 */
	ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime);
	xva.xva_vattr.va_nblocks = lr->lr_gen;

	error = dmu_object_info(zfsvfs->z_os, lr->lr_foid, NULL);
	if (error != ENOENT)
		goto out;

	if (lr->lr_common.lrc_txtype & TX_CI)
		vflg |= FIGNORECASE;

	/*
	 * Symlinks don't have fuid info, and CIFS never creates
	 * symlinks.
	 *
	 * The _ATTR versions will grab the fuid info in their subcases.
	 */
	if ((int)lr->lr_common.lrc_txtype != TX_SYMLINK &&
	    (int)lr->lr_common.lrc_txtype != TX_MKDIR_ATTR &&
	    (int)lr->lr_common.lrc_txtype != TX_CREATE_ATTR) {
		start = (lr + 1);
		zfsvfs->z_fuid_replay =
		    zfs_replay_fuid_domain(start, &start,
		    lr->lr_uid, lr->lr_gid);
	}

	cn.cn_cred = kcred;
	cn.cn_thread = curthread;
	cn.cn_flags = SAVENAME;

	vn_lock(ZTOV(dzp), LK_EXCLUSIVE | LK_RETRY);
	switch (txtype) {
	case TX_CREATE_ATTR:
		lrattr = (lr_attr_t *)(caddr_t)(lr + 1);
		xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
		zfs_replay_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), &xva);
		start = (caddr_t)(lr + 1) + xvatlen;
		zfsvfs->z_fuid_replay =
		    zfs_replay_fuid_domain(start, &start,
		    lr->lr_uid, lr->lr_gid);
		name = (char *)start;

		/*FALLTHROUGH*/
	case TX_CREATE:
		if (name == NULL)
			name = (char *)start;

		cn.cn_nameptr = name;
		error = VOP_CREATE(ZTOV(dzp), &vp, &cn, &xva.xva_vattr /*,vflg*/);
		break;
	case TX_MKDIR_ATTR:
		lrattr = (lr_attr_t *)(caddr_t)(lr + 1);
		xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
		zfs_replay_xvattr((lr_attr_t *)((caddr_t)lr + lrsize), &xva);
		start = (caddr_t)(lr + 1) + xvatlen;
		zfsvfs->z_fuid_replay =
		    zfs_replay_fuid_domain(start, &start,
		    lr->lr_uid, lr->lr_gid);
		name = (char *)start;

		/*FALLTHROUGH*/
	case TX_MKDIR:
		if (name == NULL)
			name = (char *)(lr + 1);

		cn.cn_nameptr = name;
		error = VOP_MKDIR(ZTOV(dzp), &vp, &cn, &xva.xva_vattr /*,vflg*/);
		break;
	case TX_MKXATTR:
		error = zfs_make_xattrdir(dzp, &xva.xva_vattr, &vp, kcred);
		break;
	case TX_SYMLINK:
		name = (char *)(lr + 1);
		link = name + strlen(name) + 1;
		cn.cn_nameptr = name;
		error = VOP_SYMLINK(ZTOV(dzp), &vp, &cn, &xva.xva_vattr, link /*,vflg*/);
		break;
	default:
		error = ENOTSUP;
	}
	VOP_UNLOCK(ZTOV(dzp), 0);

out:
	if (error == 0 && vp != NULL)
		VN_URELE(vp);

	VN_RELE(ZTOV(dzp));

	if (zfsvfs->z_fuid_replay)
		zfs_fuid_info_free(zfsvfs->z_fuid_replay);
	zfsvfs->z_fuid_replay = NULL;
	return (error);
}
Esempio n. 9
0
/*
 * Replay file create with optional ACL, xvattr information as well
 * as option FUID information.
 */
static int
zfs_replay_create_acl(zfsvfs_t *zfsvfs,
    lr_acl_create_t *lracl, boolean_t byteswap)
{
	char *name = NULL;		/* location determined later */
	lr_create_t *lr = (lr_create_t *)lracl;
	znode_t *dzp;
	vnode_t *vp = NULL;
	xvattr_t xva;
	int vflg = 0;
	vsecattr_t vsec = { 0 };
	lr_attr_t *lrattr;
	void *aclstart;
	void *fuidstart;
	size_t xvatlen = 0;
	uint64_t txtype;
	int error;

	txtype = (lr->lr_common.lrc_txtype & ~TX_CI);
	if (byteswap) {
		byteswap_uint64_array(lracl, sizeof (*lracl));
		if (txtype == TX_CREATE_ACL_ATTR ||
		    txtype == TX_MKDIR_ACL_ATTR) {
			lrattr = (lr_attr_t *)(caddr_t)(lracl + 1);
			zfs_replay_swap_attrs(lrattr);
			xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
		}

		aclstart = (caddr_t)(lracl + 1) + xvatlen;
		zfs_ace_byteswap(aclstart, lracl->lr_acl_bytes, B_FALSE);
		/* swap fuids */
		if (lracl->lr_fuidcnt) {
			byteswap_uint64_array((caddr_t)aclstart +
			    ZIL_ACE_LENGTH(lracl->lr_acl_bytes),
			    lracl->lr_fuidcnt * sizeof (uint64_t));
		}
	}

	if ((error = zfs_zget(zfsvfs, lr->lr_doid, &dzp)) != 0)
		return (error);

	xva_init(&xva);
	zfs_init_vattr(&xva.xva_vattr, AT_TYPE | AT_MODE | AT_UID | AT_GID,
	    lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, lr->lr_foid);

	/*
	 * All forms of zfs create (create, mkdir, mkxattrdir, symlink)
	 * eventually end up in zfs_mknode(), which assigns the object's
	 * creation time and generation number.  The generic VOP_CREATE()
	 * doesn't have either concept, so we smuggle the values inside
	 * the vattr's otherwise unused va_ctime and va_nblocks fields.
	 */
	ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime);
	xva.xva_vattr.va_nblocks = lr->lr_gen;

	error = dmu_object_info(zfsvfs->z_os, lr->lr_foid, NULL);
	if (error != ENOENT)
		goto bail;

	if (lr->lr_common.lrc_txtype & TX_CI)
		vflg |= FIGNORECASE;
	switch (txtype) {
	case TX_CREATE_ACL:
		aclstart = (caddr_t)(lracl + 1);
		fuidstart = (caddr_t)aclstart +
		    ZIL_ACE_LENGTH(lracl->lr_acl_bytes);
		zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart,
		    (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
		    lr->lr_uid, lr->lr_gid);
		/*FALLTHROUGH*/
	case TX_CREATE_ACL_ATTR:
		if (name == NULL) {
			lrattr = (lr_attr_t *)(caddr_t)(lracl + 1);
			xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
			xva.xva_vattr.va_mask |= AT_XVATTR;
			zfs_replay_xvattr(lrattr, &xva);
		}
		vsec.vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
		vsec.vsa_aclentp = (caddr_t)(lracl + 1) + xvatlen;
		vsec.vsa_aclcnt = lracl->lr_aclcnt;
		vsec.vsa_aclentsz = lracl->lr_acl_bytes;
		vsec.vsa_aclflags = lracl->lr_acl_flags;
		if (zfsvfs->z_fuid_replay == NULL) {
			fuidstart = (caddr_t)(lracl + 1) + xvatlen +
			    ZIL_ACE_LENGTH(lracl->lr_acl_bytes);
			zfsvfs->z_fuid_replay =
			    zfs_replay_fuids(fuidstart,
			    (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
			    lr->lr_uid, lr->lr_gid);
		}

#ifdef TODO
		error = VOP_CREATE(ZTOV(dzp), name, &xva.xva_vattr,
		    0, 0, &vp, kcred, vflg, NULL, &vsec);
#else
		panic("%s:%u: unsupported condition", __func__, __LINE__);
#endif
		break;
	case TX_MKDIR_ACL:
		aclstart = (caddr_t)(lracl + 1);
		fuidstart = (caddr_t)aclstart +
		    ZIL_ACE_LENGTH(lracl->lr_acl_bytes);
		zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart,
		    (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
		    lr->lr_uid, lr->lr_gid);
		/*FALLTHROUGH*/
	case TX_MKDIR_ACL_ATTR:
		if (name == NULL) {
			lrattr = (lr_attr_t *)(caddr_t)(lracl + 1);
			xvatlen = ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
			zfs_replay_xvattr(lrattr, &xva);
		}
		vsec.vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
		vsec.vsa_aclentp = (caddr_t)(lracl + 1) + xvatlen;
		vsec.vsa_aclcnt = lracl->lr_aclcnt;
		vsec.vsa_aclentsz = lracl->lr_acl_bytes;
		vsec.vsa_aclflags = lracl->lr_acl_flags;
		if (zfsvfs->z_fuid_replay == NULL) {
			fuidstart = (caddr_t)(lracl + 1) + xvatlen +
			    ZIL_ACE_LENGTH(lracl->lr_acl_bytes);
			zfsvfs->z_fuid_replay =
			    zfs_replay_fuids(fuidstart,
			    (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
			    lr->lr_uid, lr->lr_gid);
		}
#ifdef TODO
		error = VOP_MKDIR(ZTOV(dzp), name, &xva.xva_vattr,
		    &vp, kcred, NULL, vflg, &vsec);
#else
		panic("%s:%u: unsupported condition", __func__, __LINE__);
#endif
		break;
	default:
		error = ENOTSUP;
	}

bail:
	if (error == 0 && vp != NULL)
		VN_RELE(vp);

	VN_RELE(ZTOV(dzp));

	if (zfsvfs->z_fuid_replay)
		zfs_fuid_info_free(zfsvfs->z_fuid_replay);
	zfsvfs->z_fuid_replay = NULL;

	return (error);
}
Esempio n. 10
0
STATIC int
linvfs_mknod(
	struct inode	*dir,
	struct dentry	*dentry,
	int		mode,
	int		rdev)
{
	struct inode	*ip;
	vattr_t		va;
	vnode_t		*vp = NULL, *dvp = LINVFS_GET_VP(dir);
	xfs_acl_t	*default_acl = NULL;
	attrexists_t	test_default_acl = _ACL_DEFAULT_EXISTS;
	int		error;

	if (test_default_acl && test_default_acl(dvp)) {
		if (!_ACL_ALLOC(default_acl))
			return -ENOMEM;
		if (!_ACL_GET_DEFAULT(dvp, default_acl)) {
			_ACL_FREE(default_acl);
			default_acl = NULL;
		}
	}

#ifdef CONFIG_XFS_POSIX_ACL
	/*
	 * Conditionally compiled so that the ACL base kernel changes can be
	 * split out into separate patches - remove this once MS_POSIXACL is
	 * accepted, or some other way to implement this exists.
	 */
	if (IS_POSIXACL(dir) && !default_acl && has_fs_struct(current))
		mode &= ~current->fs->umask;
#endif

	memset(&va, 0, sizeof(va));
	va.va_mask = XFS_AT_TYPE|XFS_AT_MODE;
	va.va_type = IFTOVT(mode);
	va.va_mode = mode;

	switch (mode & S_IFMT) {
	case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
		va.va_rdev = XFS_MKDEV(MAJOR(rdev), MINOR(rdev));
		va.va_mask |= XFS_AT_RDEV;
		/*FALLTHROUGH*/
	case S_IFREG:
		VOP_CREATE(dvp, dentry, &va, &vp, NULL, error);
		break;
	case S_IFDIR:
		VOP_MKDIR(dvp, dentry, &va, &vp, NULL, error);
		break;
	default:
		error = EINVAL;
		break;
	}

	if (default_acl) {
		if (!error) {
			error = _ACL_INHERIT(vp, &va, default_acl);
			if (!error) {
				VMODIFY(vp);
			} else {
				struct dentry	teardown = {};
				int		err2;

				/* Oh, the horror.
				 * If we can't add the ACL we must back out.
				 * ENOSPC can hit here, among other things.
				 */
				teardown.d_inode = ip = LINVFS_GET_IP(vp);
				teardown.d_name = dentry->d_name;

				vn_mark_bad(vp);

				if (S_ISDIR(mode))
					VOP_RMDIR(dvp, &teardown, NULL, err2);
				else
					VOP_REMOVE(dvp, &teardown, NULL, err2);
				VN_RELE(vp);
			}
		}
		_ACL_FREE(default_acl);
	}

	if (!error) {
		ASSERT(vp);
		ip = LINVFS_GET_IP(vp);

		if (S_ISCHR(mode) || S_ISBLK(mode))
			ip->i_rdev = to_kdev_t(rdev);
		else if (S_ISDIR(mode))
			validate_fields(ip);
		d_instantiate(dentry, ip);
		validate_fields(dir);
	}
	return -error;
}
Esempio n. 11
0
static int zfsfuse_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode)
{
	if(strlen(name) >= MAXNAMELEN)
		return ENAMETOOLONG;

	vfs_t *vfs = (vfs_t *) fuse_req_userdata(req);
	zfsvfs_t *zfsvfs = vfs->vfs_data;

	ZFS_ENTER(zfsvfs);

	znode_t *znode;

	int error = zfs_zget(zfsvfs, parent, &znode, B_FALSE);
	if(error) {
		ZFS_EXIT(zfsvfs);
		/* If the inode we are trying to get was recently deleted
		   dnode_hold_impl will return EEXIST instead of ENOENT */
		return error == EEXIST ? ENOENT : error;
	}

	ASSERT(znode != NULL);
	vnode_t *dvp = ZTOV(znode);
	ASSERT(dvp != NULL);

	vnode_t *vp = NULL;

	vattr_t vattr = { 0 };
	vattr.va_type = VDIR;
	vattr.va_mode = mode & PERMMASK;
	vattr.va_mask = AT_TYPE | AT_MODE;

	cred_t cred;
	zfsfuse_getcred(req, &cred);

	error = VOP_MKDIR(dvp, (char *) name, &vattr, &vp, &cred, NULL, 0, NULL);
	if(error)
		goto out;

	ASSERT(vp != NULL);

	struct fuse_entry_param e = { 0 };

	e.attr_timeout = 0.0;
	e.entry_timeout = 0.0;

	e.ino = VTOZ(vp)->z_id;
	if(e.ino == 3)
		e.ino = 1;

	e.generation = VTOZ(vp)->z_phys->zp_gen;

	error = zfsfuse_stat(vp, &e.attr, &cred);

out:
	if(vp != NULL)
		VN_RELE(vp);
	VN_RELE(dvp);
	ZFS_EXIT(zfsvfs);

	if(!error)
		fuse_reply_entry(req, &e);

	return error;
}
Esempio n. 12
0
STATIC int
linvfs_mknod(
	struct inode	*dir,
	struct dentry	*dentry,
	int		mode,
	int		rdev)
{
	struct inode	*ip;
	vattr_t		va;
	vnode_t		*vp = NULL, *dvp = LINVFS_GET_VP(dir);
	xattr_exists_t	test_default_acl = _ACL_DEFAULT_EXISTS;
	int		have_default_acl = 0;
	int		error = EINVAL;

	if (test_default_acl)
		have_default_acl = test_default_acl(dvp);

#ifdef CONFIG_FS_POSIX_ACL
	/*
	 * Conditionally compiled so that the ACL base kernel changes can be
	 * split out into separate patches - remove this once MS_POSIXACL is
	 * accepted, or some other way to implement this exists.
	 */
	if (IS_POSIXACL(dir) && !have_default_acl && has_fs_struct(current))
		mode &= ~current->fs->umask;
#endif

	bzero(&va, sizeof(va));
	va.va_mask = AT_TYPE|AT_MODE;
	va.va_type = IFTOVT(mode);
	va.va_mode = mode;

	switch (mode & S_IFMT) {
	case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
		va.va_rdev = rdev;
		va.va_mask |= AT_RDEV;
		/*FALLTHROUGH*/
	case S_IFREG:
		VOP_CREATE(dvp, dentry, &va, &vp, NULL, error);
		break;
	case S_IFDIR:
		VOP_MKDIR(dvp, dentry, &va, &vp, NULL, error);
		break;
	default:
		error = EINVAL;
		break;
	}

	if (!error) {
		ASSERT(vp);
		ip = LINVFS_GET_IP(vp);
		if (!ip) {
			VN_RELE(vp);
			return -ENOMEM;
		}

		if (S_ISCHR(mode) || S_ISBLK(mode))
			ip->i_rdev = to_kdev_t(rdev);
		/* linvfs_revalidate_core returns (-) errors */
		error = -linvfs_revalidate_core(ip, ATTR_COMM);
		validate_fields(dir);
		d_instantiate(dentry, ip);
		mark_inode_dirty_sync(ip);
		mark_inode_dirty_sync(dir);
	}

	if (!error && have_default_acl) {
		_ACL_DECL	(pdacl);

		if (!_ACL_ALLOC(pdacl)) {
			error = -ENOMEM;
		} else {
			if (_ACL_GET_DEFAULT(dvp, pdacl))
				error = _ACL_INHERIT(vp, &va, pdacl);
			VMODIFY(vp);
			_ACL_FREE(pdacl);
		}
	}
	return -error;
}
/*
 * Creates the fs cache directory.
 * The directory name is the ascii version of the fsid.
 * Also makes a symlink to the directory using the specified name.
 */
int
fscdir_create(cachefscache_t *cachep, char *namep, fscache_t *fscp)
{
	int error;
	vnode_t *fscdirvp = NULL;
	vnode_t *infovp = NULL;
	vnode_t *attrvp = NULL;
	struct vattr *attrp = (struct vattr *)NULL;
	char name[CFS_FRONTFILE_NAME_SIZE];
	int files;
	int blocks = 0;
	cfs_cid_t cid;
	ino64_t fsid;

	ASSERT(MUTEX_HELD(&cachep->c_fslistlock));
	ASSERT(fscp->fs_infovp == NULL);
	ASSERT(fscp->fs_fscdirvp == NULL);
	ASSERT(fscp->fs_fsattrdir == NULL);

	/* directory, symlink and options file + attrcache dir */
	files = 0;
	while (files < 4) {
		error = cachefs_allocfile(cachep);
		if (error)
			goto out;
		files++;
	}
	error = cachefs_allocblocks(cachep, 4, CACHEFS_RL_NONE);
	if (error)
		goto out;
	blocks = 4;

	attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP);
	attrp->va_mode = S_IFDIR | 0777;
	attrp->va_uid = 0;
	attrp->va_gid = 0;
	attrp->va_type = VDIR;
	attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
	error = VOP_MKDIR(cachep->c_dirvp, namep, attrp, &fscdirvp, kcred,
	    NULL, 0, NULL);
	if (error) {
		cmn_err(CE_WARN, "Can't create fs cache directory");
		goto out;
	}

	/*
	 * Created the directory. Get the fileno. That'll be the cachefs_fsid.
	 */
	attrp->va_mask = AT_NODEID;
	error = VOP_GETATTR(fscdirvp, attrp, 0, kcred, NULL);
	if (error) {
		goto out;
	}
	fsid = attrp->va_nodeid;
	attrp->va_mode = S_IFREG | 0666;
	attrp->va_uid = 0;
	attrp->va_gid = 0;
	attrp->va_type = VREG;
	attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
	error = VOP_CREATE(fscdirvp, CACHEFS_FSINFO, attrp, EXCL,
			0600, &infovp, kcred, 0, NULL, NULL);
	if (error) {
		cmn_err(CE_WARN, "Can't create fs option file");
		goto out;
	}
	attrp->va_size = MAXBSIZE;
	attrp->va_mask = AT_SIZE;
	error = VOP_SETATTR(infovp, attrp, 0, kcred, NULL);
	if (error) {
		cmn_err(CE_WARN, "Can't set size of fsinfo file");
		goto out;
	}

	/* write out the info file */
	fscp->fs_flags |= CFS_FS_DIRTYINFO;
	error = fscache_info_sync(fscp);
	if (error)
		goto out;

	/*
	 * Install the symlink from cachefs_fsid -> directory.
	 */
	cid.cid_flags = 0;
	cid.cid_fileno = fsid;
	make_ascii_name(&cid, name);
	error = VOP_RENAME(cachep->c_dirvp, namep, cachep->c_dirvp,
		name, kcred, NULL, 0);
	if (error) {
		cmn_err(CE_WARN, "Can't rename cache directory");
		goto out;
	}
	attrp->va_mask = AT_MODE | AT_TYPE;
	attrp->va_mode = 0777;
	attrp->va_type = VLNK;
	error = VOP_SYMLINK(cachep->c_dirvp, namep, attrp, name, kcred, NULL,
	    0);
	if (error) {
		cmn_err(CE_WARN, "Can't create cache directory symlink");
		goto out;
	}

	/*
	 * Finally, make the attrcache directory
	 */
	attrp->va_mode = S_IFDIR | 0777;
	attrp->va_uid = 0;
	attrp->va_gid = 0;
	attrp->va_type = VDIR;
	attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
	error = VOP_MKDIR(fscdirvp, ATTRCACHE_NAME, attrp, &attrvp, kcred, NULL,
	    0, NULL);
	if (error) {
		cmn_err(CE_WARN, "Can't create attrcache dir for fscache");
		goto out;
	}

	mutex_enter(&fscp->fs_fslock);
	fscp->fs_cfsid = fsid;
	fscp->fs_fscdirvp = fscdirvp;
	fscp->fs_fsattrdir = attrvp;
	fscp->fs_infovp = infovp;
	mutex_exit(&fscp->fs_fslock);

out:

	if (error) {
		while (files-- > 0)
			cachefs_freefile(cachep);
		if (fscdirvp)
			VN_RELE(fscdirvp);
		if (blocks)
			cachefs_freeblocks(cachep, blocks, CACHEFS_RL_NONE);
		if (attrvp)
			VN_RELE(attrvp);
		if (infovp)
			VN_RELE(infovp);
	}
	if (attrp)
		cachefs_kmem_free(attrp, sizeof (struct vattr));
	return (error);
}
STATIC int
linvfs_mknod(
	struct inode	*dir,
	struct dentry	*dentry,
	int		mode,
	dev_t		rdev)
{
	struct inode	*ip;
	vattr_t		va;
	vnode_t		*vp = NULL, *dvp = LINVFS_GET_VP(dir);
	xfs_acl_t	*default_acl = NULL;
	attrexists_t	test_default_acl = _ACL_DEFAULT_EXISTS;
	int		error;

	/*
	 * Irix uses Missed'em'V split, but doesn't want to see
	 * the upper 5 bits of (14bit) major.
	 */
	if (!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff)
		return -EINVAL;

	if (test_default_acl && test_default_acl(dvp)) {
		if (!_ACL_ALLOC(default_acl))
			return -ENOMEM;
		if (!_ACL_GET_DEFAULT(dvp, default_acl)) {
			_ACL_FREE(default_acl);
			default_acl = NULL;
		}
	}

	if (IS_POSIXACL(dir) && !default_acl && has_fs_struct(current))
		mode &= ~current->fs->umask;

	memset(&va, 0, sizeof(va));
	va.va_mask = XFS_AT_TYPE|XFS_AT_MODE;
	va.va_mode = mode;

	switch (mode & S_IFMT) {
	case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
		va.va_rdev = sysv_encode_dev(rdev);
		va.va_mask |= XFS_AT_RDEV;
		/*FALLTHROUGH*/
	case S_IFREG:
		VOP_CREATE(dvp, dentry, &va, &vp, NULL, error);
		break;
	case S_IFDIR:
		VOP_MKDIR(dvp, dentry, &va, &vp, NULL, error);
		break;
	default:
		error = EINVAL;
		break;
	}

	if (!error)
	{
		error = linvfs_init_security(vp, dir);
		if (error)
			cleanup_inode(dvp, vp, dentry, mode);
	}

	if (default_acl) {
		if (!error) {
			error = _ACL_INHERIT(vp, &va, default_acl);
			if (!error) 
				VMODIFY(vp);
			else
				cleanup_inode(dvp, vp, dentry, mode);
		}
		_ACL_FREE(default_acl);
	}

	if (!error) {
		ASSERT(vp);
		ip = LINVFS_GET_IP(vp);

		if (S_ISCHR(mode) || S_ISBLK(mode))
			ip->i_rdev = rdev;
		else if (S_ISDIR(mode))
			validate_fields(ip);
		d_instantiate(dentry, ip);
		validate_fields(dir);
	}
	return -error;
}