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>
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
index 2a7cba2..6241c4c 100644
--- a/fs/ntfs/aops.c
+++ b/fs/ntfs/aops.c
@@ -355,6 +355,7 @@
 	u32 attr_len;
 	int err = 0;
 
+retry_readpage:
 	BUG_ON(!PageLocked(page));
 	/*
 	 * This can potentially happen because we clear PageUptodate() during
@@ -408,6 +409,14 @@
 		err = PTR_ERR(mrec);
 		goto err_out;
 	}
+	/*
+	 * If a parallel write made the attribute non-resident, drop the mft
+	 * record and retry the readpage.
+	 */
+	if (unlikely(NInoNonResident(ni))) {
+		unmap_mft_record(base_ni);
+		goto retry_readpage;
+	}
 	ctx = ntfs_attr_get_search_ctx(base_ni, mrec);
 	if (unlikely(!ctx)) {
 		err = -ENOMEM;
@@ -1248,6 +1257,7 @@
 	u32 attr_len;
 	int err;
 
+retry_writepage:
 	BUG_ON(!PageLocked(page));
 	i_size = i_size_read(vi);
 	/* Is the page fully outside i_size? (truncate in progress) */
@@ -1338,6 +1348,14 @@
 		ctx = NULL;
 		goto err_out;
 	}
+	/*
+	 * If a parallel write made the attribute non-resident, drop the mft
+	 * record and retry the writepage.
+	 */
+	if (unlikely(NInoNonResident(ni))) {
+		unmap_mft_record(base_ni);
+		goto retry_writepage;
+	}
 	ctx = ntfs_attr_get_search_ctx(base_ni, m);
 	if (unlikely(!ctx)) {
 		err = -ENOMEM;