Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Documentation/filesystems/9p.rst
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,11 @@ Options
cachetag cache tag to use the specified persistent cache.
cache tags for existing cache sessions can be listed at
/sys/fs/9p/caches. (applies only to cache=fscache)

negtimeout the duration (in milliseconds) that negative dentries (paths
that do not actually exist) are retained in the cache. If
set to a negative value, those entries are kept indefinitely
until evicted by the buffer cache management system
============= ===============================================================

Behavior
Expand Down
11 changes: 6 additions & 5 deletions fs/9p/fid.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@

static inline void __add_fid(struct dentry *dentry, struct p9_fid *fid)
{
hlist_add_head(&fid->dlist, (struct hlist_head *)&dentry->d_fsdata);
struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);

hlist_add_head(&fid->dlist, &v9fs_dentry->head);
}


Expand Down Expand Up @@ -112,18 +114,17 @@ void v9fs_open_fid_add(struct inode *inode, struct p9_fid **pfid)

static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
{
struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
struct p9_fid *fid, *ret;

p9_debug(P9_DEBUG_VFS, " dentry: %pd (%p) uid %d any %d\n",
dentry, dentry, from_kuid(&init_user_ns, uid),
any);
ret = NULL;
/* we'll recheck under lock if there's anything to look in */
if (dentry->d_fsdata) {
struct hlist_head *h = (struct hlist_head *)&dentry->d_fsdata;

if (!hlist_empty(&v9fs_dentry->head)) {
spin_lock(&dentry->d_lock);
hlist_for_each_entry(fid, h, dlist) {
hlist_for_each_entry(fid, &v9fs_dentry->head, dlist) {
if (any || uid_eq(fid->uid, uid)) {
ret = fid;
p9_fid_get(ret);
Expand Down
27 changes: 26 additions & 1 deletion fs/9p/v9fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
#include "v9fs_vfs.h"
#include "cache.h"

/* cache=loose default negative dentry retention time is 24hours */
#define CACHE_LOOSE_NDENTRY_TIMEOUT_DEFAULT (24 * 60 * 60 * 1000)

static DEFINE_SPINLOCK(v9fs_sessionlist_lock);
static LIST_HEAD(v9fs_sessionlist);
struct kmem_cache *v9fs_inode_cache;
Expand All @@ -39,7 +42,7 @@ enum {
* source if we rejected it as EINVAL */
Opt_source,
/* Options that take integer arguments */
Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid,
Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid, Opt_negtimeout,
/* String options */
Opt_uname, Opt_remotename, Opt_cache, Opt_cachetag,
/* Options that take no arguments */
Expand Down Expand Up @@ -93,6 +96,7 @@ const struct fs_parameter_spec v9fs_param_spec[] = {
fsparam_string ("access", Opt_access),
fsparam_flag ("posixacl", Opt_posixacl),
fsparam_u32 ("locktimeout", Opt_locktimeout),
fsparam_s32 ("negtimeout", Opt_negtimeout),

/* client options */
fsparam_u32 ("msize", Opt_msize),
Expand Down Expand Up @@ -159,6 +163,9 @@ int v9fs_show_options(struct seq_file *m, struct dentry *root)
from_kgid_munged(&init_user_ns, v9ses->dfltgid));
if (v9ses->afid != ~0)
seq_printf(m, ",afid=%u", v9ses->afid);
if (v9ses->flags & V9FS_NDENTRY_TIMEOUT_SET)
seq_printf(m, ",negtimeout=%d",
(int)v9ses->ndentry_timeout_ms);
if (strcmp(v9ses->uname, V9FS_DEFUSER) != 0)
seq_printf(m, ",uname=%s", v9ses->uname);
if (strcmp(v9ses->aname, V9FS_DEFANAME) != 0)
Expand Down Expand Up @@ -337,6 +344,16 @@ int v9fs_parse_param(struct fs_context *fc, struct fs_parameter *param)
session_opts->session_lock_timeout = (long)result.uint_32 * HZ;
break;

case Opt_negtimeout:
session_opts->flags |= V9FS_NDENTRY_TIMEOUT_SET;
if (result.int_32 < 0) {
session_opts->ndentry_timeout_ms =
NDENTRY_TIMEOUT_NEVER;
} else {
session_opts->ndentry_timeout_ms = result.int_32;
}
break;

/* Options for client */
case Opt_msize:
if (result.uint_32 < 4096) {
Expand Down Expand Up @@ -422,6 +439,14 @@ static void v9fs_apply_options(struct v9fs_session_info *v9ses,
v9ses->cache = ctx->session_opts.cache;
v9ses->uid = ctx->session_opts.uid;
v9ses->session_lock_timeout = ctx->session_opts.session_lock_timeout;
v9ses->ndentry_timeout_ms = ctx->session_opts.ndentry_timeout_ms;

/* If negative dentry timeout has not been overriden set default for
* cache=loose
*/
if (!(v9ses->flags & V9FS_NDENTRY_TIMEOUT_SET) &&
(v9ses->cache & CACHE_LOOSE))
v9ses->ndentry_timeout_ms = CACHE_LOOSE_NDENTRY_TIMEOUT_DEFAULT;
}

/**
Expand Down
28 changes: 18 additions & 10 deletions fs/9p/v9fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
* @V9FS_ACCESS_ANY: use a single attach for all users
* @V9FS_ACCESS_MASK: bit mask of different ACCESS options
* @V9FS_POSIX_ACL: POSIX ACLs are enforced
* @V9FS_NDENTRY_TIMEOUT_SET: Has negative dentry timeout retention time been
* overriden by ndentrycache mount option
*
* Session flags reflect options selected by users at mount time
*/
Expand All @@ -34,16 +36,17 @@
#define V9FS_ACL_MASK V9FS_POSIX_ACL

enum p9_session_flags {
V9FS_PROTO_2000U = 0x01,
V9FS_PROTO_2000L = 0x02,
V9FS_ACCESS_SINGLE = 0x04,
V9FS_ACCESS_USER = 0x08,
V9FS_ACCESS_CLIENT = 0x10,
V9FS_POSIX_ACL = 0x20,
V9FS_NO_XATTR = 0x40,
V9FS_IGNORE_QV = 0x80, /* ignore qid.version for cache hints */
V9FS_DIRECT_IO = 0x100,
V9FS_SYNC = 0x200
V9FS_PROTO_2000U = 0x01,
V9FS_PROTO_2000L = 0x02,
V9FS_ACCESS_SINGLE = 0x04,
V9FS_ACCESS_USER = 0x08,
V9FS_ACCESS_CLIENT = 0x10,
V9FS_POSIX_ACL = 0x20,
V9FS_NO_XATTR = 0x40,
V9FS_IGNORE_QV = 0x80, /* ignore qid.version for cache hints */
V9FS_DIRECT_IO = 0x100,
V9FS_SYNC = 0x200,
V9FS_NDENTRY_TIMEOUT_SET = 0x400,
};

/**
Expand Down Expand Up @@ -91,6 +94,7 @@ enum p9_cache_bits {
* @debug: debug level
* @afid: authentication handle
* @cache: cache mode of type &p9_cache_bits
* @ndentry_timeout: Negative dentry lookup cache retention time in ms
* @cachetag: the tag of the cache associated with this session
* @fscache: session cookie associated with FS-Cache
* @uname: string user name to mount hierarchy as
Expand All @@ -101,6 +105,7 @@ enum p9_cache_bits {
* @uid: if %V9FS_ACCESS_SINGLE, the numeric uid which mounted the hierarchy
* @clnt: reference to 9P network client instantiated for this session
* @slist: reference to list of registered 9p sessions
* @ndentry_timeout_ms: Negative dentry caching retention time
*
* This structure holds state for each session instance established during
* a sys_mount() .
Expand All @@ -116,6 +121,7 @@ struct v9fs_session_info {
unsigned short debug;
unsigned int afid;
unsigned int cache;
unsigned int ndentry_timeout_ms;
#ifdef CONFIG_9P_FSCACHE
char *cachetag;
struct fscache_volume *fscache;
Expand All @@ -133,6 +139,8 @@ struct v9fs_session_info {
long session_lock_timeout; /* retry interval for blocking locks */
};

#define NDENTRY_TIMEOUT_NEVER (-1U)

/* cache_validity flags */
#define V9FS_INO_INVALID_ATTR 0x01

Expand Down
15 changes: 15 additions & 0 deletions fs/9p/v9fs_vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,28 @@
/* flags for v9fs_stat2inode() & v9fs_stat2inode_dotl() */
#define V9FS_STAT2INODE_KEEP_ISIZE 1

/**
* struct v9fs_dentry - v9fs specific dentry data
* @head: List of fid associated with this dentry
* @expire_time: Lookup cache expiration time for negative dentries
* @rcu: used by kfree_rcu to schedule clean up job
*/
struct v9fs_dentry {
struct hlist_head head;
u64 expire_time;
struct rcu_head rcu;
};
#define to_v9fs_dentry(d) ((struct v9fs_dentry *)((d)->d_fsdata))

extern struct file_system_type v9fs_fs_type;
extern const struct address_space_operations v9fs_addr_operations;
extern const struct file_operations v9fs_file_operations;
extern const struct file_operations v9fs_file_operations_dotl;
extern const struct file_operations v9fs_dir_operations;
extern const struct file_operations v9fs_dir_operations_dotl;
extern const struct dentry_operations v9fs_dentry_operations;
extern void v9fs_ndentry_refresh_timeout(struct dentry *dentry);
extern void v9fs_dentry_fid_remove(struct dentry *dentry);
extern const struct dentry_operations v9fs_cached_dentry_operations;
extern struct kmem_cache *v9fs_inode_cache;

Expand Down
35 changes: 32 additions & 3 deletions fs/9p/vfs_addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,31 @@ static void v9fs_issue_read(struct netfs_io_subrequest *subreq)
{
struct netfs_io_request *rreq = subreq->rreq;
struct p9_fid *fid = rreq->netfs_priv;
char *target;
unsigned long long pos = subreq->start + subreq->transferred;
int total, err;

total = p9_client_read(fid, pos, &subreq->io_iter, &err);
int total = 0, err, len, n;

if (S_ISLNK(rreq->inode->i_mode)) {
/* p9_client_readlink() must not be called for legacy protocols
* 9p2000 or 9p2000.u.
*/
BUG_ON(!p9_is_proto_dotl(fid->clnt));
err = p9_client_readlink(fid, &target);
if (err != 0)
goto fill_subreq;
len = strnlen(target, PAGE_SIZE - 1);
n = copy_to_iter(target, len, &subreq->io_iter);
kfree(target);
if (n != len) {
err = -EFAULT;
goto fill_subreq;
}
total = i_size_read(rreq->inode);
} else {
total = p9_client_read(fid, pos, &subreq->io_iter, &err);
}

fill_subreq:
/* if we just extended the file size, any portion not in
* cache won't be on server and is zeroes */
if (subreq->rreq->origin != NETFS_UNBUFFERED_READ &&
Expand All @@ -99,6 +119,7 @@ static void v9fs_issue_read(struct netfs_io_subrequest *subreq)
static int v9fs_init_request(struct netfs_io_request *rreq, struct file *file)
{
struct p9_fid *fid;
struct dentry *dentry;
bool writing = (rreq->origin == NETFS_READ_FOR_WRITE ||
rreq->origin == NETFS_WRITETHROUGH ||
rreq->origin == NETFS_UNBUFFERED_WRITE ||
Expand All @@ -115,6 +136,14 @@ static int v9fs_init_request(struct netfs_io_request *rreq, struct file *file)
if (!fid)
goto no_fid;
p9_fid_get(fid);
} else if (S_ISLNK(rreq->inode->i_mode)) {
dentry = d_find_alias(rreq->inode);
if (!dentry)
goto no_fid;
fid = v9fs_fid_lookup(dentry);
dput(dentry);
if (IS_ERR(fid))
goto no_fid;
} else {
fid = v9fs_fid_find_inode(rreq->inode, writing, INVALID_UID, true);
if (!fid)
Expand Down
Loading
Loading