11e9ea7e0SNamjae Jeon // SPDX-License-Identifier: GPL-2.0-or-later 21e9ea7e0SNamjae Jeon /* 39c879596SNamjae Jeon * NTFS kernel file operations. 41e9ea7e0SNamjae Jeon * 51e9ea7e0SNamjae Jeon * Copyright (c) 2001-2015 Anton Altaparmakov and Tuxera Inc. 69c879596SNamjae Jeon * Copyright (c) 2025 LG Electronics Co., Ltd. 71e9ea7e0SNamjae Jeon */ 81e9ea7e0SNamjae Jeon 91e9ea7e0SNamjae Jeon #include <linux/writeback.h> 109c879596SNamjae Jeon #include <linux/blkdev.h> 119c879596SNamjae Jeon #include <linux/fs.h> 129c879596SNamjae Jeon #include <linux/iomap.h> 139c879596SNamjae Jeon #include <linux/uio.h> 149c879596SNamjae Jeon #include <linux/posix_acl.h> 159c879596SNamjae Jeon #include <linux/posix_acl_xattr.h> 169c879596SNamjae Jeon #include <linux/compat.h> 179c879596SNamjae Jeon #include <linux/falloc.h> 181e9ea7e0SNamjae Jeon 191e9ea7e0SNamjae Jeon #include "lcnalloc.h" 201e9ea7e0SNamjae Jeon #include "ntfs.h" 219c879596SNamjae Jeon #include "reparse.h" 229c879596SNamjae Jeon #include "ea.h" 239c879596SNamjae Jeon #include "iomap.h" 249c879596SNamjae Jeon #include "bitmap.h" 251e9ea7e0SNamjae Jeon 269c879596SNamjae Jeon #include <linux/filelock.h> 279c879596SNamjae Jeon 289c879596SNamjae Jeon /* 291e9ea7e0SNamjae Jeon * ntfs_file_open - called when an inode is about to be opened 301e9ea7e0SNamjae Jeon * @vi: inode to be opened 311e9ea7e0SNamjae Jeon * @filp: file structure describing the inode 321e9ea7e0SNamjae Jeon * 331e9ea7e0SNamjae Jeon * Limit file size to the page cache limit on architectures where unsigned long 341e9ea7e0SNamjae Jeon * is 32-bits. This is the most we can do for now without overflowing the page 351e9ea7e0SNamjae Jeon * cache page index. Doing it this way means we don't run into problems because 361e9ea7e0SNamjae Jeon * of existing too large files. It would be better to allow the user to read 371e9ea7e0SNamjae Jeon * the beginning of the file but I doubt very much anyone is going to hit this 381e9ea7e0SNamjae Jeon * check on a 32-bit architecture, so there is no point in adding the extra 391e9ea7e0SNamjae Jeon * complexity required to support this. 401e9ea7e0SNamjae Jeon * 411e9ea7e0SNamjae Jeon * On 64-bit architectures, the check is hopefully optimized away by the 421e9ea7e0SNamjae Jeon * compiler. 431e9ea7e0SNamjae Jeon * 441e9ea7e0SNamjae Jeon * After the check passes, just call generic_file_open() to do its work. 451e9ea7e0SNamjae Jeon */ 461e9ea7e0SNamjae Jeon static int ntfs_file_open(struct inode *vi, struct file *filp) 471e9ea7e0SNamjae Jeon { 489c879596SNamjae Jeon struct ntfs_inode *ni = NTFS_I(vi); 499c879596SNamjae Jeon 509c879596SNamjae Jeon if (NVolShutdown(ni->vol)) 519c879596SNamjae Jeon return -EIO; 529c879596SNamjae Jeon 531e9ea7e0SNamjae Jeon if (sizeof(unsigned long) < 8) { 541e9ea7e0SNamjae Jeon if (i_size_read(vi) > MAX_LFS_FILESIZE) 551e9ea7e0SNamjae Jeon return -EOVERFLOW; 561e9ea7e0SNamjae Jeon } 579c879596SNamjae Jeon 589c879596SNamjae Jeon filp->f_mode |= FMODE_NOWAIT | FMODE_CAN_ODIRECT; 599c879596SNamjae Jeon 601e9ea7e0SNamjae Jeon return generic_file_open(vi, filp); 611e9ea7e0SNamjae Jeon } 621e9ea7e0SNamjae Jeon 639c879596SNamjae Jeon /* 649c879596SNamjae Jeon * Trim preallocated space on file release. 651e9ea7e0SNamjae Jeon * 669c879596SNamjae Jeon * When the preallo_size mount option is set (default 64KB), writes extend 679c879596SNamjae Jeon * allocated_size and runlist in units of preallocated size to reduce 689c879596SNamjae Jeon * runlist merge overhead for small writes. This can leave 699c879596SNamjae Jeon * allocated_size > data_size if not all preallocated space is used. 701e9ea7e0SNamjae Jeon * 719c879596SNamjae Jeon * We perform the trim here because ->release() is called only when 729c879596SNamjae Jeon * the file is no longer open. At this point, no further writes can occur, 739c879596SNamjae Jeon * so it is safe to reclaim the unused preallocated space. 741e9ea7e0SNamjae Jeon * 759c879596SNamjae Jeon * Returns 0 on success, or negative error on failure. 761e9ea7e0SNamjae Jeon */ 779c879596SNamjae Jeon static int ntfs_trim_prealloc(struct inode *vi) 781e9ea7e0SNamjae Jeon { 799c879596SNamjae Jeon struct ntfs_inode *ni = NTFS_I(vi); 809c879596SNamjae Jeon struct ntfs_volume *vol = ni->vol; 819c879596SNamjae Jeon struct runlist_element *rl; 829c879596SNamjae Jeon s64 aligned_data_size; 839c879596SNamjae Jeon s64 vcn_ds, vcn_tr; 849c879596SNamjae Jeon ssize_t rc; 859c879596SNamjae Jeon int err = 0; 861e9ea7e0SNamjae Jeon 871e9ea7e0SNamjae Jeon inode_lock(vi); 889c879596SNamjae Jeon mutex_lock(&ni->mrec_lock); 899c879596SNamjae Jeon down_write(&ni->runlist.lock); 909c879596SNamjae Jeon 919c879596SNamjae Jeon aligned_data_size = round_up(ni->data_size, vol->cluster_size); 929c879596SNamjae Jeon if (aligned_data_size >= ni->allocated_size) 939c879596SNamjae Jeon goto out_unlock; 949c879596SNamjae Jeon 959c879596SNamjae Jeon vcn_ds = ntfs_bytes_to_cluster(vol, aligned_data_size); 969c879596SNamjae Jeon vcn_tr = -1; 979c879596SNamjae Jeon rc = ni->runlist.count - 2; 989c879596SNamjae Jeon rl = ni->runlist.rl; 999c879596SNamjae Jeon 1009c879596SNamjae Jeon while (rc >= 0 && rl[rc].lcn == LCN_HOLE && vcn_ds <= rl[rc].vcn) { 1019c879596SNamjae Jeon vcn_tr = rl[rc].vcn; 1029c879596SNamjae Jeon rc--; 1031e9ea7e0SNamjae Jeon } 1041e9ea7e0SNamjae Jeon 1059c879596SNamjae Jeon if (vcn_tr >= 0) { 1069c879596SNamjae Jeon err = ntfs_rl_truncate_nolock(vol, &ni->runlist, vcn_tr); 1079c879596SNamjae Jeon if (err) { 1089c879596SNamjae Jeon kvfree(ni->runlist.rl); 1099c879596SNamjae Jeon ni->runlist.rl = NULL; 1109c879596SNamjae Jeon ntfs_error(vol->sb, "Preallocated block rollback failed"); 1119c879596SNamjae Jeon } else { 1129c879596SNamjae Jeon ni->allocated_size = ntfs_cluster_to_bytes(vol, vcn_tr); 1139c879596SNamjae Jeon err = ntfs_attr_update_mapping_pairs(ni, 0); 1149c879596SNamjae Jeon if (err) 1159c879596SNamjae Jeon ntfs_error(vol->sb, 1169c879596SNamjae Jeon "Failed to rollback mapping pairs for prealloc"); 1179c879596SNamjae Jeon } 1189c879596SNamjae Jeon } 1199c879596SNamjae Jeon 1209c879596SNamjae Jeon out_unlock: 1219c879596SNamjae Jeon up_write(&ni->runlist.lock); 1229c879596SNamjae Jeon mutex_unlock(&ni->mrec_lock); 1239c879596SNamjae Jeon inode_unlock(vi); 1249c879596SNamjae Jeon 1259c879596SNamjae Jeon return err; 1269c879596SNamjae Jeon } 1279c879596SNamjae Jeon 1289c879596SNamjae Jeon static int ntfs_file_release(struct inode *vi, struct file *filp) 1299c879596SNamjae Jeon { 1309c879596SNamjae Jeon if (!NInoCompressed(NTFS_I(vi))) 1319c879596SNamjae Jeon return ntfs_trim_prealloc(vi); 1329c879596SNamjae Jeon 1339c879596SNamjae Jeon return 0; 1349c879596SNamjae Jeon } 1359c879596SNamjae Jeon 1369c879596SNamjae Jeon /* 1371e9ea7e0SNamjae Jeon * ntfs_file_fsync - sync a file to disk 1381e9ea7e0SNamjae Jeon * @filp: file to be synced 1399c879596SNamjae Jeon * @start: start offset to be synced 1409c879596SNamjae Jeon * @end: end offset to be synced 1411e9ea7e0SNamjae Jeon * @datasync: if non-zero only flush user data and not metadata 1421e9ea7e0SNamjae Jeon * 1431e9ea7e0SNamjae Jeon * Data integrity sync of a file to disk. Used for fsync, fdatasync, and msync 1441e9ea7e0SNamjae Jeon * system calls. This function is inspired by fs/buffer.c::file_fsync(). 1451e9ea7e0SNamjae Jeon * 1461e9ea7e0SNamjae Jeon * If @datasync is false, write the mft record and all associated extent mft 1471e9ea7e0SNamjae Jeon * records as well as the $DATA attribute and then sync the block device. 1481e9ea7e0SNamjae Jeon * 1491e9ea7e0SNamjae Jeon * If @datasync is true and the attribute is non-resident, we skip the writing 1501e9ea7e0SNamjae Jeon * of the mft record and all associated extent mft records (this might still 1511e9ea7e0SNamjae Jeon * happen due to the write_inode_now() call). 1521e9ea7e0SNamjae Jeon * 1531e9ea7e0SNamjae Jeon * Also, if @datasync is true, we do not wait on the inode to be written out 1541e9ea7e0SNamjae Jeon * but we always wait on the page cache pages to be written out. 1551e9ea7e0SNamjae Jeon */ 1561e9ea7e0SNamjae Jeon static int ntfs_file_fsync(struct file *filp, loff_t start, loff_t end, 1571e9ea7e0SNamjae Jeon int datasync) 1581e9ea7e0SNamjae Jeon { 1591e9ea7e0SNamjae Jeon struct inode *vi = filp->f_mapping->host; 1609c879596SNamjae Jeon struct ntfs_inode *ni = NTFS_I(vi); 1619c879596SNamjae Jeon struct ntfs_volume *vol = ni->vol; 1621e9ea7e0SNamjae Jeon int err, ret = 0; 1639c879596SNamjae Jeon struct inode *parent_vi, *ia_vi; 1649c879596SNamjae Jeon struct ntfs_attr_search_ctx *ctx; 1651e9ea7e0SNamjae Jeon 166e7d82353SNamjae Jeon ntfs_debug("Entering for inode 0x%llx.", ni->mft_no); 1671e9ea7e0SNamjae Jeon 1689c879596SNamjae Jeon if (NVolShutdown(vol)) 1699c879596SNamjae Jeon return -EIO; 1709c879596SNamjae Jeon 1711e9ea7e0SNamjae Jeon err = file_write_and_wait_range(filp, start, end); 1721e9ea7e0SNamjae Jeon if (err) 1731e9ea7e0SNamjae Jeon return err; 1741e9ea7e0SNamjae Jeon 1751e9ea7e0SNamjae Jeon if (!datasync || !NInoNonResident(NTFS_I(vi))) 1761e9ea7e0SNamjae Jeon ret = __ntfs_write_inode(vi, 1); 1771e9ea7e0SNamjae Jeon write_inode_now(vi, !datasync); 1789c879596SNamjae Jeon 1799c879596SNamjae Jeon ctx = ntfs_attr_get_search_ctx(ni, NULL); 1809c879596SNamjae Jeon if (!ctx) 1819c879596SNamjae Jeon return -ENOMEM; 1829c879596SNamjae Jeon 1839c879596SNamjae Jeon mutex_lock_nested(&ni->mrec_lock, NTFS_INODE_MUTEX_NORMAL_CHILD); 1849c879596SNamjae Jeon while (!(err = ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx))) { 1859c879596SNamjae Jeon if (ctx->attr->type == AT_FILE_NAME) { 1869c879596SNamjae Jeon struct file_name_attr *fn = (struct file_name_attr *)((u8 *)ctx->attr + 1879c879596SNamjae Jeon le16_to_cpu(ctx->attr->data.resident.value_offset)); 1889c879596SNamjae Jeon 1899c879596SNamjae Jeon parent_vi = ntfs_iget(vi->i_sb, MREF_LE(fn->parent_directory)); 1909c879596SNamjae Jeon if (IS_ERR(parent_vi)) 1919c879596SNamjae Jeon continue; 1929c879596SNamjae Jeon mutex_lock_nested(&NTFS_I(parent_vi)->mrec_lock, NTFS_INODE_MUTEX_NORMAL); 1939c879596SNamjae Jeon ia_vi = ntfs_index_iget(parent_vi, I30, 4); 1949c879596SNamjae Jeon mutex_unlock(&NTFS_I(parent_vi)->mrec_lock); 1959c879596SNamjae Jeon if (IS_ERR(ia_vi)) { 1969c879596SNamjae Jeon iput(parent_vi); 1979c879596SNamjae Jeon continue; 1989c879596SNamjae Jeon } 1999c879596SNamjae Jeon write_inode_now(ia_vi, 1); 2009c879596SNamjae Jeon iput(ia_vi); 2019c879596SNamjae Jeon write_inode_now(parent_vi, 1); 2029c879596SNamjae Jeon iput(parent_vi); 2039c879596SNamjae Jeon } else if (ctx->attr->non_resident) { 2049c879596SNamjae Jeon struct inode *attr_vi; 2059c879596SNamjae Jeon __le16 *name; 2069c879596SNamjae Jeon 2079c879596SNamjae Jeon name = (__le16 *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->name_offset)); 2089c879596SNamjae Jeon if (ctx->attr->type == AT_DATA && ctx->attr->name_length == 0) 2099c879596SNamjae Jeon continue; 2109c879596SNamjae Jeon 2119c879596SNamjae Jeon attr_vi = ntfs_attr_iget(vi, ctx->attr->type, 2129c879596SNamjae Jeon name, ctx->attr->name_length); 2139c879596SNamjae Jeon if (IS_ERR(attr_vi)) 2149c879596SNamjae Jeon continue; 2159c879596SNamjae Jeon spin_lock(&attr_vi->i_lock); 2169c879596SNamjae Jeon if (inode_state_read_once(attr_vi) & I_DIRTY_PAGES) { 2179c879596SNamjae Jeon spin_unlock(&attr_vi->i_lock); 2189c879596SNamjae Jeon filemap_write_and_wait(attr_vi->i_mapping); 2199c879596SNamjae Jeon } else 2209c879596SNamjae Jeon spin_unlock(&attr_vi->i_lock); 2219c879596SNamjae Jeon iput(attr_vi); 2229c879596SNamjae Jeon } 2239c879596SNamjae Jeon } 2249c879596SNamjae Jeon mutex_unlock(&ni->mrec_lock); 2259c879596SNamjae Jeon ntfs_attr_put_search_ctx(ctx); 2269c879596SNamjae Jeon 2279c879596SNamjae Jeon write_inode_now(vol->mftbmp_ino, 1); 2289c879596SNamjae Jeon down_write(&vol->lcnbmp_lock); 2299c879596SNamjae Jeon write_inode_now(vol->lcnbmp_ino, 1); 2309c879596SNamjae Jeon up_write(&vol->lcnbmp_lock); 2319c879596SNamjae Jeon write_inode_now(vol->mft_ino, 1); 2329c879596SNamjae Jeon 2331e9ea7e0SNamjae Jeon /* 2341e9ea7e0SNamjae Jeon * NOTE: If we were to use mapping->private_list (see ext2 and 2351e9ea7e0SNamjae Jeon * fs/buffer.c) for dirty blocks then we could optimize the below to be 2361e9ea7e0SNamjae Jeon * sync_mapping_buffers(vi->i_mapping). 2371e9ea7e0SNamjae Jeon */ 2381e9ea7e0SNamjae Jeon err = sync_blockdev(vi->i_sb->s_bdev); 2391e9ea7e0SNamjae Jeon if (unlikely(err && !ret)) 2401e9ea7e0SNamjae Jeon ret = err; 2411e9ea7e0SNamjae Jeon if (likely(!ret)) 2421e9ea7e0SNamjae Jeon ntfs_debug("Done."); 2431e9ea7e0SNamjae Jeon else 2449c879596SNamjae Jeon ntfs_warning(vi->i_sb, 245e7d82353SNamjae Jeon "Failed to f%ssync inode 0x%llx. Error %u.", 246e7d82353SNamjae Jeon datasync ? "data" : "", ni->mft_no, -ret); 2479c879596SNamjae Jeon if (!ret) 2489c879596SNamjae Jeon blkdev_issue_flush(vi->i_sb->s_bdev); 2491e9ea7e0SNamjae Jeon return ret; 2501e9ea7e0SNamjae Jeon } 2511e9ea7e0SNamjae Jeon 2529c879596SNamjae Jeon static int ntfs_setattr_size(struct inode *vi, struct iattr *attr) 2539c879596SNamjae Jeon { 2549c879596SNamjae Jeon struct ntfs_inode *ni = NTFS_I(vi); 2559c879596SNamjae Jeon int err; 2569c879596SNamjae Jeon loff_t old_size = vi->i_size; 2579c879596SNamjae Jeon 2589c879596SNamjae Jeon if (NInoCompressed(ni) || NInoEncrypted(ni)) { 2599c879596SNamjae Jeon ntfs_warning(vi->i_sb, 2609c879596SNamjae Jeon "Changes in inode size are not supported yet for %s files, ignoring.", 2619c879596SNamjae Jeon NInoCompressed(ni) ? "compressed" : "encrypted"); 2629c879596SNamjae Jeon return -EOPNOTSUPP; 2639c879596SNamjae Jeon } 2649c879596SNamjae Jeon 2659c879596SNamjae Jeon err = inode_newsize_ok(vi, attr->ia_size); 2669c879596SNamjae Jeon if (err) 2679c879596SNamjae Jeon return err; 2689c879596SNamjae Jeon 2699c879596SNamjae Jeon inode_dio_wait(vi); 2709c879596SNamjae Jeon /* Serialize against page faults */ 2719c879596SNamjae Jeon if (NInoNonResident(NTFS_I(vi)) && attr->ia_size < old_size) { 2729c879596SNamjae Jeon err = iomap_truncate_page(vi, attr->ia_size, NULL, 2739c879596SNamjae Jeon &ntfs_read_iomap_ops, 2749c879596SNamjae Jeon &ntfs_iomap_folio_ops, NULL); 2759c879596SNamjae Jeon if (err) 2769c879596SNamjae Jeon return err; 2779c879596SNamjae Jeon } 2789c879596SNamjae Jeon 2799c879596SNamjae Jeon truncate_setsize(vi, attr->ia_size); 2809c879596SNamjae Jeon err = ntfs_truncate_vfs(vi, attr->ia_size, old_size); 2819c879596SNamjae Jeon if (err) { 2829c879596SNamjae Jeon i_size_write(vi, old_size); 2839c879596SNamjae Jeon return err; 2849c879596SNamjae Jeon } 2859c879596SNamjae Jeon 2869c879596SNamjae Jeon if (NInoNonResident(ni) && attr->ia_size > old_size && 2879c879596SNamjae Jeon old_size % PAGE_SIZE != 0) { 2889c879596SNamjae Jeon loff_t len = min_t(loff_t, 2899c879596SNamjae Jeon round_up(old_size, PAGE_SIZE) - old_size, 2909c879596SNamjae Jeon attr->ia_size - old_size); 2919c879596SNamjae Jeon err = iomap_zero_range(vi, old_size, len, 2929c879596SNamjae Jeon NULL, &ntfs_seek_iomap_ops, 2939c879596SNamjae Jeon &ntfs_iomap_folio_ops, NULL); 2949c879596SNamjae Jeon } 2959c879596SNamjae Jeon 2969c879596SNamjae Jeon return err; 2979c879596SNamjae Jeon } 2989c879596SNamjae Jeon 2999c879596SNamjae Jeon /* 3009c879596SNamjae Jeon * ntfs_setattr 3019c879596SNamjae Jeon * 3029c879596SNamjae Jeon * Called from notify_change() when an attribute is being changed. 3039c879596SNamjae Jeon * 3049c879596SNamjae Jeon * NOTE: Changes in inode size are not supported yet for compressed or 3059c879596SNamjae Jeon * encrypted files. 3069c879596SNamjae Jeon */ 3079c879596SNamjae Jeon int ntfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, 3089c879596SNamjae Jeon struct iattr *attr) 3099c879596SNamjae Jeon { 3109c879596SNamjae Jeon struct inode *vi = d_inode(dentry); 3119c879596SNamjae Jeon int err; 3129c879596SNamjae Jeon unsigned int ia_valid = attr->ia_valid; 3139c879596SNamjae Jeon struct ntfs_inode *ni = NTFS_I(vi); 3149c879596SNamjae Jeon struct ntfs_volume *vol = ni->vol; 3159c879596SNamjae Jeon 3169c879596SNamjae Jeon if (NVolShutdown(vol)) 3179c879596SNamjae Jeon return -EIO; 3189c879596SNamjae Jeon 3199c879596SNamjae Jeon err = setattr_prepare(idmap, dentry, attr); 3209c879596SNamjae Jeon if (err) 3219c879596SNamjae Jeon goto out; 3229c879596SNamjae Jeon 3239c879596SNamjae Jeon if (!(vol->vol_flags & VOLUME_IS_DIRTY)) 3249c879596SNamjae Jeon ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY); 3259c879596SNamjae Jeon 3269c879596SNamjae Jeon if (ia_valid & ATTR_SIZE) { 3279c879596SNamjae Jeon err = ntfs_setattr_size(vi, attr); 3289c879596SNamjae Jeon if (err) 3299c879596SNamjae Jeon goto out; 3309c879596SNamjae Jeon 3319c879596SNamjae Jeon ia_valid |= ATTR_MTIME | ATTR_CTIME; 3329c879596SNamjae Jeon } 3339c879596SNamjae Jeon 3349c879596SNamjae Jeon setattr_copy(idmap, vi, attr); 3359c879596SNamjae Jeon 3369c879596SNamjae Jeon if (vol->sb->s_flags & SB_POSIXACL && !S_ISLNK(vi->i_mode)) { 3379c879596SNamjae Jeon err = posix_acl_chmod(idmap, dentry, vi->i_mode); 3389c879596SNamjae Jeon if (err) 3399c879596SNamjae Jeon goto out; 3409c879596SNamjae Jeon } 3419c879596SNamjae Jeon 3429c879596SNamjae Jeon if (0222 & vi->i_mode) 3439c879596SNamjae Jeon ni->flags &= ~FILE_ATTR_READONLY; 3449c879596SNamjae Jeon else 3459c879596SNamjae Jeon ni->flags |= FILE_ATTR_READONLY; 3469c879596SNamjae Jeon 3479c879596SNamjae Jeon if (ia_valid & (ATTR_UID | ATTR_GID | ATTR_MODE)) { 3489c879596SNamjae Jeon unsigned int flags = 0; 3499c879596SNamjae Jeon 3509c879596SNamjae Jeon if (ia_valid & ATTR_UID) 3519c879596SNamjae Jeon flags |= NTFS_EA_UID; 3529c879596SNamjae Jeon if (ia_valid & ATTR_GID) 3539c879596SNamjae Jeon flags |= NTFS_EA_GID; 3549c879596SNamjae Jeon if (ia_valid & ATTR_MODE) 3559c879596SNamjae Jeon flags |= NTFS_EA_MODE; 3569c879596SNamjae Jeon 3579c879596SNamjae Jeon if (S_ISDIR(vi->i_mode)) 3589c879596SNamjae Jeon vi->i_mode &= ~vol->dmask; 3599c879596SNamjae Jeon else 3609c879596SNamjae Jeon vi->i_mode &= ~vol->fmask; 3619c879596SNamjae Jeon 3629c879596SNamjae Jeon mutex_lock(&ni->mrec_lock); 3639c879596SNamjae Jeon ntfs_ea_set_wsl_inode(vi, 0, NULL, flags); 3649c879596SNamjae Jeon mutex_unlock(&ni->mrec_lock); 3659c879596SNamjae Jeon } 3669c879596SNamjae Jeon 3679c879596SNamjae Jeon mark_inode_dirty(vi); 3689c879596SNamjae Jeon out: 3699c879596SNamjae Jeon return err; 3709c879596SNamjae Jeon } 3719c879596SNamjae Jeon 3729c879596SNamjae Jeon int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path, 3739c879596SNamjae Jeon struct kstat *stat, unsigned int request_mask, 3749c879596SNamjae Jeon unsigned int query_flags) 3759c879596SNamjae Jeon { 3769c879596SNamjae Jeon struct inode *inode = d_backing_inode(path->dentry); 3779c879596SNamjae Jeon struct ntfs_inode *ni = NTFS_I(inode); 3789c879596SNamjae Jeon 3799c879596SNamjae Jeon generic_fillattr(idmap, request_mask, inode, stat); 3809c879596SNamjae Jeon 3819c879596SNamjae Jeon stat->blksize = NTFS_SB(inode->i_sb)->cluster_size; 3829c879596SNamjae Jeon stat->blocks = (((u64)NTFS_I(inode)->i_dealloc_clusters << 3839c879596SNamjae Jeon NTFS_SB(inode->i_sb)->cluster_size_bits) >> 9) + inode->i_blocks; 3849c879596SNamjae Jeon stat->result_mask |= STATX_BTIME; 3859c879596SNamjae Jeon stat->btime = NTFS_I(inode)->i_crtime; 3869c879596SNamjae Jeon 3879c879596SNamjae Jeon if (NInoCompressed(ni)) 3889c879596SNamjae Jeon stat->attributes |= STATX_ATTR_COMPRESSED; 3899c879596SNamjae Jeon 3909c879596SNamjae Jeon if (NInoEncrypted(ni)) 3919c879596SNamjae Jeon stat->attributes |= STATX_ATTR_ENCRYPTED; 3929c879596SNamjae Jeon 3939c879596SNamjae Jeon if (inode->i_flags & S_IMMUTABLE) 3949c879596SNamjae Jeon stat->attributes |= STATX_ATTR_IMMUTABLE; 3959c879596SNamjae Jeon 3969c879596SNamjae Jeon if (inode->i_flags & S_APPEND) 3979c879596SNamjae Jeon stat->attributes |= STATX_ATTR_APPEND; 3989c879596SNamjae Jeon 3999c879596SNamjae Jeon stat->attributes_mask |= STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED | 4009c879596SNamjae Jeon STATX_ATTR_IMMUTABLE | STATX_ATTR_APPEND; 4019c879596SNamjae Jeon 4029c879596SNamjae Jeon /* 4039c879596SNamjae Jeon * If it's a compressed or encrypted file, NTFS currently 4049c879596SNamjae Jeon * does not support DIO. For normal files, we report the bdev 4059c879596SNamjae Jeon * logical block size. 4069c879596SNamjae Jeon */ 4079c879596SNamjae Jeon if (request_mask & STATX_DIOALIGN && S_ISREG(inode->i_mode)) { 4089c879596SNamjae Jeon unsigned int align = 4099c879596SNamjae Jeon bdev_logical_block_size(inode->i_sb->s_bdev); 4109c879596SNamjae Jeon 4119c879596SNamjae Jeon stat->result_mask |= STATX_DIOALIGN; 4129c879596SNamjae Jeon if (!NInoCompressed(ni) && !NInoEncrypted(ni)) { 4139c879596SNamjae Jeon stat->dio_mem_align = align; 4149c879596SNamjae Jeon stat->dio_offset_align = align; 4159c879596SNamjae Jeon } 4169c879596SNamjae Jeon } 4179c879596SNamjae Jeon 4189c879596SNamjae Jeon return 0; 4199c879596SNamjae Jeon } 4209c879596SNamjae Jeon 4219c879596SNamjae Jeon static loff_t ntfs_file_llseek(struct file *file, loff_t offset, int whence) 4229c879596SNamjae Jeon { 4239c879596SNamjae Jeon struct inode *inode = file->f_mapping->host; 4249c879596SNamjae Jeon 4259c879596SNamjae Jeon switch (whence) { 4269c879596SNamjae Jeon case SEEK_HOLE: 4279c879596SNamjae Jeon inode_lock_shared(inode); 4289c879596SNamjae Jeon offset = iomap_seek_hole(inode, offset, &ntfs_seek_iomap_ops); 4299c879596SNamjae Jeon inode_unlock_shared(inode); 4309c879596SNamjae Jeon break; 4319c879596SNamjae Jeon case SEEK_DATA: 4329c879596SNamjae Jeon inode_lock_shared(inode); 4339c879596SNamjae Jeon offset = iomap_seek_data(inode, offset, &ntfs_seek_iomap_ops); 4349c879596SNamjae Jeon inode_unlock_shared(inode); 4359c879596SNamjae Jeon break; 4369c879596SNamjae Jeon default: 4379c879596SNamjae Jeon return generic_file_llseek_size(file, offset, whence, 4389c879596SNamjae Jeon inode->i_sb->s_maxbytes, 4399c879596SNamjae Jeon i_size_read(inode)); 4409c879596SNamjae Jeon } 4419c879596SNamjae Jeon if (offset < 0) 4429c879596SNamjae Jeon return offset; 4439c879596SNamjae Jeon return vfs_setpos(file, offset, inode->i_sb->s_maxbytes); 4449c879596SNamjae Jeon } 4459c879596SNamjae Jeon 4469c879596SNamjae Jeon static ssize_t ntfs_file_read_iter(struct kiocb *iocb, struct iov_iter *to) 4479c879596SNamjae Jeon { 4489c879596SNamjae Jeon struct inode *vi = file_inode(iocb->ki_filp); 4499c879596SNamjae Jeon struct super_block *sb = vi->i_sb; 4509c879596SNamjae Jeon ssize_t ret; 4519c879596SNamjae Jeon 4529c879596SNamjae Jeon if (NVolShutdown(NTFS_SB(sb))) 4539c879596SNamjae Jeon return -EIO; 4549c879596SNamjae Jeon 4559c879596SNamjae Jeon if (NInoCompressed(NTFS_I(vi)) && iocb->ki_flags & IOCB_DIRECT) 4569c879596SNamjae Jeon return -EOPNOTSUPP; 4579c879596SNamjae Jeon 4589c879596SNamjae Jeon inode_lock_shared(vi); 4599c879596SNamjae Jeon 4609c879596SNamjae Jeon if (iocb->ki_flags & IOCB_DIRECT) { 4619c879596SNamjae Jeon size_t count = iov_iter_count(to); 4629c879596SNamjae Jeon 4639c879596SNamjae Jeon if ((iocb->ki_pos | count) & (sb->s_blocksize - 1)) { 4649c879596SNamjae Jeon ret = -EINVAL; 4659c879596SNamjae Jeon goto inode_unlock; 4669c879596SNamjae Jeon } 4679c879596SNamjae Jeon 4689c879596SNamjae Jeon file_accessed(iocb->ki_filp); 4699c879596SNamjae Jeon ret = iomap_dio_rw(iocb, to, &ntfs_read_iomap_ops, NULL, 0, 4709c879596SNamjae Jeon NULL, 0); 4719c879596SNamjae Jeon } else { 4729c879596SNamjae Jeon ret = generic_file_read_iter(iocb, to); 4739c879596SNamjae Jeon } 4749c879596SNamjae Jeon 4759c879596SNamjae Jeon inode_unlock: 4769c879596SNamjae Jeon inode_unlock_shared(vi); 4779c879596SNamjae Jeon 4789c879596SNamjae Jeon return ret; 4799c879596SNamjae Jeon } 4809c879596SNamjae Jeon 4819c879596SNamjae Jeon static int ntfs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size, 4829c879596SNamjae Jeon int error, unsigned int flags) 4839c879596SNamjae Jeon { 4849c879596SNamjae Jeon struct inode *inode = file_inode(iocb->ki_filp); 4859c879596SNamjae Jeon 4869c879596SNamjae Jeon if (error) 4879c879596SNamjae Jeon return error; 4889c879596SNamjae Jeon 4899c879596SNamjae Jeon if (size) { 4909c879596SNamjae Jeon if (i_size_read(inode) < iocb->ki_pos + size) { 4919c879596SNamjae Jeon i_size_write(inode, iocb->ki_pos + size); 4929c879596SNamjae Jeon mark_inode_dirty(inode); 4939c879596SNamjae Jeon } 4949c879596SNamjae Jeon } 4959c879596SNamjae Jeon 4969c879596SNamjae Jeon return 0; 4979c879596SNamjae Jeon } 4989c879596SNamjae Jeon 4999c879596SNamjae Jeon static const struct iomap_dio_ops ntfs_write_dio_ops = { 5009c879596SNamjae Jeon .end_io = ntfs_file_write_dio_end_io, 5019c879596SNamjae Jeon }; 5029c879596SNamjae Jeon 5039c879596SNamjae Jeon static ssize_t ntfs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from) 5049c879596SNamjae Jeon { 5059c879596SNamjae Jeon ssize_t ret; 5069c879596SNamjae Jeon 5079c879596SNamjae Jeon ret = iomap_dio_rw(iocb, from, &ntfs_dio_iomap_ops, 5089c879596SNamjae Jeon &ntfs_write_dio_ops, 0, NULL, 0); 5099c879596SNamjae Jeon if (ret == -ENOTBLK) 5109c879596SNamjae Jeon ret = 0; 5119c879596SNamjae Jeon else if (ret < 0) 5129c879596SNamjae Jeon goto out; 5139c879596SNamjae Jeon 5149c879596SNamjae Jeon if (iov_iter_count(from)) { 5159c879596SNamjae Jeon loff_t offset, end; 5169c879596SNamjae Jeon ssize_t written; 5179c879596SNamjae Jeon int ret2; 5189c879596SNamjae Jeon 5199c879596SNamjae Jeon offset = iocb->ki_pos; 5209c879596SNamjae Jeon iocb->ki_flags &= ~IOCB_DIRECT; 5219c879596SNamjae Jeon written = iomap_file_buffered_write(iocb, from, 5229c879596SNamjae Jeon &ntfs_write_iomap_ops, &ntfs_iomap_folio_ops, 5239c879596SNamjae Jeon NULL); 5249c879596SNamjae Jeon if (written < 0) { 5259c879596SNamjae Jeon ret = written; 5269c879596SNamjae Jeon goto out; 5279c879596SNamjae Jeon } 5289c879596SNamjae Jeon 5299c879596SNamjae Jeon ret += written; 5309c879596SNamjae Jeon end = iocb->ki_pos + written - 1; 5319c879596SNamjae Jeon ret2 = filemap_write_and_wait_range(iocb->ki_filp->f_mapping, 5329c879596SNamjae Jeon offset, end); 5339c879596SNamjae Jeon if (ret2) { 5349c879596SNamjae Jeon ret = -EIO; 5359c879596SNamjae Jeon goto out; 5369c879596SNamjae Jeon } 5379c879596SNamjae Jeon if (!ret2) 5389c879596SNamjae Jeon invalidate_mapping_pages(iocb->ki_filp->f_mapping, 5399c879596SNamjae Jeon offset >> PAGE_SHIFT, 5409c879596SNamjae Jeon end >> PAGE_SHIFT); 5419c879596SNamjae Jeon } 5429c879596SNamjae Jeon 5439c879596SNamjae Jeon out: 5449c879596SNamjae Jeon return ret; 5459c879596SNamjae Jeon } 5469c879596SNamjae Jeon 5479c879596SNamjae Jeon static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) 5489c879596SNamjae Jeon { 5499c879596SNamjae Jeon struct file *file = iocb->ki_filp; 5509c879596SNamjae Jeon struct inode *vi = file->f_mapping->host; 5519c879596SNamjae Jeon struct ntfs_inode *ni = NTFS_I(vi); 5529c879596SNamjae Jeon struct ntfs_volume *vol = ni->vol; 5539c879596SNamjae Jeon ssize_t ret; 5549c879596SNamjae Jeon ssize_t count; 5559c879596SNamjae Jeon loff_t pos; 5569c879596SNamjae Jeon int err; 5579c879596SNamjae Jeon loff_t old_data_size, old_init_size; 5589c879596SNamjae Jeon 5599c879596SNamjae Jeon if (NVolShutdown(vol)) 5609c879596SNamjae Jeon return -EIO; 5619c879596SNamjae Jeon 5629c879596SNamjae Jeon if (NInoEncrypted(ni)) { 5639c879596SNamjae Jeon ntfs_error(vi->i_sb, "Writing for %s files is not supported yet", 5649c879596SNamjae Jeon NInoCompressed(ni) ? "Compressed" : "Encrypted"); 5659c879596SNamjae Jeon return -EOPNOTSUPP; 5669c879596SNamjae Jeon } 5679c879596SNamjae Jeon 5689c879596SNamjae Jeon if (NInoCompressed(ni) && iocb->ki_flags & IOCB_DIRECT) 5699c879596SNamjae Jeon return -EOPNOTSUPP; 5709c879596SNamjae Jeon 5719c879596SNamjae Jeon if (iocb->ki_flags & IOCB_NOWAIT) { 5729c879596SNamjae Jeon if (!inode_trylock(vi)) 5739c879596SNamjae Jeon return -EAGAIN; 5749c879596SNamjae Jeon } else 5759c879596SNamjae Jeon inode_lock(vi); 5769c879596SNamjae Jeon 5779c879596SNamjae Jeon ret = generic_write_checks(iocb, from); 5789c879596SNamjae Jeon if (ret <= 0) 5799c879596SNamjae Jeon goto out_lock; 5809c879596SNamjae Jeon 5819c879596SNamjae Jeon err = file_modified(iocb->ki_filp); 5829c879596SNamjae Jeon if (err) { 5839c879596SNamjae Jeon ret = err; 5849c879596SNamjae Jeon goto out_lock; 5859c879596SNamjae Jeon } 5869c879596SNamjae Jeon 5879c879596SNamjae Jeon if (!(vol->vol_flags & VOLUME_IS_DIRTY)) 5889c879596SNamjae Jeon ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY); 5899c879596SNamjae Jeon 5909c879596SNamjae Jeon pos = iocb->ki_pos; 5919c879596SNamjae Jeon count = ret; 5929c879596SNamjae Jeon 5939c879596SNamjae Jeon old_data_size = ni->data_size; 5949c879596SNamjae Jeon old_init_size = ni->initialized_size; 5959c879596SNamjae Jeon 5969c879596SNamjae Jeon if (NInoNonResident(ni) && NInoCompressed(ni)) { 5979c879596SNamjae Jeon ret = ntfs_compress_write(ni, pos, count, from); 5989c879596SNamjae Jeon if (ret > 0) 5999c879596SNamjae Jeon iocb->ki_pos += ret; 6009c879596SNamjae Jeon goto out; 6019c879596SNamjae Jeon } 6029c879596SNamjae Jeon 6039c879596SNamjae Jeon if (NInoNonResident(ni) && iocb->ki_flags & IOCB_DIRECT) 6049c879596SNamjae Jeon ret = ntfs_dio_write_iter(iocb, from); 6059c879596SNamjae Jeon else 6069c879596SNamjae Jeon ret = iomap_file_buffered_write(iocb, from, &ntfs_write_iomap_ops, 6079c879596SNamjae Jeon &ntfs_iomap_folio_ops, NULL); 6089c879596SNamjae Jeon out: 6099c879596SNamjae Jeon if (ret < 0 && ret != -EIOCBQUEUED) { 6109c879596SNamjae Jeon if (ni->initialized_size != old_init_size) { 6119c879596SNamjae Jeon mutex_lock(&ni->mrec_lock); 6129c879596SNamjae Jeon ntfs_attr_set_initialized_size(ni, old_init_size); 6139c879596SNamjae Jeon mutex_unlock(&ni->mrec_lock); 6149c879596SNamjae Jeon } 6159c879596SNamjae Jeon if (ni->data_size != old_data_size) { 6169c879596SNamjae Jeon truncate_setsize(vi, old_data_size); 6179c879596SNamjae Jeon ntfs_attr_truncate(ni, old_data_size); 6189c879596SNamjae Jeon } 6199c879596SNamjae Jeon } 6209c879596SNamjae Jeon out_lock: 6219c879596SNamjae Jeon inode_unlock(vi); 6229c879596SNamjae Jeon if (ret > 0) 6239c879596SNamjae Jeon ret = generic_write_sync(iocb, ret); 6249c879596SNamjae Jeon return ret; 6259c879596SNamjae Jeon } 6269c879596SNamjae Jeon 6279c879596SNamjae Jeon static vm_fault_t ntfs_filemap_page_mkwrite(struct vm_fault *vmf) 6289c879596SNamjae Jeon { 6299c879596SNamjae Jeon struct inode *inode = file_inode(vmf->vma->vm_file); 6309c879596SNamjae Jeon vm_fault_t ret; 6319c879596SNamjae Jeon 6329c879596SNamjae Jeon sb_start_pagefault(inode->i_sb); 6339c879596SNamjae Jeon file_update_time(vmf->vma->vm_file); 6349c879596SNamjae Jeon 6359c879596SNamjae Jeon ret = iomap_page_mkwrite(vmf, &ntfs_page_mkwrite_iomap_ops, NULL); 6369c879596SNamjae Jeon sb_end_pagefault(inode->i_sb); 6379c879596SNamjae Jeon return ret; 6389c879596SNamjae Jeon } 6399c879596SNamjae Jeon 6409c879596SNamjae Jeon static const struct vm_operations_struct ntfs_file_vm_ops = { 6419c879596SNamjae Jeon .fault = filemap_fault, 6429c879596SNamjae Jeon .map_pages = filemap_map_pages, 6439c879596SNamjae Jeon .page_mkwrite = ntfs_filemap_page_mkwrite, 6449c879596SNamjae Jeon }; 6459c879596SNamjae Jeon 6469c879596SNamjae Jeon static int ntfs_file_mmap_prepare(struct vm_area_desc *desc) 6479c879596SNamjae Jeon { 6489c879596SNamjae Jeon struct file *file = desc->file; 6499c879596SNamjae Jeon struct inode *inode = file_inode(file); 6509c879596SNamjae Jeon 6519c879596SNamjae Jeon if (NVolShutdown(NTFS_SB(file->f_mapping->host->i_sb))) 6529c879596SNamjae Jeon return -EIO; 6539c879596SNamjae Jeon 6549c879596SNamjae Jeon if (NInoCompressed(NTFS_I(inode))) 6559c879596SNamjae Jeon return -EOPNOTSUPP; 6569c879596SNamjae Jeon 657*cdd4dc3aSLinus Torvalds if (vma_desc_test(desc, VMA_WRITE_BIT)) { 6589c879596SNamjae Jeon struct inode *inode = file_inode(file); 6599c879596SNamjae Jeon loff_t from, to; 6609c879596SNamjae Jeon int err; 6619c879596SNamjae Jeon 6629c879596SNamjae Jeon from = ((loff_t)desc->pgoff << PAGE_SHIFT); 6639c879596SNamjae Jeon to = min_t(loff_t, i_size_read(inode), 6649c879596SNamjae Jeon from + desc->end - desc->start); 6659c879596SNamjae Jeon 6669c879596SNamjae Jeon if (NTFS_I(inode)->initialized_size < to) { 6679c879596SNamjae Jeon err = ntfs_extend_initialized_size(inode, to, to, false); 6689c879596SNamjae Jeon if (err) 6699c879596SNamjae Jeon return err; 6709c879596SNamjae Jeon } 6719c879596SNamjae Jeon } 6729c879596SNamjae Jeon 6739c879596SNamjae Jeon 6749c879596SNamjae Jeon file_accessed(file); 6759c879596SNamjae Jeon desc->vm_ops = &ntfs_file_vm_ops; 6769c879596SNamjae Jeon return 0; 6779c879596SNamjae Jeon } 6789c879596SNamjae Jeon 6799c879596SNamjae Jeon static int ntfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, 6809c879596SNamjae Jeon u64 start, u64 len) 6819c879596SNamjae Jeon { 6829c879596SNamjae Jeon return iomap_fiemap(inode, fieinfo, start, len, &ntfs_read_iomap_ops); 6839c879596SNamjae Jeon } 6849c879596SNamjae Jeon 6859c879596SNamjae Jeon static const char *ntfs_get_link(struct dentry *dentry, struct inode *inode, 6869c879596SNamjae Jeon struct delayed_call *done) 6879c879596SNamjae Jeon { 6889c879596SNamjae Jeon if (!NTFS_I(inode)->target) 6899c879596SNamjae Jeon return ERR_PTR(-EINVAL); 6909c879596SNamjae Jeon 6919c879596SNamjae Jeon return NTFS_I(inode)->target; 6929c879596SNamjae Jeon } 6939c879596SNamjae Jeon 6949c879596SNamjae Jeon static ssize_t ntfs_file_splice_read(struct file *in, loff_t *ppos, 6959c879596SNamjae Jeon struct pipe_inode_info *pipe, size_t len, unsigned int flags) 6969c879596SNamjae Jeon { 6979c879596SNamjae Jeon if (NVolShutdown(NTFS_SB(in->f_mapping->host->i_sb))) 6989c879596SNamjae Jeon return -EIO; 6999c879596SNamjae Jeon 7009c879596SNamjae Jeon return filemap_splice_read(in, ppos, pipe, len, flags); 7019c879596SNamjae Jeon } 7029c879596SNamjae Jeon 7039c879596SNamjae Jeon static int ntfs_ioctl_shutdown(struct super_block *sb, unsigned long arg) 7049c879596SNamjae Jeon { 7059c879596SNamjae Jeon u32 flags; 7069c879596SNamjae Jeon 7079c879596SNamjae Jeon if (!capable(CAP_SYS_ADMIN)) 7089c879596SNamjae Jeon return -EPERM; 7099c879596SNamjae Jeon 7109c879596SNamjae Jeon if (get_user(flags, (__u32 __user *)arg)) 7119c879596SNamjae Jeon return -EFAULT; 7129c879596SNamjae Jeon 7139c879596SNamjae Jeon return ntfs_force_shutdown(sb, flags); 7149c879596SNamjae Jeon } 7159c879596SNamjae Jeon 7169c879596SNamjae Jeon static int ntfs_ioctl_get_volume_label(struct file *filp, unsigned long arg) 7179c879596SNamjae Jeon { 7189c879596SNamjae Jeon struct ntfs_volume *vol = NTFS_SB(file_inode(filp)->i_sb); 7199c879596SNamjae Jeon char __user *buf = (char __user *)arg; 7209c879596SNamjae Jeon 7219c879596SNamjae Jeon if (!vol->volume_label) { 7229c879596SNamjae Jeon if (copy_to_user(buf, "", 1)) 7239c879596SNamjae Jeon return -EFAULT; 7249c879596SNamjae Jeon } else if (copy_to_user(buf, vol->volume_label, 7259c879596SNamjae Jeon MIN(FSLABEL_MAX, strlen(vol->volume_label) + 1))) 7269c879596SNamjae Jeon return -EFAULT; 7279c879596SNamjae Jeon return 0; 7289c879596SNamjae Jeon } 7299c879596SNamjae Jeon 7309c879596SNamjae Jeon static int ntfs_ioctl_set_volume_label(struct file *filp, unsigned long arg) 7319c879596SNamjae Jeon { 7329c879596SNamjae Jeon struct ntfs_volume *vol = NTFS_SB(file_inode(filp)->i_sb); 7339c879596SNamjae Jeon char *label; 7349c879596SNamjae Jeon int ret; 7359c879596SNamjae Jeon 7369c879596SNamjae Jeon if (!capable(CAP_SYS_ADMIN)) 7379c879596SNamjae Jeon return -EPERM; 7389c879596SNamjae Jeon 7399c879596SNamjae Jeon label = strndup_user((const char __user *)arg, FSLABEL_MAX); 7409c879596SNamjae Jeon if (IS_ERR(label)) 7419c879596SNamjae Jeon return PTR_ERR(label); 7429c879596SNamjae Jeon 7439c879596SNamjae Jeon ret = mnt_want_write_file(filp); 7449c879596SNamjae Jeon if (ret) 7459c879596SNamjae Jeon goto out; 7469c879596SNamjae Jeon 7479c879596SNamjae Jeon ret = ntfs_write_volume_label(vol, label); 7489c879596SNamjae Jeon mnt_drop_write_file(filp); 7499c879596SNamjae Jeon out: 7509c879596SNamjae Jeon kfree(label); 7519c879596SNamjae Jeon return ret; 7529c879596SNamjae Jeon } 7539c879596SNamjae Jeon 7549c879596SNamjae Jeon static int ntfs_ioctl_fitrim(struct ntfs_volume *vol, unsigned long arg) 7559c879596SNamjae Jeon { 7569c879596SNamjae Jeon struct fstrim_range __user *user_range; 7579c879596SNamjae Jeon struct fstrim_range range; 7589c879596SNamjae Jeon struct block_device *dev; 7599c879596SNamjae Jeon int err; 7609c879596SNamjae Jeon 7619c879596SNamjae Jeon if (!capable(CAP_SYS_ADMIN)) 7629c879596SNamjae Jeon return -EPERM; 7639c879596SNamjae Jeon 7649c879596SNamjae Jeon dev = vol->sb->s_bdev; 7659c879596SNamjae Jeon if (!bdev_max_discard_sectors(dev)) 7669c879596SNamjae Jeon return -EOPNOTSUPP; 7679c879596SNamjae Jeon 7689c879596SNamjae Jeon user_range = (struct fstrim_range __user *)arg; 7699c879596SNamjae Jeon if (copy_from_user(&range, user_range, sizeof(range))) 7709c879596SNamjae Jeon return -EFAULT; 7719c879596SNamjae Jeon 7729c879596SNamjae Jeon if (range.len == 0) 7739c879596SNamjae Jeon return -EINVAL; 7749c879596SNamjae Jeon 7759c879596SNamjae Jeon if (range.len < vol->cluster_size) 7769c879596SNamjae Jeon return -EINVAL; 7779c879596SNamjae Jeon 7789c879596SNamjae Jeon range.minlen = max_t(u32, range.minlen, bdev_discard_granularity(dev)); 7799c879596SNamjae Jeon 7809c879596SNamjae Jeon err = ntfs_trim_fs(vol, &range); 7819c879596SNamjae Jeon if (err < 0) 7829c879596SNamjae Jeon return err; 7839c879596SNamjae Jeon 7849c879596SNamjae Jeon if (copy_to_user(user_range, &range, sizeof(range))) 7859c879596SNamjae Jeon return -EFAULT; 7869c879596SNamjae Jeon 7879c879596SNamjae Jeon return 0; 7889c879596SNamjae Jeon } 7899c879596SNamjae Jeon 7909c879596SNamjae Jeon long ntfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 7919c879596SNamjae Jeon { 7929c879596SNamjae Jeon switch (cmd) { 7939c879596SNamjae Jeon case FS_IOC_SHUTDOWN: 7949c879596SNamjae Jeon return ntfs_ioctl_shutdown(file_inode(filp)->i_sb, arg); 7959c879596SNamjae Jeon case FS_IOC_GETFSLABEL: 7969c879596SNamjae Jeon return ntfs_ioctl_get_volume_label(filp, arg); 7979c879596SNamjae Jeon case FS_IOC_SETFSLABEL: 7989c879596SNamjae Jeon return ntfs_ioctl_set_volume_label(filp, arg); 7999c879596SNamjae Jeon case FITRIM: 8009c879596SNamjae Jeon return ntfs_ioctl_fitrim(NTFS_SB(file_inode(filp)->i_sb), arg); 8019c879596SNamjae Jeon default: 8029c879596SNamjae Jeon return -ENOTTY; 8039c879596SNamjae Jeon } 8049c879596SNamjae Jeon } 8059c879596SNamjae Jeon 8069c879596SNamjae Jeon #ifdef CONFIG_COMPAT 8079c879596SNamjae Jeon long ntfs_compat_ioctl(struct file *filp, unsigned int cmd, 8089c879596SNamjae Jeon unsigned long arg) 8099c879596SNamjae Jeon { 8109c879596SNamjae Jeon return ntfs_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); 8119c879596SNamjae Jeon } 8129c879596SNamjae Jeon #endif 8139c879596SNamjae Jeon 8149c879596SNamjae Jeon static int ntfs_allocate_range(struct ntfs_inode *ni, int mode, loff_t offset, 8159c879596SNamjae Jeon loff_t len) 8169c879596SNamjae Jeon { 8179c879596SNamjae Jeon struct inode *vi = VFS_I(ni); 8189c879596SNamjae Jeon struct ntfs_volume *vol = ni->vol; 8199c879596SNamjae Jeon s64 need_space; 8209c879596SNamjae Jeon loff_t old_size, new_size; 8219c879596SNamjae Jeon s64 start_vcn, end_vcn; 8229c879596SNamjae Jeon int err; 8239c879596SNamjae Jeon 8249c879596SNamjae Jeon old_size = i_size_read(vi); 8259c879596SNamjae Jeon new_size = max_t(loff_t, old_size, offset + len); 8269c879596SNamjae Jeon start_vcn = ntfs_bytes_to_cluster(vol, offset); 8279c879596SNamjae Jeon end_vcn = ntfs_bytes_to_cluster(vol, offset + len - 1) + 1; 8289c879596SNamjae Jeon 8299c879596SNamjae Jeon err = inode_newsize_ok(vi, new_size); 8309c879596SNamjae Jeon if (err) 8319c879596SNamjae Jeon goto out; 8329c879596SNamjae Jeon 8339c879596SNamjae Jeon need_space = ntfs_bytes_to_cluster(vol, ni->allocated_size); 8349c879596SNamjae Jeon if (need_space > start_vcn) 8359c879596SNamjae Jeon need_space = end_vcn - need_space; 8369c879596SNamjae Jeon else 8379c879596SNamjae Jeon need_space = end_vcn - start_vcn; 8389c879596SNamjae Jeon if (need_space > 0 && 8399c879596SNamjae Jeon need_space > (atomic64_read(&vol->free_clusters) - 8409c879596SNamjae Jeon atomic64_read(&vol->dirty_clusters))) { 8419c879596SNamjae Jeon err = -ENOSPC; 8429c879596SNamjae Jeon goto out; 8439c879596SNamjae Jeon } 8449c879596SNamjae Jeon 8459c879596SNamjae Jeon err = ntfs_attr_fallocate(ni, offset, len, 8469c879596SNamjae Jeon mode & FALLOC_FL_KEEP_SIZE ? true : false); 8479c879596SNamjae Jeon 8489c879596SNamjae Jeon if (!(mode & FALLOC_FL_KEEP_SIZE) && new_size != old_size) 8499c879596SNamjae Jeon i_size_write(vi, ni->data_size); 8509c879596SNamjae Jeon out: 8519c879596SNamjae Jeon return err; 8529c879596SNamjae Jeon } 8539c879596SNamjae Jeon 8549c879596SNamjae Jeon static int ntfs_punch_hole(struct ntfs_inode *ni, int mode, loff_t offset, 8559c879596SNamjae Jeon loff_t len) 8569c879596SNamjae Jeon { 8579c879596SNamjae Jeon struct ntfs_volume *vol = ni->vol; 8589c879596SNamjae Jeon struct inode *vi = VFS_I(ni); 8599c879596SNamjae Jeon loff_t end_offset; 8609c879596SNamjae Jeon s64 start_vcn, end_vcn; 8619c879596SNamjae Jeon int err = 0; 8629c879596SNamjae Jeon 8639c879596SNamjae Jeon loff_t offset_down = round_down(offset, max_t(unsigned int, 8649c879596SNamjae Jeon vol->cluster_size, PAGE_SIZE)); 8659c879596SNamjae Jeon 8669c879596SNamjae Jeon if (NVolDisableSparse(vol)) { 8679c879596SNamjae Jeon err = -EOPNOTSUPP; 8689c879596SNamjae Jeon goto out; 8699c879596SNamjae Jeon } 8709c879596SNamjae Jeon 8719c879596SNamjae Jeon if (offset >= ni->data_size) 8729c879596SNamjae Jeon goto out; 8739c879596SNamjae Jeon 8749c879596SNamjae Jeon if (offset + len > ni->data_size) 8759c879596SNamjae Jeon end_offset = ni->data_size; 8769c879596SNamjae Jeon else 8779c879596SNamjae Jeon end_offset = offset + len; 8789c879596SNamjae Jeon 8799c879596SNamjae Jeon err = filemap_write_and_wait_range(vi->i_mapping, offset_down, LLONG_MAX); 8809c879596SNamjae Jeon if (err) 8819c879596SNamjae Jeon goto out; 8829c879596SNamjae Jeon truncate_pagecache(vi, offset_down); 8839c879596SNamjae Jeon 8849c879596SNamjae Jeon start_vcn = ntfs_bytes_to_cluster(vol, offset); 8859c879596SNamjae Jeon end_vcn = ntfs_bytes_to_cluster(vol, end_offset - 1) + 1; 8869c879596SNamjae Jeon 8879c879596SNamjae Jeon if (offset & vol->cluster_size_mask) { 8889c879596SNamjae Jeon loff_t to; 8899c879596SNamjae Jeon 8909c879596SNamjae Jeon to = min_t(loff_t, ntfs_cluster_to_bytes(vol, start_vcn + 1), 8919c879596SNamjae Jeon end_offset); 8929c879596SNamjae Jeon err = iomap_zero_range(vi, offset, to - offset, NULL, 8939c879596SNamjae Jeon &ntfs_seek_iomap_ops, 8949c879596SNamjae Jeon &ntfs_iomap_folio_ops, NULL); 8959c879596SNamjae Jeon if (err < 0 || (end_vcn - start_vcn) == 1) 8969c879596SNamjae Jeon goto out; 8979c879596SNamjae Jeon start_vcn++; 8989c879596SNamjae Jeon } 8999c879596SNamjae Jeon 9009c879596SNamjae Jeon if (end_offset & vol->cluster_size_mask) { 9019c879596SNamjae Jeon loff_t from; 9029c879596SNamjae Jeon 9039c879596SNamjae Jeon from = ntfs_cluster_to_bytes(vol, end_vcn - 1); 9049c879596SNamjae Jeon err = iomap_zero_range(vi, from, end_offset - from, NULL, 9059c879596SNamjae Jeon &ntfs_seek_iomap_ops, 9069c879596SNamjae Jeon &ntfs_iomap_folio_ops, NULL); 9079c879596SNamjae Jeon if (err < 0 || (end_vcn - start_vcn) == 1) 9089c879596SNamjae Jeon goto out; 9099c879596SNamjae Jeon end_vcn--; 9109c879596SNamjae Jeon } 9119c879596SNamjae Jeon 9129c879596SNamjae Jeon mutex_lock_nested(&ni->mrec_lock, NTFS_INODE_MUTEX_NORMAL); 9139c879596SNamjae Jeon err = ntfs_non_resident_attr_punch_hole(ni, start_vcn, 9149c879596SNamjae Jeon end_vcn - start_vcn); 9159c879596SNamjae Jeon mutex_unlock(&ni->mrec_lock); 9169c879596SNamjae Jeon out: 9179c879596SNamjae Jeon return err; 9189c879596SNamjae Jeon } 9199c879596SNamjae Jeon 9209c879596SNamjae Jeon static int ntfs_collapse_range(struct ntfs_inode *ni, loff_t offset, loff_t len) 9219c879596SNamjae Jeon { 9229c879596SNamjae Jeon struct ntfs_volume *vol = ni->vol; 9239c879596SNamjae Jeon struct inode *vi = VFS_I(ni); 9249c879596SNamjae Jeon loff_t old_size, new_size; 9259c879596SNamjae Jeon s64 start_vcn, end_vcn; 9269c879596SNamjae Jeon int err; 9279c879596SNamjae Jeon 9289c879596SNamjae Jeon loff_t offset_down = round_down(offset, 9299c879596SNamjae Jeon max_t(unsigned long, vol->cluster_size, PAGE_SIZE)); 9309c879596SNamjae Jeon 9319c879596SNamjae Jeon if ((offset & vol->cluster_size_mask) || 9329c879596SNamjae Jeon (len & vol->cluster_size_mask) || 9339c879596SNamjae Jeon offset >= ni->allocated_size) { 9349c879596SNamjae Jeon err = -EINVAL; 9359c879596SNamjae Jeon goto out; 9369c879596SNamjae Jeon } 9379c879596SNamjae Jeon 9389c879596SNamjae Jeon old_size = i_size_read(vi); 9399c879596SNamjae Jeon start_vcn = ntfs_bytes_to_cluster(vol, offset); 9409c879596SNamjae Jeon end_vcn = ntfs_bytes_to_cluster(vol, offset + len - 1) + 1; 9419c879596SNamjae Jeon 9429c879596SNamjae Jeon if (ntfs_cluster_to_bytes(vol, end_vcn) > ni->allocated_size) 9439c879596SNamjae Jeon end_vcn = (round_up(ni->allocated_size - 1, 9449c879596SNamjae Jeon vol->cluster_size) >> vol->cluster_size_bits) + 1; 9459c879596SNamjae Jeon new_size = old_size - ntfs_cluster_to_bytes(vol, end_vcn - start_vcn); 9469c879596SNamjae Jeon if (new_size < 0) 9479c879596SNamjae Jeon new_size = 0; 9489c879596SNamjae Jeon err = filemap_write_and_wait_range(vi->i_mapping, 9499c879596SNamjae Jeon offset_down, LLONG_MAX); 9509c879596SNamjae Jeon if (err) 9519c879596SNamjae Jeon goto out; 9529c879596SNamjae Jeon 9539c879596SNamjae Jeon truncate_pagecache(vi, offset_down); 9549c879596SNamjae Jeon 9559c879596SNamjae Jeon mutex_lock_nested(&ni->mrec_lock, NTFS_INODE_MUTEX_NORMAL); 9569c879596SNamjae Jeon err = ntfs_non_resident_attr_collapse_range(ni, start_vcn, 9579c879596SNamjae Jeon end_vcn - start_vcn); 9589c879596SNamjae Jeon mutex_unlock(&ni->mrec_lock); 9599c879596SNamjae Jeon 9609c879596SNamjae Jeon if (new_size != old_size) 9619c879596SNamjae Jeon i_size_write(vi, ni->data_size); 9629c879596SNamjae Jeon out: 9639c879596SNamjae Jeon return err; 9649c879596SNamjae Jeon } 9659c879596SNamjae Jeon 9669c879596SNamjae Jeon static int ntfs_insert_range(struct ntfs_inode *ni, loff_t offset, loff_t len) 9679c879596SNamjae Jeon { 9689c879596SNamjae Jeon struct ntfs_volume *vol = ni->vol; 9699c879596SNamjae Jeon struct inode *vi = VFS_I(ni); 9709c879596SNamjae Jeon loff_t offset_down = round_down(offset, 9719c879596SNamjae Jeon max_t(unsigned long, vol->cluster_size, PAGE_SIZE)); 9729c879596SNamjae Jeon loff_t alloc_size, end_offset = offset + len; 9739c879596SNamjae Jeon loff_t old_size, new_size; 9749c879596SNamjae Jeon s64 start_vcn, end_vcn; 9759c879596SNamjae Jeon int err; 9769c879596SNamjae Jeon 9779c879596SNamjae Jeon if (NVolDisableSparse(vol)) { 9789c879596SNamjae Jeon err = -EOPNOTSUPP; 9799c879596SNamjae Jeon goto out; 9809c879596SNamjae Jeon } 9819c879596SNamjae Jeon 9829c879596SNamjae Jeon if ((offset & vol->cluster_size_mask) || 9839c879596SNamjae Jeon (len & vol->cluster_size_mask) || 9849c879596SNamjae Jeon offset >= ni->allocated_size) { 9859c879596SNamjae Jeon err = -EINVAL; 9869c879596SNamjae Jeon goto out; 9879c879596SNamjae Jeon } 9889c879596SNamjae Jeon 9899c879596SNamjae Jeon old_size = i_size_read(vi); 9909c879596SNamjae Jeon start_vcn = ntfs_bytes_to_cluster(vol, offset); 9919c879596SNamjae Jeon end_vcn = ntfs_bytes_to_cluster(vol, end_offset - 1) + 1; 9929c879596SNamjae Jeon 9939c879596SNamjae Jeon new_size = old_size + ntfs_cluster_to_bytes(vol, end_vcn - start_vcn); 9949c879596SNamjae Jeon alloc_size = ni->allocated_size + 9959c879596SNamjae Jeon ntfs_cluster_to_bytes(vol, end_vcn - start_vcn); 9969c879596SNamjae Jeon if (alloc_size < 0) { 9979c879596SNamjae Jeon err = -EFBIG; 9989c879596SNamjae Jeon goto out; 9999c879596SNamjae Jeon } 10009c879596SNamjae Jeon err = inode_newsize_ok(vi, alloc_size); 10019c879596SNamjae Jeon if (err) 10029c879596SNamjae Jeon goto out; 10039c879596SNamjae Jeon 10049c879596SNamjae Jeon err = filemap_write_and_wait_range(vi->i_mapping, 10059c879596SNamjae Jeon offset_down, LLONG_MAX); 10069c879596SNamjae Jeon if (err) 10079c879596SNamjae Jeon goto out; 10089c879596SNamjae Jeon 10099c879596SNamjae Jeon truncate_pagecache(vi, offset_down); 10109c879596SNamjae Jeon 10119c879596SNamjae Jeon mutex_lock_nested(&ni->mrec_lock, NTFS_INODE_MUTEX_NORMAL); 10129c879596SNamjae Jeon err = ntfs_non_resident_attr_insert_range(ni, start_vcn, 10139c879596SNamjae Jeon end_vcn - start_vcn); 10149c879596SNamjae Jeon mutex_unlock(&ni->mrec_lock); 10159c879596SNamjae Jeon 10169c879596SNamjae Jeon if (new_size != old_size) 10179c879596SNamjae Jeon i_size_write(vi, ni->data_size); 10189c879596SNamjae Jeon out: 10199c879596SNamjae Jeon return err; 10209c879596SNamjae Jeon } 10219c879596SNamjae Jeon 10229c879596SNamjae Jeon #define NTFS_FALLOC_FL_SUPPORTED \ 10239c879596SNamjae Jeon (FALLOC_FL_ALLOCATE_RANGE | FALLOC_FL_KEEP_SIZE | \ 10249c879596SNamjae Jeon FALLOC_FL_INSERT_RANGE | FALLOC_FL_PUNCH_HOLE | \ 10259c879596SNamjae Jeon FALLOC_FL_COLLAPSE_RANGE) 10269c879596SNamjae Jeon 10279c879596SNamjae Jeon static long ntfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) 10289c879596SNamjae Jeon { 10299c879596SNamjae Jeon struct inode *vi = file_inode(file); 10309c879596SNamjae Jeon struct ntfs_inode *ni = NTFS_I(vi); 10319c879596SNamjae Jeon struct ntfs_volume *vol = ni->vol; 10329c879596SNamjae Jeon int err = 0; 10339c879596SNamjae Jeon loff_t old_size; 10349c879596SNamjae Jeon bool map_locked = false; 10359c879596SNamjae Jeon 10369c879596SNamjae Jeon if (mode & ~(NTFS_FALLOC_FL_SUPPORTED)) 10379c879596SNamjae Jeon return -EOPNOTSUPP; 10389c879596SNamjae Jeon 10399c879596SNamjae Jeon if (!NVolFreeClusterKnown(vol)) 10409c879596SNamjae Jeon wait_event(vol->free_waitq, NVolFreeClusterKnown(vol)); 10419c879596SNamjae Jeon 10429c879596SNamjae Jeon if ((ni->vol->mft_zone_end - ni->vol->mft_zone_start) == 0) 10439c879596SNamjae Jeon return -ENOSPC; 10449c879596SNamjae Jeon 10459c879596SNamjae Jeon if (NInoNonResident(ni) && !NInoFullyMapped(ni)) { 10469c879596SNamjae Jeon down_write(&ni->runlist.lock); 10479c879596SNamjae Jeon err = ntfs_attr_map_whole_runlist(ni); 10489c879596SNamjae Jeon up_write(&ni->runlist.lock); 10499c879596SNamjae Jeon if (err) 10509c879596SNamjae Jeon return err; 10519c879596SNamjae Jeon } 10529c879596SNamjae Jeon 10539c879596SNamjae Jeon if (!(vol->vol_flags & VOLUME_IS_DIRTY)) { 10549c879596SNamjae Jeon err = ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY); 10559c879596SNamjae Jeon if (err) 10569c879596SNamjae Jeon return err; 10579c879596SNamjae Jeon } 10589c879596SNamjae Jeon 10599c879596SNamjae Jeon old_size = i_size_read(vi); 10609c879596SNamjae Jeon 10619c879596SNamjae Jeon inode_lock(vi); 10629c879596SNamjae Jeon if (NInoCompressed(ni) || NInoEncrypted(ni)) { 10639c879596SNamjae Jeon err = -EOPNOTSUPP; 10649c879596SNamjae Jeon goto out; 10659c879596SNamjae Jeon } 10669c879596SNamjae Jeon 10679c879596SNamjae Jeon inode_dio_wait(vi); 10689c879596SNamjae Jeon if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE | 10699c879596SNamjae Jeon FALLOC_FL_INSERT_RANGE)) { 10709c879596SNamjae Jeon filemap_invalidate_lock(vi->i_mapping); 10719c879596SNamjae Jeon map_locked = true; 10729c879596SNamjae Jeon } 10739c879596SNamjae Jeon 10749c879596SNamjae Jeon switch (mode & FALLOC_FL_MODE_MASK) { 10759c879596SNamjae Jeon case FALLOC_FL_ALLOCATE_RANGE: 10769c879596SNamjae Jeon case FALLOC_FL_KEEP_SIZE: 10779c879596SNamjae Jeon err = ntfs_allocate_range(ni, mode, offset, len); 10789c879596SNamjae Jeon break; 10799c879596SNamjae Jeon case FALLOC_FL_PUNCH_HOLE: 10809c879596SNamjae Jeon err = ntfs_punch_hole(ni, mode, offset, len); 10819c879596SNamjae Jeon break; 10829c879596SNamjae Jeon case FALLOC_FL_COLLAPSE_RANGE: 10839c879596SNamjae Jeon err = ntfs_collapse_range(ni, offset, len); 10849c879596SNamjae Jeon break; 10859c879596SNamjae Jeon case FALLOC_FL_INSERT_RANGE: 10869c879596SNamjae Jeon err = ntfs_insert_range(ni, offset, len); 10879c879596SNamjae Jeon break; 10889c879596SNamjae Jeon default: 10899c879596SNamjae Jeon err = -EOPNOTSUPP; 10909c879596SNamjae Jeon } 10919c879596SNamjae Jeon 10929c879596SNamjae Jeon if (err) 10939c879596SNamjae Jeon goto out; 10949c879596SNamjae Jeon 10959c879596SNamjae Jeon err = file_modified(file); 10969c879596SNamjae Jeon out: 10979c879596SNamjae Jeon if (map_locked) 10989c879596SNamjae Jeon filemap_invalidate_unlock(vi->i_mapping); 10999c879596SNamjae Jeon if (!err) { 11009c879596SNamjae Jeon if (mode == 0 && NInoNonResident(ni) && 11019c879596SNamjae Jeon offset > old_size && old_size % PAGE_SIZE != 0) { 11029c879596SNamjae Jeon loff_t len = min_t(loff_t, 11039c879596SNamjae Jeon round_up(old_size, PAGE_SIZE) - old_size, 11049c879596SNamjae Jeon offset - old_size); 11059c879596SNamjae Jeon err = iomap_zero_range(vi, old_size, len, NULL, 11069c879596SNamjae Jeon &ntfs_seek_iomap_ops, 11079c879596SNamjae Jeon &ntfs_iomap_folio_ops, NULL); 11089c879596SNamjae Jeon } 11099c879596SNamjae Jeon NInoSetFileNameDirty(ni); 11109c879596SNamjae Jeon inode_set_mtime_to_ts(vi, inode_set_ctime_current(vi)); 11119c879596SNamjae Jeon mark_inode_dirty(vi); 11129c879596SNamjae Jeon } 11139c879596SNamjae Jeon 11149c879596SNamjae Jeon inode_unlock(vi); 11159c879596SNamjae Jeon return err; 11169c879596SNamjae Jeon } 11171e9ea7e0SNamjae Jeon 11181e9ea7e0SNamjae Jeon const struct file_operations ntfs_file_ops = { 11199c879596SNamjae Jeon .llseek = ntfs_file_llseek, 11209c879596SNamjae Jeon .read_iter = ntfs_file_read_iter, 11211e9ea7e0SNamjae Jeon .write_iter = ntfs_file_write_iter, 11221e9ea7e0SNamjae Jeon .fsync = ntfs_file_fsync, 11239c879596SNamjae Jeon .mmap_prepare = ntfs_file_mmap_prepare, 11241e9ea7e0SNamjae Jeon .open = ntfs_file_open, 11259c879596SNamjae Jeon .release = ntfs_file_release, 11269c879596SNamjae Jeon .splice_read = ntfs_file_splice_read, 11279c879596SNamjae Jeon .splice_write = iter_file_splice_write, 11289c879596SNamjae Jeon .unlocked_ioctl = ntfs_ioctl, 11299c879596SNamjae Jeon #ifdef CONFIG_COMPAT 11309c879596SNamjae Jeon .compat_ioctl = ntfs_compat_ioctl, 11319c879596SNamjae Jeon #endif 11329c879596SNamjae Jeon .fallocate = ntfs_fallocate, 11339c879596SNamjae Jeon .setlease = generic_setlease, 11341e9ea7e0SNamjae Jeon }; 11351e9ea7e0SNamjae Jeon 11361e9ea7e0SNamjae Jeon const struct inode_operations ntfs_file_inode_ops = { 11371e9ea7e0SNamjae Jeon .setattr = ntfs_setattr, 11389c879596SNamjae Jeon .getattr = ntfs_getattr, 11399c879596SNamjae Jeon .listxattr = ntfs_listxattr, 11409c879596SNamjae Jeon .get_acl = ntfs_get_acl, 11419c879596SNamjae Jeon .set_acl = ntfs_set_acl, 11429c879596SNamjae Jeon .fiemap = ntfs_fiemap, 11439c879596SNamjae Jeon }; 11449c879596SNamjae Jeon 11459c879596SNamjae Jeon const struct inode_operations ntfs_symlink_inode_operations = { 11469c879596SNamjae Jeon .get_link = ntfs_get_link, 11479c879596SNamjae Jeon .setattr = ntfs_setattr, 11489c879596SNamjae Jeon .listxattr = ntfs_listxattr, 11499c879596SNamjae Jeon }; 11509c879596SNamjae Jeon 11519c879596SNamjae Jeon const struct inode_operations ntfs_special_inode_operations = { 11529c879596SNamjae Jeon .setattr = ntfs_setattr, 11539c879596SNamjae Jeon .getattr = ntfs_getattr, 11549c879596SNamjae Jeon .listxattr = ntfs_listxattr, 11559c879596SNamjae Jeon .get_acl = ntfs_get_acl, 11569c879596SNamjae Jeon .set_acl = ntfs_set_acl, 11571e9ea7e0SNamjae Jeon }; 11581e9ea7e0SNamjae Jeon 11591e9ea7e0SNamjae Jeon const struct file_operations ntfs_empty_file_ops = {}; 11601e9ea7e0SNamjae Jeon 11611e9ea7e0SNamjae Jeon const struct inode_operations ntfs_empty_inode_ops = {}; 1162