狠狠撸

狠狠撸Share a Scribd company logo
dofilewrite と vn_write
について
#start_printf
クサバ @kusabanachi
このスライドの概要など
● printf 動作を理解するために、
その経路中の dofilewrite と vn_write を
調べました
● 対象は NetBSD-6.0.1
全体地図
ココ
#start_printf wiki よ り
dofilewrite
int
dofilewrite(int fd, struct file *fp, const void *buf,
size_t nbyte, off_t *offset, int flags, register_t *retval)
{
struct iovec aiov;
struct uio auio;
size_t cnt;
int error;
aiov.iov_base = __UNCONST(buf); /* XXXUNCONST kills const */
aiov.iov_len = nbyte;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_resid = nbyte;
auio.uio_rw = UIO_WRITE;
auio.uio_vmspace = curproc->p_vmspace;
/*
* Writes return ssize_t because -1 is returned on error. Therefore
* we must restrict the length to SSIZE_MAX to avoid garbage return
* values.
*/
if (auio.uio_resid > SSIZE_MAX) {
error = EINVAL;
goto out;
}
cnt = auio.uio_resid;
error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags);
if (error) {
if (auio.uio_resid != cnt && (error == ERESTART ||
error == EINTR || error == EWOULDBLOCK))
error = 0;
if (error == EPIPE && !(fp->f_flag & FNOSIGPIPE)) {
mutex_enter(proc_lock);
psignal(curproc, SIGPIPE);
mutex_exit(proc_lock);
}
}
cnt -= auio.uio_resid;
ktrgenio(fd, UIO_WRITE, buf, cnt, error);
*retval = cnt;
out:
fd_putfile(fd);
return (error);
}
dofilewrite
dofilewrite ( man の説明)
DOFILEREAD(9) – high level file operations
dofilewrite() は buf のバッファから ,
ファイルエントリ fp のオブジェクトに ,
nbyte のデータの write をする
???
*offset はファイル操作のオフセットで、
操作後のオフセットも *offset に入って戻る
FOF_UPDATE_OFFSET フラグが flags に設定されていると、
fp のファイルオフセットが更新される
fd は ktrace 以外ではほぼ使っていない
成功すると転送されたバイト数が *retval で戻る
dofilewrite ( iovec と uio 構造体)
dofilewrite ( uio の man )
UIOMOVE(9) – uio 構造体で記述されるデータ移動
uio 構造体は通常移動中のデータを表す
struct uio {
struct iovec *uio_iov; :処理される I/O ベクタ s へのポインタ
int uio_iovcnt; : uio_iov 配列の I/O ベクタの数
off_t uio_offset; :対応するオブジェクトのオフセット
size_t uio_resid; :残り転送データ量
enum uio_rw uio_rw; :リードかライトを示すフラグ
struct vmspace *uio_vmspace; :転送データのアドレススペース
};
struct iovec {
void *iov_base; :メモリのアドレス
size_t iov_len; :バイト数
};
dofilewrite ( uio 構造体への代入)
auio に、ファイルに書き込む buf とサイズ、
WRITE フラグとアドレススペースを設定
Dofilewrite ( サイズの制限 )
/* Writes はエラー時に -1(signed) を返すから戻り値は ssize_t
* 従って、長さ(転送量)は SSIZE_MAX までに制限します
*/
src/sys/sys/errno.h
#define EINVAL 22 /* Invalid argument */
dofilewrite ( write 関数のコール)
データの転送量を退避して、
ファイルエントリに割り当てられている write 関数をコール
(関数ポインタがどうやって割り当てられたかについては
調べれていません???)
引数は
ファイルエントリ、オフセット、 uio 構造体、
ファイルエントリの f_cred 、 dofilewrite の引数の flags
vn_write
/*
* File table vnode write routine.
*/
static int
vn_write(file_t *fp, off_t *offset, struct uio *uio, kauth_cred_t cred,
int flags)
{
struct vnode *vp = (struct vnode *)fp->f_data;
int count, error, ioflag, fflag;
ioflag = IO_ADV_ENCODE(fp->f_advice) | IO_UNIT;
fflag = fp->f_flag;
if (vp->v_type == VREG && (fflag & O_APPEND))
ioflag |= IO_APPEND;
if (fflag & FNONBLOCK)
ioflag |= IO_NDELAY;
if (fflag & FFSYNC ||
(vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
ioflag |= IO_SYNC;
else if (fflag & FDSYNC)
ioflag |= IO_DSYNC;
if (fflag & FALTIO)
ioflag |= IO_ALTSEMANTICS;
if (fflag & FDIRECT)
ioflag |= IO_DIRECT;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
uio->uio_offset = *offset;
count = uio->uio_resid;
if ((error = enforce_rlimit_fsize(vp, uio, ioflag)) != 0)
goto out;
error = VOP_WRITE(vp, uio, ioflag, cred);
if (flags & FOF_UPDATE_OFFSET) {
if (ioflag & IO_APPEND) {
/*
* SUSv3 describes behaviour for count = 0 as following:
* "Before any action ... is taken, and if nbyte is zero
* and the file is a regular file, the write() function
* ... in the absence of errors ... shall return zero
* and have no other results."
*/
if (count)
*offset = uio->uio_offset;
} else
*offset += count - uio->uio_resid;
}
out:
VOP_UNLOCK(vp);
return (error);
}
vn_write
vn_write ( man の説明)
VNFILEOPS(9) – vnode file descriptor operation
vn_write(fp, offset, uio, cred, flags)
fp は file 構造体、
offset はファイル内のオフセット
uio は読み出すメモリを表す uio 構造体
cred は呼び出し元の資格
flags は FOR_UPDATE_OFFSET が定義されているときは、
ファイル内の読み出し位置を更新する
成功するとゼロを返し、そうでなければエラーを返す
vn_write ( vnode の取り出し)
FILE(9) – operations on file entries
f_data は下層のオブジェクトの実体の情報を持つ
src/sys/sys/file.h
struct file {
...
void *f_data; /* descriptor data, e.g. vnode/socket */
vn_write (フラグの再設定)
各種フラグを再設定( fp->f_flag から ioflag 変数へ)
vn_write ( f_advice のエンコード)
src/sys/sys/vnode.h
#define IO_UNIT 0x00010 /* do I/O as atomic unit */
#define IO_ADV_MASK 0x00003 /* access pattern hint */
#define IO_ADV_SHIFT 0
#define IO_ADV_ENCODE(adv) 
(((adv) << IO_ADV_SHIFT) & IO_ADV_MASK)
#define IO_ADV_DECODE(ioflag) 
(((ioflag) & IO_ADV_MASK) >> IO_ADV_SHIFT)
src/sys/sys/file.h
u_int f_advice; /* access pattern hint; UVM_ADV_* */
vn_write ( APPEND と NONBLOCK フラグ)
src/sys/sys/vnode.h
enum vtype { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK,
VFIFO, VBAD };
struct vnode {
enum vtype v_type; /* :: vnode type */
vn_write ( FSYNC と DSYNC フラグ)
src/sys/sys/fcntl.h
#define FFSYNC O_SYNC /* kernel */
#define FDSYNC O_DSYNC /* kernel */
OPEN(2) – open or create a file for reading or writing
O_SYNC は WRITE 命令がファイルデータとファイルステータスの
両方がストレージに格納されるのを待つ。 I/O ファイルの同期
O_DSYNC は WRITE 命令がファイルデータがストレージに
格納されるのを待つ。 I/O データの同期
vn_write (ファイルシステムの同期設定)
src/sys/sys/vnode.h
struct vnode {
struct mount *v_mount; /* ptr to vfs we are in */
src/sys/sys/fstypes.h
#define MNT_SYNCHRONOUS 0x00000002 /* file system written
synchronously */
vn_write ( ALTIO と DIRECT フラグ)
OPEN(2) – open or create a file for reading or writing
O_ALT_IO は代わりの I/O セグメントが使われる。
代わりの I/O セグメントは下層で定義され、
ほとんどの場合は代替の効果はない
O_DIRECT は通常ファイルの場合、
カーネルのキャッシュにバッファリングされずに、
下層のデバイスドライバと直接転送が行おうとする
vn_write ( vn_lock )
VNSUBR(9)
– high-level convenience functions for vnode operations
vn_lock(vp, flags)
vnode のロックを得るための共通コード。フラグは以下
LK_SHARED 共有ロック
LK_EXCLUSIVE 排他ロック
LK_NOWAIT ロックのために寝ない
LK_RETRY ロックできるまで、ロックやり直す
vn_write ( enforce_rlimit_fsize )
rlimit_fsize を強制する?(直訳)
vn_write --->
enforce_rlimit_fsize ( curlwp )
CURPROC(9) – current process, processor, and LWP
Struct lwp *curlwp(void);
curlwp マクロは現在の LWP の情報を持つ、 lwp 構造体を返す
NetBSD ドキュメンテーション : カーネル
http://www.jp.netbsd.org/ja/docs/kernel/
LWP すなわち軽量プロセスは、一つのプロセス、
またはカーネル内で実行されているプロセスの一つのスレッド
に対応します
vn_write --->
enforce_rlimit_fsize ( VOP_ISLOCKED )
VNODEOPS(9) – vnode operations
VOP_ISLOCKED(vp)
Vp がロックされているか調べる。
排他ロックなら LK_EXCLUSIVE が、
共有ロックなら LK_SHARED 、
ロック無しなら 0 が返る
vn_write --->
enforce_rlimit_fsize ( offset 位置)
追加書込みフラグなら、ファイルの終端から
そうでなければ、 uio に格納されたオフセットから
vn_write --->
enforce_rlimit_fsize ( RLIMIT _ FSIZE )
src/sys/sys/lwp.h
struct lwp {
struct proc *l_proc; /* parent process */
src/sys/sys/proc.h
#define p_rlimit p_limit->pl_rlimit
struct proc {
struct plimit *p_limit; /* Process limits */
src/sys/sys/resourcevar.h
struct plimit {
struct rlimit pl_rlimit[RLIM_NLIMITS];
#define RLIMIT_FSIZE 1 /* maximum file size */
vn_write --->
enforce_rlimit_fsize ( mutex )
MUTEX(9) – mutual exclusion primitives
Mutex は LWP と割込みハンドラの相互排他のために
カーネルで使われる
mutex_enter(mtx)
mutex を獲得する
すでに取られていた場合、呼出し元は獲得できるまで
ブロックされて戻ってこない。
mutex_exit(mtx)
mutex を解放する
vn_write --->
enforce_rlimit_fsize ( psignal )
SIGNAL(9) – software signal facilities
psignal(p, signum)
kpsignal のラッパー関数。
kpsignal(p, ks, data)
ks->ksi_signo のシグナルがプロセス p に配達されるように
スケジュールする。
vn_write --->
enforce_rlimit_fsize ( SIGXFSZ と EFBIG )
src/sys/sys/signal.h
#define SIGXFSZ 25 /* exceeded file size limit */
src/sys/sys/errno.h
#define EFBIG 27 /* File too large */
vn_write ( VOP_WRITE のコール)
vnode, uio 構造体 , ioflag, 資格情報を引数に VOP_WRITE を呼ぶ
vn_write ( IO_APPEND のコメント)
SuSv3:Single UNIX Specification Verision 3
なんらかのアクションが行われる前に、 nbyte がゼロで、ファイ
ルが通常ファイルで、エラーが無い場合、
write 関数はゼロを返して他に結果を持たない。
vn_write ( FOF_UPDATE_OFFSET 処理)
追加書き込みモード時は
uio->uio_offset に更新後のファイルオフセットがあるようだ
そうでない場合は、転送データ残量の差分をオフセットに
加算している
vn_write ( VOP_UNLOCK )
VNODEOPS(9) – vnode operations
VOP_UNLOCK(vp)
ロック状態のプロセスを起こす
vp はアンロックされるファイルの vnode
dofilewrite ( vn_write の戻り値)
src/sys/sys/errno.h
#define ERESTART -3 /* restart syscall */
#define EINTR 4 /* Interrupted system call */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define EPIPE 32 /* Broken pipe */
dofilewrite (エラー処理)
残り転送データ量の変化があれば、
ERESTART 、 EINTR 、 EWOULDBLOCK のエラーを消す。
パイプが壊れた時のシグナル処理
dofilewrite (エラー処理)
残り転送データ量の変化があれば、
ERESTART 、 EINTR 、 EWOULDBLOCK のエラーを消す。
パイプが壊れた時のシグナル処理
dofilewrite ( ktrace と *retval )
vn_write コール前後の、残りのデータ転送量の差分から、
転送したデータ量を計算して *retval に格納している
Ktrgenio は ktrace の入り口の関数。
int ktrace_on;
が有効なら処理が行われる
dofilewrite ( fd_putfile )
/*
* Release a reference to a file descriptor acquired with
fd_getfile().
*/
void
fd_putfile(unsigned fd)
FILEDESC(9) – file descriptor tables and operations
fd_getfile(fdp, fd)
ファイルディスクリプタ fd に対応する、
ファイルディスクリプタテーブル fdp にある
ファイルエントリを得る
dofilewrite まとめ
● Uio 構造体に write する情報等を入れる
● サイズを SSIZE_MAX に制限する
● ファイルエントリに登録されている
write 関数 (vn_write) をコール
● 戻り値がエラーの場合、必要な処理をする
● ktrace に続く関数をコール
● 転送したサイズを *retval にいれる
● ファイルディスクリプタの参照を解放する
vn_write まとめ
● 引数のファイル構造体から vnode を取り出す
● 引数のフラグを元にフラグを再設定する
● vn_lock で vnode をロックする
● 通常ファイルの場合、
ファイルサイズの上限に収まるかチェック
● VOP_WRITE をコールする
● FOF_UPDATE_OFFSET フラグが指定されてれば
新しいオフセットを計算して更新する
● VOP_UNLOCK で vnode のロックを解除する

More Related Content

What's hot (20)

Async design with Unity3D
Async design with Unity3DAsync design with Unity3D
Async design with Unity3D
Kouji Hosoda
?
Effective modern-c++#9
Effective modern-c++#9Effective modern-c++#9
Effective modern-c++#9
Tatsuki SHIMIZU
?
What is Metasepi?
What is Metasepi?What is Metasepi?
What is Metasepi?
Kiwamu Okabe
?
emc++ chapter32
emc++ chapter32emc++ chapter32
emc++ chapter32
Tatsuki SHIMIZU
?
コルーチンの使い方
コルーチンの使い方コルーチンの使い方
コルーチンの使い方
Naohiro Yoshikawa
?
Kanazawa.js.Next
Kanazawa.js.NextKanazawa.js.Next
Kanazawa.js.Next
dynamis
?
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
Yasuhiro Ishii
?
Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35
Keisuke Fukuda
?
C++でHello worldを書いてみた
C++でHello worldを書いてみたC++でHello worldを書いてみた
C++でHello worldを書いてみた
firewood
?
20分くらいでわかった気分になれる颁++20コルーチン
20分くらいでわかった気分になれる颁++20コルーチン20分くらいでわかった気分になれる颁++20コルーチン
20分くらいでわかった気分になれる颁++20コルーチン
yohhoy
?
厂肠补濒补の限定継続の応用と基本
厂肠补濒补の限定継続の応用と基本厂肠补濒补の限定継続の応用と基本
厂肠补濒补の限定継続の応用と基本
Kota Mizushima
?
Visual C++コード分析を支えるSAL
Visual C++コード分析を支えるSALVisual C++コード分析を支えるSAL
Visual C++コード分析を支えるSAL
egtra
?
狠狠撸
狠狠撸狠狠撸
狠狠撸
Takefumi MIYOSHI
?
お前は PHP の歴史的な理由の数を覚えているのか
お前は PHP の歴史的な理由の数を覚えているのかお前は PHP の歴史的な理由の数を覚えているのか
お前は PHP の歴史的な理由の数を覚えているのか
Kousuke Ebihara
?
尝尝痴惭で游ぶ(整数圧缩とか、虫86向けの自动ベクトル化とか)
尝尝痴惭で游ぶ(整数圧缩とか、虫86向けの自动ベクトル化とか)尝尝痴惭で游ぶ(整数圧缩とか、虫86向けの自动ベクトル化とか)
尝尝痴惭で游ぶ(整数圧缩とか、虫86向けの自动ベクトル化とか)
Takeshi Yamamuro
?
Sharing Deep Dive
Sharing Deep DiveSharing Deep Dive
Sharing Deep Dive
Takaaki Suzuki
?
core dumpでcode golf
core dumpでcode golfcore dumpでcode golf
core dumpでcode golf
Nomura Yusuke
?
プロセスとコンテキストスイッチ
プロセスとコンテキストスイッチプロセスとコンテキストスイッチ
プロセスとコンテキストスイッチ
Kazuki Onishi
?
Async design with Unity3D
Async design with Unity3DAsync design with Unity3D
Async design with Unity3D
Kouji Hosoda
?
Kanazawa.js.Next
Kanazawa.js.NextKanazawa.js.Next
Kanazawa.js.Next
dynamis
?
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
Yasuhiro Ishii
?
Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35
Keisuke Fukuda
?
C++でHello worldを書いてみた
C++でHello worldを書いてみたC++でHello worldを書いてみた
C++でHello worldを書いてみた
firewood
?
20分くらいでわかった気分になれる颁++20コルーチン
20分くらいでわかった気分になれる颁++20コルーチン20分くらいでわかった気分になれる颁++20コルーチン
20分くらいでわかった気分になれる颁++20コルーチン
yohhoy
?
厂肠补濒补の限定継続の応用と基本
厂肠补濒补の限定継続の応用と基本厂肠补濒补の限定継続の応用と基本
厂肠补濒补の限定継続の応用と基本
Kota Mizushima
?
Visual C++コード分析を支えるSAL
Visual C++コード分析を支えるSALVisual C++コード分析を支えるSAL
Visual C++コード分析を支えるSAL
egtra
?
お前は PHP の歴史的な理由の数を覚えているのか
お前は PHP の歴史的な理由の数を覚えているのかお前は PHP の歴史的な理由の数を覚えているのか
お前は PHP の歴史的な理由の数を覚えているのか
Kousuke Ebihara
?
尝尝痴惭で游ぶ(整数圧缩とか、虫86向けの自动ベクトル化とか)
尝尝痴惭で游ぶ(整数圧缩とか、虫86向けの自动ベクトル化とか)尝尝痴惭で游ぶ(整数圧缩とか、虫86向けの自动ベクトル化とか)
尝尝痴惭で游ぶ(整数圧缩とか、虫86向けの自动ベクトル化とか)
Takeshi Yamamuro
?
プロセスとコンテキストスイッチ
プロセスとコンテキストスイッチプロセスとコンテキストスイッチ
プロセスとコンテキストスイッチ
Kazuki Onishi
?

Similar to dofilewrite and vn_write (20)

スタート低レイヤー #0
スタート低レイヤー #0スタート低レイヤー #0
スタート低レイヤー #0
Kiwamu Okabe
?
2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ
Makiko Konoshima
?
颈苍颈迟谤补尘蹿蝉について
颈苍颈迟谤补尘蹿蝉について颈苍颈迟谤补尘蹿蝉について
颈苍颈迟谤补尘蹿蝉について
Kazuhiro Nishiyama
?
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。
Kazuki Onishi
?
コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)
コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)
コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)
NTT DATA Technology & Innovation
?
Gingerbread
GingerbreadGingerbread
Gingerbread
android sola
?
デバドラを书いてみよう!
デバドラを书いてみよう!デバドラを书いてみよう!
デバドラを书いてみよう!
Masami Ichikawa
?
笔贵部2011年12月勉强会.补苍诲谤辞颈诲蝉辞濒补
笔贵部2011年12月勉强会.补苍诲谤辞颈诲蝉辞濒补笔贵部2011年12月勉强会.补苍诲谤辞颈诲蝉辞濒补
笔贵部2011年12月勉强会.补苍诲谤辞颈诲蝉辞濒补
android sola
?
○○大学の本当にあった怖い话
○○大学の本当にあった怖い话○○大学の本当にあった怖い话
○○大学の本当にあった怖い话
idkqh7 Nishino
?
Rubyで創るOpenFlowネットワーク - LLまつり
Rubyで創るOpenFlowネットワーク - LLまつりRubyで創るOpenFlowネットワーク - LLまつり
Rubyで創るOpenFlowネットワーク - LLまつり
Yuya Rin
?
mod_auth_ticket - Bringing Single-Sign-On to lighttpd
mod_auth_ticket - Bringing Single-Sign-On to lighttpdmod_auth_ticket - Bringing Single-Sign-On to lighttpd
mod_auth_ticket - Bringing Single-Sign-On to lighttpd
Taisuke Yamada
?
2011.06.11 v7から始めるunix まとめ
2011.06.11 v7から始めるunix まとめ2011.06.11 v7から始めるunix まとめ
2011.06.11 v7から始めるunix まとめ
Makiko Konoshima
?
JIT のコードを読んでみた
JIT のコードを読んでみたJIT のコードを読んでみた
JIT のコードを読んでみた
y-uti
?
どこでも动くゲームを作るためのベタープラクティス
どこでも动くゲームを作るためのベタープラクティスどこでも动くゲームを作るためのベタープラクティス
どこでも动くゲームを作るためのベタープラクティス
5mingame2
?
础苍诲谤辞颈诲と蹿辫驳补を高速蹿颈蹿辞通信させちゃう
础苍诲谤辞颈诲と蹿辫驳补を高速蹿颈蹿辞通信させちゃう础苍诲谤辞颈诲と蹿辫驳补を高速蹿颈蹿辞通信させちゃう
础苍诲谤辞颈诲と蹿辫驳补を高速蹿颈蹿辞通信させちゃう
ksk sue
?
ある尘尘补辫の话
ある尘尘补辫の话ある尘尘补辫の话
ある尘尘补辫の话
nullnilaki
?
组み込みシステムのセキュリティ
组み込みシステムのセキュリティ组み込みシステムのセキュリティ
组み込みシステムのセキュリティ
FFRI, Inc.
?
Zend Frameworkで始める携帯サイト
Zend Frameworkで始める携帯サイトZend Frameworkで始める携帯サイト
Zend Frameworkで始める携帯サイト
清水树
?
Cvim saisentan 半精度浮動小数点数 half
Cvim saisentan 半精度浮動小数点数 halfCvim saisentan 半精度浮動小数点数 half
Cvim saisentan 半精度浮動小数点数 half
tomoaki0705
?
础苍蝉颈产濒别2.0と実用例
础苍蝉颈产濒别2.0と実用例础苍蝉颈产濒别2.0と実用例
础苍蝉颈产濒别2.0と実用例
翱厂厂ラボ株式会社
?
スタート低レイヤー #0
スタート低レイヤー #0スタート低レイヤー #0
スタート低レイヤー #0
Kiwamu Okabe
?
2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ
Makiko Konoshima
?
颈苍颈迟谤补尘蹿蝉について
颈苍颈迟谤补尘蹿蝉について颈苍颈迟谤补尘蹿蝉について
颈苍颈迟谤补尘蹿蝉について
Kazuhiro Nishiyama
?
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。
Kazuki Onishi
?
コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)
コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)
コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)
NTT DATA Technology & Innovation
?
デバドラを书いてみよう!
デバドラを书いてみよう!デバドラを书いてみよう!
デバドラを书いてみよう!
Masami Ichikawa
?
笔贵部2011年12月勉强会.补苍诲谤辞颈诲蝉辞濒补
笔贵部2011年12月勉强会.补苍诲谤辞颈诲蝉辞濒补笔贵部2011年12月勉强会.补苍诲谤辞颈诲蝉辞濒补
笔贵部2011年12月勉强会.补苍诲谤辞颈诲蝉辞濒补
android sola
?
○○大学の本当にあった怖い话
○○大学の本当にあった怖い话○○大学の本当にあった怖い话
○○大学の本当にあった怖い话
idkqh7 Nishino
?
Rubyで創るOpenFlowネットワーク - LLまつり
Rubyで創るOpenFlowネットワーク - LLまつりRubyで創るOpenFlowネットワーク - LLまつり
Rubyで創るOpenFlowネットワーク - LLまつり
Yuya Rin
?
mod_auth_ticket - Bringing Single-Sign-On to lighttpd
mod_auth_ticket - Bringing Single-Sign-On to lighttpdmod_auth_ticket - Bringing Single-Sign-On to lighttpd
mod_auth_ticket - Bringing Single-Sign-On to lighttpd
Taisuke Yamada
?
2011.06.11 v7から始めるunix まとめ
2011.06.11 v7から始めるunix まとめ2011.06.11 v7から始めるunix まとめ
2011.06.11 v7から始めるunix まとめ
Makiko Konoshima
?
JIT のコードを読んでみた
JIT のコードを読んでみたJIT のコードを読んでみた
JIT のコードを読んでみた
y-uti
?
どこでも动くゲームを作るためのベタープラクティス
どこでも动くゲームを作るためのベタープラクティスどこでも动くゲームを作るためのベタープラクティス
どこでも动くゲームを作るためのベタープラクティス
5mingame2
?
础苍诲谤辞颈诲と蹿辫驳补を高速蹿颈蹿辞通信させちゃう
础苍诲谤辞颈诲と蹿辫驳补を高速蹿颈蹿辞通信させちゃう础苍诲谤辞颈诲と蹿辫驳补を高速蹿颈蹿辞通信させちゃう
础苍诲谤辞颈诲と蹿辫驳补を高速蹿颈蹿辞通信させちゃう
ksk sue
?
ある尘尘补辫の话
ある尘尘补辫の话ある尘尘补辫の话
ある尘尘补辫の话
nullnilaki
?
组み込みシステムのセキュリティ
组み込みシステムのセキュリティ组み込みシステムのセキュリティ
组み込みシステムのセキュリティ
FFRI, Inc.
?
Zend Frameworkで始める携帯サイト
Zend Frameworkで始める携帯サイトZend Frameworkで始める携帯サイト
Zend Frameworkで始める携帯サイト
清水树
?
Cvim saisentan 半精度浮動小数点数 half
Cvim saisentan 半精度浮動小数点数 halfCvim saisentan 半精度浮動小数点数 half
Cvim saisentan 半精度浮動小数点数 half
tomoaki0705
?

dofilewrite and vn_write

  • 2. このスライドの概要など ● printf 動作を理解するために、 その経路中の dofilewrite と vn_write を 調べました ● 対象は NetBSD-6.0.1
  • 5. int dofilewrite(int fd, struct file *fp, const void *buf, size_t nbyte, off_t *offset, int flags, register_t *retval) { struct iovec aiov; struct uio auio; size_t cnt; int error; aiov.iov_base = __UNCONST(buf); /* XXXUNCONST kills const */ aiov.iov_len = nbyte; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_resid = nbyte; auio.uio_rw = UIO_WRITE; auio.uio_vmspace = curproc->p_vmspace; /* * Writes return ssize_t because -1 is returned on error. Therefore * we must restrict the length to SSIZE_MAX to avoid garbage return * values. */ if (auio.uio_resid > SSIZE_MAX) { error = EINVAL; goto out; } cnt = auio.uio_resid; error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags); if (error) { if (auio.uio_resid != cnt && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; if (error == EPIPE && !(fp->f_flag & FNOSIGPIPE)) { mutex_enter(proc_lock); psignal(curproc, SIGPIPE); mutex_exit(proc_lock); } } cnt -= auio.uio_resid; ktrgenio(fd, UIO_WRITE, buf, cnt, error); *retval = cnt; out: fd_putfile(fd); return (error); }
  • 7. dofilewrite ( man の説明) DOFILEREAD(9) – high level file operations dofilewrite() は buf のバッファから , ファイルエントリ fp のオブジェクトに , nbyte のデータの write をする ??? *offset はファイル操作のオフセットで、 操作後のオフセットも *offset に入って戻る FOF_UPDATE_OFFSET フラグが flags に設定されていると、 fp のファイルオフセットが更新される fd は ktrace 以外ではほぼ使っていない 成功すると転送されたバイト数が *retval で戻る
  • 8. dofilewrite ( iovec と uio 構造体)
  • 9. dofilewrite ( uio の man ) UIOMOVE(9) – uio 構造体で記述されるデータ移動 uio 構造体は通常移動中のデータを表す struct uio { struct iovec *uio_iov; :処理される I/O ベクタ s へのポインタ int uio_iovcnt; : uio_iov 配列の I/O ベクタの数 off_t uio_offset; :対応するオブジェクトのオフセット size_t uio_resid; :残り転送データ量 enum uio_rw uio_rw; :リードかライトを示すフラグ struct vmspace *uio_vmspace; :転送データのアドレススペース }; struct iovec { void *iov_base; :メモリのアドレス size_t iov_len; :バイト数 };
  • 10. dofilewrite ( uio 構造体への代入) auio に、ファイルに書き込む buf とサイズ、 WRITE フラグとアドレススペースを設定
  • 11. Dofilewrite ( サイズの制限 ) /* Writes はエラー時に -1(signed) を返すから戻り値は ssize_t * 従って、長さ(転送量)は SSIZE_MAX までに制限します */ src/sys/sys/errno.h #define EINVAL 22 /* Invalid argument */
  • 12. dofilewrite ( write 関数のコール) データの転送量を退避して、 ファイルエントリに割り当てられている write 関数をコール (関数ポインタがどうやって割り当てられたかについては 調べれていません???) 引数は ファイルエントリ、オフセット、 uio 構造体、 ファイルエントリの f_cred 、 dofilewrite の引数の flags
  • 14. /* * File table vnode write routine. */ static int vn_write(file_t *fp, off_t *offset, struct uio *uio, kauth_cred_t cred, int flags) { struct vnode *vp = (struct vnode *)fp->f_data; int count, error, ioflag, fflag; ioflag = IO_ADV_ENCODE(fp->f_advice) | IO_UNIT; fflag = fp->f_flag; if (vp->v_type == VREG && (fflag & O_APPEND)) ioflag |= IO_APPEND; if (fflag & FNONBLOCK) ioflag |= IO_NDELAY; if (fflag & FFSYNC || (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS))) ioflag |= IO_SYNC; else if (fflag & FDSYNC) ioflag |= IO_DSYNC; if (fflag & FALTIO) ioflag |= IO_ALTSEMANTICS; if (fflag & FDIRECT) ioflag |= IO_DIRECT; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); uio->uio_offset = *offset; count = uio->uio_resid; if ((error = enforce_rlimit_fsize(vp, uio, ioflag)) != 0) goto out; error = VOP_WRITE(vp, uio, ioflag, cred); if (flags & FOF_UPDATE_OFFSET) { if (ioflag & IO_APPEND) { /* * SUSv3 describes behaviour for count = 0 as following: * "Before any action ... is taken, and if nbyte is zero * and the file is a regular file, the write() function * ... in the absence of errors ... shall return zero * and have no other results." */ if (count) *offset = uio->uio_offset; } else *offset += count - uio->uio_resid; } out: VOP_UNLOCK(vp); return (error); }
  • 16. vn_write ( man の説明) VNFILEOPS(9) – vnode file descriptor operation vn_write(fp, offset, uio, cred, flags) fp は file 構造体、 offset はファイル内のオフセット uio は読み出すメモリを表す uio 構造体 cred は呼び出し元の資格 flags は FOR_UPDATE_OFFSET が定義されているときは、 ファイル内の読み出し位置を更新する 成功するとゼロを返し、そうでなければエラーを返す
  • 17. vn_write ( vnode の取り出し) FILE(9) – operations on file entries f_data は下層のオブジェクトの実体の情報を持つ src/sys/sys/file.h struct file { ... void *f_data; /* descriptor data, e.g. vnode/socket */
  • 19. vn_write ( f_advice のエンコード) src/sys/sys/vnode.h #define IO_UNIT 0x00010 /* do I/O as atomic unit */ #define IO_ADV_MASK 0x00003 /* access pattern hint */ #define IO_ADV_SHIFT 0 #define IO_ADV_ENCODE(adv) (((adv) << IO_ADV_SHIFT) & IO_ADV_MASK) #define IO_ADV_DECODE(ioflag) (((ioflag) & IO_ADV_MASK) >> IO_ADV_SHIFT) src/sys/sys/file.h u_int f_advice; /* access pattern hint; UVM_ADV_* */
  • 20. vn_write ( APPEND と NONBLOCK フラグ) src/sys/sys/vnode.h enum vtype { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VBAD }; struct vnode { enum vtype v_type; /* :: vnode type */
  • 21. vn_write ( FSYNC と DSYNC フラグ) src/sys/sys/fcntl.h #define FFSYNC O_SYNC /* kernel */ #define FDSYNC O_DSYNC /* kernel */ OPEN(2) – open or create a file for reading or writing O_SYNC は WRITE 命令がファイルデータとファイルステータスの 両方がストレージに格納されるのを待つ。 I/O ファイルの同期 O_DSYNC は WRITE 命令がファイルデータがストレージに 格納されるのを待つ。 I/O データの同期
  • 22. vn_write (ファイルシステムの同期設定) src/sys/sys/vnode.h struct vnode { struct mount *v_mount; /* ptr to vfs we are in */ src/sys/sys/fstypes.h #define MNT_SYNCHRONOUS 0x00000002 /* file system written synchronously */
  • 23. vn_write ( ALTIO と DIRECT フラグ) OPEN(2) – open or create a file for reading or writing O_ALT_IO は代わりの I/O セグメントが使われる。 代わりの I/O セグメントは下層で定義され、 ほとんどの場合は代替の効果はない O_DIRECT は通常ファイルの場合、 カーネルのキャッシュにバッファリングされずに、 下層のデバイスドライバと直接転送が行おうとする
  • 24. vn_write ( vn_lock ) VNSUBR(9) – high-level convenience functions for vnode operations vn_lock(vp, flags) vnode のロックを得るための共通コード。フラグは以下 LK_SHARED 共有ロック LK_EXCLUSIVE 排他ロック LK_NOWAIT ロックのために寝ない LK_RETRY ロックできるまで、ロックやり直す
  • 25. vn_write ( enforce_rlimit_fsize ) rlimit_fsize を強制する?(直訳)
  • 26. vn_write ---> enforce_rlimit_fsize ( curlwp ) CURPROC(9) – current process, processor, and LWP Struct lwp *curlwp(void); curlwp マクロは現在の LWP の情報を持つ、 lwp 構造体を返す NetBSD ドキュメンテーション : カーネル http://www.jp.netbsd.org/ja/docs/kernel/ LWP すなわち軽量プロセスは、一つのプロセス、 またはカーネル内で実行されているプロセスの一つのスレッド に対応します
  • 27. vn_write ---> enforce_rlimit_fsize ( VOP_ISLOCKED ) VNODEOPS(9) – vnode operations VOP_ISLOCKED(vp) Vp がロックされているか調べる。 排他ロックなら LK_EXCLUSIVE が、 共有ロックなら LK_SHARED 、 ロック無しなら 0 が返る
  • 28. vn_write ---> enforce_rlimit_fsize ( offset 位置) 追加書込みフラグなら、ファイルの終端から そうでなければ、 uio に格納されたオフセットから
  • 29. vn_write ---> enforce_rlimit_fsize ( RLIMIT _ FSIZE ) src/sys/sys/lwp.h struct lwp { struct proc *l_proc; /* parent process */ src/sys/sys/proc.h #define p_rlimit p_limit->pl_rlimit struct proc { struct plimit *p_limit; /* Process limits */ src/sys/sys/resourcevar.h struct plimit { struct rlimit pl_rlimit[RLIM_NLIMITS]; #define RLIMIT_FSIZE 1 /* maximum file size */
  • 30. vn_write ---> enforce_rlimit_fsize ( mutex ) MUTEX(9) – mutual exclusion primitives Mutex は LWP と割込みハンドラの相互排他のために カーネルで使われる mutex_enter(mtx) mutex を獲得する すでに取られていた場合、呼出し元は獲得できるまで ブロックされて戻ってこない。 mutex_exit(mtx) mutex を解放する
  • 31. vn_write ---> enforce_rlimit_fsize ( psignal ) SIGNAL(9) – software signal facilities psignal(p, signum) kpsignal のラッパー関数。 kpsignal(p, ks, data) ks->ksi_signo のシグナルがプロセス p に配達されるように スケジュールする。
  • 32. vn_write ---> enforce_rlimit_fsize ( SIGXFSZ と EFBIG ) src/sys/sys/signal.h #define SIGXFSZ 25 /* exceeded file size limit */ src/sys/sys/errno.h #define EFBIG 27 /* File too large */
  • 33. vn_write ( VOP_WRITE のコール) vnode, uio 構造体 , ioflag, 資格情報を引数に VOP_WRITE を呼ぶ
  • 34. vn_write ( IO_APPEND のコメント) SuSv3:Single UNIX Specification Verision 3 なんらかのアクションが行われる前に、 nbyte がゼロで、ファイ ルが通常ファイルで、エラーが無い場合、 write 関数はゼロを返して他に結果を持たない。
  • 35. vn_write ( FOF_UPDATE_OFFSET 処理) 追加書き込みモード時は uio->uio_offset に更新後のファイルオフセットがあるようだ そうでない場合は、転送データ残量の差分をオフセットに 加算している
  • 36. vn_write ( VOP_UNLOCK ) VNODEOPS(9) – vnode operations VOP_UNLOCK(vp) ロック状態のプロセスを起こす vp はアンロックされるファイルの vnode
  • 37. dofilewrite ( vn_write の戻り値) src/sys/sys/errno.h #define ERESTART -3 /* restart syscall */ #define EINTR 4 /* Interrupted system call */ #define EWOULDBLOCK EAGAIN /* Operation would block */ #define EPIPE 32 /* Broken pipe */
  • 38. dofilewrite (エラー処理) 残り転送データ量の変化があれば、 ERESTART 、 EINTR 、 EWOULDBLOCK のエラーを消す。 パイプが壊れた時のシグナル処理
  • 39. dofilewrite (エラー処理) 残り転送データ量の変化があれば、 ERESTART 、 EINTR 、 EWOULDBLOCK のエラーを消す。 パイプが壊れた時のシグナル処理
  • 40. dofilewrite ( ktrace と *retval ) vn_write コール前後の、残りのデータ転送量の差分から、 転送したデータ量を計算して *retval に格納している Ktrgenio は ktrace の入り口の関数。 int ktrace_on; が有効なら処理が行われる
  • 41. dofilewrite ( fd_putfile ) /* * Release a reference to a file descriptor acquired with fd_getfile(). */ void fd_putfile(unsigned fd) FILEDESC(9) – file descriptor tables and operations fd_getfile(fdp, fd) ファイルディスクリプタ fd に対応する、 ファイルディスクリプタテーブル fdp にある ファイルエントリを得る
  • 42. dofilewrite まとめ ● Uio 構造体に write する情報等を入れる ● サイズを SSIZE_MAX に制限する ● ファイルエントリに登録されている write 関数 (vn_write) をコール ● 戻り値がエラーの場合、必要な処理をする ● ktrace に続く関数をコール ● 転送したサイズを *retval にいれる ● ファイルディスクリプタの参照を解放する
  • 43. vn_write まとめ ● 引数のファイル構造体から vnode を取り出す ● 引数のフラグを元にフラグを再設定する ● vn_lock で vnode をロックする ● 通常ファイルの場合、 ファイルサイズの上限に収まるかチェック ● VOP_WRITE をコールする ● FOF_UPDATE_OFFSET フラグが指定されてれば 新しいオフセットを計算して更新する ● VOP_UNLOCK で vnode のロックを解除する