fs/ntfs3: Always make file nonresident on fallocate call
authorKonstantin Komarov <almaz.alexandrovich@paragon-software.com>
Tue, 16 Apr 2024 07:08:18 +0000 (10:08 +0300)
committerKonstantin Komarov <almaz.alexandrovich@paragon-software.com>
Tue, 23 Apr 2024 06:34:25 +0000 (09:34 +0300)
xfstest 438 is starting to pass with this change.

Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
fs/ntfs3/attrib.c
fs/ntfs3/file.c
fs/ntfs3/ntfs_fs.h

index 7aadf5010999455e4d16e20581e2334034451e57..8e6bcdf99770f26b01e5c551bda6664041b859d0 100644 (file)
@@ -2558,3 +2558,35 @@ undo_insert_range:
 
        goto out;
 }
+
+/*
+ * attr_force_nonresident
+ *
+ * Convert default data attribute into non resident form.
+ */
+int attr_force_nonresident(struct ntfs_inode *ni)
+{
+       int err;
+       struct ATTRIB *attr;
+       struct ATTR_LIST_ENTRY *le = NULL;
+       struct mft_inode *mi;
+
+       attr = ni_find_attr(ni, NULL, &le, ATTR_DATA, NULL, 0, NULL, &mi);
+       if (!attr) {
+               ntfs_bad_inode(&ni->vfs_inode, "no data attribute");
+               return -ENOENT;
+       }
+
+       if (attr->non_res) {
+               /* Already non resident. */
+               return 0;
+       }
+
+       down_write(&ni->file.run_lock);
+       err = attr_make_nonresident(ni, attr, le, mi,
+                                   le32_to_cpu(attr->res.data_size),
+                                   &ni->file.run, &attr, NULL);
+       up_write(&ni->file.run_lock);
+
+       return err;
+}
index 5418662c80d8878afe72a8b8e8ffc43cc834b176..fce8ea098d60e7ea3b3614bd06f5427b3bd3b6c9 100644 (file)
@@ -578,6 +578,15 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
                /* Check new size. */
                u8 cluster_bits = sbi->cluster_bits;
 
+               /* Be sure file is non resident. */
+               if (is_resident(ni)) {
+                       ni_lock(ni);
+                       err = attr_force_nonresident(ni);
+                       ni_unlock(ni);
+                       if (err)
+                               goto out;
+               }
+
                /* generic/213: expected -ENOSPC instead of -EFBIG. */
                if (!is_supported_holes) {
                        loff_t to_alloc = new_size - inode_get_bytes(inode);
index 3db6a61f61dcf45f7c572df29cc541bea8f92fcb..00dec0ec56481f3e64f43439e83c2d101a60954d 100644 (file)
@@ -452,6 +452,7 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
 int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes);
 int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes);
 int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size);
+int attr_force_nonresident(struct ntfs_inode *ni);
 
 /* Functions from attrlist.c */
 void al_destroy(struct ntfs_inode *ni);