* 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.2 (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 struct vnode
*cache_lookup();
extern char nfsiobuf
[MAXPHYS
+NBPG
];
enum vtype v_type
[NFLNK
+1];
* 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 (nfs_getattrcache(vp
, vap
)) {
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
)
* Nothin to do unless its a VCHR
nfs_close(vp
, fflags
, cred
)
register struct vnode
*vp
;
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
;
nfsstats
.rpccnt
[NFSPROC_SETATTR
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_SETATTR
], cred
, NFSX_FH
+NFSX_SATTR
);
nfsm_build(p
, u_long
*, NFSX_SATTR
);
if (vap
->va_mode
== 0xffff)
*p
++ = vtonfs_mode(vp
->v_type
, vap
->va_mode
);
if (vap
->va_uid
== 0xffff)
*p
++ = txdr_unsigned(vap
->va_uid
);
if (vap
->va_gid
== 0xffff)
*p
++ = txdr_unsigned(vap
->va_gid
);
*p
++ = txdr_unsigned(vap
->va_size
);
txdr_time(&(vap
->va_atime
), p
);
txdr_time(&(vap
->va_mtime
), p
);
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 (vdp
= cache_lookup(ndp
)) {
nfsstats
.lookupcache_hits
++;
* Get the next vnode in the path.
* See comment above `IUNLOCK' code for
* an explaination of the locking protocol.
} else if (ndp
->ni_isdotdot
) {
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)) {
newvp
->v_type
= np
->n_vattr
.va_type
;
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)) {
newvp
->v_type
= np
->n_vattr
.va_type
;
* Handling special files...
* For VCHR, use the nfs_node, but with the nfsv2chr_vnodeops
* that are a mix of nfs and blk vnode ops.
* For VBLK, get a block dev. inode using bdevvp() and release
* the nfs_node. This means that ufs_inactive() had better know
* how to release inodes that do not have an underlying ufs.
* Also, returns right away to avoid loading the name cache
if (newvp
->v_type
== VCHR
) {
newvp
->v_rdev
= np
->n_vattr
.va_rdev
;
newvp
->v_op
= &nfsv2chr_vnodeops
;
} else if (newvp
->v_type
== VBLK
) {
rdev
= np
->n_vattr
.va_rdev
;
if (error
= bdevvp(rdev
, &newvp
))
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_read(vp
, uiop
, offp
, ioflag
, cred
)
nmp
= vfs_to_nfs(vp
->v_mount
);
if (!(ioflag
& IO_NODELOCKED
))
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
);
if (!(ioflag
& IO_NODELOCKED
))
nfs_write(vp
, uiop
, offp
, ioflag
, cred
)
nmp
= vfs_to_nfs(vp
->v_mount
);
if (!(ioflag
& IO_NODELOCKED
))
if ((ioflag
&IO_UNIT
) || (vp
->v_type
== VREG
&& (ioflag
&IO_APPEND
))) {
if (error
= nfs_getattr(vp
, &va
, cred
))
if (vp
->v_type
== VREG
&& (ioflag
& IO_APPEND
))
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);
if (error
&& (ioflag
& IO_UNIT
)) {
nfs_setattr(vp
, &va
, cred
);
if (!(ioflag
& IO_NODELOCKED
))
register struct nameidata
*ndp
;
register struct vattr
*vap
;
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(p
, u_long
*, NFSX_UNSIGNED
*8);
*p
++ = vtonfs_mode(VREG
, vap
->va_mode
);
*p
++ = txdr_unsigned(ndp
->ni_cred
->cr_uid
);
*p
++ = txdr_unsigned(ndp
->ni_cred
->cr_gid
);
/* or should these be VNOVAL ?? */
txdr_time(&(vap
->va_atime
), p
);
txdr_time(&(vap
->va_mtime
), p
+2);
nfsm_request(ndp
->ni_dvp
);
nfsm_mtofh(ndp
->ni_dvp
, ndp
->ni_vp
);
register struct nameidata
*ndp
;
if (ndp
->ni_vp
->v_count
> 1)
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 ?? */
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(p
, u_long
*, NFSX_SATTR
);
*p
++ = vtonfs_mode(VLNK
, vap
->va_mode
);
*p
++ = txdr_unsigned(ndp
->ni_cred
->cr_uid
);
*p
++ = txdr_unsigned(ndp
->ni_cred
->cr_gid
);
*p
++ = txdr_unsigned(VNOVAL
);
txdr_time(&(vap
->va_atime
), p
); /* or VNOVAL ?? */
txdr_time(&(vap
->va_mtime
), p
+2); /* or VNOVAL ?? */
nfsm_request(ndp
->ni_dvp
);
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(p
, u_long
*, NFSX_SATTR
);
*p
++ = vtonfs_mode(VDIR
, vap
->va_mode
);
*p
++ = txdr_unsigned(ndp
->ni_cred
->cr_uid
);
*p
++ = txdr_unsigned(ndp
->ni_cred
->cr_gid
);
*p
++ = txdr_unsigned(VNOVAL
);
txdr_time(&(vap
->va_atime
), p
); /* or VNOVAL ?? */
txdr_time(&(vap
->va_mtime
), p
+2); /* 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
) {
if (ndp
->ni_vp
->v_count
> 1)
error
= nfs_sillyrename(ndp
, RMDIR
);
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
);
* nfs remove dir rpc called from above
register struct nameidata
*ndp
;
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
);
* 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 nfsmount
*nmp
;
if (error
= nfs_nget(mp
, &nmp
->nm_fh
, &np
))
nfsstats
.rpccnt
[NFSPROC_STATFS
]++;
nfsm_reqhead(nfs_procids
[NFSPROC_STATFS
], cred
, NFSX_FH
);
nfsm_disect(p
, u_long
*, 5*NFSX_UNSIGNED
);
sbp
->f_flags
= nmp
->nm_flag
;
sbp
->f_bsize
= fxdr_unsigned(long, *p
++);
sbp
->f_fsize
= fxdr_unsigned(long, *p
++);
sbp
->f_blocks
= fxdr_unsigned(long, *p
++);
sbp
->f_bfree
= fxdr_unsigned(long, *p
++);
sbp
->f_bavail
= fxdr_unsigned(long, *p
);
sbp
->f_files
= 0x7fffffff;
sbp
->f_ffree
= 0x7fffffff;
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
);
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
);
* Fun and games with phys i/o
register struct pte
*pte
, *ppte
;
register struct uio
*uiop
;
register struct ucred
*cr
;
register struct vnode
*vp
;
cr
->cr_gid
= 10; /* Pick anything ?? */
io
.iov_len
= uiop
->uio_resid
= bp
->b_bcount
;
uiop
->uio_segflg
= UIO_SYSSPACE
;
uiop
->uio_offset
= off
= bp
->b_blkno
*DEV_BSIZE
;
o
= (int)bp
->b_un
.b_addr
& PGOFSET
;
npf
= btoc(bp
->b_bcount
+ o
);
rp
= bp
->b_flags
&B_DIRTY
? &proc
[2] : bp
->b_proc
;
if ((bp
->b_flags
& B_PHYS
) == 0)
panic("nfs strategy Not PHYS IO");
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
mapin(ppte
, (u_int
)vaddr
, pte
->pg_pfnum
, (int)(PG_V
|PG_KW
));
io
.iov_base
= nfsiobuf
+o
;
if (bp
->b_flags
& B_READ
) {
bp
->b_error
= error
= nfs_read(vp
, uiop
, &off
, 0, cr
);
uiop
->uio_rw
= UIO_WRITE
;
bp
->b_error
= error
= nfs_write(vp
, uiop
, &off
, 0, cr
);
bp
->b_resid
= uiop
->uio_resid
;