Skip to contentSkip to conversation

dax: Release PMD lock even when there is no PMD support in DAX

PATCH Applied Jan H. Schönherr 3 participants 9 messages Jan 18, 2018 – Jan 25, 2018

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 dax: Release PMD lock even when there is no PMD support in DAX

The function follow_pte_pmd() can theoretically return after having acquired a PMD lock, even when DAX was not compiled with CONFIG_FS_DAX_PMD.

Release the PMD lock unconditionally.

Fixes f729c8c9b24f ("dax: wrprotect pmd_t in dax_mapping_entry_mkclean")
---
 fs/dax.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/dax.c +1 -1
index 9598159..c2ebf10 100644
@@ -636,8 +636,8 @@ static void dax_mapping_entry_mkclean(struct address_space *mapping,
 			pmd = pmd_mkclean(pmd);
 			set_pmd_at(vma->vm_mm, address, pmdp, pmd);
 unlock_pmd:
-			spin_unlock(ptl);
 #endif
+			spin_unlock(ptl);
 		} else {
 			if (pfn != pte_pfn(*ptep))
 				goto unlock_pte;
Signature · 1 line
2.9.3.1.gcba166c.dirty
#1 lore raw
Quoted 3 lines · Jan H. Sch�nherr

The function follow_pte_pmd() can theoretically return after having acquired a PMD lock, even when DAX was not compiled with CONFIG_FS_DAX_PMD.

I don't think it can. How would a PMD entry get into a DAX VMA if we compiled the kernel without CONFIG_FS_DAX_PMD?

#2 lore raw
Quoted 7 lines · Matthew Wilcox
Quoted 3 lines · Jan H. Sch�nherr

The function follow_pte_pmd() can theoretically return after having acquired a PMD lock, even when DAX was not compiled with CONFIG_FS_DAX_PMD.

I don't think it can. How would a PMD entry get into a DAX VMA if we compiled the kernel without CONFIG_FS_DAX_PMD?

How about this patch instead? Should shut up sparse nicely.

fs/dax.c +7 -3
index 78b72c48374e..fea1b64d111b 100644
@@ -586,6 +586,12 @@ pgoff_address(pgoff_t pgoff, struct vm_area_struct *vma)
 	return address;
 }
 
+#ifdef CONFIG_FS_DAX_PMD
+#define dax_pmd(pmdp)	pmdp
+#else
+#define dax_pmd(pmdp)	0
+#endif
+
 /* Walk all mappings of a given index of a file and writeprotect them */
 static void dax_mapping_entry_mkclean(struct address_space *mapping,
 				      pgoff_t index, unsigned long pfn)
