예제 #1
0
파일: xfs_super.c 프로젝트: xricson/knoppix
void
xfs_initialize_vnode(
	bhv_desc_t		*bdp,
	vnode_t			*vp,
	bhv_desc_t		*inode_bhv,
	int			unlock)
{
	xfs_inode_t		*ip = XFS_BHVTOI(inode_bhv);
	struct inode		*inode = LINVFS_GET_IP(vp);

	if (!inode_bhv->bd_vobj) {
		vp->v_vfsp = bhvtovfs(bdp);
		bhv_desc_init(inode_bhv, ip, vp, &xfs_vnodeops);
		bhv_insert(VN_BHV_HEAD(vp), inode_bhv);
	}

	vp->v_type = IFTOVT(ip->i_d.di_mode);

	/* Have we been called during the new inode create process,
	 * in which case we are too early to fill in the Linux inode.
	 */
	if (vp->v_type == VNON)
		return;

	xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip);

	/* For new inodes we need to set the ops vectors,
	 * and unlock the inode.
	 */
	if (unlock && (inode->i_state & I_NEW)) {
		xfs_set_inodeops(inode);
		unlock_new_inode(inode);
	}
}
예제 #2
0
int
fusefs_mkdir(void *v)
{
	struct vop_mkdir_args *ap = v;
	struct vnode *dvp = ap->a_dvp;
	struct vnode **vpp = ap->a_vpp;
	struct componentname *cnp = ap->a_cnp;
	struct vattr *vap = ap->a_vap;
	struct proc *p = cnp->cn_proc;
	struct vnode *tdp = NULL;
	struct fusefs_node *ip;
	struct fusefs_mnt *fmp;
	struct fusebuf *fbuf;
	int error = 0;

	DPRINTF("fusefs_mkdir %s\n", cnp->cn_nameptr);

	ip = VTOI(dvp);
	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;


	if (!fmp->sess_init || (fmp->undef_op & UNDEF_MKDIR)) {
		error = ENOSYS;
		goto out;
	}

	fbuf = fb_setup(FUSEFDSIZE + cnp->cn_namelen + 1, ip->ufs_ino.i_number,
	    FBT_MKDIR, p);

	fbuf->fb_io_mode = MAKEIMODE(vap->va_type, vap->va_mode);
	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
	fbuf->fb_dat[cnp->cn_namelen] = '\0';

	error = fb_queue(fmp->dev, fbuf);
	if (error) {
		if (error == ENOSYS)
			fmp->undef_op |= UNDEF_MKDIR;

		pool_put(&fusefs_fbuf_pool, fbuf);
		goto out;
	}

	if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) {
		pool_put(&fusefs_fbuf_pool, fbuf);
		goto out;
	}

	tdp->v_type = IFTOVT(fbuf->fb_io_mode);
	VTOI(tdp)->vtype = tdp->v_type;

	if (dvp != NULL && dvp->v_type == VDIR)
		VTOI(tdp)->parent = ip->ufs_ino.i_number;

	*vpp = tdp;
	VN_KNOTE(ap->a_dvp, NOTE_WRITE | NOTE_LINK);
	pool_put(&fusefs_fbuf_pool, fbuf);
out:
	vput(dvp);
	return (error);
}
예제 #3
0
static int
_xfs_getattr(
	struct vop_getattr_args /* {
		struct vnode *a_vp;
		struct vattr *a_vap;
		struct ucred *a_cred;
	} */ *ap)
{
	struct vnode	*vp = ap->a_vp;
	struct vattr	*vap = ap->a_vap;
	struct mount	*mp;
	xfs_vattr_t	va;
	int		error;
	/* extract the xfs vnode from the private data */
	//xfs_vnode_t	*xvp = (xfs_vnode_t *)vp->v_data;

	memset(&va,0,sizeof(xfs_vattr_t));
	va.va_mask = XFS_AT_STAT|XFS_AT_GENCOUNT|XFS_AT_XFLAGS;

	XVOP_GETATTR(VPTOXFSVP(vp), &va, 0, ap->a_cred, error);
	if (error)
		return (error);

	mp  = vp->v_mount;

	vap->va_type = IFTOVT(((xfs_vnode_t *)vp->v_data)->v_inode->i_d.di_mode);
	vap->va_mode = va.va_mode;
	vap->va_nlink = va.va_nlink;
	vap->va_uid = va.va_uid;
	vap->va_gid = va.va_gid;
	vap->va_fsid = mp->mnt_stat.f_fsid.val[0];
	vap->va_fileid = va.va_nodeid;
	vap->va_size = va.va_size;
	vap->va_blocksize = va.va_blocksize;
	vap->va_atime = va.va_atime;
	vap->va_mtime = va.va_mtime;
	vap->va_ctime = va.va_ctime;
	vap->va_gen = va.va_gen;
	vap->va_rdev = va.va_rdev;
	vap->va_bytes = (va.va_nblocks << BBSHIFT);

	/* XFS now supports devices that have block sizes
	 * other than 512 so BBSHIFT will work for now
	 * but need to get this value from the super block
	 */

	/*
	 * Fields with no direct equivalent in XFS
	 */
	vap->va_filerev = 0;
	vap->va_flags = 0;

	return (0);
}
예제 #4
0
void
update_vattr(struct mount *mp, struct vattr *v)
{
	v->va_fsid = mp->mnt_stat.f_fsid.val[0];
	v->va_type = IFTOVT(v->va_mode);
#if (S_BLKSIZE == 512)
	v->va_bytes = v->va_bytes << 9;
#else
	v->va_bytes = v->va_bytes * S_BLKSIZE;
#endif
	v->va_mode = v->va_mode & ~S_IFMT;
}
예제 #5
0
static void
zfs_init_vattr(vattr_t *vap, uint64_t mask, uint64_t mode,
	uint64_t uid, uint64_t gid, uint64_t rdev, uint64_t nodeid)
{
	bzero(vap, sizeof (*vap));
	vap->va_mask = (uint_t)mask;
	vap->va_type = IFTOVT(mode);
	vap->va_mode = mode & MODEMASK;
	vap->va_uid = (uid_t)(IS_EPHEMERAL(uid)) ? -1 : uid;
	vap->va_gid = (gid_t)(IS_EPHEMERAL(gid)) ? -1 : gid;
	vap->va_rdev = zfs_cmpldev(rdev);
	vap->va_nodeid = nodeid;
}
예제 #6
0
파일: vncache.c 프로젝트: bahamas10/openzfs
vnode_t *
vncache_enter(struct stat *st, vnode_t *dvp, char *name, int fd)
{
	vnode_t *old_vp;
	vnode_t *new_vp;
	vfs_t *vfs;
	char *vpath;
	avl_index_t	where;
	int len;

	/*
	 * Fill in v_path
	 * Note: fsop_root() calls with dvp=NULL
	 */
	len = strlen(name) + 1;
	if (dvp == NULL) {
		vpath = kmem_alloc(len, KM_SLEEP);
		(void) strlcpy(vpath, name, len);
		vfs = rootvfs;
	} else {
		/* add to length for parent path + "/" */
		len += (strlen(dvp->v_path) + 1);
		vpath = kmem_alloc(len, KM_SLEEP);
		(void) snprintf(vpath, len, "%s/%s", dvp->v_path, name);
		vfs = dvp->v_vfsp;
	}

	new_vp = vn_alloc(KM_SLEEP);
	new_vp->v_path = vpath;
	new_vp->v_fd = fd;
	new_vp->v_st_dev = st->st_dev;
	new_vp->v_st_ino = st->st_ino;
	new_vp->v_vfsp = vfs;
	new_vp->v_type = IFTOVT(st->st_mode);

	mutex_enter(&vncache_lock);
	old_vp = avl_find(&vncache_avl, new_vp, &where);
	if (old_vp != NULL)
		vn_hold(old_vp);
	else
		avl_insert(&vncache_avl, new_vp, where);
	mutex_exit(&vncache_lock);

	/* If we lost the race, free new_vp */
	if (old_vp != NULL) {
		vn_free(new_vp);
		return (old_vp);
	}

	return (new_vp);
}
예제 #7
0
enum vtype
hfs_catalog_keyed_record_vtype(const hfs_catalog_keyed_record_t *rec)
{
    	if (rec->type == HFS_REC_FILE) {
		uint32_t mode;

		mode = ((const hfs_file_record_t *)rec)->bsd.file_mode;
		if (mode != 0)
			return IFTOVT(mode);
		else
			return VREG;
	}
	else
		return VDIR;
}
/*
 * Initialize the vnode associated with a new inode, handle aliased
 * vnodes.
 */
void
ulfs_vinit(struct mount *mntp, int (**specops)(void *), int (**fifoops)(void *),
	struct vnode **vpp)
{
	struct timeval	tv;
	struct inode	*ip;
	struct vnode	*vp;
	dev_t		rdev;
	struct ulfsmount *ump;

	vp = *vpp;
	ip = VTOI(vp);
	switch(vp->v_type = IFTOVT(ip->i_mode)) {
	case VCHR:
	case VBLK:
		vp->v_op = specops;
		ump = ip->i_ump;
		// XXX clean this up
		if (ump->um_fstype == ULFS1)
			rdev = (dev_t)ulfs_rw32(ip->i_din->u_32.di_rdev,
			    ULFS_MPNEEDSWAP(ump->um_lfs));
		else
			rdev = (dev_t)ulfs_rw64(ip->i_din->u_64.di_rdev,
			    ULFS_MPNEEDSWAP(ump->um_lfs));
		spec_node_init(vp, rdev);
		break;
	case VFIFO:
		vp->v_op = fifoops;
		break;
	case VNON:
	case VBAD:
	case VSOCK:
	case VLNK:
	case VDIR:
	case VREG:
		break;
	}
	if (ip->i_number == ULFS_ROOTINO)
                vp->v_vflag |= VV_ROOT;
	/*
	 * Initialize modrev times
	 */
	getmicrouptime(&tv);
	ip->i_modrev = (uint64_t)(uint)tv.tv_sec << 32
			| tv.tv_usec * 4294u;
	*vpp = vp;
}
예제 #9
0
static void
zfs_init_vattr(vattr_t *vap, uint64_t mask, uint64_t mode,
	uint64_t uid, uint64_t gid, uint64_t rdev, uint64_t nodeid)
{
	VATTR_NULL(vap);
	vap->va_mask = (uint_t)mask;
	if (mask & AT_TYPE)
		vap->va_type = IFTOVT(mode);
	if (mask & AT_MODE)
		vap->va_mode = mode & MODEMASK;
	if (mask & AT_UID)
		vap->va_uid = (uid_t)(IS_EPHEMERAL(uid)) ? -1 : uid;
	if (mask & AT_GID)
		vap->va_gid = (gid_t)(IS_EPHEMERAL(gid)) ? -1 : gid;
	vap->va_rdev = zfs_cmpldev(rdev);
	vap->va_nodeid = nodeid;
}
예제 #10
0
/*
 * Initialize the vnode associated with a new inode, handle aliased
 * vnodes.
 */
