VOP_RDWR(9)

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

書式
<sys/param.h> <sys/vnode.h> <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 が書きました。