text:
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
#include "xfs_bit.h"
#include "xfs_log.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
#include "xfs_mount.h"
#include "xfs_da_btree.h"
#include "xfs_bmap_btree.h"
#include "xfs_ialloc_btree.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_inode_item.h"
#include "xfs_itable.h"
#include "xfs_ialloc.h"
#include "xfs_alloc.h"
#include "xfs_bmap.h"
#include "xfs_acl.h"
#include "xfs_attr.h"
#include "xfs_error.h"
#include "xfs_quota.h"
#include "xfs_utils.h"
#include "xfs_rtalloc.h"
#include "xfs_trans_space.h"
#include "xfs_log_priv.h"
#include "xfs_filestream.h"
#include "xfs_vnodeops.h"
#include "xfs_trace.h"

/*
 * The maximum pathlen is 1024 bytes. Since the minimum file system
 * blocksize is 512 bytes, we can get a max of 2 extents back from
 * bmapi.
 */
#define SYMLINK_MAPS 2

STATIC int
xfs_readlink_bmap(
	xfs_inode_t	*ip,
	char		*link)
{
	xfs_mount_t	*mp = ip->i_mount;
	int		pathlen = ip->i_d.di_size;
	int             nmaps = SYMLINK_MAPS;
	xfs_bmbt_irec_t mval[SYMLINK_MAPS];
	xfs_daddr_t	d;
	int		byte_cnt;
	int		n;
	xfs_buf_t	*bp;
	int		error = 0;

	error = xfs_bmapi_read(ip, 0, XFS_B_TO_FSB(mp, pathlen), mval, &nmaps,
			       0);
	if (error)
		goto out;

	for (n = 0; n < nmaps; n++) {
		d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
		byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);

		bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0);
		if (!bp)
			return XFS_ERROR(ENOMEM);
		error = bp->b_error;
		if (error) {
			xfs_buf_ioerror_alert(bp, __func__);
			xfs_buf_relse(bp);
			goto out;
		}
		if (pathlen < byte_cnt)
			byte_cnt = pathlen;
		pathlen -= byte_cnt;

		memcpy(link, bp->b_addr, byte_cnt);
		xfs_buf_relse(bp);
	}

	link[ip->i_d.di_size] = '\0';
	error = 0;

 out:
	return error;
}

int
xfs_readlink(
	xfs_inode_t     *ip,
	char		*link)
{
	xfs_mount_t	*mp = ip->i_mount;
	xfs_fsize_t	pathlen;
	int		error = 0;

	trace_xfs_readlink(ip);

	if (XFS_FORCED_SHUTDOWN(mp))
		return XFS_ERROR(EIO);

	xfs_ilock(ip, XFS_ILOCK_SHARED);

	pathlen = ip->i_d.di_size;
	if (!pathlen)
		goto out;

	if (pathlen < 0 || pathlen > MAXPATHLEN) {
		xfs_alert(mp, "%s: inode (%llu) bad symlink length (%lld)",
			 __func__, (unsigned long long) ip->i_ino,
			 (long long) pathlen);
		ASSERT(0);
		error = XFS_ERROR(EFSCORRUPTED);
		goto out;
	}

	if (ip->i_df.if_flags & XFS_IFINLINE) {
		memcpy(link, ip->i_df.if_u1.if_data, pathlen);
		link[pathlen] = '\0';
	} else {
		error = xfs_readlink_bmap(ip, link);
	}

 out:
	xfs_iunlock(ip, XFS_ILOCK_SHARED);
	return error;
}

/*
 * Flags for xfs_free_eofblocks
 */
#define XFS_FREE_EOF_TRYLOCK	(1<<0)

/*
 * This is called by xfs_inactive to free any blocks beyond eof
 * when the link count isn't zero and by xfs_dm_punch_hole() when
 * punching a hole to EOF.
 */
STATIC int
xfs_free_eofblocks(
	xfs_mount_t	*mp,
	xfs_inode_t	*ip,
	int		flags)
{
	xfs_trans_t	*tp;
	int		error;
	xfs_fileoff_t	end_fsb;
	xfs_fileoff_t	last_fsb;
	xfs_filblks_t	map_len;
	int		nimaps;
	xfs_bmbt_irec_t	imap;

	/*
	 * Figure out if there are any blocks beyond the end
	 * of the file.  If not, then there is nothing to do.
	 */
	end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_ISIZE(ip));
	last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
	if (last_fsb <= end_fsb)
		return 0;
	map_len = last_fsb - end_fsb;

	nimaps = 1;
	xfs_ilock(ip, XFS_ILOCK_SHARED);
	error = xfs_bmapi_read(ip, end_fsb, map_len, &imap, &nimaps, 0);
	xfs_iunlock(ip, XFS_ILOCK_SHARED);

	if (!error && (nimaps != 0) &&
	    (imap.br_startblock != HOLESTARTBLOCK ||
	     ip->i_delayed_blks)) {
		/*
		 * Attach the dquots to the inode up front.
		 */
		error = xfs_qm_dqattach(ip, 0);
		if (error)
			return error;

		/*
		 * There are blocks after the end of file.
		 * Free them up now by truncating the file to
		 * its current size.
		 */
		tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);

		if (flags & XFS_FREE_EOF_TRYLOCK) {
			if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
				xfs_trans_cancel(tp, 0);
				return 0;
			}
		} else {
			xfs_ilock(ip, XFS_IOLOCK_EXCL);
		}

		error = xfs_trans_reserve(tp, 0,
					  XFS_ITRUNCATE_LOG_RES(mp),
					  0, XFS_TRANS_PERM_LOG_RES,
					  XFS_ITRUNCATE_LOG_COUNT);
		if (error) {
			ASSERT(XFS_FORCED_SHUTDOWN(mp));
			xfs_trans_cancel(tp, 0);
			xfs_iunlock(ip, XFS_IOLOCK_EXCL);
			return error;
		}

		xfs_ilock(ip, XFS_ILOCK_EXCL);
		xfs_trans_ijoin(tp, ip, 0);

		/*
		 * Do not update the on-disk file size.  If we update the
		 * on-disk file size and then the system crashes before the
		 * contents of the file are flushed to disk then the files
		 * may be full of holes (ie NULL files bug).
		 */
		error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK,
					      XFS_ISIZE(ip));
		if (error) {
			/*
			 * If we get an error at this point we simply don't
			 * bother truncating the file.
			 */
			xfs_trans_cancel(tp,
					 (XFS_TRANS_RELEASE_LOG_RES |
					  XFS_TRANS_ABORT));
		} else {
			error = xfs_trans_commit(tp,
						XFS_TRANS_RELEASE_LOG_RES);
		}
		xfs_iunlock(ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL);
	}
	return error;
}

/*
 * Free a symlink that has blocks associated with it.
 */
STATIC int
xfs_inactive_symlink_rmt(
	xfs_inode_t	*ip,
	xfs_trans_t	**tpp)
{
	xfs_buf_t	*bp;
	int		committed;
	int		done;
	int		error;
	xfs_fsblock_t	first_block;
	xfs_bmap_free_t	free_list;
	int		i;
	xfs_mount_t	*mp;
	xfs_bmbt_irec_t	mval[SYMLINK_MAPS];
	int		nmaps;
	xfs_trans_t	*ntp;
	int		size;
	xfs_trans_t	*tp;

	tp = *tpp;
	mp = ip->i_mount;
	ASSERT(ip->i_d.di_size > XFS_IFORK_DSIZE(ip));
	/*
	 * We're freeing a symlink that has some
	 * blocks allocated to it.  Free the
	 * blocks here.  We know that we've got
	 * either 1 or 2 extents and that we can
	 * free them all in one bunmapi call.
	 */
	ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2);
	if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
			XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) {
		ASSERT(XFS_FORCED_SHUTDOWN(mp));
		xfs_trans_cancel(tp, 0);
		*tpp = NULL;
		return error;
	}
	/*
	 * Lock the inode, fix the size, and join it to the transaction.
	 * Hold it so in the normal path, we still have it locked for
	 * the second transaction.  In the error paths we need it
	 * held so the cancel won't rele it, see below.
	 */
	xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
	size = (int)ip->i_d.di_size;
	ip->i_d.di_size = 0;
	xfs_trans_ijoin(tp, ip, 0);
	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
	/*
	 * Find the block(s) so we can inval and unmap them.
	 */
	done = 0;
	xfs_bmap_init(&free_list, &first_block);
	nmaps = ARRAY_SIZE(mval);
	error = xfs_bmapi_read(ip, 0, XFS_B_TO_FSB(mp, size),
				mval, &nmaps, 0);
	if (error)
		goto error0;
	/*
	 * Invalidate the block(s).
	 */
	for (i = 0; i < nmaps; i++) {
		bp = xfs_trans_get_buf(tp, mp->m_ddev_targp,
			XFS_FSB_TO_DADDR(mp, mval[i].br_startblock),
			XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0);
		if (!bp) {
			error = ENOMEM;
			goto error1;
		}
		xfs_trans_binval(tp, bp);
	}
	/*
	 * Unmap the dead block(s) to the free_list.
	 */
	if ((error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps,
			&first_block, &free_list, &done)))
		goto error1;
	ASSERT(done);
	/*
	 * Commit the first transaction.  This logs the EFI and the inode.
	 */
	if ((error = xfs_bmap_finish(&tp, &free_list, &committed)))
		goto error1;
	/*
	 * The transaction must have been committed, since there were
	 * actually extents freed by xfs_bunmapi.  See xfs_bmap_finish.
	 * The new tp has the extent freeing and EFDs.
	 */
	ASSERT(committed);
	/*
	 * The first xact was committed, so add the inode to the new one.
	 * Mark it dirty so it will be logged and moved forward in the log as
	 * part of every commit.
	 */
	xfs_trans_ijoin(tp, ip, 0);
	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
	/*
	 * Get a new, empty transaction to return to our caller.
	 */
	ntp = xfs_trans_dup(tp);
	/*
	 * Commit the transaction containing extent freeing and EFDs.
	 * If we get an error on the commit here or on the reserve below,
	 * we need to unlock the inode since the new transaction doesn't
	 * have the inode attached.
	 */
	error = xfs_trans_commit(tp, 0);
	tp = ntp;
	if (error) {
		ASSERT(XFS_FORCED_SHUTDOWN(mp));
		goto error0;
	}
	/*
	 * transaction commit worked ok so we can drop the extra ticket
	 * reference that we gained in xfs_trans_dup()
	 */
	xfs_log_ticket_put(tp->t_ticket);

	/*
	 * Remove the memory for extent descriptions (just bookkeeping).
	 */
	if (ip->i_df.if_bytes)
		xfs_idata_realloc(ip, -ip->i_df.if_bytes, XFS_DATA_FORK);
	ASSERT(ip->i_df.if_bytes == 0);
	/*
	 * Put an itruncate log reservation in the new transaction
	 * for our caller.
	 */
	if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
			XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) {
		ASSERT(XFS_FORCED_SHUTDOWN(mp));
		goto error0;
	}
	/*
	 * Return with the inode locked but not joined to the transaction.
	 */
	*tpp = tp;
	return 0;

 error1:
	xfs_bmap_cancel(&free_list);
 error0:
	/*
	 * Have to come here with the inode locked and either
	 * (held and in the transaction) or (not in the transaction).
	 * If the inode isn't held then cancel would iput it, but
	 * that's wrong since this is inactive and the vnode ref
	 * count is 0 already.
	 * Cancel won't do anything to the inode if held, but it still
	 * needs to be locked until the cancel is done, if it was
	 * joined to the transaction.
	 */
	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
	xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
	*tpp = NULL;
	return error;

}

STATIC int
xfs_inactive_symlink_local(
	xfs_inode_t	*ip,
	xfs_trans_t	**tpp)
{
	int		error;

	ASSERT(ip->i_d.di_size <= XFS_IFORK_DSIZE(ip));
	/*
	 * We're freeing a symlink which fit into
	 * the inode.  Just free the memory used
	 * to hold the old symlink.
	 */
	error = xfs_trans_reserve(*tpp, 0,
				  XFS_ITRUNCATE_LOG_RES(ip->i_mount),
				  0, XFS_TRANS_PERM_LOG_RES,
				  XFS_ITRUNCATE_LOG_COUNT);

	if (error) {
		xfs_trans_cancel(*tpp, 0);
		*tpp = NULL;
		return error;
	}
	xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);

	/*
	 * Zero length symlinks _can_ exist.
	 */
	if (ip->i_df.if_bytes > 0) {
		xfs_idata_realloc(ip,
				  -(ip->i_df.if_bytes),
				  XFS_DATA_FORK);
		ASSERT(ip->i_df.if_bytes == 0);
	}
	return 0;
}

