Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F115236253
D37040.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D37040.id.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D37040: fusefs: fix VOP_ADVLOCK with SEEK_END
Attached
Detach File
Event Timeline
Log In to Comment