diff options
author | Mike Kravetz <mike.kravetz@oracle.com> | 2019-05-13 20:22:55 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-14 12:47:50 -0400 |
commit | f27a5136f70a8c90e8b30a983b6f54540742f849 (patch) | |
tree | d8c614cbaa67b50e754c37ff250e9d9722293772 | |
parent | 1f862989b04ade61d3aab49184c50e9957f84c7d (diff) |
hugetlbfs: always use address space in inode for resv_map pointer
Continuing discussion about 58b6e5e8f1ad ("hugetlbfs: fix memory leak for
resv_map") brought up the issue that inode->i_mapping may not point to the
address space embedded within the inode at inode eviction time. The
hugetlbfs truncate routine handles this by explicitly using inode->i_data.
However, code cleaning up the resv_map will still use the address space
pointed to by inode->i_mapping. Luckily, private_data is NULL for address
spaces in all such cases today but, there is no guarantee this will
continue.
Change all hugetlbfs code getting a resv_map pointer to explicitly get it
from the address space embedded within the inode. In addition, add more
comments in the code to indicate why this is being done.
Link: http://lkml.kernel.org/r/20190419204435.16984-1-mike.kravetz@oracle.com
Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com>
Reported-by: Yufen Yu <yuyufen@huawei.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: "Kirill A . Shutemov" <kirill.shutemov@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/hugetlbfs/inode.c | 11 | ||||
-rw-r--r-- | mm/hugetlb.c | 19 |
2 files changed, 27 insertions, 3 deletions
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index f23237135163..1dcc57189382 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -497,8 +497,15 @@ static void hugetlbfs_evict_inode(struct inode *inode) | |||
497 | struct resv_map *resv_map; | 497 | struct resv_map *resv_map; |
498 | 498 | ||
499 | remove_inode_hugepages(inode, 0, LLONG_MAX); | 499 | remove_inode_hugepages(inode, 0, LLONG_MAX); |
500 | resv_map = (struct resv_map *)inode->i_mapping->private_data; | 500 | |
501 | /* root inode doesn't have the resv_map, so we should check it */ | 501 | /* |
502 | * Get the resv_map from the address space embedded in the inode. | ||
503 | * This is the address space which points to any resv_map allocated | ||
504 | * at inode creation time. If this is a device special inode, | ||
505 | * i_mapping may not point to the original address space. | ||
506 | */ | ||
507 | resv_map = (struct resv_map *)(&inode->i_data)->private_data; | ||
508 | /* Only regular and link inodes have associated reserve maps */ | ||
502 | if (resv_map) | 509 | if (resv_map) |
503 | resv_map_release(&resv_map->refs); | 510 | resv_map_release(&resv_map->refs); |
504 | clear_inode(inode); | 511 | clear_inode(inode); |
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index cab38ef30238..81718c56b8f5 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -740,7 +740,15 @@ void resv_map_release(struct kref *ref) | |||
740 | 740 | ||
741 | static inline struct resv_map *inode_resv_map(struct inode *inode) | 741 | static inline struct resv_map *inode_resv_map(struct inode *inode) |
742 | { | 742 | { |
743 | return inode->i_mapping->private_data; | 743 | /* |
744 | * At inode evict time, i_mapping may not point to the original | ||
745 | * address space within the inode. This original address space | ||
746 | * contains the pointer to the resv_map. So, always use the | ||
747 | * address space embedded within the inode. | ||
748 | * The VERY common case is inode->mapping == &inode->i_data but, | ||
749 | * this may not be true for device special inodes. | ||
750 | */ | ||
751 | return (struct resv_map *)(&inode->i_data)->private_data; | ||
744 | } | 752 | } |
745 | 753 | ||
746 | static struct resv_map *vma_resv_map(struct vm_area_struct *vma) | 754 | static struct resv_map *vma_resv_map(struct vm_area_struct *vma) |
@@ -4518,6 +4526,11 @@ int hugetlb_reserve_pages(struct inode *inode, | |||
4518 | * called to make the mapping read-write. Assume !vma is a shm mapping | 4526 | * called to make the mapping read-write. Assume !vma is a shm mapping |
4519 | */ | 4527 | */ |
4520 | if (!vma || vma->vm_flags & VM_MAYSHARE) { | 4528 | if (!vma || vma->vm_flags & VM_MAYSHARE) { |
4529 | /* | ||
4530 | * resv_map can not be NULL as hugetlb_reserve_pages is only | ||
4531 | * called for inodes for which resv_maps were created (see | ||
4532 | * hugetlbfs_get_inode). | ||
4533 | */ | ||
4521 | resv_map = inode_resv_map(inode); | 4534 | resv_map = inode_resv_map(inode); |
4522 | 4535 | ||
4523 | chg = region_chg(resv_map, from, to); | 4536 | chg = region_chg(resv_map, from, to); |
@@ -4609,6 +4622,10 @@ long hugetlb_unreserve_pages(struct inode *inode, long start, long end, | |||
4609 | struct hugepage_subpool *spool = subpool_inode(inode); | 4622 | struct hugepage_subpool *spool = subpool_inode(inode); |
4610 | long gbl_reserve; | 4623 | long gbl_reserve; |
4611 | 4624 | ||
4625 | /* | ||
4626 | * Since this routine can be called in the evict inode path for all | ||
4627 | * hugetlbfs inodes, resv_map could be NULL. | ||
4628 | */ | ||
4612 | if (resv_map) { | 4629 | if (resv_map) { |
4613 | chg = region_del(resv_map, start, end); | 4630 | chg = region_del(resv_map, start, end); |
4614 | /* | 4631 | /* |