From b64e74e95aa6491b31477e9002aab1d8df3995bf Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 19 Feb 2024 07:27:09 +0100 Subject: mm: move mapping_set_update out of mapping_set_update is only used inside mm/. Move mapping_set_update to mm/internal.h and turn it into an inline function instead of a macro. Signed-off-by: Christoph Hellwig Reviewed-by: "Matthew Wilcox (Oracle)" Signed-off-by: Chandan Babu R --- mm/filemap.c | 9 +++++++++ mm/internal.h | 4 ++++ mm/workingset.c | 1 + 3 files changed, 14 insertions(+) (limited to 'mm') diff --git a/mm/filemap.c b/mm/filemap.c index 750e779c23db..6c8b089f00d2 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -124,6 +124,15 @@ * ->private_lock (zap_pte_range->block_dirty_folio) */ +static void mapping_set_update(struct xa_state *xas, + struct address_space *mapping) +{ + if (dax_mapping(mapping) || shmem_mapping(mapping)) + return; + xas_set_update(xas, workingset_update_node); + xas_set_lru(xas, &shadow_nodes); +} + static void page_cache_delete(struct address_space *mapping, struct folio *folio, void *shadow) { diff --git a/mm/internal.h b/mm/internal.h index f309a010d50f..4398f572485f 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -1266,4 +1266,8 @@ static inline void shrinker_debugfs_remove(struct dentry *debugfs_entry, } #endif /* CONFIG_SHRINKER_DEBUG */ +/* Only track the nodes of mappings with shadow entries */ +void workingset_update_node(struct xa_node *node); +extern struct list_lru shadow_nodes; + #endif /* __MM_INTERNAL_H */ diff --git a/mm/workingset.c b/mm/workingset.c index 226012974328..f2a0ecaf708d 100644 --- a/mm/workingset.c +++ b/mm/workingset.c @@ -16,6 +16,7 @@ #include #include #include +#include "internal.h" /* * Double CLOCK lists -- cgit From aefacb2041f77784059b86c5fd151066859ad19a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 19 Feb 2024 07:27:10 +0100 Subject: shmem: move shmem_mapping out of line shmem_aops really should not be exported to the world. Move shmem_mapping and export it as internal for the one semi-legitimate modular user in udmabuf. This effectively reverts commit 30e6a51dbb05 ("mm/shmem.c: make shmem_mapping() inline"). which added a bogus shmem_aops non-GPL export for no reason whatsoever as there as no shmem_mapping call outside of core MM code at that point. Signed-off-by: Christoph Hellwig Reviewed-by: "Matthew Wilcox (Oracle)" Signed-off-by: Chandan Babu R --- mm/shmem.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'mm') diff --git a/mm/shmem.c b/mm/shmem.c index d7c84ff62186..f607b0cab7e4 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -254,7 +254,7 @@ static void shmem_inode_unacct_blocks(struct inode *inode, long pages) } static const struct super_operations shmem_ops; -const struct address_space_operations shmem_aops; +static const struct address_space_operations shmem_aops; static const struct file_operations shmem_file_operations; static const struct inode_operations shmem_inode_operations; static const struct inode_operations shmem_dir_inode_operations; @@ -263,6 +263,12 @@ static const struct vm_operations_struct shmem_vm_ops; static const struct vm_operations_struct shmem_anon_vm_ops; static struct file_system_type shmem_fs_type; +bool shmem_mapping(struct address_space *mapping) +{ + return mapping->a_ops == &shmem_aops; +} +EXPORT_SYMBOL_GPL(shmem_mapping); + bool vma_is_anon_shmem(struct vm_area_struct *vma) { return vma->vm_ops == &shmem_anon_vm_ops; @@ -4466,7 +4472,7 @@ static int shmem_error_remove_folio(struct address_space *mapping, return 0; } -const struct address_space_operations shmem_aops = { +static const struct address_space_operations shmem_aops = { .writepage = shmem_writepage, .dirty_folio = noop_dirty_folio, #ifdef CONFIG_TMPFS @@ -4478,7 +4484,6 @@ const struct address_space_operations shmem_aops = { #endif .error_remove_folio = shmem_error_remove_folio, }; -EXPORT_SYMBOL(shmem_aops); static const struct file_operations shmem_file_operations = { .mmap = shmem_mmap, -- cgit From e11381d83d72198565f4545d9988b4720288eb64 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 19 Feb 2024 07:27:11 +0100 Subject: shmem: set a_ops earlier in shmem_symlink Set the a_ops in shmem_symlink before reading a folio from the mapping to prepare for asserting that shmem_get_folio is only called on shmem mappings. Signed-off-by: Christoph Hellwig Reviewed-by: "Matthew Wilcox (Oracle)" Signed-off-by: Chandan Babu R --- mm/shmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mm') diff --git a/mm/shmem.c b/mm/shmem.c index f607b0cab7e4..1900916aa84d 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3506,10 +3506,10 @@ static int shmem_symlink(struct mnt_idmap *idmap, struct inode *dir, inode->i_op = &shmem_short_symlink_operations; } else { inode_nohighmem(inode); + inode->i_mapping->a_ops = &shmem_aops; error = shmem_get_folio(inode, 0, &folio, SGP_WRITE); if (error) goto out_remove_offset; - inode->i_mapping->a_ops = &shmem_aops; inode->i_op = &shmem_symlink_inode_operations; memcpy(folio_address(folio), symname, len); folio_mark_uptodate(folio); -- cgit From 1cd81faaf61b42307e81f2dd173934005c220a64 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 19 Feb 2024 07:27:12 +0100 Subject: shmem: move the shmem_mapping assert into shmem_get_folio_gfp Move the check that the inode really is a shmemfs one from shmem_read_folio_gfp to shmem_get_folio_gfp given that shmem_get_folio can also be called from outside of shmem.c. Also turn it into a WARN_ON_ONCE and error return instead of BUG_ON to be less severe. Signed-off-by: Christoph Hellwig Reviewed-by: "Matthew Wilcox (Oracle)" Reviewed-by: "Darrick J. Wong" Signed-off-by: Chandan Babu R --- mm/shmem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'mm') diff --git a/mm/shmem.c b/mm/shmem.c index 1900916aa84d..ad533b2f0721 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1972,6 +1972,9 @@ static int shmem_get_folio_gfp(struct inode *inode, pgoff_t index, int error; bool alloced; + if (WARN_ON_ONCE(!shmem_mapping(inode->i_mapping))) + return -EINVAL; + if (index > (MAX_LFS_FILESIZE >> PAGE_SHIFT)) return -EFBIG; repeat: @@ -4915,7 +4918,6 @@ struct folio *shmem_read_folio_gfp(struct address_space *mapping, struct folio *folio; int error; - BUG_ON(!shmem_mapping(mapping)); error = shmem_get_folio_gfp(inode, index, &folio, SGP_CACHE, gfp, NULL, NULL); if (error) -- cgit From d7468609ee0f90ceb24143a32edc47d433d1dbba Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 19 Feb 2024 07:27:13 +0100 Subject: shmem: export shmem_get_folio Export shmem_get_folio as a slightly lower-level variant of shmem_read_folio_gfp. This will be useful for XFS xfile use cases that want to pass SGP_NOALLOC or get a locked page, which the thin shmem_read_folio_gfp wrapper can't provide. Signed-off-by: Christoph Hellwig Reviewed-by: "Matthew Wilcox (Oracle)" Reviewed-by: "Darrick J. Wong" Signed-off-by: Chandan Babu R --- mm/shmem.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'mm') diff --git a/mm/shmem.c b/mm/shmem.c index ad533b2f0721..aeb1fd19ea3f 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2137,12 +2137,32 @@ unlock: return error; } +/** + * shmem_get_folio - find, and lock a shmem folio. + * @inode: inode to search + * @index: the page index. + * @foliop: pointer to the folio if found + * @sgp: SGP_* flags to control behavior + * + * Looks up the page cache entry at @inode & @index. If a folio is + * present, it is returned locked with an increased refcount. + * + * When no folio is found, the behavior depends on @sgp: + * - for SGP_READ, *foliop is %NULL and 0 is returned + * - for SGP_NOALLOC, *foliop is %NULL and -ENOENT is returned + * - for all other flags a new folio is allocated, inserted into the + * page cache and returned locked in @foliop. + * + * Context: May sleep. + * Return: 0 if successful, else a negative error code. + */ int shmem_get_folio(struct inode *inode, pgoff_t index, struct folio **foliop, enum sgp_type sgp) { return shmem_get_folio_gfp(inode, index, foliop, sgp, mapping_gfp_mask(inode->i_mapping), NULL, NULL); } +EXPORT_SYMBOL_GPL(shmem_get_folio); /* * This is like autoremove_wake_function, but it removes the wait queue -- cgit From be9d93661d548a41bb8f135b9953191f0fb2e44b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 19 Feb 2024 07:27:14 +0100 Subject: shmem: export shmem_kernel_file_setup XFS wants to use this for it's internal in-memory data structures and currently duplicates the functionality. Export shmem_kernel_file_setup to allow XFS to switch over to using the proper kernel API. Signed-off-by: Christoph Hellwig Reviewed-by: "Matthew Wilcox (Oracle)" Reviewed-by: "Darrick J. Wong" Signed-off-by: Chandan Babu R --- mm/shmem.c | 1 + 1 file changed, 1 insertion(+) (limited to 'mm') diff --git a/mm/shmem.c b/mm/shmem.c index aeb1fd19ea3f..95e70e9ea060 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -4861,6 +4861,7 @@ struct file *shmem_kernel_file_setup(const char *name, loff_t size, unsigned lon { return __shmem_file_setup(shm_mnt, name, size, flags, S_PRIVATE); } +EXPORT_SYMBOL_GPL(shmem_kernel_file_setup); /** * shmem_file_setup - get an unlinked file living in tmpfs -- cgit From 9d8b36744935f83c5553e6f242b9961f676628ed Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 19 Feb 2024 07:27:15 +0100 Subject: shmem: document how to "persist" data when using shmem_*file_setup Add a blurb that simply dirtying the folio will persist data for in-kernel shmem files. This is what most of the callers already do. Signed-off-by: Christoph Hellwig Reviewed-by: "Matthew Wilcox (Oracle)" Reviewed-by: "Darrick J. Wong" Signed-off-by: Chandan Babu R --- mm/shmem.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'mm') diff --git a/mm/shmem.c b/mm/shmem.c index 95e70e9ea060..fb76da93d369 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2147,6 +2147,10 @@ unlock: * Looks up the page cache entry at @inode & @index. If a folio is * present, it is returned locked with an increased refcount. * + * If the caller modifies data in the folio, it must call folio_mark_dirty() + * before unlocking the folio to ensure that the folio is not reclaimed. + * There is no need to reserve space before calling folio_mark_dirty(). + * * When no folio is found, the behavior depends on @sgp: * - for SGP_READ, *foliop is %NULL and 0 is returned * - for SGP_NOALLOC, *foliop is %NULL and -ENOENT is returned -- cgit From 8d4dd9d741c330119ae14f688bfc4fb602b17e19 Mon Sep 17 00:00:00 2001 From: Akira Yokosawa Date: Tue, 27 Feb 2024 14:06:48 +0900 Subject: mm/shmem.c: Use new form of *@param in kernel-doc Use the form of *@param which kernel-doc recognizes now. This resolves the warnings from "make htmldocs" as reported in [1]. Reported-by: Stephen Rothwell Link: [1] https://lore.kernel.org/r/20240223153636.41358be5@canb.auug.org.au/ Acked-by: Christoph Hellwig Signed-off-by: Akira Yokosawa Signed-off-by: Chandan Babu R --- mm/shmem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'mm') diff --git a/mm/shmem.c b/mm/shmem.c index fb76da93d369..cf3689926418 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2152,8 +2152,8 @@ unlock: * There is no need to reserve space before calling folio_mark_dirty(). * * When no folio is found, the behavior depends on @sgp: - * - for SGP_READ, *foliop is %NULL and 0 is returned - * - for SGP_NOALLOC, *foliop is %NULL and -ENOENT is returned + * - for SGP_READ, *@foliop is %NULL and 0 is returned + * - for SGP_NOALLOC, *@foliop is %NULL and -ENOENT is returned * - for all other flags a new folio is allocated, inserted into the * page cache and returned locked in @foliop. * -- cgit