Skip to content

Commit e700898

Browse files
mjkravetzakpm00
authored andcommitted
hugetlb: really allocate vma lock for all sharable vmas
Commit bbff39c ("hugetlb: allocate vma lock for all sharable vmas") removed the pmd sharable checks in the vma lock helper routines. However, it left the functional version of helper routines behind #ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE. Therefore, the vma lock is not being used for sharable vmas on architectures that do not support pmd sharing. On these architectures, a potential fault/truncation race is exposed that could leave pages in a hugetlb file past i_size until the file is removed. Move the functional vma lock helpers outside the ifdef, and remove the non-functional stubs. Since the vma lock is not just for pmd sharing, rename the routine __vma_shareable_flags_pmd. Link: https://lkml.kernel.org/r/[email protected] Fixes: bbff39c ("hugetlb: allocate vma lock for all sharable vmas") Signed-off-by: Mike Kravetz <[email protected]> Reviewed-by: Miaohe Lin <[email protected]> Cc: "Aneesh Kumar K.V" <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: James Houghton <[email protected]> Cc: Mina Almasry <[email protected]> Cc: Muchun Song <[email protected]> Cc: Naoya Horiguchi <[email protected]> Cc: Peter Xu <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 7ba594d commit e700898

File tree

1 file changed

+148
-185
lines changed

1 file changed

+148
-185
lines changed

mm/hugetlb.c

Lines changed: 148 additions & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,152 @@ static inline struct hugepage_subpool *subpool_vma(struct vm_area_struct *vma)
255255
return subpool_inode(file_inode(vma->vm_file));
256256
}
257257

258+
/*
259+
* hugetlb vma_lock helper routines
260+
*/
261+
static bool __vma_shareable_lock(struct vm_area_struct *vma)
262+
{
263+
return vma->vm_flags & (VM_MAYSHARE | VM_SHARED) &&
264+
vma->vm_private_data;
265+
}
266+
267+
void hugetlb_vma_lock_read(struct vm_area_struct *vma)
268+
{
269+
if (__vma_shareable_lock(vma)) {
270+
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
271+
272+
down_read(&vma_lock->rw_sema);
273+
}
274+
}
275+
276+
void hugetlb_vma_unlock_read(struct vm_area_struct *vma)
277+
{
278+
if (__vma_shareable_lock(vma)) {
279+
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
280+
281+
up_read(&vma_lock->rw_sema);
282+
}
283+
}
284+
285+
void hugetlb_vma_lock_write(struct vm_area_struct *vma)
286+
{
287+
if (__vma_shareable_lock(vma)) {
288+
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
289+
290+
down_write(&vma_lock->rw_sema);
291+
}
292+
}
293+
294+
void hugetlb_vma_unlock_write(struct vm_area_struct *vma)
295+
{
296+
if (__vma_shareable_lock(vma)) {
297+
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
298+
299+
up_write(&vma_lock->rw_sema);
300+
}
301+
}
302+
303+
int hugetlb_vma_trylock_write(struct vm_area_struct *vma)
304+
{
305+
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
306+
307+
if (!__vma_shareable_lock(vma))
308+
return 1;
309+
310+
return down_write_trylock(&vma_lock->rw_sema);
311+
}
312+
313+
void hugetlb_vma_assert_locked(struct vm_area_struct *vma)
314+
{
315+
if (__vma_shareable_lock(vma)) {
316+
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
317+
318+
lockdep_assert_held(&vma_lock->rw_sema);
319+
}
320+
}
321+
322+
void hugetlb_vma_lock_release(struct kref *kref)
323+
{
324+
struct hugetlb_vma_lock *vma_lock = container_of(kref,
325+
struct hugetlb_vma_lock, refs);
326+
327+
kfree(vma_lock);
328+
}
329+
330+
static void __hugetlb_vma_unlock_write_put(struct hugetlb_vma_lock *vma_lock)
331+
{
332+
struct vm_area_struct *vma = vma_lock->vma;
333+
334+
/*
335+
* vma_lock structure may or not be released as a result of put,
336+
* it certainly will no longer be attached to vma so clear pointer.
337+
* Semaphore synchronizes access to vma_lock->vma field.
338+
*/
339+
vma_lock->vma = NULL;
340+
vma->vm_private_data = NULL;
341+
up_write(&vma_lock->rw_sema);
342+
kref_put(&vma_lock->refs, hugetlb_vma_lock_release);
343+
}
344+
345+
static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma)
346+
{
347+
if (__vma_shareable_lock(vma)) {
348+
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
349+
350+
__hugetlb_vma_unlock_write_put(vma_lock);
351+
}
352+
}
353+
354+
static void hugetlb_vma_lock_free(struct vm_area_struct *vma)
355+
{
356+
/*
357+
* Only present in sharable vmas.
358+
*/
359+
if (!vma || !__vma_shareable_lock(vma))
360+
return;
361+
362+
if (vma->vm_private_data) {
363+
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
364+
365+
down_write(&vma_lock->rw_sema);
366+
__hugetlb_vma_unlock_write_put(vma_lock);
367+
}
368+
}
369+
370+
static void hugetlb_vma_lock_alloc(struct vm_area_struct *vma)
371+
{
372+
struct hugetlb_vma_lock *vma_lock;
373+
374+
/* Only establish in (flags) sharable vmas */
375+
if (!vma || !(vma->vm_flags & VM_MAYSHARE))
376+
return;
377+
378+
/* Should never get here with non-NULL vm_private_data */
379+
if (vma->vm_private_data)
380+
return;
381+
382+
vma_lock = kmalloc(sizeof(*vma_lock), GFP_KERNEL);
383+
if (!vma_lock) {
384+
/*
385+
* If we can not allocate structure, then vma can not
386+
* participate in pmd sharing. This is only a possible
387+
* performance enhancement and memory saving issue.
388+
* However, the lock is also used to synchronize page
389+
* faults with truncation. If the lock is not present,
390+
* unlikely races could leave pages in a file past i_size
391+
* until the file is removed. Warn in the unlikely case of
392+
* allocation failure.
393+
*/
394+
pr_warn_once("HugeTLB: unable to allocate vma specific lock\n");
395+
return;
396+
}
397+
398+
kref_init(&vma_lock->refs);
399+
init_rwsem(&vma_lock->rw_sema);
400+
vma_lock->vma = vma;
401+
vma->vm_private_data = vma_lock;
402+
}
403+
258404
/* Helper that removes a struct file_region from the resv_map cache and returns
259405
* it for use.
260406
*/
@@ -6613,7 +6759,8 @@ bool hugetlb_reserve_pages(struct inode *inode,
66136759
}
66146760

