fs/ntfs3: Implement fallocate for compressed files
authorKonstantin Komarov <almaz.alexandrovich@paragon-software.com>
Thu, 18 Jul 2024 14:45:12 +0000 (17:45 +0300)
committerKonstantin Komarov <almaz.alexandrovich@paragon-software.com>
Tue, 3 Sep 2024 13:58:44 +0000 (16:58 +0300)
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
fs/ntfs3/attrib.c
fs/ntfs3/inode.c

index 6ede3e924deca55dccdd5f6223b04d7150a7bc45..d2a9cd9634295a3a8b605c2a4d38f5e5750f9bb2 100644 (file)
@@ -976,15 +976,17 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
                goto out;
 
        /* Check for compressed frame. */
-       err = attr_is_frame_compressed(ni, attr, vcn >> NTFS_LZNT_CUNIT, &hint);
+       err = attr_is_frame_compressed(ni, attr_b, vcn >> NTFS_LZNT_CUNIT,
+                                      &hint);
        if (err)
                goto out;
 
        if (hint) {
                /* if frame is compressed - don't touch it. */
                *lcn = COMPRESSED_LCN;
-               *len = hint;
-               err = -EOPNOTSUPP;
+               /* length to the end of frame. */
+               *len = NTFS_LZNT_CLUSTERS - (vcn & (NTFS_LZNT_CLUSTERS - 1));
+               err = 0;
                goto out;
        }
 
@@ -1027,16 +1029,16 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
 
                /* Check if 'vcn' and 'vcn0' in different attribute segments. */
                if (vcn < svcn || evcn1 <= vcn) {
-                       /* Load attribute for truncated vcn. */
-                       attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0,
-                                           &vcn, &mi);
-                       if (!attr) {
+                       struct ATTRIB *attr2;
+                       /* Load runs for truncated vcn. */
+                       attr2 = ni_find_attr(ni, attr_b, &le_b, ATTR_DATA, NULL,
+                                            0, &vcn, &mi);
+                       if (!attr2) {
                                err = -EINVAL;
                                goto out;
                        }
-                       svcn = le64_to_cpu(attr->nres.svcn);
-                       evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
-                       err = attr_load_runs(attr, ni, run, NULL);
+                       evcn1 = le64_to_cpu(attr2->nres.evcn) + 1;
+                       err = attr_load_runs(attr2, ni, run, NULL);
                        if (err)
                                goto out;
                }
@@ -1517,6 +1519,9 @@ out:
 
 /*
  * attr_is_frame_compressed - Used to detect compressed frame.
+ *
+ * attr - base (primary) attribute segment.
+ * Only base segments contains valid 'attr->nres.c_unit'
  */
 int attr_is_frame_compressed(struct ntfs_inode *ni, struct ATTRIB *attr,
                             CLST frame, CLST *clst_data)
index 56b6c4c6f528fe8b182309df94ba2602298a7002..f0b8473910bbbf39519dc8b67b5d34a06e26fbd9 100644 (file)
@@ -609,7 +609,8 @@ static noinline int ntfs_get_block_vbo(struct inode *inode, u64 vbo,
 
        bytes = ((u64)len << cluster_bits) - off;
 
-       if (lcn == SPARSE_LCN) {
+       if (lcn >= sbi->used.bitmap.nbits) {
+               /* This case includes resident/compressed/sparse. */
                if (!create) {
                        if (bh->b_size > bytes)
                                bh->b_size = bytes;