// SPDX-License-Identifier: GPL-2.0
/*
* The NFSD open file cache.
*
* (c) 2015 - Jeff Layton <jeff.layton@primarydata.com>
*
* An nfsd_file object is a per-file collection of open state that binds
* together:
* - a struct file *
* - a user credential
* - a network namespace
* - a read-ahead context
* - monitoring for writeback errors
*
* nfsd_file objects are reference-counted. Consumers acquire a new
* object via the nfsd_file_acquire API. They manage their interest in
* the acquired object, and hence the object's reference count, via
* nfsd_file_get and nfsd_file_put. There are two varieties of nfsd_file
* object:
*
* * non-garbage-collected: When a consumer wants to precisely control
* the lifetime of a file's open state, it acquires a non-garbage-
* collected nfsd_file. The final nfsd_file_put releases the open
* state immediately.
*
* * garbage-collected: When a consumer does not control the lifetime
* of open state, it acquires a garbage-collected nfsd_file. The
* final nfsd_file_put allows the open state to linger for a period
* during which it may be re-used.
*/
#include <linux/hash.h>
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/pagemap.h>
#include <linux/sched.h>
#include <linux/list_lru.h>
#include <linux/fsnotify_backend.h>
#include <linux/fsnotify.h>
#include <linux/seq_file.h>
#include <linux/rhashtable.h>
#include "vfs.h"
#include "nfsd.h"
#include "nfsfh.h"
#include "netns.h"
#include "filecache.h"
#include "trace.h"
#define NFSD_LAUNDRETTE_DELAY (2 * HZ)
#define NFSD_FILE_CACHE_UP (0)
/* We only care about NFSD_MAY_READ/WRITE for this cache */
#define NFSD_FILE_MAY_MASK (NFSD_MAY_READ|NFSD_MAY_WRITE)
static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits);
static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions);
static DEFINE_PER_CPU(unsigned long, nfsd_file_releases);
static DEFINE_PER_CPU(unsigned long, nfsd_file_total_age);
static DEFINE_PER_CPU(unsigned long, nfsd_file_evictions);
struct nfsd_fcache_disposal {
struct work_struct work;
spinlock_t lock;
struct list_head freeme;
};
static struct workqueue_struct *nfsd_filecache_wq __read_mostly;
static struct kmem_cache *nfsd_file_slab;
static struct kmem_cache *nfsd_file_mark_slab;
static struct list_lru nfsd_file_lru;
static unsigned long nfsd_file_flags;
static struct fsnotify_group *nfsd_file_fsnotify_group;
static struct delayed_work nfsd_filecache_laundrette;
static struct rhashtable nfsd_file_rhash_tbl
____cacheline_aligned_in_smp;
enum nfsd_file_lookup_type {
NFSD_FILE_KEY_INODE,
NFSD_FILE_KEY_FULL,
};
struct nfsd_file_lookup_key {
struct inode *inode;
struct net *net;
const struct cred *cred;
unsigned char need;
bool gc;
enum nfsd_file_lookup_type type;
};
/*
* The returned hash value is based solely on the address of an in-code
* inode, a pointer to a slab-allocated object. The entropy in such a
* pointer is concentrated in its middle bits.
*/
static u32 nfsd_file_inode_hash(const struct inode *inode, u32 seed)
{
unsigned long ptr = (unsigned long)inode;
u32 k;
k = ptr >> L1_CACHE_SHIFT;
k &= 0x00ffffff;
return jhash2(&k, 1, seed);
}
/**
* nfsd_file_key_hashfn - Compute the hash value of a lookup key
* @data: key on which to compute the hash value
* @len: rhash table's key_len parameter (unused)
* @seed: rhash table's random seed of the day
*
* Return value:
* Computed 32-bit hash value
*/
static u32 nfsd_file_key_hashfn(const void *data, u32 len, u32 seed)
{
const struct nfsd_file_lookup_key *key = data;
return nfsd_file_inode_hash(key->inode, seed);
}
/**
* nfsd_file_obj_hashfn - Compute the hash value of an nfsd_file
* @data: object on which to compute the hash value
* @len: rhash table's key_len parameter (unused)
* @seed: rhash table's random seed of the day