STATIC int
xfs_inactive_attrs(
	xfs_inode_t	*ip,
	xfs_trans_t	**tpp)
{
	xfs_trans_t	*tp;
	int		error;
	xfs_mount_t	*mp;

	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
	tp = *tpp;
	mp = ip->i_mount;
	ASSERT(ip->i_d.di_forkoff != 0);
	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
	xfs_iunlock(ip, XFS_ILOCK_EXCL);
	if (error)
		goto error_unlock;

	error = xfs_attr_inactive(ip);
	if (error)
		goto error_unlock;

	tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
	error = xfs_trans_reserve(tp, 0,
				  XFS_IFREE_LOG_RES(mp),
				  0, XFS_TRANS_PERM_LOG_RES,
				  XFS_INACTIVE_LOG_COUNT);
	if (error)
		goto error_cancel;

	xfs_ilock(ip, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, ip, 0);
	xfs_idestroy_fork(ip, XFS_ATTR_FORK);

	ASSERT(ip->i_d.di_anextents == 0);

	*tpp = tp;
	return 0;

error_cancel:
	ASSERT(XFS_FORCED_SHUTDOWN(mp));
	xfs_trans_cancel(tp, 0);
error_unlock:
	*tpp = NULL;
	xfs_iunlock(ip, XFS_IOLOCK_EXCL);
	return error;
}

int
xfs_release(
	xfs_inode_t	*ip)
{
	xfs_mount_t	*mp = ip->i_mount;
	int		error;

	if (!S_ISREG(ip->i_d.di_mode) || (ip->i_d.di_mode == 0))
		return 0;

	/* If this is a read-only mount, don't do this (would generate I/O) */
	if (mp->m_flags & XFS_MOUNT_RDONLY)
		return 0;

	if (!XFS_FORCED_SHUTDOWN(mp)) {
		int truncated;

		/*
		 * If we are using filestreams, and we have an unlinked
		 * file that we are processing the last close on, then nothing
		 * will be able to reopen and write to this file. Purge this
		 * inode from the filestreams cache so that it doesn't delay
		 * teardown of the inode.
		 */
		if ((ip->i_d.di_nlink == 0) && xfs_inode_is_filestream(ip))
			xfs_filestream_deassociate(ip);

		/*
		 * If we previously truncated this file and removed old data
		 * in the process, we want to initiate "early" writeout on
		 * the last close.  This is an attempt to combat the notorious
		 * NULL files problem which is particularly noticeable from a
		 * truncate down, buffered (re-)write (delalloc), followed by
		 * a crash.  What we are effectively doing here is
		 * significantly reducing the time window where we'd otherwise
		 * be exposed to that problem.
		 */
		truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED);
		if (truncated) {
			xfs_iflags_clear(ip, XFS_IDIRTY_RELEASE);
			if (VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0)
				xfs_flush_pages(ip, 0, -1, XBF_ASYNC, FI_NONE);
		}
	}

	if (ip->i_d.di_nlink == 0)
		return 0;

	if ((S_ISREG(ip->i_d.di_mode) &&
	     (VFS_I(ip)->i_size > 0 ||
	      (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) &&
	     (ip->i_df.if_flags & XFS_IFEXTENTS))  &&
	    (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) {

		/*
		 * If we can't get the iolock just skip truncating the blocks
		 * past EOF because we could deadlock with the mmap_sem
		 * otherwise.  We'll get another chance to drop them once the
		 * last reference to the inode is dropped, so we'll never leak
		 * blocks permanently.
		 *
		 * Further, check if the inode is being opened, written and
		 * closed frequently and we have delayed allocation blocks
		 * outstanding (e.g. streaming writes from the NFS server),
		 * truncating the blocks past EOF will cause fragmentation to
		 * occur.
		 *
		 * In this case don't do the truncation, either, but we have to
		 * be careful how we detect this case. Blocks beyond EOF show
		 * up as i_delayed_blks even when the inode is clean, so we
		 * need to truncate them away first before checking for a dirty
		 * release. Hence on the first dirty close we will still remove
		 * the speculative allocation, but after that we will leave it
		 * in place.
		 */
		if (xfs_iflags_test(ip, XFS_IDIRTY_RELEASE))
			return 0;

		error = xfs_free_eofblocks(mp, ip,
					   XFS_FREE_EOF_TRYLOCK);
		if (error)
			return error;

		/* delalloc blocks after truncation means it really is dirty */
		if (ip->i_delayed_blks)
			xfs_iflags_set(ip, XFS_IDIRTY_RELEASE);
	}
	return 0;
}

/*
 * xfs_inactive
 *
 * This is called when the vnode reference count for the vnode
 * goes to zero.  If the file has been unlinked, then it must
 * now be truncated.  Also, we clear all of the read-ahead state
 * kept for the inode here since the file is now closed.
 */
int
xfs_inactive(
	xfs_inode_t	*ip)
{
	xfs_bmap_free_t	free_list;
	xfs_fsblock_t	first_block;
	int		committed;
	xfs_trans_t	*tp;
	xfs_mount_t	*mp;
	int		error;
	int		truncate;

	/*
	 * If the inode is already free, then there can be nothing
	 * to clean up here.
	 */
	if (ip->i_d.di_mode == 0 || is_bad_inode(VFS_I(ip))) {
		ASSERT(ip->i_df.if_real_bytes == 0);
		ASSERT(ip->i_df.if_broot_bytes == 0);
		return VN_INACTIVE_CACHE;
	}

	/*
	 * Only do a truncate if it's a regular file with
	 * some actual space in it.  It's OK to look at the
	 * inode's fields without the lock because we're the
	 * only one with a reference to the inode.
	 */
	truncate = ((ip->i_d.di_nlink == 0) &&
	    ((ip->i_d.di_size != 0) || XFS_ISIZE(ip) != 0 ||
	     (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) &&
	    S_ISREG(ip->i_d.di_mode));

	mp = ip->i_mount;

	error = 0;

	/* If this is a read-only mount, don't do this (would generate I/O) */
	if (mp->m_flags & XFS_MOUNT_RDONLY)
		goto out;

	if (ip->i_d.di_nlink != 0) {
		if ((S_ISREG(ip->i_d.di_mode) &&
		    (VFS_I(ip)->i_size > 0 ||
		     (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) &&
		    (ip->i_df.if_flags & XFS_IFEXTENTS) &&
		    (!(ip->i_d.di_flags &
				(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) ||
		     ip->i_delayed_blks != 0))) {
			error = xfs_free_eofblocks(mp, ip, 0);
			if (error)
				return VN_INACTIVE_CACHE;
		}
		goto out;
	}

	ASSERT(ip->i_d.di_nlink == 0);

	error = xfs_qm_dqattach(ip, 0);
	if (error)
		return VN_INACTIVE_CACHE;

	tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
	if (truncate) {
		xfs_ilock(ip, XFS_IOLOCK_EXCL);

		error = xfs_trans_reserve(tp, 0,
					  XFS_ITRUNCATE_LOG_RES(mp),
					  0, XFS_TRANS_PERM_LOG_RES,
					  XFS_ITRUNCATE_LOG_COUNT);
		if (error) {
			/* Don't call itruncate_cleanup */
			ASSERT(XFS_FORCED_SHUTDOWN(mp));
			xfs_trans_cancel(tp, 0);
			xfs_iunlock(ip, XFS_IOLOCK_EXCL);
			return VN_INACTIVE_CACHE;
		}

		xfs_ilock(ip, XFS_ILOCK_EXCL);
		xfs_trans_ijoin(tp, ip, 0);

		ip->i_d.di_size = 0;
		xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);

		error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
		if (error) {
			xfs_trans_cancel(tp,
				XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
			xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
			return VN_INACTIVE_CACHE;
		}

		ASSERT(ip->i_d.di_nextents == 0);
	} else if (S_ISLNK(ip->i_d.di_mode)) {

		/*
		 * If we get an error while cleaning up a
		 * symlink we bail out.
		 */
		error = (ip->i_d.di_size > XFS_IFORK_DSIZE(ip)) ?
			xfs_inactive_symlink_rmt(ip, &tp) :
			xfs_inactive_symlink_local(ip, &tp);

		if (error) {
			ASSERT(tp == NULL);
			return VN_INACTIVE_CACHE;
		}

		xfs_trans_ijoin(tp, ip, 0);
	} else {
		error = xfs_trans_reserve(tp, 0,
					  XFS_IFREE_LOG_RES(mp),
					  0, XFS_TRANS_PERM_LOG_RES,
					  XFS_INACTIVE_LOG_COUNT);
		if (error) {
			ASSERT(XFS_FORCED_SHUTDOWN(mp));
			xfs_trans_cancel(tp, 0);
			return VN_INACTIVE_CACHE;
		}

		xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
		xfs_trans_ijoin(tp, ip, 0);
	}

	/*
	 * If there are attributes associated with the file
	 * then blow them away now.  The code calls a routine
	 * that recursively deconstructs the attribute fork.
	 * We need to just commit the current transaction
	 * because we can't use it for xfs_attr_inactive().
	 */
	if (ip->i_d.di_anextents > 0) {
		error = xfs_inactive_attrs(ip, &tp);
		/*
		 * If we got an error, the transaction is already
		 * cancelled, and the inode is unlocked. Just get out.
		 */
		 if (error)
			 return VN_INACTIVE_CACHE;
	} else if (ip->i_afp) {
		xfs_idestroy_fork(ip, XFS_ATTR_FORK);
	}

	/*
	 * Free the inode.
	 */
	xfs_bmap_init(&free_list, &first_block);
	error = xfs_ifree(tp, ip, &free_list);
	if (error) {
		/*
		 * If we fail to free the inode, shut down.  The cancel
		 * might do that, we need to make sure.  Otherwise the
		 * inode might be lost for a long time or forever.
		 */
		if (!XFS_FORCED_SHUTDOWN(mp)) {
			xfs_notice(mp, "%s: xfs_ifree returned error %d",
				__func__, error);
			xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
		}
		xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
	} else {
		/*
		 * Credit the quota account(s). The inode is gone.
		 */
		xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT, -1);

		/*
		 * Just ignore errors at this point.  There is nothing we can
		 * do except to try to keep going. Make sure it's not a silent
		 * error.
		 */
		error = xfs_bmap_finish(&tp,  &free_list, &committed);
		if (error)
			xfs_notice(mp, "%s: xfs_bmap_finish returned error %d",
				__func__, error);
		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
		if (error)
			xfs_notice(mp, "%s: xfs_trans_commit returned error %d",
				__func__, error);
	}

	/*
	 * Release the dquots held by inode, if any.
	 */
	xfs_qm_dqdetach(ip);
	xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);

 out:
	return VN_INACTIVE_CACHE;
}

/*
 * Lookups up an inode from "name". If ci_name is not NULL, then a CI match
 * is allowed, otherwise it has to be an exact match. If a CI match is found,
 * ci_name->name will point to a the actual name (caller must free) or
 * will be set to NULL if an exact match is found.
 */
int
xfs_lookup(
	xfs_inode_t		*dp,
	struct xfs_name		*name,
	xfs_inode_t		**ipp,
	struct xfs_name		*ci_name)
{
	xfs_ino_t		inum;
	int			error;
	uint			lock_mode;

	trace_xfs_lookup(dp, name);

	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
		return XFS_ERROR(EIO);

	lock_mode = xfs_ilock_map_shared(dp);
	error = xfs_dir_lookup(NULL, dp, name, &inum, ci_name);
	xfs_iunlock_map_shared(dp, lock_mode);

	if (error)
		goto out;

	error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp);
	if (error)
		goto out_free_name;

	return 0;

out_free_name:
	if (ci_name)
		kmem_free(ci_name->name);
out:
	*ipp = NULL;
	return error;
}

int
xfs_create(
	xfs_inode_t		*dp,
	struct xfs_name		*name,
	umode_t			mode,
	xfs_dev_t		rdev,
	xfs_inode_t		**ipp)
{
	int			is_dir = S_ISDIR(mode);
	struct xfs_mount	*mp = dp->i_mount;
	struct xfs_inode	*ip = NULL;
	struct xfs_trans	*tp = NULL;
	int			error;
	xfs_bmap_free_t		free_list;
	xfs_fsblock_t		first_block;
	boolean_t		unlock_dp_on_error = B_FALSE;
	uint			cancel_flags;
	int			committed;
	prid_t			prid;
	struct xfs_dquot	*udqp = NULL;
	struct xfs_dquot	*gdqp = NULL;
	uint			resblks;
	uint			log_res;
	uint			log_count;

	trace_xfs_create(dp, name);

	if (XFS_FORCED_SHUTDOWN(mp))
		return XFS_ERROR(EIO);

	if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
		prid = xfs_get_projid(dp);
	else
		prid = XFS_PROJID_DEFAULT;

	/*
	 * Make sure that we have allocated dquot(s) on disk.
	 */
	error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
	if (error)
		return error;

	if (is_dir) {
		rdev = 0;
		resblks = XFS_MKDIR_SPACE_RES(mp, name->len);
		log_res = XFS_MKDIR_LOG_RES(mp);
		log_count = XFS_MKDIR_LOG_COUNT;
		tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR);
	} else {
		resblks = XFS_CREATE_SPACE_RES(mp, name->len);
		log_res = XFS_CREATE_LOG_RES(mp);
		log_count = XFS_CREATE_LOG_COUNT;
		tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE);
	}

	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;

	/*
	 * Initially assume that the file does not exist and
	 * reserve the resources for that case.  If that is not
	 * the case we'll drop the one we have and get a more
	 * appropriate transaction later.
	 */
	error = xfs_trans_reserve(tp, resblks, log_res, 0,
			XFS_TRANS_PERM_LOG_RES, log_count);
	if (error == ENOSPC) {
		/* flush outstanding delalloc blocks and retry */
		xfs_flush_inodes(dp);
		error = xfs_trans_reserve(tp, resblks, log_res, 0,
				XFS_TRANS_PERM_LOG_RES, log_count);
	}
	if (error == ENOSPC) {
		/* No space at all so try a "no-allocation" reservation */
		resblks = 0;
		error = xfs_trans_reserve(tp, 0, log_res, 0,
				XFS_TRANS_PERM_LOG_RES, log_count);
	}
	if (error) {
		cancel_flags = 0;
		goto out_trans_cancel;
	}

	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
	unlock_dp_on_error = B_TRUE;

	xfs_bmap_init(&free_list, &first_block);

	/*
	 * Reserve disk quota and the inode.
	 */
	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
	if (error)
		goto out_trans_cancel;

	error = xfs_dir_canenter(tp, dp, name, resblks);
	if (error)
		goto out_trans_cancel;

	/*
	 * A newly created regular or special file just has one directory
	 * entry pointing to them, but a directory also the "." entry
	 * pointing to itself.
	 */
	error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev,
			       prid, resblks > 0, &ip, &committed);
	if (error) {
		if (error == ENOSPC)
			goto out_trans_cancel;
		goto out_trans_abort;
	}

	/*
	 * Now we join the directory inode to the transaction.  We do not do it
	 * earlier because xfs_dir_ialloc might commit the previous transaction
	 * (and release all the locks).  An error from here on will result in
	 * the transaction cancel unlocking dp so don't do it explicitly in the
	 * error path.
	 */
	xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
	unlock_dp_on_error = B_FALSE;

	error = xfs_dir_createname(tp, dp, name, ip->i_ino,
					&first_block, &free_list, resblks ?
					resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
	if (error) {
		ASSERT(error != ENOSPC);
		goto out_trans_abort;
	}
	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
	xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);

	if (is_dir) {
		error = xfs_dir_init(tp, ip, dp);
		if (error)
			goto out_bmap_cancel;

		error = xfs_bumplink(tp, dp);
		if (error)
			goto out_bmap_cancel;
	}

	/*
	 * If this is a synchronous mount, make sure that the
	 * create transaction goes to disk before returning to
	 * the user.
	 */
	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
		xfs_trans_set_sync(tp);

	/*
	 * Attach the dquot(s) to the inodes and modify them incore.
	 * These ids of the inode couldn't have changed since the new
	 * inode has been locked ever since it was created.
	 */
	xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);

	error = xfs_bmap_finish(&tp, &free_list, &committed);
	if (error)
		goto out_bmap_cancel;

	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
	if (error)
		goto out_release_inode;

	xfs_qm_dqrele(udqp);
	xfs_qm_dqrele(gdqp);

	*ipp = ip;
	return 0;

 out_bmap_cancel:
	xfs_bmap_cancel(&free_list);
 out_trans_abort:
	cancel_flags |= XFS_TRANS_ABORT;
 out_trans_cancel:
	xfs_trans_cancel(tp, cancel_flags);
 out_release_inode:
	/*
	 * Wait until after the current transaction is aborted to
	 * release the inode.  This prevents recursive transactions
	 * and deadlocks from xfs_inactive.
	 */
	if (ip)
		IRELE(ip);

	xfs_qm_dqrele(udqp);
	xfs_qm_dqrele(gdqp);

	if (unlock_dp_on_error)
		xfs_iunlock(dp, XFS_ILOCK_EXCL);
	return error;
}

