diff mbox series

[48/67] fscache: Implement "will_modify" parameter on fscache_use_cookie()

Message ID 163456933400.2614702.3593094196519659430.stgit@warthog.procyon.org.uk (mailing list archive)
State New, archived
Headers show
Series fscache: Rewrite index API and management system | expand

Commit Message

David Howells Oct. 18, 2021, 3:02 p.m. UTC
Implement the "will_modify" parameter passed to fscache_use_cookie().

Setting this to true will henceforth cause the affected object to be marked
as dirty on disk, subject to conflict resolution in the event that power
failure or a crash occurs or the filesystem operates in disconnected mode.

The dirty flag is removed when the cache object is discarded from memory.

A cache hook is provided to prepare for writing - and this can be used to
mark the object on disk.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/cachefiles/interface.c         |    3 +++
 fs/cachefiles/internal.h          |    2 +-
 fs/cachefiles/xattr.c             |   20 ++++++++++++++++++++
 fs/fscache/cookie.c               |   30 +++++++++++++++++++++++++++++-
 include/linux/fscache-cache.h     |    3 +++
 include/linux/fscache.h           |    2 ++
 include/trace/events/cachefiles.h |    4 ++--
 7 files changed, 60 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c
index 751b0fec4591..96f30eba585a 100644
--- a/fs/cachefiles/interface.c
+++ b/fs/cachefiles/interface.c
@@ -211,6 +211,8 @@  static void cachefiles_commit_object(struct cachefiles_object *object,
 {
 	bool update = false;
 
+	if (test_and_clear_bit(FSCACHE_COOKIE_LOCAL_WRITE, &object->cookie->flags))
+		update = true;
 	if (test_and_clear_bit(FSCACHE_COOKIE_NEEDS_UPDATE, &object->cookie->flags))
 		update = true;
 	if (update)
@@ -461,4 +463,5 @@  const struct fscache_cache_ops cachefiles_cache_ops = {
 	.invalidate_cookie	= cachefiles_invalidate_cookie,
 	.resize_cookie		= cachefiles_resize_cookie,
 	.begin_operation	= cachefiles_begin_operation,
+	.prepare_to_write	= cachefiles_prepare_to_write,
 };
diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h
index 1d3e37bca087..83cf2ca3a763 100644
--- a/fs/cachefiles/internal.h
+++ b/fs/cachefiles/internal.h
@@ -239,7 +239,7 @@  extern int cachefiles_check_auxdata(struct cachefiles_object *object,
 				    struct file *file);
 extern int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
 					  struct dentry *dentry);
-
+extern void cachefiles_prepare_to_write(struct fscache_cookie *cookie);
 
 /*
  * error handling
diff --git a/fs/cachefiles/xattr.c b/fs/cachefiles/xattr.c
index ba3d050a5174..30adca42883b 100644
--- a/fs/cachefiles/xattr.c
+++ b/fs/cachefiles/xattr.c
@@ -53,6 +53,8 @@  int cachefiles_set_object_xattr(struct cachefiles_object *object)
 	buf->zero_point		= 0;
 	buf->type		= CACHEFILES_COOKIE_TYPE_DATA;
 	buf->content		= object->content_info;
+	if (test_bit(FSCACHE_COOKIE_LOCAL_WRITE, &object->cookie->flags))
+		buf->content	= CACHEFILES_CONTENT_DIRTY;
 	if (len > 0)
 		memcpy(buf->data, fscache_get_aux(object->cookie), len);
 
@@ -145,3 +147,21 @@  int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
 	_leave(" = %d", ret);
 	return ret;
 }
+
+/*
+ * Stick a marker on the cache object to indicate that it's dirty.
+ */
+void cachefiles_prepare_to_write(struct fscache_cookie *cookie)
+{
+	const struct cred *saved_cred;
+	struct cachefiles_object *object = cookie->cache_priv;
+	struct cachefiles_cache *cache = object->volume->cache;
+
+	_enter("c=%08x", object->cookie->debug_id);
+
+	if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
+		cachefiles_begin_secure(cache, &saved_cred);
+		cachefiles_set_object_xattr(object);
+		cachefiles_end_secure(cache, saved_cred);
+	}
+}
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c
index 70bfbd269652..1420027cfe97 100644
--- a/fs/fscache/cookie.c
+++ b/fs/fscache/cookie.c
@@ -402,12 +402,20 @@  struct fscache_cookie *__fscache_acquire_cookie(
 }
 EXPORT_SYMBOL(__fscache_acquire_cookie);
 
