示例#1
0
/*
 * 	union_create:
 *
 * a_dvp is locked on entry and remains locked on return.  a_vpp is returned
 * locked if no error occurs, otherwise it is garbage.
 *
 * union_create(struct vnode *a_dvp, struct vnode **a_vpp,
 *		struct componentname *a_cnp, struct vattr *a_vap)
 */
static int
union_create(struct vop_old_create_args *ap)
{
	struct union_node *dun = VTOUNION(ap->a_dvp);
	struct componentname *cnp = ap->a_cnp;
	struct thread *td = cnp->cn_td;
	struct vnode *dvp;
	int error = EROFS;

	if ((dvp = union_lock_upper(dun, td)) != NULL) {
		struct vnode *vp;
		struct mount *mp;

		error = VOP_CREATE(dvp, &vp, cnp, ap->a_vap);
		if (error == 0) {
			mp = ap->a_dvp->v_mount;
			vn_unlock(vp);
			UDEBUG(("ALLOCVP-1 FROM %p REFS %d\n", vp, vp->v_sysref.refcnt));
			error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP,
				cnp, vp, NULLVP, 1);
			UDEBUG(("ALLOCVP-2B FROM %p REFS %d\n", *ap->a_vpp, vp->v_sysref.refcnt));
		}
		union_unlock_upper(dvp, td);
	}
	return (error);
}
示例#2
0
static int
xattr_dir_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
    int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
    vsecattr_t *vsecp)
{
	vnode_t *pvp;
	int error;

	*vpp = NULL;

	/*
	 * Don't allow creation of extended attributes with sysattr names.
	 */
	if (is_sattr_name(name)) {
		return (gfs_dir_lookup(dvp, name, vpp, cr, 0, NULL, NULL));
	}

	error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR,
	    cr, ct);
	if (error == 0) {
		error = VOP_CREATE(pvp, name, vap, excl, mode, vpp, cr, flag,
		    ct, vsecp);
	}
	return (error);
}
示例#3
0
static int
unionfs_create(void *v)
{
	struct vop_create_args *ap = v;
	struct unionfs_node *dunp;
	struct componentname *cnp;
	struct vnode   *udvp;
	struct vnode   *vp;
	int		error;

	UNIONFS_INTERNAL_DEBUG("unionfs_create: enter\n");

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

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

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

	return (error);
}
示例#4
0
int
smb_vop_create(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_CREATE(dvp, np, vap, EXCL, attr->sa_vattr.va_mode,
	    vpp, cr, option_flags, &smb_ct, vsap);

	return (error);
}
示例#5
0
int
RUMP_VOP_CREATE(struct vnode *dvp,
    struct vnode **vpp,
    struct componentname *cnp,
    struct vattr *vap)
{
	int error;

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

