Merge tag '9p-for-7.2-rc1' of https://github.com/martinetd/linux
Merge commit. Changes below are compared with the first parent: aff3ca32.
Changes
18 files changed · +321 −75
| File | Status | Add | Del | Content |
|---|---|---|---|---|
| Documentation/filesystems/9p.rst | modified | +6 | −4 | View file |
| fs/9p/fid.c | modified | +6 | −5 | View file |
| fs/9p/v9fs.c | modified | +26 | −1 | View file |
| fs/9p/v9fs.h | modified | +18 | −10 | View file |
| fs/9p/v9fs_vfs.h | modified | +15 | −0 | View file |
| fs/9p/vfs_addr.c | modified | +35 | −3 | View file |
| fs/9p/vfs_dentry.c | modified | +91 | −14 | View file |
| fs/9p/vfs_dir.c | modified | +13 | −1 | View file |
| fs/9p/vfs_file.c | modified | +1 | −1 | View file |
| fs/9p/vfs_inode.c | modified | +26 | −20 | View file |
| fs/9p/vfs_inode_dotl.c | modified | +51 | −7 | View file |
| fs/9p/vfs_super.c | modified | +1 | −0 | View file |
| include/net/9p/client.h | modified | +2 | −0 | View file |
| net/9p/client.c | modified | +5 | −2 | View file |
| net/9p/trans_fd.c | modified | +2 | −4 | View file |
| net/9p/trans_rdma.c | modified | +17 | −2 | View file |
| net/9p/trans_usbg.c | modified | +1 | −1 | View file |
| net/9p/trans_virtio.c | modified | +5 | −0 | View file |
Only the first 600 diff lines are shown. Download the complete patch.
Documentation/filesystems/9p.rst
View filediff --git a/Documentation/filesystems/9p.rst b/Documentation/filesystems/9p.rst
index be3504c..3f65db6 100644
--- a/Documentation/filesystems/9p.rst
+++ b/Documentation/filesystems/9p.rst
@@ -23,13 +23,10 @@ the 9p client is available in the form of a USENIX paper:
Other applications are described in the following papers:
* XCPU & Clustering
- http://xcpu.org/papers/xcpu-talk.pdf
* KVMFS: control file system for KVM
- http://xcpu.org/papers/kvmfs.pdf
* CellFS: A New Programming Model for the Cell BE
- http://xcpu.org/papers/cellfs-talk.pdf
* PROSE I/O: Using 9p to enable Application Partitions
- http://plan9.escet.urjc.es/iwp9/cready/PROSE_iwp9_2006.pdf
+ http://web.archive.org/web/20110101152020/http://plan9.escet.urjc.es/iwp9/cready/PROSE_iwp9_2006.pdf
* VirtFS: A Virtualization Aware File System pass-through
https://kernel.org/doc/ols/2010/ols2010-pages-109-120.pdf
@@ -238,6 +235,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
fs/9p/fid.c
View filediff --git a/fs/9p/fid.c b/fs/9p/fid.c
index f844122..76242d4 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -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);
}
@@ -112,6 +114,7 @@ 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",
@@ -119,11 +122,9 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
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);
fs/9p/v9fs.c
View filediff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index acda424..274c515 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -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;
@@ -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 */
@@ -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),
@@ -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)
@@ -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) {
@@ -426,6 +443,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 overridden 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;
}
/**
fs/9p/v9fs.h
View filediff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 6a12445..a462bcb 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -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
+ * overridden by negtimeout mount option
*
* Session flags reflect options selected by users at mount time
*/
@@ -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,
};
/**
@@ -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
@@ -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() .
@@ -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;
@@ -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
fs/9p/v9fs_vfs.h
View filediff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 34c115d..1856d91 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -28,6 +28,19 @@
/* 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;
@@ -35,6 +48,8 @@ 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;
fs/9p/vfs_addr.c
View filediff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index c21d338..1ac0b3d 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -70,11 +70,34 @@ 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));
+ if (WARN_ON_ONCE(pos)) {
+ /* reading a link at a non null offset should
+ * not happen
+ */
+ err = -EIO;
+ goto fill_subreq;
+ }
+ err = p9_client_readlink(fid, &target);
+ if (err != 0)
+ goto fill_subreq;
+ len = strlen(target);
+ n = copy_to_iter(target, len, &subreq->io_iter);
+ kfree(target);
+ total = n;
+ } 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 &&
@@ -99,6 +122,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 ||
@@ -115,6 +139,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_any_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)
fs/9p/vfs_dentry.c
View filediff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index c5bf74d..e549e22 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -24,6 +24,46 @@
#include "fid.h"
/**
+ * v9fs_ndentry_is_expired - Check if negative dentry lookup has expired
+ *
+ * This should be called to know if a negative dentry should be removed from
+ * cache.
+ *
+ * @dentry: dentry in question
+ *
+ */
+static bool v9fs_ndentry_is_expired(struct dentry const *dentry)
+{
+ struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
+ struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
+
+ if (v9ses->ndentry_timeout_ms == NDENTRY_TIMEOUT_NEVER)
+ return false;
+
+ return time_before_eq64(v9fs_dentry->expire_time, get_jiffies_64());
+}
+
+/**
+ * v9fs_ndentry_refresh_timeout - Refresh negative dentry lookup cache timeout
+ *
+ * This should be called when a look up yields a negative entry.
+ *
+ * @dentry: dentry in question
+ *
+ */
+void v9fs_ndentry_refresh_timeout(struct dentry *dentry)
+{
+ struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
+ struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
+
+ if (v9ses->ndentry_timeout_ms == NDENTRY_TIMEOUT_NEVER)
+ return;
+
+ v9fs_dentry->expire_time = get_jiffies_64() +
+ msecs_to_jiffies(v9ses->ndentry_timeout_ms);
+}
+
+/**
* v9fs_cached_dentry_delete - called when dentry refcount equals 0
* @dentry: dentry in question
*
@@ -33,20 +73,15 @@ static int v9fs_cached_dentry_delete(const struct dentry *dentry)
p9_debug(P9_DEBUG_VFS, " dentry: %pd (%p)\n",
dentry, dentry);
- /* Don't cache negative dentries */
- if (d_really_is_negative(dentry))
- return 1;
- return 0;
-}
+ if (!d_really_is_negative(dentry))
+ return 0;
-/**
- * v9fs_dentry_release - called when dentry is going to be freed
- * @dentry: dentry that is being release
- *
- */
+ return v9fs_ndentry_is_expired(dentry);
+}
-static void v9fs_dentry_release(struct dentry *dentry)
+static void __v9fs_dentry_fid_remove(struct dentry *dentry)
{
+ struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
struct hlist_node *p, *n;
struct hlist_head head;
@@ -54,13 +89,54 @@ static void v9fs_dentry_release(struct dentry *dentry)
dentry, dentry);
spin_lock(&dentry->d_lock);
- hlist_move_list((struct hlist_head *)&dentry->d_fsdata, &head);
+ hlist_move_list(&v9fs_dentry->head, &head);
spin_unlock(&dentry->d_lock);
hlist_for_each_safe(p, n, &head)
p9_fid_put(hlist_entry(p, struct p9_fid, dlist));
}
+/**
+ * v9fs_dentry_fid_remove - Release all dentry's fids
+ * @dentry: dentry in question
+ *
+ */
+void v9fs_dentry_fid_remove(struct dentry *dentry)
+{
+ __v9fs_dentry_fid_remove(dentry);
+}
+
+/**
+ * v9fs_dentry_init - Initialize v9fs dentry data
+ * @dentry: dentry in question
+ *
+ */
+static int v9fs_dentry_init(struct dentry *dentry)
+{
+ struct v9fs_dentry *v9fs_dentry = kzalloc(sizeof(*v9fs_dentry),
+ GFP_KERNEL);
+
+ if (!v9fs_dentry)
+ return -ENOMEM;
+
+ INIT_HLIST_HEAD(&v9fs_dentry->head);
+ dentry->d_fsdata = (void *)v9fs_dentry;
+ return 0;
+}
+
+/**
+ * v9fs_dentry_release - called when dentry is going to be freed
+ * @dentry: dentry that is being released
+ *
+ */
+static void v9fs_dentry_release(struct dentry *dentry)
+{
+ struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
+
+ __v9fs_dentry_fid_remove(dentry);
+ kfree_rcu(v9fs_dentry, rcu);
+}
+
static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
{
struct p9_fid *fid;
@@ -72,7 +148,7 @@ static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
inode = d_inode(dentry);
if (!inode)
- goto out_valid;
+ return !v9fs_ndentry_is_expired(dentry);
v9inode = V9FS_I(inode);
if (v9inode->cache_validity & V9FS_INO_INVALID_ATTR) {
@@ -112,7 +188,6 @@ static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
return retval;
}
}
-out_valid:
p9_debug(P9_DEBUG_VFS, "dentry: %pd (%p) is valid\n", dentry, dentry);
return 1;
}
@@ -139,12 +214,14 @@ const struct dentry_operations v9fs_cached_dentry_operations = {
.d_revalidate = v9fs_lookup_revalidate,
.d_weak_revalidate = __v9fs_lookup_revalidate,
.d_delete = v9fs_cached_dentry_delete,
+ .d_init = v9fs_dentry_init,
.d_release = v9fs_dentry_release,
.d_unalias_trylock = v9fs_dentry_unalias_trylock,
.d_unalias_unlock = v9fs_dentry_unalias_unlock,
};
const struct dentry_operations v9fs_dentry_operations = {
+ .d_init = v9fs_dentry_init,
.d_release = v9fs_dentry_release,
.d_unalias_trylock = v9fs_dentry_unalias_trylock,
.d_unalias_unlock = v9fs_dentry_unalias_unlock,
fs/9p/vfs_dir.c
View filediff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index e0d34e4..323f853 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -27,6 +27,7 @@
* struct p9_rdir - readdir accounting
* @head: start offset of current dirread buffer
* @tail: end offset of current dirread buffer
+ * @offset: file position the data at @head corresponds to
* @buf: dirread buffer
*
* private structure for keeping track of readdir
@@ -36,6 +37,7 @@
struct p9_rdir {
int head;
int tail;
+ loff_t offset;
uint8_t buf[];
};
@@ -70,7 +72,7 @@ static struct p9_rdir *v9fs_alloc_rdir_buf(struct file *filp, int buflen)
struct p9_fid *fid = filp->private_data;
if (!fid->rdir)
- fid->rdir = kzalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
+ fid->rdir = kvzalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
return fid->rdir;
}
@@ -102,6 +104,9 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
kvec.iov_base = rdir->buf;
kvec.iov_len = buflen;
+ if (rdir->head < rdir->tail && rdir->offset != ctx->pos)
+ rdir->head = rdir->tail = 0;
+
while (1) {
if (rdir->tail == rdir->head) {
struct iov_iter to;
@@ -117,6 +122,7 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
rdir->head = 0;
rdir->tail = n;
+ rdir->offset = ctx->pos;
}
while (rdir->head < rdir->tail) {
err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
@@ -134,6 +140,7 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
rdir->head += err;
ctx->pos += err;
+ rdir->offset = ctx->pos;
}
}
}
@@ -161,6 +168,9 @@ static int v9fs_dir_readdir_dotl(struct file *file, struct dir_context *ctx)
if (!rdir)
return -ENOMEM;
+ if (rdir->head < rdir->tail && rdir->offset != ctx->pos)
+ rdir->head = rdir->tail = 0;
+
while (1) {
if (rdir->tail == rdir->head) {
err = p9_client_readdir(fid, rdir->buf, buflen,
@@ -170,6 +180,7 @@ static int v9fs_dir_readdir_dotl(struct file *file, struct dir_context *ctx)
rdir->head = 0;
rdir->tail = err;
+ rdir->offset = ctx->pos;
}
while (rdir->head < rdir->tail) {
@@ -190,6 +201,7 @@ static int v9fs_dir_readdir_dotl(struct file *file, struct dir_context *ctx)
ctx->pos = curdirent.d_off;
rdir->head += err;
+ rdir->offset = ctx->pos;
}
}
}
fs/9p/vfs_file.c
View filediff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index c5e73c3..cddfb4b 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -198,7 +198,7 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
res = -EAGAIN;
break;
default:
- WARN_ONCE(1, "unknown lock status code: %d\n", status);
+ p9_debug(P9_DEBUG_ERROR, "unknown lock status code: %d\n", status);
fallthrough;
case P9_LOCK_ERROR:
case P9_LOCK_GRACE:
fs/9p/vfs_inode.c
View filediff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index f468acb..5783d03 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -302,10 +302,12 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
goto error;
}
- if (v9fs_proto_dotl(v9ses))
+ if (v9fs_proto_dotl(v9ses)) {
inode->i_op = &v9fs_symlink_inode_operations_dotl;
- else
+ inode_nohighmem(inode);
+ } else {
inode->i_op = &v9fs_symlink_inode_operations;
+ }
break;
case S_IFDIR:
@@ -488,10 +490,19 @@ static int v9fs_at_to_dotl_flags(int flags)
* - ext4 (with dir_nlink feature enabled) sets nlink to 1 if a dir has more
* than EXT4_LINK_MAX (65000) links.
*
+ * In cacheless mode the server is the source of truth for nlink and the
+ * inode is going away immediately, so locally adjusting i_nlink buys
+ * nothing and races with concurrent metadata fetches that may already
+ * have observed the post-unlink value (nlink == 0).
This diff is incomplete. Download the complete patch.
fs/9p/vfs_inode_dotl.c
View fileThis diff is incomplete. Download the complete patch.
fs/9p/vfs_super.c
View fileThis diff is incomplete. Download the complete patch.
include/net/9p/client.h
View fileThis diff is incomplete. Download the complete patch.
net/9p/client.c
View fileThis diff is incomplete. Download the complete patch.
net/9p/trans_fd.c
View fileThis diff is incomplete. Download the complete patch.
net/9p/trans_rdma.c
View fileThis diff is incomplete. Download the complete patch.
net/9p/trans_usbg.c
View fileThis diff is incomplete. Download the complete patch.
net/9p/trans_virtio.c
View fileThis diff is incomplete. Download the complete patch.