Name of the organization or individual submitting the proposal: Michael Bulanov
Describe your project.
This is my second attempt to propose a grant on integrating the SMB protocol into indexd (well, my third one if I count all attempts to bring Sia Satellite back to life in this or that sense).
The proposal is largely based on the previous project named SiaSMB, or Sia - SMB Mounts (GitHub - mike76-dev/siasmb: SMB protocol implementation for Sia cloud storage). SiaSMB uses renterd as the underlying storage. Going forward, indexd support will be required, enabling users to access the Sia storage directly.
Who benefits from your project?
Developers, by being able to implement the SMB protocol in their apps
Hosts, by getting more demand for storage
How does the project serve the Foundation’s mission of user-owned data?
The project implements yet another building block that aims to close the gap between decentralized storage and the broad audience.
Are you a resident of any jurisdiction on the sanctioned/monitored list? No
Will your payment bank account be located in any jurisdiction on that list? No
Grant Specifics
Amount of money requested and justification with a reasonable breakdown of expenses.
The proposal is requesting 24.000 USD (100% constitutes the developer fee).
Timeline with measurable objectives and goals.
Milestone 1
Add support for SMB dialects 2.1 and 3.0
Refactor the config to support indexd in the future while maintaining the compatibility with renterd
Timeline: 1/25/26
Milestone 2
Add support for SMB dialects 3.0.2 and 3.1.1
Deploy a test server based on renterd to collect the community feedback
Timeline: 2/25/26
Milestone 3
Incorporate the feedback from Milestone 2
Implement metadata store
Implement querying the store the way SMB protocol does
Timeline: 3/25/26
Milestone 4
Implement direct uploads and downloads via SMB & RHP4
Timeline: 4/25/26
Potential risks that will affect the outcome of the project:
With all foreseeable risks been considered in the earlier proposals, the project developer does not see any significant risks that could affect the project in any way.
Development Information
Will all of your project’s code be open-source? Yes
Leave a link where code will be accessible for review.
Do you agree to submit monthly progress reports? Yes
Contact Info
The contact details are already known to the Foundation.
Thanks for your proposal to The Sia Foundation Grants Program.
After review, the Committee has decided to approve your proposal. Congratulations! They’re excited to see what you can accomplish with this grant.
We’ll reach out to your provided email address for onboarding. This shouldn’t take long unless your info has changed from last time, but you may still need to adjust your timelines.
Summarize any problems that you ran into this month and how you’ll be solving them.
Windows clients (and likely only those) seem to like sending write requests out of order (like, part 1, part 10, part 6, part 2, part 3, etc.). This is incompatible with the S3-type multipart uploads, because there is no way to know the part number until all earlier parts have been received. This made me rewrite the entire upload logic, but it seems to be working now.
Thank you for your report for February. This month’s review was successful and there is no actionable feedback. The team is looking forward to seeing what you do over the next month!
Most SMB clients upload filed in chunks of at most 256KiB. With the part number limit of 10,000 enforced by renterd, this means a file size cap of ca. 2.5GB. After rewriting the upload logic, the files are now uploaded in chunks of 4MiB (the Sia sector size), which raises the cap to ca. 41GB for renterd.
Before the fix, cutting and pasting a non-empty directory on Windows moved the directory but not its contents (which was simply deleted). This was actually not a part of the feedback, but I decided to give it a priority due to a potential for data loss.
4. Connect to an indexd node and implement the filesystem
Besides renterd, it is now possible to connect to an indexd node and query the used and the available storage. Also, it is possible to create, rename, move, and delete directories.
Summarize any problems that you ran into this month and how you’ll be solving them.
Even though the a.m. fixes may have seemed easy to implement, there was a lot of hidden pitfalls behind each of them.
What will you be working on next month?
The Milestone 4: uploading and downloading data to and from an indexd node.
Hi @mike76 - your technical review is complete and here are some notes from your reviewer for you to bear in mind as you continue your work on this grant:
Hi @mecsbecs, thanks for your feedback. I’m going to address most of it by the next progress report.
I’m aware of the unused structs or fields. I will keep them for now, in case I decide to implement an extra functionality (like multichannel support), which will be using them, later on.
I always build with the -race flag, so I was thinking I had detected and fixed all data races. Would appreciate a hint on how to reproduce. The same for panics and leaks. I haven’t seen anything like that when testing recently.
Hi @mike76 - I’ve asked your reviewer for additional detail, and here’s what they said:
Panics
In main.go, the accept loop panics if IsBanned returns an error. In protect.go, blockHost panics if persisting the ban fails.
Races
A clean go test -race ./... run does not clear the server here, because almost all of the SMB/API code still lacks meaningful test coverage. The race detector only reports races in code that actually executes, and the current suite barely exercises the concurrency-heavy parts of the project.
The clearest race is in blockHost: it iterates connectionList without the server mutex while other goroutines add and remove connections under that mutex. That is a concurrent map access hazard and can panic the server. There are also file metadata races: op.size is read before op.mu is taken, and the CHANGE_NOTIFY watcher reads lastModified and size while holding the tree lock rather than the open lock. There is a separate idleTime race between request handling and the stale-connection cleanup path.
Goroutine and channel leaks
CHANGE_NOTIFY starts a polling goroutine, but closeConnection() only closes the socket and a connection-level channel; it does not cancel open contexts or notify stop channels. Those watchers can outlive the connection. Separately, async read/write workers can finish after disconnect and then block indefinitely trying to send a response because the response-sending goroutine has already exited.