Commit Graph

20 Commits

Author SHA1 Message Date
Puneet Kaushik
a7f99f7f2c Added thrift request to report outstanding FUSE calls
Summary:
Added a thrift call to return the outstanding FUSE requests.
Cli will call the thrift and print the output.
Added a unit test to test getOutstandingRequests().

Reviewed By: simpkins

Differential Revision: D7314584

fbshipit-source-id: 420790405babdb734f598e19719b487096ec53ca
2018-03-20 10:25:49 -07:00
Adam Simpkins
bfcf4c574a remove the fusell namespace
Summary: Move everything in the `facebook::eden::fusell` namespace to `facebook::eden`

Reviewed By: chadaustin

Differential Revision: D7314458

fbshipit-source-id: db56d3e5fb898235e1376ac76077cf780d9b4698
2018-03-19 17:01:52 -07:00
Adam Simpkins
f25e5d4c46 move FileHandleMapTest from inodes/test to fuse/test
Summary:
This test exercises code under eden/fs/fuse, so put it with that directory's
tests.

Reviewed By: chadaustin

Differential Revision: D7314457

fbshipit-source-id: b664aaa3086b2e65f7ae8b76ae71878f39fd9d17
2018-03-19 12:55:17 -07:00
Adam Simpkins
bbf0407287 record the FUSE version reported by the kernel
Summary:
Previously the FuseChannel code unconditionally set `connInfo_.major` and
`connInfo_.minor` to the FUSE version that it supports, rather than the FUSE
version supported by the kernel it is talking to.

This does not appear to be the intended behavior, given that in several other
location it checks the value of `connInfo_->minor` to see if particular
features are supported.

Reviewed By: wez

Differential Revision: D7300845

fbshipit-source-id: 1f5946134037b2cbe03a8b86241acaa401c21ffa
2018-03-16 17:39:13 -07:00
Adam Simpkins
1c46d4c9e1 have FuseChannel return its FD in the completion future
Summary:
Remove the `FuseChannel::stealFuseDevice()` method, and instead change the
session completion future to return the FUSE device FD if it is still valid.

This ensures we only extract the FUSE device when it is still valid: if an
unmount event is being processed by a FUSE worker thread simultaneously with a
call to `FuseChannel::takeoverStop()` the session completion future will return
an empty `folly::File` since the FUSE device has been shut down.

This also helps clarify the synchronization semantics around modification to
the `fuseDevice_` member variable.

Reviewed By: wez

Differential Revision: D7300847

fbshipit-source-id: 02ced8fc9d24e7cd526d911782949d0bfbf0e5a7
2018-03-16 17:39:13 -07:00
Adam Simpkins
8eff641bf3 prevent FuseChannel from being destroyed with outstanding requests
Summary:
The FuseChannel destructor previously could be invoked while there are still
outstanding requests, which would cause problems when responses were generated
for these requests.

This makes the FuseChannel destructor private, requiring users to always
allocate FuseChannel objects on the heap and destroy them using a destroy()
method.  The destroy() method still blocks waiting for the FUSE worker threads
to exit, but if there are still outstanding FUSE requests it defers the
deletion of the FuseChannel until they are complete.

The EdenMount class currently couldn't ever destroy FuseChannel objects with
outstanding requests, since it waits for the completion future to fire before
invoking the destructor.  Fixing this behavior is mostly for correctness of the
FuseChannel API and for the benefit of our unit tests.

Reviewed By: chadaustin

Differential Revision: D7297829

fbshipit-source-id: 643d1332be84a1f25ee30ba2a2ea3515806f00ef
2018-03-16 12:35:19 -07:00
Adam Simpkins
c5f4ea6f8b update FuseChannel::initialize() to return the completion future
Summary:
Remove the `FuseChannel::getSessionCompleteFuture()` method and instead have
`initialize()` and `initializeFromTakeover()` return the `Future` that can be
used to wait on session completion.

This makes it explicit from an API perspective that this session completion
future will only be invoked if initialization is successful.  It also
eliminates the possibility of anyone calling getSessionCompleteFuture() more
than once.

I also changed the session completion future to use a folly::SemiFuture rather
than a folly::Future, to make it explicit that callers generally should not
execute their callback inline in the same thread where the SemiFuture is
fulfilled.

Reviewed By: chadaustin

Differential Revision: D7297835

fbshipit-source-id: 3a1157951f0738f1692833ed5e875c3e9c6d6d69
2018-03-16 12:35:19 -07:00
Adam Simpkins
6cc56a6f81 fix hangs in FuseChannel shutdown
Summary:
The FuseChannel unit tests would sometimes hang because a worker thread would
still be stuck in a blocking read() call.