+/*
+ * Prepare a cache object to be written to.
+ */
+static void fscache_prepare_to_write(struct fscache_cookie *cookie)
+{
+	cookie->volume->cache->ops->prepare_to_write(cookie);
+}
+
 /*
  * Look up a cookie to the cache.
  */
 static void fscache_lookup_cookie(struct fscache_cookie *cookie)
 {
-	bool changed_stage = false, need_withdraw = false;
+	bool changed_stage = false, need_withdraw = false, prep_write = false;
 
 	_enter("");
 
@@ -429,6 +437,7 @@  static void fscache_lookup_cookie(struct fscache_cookie *cookie)
 
 	spin_lock(&cookie->lock);
 	if (cookie->stage != FSCACHE_COOKIE_STAGE_RELINQUISHING) {
+		prep_write = test_bit(FSCACHE_COOKIE_LOCAL_WRITE, &cookie->flags);
 		__fscache_set_cookie_stage(cookie, FSCACHE_COOKIE_STAGE_ACTIVE);
 		fscache_see_cookie(cookie, fscache_cookie_see_active);
 		changed_stage = true;
@@ -436,6 +445,8 @@  static void fscache_lookup_cookie(struct fscache_cookie *cookie)
 	spin_unlock(&cookie->lock);
 	if (changed_stage)
 		wake_up_cookie_stage(cookie);
+	if (prep_write)
+		fscache_prepare_to_write(cookie);
 
 out:
 	fscache_end_cookie_access(cookie, fscache_access_lookup_cookie_end);
@@ -467,6 +478,10 @@  void __fscache_use_cookie(struct fscache_cookie *cookie, bool will_modify)
 	stage = cookie->stage;
 	switch (stage) {
 	case FSCACHE_COOKIE_STAGE_QUIESCENT:
+		if (will_modify) {
+			set_bit(FSCACHE_COOKIE_LOCAL_WRITE, &cookie->flags);
+			set_bit(FSCACHE_COOKIE_DO_PREP_TO_WRITE, &cookie->flags);
+		}
 		if (!fscache_begin_volume_access(cookie->volume,
 						 fscache_access_lookup_cookie))
 			break;
@@ -484,8 +499,18 @@  void __fscache_use_cookie(struct fscache_cookie *cookie, bool will_modify)
 
 	case FSCACHE_COOKIE_STAGE_LOOKING_UP:
 	case FSCACHE_COOKIE_STAGE_CREATING:
+		if (will_modify)
+			set_bit(FSCACHE_COOKIE_LOCAL_WRITE, &cookie->flags);
+		break;
 	case FSCACHE_COOKIE_STAGE_ACTIVE:
 	case FSCACHE_COOKIE_STAGE_INVALIDATING:
+		if (will_modify &&
+		    !test_and_set_bit(FSCACHE_COOKIE_LOCAL_WRITE, &cookie->flags)) {
+			set_bit(FSCACHE_COOKIE_DO_PREP_TO_WRITE, &cookie->flags);
+			queue = true;
+		}
+		break;
+
 	case FSCACHE_COOKIE_STAGE_FAILED:
 	case FSCACHE_COOKIE_STAGE_WITHDRAWING:
 		break;
@@ -551,6 +576,8 @@  static void __fscache_cookie_worker(struct fscache_cookie *cookie)
 again:
 	switch (READ_ONCE(cookie->stage)) {
 	case FSCACHE_COOKIE_STAGE_ACTIVE:
+		if (test_and_clear_bit(FSCACHE_COOKIE_DO_PREP_TO_WRITE, &cookie->flags))
+			fscache_prepare_to_write(cookie);
 		break;
 
 	case FSCACHE_COOKIE_STAGE_LOOKING_UP:
@@ -591,6 +618,7 @@  static void __fscache_cookie_worker(struct fscache_cookie *cookie)
 		clear_bit(FSCACHE_COOKIE_NEEDS_UPDATE, &cookie->flags);
 		clear_bit(FSCACHE_COOKIE_DO_WITHDRAW, &cookie->flags);
 		clear_bit(FSCACHE_COOKIE_DO_COMMIT, &cookie->flags);
+		clear_bit(FSCACHE_COOKIE_DO_PREP_TO_WRITE, &cookie->flags);
 		set_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags);
 		fscache_set_cookie_stage(cookie, FSCACHE_COOKIE_STAGE_QUIESCENT);
 		break;
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h
index 2e7265e24df6..889ae37fae0f 100644
--- a/include/linux/fscache-cache.h
+++ b/include/linux/fscache-cache.h
@@ -76,6 +76,9 @@  struct fscache_cache_ops {
 	/* Begin an operation for the netfs lib */
 	bool (*begin_operation)(struct netfs_cache_resources *cres,
 				enum fscache_want_stage want_stage);
+
+	/* Prepare to write to a live cache object */
+	void (*prepare_to_write)(struct fscache_cookie *cookie);
 };
 
 static inline enum fscache_cache_state fscache_cache_state(const struct fscache_cache *cache)
diff --git a/include/linux/fscache.h b/include/linux/fscache.h
index 8148193045cd..8ab691e52cc5 100644
--- a/include/linux/fscache.h
+++ b/include/linux/fscache.h
@@ -125,10 +125,12 @@  struct fscache_cookie {
 #define FSCACHE_COOKIE_NEEDS_UPDATE	4		/* T if attrs have been updated */
 #define FSCACHE_COOKIE_HAS_BEEN_CACHED	5		/* T if cookie needs withdraw-on-relinq */
 #define FSCACHE_COOKIE_DISABLED		6		/* T if cookie has been disabled */
+#define FSCACHE_COOKIE_LOCAL_WRITE	7		/* T if cookie has been modified locally */
 #define FSCACHE_COOKIE_NACC_ELEVATED	8		/* T if n_accesses is incremented */
 #define FSCACHE_COOKIE_DO_RELINQUISH	9		/* T if this cookie needs relinquishment */
 #define FSCACHE_COOKIE_DO_WITHDRAW	10		/* T if this cookie needs withdrawing */
 #define FSCACHE_COOKIE_DO_COMMIT	11		/* T if this cookie needs committing */
+#define FSCACHE_COOKIE_DO_PREP_TO_WRITE	12		/* T if cookie needs write preparation */
 
 	enum fscache_cookie_stage	stage;
 	u8				advice;		/* FSCACHE_ADV_* */
diff --git a/include/trace/events/cachefiles.h b/include/trace/events/cachefiles.h
index a7b31b248f2d..11447b20fc83 100644
--- a/include/trace/events/cachefiles.h
+++ b/include/trace/events/cachefiles.h
@@ -340,7 +340,7 @@  TRACE_EVENT(cachefiles_mark_inactive,
 TRACE_EVENT(cachefiles_coherency,
 	    TP_PROTO(struct cachefiles_object *obj,
 		     ino_t ino,
-		     int content,
+		     enum cachefiles_content content,
 		     enum cachefiles_coherency_trace why),
 
 	    TP_ARGS(obj, ino, content, why),
@@ -349,7 +349,7 @@  TRACE_EVENT(cachefiles_coherency,
 	    TP_STRUCT__entry(
 		    __field(unsigned int,			obj	)
 		    __field(enum cachefiles_coherency_trace,	why	)
-		    __field(int,				content	)
+		    __field(enum cachefiles_content,		content	)
 		    __field(u64,				ino	)
 			     ),