@@ -621,8 +627,7 @@ static void dax_mapping_entry_mkclean(struct address_space *mapping,
 		 *
 		 * See Documentation/vm/mmu_notifier.txt
 		 */
-		if (pmdp) {
-#ifdef CONFIG_FS_DAX_PMD
+		if (dax_pmd(pmdp)) {
 			pmd_t pmd;
 
 			if (pfn != pmd_pfn(*pmdp))
@@ -638,7 +643,6 @@ static void dax_mapping_entry_mkclean(struct address_space *mapping,
 			set_pmd_at(vma->vm_mm, address, pmdp, pmd);
 unlock_pmd:
 			spin_unlock(ptl);
-#endif
 		} else {
 			if (pfn != pte_pfn(*ptep))
 				goto unlock_pte;
#3 lore raw
Quoted 10 lines · Matthew Wilcox
Quoted 7 lines · Matthew Wilcox
Quoted 3 lines · Jan H. Schönherr

The function follow_pte_pmd() can theoretically return after having acquired a PMD lock, even when DAX was not compiled with CONFIG_FS_DAX_PMD.

I don't think it can. How would a PMD entry get into a DAX VMA if we compiled the kernel without CONFIG_FS_DAX_PMD?

How about this patch instead? Should shut up sparse nicely.

It would still skip the unlock, in case pmdp is !=NULL (and locked) after follow_pte_pmd(). So it wouldn't address, what I intended to address with the patch.

Regards
Jan

Quoted 37 lines
fs/dax.c +7 -3
index 78b72c48374e..fea1b64d111b 100644
@@ -586,6 +586,12 @@ pgoff_address(pgoff_t pgoff, struct vm_area_struct *vma)
 	return address;
 }
 
+#ifdef CONFIG_FS_DAX_PMD
+#define dax_pmd(pmdp)	pmdp
+#else
+#define dax_pmd(pmdp)	0
+#endif
+
 /* Walk all mappings of a given index of a file and writeprotect them */
 static void dax_mapping_entry_mkclean(struct address_space *mapping,
 				      pgoff_t index, unsigned long pfn)
@@ -621,8 +627,7 @@ static void dax_mapping_entry_mkclean(struct address_space *mapping,
 		 *
 		 * See Documentation/vm/mmu_notifier.txt
 		 */
-		if (pmdp) {
-#ifdef CONFIG_FS_DAX_PMD
+		if (dax_pmd(pmdp)) {
 			pmd_t pmd;
 
 			if (pfn != pmd_pfn(*pmdp))
@@ -638,7 +643,6 @@ static void dax_mapping_entry_mkclean(struct address_space *mapping,
 			set_pmd_at(vma->vm_mm, address, pmdp, pmd);
 unlock_pmd:
 			spin_unlock(ptl);
-#endif
 		} else {
 			if (pfn != pte_pfn(*ptep))
 				goto unlock_pte;
#4 lore raw
Quoted 2 lines · Jan H. Schönherr

It would still skip the unlock, in case pmdp is !=NULL (and locked) after follow_pte_pmd(). So it wouldn't address, what I intended to address with the patch.

Small correction: we'd take the "else" branch, which would do some stuff it's not supposed to do when follow_pte_pmd() returns with pmdp!=NULL. And we'd actually do a unlock, but thinking it's a PTE, not a PMD.

So, defensive-wise, may point still stands, that we're not correctly handling an unexpectedly returned PMD entry.

Regards
Jan

#5 lore raw
In reply to Matthew Wilcox
Quoted 8 lines · Matthew Wilcox
Quoted 3 lines · Jan H. Schönherr

The function follow_pte_pmd() can theoretically return after having acquired a PMD lock, even when DAX was not compiled with CONFIG_FS_DAX_PMD.

I don't think it can. How would a PMD entry get into a DAX VMA if we compiled the kernel without CONFIG_FS_DAX_PMD?

Maybe it can not in happy cases. But the PMD parts in follow_pte_pmd() are compiled in unconditionally. So, if there's an issue elsewhere, and for some weird reason we get a PMD entry in the page table, it would screw the lock balance.

I haven't run into an actual issue with this, it's just supposed to be defensive.

Regards
Jan

Reviewed-by on v1 1/1
#6 lore raw
In reply to Jan H. Schönherr
Quoted 17 lines · Jan H. Sch�nherr

The function follow_pte_pmd() can theoretically return after having acquired a PMD lock, even when DAX was not compiled with CONFIG_FS_DAX_PMD.

Release the PMD lock unconditionally.

Fixes f729c8c9b24f ("dax: wrprotect pmd_t in dax_mapping_entry_mkclean")
---
 fs/dax.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/dax.c +0 -0
index 9598159..c2ebf10 100644

fs/dax.c static void dax_mapping_entry_mkclean(struct address_space *mapping, · line 643

Quoted 9 lines
fs/dax.c +1 -1
@@ -636,8 +636,8 @@ static void dax_mapping_entry_mkclean(struct address_space *mapping,
 			pmd = pmd_mkclean(pmd);
 			set_pmd_at(vma->vm_mm, address, pmdp, pmd);
 unlock_pmd:
-			spin_unlock(ptl);
 #endif
+			spin_unlock(ptl);
 		} else {
 			if (pfn != pte_pfn(*ptep))
 				goto unlock_pte;

Sure, this seems fine to me. This seems simple and correct - you're right that we aren't taking the PTL on the PMD conditionally based on whether CONFIG_DAX_PMD is defined, so it doesn't make sense to release it conditionally. I think if we ever hit this lock imbalance we're totally insane anyway, but it the fix is correct and doesn't mess with our code flow.

You can add:

#7 lore raw
Quoted 34 lines · Ross Zwisler
Quoted 17 lines · Jan H. Sch�nherr

The function follow_pte_pmd() can theoretically return after having acquired a PMD lock, even when DAX was not compiled with CONFIG_FS_DAX_PMD.

Release the PMD lock unconditionally.

Fixes f729c8c9b24f ("dax: wrprotect pmd_t in dax_mapping_entry_mkclean")
---
 fs/dax.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
fs/dax.c +0 -0
index 9598159..c2ebf10 100644

fs/dax.c static void dax_mapping_entry_mkclean(struct address_space *mapping, · line 643

Quoted 9 lines
fs/dax.c +1 -1
@@ -636,8 +636,8 @@ static void dax_mapping_entry_mkclean(struct address_space *mapping,
 			pmd = pmd_mkclean(pmd);
 			set_pmd_at(vma->vm_mm, address, pmdp, pmd);
 unlock_pmd:
-			spin_unlock(ptl);
 #endif
+			spin_unlock(ptl);
 		} else {
 			if (pfn != pte_pfn(*ptep))
 				goto unlock_pte;

Sure, this seems fine to me. This seems simple and correct - you're right that we aren't taking the PTL on the PMD conditionally based on whether CONFIG_DAX_PMD is defined, so it doesn't make sense to release it conditionally. I think if we ever hit this lock imbalance we're totally insane anyway, but it the fix is correct and doesn't mess with our code flow.

Quoted 2 lines

You can add:

Ah, I just realized that this patch didn't CC Andrew, and he's the one that usually takes our DAX patches.

Andrew, can you pick this up? Here's the fsdevel patchwork:

https://patchwork.kernel.org/patch/10173255/

Thanks,
- Ross

#8 lore raw
Quoted 6 lines · Ross Zwisler

Ah, I just realized that this patch didn't CC Andrew, and he's the one that usually takes our DAX patches.

Andrew, can you pick this up? Here's the fsdevel patchwork:

https://patchwork.kernel.org/patch/10173255/

Thanks for that, I didn't know.

Let me know, if I should resend instead (in case it makes things easier).

Regards
Jan