* Copyright (c) 1989 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Rick Macklem at The University of Guelph.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)nfs_vnops.c 7.7 (Berkeley) %G%
* vnode op calls for sun nfs version 2
#include "machine/mtpr.h"
#include "../ufs/inode.h"
struct vnodeops nfsv2_vnodeops
= {
/* Special device vnode ops */
struct vnodeops nfsv2chr_vnodeops
= {
extern u_long nfs_procids
[NFS_NPROCS
];
extern u_long nfs_prog
, nfs_vers
;
extern char nfsiobuf
[MAXPHYS
+NBPG
];
struct map nfsmap
[NFS_MSIZ
];
enum vtype v_type
[NFLNK
+1];
struct buf nfs_bqueue
; /* Queue head for nfsiod's */
int nfs_asyncdaemons
= 0;
struct proc
*nfs_iodwant
[MAX_ASYNCDAEMON
];
static int nfsmap_want
= 0;
* nfs null call from vfs.
nfsm_reqhead(nfs_procids
[NFSPROC_NULL
], cred
, 0);
* Essentially just get vattr and then imitate iaccess()
nfs_access(vp
, mode
, cred
)
register struct ucred
*cred
;
register struct vattr
*vap
;
* If you're the super-user,
if (error
= nfs_getattr(vp
, vap
, cred
))
* Access check is based on only one of owner, group, public.
* If not owner, then check group. If not a member of the
* group, then check public access.
if (cred
->cr_uid
!= vap
->va_uid
) {
for (i
= 0; i
< cred
->cr_ngroups
; i
++, gp
++)
if ((vap
->va_mode
& mode
) != 0)
* Just check to see if the type is ok
register enum vtype vtyp
;
if (vtyp
== VREG
|| vtyp
== VDIR
|| vtyp
== VLNK
)
* For reg files, invalidate any buffer cache entries.
* For VCHR, do the device close
nfs_close(vp
, fflags
, cred
)
register struct vnode
*vp
;
struct nfsnode
*np
= VTONFS(vp
);
if (vp
->v_type
== VREG
&& ((np
->n_flag
& NMODIFIED
) ||
((np
->n_flag
& NBUFFERED
) && np
->n_sillyrename
))) {
np
->n_flag
&= ~(NMODIFIED
|NBUFFERED
);
error
= nfs_blkflush(vp
, (daddr_t
)0, np
->n_size
, TRUE
);
if (np
->n_flag
& NWRITEERR
) {
np
->n_flag
&= ~NWRITEERR
;
error
= np
->n_error
? np
->n_error
: EIO
;
if (vp
->v_type
!= VCHR
|| vp
->v_count
> 1)
/* XXX what is this doing below the vnode op call */
if (setjmp(&u
.u_qsave
)) {
* If device close routine is interrupted,
* must return so closef can clean up.
error
= (*cdevsw
[major(dev
)].d_close
)(dev
, fflags
, IFCHR
);
* Most device close routines don't return errors,
* and dup2() doesn't work right on error.
* nfs getattr call from vfs.
nfs_getattr(vp
, vap
, cred
)
register struct vattr
*vap
;
/* First look in the cache.. */
if (nfs_getattrcache(vp
, vap
) == 0)
nfsstats
.rpccnt
[NFSPROC_GETATTR
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_GETATTR
], cred
, NFSX_FH
);
nfs_setattr(vp
, vap
, cred
)
register struct vattr
*vap
;
register struct nfsv2_sattr
*sp
;
nfsstats
.rpccnt
[NFSPROC_SETATTR
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_SETATTR
], cred
, NFSX_FH
+NFSX_SATTR
);
nfsm_build(sp
, struct nfsv2_sattr
*, NFSX_SATTR
);
if (vap
->va_mode
== 0xffff)
sp
->sa_mode
= vtonfs_mode(vp
->v_type
, vap
->va_mode
);
if (vap
->va_uid
== 0xffff)
sp
->sa_uid
= txdr_unsigned(vap
->va_uid
);
if (vap
->va_gid
== 0xffff)
sp
->sa_gid
= txdr_unsigned(vap
->va_gid
);
sp
->sa_size
= txdr_unsigned(vap
->va_size
);
if (vap
->va_size
!= VNOVAL
) {
if (np
->n_flag
& NMODIFIED
) {
np
->n_flag
&= ~NMODIFIED
;
nfs_blkflush(vp
, (daddr_t
)0, np
->n_size
, TRUE
);
txdr_time(&vap
->va_atime
, &sp
->sa_atime
);
txdr_time(&vap
->va_mtime
, &sp
->sa_mtime
);
nfsm_loadattr(vp
, (struct vattr
*)0);
/* should we fill in any vap fields ?? */
* nfs lookup call, one step at a time...
* If not found, unlock the directory nfsnode and do the rpc
register struct vnode
*vp
;
register struct nameidata
*ndp
;
register struct vnode
*vdp
;
int lockparent
, wantparent
, flag
;
lockparent
= ndp
->ni_nameiop
& LOCKPARENT
;
flag
= ndp
->ni_nameiop
& OPFLAG
;
wantparent
= ndp
->ni_nameiop
& (LOCKPARENT
|WANTPARENT
);
if ((error
= cache_lookup(ndp
)) && error
!= ENOENT
) {
if (ndp
->ni_vp
== ndp
->ni_rdir
&& ndp
->ni_isdotdot
)
* See the comment starting `Step through' in ufs/ufs_lookup.c
* for an explanation of the locking protocol
} else if (ndp
->ni_isdotdot
) {
!nfs_getattr(vdp
, &vattr
, ndp
->ni_cred
)) {
nfsstats
.lookupcache_hits
++;
ndp
->ni_vp
= (struct vnode
*)0;
nfsstats
.lookupcache_misses
++;
nfsstats
.rpccnt
[NFSPROC_LOOKUP
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_LOOKUP
], ndp
->ni_cred
, NFSX_FH
+NFSX_UNSIGNED
+nfsm_rndup(len
));
nfsm_strtom(ndp
->ni_ptr
, len
, NFS_MAXNAMLEN
);
if ((flag
== CREATE
|| flag
== RENAME
) &&
nfsm_disect(fhp
,nfsv2fh_t
*,NFSX_FH
);
* Handle DELETE and RENAME cases...
if (flag
== DELETE
&& *ndp
->ni_next
== 0) {
if (!bcmp(VTONFS(vp
)->n_fh
.fh_bytes
, (caddr_t
)fhp
, NFSX_FH
)) {
if (error
= nfs_nget(vp
->v_mount
, fhp
, &np
)) {
if (error
= nfs_loadattrcache(newvp
, &md
, &dpos
, (struct vattr
*)0)) {
if (flag
== RENAME
&& wantparent
&& *ndp
->ni_next
== 0) {
if (!bcmp(VTONFS(vp
)->n_fh
.fh_bytes
, (caddr_t
)fhp
, NFSX_FH
)) {
if (error
= nfs_nget(vp
->v_mount
, fhp
, &np
)) {
if (error
= nfs_loadattrcache(newvp
, &md
, &dpos
, (struct vattr
*)0)) {
if (!bcmp(VTONFS(vp
)->n_fh
.fh_bytes
, (caddr_t
)fhp
, NFSX_FH
)) {
} else if (ndp
->ni_isdotdot
) {
if (error
= nfs_nget(vp
->v_mount
, fhp
, &np
)) {
if (error
= nfs_nget(vp
->v_mount
, fhp
, &np
)) {
if (error
= nfs_loadattrcache(newvp
, &md
, &dpos
, (struct vattr
*)0)) {
if (vp
!= newvp
&& (!lockparent
|| *ndp
->ni_next
!= '\0'))
if (error
== 0 && ndp
->ni_makeentry
)
nfs_readlink(vp
, uiop
, cred
)
nfsstats
.rpccnt
[NFSPROC_READLINK
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_READLINK
], cred
, NFSX_FH
);
nfsm_strsiz(len
, NFS_MAXPATHLEN
);
nfs_readrpc(vp
, uiop
, offp
, cred
)
nmp
= vfs_to_nfs(vp
->v_mount
);
nfsstats
.rpccnt
[NFSPROC_READ
]++;
len
= (tsiz
> nmp
->nm_rsize
) ? nmp
->nm_rsize
: tsiz
;
nfsm_reqhead(nfs_procids
[NFSPROC_READ
], cred
, NFSX_FH
+NFSX_UNSIGNED
*3);
nfsm_build(p
, u_long
*, NFSX_UNSIGNED
*3);
*p
++ = txdr_unsigned(*offp
);
*p
++ = txdr_unsigned(len
);
nfsm_loadattr(vp
, (struct vattr
*)0);
nfsm_strsiz(retlen
, nmp
->nm_rsize
);
nfsm_mtouio(uiop
, retlen
);
nfs_writerpc(vp
, uiop
, offp
, cred
)
nmp
= vfs_to_nfs(vp
->v_mount
);
nfsstats
.rpccnt
[NFSPROC_WRITE
]++;
len
= (tsiz
> nmp
->nm_wsize
) ? nmp
->nm_wsize
: tsiz
;
nfsm_reqhead(nfs_procids
[NFSPROC_WRITE
], cred
,
NFSX_FH
+NFSX_UNSIGNED
*4);
nfsm_build(p
, u_long
*, NFSX_UNSIGNED
*4);
*(p
+1) = txdr_unsigned(*offp
);
*(p
+3) = txdr_unsigned(len
);
nfsm_loadattr(vp
, (struct vattr
*)0);
register struct nameidata
*ndp
;
register struct vattr
*vap
;
register struct nfsv2_sattr
*sp
;
nfsstats
.rpccnt
[NFSPROC_CREATE
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_CREATE
], ndp
->ni_cred
,
NFSX_FH
+NFSX_UNSIGNED
+nfsm_rndup(ndp
->ni_dent
.d_namlen
)+NFSX_SATTR
);
nfsm_strtom(ndp
->ni_dent
.d_name
, ndp
->ni_dent
.d_namlen
, NFS_MAXNAMLEN
);
nfsm_build(sp
, struct nfsv2_sattr
*, NFSX_SATTR
);
sp
->sa_mode
= vtonfs_mode(VREG
, vap
->va_mode
);
sp
->sa_uid
= txdr_unsigned(ndp
->ni_cred
->cr_uid
);
sp
->sa_gid
= txdr_unsigned(ndp
->ni_cred
->cr_gid
);
sp
->sa_size
= txdr_unsigned(0);
/* or should these be VNOVAL ?? */
txdr_time(&vap
->va_atime
, &sp
->sa_atime
);
txdr_time(&vap
->va_mtime
, &sp
->sa_mtime
);
nfsm_request(ndp
->ni_dvp
);
nfsm_mtofh(ndp
->ni_dvp
, ndp
->ni_vp
);
* To try and make nfs semantics closer to vfs semantics, a file that has
* other references to the vnode is renamed instead of removed and then
* removed later on the last close.
* Unfortunately you must flush the buffer cache and cmap to get rid of
* all extraneous vnode references before you check the reference cnt.
* 1 - If the file could have blocks in the buffer cache
* flush them out and invalidate them
* mpurge the vnode to flush out cmap references
* (This is necessary to update the vnode ref cnt as well as sensible
* for actual removes, to free up the buffers)
* If a rename is not already in the works
* call nfs_sillyrename() to set it up
register struct nameidata
*ndp
;
register struct vnode
*vp
= ndp
->ni_vp
;
register struct nfsnode
*np
= VTONFS(ndp
->ni_vp
);
if (vp
->v_type
== VREG
) {
if (np
->n_flag
& (NMODIFIED
|NBUFFERED
)) {
np
->n_flag
&= ~(NMODIFIED
|NBUFFERED
);
nfs_blkflush(vp
, (daddr_t
)0, np
->n_size
, TRUE
);
if (np
->n_flag
& NPAGEDON
)
mpurge(vp
); /* In case cmap entries still ref it */
error
= nfs_sillyrename(ndp
, REMOVE
);
nfsstats
.rpccnt
[NFSPROC_REMOVE
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_REMOVE
], ndp
->ni_cred
,
NFSX_FH
+NFSX_UNSIGNED
+nfsm_rndup(ndp
->ni_dent
.d_namlen
));
nfsm_strtom(ndp
->ni_dent
.d_name
, ndp
->ni_dent
.d_namlen
, NFS_MAXNAMLEN
);
nfsm_request(ndp
->ni_dvp
);
if (ndp
->ni_dvp
== ndp
->ni_vp
)
* nfs file remove rpc called from nfs_inactive
register struct nameidata
*ndp
;
nfsstats
.rpccnt
[NFSPROC_REMOVE
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_REMOVE
], ndp
->ni_cred
,
NFSX_FH
+NFSX_UNSIGNED
+nfsm_rndup(ndp
->ni_dent
.d_namlen
));
nfsm_strtom(ndp
->ni_dent
.d_name
, ndp
->ni_dent
.d_namlen
, NFS_MAXNAMLEN
);
nfsm_request(ndp
->ni_dvp
);
register struct nameidata
*sndp
, *tndp
;
nfsstats
.rpccnt
[NFSPROC_RENAME
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_RENAME
], tndp
->ni_cred
,
(NFSX_FH
+NFSX_UNSIGNED
)*2+nfsm_rndup(sndp
->ni_dent
.d_namlen
)+
nfsm_rndup(tndp
->ni_dent
.d_namlen
)); /* or sndp->ni_cred?*/
nfsm_fhtom(sndp
->ni_dvp
);
nfsm_strtom(sndp
->ni_dent
.d_name
,sndp
->ni_dent
.d_namlen
,NFS_MAXNAMLEN
);
nfsm_fhtom(tndp
->ni_dvp
);
nfsm_strtom(tndp
->ni_dent
.d_name
,tndp
->ni_dent
.d_namlen
,NFS_MAXNAMLEN
);
nfsm_request(sndp
->ni_dvp
);
if (sndp
->ni_vp
->v_type
== VDIR
) {
if (tndp
->ni_vp
!= NULL
&& tndp
->ni_vp
->v_type
== VDIR
)
cache_purge(tndp
->ni_dvp
);
cache_purge(sndp
->ni_dvp
);
* nfs file rename rpc called from above
register struct nameidata
*sndp
, *tndp
;
nfsstats
.rpccnt
[NFSPROC_RENAME
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_RENAME
], tndp
->ni_cred
,
(NFSX_FH
+NFSX_UNSIGNED
)*2+nfsm_rndup(sndp
->ni_dent
.d_namlen
)+
nfsm_rndup(tndp
->ni_dent
.d_namlen
)); /* or sndp->ni_cred?*/
nfsm_fhtom(sndp
->ni_dvp
);
nfsm_strtom(sndp
->ni_dent
.d_name
,sndp
->ni_dent
.d_namlen
,NFS_MAXNAMLEN
);
nfsm_fhtom(tndp
->ni_dvp
);
nfsm_strtom(tndp
->ni_dent
.d_name
,tndp
->ni_dent
.d_namlen
,NFS_MAXNAMLEN
);
nfsm_request(sndp
->ni_dvp
);
* nfs hard link create call
register struct nameidata
*ndp
;
nfsstats
.rpccnt
[NFSPROC_LINK
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_LINK
], ndp
->ni_cred
,
NFSX_FH
*2+NFSX_UNSIGNED
+nfsm_rndup(ndp
->ni_dent
.d_namlen
));
nfsm_strtom(ndp
->ni_dent
.d_name
, ndp
->ni_dent
.d_namlen
, NFS_MAXNAMLEN
);
* nfs symbolic link create call
nfs_symlink(ndp
, vap
, nm
)
char *nm
; /* is this the path ?? */
register struct nfsv2_sattr
*sp
;
nfsstats
.rpccnt
[NFSPROC_SYMLINK
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_SYMLINK
], ndp
->ni_cred
,
NFSX_FH
+NFSX_UNSIGNED
+nfsm_rndup(ndp
->ni_dent
.d_namlen
)+NFSX_UNSIGNED
);
nfsm_strtom(ndp
->ni_dent
.d_name
, ndp
->ni_dent
.d_namlen
, NFS_MAXNAMLEN
);
nfsm_strtom(nm
, strlen(nm
), NFS_MAXPATHLEN
);
nfsm_build(sp
, struct nfsv2_sattr
*, NFSX_SATTR
);
sp
->sa_mode
= vtonfs_mode(VLNK
, vap
->va_mode
);
sp
->sa_uid
= txdr_unsigned(ndp
->ni_cred
->cr_uid
);
sp
->sa_gid
= txdr_unsigned(ndp
->ni_cred
->cr_gid
);
sp
->sa_size
= txdr_unsigned(VNOVAL
);
txdr_time(&vap
->va_atime
, &sp
->sa_atime
); /* or VNOVAL ?? */
txdr_time(&vap
->va_mtime
, &sp
->sa_mtime
); /* or VNOVAL ?? */
nfsm_request(ndp
->ni_dvp
);
register struct nfsv2_sattr
*sp
;
nfsstats
.rpccnt
[NFSPROC_MKDIR
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_MKDIR
], ndp
->ni_cred
,
NFSX_FH
+NFSX_UNSIGNED
+nfsm_rndup(ndp
->ni_dent
.d_namlen
)+NFSX_SATTR
);
nfsm_strtom(ndp
->ni_dent
.d_name
, ndp
->ni_dent
.d_namlen
, NFS_MAXNAMLEN
);
nfsm_build(sp
, struct nfsv2_sattr
*, NFSX_SATTR
);
sp
->sa_mode
= vtonfs_mode(VDIR
, vap
->va_mode
);
sp
->sa_uid
= txdr_unsigned(ndp
->ni_cred
->cr_uid
);
sp
->sa_gid
= txdr_unsigned(ndp
->ni_cred
->cr_gid
);
sp
->sa_size
= txdr_unsigned(VNOVAL
);
txdr_time(&vap
->va_atime
, &sp
->sa_atime
); /* or VNOVAL ?? */
txdr_time(&vap
->va_mtime
, &sp
->sa_mtime
); /* or VNOVAL ?? */
nfsm_request(ndp
->ni_dvp
);
nfsm_mtofh(ndp
->ni_dvp
, ndp
->ni_vp
);
* nfs remove directory call
register struct nameidata
*ndp
;
if (ndp
->ni_dvp
== ndp
->ni_vp
) {
nfsstats
.rpccnt
[NFSPROC_RMDIR
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_RMDIR
], ndp
->ni_cred
,
NFSX_FH
+NFSX_UNSIGNED
+nfsm_rndup(ndp
->ni_dent
.d_namlen
));
nfsm_strtom(ndp
->ni_dent
.d_name
, ndp
->ni_dent
.d_namlen
, NFS_MAXNAMLEN
);
nfsm_request(ndp
->ni_dvp
);
cache_purge(ndp
->ni_dvp
);
* Although cookie is defined as opaque, I translate it to/from net byte
* order so that it looks more sensible. This appears consistent with the
* Ultrix implementation of NFS.
nfs_readdir(vp
, uiop
, offp
, cred
)
register struct direct
*dp
;
nfsstats
.rpccnt
[NFSPROC_READDIR
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_READDIR
], cred
, xid
);
nfsm_build(p
, u_long
*, 2*NFSX_UNSIGNED
);
*p
++ = txdr_unsigned(off
);
*p
= txdr_unsigned(uiop
->uio_resid
);
nfsm_disect(p
, u_long
*, NFSX_UNSIGNED
);
more_dirs
= fxdr_unsigned(int, *p
);
/* Save the position so that we can do nfsm_mtouio() later */
/* loop thru the dir entries, doctoring them to 4bsd form */
while (more_dirs
&& siz
< uiop
->uio_resid
) {
savoff
= off
; /* Hold onto offset and dp */
nfsm_disecton(p
, u_long
*, 2*NFSX_UNSIGNED
);
dp
->d_ino
= fxdr_unsigned(u_long
, *p
++);
len
= fxdr_unsigned(int, *p
);
if (len
<= 0 || len
> NFS_MAXNAMLEN
) {
dp
->d_namlen
= (u_short
)len
;
nfsm_disecton(p
, u_long
*, 2*NFSX_UNSIGNED
);
off
= fxdr_unsigned(off_t
, *p
);
*p
++ = 0; /* Ensures null termination of name */
more_dirs
= fxdr_unsigned(int, *p
);
dp
->d_reclen
= len
+4*NFSX_UNSIGNED
;
* If at end of rpc data, get the eof boolean
nfsm_disecton(p
, u_long
*, NFSX_UNSIGNED
);
eofflg
= fxdr_unsigned(long, *p
);
* If there is too much to fit in the data buffer, use savoff and
* savdp to trim off the last record.
if (siz
> uiop
->uio_resid
) {
dp
->d_reclen
+= (uiop
->uio_resid
-siz
);
* (Actually a vfsop, not a vnode op)
register struct statfs
*sbp
;
register struct nfsv2_statfs
*sfp
;
if (error
= nfs_nget(mp
, &nmp
->nm_fh
, &np
))
nfsstats
.rpccnt
[NFSPROC_STATFS
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_STATFS
], cred
, NFSX_FH
);
nfsm_disect(sfp
, struct nfsv2_statfs
*, NFSX_STATFS
);
sbp
->f_flags
= nmp
->nm_flag
;
sbp
->f_bsize
= fxdr_unsigned(long, sfp
->sf_tsize
);
sbp
->f_fsize
= fxdr_unsigned(long, sfp
->sf_bsize
);
sbp
->f_blocks
= fxdr_unsigned(long, sfp
->sf_blocks
);
sbp
->f_bfree
= fxdr_unsigned(long, sfp
->sf_bfree
);
sbp
->f_bavail
= fxdr_unsigned(long, sfp
->sf_bavail
);
sbp
->f_fsid
.val
[0] = mp
->m_fsid
.val
[0];
sbp
->f_fsid
.val
[1] = mp
->m_fsid
.val
[1];
bcopy(nmp
->nm_path
, sbp
->f_mntonname
, MNAMELEN
);
bcopy(nmp
->nm_host
, sbp
->f_mntfromname
, MNAMELEN
);
#define HEXTOASC(x) "0123456789abcdef"[x]
* Silly rename. To make the NFS filesystem that is stateless look a little
* more like the "ufs" a remove of an active vnode is translated to a rename
* to a funny looking filename that is removed by nfs_inactive on the
* nfsnode. There is the potential for another process on a different client
* to create the same funny name between the nfs_lookitup() fails and the
* nfs_rename() completes, but...
nfs_sillyrename(ndp
, flag
)
register struct nfsnode
*np
;
register struct sillyrename
*sp
;
register struct nameidata
*tndp
;
np
= VTONFS(ndp
->ni_dvp
);
cache_purge(ndp
->ni_dvp
);
MALLOC(sp
, struct sillyrename
*, sizeof (struct sillyrename
),
bcopy((caddr_t
)&np
->n_fh
, (caddr_t
)&sp
->s_fh
, NFSX_FH
);
tndp
->ni_cred
= crdup(ndp
->ni_cred
);
/* Fudge together a funny name */
bcopy(".nfsAxxxx4.4", tndp
->ni_dent
.d_name
, 13);
tndp
->ni_dent
.d_namlen
= 12;
tndp
->ni_dent
.d_name
[8] = HEXTOASC(pid
& 0xf);
tndp
->ni_dent
.d_name
[7] = HEXTOASC((pid
>> 4) & 0xf);
tndp
->ni_dent
.d_name
[6] = HEXTOASC((pid
>> 8) & 0xf);
tndp
->ni_dent
.d_name
[5] = HEXTOASC((pid
>> 12) & 0xf);
/* Try lookitups until we get one that isn't there */
while (nfs_lookitup(ndp
->ni_dvp
, tndp
, (nfsv2fh_t
*)0) == 0) {
tndp
->ni_dent
.d_name
[4]++;
if (tndp
->ni_dent
.d_name
[4] > 'z') {
if (error
= nfs_renameit(ndp
, tndp
))
nfs_lookitup(ndp
->ni_dvp
, tndp
, &np
->n_fh
);
free((caddr_t
)sp
, M_TEMP
);
* Look up a file name for silly rename stuff.
* Just like nfs_lookup() except that it doesn't load returned values
* into the nfsnode table.
* If fhp != NULL it copies the returned file handle out
nfs_lookitup(vp
, ndp
, fhp
)
register struct vnode
*vp
;
register struct nameidata
*ndp
;
nfsstats
.rpccnt
[NFSPROC_LOOKUP
]++;
len
= ndp
->ni_dent
.d_namlen
;
nfsm_reqhead(nfs_procids
[NFSPROC_LOOKUP
], ndp
->ni_cred
, NFSX_FH
+NFSX_UNSIGNED
+nfsm_rndup(len
));
nfsm_strtom(ndp
->ni_dent
.d_name
, len
, NFS_MAXNAMLEN
);
nfsm_disect(cp
, caddr_t
, NFSX_FH
);
bcopy(cp
, (caddr_t
)fhp
, NFSX_FH
);
* - make nfs_bmap() essentially a no-op that does no translation
* - do nfs_strategy() by faking physical I/O with nfs_readit/nfs_writeit
* after mapping the physical addresses into Kernel Virtual space in the
* (Maybe I could use the process's page mapping, but I was concerned that
* Kernel Write might not be enabled and also figured copyout() would do
* a lot more work than bcopy() and also it currently happens in the
* context of the swapper process (2).
nfs_bmap(vp
, bn
, vpp
, bnp
)
*bnp
= bn
* btodb(vp
->v_mount
->m_bsize
);
* Strategy routine for phys. i/o
* If the biod's are running, queue a request
* otherwise just call nfs_doio() to get it done
* If an i/o daemon is waiting
* queue the request, wake it up and wait for completion
* otherwise just do it ourselves
for (i
= 0; i
< nfs_asyncdaemons
; i
++) {
if (rp
= nfs_iodwant
[i
]) {
* Ensure that the async_daemon is still waiting here
if (rp
->p_stat
!= SSLEEP
||
rp
->p_wchan
!= ((caddr_t
)&nfs_iodwant
[i
])) {
nfs_iodwant
[i
] = (struct proc
*)0;
if (dp
->b_actf
== NULL
) {
nfs_iodwant
[i
] = (struct proc
*)0;
wakeup((caddr_t
)&nfs_iodwant
[i
]);
* Essentially play ubasetup() and disk interrupt service routine by
* mapping the data buffer into kernel virtual space and doing the
* nfs read or write rpc's from it.
* If the biod's are not running, this is just called from nfs_strategy(),
* otherwise it is called by the biod's to do what would normally be
* partially disk interrupt driven.
register struct pte
*pte
, *ppte
;
register struct uio
*uiop
;
register struct vnode
*vp
;
uiop
->uio_segflg
= UIO_SYSSPACE
;
if (bp
->b_flags
& B_READ
) {
io
.iov_len
= uiop
->uio_resid
= bp
->b_bcount
;
uiop
->uio_offset
= off
= bp
->b_blkno
*DEV_BSIZE
;
io
.iov_len
= uiop
->uio_resid
= bp
->b_dirtyend
-bp
->b_dirtyoff
;
uiop
->uio_offset
= off
= (bp
->b_blkno
*DEV_BSIZE
)+bp
->b_dirtyoff
;
addr
= bp
->b_un
.b_addr
+bp
->b_dirtyoff
;
bcnt
= bp
->b_dirtyend
-bp
->b_dirtyoff
;
* For phys i/o, map the b_addr into kernel virtual space using
* Also, add a temporary b_rcred for reading using the process's uid
if (bp
->b_flags
& B_PHYS
) {
VTONFS(vp
)->n_flag
|= NPAGEDON
;
bp
->b_rcred
= cr
= crget();
rp
= (bp
->b_flags
& B_DIRTY
) ? &proc
[2] : bp
->b_proc
;
cr
->cr_gid
= 0; /* Anything ?? */
npf2
= npf
= btoc(bcnt
+ o
);
* Get some mapping page table entries
while ((reg
= rmalloc(nfsmap
, (long)npf
)) == 0) {
sleep((caddr_t
)&nfsmap_want
, PZERO
-1);
/* I know it is always the else, but that may change someday */
if ((bp
->b_flags
& B_PHYS
) == 0)
pte
= kvtopte(bp
->b_un
.b_addr
);
else if (bp
->b_flags
& B_PAGET
)
pte
= &Usrptmap
[btokmx((struct pte
*)bp
->b_un
.b_addr
)];
v
= btop(bp
->b_un
.b_addr
);
if (bp
->b_flags
& B_UAREA
)
* Play vmaccess() but with the Nfsiomap page table
vbase
= vaddr
= &nfsiobuf
[reg
*NBPG
];
mapin(ppte
, (u_int
)vaddr
, pte
->pg_pfnum
, (int)(PG_V
|PG_KW
));
if (bp
->b_flags
& B_READ
) {
bp
->b_error
= error
= nfs_readrpc(vp
, uiop
, &off
, bp
->b_rcred
);
uiop
->uio_rw
= UIO_WRITE
;
bp
->b_error
= error
= nfs_writerpc(vp
, uiop
, &off
, bp
->b_wcred
);
bp
->b_dirtyoff
= bp
->b_dirtyend
= 0;
bp
->b_resid
= uiop
->uio_resid
;
* Release pte's used by physical i/o
if (bp
->b_flags
& B_PHYS
) {
rmfree(nfsmap
, (long)npf2
, (long)++reg
);
wakeup((caddr_t
)&nfsmap_want
);
* Flush all the blocks associated with a vnode.
* Walk through the buffer pool and push any dirty pages
* associated with the vnode.
nfs_fsync(vp
, fflags
, cred
)
register struct vnode
*vp
;
register struct nfsnode
*np
= VTONFS(vp
);
if (np
->n_flag
& NMODIFIED
) {
np
->n_flag
&= ~NMODIFIED
;
error
= nfs_blkflush(vp
, (daddr_t
)0, np
->n_size
, FALSE
);