	return error;
}
示例#6
0
static int
auto_create(
	vnode_t *dvp,
	char *nm,
	vattr_t *va,
	vcexcl_t excl,
	int mode,
	vnode_t **vpp,
	cred_t *cred,
	int flag,
	caller_context_t *ct,
	vsecattr_t *vsecp)
{
	vnode_t *newvp;
	int error;

	AUTOFS_DPRINT((4, "auto_create 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_CREATE(newvp, nm, va, excl,
			    mode, vpp, cred, flag, ct, vsecp);
		VN_RELE(newvp);
	} else
		error = ENOSYS;

done:
	AUTOFS_DPRINT((5, "auto_create: error=%d\n", error));
	return (error);
}
示例#7
0
文件: open.c 项目: akat1/impala
errno_t
sc_open(thread_t *p, syscall_result_t *r, sc_open_args *arg)
{
    int fd;
    int flags = arg->flags;
    int error = 0;
    vnode_t *node;
    proc_t *proc = p->thr_proc;
    char fname[PATH_MAX+1];
    if((error = copyinstr(fname, arg->fname, PATH_MAX)))
        return error;
    KASSERT(proc->p_rootdir!=NULL);
    error = vfs_lookup(proc->p_curdir, &node, fname, p, LKP_NORMAL);
    if(error) {
        if(!(flags & O_CREAT))
            return error;
        vnode_t *parent;
        error = vfs_lookup_parent(proc->p_curdir, &parent, fname, p);
        if(error)
            return error;
        if((error = VOP_ACCESS(parent, W_OK, proc->p_cred))) {
            vrele(parent);
            return error;
        }
        vattr_t attr;
        attr.va_mode = arg->mode & ~(proc->p_umask) & 0777;
        attr.va_type = VNODE_TYPE_REG;
        attr.va_uid = proc->p_cred->p_uid;
        attr.va_gid = proc->p_cred->p_gid;
        attr.va_size = 0;
        attr.va_dev = NULL;
        error = VOP_CREATE(parent, &node, _get_last_cmpt(fname), &attr);
        VOP_UNLOCK(parent);
        if(error)
            return error;
        VOP_LOCK(node);
    } else {
        //plik istnieje
        if((flags & O_CREAT) && (flags & O_EXCL)) {
            vrele(node);
            return -EEXIST;
        }
        if((node->v_type == VNODE_TYPE_DIR) && (flags & (O_RDWR | O_WRONLY))) {
            vrele(node);
            return -EISDIR;
        }
    }
    int wmode = (flags & O_RDWR) ? (W_OK | R_OK) :
                (flags & O_RDONLY) ? (R_OK) : (W_OK);
    if((error = VOP_ACCESS(node, wmode, proc->p_cred))) {
        vrele(node);
        return error;
    }
    if((error = VOP_OPEN(node, flags, arg->mode))) {
        vrele(node);
        return error;
    }
    if(ISSET(flags, O_RDWR | O_WRONLY) && ISSET(flags, O_TRUNC)
       && node->v_type == VNODE_TYPE_REG)
        VOP_TRUNCATE(node, 0);

    if((error = f_alloc(proc, node, flags, &fd))) {
        vrele(node); // <- powinno to tutaj być, dopisałem bo nie było.
        return error;
    }
    VOP_UNLOCK(node);
    r->result = fd;
    return 0;
}
static int zfsfuse_opencreate(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int fflags, mode_t createmode, const char *name)
{
	if(name && strlen(name) >= MAXNAMELEN)
		return ENAMETOOLONG;

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

	ZFS_ENTER(zfsvfs);

	cred_t cred;
	zfsfuse_getcred(req, &cred);

	/* Map flags */
	int mode, flags;

	if(fflags & O_WRONLY) {
		mode = VWRITE;
		flags = FWRITE;
	} else if(fflags & O_RDWR) {
		mode = VREAD | VWRITE;
		flags = FREAD | FWRITE;
	} else {
		mode = VREAD;
		flags = FREAD;
	}

	if(fflags & O_CREAT)
		flags |= FCREAT;
	if(fflags & O_SYNC)
		flags |= FSYNC;
	if(fflags & O_DSYNC)
		flags |= FDSYNC;
	if(fflags & O_RSYNC)
		flags |= FRSYNC;
	if(fflags & O_APPEND)
		flags |= FAPPEND;
	if(fflags & O_LARGEFILE)
		flags |= FOFFMAX;
	if(fflags & O_NOFOLLOW)
		flags |= FNOFOLLOW;
	if(fflags & O_TRUNC)
		flags |= FTRUNC;
	if(fflags & O_EXCL)
		flags |= FEXCL;

	znode_t *znode;

	int error = zfs_zget(zfsvfs, ino, &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 *vp = ZTOV(znode);
	ASSERT(vp != NULL);

	if (flags & FCREAT) {
		enum vcexcl excl;

		/*
		 * Wish to create a file.
		 */
		vattr_t vattr;
		vattr.va_type = VREG;
		vattr.va_mode = createmode;
		vattr.va_mask = AT_TYPE|AT_MODE;
		if (flags & FTRUNC) {
			vattr.va_size = 0;
			vattr.va_mask |= AT_SIZE;
		}
		if (flags & FEXCL)
			excl = EXCL;
		else
			excl = NONEXCL;

		vnode_t *new_vp;
		/* FIXME: check filesystem boundaries */
		error = VOP_CREATE(vp, (char *) name, &vattr, excl, mode, &new_vp, &cred, 0, NULL, NULL);

		if(error)
			goto out;

		VN_RELE(vp);
		vp = new_vp;
	} else {
		/*
		 * Get the attributes to check whether file is large.
		 * We do this only if the O_LARGEFILE flag is not set and
		 * only for regular files.
		 */
		if (!(flags & FOFFMAX) && (vp->v_type == VREG)) {
			vattr_t vattr;
			vattr.va_mask = AT_SIZE;
			if ((error = VOP_GETATTR(vp, &vattr, 0, &cred, NULL)))
				goto out;

			if (vattr.va_size > (u_offset_t) MAXOFF32_T) {
				/*
				 * Large File API - regular open fails
				 * if FOFFMAX flag is set in file mode
				 */
				error = EOVERFLOW;
				goto out;
			}
		}

		/*
		 * Check permissions.
		 */
		if (error = VOP_ACCESS(vp, mode, 0, &cred, NULL))
			goto out;
	}

	if ((flags & FNOFOLLOW) && vp->v_type == VLNK) {
		error = ELOOP;
		goto out;
	}

	vnode_t *old_vp = vp;

	error = VOP_OPEN(&vp, flags, &cred, NULL);

	ASSERT(old_vp == vp);

	if(error)
		goto out;

	struct fuse_entry_param e = { 0 };

	if(flags & FCREAT) {
		error = zfsfuse_stat(vp, &e.attr, &cred);
		if(error)
			goto out;
	}

	file_info_t *info = kmem_cache_alloc(file_info_cache, KM_NOSLEEP);
	if(info == NULL) {
		error = ENOMEM;
		goto out;
	}

	info->vp = vp;
	info->flags = flags;

	fi->fh = (uint64_t) (uintptr_t) info;
	fi->keep_cache = 1;

	if(flags & FCREAT) {
		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;
	}

out:
	if(error) {
		ASSERT(vp->v_count > 0);
		VN_RELE(vp);
	}

	ZFS_EXIT(zfsvfs);

	if(!error) {
		if(!(flags & FCREAT))
			fuse_reply_open(req, fi);
		else
			fuse_reply_create(req, &e, fi);
	}
	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);
}
示例#10
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);
}
示例#11
0
extern int
vnode_iop_create(
    INODE_T * parent,
    struct dentry * dentry,
    int mode,
    struct nameidata *nd
)
{
    int err = 0;
    VATTR_T *vap;
    VNODE_T *newvp;
    struct create_ctx ctx;
    CALL_DATA_T cd;

    ASSERT_I_SEM_MINE(parent);
    ASSERT(MDKI_INOISMVFS(parent));

    vap = VATTR_ALLOC();
    if (vap == NULL)
        return -ENOMEM;
    VATTR_NULL(vap);
    mdki_linux_init_call_data(&cd);
    /*
     * Solaris sends only type, mode, size, so we will too.
     */
    vap->va_type = VREG;
    vap->va_mode = mode & ~S_IFMT;
    vap->va_size = 0;
    vap->va_mask = AT_TYPE|AT_MODE|AT_SIZE;
    newvp = NULL;
    dentry->d_inode = NULL;
    ctx.dentry = dentry;
    ctx.parent = parent;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
    /* break any rcu-walk in progress */
# if defined(MRG)
    write_seqlock_barrier(&dentry->d_lock);
# else /* defined (MRG) */
    write_seqcount_barrier(&dentry->d_seq);
# endif /* else defined (MRG) */
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) */
    err = VOP_CREATE(ITOV(parent),
                     (/* drop const */ char *) dentry->d_name.name,
                     vap,
                     NONEXCL, /* XXX handled by generic layer? */
                     mode, /* not used except for passthrough, see vap->va_mode */
                     &newvp,
                     &cd,
                     &ctx);
    err = mdki_errno_unix_to_linux(err);

    /* dentry reference uses the hold count from a successful create */
    if (!err) {
        if (dentry->d_inode == NULL) {
            /* Not a shadow object */
            ASSERT(newvp != NULL);
            ASSERT(VTOI(newvp) != NULL);
            VNODE_D_INSTANTIATE(dentry, VTOI(newvp));
            VATTR_SET_MASK(vap, AT_ALL);
            if (VOP_GETATTR(newvp, vap, 0, &cd) == 0)
                mdki_linux_vattr_pullup(newvp, vap, AT_ALL);
        } else {
            /* drop the extra ref returned in newvp */
            VN_RELE(newvp);
        }
        /* I nuked the code checking not VCHR, VREG--we are always VREG */
    } else {
        ASSERT(!dentry->d_inode);
        ASSERT(!newvp);
    }
    VATTR_FREE(vap);
    mdki_linux_destroy_call_data(&cd);
    return(err);
}
/*
 * Sets up for writing to the log files.
 */