#ifdef DEBUG
int xfs_locked_n;
int xfs_small_retries;
int xfs_middle_retries;
int xfs_lots_retries;
int xfs_lock_delays;
#endif

/*
 * Bump the subclass so xfs_lock_inodes() acquires each lock with
 * a different value
 */
static inline int
xfs_lock_inumorder(int lock_mode, int subclass)
{
	if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
		lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_IOLOCK_SHIFT;
	if (lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL))
		lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_ILOCK_SHIFT;

	return lock_mode;
}

/*
 * The following routine will lock n inodes in exclusive mode.
 * We assume the caller calls us with the inodes in i_ino order.
 *
 * We need to detect deadlock where an inode that we lock
 * is in the AIL and we start waiting for another inode that is locked
 * by a thread in a long running transaction (such as truncate). This can
 * result in deadlock since the long running trans might need to wait
 * for the inode we just locked in order to push the tail and free space
 * in the log.
 */
void
xfs_lock_inodes(
	xfs_inode_t	**ips,
	int		inodes,
	uint		lock_mode)
{
	int		attempts = 0, i, j, try_lock;
	xfs_log_item_t	*lp;

	ASSERT(ips && (inodes >= 2)); /* we need at least two */

	try_lock = 0;
	i = 0;

again:
	for (; i < inodes; i++) {
		ASSERT(ips[i]);

		if (i && (ips[i] == ips[i-1]))	/* Already locked */
			continue;

		/*
		 * If try_lock is not set yet, make sure all locked inodes
		 * are not in the AIL.
		 * If any are, set try_lock to be used later.
		 */

		if (!try_lock) {
			for (j = (i - 1); j >= 0 && !try_lock; j--) {
				lp = (xfs_log_item_t *)ips[j]->i_itemp;
				if (lp && (lp->li_flags & XFS_LI_IN_AIL)) {
					try_lock++;
				}
			}
		}

		/*
		 * If any of the previous locks we have locked is in the AIL,
		 * we must TRY to get the second and subsequent locks. If
		 * we can't get any, we must release all we have
		 * and try again.
		 */

		if (try_lock) {
			/* try_lock must be 0 if i is 0. */
			/*
			 * try_lock means we have an inode locked
			 * that is in the AIL.
			 */
			ASSERT(i != 0);
			if (!xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) {
				attempts++;

				/*
				 * Unlock all previous guys and try again.
				 * xfs_iunlock will try to push the tail
				 * if the inode is in the AIL.
				 */

				for(j = i - 1; j >= 0; j--) {

					/*
					 * Check to see if we've already
					 * unlocked this one.
					 * Not the first one going back,
					 * and the inode ptr is the same.
					 */
					if ((j != (i - 1)) && ips[j] ==
								ips[j+1])
						continue;

					xfs_iunlock(ips[j], lock_mode);
				}

				if ((attempts % 5) == 0) {
					delay(1); /* Don't just spin the CPU */
#ifdef DEBUG
					xfs_lock_delays++;
#endif
				}
				i = 0;
				try_lock = 0;
				goto again;
			}
		} else {
			xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i));
		}
	}

#ifdef DEBUG
	if (attempts) {
		if (attempts < 5) xfs_small_retries++;
		else if (attempts < 100) xfs_middle_retries++;
		else xfs_lots_retries++;
	} else {
		xfs_locked_n++;
	}
#endif
}

/*
 * xfs_lock_two_inodes() can only be used to lock one type of lock
 * at a time - the iolock or the ilock, but not both at once. If
 * we lock both at once, lockdep will report false positives saying
 * we have violated locking orders.
 */
void
xfs_lock_two_inodes(
	xfs_inode_t		*ip0,
	xfs_inode_t		*ip1,
	uint			lock_mode)
{
	xfs_inode_t		*temp;
	int			attempts = 0;
	xfs_log_item_t		*lp;

	if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
		ASSERT((lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)) == 0);
	ASSERT(ip0->i_ino != ip1->i_ino);

	if (ip0->i_ino > ip1->i_ino) {
		temp = ip0;
		ip0 = ip1;
		ip1 = temp;
	}

 again:
	xfs_ilock(ip0, xfs_lock_inumorder(lock_mode, 0));

	/*
	 * If the first lock we have locked is in the AIL, we must TRY to get
	 * the second lock. If we can't get it, we must release the first one
	 * and try again.
	 */
	lp = (xfs_log_item_t *)ip0->i_itemp;
	if (lp && (lp->li_flags & XFS_LI_IN_AIL)) {
		if (!xfs_ilock_nowait(ip1, xfs_lock_inumorder(lock_mode, 1))) {
			xfs_iunlock(ip0, lock_mode);
			if ((++attempts % 5) == 0)
				delay(1); /* Don't just spin the CPU */
			goto again;
		}
	} else {
		xfs_ilock(ip1, xfs_lock_inumorder(lock_mode, 1));
	}
}

int
xfs_remove(
	xfs_inode_t             *dp,
	struct xfs_name		*name,
	xfs_inode_t		*ip)
{
	xfs_mount_t		*mp = dp->i_mount;
	xfs_trans_t             *tp = NULL;
	int			is_dir = S_ISDIR(ip->i_d.di_mode);
	int                     error = 0;
	xfs_bmap_free_t         free_list;
	xfs_fsblock_t           first_block;
	int			cancel_flags;
	int			committed;
	int			link_zero;
	uint			resblks;
	uint			log_count;

	trace_xfs_remove(dp, name);

	if (XFS_FORCED_SHUTDOWN(mp))
		return XFS_ERROR(EIO);

	error = xfs_qm_dqattach(dp, 0);
	if (error)
		goto std_return;

	error = xfs_qm_dqattach(ip, 0);
	if (error)
		goto std_return;

	if (is_dir) {
		tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR);
		log_count = XFS_DEFAULT_LOG_COUNT;
	} else {
		tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE);
		log_count = XFS_REMOVE_LOG_COUNT;
	}
	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;

	/*
	 * We try to get the real space reservation first,
	 * allowing for directory btree deletion(s) implying
	 * possible bmap insert(s).  If we can't get the space
	 * reservation then we use 0 instead, and avoid the bmap
	 * btree insert(s) in the directory code by, if the bmap
	 * insert tries to happen, instead trimming the LAST
	 * block from the directory.
	 */
	resblks = XFS_REMOVE_SPACE_RES(mp);
	error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0,
				  XFS_TRANS_PERM_LOG_RES, log_count);
	if (error == ENOSPC) {
		resblks = 0;
		error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0,
					  XFS_TRANS_PERM_LOG_RES, log_count);
	}
	if (error) {
		ASSERT(error != ENOSPC);
		cancel_flags = 0;
		goto out_trans_cancel;
	}

	xfs_lock_two_inodes(dp, ip, XFS_ILOCK_EXCL);

	xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);

	/*
	 * If we're removing a directory perform some additional validation.
	 */
	if (is_dir) {
		ASSERT(ip->i_d.di_nlink >= 2);
		if (ip->i_d.di_nlink != 2) {
			error = XFS_ERROR(ENOTEMPTY);
			goto out_trans_cancel;
		}
		if (!xfs_dir_isempty(ip)) {
			error = XFS_ERROR(ENOTEMPTY);
			goto out_trans_cancel;
		}
	}

	xfs_bmap_init(&free_list, &first_block);
	error = xfs_dir_removename(tp, dp, name, ip->i_ino,
					&first_block, &free_list, resblks);
	if (error) {
		ASSERT(error != ENOENT);
		goto out_bmap_cancel;
	}
	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);

	if (is_dir) {
		/*
		 * Drop the link from ip's "..".
		 */
		error = xfs_droplink(tp, dp);
		if (error)
			goto out_bmap_cancel;

		/*
		 * Drop the "." link from ip to self.
		 */
		error = xfs_droplink(tp, ip);
		if (error)
			goto out_bmap_cancel;
	} else {
		/*
		 * When removing a non-directory we need to log the parent
		 * inode here.  For a directory this is done implicitly
		 * by the xfs_droplink call for the ".." entry.
		 */
		xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
	}

	/*
	 * Drop the link from dp to ip.
	 */
	error = xfs_droplink(tp, ip);
	if (error)
		goto out_bmap_cancel;

	/*
	 * Determine if this is the last link while
	 * we are in the transaction.
	 */
	link_zero = (ip->i_d.di_nlink == 0);

	/*
	 * If this is a synchronous mount, make sure that the
	 * remove transaction goes to disk before returning to
	 * the user.
	 */
	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
		xfs_trans_set_sync(tp);

	error = xfs_bmap_finish(&tp, &free_list, &committed);
	if (error)
		goto out_bmap_cancel;

	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
	if (error)
		goto std_return;

	/*
	 * If we are using filestreams, kill the stream association.
	 * If the file is still open it may get a new one but that
	 * will get killed on last close in xfs_close() so we don't
	 * have to worry about that.
	 */
	if (!is_dir && link_zero && xfs_inode_is_filestream(ip))
		xfs_filestream_deassociate(ip);

	return 0;

 out_bmap_cancel:
	xfs_bmap_cancel(&free_list);
	cancel_flags |= XFS_TRANS_ABORT;
 out_trans_cancel:
	xfs_trans_cancel(tp, cancel_flags);
 std_return:
	return error;
}

int
xfs_link(
	xfs_inode_t		*tdp,
	xfs_inode_t		*sip,
	struct xfs_name		*target_name)
{
	xfs_mount_t		*mp = tdp->i_mount;
	xfs_trans_t		*tp;
	int			error;
	xfs_bmap_free_t         free_list;
	xfs_fsblock_t           first_block;
	int			cancel_flags;
	int			committed;
	int			resblks;

