fs/xfs/xfs_reflink.c

Source file repositories/reference/linux-study-clean/fs/xfs/xfs_reflink.c

File Facts

System
Linux kernel
Corpus path
fs/xfs/xfs_reflink.c
Extension
.c
Size
55611 bytes
Lines
1929
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

if (found) {
			xfs_trans_cancel(tp);
			break;
		}

		ASSERT(isnullstartblock(cmap->br_startblock) ||
		       cmap->br_startblock == DELAYSTARTBLOCK);

		/*
		 * Replace delalloc reservation with an unwritten extent.
		 */
		nimaps = 1;
		error = xfs_bmapi_write(tp, ip, cmap->br_startoff,
				cmap->br_blockcount,
				XFS_BMAPI_COWFORK | XFS_BMAPI_PREALLOC, 0,
				cmap, &nimaps);
		if (error)
			goto out_trans_cancel;

		xfs_inode_set_cowblocks_tag(ip);
		error = xfs_trans_commit(tp);
		if (error)
			return error;
	} while (cmap->br_startoff + cmap->br_blockcount <= imap->br_startoff);

	return xfs_reflink_convert_unwritten(ip, imap, cmap, convert_now);

out_trans_cancel:
	xfs_trans_cancel(tp);
	return error;
}

/* Allocate all CoW reservations covering a range of blocks in a file. */
int
xfs_reflink_allocate_cow(
	struct xfs_inode	*ip,
	struct xfs_bmbt_irec	*imap,
	struct xfs_bmbt_irec	*cmap,
	bool			*shared,
	uint			*lockmode,
	bool			convert_now)
{
	int			error;
	bool			found;

	xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);
	if (!ip->i_cowfp) {
		ASSERT(!xfs_is_reflink_inode(ip));
		xfs_ifork_init_cow(ip);
	}

	error = xfs_find_trim_cow_extent(ip, imap, cmap, shared, &found);
	if (error || !*shared)
		return error;

	/* CoW fork has a real extent */
	if (found)
		return xfs_reflink_convert_unwritten(ip, imap, cmap,
				convert_now);

	/*
	 * CoW fork does not have an extent and data extent is shared.
	 * Allocate a real extent in the CoW fork.
	 */
	if (cmap->br_startoff > imap->br_startoff)
		return xfs_reflink_fill_cow_hole(ip, imap, cmap, shared,
				lockmode, convert_now);

	/*
	 * CoW fork has a delalloc reservation. Replace it with a real extent.
	 * There may or may not be a data fork mapping.
	 */
	if (isnullstartblock(cmap->br_startblock) ||
	    cmap->br_startblock == DELAYSTARTBLOCK)
		return xfs_reflink_fill_delalloc(ip, imap, cmap, shared,
				lockmode, convert_now);

	/* Shouldn't get here. */
	ASSERT(0);
	return -EFSCORRUPTED;
}

/*
 * Cancel CoW reservations for some block range of an inode.
 *
 * If cancel_real is true this function cancels all COW fork extents for the
 * inode; if cancel_real is false, real extents are not cleared.
 *
 * Caller must have already joined the inode to the current transaction. The
 * inode will be joined to the transaction returned to the caller.

Annotation

Implementation Notes