From owner-svn-src-projects@freebsd.org Wed Apr 17 23:32:40 2019 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id B9FBC157CAD9 for ; Wed, 17 Apr 2019 23:32:40 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 627B469A9A; Wed, 17 Apr 2019 23:32:40 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 35993E73D; Wed, 17 Apr 2019 23:32:40 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x3HNWeuu092606; Wed, 17 Apr 2019 23:32:40 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x3HNWdpT092601; Wed, 17 Apr 2019 23:32:39 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201904172332.x3HNWdpT092601@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers Date: Wed, 17 Apr 2019 23:32:39 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r346339 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Group: projects X-SVN-Commit-Author: asomers X-SVN-Commit-Paths: in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Commit-Revision: 346339 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 627B469A9A X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.98 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.98)[-0.984,0]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US] X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 17 Apr 2019 23:32:41 -0000 Author: asomers Date: Wed Apr 17 23:32:38 2019 New Revision: 346339 URL: https://svnweb.freebsd.org/changeset/base/346339 Log: fusefs: WIP making FUSE operations interruptible The fuse protocol includes a FUSE_INTERRUPT operation that the client can send to the server to indicate that it wants to abort an in-progress operation. It's required to interrupt any syscall that is blocking on a fuse operation. This commit adds basic FUSE_INTERRUPT support. If a process receives any signal while it's blocking on a FUSE operation, it will send a FUSE_INTERRUPT and wait for the original operation to complete. But there is still much to do: * The current code will leak memory if the server ignores FUSE_INTERRUPT, which many do. It will also leak memory if the server completes the original operation before it receives the FUSE_INTERRUPT. * An interrupted read(2) will incorrectly appear to be successful. * fusefs should return immediately for fatal signals. * Operations that haven't been sent to the server yet should be aborted without sending FUSE_INTERRUPT. * Test coverage should be better. * It would be great if write operations could be made restartable. That would require delaying uiomove until the last possible moment, which would be sometime during fuse_device_read. PR: 236530 Sponsored by: The FreeBSD Foundation Modified: projects/fuse2/sys/fs/fuse/fuse_device.c projects/fuse2/sys/fs/fuse/fuse_io.c projects/fuse2/sys/fs/fuse/fuse_ipc.c projects/fuse2/sys/fs/fuse/fuse_ipc.h projects/fuse2/tests/sys/fs/fusefs/interrupt.cc projects/fuse2/tests/sys/fs/fusefs/mockfs.cc Modified: projects/fuse2/sys/fs/fuse/fuse_device.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_device.c Wed Apr 17 23:09:06 2019 (r346338) +++ projects/fuse2/sys/fs/fuse/fuse_device.c Wed Apr 17 23:32:38 2019 (r346339) @@ -346,8 +346,8 @@ fuse_ohead_audit(struct fuse_out_header *ohead, struct return (0); } -SDT_PROBE_DEFINE1(fuse, , device, fuse_device_write_bumped_into_callback, - "uint64_t"); +SDT_PROBE_DEFINE1(fuse, , device, fuse_device_write_missing_ticket, "uint64_t"); +SDT_PROBE_DEFINE1(fuse, , device, fuse_device_write_found, "struct fuse_ticket*"); /* * fuse_device_write first reads the header sent by the daemon. * If that's OK, looks up ticket/callback node by the unique id seen in header. @@ -393,10 +393,9 @@ fuse_device_write(struct cdev *dev, struct uio *uio, i fuse_lck_mtx_lock(data->aw_mtx); TAILQ_FOREACH_SAFE(tick, &data->aw_head, tk_aw_link, x_tick) { - SDT_PROBE1(fuse, , device, - fuse_device_write_bumped_into_callback, - tick->tk_unique); if (tick->tk_unique == ohead.unique) { + SDT_PROBE1(fuse, , device, fuse_device_write_found, + tick); found = 1; fuse_aw_remove(tick); break; @@ -432,8 +431,8 @@ fuse_device_write(struct cdev *dev, struct uio *uio, i fuse_ticket_drop(tick); } else { /* no callback at all! */ - SDT_PROBE2(fuse, , device, trace, 1, - "erhm, no handler for this response"); + SDT_PROBE1(fuse, , device, fuse_device_write_missing_ticket, + ohead.unique); err = EINVAL; } Modified: projects/fuse2/sys/fs/fuse/fuse_io.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_io.c Wed Apr 17 23:09:06 2019 (r346338) +++ projects/fuse2/sys/fs/fuse/fuse_io.c Wed Apr 17 23:32:38 2019 (r346339) @@ -379,8 +379,25 @@ fuse_write_directbackend(struct vnode *vp, struct uio break; retry: - if ((err = fdisp_wait_answ(&fdi))) + err = fdisp_wait_answ(&fdi); + if (err == ERESTART || err == EINTR || err == EWOULDBLOCK) { + /* + * Rewind the uio so dofilewrite will know it's + * incomplete + */ + uio->uio_resid += fwi->size; + uio->uio_offset -= fwi->size; + /* + * Change ERESTART into EINTR because we can't rewind + * uio->uio_iov. Basically, once uiomove(9) has been + * called, it's impossible to restart a syscall. + */ + if (err == ERESTART) + err = EINTR; break; + } else if (err) { + break; + } fwo = ((struct fuse_write_out *)fdi.answ); Modified: projects/fuse2/sys/fs/fuse/fuse_ipc.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_ipc.c Wed Apr 17 23:09:06 2019 (r346338) +++ projects/fuse2/sys/fs/fuse/fuse_ipc.c Wed Apr 17 23:32:38 2019 (r346339) @@ -92,7 +92,10 @@ SDT_PROVIDER_DECLARE(fuse); */ SDT_PROBE_DEFINE2(fuse, , ipc, trace, "int", "char*"); +static void fdisp_make_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op, + struct fuse_data *data, uint64_t nid, pid_t pid, struct ucred *cred); static void fiov_clear(struct fuse_iov *fiov); +static void fuse_interrupt_send(struct fuse_ticket *otick); static struct fuse_ticket *fticket_alloc(struct fuse_data *data); static void fticket_refresh(struct fuse_ticket *ftick); static void fticket_destroy(struct fuse_ticket *ftick); @@ -126,25 +129,76 @@ SYSCTL_INT(_vfs_fusefs, OID_AUTO, iov_credit, CTLFLAG_ MALLOC_DEFINE(M_FUSEMSG, "fuse_msgbuf", "fuse message buffer"); static uma_zone_t ticket_zone; -static void -fuse_block_sigs(sigset_t *oldset) +/* + * TODO: figure out how to timeout INTERRUPT requests, because the daemon may + * leagally never respond + * + * TODO: remove an INTERRUPT request if the daemon responds to the original + */ +static int +fuse_interrupt_callback(struct fuse_ticket *tick, struct uio *uio) { - sigset_t newset; + if (tick->tk_aw_ohead.error == EAGAIN) { + /* + * There are two reasons we might get this: + * 1) the daemon received the INTERRUPT request before the + * original, or + * 2) the daemon received the INTERRUPT request after it + * completed the original request. + * In the first case we should re-send the INTERRUPT. In the + * second, we should ignore it. + */ + struct fuse_interrupt_in *fii; + struct fuse_data *data; + struct fuse_ticket *otick, *x_tick; + bool found = false; - SIGFILLSET(newset); - SIGDELSET(newset, SIGKILL); - if (kern_sigprocmask(curthread, SIG_BLOCK, &newset, oldset, 0)) - panic("%s: Invalid operation for kern_sigprocmask()", - __func__); + data = tick->tk_data; + fii = (struct fuse_interrupt_in*)((char*)tick->tk_ms_fiov.base + + sizeof(struct fuse_in_header)); + fuse_lck_mtx_lock(data->aw_mtx); + TAILQ_FOREACH_SAFE(otick, &data->aw_head, tk_aw_link, x_tick) { + if (otick->tk_unique == fii->unique) { + found = true; + break; + } + } + fuse_lck_mtx_unlock(data->aw_mtx); + if (found) { + /* Resend */ + fuse_interrupt_send(otick); + } else { + /* Original is already complete; nothing to do */ + } + return 0; + } else { + /* Illegal FUSE_INTERRUPT response */ + return EINVAL; + } } -static void -fuse_restore_sigs(sigset_t *oldset) +void +fuse_interrupt_send(struct fuse_ticket *otick) { + struct fuse_dispatcher fdi; + struct fuse_interrupt_in *fii; + struct fuse_in_header *ftick_hdr; + struct fuse_data *data = otick->tk_data; + struct ucred reused_creds; - if (kern_sigprocmask(curthread, SIG_SETMASK, oldset, NULL, 0)) - panic("%s: Invalid operation for kern_sigprocmask()", - __func__); + ftick_hdr = fticket_in_header(otick); + reused_creds.cr_uid = ftick_hdr->uid; + reused_creds.cr_rgid = ftick_hdr->gid; + fdisp_init(&fdi, sizeof(*fii)); + fdisp_make_pid(&fdi, FUSE_INTERRUPT, data, ftick_hdr->nodeid, + ftick_hdr->pid, &reused_creds); + + fii = fdi.indata; + fii->unique = otick->tk_unique; + fuse_insert_callback(fdi.tick, fuse_interrupt_callback); + + fuse_insert_message(fdi.tick); + fdisp_destroy(&fdi); } void @@ -329,12 +383,16 @@ fticket_reset(struct fuse_ticket *ftick) static int fticket_wait_answer(struct fuse_ticket *ftick) { - sigset_t tset; + struct thread *td = curthread; + sigset_t blockedset, oldset; int err = 0; struct fuse_data *data; fuse_lck_mtx_lock(ftick->tk_aw_mtx); + SIGEMPTYSET(blockedset); + kern_sigprocmask(td, SIG_BLOCK, &blockedset, &oldset, 0); +retry: if (fticket_answered(ftick)) { goto out; } @@ -345,11 +403,12 @@ fticket_wait_answer(struct fuse_ticket *ftick) fticket_set_answered(ftick); goto out; } - fuse_block_sigs(&tset); err = msleep(ftick, &ftick->tk_aw_mtx, PCATCH, "fu_ans", data->daemon_timeout * hz); - fuse_restore_sigs(&tset); - if (err == EAGAIN) { /* same as EWOULDBLOCK */ + kern_sigprocmask(td, SIG_SETMASK, &oldset, NULL, 0); + if (err == EWOULDBLOCK) { + SDT_PROBE2(fuse, , ipc, trace, 3, + "fticket_wait_answer: EWOULDBLOCK"); #ifdef XXXIP /* die conditionally */ if (!fdata_get_dead(data)) { fdata_set_dead(data); @@ -357,6 +416,45 @@ fticket_wait_answer(struct fuse_ticket *ftick) #endif err = ETIMEDOUT; fticket_set_answered(ftick); + } else if ((err == EINTR || err == ERESTART)) { + /* + * Whether we get EINTR or ERESTART depends on whether + * SA_RESTART was set by sigaction(2). + * + * Try to interrupt the operation and wait for an EINTR response + * to the original operation. If the file system does not + * support FUSE_INTERRUPT, then we'll just wait for it to + * complete like normal. If it does support FUSE_INTERRUPT, + * then it will either respond EINTR to the original operation, + * or EAGAIN to the interrupt. + */ + int sig; + + SDT_PROBE2(fuse, , ipc, trace, 4, + "fticket_wait_answer: interrupt"); + fuse_lck_mtx_unlock(ftick->tk_aw_mtx); + fuse_interrupt_send(ftick); + fuse_lck_mtx_lock(ftick->tk_aw_mtx); + + /* TODO: return, rather than retry, for fatal signals */ + + /* + * Block the just-delivered signal while we wait for an + * interrupt response + */ + PROC_LOCK(td->td_proc); + mtx_lock(&td->td_proc->p_sigacts->ps_mtx); + sig = cursig(td); + mtx_unlock(&td->td_proc->p_sigacts->ps_mtx); + PROC_UNLOCK(td->td_proc); + SIGADDSET(blockedset, sig); + kern_sigprocmask(curthread, SIG_BLOCK, &blockedset, NULL, 0); + goto retry; + } else if (err) { + SDT_PROBE2(fuse, , ipc, trace, 6, + "fticket_wait_answer: other error"); + } else { + SDT_PROBE2(fuse, , ipc, trace, 7, "fticket_wait_answer: OK"); } out: if (!(err || fticket_answered(ftick))) { @@ -762,10 +860,8 @@ fdisp_refresh_pid(struct fuse_dispatcher *fdip, enum f /* Initialize a dispatcher from a pid and node id */ static void fdisp_make_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op, - struct mount *mp, uint64_t nid, pid_t pid, struct ucred *cred) + struct fuse_data *data, uint64_t nid, pid_t pid, struct ucred *cred) { - struct fuse_data *data = fuse_get_mpdata(mp); - if (fdip->tick) { fticket_refresh(fdip->tick); } else { @@ -783,17 +879,21 @@ void fdisp_make(struct fuse_dispatcher *fdip, enum fuse_opcode op, struct mount *mp, uint64_t nid, struct thread *td, struct ucred *cred) { + struct fuse_data *data = fuse_get_mpdata(mp); RECTIFY_TDCR(td, cred); - return fdisp_make_pid(fdip, op, mp, nid, td->td_proc->p_pid, cred); + return fdisp_make_pid(fdip, op, data, nid, td->td_proc->p_pid, cred); } void fdisp_make_vp(struct fuse_dispatcher *fdip, enum fuse_opcode op, struct vnode *vp, struct thread *td, struct ucred *cred) { + struct mount *mp = vnode_mount(vp); + struct fuse_data *data = fuse_get_mpdata(mp); + RECTIFY_TDCR(td, cred); - return fdisp_make_pid(fdip, op, vnode_mount(vp), VTOI(vp), + return fdisp_make_pid(fdip, op, data, VTOI(vp), td->td_proc->p_pid, cred); } Modified: projects/fuse2/sys/fs/fuse/fuse_ipc.h ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_ipc.h Wed Apr 17 23:09:06 2019 (r346338) +++ projects/fuse2/sys/fs/fuse/fuse_ipc.h Wed Apr 17 23:32:38 2019 (r346339) @@ -147,10 +147,16 @@ fticket_set_answered(struct fuse_ticket *ftick) ftick->tk_flag |= FT_ANSW; } +static inline struct fuse_in_header* +fticket_in_header(struct fuse_ticket *ftick) +{ + return (struct fuse_in_header *)(ftick->tk_ms_fiov.base); +} + static inline enum fuse_opcode fticket_opcode(struct fuse_ticket *ftick) { - return (((struct fuse_in_header *)(ftick->tk_ms_fiov.base))->opcode); + return fticket_in_header(ftick)->opcode; } int fticket_pull(struct fuse_ticket *ftick, struct uio *uio); @@ -174,6 +180,11 @@ struct fuse_data { struct mtx aw_mtx; TAILQ_HEAD(, fuse_ticket) aw_head; + /* + * Holds the next value of the FUSE operation unique value. + * Also, serves as a wakeup channel to prevent any operations from + * being created before INIT completes. + */ u_long ticketer; struct sx rename_lock; Modified: projects/fuse2/tests/sys/fs/fusefs/interrupt.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Wed Apr 17 23:09:06 2019 (r346338) +++ projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Wed Apr 17 23:32:38 2019 (r346339) @@ -41,8 +41,10 @@ using namespace testing; /* Don't do anything; all we care about is that the syscall gets interrupted */ void sigusr2_handler(int __unused sig) { - if (verbosity > 1) - printf("Signaled!\n"); + if (verbosity > 1) { + printf("Signaled! thread %p\n", pthread_self()); + } + } void* killer(void* target) { @@ -52,8 +54,8 @@ void* killer(void* target) { */ usleep(250'000); if (verbosity > 1) - printf("Signalling!\n"); - pthread_kill(*(pthread_t*)target, SIGUSR2); + printf("Signalling! thread %p\n", target); + pthread_kill((pthread_t)target, SIGUSR2); return(NULL); } @@ -94,9 +96,14 @@ void setup_interruptor(pthread_t self) } void TearDown() { + struct sigaction sa; + if (m_child != NULL) { pthread_join(m_child, NULL); } + bzero(&sa, sizeof(sa)); + sa.sa_handler = SIG_DFL; + sigaction(SIGUSR2, &sa, NULL); FuseTest::TearDown(); } @@ -107,7 +114,7 @@ void TearDown() { * complete should generate an EAGAIN response. */ /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236530 */ -TEST_F(Interrupt, DISABLED_already_complete) +TEST_F(Interrupt, already_complete) { const char FULLPATH[] = "mountpoint/some_file.txt"; const char RELPATH[] = "some_file.txt"; @@ -122,7 +129,6 @@ TEST_F(Interrupt, DISABLED_already_complete) expect_lookup(RELPATH, ino); expect_open(ino, 0, 1); - expect_getattr(ino, 0); expect_write(ino, &write_unique); EXPECT_CALL(*m_mock, process( ResultOf([&](auto in) { @@ -150,7 +156,7 @@ TEST_F(Interrupt, DISABLED_already_complete) ASSERT_LE(0, fd) << strerror(errno); setup_interruptor(self); - ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno); + EXPECT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno); /* Deliberately leak fd. close(2) will be tested in release.cc */ } @@ -160,7 +166,7 @@ TEST_F(Interrupt, DISABLED_already_complete) * complete the original operation whenever it damn well pleases. */ /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236530 */ -TEST_F(Interrupt, DISABLED_ignore) +TEST_F(Interrupt, ignore) { const char FULLPATH[] = "mountpoint/some_file.txt"; const char RELPATH[] = "some_file.txt"; @@ -175,10 +181,9 @@ TEST_F(Interrupt, DISABLED_ignore) expect_lookup(RELPATH, ino); expect_open(ino, 0, 1); - expect_getattr(ino, 0); expect_write(ino, &write_unique); EXPECT_CALL(*m_mock, process( - ResultOf([=](auto in) { + ResultOf([&](auto in) { return (in->header.opcode == FUSE_INTERRUPT && in->body.interrupt.unique == write_unique); }, Eq(true)), @@ -208,7 +213,7 @@ TEST_F(Interrupt, DISABLED_ignore) * return EINTR to userspace */ /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236530 */ -TEST_F(Interrupt, DISABLED_in_progress) +TEST_F(Interrupt, in_progress) { const char FULLPATH[] = "mountpoint/some_file.txt"; const char RELPATH[] = "some_file.txt"; @@ -223,10 +228,9 @@ TEST_F(Interrupt, DISABLED_in_progress) expect_lookup(RELPATH, ino); expect_open(ino, 0, 1); - expect_getattr(ino, 0); expect_write(ino, &write_unique); EXPECT_CALL(*m_mock, process( - ResultOf([=](auto in) { + ResultOf([&](auto in) { return (in->header.opcode == FUSE_INTERRUPT && in->body.interrupt.unique == write_unique); }, Eq(true)), @@ -260,11 +264,12 @@ TEST_F(Interrupt, DISABLED_in_progress) * successfully interrupts the original */ /* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236530 */ -TEST_F(Interrupt, DISABLED_too_soon) +TEST_F(Interrupt, too_soon) { const char FULLPATH[] = "mountpoint/some_file.txt"; const char RELPATH[] = "some_file.txt"; const char *CONTENTS = "abcdefgh"; + Sequence seq; uint64_t ino = 42; int fd; ssize_t bufsize = strlen(CONTENTS); @@ -275,25 +280,25 @@ TEST_F(Interrupt, DISABLED_too_soon) expect_lookup(RELPATH, ino); expect_open(ino, 0, 1); - expect_getattr(ino, 0); expect_write(ino, &write_unique); EXPECT_CALL(*m_mock, process( - ResultOf([=](auto in) { + ResultOf([&](auto in) { return (in->header.opcode == FUSE_INTERRUPT && in->body.interrupt.unique == write_unique); }, Eq(true)), _) - ).WillOnce(Invoke(ReturnErrno(EAGAIN))) - .RetiresOnSaturation(); + ).InSequence(seq) + .WillOnce(Invoke(ReturnErrno(EAGAIN))); EXPECT_CALL(*m_mock, process( - ResultOf([=](auto in) { + ResultOf([&](auto in) { return (in->header.opcode == FUSE_INTERRUPT && in->body.interrupt.unique == write_unique); }, Eq(true)), _) - ).WillOnce(Invoke([&](auto in __unused, auto &out __unused) { + ).InSequence(seq) + .WillOnce(Invoke([&](auto in __unused, auto &out __unused) { auto out0 = new mockfs_buf_out; out0->header.error = -EINTR; out0->header.unique = write_unique; @@ -310,3 +315,14 @@ TEST_F(Interrupt, DISABLED_too_soon) /* Deliberately leak fd. close(2) will be tested in release.cc */ } + + +// TODO: add a test that uses siginterrupt and an interruptible signal +// TODO: add a test that verifies a process can be cleanly killed even if a +// FUSE_WRITE command never returns. +// TODO: write in-progress tests for read and other operations +// TODO: add a test where write returns EWOULDBLOCK +// TODO: test that if a fatal signal is received, fticket_wait_answer will +// return without waiting for a response to the interrupted operation. +// TODO: test that operations that haven't been received by the server can be +// interrupted without generating a FUSE_INTERRUPT. Modified: projects/fuse2/tests/sys/fs/fusefs/mockfs.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/mockfs.cc Wed Apr 17 23:09:06 2019 (r346338) +++ projects/fuse2/tests/sys/fs/fusefs/mockfs.cc Wed Apr 17 23:32:38 2019 (r346339) @@ -184,6 +184,9 @@ void debug_fuseop(const mockfs_buf_in *in) case FUSE_FSYNCDIR: printf(" flags=%#x", in->body.fsyncdir.fsync_flags); break; + case FUSE_INTERRUPT: + printf(" unique=%lu", in->body.interrupt.unique); + break; case FUSE_LOOKUP: printf(" %s", in->body.lookup); break; From owner-svn-src-projects@freebsd.org Thu Apr 18 19:16:37 2019 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 0A7CC157A208 for ; Thu, 18 Apr 2019 19:16:37 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id A1D8575903; Thu, 18 Apr 2019 19:16:36 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 927EA23525; Thu, 18 Apr 2019 19:16:36 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x3IJGaKp025543; Thu, 18 Apr 2019 19:16:36 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x3IJGZfe025435; Thu, 18 Apr 2019 19:16:35 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201904181916.x3IJGZfe025435@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers Date: Thu, 18 Apr 2019 19:16:35 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r346357 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Group: projects X-SVN-Commit-Author: asomers X-SVN-Commit-Paths: in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Commit-Revision: 346357 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: A1D8575903 X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.96 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; NEURAL_HAM_SHORT(-0.96)[-0.961,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US] X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Apr 2019 19:16:37 -0000 Author: asomers Date: Thu Apr 18 19:16:34 2019 New Revision: 346357 URL: https://svnweb.freebsd.org/changeset/base/346357 Log: fusefs: improvements to interruptibility * If a process receives a fatal signal while blocked on a fuse operation, return ASAP without waiting for the operation to complete. But still send the FUSE_INTERRUPT op to the daemon. * Plug memory leaks from r346339 Interruptibility is now fully functional, but it could be better: * Operations that haven't been sent to the server yet should be aborted without sending FUSE_INTERRUPT. * It would be great if write operations could be made restartable. That would require delaying uiomove until the last possible moment, which would be sometime during fuse_device_read. * It would be nice if we didn't have to guess which EAGAIN responses were for FUSE_INTERRUPT operations. PR: 236530 Sponsored by: The FreeBSD Foundation Modified: projects/fuse2/sys/fs/fuse/fuse_device.c projects/fuse2/sys/fs/fuse/fuse_ipc.c projects/fuse2/sys/fs/fuse/fuse_ipc.h projects/fuse2/tests/sys/fs/fusefs/allow_other.cc projects/fuse2/tests/sys/fs/fusefs/interrupt.cc projects/fuse2/tests/sys/fs/fusefs/open.cc projects/fuse2/tests/sys/fs/fusefs/utils.cc projects/fuse2/tests/sys/fs/fusefs/utils.hh Modified: projects/fuse2/sys/fs/fuse/fuse_device.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_device.c Thu Apr 18 19:04:07 2019 (r346356) +++ projects/fuse2/sys/fs/fuse/fuse_device.c Thu Apr 18 19:16:34 2019 (r346357) @@ -360,7 +360,7 @@ fuse_device_write(struct cdev *dev, struct uio *uio, i struct fuse_out_header ohead; int err = 0; struct fuse_data *data; - struct fuse_ticket *tick, *x_tick; + struct fuse_ticket *tick, *itick, *x_tick; int found = 0; err = devfs_get_cdevpriv((void **)&data); @@ -401,6 +401,20 @@ fuse_device_write(struct cdev *dev, struct uio *uio, i break; } } + if (found && tick->irq_unique > 0) { + /* + * Discard the FUSE_INTERRUPT ticket that tried to interrupt + * this operation + */ + TAILQ_FOREACH_SAFE(itick, &data->aw_head, tk_aw_link, + x_tick) { + if (itick->tk_unique == tick->irq_unique) { + fuse_aw_remove(itick); + break; + } + } + tick->irq_unique = 0; + } fuse_lck_mtx_unlock(data->aw_mtx); if (found) { @@ -433,7 +447,20 @@ fuse_device_write(struct cdev *dev, struct uio *uio, i /* no callback at all! */ SDT_PROBE1(fuse, , device, fuse_device_write_missing_ticket, ohead.unique); - err = EINVAL; + if (ohead.error == EAGAIN) { + /* + * This was probably a response to a FUSE_INTERRUPT + * operation whose original operation is already + * complete. We can't store FUSE_INTERRUPT tickets + * indefinitely because their responses are optional. + * So we delete them when the original operation + * completes. And sadly the fuse_header_out doesn't + * identify the opcode, so we have to guess. + */ + err = 0; + } else { + err = EINVAL; + } } return (err); Modified: projects/fuse2/sys/fs/fuse/fuse_ipc.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_ipc.c Thu Apr 18 19:04:07 2019 (r346356) +++ projects/fuse2/sys/fs/fuse/fuse_ipc.c Thu Apr 18 19:16:34 2019 (r346357) @@ -138,6 +138,32 @@ static uma_zone_t ticket_zone; static int fuse_interrupt_callback(struct fuse_ticket *tick, struct uio *uio) { + struct fuse_ticket *otick, *x_tick; + struct fuse_interrupt_in *fii; + struct fuse_data *data; + data = tick->tk_data; + bool found = false; + + fii = (struct fuse_interrupt_in*)((char*)tick->tk_ms_fiov.base + + sizeof(struct fuse_in_header)); + + fuse_lck_mtx_lock(data->aw_mtx); + TAILQ_FOREACH_SAFE(otick, &data->aw_head, tk_aw_link, x_tick) { + if (otick->tk_unique == fii->unique) { + found = true; + break; + } + } + fuse_lck_mtx_unlock(data->aw_mtx); + + if (!found) { + /* Original is already complete. Just return */ + return 0; + } + + /* Clear the original ticket's interrupt association */ + otick->irq_unique = 0; + if (tick->tk_aw_ohead.error == EAGAIN) { /* * There are two reasons we might get this: @@ -148,28 +174,8 @@ fuse_interrupt_callback(struct fuse_ticket *tick, stru * In the first case we should re-send the INTERRUPT. In the * second, we should ignore it. */ - struct fuse_interrupt_in *fii; - struct fuse_data *data; - struct fuse_ticket *otick, *x_tick; - bool found = false; - - data = tick->tk_data; - fii = (struct fuse_interrupt_in*)((char*)tick->tk_ms_fiov.base + - sizeof(struct fuse_in_header)); - fuse_lck_mtx_lock(data->aw_mtx); - TAILQ_FOREACH_SAFE(otick, &data->aw_head, tk_aw_link, x_tick) { - if (otick->tk_unique == fii->unique) { - found = true; - break; - } - } - fuse_lck_mtx_unlock(data->aw_mtx); - if (found) { - /* Resend */ - fuse_interrupt_send(otick); - } else { - /* Original is already complete; nothing to do */ - } + /* Resend */ + fuse_interrupt_send(otick); return 0; } else { /* Illegal FUSE_INTERRUPT response */ @@ -186,19 +192,24 @@ fuse_interrupt_send(struct fuse_ticket *otick) struct fuse_data *data = otick->tk_data; struct ucred reused_creds; - ftick_hdr = fticket_in_header(otick); - reused_creds.cr_uid = ftick_hdr->uid; - reused_creds.cr_rgid = ftick_hdr->gid; - fdisp_init(&fdi, sizeof(*fii)); - fdisp_make_pid(&fdi, FUSE_INTERRUPT, data, ftick_hdr->nodeid, - ftick_hdr->pid, &reused_creds); + if (otick->irq_unique == 0) { + ftick_hdr = fticket_in_header(otick); + reused_creds.cr_uid = ftick_hdr->uid; + reused_creds.cr_rgid = ftick_hdr->gid; + fdisp_init(&fdi, sizeof(*fii)); + fdisp_make_pid(&fdi, FUSE_INTERRUPT, data, ftick_hdr->nodeid, + ftick_hdr->pid, &reused_creds); - fii = fdi.indata; - fii->unique = otick->tk_unique; - fuse_insert_callback(fdi.tick, fuse_interrupt_callback); + fii = fdi.indata; + fii->unique = otick->tk_unique; + fuse_insert_callback(fdi.tick, fuse_interrupt_callback); - fuse_insert_message(fdi.tick); - fdisp_destroy(&fdi); + otick->irq_unique = fdi.tick->tk_unique; + fuse_insert_message(fdi.tick); + fdisp_destroy(&fdi); + } else { + /* This ticket has already been interrupted */ + } } void @@ -278,6 +289,8 @@ fticket_ctor(void *mem, int size, void *arg, int flags if (ftick->tk_unique == 0) ftick->tk_unique = atomic_fetchadd_long(&data->ticketer, 1); + ftick->irq_unique = 0; + refcount_init(&ftick->tk_refcount, 1); atomic_add_acq_int(&fuse_ticket_count, 1); @@ -436,20 +449,23 @@ retry: fuse_interrupt_send(ftick); fuse_lck_mtx_lock(ftick->tk_aw_mtx); - /* TODO: return, rather than retry, for fatal signals */ - - /* - * Block the just-delivered signal while we wait for an - * interrupt response - */ PROC_LOCK(td->td_proc); mtx_lock(&td->td_proc->p_sigacts->ps_mtx); sig = cursig(td); mtx_unlock(&td->td_proc->p_sigacts->ps_mtx); PROC_UNLOCK(td->td_proc); - SIGADDSET(blockedset, sig); - kern_sigprocmask(curthread, SIG_BLOCK, &blockedset, NULL, 0); - goto retry; + if (!sig_isfatal(td->td_proc, sig)) { + /* + * Block the just-delivered signal while we wait for an + * interrupt response + */ + SIGADDSET(blockedset, sig); + kern_sigprocmask(curthread, SIG_BLOCK, &blockedset, + NULL, 0); + goto retry; + } else { + /* Return immediately for fatal signals */ + } } else if (err) { SDT_PROBE2(fuse, , ipc, trace, 6, "fticket_wait_answer: other error"); Modified: projects/fuse2/sys/fs/fuse/fuse_ipc.h ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_ipc.h Thu Apr 18 19:04:07 2019 (r346356) +++ projects/fuse2/sys/fs/fuse/fuse_ipc.h Thu Apr 18 19:16:34 2019 (r346357) @@ -103,6 +103,12 @@ struct fuse_ticket { struct fuse_data *tk_data; int tk_flag; u_int tk_refcount; + /* + * If this ticket's operation has been interrupted, this will hold the + * unique value of the FUSE_INTERRUPT operation. Otherwise, it will be + * 0. + */ + uint64_t irq_unique; /* fields for initiating an upgoing message */ struct fuse_iov tk_ms_fiov; Modified: projects/fuse2/tests/sys/fs/fusefs/allow_other.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/allow_other.cc Thu Apr 18 19:04:07 2019 (r346356) +++ projects/fuse2/tests/sys/fs/fusefs/allow_other.cc Thu Apr 18 19:16:34 2019 (r346357) @@ -36,6 +36,7 @@ extern "C" { #include #include +#include #include #include } @@ -74,7 +75,9 @@ virtual void SetUp() { TEST_F(AllowOther, allowed) { - fork(true, [&] { + int status; + + fork(true, &status, [&] { uint64_t ino = 42; expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 1); @@ -92,6 +95,7 @@ TEST_F(AllowOther, allowed) return 0; } ); + ASSERT_EQ(0, WEXITSTATUS(status)); } /* @@ -104,12 +108,12 @@ TEST_F(AllowOther, privilege_escalation) { const static char FULLPATH[] = "mountpoint/some_file.txt"; const static char RELPATH[] = "some_file.txt"; - int fd1; + int fd1, status; const static uint64_t ino = 42; const static uint64_t fh = 100; /* Fork a child to open the file with different credentials */ - fork(true, [&] { + fork(true, &status, [&] { expect_lookup(RELPATH, ino, S_IFREG | 0600, 0, 2); EXPECT_CALL(*m_mock, process( @@ -156,12 +160,15 @@ TEST_F(AllowOther, privilege_escalation) return 0; } ); + ASSERT_EQ(0, WEXITSTATUS(status)); /* Deliberately leak fd1. close(2) will be tested in release.cc */ } TEST_F(NoAllowOther, disallowed) { - fork(true, [] { + int status; + + fork(true, &status, [] { }, []() { int fd; @@ -177,6 +184,7 @@ TEST_F(NoAllowOther, disallowed) return 0; } ); + ASSERT_EQ(0, WEXITSTATUS(status)); } /* @@ -191,7 +199,7 @@ TEST_F(NoAllowOther, disallowed_beneath_root) const static char RELPATH2[] = "other_dir"; const static uint64_t ino = 42; const static uint64_t ino2 = 43; - int dfd; + int dfd, status; expect_lookup(RELPATH, ino, S_IFDIR | 0755, 0, 1); EXPECT_LOOKUP(ino, RELPATH2) @@ -206,7 +214,7 @@ TEST_F(NoAllowOther, disallowed_beneath_root) dfd = open(FULLPATH, O_DIRECTORY); ASSERT_LE(0, dfd) << strerror(errno); - fork(true, [] { + fork(true, &status, [] { }, [&]() { int fd; @@ -222,6 +230,7 @@ TEST_F(NoAllowOther, disallowed_beneath_root) return 0; } ); + ASSERT_EQ(0, WEXITSTATUS(status)); } /* @@ -230,9 +239,9 @@ TEST_F(NoAllowOther, disallowed_beneath_root) */ TEST_F(NoAllowOther, setextattr) { - int ino = 42; + int ino = 42, status; - fork(true, [&] { + fork(true, &status, [&] { EXPECT_LOOKUP(1, RELPATH) .WillOnce(Invoke( ReturnImmediate([=](auto in __unused, auto out) { @@ -268,4 +277,5 @@ TEST_F(NoAllowOther, setextattr) return 0; } ); + ASSERT_EQ(0, WEXITSTATUS(status)); } Modified: projects/fuse2/tests/sys/fs/fusefs/interrupt.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Thu Apr 18 19:04:07 2019 (r346356) +++ projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Thu Apr 18 19:16:34 2019 (r346357) @@ -29,6 +29,7 @@ */ extern "C" { +#include #include #include #include @@ -68,10 +69,27 @@ Interrupt(): m_child(NULL) {}; void expect_lookup(const char *relpath, uint64_t ino) { - FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 0, 1); + FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 1000, 1); } /* + * Expect a FUSE_READ but don't reply. Instead, just record the unique value + * to the provided pointer + */ +void expect_read(uint64_t ino, uint64_t *read_unique) +{ + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_READ && + in->header.nodeid == ino); + }, Eq(true)), + _) + ).WillOnce(Invoke([=](auto in, auto &out __unused) { + *read_unique = in->header.unique; + })); +} + +/* * Expect a FUSE_WRITE but don't reply. Instead, just record the unique value * to the provided pointer */ @@ -90,7 +108,7 @@ void expect_write(uint64_t ino, uint64_t *write_unique void setup_interruptor(pthread_t self) { - ASSERT_EQ(0, signal(SIGUSR2, sigusr2_handler)) << strerror(errno); + ASSERT_NE(SIG_ERR, signal(SIGUSR2, sigusr2_handler)) << strerror(errno); ASSERT_EQ(0, pthread_create(&m_child, NULL, killer, (void*)self)) << strerror(errno); } @@ -162,6 +180,74 @@ TEST_F(Interrupt, already_complete) } /* + * Upon receipt of a fatal signal, fusefs should return ASAP after sending + * FUSE_INTERRUPT. + */ +TEST_F(Interrupt, fatal_signal) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char *CONTENTS = "abcdefgh"; + const char RELPATH[] = "some_file.txt"; + ssize_t bufsize = strlen(CONTENTS); + uint64_t ino = 42; + int status; + pthread_t self; + uint64_t write_unique; + + self = pthread_self(); + + expect_lookup(RELPATH, ino); + expect_open(ino, 0, 1); + expect_write(ino, &write_unique); + EXPECT_CALL(*m_mock, process( + ResultOf([&](auto in) { + return (in->header.opcode == FUSE_INTERRUPT && + in->body.interrupt.unique == write_unique); + }, Eq(true)), + _) + ).WillOnce(Invoke([&](auto in __unused, auto &out __unused) { + /* Don't respond. The process should exit anyway */ + })); + expect_flush(ino, 1, ReturnErrno(0)); + expect_release(ino, FH); + + fork(false, &status, [&] { + }, [&]() { + struct sigaction sa; + int fd, r; + pthread_t killer_th; + pthread_t self; + + fd = open(FULLPATH, O_WRONLY); + if (fd < 0) { + perror("open"); + return 1; + } + + /* SIGUSR2 terminates the process by default */ + bzero(&sa, sizeof(sa)); + sa.sa_handler = SIG_DFL; + r = sigaction(SIGUSR2, &sa, NULL); + if (r != 0) { + perror("sigaction"); + return 1; + } + self = pthread_self(); + r = pthread_create(&killer_th, NULL, killer, (void*)self); + if (r != 0) { + perror("pthread_create"); + return 1; + } + + write(fd, CONTENTS, bufsize); + return 1; + }); + ASSERT_EQ(SIGUSR2, WTERMSIG(status)); + + /* Deliberately leak fd. close(2) will be tested in release.cc */ +} + +/* * A FUSE filesystem is legally allowed to ignore INTERRUPT operations, and * complete the original operation whenever it damn well pleases. */ @@ -253,6 +339,47 @@ TEST_F(Interrupt, in_progress) /* Deliberately leak fd. close(2) will be tested in release.cc */ } +/* Reads should also be interruptible */ +TEST_F(Interrupt, in_progress_read) +{ + const char FULLPATH[] = "mountpoint/some_file.txt"; + const char RELPATH[] = "some_file.txt"; + const size_t bufsize = 80; + char buf[bufsize]; + uint64_t ino = 42; + int fd; + pthread_t self; + uint64_t read_unique; + + self = pthread_self(); + + expect_lookup(RELPATH, ino); + expect_open(ino, 0, 1); + expect_read(ino, &read_unique); + EXPECT_CALL(*m_mock, process( + ResultOf([&](auto in) { + return (in->header.opcode == FUSE_INTERRUPT && + in->body.interrupt.unique == read_unique); + }, Eq(true)), + _) + ).WillOnce(Invoke([&](auto in __unused, auto &out) { + auto out0 = new mockfs_buf_out; + out0->header.error = -EINTR; + out0->header.unique = read_unique; + out0->header.len = sizeof(out0->header); + out.push_back(out0); + })); + + fd = open(FULLPATH, O_RDONLY); + ASSERT_LE(0, fd) << strerror(errno); + + setup_interruptor(self); + ASSERT_EQ(-1, read(fd, buf, bufsize)); + EXPECT_EQ(EINTR, errno); + + /* Deliberately leak fd. close(2) will be tested in release.cc */ +} + /* * If the FUSE filesystem receives the FUSE_INTERRUPT operation before * processing the original, then it should wait for "some timeout" for the @@ -320,9 +447,7 @@ TEST_F(Interrupt, too_soon) // TODO: add a test that uses siginterrupt and an interruptible signal // TODO: add a test that verifies a process can be cleanly killed even if a // FUSE_WRITE command never returns. -// TODO: write in-progress tests for read and other operations +// TODO: write in-progress tests for other operations // TODO: add a test where write returns EWOULDBLOCK -// TODO: test that if a fatal signal is received, fticket_wait_answer will -// return without waiting for a response to the interrupted operation. // TODO: test that operations that haven't been received by the server can be // interrupted without generating a FUSE_INTERRUPT. Modified: projects/fuse2/tests/sys/fs/fusefs/open.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/open.cc Thu Apr 18 19:04:07 2019 (r346356) +++ projects/fuse2/tests/sys/fs/fusefs/open.cc Thu Apr 18 19:16:34 2019 (r346357) @@ -29,6 +29,7 @@ */ extern "C" { +#include #include } @@ -166,12 +167,12 @@ TEST_F(Open, multiple_creds) { const static char FULLPATH[] = "mountpoint/some_file.txt"; const static char RELPATH[] = "some_file.txt"; - int fd1; + int fd1, status; const static uint64_t ino = 42; const static uint64_t fh0 = 100, fh1 = 200; /* Fork a child to open the file with different credentials */ - fork(false, [&] { + fork(false, &status, [&] { expect_lookup(RELPATH, ino, S_IFREG | 0644, 0, 2); EXPECT_CALL(*m_mock, process( @@ -218,6 +219,7 @@ TEST_F(Open, multiple_creds) return 0; } ); + ASSERT_EQ(0, WEXITSTATUS(status)); close(fd1); } Modified: projects/fuse2/tests/sys/fs/fusefs/utils.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/utils.cc Thu Apr 18 19:04:07 2019 (r346356) +++ projects/fuse2/tests/sys/fs/fusefs/utils.cc Thu Apr 18 19:16:34 2019 (r346357) @@ -336,7 +336,8 @@ get_unprivileged_uid(uid_t *uid) } void -FuseTest::fork(bool drop_privs, std::function parent_func, +FuseTest::fork(bool drop_privs, int *child_status, + std::function parent_func, std::function child_func) { sem_t *sem; @@ -376,8 +377,6 @@ out: sem_destroy(sem); _exit(err); } else if (child > 0) { - int child_status; - /* * In parent. Cleanup must happen here, because it's still * privileged. @@ -388,12 +387,12 @@ out: /* Signal the child process to go */ ASSERT_EQ(0, sem_post(sem)) << strerror(errno); - ASSERT_LE(0, wait(&child_status)) << strerror(errno); - ASSERT_EQ(0, WEXITSTATUS(child_status)); + ASSERT_LE(0, wait(child_status)) << strerror(errno); } else { FAIL() << strerror(errno); } munmap(sem, sizeof(*sem)); + return; } static void usage(char* progname) { Modified: projects/fuse2/tests/sys/fs/fusefs/utils.hh ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/utils.hh Thu Apr 18 19:04:07 2019 (r346356) +++ projects/fuse2/tests/sys/fs/fusefs/utils.hh Thu Apr 18 19:16:34 2019 (r346357) @@ -106,7 +106,7 @@ class FuseTest : public ::testing::Test { uid_t uid = 0); /* - * Create an expectation that FUSE_GETATTR will be called for the given + * Create an expectation that FUSE_OPEN will be called for the given * inode exactly times times. It will return with open_flags flags and * file handle FH. */ @@ -162,11 +162,11 @@ class FuseTest : public ::testing::Test { * * # Returns * - * fusetest_fork will FAIL the test if child_func returns nonzero. - * It may SKIP the test, which the caller should detect with the - * IsSkipped() method. + * fusetest_fork may SKIP the test, which the caller should detect with + * the IsSkipped() method. If not, then the child's exit status will + * be returned in status. */ - void fork(bool drop_privs, + void fork(bool drop_privs, int *status, std::function parent_func, std::function child_func); }; From owner-svn-src-projects@freebsd.org Fri Apr 19 15:05:34 2019 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id DE3F2156F34C for ; Fri, 19 Apr 2019 15:05:33 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 77D8982EC9; Fri, 19 Apr 2019 15:05:33 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 649B82FEEB; Fri, 19 Apr 2019 15:05:33 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x3JF5XJd054576; Fri, 19 Apr 2019 15:05:33 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x3JF5Xrf054574; Fri, 19 Apr 2019 15:05:33 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201904191505.x3JF5Xrf054574@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers Date: Fri, 19 Apr 2019 15:05:33 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r346387 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Group: projects X-SVN-Commit-Author: asomers X-SVN-Commit-Paths: in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Commit-Revision: 346387 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 77D8982EC9 X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.97 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; NEURAL_HAM_SHORT(-0.97)[-0.967,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US] X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 19 Apr 2019 15:05:34 -0000 Author: asomers Date: Fri Apr 19 15:05:32 2019 New Revision: 346387 URL: https://svnweb.freebsd.org/changeset/base/346387 Log: fusefs: don't send FUSE_INTERRUPT for ops that are still in-kernel If a pending FUSE operation hasn't yet been sent to the daemon, then there's no reason to inform the daemon that it's been interrupted. Instead, simply remove it from the fuse message queue and set its status to EINTR or ERESTART as appropriate. PR: 346357 Sponsored by: The FreeBSD Foundation Modified: projects/fuse2/sys/fs/fuse/fuse_ipc.c projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Modified: projects/fuse2/sys/fs/fuse/fuse_ipc.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_ipc.c Fri Apr 19 13:43:33 2019 (r346386) +++ projects/fuse2/sys/fs/fuse/fuse_ipc.c Fri Apr 19 15:05:32 2019 (r346387) @@ -95,7 +95,7 @@ SDT_PROBE_DEFINE2(fuse, , ipc, trace, "int", "char*"); static void fdisp_make_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op, struct fuse_data *data, uint64_t nid, pid_t pid, struct ucred *cred); static void fiov_clear(struct fuse_iov *fiov); -static void fuse_interrupt_send(struct fuse_ticket *otick); +static void fuse_interrupt_send(struct fuse_ticket *otick, int err); static struct fuse_ticket *fticket_alloc(struct fuse_data *data); static void fticket_refresh(struct fuse_ticket *ftick); static void fticket_destroy(struct fuse_ticket *ftick); @@ -175,7 +175,7 @@ fuse_interrupt_callback(struct fuse_ticket *tick, stru * second, we should ignore it. */ /* Resend */ - fuse_interrupt_send(otick); + fuse_interrupt_send(otick, EINTR); return 0; } else { /* Illegal FUSE_INTERRUPT response */ @@ -183,16 +183,49 @@ fuse_interrupt_callback(struct fuse_ticket *tick, stru } } +/* Interrupt the operation otick. Return err as its error code */ void -fuse_interrupt_send(struct fuse_ticket *otick) +fuse_interrupt_send(struct fuse_ticket *otick, int err) { struct fuse_dispatcher fdi; struct fuse_interrupt_in *fii; struct fuse_in_header *ftick_hdr; struct fuse_data *data = otick->tk_data; + struct fuse_ticket *tick, *xtick; struct ucred reused_creds; if (otick->irq_unique == 0) { + /* + * If the daemon hasn't yet received otick, then we can answer + * it ourselves and return. + */ + fuse_lck_mtx_lock(data->ms_mtx); + STAILQ_FOREACH_SAFE(tick, &otick->tk_data->ms_head, tk_ms_link, + xtick) { + if (tick == otick) { + STAILQ_REMOVE(&otick->tk_data->ms_head, tick, + fuse_ticket, tk_ms_link); + otick->tk_ms_link.stqe_next = NULL; + fuse_lck_mtx_unlock(data->ms_mtx); + + fuse_lck_mtx_lock(otick->tk_aw_mtx); + if (!fticket_answered(otick)) { + fticket_set_answered(otick); + otick->tk_aw_errno = err; + wakeup(otick); + } + fuse_lck_mtx_unlock(otick->tk_aw_mtx); + + fuse_ticket_drop(tick); + return; + } + } + fuse_lck_mtx_unlock(data->ms_mtx); + + /* + * If the fuse daemon has already received otick, then we must + * send FUSE_INTERRUPT. + */ ftick_hdr = fticket_in_header(otick); reused_creds.cr_uid = ftick_hdr->uid; reused_creds.cr_rgid = ftick_hdr->gid; @@ -400,11 +433,12 @@ fticket_wait_answer(struct fuse_ticket *ftick) sigset_t blockedset, oldset; int err = 0; struct fuse_data *data; + SIGEMPTYSET(blockedset); + kern_sigprocmask(td, SIG_BLOCK, NULL, &oldset, 0); + fuse_lck_mtx_lock(ftick->tk_aw_mtx); - SIGEMPTYSET(blockedset); - kern_sigprocmask(td, SIG_BLOCK, &blockedset, &oldset, 0); retry: if (fticket_answered(ftick)) { goto out; @@ -416,6 +450,7 @@ retry: fticket_set_answered(ftick); goto out; } + kern_sigprocmask(td, SIG_BLOCK, &blockedset, NULL, 0); err = msleep(ftick, &ftick->tk_aw_mtx, PCATCH, "fu_ans", data->daemon_timeout * hz); kern_sigprocmask(td, SIG_SETMASK, &oldset, NULL, 0); @@ -446,22 +481,21 @@ retry: SDT_PROBE2(fuse, , ipc, trace, 4, "fticket_wait_answer: interrupt"); fuse_lck_mtx_unlock(ftick->tk_aw_mtx); - fuse_interrupt_send(ftick); - fuse_lck_mtx_lock(ftick->tk_aw_mtx); + fuse_interrupt_send(ftick, err); PROC_LOCK(td->td_proc); mtx_lock(&td->td_proc->p_sigacts->ps_mtx); sig = cursig(td); mtx_unlock(&td->td_proc->p_sigacts->ps_mtx); PROC_UNLOCK(td->td_proc); + + fuse_lck_mtx_lock(ftick->tk_aw_mtx); if (!sig_isfatal(td->td_proc, sig)) { /* * Block the just-delivered signal while we wait for an * interrupt response */ SIGADDSET(blockedset, sig); - kern_sigprocmask(curthread, SIG_BLOCK, &blockedset, - NULL, 0); goto retry; } else { /* Return immediately for fatal signals */ Modified: projects/fuse2/tests/sys/fs/fusefs/interrupt.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Fri Apr 19 13:43:33 2019 (r346386) +++ projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Fri Apr 19 15:05:32 2019 (r346387) @@ -32,6 +32,7 @@ extern "C" { #include #include #include +#include #include } @@ -290,6 +291,88 @@ TEST_F(Interrupt, ignore) ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno); /* Deliberately leak fd. close(2) will be tested in release.cc */ +} + +void* write0(void* arg) { + const char *CONTENTS = "abcdefgh"; + ssize_t bufsize = strlen(CONTENTS); + int fd = (int)(intptr_t)arg; + ssize_t r; + + r = write(fd, CONTENTS, bufsize); + if (r >= 0) + return 0; + else + return (void*)(intptr_t)errno; +} + +/* + * An operation that hasn't yet been sent to userland can be interrupted + * without sending FUSE_INTERRUPT + */ +TEST_F(Interrupt, in_kernel) +{ + const char FULLPATH0[] = "mountpoint/some_file.txt"; + const char RELPATH0[] = "some_file.txt"; + const char FULLPATH1[] = "mountpoint/other_file.txt"; + const char RELPATH1[] = "other_file.txt"; + const char *CONTENTS = "ijklmnop"; + ssize_t bufsize = strlen(CONTENTS); + uint64_t ino0 = 42, ino1 = 43; + int fd0, fd1; + pthread_t self, th0; + sem_t sem0, sem1; + void *thr0_value; + + ASSERT_EQ(0, sem_init(&sem0, 0, 0)) << strerror(errno); + ASSERT_EQ(0, sem_init(&sem1, 0, 0)) << strerror(errno); + self = pthread_self(); + + expect_lookup(RELPATH0, ino0); + expect_open(ino0, 0, 1); + expect_lookup(RELPATH1, ino1); + expect_open(ino1, 0, 1); + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_WRITE && + in->header.nodeid == ino0); + }, Eq(true)), + _) + ).WillOnce(Invoke(ReturnImmediate([&](auto in, auto out) { + /* Let the next write proceed */ + sem_post(&sem1); + /* Pause the daemon thread so it won't read the next op */ + sem_wait(&sem0); + + SET_OUT_HEADER_LEN(out, write); + out->body.write.size = in->body.write.size; + }))); + + fd0 = open(FULLPATH0, O_WRONLY); + ASSERT_LE(0, fd0) << strerror(errno); + fd1 = open(FULLPATH1, O_WRONLY); + ASSERT_LE(0, fd1) << strerror(errno); + + /* Use a separate thread for the first write */ + ASSERT_EQ(0, pthread_create(&th0, NULL, write0, (void*)(intptr_t)fd0)) + << strerror(errno); + + setup_interruptor(self); + + sem_wait(&sem1); /* Sequence the two writes */ + ASSERT_EQ(-1, write(fd1, CONTENTS, bufsize)); + EXPECT_EQ(EINTR, errno); + + /* Unstick the daemon */ + ASSERT_EQ(0, sem_post(&sem0)) << strerror(errno); + + /* Wait awhile to make sure the signal generates no FUSE_INTERRUPT */ + usleep(250'000); + + pthread_join(th0, &thr0_value); + EXPECT_EQ(0, (intptr_t)thr0_value); + sem_destroy(&sem1); + sem_destroy(&sem0); } /* From owner-svn-src-projects@freebsd.org Fri Apr 19 20:31:14 2019 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 8F7EB1578270 for ; Fri, 19 Apr 2019 20:31:14 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 2886D6A8AA; Fri, 19 Apr 2019 20:31:14 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id A282E3A09; Fri, 19 Apr 2019 20:31:13 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x3JKVDbZ028587; Fri, 19 Apr 2019 20:31:13 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x3JKVDqG028585; Fri, 19 Apr 2019 20:31:13 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201904192031.x3JKVDqG028585@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers Date: Fri, 19 Apr 2019 20:31:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r346417 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Group: projects X-SVN-Commit-Author: asomers X-SVN-Commit-Paths: in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Commit-Revision: 346417 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 2886D6A8AA X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.97 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.97)[-0.967,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; NEURAL_HAM_LONG(-1.00)[-1.000,0] X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 19 Apr 2019 20:31:14 -0000 Author: asomers Date: Fri Apr 19 20:31:12 2019 New Revision: 346417 URL: https://svnweb.freebsd.org/changeset/base/346417 Log: fusefs: fix interrupting FUSE_SETXATTR fusefs's VOP_SETEXTATTR calls uiomove(9) before blocking, so it can't be restarted. It must be interrupted instead. PR: 236530 Sponsored by: The FreeBSD Foundation Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_vnops.c Fri Apr 19 20:29:49 2019 (r346416) +++ projects/fuse2/sys/fs/fuse/fuse_vnops.c Fri Apr 19 20:31:12 2019 (r346417) @@ -2127,6 +2127,10 @@ fuse_vnop_setextattr(struct vop_setextattr_args *ap) fsess_set_notimpl(mp, FUSE_SETXATTR); err = EOPNOTSUPP; } + if (err == ERESTART) { + /* Can't restart after calling uiomove */ + err = EINTR; + } out: fdisp_destroy(&fdi); Modified: projects/fuse2/tests/sys/fs/fusefs/interrupt.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Fri Apr 19 20:29:49 2019 (r346416) +++ projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Fri Apr 19 20:31:12 2019 (r346417) @@ -29,6 +29,8 @@ */ extern "C" { +#include +#include #include #include #include @@ -41,6 +43,9 @@ extern "C" { using namespace testing; +/* Initial size of files used by these tests */ +const off_t FILESIZE = 1000; + /* Don't do anything; all we care about is that the syscall gets interrupted */ void sigusr2_handler(int __unused sig) { if (verbosity > 1) { @@ -70,7 +75,7 @@ Interrupt(): m_child(NULL) {}; void expect_lookup(const char *relpath, uint64_t ino) { - FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, 1000, 1); + FuseTest::expect_lookup(relpath, ino, S_IFREG | 0644, FILESIZE, 1); } /* @@ -306,6 +311,19 @@ void* write0(void* arg) { return (void*)(intptr_t)errno; } +void* read1(void* arg) { + const size_t bufsize = FILESIZE; + char buf[bufsize]; + int fd = (int)(intptr_t)arg; + ssize_t r; + + r = read(fd, buf, bufsize); + if (r >= 0) + return 0; + else + return (void*)(intptr_t)errno; +} + /* * An operation that hasn't yet been sent to userland can be interrupted * without sending FUSE_INTERRUPT @@ -375,7 +393,152 @@ TEST_F(Interrupt, in_kernel) sem_destroy(&sem0); } +/* + * A restartable operation (basically, anything except write or setextattr) + * that hasn't yet been sent to userland can be interrupted without sending + * FUSE_INTERRUPT, and will be automatically restarted. + */ +TEST_F(Interrupt, in_kernel_restartable) +{ + const char FULLPATH0[] = "mountpoint/some_file.txt"; + const char RELPATH0[] = "some_file.txt"; + const char FULLPATH1[] = "mountpoint/other_file.txt"; + const char RELPATH1[] = "other_file.txt"; + uint64_t ino0 = 42, ino1 = 43; + int fd0, fd1; + pthread_t self, th0, th1; + sem_t sem0, sem1; + void *thr0_value, *thr1_value; + + ASSERT_EQ(0, sem_init(&sem0, 0, 0)) << strerror(errno); + ASSERT_EQ(0, sem_init(&sem1, 0, 0)) << strerror(errno); + self = pthread_self(); + + expect_lookup(RELPATH0, ino0); + expect_open(ino0, 0, 1); + expect_lookup(RELPATH1, ino1); + expect_open(ino1, 0, 1); + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_WRITE && + in->header.nodeid == ino0); + }, Eq(true)), + _) + ).WillOnce(Invoke(ReturnImmediate([&](auto in, auto out) { + /* Let the next write proceed */ + sem_post(&sem1); + /* Pause the daemon thread so it won't read the next op */ + sem_wait(&sem0); + + SET_OUT_HEADER_LEN(out, write); + out->body.write.size = in->body.write.size; + }))); + FuseTest::expect_read(ino1, 0, FILESIZE, 0, NULL); + + fd0 = open(FULLPATH0, O_WRONLY); + ASSERT_LE(0, fd0) << strerror(errno); + fd1 = open(FULLPATH1, O_RDONLY); + ASSERT_LE(0, fd1) << strerror(errno); + + /* Use a separate thread for each operation */ + ASSERT_EQ(0, pthread_create(&th0, NULL, write0, (void*)(intptr_t)fd0)) + << strerror(errno); + + sem_wait(&sem1); /* Sequence the two operations */ + + ASSERT_EQ(0, pthread_create(&th1, NULL, read1, (void*)(intptr_t)fd1)) + << strerror(errno); + + setup_interruptor(self); + + pause(); /* Wait for signal */ + + /* Unstick the daemon */ + ASSERT_EQ(0, sem_post(&sem0)) << strerror(errno); + + /* Wait awhile to make sure the signal generates no FUSE_INTERRUPT */ + usleep(250'000); + + pthread_join(th1, &thr1_value); + pthread_join(th0, &thr0_value); + EXPECT_EQ(0, (intptr_t)thr1_value); + EXPECT_EQ(0, (intptr_t)thr0_value); + sem_destroy(&sem1); + sem_destroy(&sem0); +} + /* + * Like FUSE_WRITE, FUSE_SETXATTR is non-restartable because it calls uiomove + * before blocking in fticket_wait_answ + */ +TEST_F(Interrupt, in_kernel_setxattr) +{ + const char FULLPATH0[] = "mountpoint/some_file.txt"; + const char RELPATH0[] = "some_file.txt"; + const char FULLPATH1[] = "mountpoint/other_file.txt"; + const char RELPATH1[] = "other_file.txt"; + const char value[] = "whatever"; + ssize_t value_len = strlen(value) + 1; + uint64_t ino0 = 42, ino1 = 43; + int ns = EXTATTR_NAMESPACE_USER; + int fd0, fd1; + pthread_t self, th0; + sem_t sem0, sem1; + void *thr0_value; + ssize_t r; + + ASSERT_EQ(0, sem_init(&sem0, 0, 0)) << strerror(errno); + ASSERT_EQ(0, sem_init(&sem1, 0, 0)) << strerror(errno); + self = pthread_self(); + + expect_lookup(RELPATH0, ino0); + expect_open(ino0, 0, 1); + expect_lookup(RELPATH1, ino1); + expect_open(ino1, 0, 1); + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_WRITE && + in->header.nodeid == ino0); + }, Eq(true)), + _) + ).WillOnce(Invoke(ReturnImmediate([&](auto in, auto out) { + /* Let the next write proceed */ + sem_post(&sem1); + /* Pause the daemon thread so it won't read the next op */ + sem_wait(&sem0); + + SET_OUT_HEADER_LEN(out, write); + out->body.write.size = in->body.write.size; + }))); + + fd0 = open(FULLPATH0, O_WRONLY); + ASSERT_LE(0, fd0) << strerror(errno); + fd1 = open(FULLPATH1, O_WRONLY); + ASSERT_LE(0, fd1) << strerror(errno); + + /* Use a separate thread for the first write */ + ASSERT_EQ(0, pthread_create(&th0, NULL, write0, (void*)(intptr_t)fd0)) + << strerror(errno); + + setup_interruptor(self); + + sem_wait(&sem1); /* Sequence the two operations */ + r = extattr_set_fd(fd1, ns, "foo", (void*)value, value_len); + EXPECT_EQ(EINTR, errno); + + /* Unstick the daemon */ + ASSERT_EQ(0, sem_post(&sem0)) << strerror(errno); + + /* Wait awhile to make sure the signal generates no FUSE_INTERRUPT */ + usleep(250'000); + + pthread_join(th0, &thr0_value); + EXPECT_EQ(0, (intptr_t)thr0_value); + sem_destroy(&sem1); + sem_destroy(&sem0); +} + +/* * A syscall that gets interrupted while blocking on FUSE I/O should send a * FUSE_INTERRUPT command to the fuse filesystem, which should then send EINTR * in response to the _original_ operation. The kernel should ultimately @@ -527,10 +690,4 @@ TEST_F(Interrupt, too_soon) } -// TODO: add a test that uses siginterrupt and an interruptible signal -// TODO: add a test that verifies a process can be cleanly killed even if a -// FUSE_WRITE command never returns. -// TODO: write in-progress tests for other operations // TODO: add a test where write returns EWOULDBLOCK -// TODO: test that operations that haven't been received by the server can be -// interrupted without generating a FUSE_INTERRUPT. From owner-svn-src-projects@freebsd.org Fri Apr 19 21:50:25 2019 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 3387E1579F10 for ; Fri, 19 Apr 2019 21:50:25 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id D0FEF6D17A; Fri, 19 Apr 2019 21:50:24 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 9D4D6490F; Fri, 19 Apr 2019 21:50:24 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x3JLoOrm068955; Fri, 19 Apr 2019 21:50:24 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x3JLoNXA068951; Fri, 19 Apr 2019 21:50:23 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201904192150.x3JLoNXA068951@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers Date: Fri, 19 Apr 2019 21:50:23 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r346418 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Group: projects X-SVN-Commit-Author: asomers X-SVN-Commit-Paths: in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs X-SVN-Commit-Revision: 346418 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: D0FEF6D17A X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.98 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.98)[-0.985,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; NEURAL_HAM_LONG(-1.00)[-1.000,0] X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 19 Apr 2019 21:50:25 -0000 Author: asomers Date: Fri Apr 19 21:50:23 2019 New Revision: 346418 URL: https://svnweb.freebsd.org/changeset/base/346418 Log: fusefs: give priority to FUSE_INTERRUPT operations When interrupting a FUSE operation, send the FUSE_INTERRUPT op to the daemon ASAP, ahead of other unrelated operations. PR: 236530 Sponsored by: The FreeBSD Foundation Modified: projects/fuse2/sys/fs/fuse/fuse_internal.c projects/fuse2/sys/fs/fuse/fuse_ipc.c projects/fuse2/sys/fs/fuse/fuse_ipc.h projects/fuse2/sys/fs/fuse/fuse_vnops.c projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Modified: projects/fuse2/sys/fs/fuse/fuse_internal.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_internal.c Fri Apr 19 20:31:12 2019 (r346417) +++ projects/fuse2/sys/fs/fuse/fuse_internal.c Fri Apr 19 21:50:23 2019 (r346418) @@ -295,7 +295,7 @@ fuse_internal_fsync(struct vnode *vp, } else { fuse_insert_callback(fdi.tick, fuse_internal_fsync_callback); - fuse_insert_message(fdi.tick); + fuse_insert_message(fdi.tick, false); } if (err == ENOSYS) { /* ENOSYS means "success, and don't call again" */ @@ -593,7 +593,7 @@ fuse_internal_forget_send(struct mount *mp, ffi = fdi.indata; ffi->nlookup = nlookup; - fuse_insert_message(fdi.tick); + fuse_insert_message(fdi.tick, false); fdisp_destroy(&fdi); } @@ -736,7 +736,7 @@ fuse_internal_send_init(struct fuse_data *data, struct fiii->flags = FUSE_POSIX_LOCKS; fuse_insert_callback(fdi.tick, fuse_internal_init_callback); - fuse_insert_message(fdi.tick); + fuse_insert_message(fdi.tick, false); fdisp_destroy(&fdi); } Modified: projects/fuse2/sys/fs/fuse/fuse_ipc.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_ipc.c Fri Apr 19 20:31:12 2019 (r346417) +++ projects/fuse2/sys/fs/fuse/fuse_ipc.c Fri Apr 19 21:50:23 2019 (r346418) @@ -238,7 +238,8 @@ fuse_interrupt_send(struct fuse_ticket *otick, int err fuse_insert_callback(fdi.tick, fuse_interrupt_callback); otick->irq_unique = fdi.tick->tk_unique; - fuse_insert_message(fdi.tick); + /* Interrupt ops should be delivered ASAP */ + fuse_insert_message(fdi.tick, true); fdisp_destroy(&fdi); } else { /* This ticket has already been interrupted */ @@ -660,8 +661,14 @@ fuse_insert_callback(struct fuse_ticket *ftick, fuse_h fuse_lck_mtx_unlock(ftick->tk_data->aw_mtx); } +/* + * Insert a new upgoing ticket into the message queue + * + * If urgent is true, insert at the front of the queue. Otherwise, insert in + * FIFO order. + */ void -fuse_insert_message(struct fuse_ticket *ftick) +fuse_insert_message(struct fuse_ticket *ftick, bool urgent) { if (ftick->tk_flag & FT_DIRTY) { panic("FUSE: ticket reused without being refreshed"); @@ -672,7 +679,10 @@ fuse_insert_message(struct fuse_ticket *ftick) return; } fuse_lck_mtx_lock(ftick->tk_data->ms_mtx); - fuse_ms_push(ftick); + if (urgent) + fuse_ms_push_head(ftick); + else + fuse_ms_push(ftick); wakeup_one(ftick->tk_data); selwakeuppri(&ftick->tk_data->ks_rsel, PZERO + 1); fuse_lck_mtx_unlock(ftick->tk_data->ms_mtx); @@ -972,7 +982,7 @@ fdisp_wait_answ(struct fuse_dispatcher *fdip) fdip->answ_stat = 0; fuse_insert_callback(fdip->tick, fuse_standard_handler); - fuse_insert_message(fdip->tick); + fuse_insert_message(fdip->tick, false); if ((err = fticket_wait_answer(fdip->tick))) { fuse_lck_mtx_lock(fdip->tick->tk_aw_mtx); Modified: projects/fuse2/sys/fs/fuse/fuse_ipc.h ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_ipc.h Fri Apr 19 20:31:12 2019 (r346417) +++ projects/fuse2/sys/fs/fuse/fuse_ipc.h Fri Apr 19 21:50:23 2019 (r346418) @@ -285,6 +285,7 @@ fsess_opt_brokenio(struct mount *mp) return (fuse_fix_broken_io || (data->dataflags & FSESS_BROKENIO)); } +/* Insert a new upgoing message */ static inline void fuse_ms_push(struct fuse_ticket *ftick) { @@ -293,6 +294,15 @@ fuse_ms_push(struct fuse_ticket *ftick) STAILQ_INSERT_TAIL(&ftick->tk_data->ms_head, ftick, tk_ms_link); } +/* Insert a new upgoing message to the front of the queue */ +static inline void +fuse_ms_push_head(struct fuse_ticket *ftick) +{ + mtx_assert(&ftick->tk_data->ms_mtx, MA_OWNED); + refcount_acquire(&ftick->tk_refcount); + STAILQ_INSERT_HEAD(&ftick->tk_data->ms_head, ftick, tk_ms_link); +} + static inline struct fuse_ticket * fuse_ms_pop(struct fuse_data *data) { @@ -345,7 +355,7 @@ fuse_aw_pop(struct fuse_data *data) struct fuse_ticket *fuse_ticket_fetch(struct fuse_data *data); int fuse_ticket_drop(struct fuse_ticket *ftick); void fuse_insert_callback(struct fuse_ticket *ftick, fuse_handler_t *handler); -void fuse_insert_message(struct fuse_ticket *ftick); +void fuse_insert_message(struct fuse_ticket *ftick, bool irq); static inline bool fuse_libabi_geq(struct fuse_data *data, uint32_t abi_maj, uint32_t abi_min) Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_vnops.c Fri Apr 19 20:31:12 2019 (r346417) +++ projects/fuse2/sys/fs/fuse/fuse_vnops.c Fri Apr 19 21:50:23 2019 (r346418) @@ -592,7 +592,7 @@ fuse_vnop_create(struct vop_create_args *ap) fri->fh = fh_id; fri->flags = flags; fuse_insert_callback(fdip->tick, fuse_internal_forget_callback); - fuse_insert_message(fdip->tick); + fuse_insert_message(fdip->tick, false); goto out; } ASSERT_VOP_ELOCKED(*vpp, "fuse_vnop_create"); Modified: projects/fuse2/tests/sys/fs/fusefs/interrupt.cc ============================================================================== --- projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Fri Apr 19 20:31:12 2019 (r346417) +++ projects/fuse2/tests/sys/fs/fusefs/interrupt.cc Fri Apr 19 21:50:23 2019 (r346418) @@ -46,6 +46,8 @@ using namespace testing; /* Initial size of files used by these tests */ const off_t FILESIZE = 1000; +static sem_t *signaled_semaphore; + /* Don't do anything; all we care about is that the syscall gets interrupted */ void sigusr2_handler(int __unused sig) { if (verbosity > 1) { @@ -63,6 +65,8 @@ void* killer(void* target) { if (verbosity > 1) printf("Signalling! thread %p\n", target); pthread_kill((pthread_t)target, SIGUSR2); + if (signaled_semaphore != NULL) + sem_post(signaled_semaphore); return(NULL); } @@ -112,13 +116,18 @@ void expect_write(uint64_t ino, uint64_t *write_unique })); } -void setup_interruptor(pthread_t self) +void setup_interruptor(pthread_t target) { ASSERT_NE(SIG_ERR, signal(SIGUSR2, sigusr2_handler)) << strerror(errno); - ASSERT_EQ(0, pthread_create(&m_child, NULL, killer, (void*)self)) + ASSERT_EQ(0, pthread_create(&m_child, NULL, killer, (void*)target)) << strerror(errno); } +void SetUp() { + signaled_semaphore = NULL; + FuseTest::SetUp(); +} + void TearDown() { struct sigaction sa; @@ -624,6 +633,98 @@ TEST_F(Interrupt, in_progress_read) EXPECT_EQ(EINTR, errno); /* Deliberately leak fd. close(2) will be tested in release.cc */ +} + +/* FUSE_INTERRUPT operations should take priority over other pending ops */ +TEST_F(Interrupt, priority) +{ + const char FULLPATH0[] = "mountpoint/some_file.txt"; + const char RELPATH0[] = "some_file.txt"; + const char FULLPATH1[] = "mountpoint/other_file.txt"; + const char RELPATH1[] = "other_file.txt"; + const char *CONTENTS = "ijklmnop"; + Sequence seq; + ssize_t bufsize = strlen(CONTENTS); + uint64_t ino0 = 42, ino1 = 43; + int fd0, fd1; + uint64_t write_unique; + pthread_t self, th0; + sem_t sem0, sem1; + + ASSERT_EQ(0, sem_init(&sem0, 0, 0)) << strerror(errno); + ASSERT_EQ(0, sem_init(&sem1, 0, 0)) << strerror(errno); + self = pthread_self(); + + expect_lookup(RELPATH0, ino0); + expect_open(ino0, 0, 1); + expect_lookup(RELPATH1, ino1); + expect_open(ino1, 0, 1); + EXPECT_CALL(*m_mock, process( + ResultOf([=](auto in) { + return (in->header.opcode == FUSE_WRITE && + in->header.nodeid == ino0); + }, Eq(true)), + _) + ).InSequence(seq) + .WillOnce(Invoke(ReturnImmediate([&](auto in, auto out) { + write_unique = in->header.unique; + + /* Let the next write proceed */ + sem_post(&sem1); + + /* Pause the daemon thread so it won't read the next op */ + sem_wait(&sem0); + + /* Finally, interrupt the original op */ + out->header.error = -EINTR; + out->header.unique = write_unique; + out->header.len = sizeof(out->header); + }))); + /* + * FUSE_INTERRUPT should be received before the second FUSE_WRITE, even + * though it was generated later + */ + EXPECT_CALL(*m_mock, process( + ResultOf([&](auto in) { + return (in->header.opcode == FUSE_INTERRUPT && + in->body.interrupt.unique == write_unique); + }, Eq(true)), + _) + ).InSequence(seq) + .WillOnce(Invoke(ReturnErrno(EAGAIN))); + EXPECT_CALL(*m_mock, process( + ResultOf([&](auto in) { + return (in->header.opcode == FUSE_WRITE && + in->header.nodeid == ino1); + }, Eq(true)), + _) + ).InSequence(seq) + .WillOnce(Invoke(ReturnImmediate([=](auto in , auto out) { + SET_OUT_HEADER_LEN(out, write); + out->body.write.size = in->body.write.size; + }))); + + fd0 = open(FULLPATH0, O_WRONLY); + ASSERT_LE(0, fd0) << strerror(errno); + fd1 = open(FULLPATH1, O_WRONLY); + ASSERT_LE(0, fd1) << strerror(errno); + + /* Use a separate thread for the first write */ + ASSERT_EQ(0, pthread_create(&th0, NULL, write0, (void*)(intptr_t)fd0)) + << strerror(errno); + + signaled_semaphore = &sem0; + + sem_wait(&sem1); /* Sequence the two writes */ + setup_interruptor(th0); + ASSERT_EQ(bufsize, write(fd1, CONTENTS, bufsize)) << strerror(errno); + + /* Wait awhile to make sure the signal generates no FUSE_INTERRUPT */ + usleep(250'000); + + pthread_join(th0, NULL); + sem_destroy(&sem1); + sem_destroy(&sem0); } /* From owner-svn-src-projects@freebsd.org Fri Apr 19 23:04:09 2019 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 8E6E6157B700 for ; Fri, 19 Apr 2019 23:04:09 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 319116F8AB; Fri, 19 Apr 2019 23:04:09 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 0BDCC56C8; Fri, 19 Apr 2019 23:04:09 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x3JN48d3010898; Fri, 19 Apr 2019 23:04:08 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x3JN48Mc010893; Fri, 19 Apr 2019 23:04:08 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201904192304.x3JN48Mc010893@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers Date: Fri, 19 Apr 2019 23:04:08 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r346422 - projects/fuse2/sys/fs/fuse X-SVN-Group: projects X-SVN-Commit-Author: asomers X-SVN-Commit-Paths: projects/fuse2/sys/fs/fuse X-SVN-Commit-Revision: 346422 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 319116F8AB X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.98 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.98)[-0.984,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; NEURAL_HAM_LONG(-1.00)[-1.000,0] X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 19 Apr 2019 23:04:09 -0000 Author: asomers Date: Fri Apr 19 23:04:07 2019 New Revision: 346422 URL: https://svnweb.freebsd.org/changeset/base/346422 Log: fusefs: reap dead code Sponsored by: The FreeBSD Foundation Modified: projects/fuse2/sys/fs/fuse/fuse.h projects/fuse2/sys/fs/fuse/fuse_internal.h projects/fuse2/sys/fs/fuse/fuse_ipc.c projects/fuse2/sys/fs/fuse/fuse_ipc.h projects/fuse2/sys/fs/fuse/fuse_main.c Modified: projects/fuse2/sys/fs/fuse/fuse.h ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse.h Fri Apr 19 22:20:42 2019 (r346421) +++ projects/fuse2/sys/fs/fuse/fuse.h Fri Apr 19 23:04:07 2019 (r346422) @@ -63,84 +63,6 @@ #define FUSE_MIN_DAEMON_TIMEOUT 0 /* s */ #define FUSE_MAX_DAEMON_TIMEOUT 600 /* s */ -#ifndef FUSE_FREEBSD_VERSION -#define FUSE_FREEBSD_VERSION "0.4.4" -#endif - -/* Mapping versions to features */ - -#define FUSE_KERNELABI_GEQ(maj, min) \ -(FUSE_KERNEL_VERSION > (maj) || (FUSE_KERNEL_VERSION == (maj) && FUSE_KERNEL_MINOR_VERSION >= (min))) - -/* - * Appearance of new FUSE operations is not always in par with version - * numbering... At least, 7.3 is a sufficient condition for having - * FUSE_{ACCESS,CREATE}. - */ -#if FUSE_KERNELABI_GEQ(7, 3) -#ifndef FUSE_HAS_ACCESS -#define FUSE_HAS_ACCESS 1 -#endif -#ifndef FUSE_HAS_CREATE -#define FUSE_HAS_CREATE 1 -#endif -#else /* FUSE_KERNELABI_GEQ(7, 3) */ -#ifndef FUSE_HAS_ACCESS -#define FUSE_HAS_ACCESS 0 -#endif -#ifndef FUSE_HAS_CREATE -#define FUSE_HAS_CREATE 0 -#endif -#endif - -#if FUSE_KERNELABI_GEQ(7, 7) -#ifndef FUSE_HAS_GETLK -#define FUSE_HAS_GETLK 1 -#endif -#ifndef FUSE_HAS_SETLK -#define FUSE_HAS_SETLK 1 -#endif -#ifndef FUSE_HAS_SETLKW -#define FUSE_HAS_SETLKW 1 -#endif -#ifndef FUSE_HAS_INTERRUPT -#define FUSE_HAS_INTERRUPT 1 -#endif -#else /* FUSE_KERNELABI_GEQ(7, 7) */ -#ifndef FUSE_HAS_GETLK -#define FUSE_HAS_GETLK 0 -#endif -#ifndef FUSE_HAS_SETLK -#define FUSE_HAS_SETLK 0 -#endif -#ifndef FUSE_HAS_SETLKW -#define FUSE_HAS_SETLKW 0 -#endif -#ifndef FUSE_HAS_INTERRUPT -#define FUSE_HAS_INTERRUPT 0 -#endif -#endif - -#if FUSE_KERNELABI_GEQ(7, 8) -#ifndef FUSE_HAS_FLUSH_RELEASE -#define FUSE_HAS_FLUSH_RELEASE 1 -/* - * "DESTROY" came in the middle of the 7.8 era, - * so this is not completely exact... - */ -#ifndef FUSE_HAS_DESTROY -#define FUSE_HAS_DESTROY 1 -#endif -#endif -#else /* FUSE_KERNELABI_GEQ(7, 8) */ -#ifndef FUSE_HAS_FLUSH_RELEASE -#define FUSE_HAS_FLUSH_RELEASE 0 -#ifndef FUSE_HAS_DESTROY -#define FUSE_HAS_DESTROY 0 -#endif -#endif -#endif - /* misc */ SYSCTL_DECL(_vfs_fusefs); Modified: projects/fuse2/sys/fs/fuse/fuse_internal.h ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_internal.h Fri Apr 19 22:20:42 2019 (r346421) +++ projects/fuse2/sys/fs/fuse/fuse_internal.h Fri Apr 19 23:04:07 2019 (r346422) @@ -80,12 +80,6 @@ vnode_mount(struct vnode *vp) return (vp->v_mount); } -static inline bool -vnode_mountedhere(struct vnode *vp) -{ - return (vp->v_mountedhere != NULL); -} - static inline enum vtype vnode_vtype(struct vnode *vp) { Modified: projects/fuse2/sys/fs/fuse/fuse_ipc.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_ipc.c Fri Apr 19 22:20:42 2019 (r346421) +++ projects/fuse2/sys/fs/fuse/fuse_ipc.c Fri Apr 19 23:04:07 2019 (r346422) @@ -109,8 +109,6 @@ static int fuse_body_audit(struct fuse_ticket *ftick, static fuse_handler_t fuse_standard_handler; SYSCTL_NODE(_vfs, OID_AUTO, fusefs, CTLFLAG_RW, 0, "FUSE tunables"); -SYSCTL_STRING(_vfs_fusefs, OID_AUTO, version, CTLFLAG_RD, - FUSE_FREEBSD_VERSION, 0, "fuse-freebsd version"); static int fuse_ticket_count = 0; SYSCTL_INT(_vfs_fusefs, OID_AUTO, ticket_count, CTLFLAG_RW, Modified: projects/fuse2/sys/fs/fuse/fuse_ipc.h ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_ipc.h Fri Apr 19 22:20:42 2019 (r346421) +++ projects/fuse2/sys/fs/fuse/fuse_ipc.h Fri Apr 19 23:04:07 2019 (r346422) @@ -167,8 +167,6 @@ fticket_opcode(struct fuse_ticket *ftick) int fticket_pull(struct fuse_ticket *ftick, struct uio *uio); -enum mountpri { FM_NOMOUNTED, FM_PRIMARY, FM_SECONDARY }; - /* * The data representing a FUSE session. */ Modified: projects/fuse2/sys/fs/fuse/fuse_main.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_main.c Fri Apr 19 22:20:42 2019 (r346421) +++ projects/fuse2/sys/fs/fuse/fuse_main.c Fri Apr 19 23:04:07 2019 (r346422) @@ -137,11 +137,6 @@ fuse_loader(struct module *m, int what, void *arg) /* vfs_modevent ignores its first arg */ if ((err = vfs_modevent(NULL, what, &fuse_vfsconf))) fuse_bringdown(eh_tag); - else - printf("fuse-freebsd: version %s, FUSE ABI %d.%d\n", - FUSE_FREEBSD_VERSION, - FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); - break; case MOD_UNLOAD: if ((err = vfs_modevent(NULL, what, &fuse_vfsconf))) From owner-svn-src-projects@freebsd.org Sat Apr 20 00:04:34 2019 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 428B6157CF16 for ; Sat, 20 Apr 2019 00:04:34 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id D957672553; Sat, 20 Apr 2019 00:04:33 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 90F8960DC; Sat, 20 Apr 2019 00:04:33 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x3K04XUK045220; Sat, 20 Apr 2019 00:04:33 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x3K04VA1045211; Sat, 20 Apr 2019 00:04:31 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201904200004.x3K04VA1045211@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers Date: Sat, 20 Apr 2019 00:04:31 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r346425 - projects/fuse2/sys/fs/fuse X-SVN-Group: projects X-SVN-Commit-Author: asomers X-SVN-Commit-Paths: projects/fuse2/sys/fs/fuse X-SVN-Commit-Revision: 346425 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: D957672553 X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.97 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.97)[-0.969,0]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US] X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 20 Apr 2019 00:04:34 -0000 Author: asomers Date: Sat Apr 20 00:04:31 2019 New Revision: 346425 URL: https://svnweb.freebsd.org/changeset/base/346425 Log: fusefs: rename the SDT probes from "fuse" to "fusefs" This matches the new name of the kld. Sponsored by: The FreeBSD Foundation Modified: projects/fuse2/sys/fs/fuse/fuse_device.c projects/fuse2/sys/fs/fuse/fuse_file.c projects/fuse2/sys/fs/fuse/fuse_internal.c projects/fuse2/sys/fs/fuse/fuse_io.c projects/fuse2/sys/fs/fuse/fuse_ipc.c projects/fuse2/sys/fs/fuse/fuse_main.c projects/fuse2/sys/fs/fuse/fuse_node.c projects/fuse2/sys/fs/fuse/fuse_vfsops.c projects/fuse2/sys/fs/fuse/fuse_vnops.c Modified: projects/fuse2/sys/fs/fuse/fuse_device.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_device.c Fri Apr 19 23:35:08 2019 (r346424) +++ projects/fuse2/sys/fs/fuse/fuse_device.c Sat Apr 20 00:04:31 2019 (r346425) @@ -83,13 +83,13 @@ __FBSDID("$FreeBSD$"); #include "fuse.h" #include "fuse_ipc.h" -SDT_PROVIDER_DECLARE(fuse); +SDT_PROVIDER_DECLARE(fusefs); /* * Fuse trace probe: * arg0: verbosity. Higher numbers give more verbose messages * arg1: Textual message */ -SDT_PROBE_DEFINE2(fuse, , device, trace, "int", "char*"); +SDT_PROBE_DEFINE2(fusefs, , device, trace, "int", "char*"); static struct cdev *fuse_dev; @@ -133,14 +133,14 @@ fuse_device_open(struct cdev *dev, int oflags, int dev struct fuse_data *fdata; int error; - SDT_PROBE2(fuse, , device, trace, 1, "device open"); + SDT_PROBE2(fusefs, , device, trace, 1, "device open"); fdata = fdata_alloc(dev, td->td_ucred); error = devfs_set_cdevpriv(fdata, fdata_dtor); if (error != 0) fdata_trydestroy(fdata); else - SDT_PROBE2(fuse, , device, trace, 1, "device open success"); + SDT_PROBE2(fusefs, , device, trace, 1, "device open success"); return (error); } @@ -175,7 +175,7 @@ fuse_device_close(struct cdev *dev, int fflag, int dev fuse_lck_mtx_unlock(data->aw_mtx); FUSE_UNLOCK(); - SDT_PROBE2(fuse, , device, trace, 1, "device close"); + SDT_PROBE2(fusefs, , device, trace, 1, "device close"); return (0); } @@ -219,7 +219,7 @@ fuse_device_read(struct cdev *dev, struct uio *uio, in int buflen[3]; int i; - SDT_PROBE2(fuse, , device, trace, 1, "fuse device read"); + SDT_PROBE2(fusefs, , device, trace, 1, "fuse device read"); err = devfs_get_cdevpriv((void **)&data); if (err != 0) @@ -228,7 +228,7 @@ fuse_device_read(struct cdev *dev, struct uio *uio, in fuse_lck_mtx_lock(data->ms_mtx); again: if (fdata_get_dead(data)) { - SDT_PROBE2(fuse, , device, trace, 2, + SDT_PROBE2(fusefs, , device, trace, 2, "we know early on that reader should be kicked so we " "don't wait for news"); fuse_lck_mtx_unlock(data->ms_mtx); @@ -256,7 +256,7 @@ again: * -- and some other cases, too, tho not totally clear, when * (cv_signal/wakeup_one signals the whole process ?) */ - SDT_PROBE2(fuse, , device, trace, 1, "no message on thread"); + SDT_PROBE2(fusefs, , device, trace, 1, "no message on thread"); goto again; } fuse_lck_mtx_unlock(data->ms_mtx); @@ -266,9 +266,10 @@ again: * somebody somewhere -- eg., umount routine -- * wants this liaison finished off */ - SDT_PROBE2(fuse, , device, trace, 2, "reader is to be sacked"); + SDT_PROBE2(fusefs, , device, trace, 2, + "reader is to be sacked"); if (tick) { - SDT_PROBE2(fuse, , device, trace, 2, "weird -- " + SDT_PROBE2(fusefs, , device, trace, 2, "weird -- " "\"kick\" is set tho there is message"); FUSE_ASSERT_MS_DONE(tick); fuse_ticket_drop(tick); @@ -276,7 +277,7 @@ again: return (ENODEV); /* This should make the daemon get off * of us */ } - SDT_PROBE2(fuse, , device, trace, 1, + SDT_PROBE2(fusefs, , device, trace, 1, "fuse device read message successfully"); KASSERT(tick->tk_ms_bufdata || tick->tk_ms_bufsize == 0, @@ -311,7 +312,7 @@ again: */ if (uio->uio_resid < buflen[i]) { fdata_set_dead(data); - SDT_PROBE2(fuse, , device, trace, 2, + SDT_PROBE2(fusefs, , device, trace, 2, "daemon is stupid, kick it off..."); err = ENODEV; break; @@ -331,12 +332,13 @@ static inline int fuse_ohead_audit(struct fuse_out_header *ohead, struct uio *uio) { if (uio->uio_resid + sizeof(struct fuse_out_header) != ohead->len) { - SDT_PROBE2(fuse, , device, trace, 1, "Format error: body size " + SDT_PROBE2(fusefs, , device, trace, 1, + "Format error: body size " "differs from size claimed by header"); return (EINVAL); } if (uio->uio_resid && ohead->error) { - SDT_PROBE2(fuse, , device, trace, 1, + SDT_PROBE2(fusefs, , device, trace, 1, "Format error: non zero error but message had a body"); return (EINVAL); } @@ -346,8 +348,10 @@ fuse_ohead_audit(struct fuse_out_header *ohead, struct return (0); } -SDT_PROBE_DEFINE1(fuse, , device, fuse_device_write_missing_ticket, "uint64_t"); -SDT_PROBE_DEFINE1(fuse, , device, fuse_device_write_found, "struct fuse_ticket*"); +SDT_PROBE_DEFINE1(fusefs, , device, fuse_device_write_missing_ticket, + "uint64_t"); +SDT_PROBE_DEFINE1(fusefs, , device, fuse_device_write_found, + "struct fuse_ticket*"); /* * fuse_device_write first reads the header sent by the daemon. * If that's OK, looks up ticket/callback node by the unique id seen in header. @@ -368,7 +372,7 @@ fuse_device_write(struct cdev *dev, struct uio *uio, i return (err); if (uio->uio_resid < sizeof(struct fuse_out_header)) { - SDT_PROBE2(fuse, , device, trace, 1, + SDT_PROBE2(fusefs, , device, trace, 1, "fuse_device_write got less than a header!"); fdata_set_dead(data); return (EINVAL); @@ -394,7 +398,7 @@ fuse_device_write(struct cdev *dev, struct uio *uio, i TAILQ_FOREACH_SAFE(tick, &data->aw_head, tk_aw_link, x_tick) { if (tick->tk_unique == ohead.unique) { - SDT_PROBE1(fuse, , device, fuse_device_write_found, + SDT_PROBE1(fusefs, , device, fuse_device_write_found, tick); found = 1; fuse_aw_remove(tick); @@ -427,13 +431,13 @@ fuse_device_write(struct cdev *dev, struct uio *uio, i * via ticket_drop(), so no manual mucking * around...) */ - SDT_PROBE2(fuse, , device, trace, 1, + SDT_PROBE2(fusefs, , device, trace, 1, "pass ticket to a callback"); memcpy(&tick->tk_aw_ohead, &ohead, sizeof(ohead)); err = tick->tk_aw_handler(tick, uio); } else { /* pretender doesn't wanna do anything with answer */ - SDT_PROBE2(fuse, , device, trace, 1, + SDT_PROBE2(fusefs, , device, trace, 1, "stuff devalidated, so we drop it"); } @@ -445,7 +449,7 @@ fuse_device_write(struct cdev *dev, struct uio *uio, i fuse_ticket_drop(tick); } else { /* no callback at all! */ - SDT_PROBE1(fuse, , device, fuse_device_write_missing_ticket, + SDT_PROBE1(fusefs, , device, fuse_device_write_missing_ticket, ohead.unique); if (ohead.error == EAGAIN) { /* Modified: projects/fuse2/sys/fs/fuse/fuse_file.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_file.c Fri Apr 19 23:35:08 2019 (r346424) +++ projects/fuse2/sys/fs/fuse/fuse_file.c Sat Apr 20 00:04:31 2019 (r346425) @@ -85,13 +85,13 @@ __FBSDID("$FreeBSD$"); MALLOC_DEFINE(M_FUSE_FILEHANDLE, "fuse_filefilehandle", "FUSE file handle"); -SDT_PROVIDER_DECLARE(fuse); +SDT_PROVIDER_DECLARE(fusefs); /* * Fuse trace probe: * arg0: verbosity. Higher numbers give more verbose messages * arg1: Textual message */ -SDT_PROBE_DEFINE2(fuse, , file, trace, "int", "char*"); +SDT_PROBE_DEFINE2(fusefs, , file, trace, "int", "char*"); static int fuse_fh_count = 0; @@ -180,7 +180,7 @@ fuse_filehandle_open(struct vnode *vp, int a_mode, foi->flags = oflags; if ((err = fdisp_wait_answ(&fdi))) { - SDT_PROBE2(fuse, , file, trace, 1, + SDT_PROBE2(fusefs, , file, trace, 1, "OUCH ... daemon didn't give fh"); if (err == ENOENT) { fuse_internal_vnode_disappear(vp); Modified: projects/fuse2/sys/fs/fuse/fuse_internal.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_internal.c Fri Apr 19 23:35:08 2019 (r346424) +++ projects/fuse2/sys/fs/fuse/fuse_internal.c Sat Apr 20 00:04:31 2019 (r346425) @@ -93,13 +93,13 @@ __FBSDID("$FreeBSD$"); #include "fuse_node.h" #include "fuse_file.h" -SDT_PROVIDER_DECLARE(fuse); +SDT_PROVIDER_DECLARE(fusefs); /* * Fuse trace probe: * arg0: verbosity. Higher numbers give more verbose messages * arg1: Textual message */ -SDT_PROBE_DEFINE2(fuse, , internal, trace, "int", "char*"); +SDT_PROBE_DEFINE2(fusefs, , internal, trace, "int", "char*"); #ifdef ZERO_PAD_INCOMPLETE_BUFS static int isbzero(void *buf, size_t len); @@ -683,7 +683,7 @@ fuse_internal_init_callback(struct fuse_ticket *tick, /* XXX: Do we want to check anything further besides this? */ if (fiio->major < 7) { - SDT_PROBE2(fuse, , internal, trace, 1, + SDT_PROBE2(fusefs, , internal, trace, 1, "userpace version too low"); err = EPROTONOSUPPORT; goto out; Modified: projects/fuse2/sys/fs/fuse/fuse_io.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_io.c Fri Apr 19 23:35:08 2019 (r346424) +++ projects/fuse2/sys/fs/fuse/fuse_io.c Sat Apr 20 00:04:31 2019 (r346425) @@ -98,13 +98,13 @@ __FBSDID("$FreeBSD$"); #include "fuse_ipc.h" #include "fuse_io.h" -SDT_PROVIDER_DECLARE(fuse); +SDT_PROVIDER_DECLARE(fusefs); /* * Fuse trace probe: * arg0: verbosity. Higher numbers give more verbose messages * arg1: Textual message */ -SDT_PROBE_DEFINE2(fuse, , io, trace, "int", "char*"); +SDT_PROBE_DEFINE2(fusefs, , io, trace, "int", "char*"); static int fuse_read_directbackend(struct vnode *vp, struct uio *uio, @@ -119,7 +119,7 @@ static int fuse_write_biobackend(struct vnode *vp, struct uio *uio, struct ucred *cred, struct fuse_filehandle *fufh, int ioflag, pid_t pid); -SDT_PROBE_DEFINE5(fuse, , io, io_dispatch, "struct vnode*", "struct uio*", +SDT_PROBE_DEFINE5(fusefs, , io, io_dispatch, "struct vnode*", "struct uio*", "int", "struct ucred*", "struct fuse_filehandle*"); int fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag, @@ -137,7 +137,7 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, in printf("FUSE: io dispatch: filehandles are closed\n"); return err; } - SDT_PROBE5(fuse, , io, io_dispatch, vp, uio, ioflag, cred, fufh); + SDT_PROBE5(fusefs, , io, io_dispatch, vp, uio, ioflag, cred, fufh); /* * Ideally, when the daemon asks for direct io at open time, the @@ -154,11 +154,11 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, in switch (uio->uio_rw) { case UIO_READ: if (directio) { - SDT_PROBE2(fuse, , io, trace, 1, + SDT_PROBE2(fusefs, , io, trace, 1, "direct read of vnode"); err = fuse_read_directbackend(vp, uio, cred, fufh); } else { - SDT_PROBE2(fuse, , io, trace, 1, + SDT_PROBE2(fusefs, , io, trace, 1, "buffered read of vnode"); err = fuse_read_biobackend(vp, uio, cred, fufh, pid); } @@ -173,7 +173,7 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, in if (directio || fuse_data_cache_mode == FUSE_CACHE_WT) { off_t start, end; - SDT_PROBE2(fuse, , io, trace, 1, + SDT_PROBE2(fusefs, , io, trace, 1, "direct write of vnode"); start = uio->uio_offset; end = start + uio->uio_resid; @@ -181,7 +181,7 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, in err = fuse_write_directbackend(vp, uio, cred, fufh, ioflag); } else { - SDT_PROBE2(fuse, , io, trace, 1, + SDT_PROBE2(fusefs, , io, trace, 1, "buffered write of vnode"); err = fuse_write_biobackend(vp, uio, cred, fufh, ioflag, pid); @@ -194,9 +194,9 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, in return (err); } -SDT_PROBE_DEFINE3(fuse, , io, read_bio_backend_start, "int", "int", "int"); -SDT_PROBE_DEFINE2(fuse, , io, read_bio_backend_feed, "int", "int"); -SDT_PROBE_DEFINE3(fuse, , io, read_bio_backend_end, "int", "ssize_t", "int"); +SDT_PROBE_DEFINE3(fusefs, , io, read_bio_backend_start, "int", "int", "int"); +SDT_PROBE_DEFINE2(fusefs, , io, read_bio_backend_feed, "int", "int"); +SDT_PROBE_DEFINE3(fusefs, , io, read_bio_backend_end, "int", "ssize_t", "int"); static int fuse_read_biobackend(struct vnode *vp, struct uio *uio, struct ucred *cred, struct fuse_filehandle *fufh, pid_t pid) @@ -225,7 +225,7 @@ fuse_read_biobackend(struct vnode *vp, struct uio *uio lbn = uio->uio_offset / biosize; on = uio->uio_offset & (biosize - 1); - SDT_PROBE3(fuse, , io, read_bio_backend_start, + SDT_PROBE3(fusefs, , io, read_bio_backend_start, biosize, (int)lbn, on); /* @@ -275,20 +275,21 @@ fuse_read_biobackend(struct vnode *vp, struct uio *uio if (on < bcount) n = MIN((unsigned)(bcount - on), uio->uio_resid); if (n > 0) { - SDT_PROBE2(fuse, , io, read_bio_backend_feed, + SDT_PROBE2(fusefs, , io, read_bio_backend_feed, n, n + (int)bp->b_resid); err = uiomove(bp->b_data + on, n, uio); } brelse(bp); - SDT_PROBE3(fuse, , io, read_bio_backend_end, err, + SDT_PROBE3(fusefs, , io, read_bio_backend_end, err, uio->uio_resid, n); } while (err == 0 && uio->uio_resid > 0 && n > 0); return (err); } -SDT_PROBE_DEFINE1(fuse, , io, read_directbackend_start, "struct fuse_read_in*"); -SDT_PROBE_DEFINE2(fuse, , io, read_directbackend_complete, +SDT_PROBE_DEFINE1(fusefs, , io, read_directbackend_start, + "struct fuse_read_in*"); +SDT_PROBE_DEFINE2(fusefs, , io, read_directbackend_complete, "struct fuse_dispatcher*", "struct uio*"); static int @@ -321,12 +322,12 @@ fuse_read_directbackend(struct vnode *vp, struct uio * fri->size = MIN(uio->uio_resid, fuse_get_mpdata(vp->v_mount)->max_read); - SDT_PROBE1(fuse, , io, read_directbackend_start, fri); + SDT_PROBE1(fusefs, , io, read_directbackend_start, fri); if ((err = fdisp_wait_answ(&fdi))) goto out; - SDT_PROBE2(fuse, , io, read_directbackend_complete, + SDT_PROBE2(fusefs, , io, read_directbackend_complete, fdi.iosize, uio); if ((err = uiomove(fdi.answ, MIN(fri->size, fdi.iosize), uio))) @@ -453,9 +454,9 @@ retry: return (err); } -SDT_PROBE_DEFINE6(fuse, , io, write_biobackend_start, "int64_t", "int", "int", +SDT_PROBE_DEFINE6(fusefs, , io, write_biobackend_start, "int64_t", "int", "int", "struct uio*", "int", "bool"); -SDT_PROBE_DEFINE2(fuse, , io, write_biobackend_append_race, "long", "int"); +SDT_PROBE_DEFINE2(fusefs, , io, write_biobackend_append_race, "long", "int"); static int fuse_write_biobackend(struct vnode *vp, struct uio *uio, @@ -509,7 +510,7 @@ again: * readers from reading garbage. */ bcount = on; - SDT_PROBE6(fuse, , io, write_biobackend_start, + SDT_PROBE6(fusefs, , io, write_biobackend_start, lbn, on, n, uio, bcount, true); bp = getblk(vp, lbn, bcount, PCATCH, 0, 0); @@ -540,7 +541,7 @@ again: bcount = fvdat->filesize - (off_t)lbn *biosize; } - SDT_PROBE6(fuse, , io, write_biobackend_start, + SDT_PROBE6(fusefs, , io, write_biobackend_start, lbn, on, n, uio, bcount, false); bp = getblk(vp, lbn, bcount, PCATCH, 0, 0); if (bp && uio->uio_offset + n > fvdat->filesize) { @@ -603,7 +604,7 @@ again: */ if (bp->b_dirtyend > bcount) { - SDT_PROBE2(fuse, , io, write_biobackend_append_race, + SDT_PROBE2(fusefs, , io, write_biobackend_append_race, (long)bp->b_blkno * biosize, bp->b_dirtyend - bcount); bp->b_dirtyend = bcount; @@ -784,7 +785,7 @@ fuse_io_strategy(struct vnode *vp, struct buf *bp) * If we only need to commit, try to commit */ if (bp->b_flags & B_NEEDCOMMIT) { - SDT_PROBE2(fuse, , io, trace, 1, + SDT_PROBE2(fusefs, , io, trace, 1, "write: B_NEEDCOMMIT flags set"); } /* Modified: projects/fuse2/sys/fs/fuse/fuse_ipc.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_ipc.c Fri Apr 19 23:35:08 2019 (r346424) +++ projects/fuse2/sys/fs/fuse/fuse_ipc.c Sat Apr 20 00:04:31 2019 (r346425) @@ -84,13 +84,13 @@ __FBSDID("$FreeBSD$"); #include "fuse_ipc.h" #include "fuse_internal.h" -SDT_PROVIDER_DECLARE(fuse); +SDT_PROVIDER_DECLARE(fusefs); /* * Fuse trace probe: * arg0: verbosity. Higher numbers give more verbose messages * arg1: Textual message */ -SDT_PROBE_DEFINE2(fuse, , ipc, trace, "int", "char*"); +SDT_PROBE_DEFINE2(fusefs, , ipc, trace, "int", "char*"); static void fdisp_make_pid(struct fuse_dispatcher *fdip, enum fuse_opcode op, struct fuse_data *data, uint64_t nid, pid_t pid, struct ucred *cred); @@ -454,7 +454,7 @@ retry: data->daemon_timeout * hz); kern_sigprocmask(td, SIG_SETMASK, &oldset, NULL, 0); if (err == EWOULDBLOCK) { - SDT_PROBE2(fuse, , ipc, trace, 3, + SDT_PROBE2(fusefs, , ipc, trace, 3, "fticket_wait_answer: EWOULDBLOCK"); #ifdef XXXIP /* die conditionally */ if (!fdata_get_dead(data)) { @@ -477,7 +477,7 @@ retry: */ int sig; - SDT_PROBE2(fuse, , ipc, trace, 4, + SDT_PROBE2(fusefs, , ipc, trace, 4, "fticket_wait_answer: interrupt"); fuse_lck_mtx_unlock(ftick->tk_aw_mtx); fuse_interrupt_send(ftick, err); @@ -500,14 +500,14 @@ retry: /* Return immediately for fatal signals */ } } else if (err) { - SDT_PROBE2(fuse, , ipc, trace, 6, + SDT_PROBE2(fusefs, , ipc, trace, 6, "fticket_wait_answer: other error"); } else { - SDT_PROBE2(fuse, , ipc, trace, 7, "fticket_wait_answer: OK"); + SDT_PROBE2(fusefs, , ipc, trace, 7, "fticket_wait_answer: OK"); } out: if (!(err || fticket_answered(ftick))) { - SDT_PROBE2(fuse, , ipc, trace, 1, + SDT_PROBE2(fusefs, , ipc, trace, 1, "FUSE: requester was woken up but still no answer"); err = ENXIO; } @@ -971,7 +971,7 @@ fdisp_refresh(struct fuse_dispatcher *fdip) fticket_refresh(fdip->tick); } -SDT_PROBE_DEFINE2(fuse, , ipc, fdisp_wait_answ_error, "char*", "int"); +SDT_PROBE_DEFINE2(fusefs, , ipc, fdisp_wait_answ_error, "char*", "int"); int fdisp_wait_answ(struct fuse_dispatcher *fdip) @@ -991,7 +991,7 @@ fdisp_wait_answ(struct fuse_dispatcher *fdip) * the standard handler has completed his job. * So we drop the ticket and exit as usual. */ - SDT_PROBE2(fuse, , ipc, fdisp_wait_answ_error, + SDT_PROBE2(fusefs, , ipc, fdisp_wait_answ_error, "IPC: interrupted, already answered", err); fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx); goto out; @@ -1001,7 +1001,7 @@ fdisp_wait_answ(struct fuse_dispatcher *fdip) * Then by setting the answered flag we get *him* * to drop the ticket. */ - SDT_PROBE2(fuse, , ipc, fdisp_wait_answ_error, + SDT_PROBE2(fusefs, , ipc, fdisp_wait_answ_error, "IPC: interrupted, setting to answered", err); fticket_set_answered(fdip->tick); fuse_lck_mtx_unlock(fdip->tick->tk_aw_mtx); @@ -1010,13 +1010,13 @@ fdisp_wait_answ(struct fuse_dispatcher *fdip) } if (fdip->tick->tk_aw_errno) { - SDT_PROBE2(fuse, , ipc, fdisp_wait_answ_error, + SDT_PROBE2(fusefs, , ipc, fdisp_wait_answ_error, "IPC: explicit EIO-ing", fdip->tick->tk_aw_errno); err = EIO; goto out; } if ((err = fdip->tick->tk_aw_ohead.error)) { - SDT_PROBE2(fuse, , ipc, fdisp_wait_answ_error, + SDT_PROBE2(fusefs, , ipc, fdisp_wait_answ_error, "IPC: setting status", fdip->tick->tk_aw_ohead.error); /* * This means a "proper" fuse syscall error. Modified: projects/fuse2/sys/fs/fuse/fuse_main.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_main.c Fri Apr 19 23:35:08 2019 (r346424) +++ projects/fuse2/sys/fs/fuse/fuse_main.c Sat Apr 20 00:04:31 2019 (r346425) @@ -100,7 +100,7 @@ SYSCTL_INT(_vfs_fusefs, OID_AUTO, kernelabi_major, CTL SYSCTL_NULL_INT_PTR, FUSE_KERNEL_VERSION, "FUSE kernel abi major version"); SYSCTL_INT(_vfs_fusefs, OID_AUTO, kernelabi_minor, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, FUSE_KERNEL_MINOR_VERSION, "FUSE kernel abi minor version"); -SDT_PROVIDER_DEFINE(fuse); +SDT_PROVIDER_DEFINE(fusefs); /****************************** * Modified: projects/fuse2/sys/fs/fuse/fuse_node.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_node.c Fri Apr 19 23:35:08 2019 (r346424) +++ projects/fuse2/sys/fs/fuse/fuse_node.c Sat Apr 20 00:04:31 2019 (r346425) @@ -90,13 +90,13 @@ __FBSDID("$FreeBSD$"); #include "fuse_io.h" #include "fuse_ipc.h" -SDT_PROVIDER_DECLARE(fuse); +SDT_PROVIDER_DECLARE(fusefs); /* * Fuse trace probe: * arg0: verbosity. Higher numbers give more verbose messages * arg1: Textual message */ -SDT_PROBE_DEFINE2(fuse, , node, trace, "int", "char*"); +SDT_PROBE_DEFINE2(fusefs, , node, trace, "int", "char*"); MALLOC_DEFINE(M_FUSEVN, "fuse_vnode", "fuse vnode private data"); @@ -244,7 +244,7 @@ fuse_vnode_alloc(struct mount *mp, return (EAGAIN); } MPASS((*vpp)->v_data != NULL); - SDT_PROBE2(fuse, , node, trace, 1, "vnode taken from hash"); + SDT_PROBE2(fusefs, , node, trace, 1, "vnode taken from hash"); return (0); } fvdat = malloc(sizeof(*fvdat), M_FUSEVN, M_WAITOK | M_ZERO); @@ -409,7 +409,7 @@ fuse_vnode_refreshsize(struct vnode *vp, struct ucred return 0; err = VOP_GETATTR(vp, &va, cred); - SDT_PROBE2(fuse, , node, trace, 1, "refreshed file size"); + SDT_PROBE2(fusefs, , node, trace, 1, "refreshed file size"); return err; } Modified: projects/fuse2/sys/fs/fuse/fuse_vfsops.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_vfsops.c Fri Apr 19 23:35:08 2019 (r346424) +++ projects/fuse2/sys/fs/fuse/fuse_vfsops.c Sat Apr 20 00:04:31 2019 (r346425) @@ -88,13 +88,13 @@ __FBSDID("$FreeBSD$"); #include #include -SDT_PROVIDER_DECLARE(fuse); +SDT_PROVIDER_DECLARE(fusefs); /* * Fuse trace probe: * arg0: verbosity. Higher numbers give more verbose messages * arg1: Textual message */ -SDT_PROBE_DEFINE2(fuse, , vfsops, trace, "int", "char*"); +SDT_PROBE_DEFINE2(fusefs, , vfsops, trace, "int", "char*"); /* This will do for privilege types for now */ #ifndef PRIV_VFS_FUSE_ALLOWOTHER @@ -207,8 +207,8 @@ fuse_getdevice(const char *fspec, struct thread *td, s vfs_flagopt(opts, "__" #fnam, &__mntopts, fval); \ } while (0) -SDT_PROBE_DEFINE1(fuse, , vfsops, mntopts, "uint64_t"); -SDT_PROBE_DEFINE4(fuse, , vfsops, mount_err, "char*", "struct fuse_data*", +SDT_PROBE_DEFINE1(fusefs, , vfsops, mntopts, "uint64_t"); +SDT_PROBE_DEFINE4(fusefs, , vfsops, mount_err, "char*", "struct fuse_data*", "struct mount*", "int"); static int @@ -292,11 +292,11 @@ fuse_vfsop_mount(struct mount *mp) } subtype = vfs_getopts(opts, "subtype=", &err); - SDT_PROBE1(fuse, , vfsops, mntopts, mntopts); + SDT_PROBE1(fusefs, , vfsops, mntopts, mntopts); err = fget(td, fd, &cap_read_rights, &fp); if (err != 0) { - SDT_PROBE2(fuse, , vfsops, trace, 1, + SDT_PROBE2(fusefs, , vfsops, trace, 1, "invalid or not opened device"); goto out; } @@ -308,14 +308,14 @@ fuse_vfsop_mount(struct mount *mp) FUSE_LOCK(); if (err != 0 || data == NULL || data->mp != NULL) { err = ENXIO; - SDT_PROBE4(fuse, , vfsops, mount_err, + SDT_PROBE4(fusefs, , vfsops, mount_err, "invalid or not opened device", data, mp, err); FUSE_UNLOCK(); goto out; } if (fdata_get_dead(data)) { err = ENOTCONN; - SDT_PROBE4(fuse, , vfsops, mount_err, + SDT_PROBE4(fusefs, , vfsops, mount_err, "device is dead during mount", data, mp, err); FUSE_UNLOCK(); goto out; @@ -365,7 +365,7 @@ out: * Destroy device only if we acquired reference to * it */ - SDT_PROBE4(fuse, , vfsops, mount_err, + SDT_PROBE4(fusefs, , vfsops, mount_err, "mount failed, destroy device", data, mp, err); data->mp = NULL; fdata_trydestroy(data); @@ -453,13 +453,13 @@ fuse_vfsop_root(struct mount *mp, int lkflags, struct FUSE_LOCK(); MPASS(data->vroot == NULL || data->vroot == *vpp); if (data->vroot == NULL) { - SDT_PROBE2(fuse, , vfsops, trace, 1, + SDT_PROBE2(fusefs, , vfsops, trace, 1, "new root vnode"); data->vroot = *vpp; FUSE_UNLOCK(); vref(*vpp); } else if (data->vroot != *vpp) { - SDT_PROBE2(fuse, , vfsops, trace, 1, + SDT_PROBE2(fusefs, , vfsops, trace, 1, "root vnode race"); FUSE_UNLOCK(); VOP_UNLOCK(*vpp, 0); Modified: projects/fuse2/sys/fs/fuse/fuse_vnops.c ============================================================================== --- projects/fuse2/sys/fs/fuse/fuse_vnops.c Fri Apr 19 23:35:08 2019 (r346424) +++ projects/fuse2/sys/fs/fuse/fuse_vnops.c Sat Apr 20 00:04:31 2019 (r346425) @@ -109,13 +109,13 @@ __FBSDID("$FreeBSD$"); /* Maximum number of hardlinks to a single FUSE file */ #define FUSE_LINK_MAX UINT32_MAX -SDT_PROVIDER_DECLARE(fuse); +SDT_PROVIDER_DECLARE(fusefs); /* * Fuse trace probe: * arg0: verbosity. Higher numbers give more verbose messages * arg1: Textual message */ -SDT_PROBE_DEFINE2(fuse, , vnops, trace, "int", "char*"); +SDT_PROBE_DEFINE2(fusefs, , vnops, trace, "int", "char*"); /* vnode ops */ static vop_access_t fuse_vnop_access; @@ -815,7 +815,7 @@ fuse_lookup_alloc(struct mount *mp, void *arg, int lkf flaa->vtyp); } -SDT_PROBE_DEFINE3(fuse, , vnops, cache_lookup, +SDT_PROBE_DEFINE3(fusefs, , vnops, cache_lookup, "int", "struct timespec*", "struct timespec*"); /* struct vnop_lookup_args { @@ -882,7 +882,7 @@ fuse_vnop_lookup(struct vop_lookup_args *ap) err = cache_lookup(dvp, vpp, cnp, &timeout, NULL); getnanouptime(&now); - SDT_PROBE3(fuse, , vnops, cache_lookup, err, &timeout, &now); + SDT_PROBE3(fusefs, , vnops, cache_lookup, err, &timeout, &now); switch (err) { case -1: /* positive match */ if (timespeccmp(&timeout, &now, >)) { @@ -1404,7 +1404,7 @@ fuse_vnop_rename(struct vop_rename_args *ap) } if (fvp->v_mount != tdvp->v_mount || (tvp && fvp->v_mount != tvp->v_mount)) { - SDT_PROBE2(fuse, , vnops, trace, 1, "cross-device rename"); + SDT_PROBE2(fusefs, , vnops, trace, 1, "cross-device rename"); err = EXDEV; goto out; } @@ -1584,7 +1584,7 @@ fuse_vnop_setattr(struct vop_setattr_args *ap) if (vnode_vtype(vp) != vtyp) { if (vnode_vtype(vp) == VNON && vtyp != VNON) { - SDT_PROBE2(fuse, , vnops, trace, 1, "FUSE: Dang! " + SDT_PROBE2(fusefs, , vnops, trace, 1, "FUSE: Dang! " "vnode_vtype is VNON and vtype isn't."); } else { /* @@ -1732,7 +1732,7 @@ fuse_vnop_write(struct vop_write_args *ap) return fuse_io_dispatch(vp, uio, ioflag, cred, pid); } -SDT_PROBE_DEFINE1(fuse, , vnops, vnop_getpages_error, "int"); +SDT_PROBE_DEFINE1(fusefs, , vnops, vnop_getpages_error, "int"); /* struct vnop_getpages_args { struct vnode *a_vp; @@ -1763,7 +1763,7 @@ fuse_vnop_getpages(struct vop_getpages_args *ap) npages = ap->a_count; if (!fsess_opt_mmap(vnode_mount(vp))) { - SDT_PROBE2(fuse, , vnops, trace, 1, + SDT_PROBE2(fusefs, , vnops, trace, 1, "called on non-cacheable vnode??\n"); return (VM_PAGER_ERROR); } @@ -1809,7 +1809,7 @@ fuse_vnop_getpages(struct vop_getpages_args *ap) uma_zfree(fuse_pbuf_zone, bp); if (error && (uio.uio_resid == count)) { - SDT_PROBE1(fuse, , vnops, vnop_getpages_error, error); + SDT_PROBE1(fusefs, , vnops, vnop_getpages_error, error); return VM_PAGER_ERROR; } /* @@ -1900,7 +1900,7 @@ fuse_vnop_putpages(struct vop_putpages_args *ap) offset = IDX_TO_OFF(pages[0]->pindex); if (!fsess_opt_mmap(vnode_mount(vp))) { - SDT_PROBE2(fuse, , vnops, trace, 1, + SDT_PROBE2(fusefs, , vnops, trace, 1, "called on non-cacheable vnode??\n"); } for (i = 0; i < npages; i++)