	trace_xfs_link(tdp, target_name);

	ASSERT(!S_ISDIR(sip->i_d.di_mode));

	if (XFS_FORCED_SHUTDOWN(mp))
		return XFS_ERROR(EIO);

	error = xfs_qm_dqattach(sip, 0);
	if (error)
		goto std_return;

	error = xfs_qm_dqattach(tdp, 0);
	if (error)
		goto std_return;

	tp = xfs_trans_alloc(mp, XFS_TRANS_LINK);
	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
	resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
	error = xfs_trans_reserve(tp, resblks, XFS_LINK_LOG_RES(mp), 0,
			XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT);
	if (error == ENOSPC) {
		resblks = 0;
		error = xfs_trans_reserve(tp, 0, XFS_LINK_LOG_RES(mp), 0,
				XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT);
	}
	if (error) {
		cancel_flags = 0;
		goto error_return;
	}

	xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL);

	xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);

	/*
	 * If we are using project inheritance, we only allow hard link
	 * creation in our tree when the project IDs are the same; else
	 * the tree quota mechanism could be circumvented.
	 */
	if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
		     (xfs_get_projid(tdp) != xfs_get_projid(sip)))) {
		error = XFS_ERROR(EXDEV);
		goto error_return;
	}

	error = xfs_dir_canenter(tp, tdp, target_name, resblks);
	if (error)
		goto error_return;

	xfs_bmap_init(&free_list, &first_block);

	error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
					&first_block, &free_list, resblks);
	if (error)
		goto abort_return;
	xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
	xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);

	error = xfs_bumplink(tp, sip);
	if (error)
		goto abort_return;

	/*
	 * If this is a synchronous mount, make sure that the
	 * link transaction goes to disk before returning to
	 * the user.
	 */
	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
		xfs_trans_set_sync(tp);
	}

	error = xfs_bmap_finish (&tp, &free_list, &committed);
	if (error) {
		xfs_bmap_cancel(&free_list);
		goto abort_return;
	}

	return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);

 abort_return:
	cancel_flags |= XFS_TRANS_ABORT;
 error_return:
	xfs_trans_cancel(tp, cancel_flags);
 std_return:
	return error;
}

int
xfs_symlink(
	xfs_inode_t		*dp,
	struct xfs_name		*link_name,
	const char		*target_path,
	umode_t			mode,
	xfs_inode_t		**ipp)
{
	xfs_mount_t		*mp = dp->i_mount;
	xfs_trans_t		*tp;
	xfs_inode_t		*ip;
	int			error;
	int			pathlen;
	xfs_bmap_free_t		free_list;
	xfs_fsblock_t		first_block;
	boolean_t		unlock_dp_on_error = B_FALSE;
	uint			cancel_flags;
	int			committed;
	xfs_fileoff_t		first_fsb;
	xfs_filblks_t		fs_blocks;
	int			nmaps;
	xfs_bmbt_irec_t		mval[SYMLINK_MAPS];
	xfs_daddr_t		d;
	const char		*cur_chunk;
	int			byte_cnt;
	int			n;
	xfs_buf_t		*bp;
	prid_t			prid;
	struct xfs_dquot	*udqp, *gdqp;
	uint			resblks;

	*ipp = NULL;
	error = 0;
	ip = NULL;
	tp = NULL;

	trace_xfs_symlink(dp, link_name);

	if (XFS_FORCED_SHUTDOWN(mp))
		return XFS_ERROR(EIO);

	/*
	 * Check component lengths of the target path name.
	 */
	pathlen = strlen(target_path);
	if (pathlen >= MAXPATHLEN)      /* total string too long */
		return XFS_ERROR(ENAMETOOLONG);

	udqp = gdqp = NULL;
	if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
		prid = xfs_get_projid(dp);
	else
		prid = XFS_PROJID_DEFAULT;

	/*
	 * Make sure that we have allocated dquot(s) on disk.
	 */
	error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
			XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
	if (error)
		goto std_return;

	tp = xfs_trans_alloc(mp, XFS_TRANS_SYMLINK);
	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
	/*
	 * The symlink will fit into the inode data fork?
	 * There can't be any attributes so we get the whole variable part.
	 */
	if (pathlen <= XFS_LITINO(mp))
		fs_blocks = 0;
	else
		fs_blocks = XFS_B_TO_FSB(mp, pathlen);
	resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks);
	error = xfs_trans_reserve(tp, resblks, XFS_SYMLINK_LOG_RES(mp), 0,
			XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT);
	if (error == ENOSPC && fs_blocks == 0) {
		resblks = 0;
		error = xfs_trans_reserve(tp, 0, XFS_SYMLINK_LOG_RES(mp), 0,
				XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT);
	}
	if (error) {
		cancel_flags = 0;
		goto error_return;
	}

	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
	unlock_dp_on_error = B_TRUE;

	/*
	 * Check whether the directory allows new symlinks or not.
	 */
	if (dp->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) {
		error = XFS_ERROR(EPERM);
		goto error_return;
	}

	/*
	 * Reserve disk quota : blocks and inode.
	 */
	error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, resblks, 1, 0);
	if (error)
		goto error_return;

	/*
	 * Check for ability to enter directory entry, if no space reserved.
	 */
	error = xfs_dir_canenter(tp, dp, link_name, resblks);
	if (error)
		goto error_return;
	/*
	 * Initialize the bmap freelist prior to calling either
	 * bmapi or the directory create code.
	 */
	xfs_bmap_init(&free_list, &first_block);

	/*
	 * Allocate an inode for the symlink.
	 */
	error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), 1, 0,
			       prid, resblks > 0, &ip, NULL);
	if (error) {
		if (error == ENOSPC)
			goto error_return;
		goto error1;
	}

	/*
	 * An error after we've joined dp to the transaction will result in the
	 * transaction cancel unlocking dp so don't do it explicitly in the
	 * error path.
	 */
	xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
	unlock_dp_on_error = B_FALSE;

	/*
	 * Also attach the dquot(s) to it, if applicable.
	 */
	xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);

	if (resblks)
		resblks -= XFS_IALLOC_SPACE_RES(mp);
	/*
	 * If the symlink will fit into the inode, write it inline.
	 */
	if (pathlen <= XFS_IFORK_DSIZE(ip)) {
		xfs_idata_realloc(ip, pathlen, XFS_DATA_FORK);
		memcpy(ip->i_df.if_u1.if_data, target_path, pathlen);
		ip->i_d.di_size = pathlen;

		/*
		 * The inode was initially created in extent format.
		 */
		ip->i_df.if_flags &= ~(XFS_IFEXTENTS | XFS_IFBROOT);
		ip->i_df.if_flags |= XFS_IFINLINE;

		ip->i_d.di_format = XFS_DINODE_FMT_LOCAL;
		xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE);

	} else {
		first_fsb = 0;
		nmaps = SYMLINK_MAPS;

		error = xfs_bmapi_write(tp, ip, first_fsb, fs_blocks,
				  XFS_BMAPI_METADATA, &first_block, resblks,
				  mval, &nmaps, &free_list);
		if (error)
			goto error2;

		if (resblks)
			resblks -= fs_blocks;
		ip->i_d.di_size = pathlen;
		xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);

		cur_chunk = target_path;
		for (n = 0; n < nmaps; n++) {
			d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
			byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
			bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
					       BTOBB(byte_cnt), 0);
			if (!bp) {
				error = ENOMEM;
				goto error2;
			}
			if (pathlen < byte_cnt) {
				byte_cnt = pathlen;
			}
			pathlen -= byte_cnt;

			memcpy(bp->b_addr, cur_chunk, byte_cnt);
			cur_chunk += byte_cnt;

			xfs_trans_log_buf(tp, bp, 0, byte_cnt - 1);
		}
	}

	/*
	 * Create the directory entry for the symlink.
	 */
	error = xfs_dir_createname(tp, dp, link_name, ip->i_ino,
					&first_block, &free_list, resblks);
	if (error)
		goto error2;
	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
	xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);

	/*
	 * If this is a synchronous mount, make sure that the
	 * symlink transaction goes to disk before returning to
	 * the user.
	 */
	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
		xfs_trans_set_sync(tp);
	}

	error = xfs_bmap_finish(&tp, &free_list, &committed);
	if (error) {
		goto error2;
	}
	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
	xfs_qm_dqrele(udqp);
	xfs_qm_dqrele(gdqp);

	*ipp = ip;
	return 0;

 error2:
	IRELE(ip);
 error1:
	xfs_bmap_cancel(&free_list);
	cancel_flags |= XFS_TRANS_ABORT;
 error_return:
	xfs_trans_cancel(tp, cancel_flags);
	xfs_qm_dqrele(udqp);
	xfs_qm_dqrele(gdqp);

	if (unlock_dp_on_error)
		xfs_iunlock(dp, XFS_ILOCK_EXCL);
 std_return:
	return error;
}

int
xfs_set_dmattrs(
	xfs_inode_t     *ip,
	u_int		evmask,
	u_int16_t	state)
{
	xfs_mount_t	*mp = ip->i_mount;
	xfs_trans_t	*tp;
	int		error;

	if (!capable(CAP_SYS_ADMIN))
		return XFS_ERROR(EPERM);

	if (XFS_FORCED_SHUTDOWN(mp))
		return XFS_ERROR(EIO);

	tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS);
	error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES (mp), 0, 0, 0);
	if (error) {
		xfs_trans_cancel(tp, 0);
		return error;
	}
	xfs_ilock(ip, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);

	ip->i_d.di_dmevmask = evmask;
	ip->i_d.di_dmstate  = state;

	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
	error = xfs_trans_commit(tp, 0);

	return error;
}

/*
 * xfs_alloc_file_space()
 *      This routine allocates disk space for the given file.
 *
 *	If alloc_type == 0, this request is for an ALLOCSP type
 *	request which will change the file size.  In this case, no
 *	DMAPI event will be generated by the call.  A TRUNCATE event
 *	will be generated later by xfs_setattr.
 *
 *	If alloc_type != 0, this request is for a RESVSP type
 *	request, and a DMAPI DM_EVENT_WRITE will be generated if the
 *	lower block boundary byte address is less than the file's
 *	length.
 *
 * RETURNS:
 *       0 on success
 *      errno on error
 *
 */
STATIC int
xfs_alloc_file_space(
	xfs_inode_t		*ip,
	xfs_off_t		offset,
	xfs_off_t		len,
	int			alloc_type,
	int			attr_flags)
{
	xfs_mount_t		*mp = ip->i_mount;
	xfs_off_t		count;
	xfs_filblks_t		allocated_fsb;
	xfs_filblks_t		allocatesize_fsb;
	xfs_extlen_t		extsz, temp;
	xfs_fileoff_t		startoffset_fsb;
	xfs_fsblock_t		firstfsb;
	int			nimaps;
	int			quota_flag;
	int			rt;
	xfs_trans_t		*tp;
	xfs_bmbt_irec_t		imaps[1], *imapp;
	xfs_bmap_free_t		free_list;
	uint			qblocks, resblks, resrtextents;
	int			committed;
	int			error;

	trace_xfs_alloc_file_space(ip);

	if (XFS_FORCED_SHUTDOWN(mp))
		return XFS_ERROR(EIO);

	error = xfs_qm_dqattach(ip, 0);
	if (error)
		return error;

	if (len <= 0)
		return XFS_ERROR(EINVAL);

	rt = XFS_IS_REALTIME_INODE(ip);
	extsz = xfs_get_extsz_hint(ip);

	count = len;
	imapp = &imaps[0];
	nimaps = 1;
	startoffset_fsb	= XFS_B_TO_FSBT(mp, offset);
	allocatesize_fsb = XFS_B_TO_FSB(mp, count);

	/*
	 * Allocate file space until done or until there is an error
	 */
	while (allocatesize_fsb && !error) {
		xfs_fileoff_t	s, e;

		/*
		 * Determine space reservations for data/realtime.
		 */
		if (unlikely(extsz)) {
			s = startoffset_fsb;
			do_div(s, extsz);
			s *= extsz;
			e = startoffset_fsb + allocatesize_fsb;
			if ((temp = do_mod(startoffset_fsb, extsz)))
				e += temp;
			if ((temp = do_mod(e, extsz)))
				e += extsz - temp;
		} else {
			s = 0;
			e = allocatesize_fsb;
		}

		/*
		 * The transaction reservation is limited to a 32-bit block
		 * count, hence we need to limit the number of blocks we are
		 * trying to reserve to avoid an overflow. We can't allocate
		 * more than @nimaps extents, and an extent is limited on disk
		 * to MAXEXTLEN (21 bits), so use that to enforce the limit.
		 */
		resblks = min_t(xfs_fileoff_t, (e - s), (MAXEXTLEN * nimaps));
		if (unlikely(rt)) {
			resrtextents = qblocks = resblks;
			resrtextents /= mp->m_sb.sb_rextsize;
			resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
			quota_flag = XFS_QMOPT_RES_RTBLKS;
		} else {
			resrtextents = 0;
			resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resblks);
			quota_flag = XFS_QMOPT_RES_REGBLKS;
		}

		/*
		 * Allocate and setup the transaction.
		 */
		tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
		error = xfs_trans_reserve(tp, resblks,
					  XFS_WRITE_LOG_RES(mp), resrtextents,
					  XFS_TRANS_PERM_LOG_RES,
					  XFS_WRITE_LOG_COUNT);
		/*
		 * Check for running out of space
		 */
		if (error) {
			/*
			 * Free the transaction structure.
			 */
			ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp));
			xfs_trans_cancel(tp, 0);
			break;
		}
		xfs_ilock(ip, XFS_ILOCK_EXCL);
		error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks,
						      0, quota_flag);
		if (error)
			goto error1;

		xfs_trans_ijoin(tp, ip, 0);

		xfs_bmap_init(&free_list, &firstfsb);
		error = xfs_bmapi_write(tp, ip, startoffset_fsb,
					allocatesize_fsb, alloc_type, &firstfsb,
					0, imapp, &nimaps, &free_list);
		if (error) {
			goto error0;
		}

		/*
		 * Complete the transaction
		 */
		error = xfs_bmap_finish(&tp, &free_list, &committed);
		if (error) {
			goto error0;
		}

		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
		xfs_iunlock(ip, XFS_ILOCK_EXCL);
		if (error) {
			break;
		}

		allocated_fsb = imapp->br_blockcount;

		if (nimaps == 0) {
			error = XFS_ERROR(ENOSPC);
			break;
		}

		startoffset_fsb += allocated_fsb;
		allocatesize_fsb -= allocated_fsb;
	}

	return error;

