@@ -1860,7 +1860,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
18601860 struct ATTRIB * attr = NULL , * attr_b ;
18611861 struct ATTR_LIST_ENTRY * le , * le_b ;
18621862 struct mft_inode * mi , * mi_b ;
1863- CLST svcn , evcn1 , len , dealloc , alen ;
1863+ CLST svcn , evcn1 , len , dealloc , alen , done ;
18641864 CLST vcn , end ;
18651865 u64 valid_size , data_size , alloc_size , total_size ;
18661866 u32 mask ;
@@ -1923,6 +1923,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
19231923 len = bytes >> sbi -> cluster_bits ;
19241924 end = vcn + len ;
19251925 dealloc = 0 ;
1926+ done = 0 ;
19261927
19271928 svcn = le64_to_cpu (attr_b -> nres .svcn );
19281929 evcn1 = le64_to_cpu (attr_b -> nres .evcn ) + 1 ;
@@ -1931,23 +1932,28 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
19311932 attr = attr_b ;
19321933 le = le_b ;
19331934 mi = mi_b ;
1934- } else if (!le_b ) {
1935+ goto check_seg ;
1936+ }
1937+
1938+ if (!le_b ) {
19351939 err = - EINVAL ;
19361940 goto out ;
1937- } else {
1938- le = le_b ;
1939- attr = ni_find_attr (ni , attr_b , & le , ATTR_DATA , NULL , 0 , & vcn ,
1940- & mi );
1941- if (!attr ) {
1942- err = - EINVAL ;
1943- goto out ;
1944- }
1941+ }
19451942
1946- svcn = le64_to_cpu (attr -> nres .svcn );
1947- evcn1 = le64_to_cpu (attr -> nres .evcn ) + 1 ;
1943+ le = le_b ;
1944+ attr = ni_find_attr (ni , attr_b , & le , ATTR_DATA , NULL , 0 , & vcn , & mi );
1945+ if (!attr ) {
1946+ err = - EINVAL ;
1947+ goto out ;
19481948 }
19491949
19501950 for (;;) {
1951+ CLST vcn1 , eat , next_svcn ;
1952+
1953+ svcn = le64_to_cpu (attr -> nres .svcn );
1954+ evcn1 = le64_to_cpu (attr -> nres .evcn ) + 1 ;
1955+
1956+ check_seg :
19511957 if (svcn >= end ) {
19521958 /* Shift VCN- */
19531959 attr -> nres .svcn = cpu_to_le64 (svcn - len );
@@ -1957,30 +1963,33 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
19571963 ni -> attr_list .dirty = true;
19581964 }
19591965 mi -> dirty = true;
1960- } else if ( svcn < vcn || end < evcn1 ) {
1961- CLST vcn1 , eat , next_svcn ;
1966+ goto next_attr ;
1967+ }
19621968
1963- /* Collapse a part of this attribute segment. */
1964- err = attr_load_runs (attr , ni , run , & svcn );
1965- if (err )
1966- goto out ;
1967- vcn1 = max (vcn , svcn );
1968- eat = min (end , evcn1 ) - vcn1 ;
1969+ run_truncate (run , 0 );
1970+ err = attr_load_runs (attr , ni , run , & svcn );
1971+ if (err )
1972+ goto out ;
19691973
1970- err = run_deallocate_ex (sbi , run , vcn1 , eat , & dealloc ,
1971- true);
1972- if (err )
1973- goto out ;
1974+ vcn1 = vcn + done ; /* original vcn in attr/run. */
1975+ eat = min (end , evcn1 ) - vcn1 ;
1976+
1977+ err = run_deallocate_ex (sbi , run , vcn1 , eat , & dealloc , true);
1978+ if (err )
1979+ goto out ;
19741980
1975- if (!run_collapse_range (run , vcn1 , eat )) {
1981+ if (svcn + eat < evcn1 ) {
1982+ /* Collapse a part of this attribute segment. */
1983+
1984+ if (!run_collapse_range (run , vcn1 , eat , done )) {
19761985 err = - ENOMEM ;
19771986 goto out ;
19781987 }
19791988
19801989 if (svcn >= vcn ) {
19811990 /* Shift VCN */
19821991 attr -> nres .svcn = cpu_to_le64 (vcn );
1983- if (le ) {
1992+ if (le && attr -> nres . svcn != le -> vcn ) {
19841993 le -> vcn = attr -> nres .svcn ;
19851994 ni -> attr_list .dirty = true;
19861995 }
@@ -1991,7 +2000,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
19912000 goto out ;
19922001
19932002 next_svcn = le64_to_cpu (attr -> nres .evcn ) + 1 ;
1994- if (next_svcn + eat < evcn1 ) {
2003+ if (next_svcn + eat + done < evcn1 ) {
19952004 err = ni_insert_nonresident (
19962005 ni , ATTR_DATA , NULL , 0 , run , next_svcn ,
19972006 evcn1 - eat - next_svcn , a_flags , & attr ,
@@ -2005,18 +2014,9 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
20052014
20062015 /* Free all allocated memory. */
20072016 run_truncate (run , 0 );
2017+ done += eat ;
20082018 } else {
20092019 u16 le_sz ;
2010- u16 roff = le16_to_cpu (attr -> nres .run_off );
2011-
2012- if (roff > le32_to_cpu (attr -> size )) {
2013- err = - EINVAL ;
2014- goto out ;
2015- }
2016-
2017- run_unpack_ex (RUN_DEALLOCATE , sbi , ni -> mi .rno , svcn ,
2018- evcn1 - 1 , svcn , Add2Ptr (attr , roff ),
2019- le32_to_cpu (attr -> size ) - roff );
20202020
20212021 /* Delete this attribute segment. */
20222022 mi_remove_attr (NULL , mi , attr );
@@ -2029,6 +2029,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
20292029 goto out ;
20302030 }
20312031
2032+ done += evcn1 - svcn ;
20322033 if (evcn1 >= alen )
20332034 break ;
20342035
@@ -2046,11 +2047,12 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
20462047 err = - EINVAL ;
20472048 goto out ;
20482049 }
2049- goto next_attr ;
2050+ continue ;
20502051 }
20512052 le = (struct ATTR_LIST_ENTRY * )((u8 * )le - le_sz );
20522053 }
20532054
2055+ next_attr :
20542056 if (evcn1 >= alen )
20552057 break ;
20562058
@@ -2059,10 +2061,6 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
20592061 err = - EINVAL ;
20602062 goto out ;
20612063 }
2062-
2063- next_attr :
2064- svcn = le64_to_cpu (attr -> nres .svcn );
2065- evcn1 = le64_to_cpu (attr -> nres .evcn ) + 1 ;
20662064 }
20672065
20682066 if (!attr_b ) {
@@ -2552,7 +2550,7 @@ int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
25522550 if (attr_load_runs (attr , ni , run , NULL ))
25532551 goto bad_inode ;
25542552
2555- if (!run_collapse_range (run , vcn , len ))
2553+ if (!run_collapse_range (run , vcn , len , 0 ))
25562554 goto bad_inode ;
25572555
25582556 if (mi_pack_runs (mi , attr , run , evcn1 + len - svcn ))
0 commit comments