コード例 #1
0
ファイル: zfs_dir.c プロジェクト: JHUDSSJC/osx-zfs-crypto
/*
 * Delete the entire contents of a directory.  Return a count
 * of the number of entries that could not be deleted. If we encounter
 * an error, return a count of at least one so that the directory stays
 * in the unlinked set.
 *
 * NOTE: this function assumes that the directory is inactive,
 *	so there is no need to lock its entries before deletion.
 *	Also, it assumes the directory contents is *only* regular
 *	files.
 */
static int
zfs_purgedir(znode_t *dzp)
{
	zap_cursor_t	zc;
	zap_attribute_t	zap;
	znode_t		*xzp;
	dmu_tx_t	*tx;
	zfsvfs_t	*zfsvfs = dzp->z_zfsvfs;
	zfs_dirlock_t	dl;
	int skipped = 0;
	int error;

	for (zap_cursor_init(&zc, zfsvfs->z_os, dzp->z_id);
	    (error = zap_cursor_retrieve(&zc, &zap)) == 0;
	    zap_cursor_advance(&zc)) {
		error = zfs_zget(zfsvfs,
		    ZFS_DIRENT_OBJ(zap.za_first_integer), &xzp);
		if (error) {
			skipped += 1;
			continue;
		}

/*
	    ASSERT((ZTOV(xzp)->v_type == VREG) ||
		    (ZTOV(xzp)->v_type == VLNK));
*/

		tx = dmu_tx_create(zfsvfs->z_os);
		dmu_tx_hold_sa(tx, dzp->z_sa_hdl, B_FALSE);
		dmu_tx_hold_zap(tx, dzp->z_id, FALSE, zap.za_name);
		dmu_tx_hold_sa(tx, xzp->z_sa_hdl, B_FALSE);
		dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL);
		/* Is this really needed ? */
		zfs_sa_upgrade_txholds(tx, xzp);
		error = dmu_tx_assign(tx, TXG_WAIT);
		if (error) {
			dmu_tx_abort(tx);
			//VN_RELE(ZTOV(xzp)); // async
			VN_RELE_ASYNC(ZTOV(xzp), dsl_pool_vnrele_taskq(dmu_objset_pool(zfsvfs->z_os)));
			skipped += 1;
			continue;
		}
		bzero(&dl, sizeof (dl));
		dl.dl_dzp = dzp;
		dl.dl_name = zap.za_name;

		error = zfs_link_destroy(&dl, xzp, tx, 0, NULL);
		if (error)
			skipped += 1;
		dmu_tx_commit(tx);

		//VN_RELE(ZTOV(xzp)); // async
		VN_RELE_ASYNC(ZTOV(xzp), dsl_pool_vnrele_taskq(dmu_objset_pool(zfsvfs->z_os)));
	}
	zap_cursor_fini(&zc);
	if (error != ENOENT)
		skipped += 1;
	return (skipped);
}
コード例 #2
0
ファイル: zfs_dir.c プロジェクト: ColinIanKing/zfs
/*
 * Delete the entire contents of a directory.  Return a count
 * of the number of entries that could not be deleted. If we encounter
 * an error, return a count of at least one so that the directory stays
 * in the unlinked set.
 *
 * NOTE: this function assumes that the directory is inactive,
 *	so there is no need to lock its entries before deletion.
 *	Also, it assumes the directory contents is *only* regular
 *	files.
 */
static int
zfs_purgedir(znode_t *dzp)
{
	zap_cursor_t	zc;
	zap_attribute_t	zap;
	znode_t		*xzp;
	dmu_tx_t	*tx;
	zfsvfs_t	*zfsvfs = ZTOZSB(dzp);
	zfs_dirlock_t	dl;
	int skipped = 0;
	int error;

	for (zap_cursor_init(&zc, zfsvfs->z_os, dzp->z_id);
	    (error = zap_cursor_retrieve(&zc, &zap)) == 0;
	    zap_cursor_advance(&zc)) {
		error = zfs_zget(zfsvfs,
		    ZFS_DIRENT_OBJ(zap.za_first_integer), &xzp);
		if (error) {
			skipped += 1;
			continue;
		}

		ASSERT(S_ISREG(ZTOI(xzp)->i_mode) ||
		    S_ISLNK(ZTOI(xzp)->i_mode));

		tx = dmu_tx_create(zfsvfs->z_os);
		dmu_tx_hold_sa(tx, dzp->z_sa_hdl, B_FALSE);
		dmu_tx_hold_zap(tx, dzp->z_id, FALSE, zap.za_name);
		dmu_tx_hold_sa(tx, xzp->z_sa_hdl, B_FALSE);
		dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL);
		/* Is this really needed ? */
		zfs_sa_upgrade_txholds(tx, xzp);
		dmu_tx_mark_netfree(tx);
		error = dmu_tx_assign(tx, TXG_WAIT);
		if (error) {
			dmu_tx_abort(tx);
			zfs_iput_async(ZTOI(xzp));
			skipped += 1;
			continue;
		}
		bzero(&dl, sizeof (dl));
		dl.dl_dzp = dzp;
		dl.dl_name = zap.za_name;

		error = zfs_link_destroy(&dl, xzp, tx, 0, NULL);
		if (error)
			skipped += 1;
		dmu_tx_commit(tx);

		zfs_iput_async(ZTOI(xzp));
	}
	zap_cursor_fini(&zc);
	if (error != ENOENT)
		skipped += 1;
	return (skipped);
}
コード例 #3
0
ファイル: zfs_dir.c プロジェクト: glycerine/zfs
/*
 * Delete the entire contents of a directory.  Return a count
 * of the number of entries that could not be deleted. If we encounter
 * an error, return a count of at least one so that the directory stays
 * in the unlinked set.
 *
 * NOTE: this function assumes that the directory is inactive,
 *	so there is no need to lock its entries before deletion.
 *	Also, it assumes the directory contents is *only* regular
 *	files.
 */
