スポンサーリンク

VOP_RDWR(9) FreeBSD カーネル開発者マニュアル VOP_RDWR(9)

名称

VOP_READ, VOP_WRITE − ファイルの読み込みまたは書き込み

書式

#include <sys/param.h>
#include <sys/vnode.h>
#include <sys/uio.h>

int

VOP_READ(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred);

int

VOP_WRITE(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred);

解説

これらのエントリポイントは、ファイルの内容を読み込みまたは書き込みます。

引数は以下の通りです。

       vp

ファイルの vnode。

uio
読み込みまたは書き込み対象のデータの位置。

ioflag
様々なフラグ。

cnp
呼び出し側の証明。

ioflag 引数は、ファイルシステムに対する命令およびヒントを与えるために使用 されます。読み込みを試みる時には、上位の 16 ビットは、ファイルシステムが 試みるべき先読みのヒントを (ファイルシステムブロック単位で) 提供するため に使用されます。下位の 16 ビットは、以下のフラグを含むことができるビット マスクです。

IO_UNIT
不可分に入出力を行ないます。

IO_APPEND
末尾に追加書き込みを行ないます。

IO_SYNC
同期的に入出力を行ないます。

IO_NODELOCKED
下位層のノードは既にロックされています。

IO_NDELAY
ファイルテーブルに FNDELAY フラグを設定します。

IO_VMIO
仮想メモリ入出力 (VMIO) 領域にデータが既にあります。

ロック

入る時に、ファイルはロックされているべきで、終了時までロックされ続けま す。

戻り値

成功時には 0 が返され、そうでない場合にはエラーコードが返されます。

疑似コード

int
vop_read(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred)
{
    struct buf *bp;
    off_t bytesinfile;
    daddr_t lbn, nextlbn;
    long size, xfersize, blkoffset;
    int error;

   size = block size of file system;

   for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {

bytesinfile = size of file - uio->uio_offset;

if (bytesinfile <= 0)

break;

lbn = uio->uio_offset / size;

blkoffset = uio->uio_offset - lbn * size;

xfersize = size - blkoffset;

if (uio->uio_resid < xfersize)

xfersize = uio->uio_resid;

if (bytesinfile < xfersize)

xfersize = bytesinfile;

error = bread(vp, lbn, size, NOCRED, &bp);

if (error) {

brelse(bp);

bp = NULL;

break;

}

/*

* 入出力エラーが起こった時には 0 でない b_resid のみ

* を得ます。これは上で break を引き起こすべきです。

* しかしながら、短い読み込みがエラーを起こさなかった

* 場合には、間違ったまたは初期化されていないデータの

* uiomove を行なわないことを保証したい。

*/

size -= bp->b_resid;

if (size < xfersize) {

if (size == 0)

break;

xfersize = size;

}

error = uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);

if (error)

break;

bqrelse(bp);

}
if (bp != NULL)

bqrelse(bp);

return (error);
}

int
vop_write(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred)
{
struct buf *bp;
off_t bytesinfile;
daddr_t lbn, nextlbn;
off_t osize;
long size, resid, xfersize, blkoffset;
int flags;
int error;

osize = size of file;
size = block size of file system;
resid = uio->uio_resid;
if (ioflag & IO_SYNC)

flags = B_SYNC;

else

flags = 0;

for (error = 0; uio->uio_resid > 0;) {

lbn = uio->uio_offset / size;

blkoffset = uio->uio_offset - lbn * size;

xfersize = size - blkoffset;

if (uio->uio_resid < xfersize)

xfersize = uio->uio_resid;

if (uio->uio_offset + xfersize > size of file)

vnode_pager_setsize(vp, uio->uio_offset + xfersize);

if (size > xfersize)

flags |= B_CLRBUF;

else

flags &= ~B_CLRBUF;

error = find_block_in_file(vp, lbn, blkoffset + xfersize,

cred, &bp, flags);

if (error)

break;

if (uio->uio_offset + xfersize > size of file)

set size of file to uio->uio_offset + xfersize;

error = uiomove((char *)bp->b_data + blkoffset, (int) xfersize, uio);

/* XXX ufs はここでエラーチェックをしていません。何故? */

if (ioflag & IO_VMIO)

bp->b_flags |= B_RELBUF; /* ??? */

if (ioflag & IO_SYNC)

bwrite(bp);

else if (xfersize + blkoffset == size)

bawrite(bp);

else

bdwrite(bp);

if (error || xfersize == 0)

break;

}

if (error) {

if (ioflag & IO_UNIT) {

/* ファイルを切り詰める私的なルーチンを呼び出す。 */

your_truncate(vp, osize, ioflag & IO_SYNC, cred, uio->uio_td);

uio->uio_offset -= resid - uio->uio_resid;

uio->uio_resid = resid;

}

} else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {

struct timeval tv;

error = VOP_UPDATE(vp, &tv, &tv, 1); /* XXX これは何をしているの? */

}

return (error);
}

エラー

       [EFBIG]

プロセスのファイルサイズリミットまたは最大ファイルサイ ズを超えるファイルを書込もうとしました。

[ENOSPC]
ファイルシステムが一杯です。

[EPERM]
追加のみのフラグがファイルに設定されていますが、呼び出 し側が現在のファイル終了位置より前に書込もうとしまし た。

関連項目

uiomove(9), vnode(9)

作者

このマニュアルページは Doug Rabson が書きました。

FreeBSD 10.0 July 24, 1996 FreeBSD 10.0

スポンサーリンク