xref: /linux/fs/ntfs/aops.c (revision cdd4dc3aebeab43a72ce0bc2b5bab6f0a80b97a5)
11e9ea7e0SNamjae Jeon // SPDX-License-Identifier: GPL-2.0-or-later
21e9ea7e0SNamjae Jeon /*
3b041ca56SNamjae Jeon  * NTFS kernel address space operations and page cache handling.
41e9ea7e0SNamjae Jeon  *
51e9ea7e0SNamjae Jeon  * Copyright (c) 2001-2014 Anton Altaparmakov and Tuxera Inc.
61e9ea7e0SNamjae Jeon  * Copyright (c) 2002 Richard Russon
7b041ca56SNamjae Jeon  * Copyright (c) 2025 LG Electronics Co., Ltd.
81e9ea7e0SNamjae Jeon  */
91e9ea7e0SNamjae Jeon 
101e9ea7e0SNamjae Jeon #include <linux/writeback.h>
111e9ea7e0SNamjae Jeon 
121e9ea7e0SNamjae Jeon #include "attrib.h"
131e9ea7e0SNamjae Jeon #include "mft.h"
141e9ea7e0SNamjae Jeon #include "ntfs.h"
15b041ca56SNamjae Jeon #include "debug.h"
16b041ca56SNamjae Jeon #include "iomap.h"
171e9ea7e0SNamjae Jeon 
181e9ea7e0SNamjae Jeon /*
19b041ca56SNamjae Jeon  * ntfs_read_folio - Read data for a folio from the device
201e9ea7e0SNamjae Jeon  * @file:	open file to which the folio @folio belongs or NULL
211e9ea7e0SNamjae Jeon  * @folio:	page cache folio to fill with data
221e9ea7e0SNamjae Jeon  *
23b041ca56SNamjae Jeon  * This function handles reading data into the page cache. It first checks
24b041ca56SNamjae Jeon  * for specific ntfs attribute type like encryption and compression.
251e9ea7e0SNamjae Jeon  *
26b041ca56SNamjae Jeon  * - If the attribute is encrypted, access is denied (-EACCES) because
27b041ca56SNamjae Jeon  *   decryption is not supported in this path.
28b041ca56SNamjae Jeon  * - If the attribute is non-resident and compressed, the read operation is
29b041ca56SNamjae Jeon  *   delegated to ntfs_read_compressed_block().
30b041ca56SNamjae Jeon  * - For normal resident or non-resident attribute, it utilizes the generic
31b041ca56SNamjae Jeon  *   iomap infrastructure via iomap_bio_read_folio() to perform the I/O.
321e9ea7e0SNamjae Jeon  *
33b041ca56SNamjae Jeon  * Return: 0 on success, or -errno on error.
341e9ea7e0SNamjae Jeon  */
351e9ea7e0SNamjae Jeon static int ntfs_read_folio(struct file *file, struct folio *folio)
361e9ea7e0SNamjae Jeon {
37b041ca56SNamjae Jeon 	struct ntfs_inode *ni = NTFS_I(folio->mapping->host);
381e9ea7e0SNamjae Jeon 
391e9ea7e0SNamjae Jeon 	/*
401e9ea7e0SNamjae Jeon 	 * Only $DATA attributes can be encrypted and only unnamed $DATA
411e9ea7e0SNamjae Jeon 	 * attributes can be compressed.  Index root can have the flags set but
421e9ea7e0SNamjae Jeon 	 * this means to create compressed/encrypted files, not that the
431e9ea7e0SNamjae Jeon 	 * attribute is compressed/encrypted.  Note we need to check for
441e9ea7e0SNamjae Jeon 	 * AT_INDEX_ALLOCATION since this is the type of both directory and
451e9ea7e0SNamjae Jeon 	 * index inodes.
461e9ea7e0SNamjae Jeon 	 */
471e9ea7e0SNamjae Jeon 	if (ni->type != AT_INDEX_ALLOCATION) {
481e9ea7e0SNamjae Jeon 		/*
49b041ca56SNamjae Jeon 		 * EFS-encrypted files are not supported.
50b041ca56SNamjae Jeon 		 * (decryption/encryption is not implemented yet)
511e9ea7e0SNamjae Jeon 		 */
521e9ea7e0SNamjae Jeon 		if (NInoEncrypted(ni)) {
531e9ea7e0SNamjae Jeon 			folio_unlock(folio);
54b041ca56SNamjae Jeon 			return -EOPNOTSUPP;
551e9ea7e0SNamjae Jeon 		}
561e9ea7e0SNamjae Jeon 		/* Compressed data streams are handled in compress.c. */
57b041ca56SNamjae Jeon 		if (NInoNonResident(ni) && NInoCompressed(ni))
58b041ca56SNamjae Jeon 			return ntfs_read_compressed_block(folio);
591e9ea7e0SNamjae Jeon 	}
60b041ca56SNamjae Jeon 
61b041ca56SNamjae Jeon 	iomap_bio_read_folio(folio, &ntfs_read_iomap_ops);
621e9ea7e0SNamjae Jeon 	return 0;
63b041ca56SNamjae Jeon }
64b041ca56SNamjae Jeon 
651e9ea7e0SNamjae Jeon /*
661e9ea7e0SNamjae Jeon  * ntfs_bmap - map logical file block to physical device block
671e9ea7e0SNamjae Jeon  * @mapping:	address space mapping to which the block to be mapped belongs
681e9ea7e0SNamjae Jeon  * @block:	logical block to map to its physical device block
691e9ea7e0SNamjae Jeon  *
701e9ea7e0SNamjae Jeon  * For regular, non-resident files (i.e. not compressed and not encrypted), map
711e9ea7e0SNamjae Jeon  * the logical @block belonging to the file described by the address space
721e9ea7e0SNamjae Jeon  * mapping @mapping to its physical device block.
731e9ea7e0SNamjae Jeon  *
741e9ea7e0SNamjae Jeon  * The size of the block is equal to the @s_blocksize field of the super block
751e9ea7e0SNamjae Jeon  * of the mounted file system which is guaranteed to be smaller than or equal
761e9ea7e0SNamjae Jeon  * to the cluster size thus the block is guaranteed to fit entirely inside the
771e9ea7e0SNamjae Jeon  * cluster which means we do not need to care how many contiguous bytes are
781e9ea7e0SNamjae Jeon  * available after the beginning of the block.
791e9ea7e0SNamjae Jeon  *
801e9ea7e0SNamjae Jeon  * Return the physical device block if the mapping succeeded or 0 if the block
811e9ea7e0SNamjae Jeon  * is sparse or there was an error.
821e9ea7e0SNamjae Jeon  *
831e9ea7e0SNamjae Jeon  * Note: This is a problem if someone tries to run bmap() on $Boot system file
841e9ea7e0SNamjae Jeon  * as that really is in block zero but there is nothing we can do.  bmap() is
851e9ea7e0SNamjae Jeon  * just broken in that respect (just like it cannot distinguish sparse from
861e9ea7e0SNamjae Jeon  * not available or error).
871e9ea7e0SNamjae Jeon  */
881e9ea7e0SNamjae Jeon static sector_t ntfs_bmap(struct address_space *mapping, sector_t block)
891e9ea7e0SNamjae Jeon {
901e9ea7e0SNamjae Jeon 	s64 ofs, size;
911e9ea7e0SNamjae Jeon 	loff_t i_size;
92b041ca56SNamjae Jeon 	s64 lcn;
931e9ea7e0SNamjae Jeon 	unsigned long blocksize, flags;
94b041ca56SNamjae Jeon 	struct ntfs_inode *ni = NTFS_I(mapping->host);
95b041ca56SNamjae Jeon 	struct ntfs_volume *vol = ni->vol;
96b041ca56SNamjae Jeon 	unsigned int delta;
97b041ca56SNamjae Jeon 	unsigned char blocksize_bits;
981e9ea7e0SNamjae Jeon 
99*d9038d99SNamjae Jeon 	ntfs_debug("Entering for mft_no 0x%llx, logical block 0x%llx.",
1001e9ea7e0SNamjae Jeon 			ni->mft_no, (unsigned long long)block);
101b041ca56SNamjae Jeon 	if (ni->type != AT_DATA || !NInoNonResident(ni) || NInoEncrypted(ni) ||
102b041ca56SNamjae Jeon 	    NInoMstProtected(ni)) {
103b041ca56SNamjae Jeon 		ntfs_error(vol->sb, "BMAP does not make sense for %s attributes, returning 0.",
1041e9ea7e0SNamjae Jeon 				(ni->type != AT_DATA) ? "non-data" :
1051e9ea7e0SNamjae Jeon 				(!NInoNonResident(ni) ? "resident" :
1061e9ea7e0SNamjae Jeon 				"encrypted"));
1071e9ea7e0SNamjae Jeon 		return 0;
1081e9ea7e0SNamjae Jeon 	}
1091e9ea7e0SNamjae Jeon 	/* None of these can happen. */
1101e9ea7e0SNamjae Jeon 	blocksize = vol->sb->s_blocksize;
1111e9ea7e0SNamjae Jeon 	blocksize_bits = vol->sb->s_blocksize_bits;
1121e9ea7e0SNamjae Jeon 	ofs = (s64)block << blocksize_bits;
1131e9ea7e0SNamjae Jeon 	read_lock_irqsave(&ni->size_lock, flags);
1141e9ea7e0SNamjae Jeon 	size = ni->initialized_size;
1151e9ea7e0SNamjae Jeon 	i_size = i_size_read(VFS_I(ni));
1161e9ea7e0SNamjae Jeon 	read_unlock_irqrestore(&ni->size_lock, flags);
1171e9ea7e0SNamjae Jeon 	/*
1181e9ea7e0SNamjae Jeon 	 * If the offset is outside the initialized size or the block straddles
1191e9ea7e0SNamjae Jeon 	 * the initialized size then pretend it is a hole unless the
1201e9ea7e0SNamjae Jeon 	 * initialized size equals the file size.
1211e9ea7e0SNamjae Jeon 	 */
1221e9ea7e0SNamjae Jeon 	if (unlikely(ofs >= size || (ofs + blocksize > size && size < i_size)))
1231e9ea7e0SNamjae Jeon 		goto hole;
1241e9ea7e0SNamjae Jeon 	down_read(&ni->runlist.lock);
125b041ca56SNamjae Jeon 	lcn = ntfs_attr_vcn_to_lcn_nolock(ni, ntfs_bytes_to_cluster(vol, ofs),
126b041ca56SNamjae Jeon 			false);
1271e9ea7e0SNamjae Jeon 	up_read(&ni->runlist.lock);
1281e9ea7e0SNamjae Jeon 	if (unlikely(lcn < LCN_HOLE)) {
1291e9ea7e0SNamjae Jeon 		/*
1301e9ea7e0SNamjae Jeon 		 * Step down to an integer to avoid gcc doing a long long
1311e9ea7e0SNamjae Jeon 		 * comparision in the switch when we know @lcn is between
1321e9ea7e0SNamjae Jeon 		 * LCN_HOLE and LCN_EIO (i.e. -1 to -5).
1331e9ea7e0SNamjae Jeon 		 *
1341e9ea7e0SNamjae Jeon 		 * Otherwise older gcc (at least on some architectures) will
1351e9ea7e0SNamjae Jeon 		 * try to use __cmpdi2() which is of course not available in
1361e9ea7e0SNamjae Jeon 		 * the kernel.
1371e9ea7e0SNamjae Jeon 		 */
1381e9ea7e0SNamjae Jeon 		switch ((int)lcn) {
1391e9ea7e0SNamjae Jeon 		case LCN_ENOENT:
1401e9ea7e0SNamjae Jeon 			/*
1411e9ea7e0SNamjae Jeon 			 * If the offset is out of bounds then pretend it is a
1421e9ea7e0SNamjae Jeon 			 * hole.
1431e9ea7e0SNamjae Jeon 			 */
1441e9ea7e0SNamjae Jeon 			goto hole;
1451e9ea7e0SNamjae Jeon 		case LCN_ENOMEM:
146b041ca56SNamjae Jeon 			ntfs_error(vol->sb,
147*d9038d99SNamjae Jeon 				"Not enough memory to complete mapping for inode 0x%llx. Returning 0.",
148b041ca56SNamjae Jeon 				ni->mft_no);
1491e9ea7e0SNamjae Jeon 			break;
1501e9ea7e0SNamjae Jeon 		default:
151b041ca56SNamjae Jeon 			ntfs_error(vol->sb,
152*d9038d99SNamjae Jeon 				"Failed to complete mapping for inode 0x%llx.  Run chkdsk. Returning 0.",
153b041ca56SNamjae Jeon 				ni->mft_no);
1541e9ea7e0SNamjae Jeon 			break;
1551e9ea7e0SNamjae Jeon 		}
1561e9ea7e0SNamjae Jeon 		return 0;
1571e9ea7e0SNamjae Jeon 	}
1581e9ea7e0SNamjae Jeon 	if (lcn < 0) {
1591e9ea7e0SNamjae Jeon 		/* It is a hole. */
1601e9ea7e0SNamjae Jeon hole:
1611e9ea7e0SNamjae Jeon 		ntfs_debug("Done (returning hole).");
1621e9ea7e0SNamjae Jeon 		return 0;
1631e9ea7e0SNamjae Jeon 	}
1641e9ea7e0SNamjae Jeon 	/*
1651e9ea7e0SNamjae Jeon 	 * The block is really allocated and fullfils all our criteria.
1661e9ea7e0SNamjae Jeon 	 * Convert the cluster to units of block size and return the result.
1671e9ea7e0SNamjae Jeon 	 */
1681e9ea7e0SNamjae Jeon 	delta = ofs & vol->cluster_size_mask;
1691e9ea7e0SNamjae Jeon 	if (unlikely(sizeof(block) < sizeof(lcn))) {
170b041ca56SNamjae Jeon 		block = lcn = (ntfs_cluster_to_bytes(vol, lcn) + delta) >>
1711e9ea7e0SNamjae Jeon 				blocksize_bits;
1721e9ea7e0SNamjae Jeon 		/* If the block number was truncated return 0. */
1731e9ea7e0SNamjae Jeon 		if (unlikely(block != lcn)) {
174b041ca56SNamjae Jeon 			ntfs_error(vol->sb,
175b041ca56SNamjae Jeon 				"Physical block 0x%llx is too large to be returned, returning 0.",
1761e9ea7e0SNamjae Jeon 				(long long)lcn);
1771e9ea7e0SNamjae Jeon 			return 0;
1781e9ea7e0SNamjae Jeon 		}
1791e9ea7e0SNamjae Jeon 	} else
180b041ca56SNamjae Jeon 		block = (ntfs_cluster_to_bytes(vol, lcn) + delta) >>
1811e9ea7e0SNamjae Jeon 				blocksize_bits;
1821e9ea7e0SNamjae Jeon 	ntfs_debug("Done (returning block 0x%llx).", (unsigned long long)lcn);
1831e9ea7e0SNamjae Jeon 	return block;
1841e9ea7e0SNamjae Jeon }
1851e9ea7e0SNamjae Jeon 
186b041ca56SNamjae Jeon static void ntfs_readahead(struct readahead_control *rac)
187b041ca56SNamjae Jeon {
188b041ca56SNamjae Jeon 	struct address_space *mapping = rac->mapping;
189b041ca56SNamjae Jeon 	struct inode *inode = mapping->host;
190b041ca56SNamjae Jeon 	struct ntfs_inode *ni = NTFS_I(inode);
191b041ca56SNamjae Jeon 
1921e9ea7e0SNamjae Jeon 	/*
193b041ca56SNamjae Jeon 	 * Resident files are not cached in the page cache,
194b041ca56SNamjae Jeon 	 * and readahead is not implemented for compressed files.
1951e9ea7e0SNamjae Jeon 	 */
196b041ca56SNamjae Jeon 	if (!NInoNonResident(ni) || NInoCompressed(ni))
197b041ca56SNamjae Jeon 		return;
198b041ca56SNamjae Jeon 	iomap_bio_readahead(rac, &ntfs_read_iomap_ops);
199b041ca56SNamjae Jeon }
200b041ca56SNamjae Jeon 
201b041ca56SNamjae Jeon static int ntfs_writepages(struct address_space *mapping,
202b041ca56SNamjae Jeon 		struct writeback_control *wbc)
203b041ca56SNamjae Jeon {
204b041ca56SNamjae Jeon 	struct inode *inode = mapping->host;
205b041ca56SNamjae Jeon 	struct ntfs_inode *ni = NTFS_I(inode);
206b041ca56SNamjae Jeon 	struct iomap_writepage_ctx wpc = {
207b041ca56SNamjae Jeon 		.inode		= mapping->host,
208b041ca56SNamjae Jeon 		.wbc		= wbc,
209b041ca56SNamjae Jeon 		.ops		= &ntfs_writeback_ops,
210b041ca56SNamjae Jeon 	};
211b041ca56SNamjae Jeon 
212b041ca56SNamjae Jeon 	if (NVolShutdown(ni->vol))
213b041ca56SNamjae Jeon 		return -EIO;
214b041ca56SNamjae Jeon 
215b041ca56SNamjae Jeon 	if (!NInoNonResident(ni))
216b041ca56SNamjae Jeon 		return 0;
217b041ca56SNamjae Jeon 
218b041ca56SNamjae Jeon 	/*
219b041ca56SNamjae Jeon 	 * EFS-encrypted files are not supported.
220b041ca56SNamjae Jeon 	 * (decryption/encryption is not implemented yet)
221b041ca56SNamjae Jeon 	 */
222b041ca56SNamjae Jeon 	if (NInoEncrypted(ni)) {
223b041ca56SNamjae Jeon 		ntfs_debug("Encrypted I/O not supported");
224b041ca56SNamjae Jeon 		return -EOPNOTSUPP;
225b041ca56SNamjae Jeon 	}
226b041ca56SNamjae Jeon 
227b041ca56SNamjae Jeon 	return iomap_writepages(&wpc);
228b041ca56SNamjae Jeon }
229b041ca56SNamjae Jeon 
230b041ca56SNamjae Jeon static int ntfs_swap_activate(struct swap_info_struct *sis,
231b041ca56SNamjae Jeon 		struct file *swap_file, sector_t *span)
232b041ca56SNamjae Jeon {
233b041ca56SNamjae Jeon 	return iomap_swapfile_activate(sis, swap_file, span,
234b041ca56SNamjae Jeon 			&ntfs_read_iomap_ops);
235b041ca56SNamjae Jeon }
236b041ca56SNamjae Jeon 
237b041ca56SNamjae Jeon const struct address_space_operations ntfs_aops = {
2381e9ea7e0SNamjae Jeon 	.read_folio		= ntfs_read_folio,
239b041ca56SNamjae Jeon 	.readahead		= ntfs_readahead,
240b041ca56SNamjae Jeon 	.writepages		= ntfs_writepages,
241b041ca56SNamjae Jeon 	.direct_IO		= noop_direct_IO,
242b041ca56SNamjae Jeon 	.dirty_folio		= iomap_dirty_folio,
2431e9ea7e0SNamjae Jeon 	.bmap			= ntfs_bmap,
244b041ca56SNamjae Jeon 	.migrate_folio		= filemap_migrate_folio,
245b041ca56SNamjae Jeon 	.is_partially_uptodate	= iomap_is_partially_uptodate,
2461e9ea7e0SNamjae Jeon 	.error_remove_folio	= generic_error_remove_folio,
247b041ca56SNamjae Jeon 	.release_folio		= iomap_release_folio,
248b041ca56SNamjae Jeon 	.invalidate_folio	= iomap_invalidate_folio,
249b041ca56SNamjae Jeon 	.swap_activate          = ntfs_swap_activate,
2501e9ea7e0SNamjae Jeon };
2511e9ea7e0SNamjae Jeon 
252b041ca56SNamjae Jeon const struct address_space_operations ntfs_mft_aops = {
2531e9ea7e0SNamjae Jeon 	.read_folio		= ntfs_read_folio,
254b041ca56SNamjae Jeon 	.readahead		= ntfs_readahead,
255b041ca56SNamjae Jeon 	.writepages		= ntfs_mft_writepages,
256b041ca56SNamjae Jeon 	.dirty_folio		= iomap_dirty_folio,
257b041ca56SNamjae Jeon 	.bmap			= ntfs_bmap,
258b041ca56SNamjae Jeon 	.migrate_folio		= filemap_migrate_folio,
259b041ca56SNamjae Jeon 	.is_partially_uptodate	= iomap_is_partially_uptodate,
2601e9ea7e0SNamjae Jeon 	.error_remove_folio	= generic_error_remove_folio,
261b041ca56SNamjae Jeon 	.release_folio		= iomap_release_folio,
262b041ca56SNamjae Jeon 	.invalidate_folio	= iomap_invalidate_folio,
2631e9ea7e0SNamjae Jeon };
264