int
ext2_vinit(struct mount *mntp, struct vop_vector *fifoops, struct vnode **vpp)
{
	struct inode *ip;
	struct vnode *vp;

	vp = *vpp;
	ip = VTOI(vp);
	vp->v_type = IFTOVT(ip->i_mode);
	if (vp->v_type == VFIFO)
		vp->v_op = fifoops;

	if (ip->i_number == EXT2_ROOTINO)
		vp->v_vflag |= VV_ROOT;
	ip->i_modrev = init_va_filerev();
	*vpp = vp;
	return (0);
}
예제 #11
0
static int
ext2_getattr(struct vop_getattr_args *ap)
{
	struct vnode *vp = ap->a_vp;
	struct inode *ip = VTOI(vp);
	struct vattr *vap = ap->a_vap;

	ext2_itimes(vp);
	/*
	 * Copy from inode table
	 */
	vap->va_fsid = dev2udev(ip->i_devvp->v_rdev);
	vap->va_fileid = ip->i_number;
	vap->va_mode = ip->i_mode & ~IFMT;
	vap->va_nlink = ip->i_nlink;
	vap->va_uid = ip->i_uid;
	vap->va_gid = ip->i_gid;
	vap->va_rdev = ip->i_rdev;
	vap->va_size = ip->i_size;
	vap->va_atime.tv_sec = ip->i_atime;
	vap->va_atime.tv_nsec = E2DI_HAS_XTIME(ip) ? ip->i_atimensec : 0;
	vap->va_mtime.tv_sec = ip->i_mtime;
	vap->va_mtime.tv_nsec = E2DI_HAS_XTIME(ip) ? ip->i_mtimensec : 0;
	vap->va_ctime.tv_sec = ip->i_ctime;
	vap->va_ctime.tv_nsec = E2DI_HAS_XTIME(ip) ? ip->i_ctimensec : 0;
	if E2DI_HAS_XTIME(ip) {
		vap->va_birthtime.tv_sec = ip->i_birthtime;
		vap->va_birthtime.tv_nsec = ip->i_birthnsec;
	}
	vap->va_flags = ip->i_flags;
	vap->va_gen = ip->i_gen;
	vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
	vap->va_bytes = dbtob((u_quad_t)ip->i_blocks);
	vap->va_type = IFTOVT(ip->i_mode);
	vap->va_filerev = ip->i_modrev;
	return (0);
}
예제 #12
0
int
fusefs_lookup(void *v)
{
	struct vop_lookup_args *ap = v;
	struct vnode *vdp;	/* vnode for directory being searched */
	struct fusefs_node *dp;	/* inode for directory being searched */
	struct fusefs_mnt *fmp;	/* file system that directory is in */
	int lockparent;		/* 1 => lockparent flag is set */
	struct vnode *tdp;	/* returned by VOP_VGET */
	struct fusebuf *fbuf = NULL;
	struct vnode **vpp = ap->a_vpp;
	struct componentname *cnp = ap->a_cnp;
	struct proc *p = cnp->cn_proc;
	struct ucred *cred = cnp->cn_cred;
	int flags;
	int nameiop = cnp->cn_nameiop;
	int wantparent;
	int error = 0;
	uint64_t nid;

	flags = cnp->cn_flags;
	*vpp = NULL;
	vdp = ap->a_dvp;
	dp = VTOI(vdp);
	fmp = (struct fusefs_mnt *)dp->ufs_ino.i_ump;
	lockparent = flags & LOCKPARENT;
	wantparent = flags & (LOCKPARENT | WANTPARENT);

	DPRINTF("lookup path %s\n", cnp->cn_pnbuf);
	DPRINTF("lookup file %s\n", cnp->cn_nameptr);

	if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) != 0)
		return (error);

	if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
		return (EROFS);

	if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
		return (error);

	if (flags & ISDOTDOT) {
		/* got ".." */
		nid = dp->parent;
		if (nid == 0)
			return (ENOENT);
	} else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') {
		nid = dp->ufs_ino.i_number;
	} else {
		/* got a real entry */
		fbuf = fb_setup(FUSEFDSIZE + cnp->cn_namelen + 1,
		    dp->ufs_ino.i_number, FBT_LOOKUP, p);

		memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
		fbuf->fb_dat[cnp->cn_namelen] = '\0';

		error = fb_queue(fmp->dev, fbuf);

		/* tsleep return */
		if (error == EWOULDBLOCK)
			goto out;

		if (error) {
			if ((nameiop == CREATE || nameiop == RENAME) &&
			    (flags & ISLASTCN)) {
				if (vdp->v_mount->mnt_flag & MNT_RDONLY)
					return (EROFS);

				cnp->cn_flags |= SAVENAME;

				if (!lockparent) {
					VOP_UNLOCK(vdp, 0, p);
					cnp->cn_flags |= PDIRUNLOCK;
				}

				error = EJUSTRETURN;
				goto out;
			}

			error = ENOENT;
			goto out;
		}

		nid = fbuf->fb_vattr.va_fileid;
	}

	if (nameiop == DELETE && (flags & ISLASTCN)) {
		/*
		 * Write access to directory required to delete files.
		 */
		error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
		if (error != 0) {
			if (fbuf)
				pool_put(&fusefs_fbuf_pool, fbuf);
			return (error);
		}

		cnp->cn_flags |= SAVENAME;
	}

	if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
		/*
		 * Write access to directory required to delete files.
		 */
		if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) != 0)
			return (error);

		if (nid == VTOI(vdp)->ufs_ino.i_number) {
			error = EISDIR;
			goto out;
		}

		error = VFS_VGET(fmp->mp, nid, &tdp);
		if (error)
			goto out;

		tdp->v_type = IFTOVT(fbuf->fb_vattr.va_mode);
		VTOI(tdp)->vtype = tdp->v_type;
		*vpp = tdp;
		cnp->cn_flags |= SAVENAME;

		goto out;
	}

	if (flags & ISDOTDOT) {
		VOP_UNLOCK(vdp, 0, p);	/* race to get the inode */
		cnp->cn_flags |= PDIRUNLOCK;

		error = VFS_VGET(fmp->mp, nid, &tdp);

		if (error) {
			if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p) == 0)
				cnp->cn_flags &= ~PDIRUNLOCK;

			return (error);
		}

		if (lockparent && (flags & ISLASTCN)) {
			if ((error = vn_lock(vdp, LK_EXCLUSIVE, p))) {
				vput(tdp);
				return (error);
			}
			cnp->cn_flags &= ~PDIRUNLOCK;
		}
		*vpp = tdp;

	} else if (nid == dp->ufs_ino.i_number) {
		vref(vdp);
		*vpp = vdp;
		error = 0;
	} else {
		error = VFS_VGET(fmp->mp, nid, &tdp);

		if (!error) {
			tdp->v_type = IFTOVT(fbuf->fb_vattr.va_mode);
			VTOI(tdp)->vtype = tdp->v_type;
		}

		update_vattr(fmp->mp, &fbuf->fb_vattr);
		memcpy(&(VTOI(tdp)->cached_attrs), &fbuf->fb_vattr,
		    sizeof(struct vattr));

		if (error) {
			if (fbuf)
				pool_put(&fusefs_fbuf_pool, fbuf);
			return (error);
		}

		if (vdp != NULL && vdp->v_type == VDIR)
			VTOI(tdp)->parent = dp->ufs_ino.i_number;

		if (!lockparent || !(flags & ISLASTCN)) {
			VOP_UNLOCK(vdp, 0, p);
			cnp->cn_flags |= PDIRUNLOCK;
		}

		*vpp = tdp;
	}