int
cachefs_dlog_setup(fscache_t *fscp, int createfile)
{
	struct vattr vattr;
	int error = 0;
	int createdone = 0;
	int lookupdone = 0;
	int version = CFS_DLOG_VERSION;
	off_t offset;
	struct cfs_dlog_trailer trailer;

	mutex_enter(&fscp->fs_dlock);

	/* all done if the log files already exist */
	if (fscp->fs_dlogfile) {
		ASSERT(fscp->fs_dmapfile);
		goto out;
	}

	/* see if the log file exists */
	error = VOP_LOOKUP(fscp->fs_fscdirvp, CACHEFS_DLOG_FILE,
	    &fscp->fs_dlogfile, NULL, 0, NULL, kcred, NULL, NULL, NULL);
	if (error && (createfile == 0))
		goto out;

	/* if the lookup failed then create file log files */
	if (error) {
		createdone++;

		vattr.va_mode = S_IFREG | 0666;
		vattr.va_uid = 0;
		vattr.va_gid = 0;
		vattr.va_type = VREG;
		vattr.va_mask = AT_TYPE|AT_MODE|AT_UID|AT_GID;
		error = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_DLOG_FILE,
		    &vattr, 0, 0666, &fscp->fs_dlogfile, kcred, 0, NULL, NULL);
		if (error) {
#ifdef CFSDEBUG
			CFS_DEBUG(CFSDEBUG_DLOG)
				printf("cachefs: log file create fail %d\n",
				    error);
#endif
			goto out;
		}

		/* write the version number into the log file */
		error = vn_rdwr(UIO_WRITE, fscp->fs_dlogfile, (caddr_t)&version,
		    sizeof (version), (offset_t)0, UIO_SYSSPACE, FSYNC,
		    RLIM_INFINITY, kcred, NULL);
		if (error) {
#ifdef CFSDEBUG
			CFS_DEBUG(CFSDEBUG_DLOG)
				printf("cachefs: log file init fail %d\n",
				    error);
#endif
			goto out;
		}

		vattr.va_mode = S_IFREG | 0666;
		vattr.va_uid = 0;
		vattr.va_gid = 0;
		vattr.va_type = VREG;
		vattr.va_mask = AT_TYPE|AT_MODE|AT_UID|AT_GID;
		error = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_DMAP_FILE,
		    &vattr, 0, 0666, &fscp->fs_dmapfile, kcred, 0, NULL, NULL);
		if (error) {
#ifdef CFSDEBUG
			CFS_DEBUG(CFSDEBUG_DLOG)
				printf("cachefs: map file create fail %d\n",
				    error);
#endif
			goto out;
		}

		fscp->fs_dlogoff = sizeof (version);
		fscp->fs_dlogseq = 0;
		fscp->fs_dmapoff = 0;
		fscp->fs_dmapsize = 0;
	}

	/*
	 * Else the lookup succeeded.
	 * Before mounting, fsck should have fixed any problems
	 * in the log file.
	 */
	else {
		lookupdone++;

		/* find the end of the log file */
		vattr.va_mask = AT_ALL;
		error = VOP_GETATTR(fscp->fs_dlogfile, &vattr, 0, kcred, NULL);
		if (error) {
#ifdef CFSDEBUG
			CFS_DEBUG(CFSDEBUG_DLOG)
				printf("cachefs: log file getattr fail %d\n",
				    error);
#endif
			goto out;
		}
		/*LINTED alignment okay*/
		ASSERT(vattr.va_size <= MAXOFF_T);
		fscp->fs_dlogoff = (off_t)vattr.va_size;

		offset = vattr.va_size - sizeof (struct cfs_dlog_trailer);
		/*
		 * The last record in the dlog file is a trailer record
		 * that contains the last sequence number used. This is
		 * used to reset the sequence number when a logfile already
		 * exists.
		 */
		error = vn_rdwr(UIO_READ, fscp->fs_dlogfile, (caddr_t)&trailer,
		    sizeof (struct cfs_dlog_trailer), (offset_t)offset,
		    UIO_SYSSPACE, FSYNC, RLIM_INFINITY, kcred, NULL);
		if (error == 0) {
			if (trailer.dl_op == CFS_DLOG_TRAILER) {
				fscp->fs_dlogseq = trailer.dl_seq;
				/*
				 * Set the offset of the next record to be
				 * written, to over write the current
				 * trailer.
				 */
				fscp->fs_dlogoff = offset;
			} else {
#ifdef CFSDEBUG
				CFS_DEBUG(CFSDEBUG_DLOG) {
					cmn_err(CE_WARN,
					    "cachefs: can't find dlog trailer");
					cmn_err(CE_WARN,
					    "cachefs: fsck required");
				}
#endif /* CFSDEBUG */
				/*LINTED alignment okay*/
				fscp->fs_dlogseq = (uint_t)vattr.va_size;
			}
		} else {
#ifdef CFSDEBUG
			CFS_DEBUG(CFSDEBUG_DLOG)
				cmn_err(CE_WARN,
				    "cachefs: error reading dlog trailer");
#endif /* CFSDEBUG */
			/*LINTED alignment okay*/
			fscp->fs_dlogseq = (uint_t)vattr.va_size;
		}


		error = VOP_LOOKUP(fscp->fs_fscdirvp, CACHEFS_DMAP_FILE,
		    &fscp->fs_dmapfile, NULL, 0, NULL, kcred, NULL, NULL, NULL);
		if (error) {
#ifdef CFSDEBUG
			CFS_DEBUG(CFSDEBUG_DLOG)
				printf("cachefs: map file lookup fail %d\n",
				    error);
#endif
			goto out;
		}

		vattr.va_mask = AT_ALL;
		error = VOP_GETATTR(fscp->fs_dmapfile, &vattr, 0, kcred, NULL);
		if (error) {
#ifdef CFSDEBUG
			CFS_DEBUG(CFSDEBUG_DLOG)
				printf("cachefs: map file getattr fail %d\n",
				    error);
#endif
			goto out;
		}
		fscp->fs_dmapoff = (off_t)vattr.va_size;
		fscp->fs_dmapsize = (off_t)vattr.va_size;
	}
