summaryrefslogtreecommitdiff
path: root/mm/shmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/shmem.c')
-rw-r--r--mm/shmem.c30
1 files changed, 18 insertions, 12 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index dc8cd4f563f4..89a1495e55f7 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1042,6 +1042,8 @@ unsigned long shmem_swap_usage(struct vm_area_struct *vma)
struct inode *inode = file_inode(vma->vm_file);
struct shmem_inode_info *info = SHMEM_I(inode);
struct address_space *mapping = inode->i_mapping;
+ const pgoff_t pgoff = vma_start_pgoff(vma);
+ const pgoff_t pgoff_end = vma_end_pgoff(vma);
unsigned long swapped;
/* Be careful as we don't hold info->lock */
@@ -1055,12 +1057,11 @@ unsigned long shmem_swap_usage(struct vm_area_struct *vma)
if (!swapped)
return 0;
- if (!vma->vm_pgoff && vma->vm_end - vma->vm_start >= inode->i_size)
+ if (!pgoff && vma->vm_end - vma->vm_start >= inode->i_size)
return swapped << PAGE_SHIFT;
/* Here comes the more involved part */
- return shmem_partial_swap_usage(mapping, vma->vm_pgoff,
- vma->vm_pgoff + vma_pages(vma));
+ return shmem_partial_swap_usage(mapping, pgoff, pgoff_end);
}
/*
@@ -1297,7 +1298,8 @@ static int shmem_getattr(struct mnt_idmap *idmap,
struct inode *inode = path->dentry->d_inode;
struct shmem_inode_info *info = SHMEM_I(inode);
- if (info->alloced - info->swapped != inode->i_mapping->nrpages)
+ /* Fast-path hint; recalc under info->lock corrects any stale read. */
+ if (data_race(info->alloced - info->swapped != inode->i_mapping->nrpages))
shmem_recalc_inode(inode, 0, 0);
if (info->fsflags & FS_APPEND_FL)
@@ -1438,7 +1440,10 @@ static void shmem_evict_inode(struct inode *inode)
simple_xattrs_free(&sbinfo->xa_cache, &info->xattrs, sbinfo->max_inodes ? &freed : NULL);
shmem_free_inode(inode->i_sb, freed);
- WARN_ON(inode->i_blocks);
+ if (inode->i_blocks)
+ pr_warn("%s: ino=%llu i_blocks=%llu alloced=%lu swapped=%lu nrpages=%lu\n",
+ __func__, inode->i_ino, inode->i_blocks,
+ info->alloced, info->swapped, inode->i_mapping->nrpages);
clear_inode(inode);
#ifdef CONFIG_TMPFS_QUOTA
dquot_free_inode(inode);
@@ -1667,7 +1672,7 @@ try_split:
* reactivate the folio, and let shmem_fallocate() quit when too many.
*/
if (!folio_test_uptodate(folio)) {
- if (inode->i_private) {
+ if (READ_ONCE(inode->i_private)) {
struct shmem_falloc *shmem_falloc;
spin_lock(&inode->i_lock);
shmem_falloc = inode->i_private;
@@ -2703,7 +2708,7 @@ static vm_fault_t shmem_fault(struct vm_fault *vmf)
* Trinity finds that probing a hole which tmpfs is punching can
* prevent the hole-punch from ever completing: noted in i_private.
*/
- if (unlikely(inode->i_private)) {
+ if (unlikely(READ_ONCE(inode->i_private))) {
ret = shmem_falloc_wait(vmf, inode);
if (ret)
return ret;
@@ -2849,7 +2854,7 @@ static struct mempolicy *shmem_get_policy(struct vm_area_struct *vma,
* by page order, as in shmem_get_pgoff_policy() and get_vma_policy()).
*/
*ilx = inode->i_ino;
- index = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+ index = linear_page_index(vma, addr);
return mpol_shared_policy_lookup(&SHMEM_I(inode)->policy, index);
}
@@ -3640,7 +3645,7 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset,
shmem_falloc.start = (u64)unmap_start >> PAGE_SHIFT;
shmem_falloc.next = (unmap_end + 1) >> PAGE_SHIFT;
spin_lock(&inode->i_lock);
- inode->i_private = &shmem_falloc;
+ WRITE_ONCE(inode->i_private, &shmem_falloc);
spin_unlock(&inode->i_lock);
if ((u64)unmap_end > (u64)unmap_start)
@@ -3650,7 +3655,7 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset,
/* No need to unmap again: hole-punching leaves COWed pages */
spin_lock(&inode->i_lock);
- inode->i_private = NULL;
+ WRITE_ONCE(inode->i_private, NULL);
wake_up_all(&shmem_falloc_waitq);
WARN_ON_ONCE(!list_empty(&shmem_falloc_waitq.head));
spin_unlock(&inode->i_lock);
@@ -3682,7 +3687,7 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset,
shmem_falloc.nr_falloced = 0;
shmem_falloc.nr_unswapped = 0;
spin_lock(&inode->i_lock);
- inode->i_private = &shmem_falloc;
+ WRITE_ONCE(inode->i_private, &shmem_falloc);
spin_unlock(&inode->i_lock);
/*
@@ -3757,7 +3762,7 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset,
i_size_write(inode, offset + len);
undone:
spin_lock(&inode->i_lock);
- inode->i_private = NULL;
+ WRITE_ONCE(inode->i_private, NULL);
spin_unlock(&inode->i_lock);
out:
if (!error)
@@ -4067,6 +4072,7 @@ static int shmem_symlink(struct mnt_idmap *idmap, struct inode *dir,
goto out_remove_offset;
inode->i_op = &shmem_symlink_inode_operations;
memcpy(folio_address(folio), symname, len);
+ folio_zero_range(folio, len, folio_size(folio) - len);
folio_mark_uptodate(folio);
folio_mark_dirty(folio);
folio_unlock(folio);