out:
	if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE &&
	    nameiop != DELETE)
		cache_enter(vdp, *vpp, cnp);

	if (fbuf)
		pool_put(&fusefs_fbuf_pool, fbuf);
	return (error);
}
예제 #13
0
errno_t
FSNodeGetOrCreateFileVNodeByID(vnode_t              *vnPtr,
                               uint32_t              flags,
                               struct fuse_abi_data *feo,
                               mount_t               mp,
                               vnode_t               dvp,
                               vfs_context_t         context,
                               uint32_t             *oflags)
{
    int   err;

    vnode_t  vn    = NULLVP;
    HNodeRef hn    = NULL;

    struct fuse_vnode_data *fvdat   = NULL;
    struct fuse_data       *mntdata = NULL;
    fuse_device_t           dummy_device;

    struct fuse_abi_data fa;

    enum vtype vtyp;

    fuse_abi_data_init(&fa, feo->fad_version, fuse_entry_out_get_attr(feo));

    vtyp = IFTOVT(fuse_attr_get_mode(&fa));

    if ((vtyp >= VBAD) || (vtyp == VNON)) {
        return EINVAL;
    }

    int      markroot   = (flags & FN_IS_ROOT) ? 1 : 0;
    uint64_t size       = (flags & FN_IS_ROOT) ? 0 : fuse_attr_get_size(&fa);
    uint32_t rdev       = (flags & FN_IS_ROOT) ? 0 : fuse_attr_get_rdev(&fa);
    uint64_t generation = fuse_entry_out_get_generation(feo);

    mntdata = fuse_get_mpdata(mp);
    dummy_device = mntdata->fdev;

    err = HNodeLookupCreatingIfNecessary(dummy_device, fuse_entry_out_get_nodeid(feo),
                                         0 /* fork index */, &hn, &vn);
    if ((err == 0) && (vn == NULL)) {

        struct vnode_fsparam params;

        fvdat = (struct fuse_vnode_data *)FSNodeGenericFromHNode(hn);

        if (!fvdat->fInitialised) {

            fvdat->fInitialised = true;

            /* self */
            fvdat->vp           = NULLVP; /* hold on */
            fvdat->nodeid       = fuse_entry_out_get_nodeid(feo);
            fvdat->generation   = generation;

            /* parent */
            fvdat->parentvp     = dvp;
            if (dvp) {
                fvdat->parent_nodeid = VTOI(dvp);
            } else {
                fvdat->parent_nodeid = 0;
            }

            /* I/O */
            {
                int k;
                for (k = 0; k < FUFH_MAXTYPE; k++) {
                    FUFH_USE_RESET(&(fvdat->fufh[k]));
                }
            }

            /* flags */
            fvdat->flag         = flags;
            fvdat->c_flag       = 0;

            /* meta */

            /* XXX: truncation */
            fvdat->entry_valid.tv_sec  = (time_t)fuse_entry_out_get_entry_valid(feo);

            fvdat->entry_valid.tv_nsec = fuse_entry_out_get_entry_valid_nsec(feo);

            /* XXX: truncation */
            fvdat->attr_valid.tv_sec   = 0;

            fvdat->attr_valid.tv_nsec  = 0;

            /* XXX: truncation */
            fvdat->modify_time.tv_sec  = (time_t)fuse_attr_get_mtime(&fa);

            fvdat->modify_time.tv_nsec = fuse_attr_get_mtimensec(&fa);

            fvdat->filesize            = size;
            fvdat->nlookup             = 0;
            fvdat->vtype               = vtyp;

            /* locking */
            fvdat->createlock = lck_mtx_alloc_init(fuse_lock_group,
                                                   fuse_lock_attr);
            fvdat->creator = current_thread();
#if M_OSXFUSE_ENABLE_TSLOCKING
            fvdat->nodelock = lck_rw_alloc_init(fuse_lock_group,
                                                fuse_lock_attr);
            fvdat->nodelockowner = NULL;
            fvdat->truncatelock  = lck_rw_alloc_init(fuse_lock_group,
                                                     fuse_lock_attr);
#endif
        }

        if (err == 0) {
            params.vnfs_mp     = mp;
            params.vnfs_vtype  = vtyp;
            params.vnfs_str    = NULL;
            params.vnfs_dvp    = dvp; /* NULLVP for the root vnode */
            params.vnfs_fsnode = hn;

#if M_OSXFUSE_ENABLE_SPECFS
            if ((vtyp == VBLK) || (vtyp == VCHR)) {
                params.vnfs_vops = fuse_spec_operations;
                params.vnfs_rdev = (dev_t)rdev;
#else
            if (0) {
#endif
#if M_OSXFUSE_ENABLE_FIFOFS
            } else if (vtyp == VFIFO) {
                params.vnfs_vops = fuse_fifo_operations;
                params.vnfs_rdev = 0;
                (void)rdev;
#else
            } else if (0) {
#endif
            } else {
                params.vnfs_vops = fuse_vnode_operations;
                params.vnfs_rdev = 0;
                (void)rdev;
            }

            params.vnfs_marksystem = 0;
            params.vnfs_cnp        = NULL;
            params.vnfs_flags      = VNFS_NOCACHE | VNFS_CANTCACHE;
            params.vnfs_filesize   = size;
            params.vnfs_markroot   = markroot;

#if M_OSXFUSE_ENABLE_BIG_LOCK
            fuse_biglock_unlock(mntdata->biglock);
#endif
            err = vnode_create(VNCREATE_FLAVOR, (uint32_t)sizeof(params),
                               &params, &vn);
#if M_OSXFUSE_ENABLE_BIG_LOCK
            fuse_biglock_lock(mntdata->biglock);
#endif
        }

        if (err == 0) {
            if (markroot) {
                fvdat->parentvp = vn;
            } else {
                fvdat->parentvp = dvp;
            }
            if (oflags) {
                *oflags |= MAKEENTRY;
            }

            /* Need VT_OSXFUSE from xnu */
            vnode_settag(vn, VT_OTHER);

            cache_attrs(vn, fuse_entry_out, feo);

            HNodeAttachVNodeSucceeded(hn, 0 /* forkIndex */, vn);
            FUSE_OSAddAtomic(1, (SInt32 *)&fuse_vnodes_current);
        } else {
            if (HNodeAttachVNodeFailed(hn, 0 /* forkIndex */)) {
                FSNodeScrub(fvdat);
                HNodeScrubDone(hn);
            }
        }
    }

    if (err == 0) {
        if (vnode_vtype(vn) != vtyp) {
            IOLog("osxfuse: vnode changed type behind us (old=%d, new=%d)\n",
                  vnode_vtype(vn), vtyp);
#if M_OSXFUSE_ENABLE_BIG_LOCK
            fuse_biglock_unlock(mntdata->biglock);
#endif
            fuse_internal_vnode_disappear(vn, context, REVOKE_SOFT);
            vnode_put(vn);
#if M_OSXFUSE_ENABLE_BIG_LOCK
            fuse_biglock_lock(mntdata->biglock);
#endif
            err = EIO;
        } else if (VTOFUD(vn)->generation != generation) {
            IOLog("osxfuse: vnode changed generation\n");
#if M_OSXFUSE_ENABLE_BIG_LOCK
            fuse_biglock_unlock(mntdata->biglock);
#endif
            fuse_internal_vnode_disappear(vn, context, REVOKE_SOFT);
            vnode_put(vn);
#if M_OSXFUSE_ENABLE_BIG_LOCK
            fuse_biglock_lock(mntdata->biglock);
#endif
            err = ESTALE;
        }
    }

    if (err == 0) {
        *vnPtr = vn;
    }

    /* assert((err == 0) == (*vnPtr != NULL); */

    return err;
}

int
fuse_vget_i(vnode_t              *vpp,
            uint32_t              flags,
            struct fuse_abi_data *feo,
            struct componentname *cnp,
            vnode_t               dvp,
            mount_t               mp,
            vfs_context_t         context)
{
    int err = 0;

    if (!feo) {
        return EINVAL;
    }

    err = FSNodeGetOrCreateFileVNodeByID(vpp, flags, feo, mp, dvp,
                                         context, NULL);
    if (err) {
        return err;
    }

    if (!fuse_isnovncache_mp(mp) && (cnp->cn_flags & MAKEENTRY)) {
        fuse_vncache_enter(dvp, *vpp, cnp);
    }

/* found: */

    VTOFUD(*vpp)->nlookup++;

    return 0;
}
예제 #14
0
int
zfs_getattr_znode_unlocked(struct vnode *vp, vattr_t *vap)
{
	znode_t *zp = VTOZ(vp);
	zfsvfs_t *zfsvfs = zp->z_zfsvfs;
	int error = 0;
	uint64_t	parent;

    //printf("getattr_osx\n");

	ZFS_ENTER(zfsvfs);
    if (!zp->z_sa_hdl) {
        ZFS_EXIT(zfsvfs);
        return EIO;
    }

	/*
	 * On Mac OS X we always export the root directory id as 2
	 */
	vap->va_fileid = (zp->z_id == zfsvfs->z_root) ? 2 : zp->z_id;
	//vap->va_fileid = (zp->z_id == zfsvfs->z_root) ? 2 : zp->z_vid;
	vap->va_nlink = zp->z_links;
	vap->va_data_size = zp->z_size;
	vap->va_total_size = zp->z_size;
	vap->va_gen = zp->z_gen;

	/*
	 * For Carbon compatibility,pretend to support this legacy/unused attribute
	 */
	if (VATTR_IS_ACTIVE(vap, va_backup_time)) {
		vap->va_backup_time.tv_sec = 0;
		vap->va_backup_time.tv_nsec = 0;
		VATTR_SET_SUPPORTED(vap, va_backup_time);
    }
	vap->va_flags = zfs_getbsdflags(zp);
	/*
	 * On Mac OS X we always export the root directory id as 2
     * and its parent as 1
	 */
	error = sa_lookup(zp->z_sa_hdl, SA_ZPL_PARENT(zfsvfs),
                      &parent, sizeof (parent));

    if (!error) {
        if (zp->z_id == zfsvfs->z_root)
            vap->va_parentid = 1;
        else if (parent == zfsvfs->z_root)
            vap->va_parentid = 2;
        else
            vap->va_parentid = parent;
    }

	vap->va_iosize = zp->z_blksz ? zp->z_blksz : zfsvfs->z_max_blksz;
	//vap->va_iosize = 512;
    VATTR_SET_SUPPORTED(vap, va_iosize);

	/* Don't include '.' and '..' in the number of entries */
	if (VATTR_IS_ACTIVE(vap, va_nchildren) && vnode_isdir(vp)) {
		VATTR_RETURN(vap, va_nchildren, vap->va_nlink - 2);
    }

	/*
	 * va_dirlinkcount is the count of directory hard links. When a file
	 * system does not support ATTR_DIR_LINKCOUNT, xnu will default to 1.
	 * Since we claim to support ATTR_DIR_LINKCOUNT both as valid and as
	 * native, we'll just return 1. We set 1 for this value in dirattrpack
	 * as well. If in the future ZFS actually supports directory hard links,
	 * we can return a real value.
	 */
	if (VATTR_IS_ACTIVE(vap, va_dirlinkcount) && vnode_isdir(vp)) {
		VATTR_RETURN(vap, va_dirlinkcount, 1);
    }

	if (VATTR_IS_ACTIVE(vap, va_acl)) {
        //printf("want acl\n");
#if 0
        zfs_acl_phys_t acl;

        if (sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs),
                      &acl, sizeof (zfs_acl_phys_t))) {
            //if (zp->z_acl.z_acl_count == 0) {
			vap->va_acl = (kauth_acl_t) KAUTH_FILESEC_NONE;
		} else {
			if ((error = zfs_getacl(zp, &vap->va_acl, B_TRUE, NULL))) {
                dprintf("zfs_getacl returned error %d\n", error);
                error = 0;
				//ZFS_EXIT(zfsvfs);
				//return (error);
			}
		}

#endif
      //VATTR_SET_SUPPORTED(vap, va_acl);
        VATTR_RETURN(vap, va_uuuid, kauth_null_guid);
        VATTR_RETURN(vap, va_guuid, kauth_null_guid);

        //dprintf("Calling getacl\n");
        if ((error = zfs_getacl(zp, &vap->va_acl, B_FALSE, NULL))) {
            //  dprintf("zfs_getacl returned error %d\n", error);
            error = 0;
        } else {

            VATTR_SET_SUPPORTED(vap, va_acl);
            /* va_acl implies that va_uuuid and va_guuid are also supported. */
            VATTR_RETURN(vap, va_uuuid, kauth_null_guid);
            VATTR_RETURN(vap, va_guuid, kauth_null_guid);
        }

    }

	if (VATTR_IS_ACTIVE(vap, va_data_alloc) || VATTR_IS_ACTIVE(vap, va_total_alloc)) {
		uint32_t  blksize;
		u_longlong_t  nblks;
        sa_object_size(zp->z_sa_hdl, &blksize, &nblks);
		vap->va_data_alloc = (uint64_t)512LL * (uint64_t)nblks;
		vap->va_total_alloc = vap->va_data_alloc;
		vap->va_supported |= VNODE_ATTR_va_data_alloc |
            VNODE_ATTR_va_total_alloc;
	}

	if (VATTR_IS_ACTIVE(vap, va_name)) {
        vap->va_name[0] = 0;

        if (!vnode_isvroot(vp)) {
            /* Lets not supply name as zap_cursor can cause panic */
#if 0
            if (zap_value_search(zfsvfs->z_os, parent, zp->z_id,
                                 ZFS_DIRENT_OBJ(-1ULL), vap->va_name) == 0)
                VATTR_SET_SUPPORTED(vap, va_name);
#endif
            /*
             * Finder (Carbon) relies on getattr returning the correct name
             * for hardlinks to work, so we store the lookup name in
             * vnop_lookup if file references are high, then set the
             * return name here.
             * If we also want ATTR_CMN_* lookups to work, we need to
             * set a unique va_linkid for each entry, and based on the
             * linkid in the lookup, return the correct name.
             * It is set in zfs_finder_keep_hardlink()
             */

            if ((zp->z_links > 1) && (IFTOVT((mode_t)zp->z_mode) == VREG) &&
                zp->z_finder_hardlink_name[0]) {

                strlcpy(vap->va_name, zp->z_finder_hardlink_name,
                        MAXPATHLEN);
                VATTR_SET_SUPPORTED(vap, va_name);

                dprintf("getattr: %p return name '%s':%04x\n", vp,
                       vap->va_name,
                       vap->va_linkid);
            }


        } else {
            /*
             * The vroot objects must return a unique name for Finder to
             * be able to distringuish between mounts. For this reason
             * we simply return the fullname, from the statfs mountedfrom
             */
            strlcpy(vap->va_name,
                    vfs_statfs(vnode_mount(vp))->f_mntfromname,
                    MAXPATHLEN);
            VATTR_SET_SUPPORTED(vap, va_name);
        }
	}

    if (VATTR_IS_ACTIVE(vap, va_linkid)) {
        VATTR_RETURN(vap, va_linkid, vap->va_fileid);
    }
	if (VATTR_IS_ACTIVE(vap, va_filerev)) {
        VATTR_RETURN(vap, va_filerev, 0);
    }
	if (VATTR_IS_ACTIVE(vap, va_fsid)) {
        VATTR_RETURN(vap, va_fsid, vfs_statfs(zfsvfs->z_vfs)->f_fsid.val[0]);
    }
	if (VATTR_IS_ACTIVE(vap, va_type)) {
        VATTR_RETURN(vap, va_type, vnode_vtype(ZTOV(zp)));
    }
	if (VATTR_IS_ACTIVE(vap, va_encoding)) {
        VATTR_RETURN(vap, va_encoding, kTextEncodingMacUnicode);
    }
#ifdef VNODE_ATTR_va_addedtime
	if (VATTR_IS_ACTIVE(vap, va_addedtime)) {
        VATTR_RETURN(vap, va_addedtime, vap->va_ctime);
    }
#endif
	if (VATTR_IS_ACTIVE(vap, va_uuuid)) {
        kauth_cred_uid2guid(zp->z_uid, &vap->va_uuuid);
    }
	if (VATTR_IS_ACTIVE(vap, va_guuid)) {
        kauth_cred_uid2guid(zp->z_gid, &vap->va_guuid);
    }

	vap->va_supported |= ZFS_SUPPORTED_VATTRS;

	ZFS_EXIT(zfsvfs);
	return (error);
}
예제 #15
0
int
sam_refresh_shared_reader_ino(
	sam_node_t *ip,			/* Pointer to the inode */
	boolean_t writelock,		/* Inode WRITER lock held, */
					/*   otherwise READER lock held. */
	cred_t *credp)			/* credentials. */
{
	sam_id_t id;
	struct sam_perm_inode *permip;
	buf_t *bp;
	int refresh = 0;
	int error;

	if ((ip->updtime + ip->mp->mt.fi_invalid) > SAM_SECOND()) {
		return (0);
	}

	if (!writelock) {
		/*
		 * Acquire inode lock before buffer lock. Recheck the update
		 * time.
		 */
		if (!rw_tryupgrade(&ip->inode_rwl)) {
			RW_UNLOCK_OS(&ip->inode_rwl, RW_READER);
			RW_LOCK_OS(&ip->inode_rwl, RW_WRITER);
			if ((ip->updtime + ip->mp->mt.fi_invalid) >
			    SAM_SECOND()) {
				error = 0;
				goto out;
			}
		}
	}
	id = ip->di.id;
	if ((error = sam_read_ino(ip->mp, id.ino, &bp, &permip))) {
		goto out;
	}
	if ((permip->di.mode != 0) && (permip->di.id.ino == ip->di.id.ino) &&
	    (permip->di.id.gen == ip->di.id.gen)) {
		if ((permip->di.modify_time.tv_sec !=
		    ip->di.modify_time.tv_sec) ||
		    (permip->di.modify_time.tv_nsec !=
		    ip->di.modify_time.tv_nsec)||
		    (permip->di.change_time.tv_sec !=
		    ip->di.change_time.tv_sec) ||
		    (permip->di.change_time.tv_nsec !=
		    ip->di.change_time.tv_nsec)||
		    (permip->di.residence_time != ip->di.residence_time) ||
		    (permip->di.rm.size != ip->di.rm.size) ||
		    (permip->di.mode != ip->di.mode)) {
			refresh = 1;
		} else {
			ip->di.uid = permip->di.uid;
			ip->di.gid = permip->di.gid;
		}
	} else {
		refresh = 1;
		error = ENOENT;		/* This inode has been removed */
	}
	if (refresh) {
		vnode_t *vp = SAM_ITOV(ip);

		/*
		 * If a refresh is needed on a directory inode,
		 * invalidate associated dnlc entries.
		 */
		if (S_ISDIR(ip->di.mode)) {
			sam_invalidate_dnlc(vp);
		}

		/*
		 * Move shared_writer's inode copy into inode. Set size
		 * and invalidate pages. Set shared_reader update time.
		 */
		ip->di = permip->di; /* Move disk ino to incore ino */
		ip->di2 = permip->di2;
		brelse(bp);
		vp->v_type = IFTOVT(S_ISREQ(ip->di.mode) ?
		    S_IFREG : ip->di.mode);
		sam_set_size(ip);
		(void) VOP_PUTPAGE_OS(vp, 0, 0, B_INVAL, credp, NULL);
		if (ip->di.status.b.acl) {
			(void) sam_acl_inactive(ip);
			error = sam_get_acl(ip, &ip->aclp);
		}
		ip->updtime = SAM_SECOND();
	} else {
		ip->updtime = SAM_SECOND();
		brelse(bp);
	}

out:
	if (!writelock) {
		rw_downgrade(&ip->inode_rwl);
	}
	return (error);
}
예제 #16
0
/*
 * Allocate a new inode.
 */
int
ufs_makeinode(int mode, struct vnode *dvp, const struct ufs_lookup_results *ulr,
	struct vnode **vpp, struct componentname *cnp)
{
	struct inode	*ip, *pdir;
	struct direct	*newdir;
	struct vnode	*tvp;
	int		error;

	UFS_WAPBL_JUNLOCK_ASSERT(dvp->v_mount);

	pdir = VTOI(dvp);

	if ((mode & IFMT) == 0)
		mode |= IFREG;

	if ((error = UFS_VALLOC(dvp, mode, cnp->cn_cred, vpp)) != 0) {
		return (error);
	}
	tvp = *vpp;
	ip = VTOI(tvp);
	ip->i_gid = pdir->i_gid;
	DIP_ASSIGN(ip, gid, ip->i_gid);
	ip->i_uid = kauth_cred_geteuid(cnp->cn_cred);
	DIP_ASSIGN(ip, uid, ip->i_uid);
	error = UFS_WAPBL_BEGIN1(dvp->v_mount, dvp);
	if (error) {
		/*
		 * Note, we can't VOP_VFREE(tvp) here like we should
		 * because we can't write to the disk.  Instead, we leave
		 * the vnode dangling from the journal.
		 */
		vput(tvp);
		return (error);
	}
#if defined(QUOTA) || defined(QUOTA2)
	if ((error = chkiq(ip, 1, cnp->cn_cred, 0))) {
		UFS_VFREE(tvp, ip->i_number, mode);
		UFS_WAPBL_END1(dvp->v_mount, dvp);
		vput(tvp);
		return (error);
	}
#endif
	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
	ip->i_mode = mode;
	DIP_ASSIGN(ip, mode, mode);
	tvp->v_type = IFTOVT(mode);	/* Rest init'd in getnewvnode(). */
	ip->i_nlink = 1;
	DIP_ASSIGN(ip, nlink, 1);

	/* Authorize setting SGID if needed. */
	if (ip->i_mode & ISGID) {
		error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY,
		    tvp, NULL, genfs_can_chmod(tvp->v_type, cnp->cn_cred, ip->i_uid,
		    ip->i_gid, mode));
		if (error) {
			ip->i_mode &= ~ISGID;
			DIP_ASSIGN(ip, mode, ip->i_mode);
		}
	}

	if (cnp->cn_flags & ISWHITEOUT) {
		ip->i_flags |= UF_OPAQUE;
		DIP_ASSIGN(ip, flags, ip->i_flags);
	}

	/*
	 * Make sure inode goes to disk before directory entry.
	 */
	if ((error = UFS_UPDATE(tvp, NULL, NULL, UPDATE_DIROP)) != 0)
		goto bad;
	newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK);
	ufs_makedirentry(ip, cnp, newdir);
	error = ufs_direnter(dvp, ulr, tvp, newdir, cnp, NULL);
	pool_cache_put(ufs_direct_cache, newdir);
	if (error)
		goto bad;
	*vpp = tvp;
	return (0);

 bad:
	/*
	 * Write error occurred trying to update the inode
	 * or the directory so must deallocate the inode.
	 */
	ip->i_nlink = 0;
	DIP_ASSIGN(ip, nlink, 0);
	ip->i_flag |= IN_CHANGE;
	UFS_WAPBL_UPDATE(tvp, NULL, NULL, 0);
	tvp->v_type = VNON;		/* explodes later if VBLK */
	UFS_WAPBL_END1(dvp->v_mount, dvp);
	vput(tvp);
	return (error);
}
예제 #17
0
int
fusefs_mknod(void *v)
{
	struct vop_mknod_args *ap = v;
	struct componentname *cnp = ap->a_cnp;
	struct vnode **vpp = ap->a_vpp;
	struct vnode *dvp = ap->a_dvp;
	struct vattr *vap = ap->a_vap;
	struct proc *p = cnp->cn_proc;
	struct vnode *tdp = NULL;
	struct fusefs_mnt *fmp;
	struct fusefs_node *ip;
	struct fusebuf *fbuf;
	int error = 0;

	ip = VTOI(dvp);
	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;

	if (!fmp->sess_init || (fmp->undef_op & UNDEF_MKNOD)) {
		error = ENOSYS;
		goto out;
	}

	fbuf = fb_setup(cnp->cn_namelen + 1, ip->ufs_ino.i_number,
	    FBT_MKNOD, p);

	fbuf->fb_io_mode = MAKEIMODE(vap->va_type, vap->va_mode);
	if (vap->va_rdev != VNOVAL)
		fbuf->fb_io_rdev = vap->va_rdev;

	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
	fbuf->fb_dat[cnp->cn_namelen] = '\0';

	error = fb_queue(fmp->dev, fbuf);
	if (error) {
		if (error == ENOSYS)
			fmp->undef_op |= UNDEF_MKNOD;

		fb_delete(fbuf);
		goto out;
	}

	if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) {
		fb_delete(fbuf);
		goto out;
	}

	tdp->v_type = IFTOVT(fbuf->fb_io_mode);
	VTOI(tdp)->vtype = tdp->v_type;

	if (dvp != NULL && dvp->v_type == VDIR)
		VTOI(tdp)->parent = ip->ufs_ino.i_number;

	*vpp = tdp;
	VN_KNOTE(ap->a_dvp, NOTE_WRITE);
	fb_delete(fbuf);
	vput(ap->a_dvp);

	/* Remove inode so that it will be reloaded by VFS_VGET and
	 * checked to see if it is an alias of an existing entry in
	 * the inode cache.
	 */
	vput(*vpp);
	(*vpp)->v_type = VNON;
	vgone(*vpp);
	*vpp = NULL;
	return (0);
