fs/xfs/xfs_exchrange.c

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

File Facts

System
Linux kernel
Corpus path
fs/xfs/xfs_exchrange.c
Extension
.c
Size
26208 bytes
Lines
924
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

struct xfs_commit_range_fresh {
	xfs_fsid_t	fsid;		/* m_fixedfsid */
	__u64		file2_ino;	/* inode number */
	__s64		file2_mtime;	/* modification time */
	__s64		file2_ctime;	/* change time */
	__s32		file2_mtime_nsec; /* mod time, nsec */
	__s32		file2_ctime_nsec; /* change time, nsec */
	__u32		file2_gen;	/* inode generation */
	__u32		magic;		/* zero */
};
#define XCR_FRESH_MAGIC	0x444F524B	/* DORK */

/* Set up a commitrange operation by sampling file2's write-related attrs */
long
xfs_ioc_start_commit(
	struct file			*file,
	struct xfs_commit_range __user	*argp)
{
	struct xfs_commit_range		args = { };
	struct kstat			kstat = { };
	struct xfs_commit_range_fresh	*kern_f;
	struct xfs_commit_range_fresh	__user *user_f;
	struct inode			*inode2 = file_inode(file);
	struct xfs_inode		*ip2 = XFS_I(inode2);
	const unsigned int		lockflags = XFS_IOLOCK_SHARED |
						    XFS_MMAPLOCK_SHARED |
						    XFS_ILOCK_SHARED;

	BUILD_BUG_ON(sizeof(struct xfs_commit_range_fresh) !=
		     sizeof(args.file2_freshness));

	kern_f = (struct xfs_commit_range_fresh *)&args.file2_freshness;

	memcpy(&kern_f->fsid, ip2->i_mount->m_fixedfsid, sizeof(xfs_fsid_t));

	xfs_ilock(ip2, lockflags);
	/* Force writing of a distinct ctime if any writes happen. */
	fill_mg_cmtime(&kstat, STATX_CTIME | STATX_MTIME, inode2);
	kern_f->file2_ctime		= kstat.ctime.tv_sec;
	kern_f->file2_ctime_nsec	= kstat.ctime.tv_nsec;
	kern_f->file2_mtime		= kstat.mtime.tv_sec;
	kern_f->file2_mtime_nsec	= kstat.mtime.tv_nsec;
	kern_f->file2_ino		= inode2->i_ino;
	kern_f->file2_gen		= inode2->i_generation;
	kern_f->magic			= XCR_FRESH_MAGIC;
	xfs_iunlock(ip2, lockflags);

	user_f = (struct xfs_commit_range_fresh __user *)&argp->file2_freshness;
	if (copy_to_user(user_f, kern_f, sizeof(*kern_f)))
		return -EFAULT;

	return 0;
}

/*
 * Exchange file1 and file2 contents if file2 has not been written since the
 * start commit operation.
 */
long
xfs_ioc_commit_range(
	struct file			*file,
	struct xfs_commit_range __user	*argp)
{
	struct xfs_exchrange		fxr = {
		.file2			= file,
	};
	struct xfs_commit_range		args;
	struct xfs_commit_range_fresh	*kern_f;
	struct xfs_inode		*ip2 = XFS_I(file_inode(file));
	struct xfs_mount		*mp = ip2->i_mount;

	kern_f = (struct xfs_commit_range_fresh *)&args.file2_freshness;

	if (copy_from_user(&args, argp, sizeof(args)))
		return -EFAULT;
	if (args.flags & ~XFS_EXCHANGE_RANGE_ALL_FLAGS)
		return -EINVAL;
	if (kern_f->magic != XCR_FRESH_MAGIC)
		return -EBUSY;
	if (memcmp(&kern_f->fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t)))
		return -EBUSY;

	fxr.file1_offset	= args.file1_offset;
	fxr.file2_offset	= args.file2_offset;
	fxr.length		= args.length;
	fxr.flags		= args.flags | __XFS_EXCHANGE_RANGE_CHECK_FRESH2;
	fxr.file2_ino		= kern_f->file2_ino;
	fxr.file2_gen		= kern_f->file2_gen;
	fxr.file2_mtime.tv_sec	= kern_f->file2_mtime;
	fxr.file2_mtime.tv_nsec	= kern_f->file2_mtime_nsec;

Annotation

Implementation Notes