示例#13
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;
}
示例#14
0
/*
 * Common code for vnode open operations.
 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
 */
int
vn_open(struct nameidata *ndp, int fmode, int cmode)
{
	struct vnode *vp;
	struct proc *p = ndp->ni_cnd.cn_proc;
	struct ucred *cred = p->p_ucred;
	struct vattr va;
	int error;

	if ((fmode & (FREAD|FWRITE)) == 0)
		return (EINVAL);
	if ((fmode & (O_TRUNC | FWRITE)) == O_TRUNC)
		return (EINVAL);
	if (fmode & O_CREAT) {
		ndp->ni_cnd.cn_nameiop = CREATE;
		ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
		if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0)
			ndp->ni_cnd.cn_flags |= FOLLOW;
		if ((error = namei(ndp)) != 0)
			return (error);

		if (ndp->ni_vp == NULL) {
			VATTR_NULL(&va);
			va.va_type = VREG;
			va.va_mode = cmode;
			error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
					   &ndp->ni_cnd, &va);
			if (error)
				return (error);
			fmode &= ~O_TRUNC;
			vp = ndp->ni_vp;
		} else {
			VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
			if (ndp->ni_dvp == ndp->ni_vp)
				vrele(ndp->ni_dvp);
			else
				vput(ndp->ni_dvp);
			ndp->ni_dvp = NULL;
			vp = ndp->ni_vp;
			if (fmode & O_EXCL) {
				error = EEXIST;
				goto bad;
			}
			fmode &= ~O_CREAT;
		}
	} else {
		ndp->ni_cnd.cn_nameiop = LOOKUP;
		ndp->ni_cnd.cn_flags =
		    ((fmode & O_NOFOLLOW) ? NOFOLLOW : FOLLOW) | LOCKLEAF;
		if ((error = namei(ndp)) != 0)
			return (error);
		vp = ndp->ni_vp;
	}
	if (vp->v_type == VSOCK) {
		error = EOPNOTSUPP;
		goto bad;
	}
	if (vp->v_type == VLNK) {
		error = EMLINK;
		goto bad;
	}
	if ((fmode & O_CREAT) == 0) {
		if (fmode & FREAD) {
			if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0)
				goto bad;
		}
		if (fmode & FWRITE) {
			if (vp->v_type == VDIR) {
				error = EISDIR;
				goto bad;
			}
			if ((error = vn_writechk(vp)) != 0 ||
			    (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0)
				goto bad;
		}
	}
	if ((fmode & O_TRUNC) && vp->v_type == VREG) {
		VATTR_NULL(&va);
		va.va_size = 0;
		if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0)
			goto bad;
	}
	if ((error = VOP_OPEN(vp, fmode, cred, p)) != 0)
		goto bad;

	if (vp->v_flag & VCLONED) {
		struct cloneinfo *cip = (struct cloneinfo *) vp->v_data;

		vp->v_flag &= ~VCLONED;
		ndp->ni_vp = cip->ci_vp; /* return cloned vnode */
		vp->v_data = cip->ci_data; /* restore v_data */
		VOP_UNLOCK(vp, 0, p); /* keep a reference */
		vp = ndp->ni_vp; /* for the increment below */

		free(cip, M_TEMP);
	}

	if (fmode & FWRITE)
		vp->v_writecount++;
	return (0);
