linux/fs/drop_caches.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Implement the manual drop-all-pagecache function
   4 */
   5
   6#include <linux/kernel.h>
   7#include <linux/mm.h>
   8#include <linux/fs.h>
   9#include <linux/writeback.h>
  10#include <linux/sysctl.h>
  11#include <linux/gfp.h>
  12#include "internal.h"
  13
  14/* A global variable is a bit ugly, but it keeps the code simple */
  15int sysctl_drop_caches;
  16
  17static void drop_pagecache_sb(struct super_block *sb, void *unused)
  18{
  19        struct inode *inode, *toput_inode = NULL;
  20
  21        spin_lock(&sb->s_inode_list_lock);
  22        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
  23                spin_lock(&inode->i_lock);
  24                /*
  25                 * We must skip inodes in unusual state. We may also skip
  26                 * inodes without pages but we deliberately won't in case
  27                 * we need to reschedule to avoid softlockups.
  28                 */
  29                if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
  30                    (inode->i_mapping->nrpages == 0 && !need_resched())) {
  31                        spin_unlock(&inode->i_lock);
  32                        continue;
  33                }
  34                __iget(inode);
  35                spin_unlock(&inode->i_lock);
  36                spin_unlock(&sb->s_inode_list_lock);
  37
  38                cond_resched();
  39                invalidate_mapping_pages(inode->i_mapping, 0, -1);
  40                iput(toput_inode);
  41                toput_inode = inode;
  42
  43                spin_lock(&sb->s_inode_list_lock);
  44        }
  45        spin_unlock(&sb->s_inode_list_lock);
  46        iput(toput_inode);
  47}
  48
  49int drop_caches_sysctl_handler(struct ctl_table *table, int write,
  50        void __user *buffer, size_t *length, loff_t *ppos)
  51{
  52        int ret;
  53
  54        ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
  55        if (ret)
  56                return ret;
  57        if (write) {
  58                static int stfu;
  59
  60                if (sysctl_drop_caches & 1) {
  61                        iterate_supers(drop_pagecache_sb, NULL);
  62                        count_vm_event(DROP_PAGECACHE);
  63                }
  64                if (sysctl_drop_caches & 2) {
  65                        drop_slab();
  66                        count_vm_event(DROP_SLAB);
  67                }
  68                if (!stfu) {
  69                        pr_info("%s (%d): drop_caches: %d\n",
  70                                current->comm, task_pid_nr(current),
  71                                sysctl_drop_caches);
  72                }
  73                stfu |= sysctl_drop_caches & 4;
  74        }
  75        return 0;
  76}
  77