out:
	vput(ap->a_dvp);
	return (error);
}
예제 #18
0
/*
 * fdesc_getattr(struct vnode *a_vp, struct vattr *a_vap, struct ucred *a_cred)
 */
static int
fdesc_getattr(struct vop_getattr_args *ap)
{
	struct proc *p = curproc;
	struct vnode *vp = ap->a_vp;
	struct vattr *vap = ap->a_vap;
	struct file *fp;
	struct stat stb;
	u_int fd;
	int error = 0;

	KKASSERT(p);

	switch (VTOFDESC(vp)->fd_type) {
	case Froot:
		VATTR_NULL(vap);

		vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
		vap->va_type = VDIR;
		vap->va_nlink = 2;
		vap->va_size = DEV_BSIZE;
		vap->va_fileid = VTOFDESC(vp)->fd_ix;
		vap->va_uid = 0;
		vap->va_gid = 0;
		vap->va_blocksize = DEV_BSIZE;
		vap->va_atime.tv_sec = boottime.tv_sec;
		vap->va_atime.tv_nsec = 0;
		vap->va_mtime = vap->va_atime;
		vap->va_ctime = vap->va_mtime;
		vap->va_gen = 0;
		vap->va_flags = 0;
		vap->va_rmajor = VNOVAL;
		vap->va_rminor = VNOVAL;
		vap->va_bytes = 0;
		break;

	case Fdesc:
		fd = VTOFDESC(vp)->fd_fd;

		fp = holdfp(p->p_fd, fd, -1);
		if (fp == NULL)
			return (EBADF);

		bzero(&stb, sizeof(stb));
		error = fo_stat(fp, &stb, curproc->p_ucred);
		fdrop(fp);

		if (error == 0) {
			VATTR_NULL(vap);
			vap->va_type = IFTOVT(stb.st_mode);
			vap->va_mode = stb.st_mode;
#define FDRX (VREAD|VEXEC)
			if (vap->va_type == VDIR)
				vap->va_mode &= ~((FDRX)|(FDRX>>3)|(FDRX>>6));
#undef FDRX
			vap->va_nlink = 1;
			vap->va_flags = 0;
			vap->va_bytes = stb.st_blocks * stb.st_blksize;
			vap->va_fileid = VTOFDESC(vp)->fd_ix;
			vap->va_size = stb.st_size;
			vap->va_blocksize = stb.st_blksize;
			vap->va_rmajor = umajor(stb.st_rdev);
			vap->va_rminor = uminor(stb.st_rdev);

			/*
			 * If no time data is provided, use the current time.
			 */
			if (stb.st_atimespec.tv_sec == 0 &&
			    stb.st_atimespec.tv_nsec == 0)
				nanotime(&stb.st_atimespec);

			if (stb.st_ctimespec.tv_sec == 0 &&
			    stb.st_ctimespec.tv_nsec == 0)
				nanotime(&stb.st_ctimespec);

			if (stb.st_mtimespec.tv_sec == 0 &&
			    stb.st_mtimespec.tv_nsec == 0)
				nanotime(&stb.st_mtimespec);

			vap->va_atime = stb.st_atimespec;
			vap->va_mtime = stb.st_mtimespec;
			vap->va_ctime = stb.st_ctimespec;
			vap->va_uid = stb.st_uid;
			vap->va_gid = stb.st_gid;
		}
		break;

	default:
		panic("fdesc_getattr");
		break;
	}
예제 #19
0
/*
 * Allocate a new inode.
 */
int
ulfs_makeinode(int mode, struct vnode *dvp, const struct ulfs_lookup_results *ulr,
	struct vnode **vpp, struct componentname *cnp)
{
	struct inode	*ip, *pdir;
	struct lfs_direct	*newdir;
	struct vnode	*tvp;
	int		error;

	pdir = VTOI(dvp);

	if ((mode & LFS_IFMT) == 0)
		mode |= LFS_IFREG;

	if ((error = lfs_valloc(dvp, mode, cnp->cn_cred, vpp)) != 0) {
		return (error);
	}
	tvp = *vpp;
	ip = VTOI(tvp);
	ip->i_gid = pdir->i_gid;
	DIP_ASSIGN(ip, gid, ip->i_gid);
	ip->i_uid = kauth_cred_geteuid(cnp->cn_cred);
	DIP_ASSIGN(ip, uid, ip->i_uid);
#if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
	if ((error = lfs_chkiq(ip, 1, cnp->cn_cred, 0))) {
		lfs_vfree(tvp, ip->i_number, mode);
		vput(tvp);
		return (error);
	}
#endif
	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
	ip->i_mode = mode;
	DIP_ASSIGN(ip, mode, mode);
	tvp->v_type = IFTOVT(mode);	/* Rest init'd in getnewvnode(). */
	ip->i_nlink = 1;
	DIP_ASSIGN(ip, nlink, 1);

	/* Authorize setting SGID if needed. */
	if (ip->i_mode & ISGID) {
		error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY,
		    tvp, NULL, genfs_can_chmod(tvp->v_type, cnp->cn_cred, ip->i_uid,
		    ip->i_gid, mode));
		if (error) {
			ip->i_mode &= ~ISGID;
			DIP_ASSIGN(ip, mode, ip->i_mode);
		}
	}

	if (cnp->cn_flags & ISWHITEOUT) {
		ip->i_flags |= UF_OPAQUE;
		DIP_ASSIGN(ip, flags, ip->i_flags);
	}

	/*
	 * Make sure inode goes to disk before directory entry.
	 */
	if ((error = lfs_update(tvp, NULL, NULL, UPDATE_DIROP)) != 0)
		goto bad;
	newdir = pool_cache_get(ulfs_direct_cache, PR_WAITOK);
	ulfs_makedirentry(ip, cnp, newdir);
	error = ulfs_direnter(dvp, ulr, tvp, newdir, cnp, NULL);
	pool_cache_put(ulfs_direct_cache, newdir);
	if (error)
		goto bad;
	*vpp = tvp;
	return (0);

 bad:
	/*
	 * Write error occurred trying to update the inode
	 * or the directory so must deallocate the inode.
	 */
	ip->i_nlink = 0;
	DIP_ASSIGN(ip, nlink, 0);
	ip->i_flag |= IN_CHANGE;
	/* If IN_ADIROP, account for it */
	lfs_unmark_vnode(tvp);
	tvp->v_type = VNON;		/* explodes later if VBLK */
	vput(tvp);
	return (error);
}
예제 #20
0
/*
 * Allocate a new inode.
 */
int
ext2fs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
    struct componentname *cnp)
{
	struct inode *ip, *pdir;
	struct vnode *tvp;
	int error;

	pdir = VTOI(dvp);
#ifdef DIAGNOSTIC
	if ((cnp->cn_flags & HASBUF) == 0)
		panic("ext2fs_makeinode: no name");
#endif
	*vpp = NULL;
	if ((mode & IFMT) == 0)
		mode |= IFREG;

	if ((error = ext2fs_inode_alloc(pdir, mode, cnp->cn_cred, &tvp)) 
	    != 0) {
		pool_put(&namei_pool, cnp->cn_pnbuf);
		vput(dvp);
		return (error);
	}
	ip = VTOI(tvp);
	ip->i_e2fs_gid = pdir->i_e2fs_gid;
	ip->i_e2fs_uid = cnp->cn_cred->cr_uid;
	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
	ip->i_e2fs_mode = mode;
	tvp->v_type = IFTOVT(mode);	/* Rest init'd in getnewvnode(). */
	ip->i_e2fs_nlink = 1;
	if ((ip->i_e2fs_mode & ISGID) &&
		!groupmember(ip->i_e2fs_gid, cnp->cn_cred) &&
	    suser_ucred(cnp->cn_cred))
		ip->i_e2fs_mode &= ~ISGID;

