ANDROID: fuse-bpf: Add partial flock support

This adds passthrough support for flock on fuse-bpf files. It does not
give any control via a bpf filter. The flock will act as though it was
taken on the lower file.

Bug: 289882899
Bug: 296641006
Test: fuse_test -t32 (flock_test)
Signed-off-by: Daniel Rosenberg <drosen@google.com>
(cherry picked from https://android-review.googlesource.com/q/commit:6d6ee09bb74fe3b86cfdc87da6f7a40c82f7b36d)
Merged-In: Iba0b9630766cedbd3195532c5e929891593cfe30
Change-Id: Iba0b9630766cedbd3195532c5e929891593cfe30
diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c
index 5665ff7..5703be7 100644
--- a/fs/fuse/backing.c
+++ b/fs/fuse/backing.c
@@ -991,6 +991,20 @@
 	return ERR_PTR(fwio->ret);
 }
 
+int fuse_file_flock_backing(struct file *file, int cmd, struct file_lock *fl)
+{
+	struct fuse_file *ff = file->private_data;
+	struct file *backing_file = ff->backing_file;
+	int error;
+
+	fl->fl_file = backing_file;
+	if (backing_file->f_op->flock)
+		error = backing_file->f_op->flock(backing_file, cmd, fl);
+	else
+		error = locks_lock_file_wait(backing_file, fl);
+	return error;
+}
+
 ssize_t fuse_backing_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	int ret;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 3963816..39a00074 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -2663,12 +2663,18 @@
 {
 	struct inode *inode = file_inode(file);
 	struct fuse_conn *fc = get_fuse_conn(inode);
+	struct fuse_file *ff = file->private_data;
 	int err;
 
+#ifdef CONFIG_FUSE_BPF
+	/* TODO - this is simply passthrough, not a proper BPF filter */
+	if (ff->backing_file)
+		return fuse_file_flock_backing(file, cmd, fl);
+#endif
+
 	if (fc->no_flock) {
 		err = locks_lock_file_wait(file, fl);
 	} else {
-		struct fuse_file *ff = file->private_data;
 
 		/* emulate flock with POSIX locks */
 		ff->flock = true;
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 31f6fbbd..f7d214b 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1634,6 +1634,7 @@
 void *fuse_file_write_iter_finalize(struct fuse_bpf_args *fa,
 		struct kiocb *iocb, struct iov_iter *from);
 
+int fuse_file_flock_backing(struct file *file, int cmd, struct file_lock *fl);
 ssize_t fuse_backing_mmap(struct file *file, struct vm_area_struct *vma);
 
 int fuse_file_fallocate_initialize(struct fuse_bpf_args *fa,
diff --git a/tools/testing/selftests/filesystems/fuse/fuse_test.c b/tools/testing/selftests/filesystems/fuse/fuse_test.c
index c23f75b..a1a0929 100644
--- a/tools/testing/selftests/filesystems/fuse/fuse_test.c
+++ b/tools/testing/selftests/filesystems/fuse/fuse_test.c
@@ -12,6 +12,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <sys/file.h>
 #include <sys/inotify.h>
 #include <sys/mman.h>
 #include <sys/mount.h>
@@ -1336,6 +1337,50 @@
 	return result;
 }
 
+static int flock_test(const char *mount_dir)
+{
+	const char *file = "file";
+	int result = TEST_FAILURE;
+	int src_fd = -1;
+	int fuse_dev = -1;
+	int fd = -1, fd2 = -1;
+	int backing_fd = -1;
+	char *addr = NULL;
+
+	TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
+	     src_fd != -1);
+	TESTEQUAL(mount_fuse(mount_dir, -1, src_fd, &fuse_dev), 0);
+	TEST(fd = s_open(s_path(s(mount_dir), s(file)),
+			 O_CREAT | O_RDWR | O_CLOEXEC, 0777),
+	     fd != -1);
+	TEST(fd2 = s_open(s_path(s(mount_dir), s(file)),
+				 O_RDWR | O_CLOEXEC, 0777),
+		     fd2 != -1);
+	TESTSYSCALL(flock(fd, LOCK_EX | LOCK_NB));
+	TESTCONDERR((flock(fd2, LOCK_EX | LOCK_NB)) == -1);
+	TESTCOND(errno == EAGAIN);
+	TESTSYSCALL(flock(fd, LOCK_UN));
+	TESTSYSCALL(flock(fd2, LOCK_EX | LOCK_NB));
+	TEST(backing_fd = s_open(s_path(s(ft_src), s(file)),
+				 O_RDONLY | O_CLOEXEC),
+				 backing_fd != -1);
+	TESTCONDERR((flock(backing_fd, LOCK_EX | LOCK_NB)) == -1);
+	TESTCOND(errno == EAGAIN);
+	close(fd2);
+	fd2 = 0;
+	TESTSYSCALL(flock(backing_fd, LOCK_EX | LOCK_NB));
+
+	result = TEST_SUCCESS;
+out:
+	close(fd);
+	close(fd2);
+	close(backing_fd);
+	umount(mount_dir);
+	close(fuse_dev);
+	close(src_fd);
+	return result;
+}
+
 static int readdir_perms_test(const char *mount_dir)
 {
 	int result = TEST_FAILURE;
@@ -2091,6 +2136,7 @@
 		MAKE_TEST(bpf_test_no_readdirplus_without_nodeid),
 		MAKE_TEST(bpf_test_revalidate_handle_backing_fd),
 		MAKE_TEST(bpf_test_lookup_postfilter),
+		MAKE_TEST(flock_test),
 	};
 #undef MAKE_TEST