66156761
/*
6616-
* vma specific semaphore used for pmd sharing synchronization
6762+
* vma specific semaphore used for pmd sharing and fault/truncation
6763+
* synchronization
66176764
*/
66186765
hugetlb_vma_lock_alloc(vma);
66196766

@@ -6869,149 +7016,6 @@ void adjust_range_if_pmd_sharing_possible(struct vm_area_struct *vma,
68697016
*end = ALIGN(*end, PUD_SIZE);
68707017
}
68717018

6872-
static bool __vma_shareable_flags_pmd(struct vm_area_struct *vma)
6873-
{
6874-
return vma->vm_flags & (VM_MAYSHARE | VM_SHARED) &&
6875-
vma->vm_private_data;
6876-
}
6877-
6878-
void hugetlb_vma_lock_read(struct vm_area_struct *vma)
6879-
{
6880-
if (__vma_shareable_flags_pmd(vma)) {
6881-
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
6882-
6883-
down_read(&vma_lock->rw_sema);
6884-
}
6885-
}
6886-
6887-
void hugetlb_vma_unlock_read(struct vm_area_struct *vma)
6888-
{
6889-
if (__vma_shareable_flags_pmd(vma)) {
6890-
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
6891-
6892-
up_read(&vma_lock->rw_sema);
6893-
}
6894-
}
6895-
6896-
void hugetlb_vma_lock_write(struct vm_area_struct *vma)
6897-
{
6898-
if (__vma_shareable_flags_pmd(vma)) {
6899-
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
6900-
6901-
down_write(&vma_lock->rw_sema);
6902-
}
6903-
}
6904-
6905-
void hugetlb_vma_unlock_write(struct vm_area_struct *vma)
6906-
{
6907-
if (__vma_shareable_flags_pmd(vma)) {
6908-
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
6909-
6910-
up_write(&vma_lock->rw_sema);
6911-
}
6912-
}
6913-
6914-
int hugetlb_vma_trylock_write(struct vm_area_struct *vma)
6915-
{
6916-
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
6917-
6918-
if (!__vma_shareable_flags_pmd(vma))
6919-
return 1;
6920-
6921-
return down_write_trylock(&vma_lock->rw_sema);
6922-
}
6923-
6924-
void hugetlb_vma_assert_locked(struct vm_area_struct *vma)
6925-
{
6926-
if (__vma_shareable_flags_pmd(vma)) {
6927-
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
6928-
6929-
lockdep_assert_held(&vma_lock->rw_sema);
6930-
}
6931-
}
6932-
6933-
void hugetlb_vma_lock_release(struct kref *kref)
6934-
{
6935-
struct hugetlb_vma_lock *vma_lock = container_of(kref,
6936-
struct hugetlb_vma_lock, refs);
6937-
6938-
kfree(vma_lock);
6939-
}
6940-
6941-
static void __hugetlb_vma_unlock_write_put(struct hugetlb_vma_lock *vma_lock)
6942-
{
6943-
struct vm_area_struct *vma = vma_lock->vma;
6944-
6945-
/*
6946-
* vma_lock structure may or not be released as a result of put,
6947-
* it certainly will no longer be attached to vma so clear pointer.
6948-
* Semaphore synchronizes access to vma_lock->vma field.
6949-
*/
6950-
vma_lock->vma = NULL;
6951-
vma->vm_private_data = NULL;
6952-
up_write(&vma_lock->rw_sema);
6953-
kref_put(&vma_lock->refs, hugetlb_vma_lock_release);
6954-
}
6955-
6956-
static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma)
6957-
{
6958-
if (__vma_shareable_flags_pmd(vma)) {
6959-
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
6960-
6961-
__hugetlb_vma_unlock_write_put(vma_lock);
6962-
}
6963-
}
6964-
6965-
static void hugetlb_vma_lock_free(struct vm_area_struct *vma)
6966-
{
6967-
/*
6968-
* Only present in sharable vmas.
6969-
*/
6970-
if (!vma || !__vma_shareable_flags_pmd(vma))
6971-
return;
6972-
6973-
if (vma->vm_private_data) {
6974-
struct hugetlb_vma_lock *vma_lock = vma->vm_private_data;
6975-
6976-
down_write(&vma_lock->rw_sema);
6977-
__hugetlb_vma_unlock_write_put(vma_lock);
6978-
}
6979-
}
6980-
6981-
static void hugetlb_vma_lock_alloc(struct vm_area_struct *vma)
6982-
{
6983-
struct hugetlb_vma_lock *vma_lock;
6984-
6985-
/* Only establish in (flags) sharable vmas */
6986-
if (!vma || !(vma->vm_flags & VM_MAYSHARE))
6987-
return;
6988-
6989-
/* Should never get here with non-NULL vm_private_data */
6990-
if (vma->vm_private_data)
6991-
return;
6992-
6993-
vma_lock = kmalloc(sizeof(*vma_lock), GFP_KERNEL);
6994-
if (!vma_lock) {
6995-
/*
6996-
* If we can not allocate structure, then vma can not
6997-
* participate in pmd sharing. This is only a possible
6998-
* performance enhancement and memory saving issue.
6999-
* However, the lock is also used to synchronize page
7000-
* faults with truncation. If the lock is not present,
7001-
* unlikely races could leave pages in a file past i_size
7002-
* until the file is removed. Warn in the unlikely case of
7003-
* allocation failure.
7004-
*/
7005-
pr_warn_once("HugeTLB: unable to allocate vma specific lock\n");
7006-
return;
7007-
}
7008-
7009-
kref_init(&vma_lock->refs);
7010-
init_rwsem(&vma_lock->rw_sema);
7011-
vma_lock->vma = vma;
7012-
vma->vm_private_data = vma_lock;
7013-
}
7014-
70157019
/*
70167020
* Search for a shareable pmd page for hugetlb. In any case calls pmd_alloc()
70177021
* and returns the corresponding pte. While this is not necessary for the
@@ -7100,47 +7104,6 @@ int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma,
71007104

71017105
#else /* !CONFIG_ARCH_WANT_HUGE_PMD_SHARE */
71027106