	/*
	 * Make sure inode goes to disk before directory entry.
	 */
	if ((error = ext2fs_update(ip, NULL, NULL, 1)) != 0)
		goto bad;
	error = ext2fs_direnter(ip, dvp, cnp);
	if (error != 0)
		goto bad;
	if ((cnp->cn_flags & SAVESTART) == 0)
		pool_put(&namei_pool, cnp->cn_pnbuf);
	vput(dvp);
	*vpp = tvp;
	return (0);

bad:
	/*
	 * Write error occurred trying to update the inode
	 * or the directory so must deallocate the inode.
	 */
	pool_put(&namei_pool, cnp->cn_pnbuf);
	vput(dvp);
	ip->i_e2fs_nlink = 0;
	ip->i_flag |= IN_CHANGE;
	tvp->v_type = VNON;
	vput(tvp);
	return (error);
}
예제 #21
0
/*
    struct vnop_lookup_args {
	struct vnodeop_desc *a_desc;
	struct vnode *a_dvp;
	struct vnode **a_vpp;
	struct componentname *a_cnp;
    };
*/
int
fuse_vnop_lookup(struct vop_lookup_args *ap)
{
	struct vnode *dvp = ap->a_dvp;
	struct vnode **vpp = ap->a_vpp;
	struct componentname *cnp = ap->a_cnp;
	struct thread *td = cnp->cn_thread;
	struct ucred *cred = cnp->cn_cred;

	int nameiop = cnp->cn_nameiop;
	int flags = cnp->cn_flags;
	int wantparent = flags & (LOCKPARENT | WANTPARENT);
	int islastcn = flags & ISLASTCN;
	struct mount *mp = vnode_mount(dvp);

	int err = 0;
	int lookup_err = 0;
	struct vnode *vp = NULL;

	struct fuse_dispatcher fdi;
	enum fuse_opcode op;

	uint64_t nid;
	struct fuse_access_param facp;

	FS_DEBUG2G("parent_inode=%ju - %*s\n",
	    (uintmax_t)VTOI(dvp), (int)cnp->cn_namelen, cnp->cn_nameptr);

	if (fuse_isdeadfs(dvp)) {
		*vpp = NULL;
		return ENXIO;
	}
	if (!vnode_isdir(dvp)) {
		return ENOTDIR;
	}
	if (islastcn && vfs_isrdonly(mp) && (nameiop != LOOKUP)) {
		return EROFS;
	}
	/*
         * We do access check prior to doing anything else only in the case
         * when we are at fs root (we'd like to say, "we are at the first
         * component", but that's not exactly the same... nevermind).
         * See further comments at further access checks.
         */

	bzero(&facp, sizeof(facp));
	if (vnode_isvroot(dvp)) {	/* early permission check hack */
		if ((err = fuse_internal_access(dvp, VEXEC, &facp, td, cred))) {
			return err;
		}
	}
	if (flags & ISDOTDOT) {
		nid = VTOFUD(dvp)->parent_nid;
		if (nid == 0) {
			return ENOENT;
		}
		fdisp_init(&fdi, 0);
		op = FUSE_GETATTR;
		goto calldaemon;
	} else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') {
		nid = VTOI(dvp);
		fdisp_init(&fdi, 0);
		op = FUSE_GETATTR;
		goto calldaemon;
	} else if (fuse_lookup_cache_enable) {
		err = cache_lookup(dvp, vpp, cnp, NULL, NULL);
		switch (err) {

		case -1:		/* positive match */
			atomic_add_acq_long(&fuse_lookup_cache_hits, 1);
			return 0;

		case 0:		/* no match in cache */
			atomic_add_acq_long(&fuse_lookup_cache_misses, 1);
			break;

		case ENOENT:		/* negative match */
			/* fall through */
		default:
			return err;
		}
	}
	nid = VTOI(dvp);
	fdisp_init(&fdi, cnp->cn_namelen + 1);
	op = FUSE_LOOKUP;

calldaemon:
	fdisp_make(&fdi, op, mp, nid, td, cred);

	if (op == FUSE_LOOKUP) {
		memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen);
		((char *)fdi.indata)[cnp->cn_namelen] = '\0';
	}
	lookup_err = fdisp_wait_answ(&fdi);

	if ((op == FUSE_LOOKUP) && !lookup_err) {	/* lookup call succeeded */
		nid = ((struct fuse_entry_out *)fdi.answ)->nodeid;
		if (!nid) {
			/*
	                 * zero nodeid is the same as "not found",
	                 * but it's also cacheable (which we keep
	                 * keep on doing not as of writing this)
	                 */
			lookup_err = ENOENT;
		} else if (nid == FUSE_ROOT_ID) {
			lookup_err = EINVAL;
		}
	}
	if (lookup_err &&
	    (!fdi.answ_stat || lookup_err != ENOENT || op != FUSE_LOOKUP)) {
		fdisp_destroy(&fdi);
		return lookup_err;
	}
	/* lookup_err, if non-zero, must be ENOENT at this point */

	if (lookup_err) {

		if ((nameiop == CREATE || nameiop == RENAME) && islastcn
		     /* && directory dvp has not been removed */ ) {

			if (vfs_isrdonly(mp)) {
				err = EROFS;
				goto out;
			}
#if 0 /* THINK_ABOUT_THIS */
			if ((err = fuse_internal_access(dvp, VWRITE, cred, td, &facp))) {
				goto out;
			}
#endif

			/*
	                 * Possibly record the position of a slot in the
	                 * directory large enough for the new component name.
	                 * This can be recorded in the vnode private data for
	                 * dvp. Set the SAVENAME flag to hold onto the
	                 * pathname for use later in VOP_CREATE or VOP_RENAME.
	                 */
			cnp->cn_flags |= SAVENAME;

			err = EJUSTRETURN;
			goto out;
		}
		/* Consider inserting name into cache. */

		/*
	         * No we can't use negative caching, as the fs
	         * changes are out of our control.
	         * False positives' falseness turns out just as things
	         * go by, but false negatives' falseness doesn't.
	         * (and aiding the caching mechanism with extra control
	         * mechanisms comes quite close to beating the whole purpose
	         * caching...)
	         */
#if 0
		if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) {
			FS_DEBUG("inserting NULL into cache\n");
			cache_enter(dvp, NULL, cnp);
		}
#endif
		err = ENOENT;
		goto out;

	} else {

		/* !lookup_err */

		struct fuse_entry_out *feo = NULL;
		struct fuse_attr *fattr = NULL;

		if (op == FUSE_GETATTR) {
			fattr = &((struct fuse_attr_out *)fdi.answ)->attr;
		} else {
			feo = (struct fuse_entry_out *)fdi.answ;
			fattr = &(feo->attr);
		}

		/*
	         * If deleting, and at end of pathname, return parameters
	         * which can be used to remove file.  If the wantparent flag
	         * isn't set, we return only the directory, otherwise we go on
	         * and lock the inode, being careful with ".".
	         */
		if (nameiop == DELETE && islastcn) {
			/*
	                 * Check for write access on directory.
	                 */
			facp.xuid = fattr->uid;
			facp.facc_flags |= FACCESS_STICKY;
			err = fuse_internal_access(dvp, VWRITE, &facp, td, cred);
			facp.facc_flags &= ~FACCESS_XQUERIES;

			if (err) {
				goto out;
			}
			if (nid == VTOI(dvp)) {
				vref(dvp);
				*vpp = dvp;
			} else {
				err = fuse_vnode_get(dvp->v_mount, nid, dvp,
				    &vp, cnp, IFTOVT(fattr->mode));
				if (err)
					goto out;
				*vpp = vp;
			}

			/*
			 * Save the name for use in VOP_RMDIR and VOP_REMOVE
			 * later.
			 */
			cnp->cn_flags |= SAVENAME;
			goto out;

		}
		/*
	         * If rewriting (RENAME), return the inode and the
	         * information required to rewrite the present directory
	         * Must get inode of directory entry to verify it's a
	         * regular file, or empty directory.
	         */
		if (nameiop == RENAME && wantparent && islastcn) {

#if 0 /* THINK_ABOUT_THIS */
			if ((err = fuse_internal_access(dvp, VWRITE, cred, td, &facp))) {
				goto out;
			}
#endif

			/*
	                 * Check for "."
	                 */
			if (nid == VTOI(dvp)) {
				err = EISDIR;
				goto out;
			}
			err = fuse_vnode_get(vnode_mount(dvp),
			    nid,
			    dvp,
			    &vp,
			    cnp,
			    IFTOVT(fattr->mode));
			if (err) {
				goto out;
			}
			*vpp = vp;
			/*
	                 * Save the name for use in VOP_RENAME later.
	                 */
			cnp->cn_flags |= SAVENAME;

			goto out;
		}
		if (flags & ISDOTDOT) {
			struct mount *mp;
			int ltype;

			/*
			 * Expanded copy of vn_vget_ino() so that
			 * fuse_vnode_get() can be used.
			 */
			mp = dvp->v_mount;
			ltype = VOP_ISLOCKED(dvp);
			err = vfs_busy(mp, MBF_NOWAIT);
			if (err != 0) {
				vfs_ref(mp);
				VOP_UNLOCK(dvp, 0);
				err = vfs_busy(mp, 0);
				vn_lock(dvp, ltype | LK_RETRY);
				vfs_rel(mp);
				if (err)
					goto out;
				if ((dvp->v_iflag & VI_DOOMED) != 0) {
					err = ENOENT;
					vfs_unbusy(mp);
					goto out;
				}
			}
			VOP_UNLOCK(dvp, 0);
			err = fuse_vnode_get(vnode_mount(dvp),
			    nid,
			    NULL,
			    &vp,
			    cnp,
			    IFTOVT(fattr->mode));
			vfs_unbusy(mp);
			vn_lock(dvp, ltype | LK_RETRY);
			if ((dvp->v_iflag & VI_DOOMED) != 0) {
				if (err == 0)
					vput(vp);
				err = ENOENT;
			}
			if (err)
				goto out;
			*vpp = vp;
		} else if (nid == VTOI(dvp)) {
			vref(dvp);
			*vpp = dvp;
		} else {
			err = fuse_vnode_get(vnode_mount(dvp),
			    nid,
			    dvp,
			    &vp,
			    cnp,
			    IFTOVT(fattr->mode));
			if (err) {
				goto out;
			}
			fuse_vnode_setparent(vp, dvp);
			*vpp = vp;
		}

		if (op == FUSE_GETATTR) {
			cache_attrs(*vpp, (struct fuse_attr_out *)fdi.answ);
		} else {
			cache_attrs(*vpp, (struct fuse_entry_out *)fdi.answ);
		}

		/* Insert name into cache if appropriate. */

		/*
	         * Nooo, caching is evil. With caching, we can't avoid stale
	         * information taking over the playground (cached info is not
	         * just positive/negative, it does have qualitative aspects,
	         * too). And a (VOP/FUSE)_GETATTR is always thrown anyway, when
	         * walking down along cached path components, and that's not
	         * any cheaper than FUSE_LOOKUP. This might change with
	         * implementing kernel side attr caching, but... In Linux,
	         * lookup results are not cached, and the daemon is bombarded
	         * with FUSE_LOOKUPS on and on. This shows that by design, the
	         * daemon is expected to handle frequent lookup queries
	         * efficiently, do its caching in userspace, and so on.
	         *
	         * So just leave the name cache alone.
	         */

		/*
	         * Well, now I know, Linux caches lookups, but with a
	         * timeout... So it's the same thing as attribute caching:
	         * we can deal with it when implement timeouts.
	         */
#if 0
		if (cnp->cn_flags & MAKEENTRY) {
			cache_enter(dvp, *vpp, cnp);
		}
#endif
	}