The issue appears to be that the kernel would often automatically restart the
interrupted read(), so the worker would never wake up.  This switches the code
from using SIGPIPE to wake up, and instead uses SIGUSR2, and installs a handler
for SIGUSR2 with the SA_RESTART flag unset.

It's possible that this was an issue only for the unit tests, where the FUSE
device is a socket.  I'm not sure if the kernel would automatically restart
read operations on a real FUSE device.

There are still theoretically some race conditions here, since
`requestSessionExit()` could be called right after a worker thread checks
`(runState_` and before it enters the blocking `read()` call.  Fixing that
would likely require switching to something like `folly::EventBase` or manually
using epoll.  Fortunately I haven't seen that be an issue in practice so far.

Reviewed By: chadaustin, wez

Differential Revision: D7282002

fbshipit-source-id: 99d29de13a7858dd25f258fdc94d8f8c71ee84d9
2018-03-15 13:48:45 -07:00
Adam Simpkins
fdecf19d91 update FuseChannel to signal the session complete future immediately
Summary:
This changes FuseChannel to fulfill the session complete future immediately in
the thread where it finishes.  This may occur inside a FUSE worker thread.
It is now up to the caller to use `via()` if they want their callback to run in
a separate thread.

This simplifies the FuseChannel code and also addresses a crash that occurs in
the unit tests sometimes: If the FuseChannel destructor is invoked without
explicitly invoking the FuseChannel, it would schedule the session complete
promise to be fulfilled in a separate EventBase thread.  However, the promise
may then have already been destroyed by the time it can run in the EventBase
thread.

There are still additional synchronization issues to fix in the FuseChannel
tests, but this resolves one problem.

Reviewed By: chadaustin

Differential Revision: D7282001

fbshipit-source-id: be64d3ef6a0e664ed7a2cf93a549acc140184095
2018-03-15 13:48:45 -07:00
Adam Simpkins
1a9f74b940 fix a race between FuseChannel::startWorkerThreads() and the destructor
Summary:
Update FuseChannel::startWorkerThreads() to return without doing anything if
runState_ indicates that the FuseChannel is currently stopping.

This addresses a race betwen startWorkerThreads() and the destructor.  If the
destructor is invoked in parallel with startWorkerThreads() the destructor can
grab the state_ lock and clear out the workerThreads list first.  This then
causes problems when startWorkerThreads() runs and adds new threads to the
workerThreads list, which then never get joined.

Reviewed By: wez

Differential Revision: D7253574

fbshipit-source-id: f2cac11f1e71e1a14e3f020368152e0f2948c625
2018-03-13 18:30:49 -07:00
Adam Simpkins
d622eb481d allow stopping FuseChannel during initialization
Summary:
Update FuseChannel::readInitPacket() to honor `runState_` and stop if it is
changed to indicate that the channel is stopping.  Previously the init worker
thread would always wait until it received an INIT packet or an error on the
FUSE channel.

This also refactors the `readInitPacket()` code slightly mainly to to reduce
the level of indentation.

Reviewed By: wez

Differential Revision: D7253575

fbshipit-source-id: 7f27698947b629daecd9cd4ddffb6e6a921ce41e
2018-03-13 18:30:49 -07:00
Adam Simpkins
9bb25beab3 update FuseChannel to record the reason why we stopped
Summary:
Update the FuseChannel code to keep track of why it is stopping, and to return
this data in the session complete future.

This is mainly just available for diagnostic reasons, and at the moment nothing
is using this outside of the unit tests.

Reviewed By: wez

Differential Revision: D7253573

fbshipit-source-id: 0c7e5b8bd9c3c1de3788918c2257c06d4fe0a90c
2018-03-13 18:30:49 -07:00
Adam Simpkins
fef4a43da7 restructure FuseChannel initialization and synchronization
Summary:
- Update FuseChannel::initializate() to not require an Executor.  Rather than
  performing initialization using the supplied Executor, it simply starts one
  worker thread first and performs initialization there.
- Change the API semantics slightly so that the session complete future is
  invoked only if initialization succeeds.  Previously the session complete
  future could be invoked if initialization failed as well.
- Replace the activeThreads counter with a stoppedThreads counter to determine
  when the session complete future should be invoked.  The previous
  activeThreads behavior was somewhat racy, since the activeThreads counter was
  incremented inside each worker thread, but most places that checked it did
  not wait to ensure that all worker threads had successfully incremented it
  yet.

Reviewed By: chadaustin

Differential Revision: D7243910

fbshipit-source-id: 93b3465509bd9bf6fa90ea097e70dac3193172f9
2018-03-13 13:29:03 -07:00
Adam Simpkins
1b441aa0b4 split up FUSE initialization for fresh start vs takeover
Summary:
Split up the FuseChannel and EdenMount APIs for starting a brand new FUSE
channel vs taking over an existing channel.

These operations are somewhat different as initializing a new FUSE channel
requires performing a negotiation with the kernel that will not complete
immediately.  Therefore these APIs return a Future object.  Taking over an
existing FUSE channel is always an immediate operation, and therefor does not
need to return a Future object.

Reviewed By: chadaustin

Differential Revision: D7241997

fbshipit-source-id: 22780f2df76b2d554ab2a4043b6425fa7a4e9c94
2018-03-12 21:28:50 -07:00
Adam Simpkins
81aa1a31a4 make sure we ignore SIGPIPE in unit tests
Summary:
Ensure that we ignore SIGPIPE in unit tests.  The
`FuseChannel::requestSessionExit()` function sends SIGPIPE to its worker
threads, and expects this to wake up the worker threads if they are stuck
inside a read() call.

In normal program builds folly/Subprocess.cpp causes SIGPIPE to be ignored on
startup.  However, Subprocess.cpp is not necessarily linked into all of our
unit tests.  I haven't tracked down exactly why, but SIGPIPE in the unit tests
seems to kill the entire process only in opt-ubsan builds.

In the future we probably should clean up how requestSessionExit() triggers its
worker threads to exit: the current code is still potentially racy, since the
worker threads could receive the SIGPIPE just after checking `sessionFinished_`
and before calling `read()`, in which case they may go back to sleep rather
than exiting.  However for now this should be a simple fix to get the tests
passing in all build modes.

Reviewed By: wez

Differential Revision: D7224370

fbshipit-source-id: a56fe3331fc5aa6a49ccbe6b0678b479a44ffc07
2018-03-12 11:46:20 -07:00
Adam Simpkins
d5e3d5dd63 add initial test code for FUSE channel communication
Summary:
This adds a FakeFuse class to simulate a FUSE connection to the kernel, but
that is actually communicating with our userspace test harness code.  This also
adds a FakePrivHelper class which implements the PrivHelper interface but
returns FakeFuse connections rather than real FUSE connections to the kernel.

This will enable us to write unit tests that exercise more of the FUSE and
EdenMount logic, and will also enable us to test error conditions and ordering
behaviors that are difficult to reliably reproduce with a real FUSE mount.

This also includes some very basic tests using this new code.  The code in
fuse/test/FuseChannelTest.cpp creates a FuseChannel using a FakeFuse object,
and the code in inodes/test/FuseTest.cpp creates a full EdenMount object using
FakePrivHelper and FakeFuse.  The tests are pretty similar for now, and only
exercise the FUSE initialization code.  I will expand these tests in subsequent
diffs.

Reviewed By: wez

Differential Revision: D7050826

fbshipit-source-id: 4f82375d65664ca3a5a228a577caa4d1d47454fe
2018-02-27 22:57:09 -08:00
Adam Simpkins
21d2b6c46d Remove TARGETS files
Summary:
This removes the TARGETS files from the eden github repository.  The
open source buck build has been failing for several months, since buck
removed support for the thrift_library() rule.

I will potentially take a stab at adding CMake build support for Eden
at some point in the future.

Reviewed By: chadaustin

Differential Revision: D6893233

fbshipit-source-id: e6023094a807cf481ac49998c6f21b213be6c288
2018-02-20 19:57:45 -08:00
Sergey Zhupanov
ea2994c045 Misc cleanup of cpp files in eden/fs/fuse/
Summary: Misc cleanup (mainly constification).

Reviewed By: simpkins

Differential Revision: D6720987

fbshipit-source-id: c9c719fce93d413857c48c61e0c920319e865209
2018-01-17 13:41:19 -08:00
Philip Jameson
8604b8f5b0 Migrate TARGETS files from @/ to //
Summary:
This is a codemod to change from using @/ to // in basic cases.
- TARGETS files with lines starting with @/ (but excluding @/third-party:
- autodeps lines in source and TARGETS files ( (dep|manual)=@/ ), excluding @/third-party
- Targets in string macros

The only thing left of the old format should be @/third-party:foo:bar

drop-conflicts

Reviewed By: ttsugriy

Differential Revision: D6605465

fbshipit-source-id: ae50de2e1edb3f97c0b839d4021f38d77b7ab64c
2017-12-20 16:57:41 -08:00
Chad Austin
8a6d0592f7 allow returning the open file handle before the load/materialize completes
Summary:
There's no technical reason to block an open() request until the data
load / materialization returns.  This change returns immediately from
open() and then waits if necessary in a subsequent write() call.

Reviewed By: wez

Differential Revision: D6391486

fbshipit-source-id: 862f87e3c3a0d760bacb0f8ca7acc479037fec2f
2017-12-05 11:21:26 -08:00