Ejemplo n.º 1
0
/*
 * Delete-duplicate a cluster in-place.
 */
void
hammer2_cluster_delete_duplicate(hammer2_trans_t *trans,
				 hammer2_cluster_t *cluster, int flags)
{
	hammer2_chain_t *chain;
	int i;

	cluster->focus = NULL;
	for (i = 0; i < cluster->nchains; ++i) {
		chain = cluster->array[i];
		if (chain) {
			hammer2_chain_delete_duplicate(trans, &chain, flags);
			cluster->array[i] = chain;
			if (cluster->focus == NULL)
				cluster->focus = chain;
		}
	}
}
Ejemplo n.º 2
0
/*
 * Given an exclusively locked inode and chain we consolidate its chain
 * for hardlink creation, adding (nlinks) to the file's link count and
 * potentially relocating the inode to a directory common to ip->pip and tdip.
 *
 * Replaces (*chainp) if consolidation occurred, unlocking the old chain
 * and returning a new locked chain.
 *
 * NOTE!  This function will also replace ip->chain.
 */
int
hammer2_hardlink_consolidate(hammer2_trans_t *trans,
			     hammer2_inode_t *ip, hammer2_chain_t **chainp,
			     hammer2_inode_t *cdip, hammer2_chain_t **cdchainp,
			     int nlinks)
{
	hammer2_inode_data_t *ipdata;
	hammer2_chain_t *chain;
	hammer2_chain_t *nchain;
	int error;

	chain = *chainp;
	if (nlinks == 0 &&			/* no hardlink needed */
	    (chain->data->ipdata.name_key & HAMMER2_DIRHASH_VISIBLE)) {
		return (0);
	}
	if (hammer2_hardlink_enable < 0) {	/* fake hardlinks */
		return (0);
	}

	if (hammer2_hardlink_enable == 0) {	/* disallow hardlinks */
		hammer2_chain_unlock(chain);
		*chainp = NULL;
		return (ENOTSUP);
	}

	/*
	 * If no change in the hardlink's target directory is required and
	 * this is already a hardlink target, all we need to do is adjust
	 * the link count.
	 */
	if (cdip == ip->pip &&
	    (chain->data->ipdata.name_key & HAMMER2_DIRHASH_VISIBLE) == 0) {
		if (nlinks) {
			hammer2_chain_modify(trans, &chain, 0);
			chain->data->ipdata.nlinks += nlinks;
		}
		error = 0;
		goto done;
	}


	/*
	 * chain is the real inode.  If it's visible we have to convert it
	 * to a hardlink pointer.  If it is not visible then it is already
	 * a hardlink target and only needs to be deleted.
	 */
	KKASSERT((chain->flags & HAMMER2_CHAIN_DELETED) == 0);
	KKASSERT(chain->data->ipdata.type != HAMMER2_OBJTYPE_HARDLINK);
	if (chain->data->ipdata.name_key & HAMMER2_DIRHASH_VISIBLE) {
		/*
		 * We are going to duplicate chain later, causing its
		 * media block to be shifted to the duplicate.  Even though
		 * we are delete-duplicating nchain here it might decide not
		 * to reallocate the block.  Set FORCECOW to force it to.
		 */
		nchain = chain;
		hammer2_chain_lock(nchain, HAMMER2_RESOLVE_ALWAYS);
		atomic_set_int(&nchain->flags, HAMMER2_CHAIN_FORCECOW);
		hammer2_chain_delete_duplicate(trans, &nchain,
					       HAMMER2_DELDUP_RECORE);
		KKASSERT((chain->flags & HAMMER2_CHAIN_DUPLICATED) == 0);

		ipdata = &nchain->data->ipdata;
		ipdata->target_type = ipdata->type;
		ipdata->type = HAMMER2_OBJTYPE_HARDLINK;
		ipdata->uflags = 0;
		ipdata->rmajor = 0;
		ipdata->rminor = 0;
		ipdata->ctime = 0;
		ipdata->mtime = 0;
		ipdata->atime = 0;
		ipdata->btime = 0;
		bzero(&ipdata->uid, sizeof(ipdata->uid));
		bzero(&ipdata->gid, sizeof(ipdata->gid));
		ipdata->op_flags = HAMMER2_OPFLAG_DIRECTDATA;
		ipdata->cap_flags = 0;
		ipdata->mode = 0;
		ipdata->size = 0;
		ipdata->nlinks = 1;
		ipdata->iparent = 0;	/* XXX */
		ipdata->pfs_type = 0;
		ipdata->pfs_inum = 0;
		bzero(&ipdata->pfs_clid, sizeof(ipdata->pfs_clid));
		bzero(&ipdata->pfs_fsid, sizeof(ipdata->pfs_fsid));
		ipdata->data_quota = 0;
		ipdata->data_count = 0;
		ipdata->inode_quota = 0;
		ipdata->inode_count = 0;
		ipdata->attr_tid = 0;
		ipdata->dirent_tid = 0;
		bzero(&ipdata->u, sizeof(ipdata->u));
		/* XXX transaction ids */
	} else {
		hammer2_chain_delete(trans, chain, 0);
		nchain = NULL;
	}

	/*
	 * chain represents the hardlink target and is now flagged deleted.
	 * duplicate it to the parent directory and adjust nlinks.
	 *
	 * WARNING! The shiftup() call can cause nchain to be moved into
	 *	    an indirect block, and our nchain will wind up pointing
	 *	    to the older/original version.
	 */
	KKASSERT(chain->flags & HAMMER2_CHAIN_DELETED);
	hammer2_hardlink_shiftup(trans, &chain, cdip, cdchainp, nlinks, &error);

	if (error == 0)
		hammer2_inode_repoint(ip, cdip, chain);

	/*
	 * Unlock the original chain last as the lock blocked races against
	 * the creation of the new hardlink target.
	 */
	if (nchain)
		hammer2_chain_unlock(nchain);

done:
	/*
	 * Cleanup, chain/nchain already dealt with.
	 */
	*chainp = chain;
	hammer2_inode_drop(cdip);

	return (error);
}
Ejemplo n.º 3
0
/*
 * Given an exclusively locked inode we consolidate its chain for hardlink
 * creation, adding (nlinks) to the file's link count and potentially
 * relocating the inode to a directory common to ip->pip and tdip.
 *
 * Replaces (*chainp) if consolidation occurred, unlocking the old chain
 * and returning a new locked chain.
 *
 * NOTE!  This function will also replace ip->chain.
 */
