Page MenuHomeFreeBSD

D37040.id.diff
No OneTemporary

D37040.id.diff

diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -478,7 +478,9 @@
struct fuse_dispatcher fdi;
struct fuse_lk_in *fli;
struct fuse_lk_out *flo;
+ struct vattr vattr;
enum fuse_opcode op;
+ off_t size, start;
int dataflags, err;
int flags = ap->a_flags;
@@ -513,6 +515,33 @@
vn_lock(vp, LK_SHARED | LK_RETRY);
+ switch (fl->l_whence) {
+ case SEEK_SET:
+ case SEEK_CUR:
+ /*
+ * Caller is responsible for adding any necessary offset
+ * when SEEK_CUR is used.
+ */
+ start = fl->l_start;
+ break;
+
+ case SEEK_END:
+ err = fuse_internal_getattr(vp, &vattr, cred, td);
+ if (err)
+ goto out;
+ size = vattr.va_size;
+ if (size > OFF_MAX ||
+ (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) {
+ err = EOVERFLOW;
+ goto out;
+ }
+ start = size + fl->l_start;
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
err = fuse_filehandle_get_anyflags(vp, &fufh, cred, pid);
if (err)
goto out;
@@ -523,9 +552,9 @@
fli = fdi.indata;
fli->fh = fufh->fh_id;
fli->owner = td->td_proc->p_pid;
- fli->lk.start = fl->l_start;
+ fli->lk.start = start;
if (fl->l_len != 0)
- fli->lk.end = fl->l_start + fl->l_len - 1;
+ fli->lk.end = start + fl->l_len - 1;
else
fli->lk.end = INT64_MAX;
fli->lk.type = fl->l_type;
diff --git a/tests/sys/fs/fusefs/locks.cc b/tests/sys/fs/fusefs/locks.cc
--- a/tests/sys/fs/fusefs/locks.cc
+++ b/tests/sys/fs/fusefs/locks.cc
@@ -420,6 +420,71 @@
leak(fd);
}
+/*
+ * F_GETLK with SEEK_END
+ */
+TEST_F(Getlk, seek_end)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ uint64_t ino = 42;
+ struct flock fl;
+ int fd;
+ pid_t pid = getpid();
+
+ expect_lookup(RELPATH, ino, 1024);
+ expect_open(ino, 0, 1);
+ EXPECT_CALL(*m_mock, process(
+ ResultOf([=](auto in) {
+ return (in.header.opcode == FUSE_GETLK &&
+ in.header.nodeid == ino &&
+ in.body.getlk.fh == FH &&
+ /*
+ * Though it seems useless, libfuse expects the
+ * owner and pid fields to be set during
+ * FUSE_GETLK.
+ */
+ in.body.getlk.owner == (uint32_t)pid &&
+ in.body.getlk.lk.pid == (uint64_t)pid &&
+ in.body.getlk.lk.start == 512 &&
+ in.body.getlk.lk.end == 1023 &&
+ in.body.getlk.lk.type == F_RDLCK);
+ }, Eq(true)),
+ _)
+ ).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
+ SET_OUT_HEADER_LEN(out, getlk);
+ out.body.getlk.lk.start = 400;
+ out.body.getlk.lk.end = 499;
+ out.body.getlk.lk.type = F_WRLCK;
+ out.body.getlk.lk.pid = (uint32_t)pid + 1;
+ })));
+
+ fd = open(FULLPATH, O_RDWR);
+ ASSERT_LE(0, fd) << strerror(errno);
+ ASSERT_NE(-1, lseek(fd, 500, SEEK_SET));
+
+ fl.l_start = -512;
+ fl.l_len = 512;
+ fl.l_pid = 42;
+ fl.l_type = F_RDLCK;
+ fl.l_whence = SEEK_END;
+ fl.l_sysid = 0;
+ ASSERT_NE(-1, fcntl(fd, F_GETLK, &fl)) << strerror(errno);
+
+ /*
+ * After a successful F_GETLK request, the value of l_whence is
+ * SEEK_SET.
+ */
+ EXPECT_EQ(F_WRLCK, fl.l_type);
+ EXPECT_EQ(fl.l_pid, pid + 1);
+ EXPECT_EQ(fl.l_start, 400);
+ EXPECT_EQ(fl.l_len, 100);
+ EXPECT_EQ(fl.l_whence, SEEK_SET);
+ ASSERT_EQ(fl.l_sysid, 0);
+
+ leak(fd);
+}
+
/*
* If the fuse filesystem does not support posix file locks, then the kernel
* should fall back to local locks.
@@ -525,6 +590,63 @@
leak(fd);
}
+/* Set a new lock with FUSE_SETLK, using SEEK_CUR for l_whence */
+TEST_F(Setlk, set_seek_cur)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ uint64_t ino = 42;
+ struct flock fl;
+ int fd;
+ pid_t pid = getpid();
+
+ expect_lookup(RELPATH, ino, 1024);
+ expect_open(ino, 0, 1);
+ expect_setlk(ino, pid, 500, 509, F_RDLCK, 0);
+
+ fd = open(FULLPATH, O_RDWR);
+ ASSERT_LE(0, fd) << strerror(errno);
+ ASSERT_NE(-1, lseek(fd, 500, SEEK_SET));
+
+ fl.l_start = 0;
+ fl.l_len = 10;
+ fl.l_pid = 0;
+ fl.l_type = F_RDLCK;
+ fl.l_whence = SEEK_CUR;
+ fl.l_sysid = 0;
+ ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno);
+
+ leak(fd);
+}
+
+/* Set a new lock with FUSE_SETLK, using SEEK_END for l_whence */
+TEST_F(Setlk, set_seek_end)
+{
+ const char FULLPATH[] = "mountpoint/some_file.txt";
+ const char RELPATH[] = "some_file.txt";
+ uint64_t ino = 42;
+ struct flock fl;
+ int fd;
+ pid_t pid = getpid();
+
+ expect_lookup(RELPATH, ino, 1024);
+ expect_open(ino, 0, 1);
+ expect_setlk(ino, pid, 1000, 1009, F_RDLCK, 0);
+
+ fd = open(FULLPATH, O_RDWR);
+ ASSERT_LE(0, fd) << strerror(errno);
+
+ fl.l_start = -24;
+ fl.l_len = 10;
+ fl.l_pid = 0;
+ fl.l_type = F_RDLCK;
+ fl.l_whence = SEEK_END;
+ fl.l_sysid = 0;
+ ASSERT_NE(-1, fcntl(fd, F_SETLK, &fl)) << strerror(errno);
+
+ leak(fd);
+}
+
/* Fail to set a new lock with FUSE_SETLK due to a conflict */
TEST_F(Setlk, eagain)
{
diff --git a/tests/sys/fs/fusefs/mockfs.cc b/tests/sys/fs/fusefs/mockfs.cc
--- a/tests/sys/fs/fusefs/mockfs.cc
+++ b/tests/sys/fs/fusefs/mockfs.cc
@@ -229,6 +229,18 @@
case FUSE_FSYNCDIR:
printf(" flags=%#x", in.body.fsyncdir.fsync_flags);
break;
+ case FUSE_GETLK:
+ printf(" fh=%#" PRIx64
+ " type=%u pid=%u",
+ in.body.getlk.fh,
+ in.body.getlk.lk.type,
+ in.body.getlk.lk.pid);
+ if (verbosity >= 2) {
+ printf(" range=[%" PRIi64 ":%" PRIi64 "]",
+ in.body.getlk.lk.start,
+ in.body.getlk.lk.end);
+ }
+ break;
case FUSE_INTERRUPT:
printf(" unique=%" PRIu64, in.body.interrupt.unique);
break;
@@ -338,7 +350,7 @@
in.body.setlk.lk.type,
in.body.setlk.lk.pid);
if (verbosity >= 2) {
- printf(" range=[%" PRIu64 "-%" PRIu64 "]",
+ printf(" range=[%" PRIi64 ":%" PRIi64 "]",
in.body.setlk.lk.start,
in.body.setlk.lk.end);
}

File Metadata

Mime Type
text/plain
Expires
Tue, Apr 22, 5:23 PM (38 m, 18 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17704747
Default Alt Text
D37040.id.diff (5 KB)

Event Timeline