static int
zfs_purgedir(znode_t *dzp)
{
	zap_cursor_t	zc;
	zap_attribute_t	zap;
	znode_t		*xzp;
	dmu_tx_t	*tx;
	zfsvfs_t	*zfsvfs = dzp->z_zfsvfs;
	zfs_dirlock_t	dl;
	int skipped = 0;
	int error;

	for (zap_cursor_init(&zc, zfsvfs->z_os, dzp->z_id);
	    (error = zap_cursor_retrieve(&zc, &zap)) == 0;
	    zap_cursor_advance(&zc)) {
		error = zfs_zget(zfsvfs,
		    ZFS_DIRENT_OBJ(zap.za_first_integer), &xzp);
		if (error) {
			skipped += 1;
			continue;
		}

		ASSERT((ZTOV(xzp)->v_type == VREG) ||
		    (ZTOV(xzp)->v_type == VLNK));

		tx = dmu_tx_create(zfsvfs->z_os);
		dmu_tx_hold_bonus(tx, dzp->z_id);
		dmu_tx_hold_zap(tx, dzp->z_id, FALSE, zap.za_name);
		dmu_tx_hold_bonus(tx, xzp->z_id);
		dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL);
		error = dmu_tx_assign(tx, TXG_WAIT);
		if (error) {
			dmu_tx_abort(tx);
			VN_RELE(ZTOV(xzp));
			skipped += 1;
			continue;
		}
		bzero(&dl, sizeof (dl));
		dl.dl_dzp = dzp;
		dl.dl_name = zap.za_name;

		error = zfs_link_destroy(&dl, xzp, tx, 0, NULL);
		if (error)
			skipped += 1;
		dmu_tx_commit(tx);

		VN_RELE(ZTOV(xzp));
	}
	zap_cursor_fini(&zc);
	if (error != ENOENT)
		skipped += 1;
	return (skipped);
}
コード例 #4
0
ファイル: zfs_dir.c プロジェクト: jaredmcneill/freebsd
/*
 * Delete the entire contents of a directory.  Return a count
 * of the number of entries that could not be deleted. If we encounter
 * an error, return a count of at least one so that the directory stays
 * in the unlinked set.
 *
 * NOTE: this function assumes that the directory is inactive,
 *	so there is no need to lock its entries before deletion.
 *	Also, it assumes the directory contents is *only* regular
 *	files.
 */
static int
zfs_purgedir(znode_t *dzp)
{
    zap_cursor_t	zc;
    zap_attribute_t	zap;
    znode_t		*xzp;
    dmu_tx_t	*tx;
    zfsvfs_t	*zfsvfs = dzp->z_zfsvfs;
    int skipped = 0;
    int error;

    for (zap_cursor_init(&zc, zfsvfs->z_os, dzp->z_id);
            (error = zap_cursor_retrieve(&zc, &zap)) == 0;
            zap_cursor_advance(&zc)) {
        error = zfs_zget(zfsvfs,
                         ZFS_DIRENT_OBJ(zap.za_first_integer), &xzp);
        if (error) {
            skipped += 1;
            continue;
        }

        vn_lock(ZTOV(xzp), LK_EXCLUSIVE | LK_RETRY);
        ASSERT((ZTOV(xzp)->v_type == VREG) ||
               (ZTOV(xzp)->v_type == VLNK));

        tx = dmu_tx_create(zfsvfs->z_os);
        dmu_tx_hold_sa(tx, dzp->z_sa_hdl, B_FALSE);
        dmu_tx_hold_zap(tx, dzp->z_id, FALSE, zap.za_name);
        dmu_tx_hold_sa(tx, xzp->z_sa_hdl, B_FALSE);
        dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL);
        /* Is this really needed ? */
        zfs_sa_upgrade_txholds(tx, xzp);
        dmu_tx_mark_netfree(tx);
        error = dmu_tx_assign(tx, TXG_WAIT);
        if (error) {
            dmu_tx_abort(tx);
            vput(ZTOV(xzp));
            skipped += 1;
            continue;
        }

        error = zfs_link_destroy(dzp, zap.za_name, xzp, tx, 0, NULL);
        if (error)
            skipped += 1;
        dmu_tx_commit(tx);

        vput(ZTOV(xzp));
    }
    zap_cursor_fini(&zc);
    if (error != ENOENT)
        skipped += 1;
    return (skipped);
}
コード例 #5
0
ファイル: zfs_dir.c プロジェクト: Bingfeng/zfs
/*
 * zfs_match_find() is used by zfs_dirent_lock() to peform zap lookups
 * of names after deciding which is the appropriate lookup interface.
 */
