[インデックス 14053] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおけるLinux/ARMアーキテクチャ向けのStatfs
およびFstatfs
システムコールの実装に関する修正です。具体的には、これらの関数が正しく動作するように、引数の渡し方とシステムコール呼び出しのロジックが変更されています。
コミット
commit f8485954bf06546675ac779f18fa7e8fb561113a
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Mon Oct 8 00:13:28 2012 +0800
syscall: fix Statfs and Fstatfs on Linux/ARM
R=golang-dev, dave, rsc
CC=golang-dev
https://golang.org/cl/6615055
---
src/pkg/syscall/syscall_linux_arm.go | 24 ++++++++++++++++++++++--
src/pkg/syscall/zsyscall_linux_arm.go | 25 -------------------------
2 files changed, 22 insertions(+), 27 deletions(-)
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f8485954bf06546675ac779f18fa7e8fb561113a
元コミット内容
syscall: fix Statfs and Fstatfs on Linux/ARM
このコミットメッセージは、Linux/ARM環境におけるStatfs
およびFstatfs
システムコールの問題を修正することを示しています。
変更の背景
Go言語のsyscall
パッケージは、オペレーティングシステムの低レベルな機能(システムコール)にアクセスするためのインターフェースを提供します。システムコールはOSのカーネルが提供するサービスを利用するための唯一の手段であり、ファイルシステム情報の取得(Statfs
やFstatfs
など)もその一つです。
Linux/ARMアーキテクチャでは、システムコールの呼び出し規約(レジスタへの引数の渡し方など)が他のアーキテクチャ(x86-64など)と異なる場合があります。特に、構造体を引数として渡す場合や、ポインタとサイズを同時に渡す場合に、特定のレジスタに正しい値を配置する必要があります。
このコミット以前のGoのsyscall
パッケージにおけるStatfs
とFstatfs
の実装は、Linux/ARM環境で正しく機能していませんでした。これはおそらく、システムコールに渡される引数(特にStatfs_t
構造体へのポインタとそのサイズ)が、ARMのシステムコール規約に合致していなかったためと考えられます。結果として、これらの関数を呼び出すと、不正なデータが渡されたり、システムコールが期待通りに実行されなかったりする問題が発生していました。
この修正は、Linux/ARM環境でファイルシステム情報を正確に取得できるようにするために不可欠でした。
前提知識の解説
- システムコール (System Call): オペレーティングシステムが提供するサービスをプログラムが利用するためのインターフェースです。ファイル操作、メモリ管理、プロセス制御など、OSの機能にアクセスするために使用されます。
Statfs
/Fstatfs
: これらはファイルシステムに関する統計情報を取得するためのシステムコールです。Statfs
: 指定されたパス(ファイルまたはディレクトリ)が属するファイルシステムの情報を取得します。Fstatfs
: 指定されたファイルディスクリプタに関連付けられたファイルシステムの情報を取得します。- 取得される情報には、ブロックサイズ、総ブロック数、空きブロック数、利用可能なブロック数、inode数などが含まれます。
Statfs_t
構造体:Statfs
およびFstatfs
システムコールによって返されるファイルシステム情報を格納するための構造体です。この構造体の定義は、OSやアーキテクチャによって異なる場合があります。- ARMアーキテクチャ: Advanced RISC Machineの略で、モバイルデバイスや組み込みシステムで広く使用されているCPUアーキテクチャです。RISC(Reduced Instruction Set Computer)の原則に基づいて設計されており、電力効率と性能のバランスが特徴です。
- システムコール規約: 特定のアーキテクチャ(例: ARM)とOS(例: Linux)の組み合わせにおいて、システムコールを呼び出す際に、引数をどのようにレジスタに配置するか、戻り値をどのように取得するかといった取り決めです。これはABI (Application Binary Interface) の一部です。
Syscall
関数 (Go言語): Go言語のsyscall
パッケージで提供される汎用的なシステムコール呼び出し関数です。引数としてシステムコール番号と、最大3つのuintptr
型の引数を取ります。unsafe.Pointer
(Go言語): Go言語のunsafe
パッケージで提供される型で、任意の型のポインタを保持できます。Goの型システムをバイパスして、低レベルなメモリ操作を行う際に使用されます。システムコールに構造体へのポインタを渡す際などに利用されます。unsafe.Sizeof
(Go言語): Go言語のunsafe
パッケージで提供される関数で、指定された型のサイズ(バイト単位)を返します。システムコールに構造体のサイズを渡す際などに利用されます。zsyscall_linux_arm.go
: Goのsyscall
パッケージにおいて、特定のアーキテクチャ(この場合はLinux/ARM)向けのシステムコールラッパー関数が自動生成されるファイルです。通常、mksyscall.pl
のようなスクリプトによって生成されます。
技術的詳細
Linux/ARMにおけるStatfs
およびFstatfs
システムコールは、通常、statfs
またはfstatfs
という名前で提供されます。これらのシステムコールは、ファイルシステム情報を格納するための構造体へのポインタと、その構造体のサイズを引数として受け取ることが一般的です。
元の実装では、zsyscall_linux_arm.go
ファイルに自動生成されたFstatfs
およびStatfs
関数が使用されていました。これらの関数は、Syscall
関数を呼び出す際に、Statfs_t
構造体のポインタを渡していましたが、構造体のサイズを適切に渡していなかった可能性があります。
ARMアーキテクチャのシステムコール規約では、システムコールに構造体を渡す場合、その構造体へのポインタだけでなく、構造体のサイズも別の引数として渡す必要がある場合があります。これは、カーネルが渡された構造体のサイズを知ることで、正しいバージョンの構造体(例えば、32ビットシステムと64ビットシステムで構造体のレイアウトが異なる場合など)を処理できるようにするためです。
このコミットでは、src/pkg/syscall/syscall_linux_arm.go
にFstatfs
とStatfs
のカスタム実装を追加することで、この問題を解決しています。新しい実装では、Syscall
関数を呼び出す際に、unsafe.Sizeof(*buf)
を使用してStatfs_t
構造体のサイズを明示的に第2引数として渡しています。これにより、カーネルが期待する引数の形式に合致し、システムコールが正しく実行されるようになります。
また、zsyscall_linux_arm.go
からこれらの自動生成された関数を削除することで、カスタム実装が優先されるようにしています。これは、自動生成されたコードが特定のアーキテクチャの特殊なシステムコール規約に対応できない場合に、手動でオーバーライドする一般的なパターンです。
コアとなるコードの変更箇所
src/pkg/syscall/syscall_linux_arm.go
import "unsafe"
が追加されました。これは、unsafe.Sizeof
とunsafe.Pointer
を使用するために必要です。//sys Fstatfs(fd int, buf *Statfs_t) (err error) = SYS_FSTATFS64
の行がコメントアウトされました。これは、自動生成されるFstatfs
関数ではなく、手動で実装するFstatfs
関数を使用することを示すためです。//sys Statfs(path string, buf *Statfs_t) (err error) = SYS_STATFS64
の行がコメントアウトされました。これも同様に、手動で実装するStatfs
関数を使用することを示すためです。- 以下の
Fstatfs
関数のカスタム実装が追加されました。
この実装では、func Fstatfs(fd int, buf *Statfs_t) (err error) { _, _, e := Syscall(SYS_FSTATFS64, uintptr(fd), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf))) if e != 0 { err = e } return }
SYS_FSTATFS64
システムコールを呼び出す際に、ファイルディスクリプタfd
、Statfs_t
構造体のサイズunsafe.Sizeof(*buf)
、そしてStatfs_t
構造体へのポインタuintptr(unsafe.Pointer(buf))
を引数として渡しています。 - 以下の
Statfs
関数のカスタム実装が追加されました。
この実装では、func Statfs(path string, buf *Statfs_t) (err error) { pathp, err := BytePtrFromString(path) if err != nil { return err } _, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(pathp)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf))) if e != 0 { err = e } return }
SYS_STATFS64
システムコールを呼び出す際に、パス文字列へのポインタuintptr(unsafe.Pointer(pathp))
、Statfs_t
構造体のサイズunsafe.Sizeof(*buf)
、そしてStatfs_t
構造体へのポインタuintptr(unsafe.Pointer(buf))
を引数として渡しています。
src/pkg/syscall/zsyscall_linux_arm.go
- 自動生成されていた
Fstatfs
関数が削除されました。 - 自動生成されていた
Statfs
関数が削除されました。
コアとなるコードの解説
この修正の核心は、Linux/ARMアーキテクチャにおけるStatfs
およびFstatfs
システムコールの呼び出し規約に正確に合わせるために、Syscall
関数に渡す引数を調整した点にあります。
以前の自動生成されたコードでは、Statfs_t
構造体へのポインタのみを渡していた可能性があります。しかし、Linux/ARMの特定のバージョンやカーネルでは、statfs
やfstatfs
システムコールが、構造体へのポインタに加えて、その構造体のサイズも引数として期待する場合があります。これは、カーネルが異なるバージョンのstatfs
構造体(例えば、32ビットと64ビットのシステムでフィールドの配置やサイズが異なる場合)を区別するために必要となることがあります。
新しい実装では、Syscall
関数の第2引数としてunsafe.Sizeof(*buf)
を明示的に追加しています。これにより、システムコールはファイルディスクリプタ(またはパス)、構造体のサイズ、そして構造体へのポインタという3つの引数を受け取ることになります。この引数の並びと内容が、Linux/ARMカーネルが期待するstatfs
/fstatfs
システムコールの呼び出し規約に合致することで、システムコールが正しく解釈され、ファイルシステム情報が正確に取得できるようになります。
unsafe
パッケージの使用は、Goの型安全性を一時的にバイパスして、低レベルなメモリ操作を行うことを意味します。これはシステムコールのようなOSとの直接的なインターフェースを扱う際には一般的ですが、誤用するとプログラムの不安定性やセキュリティ上の問題を引き起こす可能性があるため、慎重に扱う必要があります。このケースでは、システムコールの正確な引数渡しのために必要不可欠な使用法です。
zsyscall_linux_arm.go
から該当する関数を削除したことは、Goのビルドシステムが自動生成するコードよりも、手動で記述されたsyscall_linux_arm.go
内のコードを優先させるための標準的な方法です。これにより、特定のアーキテクチャやOSの特殊な要件に対応するための柔軟性が提供されます。
関連リンク
- Go言語の
syscall
パッケージのドキュメント: https://pkg.go.dev/syscall - Linux
statfs
manページ:man 2 statfs
(Linuxシステムでコマンドラインから参照可能) - Linux
fstatfs
manページ:man 2 fstatfs
(Linuxシステムでコマンドラインから参照可能) - Go言語の
unsafe
パッケージのドキュメント: https://pkg.go.dev/unsafe
参考にした情報源リンク
- Go言語のソースコード(特に
src/pkg/syscall
ディレクトリ) - Linuxカーネルのシステムコール実装に関するドキュメントやソースコード
- ARMアーキテクチャのABI(Application Binary Interface)に関するドキュメント
- Go言語のIssueトラッカーやコードレビューシステム(CL: Change List)
- このコミットのCL: https://golang.org/cl/6615055 (コミットメッセージに記載されているリンク)