FreeBSD/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c
/*
 * Unlink zp from dzp, and mark zp for deletion if this was the last link.
 * Can fail if zp is a mount point (EBUSY) or a non-empty directory (EEXIST).
 * If 'unlinkedp' is NULL, we put unlinked znodes on the unlinked list.
 * If it's non-NULL, we use it to indicate whether the znode needs deletion,
 * and it's the caller's job to do it.
 */
Unlink zp from dzp, and mark zp for deletion if this was the last link.
Can fail if zp is a mount point (EBUSY) or a non-empty directory (EEXIST).
If 'unlinkedp' is NULL, we put unlinked znodes on the unlinked list.
If it's non-NULL, we use it to indicate whether the znode needs deletion,
and it's the caller's job to do it.
Unlink zp from dzp and mark zp for deletion if this was the last link . Can fail if zp is a mount point ( EBUSY ) or a non - empty directory ( EEXIST ) . If ' unlinkedp ' is NULL we put unlinked znodes on the unlinked list . If it ' s non - NULL we use it to indicate whether the znode needs deletion and it ' s the caller ' s job to do it .
int
zfs_link_destroy(znode_t *dzp, const char *name, znode_t *zp, dmu_tx_t *tx,
    int flag, boolean_t *unlinkedp)
{
	zfsvfs_t *zfsvfs = dzp->z_zfsvfs;
	vnode_t *vp = ZTOV(zp);
	int zp_is_dir = (vp->v_type == VDIR);
	boolean_t unlinked = B_FALSE;
	sa_bulk_attr_t bulk[5];
	uint64_t mtime[2], ctime[2];
	int count = 0;
	int error;
	ASSERT_VOP_ELOCKED(ZTOV(dzp), __func__);
	ASSERT_VOP_ELOCKED(ZTOV(zp), __func__);
	if (!(flag & ZRENAMING)) {
		if (zp_is_dir && !zfs_dirempty(zp)) {
#ifdef illumos
			return (SET_ERROR(EEXIST));
#else
			return (SET_ERROR(ENOTEMPTY));
#endif
		}
		error = zfs_dropname(dzp, name, zp, tx, flag);
		if (error != 0) {
			return (error);
		}
		if (zp->z_links <= zp_is_dir) {
			zfs_panic_recover("zfs: link count on vnode %p is %u, "
			    "should be at least %u", zp->z_vnode,
			    (int)zp->z_links,
			    zp_is_dir + 1);
			zp->z_links = zp_is_dir + 1;
		}
		if (--zp->z_links == zp_is_dir) {
			zp->z_unlinked = B_TRUE;
			zp->z_links = 0;
			unlinked = B_TRUE;
		} else {
			SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs),
			    NULL, &ctime, sizeof (ctime));
			SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs),
			    NULL, &zp->z_pflags, sizeof (zp->z_pflags));
			zfs_tstamp_update_setup(zp, STATE_CHANGED, mtime, ctime,
			    B_TRUE);
		}
		SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zfsvfs),
		    NULL, &zp->z_links, sizeof (zp->z_links));
		error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
		count = 0;
		ASSERT0(error);
	} else {
		ASSERT(zp->z_unlinked == 0);
		error = zfs_dropname(dzp, name, zp, tx, flag);
		if (error != 0)
			return (error);
	}
	dzp->z_size--;		
	dzp->z_links -= zp_is_dir;	
	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zfsvfs),
	    NULL, &dzp->z_links, sizeof (dzp->z_links));
	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_SIZE(zfsvfs),
	    NULL, &dzp->z_size, sizeof (dzp->z_size));
	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs),
	    NULL, ctime, sizeof (ctime));
	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zfsvfs),
	    NULL, mtime, sizeof (mtime));
	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs),
	    NULL, &dzp->z_pflags, sizeof (dzp->z_pflags));
	zfs_tstamp_update_setup(dzp, CONTENT_MODIFIED, mtime, ctime, B_TRUE);
	error = sa_bulk_update(dzp->z_sa_hdl, bulk, count, tx);
	ASSERT0(error);
	if (unlinkedp != NULL)
		*unlinkedp = unlinked;
	else if (unlinked)
		zfs_unlinked_add(zp, tx);
	return (0);
}
int zfs_link_destroy ( znode_t * dzp , const char * name , znode_t * zp , dmu_tx_t * tx , int flag , boolean_t * unlinkedp ) { zfsvfs_t * zfsvfs = dzp -> z_zfsvfs ; vnode_t * vp = ZTOV ( zp ) ; int zp_is_dir = ( vp -> v_type == VDIR ) ; boolean_t unlinked = B_FALSE ; sa_bulk_attr_t bulk [ 5 ] ; uint64_t mtime [ 2 ] , ctime [ 2 ] ; int count = 0 ; int error ; ASSERT_VOP_ELOCKED ( ZTOV ( dzp ) , __func__ ) ; ASSERT_VOP_ELOCKED ( ZTOV ( zp ) , __func__ ) ; if ( ! ( flag & ZRENAMING ) ) { if ( zp_is_dir && ! zfs_dirempty ( zp ) ) { #ifdef illumos return ( SET_ERROR ( EEXIST ) ) ; #else return ( SET_ERROR ( ENOTEMPTY ) ) ; #endif } error = zfs_dropname ( dzp , name , zp , tx , flag ) ; if ( error != 0 ) { return ( error ) ; } if ( zp -> z_links <= zp_is_dir ) { zfs_panic_recover ( " " " " , zp -> z_vnode , ( int ) zp -> z_links , zp_is_dir + 1 ) ; zp -> z_links = zp_is_dir + 1 ; } if ( -- zp -> z_links == zp_is_dir ) { zp -> z_unlinked = B_TRUE ; zp -> z_links = 0 ; unlinked = B_TRUE ; } else { SA_ADD_BULK_ATTR ( bulk , count , SA_ZPL_CTIME ( zfsvfs ) , NULL , & ctime , sizeof ( ctime ) ) ; SA_ADD_BULK_ATTR ( bulk , count , SA_ZPL_FLAGS ( zfsvfs ) , NULL , & zp -> z_pflags , sizeof ( zp -> z_pflags ) ) ; zfs_tstamp_update_setup ( zp , STATE_CHANGED , mtime , ctime , B_TRUE ) ; } SA_ADD_BULK_ATTR ( bulk , count , SA_ZPL_LINKS ( zfsvfs ) , NULL , & zp -> z_links , sizeof ( zp -> z_links ) ) ; error = sa_bulk_update ( zp -> z_sa_hdl , bulk , count , tx ) ; count = 0 ; ASSERT0 ( error ) ; } else { ASSERT ( zp -> z_unlinked == 0 ) ; error = zfs_dropname ( dzp , name , zp , tx , flag ) ; if ( error != 0 ) return ( error ) ; } dzp -> z_size -- ; dzp -> z_links -= zp_is_dir ; SA_ADD_BULK_ATTR ( bulk , count , SA_ZPL_LINKS ( zfsvfs ) , NULL , & dzp -> z_links , sizeof ( dzp -> z_links ) ) ; SA_ADD_BULK_ATTR ( bulk , count , SA_ZPL_SIZE ( zfsvfs ) , NULL , & dzp -> z_size , sizeof ( dzp -> z_size ) ) ; SA_ADD_BULK_ATTR ( bulk , count , SA_ZPL_CTIME ( zfsvfs ) , NULL , ctime , sizeof ( ctime ) ) ; SA_ADD_BULK_ATTR ( bulk , count , SA_ZPL_MTIME ( zfsvfs ) , NULL , mtime , sizeof ( mtime ) ) ; SA_ADD_BULK_ATTR ( bulk , count , SA_ZPL_FLAGS ( zfsvfs ) , NULL , & dzp -> z_pflags , sizeof ( dzp -> z_pflags ) ) ; zfs_tstamp_update_setup ( dzp , CONTENT_MODIFIED , mtime , ctime , B_TRUE ) ; error = sa_bulk_update ( dzp -> z_sa_hdl , bulk , count , tx ) ; ASSERT0 ( error ) ; if ( unlinkedp != NULL ) * unlinkedp = unlinked ; else if ( unlinked ) zfs_unlinked_add ( zp , tx ) ; return ( 0 ) ; }
Unlink zp from dzp, and mark zp for deletion if this was the last link.
Unlink zp from dzp and mark zp for deletion if this was the last link .
/*
		 * If we get here, we are going to try to remove the object.
		 * First try removing the name from the directory; if that
		 * fails, return the error.
		 */ /* one dirent removed */ /* ".." link from zp */