Skip to content

Commit ad26a9c

Browse files
fs/ntfs3: Fixing wrong logic in attr_set_size and ntfs_fallocate
There were 2 problems: - in some cases we lost dirty flag; - cluster allocation can be called even when it wasn't needed. Fixes xfstest generic/465 Signed-off-by: Konstantin Komarov <[email protected]>
1 parent 2b10826 commit ad26a9c

File tree

4 files changed

+43
-38
lines changed

4 files changed

+43
-38
lines changed

fs/ntfs3/attrib.c

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
414414
CLST alen, vcn, lcn, new_alen, old_alen, svcn, evcn;
415415
CLST next_svcn, pre_alloc = -1, done = 0;
416416
bool is_ext, is_bad = false;
417+
bool dirty = false;
417418
u32 align;
418419
struct MFT_REC *rec;
419420

@@ -434,8 +435,10 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
434435
return err;
435436

436437
/* Return if file is still resident. */
437-
if (!attr_b->non_res)
438+
if (!attr_b->non_res) {
439+
dirty = true;
438440
goto ok1;
441+
}
439442

440443
/* Layout of records may be changed, so do a full search. */
441444
goto again;
@@ -458,7 +461,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
458461

459462
if (keep_prealloc && new_size < old_size) {
460463
attr_b->nres.data_size = cpu_to_le64(new_size);
461-
mi_b->dirty = true;
464+
mi_b->dirty = dirty = true;
462465
goto ok;
463466
}
464467

@@ -504,7 +507,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
504507

505508
if (new_alloc <= old_alloc) {
506509
attr_b->nres.data_size = cpu_to_le64(new_size);
507-
mi_b->dirty = true;
510+
mi_b->dirty = dirty = true;
508511
goto ok;
509512
}
510513

@@ -595,7 +598,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
595598
next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
596599
new_alloc_tmp = (u64)next_svcn << cluster_bits;
597600
attr_b->nres.alloc_size = cpu_to_le64(new_alloc_tmp);
598-
mi_b->dirty = true;
601+
mi_b->dirty = dirty = true;
599602

600603
if (next_svcn >= vcn && !to_allocate) {
601604
/* Normal way. Update attribute and exit. */
@@ -681,7 +684,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
681684
old_valid = old_size = old_alloc = (u64)vcn << cluster_bits;
682685
attr_b->nres.valid_size = attr_b->nres.data_size =
683686
attr_b->nres.alloc_size = cpu_to_le64(old_size);
684-
mi_b->dirty = true;
687+
mi_b->dirty = dirty = true;
685688
goto again_1;
686689
}
687690

@@ -743,7 +746,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
743746
attr_b->nres.valid_size =
744747
attr_b->nres.alloc_size;
745748
}
746-
mi_b->dirty = true;
749+
mi_b->dirty = dirty = true;
747750

748751
err = run_deallocate_ex(sbi, run, vcn, evcn - vcn + 1, &dlen,
749752
true);
@@ -804,16 +807,9 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
804807
if (ret)
805808
*ret = attr_b;
806809

