From 905685f68fc72844b8c2689c39a5c6c35e840152 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Thu, 10 Mar 2005 11:06:19 +0000 Subject: NTFS: - Modify ->readpage and ->writepage (fs/ntfs/aops.c) so they detect and handle the case where an attribute is converted from resident to non-resident by a concurrent file write. - Reorder some operations when converting an attribute from resident to non-resident (fs/ntfs/attrib.c) so it is safe wrt concurrent ->readpage and ->writepage. Signed-off-by: Anton Altaparmakov --- fs/ntfs/attrib.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'fs/ntfs/attrib.c') diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 3b9de404021..41859343a0c 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -1376,19 +1376,6 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) err = ntfs_attr_record_resize(m, a, arec_size); if (unlikely(err)) goto err_out; - /* Setup the in-memory attribute structure to be non-resident. */ - NInoSetNonResident(ni); - ni->runlist.rl = rl; - write_lock_irqsave(&ni->size_lock, flags); - ni->allocated_size = new_size; - write_unlock_irqrestore(&ni->size_lock, flags); - /* - * FIXME: For now just clear all of these as we do not support them - * when writing. - */ - NInoClearCompressed(ni); - NInoClearSparse(ni); - NInoClearEncrypted(ni); /* * Convert the resident part of the attribute record to describe a * non-resident attribute. @@ -1399,7 +1386,10 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset), a->name_length * sizeof(ntfschar)); a->name_offset = cpu_to_le16(name_ofs); - /* Update the flags to match the in-memory ones. */ + /* + * FIXME: For now just clear all of these as we do not support them + * when writing. + */ a->flags &= cpu_to_le16(0xffff & ~le16_to_cpu(ATTR_IS_SPARSE | ATTR_IS_ENCRYPTED | ATTR_COMPRESSION_MASK)); /* Setup the fields specific to non-resident attributes. */ @@ -1422,6 +1412,25 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) err); goto undo_err_out; } + /* Setup the in-memory attribute structure to be non-resident. */ + /* + * FIXME: For now just clear all of these as we do not support them + * when writing. + */ + NInoClearSparse(ni); + NInoClearEncrypted(ni); + NInoClearCompressed(ni); + ni->runlist.rl = rl; + write_lock_irqsave(&ni->size_lock, flags); + ni->allocated_size = new_size; + write_unlock_irqrestore(&ni->size_lock, flags); + /* + * This needs to be last since the address space operations ->readpage + * and ->writepage can run concurrently with us as they are not + * serialized on i_sem. Note, we are not allowed to fail once we flip + * this switch, which is another reason to do this last. + */ + NInoSetNonResident(ni); /* Mark the mft record dirty, so it gets written back. */ flush_dcache_mft_record_page(ctx->ntfs_ino); mark_mft_record_dirty(ctx->ntfs_ino); @@ -1431,6 +1440,7 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) if (page) { set_page_dirty(page); unlock_page(page); + mark_page_accessed(page); page_cache_release(page); } ntfs_debug("Done."); @@ -1492,11 +1502,10 @@ undo_err_out: memcpy((u8*)a + mp_ofs, kaddr, attr_size); kunmap_atomic(kaddr, KM_USER0); } - /* Finally setup the ntfs inode appropriately. */ + /* Setup the allocated size in the ntfs inode in case it changed. */ write_lock_irqsave(&ni->size_lock, flags); ni->allocated_size = arec_size - mp_ofs; write_unlock_irqrestore(&ni->size_lock, flags); - NInoClearNonResident(ni); /* Mark the mft record dirty, so it gets written back. */ flush_dcache_mft_record_page(ctx->ntfs_ino); mark_mft_record_dirty(ctx->ntfs_ino); -- cgit v1.2.3