error0:	/* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
	xfs_bmap_cancel(&free_list);
	xfs_trans_unreserve_quota_nblks(tp, ip, (long)qblocks, 0, quota_flag);

error1:	/* Just cancel transaction */
	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
	xfs_iunlock(ip, XFS_ILOCK_EXCL);
	return error;
}

/*
 * Zero file bytes between startoff and endoff inclusive.
 * The iolock is held exclusive and no blocks are buffered.
 *
 * This function is used by xfs_free_file_space() to zero
 * partial blocks when the range to free is not block aligned.
 * When unreserving space with boundaries that are not block
 * aligned we round up the start and round down the end
 * boundaries and then use this function to zero the parts of
 * the blocks that got dropped during the rounding.
 */
STATIC int
xfs_zero_remaining_bytes(
	xfs_inode_t		*ip,
	xfs_off_t		startoff,
	xfs_off_t		endoff)
{
	xfs_bmbt_irec_t		imap;
	xfs_fileoff_t		offset_fsb;
	xfs_off_t		lastoffset;
	xfs_off_t		offset;
	xfs_buf_t		*bp;
	xfs_mount_t		*mp = ip->i_mount;
	int			nimap;
	int			error = 0;

	/*
	 * Avoid doing I/O beyond eof - it's not necessary
	 * since nothing can read beyond eof.  The space will
	 * be zeroed when the file is extended anyway.
	 */
	if (startoff >= XFS_ISIZE(ip))
		return 0;

	if (endoff > XFS_ISIZE(ip))
		endoff = XFS_ISIZE(ip);

	bp = xfs_buf_get_uncached(XFS_IS_REALTIME_INODE(ip) ?
					mp->m_rtdev_targp : mp->m_ddev_targp,
				  BTOBB(mp->m_sb.sb_blocksize), 0);
	if (!bp)
		return XFS_ERROR(ENOMEM);

	xfs_buf_unlock(bp);

	for (offset = startoff; offset <= endoff; offset = lastoffset + 1) {
		offset_fsb = XFS_B_TO_FSBT(mp, offset);
		nimap = 1;
		error = xfs_bmapi_read(ip, offset_fsb, 1, &imap, &nimap, 0);
		if (error || nimap < 1)
			break;
		ASSERT(imap.br_blockcount >= 1);
		ASSERT(imap.br_startoff == offset_fsb);
		lastoffset = XFS_FSB_TO_B(mp, imap.br_startoff + 1) - 1;
		if (lastoffset > endoff)
			lastoffset = endoff;
		if (imap.br_startblock == HOLESTARTBLOCK)
			continue;
		ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
		if (imap.br_state == XFS_EXT_UNWRITTEN)
			continue;
		XFS_BUF_UNDONE(bp);
		XFS_BUF_UNWRITE(bp);
		XFS_BUF_READ(bp);
		XFS_BUF_SET_ADDR(bp, xfs_fsb_to_db(ip, imap.br_startblock));
		xfsbdstrat(mp, bp);
		error = xfs_buf_iowait(bp);
		if (error) {
			xfs_buf_ioerror_alert(bp,
					"xfs_zero_remaining_bytes(read)");
			break;
		}
		memset(bp->b_addr +
			(offset - XFS_FSB_TO_B(mp, imap.br_startoff)),
		      0, lastoffset - offset + 1);
		XFS_BUF_UNDONE(bp);
		XFS_BUF_UNREAD(bp);
		XFS_BUF_WRITE(bp);
		xfsbdstrat(mp, bp);
		error = xfs_buf_iowait(bp);
		if (error) {
			xfs_buf_ioerror_alert(bp,
					"xfs_zero_remaining_bytes(write)");
			break;
		}
	}
	xfs_buf_free(bp);
	return error;
}

/*
 * xfs_free_file_space()
 *      This routine frees disk space for the given file.
 *
 *	This routine is only called by xfs_change_file_space
 *	for an UNRESVSP type call.
 *
 * RETURNS:
 *       0 on success
 *      errno on error
 *
 */
STATIC int
xfs_free_file_space(
	xfs_inode_t		*ip,
	xfs_off_t		offset,
	xfs_off_t		len,
	int			attr_flags)
{
	int			committed;
	int			done;
	xfs_fileoff_t		endoffset_fsb;
	int			error;
	xfs_fsblock_t		firstfsb;
	xfs_bmap_free_t		free_list;
	xfs_bmbt_irec_t		imap;
	xfs_off_t		ioffset;
	xfs_extlen_t		mod=0;
	xfs_mount_t		*mp;
	int			nimap;
	uint			resblks;
	uint			rounding;
	int			rt;
	xfs_fileoff_t		startoffset_fsb;
	xfs_trans_t		*tp;
	int			need_iolock = 1;

	mp = ip->i_mount;

	trace_xfs_free_file_space(ip);

	error = xfs_qm_dqattach(ip, 0);
	if (error)
		return error;

	error = 0;
	if (len <= 0)	/* if nothing being freed */
		return error;
	rt = XFS_IS_REALTIME_INODE(ip);
	startoffset_fsb	= XFS_B_TO_FSB(mp, offset);
	endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len);

	if (attr_flags & XFS_ATTR_NOLOCK)
		need_iolock = 0;
	if (need_iolock) {
		xfs_ilock(ip, XFS_IOLOCK_EXCL);
		/* wait for the completion of any pending DIOs */
		inode_dio_wait(VFS_I(ip));
	}

	rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE);
	ioffset = offset & ~(rounding - 1);

	if (VN_CACHED(VFS_I(ip)) != 0) {
		error = xfs_flushinval_pages(ip, ioffset, -1, FI_REMAPF_LOCKED);
		if (error)
			goto out_unlock_iolock;
	}

	/*
	 * Need to zero the stuff we're not freeing, on disk.
	 * If it's a realtime file & can't use unwritten extents then we
	 * actually need to zero the extent edges.  Otherwise xfs_bunmapi
	 * will take care of it for us.
	 */
	if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) {
		nimap = 1;
		error = xfs_bmapi_read(ip, startoffset_fsb, 1,
					&imap, &nimap, 0);
		if (error)
			goto out_unlock_iolock;
		ASSERT(nimap == 0 || nimap == 1);
		if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
			xfs_daddr_t	block;

			ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
			block = imap.br_startblock;
			mod = do_div(block, mp->m_sb.sb_rextsize);
			if (mod)
				startoffset_fsb += mp->m_sb.sb_rextsize - mod;
		}
		nimap = 1;
		error = xfs_bmapi_read(ip, endoffset_fsb - 1, 1,
					&imap, &nimap, 0);
		if (error)
			goto out_unlock_iolock;
		ASSERT(nimap == 0 || nimap == 1);
		if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
			ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
			mod++;
			if (mod && (mod != mp->m_sb.sb_rextsize))
				endoffset_fsb -= mod;
		}
	}
	if ((done = (endoffset_fsb <= startoffset_fsb)))
		/*
		 * One contiguous piece to clear
		 */
		error = xfs_zero_remaining_bytes(ip, offset, offset + len - 1);
	else {
		/*
		 * Some full blocks, possibly two pieces to clear
		 */
		if (offset < XFS_FSB_TO_B(mp, startoffset_fsb))
			error = xfs_zero_remaining_bytes(ip, offset,
				XFS_FSB_TO_B(mp, startoffset_fsb) - 1);
		if (!error &&
		    XFS_FSB_TO_B(mp, endoffset_fsb) < offset + len)
			error = xfs_zero_remaining_bytes(ip,
				XFS_FSB_TO_B(mp, endoffset_fsb),
				offset + len - 1);
	}

	/*
	 * free file space until done or until there is an error
	 */
	resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
	while (!error && !done) {

		/*
		 * allocate and setup the transaction. Allow this
		 * transaction to dip into the reserve blocks to ensure
		 * the freeing of the space succeeds at ENOSPC.
		 */
		tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
		tp->t_flags |= XFS_TRANS_RESERVE;
		error = xfs_trans_reserve(tp,
					  resblks,
					  XFS_WRITE_LOG_RES(mp),
					  0,
					  XFS_TRANS_PERM_LOG_RES,
					  XFS_WRITE_LOG_COUNT);

		/*
		 * check for running out of space
		 */
		if (error) {
			/*
			 * Free the transaction structure.
			 */
			ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp));
			xfs_trans_cancel(tp, 0);
			break;
		}
		xfs_ilock(ip, XFS_ILOCK_EXCL);
		error = xfs_trans_reserve_quota(tp, mp,
				ip->i_udquot, ip->i_gdquot,
				resblks, 0, XFS_QMOPT_RES_REGBLKS);
		if (error)
			goto error1;

		xfs_trans_ijoin(tp, ip, 0);

		/*
		 * issue the bunmapi() call to free the blocks
		 */
		xfs_bmap_init(&free_list, &firstfsb);
		error = xfs_bunmapi(tp, ip, startoffset_fsb,
				  endoffset_fsb - startoffset_fsb,
				  0, 2, &firstfsb, &free_list, &done);
		if (error) {
			goto error0;
		}

		/*
		 * complete the transaction
		 */
		error = xfs_bmap_finish(&tp, &free_list, &committed);
		if (error) {
			goto error0;
		}

		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
		xfs_iunlock(ip, XFS_ILOCK_EXCL);
	}

 out_unlock_iolock:
	if (need_iolock)
		xfs_iunlock(ip, XFS_IOLOCK_EXCL);
	return error;

 error0:
	xfs_bmap_cancel(&free_list);
 error1:
	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
	xfs_iunlock(ip, need_iolock ? (XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL) :
		    XFS_ILOCK_EXCL);
	return error;
}

/*
 * xfs_change_file_space()
 *      This routine allocates or frees disk space for the given file.
 *      The user specified parameters are checked for alignment and size
 *      limitations.
 *
 * RETURNS:
 *       0 on success
 *      errno on error
 *
 */
