对 Zed 说谎以使其远程服务器在 FreeBSD 上运行
Lying to Zed to get its remote server running on FreeBSD

原始链接: https://hayzam.com/blog/03-lying-to-zeds-remote-editor/

作者请求 Zed 支持原生 FreeBSD 远程服务器,称赞其速度和内置 AI 禁用开关优于 VS Code。在此之前,可通过启用 Linux 兼容层、安装 linux_base-rl9,并使用一个小型 ~/.local/bin/uname 包装器(向 Zed 的平台查询报告 "Linux x86_64")在 FreeBSD 上使用 Zed 的 Linux 服务器。通过 SSH 连接后,Linux 服务器会被上传。要避免空项目树,需要内核修复:FreeBSD 的 Linuxulator 将目录读取缓冲区大小向上舍入到 512 字节,允许原生读取超出调用者缓冲区并返回 EINVAL。修复 ec6629628cb(包含在 FreeBSD 15.2 中)将读取限制在调用者缓冲区内。通过 editors/zed 端口使用原生 Zed 服务器是可能的,但必须与 Zed 版本完全匹配;Linux 路线则跟随 Zed 的下载。

Hacker News 新帖 | 过往 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 骗 Zed 让其远程服务器在 FreeBSD 上运行 (hayzam.com) 9 分 作者 arch1e 2小时前 隐藏 | 过往 | 收藏 | 1 条评论 帮助 eddythompson80 1 分钟前 [–] 远程服务器只需为 FreeBSD 编译一下吗?看起来对于编辑器本身,只有音频通话(什么鬼?)在 FreeBSD 上不能用 https://zed.dev/docs/development/freebsd 回复 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

I’ve used VS Code since I was about 16, so for almost ten years and honestly it was mostly fine. But as of late it has become unbearable: slow, and increasingly weighed down by AI slop. grahamperrin@ pointed out to me that VS Code now has chat.disableAIFeatures, and they’re right. I totally missed it! It really does turn the built-in AI features off atleast from what I can see in limited testing, and it works. But even with it off, VS Code still feels clunky as hell. Zed, on the other hand, is fast, and it had a native switch that turns all of its AI stuff off slightly earlier than VS Code did, which I absolutely adore. (It’s a toggle in Settings, or "disable_ai": true in your settings file.)

That’s not because I avoid LLMs. I just don’t want them trying to edit every line I write, or sitting in the corner judging me ominously. I still write most of my FOSS code myself: it keeps me sane, and I feel FOSS developers have a responsibility to keep code clean for LLMs to steal from lol. What I do hand off is the tiring part: regression testing, edge cases, and exploration beyond what my tiny 20-watt brain can hold. For that I use harnesses that work well with models, like OpenCode. Beyond auto-complete.. I’ve always found entire harnesses like claude code etc. very clunky in editors.

Getting it working

Zed has no FreeBSD remote server offering (yet), but FreeBSD can run Linux binaries in spades, so we use Zed’s Linux one. All you need is a FreeBSD server you can SSH into.

1. Turn on Linux compatibility

sudo sysrc linux_enable=YES
sudo service linux start
sudo pkg install linux_base-rl9
kldstat -m linux64    # should print a module

2. Make Zed pick the Linux server

Zed asks the host what platform it runs. FreeBSD says FreeBSD amd64, there’s no server for that, and Zed gives up. This wrapper says Linux x86_64 to that one question and passes everything else to the real uname. Save it as ~/.local/bin/uname and make it executable:

#!/bin/sh
case "$#:$*" in
  1:-sm|1:-ms) printf 'Linux x86_64\n' ;;
  *) exec /usr/bin/uname "$@" ;;
esac

Put ~/.local/bin on PATH for non-interactive SSH sessions. For zsh, add this to ~/.zshenv (use your shell’s equivalent):

export PATH="$HOME/.local/bin:$PATH"

It’s a small lie, but a contained one, and the part I’d love to retire.

3. Connect.

Connect over SSH from Zed and open a folder. The first connection uploads the Linux server to ~/.zed_server/. To watch, run tail -f ~/.local/share/zed/logs/server-workspace-*.log.

4. Run a kernel with the (FreeBSD) fix

Without it you’ll connect fine and get an empty project tree, with this in the server log:

error processing entry failed to read directory entry
Caused by:
    Invalid argument (os error 22)

The fix is ec6629628cb, in main, stable/15 and releng/15.2, so 15.2-RELEASE will include it. If the error persists, check you booted the new kernel with uname -v.

The bug in layman terms

To show your project, Zed asks the server for the names of the files in each folder, a few at a time. Zed sets aside a small amount of space for each batch.

Picture a teacher reading a class roll to a student who writes the names on a sticky note (I couldn’t come up with a better analogy, bare with me). The teacher crosses off each name as she reads it, and she never reads a crossed-off name again. The student’s note has room for 6 names. The teacher reads in groups of 4, a sensible habit that works fine almost every time. But 6 isn’t a whole number of groups, so she reads 8 names and crosses all 8 off. Only 6 fit on the note.

Now she’s in a bind. Her slip was grabbing more than fit before checking. She can’t hand over the 6 that fit and keep the other 2 for later, because they’re already crossed off and she would never read them again. So she reports an error instead, which at least is loud. When I tried the quiet way, 112 of my 1,002 files vanished (from the listing) with no warning. A loud error beats a quiet loss I’m pretty sure. Zed saw the error and decided it couldn’t read the folder, and showed it up empty.

The fix is small: read no more names than fit on the note. Read 6, cross off 6, come back for the next 6, until the roll is done. In the real bug, the teacher is FreeBSD’s Linux translator (Linuxulator), the note is a 768-byte buffer, and a group of 4 names is a 512-byte block.

For the kernel nerds

This is a regression. A February 2026 fix for NFS directories returning bogus entries (110f2567cb51, PR 292282) changed how sys/compat/linux/linux_file.c sizes its native read, in both linux_getdents() and linux_getdents64():

/* before February 2026 */
buflen = min(args->count, MAXBSIZE);

/* after: every request rounded up to a 512-byte block */
buflen = min(roundup2(args->count, DEV_BSIZE), MAXBSIZE);

If the caller’s buffer isn’t a multiple of 512 bytes, the native batch can outgrow it. The emulation layer converts records until one doesn’t fit and returns EINVAL, but kern_getdirentries() has already advanced the directory offset past the whole batch. That’s why returning a partial batch isn’t enough on its own.

The fix (ec6629628cb, reviewed in D60760):

if (args->count >= DEV_BSIZE)
	buflen = min(args->count, MAXBSIZE);
else
	buflen = roundup2(args->count, DEV_BSIZE);

It’s safe because Linux directory records are never larger than FreeBSD’s: for dirent64 the header is 19 bytes against 24, and both round each record up to a multiple of 8. A native batch that fits in the caller’s buffer translates into one that fits too.

Legacy getdents had the same bug for 32-bit and 64-bit callers. My first patch only fixed getdents64; fixing both took the test matrix from 86 failures to zero.

Acknowledgements

I’ve had plenty of patches merged before this one, but this was among the quickest to land in releng/15.2: it didn’t sit in stable for long (thankfully!). The release engineering team (re@) runs a really cool process that I am yet to fully understand in depth. Thank you also to Kyle Evans (kevans@) and Mark Johnston (markj@) for reviewing the patch and for their notes along the way.

联系我们 contact @ memedata.com