807-
/* Update inode_set_bytes. */
808810
if (((type == ATTR_DATA && !name_len) ||
809811
(type == ATTR_ALLOC && name == I30_NAME))) {
810-
bool dirty = false;
811-
812-
if (ni->vfs_inode.i_size != new_size) {
813-
ni->vfs_inode.i_size = new_size;
814-
dirty = true;
815-
}
816-
812+
/* Update inode_set_bytes. */
817813
if (attr_b->non_res) {
818814
new_alloc = le64_to_cpu(attr_b->nres.alloc_size);
819815
if (inode_get_bytes(&ni->vfs_inode) != new_alloc) {
@@ -822,6 +818,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
822818
}
823819
}
824820

821+
/* Don't forget to update duplicate information in parent. */
825822
if (dirty) {
826823
ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
827824
mark_inode_dirty(&ni->vfs_inode);

fs/ntfs3/file.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,6 @@ static int ntfs_extend(struct inode *inode, loff_t pos, size_t count,
337337
err = ntfs_set_size(inode, end);
338338
if (err)
339339
goto out;
340-
inode->i_size = end;
341340
}
342341

343342
if (extend_init && !is_compressed(ni)) {
@@ -588,12 +587,14 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
588587
if (err)
589588
goto out;
590589

591-
/*
592-
* Allocate clusters, do not change 'valid' size.
593-
*/
594-
err = ntfs_set_size(inode, new_size);
595-
if (err)
596-
goto out;
590+
if (new_size > i_size) {
591+
/*
592+
* Allocate clusters, do not change 'valid' size.
593+
*/
594+
err = ntfs_set_size(inode, new_size);
595+
if (err)
596+
goto out;
597+
}
597598

598599
if (is_supported_holes) {
599600
CLST vcn = vbo >> sbi->cluster_bits;
@@ -635,6 +636,8 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
635636
&ni->file.run, i_size, &ni->i_valid,
636637
true, NULL);
637638
ni_unlock(ni);
639+
} else if (new_size > i_size) {
640+
inode->i_size = new_size;
638641
}
639642
}
640643

@@ -678,24 +681,27 @@ int ntfs3_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
678681
goto out;
679682

680683
if (ia_valid & ATTR_SIZE) {
681-
loff_t oldsize = inode->i_size;
684+
loff_t newsize, oldsize;
682685

683686
if (WARN_ON(ni->ni_flags & NI_FLAG_COMPRESSED_MASK)) {
684687
/* Should never be here, see ntfs_file_open(). */
685688
err = -EOPNOTSUPP;
686689
goto out;
687690
}
688691
inode_dio_wait(inode);
692+
oldsize = inode->i_size;
693+
newsize = attr->ia_size;
689694

690-
if (attr->ia_size <= oldsize)
691-
err = ntfs_truncate(inode, attr->ia_size);
692-
else if (attr->ia_size > oldsize)
693-
err = ntfs_extend(inode, attr->ia_size, 0, NULL);
695+
if (newsize <= oldsize)
696+
err = ntfs_truncate(inode, newsize);
697+
else
698+
err = ntfs_extend(inode, newsize, 0, NULL);
694699

695700
if (err)
696701
goto out;
697702

698703
ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
704+
inode->i_size = newsize;
699705
}
700706

701707
setattr_copy(mnt_userns, inode, attr);

fs/ntfs3/index.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,6 +1445,9 @@ static int indx_add_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
14451445
goto out1;
14461446
}
14471447

1448+
if (in->name == I30_NAME)
1449+
ni->vfs_inode.i_size = data_size;
1450+
14481451
*vbn = bit << indx->idx2vbn_bits;
14491452

14501453
return 0;
@@ -1978,6 +1981,9 @@ static int indx_shrink(struct ntfs_index *indx, struct ntfs_inode *ni,
19781981
if (err)
19791982
return err;
19801983

1984+
if (in->name == I30_NAME)
1985+
ni->vfs_inode.i_size = new_data;
1986+
19811987
bpb = bitmap_size(bit);
19821988
if (bpb * 8 == nbits)
19831989
return 0;
@@ -2461,6 +2467,9 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
24612467

24622468
err = attr_set_size(ni, ATTR_ALLOC, in->name, in->name_len,
24632469
&indx->alloc_run, 0, NULL, false, NULL);
2470+
if (in->name == I30_NAME)
2471+
ni->vfs_inode.i_size = 0;
2472+
24642473
err = ni_remove_attr(ni, ATTR_ALLOC, in->name, in->name_len,
24652474
false, NULL);
24662475
run_close(&indx->alloc_run);

fs/ntfs3/inode.c

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -551,17 +551,6 @@ static noinline int ntfs_get_block_vbo(struct inode *inode, u64 vbo,
551551
clear_buffer_new(bh);
552552
clear_buffer_uptodate(bh);
553553

554-
/* Direct write uses 'create=0'. */
555-
if (!create && vbo >= ni->i_valid) {
556-
/* Out of valid. */
557-
return 0;
558-
}
559-
560-
if (vbo >= inode->i_size) {
561-
/* Out of size. */
562-
return 0;
563-
}
564-
565554
if (is_resident(ni)) {
566555
ni_lock(ni);
567556
err = attr_data_read_resident(ni, page);
@@ -625,7 +614,6 @@ static noinline int ntfs_get_block_vbo(struct inode *inode, u64 vbo,
625614
}
626615
} else if (vbo >= valid) {
627616
/* Read out of valid data. */
628-
/* Should never be here 'cause already checked. */
629617
clear_buffer_mapped(bh);
630618
} else if (vbo + bytes <= valid) {
631619
/* Normal read. */
@@ -975,6 +963,11 @@ int ntfs_write_end(struct file *file, struct address_space *mapping,
975963
dirty = true;
976964
}
977965

966+
if (pos + err > inode->i_size) {
967+
inode->i_size = pos + err;
968+
dirty = true;
969+
}
970+
978971
if (dirty)
979972
mark_inode_dirty(inode);
980973
}

0 commit comments

Comments
 (0)