int
hammer2_hardlink_consolidate(hammer2_trans_t *trans, hammer2_inode_t *ip,
			     hammer2_chain_t **chainp,
			     hammer2_inode_t *tdip, int nlinks)
{
	hammer2_inode_data_t *ipdata;
	hammer2_inode_t *fdip;
	hammer2_inode_t *cdip;
	hammer2_chain_t *chain;
	hammer2_chain_t *nchain;
	int error;

	chain = *chainp;
	if (nlinks == 0 &&			/* no hardlink needed */
	    (chain->data->ipdata.name_key & HAMMER2_DIRHASH_VISIBLE)) {
		return (0);
	}
	if (hammer2_hardlink_enable < 0) {	/* fake hardlinks */
		return (0);
	}

	if (hammer2_hardlink_enable == 0) {	/* disallow hardlinks */
		hammer2_chain_unlock(chain);
		*chainp = NULL;
		return (ENOTSUP);
	}

	/*
	 * cdip will be returned with a ref, but not locked.
	 */
	fdip = ip->pip;
	cdip = hammer2_inode_common_parent(fdip, tdip);

	/*
	 * If no change in the hardlink's target directory is required and
	 * this is already a hardlink target, all we need to do is adjust
	 * the link count.
	 *
	 * XXX The common parent is a big wiggly due to duplication from
	 *     renames.  Compare the core (RBTREE) pointer instead of the
	 *     ip's.
	 */
	if (cdip == fdip &&
	    (chain->data->ipdata.name_key & HAMMER2_DIRHASH_VISIBLE) == 0) {
		if (nlinks) {
			hammer2_chain_modify(trans, &chain, 0);
			chain->data->ipdata.nlinks += nlinks;
		}
		error = 0;
		goto done;
	}

	/*
	 * We either have to move an existing hardlink target or we have
	 * to create a fresh hardlink target.
	 *
	 * Hardlink targets are hidden inodes in a parent directory common
	 * to all directory entries referencing the hardlink.
	 */
	nchain = hammer2_hardlink_shiftup(trans, &chain, cdip, &error);

	if (error == 0) {
		/*
		 * Bump nlinks on duplicated hidden inode, repoint
		 * ip->chain.
		 */
		hammer2_chain_modify(trans, &nchain, 0);
		nchain->data->ipdata.nlinks += nlinks;
		hammer2_inode_repoint(ip, cdip, nchain);

		/*
		 * If the old chain is not a hardlink target then replace
		 * it with a OBJTYPE_HARDLINK pointer.
		 *
		 * If the old chain IS a hardlink target then delete it.
		 */
		if (chain->data->ipdata.name_key & HAMMER2_DIRHASH_VISIBLE) {
			/*
			 * Replace original non-hardlink that's been dup'd
			 * with a special hardlink directory entry.  We must
			 * set the DIRECTDATA flag to prevent sub-chains
			 * from trying to synchronize to the inode if the
			 * file is extended afterwords.
			 */
			hammer2_chain_modify(trans, &chain, 0);
			hammer2_chain_delete_duplicate(trans, &chain,
						       HAMMER2_DELDUP_RECORE);
			ipdata = &chain->data->ipdata;
			ipdata->target_type = ipdata->type;
			ipdata->type = HAMMER2_OBJTYPE_HARDLINK;
			ipdata->uflags = 0;
			ipdata->rmajor = 0;
			ipdata->rminor = 0;
			ipdata->ctime = 0;
			ipdata->mtime = 0;
			ipdata->atime = 0;
			ipdata->btime = 0;
			bzero(&ipdata->uid, sizeof(ipdata->uid));
			bzero(&ipdata->gid, sizeof(ipdata->gid));
			ipdata->op_flags = HAMMER2_OPFLAG_DIRECTDATA;
			ipdata->cap_flags = 0;
			ipdata->mode = 0;
			ipdata->size = 0;
			ipdata->nlinks = 1;
			ipdata->iparent = 0;	/* XXX */
			ipdata->pfs_type = 0;
			ipdata->pfs_inum = 0;
			bzero(&ipdata->pfs_clid, sizeof(ipdata->pfs_clid));
			bzero(&ipdata->pfs_fsid, sizeof(ipdata->pfs_fsid));
			ipdata->data_quota = 0;
			ipdata->data_count = 0;
			ipdata->inode_quota = 0;
			ipdata->inode_count = 0;
			ipdata->attr_tid = 0;
			ipdata->dirent_tid = 0;
			bzero(&ipdata->u, sizeof(ipdata->u));
			/* XXX transaction ids */
		} else {
			hammer2_chain_delete(trans, chain);
		}

		/*
		 * Return the new chain.
		 */
		hammer2_chain_unlock(chain);
		chain = nchain;
	} else {
		/*
		 * Return an error
		 */
		hammer2_chain_unlock(chain);
		chain = NULL;
	}

	/*
	 * Cleanup, chain/nchain already dealt with.
	 */
done:
	*chainp = chain;
	hammer2_inode_drop(cdip);

	return (error);
}