7103-
void hugetlb_vma_lock_read(struct vm_area_struct *vma)
7104-
{
7105-
}
7106-
7107-
void hugetlb_vma_unlock_read(struct vm_area_struct *vma)
7108-
{
7109-
}
7110-
7111-
void hugetlb_vma_lock_write(struct vm_area_struct *vma)
7112-
{
7113-
}
7114-
7115-
void hugetlb_vma_unlock_write(struct vm_area_struct *vma)
7116-
{
7117-
}
7118-
7119-
int hugetlb_vma_trylock_write(struct vm_area_struct *vma)
7120-
{
7121-
return 1;
7122-
}
7123-
7124-
void hugetlb_vma_assert_locked(struct vm_area_struct *vma)
7125-
{
7126-
}
7127-
7128-
void hugetlb_vma_lock_release(struct kref *kref)
7129-
{
7130-
}
7131-
7132-
static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma)
7133-
{
7134-
}
7135-
7136-
static void hugetlb_vma_lock_free(struct vm_area_struct *vma)
7137-
{
7138-
}
7139-
7140-
static void hugetlb_vma_lock_alloc(struct vm_area_struct *vma)
7141-
{
7142-
}
7143-
71447107
pte_t *huge_pmd_share(struct mm_struct *mm, struct vm_area_struct *vma,
71457108
unsigned long addr, pud_t *pud)
71467109
{

0 commit comments

Comments
 (0)