diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2019-02-21 11:48:09 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-02-21 12:01:00 -0500 |
commit | 1062af920c07f5b54cf5060fde3339da6df0cf6b (patch) | |
tree | 42c3494136a9d8338ddfdbeef4db7a726d757b0d /mm/shmem.c | |
parent | 4e37504d1c49eec6434d0cc97278d2b51c9e8763 (diff) |
tmpfs: fix link accounting when a tmpfile is linked in
tmpfs has a peculiarity of accounting hard links as if they were
separate inodes: so that when the number of inodes is limited, as it is
by default, a user cannot soak up an unlimited amount of unreclaimable
dcache memory just by repeatedly linking a file.
But when v3.11 added O_TMPFILE, and the ability to use linkat() on the
fd, we missed accommodating this new case in tmpfs: "df -i" shows that
an extra "inode" remains accounted after the file is unlinked and the fd
closed and the actual inode evicted. If a user repeatedly links
tmpfiles into a tmpfs, the limit will be hit (ENOSPC) even after they
are deleted.
Just skip the extra reservation from shmem_link() in this case: there's
a sense in which this first link of a tmpfile is then cheaper than a
hard link of another file, but the accounting works out, and there's
still good limiting, so no need to do anything more complicated.
Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1902182134370.7035@eggly.anvils
Fixes: f4e0c30c191 ("allow the temp files created by open() to be linked to")
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Hugh Dickins <hughd@google.com>
Reported-by: Matej Kupljen <matej.kupljen@gmail.com>
Acked-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 6ece1e2fe76e..0905215fb016 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -2854,10 +2854,14 @@ static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentr | |||
2854 | * No ordinary (disk based) filesystem counts links as inodes; | 2854 | * No ordinary (disk based) filesystem counts links as inodes; |
2855 | * but each new link needs a new dentry, pinning lowmem, and | 2855 | * but each new link needs a new dentry, pinning lowmem, and |
2856 | * tmpfs dentries cannot be pruned until they are unlinked. | 2856 | * tmpfs dentries cannot be pruned until they are unlinked. |
2857 | * But if an O_TMPFILE file is linked into the tmpfs, the | ||
2858 | * first link must skip that, to get the accounting right. | ||
2857 | */ | 2859 | */ |
2858 | ret = shmem_reserve_inode(inode->i_sb); | 2860 | if (inode->i_nlink) { |
2859 | if (ret) | 2861 | ret = shmem_reserve_inode(inode->i_sb); |
2860 | goto out; | 2862 | if (ret) |
2863 | goto out; | ||
2864 | } | ||
2861 | 2865 | ||
2862 | dir->i_size += BOGO_DIRENT_SIZE; | 2866 | dir->i_size += BOGO_DIRENT_SIZE; |
2863 | inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode); | 2867 | inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode); |