int
xfs_change_file_space(
	xfs_inode_t	*ip,
	int		cmd,
	xfs_flock64_t	*bf,
	xfs_off_t	offset,
	int		attr_flags)
{
	xfs_mount_t	*mp = ip->i_mount;
	int		clrprealloc;
	int		error;
	xfs_fsize_t	fsize;
	int		setprealloc;
	xfs_off_t	startoffset;
	xfs_off_t	llen;
	xfs_trans_t	*tp;
	struct iattr	iattr;
	int		prealloc_type;

	if (!S_ISREG(ip->i_d.di_mode))
		return XFS_ERROR(EINVAL);

	switch (bf->l_whence) {
	case 0: /*SEEK_SET*/
		break;
	case 1: /*SEEK_CUR*/
		bf->l_start += offset;
		break;
	case 2: /*SEEK_END*/
		bf->l_start += XFS_ISIZE(ip);
		break;
	default:
		return XFS_ERROR(EINVAL);
	}

	llen = bf->l_len > 0 ? bf->l_len - 1 : bf->l_len;

	if (   (bf->l_start < 0)
	    || (bf->l_start > XFS_MAXIOFFSET(mp))
	    || (bf->l_start + llen < 0)
	    || (bf->l_start + llen > XFS_MAXIOFFSET(mp)))
		return XFS_ERROR(EINVAL);

	bf->l_whence = 0;

	startoffset = bf->l_start;
	fsize = XFS_ISIZE(ip);

	/*
	 * XFS_IOC_RESVSP and XFS_IOC_UNRESVSP will reserve or unreserve
	 * file space.
	 * These calls do NOT zero the data space allocated to the file,
	 * nor do they change the file size.
	 *
	 * XFS_IOC_ALLOCSP and XFS_IOC_FREESP will allocate and free file
	 * space.
	 * These calls cause the new file data to be zeroed and the file
	 * size to be changed.
	 */
	setprealloc = clrprealloc = 0;
	prealloc_type = XFS_BMAPI_PREALLOC;

	switch (cmd) {
	case XFS_IOC_ZERO_RANGE:
		prealloc_type |= XFS_BMAPI_CONVERT;
		xfs_tosspages(ip, startoffset, startoffset + bf->l_len, 0);
		/* FALLTHRU */
	case XFS_IOC_RESVSP:
	case XFS_IOC_RESVSP64:
		error = xfs_alloc_file_space(ip, startoffset, bf->l_len,
						prealloc_type, attr_flags);
		if (error)
			return error;
		setprealloc = 1;
		break;

	case XFS_IOC_UNRESVSP:
	case XFS_IOC_UNRESVSP64:
		if ((error = xfs_free_file_space(ip, startoffset, bf->l_len,
								attr_flags)))
			return error;
		break;

	case XFS_IOC_ALLOCSP:
	case XFS_IOC_ALLOCSP64:
	case XFS_IOC_FREESP:
	case XFS_IOC_FREESP64:
		/*
		 * These operations actually do IO when extending the file, but
		 * the allocation is done seperately to the zeroing that is
		 * done. This set of operations need to be serialised against
		 * other IO operations, such as truncate and buffered IO. We
		 * need to take the IOLOCK here to serialise the allocation and
		 * zeroing IO to prevent other IOLOCK holders (e.g. getbmap,
		 * truncate, direct IO) from racing against the transient
		 * allocated but not written state we can have here.
		 */
		xfs_ilock(ip, XFS_IOLOCK_EXCL);
		if (startoffset > fsize) {
			error = xfs_alloc_file_space(ip, fsize,
					startoffset - fsize, 0,
					attr_flags | XFS_ATTR_NOLOCK);
			if (error) {
				xfs_iunlock(ip, XFS_IOLOCK_EXCL);
				break;
			}
		}

		iattr.ia_valid = ATTR_SIZE;
		iattr.ia_size = startoffset;

		error = xfs_setattr_size(ip, &iattr,
					 attr_flags | XFS_ATTR_NOLOCK);
		xfs_iunlock(ip, XFS_IOLOCK_EXCL);

		if (error)
			return error;

		clrprealloc = 1;
		break;

	default:
		ASSERT(0);
		return XFS_ERROR(EINVAL);
	}

	/*
	 * update the inode timestamp, mode, and prealloc flag bits
	 */
	tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID);

	if ((error = xfs_trans_reserve(tp, 0, XFS_WRITEID_LOG_RES(mp),
				      0, 0, 0))) {
		/* ASSERT(0); */
		xfs_trans_cancel(tp, 0);
		return error;
	}

	xfs_ilock(ip, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);

	if ((attr_flags & XFS_ATTR_DMI) == 0) {
		ip->i_d.di_mode &= ~S_ISUID;

		/*
		 * Note that we don't have to worry about mandatory
		 * file locking being disabled here because we only
		 * clear the S_ISGID bit if the Group execute bit is
		 * on, but if it was on then mandatory locking wouldn't
		 * have been enabled.
		 */
		if (ip->i_d.di_mode & S_IXGRP)
			ip->i_d.di_mode &= ~S_ISGID;

		xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
	}
	if (setprealloc)
		ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;
	else if (clrprealloc)
		ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC;

	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
	if (attr_flags & XFS_ATTR_SYNC)
		xfs_trans_set_sync(tp);
	return xfs_trans_commit(tp, 0);
}


text:
German Swiss International School Accra (GSIS-Accra or ) is a German-Swiss international school in Accra, Ghana. It serves elementary and junior high school levels.

History
In 1966, the RMS Swiss School, meaning Ramseyer Memorial opened in Accra with two teachers and 23 students. The school became jointly sponsored by Germany and Switzerland and uses a bilingual German–English programme.

Demographics
As of 2007, almost all of the colored children came from mixed families, and only one student was 100% Ghanaian.

In 2009, the school had 75 students.

As of 2013, the school had 90 students originating from 13 countries in years nursery through 10 (age 15), and 15 teachers.

See also

 Education in Ghana
 List of schools in Ghana

References

Further reading
 "Deutsche Schule Accra empfängt Botschafter und erhält PASCH-Plakette." Federal Office of Administration. 21 February 2014.
 Schweizerschule Akkra / RMS Swiss School Accra - EAD, Swiss National Library

External links
  , the school's official website
 German Swiss International School English site (Archive)

1966 establishments in Ghana
Educational institutions established in 1966
Elementary and primary schools in Ghana
German international schools in Africa
International schools in Ghana
Schools in Accra
Swiss international schools
High schools and secondary schools in Ghana
International high schools

redpajama_set_name: RedPajamaWikipedia


The Park Foundation has a big heart and focus on youth and especially those who may be under privileged or at risk. Youth today battle so many societal and peer pressures along with the trends of today of attempting to get them more active and living a healthy lifestyle both physically and mentally. Studies have proven that accessibility to facilities and programs during idle times drastically increase their ability to lead happy and productive lives and make good decisions.
Over the years the Foundation has annually supported the I-Compete Program in coordination with the Partners for Our Communities (POC). The goal of the I-Compete program is to stimulate and encourage interest in this way of life, introduce various skill development opportunities, nurture, coach and open doors to structured and competitive programs. I-Compete program concentrates its efforts on the youth within the northeast quadrant of Palatine and facilitates numerous programs and services such as summer camp, trips, events and after school structure. The base of the program is hosted at the Falcon Park Recreation Community Center. To date it is estimated that 55,000 youth have participated in the I-Compete Program and the Foundation over this same time has contributed more than $21,000 to create these opportunities.


text:
package net.metainf.asm.util;

import java.util.HashSet;
import java.util.Set;

public class StringUtil {

    public static String getPackage(String className) {
        int n = className.lastIndexOf('.');
        if (n > -1) {
            className = className.substring(0, n);
        }
        return className;
    }

    public static Set<String> getPackages(Set<String> classSet) {
        Set<String> packageSet = new HashSet<String>(classSet.size());
        for (String clazz : classSet) {
            packageSet.add(getPackage(clazz));
        }
        return packageSet;
    }

}

redpajama_set_name: RedPajamaGithub


text:
Пульниково — упразднённый в апреле 2020 года посёлок, находившийся в Талицком городском округе Свердловской области, Россия.

Географическое положение
Пульниково располагалось к северо-западу от города Талицы, на водоразделе рек Куяр и Юрмыч (левые притоки Пышмы). В 2 километрах к северу от бывшего посёлка проходит Сибирский тракт, а в самом посёлке ранее находился остановочный пункт Пульниково Свердловской железной дороги.

История
В марте 2020 года был внесён законопроект об упразднении посёлка. Законопроект внесла в заксобрание дума Талицкого городского округа. В пояснительной записке говорится, что в посёлке Пульниково нет ни постоянно проживающего населения, ни жилых, ни административных и хозяйственных построек, нет социальной, транспортной и иной инфраструктуры. Упразднён областным законом № 33-ОЗ от 25 марта 2020.

Население

Примечания

Литература

Упразднённые населённые пункты Талицкого городского округа


text:
Avian influenza in humans - Facts and figures - Data as of 29 July 2010
News announcement30 July 2010Directorate-General for Health and Food Safety
Links between human and avian influenza
Influenza viruses are classified as types A, B and C, and they are found in various birds and mammals, including humans. In addition to man, influenza A viruses cause natural infections in birds while influenza B and C types usually affect humans. Influenza A viruses are also frequently isolated from pigs and horses. Wild birds are thought to be the reservoir of influenza A viruses.
Avian Influenza (AI) is a serious disease of poultry occuring more and more frequently all over the world. The recent spread in bird populations in Asia is unprecedented. Two groups of viruses are recognised on the basis of their ability to cause disease in poultry: Highly Pathogenic Avian Influenza (HPAI) and Low Pathogenic Avian Influenza (LPAI).
Learn more about HPAI and LPAI on the Animal Health and Welfare Website
Influenza A viruses have a segmented genome allowing for genetic re-assortment. As a result, circulating influenza viruses show a high level of genetic variations and may develop the capability of crossing the species barrier. Animal husbandry systems where humans live in close cohabitation with poultry and pigs are considered as potential sources of new strains capable to cross the species barrier from animal to man. Avian influenza viruses able to infect humans and to spread easily from person to person may cause an influenza pandemic.
The reported symptoms of avian influenza in humans range from typical influenza-like symptoms (e.g., fever, cough, sore throat, and muscle aches) to eye infections (conjunctivitis), pneumonia, acute respiratory distress, viral pneumonia, and other severe and life-threatening complications.
Humans are not commonly affected by avian influenza. However, the large epidemics of highly pathogenic avian influenza that currently affect poultry in Asia, and the widespread presence of the virus in the environment increase opportunities for human exposure and infection. In fact, over the past years, avian influenza infections in humans have been repeatedly reported from Asia. Stringent measures such as large scale culling of affected poultry are believed to have prevented the evolution of these outbreaks towards a pandemic. The Office International des Epizooties OIE and the Food and Agricultural Organisation FAO maintain rapid alert and notification systems on animal health and food safety that cover influenza.
Analysis of the evidence available during past outbreaks indicates that:
the majority of human infections is caused by HPAI viruses following direct exposure to infected birds.
direct contact with infected poultry appears to be the favourite way of transmission from poultry to humans.
human to human transmission is very limited;
only HPAI viruses are fatal to humans.
considering the massive exposure, there are very few human infections resulting from HPAI.
EU response
Firstly, legislation adopted by the EU to prevent the spread of avian influenza amongst birds and poultry (control measures to be applied, preventive vaccination) has a direct impact on human health. These measures contribute to reduce the opportunities for human exposure and infection.
Learn more about EU measures in the animal health domain
In addition, according to the terms of the Decision No 2119 of the European Parliament and of the Council, the EU took some measures to watch over the disease and to facilitate communication between Community health services and Member States concerning avian influenza :
Since the first human cases have been notified by Viet Nam, the Commission services have facilitated communication at community level. Through the activation of the EU Early Warning and Response System, Member States, EEA/EFTA and acceding countries are sharing information on measures that they have undertaken or that they have planned to implement.
A restricted web-based portal Health Emergency & Diseases Information System (HEDIS) has been developed. The site is designed to support Community services and Member States during disease outbreaks and health emergencies. It is currently used to provide a central point of access to all information concerning avian influenza derived from various sources available: news, press releases, updated situational maps, online questionnaires, activity logbook, virtual meetings, access to relevant documents, discussion forums, etc.
At global level, the European Commission contributes to the assistance offered to affected countries. International cooperation has been set up to assist these countries to control and eradicate the disease in poultry. The Commission closely cooperates with the WHO to follow the evolution of the disease.
Furthermore, avian influenza in humans may be a potential source of pandemic influenza. Concerning this issue, the Commission actively collaborates with Member States and the WHO to develop influenza pandemic preparedness planning at EU level.
Learn more about influenza pandemic preparedness planning
The European Centre for Disease Prevention and Control (ECDC), an EU Agency created in 2004 to help strengthen Europe's defences against infectious diseases, has taken over the task to provide scientific advice on risk assessment and to coordinate influenza surveillance at EU level. The ECDC has issued several documents:
The Public Health Risk from Highly Pathogenic Avian Influenza Viruses Emerging in Europe with Specific Reference to type A/H5N1 (Version June 1st 2006)
Guidelines to minimise the Risk of Humans Acquiring Highly Pathogenic Avian Influenza from Exposure to Infected Birds or Animals (Version December 21th 2005)
Guidance for National Authorities to Produce Messages for the Public Concerning the Protection of Vulnerable Groups (Version February 2006)
Health advice for people living in or travelling to countries where the A/H5N1 virus has been detected (Version April 2006)
More ECDC documents
The European Food Safety Authority (EFSA), the EU Agency providing scientific advice on all matters on nutrition in relation to community legislation, issued a report on avian influenza and food safety.
Learn more about avian influenza and food safety
Seasonal influenza is a highly contagious viral disease, which typically occurs as epidemics during the cold months. This respiratory infection may include symptoms like fever, cough, pains and weakness. Annual outbreaks of influenza are due to minor changes in the virus. These changes enable the virus to evade the immunity developed by humans after previous infections or in response to vaccinations. Every year, some 100 million people are affected in Europe, Japan and the USA alone.
A European Influenza Surveillance Network (EISN) led by the European Centre for Disease Prevention and Control (ECDC) aims at reducing the burden of the disease in Europe through regular exchange of information on influenza activity.
On 22 December 2009, the Council adopted a Recommendation on seasonal influenza vaccination aiming at a coverage of 75% for at risk groups by 2014-2015 winter season.
Influenza strains from animal origin
Some influenza strains can also be found in animals. Under certain circumstances, they can be communicable to humans and can cause high morbidity and mortality in human populations. Animal husbandry systems where humans live in close cohabitation with poultry and pigs are considered the most likely source of new strains, capable to cross the species barrier from animal to man, through a mutation mechanism, and may cause a pandemic.
Learn more about the Influenza A(H1N1)
Learn more about avian influenza in humans and the EU response
Consult maps and tables on avian influenza in humans' situation
Influenza pandemic
An influenza pandemic occurs when a radical change in influenza virus takes place. There have been three pandemics in the last century. The change is so radical that affected humans have no immunity against this new virus. With increased mobility of people, as well as conditions of overcrowding, epidemics due to a newly emerging influenza virus are likely to spread quickly all around the world and are at risk to eventually become a pandemic. It is therefore important to be prepared to this eventuality.
Learn more about influenza pandemic preparedness planning at EU level

