Merge branch 'stable/cleancache.v13' into linux-next
* stable/cleancache.v13: mm: cleancache: Use __read_mostly as appropiate. mm: cleancache: report statistics via debugfs instead of sysfs. mm: zcache/tmem/cleancache: s/flush/invalidate/ mm: cleancache: s/flush/invalidate/
This commit is contained in:
commit
16c0cfa425
10 changed files with 89 additions and 121 deletions
|
@ -1,11 +0,0 @@
|
|||
What: /sys/kernel/mm/cleancache/
|
||||
Date: April 2011
|
||||
Contact: Dan Magenheimer <dan.magenheimer@oracle.com>
|
||||
Description:
|
||||
/sys/kernel/mm/cleancache/ contains a number of files which
|
||||
record a count of various cleancache operations
|
||||
(sum across all filesystems):
|
||||
succ_gets
|
||||
failed_gets
|
||||
puts
|
||||
flushes
|
|
@ -46,10 +46,11 @@ a negative return value indicates failure. A "put_page" will copy a
|
|||
the pool id, a file key, and a page index into the file. (The combination
|
||||
of a pool id, a file key, and an index is sometimes called a "handle".)
|
||||
A "get_page" will copy the page, if found, from cleancache into kernel memory.
|
||||
A "flush_page" will ensure the page no longer is present in cleancache;
|
||||
a "flush_inode" will flush all pages associated with the specified file;
|
||||
and, when a filesystem is unmounted, a "flush_fs" will flush all pages in
|
||||
all files specified by the given pool id and also surrender the pool id.
|
||||
An "invalidate_page" will ensure the page no longer is present in cleancache;
|
||||
an "invalidate_inode" will invalidate all pages associated with the specified
|
||||
file; and, when a filesystem is unmounted, an "invalidate_fs" will invalidate
|
||||
all pages in all files specified by the given pool id and also surrender
|
||||
the pool id.
|
||||
|
||||
An "init_shared_fs", like init_fs, obtains a pool id but tells cleancache
|
||||
to treat the pool as shared using a 128-bit UUID as a key. On systems
|
||||
|
@ -62,12 +63,12 @@ of the kernel (e.g. by "tools" that control cleancache). Or a
|
|||
cleancache implementation can simply disable shared_init by always
|
||||
returning a negative value.
|
||||
|
||||
If a get_page is successful on a non-shared pool, the page is flushed (thus
|
||||
making cleancache an "exclusive" cache). On a shared pool, the page
|
||||
is NOT flushed on a successful get_page so that it remains accessible to
|
||||
If a get_page is successful on a non-shared pool, the page is invalidated
|
||||
(thus making cleancache an "exclusive" cache). On a shared pool, the page
|
||||
is NOT invalidated on a successful get_page so that it remains accessible to
|
||||
other sharers. The kernel is responsible for ensuring coherency between
|
||||
cleancache (shared or not), the page cache, and the filesystem, using
|
||||
cleancache flush operations as required.
|
||||
cleancache invalidate operations as required.
|
||||
|
||||
Note that cleancache must enforce put-put-get coherency and get-get
|
||||
coherency. For the former, if two puts are made to the same handle but
|
||||
|
@ -77,20 +78,20 @@ if a get for a given handle fails, subsequent gets for that handle will
|
|||
never succeed unless preceded by a successful put with that handle.
|
||||
|
||||
Last, cleancache provides no SMP serialization guarantees; if two
|
||||
different Linux threads are simultaneously putting and flushing a page
|
||||
different Linux threads are simultaneously putting and invalidating a page
|
||||
with the same handle, the results are indeterminate. Callers must
|
||||
lock the page to ensure serial behavior.
|
||||
|
||||
CLEANCACHE PERFORMANCE METRICS
|
||||
|
||||
Cleancache monitoring is done by sysfs files in the
|
||||
/sys/kernel/mm/cleancache directory. The effectiveness of cleancache
|
||||
If properly configured, monitoring of cleancache is done via debugfs in
|
||||
the /sys/kernel/debug/mm/cleancache directory. The effectiveness of cleancache
|
||||
can be measured (across all filesystems) with:
|
||||
|
||||
succ_gets - number of gets that were successful
|
||||
failed_gets - number of gets that failed
|
||||
puts - number of puts attempted (all "succeed")
|
||||
flushes - number of flushes attempted
|
||||
invalidates - number of invalidates attempted
|
||||
|
||||
A backend implementatation may provide additional metrics.
|
||||
|
||||
|
@ -143,7 +144,7 @@ systems.
|
|||
|
||||
The core hooks for cleancache in VFS are in most cases a single line
|
||||
and the minimum set are placed precisely where needed to maintain
|
||||
coherency (via cleancache_flush operations) between cleancache,
|
||||
coherency (via cleancache_invalidate operations) between cleancache,
|
||||
the page cache, and disk. All hooks compile into nothingness if
|
||||
cleancache is config'ed off and turn into a function-pointer-
|
||||
compare-to-NULL if config'ed on but no backend claims the ops
|
||||
|
@ -184,15 +185,15 @@ or for real kernel-addressable RAM, it makes perfect sense for
|
|||
transcendent memory.
|
||||
|
||||
4) Why is non-shared cleancache "exclusive"? And where is the
|
||||
page "flushed" after a "get"? (Minchan Kim)
|
||||
page "invalidated" after a "get"? (Minchan Kim)
|
||||
|
||||
The main reason is to free up space in transcendent memory and
|
||||
to avoid unnecessary cleancache_flush calls. If you want inclusive,
|
||||
to avoid unnecessary cleancache_invalidate calls. If you want inclusive,
|
||||
the page can be "put" immediately following the "get". If
|
||||
put-after-get for inclusive becomes common, the interface could
|
||||
be easily extended to add a "get_no_flush" call.
|
||||
be easily extended to add a "get_no_invalidate" call.
|
||||
|
||||
The flush is done by the cleancache backend implementation.
|
||||
The invalidate is done by the cleancache backend implementation.
|
||||
|
||||
5) What's the performance impact?
|
||||
|
||||
|
@ -222,7 +223,7 @@ Some points for a filesystem to consider:
|
|||
as tmpfs should not enable cleancache)
|
||||
- To ensure coherency/correctness, the FS must ensure that all
|
||||
file removal or truncation operations either go through VFS or
|
||||
add hooks to do the equivalent cleancache "flush" operations
|
||||
add hooks to do the equivalent cleancache "invalidate" operations
|
||||
- To ensure coherency/correctness, either inode numbers must
|
||||
be unique across the lifetime of the on-disk file OR the
|
||||
FS must provide an "encode_fh" function.
|
||||
|
@ -243,11 +244,11 @@ If cleancache would use the inode virtual address instead of
|
|||
inode/filehandle, the pool id could be eliminated. But, this
|
||||
won't work because cleancache retains pagecache data pages
|
||||
persistently even when the inode has been pruned from the
|
||||
inode unused list, and only flushes the data page if the file
|
||||
inode unused list, and only invalidates the data page if the file
|
||||
gets removed/truncated. So if cleancache used the inode kva,
|
||||
there would be potential coherency issues if/when the inode
|
||||
kva is reused for a different file. Alternately, if cleancache
|
||||
flushed the pages when the inode kva was freed, much of the value
|
||||
invalidated the pages when the inode kva was freed, much of the value
|
||||
of cleancache would be lost because the cache of pages in cleanache
|
||||
is potentially much larger than the kernel pagecache and is most
|
||||
useful if the pages survive inode cache removal.
|
||||
|
|
|
@ -1757,9 +1757,9 @@ static int zcache_cleancache_init_shared_fs(char *uuid, size_t pagesize)
|
|||
static struct cleancache_ops zcache_cleancache_ops = {
|
||||
.put_page = zcache_cleancache_put_page,
|
||||
.get_page = zcache_cleancache_get_page,
|
||||
.flush_page = zcache_cleancache_flush_page,
|
||||
.flush_inode = zcache_cleancache_flush_inode,
|
||||
.flush_fs = zcache_cleancache_flush_fs,
|
||||
.invalidate_page = zcache_cleancache_flush_page,
|
||||
.invalidate_inode = zcache_cleancache_flush_inode,
|
||||
.invalidate_fs = zcache_cleancache_flush_fs,
|
||||
.init_shared_fs = zcache_cleancache_init_shared_fs,
|
||||
.init_fs = zcache_cleancache_init_fs
|
||||
};
|
||||
|
@ -1867,8 +1867,8 @@ static void zcache_frontswap_init(unsigned ignored)
|
|||
static struct frontswap_ops zcache_frontswap_ops = {
|
||||
.put_page = zcache_frontswap_put_page,
|
||||
.get_page = zcache_frontswap_get_page,
|
||||
.flush_page = zcache_frontswap_flush_page,
|
||||
.flush_area = zcache_frontswap_flush_area,
|
||||
.invalidate_page = zcache_frontswap_flush_page,
|
||||
.invalidate_area = zcache_frontswap_flush_area,
|
||||
.init = zcache_frontswap_init
|
||||
};
|
||||
|
||||
|
|
|
@ -242,9 +242,9 @@ __setup("nocleancache", no_cleancache);
|
|||
static struct cleancache_ops tmem_cleancache_ops = {
|
||||
.put_page = tmem_cleancache_put_page,
|
||||
.get_page = tmem_cleancache_get_page,
|
||||
.flush_page = tmem_cleancache_flush_page,
|
||||
.flush_inode = tmem_cleancache_flush_inode,
|
||||
.flush_fs = tmem_cleancache_flush_fs,
|
||||
.invalidate_page = tmem_cleancache_flush_page,
|
||||
.invalidate_inode = tmem_cleancache_flush_inode,
|
||||
.invalidate_fs = tmem_cleancache_flush_fs,
|
||||
.init_shared_fs = tmem_cleancache_init_shared_fs,
|
||||
.init_fs = tmem_cleancache_init_fs
|
||||
};
|
||||
|
@ -369,8 +369,8 @@ __setup("nofrontswap", no_frontswap);
|
|||
static struct frontswap_ops tmem_frontswap_ops = {
|
||||
.put_page = tmem_frontswap_put_page,
|
||||
.get_page = tmem_frontswap_get_page,
|
||||
.flush_page = tmem_frontswap_flush_page,
|
||||
.flush_area = tmem_frontswap_flush_area,
|
||||
.invalidate_page = tmem_frontswap_flush_page,
|
||||
.invalidate_area = tmem_frontswap_flush_area,
|
||||
.init = tmem_frontswap_init
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -109,7 +109,7 @@ void invalidate_bdev(struct block_device *bdev)
|
|||
/* 99% of the time, we don't need to flush the cleancache on the bdev.
|
||||
* But, for the strange corners, lets be cautious
|
||||
*/
|
||||
cleancache_flush_inode(mapping);
|
||||
cleancache_invalidate_inode(mapping);
|
||||
}
|
||||
EXPORT_SYMBOL(invalidate_bdev);
|
||||
|
||||
|
|
|
@ -250,7 +250,7 @@ void deactivate_locked_super(struct super_block *s)
|
|||
{
|
||||
struct file_system_type *fs = s->s_type;
|
||||
if (atomic_dec_and_test(&s->s_active)) {
|
||||
cleancache_flush_fs(s);
|
||||
cleancache_invalidate_fs(s);
|
||||
fs->kill_sb(s);
|
||||
|
||||
/* caches are now gone, we can safely kill the shrinker now */
|
||||
|
|
|
@ -28,9 +28,9 @@ struct cleancache_ops {
|
|||
pgoff_t, struct page *);
|
||||
void (*put_page)(int, struct cleancache_filekey,
|
||||
pgoff_t, struct page *);
|
||||
void (*flush_page)(int, struct cleancache_filekey, pgoff_t);
|
||||
void (*flush_inode)(int, struct cleancache_filekey);
|
||||
void (*flush_fs)(int);
|
||||
void (*invalidate_page)(int, struct cleancache_filekey, pgoff_t);
|
||||
void (*invalidate_inode)(int, struct cleancache_filekey);
|
||||
void (*invalidate_fs)(int);
|
||||
};
|
||||
|
||||
extern struct cleancache_ops
|
||||
|
@ -39,9 +39,9 @@ extern void __cleancache_init_fs(struct super_block *);
|
|||
extern void __cleancache_init_shared_fs(char *, struct super_block *);
|
||||
extern int __cleancache_get_page(struct page *);
|
||||
extern void __cleancache_put_page(struct page *);
|
||||
extern void __cleancache_flush_page(struct address_space *, struct page *);
|
||||
extern void __cleancache_flush_inode(struct address_space *);
|
||||
extern void __cleancache_flush_fs(struct super_block *);
|
||||
extern void __cleancache_invalidate_page(struct address_space *, struct page *);
|
||||
extern void __cleancache_invalidate_inode(struct address_space *);
|
||||
extern void __cleancache_invalidate_fs(struct super_block *);
|
||||
extern int cleancache_enabled;
|
||||
|
||||
#ifdef CONFIG_CLEANCACHE
|
||||
|
@ -99,24 +99,24 @@ static inline void cleancache_put_page(struct page *page)
|
|||
__cleancache_put_page(page);
|
||||
}
|
||||
|
||||
static inline void cleancache_flush_page(struct address_space *mapping,
|
||||
static inline void cleancache_invalidate_page(struct address_space *mapping,
|
||||
struct page *page)
|
||||
{
|
||||
/* careful... page->mapping is NULL sometimes when this is called */
|
||||
if (cleancache_enabled && cleancache_fs_enabled_mapping(mapping))
|
||||
__cleancache_flush_page(mapping, page);
|
||||
__cleancache_invalidate_page(mapping, page);
|
||||
}
|
||||
|
||||
static inline void cleancache_flush_inode(struct address_space *mapping)
|
||||
static inline void cleancache_invalidate_inode(struct address_space *mapping)
|
||||
{
|
||||
if (cleancache_enabled && cleancache_fs_enabled_mapping(mapping))
|
||||
__cleancache_flush_inode(mapping);
|
||||
__cleancache_invalidate_inode(mapping);
|
||||
}
|
||||
|
||||
static inline void cleancache_flush_fs(struct super_block *sb)
|
||||
static inline void cleancache_invalidate_fs(struct super_block *sb)
|
||||
{
|
||||
if (cleancache_enabled)
|
||||
__cleancache_flush_fs(sb);
|
||||
__cleancache_invalidate_fs(sb);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_CLEANCACHE_H */
|
||||
|
|
|
@ -15,29 +15,34 @@
|
|||
#include <linux/fs.h>
|
||||
#include <linux/exportfs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/cleancache.h>
|
||||
|
||||
/*
|
||||
* This global enablement flag may be read thousands of times per second
|
||||
* by cleancache_get/put/flush even on systems where cleancache_ops
|
||||
* by cleancache_get/put/invalidate even on systems where cleancache_ops
|
||||
* is not claimed (e.g. cleancache is config'ed on but remains
|
||||
* disabled), so is preferred to the slower alternative: a function
|
||||
* call that checks a non-global.
|
||||
*/
|
||||
int cleancache_enabled;
|
||||
int cleancache_enabled __read_mostly;
|
||||
EXPORT_SYMBOL(cleancache_enabled);
|
||||
|
||||
/*
|
||||
* cleancache_ops is set by cleancache_ops_register to contain the pointers
|
||||
* to the cleancache "backend" implementation functions.
|
||||
*/
|
||||
static struct cleancache_ops cleancache_ops;
|
||||
static struct cleancache_ops cleancache_ops __read_mostly;
|
||||
|
||||
/* useful stats available in /sys/kernel/mm/cleancache */
|
||||
static unsigned long cleancache_succ_gets;
|
||||
static unsigned long cleancache_failed_gets;
|
||||
static unsigned long cleancache_puts;
|
||||
static unsigned long cleancache_flushes;
|
||||
/*
|
||||
* Counters available via /sys/kernel/debug/frontswap (if debugfs is
|
||||
* properly configured. These are for information only so are not protected
|
||||
* against increment races.
|
||||
*/
|
||||
static u64 cleancache_succ_gets;
|
||||
static u64 cleancache_failed_gets;
|
||||
static u64 cleancache_puts;
|
||||
static u64 cleancache_invalidates;
|
||||
|
||||
/*
|
||||
* register operations for cleancache, returning previous thus allowing
|
||||
|
@ -148,10 +153,11 @@ void __cleancache_put_page(struct page *page)
|
|||
EXPORT_SYMBOL(__cleancache_put_page);
|
||||
|
||||
/*
|
||||
* Flush any data from cleancache associated with the poolid and the
|
||||
* Invalidate any data from cleancache associated with the poolid and the
|
||||
* page's inode and page index so that a subsequent "get" will fail.
|
||||
*/
|
||||
void __cleancache_flush_page(struct address_space *mapping, struct page *page)
|
||||
void __cleancache_invalidate_page(struct address_space *mapping,
|
||||
struct page *page)
|
||||
{
|
||||
/* careful... page->mapping is NULL sometimes when this is called */
|
||||
int pool_id = mapping->host->i_sb->cleancache_poolid;
|
||||
|
@ -160,85 +166,57 @@ void __cleancache_flush_page(struct address_space *mapping, struct page *page)
|
|||
if (pool_id >= 0) {
|
||||
VM_BUG_ON(!PageLocked(page));
|
||||
if (cleancache_get_key(mapping->host, &key) >= 0) {
|
||||
(*cleancache_ops.flush_page)(pool_id, key, page->index);
|
||||
cleancache_flushes++;
|
||||
(*cleancache_ops.invalidate_page)(pool_id,
|
||||
key, page->index);
|
||||
cleancache_invalidates++;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(__cleancache_flush_page);
|
||||
EXPORT_SYMBOL(__cleancache_invalidate_page);
|
||||
|
||||
/*
|
||||
* Flush all data from cleancache associated with the poolid and the
|
||||
* Invalidate all data from cleancache associated with the poolid and the
|
||||
* mappings's inode so that all subsequent gets to this poolid/inode
|
||||
* will fail.
|
||||
*/
|
||||
void __cleancache_flush_inode(struct address_space *mapping)
|
||||
void __cleancache_invalidate_inode(struct address_space *mapping)
|
||||
{
|
||||
int pool_id = mapping->host->i_sb->cleancache_poolid;
|
||||
struct cleancache_filekey key = { .u.key = { 0 } };
|
||||
|
||||
if (pool_id >= 0 && cleancache_get_key(mapping->host, &key) >= 0)
|
||||
(*cleancache_ops.flush_inode)(pool_id, key);
|
||||
(*cleancache_ops.invalidate_inode)(pool_id, key);
|
||||
}
|
||||
EXPORT_SYMBOL(__cleancache_flush_inode);
|
||||
EXPORT_SYMBOL(__cleancache_invalidate_inode);
|
||||
|
||||
/*
|
||||
* Called by any cleancache-enabled filesystem at time of unmount;
|
||||
* note that pool_id is surrendered and may be reutrned by a subsequent
|
||||
* cleancache_init_fs or cleancache_init_shared_fs
|
||||
*/
|
||||
void __cleancache_flush_fs(struct super_block *sb)
|
||||
void __cleancache_invalidate_fs(struct super_block *sb)
|
||||
{
|
||||
if (sb->cleancache_poolid >= 0) {
|
||||
int old_poolid = sb->cleancache_poolid;
|
||||
sb->cleancache_poolid = -1;
|
||||
(*cleancache_ops.flush_fs)(old_poolid);
|
||||
(*cleancache_ops.invalidate_fs)(old_poolid);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(__cleancache_flush_fs);
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
|
||||
/* see Documentation/ABI/xxx/sysfs-kernel-mm-cleancache */
|
||||
|
||||
#define CLEANCACHE_SYSFS_RO(_name) \
|
||||
static ssize_t cleancache_##_name##_show(struct kobject *kobj, \
|
||||
struct kobj_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, "%lu\n", cleancache_##_name); \
|
||||
} \
|
||||
static struct kobj_attribute cleancache_##_name##_attr = { \
|
||||
.attr = { .name = __stringify(_name), .mode = 0444 }, \
|
||||
.show = cleancache_##_name##_show, \
|
||||
}
|
||||
|
||||
CLEANCACHE_SYSFS_RO(succ_gets);
|
||||
CLEANCACHE_SYSFS_RO(failed_gets);
|
||||
CLEANCACHE_SYSFS_RO(puts);
|
||||
CLEANCACHE_SYSFS_RO(flushes);
|
||||
|
||||
static struct attribute *cleancache_attrs[] = {
|
||||
&cleancache_succ_gets_attr.attr,
|
||||
&cleancache_failed_gets_attr.attr,
|
||||
&cleancache_puts_attr.attr,
|
||||
&cleancache_flushes_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group cleancache_attr_group = {
|
||||
.attrs = cleancache_attrs,
|
||||
.name = "cleancache",
|
||||
};
|
||||
|
||||
#endif /* CONFIG_SYSFS */
|
||||
EXPORT_SYMBOL(__cleancache_invalidate_fs);
|
||||
|
||||
static int __init init_cleancache(void)
|
||||
{
|
||||
#ifdef CONFIG_SYSFS
|
||||
int err;
|
||||
|
||||
err = sysfs_create_group(mm_kobj, &cleancache_attr_group);
|
||||
#endif /* CONFIG_SYSFS */
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *root = debugfs_create_dir("cleancache", NULL);
|
||||
if (root == NULL)
|
||||
return -ENXIO;
|
||||
debugfs_create_u64("succ_gets", S_IRUGO, root, &cleancache_succ_gets);
|
||||
debugfs_create_u64("failed_gets", S_IRUGO,
|
||||
root, &cleancache_failed_gets);
|
||||
debugfs_create_u64("puts", S_IRUGO, root, &cleancache_puts);
|
||||
debugfs_create_u64("invalidates", S_IRUGO,
|
||||
root, &cleancache_invalidates);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
module_init(init_cleancache)
|
||||
|
|
|
@ -123,7 +123,7 @@ void __delete_from_page_cache(struct page *page)
|
|||
if (PageUptodate(page) && PageMappedToDisk(page))
|
||||
cleancache_put_page(page);
|
||||
else
|
||||
cleancache_flush_page(mapping, page);
|
||||
cleancache_invalidate_page(mapping, page);
|
||||
|
||||
radix_tree_delete(&mapping->page_tree, page->index);
|
||||
page->mapping = NULL;
|
||||
|
|
|
@ -52,7 +52,7 @@ void do_invalidatepage(struct page *page, unsigned long offset)
|
|||
static inline void truncate_partial_page(struct page *page, unsigned partial)
|
||||
{
|
||||
zero_user_segment(page, partial, PAGE_CACHE_SIZE);
|
||||
cleancache_flush_page(page->mapping, page);
|
||||
cleancache_invalidate_page(page->mapping, page);
|
||||
if (page_has_private(page))
|
||||
do_invalidatepage(page, partial);
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
|
|||
pgoff_t end;
|
||||
int i;
|
||||
|
||||
cleancache_flush_inode(mapping);
|
||||
cleancache_invalidate_inode(mapping);
|
||||
if (mapping->nrpages == 0)
|
||||
return;
|
||||
|
||||
|
@ -292,7 +292,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
|
|||
mem_cgroup_uncharge_end();
|
||||
index++;
|
||||
}
|
||||
cleancache_flush_inode(mapping);
|
||||
cleancache_invalidate_inode(mapping);
|
||||
}
|
||||
EXPORT_SYMBOL(truncate_inode_pages_range);
|
||||
|
||||
|
@ -444,7 +444,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
|
|||
int ret2 = 0;
|
||||
int did_range_unmap = 0;
|
||||
|
||||
cleancache_flush_inode(mapping);
|
||||
cleancache_invalidate_inode(mapping);
|
||||
pagevec_init(&pvec, 0);
|
||||
index = start;
|
||||
while (index <= end && pagevec_lookup(&pvec, mapping, index,
|
||||
|
@ -500,7 +500,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
|
|||
cond_resched();
|
||||
index++;
|
||||
}
|
||||
cleancache_flush_inode(mapping);
|
||||
cleancache_invalidate_inode(mapping);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range);
|
||||
|
|
Loading…
Reference in a new issue