bad:
	vput(vp);
	return (error);
}
示例#15
0
/*
 * Common code for vnode open operations.
 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
 */
int
vn_open(struct nameidata *ndp, int fmode, int cmode)
{
	struct vnode *vp;
	struct lwp *l = curlwp;
	kauth_cred_t cred = l->l_cred;
	struct vattr va;
	int error;
	const char *pathstring;

	if ((fmode & (O_CREAT | O_DIRECTORY)) == (O_CREAT | O_DIRECTORY))
		return EINVAL;

	ndp->ni_cnd.cn_flags &= TRYEMULROOT | NOCHROOT;

	if (fmode & O_CREAT) {
		ndp->ni_cnd.cn_nameiop = CREATE;
		ndp->ni_cnd.cn_flags |= LOCKPARENT | LOCKLEAF;
		if ((fmode & O_EXCL) == 0 &&
		    ((fmode & O_NOFOLLOW) == 0))
			ndp->ni_cnd.cn_flags |= FOLLOW;
	} else {
		ndp->ni_cnd.cn_nameiop = LOOKUP;
		ndp->ni_cnd.cn_flags |= LOCKLEAF;
		if ((fmode & O_NOFOLLOW) == 0)
			ndp->ni_cnd.cn_flags |= FOLLOW;
	}

	pathstring = pathbuf_stringcopy_get(ndp->ni_pathbuf);
	if (pathstring == NULL) {
		return ENOMEM;
	}

	error = namei(ndp);
	if (error)
		goto out;

	vp = ndp->ni_vp;

#if NVERIEXEC > 0
	error = veriexec_openchk(l, ndp->ni_vp, pathstring, fmode);
	if (error)
		goto bad;
#endif /* NVERIEXEC > 0 */

	if (fmode & O_CREAT) {
		if (ndp->ni_vp == NULL) {
			vattr_null(&va);
			va.va_type = VREG;
			va.va_mode = cmode;
			if (fmode & O_EXCL)
				 va.va_vaflags |= VA_EXCLUSIVE;
			error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
					   &ndp->ni_cnd, &va);
			vput(ndp->ni_dvp);
			if (error)
				goto out;
			fmode &= ~O_TRUNC;
			vp = ndp->ni_vp;
			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
		} else {
			VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
			if (ndp->ni_dvp == ndp->ni_vp)
				vrele(ndp->ni_dvp);
			else
				vput(ndp->ni_dvp);
			ndp->ni_dvp = NULL;
			vp = ndp->ni_vp;
			if (fmode & O_EXCL) {
				error = EEXIST;
				goto bad;
			}
			fmode &= ~O_CREAT;
		}
	} else {
		vp = ndp->ni_vp;
	}
	if (vp->v_type == VSOCK) {
		error = EOPNOTSUPP;
		goto bad;
	}
	if (ndp->ni_vp->v_type == VLNK) {
		error = EFTYPE;
		goto bad;
	}

	if ((fmode & O_CREAT) == 0) {
		error = vn_openchk(vp, cred, fmode);
		if (error != 0)
			goto bad;
	}

	if (fmode & O_TRUNC) {
		vattr_null(&va);
		va.va_size = 0;
		error = VOP_SETATTR(vp, &va, cred);
		if (error != 0)
			goto bad;
	}
	if ((error = VOP_OPEN(vp, fmode, cred)) != 0)
		goto bad;
	if (fmode & FWRITE) {
		mutex_enter(vp->v_interlock);
		vp->v_writecount++;
		mutex_exit(vp->v_interlock);
	}

bad:
	if (error)
		vput(vp);
out:
	pathbuf_stringcopy_put(ndp->ni_pathbuf, pathstring);
	return (error);
}
示例#16
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;
}
示例#17
0
static int zfsfuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev)
{
	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);

	cred_t cred;
	zfsfuse_getcred(req, &cred);

	vattr_t vattr;
	vattr.va_type = IFTOVT(mode);
	vattr.va_mode = mode & PERMMASK;
	vattr.va_mask = AT_TYPE | AT_MODE;

	if(mode & (S_IFCHR | S_IFBLK)) {
		vattr.va_rdev = rdev;
		vattr.va_mask |= AT_RDEV;
	}

	vnode_t *vp = NULL;

	/* FIXME: check filesystem boundaries */
	error = VOP_CREATE(dvp, (char *) name, &vattr, EXCL, 0, &vp, &cred, 0, NULL, NULL);

	VN_RELE(dvp);

	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);
	ZFS_EXIT(zfsvfs);

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

	return error;
}
示例#18
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);
}
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;
}