Skip to content

Commit 7d7dcbf

Browse files
committed
feat: vendor russh-sftp with serde_bytes perf fix
Add `crates/bssh-russh-sftp`, a temporary fork of upstream `russh-sftp` following the same pattern as the existing `crates/bssh-russh`. The only functional change versus upstream v2.1.1 is a `#[serde(with = "serde_bytes")]` annotation on `protocol::Write::data` and `protocol::Data::data`, plus a wire-compatible `serialize_bytes` implementation in `ser.rs`. Without it, `#[derive(Deserialize)]` for `Vec<u8>` dispatches to `deserialize_seq` and parses the SFTP payload one byte at a time — `perf` shows ~42% of server CPU in `VecVisitor::visit_seq` during 1 GiB uploads. The annotation routes through the existing bulk `try_get_bytes` path in the crate's own Deserializer, which is already implemented. Measured impact on a CPU-bound host (Xeon Silver 4214) with an OpenSSH client performing a 1 GiB SFTP upload: - upstream russh-sftp 2.1.1: 74.8 MiB/s - this fork: 96.4 MiB/s (+29%) OpenSSH `sftp-server` on the same host measures ~101 MiB/s, so the gap narrows from ~26% to ~5%. Upstream russh-sftp has had no commits since its v2.1.1 bump (2025-04-18) and two download-perf issues (#55 closed without root cause, #70 open) sit unanswered, so the fix lives here until upstream activity resumes. `sync-upstream.sh` and `create-patch.sh` mirror the `bssh-russh` tooling so future syncs are mechanical. The top-level dependency is switched from `russh-sftp = "2.1.1"` to `russh-sftp = { package = "bssh-russh-sftp", version = "2.1.1", path = "crates/bssh-russh-sftp" }` so every `use russh_sftp::...` import in bssh continues to work unchanged.
1 parent 60e1bec commit 7d7dcbf

53 files changed

Lines changed: 4515 additions & 53 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
- Internal fork of `russh-sftp` as `crates/bssh-russh-sftp` with a `serde_bytes` performance fix for `SSH_FXP_WRITE` and `SSH_FXP_DATA` packets. The upstream serde derive routes `Vec<u8>` through `deserialize_seq` (byte-by-byte), accounting for ~42% of server CPU during 1 GiB SFTP uploads in `perf` profiling. Annotating the `data` fields with `#[serde(with = "serde_bytes")]` and implementing wire-compatible `serialize_bytes` on the SFTP `Serializer` routes through the existing bulk `deserialize_byte_buf`/`try_get_bytes` path. Measured impact on a CPU-bound host (Xeon Silver 4214): 1 GiB SFTP upload throughput improves from 74.8 MiB/s to 96.4 MiB/s (+29%), closing the gap to OpenSSH `sftp-server` from ~26% to ~5%.
12+
13+
### Changed
14+
- Switched the top-level `russh-sftp` dependency from crates.io `russh-sftp = "2.1.1"` to `russh-sftp = { package = "bssh-russh-sftp", version = "2.1.1", path = "crates/bssh-russh-sftp" }`. All existing `use russh_sftp::...` imports continue to work unchanged.
15+
1016
## [2.1.2] - 2026-04-27
1117

1218
### Fixed

Cargo.lock

Lines changed: 62 additions & 52 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
members = [
33
".",
44
"crates/bssh-russh",
5+
"crates/bssh-russh-sftp",
56
]
67

78
[package]
@@ -23,7 +24,8 @@ tokio = { version = "1.52.1", features = ["full"] }
2324
# - Development: uses local path (crates/bssh-russh)
2425
# - Publishing: uses crates.io version (path ignored)
2526
russh = { package = "bssh-russh", version = "0.60.1", path = "crates/bssh-russh" }
26-
russh-sftp = "2.1.1"
27+
# Use our internal russh-sftp fork with a serde_bytes perf fix
28+
russh-sftp = { package = "bssh-russh-sftp", version = "2.1.1", path = "crates/bssh-russh-sftp" }
2729
clap = { version = "4.6.1", features = ["derive", "env"] }
2830
anyhow = "1.0.102"
2931
thiserror = "2.0.18"

crates/bssh-russh-sftp/Cargo.toml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
[package]
2+
name = "bssh-russh-sftp"
3+
version = "2.1.1"
4+
authors = ["Jeongkyu Shin <inureyes@gmail.com>"]
5+
description = "Temporary fork of russh-sftp with a serde_bytes performance fix for SFTP Write/Data packets"
6+
documentation = "https://docs.rs/bssh-russh-sftp"
7+
edition = "2021"
8+
homepage = "https://github.com/lablup/bssh"
9+
keywords = ["russh", "sftp", "ssh2", "server", "client"]
10+
license = "Apache-2.0"
11+
readme = "README.md"
12+
repository = "https://github.com/lablup/bssh"
13+
14+
[dependencies]
15+
tokio = { version = "1", default-features = false, features = [
16+
"io-util",
17+
"rt",
18+
"sync",
19+
"time",
20+
"macros",
21+
] }
22+
tokio-util = "0.7"
23+
serde = { version = "1.0", features = ["derive"] }
24+
serde_bytes = "0.11"
25+
bitflags = { version = "2.9", features = ["serde"] }
26+
async-trait = { version = "0.1", optional = true }
27+
28+
thiserror = "2.0"
29+
chrono = "0.4"
30+
bytes = "1.10"
31+
log = "0.4"
32+
flurry = "0.5"
33+
34+
[features]
35+
async-trait = ["dep:async-trait"]

0 commit comments

Comments
 (0)