Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Implement the manual drop-all-pagecache function
0004  */
0005 
0006 #include <linux/pagemap.h>
0007 #include <linux/kernel.h>
0008 #include <linux/mm.h>
0009 #include <linux/fs.h>
0010 #include <linux/writeback.h>
0011 #include <linux/sysctl.h>
0012 #include <linux/gfp.h>
0013 #include "internal.h"
0014 
0015 /* A global variable is a bit ugly, but it keeps the code simple */
0016 int sysctl_drop_caches;
0017 
0018 static void drop_pagecache_sb(struct super_block *sb, void *unused)
0019 {
0020     struct inode *inode, *toput_inode = NULL;
0021 
0022     spin_lock(&sb->s_inode_list_lock);
0023     list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
0024         spin_lock(&inode->i_lock);
0025         /*
0026          * We must skip inodes in unusual state. We may also skip
0027          * inodes without pages but we deliberately won't in case
0028          * we need to reschedule to avoid softlockups.
0029          */
0030         if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
0031             (mapping_empty(inode->i_mapping) && !need_resched())) {
0032             spin_unlock(&inode->i_lock);
0033             continue;
0034         }
0035         __iget(inode);
0036         spin_unlock(&inode->i_lock);
0037         spin_unlock(&sb->s_inode_list_lock);
0038 
0039         invalidate_mapping_pages(inode->i_mapping, 0, -1);
0040         iput(toput_inode);
0041         toput_inode = inode;
0042 
0043         cond_resched();
0044         spin_lock(&sb->s_inode_list_lock);
0045     }
0046     spin_unlock(&sb->s_inode_list_lock);
0047     iput(toput_inode);
0048 }
0049 
0050 int drop_caches_sysctl_handler(struct ctl_table *table, int write,
0051         void *buffer, size_t *length, loff_t *ppos)
0052 {
0053     int ret;
0054 
0055     ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
0056     if (ret)
0057         return ret;
0058     if (write) {
0059         static int stfu;
0060 
0061         if (sysctl_drop_caches & 1) {
0062             iterate_supers(drop_pagecache_sb, NULL);
0063             count_vm_event(DROP_PAGECACHE);
0064         }
0065         if (sysctl_drop_caches & 2) {
0066             drop_slab();
0067             count_vm_event(DROP_SLAB);
0068         }
0069         if (!stfu) {
0070             pr_info("%s (%d): drop_caches: %d\n",
0071                 current->comm, task_pid_nr(current),
0072                 sysctl_drop_caches);
0073         }
0074         stfu |= sysctl_drop_caches & 4;
0075     }
0076     return 0;
0077 }