static int
zfs_match_find(zfs_sb_t *zsb, znode_t *dzp, char *name, boolean_t exact,
    boolean_t update, int *deflags, pathname_t *rpnp, uint64_t *zoid)
{
	boolean_t conflict = B_FALSE;
	int error;

	if (zsb->z_norm) {
		matchtype_t mt = MT_FIRST;
		size_t bufsz = 0;
		char *buf = NULL;

		if (rpnp) {
			buf = rpnp->pn_buf;
			bufsz = rpnp->pn_bufsize;
		}
		if (exact)
			mt = MT_EXACT;
		/*
		 * In the non-mixed case we only expect there would ever
		 * be one match, but we need to use the normalizing lookup.
		 */
		error = zap_lookup_norm(zsb->z_os, dzp->z_id, name, 8, 1,
		    zoid, mt, buf, bufsz, &conflict);
	} else {
		error = zap_lookup(zsb->z_os, dzp->z_id, name, 8, 1, zoid);
	}

	/*
	 * Allow multiple entries provided the first entry is
	 * the object id.  Non-zpl consumers may safely make
	 * use of the additional space.
	 *
	 * XXX: This should be a feature flag for compatibility
	 */
	if (error == EOVERFLOW)
		error = 0;

	if (zsb->z_norm && !error && deflags)
		*deflags = conflict ? ED_CASE_CONFLICT : 0;

	*zoid = ZFS_DIRENT_OBJ(*zoid);

#ifdef HAVE_DNLC
	if (error == ENOENT && update)
		dnlc_update(ZTOI(dzp), name, DNLC_NO_VNODE);
#endif /* HAVE_DNLC */

	return (error);
}
コード例 #6
0
ファイル: zfs_dir.c プロジェクト: jaredmcneill/freebsd
/*
 * zfs_match_find() is used by zfs_dirent_lookup() to peform zap lookups
 * of names after deciding which is the appropriate lookup interface.
 */
static int
zfs_match_find(zfsvfs_t *zfsvfs, znode_t *dzp, const char *name,
               boolean_t exact, uint64_t *zoid)
{
    int error;

    if (zfsvfs->z_norm) {
        matchtype_t mt = exact? MT_EXACT : MT_FIRST;

        /*
         * In the non-mixed case we only expect there would ever
         * be one match, but we need to use the normalizing lookup.
         */
        error = zap_lookup_norm(zfsvfs->z_os, dzp->z_id, name, 8, 1,
                                zoid, mt, NULL, 0, NULL);
    } else {
        error = zap_lookup(zfsvfs->z_os, dzp->z_id, name, 8, 1, zoid);
    }
    *zoid = ZFS_DIRENT_OBJ(*zoid);

    return (error);
}
コード例 #7
0
ファイル: zfs_dir.c プロジェクト: kohlschuetter/zfs
/*
 * zfs_match_find() is used by zfs_dirent_lock() to peform zap lookups
 * of names after deciding which is the appropriate lookup interface.
 */
