Skip to content

Commit eb449bd

Browse files
surenbaghdasaryanPeter Zijlstra
authored andcommitted
mm: convert mm_lock_seq to a proper seqcount
Convert mm_lock_seq to be seqcount_t and change all mmap_write_lock variants to increment it, in-line with the usual seqcount usage pattern. This lets us check whether the mmap_lock is write-locked by checking mm_lock_seq.sequence counter (odd=locked, even=unlocked). This will be used when implementing mmap_lock speculation functions. As a result vm_lock_seq is also change to be unsigned to match the type of mm_lock_seq.sequence. Suggested-by: Peter Zijlstra <[email protected]> Signed-off-by: Suren Baghdasaryan <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Liam R. Howlett <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 7528585 commit eb449bd

File tree

7 files changed

+53
-36
lines changed

7 files changed

+53
-36
lines changed

include/linux/mm.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ static inline bool vma_start_read(struct vm_area_struct *vma)
710710
* we don't rely on for anything - the mm_lock_seq read against which we
711711
* need ordering is below.
712712
*/
713-
if (READ_ONCE(vma->vm_lock_seq) == READ_ONCE(vma->vm_mm->mm_lock_seq))
713+
if (READ_ONCE(vma->vm_lock_seq) == READ_ONCE(vma->vm_mm->mm_lock_seq.sequence))
714714
return false;
715715

716716
if (unlikely(down_read_trylock(&vma->vm_lock->lock) == 0))
@@ -727,7 +727,7 @@ static inline bool vma_start_read(struct vm_area_struct *vma)
727727
* after it has been unlocked.
728728
* This pairs with RELEASE semantics in vma_end_write_all().
729729
*/
730-
if (unlikely(vma->vm_lock_seq == smp_load_acquire(&vma->vm_mm->mm_lock_seq))) {
730+
if (unlikely(vma->vm_lock_seq == raw_read_seqcount(&vma->vm_mm->mm_lock_seq))) {
731731
up_read(&vma->vm_lock->lock);
732732
return false;
733733
}
@@ -742,15 +742,15 @@ static inline void vma_end_read(struct vm_area_struct *vma)
742742
}
743743

744744
/* WARNING! Can only be used if mmap_lock is expected to be write-locked */
745-
static bool __is_vma_write_locked(struct vm_area_struct *vma, int *mm_lock_seq)
745+
static bool __is_vma_write_locked(struct vm_area_struct *vma, unsigned int *mm_lock_seq)
746746
{
747747
mmap_assert_write_locked(vma->vm_mm);
748748

749749
/*
750750
* current task is holding mmap_write_lock, both vma->vm_lock_seq and
751751
* mm->mm_lock_seq can't be concurrently modified.
752752
*/
753-
*mm_lock_seq = vma->vm_mm->mm_lock_seq;
753+
*mm_lock_seq = vma->vm_mm->mm_lock_seq.sequence;
754754
return (vma->vm_lock_seq == *mm_lock_seq);
755755
}
756756

@@ -761,7 +761,7 @@ static bool __is_vma_write_locked(struct vm_area_struct *vma, int *mm_lock_seq)
761761
*/
762762
static inline void vma_start_write(struct vm_area_struct *vma)
763763
{
764-
int mm_lock_seq;
764+
unsigned int mm_lock_seq;
765765

766766
if (__is_vma_write_locked(vma, &mm_lock_seq))
767767
return;
@@ -779,7 +779,7 @@ static inline void vma_start_write(struct vm_area_struct *vma)
779779

780780
static inline void vma_assert_write_locked(struct vm_area_struct *vma)
781781
{
782-
int mm_lock_seq;
782+
unsigned int mm_lock_seq;
783783

784784
VM_BUG_ON_VMA(!__is_vma_write_locked(vma, &mm_lock_seq), vma);
785785
}

include/linux/mm_types.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ struct vm_area_struct {
697697
* counter reuse can only lead to occasional unnecessary use of the
698698
* slowpath.
699699
*/
700-
int vm_lock_seq;
700+
unsigned int vm_lock_seq;
701701
/* Unstable RCU readers are allowed to read this. */
702702
struct vma_lock *vm_lock;
703703
#endif
@@ -891,6 +891,9 @@ struct mm_struct {
891891
* Roughly speaking, incrementing the sequence number is
892892
* equivalent to releasing locks on VMAs; reading the sequence
893893
* number can be part of taking a read lock on a VMA.
894+
* Incremented every time mmap_lock is write-locked/unlocked.
895+
* Initialized to 0, therefore odd values indicate mmap_lock
896+
* is write-locked and even values that it's released.
894897
*
895898
* Can be modified under write mmap_lock using RELEASE
896899
* semantics.
@@ -899,7 +902,7 @@ struct mm_struct {
899902
* Can be read with ACQUIRE semantics if not holding write
900903
* mmap_lock.
901904
*/
902-
int mm_lock_seq;
905+
seqcount_t mm_lock_seq;
903906
#endif
904907

905908

include/linux/mmap_lock.h

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -71,46 +71,47 @@ static inline void mmap_assert_write_locked(const struct mm_struct *mm)
7171
}
7272

7373
#ifdef CONFIG_PER_VMA_LOCK
74-
/*
75-
* Drop all currently-held per-VMA locks.
76-
* This is called from the mmap_lock implementation directly before releasing
77-
* a write-locked mmap_lock (or downgrading it to read-locked).
78-
* This should normally NOT be called manually from other places.
79-
* If you want to call this manually anyway, keep in mind that this will release
80-
* *all* VMA write locks, including ones from further up the stack.
81-
*/
82-
static inline void vma_end_write_all(struct mm_struct *mm)
74+
static inline void mm_lock_seqcount_init(struct mm_struct *mm)
8375
{
84-
mmap_assert_write_locked(mm);
85-
/*
86-
* Nobody can concurrently modify mm->mm_lock_seq due to exclusive
87-
* mmap_lock being held.
88-
* We need RELEASE semantics here to ensure that preceding stores into
89-
* the VMA take effect before we unlock it with this store.
90-
* Pairs with ACQUIRE semantics in vma_start_read().
91-
*/
92-
smp_store_release(&mm->mm_lock_seq, mm->mm_lock_seq + 1);
76+
seqcount_init(&mm->mm_lock_seq);
77+
}
78+
79+
static inline void mm_lock_seqcount_begin(struct mm_struct *mm)
80+
{
81+
do_raw_write_seqcount_begin(&mm->mm_lock_seq);
82+
}
83+
84+
static inline void mm_lock_seqcount_end(struct mm_struct *mm)
85+
{
86+
ASSERT_EXCLUSIVE_WRITER(mm->mm_lock_seq);
87+
do_raw_write_seqcount_end(&mm->mm_lock_seq);
9388
}
89+
9490
#else
95-
static inline void vma_end_write_all(struct mm_struct *mm) {}
91+
static inline void mm_lock_seqcount_init(struct mm_struct *mm) {}
92+
static inline void mm_lock_seqcount_begin(struct mm_struct *mm) {}
93+
static inline void mm_lock_seqcount_end(struct mm_struct *mm) {}
9694
#endif
9795

9896
static inline void mmap_init_lock(struct mm_struct *mm)
9997
{
10098
init_rwsem(&mm->mmap_lock);
99+
mm_lock_seqcount_init(mm);
101100
}
102101

103102
static inline void mmap_write_lock(struct mm_struct *mm)
104103
{
105104
__mmap_lock_trace_start_locking(mm, true);
106105
down_write(&mm->mmap_lock);
106+
mm_lock_seqcount_begin(mm);
107107
__mmap_lock_trace_acquire_returned(mm, true, true);
108108
}
109109

110110
static inline void mmap_write_lock_nested(struct mm_struct *mm, int subclass)
111111
{
112112
__mmap_lock_trace_start_locking(mm, true);
113113
down_write_nested(&mm->mmap_lock, subclass);
114+
mm_lock_seqcount_begin(mm);
114115
__mmap_lock_trace_acquire_returned(mm, true, true);
115116
}
116117

@@ -120,10 +121,26 @@ static inline int mmap_write_lock_killable(struct mm_struct *mm)
120121

121122
__mmap_lock_trace_start_locking(mm, true);
122123
ret = down_write_killable(&mm->mmap_lock);
124+
if (!ret)
125+
mm_lock_seqcount_begin(mm);
123126
__mmap_lock_trace_acquire_returned(mm, true, ret == 0);
124127
return ret;
125128
}
126129

130+
/*
131+
* Drop all currently-held per-VMA locks.
132+
* This is called from the mmap_lock implementation directly before releasing
133+
* a write-locked mmap_lock (or downgrading it to read-locked).
134+
* This should normally NOT be called manually from other places.
135+
* If you want to call this manually anyway, keep in mind that this will release
136+
* *all* VMA write locks, including ones from further up the stack.
137+
*/
138+
static inline void vma_end_write_all(struct mm_struct *mm)
139+
{
140+
mmap_assert_write_locked(mm);
141+
mm_lock_seqcount_end(mm);
142+
}
143+
127144
static inline void mmap_write_unlock(struct mm_struct *mm)
128145
{
129146
__mmap_lock_trace_released(mm, true);

kernel/fork.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ static bool vma_lock_alloc(struct vm_area_struct *vma)
448448
return false;
449449

450450
init_rwsem(&vma->vm_lock->lock);
451-
vma->vm_lock_seq = -1;
451+
vma->vm_lock_seq = UINT_MAX;
452452

453453
return true;
454454
}
@@ -1267,9 +1267,6 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
12671267
seqcount_init(&mm->write_protect_seq);
12681268
mmap_init_lock(mm);
12691269
INIT_LIST_HEAD(&mm->mmlist);
1270-
#ifdef CONFIG_PER_VMA_LOCK
1271-
mm->mm_lock_seq = 0;
1272-
#endif
12731270
mm_pgtables_bytes_init(mm);
12741271
mm->map_count = 0;
12751272
mm->locked_vm = 0;

mm/init-mm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ struct mm_struct init_mm = {
4040
.arg_lock = __SPIN_LOCK_UNLOCKED(init_mm.arg_lock),
4141
.mmlist = LIST_HEAD_INIT(init_mm.mmlist),
4242
#ifdef CONFIG_PER_VMA_LOCK
43-
.mm_lock_seq = 0,
43+
.mm_lock_seq = SEQCNT_ZERO(init_mm.mm_lock_seq),
4444
#endif
4545
.user_ns = &init_user_ns,
4646
.cpu_bitmap = CPU_BITS_NONE,

tools/testing/vma/vma.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ static struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
8989
* begun. Linking to the tree will have caused this to be incremented,
9090
* which means we will get a false positive otherwise.
9191
*/
92-
vma->vm_lock_seq = -1;
92+
vma->vm_lock_seq = UINT_MAX;
9393

9494
return vma;
9595
}
@@ -214,7 +214,7 @@ static bool vma_write_started(struct vm_area_struct *vma)
214214
int seq = vma->vm_lock_seq;
215215

216216
/* We reset after each check. */
217-
vma->vm_lock_seq = -1;
217+
vma->vm_lock_seq = UINT_MAX;
218218

219219
/* The vma_start_write() stub simply increments this value. */
220220
return seq > -1;

tools/testing/vma/vma_internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ struct vm_area_struct {
241241
* counter reuse can only lead to occasional unnecessary use of the
242242
* slowpath.
243243
*/
244-
int vm_lock_seq;
244+
unsigned int vm_lock_seq;
245245
struct vma_lock *vm_lock;
246246
#endif
247247

@@ -416,7 +416,7 @@ static inline bool vma_lock_alloc(struct vm_area_struct *vma)
416416
return false;
417417

418418
init_rwsem(&vma->vm_lock->lock);
419-
vma->vm_lock_seq = -1;
419+
vma->vm_lock_seq = UINT_MAX;
420420

421421
return true;
422422
}

0 commit comments

Comments
 (0)