Remove pseudocode from VOP_* manual pages. It was out of date anyway.
Reviewed by: scottl Approved by: rwatson (mentor)
This commit is contained in:
parent
584f7327f1
commit
6283502e20
@ -68,40 +68,6 @@ The vnode will be locked on entry and should remain locked on return.
|
||||
.Sh RETURN VALUES
|
||||
If the file is accessible in the specified way, then zero is returned,
|
||||
otherwise an appropriate error code is returned.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
int
|
||||
vop_access(struct vnode *vp, accmode_t accmode, struct ucred *cred, struct thread *td)
|
||||
{
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Disallow write attempts on read-only file systems;
|
||||
* unless the file is a socket, fifo, or a block or
|
||||
* character device resident on the filesystem.
|
||||
*/
|
||||
if (accmode & VWRITE) {
|
||||
switch (vp->v_type) {
|
||||
case VDIR:
|
||||
case VLNK:
|
||||
case VREG:
|
||||
if (vp->v_mount->mnt_flag & MNT_RDONLY)
|
||||
return EROFS;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If immutable bit set, nobody gets to write it. */
|
||||
if ((accmode & VWRITE) && vp has immutable bit set)
|
||||
return (EPERM);
|
||||
|
||||
error = vaccess(vp->v_type, mode of vp, owner of vp,
|
||||
group of vp, ap->a_accmode, ap->a_cred, NULL);
|
||||
|
||||
return (error);
|
||||
}
|
||||
.Ed
|
||||
.Sh ERRORS
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EPERM
|
||||
|
@ -84,68 +84,6 @@ otherwise an appropriate error is returned.
|
||||
.Fn VOP_SETATTR
|
||||
returns zero if the attributes were changed successfully, otherwise an
|
||||
appropriate error is returned.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
int
|
||||
vop_getattr(struct vnode *vp, struct vattr *vap, struct ucred *cred)
|
||||
{
|
||||
|
||||
/*
|
||||
* Fill in the contents of *vap with information from
|
||||
* the file system.
|
||||
*/
|
||||
...;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
vop_setattr(struct vnode *vp, struct vattr *vap, struct ucred *cred)
|
||||
{
|
||||
|
||||
/*
|
||||
* Check for unsettable attributes.
|
||||
*/
|
||||
if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
|
||||
(vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
|
||||
(vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
|
||||
((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
if (vap->va_flags != VNOVAL) {
|
||||
/*
|
||||
* Set the immutable and append flags of the file.
|
||||
*/
|
||||
}
|
||||
|
||||
if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
|
||||
/*
|
||||
* Change owner and/or group of the file.
|
||||
*/
|
||||
}
|
||||
|
||||
if (vap->va_size != VNOVAL) {
|
||||
/*
|
||||
* Truncate the file to the specified size.
|
||||
*/
|
||||
}
|
||||
|
||||
if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
|
||||
/*
|
||||
* Change access and/or modification time of file.
|
||||
*/
|
||||
}
|
||||
|
||||
if (vap->va_mode != (mode_t)VNOVAL) {
|
||||
/*
|
||||
* Change permissions of file.
|
||||
*/
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
.Ed
|
||||
.Sh ERRORS
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EPERM
|
||||
|
@ -80,67 +80,6 @@ If successful, the vnode for the new object is placed in
|
||||
.Fa *vpp
|
||||
and zero is returned.
|
||||
Otherwise, an appropriate error is returned.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
int
|
||||
vop_create(struct vnode *dvp,
|
||||
struct vnode **vpp,
|
||||
struct componentname *cnp
|
||||
struct vattr *vap)
|
||||
{
|
||||
int mode = MAKEIMODE(vap->va_type, vap->va_mode);
|
||||
struct vnode *vp;
|
||||
int error;
|
||||
|
||||
*vpp = NULL;
|
||||
if ((mode & IFMT) == 0)
|
||||
mode |= IFREG;
|
||||
|
||||
error = SOMEFS_VALLOC(dvp, mode, cnp->cn_cred, &vp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* Update the permissions for the new vnode, including
|
||||
* copying the group from the directory.
|
||||
*/
|
||||
...;
|
||||
|
||||
#ifdef QUOTA
|
||||
/*
|
||||
* Possibly check quota information.
|
||||
*/
|
||||
...;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enter new vnode in directory, taking care that the vnode
|
||||
* hits the disk before the directory contents are changed.
|
||||
*/
|
||||
error = ...;
|
||||
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
*vpp = vp;
|
||||
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
/*
|
||||
* Write error occurred trying to update the inode
|
||||
* or the directory so must deallocate the inode.
|
||||
*/
|
||||
vput(vp);
|
||||
|
||||
/*
|
||||
* Deallocate file system resources for vp.
|
||||
*/
|
||||
...;
|
||||
|
||||
return error;
|
||||
}
|
||||
.Ed
|
||||
.Sh ERRORS
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er ENOSPC
|
||||
|
@ -79,61 +79,6 @@ The file should be locked on entry.
|
||||
.Sh RETURN VALUES
|
||||
Zero is returned if the call is successful, otherwise an appropriate
|
||||
error code is returned.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
int
|
||||
vop_fsync(struct vnode *vp, int waitfor, struct thread *td)
|
||||
{
|
||||
struct buf *bp;
|
||||
struct buf *nbp;
|
||||
struct timeval tv;
|
||||
int s;
|
||||
|
||||
loop:
|
||||
s = splbio();
|
||||
for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
|
||||
nbp = bp->b_vnbufs.le_next;
|
||||
|
||||
/*
|
||||
* Ignore buffers which are already being written.
|
||||
*/
|
||||
if (bp->b_flags & B_BUSY)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Make sure the buffer is dirty.
|
||||
*/
|
||||
if ((bp->b_flags & B_DELWRI) == 0)
|
||||
panic("vop_fsync: not dirty");
|
||||
|
||||
vfs_bio_awrite(bp);
|
||||
splx(s);
|
||||
goto loop;
|
||||
}
|
||||
splx(s);
|
||||
|
||||
if (waitfor == MNT_WAIT) {
|
||||
s = splbio();
|
||||
while (vp->v_numoutput) {
|
||||
vp->v_flag |= VBWAIT;
|
||||
tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "vopfsn");
|
||||
}
|
||||
splx(s);
|
||||
#ifdef DIAGNOSTIC
|
||||
if (vp->v_dirtyblkhd.lh_first) {
|
||||
vprint("vop_fsync: dirty", vp);
|
||||
goto loop;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out the on-disc version of the vnode.
|
||||
*/
|
||||
tv = time;
|
||||
return VOP_UPDATE(vp, &tv, &tv, waitfor == MNT_WAIT);
|
||||
}
|
||||
.Ed
|
||||
.Sh ERRORS
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er ENOSPC
|
||||
|
@ -74,38 +74,6 @@ prior to returning.
|
||||
For VOP_RECLAIM, the
|
||||
.Fa vp
|
||||
will not be locked on entry and should be left unlocked on return.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
int
|
||||
vop_inactive(struct vnode *vp, struct thread *td)
|
||||
{
|
||||
if (link count of vp == 0) {
|
||||
/*
|
||||
* Reclaim space in file system for vp.
|
||||
*/
|
||||
...;
|
||||
}
|
||||
VOP_UNLOCK(vp, 0, td);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
vop_reclaim(struct vnode *vp, struct thread *td)
|
||||
{
|
||||
/*
|
||||
* Clean out the name cache.
|
||||
*/
|
||||
cache_purge(vp);
|
||||
|
||||
/*
|
||||
* Free file system related data.
|
||||
*/
|
||||
...;
|
||||
|
||||
return 0;
|
||||
}
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr vnode 9
|
||||
.Sh AUTHORS
|
||||
|
@ -67,16 +67,6 @@ If successful, zero is returned, otherwise an appropriate error code.
|
||||
If the ioctl is not recognized or not handled,
|
||||
.Er ENOTTY
|
||||
should be returned.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
int
|
||||
vop_ioctl(struct vnode *vp, int command, caddr_t data, int fflag,
|
||||
struct ucred *cred, struct thread *td)
|
||||
{
|
||||
|
||||
return ENOTTY;
|
||||
}
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr vnode 9
|
||||
.Sh AUTHORS
|
||||
|
@ -66,37 +66,6 @@ the vnodes locked on return.
|
||||
.Sh RETURN VALUES
|
||||
Zero is returned if the file was linked successfully, otherwise an
|
||||
error is returned.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
int
|
||||
vop_link(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if (vp->v_mount != dvp->v_mount)
|
||||
return (EXDEV);
|
||||
|
||||
if (vp would have too many links)
|
||||
return (EMLINK);
|
||||
|
||||
if (vp is immutable)
|
||||
return (EPERM);
|
||||
|
||||
/*
|
||||
* Increment link count of vp and write back the on-disc version of it.
|
||||
*/
|
||||
...;
|
||||
|
||||
if (!error) {
|
||||
/*
|
||||
* Add the new name to the directory.
|
||||
*/
|
||||
...;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
.Ed
|
||||
.Sh ERRORS
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EMLINK
|
||||
|
@ -116,72 +116,6 @@ also does not want a thread specified as argument but it
|
||||
assumes curthread to be used.
|
||||
.Sh RETURN VALUES
|
||||
Zero is returned on success, otherwise an error is returned.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
struct vopnode {
|
||||
int von_flag;
|
||||
/*
|
||||
* Other file system specific data.
|
||||
*/
|
||||
...;
|
||||
};
|
||||
#define VON_LOCKED 1
|
||||
#define VON_WANTED 2
|
||||
#define VTOVON(vp) ((struct vopnode *) (vp)->v_data)
|
||||
|
||||
int
|
||||
vop_lock(struct vnode *vp)
|
||||
{
|
||||
struct vopnode* vop;
|
||||
|
||||
start:
|
||||
while (vp->v_flag & VXLOCK) {
|
||||
vp->v_flag |= VXWANT;
|
||||
tsleep((caddr_t)vp, PINOD, "voplk1", 0);
|
||||
}
|
||||
if (vp->v_tag == VT_NON)
|
||||
return ENOENT;
|
||||
|
||||
vop = VTOVON(vp);
|
||||
if (vop->von_flag & VON_LOCKED) {
|
||||
vop->von_flag |= VON_WANTED;
|
||||
tsleep((caddr_t) vop, PINOD, "voplk2", 0);
|
||||
goto start;
|
||||
}
|
||||
|
||||
vop->von_flag |= VON_LOCKED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
vop_unlock(struct vnode *vp)
|
||||
{
|
||||
struct vopnode *vop = VTOVON(vp);
|
||||
|
||||
if ((vop->von_flag & VON_LOCKED) == 0) {
|
||||
panic("vop_unlock not locked");
|
||||
}
|
||||
vop->von_flag &= ~VON_LOCKED;
|
||||
if (vop->von_flag & VON_WANTED) {
|
||||
vop->von_flag &= ~VON_WANTED;
|
||||
wakeup((caddr_t) vop);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
vop_islocked(struct vnode *vp)
|
||||
{
|
||||
struct vopnode *vop = VTOVON(vp);
|
||||
|
||||
if (vop->von_flag & VON_LOCKED)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr vnode 9
|
||||
.Sh AUTHORS
|
||||
|
@ -156,260 +156,6 @@ is specified and the operation would succeed, the special return value
|
||||
.Er EJUSTRETURN
|
||||
is returned.
|
||||
Otherwise, an appropriate error code is returned.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
int
|
||||
vop_lookup(struct vnode *dvp,
|
||||
struct vnode **vpp,
|
||||
struct componentname *cnp)
|
||||
{
|
||||
int error;
|
||||
int nameiop = cnp->cn_nameiop;
|
||||
int flags = cnp->cn_flags;
|
||||
int lockparent = flags & LOCKPARENT;
|
||||
int islastcn = flags & ISLASTCN;
|
||||
struct vnode *vp = NULL;
|
||||
|
||||
/*
|
||||
* Check accessibility of directory.
|
||||
*/
|
||||
if (dvp->v_type != VDIR)
|
||||
return ENOTDIR;
|
||||
|
||||
error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_thread);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
if (islastcn && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
|
||||
(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
|
||||
return (EROFS);
|
||||
|
||||
/*
|
||||
* Check name cache for directory/name pair. This returns ENOENT
|
||||
* if the name is known not to exist, -1 if the name was found, or
|
||||
* zero if not.
|
||||
*/
|
||||
error = cache_lookup(dvp, vpp, cnp);
|
||||
if (error) {
|
||||
int vpid;
|
||||
|
||||
if (error = ENOENT)
|
||||
return error;
|
||||
|
||||
vp = *vpp;
|
||||
if (dvp == vp) { /* lookup on "." */
|
||||
VREF(vp);
|
||||
error = 0;
|
||||
} else if (flags & ISDOTDOT) {
|
||||
/*
|
||||
* We need to unlock the directory before getting
|
||||
* the locked vnode for ".." to avoid deadlocks.
|
||||
*/
|
||||
VOP_UNLOCK(dvp);
|
||||
error = vget(vp, 1);
|
||||
if (!error) {
|
||||
if (lockparent && islastcn)
|
||||
error = VOP_LOCK(dvp);
|
||||
}
|
||||
} else {
|
||||
error = vget(vp, 1);
|
||||
if (error || !(lockparent && islastcn)) {
|
||||
VOP_UNLOCK(dvp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the capability number did not change
|
||||
* while we were waiting for the lock.
|
||||
*/
|
||||
if (!error) {
|
||||
if (vpid == vp->v_id) {
|
||||
/*
|
||||
* dvp is locked if lockparent && islastcn.
|
||||
* vp is locked.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
vput(vp);
|
||||
|
||||
if (dvp != vp && lockparent && islastcn)
|
||||
VOP_UNLOCK(pdp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-lock dvp for the directory search below.
|
||||
*/
|
||||
error = VOP_LOCK(dvp);
|
||||
if (error) {
|
||||
return (error);
|
||||
}
|
||||
|
||||
*vpp = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search dvp for the component cnp->cn_nameptr.
|
||||
*/
|
||||
...;
|
||||
|
||||
if (!found) {
|
||||
if ((nameiop == CREATE || nameiop == RENAME)
|
||||
&& islastcn
|
||||
&& directory dvp has not been removed) {
|
||||
/*
|
||||
* Check for write access on directory.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Possibly record the position of a slot in the directory
|
||||
* large enough for the new component name. This can be
|
||||
* recorded in the vnode private data for dvp.
|
||||
* Set the SAVENAME flag to hold onto the pathname for use
|
||||
* later in VOP_CREATE or VOP_RENAME.
|
||||
*/
|
||||
cnp->cn_flags |= SAVENAME;
|
||||
if (!lockparent)
|
||||
/*
|
||||
* Note that the extra data recorded above is only
|
||||
* useful if lockparent is specified.
|
||||
*/
|
||||
VOP_UNLOCK(dvp);
|
||||
|
||||
return EJUSTRETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Consider inserting name into cache.
|
||||
*/
|
||||
if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
|
||||
cache_enter(dvp, NULL, cnp);
|
||||
|
||||
return ENOENT;
|
||||
} else {
|
||||
/*
|
||||
* If deleting, and at end of pathname, return parameters
|
||||
* which can be used to remove file. If the wantparent flag
|
||||
* isn't set, we return only the directory, otherwise we go on
|
||||
* and lock the inode, being careful with ".".
|
||||
*/
|
||||
if (nameiop == DELETE && islastcn) {
|
||||
/*
|
||||
* Check for write access on directory.
|
||||
*/
|
||||
error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_thread);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
if (found entry is same as dvp) {
|
||||
VREF(dvp);
|
||||
*vpp = dvp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
error = VFS_VGET(dvp->v_mount, ..., &vp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (directory is sticky
|
||||
&& cred->cr_uid != 0
|
||||
&& cred->cr_uid != owner of dvp
|
||||
&& owner of vp != cred->cr_uid) {
|
||||
vput(vp);
|
||||
return EPERM;
|
||||
}
|
||||
*vpp = vp;
|
||||
if (!lockparent)
|
||||
VOP_UNLOCK(dvp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If rewriting (RENAME), return the inode and the
|
||||
* information required to rewrite the present directory
|
||||
* Must get inode of directory entry to verify it's a
|
||||
* regular file, or empty directory.
|
||||
*/
|
||||
if (nameiop == RENAME && wantparent && islastcn) {
|
||||
error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_thread);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Check for "."
|
||||
*/
|
||||
if (found entry is same as dvp)
|
||||
return EISDIR;
|
||||
|
||||
error = VFS_VGET(dvp->v_mount, ..., &vp);
|
||||
if (error)
|
||||
return error;
|
||||
*vpp = vp;
|
||||
/*
|
||||
* Save the name for use in VOP_RENAME later.
|
||||
*/
|
||||
cnp->cn_flags |= SAVENAME;
|
||||
if (!lockparent)
|
||||
VOP_UNLOCK(dvp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Step through the translation in the name. We do not `vput' the
|
||||
* directory because we may need it again if a symbolic link
|
||||
* is relative to the current directory. Instead we save it
|
||||
* unlocked as "pdp". We must get the target inode before unlocking
|
||||
* the directory to insure that the inode will not be removed
|
||||
* before we get it. We prevent deadlock by always fetching
|
||||
* inodes from the root, moving down the directory tree. Thus
|
||||
* when following backward pointers ".." we must unlock the
|
||||
* parent directory before getting the requested directory.
|
||||
* There is a potential race condition here if both the current
|
||||
* and parent directories are removed before the VFS_VGET for the
|
||||
* inode associated with ".." returns. We hope that this occurs
|
||||
* infrequently since we cannot avoid this race condition without
|
||||
* implementing a sophisticated deadlock detection algorithm.
|
||||
* Note also that this simple deadlock detection scheme will not
|
||||
* work if the file system has any hard links other than ".."
|
||||
* that point backwards in the directory structure.
|
||||
*/
|
||||
if (flags & ISDOTDOT) {
|
||||
VOP_UNLOCK(dvp); /* race to get the inode */
|
||||
error = VFS_VGET(dvp->v_mount, ..., &vp);
|
||||
if (error) {
|
||||
VOP_LOCK(dvp);
|
||||
return (error);
|
||||
}
|
||||
if (lockparent && islastcn) {
|
||||
error = VOP_LOCK(dvp);
|
||||
if (error) {
|
||||
vput(vp);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
*vpp = vp;
|
||||
} else if (found entry is same as dvp) {
|
||||
VREF(dvp); /* we want ourself, ie "." */
|
||||
*vpp = dvp;
|
||||
} else {
|
||||
error = VFS_VGET(dvp->v_mount, ..., &vp);
|
||||
if (error)
|
||||
return (error);
|
||||
if (!lockparent || !islastcn)
|
||||
VOP_UNLOCK(dvp);
|
||||
*vpp = vp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert name into cache if appropriate.
|
||||
*/
|
||||
if (cnp->cn_flags & MAKEENTRY)
|
||||
cache_enter(dvp, *vpp, cnp);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
.Ed
|
||||
.Sh ERRORS
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er ENOTDIR
|
||||
|
@ -94,18 +94,6 @@ expects an unlocked, referenced vnode and will dereference the vnode prior
|
||||
to returning.
|
||||
.Sh RETURN VALUES
|
||||
Zero is returned on success, otherwise an error code is returned.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
int
|
||||
vop_open(struct vnode *vp, int mode, struct ucred *cred, struct thread *td,
|
||||
struct file *fp)
|
||||
{
|
||||
/*
|
||||
* Most file systems don't do much here.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr vnode 9 ,
|
||||
.Xr VOP_LOOKUP 9
|
||||
|
@ -85,141 +85,6 @@ Data already in VMIO space.
|
||||
The file should be locked on entry and will still be locked on exit.
|
||||
.Sh RETURN VALUES
|
||||
Zero is returned on success, otherwise an error code is returned.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
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);
|
||||
}
|
||||
.Ed
|
||||
.Sh ERRORS
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EFBIG
|
||||
|
@ -96,70 +96,6 @@ Memory for the cookies should be allocated using:
|
||||
*cookies = (u_int*)#
|
||||
malloc(*ncookies * sizeof(u_int), M_TEMP, M_WAITOK);
|
||||
.Ed
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
int
|
||||
vop_readdir(struct vnode *vp, struct uio *uio, struct ucred *cred,
|
||||
int *eofflag, int *ncookies, u_int **cookies)
|
||||
{
|
||||
off_t off;
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* Remember the original offset to use later in generating cookies.
|
||||
*/
|
||||
off = uio->uio_offset;
|
||||
|
||||
/*
|
||||
* Read directory contents starting at uio->uio_offset into buffer
|
||||
* pointed to by uio.
|
||||
*/
|
||||
...;
|
||||
|
||||
if (!error && ncookies != NULL) {
|
||||
struct dirent *dpStart;
|
||||
struct dirent *dpEnd;
|
||||
struct dirent *dp;
|
||||
int count;
|
||||
u_int *cookiebuf;
|
||||
u_int *cookiep;
|
||||
|
||||
if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
|
||||
panic("vop_readdir: unexpected uio from NFS server");
|
||||
|
||||
/*
|
||||
* Parse the stuff just read into the uio.
|
||||
*/
|
||||
dpStart = (struct dirent *)
|
||||
((char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
|
||||
dpEnd = (struct dirent *) uio->uio_iov->iov_base;
|
||||
|
||||
/*
|
||||
* Count number of entries.
|
||||
*/
|
||||
for (dp = dpStart, count = 0;
|
||||
dp < dpEnd;
|
||||
dp = (struct dirent *)((caddr_t) dp + dp->d_reclen))
|
||||
count++;
|
||||
|
||||
cookiebuf = (u_int *) malloc(count * sizeof(u_int), M_TEMP, M_WAITOK);
|
||||
for (dp = dpStart; cookiep = cookiebuf;
|
||||
dp < dpEnd;
|
||||
dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
|
||||
off += dp->d_reclen;
|
||||
*cookiep++ = (u_int) off;
|
||||
}
|
||||
*ncookies = count;
|
||||
*cookies = cookiebuf;
|
||||
}
|
||||
|
||||
if (eofflag && uio->uio_offset is past the end of the directory) {
|
||||
*eofflag = TRUE;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
.Ed
|
||||
.Sh ERRORS
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EINVAL
|
||||
|
@ -54,21 +54,6 @@ The credentials of the caller.
|
||||
The vnode should be locked on entry and will still be locked on exit.
|
||||
.Sh RETURN VALUES
|
||||
Zero is returned on success, otherwise an error code is returned.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
int
|
||||
vop_readlink(struct vnode *vp, struct uio *uio, struct ucred *cred)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* Read the target of the symlink.
|
||||
*/
|
||||
...;
|
||||
|
||||
return error;
|
||||
}
|
||||
.Ed
|
||||
.Sh ERRORS
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EIO
|
||||
|
@ -62,27 +62,6 @@ and
|
||||
should be locked on entry and remain locked on return.
|
||||
.Sh RETURN VALUES
|
||||
Zero is returned on success, otherwise an error code is returned.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
int
|
||||
vop_remove(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if (vp is immutable) {
|
||||
error = EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove name cnp->cn_nameptr from directory and update link count
|
||||
* of vp.
|
||||
*/
|
||||
...;
|
||||
|
||||
return error;
|
||||
}
|
||||
.Ed
|
||||
.Sh ERRORS
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EPERM
|
||||
|
@ -72,205 +72,6 @@ The VOP routine is expected to
|
||||
.Xr vput 9
|
||||
both prior to
|
||||
returning.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
int
|
||||
vop_rename(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp,
|
||||
struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp)
|
||||
{
|
||||
int doingdirectory = 0;
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* Check for cross-device rename.
|
||||
*/
|
||||
if (fvp->v_mount != tdvp->v_mount) {
|
||||
error = EXDEV;
|
||||
abortit:
|
||||
if (tdvp == tvp)
|
||||
vrele(tdvp);
|
||||
else
|
||||
vput(tdvp);
|
||||
if (tvp)
|
||||
vput(tvp);
|
||||
vrele(fdvp);
|
||||
vrele(fvp);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (tvp exists and is immutable) {
|
||||
error = EPERM;
|
||||
goto abortit;
|
||||
}
|
||||
|
||||
/*
|
||||
* POSIX: "If the old argument and the new argument
|
||||
* both refer to links to the same existing file,
|
||||
* the rename() function shall return successfully
|
||||
* and perform no other action."
|
||||
* The upper layers already handle this case.
|
||||
*/
|
||||
KASSERT(fvp != tvp, ("vop_rename: source and destination are the same"));
|
||||
|
||||
if (fvp is immutable) {
|
||||
error = EPERM;
|
||||
goto abortit;
|
||||
}
|
||||
|
||||
error = VOP_LOCK(fvp);
|
||||
if (error)
|
||||
goto abortit;
|
||||
|
||||
if (vp is a directory) {
|
||||
/*
|
||||
* Avoid ".", "..", and aliases of "." for obvious reasons.
|
||||
*/
|
||||
if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')
|
||||
|| fdvp == fvp
|
||||
|| ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT)) {
|
||||
VOP_UNLOCK(fvp);
|
||||
error = EINVAL;
|
||||
goto abortit;
|
||||
}
|
||||
doingdirectory = 1;
|
||||
}
|
||||
vrele(fdvp);
|
||||
|
||||
/*
|
||||
* Bump link count on fvp while we are moving stuff around. If we
|
||||
* crash before completing the work, the link count may be wrong
|
||||
* but correctable.
|
||||
*/
|
||||
...;
|
||||
|
||||
/*
|
||||
* If ".." must be changed (ie the directory gets a new
|
||||
* parent) then the source directory must not be in the
|
||||
* directory hierarchy above the target, as this would
|
||||
* orphan everything below the source directory. Also
|
||||
* the user must have write permission in the source so
|
||||
* as to be able to change "..".
|
||||
*/
|
||||
error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread);
|
||||
VOP_UNLOCK(fvp);
|
||||
if (doingdirectory && fdvp != tdvp) {
|
||||
/*
|
||||
* Check for pathname conflict.
|
||||
*/
|
||||
...;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the target doesn't exist, link the target to the source and
|
||||
* unlink the source. Otherwise, rewrite the target directory to
|
||||
* reference the source and remove the original entry.
|
||||
*/
|
||||
if (tvp == NULL) {
|
||||
/*
|
||||
* Account for ".." in new directory.
|
||||
*/
|
||||
if (doingdirectory && fdvp != tdvp) {
|
||||
/*
|
||||
* Increase link count of tdvp.
|
||||
*/
|
||||
...;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add name in new directory.
|
||||
*/
|
||||
...;
|
||||
|
||||
if (error) {
|
||||
if (doingdirectory && fdvp != tdvp) {
|
||||
/*
|
||||
* Decrease link count if tdvp.
|
||||
*/
|
||||
...;
|
||||
}
|
||||
goto bad;
|
||||
}
|
||||
vput(tdvp);
|
||||
} else {
|
||||
/*
|
||||
* Target must be empty if a directory and have no links
|
||||
* to it. Also, ensure source and target are compatible
|
||||
* (both directories, or both not directories).
|
||||
*/
|
||||
if (tvp is a directory) {
|
||||
if (tvp is not empty) {
|
||||
error = ENOTEMPTY;
|
||||
goto bad;
|
||||
}
|
||||
if (!doingdirectory) {
|
||||
error = ENOTDIR;
|
||||
goto bad;
|
||||
}
|
||||
/*
|
||||
* Update name cache since directory is going away.
|
||||
*/
|
||||
cache_purge(tdvp);
|
||||
} else if (doingdirectory) {
|
||||
error = ENOTDIR;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change name tcnp in tdvp to point at fvp.
|
||||
*/
|
||||
...;
|
||||
|
||||
/*
|
||||
* If the target directory is in same directory as the source
|
||||
* directory, decrement the link count on the parent of the
|
||||
* target directory. This accounts for the fact that a
|
||||
* directory links back to its parent with "..".
|
||||
*/
|
||||
if (doingdirectory && fdvp == tdvp) {
|
||||
/*
|
||||
* Decrement link count of tdvp.
|
||||
*/
|
||||
...;
|
||||
}
|
||||
vput(tdvp);
|
||||
|
||||
/*
|
||||
* Decrement the link count of tvp since the directory no
|
||||
* longer points at it.
|
||||
*/
|
||||
...;
|
||||
if (doingdirectory) {
|
||||
/*
|
||||
* Clean up the old directory tvp.
|
||||
*/
|
||||
...;
|
||||
}
|
||||
vput(tvp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlink the source. If a directory was moved to a new parent,
|
||||
* update its ".." entry. Gobs of ugly UFS code omitted here.
|
||||
*/
|
||||
...;
|
||||
|
||||
bad:
|
||||
if (tvp)
|
||||
vput(tvp);
|
||||
vput(tdvp);
|
||||
out:
|
||||
if (VOP_LOCK(fvp) == 0) {
|
||||
/*
|
||||
* Decrement link count of fvp.
|
||||
*/
|
||||
...;
|
||||
vput(fvp);
|
||||
} else
|
||||
vrele(fvp);
|
||||
|
||||
return error;
|
||||
}
|
||||
.Ed
|
||||
.Sh ERRORS
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EPERM
|
||||
|
@ -70,30 +70,6 @@ parent directory vnode will be unlocked on a successful exit. However, it
|
||||
will have its hold count incremented.
|
||||
.Sh RETURN VALUES
|
||||
Zero is returned on success, otherwise an error code is returned.
|
||||
.Sh PSEUDOCODE
|
||||
.Bd -literal
|
||||
int
|
||||
vop_vptocnp(struct vnode *vp, struct vnode **dvp, char *buf, int *buflen)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* Translate the vnode to its component name.
|
||||
*
|
||||
* Decrement the component name's length from buflen.
|
||||
*
|
||||
* Obtain the vnode's parent directory vnode.
|
||||
*/
|
||||
...;
|
||||
|
||||
/*
|
||||
* Increment the parent directory's hold count.
|
||||
*/
|
||||
vhold(*dvp);
|
||||
|
||||
return error;
|
||||
}
|
||||
.Ed
|
||||
.Sh ERRORS
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er ENOMEM
|
||||
|
Loading…
x
Reference in New Issue
Block a user