static int
zfs_match_find(zfs_sb_t *zsb, znode_t *dzp, char *name, boolean_t exact,
               boolean_t update, int *deflags, pathname_t *rpnp, uint64_t *zoid)
{
    int error;

    if (zsb->z_norm) {
        matchtype_t mt = MT_FIRST;
        boolean_t conflict = B_FALSE;
        size_t bufsz = 0;
        char *buf = NULL;

        if (rpnp) {
            buf = rpnp->pn_buf;
            bufsz = rpnp->pn_bufsize;
        }
        if (exact)
            mt = MT_EXACT;
        /*
         * In the non-mixed case we only expect there would ever
         * be one match, but we need to use the normalizing lookup.
         */
        error = zap_lookup_norm(zsb->z_os, dzp->z_id, name, 8, 1,
                                zoid, mt, buf, bufsz, &conflict);
        if (!error && deflags)
            *deflags = conflict ? ED_CASE_CONFLICT : 0;
    } else {
        error = zap_lookup(zsb->z_os, dzp->z_id, name, 8, 1, zoid);
    }
    *zoid = ZFS_DIRENT_OBJ(*zoid);

#ifdef HAVE_DNLC
    if (error == ENOENT && update)
        dnlc_update(ZTOI(dzp), name, DNLC_NO_VNODE);
#endif /* HAVE_DNLC */

    return (error);
}
コード例 #8
0
ファイル: zfs_vfsops.c プロジェクト: roddi/mac-zfs
/*ARGSUSED*/
static int
zfs_vfs_unmount(struct mount *mp, int mntflags, vfs_context_t context)
{
	zfsvfs_t *zfsvfs = vfs_fsprivate(mp);	
	objset_t *os = zfsvfs->z_os;
	znode_t	*zp, *nextzp;
	int ret, i;
	int flags;
	
	/*XXX NOEL: delegation admin stuffs, add back if we use delg. admin */
#if 0
	ret = 0; /* UNDEFINED: secpolicy_fs_unmount(cr, vfsp); */
	if (ret) {
		ret = dsl_deleg_access((char *)refstr_value(vfsp->vfs_resource),
		    ZFS_DELEG_PERM_MOUNT, cr);
		if (ret)
			return (ret);
	}

	/*
	 * We purge the parent filesystem's vfsp as the parent filesystem
	 * and all of its snapshots have their vnode's v_vfsp set to the
	 * parent's filesystem's vfsp.  Note, 'z_parent' is self
	 * referential for non-snapshots.
	 */
	(void) dnlc_purge_vfsp(zfsvfs->z_parent->z_vfs, 0);
#endif

	/*
	 * Unmount any snapshots mounted under .zfs before unmounting the
	 * dataset itself.
	 */
#if 0
	if (zfsvfs->z_ctldir != NULL &&
	    (ret = zfsctl_umount_snapshots(vfsp, fflag, cr)) != 0) {
		return (ret);
#endif
	flags = SKIPSYSTEM;
	if (mntflags & MNT_FORCE)
		flags |= FORCECLOSE;

	ret = vflush(mp, NULLVP, flags);

	/*
	 * Mac OS X needs a file system modify time
	 *
	 * We use the mtime of the "com.apple.system.mtime" 
	 * extended attribute, which is associated with the
	 * file system root directory.
	 *
	 * Here we need to release the ref we took on z_mtime_vp during mount.
	 */
	if ((ret == 0) || (mntflags & MNT_FORCE)) {
		if (zfsvfs->z_mtime_vp != NULL) {
			struct vnode *mvp;

			mvp = zfsvfs->z_mtime_vp;
			zfsvfs->z_mtime_vp = NULL;

			if (vnode_get(mvp) == 0) {
				vnode_rele(mvp);
				vnode_recycle(mvp);
				vnode_put(mvp);
			}
		}
	}

	if (!(mntflags & MNT_FORCE)) {
		/*
		 * Check the number of active vnodes in the file system.
		 * Our count is maintained in the vfs structure, but the
		 * number is off by 1 to indicate a hold on the vfs
		 * structure itself.
		 *
		 * The '.zfs' directory maintains a reference of its
		 * own, and any active references underneath are
		 * reflected in the vnode count.
		 */
		
		if (ret)
			return (EBUSY);
#if 0
		if (zfsvfs->z_ctldir == NULL) {
			if (vfsp->vfs_count > 1)
				return (EBUSY);
		} else {
			if (vfsp->vfs_count > 2 ||
			    zfsvfs->z_ctldir->v_count > 1) {
				return (EBUSY);
			}
		}
#endif
	}

	rw_enter(&zfsvfs->z_unmount_lock, RW_WRITER);
	rw_enter(&zfsvfs->z_unmount_inactive_lock, RW_WRITER);

	/*
	 * At this point there are no vops active, and any new vops will
	 * fail with EIO since we have z_unmount_lock for writer (only
	 * relavent for forced unmount).
	 *
	 * Release all holds on dbufs.
	 * Note, the dmu can still callback via znode_pageout_func()
	 * which can zfs_znode_free() the znode.  So we lock
	 * z_all_znodes; search the list for a held dbuf; drop the lock
	 * (we know zp can't disappear if we hold a dbuf lock) then
	 * regrab the lock and restart.
	 */
	mutex_enter(&zfsvfs->z_znodes_lock);
	for (zp = list_head(&zfsvfs->z_all_znodes); zp; zp = nextzp) {
		nextzp = list_next(&zfsvfs->z_all_znodes, zp);
		if (zp->z_dbuf_held) {
			/* dbufs should only be held when force unmounting */
			zp->z_dbuf_held = 0;
			mutex_exit(&zfsvfs->z_znodes_lock);
			dmu_buf_rele(zp->z_dbuf, NULL);
			/* Start again */
			mutex_enter(&zfsvfs->z_znodes_lock);
			nextzp = list_head(&zfsvfs->z_all_znodes);
		}
	}
	mutex_exit(&zfsvfs->z_znodes_lock);

	/*
	 * Set the unmounted flag and let new vops unblock.
	 * zfs_inactive will have the unmounted behavior, and all other
	 * vops will fail with EIO.
	 */
	zfsvfs->z_unmounted = B_TRUE;
	rw_exit(&zfsvfs->z_unmount_lock);
	rw_exit(&zfsvfs->z_unmount_inactive_lock);

	/*
	 * Unregister properties.
	 */
#ifndef __APPLE__
	if (!dmu_objset_is_snapshot(os))
		zfs_unregister_callbacks(zfsvfs);
#endif
	/*
	 * Close the zil. NB: Can't close the zil while zfs_inactive
	 * threads are blocked as zil_close can call zfs_inactive.
	 */
	if (zfsvfs->z_log) {
		zil_close(zfsvfs->z_log);
		zfsvfs->z_log = NULL;
	}

	/*
	 * Evict all dbufs so that cached znodes will be freed
	 */
	if (dmu_objset_evict_dbufs(os, B_TRUE)) {
		txg_wait_synced(dmu_objset_pool(zfsvfs->z_os), 0);
		(void) dmu_objset_evict_dbufs(os, B_FALSE);
	}

	/*
	 * Finally close the objset
	 */
	dmu_objset_close(os);

	/*
	 * We can now safely destroy the '.zfs' directory node.
	 */
#if 0
	if (zfsvfs->z_ctldir != NULL)
		zfsctl_destroy(zfsvfs);
#endif

	/*
	 * Note that this work is normally done in zfs_freevfs, but since
	 * there is no VOP_FREEVFS in OSX, we free VFS items here
	 */
	OSDecrementAtomic((SInt32 *)&zfs_active_fs_count);
 	for (i = 0; i != ZFS_OBJ_MTX_SZ; i++)
 		mutex_destroy(&zfsvfs->z_hold_mtx[i]);
 
 	mutex_destroy(&zfsvfs->z_znodes_lock);
 	list_destroy(&zfsvfs->z_all_znodes);
 	rw_destroy(&zfsvfs->z_unmount_lock);
 	rw_destroy(&zfsvfs->z_unmount_inactive_lock);

	return (0);
}


 
struct vnode* vnode_getparent(struct vnode *vp);  /* sys/vnode_internal.h */

static int
zfs_vget_internal(zfsvfs_t *zfsvfs, ino64_t ino, struct vnode **vpp)
{
	struct vnode	*vp;
	struct vnode	*dvp = NULL;
	znode_t		*zp;
	int		error;

	*vpp = NULL;
	
	/*
	 * On Mac OS X we always export the root directory id as 2
	 * and its parent as 1
	 */
	if (ino == 2 || ino == 1)
		ino = zfsvfs->z_root;
	
	if ((error = zfs_zget(zfsvfs, ino, &zp)))
		goto out;

	/* Don't expose EA objects! */
	if (zp->z_phys->zp_flags & ZFS_XATTR) {
		vnode_put(ZTOV(zp));
		error = ENOENT;
		goto out;
	}

	*vpp = vp = ZTOV(zp);

	if (vnode_isvroot(vp))
		goto out;

	/*
	 * If this znode didn't just come from the cache then
	 * it won't have a valid identity (parent and name).
	 *
	 * Manually fix its identity here (normally done by namei lookup).
	 */
	if ((dvp = vnode_getparent(vp)) == NULL) {
		if (zp->z_phys->zp_parent != 0 &&
		    zfs_vget_internal(zfsvfs, zp->z_phys->zp_parent, &dvp)) {
			goto out;
		}
		if ( vnode_isdir(dvp) ) {
			char objname[ZAP_MAXNAMELEN];  /* 256 bytes */
			int flags = VNODE_UPDATE_PARENT;

			/* Look for znode's name in its parent's zap */
			if ( zap_value_search(zfsvfs->z_os,
			                      zp->z_phys->zp_parent, 
			                      zp->z_id,
			                      ZFS_DIRENT_OBJ(-1ULL),
			                      objname) == 0 ) {
				flags |= VNODE_UPDATE_NAME;
			}

			/* Update the znode's parent and name */
			vnode_update_identity(vp, dvp, objname, 0, 0, flags);
		}
	}
	/* All done with znode's parent */
	vnode_put(dvp);
out:
	return (error);
}

/*
 * Get a vnode from a file id (ignoring the generation)
 *
 * Use by NFS Server (readdirplus) and VFS (build_path)
 */
static int
zfs_vfs_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, __unused vfs_context_t context)
{
	zfsvfs_t *zfsvfs = vfs_fsprivate(mp);
	int error;

	ZFS_ENTER(zfsvfs);

	/*
	 * On Mac OS X we always export the root directory id as 2.
	 * So we don't expect to see the real root directory id
	 * from zfs_vfs_vget KPI (unless of course the real id was
	 * already 2).
	 */
	if ((ino == zfsvfs->z_root) && (zfsvfs->z_root != 2)) {
		ZFS_EXIT(zfsvfs);
		return (ENOENT);
	}
	error = zfs_vget_internal(zfsvfs, ino, vpp);

	ZFS_EXIT(zfsvfs);
	return (error);
}
コード例 #9
0
ファイル: zfs_znode.c プロジェクト: networkelements/zfs
static int
zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
    sa_attr_type_t *sa_table, char *buf, int len)
{
	sa_handle_t *sa_hdl;
	sa_handle_t *prevhdl = NULL;
	dmu_buf_t *prevdb = NULL;
	dmu_buf_t *sa_db = NULL;
	char *path = buf + len - 1;
	int error;

	*path = '\0';
	sa_hdl = hdl;

	for (;;) {
		uint64_t pobj = 0;
		char component[MAXNAMELEN + 2];
		size_t complen;
		int is_xattrdir = 0;

		if (prevdb)
			zfs_release_sa_handle(prevhdl, prevdb, FTAG);

		if ((error = zfs_obj_to_pobj(sa_hdl, sa_table, &pobj,
		    &is_xattrdir)) != 0)
			break;

		if (pobj == obj) {
			if (path[0] != '/')
				*--path = '/';
			break;
		}

		component[0] = '/';
		if (is_xattrdir) {
			(void) sprintf(component + 1, "<xattrdir>");
		} else {
			error = zap_value_search(osp, pobj, obj,
			    ZFS_DIRENT_OBJ(-1ULL), component + 1);
			if (error != 0)
				break;
		}

		complen = strlen(component);
		path -= complen;
		ASSERT(path >= buf);
		bcopy(component, path, complen);
		obj = pobj;

		if (sa_hdl != hdl) {
			prevhdl = sa_hdl;
			prevdb = sa_db;
		}
		error = zfs_grab_sa_handle(osp, obj, &sa_hdl, &sa_db, FTAG);
		if (error != 0) {
			sa_hdl = prevhdl;
			sa_db = prevdb;
			break;
		}
	}

	if (sa_hdl != NULL && sa_hdl != hdl) {
		ASSERT(sa_db != NULL);
		zfs_release_sa_handle(sa_hdl, sa_db, FTAG);
	}

	if (error == 0)
		(void) memmove(buf, path, buf + len - path);

	return (error);
}
コード例 #10
0
ファイル: zfs_dir.c プロジェクト: BjoKaSH/zfs-osx
zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
                int flag)
