-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Windows mount support #5003
Comments
My vote is for WinFsp. It has an active developer and in my opinion is the best FUSE alternative for Windows. I'm using it daily in conjunction with SSHFS. |
Adding myself here so that I can receive notifications and provide help. |
I add here some comments I made over private email regarding the task of creating a Go shim for WinFsp.
I am happy to elaborate on any of this. |
Much appreciated @billziss-gh. Very glad to have your support with this, and a clear outline of what's necessary. 👍
I have considered packaging |
NP. Feel free to ping anytime and I will continue monitoring this issue.
While I do not understand the internals of IPFS, in general file systems benefit from being run as Services under Windows. I outline some of the reasons here: https://github.com/billziss-gh/winfsp/wiki/WinFsp-Service-Architecture |
https://github.com/billziss-gh/cgofuse is a go library for fuse maintained by the winfsp maintainer. It might be best in the long run to use it to create one ipfs-mount that works on all platforms. winfsp has a fuse compatability mode, when used with a cygwin dll. This would also allow decoupling somewhat the mount functionality. |
I should mention I'll be dumping my work here from time to time @BillDStrong For the moment, I'm dumping this in
or
We'll have to see in time. |
I looks like cgofuse has a cross compilation option based on xgo. It looks to include the necessary windows winfsp libraries setup. This would still add a dependency on the c compiler, but xgo's ease of use should be enough to offset that downside. It is contained in a docker container, so compilation shouldn't require to much setup over the current workflow. This is just my opinion, though.
|
@BillDStrong thanks for showing me |
Excluding the build dependencies, I'm concerned with some of the API differences I'd rather not target FUSE on Windows if it means making compromises. Since we already have FUSE for the other platforms, it feels like we're not restricted to it (on Windows) now. Thoughts on this? @BillDStrong @Kubuxu @billziss-gh |
TLDRCgofuse gets you nice cross-platform compatibility (on the 3 OS'es) but at the cost of having some major external dependencies (native toolchain or docker+xgo). These may or may not be appropriate for a large project with an established community and expectations. In detailI can see both sides of the argument. I originally created cgofuse to support rclone. As I was new with Golang at the time, I followed @ ncw 's pointers and used cgo to create a single layer that would run on the 3 OS'es. I find that cgofuse has been a success as it allows the creation of a file system that runs on the 3 OS'es with relative ease. For example, I use cgofuse in my fledgling project objfs (currently pre-alpha) and I do not have to think very much about cross-platform issues. This benefit outweighs for me any potential negatives. Now for those negatives:
Additional considerations for go-ipfs
Native API vs FUSE.Given that IPFS is likely closer to the POSIX file system model rather than the Windows file system model, the differences between the two API's might not mean much for IPFS. For example, if IPFS has no need for and does not use "security descriptors" (Windows ACL's), the ability to use the native |
@billziss-gh
I'm curious to hear more about this, since that seems to be the current task at hand for me. I'm wondering if something couldn't be done to extend cgo-fuse to add dynamic-link support via build tags. However this still restricts us to FUSE. On the topic of FUSE vs Native. I'm being extra cautious to harp on these details now, only to make sure we don't lock ourselves into something that will cause problems later. It seems like FUSE at least provides the necessities, but I want to make sure this is talked about first. While not critical at the moment, I should also bring up performance as something to consider as well here. Will the lack of async i/o bite us? On the topic of more build dependencies. |
My recollection is that we were trying to create what golang calls "binary only packages", which were implemented in Go 1.7 (I think). While this experiment was successful the native toolchain was still required to build the final executable of a project that uses cgofuse (perhaps only the native linker was required). Ping @ncw who may remember more on this. Nick, the question is if you recall what the issues with using cgofuse as a binary only package were.
I have considered before the possibility of modifying cgofuse to use the It may still be worthwhile to do this on the Windows platform only. Another approach (and perhaps the one you allude to @djdv) is to build cgofuse as a shared library or a plugin. Unfortunately
This is actually related to something I deeply care about: how to streamline the differences between the 2 major approaches to file systems (POSIX and Windows). ACL's are a big part of that. For example, I would love to be able to set ACL's on Windows and have them easily translate into ACL's on my Mac, especially because the ACL systems are conceptually compatible. The biggest hurdle I usually face is the need for a user name/id mapping service, but it sounds like IPFS may already have that problem solved.
In general I have not found the lack of async I/O in the FUSE interface to be a performance problem. One complaint from some users with heavy-weight scenarios, is that their file system may sometimes stall while doing too many blocking operations, because they run out of threads. The remedy is usually to increase the number of threads; some even go as far as to implement asynchronous I/O. Only a small number of commercial users with highly parallel file systems have had the need to implement asynchronous I/O. Increasing the number of OS threads is not very costly in WinFsp (in terms of context-switching), because it uses IOCP scheduling under the hood. More details in this document. |
In the last 2 days I spent considerable time refactoring cgofuse with the goal of eliminating the need for cgo on Windows. My intent was to allow building with either My thinking was that with the help of A FUSE file system needs to be able to receive file system requests ( This all works fine in the "cgo" version. However the initial Even worse it spells doom for any effort that wishes to eliminate the need for cgo (regardless of whether cgofuse is used), because (There is also the alternative of rewriting the WinFsp DLL in Go, so that it interfaces directly with the WinFsp FSD, but this is a huge undertaking and I would not recommend it.) |
This is great to hear! As always, the continued effort is appreciated.
It's unfortunate that we're blocked on Go itself, but that seems to be a trend for our Windows tasks recently. Based on our needs and what was said, it seems like cgofuse (sans cgo) would be a good solution after the fix is implemented. |
@billziss-gh wrote:
As far as I can remember we were trying to make binary blob you could just link using the go linker so with the C parts of it already linked in. I can't remember why it didn't work though and I can't find any notes I made either :-(
:-( I've found the go team very good to work with so if you had the time to track the go bug down you would have a receptive audience! |
Correction, it seems like we have 2 upstream options. If I understand correctly, I believe this would sidestep the issue. cgofuse would still use cgo, but we would at least be able to link with it, without adding any build dependencies. We could just check for the existence of the plugin and either link with it or not. I'd still prefer to take advantage of the cgo-less version of cgofuse if we can though. |
@ncw wrote:
My understanding (based on assumptions rather than facts) is that when you do not use cgo, go uses its own linker and avoids using the native linker. But when you do use cgo, the native linker must be used in order to correctly create the executable; the reason being that the standard C library has to be linked in which normally the go linker avoids to do. The fact that go uses its own linker is probably why we do not have Some relevant golang issue links are here:
(I have not linked directly to them to avoid adding extraneous references.) Additional interesting links: |
An update on this. There is a PR (golang/go#25575) that addresses the thread hanging issue with Over the weekend I was able to further develop the "nocgo" version of cgofuse, using a locally patched version of go. I was able to bring up the "nocgo" version of the 64-bit memfs sample and it worked without problems. There is additional work to be done for the 32-bit version and some more rigorous testing to be performed. But I am now fairly confident that this approach will work. (The reason for the 32-bit vs 64-bit difference is that |
@billziss-gh thanks for the update! and for pushing this so hard :) Its exciting to think that we might actually get decent windows filesystem support (something I had previously thought would never happen). |
@whyrusleeping thanks :) BTW, I have finished updating cgofuse so that it now has cgo and !cgo variants. The updated cgofuse passes all tests on macOS, Linux and Windows. On Windows both cgo and !cgo variants are tested. So we are now waiting on the Go team and hopefully an approval of golang/go#25575. |
@billziss-gh any thought towards getting the |
The problem with user-mode locking is that it is not currently supported on OSXFUSE or WinFsp. So you have 2 out of the "3 OS'es" without locking support by default. This is why I have chosen not to implement it in cgofuse. (To clarify file locking does work at the kernel level, it is just that it is not exposed to user mode. In practice this means that file locking will work for processes on the same machine, but it cannot be made to work for processes on different machines.) Consider adding your voice at winfsp/winfsp#116. I actually have an unpublished implementation of user-mode locking support for WinFsp, but have not incorporated it into its public repo because of the problems documented in that issue. |
The PR golang/go#25575 has been merged into go as commit golang/go@bb0fae6. |
Status update [5965a25] |
That's really cool. Thanks for the update! |
Great work! |
Hmm, I would like to compile this PR for linux to test the performance but seems its not currently possible? Looks like something changed in the main repo that needs to be merged first or do I misunderstand? I'm not very familiar with compiling go :( |
@ZerxXxes |
Hey no worries, looking forward to the next commit. |
Status update: The general idea being that we have a middle abstraction between FUSE and our APIs, essentially wrapping and conforming multiple APIs to a generic filesystem API. We then use that API to implement the FUSE interface itself, while also exposing it so that developers can use the same Go bindings for other tasks. Essentially you should be able to do Separate, more formal issues/PRs will come up around this later. To implement FUSE we have to implement this interface. A good example of the full pipeline is the The tie between the mount interfaces and the fuse interface, are in the process of being separated and made more generic. So the end result should be similar, but who's responsible for what will change. func (fs *fuseIf) FuseOperationX(path, args) statusCode {
// your specific code can go before or after these calls
// unifying FS operations across API boundaries
node, err := mountApi.Lookup(path) // use mount API to resolve paths to nodes, using daemon side logic
//node, err := mountApi.Lookup("/ipfs/Qm.../file.ext")
status := node.OperationX(args) // call desired operation
//bytes, err := node.Read(offset)
// more fuse specific logic
if status == mountOpFail {
return fuseFailedValue
}
fs.SideEffect(path)
return status
} But the idea being that you could have doMyOwnWorkPart(1)
node, err := mountApi.Lookup(path) // get node from api
status := node.OperationX(args) // call desired operation on node
doMyOwnWorkPart(2) anywhere you have API access, in the same way you can with IPFS paths and the coreapi. The broader goal is that this is generally more maintainable and pleasant. |
We're going over all the The current Incomplete/Inaccurate: Not flexible/dynamic: Other IPFS components stand to benefit from ipfs/interface-go-ipfs-core#30 The gateway could use a
There's desire to merge Neat: |
Looks like 2 years of no activity on this Issue, and it is not yet closed. Can anyone tell what's the current status of Windows Mount in current go-ipfs release? |
Whoops, my bad. I failed this effort a long time ago. Closing now. It was requested that I separate the code from Here's the most recent status of that if you're interested. |
Looks very nice! Maybe at least your fully working version inside single go-ipfs binary (or separate binary) is available somewhere in public? (in github of your user as a fork+branch?) So that I (or anyone else) can compile it and try on Windows. Also very interesting if your file system can show files and folder of unpinned files? E.g. if you do |
@polkovnikov
For sure.
I don't have any documentation up yet, but I'll try to put some in there later. For now you can reference this for the dependencies needed on the supported operating systems: https://github.com/billziss-gh/cgofuse#----cross-platform-fuse-library-for-go To build run The CLI isn't finished yet, so it's going to change, but for right now you should be able to do On Windows this can be a drive letter For other things, try calling
Yeah. Currently only Fuse is supported, the 9P interfaces will also be ported over so that you can do |
@djdv Thanks for detailed comments! I successfully managed to build But when I run it like But I don't remember that I was installing any WinFsp. If I look into regular location of program, i.e. inside Window's Also when I try to install through Chocolatey's And I see this weird behaviour (of WinFsp being installed) I see on both of my two laptops, on both laptops I didn't install WinFsp before. Seems to me that standard modern Windows installation somehow includes pre-installed WinFsp drivers/service. But this ghosty pre-installed WinFsp doesn't work with |
@djdv Just a side comment - you seems to know a lot about net-ipfs-mount project. Seems to me that it doesn't recognize For example Do you know by any chance if there's a work around for |
I searched whole my file system for
Both things refer to famous Russian cloud storage service called "Mail.Ru Disk-O". I installed it before. After uninstalling this application Also your As a stress test I tried to open and browse 82 GB file I can admit that your Linux version heavy-loaded my 4 cores (8 threads) with 90-100% of CPU usage and 1 MB/sec download speed for 1 hour, after 1 hour and 1 GB downloaded blocks I managed to open this Wikipedia under Linux. Under Linux I used not Chrome extension, but standalone Kiwix application obtained by link mentioned above. Your So looking forward to integrating your utils into official IPFS package! They look very nice and work well for even huge file. I hope this integration happens soon so that everybody can benefit from great things of IPFS. |
@djdv BTW, do you have following improvement in your file system code? For example I have very huge file (like 82 GB wikipedia ZIM file from previous comment). Then I want to do very small few-bytes readings from it, for example I'm parsing some metadata byte by byte. Also this small reads can be random access reads. If I do millions of such few-bytes random read requests to your file system, how do you handle them? Do you just forward all few-bytes small requests to IPFS API? Or you do some caching technique in your code? For example if I random-read small portion then some cache in your code instead can request 256 KB block from IPFS, then cache this 256KB block into RAM. If I do another small read from existing-in-cache block then your code returns this portion immediately instead of doing API call to IPFS node. If too many blocks were cached then least used (or oldest) block is removed from cache to reduce RAM usage. Do you have anything like this? This is just an idea how to improve speed of small random reads greatly. Because 82 GB Wiki mentioned above was read by Kiwix really really slow on Linux's standard FUSE of |
@polkovnikov
Glad to hear that.
Unfortunately this is not likely to happen. Members of the project already evaluated this effort and myself a while ago. As it turns out, both are unacceptable.
At the moment, yeah. We're essentially, just translating formats and calling conventions from Fuse and 9P into ones for the IPFS APIs. To summarize, there's a lot of potential to do whatever, wherever, if it make sense to. The much longer version: (click to expand)The most basic example is in Fuse where we actually keep track of open references instead of constructing and deconstructing them each time they're needed. In the old interface that hasn't been ported over yet, there was a lot of logic around making IPNS fast enough to be usable. Thankfully, this shouldn't be our responsibility anymore as IPNS itself has improved significantly in terms of speed. But back then, each request could take long enough to trigger the OS's IO timeout (we're talking upwards of 30 seconds per iop), yet the mount implementation I had was practically instant most of the time for reads and writes. It was good enough that users remarked on it :^)
Today, I shouldn't have to use clever caching techniques in that layer because IPNS is doing some of the same things internally, as well as other tricks. Which is better for everyone. Kind of like what you're saying with reading into ram, potentially ahead of time. I had to avoid using the MFS library directly because it liked to deadlock for reasons that are not the callers fault. So there already have been reasons to do things like this, and they have been possible and implemented. And that's only easier to do now with some of the separation between modules, and the work done on IPFS itself.
While I did port the code for that over to my interfaces for legacy compatibility. I did not make much effort to inspect it. And have since dropped it entirely since we don't have to be part of However, I know the culprit is not Linux's fuse. It's either bazil's library, the ipfs implementation that uses it, or a combination of both. Also, we should probably use https://github.com/djdv/go-filesystem-utils/discussions for further discussion. |
@djdv So if your project is never going to get into official binary or package then at least would be great if you keep your project public and never close it, and possible maintain it at least from time to time. Because your project is currently the only way that I have found for IPFS mounting to work on Windows, there are other few projects doing similar stuff but either they don't work or abandoned and outdated. Your project is the only working solution according to my knowledge on Windows. Would be great if IPFS people at least mention your project on official website (ipfs.io) as a Windows-mounting solution. Because right now in web search engines I only see solution for Unix systems. But world of Windows is very huge, personally I use Windows much more often than Linux. |
Unfortunately it seems so.
If users find the solution useful, it will spread organically as it enters various states of stable. Also, the burden to fix fundamental problems with the project, should be on the IPFS team, not their users to compensate for them. In my opinion, to point to a 3rd party stopgap for a 1st party problem, especially after initially claiming the solution and its author have no merit, would be nothing short of taking advantage of impatience, while also being personally offensive. It should be said explicitly that while I may disagree with their decisions and remarks, there is no animosity between me and the team. I keep in contact with some of them and they are appreciative of what's being done. But I think there is a mutual understanding of what is and isn't fair. Maybe eventually we can do a handoff where my work is considered done, and they maintain it. But it's going to take time to get it up to their standards. I hope that message doesn't come off as vitriolic, it's very hard to convey opposing forces and motivations at various levels like that. There's desires and ideals meeting against practicality and fairness that just sound like conflicting contradictions. And my English is terrible too. I hope it makes sense. ┐('~`;)┌ In any case, the focus should stay on the technical aspects and not much else. There's not much point to rehashing, speculation, or other things. |
Tracking/discussion issue for the topic of implementing
ipfs mount
on Windows.This is a broad topic, all comments and criticisms are welcome here as long as they help drive us towards a solution. Nothing is set in stone yet and we'd like to implement this correctly.
Currently we have no first party support for this:
For third party, I'm aware of these projects:
https://github.com/alexpmorris/dipfs
https://github.com/richardschneider/net-ipfs-mount
both utilize the IPFS API and Dokany(a Windows FUSE alternative).
dipfs
does not appear to be maintained.In my experience it will succeed in mounting IPFS as a drive letter, and allows you to traverse IPFS paths via CLI, however it hangs in explorer (likely from it trying to access metadata), or when trying to read data through any means.
net-ipfs-mount
is currently being maintained.This is our best contender, everything appears to work as intended unless you have a non-tiny pinset. When trying to traverse IPFS paths with a large enough pinset, passing the list of pins from the API to net-ipfs-mount can take long enough for Windows to deem
/ipfs
inaccessible.For local testing you can run
ipfs pins ls
and see how long it takes to return.I would like to start an initiative, aimed at getting Windows mounting on par with the other platforms.
That is to say, at the very least, exposing read only access to
/ipfs
and/ipns
constructs.If possible, it would be nice to extend the feature set to expose a writable MFS root as well, similar to this https://github.com/tableflip/ipfs-fuse
Most likely, this will mean implementing first party support for
mount
ingo-ipfs
, utilizing core APIs where possible.Mention of https://github.com/billziss-gh/winfsp has come up as an alternative to Dokany. It's likely that
winfsp
's native API will be our target, however this is not locked down yet. If you have opinions on Windows filesystem APIs, positive or negative, please post them here.cc:
@mgoelzer, @alanshaw, @dryajov, @mrlindblom, @Kubuxu, @whyrusleeping
Edit: forgot to cc: @alexpmorris, @richardschneider
The text was updated successfully, but these errors were encountered: