Skip to content

Commit 5c26f6a

Browse files
surenbaghdasaryantorvalds
authored andcommitted
mm: refactor vm_area_struct::anon_vma_name usage code
Avoid mixing strings and their anon_vma_name referenced pointers by using struct anon_vma_name whenever possible. This simplifies the code and allows easier sharing of anon_vma_name structures when they represent the same name. [surenb@google.com: fix comment] Link: https://lkml.kernel.org/r/20220223153613.835563-1-surenb@google.com Link: https://lkml.kernel.org/r/20220224231834.1481408-1-surenb@google.com Signed-off-by: Suren Baghdasaryan <surenb@google.com> Suggested-by: Matthew Wilcox <willy@infradead.org> Suggested-by: Michal Hocko <mhocko@suse.com> Acked-by: Michal Hocko <mhocko@suse.com> Cc: Colin Cross <ccross@google.com> Cc: Sumit Semwal <sumit.semwal@linaro.org> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Kees Cook <keescook@chromium.org> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Christian Brauner <brauner@kernel.org> Cc: Alexey Gladkov <legion@kernel.org> Cc: Sasha Levin <sashal@kernel.org> Cc: Chris Hyser <chris.hyser@oracle.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: Peter Collingbourne <pcc@google.com> Cc: Xiaofeng Cao <caoxiaofeng@yulong.com> Cc: David Hildenbrand <david@redhat.com> Cc: Cyrill Gorcunov <gorcunov@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent ff712a6 commit 5c26f6a

12 files changed

Lines changed: 125 additions & 114 deletions

File tree

fs/proc/task_mmu.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
309309

310310
name = arch_vma_name(vma);
311311
if (!name) {
312-
const char *anon_name;
312+
struct anon_vma_name *anon_name;
313313

314314
if (!mm) {
315315
name = "[vdso]";
@@ -327,10 +327,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
327327
goto done;
328328
}
329329

330-
anon_name = vma_anon_name(vma);
330+
anon_name = anon_vma_name(vma);
331331
if (anon_name) {
332332
seq_pad(m, ' ');
333-
seq_printf(m, "[anon:%s]", anon_name);
333+
seq_printf(m, "[anon:%s]", anon_name->name);
334334
}
335335
}
336336

fs/userfaultfd.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -878,7 +878,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
878878
new_flags, vma->anon_vma,
879879
vma->vm_file, vma->vm_pgoff,
880880
vma_policy(vma),
881-
NULL_VM_UFFD_CTX, vma_anon_name(vma));
881+
NULL_VM_UFFD_CTX, anon_vma_name(vma));
882882
if (prev)
883883
vma = prev;
884884
else
@@ -1438,7 +1438,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
14381438
vma->anon_vma, vma->vm_file, vma->vm_pgoff,
14391439
vma_policy(vma),
14401440
((struct vm_userfaultfd_ctx){ ctx }),
1441-
vma_anon_name(vma));
1441+
anon_vma_name(vma));
14421442
if (prev) {
14431443
vma = prev;
14441444
goto next;
@@ -1615,7 +1615,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
16151615
prev = vma_merge(mm, prev, start, vma_end, new_flags,
16161616
vma->anon_vma, vma->vm_file, vma->vm_pgoff,
16171617
vma_policy(vma),
1618-
NULL_VM_UFFD_CTX, vma_anon_name(vma));
1618+
NULL_VM_UFFD_CTX, anon_vma_name(vma));
16191619
if (prev) {
16201620
vma = prev;
16211621
goto next;

include/linux/mm.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2626,7 +2626,7 @@ static inline int vma_adjust(struct vm_area_struct *vma, unsigned long start,
26262626
extern struct vm_area_struct *vma_merge(struct mm_struct *,
26272627
struct vm_area_struct *prev, unsigned long addr, unsigned long end,
26282628
unsigned long vm_flags, struct anon_vma *, struct file *, pgoff_t,
2629-
struct mempolicy *, struct vm_userfaultfd_ctx, const char *);
2629+
struct mempolicy *, struct vm_userfaultfd_ctx, struct anon_vma_name *);
26302630
extern struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *);
26312631
extern int __split_vma(struct mm_struct *, struct vm_area_struct *,
26322632
unsigned long addr, int new_below);
@@ -3372,11 +3372,12 @@ static inline int seal_check_future_write(int seals, struct vm_area_struct *vma)
33723372

33733373
#ifdef CONFIG_ANON_VMA_NAME
33743374
int madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
3375-
unsigned long len_in, const char *name);
3375+
unsigned long len_in,
3376+
struct anon_vma_name *anon_name);
33763377
#else
33773378
static inline int
33783379
madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
3379-
unsigned long len_in, const char *name) {
3380+
unsigned long len_in, struct anon_vma_name *anon_name) {
33803381
return 0;
33813382
}
33823383
#endif

include/linux/mm_inline.h

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -140,50 +140,81 @@ static __always_inline void del_page_from_lru_list(struct page *page,
140140

141141
#ifdef CONFIG_ANON_VMA_NAME
142142
/*
143-
* mmap_lock should be read-locked when calling vma_anon_name() and while using
144-
* the returned pointer.
143+
* mmap_lock should be read-locked when calling anon_vma_name(). Caller should
144+
* either keep holding the lock while using the returned pointer or it should
145+
* raise anon_vma_name refcount before releasing the lock.
145146
*/
146-
extern const char *vma_anon_name(struct vm_area_struct *vma);
147+
extern struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma);
148+
extern struct anon_vma_name *anon_vma_name_alloc(const char *name);
149+
extern void anon_vma_name_free(struct kref *kref);
147150

148-
/*
149-
* mmap_lock should be read-locked for orig_vma->vm_mm.
150-
* mmap_lock should be write-locked for new_vma->vm_mm or new_vma should be
151-
* isolated.
152-
*/
153-
extern void dup_vma_anon_name(struct vm_area_struct *orig_vma,
154-
struct vm_area_struct *new_vma);
151+
/* mmap_lock should be read-locked */
152+
static inline void anon_vma_name_get(struct anon_vma_name *anon_name)
153+
{
154+
if (anon_name)
155+
kref_get(&anon_name->kref);
156+
}
155157

156-
/*
157-
* mmap_lock should be write-locked or vma should have been isolated under
158-
* write-locked mmap_lock protection.
159-
*/
160-
extern void free_vma_anon_name(struct vm_area_struct *vma);
158+
static inline void anon_vma_name_put(struct anon_vma_name *anon_name)
159+
{
160+
if (anon_name)
161+
kref_put(&anon_name->kref, anon_vma_name_free);
162+
}
161163

162-
/* mmap_lock should be read-locked */
163-
static inline bool is_same_vma_anon_name(struct vm_area_struct *vma,
164-
const char *name)
164+
static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma,
165+
struct vm_area_struct *new_vma)
166+
{
167+
struct anon_vma_name *anon_name = anon_vma_name(orig_vma);
168+
169+
if (anon_name) {
170+
anon_vma_name_get(anon_name);
171+
new_vma->anon_name = anon_name;
172+
}
173+
}
174+
175+
static inline void free_anon_vma_name(struct vm_area_struct *vma)
165176
{
166-
const char *vma_name = vma_anon_name(vma);
177+
/*
178+
* Not using anon_vma_name because it generates a warning if mmap_lock
179+
* is not held, which might be the case here.
180+
*/
181+
if (!vma->vm_file)
182+
anon_vma_name_put(vma->anon_name);
183+
}
167184

168-
/* either both NULL, or pointers to same string */
169-
if (vma_name == name)
185+
static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1,
186+
struct anon_vma_name *anon_name2)
187+
{
188+
if (anon_name1 == anon_name2)
170189
return true;
171190

172-
return name && vma_name && !strcmp(name, vma_name);
191+
return anon_name1 && anon_name2 &&
192+
!strcmp(anon_name1->name, anon_name2->name);
173193
}
194+
174195
#else /* CONFIG_ANON_VMA_NAME */
175-
static inline const char *vma_anon_name(struct vm_area_struct *vma)
196+
static inline struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma)
176197
{
177198
return NULL;
178199
}
179-
static inline void dup_vma_anon_name(struct vm_area_struct *orig_vma,
180-
struct vm_area_struct *new_vma) {}
181-
static inline void free_vma_anon_name(struct vm_area_struct *vma) {}
182-
static inline bool is_same_vma_anon_name(struct vm_area_struct *vma,
183-
const char *name)
200+
201+
static inline struct anon_vma_name *anon_vma_name_alloc(const char *name)
202+
{
203+
return NULL;
204+
}
205+
206+
static inline void anon_vma_name_get(struct anon_vma_name *anon_name) {}
207+
static inline void anon_vma_name_put(struct anon_vma_name *anon_name) {}
208+
static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma,
209+
struct vm_area_struct *new_vma) {}
210+
static inline void free_anon_vma_name(struct vm_area_struct *vma) {}
211+
212+
static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1,
213+
struct anon_vma_name *anon_name2)
184214
{
185215
return true;
186216
}
217+
187218
#endif /* CONFIG_ANON_VMA_NAME */
188219

189220
static inline void init_tlb_flush_pending(struct mm_struct *mm)

include/linux/mm_types.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,10 @@ struct vm_area_struct {
416416
struct rb_node rb;
417417
unsigned long rb_subtree_last;
418418
} shared;
419-
/* Serialized by mmap_sem. */
419+
/*
420+
* Serialized by mmap_sem. Never use directly because it is
421+
* valid only when vm_file is NULL. Use anon_vma_name instead.
422+
*/
420423
struct anon_vma_name *anon_name;
421424
};
422425

kernel/fork.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,14 +366,14 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig)
366366
*new = data_race(*orig);
367367
INIT_LIST_HEAD(&new->anon_vma_chain);
368368
new->vm_next = new->vm_prev = NULL;
369-
dup_vma_anon_name(orig, new);
369+
dup_anon_vma_name(orig, new);
370370
}
371371
return new;
372372
}
373373

374374
void vm_area_free(struct vm_area_struct *vma)
375375
{
376-
free_vma_anon_name(vma);
376+
free_anon_vma_name(vma);
377377
kmem_cache_free(vm_area_cachep, vma);
378378
}
379379

kernel/sys.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <linux/export.h>
99
#include <linux/mm.h>
10+
#include <linux/mm_inline.h>
1011
#include <linux/utsname.h>
1112
#include <linux/mman.h>
1213
#include <linux/reboot.h>
@@ -2286,15 +2287,16 @@ static int prctl_set_vma(unsigned long opt, unsigned long addr,
22862287
{
22872288
struct mm_struct *mm = current->mm;
22882289
const char __user *uname;
2289-
char *name, *pch;
2290+
struct anon_vma_name *anon_name = NULL;
22902291
int error;
22912292

22922293
switch (opt) {
22932294
case PR_SET_VMA_ANON_NAME:
22942295
uname = (const char __user *)arg;
22952296
if (uname) {
2296-
name = strndup_user(uname, ANON_VMA_NAME_MAX_LEN);
2297+
char *name, *pch;
22972298

2299+
name = strndup_user(uname, ANON_VMA_NAME_MAX_LEN);
22982300
if (IS_ERR(name))
22992301
return PTR_ERR(name);
23002302

@@ -2304,15 +2306,18 @@ static int prctl_set_vma(unsigned long opt, unsigned long addr,
23042306
return -EINVAL;
23052307
}
23062308
}
2307-
} else {
2308-
/* Reset the name */
2309-
name = NULL;
2309+
/* anon_vma has its own copy */
2310+
anon_name = anon_vma_name_alloc(name);
2311+
kfree(name);
2312+
if (!anon_name)
2313+
return -ENOMEM;
2314+
23102315
}
23112316

23122317
mmap_write_lock(mm);
2313-
error = madvise_set_anon_name(mm, addr, size, name);
2318+
error = madvise_set_anon_name(mm, addr, size, anon_name);
23142319
mmap_write_unlock(mm);
2315-
kfree(name);
2320+
anon_vma_name_put(anon_name);
23162321
break;
23172322
default:
23182323
error = -EINVAL;

0 commit comments

Comments
 (0)