forked from mirrors/linux
		
	 629fdaf5f5
			
		
	
	
		629fdaf5f5
		
	
	
	
	
		
			
			Build on the code that was recently added to the temporary repair file code so that we can atomically switch the contents of any file fork, even if the fork is in local format. The upcoming functions to repair xattrs, directories, and symlinks will need that capability. Repair can lock out access to these user files by holding IOLOCK_EXCL on these user files. Therefore, it is safe to drop the ILOCK of both the file being repaired and the tempfile being used for staging, and cancel the scrub transaction. We do this so that we can reuse the resource estimation and transaction allocation functions used by a regular file exchange operation. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
		
			
				
	
	
		
			124 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			124 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* SPDX-License-Identifier: GPL-2.0-or-later */
 | |
| /*
 | |
|  * Copyright (c) 2020-2024 Oracle.  All Rights Reserved.
 | |
|  * Author: Darrick J. Wong <djwong@kernel.org>
 | |
|  */
 | |
| #ifndef __XFS_EXCHMAPS_H__
 | |
| #define __XFS_EXCHMAPS_H__
 | |
| 
 | |
| /* In-core deferred operation info about a file mapping exchange request. */
 | |
| struct xfs_exchmaps_intent {
 | |
| 	/* List of other incore deferred work. */
 | |
| 	struct list_head	xmi_list;
 | |
| 
 | |
| 	/* Inodes participating in the operation. */
 | |
| 	struct xfs_inode	*xmi_ip1;
 | |
| 	struct xfs_inode	*xmi_ip2;
 | |
| 
 | |
| 	/* File offset range information. */
 | |
| 	xfs_fileoff_t		xmi_startoff1;
 | |
| 	xfs_fileoff_t		xmi_startoff2;
 | |
| 	xfs_filblks_t		xmi_blockcount;
 | |
| 
 | |
| 	/* Set these file sizes after the operation, unless negative. */
 | |
| 	xfs_fsize_t		xmi_isize1;
 | |
| 	xfs_fsize_t		xmi_isize2;
 | |
| 
 | |
| 	uint64_t		xmi_flags;	/* XFS_EXCHMAPS_* flags */
 | |
| };
 | |
| 
 | |
| /* Try to convert inode2 from block to short format at the end, if possible. */
 | |
| #define __XFS_EXCHMAPS_INO2_SHORTFORM	(1ULL << 63)
 | |
| 
 | |
| #define XFS_EXCHMAPS_INTERNAL_FLAGS	(__XFS_EXCHMAPS_INO2_SHORTFORM)
 | |
| 
 | |
| /* flags that can be passed to xfs_exchmaps_{estimate,mappings} */
 | |
| #define XFS_EXCHMAPS_PARAMS		(XFS_EXCHMAPS_ATTR_FORK | \
 | |
| 					 XFS_EXCHMAPS_SET_SIZES | \
 | |
| 					 XFS_EXCHMAPS_INO1_WRITTEN)
 | |
| 
 | |
| static inline int
 | |
| xfs_exchmaps_whichfork(const struct xfs_exchmaps_intent *xmi)
 | |
| {
 | |
| 	if (xmi->xmi_flags & XFS_EXCHMAPS_ATTR_FORK)
 | |
| 		return XFS_ATTR_FORK;
 | |
| 	return XFS_DATA_FORK;
 | |
| }
 | |
| 
 | |
| /* Parameters for a mapping exchange request. */
 | |
| struct xfs_exchmaps_req {
 | |
| 	/* Inodes participating in the operation. */
 | |
| 	struct xfs_inode	*ip1;
 | |
| 	struct xfs_inode	*ip2;
 | |
| 
 | |
| 	/* File offset range information. */
 | |
| 	xfs_fileoff_t		startoff1;
 | |
| 	xfs_fileoff_t		startoff2;
 | |
| 	xfs_filblks_t		blockcount;
 | |
| 
 | |
| 	/* XFS_EXCHMAPS_* operation flags */
 | |
| 	uint64_t		flags;
 | |
| 
 | |
| 	/*
 | |
| 	 * Fields below this line are filled out by xfs_exchmaps_estimate;
 | |
| 	 * callers should initialize this part of the struct to zero.
 | |
| 	 */
 | |
| 
 | |
| 	/*
 | |
| 	 * Data device blocks to be moved out of ip1, and free space needed to
 | |
| 	 * handle the bmbt changes.
 | |
| 	 */
 | |
| 	xfs_filblks_t		ip1_bcount;
 | |
| 
 | |
| 	/*
 | |
| 	 * Data device blocks to be moved out of ip2, and free space needed to
 | |
| 	 * handle the bmbt changes.
 | |
| 	 */
 | |
| 	xfs_filblks_t		ip2_bcount;
 | |
| 
 | |
| 	/* rt blocks to be moved out of ip1. */
 | |
| 	xfs_filblks_t		ip1_rtbcount;
 | |
| 
 | |
| 	/* rt blocks to be moved out of ip2. */
 | |
| 	xfs_filblks_t		ip2_rtbcount;
 | |
| 
 | |
| 	/* Free space needed to handle the bmbt changes */
 | |
| 	unsigned long long	resblks;
 | |
| 
 | |
| 	/* Number of exchanges needed to complete the operation */
 | |
| 	unsigned long long	nr_exchanges;
 | |
| };
 | |
| 
 | |
| static inline int
 | |
| xfs_exchmaps_reqfork(const struct xfs_exchmaps_req *req)
 | |
| {
 | |
| 	if (req->flags & XFS_EXCHMAPS_ATTR_FORK)
 | |
| 		return XFS_ATTR_FORK;
 | |
| 	return XFS_DATA_FORK;
 | |
| }
 | |
| 
 | |
| int xfs_exchmaps_estimate_overhead(struct xfs_exchmaps_req *req);
 | |
| int xfs_exchmaps_estimate(struct xfs_exchmaps_req *req);
 | |
| 
 | |
| extern struct kmem_cache	*xfs_exchmaps_intent_cache;
 | |
| 
 | |
| int __init xfs_exchmaps_intent_init_cache(void);
 | |
| void xfs_exchmaps_intent_destroy_cache(void);
 | |
| 
 | |
| struct xfs_exchmaps_intent *xfs_exchmaps_init_intent(
 | |
| 		const struct xfs_exchmaps_req *req);
 | |
| void xfs_exchmaps_ensure_reflink(struct xfs_trans *tp,
 | |
| 		const struct xfs_exchmaps_intent *xmi);
 | |
| void xfs_exchmaps_upgrade_extent_counts(struct xfs_trans *tp,
 | |
| 		const struct xfs_exchmaps_intent *xmi);
 | |
| 
 | |
| int xfs_exchmaps_finish_one(struct xfs_trans *tp,
 | |
| 		struct xfs_exchmaps_intent *xmi);
 | |
| 
 | |
| int xfs_exchmaps_check_forks(struct xfs_mount *mp,
 | |
| 		const struct xfs_exchmaps_req *req);
 | |
| 
 | |
| void xfs_exchange_mappings(struct xfs_trans *tp,
 | |
| 		const struct xfs_exchmaps_req *req);
 | |
| 
 | |
| #endif /* __XFS_EXCHMAPS_H__ */
 |