linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Miklos Szeredi <mszeredi@redhat.com>
To: linux-fsdevel@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Subject: [PATCH 6/9] fuse: add readdir cache version
Date: Fri, 28 Sep 2018 17:42:31 +0200	[thread overview]
Message-ID: <20180928154234.19270-7-mszeredi@redhat.com> (raw)
In-Reply-To: <20180928154234.19270-1-mszeredi@redhat.com>

Allow the cache to be invalidated when page(s) have gone missing.  In this
case increment the version of the cache and reset to an empty state.

Add a version number to the directory stream in struct fuse_file as well,
indicating the version of the cache it's supposed to be reading.  If the
cache version doesn't match the stream's version, then reset the stream to
the beginning of the cache.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
---
 fs/fuse/fuse_i.h  |  7 +++++++
 fs/fuse/inode.c   |  1 +
 fs/fuse/readdir.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 116fe14053f1..ef018ea5bcd9 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -114,6 +114,9 @@ struct fuse_inode {
 		/** position at end of cache (position of next entry) */
 		loff_t pos;
 
+		/** version of the cache */
+		u64 version;
+
 		/** protects above fields */
 		spinlock_t lock;
 	} rdc;
@@ -176,6 +179,10 @@ struct fuse_file {
 
 		/** Offset in cache */
 		loff_t cache_off;
+
+		/** Version of cache we are reading */
+		u64 version;
+
 	} readdir;
 
 	/** RB node to be linked on fuse_conn->polled_files */
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 03d8105a851d..6d0a87308f86 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -104,6 +104,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
 	fi->rdc.cached = false;
 	fi->rdc.size = 0;
 	fi->rdc.pos = 0;
+	fi->rdc.version = 0;
 	mutex_init(&fi->mutex);
 	fi->forget = fuse_alloc_forget();
 	if (!fi->forget) {
diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c
index e6ae82f2df9d..edb445c4cfbd 100644
--- a/fs/fuse/readdir.c
+++ b/fs/fuse/readdir.c
@@ -34,6 +34,7 @@ static void fuse_add_dirent_to_cache(struct file *file,
 	pgoff_t index;
 	struct page *page;
 	loff_t size;
+	u64 version;
 	unsigned int offset;
 	void *addr;
 
@@ -46,6 +47,7 @@ static void fuse_add_dirent_to_cache(struct file *file,
 		spin_unlock(&fi->rdc.lock);
 		return;
 	}
+	version = fi->rdc.version;
 	size = fi->rdc.size;
 	offset = size & ~PAGE_MASK;
 	index = size >> PAGE_SHIFT;
@@ -67,7 +69,8 @@ static void fuse_add_dirent_to_cache(struct file *file,
 
 	spin_lock(&fi->rdc.lock);
 	/* Raced with another readdir */
-	if (fi->rdc.size != size || WARN_ON(fi->rdc.pos != pos))
+	if (fi->rdc.version != version || fi->rdc.size != size ||
+	    WARN_ON(fi->rdc.pos != pos))
 		goto unlock;
 
 	addr = kmap_atomic(page);
@@ -394,6 +397,14 @@ static enum fuse_parse_result fuse_parse_cache(struct fuse_file *ff,
 	return res;
 }
 
+static void fuse_rdc_reset(struct fuse_inode *fi)
+{
+	fi->rdc.cached = false;
+	fi->rdc.version++;
+	fi->rdc.size = 0;
+	fi->rdc.pos = 0;
+}
+
 #define UNCACHED 1
 
 static int fuse_readdir_cached(struct file *file, struct dir_context *ctx)
@@ -419,6 +430,21 @@ static int fuse_readdir_cached(struct file *file, struct dir_context *ctx)
 		spin_unlock(&fi->rdc.lock);
 		return UNCACHED;
 	}
+	/*
+	 * If cache version changed since the last getdents() call, then reset
+	 * the cache stream.
+	 */
+	if (ff->readdir.version != fi->rdc.version) {
+		ff->readdir.pos = 0;
+		ff->readdir.cache_off = 0;
+	}
+	/*
+	 * If at the beginning of the cache, than reset version to
+	 * current.
+	 */
+	if (ff->readdir.pos == 0)
+		ff->readdir.version = fi->rdc.version;
+
 	WARN_ON(fi->rdc.size < ff->readdir.cache_off);
 
 	index = ff->readdir.cache_off >> PAGE_SHIFT;
@@ -435,13 +461,30 @@ static int fuse_readdir_cached(struct file *file, struct dir_context *ctx)
 
 	page = find_get_page_flags(file->f_mapping, index,
 				   FGP_ACCESSED | FGP_LOCK);
+	spin_lock(&fi->rdc.lock);
 	if (!page) {
 		/*
 		 * Uh-oh: page gone missing, cache is useless
 		 */
+		if (fi->rdc.version == ff->readdir.version)
+			fuse_rdc_reset(fi);
+		spin_unlock(&fi->rdc.lock);
 		return UNCACHED;
 	}
 
+	/* Make sure it's still the same version after getting the page. */
+	if (ff->readdir.version != fi->rdc.version) {
+		spin_unlock(&fi->rdc.lock);
+		unlock_page(page);
+		put_page(page);
+		goto retry;
+	}
+	spin_unlock(&fi->rdc.lock);
+
+	/*
+	 * Contents of the page are now protected against changing by holding
+	 * the page lock.
+	 */
 	addr = kmap(page);
 	res = fuse_parse_cache(ff, addr, size, ctx);
 	kunmap(page);
-- 
2.14.3

  parent reply	other threads:[~2018-09-28 22:07 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-09-28 15:42 [PATCH 0/9] fuse: readdir caching Miklos Szeredi
2018-09-28 15:42 ` [PATCH 1/9] fuse: split out readdir.c Miklos Szeredi
2018-09-28 15:42 ` [PATCH 2/9] fuse: add FOPEN_CACHE_DIR Miklos Szeredi
2018-09-28 15:42 ` [PATCH 3/9] fuse: extract fuse_emit() helper Miklos Szeredi
2018-09-28 15:42 ` [PATCH 4/9] fuse: allow caching readdir Miklos Szeredi
2018-09-28 16:42   ` Matthew Wilcox
2018-09-28 15:42 ` [PATCH 5/9] fuse: allow using readdir cache Miklos Szeredi
2018-09-28 15:42 ` Miklos Szeredi [this message]
2018-09-28 15:42 ` [PATCH 7/9] fuse: use mtime for readdir cache verification Miklos Szeredi
2018-09-28 15:42 ` [PATCH 8/9] fuse: use iversion " Miklos Szeredi
2018-09-28 15:42 ` [PATCH 9/9] fuse: reduce size of struct fuse_inode Miklos Szeredi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180928154234.19270-7-mszeredi@redhat.com \
    --to=mszeredi@redhat.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).