redpajama_set_name: RedPajamaCommonCrawl


text:
Outside Online
Tools & Tech
Gear Picks
Exploration & Survival
Active Families
Love & Humor
Outside Feed
To create these restorations, Land Rover is seeking out unmodified, original examples of the Series 1. As you can see, that means starting from a very rough survivor. (photo: Land Rover)
Gear Cars & Trucks
Indefinitely Wild
Land Rover Wants to Sell You a New Truck—From 1948
The original Series 1 is being "reborn" with official factory restorations
Wes Siler
Receive $50 off an eligible $100 purchase at the Outside Shop, where you'll find a selection of brand-name products curated by our gear editors, when you sign up for Outside+ today.
Land Rover has big plans for its next Defender, due in late 2018. Historically selling only 10,000 or so of the old-school model (production ended in January), it's targeting an annual volume of 100,000 for the next, potentially providing a direct rival for the Jeep Wrangler. And what better way to start driving demand for the new truck than by reminding people just how great the first one was?
That's the idea with Land Rover's new "Reborn" program, which will eventually offer the brand's customers factory restorations of their own vehicles. To begin, though, the company is selecting 25 prime examples of the original 1948 Land Rover Series 1 and restoring them to factory-new condition.
This is a short wheelbase 90 model. Land Rover will also be restoring several long wheelbase 110s. (Land Rover)
Restorations will take place at Land Rover's Solihull factory, and be carried out with original, or, where necessary, recreated parts. The process is far from typical, and its exacting degree of originality will take between six to nine months per individual vehicle. The quality of work should be so good that Land Rover is guaranteeing it with a factory warranty, spanning 12 months and 12,000 miles. It will, of course, also come at a price: $85,000 to $110,000 per vehicle. A rate far in excess even of today's inflated classic car market. (A friend just purchased a privately-restored Series 1 for $15,000.) I guess customer-funded brand marketing doesn't come cheap.
The project also represents the launch of Land Rover Classic, a new factory service that will, at an undetermined time in the future, offer owners similar OCD levels of factory restoration for their own vehicles. Have a first-generation Range Rover or maybe an awesome built-out Discovery? This will be the nuclear operation to take it back to brand new, warranteed condition.
Starting here, Land Rover returns the vehicles to as-new condition. (Land Rover)
What can all this tell us about Land Rover's plans for the next Defender? According to TruckYeah! that vehicle will depart significantly from the classic Defender's throwback, utilitarian design, but also look nothing like the concepts and renderings that have been floating around for the last few years. That's not necessarily a bad thing: the last Defender was eventually killed-off by progressing pedestrian safety regulations, which no longer allow solid boxes of steel to drive around, impacting people's bodies like 4,000-pound hammers. Our sincere hope is that, with a the company putting an exclamation point on the capability of the original model, the nameplate will carry forward as a genuinely capable off-roader, rather than the soft, luxury crossovers that the rest of the brand's range has become.
The same as it was in 1948, when this Series 1 was brand new. (Land Rover)
Filed to:
Lead photo: Land Rover
How to Build Your Overland Vehicle Like an Australian
By: Wes Siler
The 2024 Chevy Silverado Electric Pickup Is Here
A $150 Reminder That LED Headlight Bulbs Don't Work
How to (Safely) Heat a Tent
Twitter Icon sms
Join Outside+ to get Outside magazine, access to exclusive content, 1,000s of training plans, and more.


text:
Fatima Whitbreadová (* 3. března 1961 Londýn) je bývalá britská oštěpařka, mistryně světa z roku 1987.

Sportovní kariéra
Svoji mezinárodní kariéru začala vítězstvím v hodu oštěpem na juniorském mistrovství Evropy v roce 1979. Na premiérovém mistrovství světa v Helsinkách v roce 1983 vybojovala v soutěži oštěpařek stříbrnou medaili výkonem 69,14 metru. O rok později v Los Angeles skončila v oštěpařském finále třetí. Největším úspěchem pro ni byly tituly mistryně Evropy v roce 1986 (zde v kvalifikaci vytvořila nový světový rekord 77,44 metru) a mistryně světa v roce 1987 v Římě. Na olympiádě v Soulu v roce 1988 získala stříbrnou medaili za Němkou Felkeovou.

Externí odkazy

Britští oštěpaři
Narození v roce 1961
Narození 3. března
Žijící lidé
Ženy
Britští stříbrní olympijští medailisté
Britští bronzoví olympijští medailisté
Stříbrní olympijští medailisté v atletice
Bronzoví olympijští medailisté v atletice


The Stanford Linear Accelerator Center (SLAC) needed a calibration shield for a moving Hall Effect Probe as part of their Undulator Project with DESY — the German Synchrotron Facility. Typical Zero Gauss Chambers consist of an open-ended tube, which was unacceptable in SLAC's Undulator configuration.
The design originated as a single slot Undulator shield and was so successful, that it was graduated to the dual slot system shown above, which enabled full pass-through of the Hall Probe.
The probe needed to pass through the shield lengthwise. By equating the flange width to "end effects" on a cylinder, and with an understanding of the customer's application, we applied tubulation theory to a slot configuration to reduce fringing and end effects.
Note the Magnetic modeling image – confirmed what extensive testing proved.


text:
Q: Why does the browser include adjacent elements after selecting a block level element wrapped in  tag? As shown in the figure below, when I select the first a tag, the browser will include the following a tag, and the margin of the P element in the A tag is also collapsed with the .box2.How to explain this ?

   .box1 {
        width: 100px;
        height: 100px;
        background-color: antiquewhite;
      }
      p {
        margin-top: 10px;
      }

abc

      abc

A: You have a block element (the p) inside an inline element (the link) then an inline element right after (the second link).
Here is a better illustration with some padding and outline.

p {
  margin-top: 10px;
}

a:first-child {
  padding: 0 5px;
  outline: 1px solid red;
}

abc

  abc

The use of a block element inside an inline one will activate a complex mechanism where you will have an inline content before the block element and another one after the block element (highlighted by the outline). And since you have another a which is also an inline element, it will be on the same line with the second inline content.
The Devtool will show you the rectangular region that contain both inline contents (in red) and the block content (the p) and also the next a because it happen to be at the same line.

When an inline box contains an in-flow block-level box, the inline box (and its inline ancestors within the same line box) are broken around the block-level box (and any block-level siblings that are consecutive or separated only by collapsible whitespace and/or out-of-flow elements), splitting the inline box into two boxes (even if either side is empty), one on each side of the block-level box(es). The line boxes before the break and after the break are enclosed in anonymous block boxes, and the block-level box becomes a sibling of those anonymous boxes. When such an inline box is affected by relative positioning, any resulting translation also affects the block-level box contained in the inline box. ref

redpajama_set_name: RedPajamaStackExchange


text:
\section{Motivation}
\label{sec:1}

The recent development of visualization techniques in superfluid
helium based on micron-size tracers \cite{Bewley,Zhang-VanSciver}
has raised the possibility of experimentally determining
superfluid and normal fluid profiles and the spatial distribution of
quantised vortices in a channel, thus solving outstanding problems
in quantum turbulence. Particularly interesting (and relevant to
engineering applications) is
the turbulence induced by heat transfer (counterflow
turbulence).  It is well known that if the applied heat
flux $\dot Q$ is less than a small critical value ${\dot Q}_c$ then
the heat
is carried by the normal fluid component, and the superfluid component
flows in the opposite direction to conserve mass.
If ${\dot Q}>{\dot Q}_c$ the superfluid component becomes turbulent,
forming a disorganized tangle of quantised vortices. In some geometries,
at larger heat flux a transition to a more intense vortex tangle
has been observed \cite{Tough}, which is perhaps related to the onset of
turbulence in the normal fluid \cite{Melotte}.

In this paper we are concerned with the intermediate heat transfer
regime, in which the normal fluid is still laminar, but the superfluid
forms a turbulent tangle. The issue which we address is the average
superfluid profile and the average spatial distribution of vortices in the channel.
Let $\vv_n$ and $\vv_s$ be respectively the normal fluid and superfluid velocity fields.
The normal fluid satisfies no slip boundary conditions at the wall
of the channels, so, for the sake of simplicity, we assume that $\vv_n$
is a steady classical parabolic Poiseuille profile (this approximation implies
that the constant pressure drop along the channel is the same with and without
the vortex tangle). The superfluid slips at the boundaries, so, in the
absence of vortices, it is natural to assume that $\vv_s$ has a constant
(uniform) profile. The velocity fields
$\vv_n$ and $\vv_s$ are related by the counterflow condition
of no net mass flow along the channel.

The question which we ask is the following:
if ${\dot Q} > {\dot Q}_c$, are the vortices uniformly distributed
in the channel, or do they organize themselves spatially, creating a
non-uniform superfluid profile at scales larger than the average
vortex separation $\ell$ but smaller than the channel size $D$ ?

\section{Model}
\label{sec:2}

To answer the question we consider the following idealised two-dimensional
model which, we argue, captures the most important physical
ingredients. Let $x$ and $y$ be respectively directions along
and across the channel, with walls at $y=\pm D/2$ and periodic
boundary conditions at $x=0$ and $x=\lambda$. The normal fluid
velocity is $\vv_n=(v_{n}^x,v_{n}^y)=\left ( -V_{n0} [1-(2y/D)^2]\, , \, 0 \right )$
with $V_{n0}>0$ and thus pointing in the negative $x$ direction.
The superfluid velocity $\vv_s=(v_{s}^x,v_{s}^y)$
is decomposed
in two parts, $\vv_s=\vv_{s0} + \vv_{si}$; the former is the uniform
flow $\vv_{s0}=V_{s0}(t)\xhat$ , $\xhat$ being the unit vector along
$x$, and the latter,
$\vv_{si}$, is the velocity field induced by
$N$ vortex points located at positions $\rr_j=(x_j(t),y_j(t))$
(for $j=1,\cdots N$) where $t$ is time. Half the vortices have
positive circulation $\Gamma_j=\kappa$, and half have negative
circulation $\Gamma_j=-\kappa$, where $\kappa=10^{-3}~\rm cm^2/s$
is the quantum of circulation in superfluid $^4$He.
To satisfy the superfluid's boundary condition that $v_{s}^y=0$ at
$y=\pm D/2$ (no flow into the wall),
we attach to each vortex point an infinite series of image vortex
points in the positive and negative regions $y>D/2$ and
$y<-D/2$ \cite{Greengard}.

The equation of motion of a vortex located at $\rr_j$ is \cite{Schwarz}
\begin{equation}
\frac{d\rr_j}{dt}=\vv_s(\rr_j)
+ \alpha {\bf s}'(\rr_j) \times (\vv_n(\rr_j) - \vv_s(\rr_j)) +
\alpha' (\vv_n(\rr_j) - \vv_s(\rr_j)),
\label{eq:Schwarz}
\end{equation}
where ${\bf s}'_j$ is the unit vector along the vortex $j$
(in the positive or negative $z$ direction) and $\alpha$ and $\alpha'$ are
temperature dependent mutual friction coefficients \cite{BDV}.

The quantity $V_{s0}$ is determined at each time $t$
by imposing the counterflow condition

\begin{equation}
\rho_n <v_{n}^x> + \rho_s <v_{s}^x>=0,
\label{eq:counterflow}
\end{equation}

\noindent
where $\rho_n$ and $\rho_s$ are the temperature-dependent normal
fluid and superfluid densities, $\rho=\rho_n+\rho_s$ is the total
helium density,
and $<v_{n}^x>$ and $<v_s^x>$ are the channel averages of the
$x$-components of
the normal fluid and superfluid velocities, defined as

\begin{equation}
<v_{s}^x>=\frac{1}{\lambda D}\!\!\int_0^\lambda\!\!\int_{-D/2}^{D/2} v_{s}^x(x,y)dxdy
        =V_{s0}+\frac{1}{\lambda D}\!\! \int_0^\lambda\!\!\int_{-D/2}^{D/2}
v_{si}^x(x,y)dxdy
\label{eq:average-vs}
\end{equation}

\noindent
and
\begin{equation}
<v_{n}^x>=\frac{1}{D}\int_{-D/2}^{D/2} v_{n}^x(y) dy
        =-\frac{2}{3}V_{n0}.
\label{eq:average-vn}
\end{equation}