#endif
{
    zfsvfs_t	*zfsvfs = dzp->z_zfsvfs;
    zfs_dirlock_t	*dl;
    uint64_t	zoid;
    int		error;
    vnode_t		*vp;
#ifdef __APPLE__
    char		*name;
    u_int8_t	*nfc_name = NULL;  /* NFC form of name */
    int		nfc_namesize = 0;
#endif

    *zpp = NULL;
    *dlpp = NULL;

#ifdef __APPLE__
    /* Note: cnp will be NULL for ZXATTR case */
    name = cnp ? cnp->cn_nameptr : "";
    if (cnp)
        ASSERT(name[cnp->cn_namelen] == '\0');
#endif
    /*
     * Verify that we are not trying to lock '.', '..', or '.zfs'
     */
    if ((name[0] == '.') &&
            ((name[1] == '\0') || ((name[1] == '.') && (name[2] == '\0'))) ||
            zfs_has_ctldir(dzp) && strcmp(name, ZFS_CTLDIR_NAME) == 0)
        return (EEXIST);

#ifdef __APPLE__
    /*
     * Mac OS X: store non-ascii names in UTF-8 NFC (pre-composed) on disk.
     *
     * The NFC name ptr is stored in dl->dl_name (allocated here)
     * and its freed by zfs_dirent_unlock (since dl_namesize != 0).
     *
     * Since NFC size will not expand, we can allocate the same sized buffer.
     */
    if (!is_ascii_str(name)) {
        size_t outlen;

        nfc_namesize = strlen(name) + 1;
        nfc_name = kmem_alloc(nfc_namesize, KM_SLEEP);

        if (utf8_normalizestr((const u_int8_t *)name, nfc_namesize, nfc_name,
                              &outlen, nfc_namesize, UTF_PRECOMPOSED) == 0) {

            /* Normalization succeeded, switch to NFC name. */
            name = (char *)nfc_name;
        } else {
            /* Normalization failed, just use input name as-is. */
            kmem_free(nfc_name, nfc_namesize);
            nfc_name = NULL;
        }
    }
#endif
    /*
     * Wait until there are no locks on this name.
     */
    rw_enter(&dzp->z_name_lock, RW_READER);
    mutex_enter(&dzp->z_lock);
    for (;;) {
        if (dzp->z_unlinked) {
            mutex_exit(&dzp->z_lock);
            rw_exit(&dzp->z_name_lock);
#ifdef __APPLE__
            /* Release any unused NFC name before returning */
            if (nfc_name) {
                kmem_free(nfc_name, nfc_namesize);
            }
#endif
            return (ENOENT);
        }
        for (dl = dzp->z_dirlocks; dl != NULL; dl = dl->dl_next)
            if (strcmp(name, dl->dl_name) == 0)
                break;
        if (dl == NULL)	{
            /*
             * Allocate a new dirlock and add it to the list.
             */
            dl = kmem_alloc(sizeof (zfs_dirlock_t), KM_SLEEP);
            cv_init(&dl->dl_cv, NULL, CV_DEFAULT, NULL);
            dl->dl_name = name;
            dl->dl_sharecnt = 0;
            dl->dl_namesize = 0;
            dl->dl_dzp = dzp;
            dl->dl_next = dzp->z_dirlocks;
            dzp->z_dirlocks = dl;
#ifdef __APPLE__
            /*
             * Keep the NFC name around in dir lock by tagging it
             * (setting nfc_namesize).
             */
            if (nfc_name) {
                dl->dl_namesize = nfc_namesize;
                nfc_name = NULL;  /* its now part of the dir lock */
            }
#endif
            break;
        }
        if ((flag & ZSHARED) && dl->dl_sharecnt != 0)
            break;
        cv_wait(&dl->dl_cv, &dzp->z_lock);
        dl=NULL;
    }

#ifdef __APPLE__
    /*
     * Release any unused NFC name (ie if we found a pre-existing lock entry)
     */
    if (nfc_name) {
        kmem_free(nfc_name, nfc_namesize);
        nfc_name = NULL;
    }
#endif
    if ((flag & ZSHARED) && ++dl->dl_sharecnt > 1 && dl->dl_namesize == 0) {
        /*
         * We're the second shared reference to dl.  Make a copy of
         * dl_name in case the first thread goes away before we do.
         * Note that we initialize the new name before storing its
         * pointer into dl_name, because the first thread may load
         * dl->dl_name at any time.  He'll either see the old value,
         * which is his, or the new shared copy; either is OK.
         */
        dl->dl_namesize = strlen(dl->dl_name) + 1;
        name = kmem_alloc(dl->dl_namesize, KM_SLEEP);
        bcopy(dl->dl_name, name, dl->dl_namesize);
        dl->dl_name = name;
    }

    mutex_exit(&dzp->z_lock);

    /*
     * We have a dirlock on the name.  (Note that it is the dirlock,
     * not the dzp's z_lock, that protects the name in the zap object.)
     * See if there's an object by this name; if so, put a hold on it.
     */
    if (flag & ZXATTR) {
        error = sa_lookup(dzp->z_sa_hdl, SA_ZPL_XATTR(zfsvfs), &zoid,
                          sizeof (zoid));
        if (error == 0)
            error = (zoid == 0 ? ENOENT : 0);
    } else {
#ifdef __APPLE__
        /*
         * Lookup an entry in the vnode name cache
         *
         * If the lookup succeeds, the vnode is returned in *vpp,
         * and a status of -1 is returned.
         *
         * If the lookup determines that the name does not exist
         * (negative caching), a status of ENOENT is returned.
         *
         * If the lookup fails, a status of zero is returned.
         */
        switch ( cache_lookup(ZTOV(dzp), &vp, cnp) ) {
        case -1:
            break;
        case ENOENT:
            vp = DNLC_NO_VNODE;
            break;
        default:
            vp = NULLVP;
        }
#else
        vp = dnlc_lookup(ZTOV(dzp), name);
#endif /* __APPLE__ */
        if (vp == DNLC_NO_VNODE) {
            VN_RELE(vp);
            error = ENOENT;
        } else if (vp) {
            if (flag & ZNEW) {
                zfs_dirent_unlock(dl);
                VN_RELE(vp);
                return (EEXIST);
            }
            *dlpp = dl;
            *zpp = VTOZ(vp);
            return (0);
        } else {
            error = zap_lookup(zfsvfs->z_os, dzp->z_id, name,
                               8, 1, &zoid);
            zoid = ZFS_DIRENT_OBJ(zoid);
            if (error == ENOENT)
#ifdef __APPLE__
                /*
                 * Add a negative entry into the VFS name cache
                 */
                if ((flag & ZNEW) == 0 &&
                        (dzp->z_pflags & ZFS_XATTR) == 0 &&
                        (cnp) &&
                        (cnp->cn_flags & MAKEENTRY) &&
                        (cnp->cn_nameiop != CREATE) &&
                        (cnp->cn_nameiop != RENAME)) {
                    cache_enter(ZTOV(dzp), NULLVP, cnp);
                }
#else
                dnlc_update(ZTOV(dzp), name, DNLC_NO_VNODE);
#endif /* __APPLE__ */
        }
    }
    if (error) {
        if (error != ENOENT || (flag & ZEXISTS)) {
            zfs_dirent_unlock(dl);
            return (error);
        }
    } else {
        if (flag & ZNEW) {
            zfs_dirent_unlock(dl);
            return (EEXIST);
        }
        //error = zfs_zget_sans_vnode(zfsvfs, zoid, zpp);
        error = zfs_zget(zfsvfs, zoid, zpp);
        if (error) {
            zfs_dirent_unlock(dl);
            return (error);
        } else {
            // Should this be here?
            //printf("zfs_dir attach 1\n");
            //zfs_attach_vnode(*zpp);
        }
        if (!(flag & ZXATTR))
#ifdef __APPLE__
            if (cnp && cnp->cn_flags & MAKEENTRY)
                cache_enter(ZTOV(dzp), ZTOV(*zpp), cnp);
#else
            dnlc_update(ZTOV(dzp), name, ZTOV(*zpp));
#endif /* __APPLE__ */
    }

    *dlpp = dl;

    return (0);
}
コード例 #11
0
ファイル: zfs_dir.c プロジェクト: BjoKaSH/zfs-osx
/*
 * Delete the entire contents of a directory.  Return a count
 * of the number of entries that could not be deleted.
 *
 * NOTE: this function assumes that the directory is inactive,
 *	so there is no need to lock its entries before deletion.
 *	Also, it assumes the directory contents is *only* regular
 *	files.
 */
