diff options
author | Anton Altaparmakov <aia21@cantab.net> | 2005-03-10 11:06:19 +0000 |
---|---|---|
committer | Anton Altaparmakov <aia21@cantab.net> | 2005-05-05 11:26:01 +0100 |
commit | 905685f68fc72844b8c2689c39a5c6c35e840152 (patch) | |
tree | 0ff1d145a7771b24643c1b685ecbb3f791cda6fb /fs/ntfs/attrib.c | |
parent | 43b01fda8b17b2b63e7dcdeed11c2ebba56b1fc9 (diff) | |
download | lwn-905685f68fc72844b8c2689c39a5c6c35e840152.tar.gz lwn-905685f68fc72844b8c2689c39a5c6c35e840152.zip |
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 <aia21@cantab.net>
Diffstat (limited to 'fs/ntfs/attrib.c')
-rw-r--r-- | fs/ntfs/attrib.c | 41 |
1 files changed, 25 insertions, 16 deletions
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 3b9de4040216..41859343a0c8 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); |