out:
	if (!lookup_err) {

		/* No lookup error; need to clean up. */

		if (err) {		/* Found inode; exit with no vnode. */
			if (op == FUSE_LOOKUP) {
				fuse_internal_forget_send(vnode_mount(dvp), td, cred,
				    nid, 1);
			}
			fdisp_destroy(&fdi);
			return err;
		} else {
#ifndef NO_EARLY_PERM_CHECK_HACK
			if (!islastcn) {
				/*
				 * We have the attributes of the next item
				 * *now*, and it's a fact, and we do not
				 * have to do extra work for it (ie, beg the
				 * daemon), and it neither depends on such
				 * accidental things like attr caching. So
				 * the big idea: check credentials *now*,
				 * not at the beginning of the next call to
				 * lookup.
				 * 
				 * The first item of the lookup chain (fs root)
				 * won't be checked then here, of course, as
				 * its never "the next". But go and see that
				 * the root is taken care about at the very
				 * beginning of this function.
				 * 
				 * Now, given we want to do the access check
				 * this way, one might ask: so then why not
				 * do the access check just after fetching
				 * the inode and its attributes from the
				 * daemon? Why bother with producing the
				 * corresponding vnode at all if something
				 * is not OK? We know what's the deal as
				 * soon as we get those attrs... There is
				 * one bit of info though not given us by
				 * the daemon: whether his response is
				 * authorative or not... His response should
				 * be ignored if something is mounted over
				 * the dir in question. But that can be
				 * known only by having the vnode...
				 */
				int tmpvtype = vnode_vtype(*vpp);

				bzero(&facp, sizeof(facp));
				/*the early perm check hack */
				    facp.facc_flags |= FACCESS_VA_VALID;

				if ((tmpvtype != VDIR) && (tmpvtype != VLNK)) {
					err = ENOTDIR;
				}
				if (!err && !vnode_mountedhere(*vpp)) {
					err = fuse_internal_access(*vpp, VEXEC, &facp, td, cred);
				}
				if (err) {
					if (tmpvtype == VLNK)
						FS_DEBUG("weird, permission error with a symlink?\n");
					vput(*vpp);
					*vpp = NULL;
				}
			}
#endif
		}
	}
	fdisp_destroy(&fdi);

	return err;
}
예제 #22
0
/*
    struct vnop_setattr_args {
	struct vnode *a_vp;
	struct vattr *a_vap;
	struct ucred *a_cred;
	struct thread *a_td;
    };
*/
static int
fuse_vnop_setattr(struct vop_setattr_args *ap)
{
	struct vnode *vp = ap->a_vp;
	struct vattr *vap = ap->a_vap;
	struct ucred *cred = ap->a_cred;
	struct thread *td = curthread;

	struct fuse_dispatcher fdi;
	struct fuse_setattr_in *fsai;
	struct fuse_access_param facp;

	int err = 0;
	enum vtype vtyp;
	int sizechanged = 0;
	uint64_t newsize = 0;

	FS_DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp));

	if (fuse_isdeadfs(vp)) {
		return ENXIO;
	}
	fdisp_init(&fdi, sizeof(*fsai));
	fdisp_make_vp(&fdi, FUSE_SETATTR, vp, td, cred);
	fsai = fdi.indata;
	fsai->valid = 0;

	bzero(&facp, sizeof(facp));

	facp.xuid = vap->va_uid;
	facp.xgid = vap->va_gid;

	if (vap->va_uid != (uid_t)VNOVAL) {
		facp.facc_flags |= FACCESS_CHOWN;
		fsai->uid = vap->va_uid;
		fsai->valid |= FATTR_UID;
	}
	if (vap->va_gid != (gid_t)VNOVAL) {
		facp.facc_flags |= FACCESS_CHOWN;
		fsai->gid = vap->va_gid;
		fsai->valid |= FATTR_GID;
	}
	if (vap->va_size != VNOVAL) {

		struct fuse_filehandle *fufh = NULL;

		/*Truncate to a new value. */
		    fsai->size = vap->va_size;
		sizechanged = 1;
		newsize = vap->va_size;
		fsai->valid |= FATTR_SIZE;

		fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh);
		if (fufh) {
			fsai->fh = fufh->fh_id;
			fsai->valid |= FATTR_FH;
		}
	}
	if (vap->va_atime.tv_sec != VNOVAL) {
		fsai->atime = vap->va_atime.tv_sec;
		fsai->atimensec = vap->va_atime.tv_nsec;
		fsai->valid |= FATTR_ATIME;
	}
	if (vap->va_mtime.tv_sec != VNOVAL) {
		fsai->mtime = vap->va_mtime.tv_sec;
		fsai->mtimensec = vap->va_mtime.tv_nsec;
		fsai->valid |= FATTR_MTIME;
	}
	if (vap->va_mode != (mode_t)VNOVAL) {
		fsai->mode = vap->va_mode & ALLPERMS;
		fsai->valid |= FATTR_MODE;
	}
	if (!fsai->valid) {
		goto out;
	}
	vtyp = vnode_vtype(vp);

	if (fsai->valid & FATTR_SIZE && vtyp == VDIR) {
		err = EISDIR;
		goto out;
	}
	if (vfs_isrdonly(vnode_mount(vp)) && (fsai->valid & ~FATTR_SIZE || vtyp == VREG)) {
		err = EROFS;
		goto out;
	}
	if (fsai->valid & ~FATTR_SIZE) {
	  /*err = fuse_internal_access(vp, VADMIN, context, &facp); */
	  /*XXX */
		    err = 0;
	}
	facp.facc_flags &= ~FACCESS_XQUERIES;

	if (err && !(fsai->valid & ~(FATTR_ATIME | FATTR_MTIME)) &&
	    vap->va_vaflags & VA_UTIMES_NULL) {
		err = fuse_internal_access(vp, VWRITE, &facp, td, cred);
	}
	if (err)
		goto out;
	if ((err = fdisp_wait_answ(&fdi)))
		goto out;
	vtyp = IFTOVT(((struct fuse_attr_out *)fdi.answ)->attr.mode);

	if (vnode_vtype(vp) != vtyp) {
		if (vnode_vtype(vp) == VNON && vtyp != VNON) {
			debug_printf("FUSE: Dang! vnode_vtype is VNON and vtype isn't.\n");
		} else {
			/*
	                 * STALE vnode, ditch
	                 *
	                 * The vnode has changed its type "behind our back". There's
	                 * nothing really we can do, so let us just force an internal
	                 * revocation and tell the caller to try again, if interested.
	                 */
			fuse_internal_vnode_disappear(vp);
			err = EAGAIN;
		}
	}
	if (!err && !sizechanged) {
		cache_attrs(vp, (struct fuse_attr_out *)fdi.answ);
	}
out:
	fdisp_destroy(&fdi);
	if (!err && sizechanged) {
		fuse_vnode_setsize(vp, cred, newsize);
		VTOFUD(vp)->flag &= ~FN_SIZECHANGE;
	}
	return err;
}
예제 #23
0
/*
 * This function is either called directly from reclaim, or in a delayed
 * manner, so the value of zp->z_vnode may be NULL.
 */
void
zfs_rmnode(znode_t *zp)
{
	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
	objset_t	*os = zfsvfs->z_os;
	znode_t		*xzp = NULL;
	dmu_tx_t	*tx;
	uint64_t	acl_obj;
	uint64_t	xattr_obj;
	int		error;

	ASSERT(zp->z_links == 0);

	/*
	 * If this is an attribute directory, purge its contents.
	 */
	if (IFTOVT((mode_t)zp->z_mode) == VDIR &&
	    (zp->z_pflags & ZFS_XATTR)) {

        if (!ZTOV(zp) || zfs_purgedir(zp) != 0) {
            /*
             * Not enough space to delete some xattrs.
             * Leave it in the unlinked set.
             */
            zfs_znode_dmu_fini(zp);
            return;
        }
	}

	/*
	 * Free up all the data in the file.
	 */
	error = dmu_free_long_range(os, zp->z_id, 0, DMU_OBJECT_END);
	if (error) {
		/*
		 * Not enough space.  Leave the file in the unlinked set.
		 */
		zfs_znode_dmu_fini(zp);
		//zfs_znode_free(zp);
		return;
	}

	/*
	 * If the file has extended attributes, we're going to unlink
	 * the xattr dir.
	 */
	error = sa_lookup(zp->z_sa_hdl, SA_ZPL_XATTR(zfsvfs),
	    &xattr_obj, sizeof (xattr_obj));
	if (error == 0 && xattr_obj) {
		error = zfs_zget(zfsvfs, xattr_obj, &xzp);
		ASSERT(error == 0);
	}

	acl_obj = zfs_external_acl(zp);

	/*
	 * Set up the final transaction.
	 */
	tx = dmu_tx_create(os);
	dmu_tx_hold_free(tx, zp->z_id, 0, DMU_OBJECT_END);
	dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL);
	if (xzp) {
		dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, TRUE, NULL);
		dmu_tx_hold_sa(tx, xzp->z_sa_hdl, B_FALSE);
	}
	if (acl_obj)
		dmu_tx_hold_free(tx, acl_obj, 0, DMU_OBJECT_END);

	zfs_sa_upgrade_txholds(tx, zp);
	error = dmu_tx_assign(tx, TXG_WAIT);
	if (error) {
		/*
		 * Not enough space to delete the file.  Leave it in the
		 * unlinked set, leaking it until the fs is remounted (at
		 * which point we'll call zfs_unlinked_drain() to process it).
		 */
		dmu_tx_abort(tx);
		zfs_znode_dmu_fini(zp);
		//zfs_znode_free(zp);
		goto out;
	}

	if (xzp) {
		ASSERT(error == 0);
		mutex_enter(&xzp->z_lock);
		xzp->z_unlinked = B_TRUE;	/* mark xzp for deletion */
		xzp->z_links = 0;	/* no more links to it */
		VERIFY(0 == sa_update(xzp->z_sa_hdl, SA_ZPL_LINKS(zfsvfs),
		    &xzp->z_links, sizeof (xzp->z_links), tx));
		mutex_exit(&xzp->z_lock);
		zfs_unlinked_add(xzp, tx);
	}

	/* Remove this znode from the unlinked set */
	VERIFY3U(0, ==,
	    zap_remove_int(zfsvfs->z_os, zfsvfs->z_unlinkedobj, zp->z_id, tx));

	zfs_znode_delete(zp, tx);

	dmu_tx_commit(tx);
out:
	if (xzp)
		//VN_RELE(ZTOV(xzp)); // async
	VN_RELE_ASYNC(ZTOV(xzp), dsl_pool_vnrele_taskq(dmu_objset_pool(zfsvfs->z_os)));
}
예제 #24
0
/*
 * Construct a new znode/vnode and intialize.
 *
 * This does not do a call to dmu_set_user() that is
 * up to the caller to do, in case you don't want to
 * return the znode
 */
