[PATCH 41/52] fuse: Reschedule dax free work if too many EAGAIN attempts

From: Vivek Goyal
Date: Mon Dec 10 2018 - 12:15:46 EST


fuse_dax_free_memory() can be very cpu intensive in corner cases. For example,
if one inode has consumed all the memory and a setupmapping request is
pending, that means inode lock is held by request and worker thread will
not get lock for a while. And given there is only one inode consuming all
the dax ranges, all the attempts to acquire lock will fail.

So if there are too many inode lock failures (-EAGAIN), reschedule the
worker with a 10ms delay.

Signed-off-by: Vivek Goyal <vgoyal@xxxxxxxxxx>
---
fs/fuse/file.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index dbe3410a94d7..709747458335 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -3909,7 +3909,7 @@ int fuse_dax_free_one_mapping(struct fuse_conn *fc, struct inode *inode,
int fuse_dax_free_memory(struct fuse_conn *fc, unsigned long nr_to_free)
{
struct fuse_dax_mapping *dmap, *pos, *temp;
- int ret, nr_freed = 0;
+ int ret, nr_freed = 0, nr_eagain = 0;
u64 dmap_start = 0, window_offset = 0;
struct inode *inode = NULL;

@@ -3918,6 +3918,12 @@ int fuse_dax_free_memory(struct fuse_conn *fc, unsigned long nr_to_free)
if (nr_freed >= nr_to_free)
break;

+ if (nr_eagain > 20) {
+ queue_delayed_work(system_long_wq, &fc->dax_free_work,
+ msecs_to_jiffies(10));
+ return 0;
+ }
+
dmap = NULL;
spin_lock(&fc->lock);

@@ -3955,8 +3961,10 @@ int fuse_dax_free_memory(struct fuse_conn *fc, unsigned long nr_to_free)
}

/* Could not get inode lock. Try next element */
- if (ret == -EAGAIN)
+ if (ret == -EAGAIN) {
+ nr_eagain++;
continue;
+ }
nr_freed++;
}
return 0;
--
2.13.6