static int
zfs_purgedir(znode_t *dzp)
{
    zap_cursor_t	zc;
    zap_attribute_t	zap;
    znode_t		*xzp;
    dmu_tx_t	*tx;
    zfsvfs_t	*zfsvfs = dzp->z_zfsvfs;
    zfs_dirlock_t	dl;
    int skipped = 0;
    int error;

    for (zap_cursor_init(&zc, zfsvfs->z_os, dzp->z_id);
            (error = zap_cursor_retrieve(&zc, &zap)) == 0;
            zap_cursor_advance(&zc)) {
#ifdef __APPLE__
        error = zfs_zget_sans_vnode(zfsvfs,  ZFS_DIRENT_OBJ(zap.za_first_integer), &xzp);
        ASSERT3U(error, ==, 0);

#else
        error = zfs_zget(zfsvfs,
                         ZFS_DIRENT_OBJ(zap.za_first_integer), &xzp);
        ASSERT3U(error, ==, 0);

        ASSERT((ZTOV(xzp)->v_type == VREG) ||
               (ZTOV(xzp)->v_type == VLNK));
#endif /* __APPLE__ */
        tx = dmu_tx_create(zfsvfs->z_os);
        dmu_tx_hold_sa(tx, dzp->z_sa_hdl, B_FALSE);
        dmu_tx_hold_zap(tx, dzp->z_id, FALSE, zap.za_name);
        dmu_tx_hold_sa(tx, xzp->z_sa_hdl, B_FALSE);
        dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL);
        /* Is this really needed ? */
        zfs_sa_upgrade_txholds(tx, xzp);

        error = dmu_tx_assign(tx, TXG_WAIT);
        if (error) {
            dmu_tx_abort(tx);
#ifdef __APPLE__
            if (ZTOV(xzp) == NULL) {
                zfs_zinactive(xzp);
            } else {
                VN_RELE(ZTOV(xzp));
            }
#else
            VN_RELE(ZTOV(xzp));
#endif /* __APPLE__ */
            skipped += 1;
            continue;
        }
        bzero(&dl, sizeof (dl));
        dl.dl_dzp = dzp;
        dl.dl_name = zap.za_name;

        error = zfs_link_destroy(&dl, xzp, tx, 0, NULL);
        ASSERT3U(error, ==, 0);
        dmu_tx_commit(tx);

#ifdef __APPLE__
        if (ZTOV(xzp) == NULL) {
            zfs_zinactive(xzp);
        } else {
            VN_RELE(ZTOV(xzp));
        }
#else
        VN_RELE(ZTOV(xzp));
#endif /* __APPLE__ */
    }
    zap_cursor_fini(&zc);
    ASSERT(error == ENOENT);
    return (skipped);
}
コード例 #12
0
ファイル: zfs_vnops_osx_lib.c プロジェクト: RJVB/zfs
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);
	/*
	 * 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
        } 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_filerev)) {
        VATTR_RETURN(vap, va_filerev, 0);
    }
	if (VATTR_IS_ACTIVE(vap, va_linkid)) {
        VATTR_RETURN(vap, va_linkid, vap->va_fileid);
    }
	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);
}