\noindent
To model the creation and the destruction of vortices within our 2-dimensional
model, we proceed as follows. When the distance between
two vortex points of opposite circulation becomes smaller than a critical
value $\epsilon_1$, we perform a ``numerical vortex
reconnection'' and remove these vortex points;
similarly, when the distance between a vortex point and a boundary
is less than $\epsilon_2=0.5\,\epsilon_1$, we
remove this vortex point (the vortex of opposite circulation being the nearest image
vortex beyond the wall). To maintain a steady state, when a vortex point
is removed, a new vortex point of the same circulation is re-inserted into
the channel, either on the axis ($y=0$) or near the walls
or randomly, as described in the next section.

At selected times, given the vortex configuration $\rr_j(t)$ ($j=1,\cdots N$),
we define a {\it coarse-grained} superfluid velocity $\vvv_s$
by averaging the components of the (microscopic) velocity $\vv_s$
over channel strips of size $\Delta$ in the $y$ direction, such that
$\ell < \Delta <D$.
The limit $\ell << \Delta << D$ corresponds to the
Hall - Vinen - Bekarevich - Khalatnikov (HVBK) equations
\cite{Hills-Roberts}.
We assume that the velocity $\vvv_s$ is parallel to the walls,
$\vvv_s=(\bar{v}_s,0)$.  The curl of
$\vvv_s$ can be interpreted as the
coarse-grained superfluid vorticity.

To make connection with the experiments, we interpret $n=N/(\lambda D)$
(number of vortex points per unit area) as the vortex line density $L$
(vortex length per unit volume), from which $\ell=n^{-1/2}$ is the
average intervortex spacing. The imposed heat flux
$\dot Q$, which is reported in experiments, is related to
the average counterflow velocity $V_{ns}=<v_{n}^x>-<v_{s}^x>$ by the
relation ${\dot Q}=T \rho_s S V_{ns}$,
where $T$ is the temperature and $S$ the specific entropy.

The calculation consists in computing the evolution of the vortex
points, starting from an arbitrary initial condition, until a steady
state regime is achieved and the profile of $\vvv_s$ becomes constant.
The time integration is performed using the second--order Adam-Bashfort
method with time step $\Delta t$.

\section{Results}
\label{sec:3}

The numerical code solves the governing equations written in
dimensionless form. The units of length, velocity and time
are respectively $\delta_c=D/2=4.55\times 10^{-3}~\rm cm$ ,
$u_c=~\kappa/(2\pi\delta_c)= 3.49\times 10^{-2}~\rm cm/s$,
$t_c=\delta_c/u_c=0.13~\rm s$.
Non-dimensional quantities are denoted by the superscript `$\ast$'.
We choose parameters taking into account the available computing
power and the experiments of Tough and collaborators
\cite{Ladner-Tough,Martin-Tough}: $N=1876$, $\lambda^\ast=6$,
$T=1.7~\rm K$, $D^\ast=2$ (corresponding to tube $R4$ in
Ref.~\cite{Ladner-Tough}), $\epsilon_1=1.25\times10^{-2}\,\ell$,
$\Delta=1.25\,\ell$, $V_{ns}^\ast=-478.5$ and
$\Delta t^*=1.9\times 10^{-6}$. At this temperature, taking into account
pressure and temperature variations experimentally measured
along the channels \cite{Ladner-Tough}, we can assume the constant values
$\rho_s=0.112~\rm g~cm^{-3} $, $\rho_n=~3.32\times10^{-2}~\rm g~cm^{-3}$
and $S=~0.395~\rm J~(g~ K)^{-1}~$ \cite{Donnelly-Barenghi}. Using
Eqs.~(\ref{eq:counterflow}), (\ref{eq:average-vn}) and the definition of
$V_{ns}$ we have $V_{n0}^\ast=553.6$.
The vortex density is
$n^\ast=~156.3$, and the average intervortex spacing,
$\ell^\ast \approx 0.08$, corresponds to
the dimensionless number $L^{1/2}D=D^\ast\sqrt{n^\ast}=~25$ ,
which is typical of counterflow experiments \cite{Martin-Tough}.

\begin{figure}[htbp]
\hspace{-1.5cm}
     \begin{minipage}{0.46\textwidth}
      \centering
       \includegraphics[width=1.0\textwidth]{figure_1.ps}
     \end{minipage}
     \hspace{0.2cm}
     \begin{minipage}{0.46\textwidth}
      \centering
       \includegraphics[width=1.0\textwidth]{figure_2.ps}
     \end{minipage}
\vspace{1.1cm}
\caption{(color online). Initial random vortex configuration (left) and
vortex configuration at $t^\ast=4.75\times 10^{-2}$ (right).
Positive and negative vortices are respectively denoted by empty (red) and
filled (black) circles.}
\label{fig:1}
\end{figure}

To distinguish the three different ``re--nucleation'' regimes,
hereafter we indicate with $(a)$ random vortex-reinsertion in the
channel, and with $(b)$ and $(c)$  vortex re-insertion
on the axis and near the walls, respectively.

Case $(a)$ is the simplest and corresponds physically to
3-dimensional superfluid vorticity production
taking place throughout the vortex-tangle due to reconnections
and vortex-rings emission.
The initial condition, shared by all three cases, is shown in
Fig.~\ref{fig:1} (left) and consists of
a random vortex configuration. During the evolution of case $(a)$,
positive and negative vortices move on the average towards
the $y^\ast=-1$  and $y^\ast=+1$ wall respectively. The trajectory
of an individual vortex can be very irregular, due to the interaction
with other vortices. A drift in the
positive $x$ direction is superimposed to this motion towards walls.

After a time-interval of the order of
$\tau^\ast_{a} \approx 2\times 10^{-2}$, the vortex configuration
reaches a steady state, as illustrated in Fig.~\ref{fig:1} (right).
Note that there are more positive
vortices in the $y^\ast~<~0$ region and more negative vortices in the
$y^\ast~>~0$ region, as confirmed
by the density profile of positive vortices, $n^\ast_+(y^\ast)$,
 shown in Fig.~\ref{fig:3} (right)
(the density profile of negative vortices, $n^\ast_-(y^\ast)$,
is symmetrical with respect to the channel axis). The polarization
of the vortex configuration is not complete - not {\it all} positive
vortices are in $y^\ast~<~0$ and not {\it all} negative vortices
are in $y^\ast~>~0$ - in agreement with arguments discussed in
Ref.~\cite{Hulton}.

The resulting coarse-grained superfluid velocity
profile associated to this partial polarization is compared to the driving
normal fluid velocity in Fig.~\ref{fig:2} (left): we find that the profile is
almost parabolic, $\bar{v}_s^\ast\sim~y^{\ast^{2.19}}$.
The distribution of vortices irrespective of their sign,
$n^\ast(y^\ast)$, is almost constant, as shown in
Fig.~\ref{fig:3} (left).

\begin{figure}[htbp]
\hspace{-1.9cm}
     \begin{minipage}{0.48\textwidth}
      \centering
       \includegraphics[width=1.1\textwidth]{figure_3.ps}
     \end{minipage}
     \hspace{0.2cm}
     \begin{minipage}{0.48\textwidth}
      \centering
       \includegraphics[width=1.1\textwidth]{figure_4.ps}
     \end{minipage}
\vspace{0.2cm}
\caption{(color online).
Solid (red) line: coarse-grained superfluid velocity
$\bar{v}_s^\ast(y^\ast)$; the
labels $(a)$, $(c_1)$, $(c_2)$ (left) and $(b)$ (right) correspond to
the cases discussed in the text. Dashed (blue) line: analytical
laminar solution \cite{GCM} of HBVK equations which applies Geurst's
approach \cite{Geurst} to Cartesian geometry. Curves $G_c$ (left) and
$G_b$ (right) correspond respectively to cases $(c)$ and $(b)$ in the text.
Dot-dashed (black) line: normal fluid velocity profile (left, right).}
\label{fig:2}
\end{figure}

The  other two cases which we investigate, case $(b)$ (nucleation
at $y^\ast=0$) and case $(c)$ (nucleation at
$y^\ast=\pm 1$), are suggested by the analysis of
Geurst \cite{Geurst} based on the HVBK equations.
Case $(b)$ induces a vortex density profile
$n^\ast(y^\ast)$ with a sharp peak near $y^\ast=0$
(Fig.~\ref{fig:3} (left) ). We find that this concentration
of vortices on the axis is unstable: collective motion
of vortices of the same polarity appears, and the resulting
coarse-grained superfluid velocity profile,
$\bar{v}_s^\ast(y^\ast)$, shown in
Fig.~\ref{fig:2} (right), undergoes
small-amplitude but persistent oscillations.
A power-law regression yields the dependence
$\bar{v}_s^\ast\sim~y^{\ast^{1.6}}$; as in case $(a)$, after
a transient of the order of $\tau^\ast_{b}\sim 6\times 10^{-2}$,
we obtain the partially polarized steady state vortex--distribution
shown in Fig.~\ref{fig:3} (right).

Finally, we consider case $(c)$.
This nucleation regime corresponds physically
to 3-dimensional superfluid vorticity production arising from
vortex--rings emission by vortices pinned to the walls.
In our model, the positive (negative) vortex points are re-inserted near
(rather than at) the
$y^\ast=1$ ($y^\ast=-1$) wall, in order not to collapse rapidly on
the boundaries due to the Magnus-mutual friction forces balance.
Let $\xi$ be the distance of nucleation away from the walls.
To investigate the dependence of the flow on $\xi$,
we choose values $\xi_1=\ell$ and $\xi_2= 0.5\, \ell$,
which we refer to as cases $(c_1)$ and $(c_2)$.
The resulting coarse-grained superfluid velocity profile
$\bar{v}_s^\ast(y^\ast)$ in the two cases is shown
in Fig.~\ref{fig:2} (left): note the reversed concavity, compared to
cases $(a)$, $(b)$ and the normal fluid.

Fig.~\ref{fig:3} shows that the nucleation location
clearly influences the
vortex distribution and the steady state vortex density profile
$n^\ast(y^\ast)$, which is reached
after a transient time interval of the order of
$\tau^\ast_{c}\approx 3\times 10^{-2}$,
independently of $\xi$.

\begin{figure}[htbp]
\hspace{-2.2cm}
     \begin{minipage}{0.48\textwidth}
      \centering
       \includegraphics[width=1.15\textwidth]{figure_5.ps}
     \end{minipage}
     \hspace{0.2cm}
     \begin{minipage}{0.48\textwidth}
      \centering
       \includegraphics[width=1.15\textwidth]{figure_6.ps}
     \end{minipage}
\vspace{0.2cm}
\caption{(color online). Vortex density $n^\ast(y^\ast)$ (left)
and positive vortex density $n_+^\ast(y^\ast)$ (right)
for cases: $(a)$, dashed (blue) line; $(b)$, dot-dashed (black) line;
$(c_1)$ and $(c_2)$, solid (red) lines.}
\label{fig:3}
\end{figure}
\vspace{-0.5cm}

\section{Discussion}
\label{sec:4}

The model which we have presented, being 2-dimensional, is
clearly rather idealized, and we do not claim that it is
possible to make direct comparison with experiments.
Nevertheless, the model contains what we argue are the most
important physical ingredients, and it allows us to make
predictions about the vortex distribution and the superfluid
profile across a channel at small values of the applied heat flux.
The 2-dimensional
solution which we have found can be interpreted in 3-dimensions
as vortex loops which move from the outer parts of the channel towards
the centre, speeding up during this process, or, perhaps more precisely,
as a tangle which is polarised by the presence of such loops.

Our coarsed-grained superfluid velocity
profile $\bar{v}_s^\ast(y^\ast)$ compares very well with the
2-dimensional laminar solution of the HVBK equations  which
can be derived by
applying Geurst's  approach \cite{Geurst} for a cylindrical pipe
to Cartesian geometry \cite{GCM}.
Indeed, Fig.~\ref{fig:2} (right) shows that case $(b)$ and
this laminar solution \cite{GCM} are very similar
(with the exception of the
channel axis, where Guerst's solution is singular and
$n^\ast \to \infty$).

In Fig.~\ref{fig:2} (left) we compare the
analytical solution corresponding to nucleation at the walls
($\xi=0$) to
the velocity profile $\bar{v}_s^\ast(y^\ast)$ for case $(c)$.
It is apparent  that, with decreasing $\xi$, $\bar{v}_s^\ast(y^\ast)$
tends to the analytical solution (the difference which is present
near the walls arises from the boundary conditions
for the superfluid velocity which ensure
infinite vorticity in the nucleation region \cite{Geurst,GCM}).

Further work will generalise the approach which we have presented,
by solving self-consistently the equation for the normal fluid in the
presence of the mutual friction, rather than assuming a
given profile for $\vv_n$. We also plan to investigate the
dependence of the profiles on the
vortex densities.
The current rapid progress of visualization techniques, such as the
recently developed laser-induced fluorescence of metastable
molecules \cite{Vinen}, will clearly stimulate more work
on the nature of laminar and turbulent profiles of helium~II in
channels.

\begin{acknowledgements}
M.S. acknowledges a travel grant of the Istituto Nazionale di Alta
Matematica. C.F.B.'s work is supported by the Leverhulme Trust.
\end{acknowledgements}

redpajama_set_name: RedPajamaArXiv