---
name: "VOP_READ"
section: "9"
platform: "linux"
package: "freebsd-manpages"
version: "6.0-5"
release: "Debian 4.0 (Etch)"
platforms: ["linux", "freebsd"]
url: "https://new.carta.tech/VOP_READ"
---

# VOP\_READ(9)

read or write a file

## NAME

**VOP\_READ**, **VOP\_WRITE** – read or write a file

## SYNOPSIS

**#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*);

## DESCRIPTION

These entry points read or write the contents of a file

The arguments are:

- *vp*

  The vnode of the file.

- *uio*

  The location of the data to be read or written.

- *ioflag*

  Various flags.

- *cnp*

  The credentials of the caller.

The *ioflag* argument is used to give directives and hints to the file system. When attempting a read, the high 16 bits are used to provide a read-ahead hint (in units of file system blocks) that the file system should attempt. The low 16 bits are a bit mask which can contain the following flags:

- IO\_UNIT

  Do I/O as atomic unit.

- IO\_APPEND

  Append write to end.

- IO\_SYNC

  Do I/O synchronously.

- IO\_NODELOCKED

  Underlying node already locked.

- IO\_NDELAY

  FNDELAY flag set in file table.

- IO\_VMIO

  Data already in VMIO space.

## LOCKS

The file should be locked on entry and will still be locked on exit.

## RETURN VALUES

Zero is returned on success, otherwise an error code is returned.

## PSEUDOCODE

```
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;
	}
	/*
	 * We should only get non-zero b_resid when an I/O error
	 * has occurred, which should cause us to break above.
	 * However, if the short read did not cause an error,
	 * then we want to ensure that we do not uiomove bad
	 * or uninitialized data.
	 */
	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 does not check the error here.  Why? */
	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) {
	    /* call private routine to truncate file. */
	    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 what does this do? */
    }
    return (error);
}
```

## ERRORS

- \[EFBIG\]

  An attempt was made to write a file that exceeds the process's file size limit or the maximum file size.

- \[ENOSPC\]

  The file system is full.

- \[EPERM\]

  An append-only flag is set on the file, but the caller is attempting to write before the current end of file.

## SEE ALSO

[uiomove(9)](/uiomove/9.md), [vnode(9)](/vnode/9.md)

## AUTHORS

This manual page was written by Doug Rabson.
