ANDROID: fuse: Adjust Passthrough for writeback cache

This adjusts some tracking to allow passthrough and writeback cache to
co-exist with eachother

Change-Id: I5b8b3940a8c096cd3598d7c188439c6c636c01a1
Bug: 372951405
Fixes: 3ae410445f ("ANDROID: fuse: Allow passthrough and not passthrough")
test: atest android.scopedstorage.cts.general.ScopedStorageDeviceTest
Signed-off-by: Daniel Rosenberg <drosen@google.com>
This commit is contained in:
Daniel Rosenberg
2025-02-04 17:14:23 -08:00
parent 09db6ed78d
commit e878b35d3d
4 changed files with 42 additions and 6 deletions
+1
View File
@@ -3539,6 +3539,7 @@ void fuse_init_file_inode(struct inode *inode, unsigned int flags)
INIT_LIST_HEAD(&fi->queued_writes);
fi->writectr = 0;
fi->iocachectr = 0;
fi->iopassctr = 0;
init_waitqueue_head(&fi->page_waitq);
init_waitqueue_head(&fi->direct_io_waitq);
fi->writepages = RB_ROOT;
+4 -1
View File
@@ -195,6 +195,9 @@ struct fuse_inode {
/** Number of files/maps using page cache */
int iocachectr;
/* Number of files using passthrough */
int iopassctr;
/* Waitq for writepage completion */
wait_queue_head_t page_waitq;
@@ -328,7 +331,7 @@ struct fuse_file {
wait_queue_head_t poll_wait;
/** Does file hold a fi->iocachectr refcount? */
enum { IOM_NONE, IOM_CACHED, IOM_UNCACHED } iomode;
enum { IOM_NONE, IOM_CACHED, IOM_UNCACHED, IOM_PASSTHROUGH } iomode;
#ifdef CONFIG_FUSE_PASSTHROUGH
/** Reference to backing file in passthrough mode */
+1
View File
@@ -184,6 +184,7 @@ static void fuse_evict_inode(struct inode *inode)
}
if (S_ISREG(inode->i_mode) && !fuse_is_bad(inode)) {
WARN_ON(fi->iocachectr != 0);
WARN_ON(fi->iopassctr != 0);
WARN_ON(!list_empty(&fi->write_files));
WARN_ON(!list_empty(&fi->queued_writes));
}
+36 -5
View File
@@ -62,6 +62,7 @@ int fuse_file_cached_io_open(struct inode *inode, struct fuse_file *ff)
#endif
WARN_ON(ff->iomode == IOM_UNCACHED);
WARN_ON(ff->iomode == IOM_PASSTHROUGH);
if (ff->iomode == IOM_NONE) {
ff->iomode = IOM_CACHED;
if (fi->iocachectr == 0)
@@ -85,7 +86,7 @@ static void fuse_file_cached_io_release(struct fuse_file *ff,
spin_unlock(&fi->lock);
}
/* Start strictly uncached io mode where cache access is not allowed */
/* Start strictly uncached io mode where cache access is not allowed if not in passthrough mode */
int fuse_inode_uncached_io_start(struct fuse_inode *fi, struct fuse_backing *fb)
{
struct fuse_backing *oldfb;
@@ -98,11 +99,14 @@ int fuse_inode_uncached_io_start(struct fuse_inode *fi, struct fuse_backing *fb)
err = -EBUSY;
goto unlock;
}
if (fi->iocachectr > 0) {
if (!fb && fi->iocachectr > 0) {
err = -ETXTBSY;
goto unlock;
}
fi->iocachectr--;
if (fb)
fi->iopassctr++;
else
fi->iocachectr--;
/* fuse inode holds a single refcount of backing file */
if (fb && !oldfb) {
@@ -129,7 +133,7 @@ static int fuse_file_uncached_io_open(struct inode *inode,
return err;
WARN_ON(ff->iomode != IOM_NONE);
ff->iomode = IOM_UNCACHED;
ff->iomode = IOM_PASSTHROUGH;
return 0;
}
@@ -158,6 +162,30 @@ static void fuse_file_uncached_io_release(struct fuse_file *ff,
fuse_inode_uncached_io_end(fi);
}
static void fuse_inode_passthrough_io_end(struct fuse_inode *fi)
{
struct fuse_backing *oldfb = NULL;
spin_lock(&fi->lock);
WARN_ON(fi->iopassctr == 0);
fi->iopassctr--;
if (!fi->iopassctr) {
oldfb = fuse_inode_backing_set(fi, NULL);
}
spin_unlock(&fi->lock);
if (oldfb)
fuse_backing_put(oldfb);
}
/* Drop uncached_io reference from passthrough open */
static void fuse_file_passthrough_io_release(struct fuse_file *ff,
struct fuse_inode *fi)
{
WARN_ON(ff->iomode != IOM_PASSTHROUGH);
ff->iomode = IOM_NONE;
fuse_inode_passthrough_io_end(fi);
}
/*
* Open flags that are allowed in combination with FOPEN_PASSTHROUGH.
* A combination of FOPEN_PASSTHROUGH and FOPEN_DIRECT_IO means that read/write
@@ -167,7 +195,7 @@ static void fuse_file_uncached_io_release(struct fuse_file *ff,
*/
#define FOPEN_PASSTHROUGH_MASK \
(FOPEN_PASSTHROUGH | FOPEN_DIRECT_IO | FOPEN_PARALLEL_DIRECT_WRITES | \
FOPEN_NOFLUSH)
FOPEN_NOFLUSH | FOPEN_KEEP_CACHE)
static int fuse_file_passthrough_open(struct inode *inode, struct file *file)
{
@@ -277,5 +305,8 @@ void fuse_file_io_release(struct fuse_file *ff, struct inode *inode)
case IOM_CACHED:
fuse_file_cached_io_release(ff, fi);
break;
case IOM_PASSTHROUGH:
fuse_file_passthrough_io_release(ff, fi);
break;
}
}