static znode_t *
zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz)
{
	znode_t	*zp;
	vnode_t *vp;

	zp = kmem_cache_alloc(znode_cache, KM_SLEEP);
	zfs_znode_cache_constructor(zp, zfsvfs->z_parent->z_vfs, 0);

	ASSERT(zp->z_dirlocks == NULL);
	ASSERT(zp->z_dbuf == NULL);
	ASSERT(!POINTER_IS_VALID(zp->z_zfsvfs));

	/*
	 * Defer setting z_zfsvfs until the znode is ready to be a candidate for
	 * the zfs_znode_move() callback.
	 */
	zp->z_phys = NULL;
	zp->z_unlinked = 0;
	zp->z_atime_dirty = 0;
	zp->z_mapcnt = 0;
	zp->z_last_itx = 0;
	zp->z_id = db->db_object;
	zp->z_blksz = blksz;
	zp->z_seq = 0x7A4653;
	zp->z_sync_cnt = 0;

	vp = ZTOV(zp);
#ifdef TODO
	vn_reinit(vp);
#endif

	zfs_znode_dmu_init(zfsvfs, zp, db);

	zp->z_gen = zp->z_phys->zp_gen;

#if 0
	if (vp == NULL)
		return (zp);
#endif

	vp->v_type = IFTOVT((mode_t)zp->z_phys->zp_mode);
	switch (vp->v_type) {
	case VDIR:
		zp->z_zn_prefetch = B_TRUE; /* z_prefetch default is enabled */
		break;
	case VFIFO:
		vp->v_op = &zfs_fifoops;
		break;
	}
	if (vp->v_type != VFIFO)
		VN_LOCK_ASHARE(vp);

	mutex_enter(&zfsvfs->z_znodes_lock);
	list_insert_tail(&zfsvfs->z_all_znodes, zp);
	membar_producer();
	/*
	 * Everything else must be valid before assigning z_zfsvfs makes the
	 * znode eligible for zfs_znode_move().
	 */
	zp->z_zfsvfs = zfsvfs;
	mutex_exit(&zfsvfs->z_znodes_lock);

	VFS_HOLD(zfsvfs->z_vfs);
	return (zp);
}
예제 #25
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;
}
예제 #26
0
파일: ufs_vnops.c 프로젝트: sofuture/bitrig
/*
 * Initialize the vnode associated with a new inode, handle aliased
 * vnodes.
 */
int
ufs_vinit(struct mount *mntp, struct vops *specops, struct vops *fifoops,
    struct vnode **vpp)
{
	struct inode *ip;
	struct vnode *vp, *nvp;
	struct timeval mtv;

	vp = *vpp;
	ip = VTOI(vp);
	switch(vp->v_type = IFTOVT(DIP(ip, mode))) {
	case VCHR:
	case VBLK:
		vp->v_op = specops;
		if ((nvp = checkalias(vp, DIP(ip, rdev), mntp)) != NULL) {
			/*
			 * Discard unneeded vnode, but save its inode.
			 * Note that the lock is carried over in the inode
			 * to the replacement vnode.
			 */
			nvp->v_data = vp->v_data;
			vp->v_data = NULL;
			vp->v_op = &spec_vops;
#ifdef VFSLCKDEBUG
			vp->v_flag &= ~VLOCKSWORK;
#endif
			vrele(vp);
			vgone(vp);
			/*
			 * Reinitialize aliased inode.
			 */
			vp = nvp;
			ip->i_vnode = vp;
		}
		break;
	case VFIFO:
#ifdef FIFO
		vp->v_op = fifoops;
		break;
#else
		return (EOPNOTSUPP);
#endif
	case VNON:
	case VBAD:
	case VSOCK:
	case VLNK:
	case VDIR:
	case VREG:
		break;
	}
	if (ip->i_number == ROOTINO)
                vp->v_flag |= VROOT;
	/*
	 * Initialize modrev times
	 */
	getmicrouptime(&mtv);
	SETHIGH(ip->i_modrev, mtv.tv_sec);
	SETLOW(ip->i_modrev, mtv.tv_usec * 4294);
	*vpp = vp;
	return (0);
}
예제 #27
0
/*
 * Allocate a new inode.
 */
static int
ext2_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
    struct componentname *cnp)
{
	struct inode *ip, *pdir;
	struct vnode *tvp;
	int error;

	pdir = VTOI(dvp);
#ifdef DIAGNOSTIC
	if ((cnp->cn_flags & HASBUF) == 0)
		panic("ext2_makeinode: no name");
#endif
	*vpp = NULL;
	if ((mode & IFMT) == 0)
		mode |= IFREG;

	error = ext2_valloc(dvp, mode, cnp->cn_cred, &tvp);
	if (error) {
		return (error);
	}
	ip = VTOI(tvp);
	ip->i_gid = pdir->i_gid;
#ifdef SUIDDIR
	{
		/*
		 * if we are
		 * not the owner of the directory,
		 * and we are hacking owners here, (only do this where told to)
		 * and we are not giving it TOO root, (would subvert quotas)
		 * then go ahead and give it to the other user.
		 * Note that this drops off the execute bits for security.
		 */
		if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
		     (pdir->i_mode & ISUID) &&
		     (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) {
			ip->i_uid = pdir->i_uid;
			mode &= ~07111;
		} else {
			ip->i_uid = cnp->cn_cred->cr_uid;
		}
	}
#else
	ip->i_uid = cnp->cn_cred->cr_uid;
#endif
	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
	ip->i_mode = mode;
	tvp->v_type = IFTOVT(mode);	/* Rest init'd in getnewvnode(). */
	ip->i_nlink = 1;
	if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred)) {
		if (priv_check_cred(cnp->cn_cred, PRIV_VFS_RETAINSUGID, 0))
			ip->i_mode &= ~ISGID;
	}

	if (cnp->cn_flags & ISWHITEOUT)
		ip->i_flags |= UF_OPAQUE;

	/*
	 * Make sure inode goes to disk before directory entry.
	 */
	error = ext2_update(tvp, !DOINGASYNC(tvp));
	if (error)
		goto bad;
	error = ext2_direnter(ip, dvp, cnp);
	if (error)
		goto bad;

	*vpp = tvp;
	return (0);

bad:
	/*
	 * Write error occurred trying to update the inode
	 * or the directory so must deallocate the inode.
	 */
	ip->i_nlink = 0;
	ip->i_flag |= IN_CHANGE;
	vput(tvp);
	return (error);
}
예제 #28
0
파일: ufs_vnops.c 프로젝트: sofuture/bitrig
/*
 * Allocate a new inode.
 */
int
ufs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
    struct componentname *cnp)
{
	struct inode *ip, *pdir;
	struct direct newdir;
	struct vnode *tvp;
	int error;

	pdir = VTOI(dvp);
#ifdef DIAGNOSTIC
	if ((cnp->cn_flags & HASBUF) == 0)
		panic("ufs_makeinode: no name");
#endif
	*vpp = NULL;
	if ((mode & IFMT) == 0)
		mode |= IFREG;

	if ((error = UFS_INODE_ALLOC(pdir, mode, cnp->cn_cred, &tvp)) != 0) {
		pool_put(&namei_pool, cnp->cn_pnbuf);
		vput(dvp);
		return (error);
	}

	ip = VTOI(tvp);

	DIP_ASSIGN(ip, gid, DIP(pdir, gid));
	DIP_ASSIGN(ip, uid, cnp->cn_cred->cr_uid);

	if ((error = getinoquota(ip)) ||
	    (error = ufs_quota_alloc_inode(ip, cnp->cn_cred))) {
		pool_put(&namei_pool, cnp->cn_pnbuf);
		UFS_INODE_FREE(ip, ip->i_number, mode);
		vput(tvp);
		vput(dvp);
		return (error);
	}

	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
	DIP_ASSIGN(ip, mode, mode);
	tvp->v_type = IFTOVT(mode);	/* Rest init'd in getnewvnode(). */
	ip->i_effnlink = 1;
	DIP_ASSIGN(ip, nlink, 1);
	if (DOINGSOFTDEP(tvp))
		softdep_change_linkcnt(ip, 0);
	if ((DIP(ip, mode) & ISGID) &&
		!groupmember(DIP(ip, gid), cnp->cn_cred) &&
	    suser_ucred(cnp->cn_cred))
		DIP_AND(ip, mode, ~ISGID);

	/*
	 * Make sure inode goes to disk before directory entry.
	 */
	if ((error = UFS_UPDATE(ip, !DOINGSOFTDEP(tvp))) != 0)
		goto bad;

	ufs_makedirentry(ip, cnp, &newdir);
	if ((error = ufs_direnter(dvp, tvp, &newdir, cnp, NULL)) != 0)
		goto bad;

	if ((cnp->cn_flags & SAVESTART) == 0)
		pool_put(&namei_pool, cnp->cn_pnbuf);
	vput(dvp);
	*vpp = tvp;
	return (0);

bad:
	/*
	 * Write error occurred trying to update the inode
	 * or the directory so must deallocate the inode.
	 */
	pool_put(&namei_pool, cnp->cn_pnbuf);
	vput(dvp);
	ip->i_effnlink = 0;
	DIP_ASSIGN(ip, nlink, 0);
	ip->i_flag |= IN_CHANGE;
	if (DOINGSOFTDEP(tvp))
		softdep_change_linkcnt(ip, 0);
	tvp->v_type = VNON;
	vput(tvp);

	return (error);
}
예제 #29
0
int
fusefs_create(void *v)
{
	struct vop_create_args *ap = v;
	struct componentname *cnp = ap->a_cnp;
	struct vnode **vpp = ap->a_vpp;
	struct vnode *dvp = ap->a_dvp;
	struct vattr *vap = ap->a_vap;
	struct proc *p = cnp->cn_proc;
	struct vnode *tdp = NULL;
	struct fusefs_mnt *fmp;
	struct fusefs_node *ip;
	struct fusebuf *fbuf;
	int error = 0;
	mode_t mode;

	ip = VTOI(dvp);
	fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump;
	mode = MAKEIMODE(vap->va_type, vap->va_mode);

	if (!fmp->sess_init || (fmp->undef_op & UNDEF_CREATE)) {
		error = ENOSYS;
		goto out;
	}

	fbuf = fb_setup(cnp->cn_namelen + 1, ip->ufs_ino.i_number,
	    FBT_CREATE, p);

	fbuf->fb_io_mode = mode;
	fbuf->fb_io_flags = O_CREAT | O_RDWR;

	memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen);
	fbuf->fb_dat[cnp->cn_namelen] = '\0';

	error = fb_queue(fmp->dev, fbuf);
	if (error) {
		if (error == ENOSYS)
			fmp->undef_op |= UNDEF_CREATE;

		fb_delete(fbuf);
		goto out;
	}

	if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) {
		fb_delete(fbuf);
		goto out;
	}

	tdp->v_type = IFTOVT(fbuf->fb_io_mode);
	VTOI(tdp)->vtype = tdp->v_type;

	if (dvp != NULL && dvp->v_type == VDIR)
		VTOI(tdp)->parent = ip->ufs_ino.i_number;

	*vpp = tdp;
	VN_KNOTE(ap->a_dvp, NOTE_WRITE);
	fb_delete(fbuf);
out:
	vput(ap->a_dvp);
	return (error);
}
예제 #30
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;
}