SlideShare una empresa de Scribd logo
1 de 43
Descargar para leer sin conexión
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 のロックを解除する

Más contenido relacionado

La actualidad más candente

Async design with Unity3D
Async design with Unity3DAsync design with Unity3D
Async design with Unity3DKouji Hosoda
 
Kanazawa.js.Next
Kanazawa.js.NextKanazawa.js.Next
Kanazawa.js.Nextdynamis
 
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519Yasuhiro Ishii
 
Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35Keisuke Fukuda
 
C++でHello worldを書いてみた
C++でHello worldを書いてみたC++でHello worldを書いてみた
C++でHello worldを書いてみたfirewood
 
20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチンyohhoy
 
Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本Kota Mizushima
 
Visual C++コード分析を支えるSAL
Visual C++コード分析を支えるSALVisual C++コード分析を支えるSAL
Visual C++コード分析を支えるSALegtra
 
お前は PHP の歴史的な理由の数を覚えているのか
お前は PHP の歴史的な理由の数を覚えているのかお前は PHP の歴史的な理由の数を覚えているのか
お前は PHP の歴史的な理由の数を覚えているのかKousuke Ebihara
 
Boost9 session
Boost9 sessionBoost9 session
Boost9 sessionfreedom404
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)Takeshi Yamamuro
 
core dumpでcode golf
core dumpでcode golfcore dumpでcode golf
core dumpでcode golfNomura Yusuke
 
プロセスとコンテキストスイッチ
プロセスとコンテキストスイッチプロセスとコンテキストスイッチ
プロセスとコンテキストスイッチKazuki Onishi
 

La actualidad más candente (20)

Async design with Unity3D
Async design with Unity3DAsync design with Unity3D
Async design with Unity3D
 
Effective modern-c++#9
Effective modern-c++#9Effective modern-c++#9
Effective modern-c++#9
 
What is Metasepi?
What is Metasepi?What is Metasepi?
What is Metasepi?
 
emc++ chapter32
emc++ chapter32emc++ chapter32
emc++ chapter32
 
コルーチンの使い方
コルーチンの使い方コルーチンの使い方
コルーチンの使い方
 
Kanazawa.js.Next
Kanazawa.js.NextKanazawa.js.Next
Kanazawa.js.Next
 
llvm入門
llvm入門llvm入門
llvm入門
 
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
DE0でラジコンカー作ってみた 関西de0 fpga勉強会20120519
 
Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35Effective Modern C++ 読書会 Item 35
Effective Modern C++ 読書会 Item 35
 
C++でHello worldを書いてみた
C++でHello worldを書いてみたC++でHello worldを書いてみた
C++でHello worldを書いてみた
 
20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン20分くらいでわかった気分になれるC++20コルーチン
20分くらいでわかった気分になれるC++20コルーチン
 
Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本Scalaの限定継続の応用と基本
Scalaの限定継続の応用と基本
 
Visual C++コード分析を支えるSAL
Visual C++コード分析を支えるSALVisual C++コード分析を支えるSAL
Visual C++コード分析を支えるSAL
 
Slide
SlideSlide
Slide
 
お前は PHP の歴史的な理由の数を覚えているのか
お前は PHP の歴史的な理由の数を覚えているのかお前は PHP の歴史的な理由の数を覚えているのか
お前は PHP の歴史的な理由の数を覚えているのか
 
Boost9 session
Boost9 sessionBoost9 session
Boost9 session
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
 
Sharing Deep Dive
Sharing Deep DiveSharing Deep Dive
Sharing Deep Dive
 
core dumpでcode golf
core dumpでcode golfcore dumpでcode golf
core dumpでcode golf
 
プロセスとコンテキストスイッチ
プロセスとコンテキストスイッチプロセスとコンテキストスイッチ
プロセスとコンテキストスイッチ
 

Similar a dofilewrite and vn_write

スタート低レイヤー #0
スタート低レイヤー #0スタート低レイヤー #0
スタート低レイヤー #0Kiwamu Okabe
 
2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめMakiko Konoshima
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。Kazuki Onishi
 
コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)
コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)
コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)NTT DATA Technology & Innovation
 
デバドラを書いてみよう!
デバドラを書いてみよう!デバドラを書いてみよう!
デバドラを書いてみよう!Masami Ichikawa
 
PF部2011年12月勉強会.androidsola
PF部2011年12月勉強会.androidsolaPF部2011年12月勉強会.androidsola
PF部2011年12月勉強会.androidsolaandroid 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 lighttpdTaisuke 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
 
Androidとfpgaを高速fifo通信させちゃう
Androidとfpgaを高速fifo通信させちゃうAndroidとfpgaを高速fifo通信させちゃう
Androidとfpgaを高速fifo通信させちゃうksk sue
 
あるmmapの話
あるmmapの話あるmmapの話
あるmmapの話nullnilaki
 
組み込みシステムのセキュリティ
組み込みシステムのセキュリティ組み込みシステムのセキュリティ
組み込みシステムのセキュリティFFRI, Inc.
 
Zend Frameworkで始める携帯サイト
Zend Frameworkで始める携帯サイトZend Frameworkで始める携帯サイト
Zend Frameworkで始める携帯サイト清水樹
 
Cvim saisentan 半精度浮動小数点数 half
Cvim saisentan 半精度浮動小数点数 halfCvim saisentan 半精度浮動小数点数 half
Cvim saisentan 半精度浮動小数点数 halftomoaki0705
 

Similar a dofilewrite and vn_write (20)

スタート低レイヤー #0
スタート低レイヤー #0スタート低レイヤー #0
スタート低レイヤー #0
 
2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ
 
initramfsについて
initramfsについてinitramfsについて
initramfsについて
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。
 
コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)
コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)
コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)
 
Gingerbread
GingerbreadGingerbread
Gingerbread
 
デバドラを書いてみよう!
デバドラを書いてみよう!デバドラを書いてみよう!
デバドラを書いてみよう!
 
PF部2011年12月勉強会.androidsola
PF部2011年12月勉強会.androidsolaPF部2011年12月勉強会.androidsola
PF部2011年12月勉強会.androidsola
 
○○大学の本当にあった怖い話
○○大学の本当にあった怖い話○○大学の本当にあった怖い話
○○大学の本当にあった怖い話
 
Rubyで創るOpenFlowネットワーク - LLまつり
Rubyで創るOpenFlowネットワーク - LLまつりRubyで創るOpenFlowネットワーク - LLまつり
Rubyで創るOpenFlowネットワーク - LLまつり
 
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
 
2011.06.11 v7から始めるunix まとめ
2011.06.11 v7から始めるunix まとめ2011.06.11 v7から始めるunix まとめ
2011.06.11 v7から始めるunix まとめ
 
JIT のコードを読んでみた
JIT のコードを読んでみたJIT のコードを読んでみた
JIT のコードを読んでみた
 
どこでも動くゲームを作るためのベタープラクティス
どこでも動くゲームを作るためのベタープラクティスどこでも動くゲームを作るためのベタープラクティス
どこでも動くゲームを作るためのベタープラクティス
 
Androidとfpgaを高速fifo通信させちゃう
Androidとfpgaを高速fifo通信させちゃうAndroidとfpgaを高速fifo通信させちゃう
Androidとfpgaを高速fifo通信させちゃう
 
あるmmapの話
あるmmapの話あるmmapの話
あるmmapの話
 
組み込みシステムのセキュリティ
組み込みシステムのセキュリティ組み込みシステムのセキュリティ
組み込みシステムのセキュリティ
 
Zend Frameworkで始める携帯サイト
Zend Frameworkで始める携帯サイトZend Frameworkで始める携帯サイト
Zend Frameworkで始める携帯サイト
 
Cvim saisentan 半精度浮動小数点数 half
Cvim saisentan 半精度浮動小数点数 halfCvim saisentan 半精度浮動小数点数 half
Cvim saisentan 半精度浮動小数点数 half
 
Ansible2.0と実用例
Ansible2.0と実用例Ansible2.0と実用例
Ansible2.0と実用例
 

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 のロックを解除する