From 85182a8d785d189f1e845c7d66810e3977ac161b Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 18 Sep 2001 23:32:09 +0000 Subject: Cleanup and split of nfs client and server code. This builds on the top of several repo-copies. --- sys/nfs/bootp_subr.c | 2042 ----------------------- sys/nfs/krpc.h | 31 - sys/nfs/krpc_subr.c | 487 ------ sys/nfs/nfs.h | 727 --------- sys/nfs/nfs_bio.c | 1641 ------------------- sys/nfs/nfs_common.c | 2069 +---------------------- sys/nfs/nfs_common.h | 563 +------ sys/nfs/nfs_lock.c | 286 ---- sys/nfs/nfs_lock.h | 112 -- sys/nfs/nfs_node.c | 468 ------ sys/nfs/nfs_nqlease.c | 1288 --------------- sys/nfs/nfs_serv.c | 4235 ------------------------------------------------ sys/nfs/nfs_socket.c | 2296 -------------------------- sys/nfs/nfs_srvcache.c | 352 ---- sys/nfs/nfs_subs.c | 2243 ------------------------- sys/nfs/nfs_syscalls.c | 1214 -------------- sys/nfs/nfs_vfsops.c | 1075 ------------ sys/nfs/nfs_vnops.c | 3344 -------------------------------------- sys/nfs/nfsdiskless.h | 124 -- sys/nfs/nfsmount.h | 106 -- sys/nfs/nfsproto.h | 21 +- sys/nfs/nfsrtt.h | 104 -- sys/nfs/nfsrvcache.h | 91 -- sys/nfs/nfsv2.h | 40 - sys/nfs/nlminfo.h | 45 - sys/nfs/nqnfs.h | 208 --- sys/nfs/rpcv2.h | 41 - 27 files changed, 133 insertions(+), 25120 deletions(-) delete mode 100644 sys/nfs/bootp_subr.c delete mode 100644 sys/nfs/krpc.h delete mode 100644 sys/nfs/krpc_subr.c delete mode 100644 sys/nfs/nfs.h delete mode 100644 sys/nfs/nfs_bio.c delete mode 100644 sys/nfs/nfs_lock.c delete mode 100644 sys/nfs/nfs_lock.h delete mode 100644 sys/nfs/nfs_node.c delete mode 100644 sys/nfs/nfs_nqlease.c delete mode 100644 sys/nfs/nfs_serv.c delete mode 100644 sys/nfs/nfs_socket.c delete mode 100644 sys/nfs/nfs_srvcache.c delete mode 100644 sys/nfs/nfs_subs.c delete mode 100644 sys/nfs/nfs_syscalls.c delete mode 100644 sys/nfs/nfs_vfsops.c delete mode 100644 sys/nfs/nfs_vnops.c delete mode 100644 sys/nfs/nfsdiskless.h delete mode 100644 sys/nfs/nfsmount.h delete mode 100644 sys/nfs/nfsrtt.h delete mode 100644 sys/nfs/nfsrvcache.h delete mode 100644 sys/nfs/nfsv2.h delete mode 100644 sys/nfs/nlminfo.h delete mode 100644 sys/nfs/nqnfs.h (limited to 'sys/nfs') diff --git a/sys/nfs/bootp_subr.c b/sys/nfs/bootp_subr.c deleted file mode 100644 index 063f77f..0000000 --- a/sys/nfs/bootp_subr.c +++ /dev/null @@ -1,2042 +0,0 @@ -/* $FreeBSD$ */ - -/* - * Copyright (c) 1995 Gordon Ross, Adam Glass - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Lawrence Berkeley Laboratory and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * based on: - * nfs/krpc_subr.c - * $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $ - */ - -#include "opt_bootp.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - - -#define BOOTP_MIN_LEN 300 /* Minimum size of bootp udp packet */ - -#ifndef BOOTP_SETTLE_DELAY -#define BOOTP_SETTLE_DELAY 3 -#endif - -/* - * What is the longest we will wait before re-sending a request? - * Note this is also the frequency of "RPC timeout" messages. - * The re-send loop count sup linearly to this maximum, so the - * first complaint will happen after (1+2+3+4+5)=15 seconds. - */ -#define MAX_RESEND_DELAY 5 /* seconds */ - -/* Definitions from RFC951 */ -struct bootp_packet { - u_int8_t op; - u_int8_t htype; - u_int8_t hlen; - u_int8_t hops; - u_int32_t xid; - u_int16_t secs; - u_int16_t flags; - struct in_addr ciaddr; - struct in_addr yiaddr; - struct in_addr siaddr; - struct in_addr giaddr; - unsigned char chaddr[16]; - char sname[64]; - char file[128]; - unsigned char vend[256]; -}; - -struct bootpc_ifcontext { - struct bootpc_ifcontext *next; - struct bootp_packet call; - struct bootp_packet reply; - int replylen; - int overload; - struct socket *so; - struct ifreq ireq; - struct ifnet *ifp; - struct sockaddr_dl *sdl; - struct sockaddr_in myaddr; - struct sockaddr_in netmask; - struct sockaddr_in gw; - struct sockaddr_in broadcast; /* Different for each interface */ - int gotgw; - int gotnetmask; - int gotrootpath; - int outstanding; - int sentmsg; - u_int32_t xid; - enum { - IF_BOOTP_UNRESOLVED, - IF_BOOTP_RESOLVED, - IF_BOOTP_FAILED, - IF_DHCP_UNRESOLVED, - IF_DHCP_OFFERED, - IF_DHCP_RESOLVED, - IF_DHCP_FAILED, - } state; - int dhcpquerytype; /* dhcp type sent */ - struct in_addr dhcpserver; - int gotdhcpserver; -}; - -#define TAG_MAXLEN 1024 -struct bootpc_tagcontext { - char buf[TAG_MAXLEN + 1]; - int overload; - int badopt; - int badtag; - int foundopt; - int taglen; -}; - -struct bootpc_globalcontext { - struct bootpc_ifcontext *interfaces; - struct bootpc_ifcontext *lastinterface; - u_int32_t xid; - int gotrootpath; - int gotswappath; - int gotgw; - int ifnum; - int secs; - int starttime; - struct bootp_packet reply; - int replylen; - struct bootpc_ifcontext *setswapfs; - struct bootpc_ifcontext *setrootfs; - struct bootpc_ifcontext *sethostname; - char lookup_path[24]; - struct bootpc_tagcontext tmptag; - struct bootpc_tagcontext tag; -}; - -#define IPPORT_BOOTPC 68 -#define IPPORT_BOOTPS 67 - -#define BOOTP_REQUEST 1 -#define BOOTP_REPLY 2 - -/* Common tags */ -#define TAG_PAD 0 /* Pad option, implicit length 1 */ -#define TAG_SUBNETMASK 1 /* RFC 950 subnet mask */ -#define TAG_ROUTERS 3 /* Routers (in order of preference) */ -#define TAG_HOSTNAME 12 /* Client host name */ -#define TAG_ROOT 17 /* Root path */ - -/* DHCP specific tags */ -#define TAG_OVERLOAD 52 /* Option Overload */ -#define TAG_MAXMSGSIZE 57 /* Maximum DHCP Message Size */ - -#define TAG_END 255 /* End Option (i.e. no more options) */ - -/* Overload values */ -#define OVERLOAD_FILE 1 -#define OVERLOAD_SNAME 2 - -/* Site specific tags: */ -#define TAG_SWAP 128 -#define TAG_SWAPSIZE 129 -#define TAG_ROOTOPTS 130 -#define TAG_SWAPOPTS 131 - -#define TAG_DHCP_MSGTYPE 53 -#define TAG_DHCP_REQ_ADDR 50 -#define TAG_DHCP_SERVERID 54 -#define TAG_DHCP_LEASETIME 51 - -#define DHCP_NOMSG 0 -#define DHCP_DISCOVER 1 -#define DHCP_OFFER 2 -#define DHCP_REQUEST 3 -#define DHCP_ACK 5 - -extern int nfs_diskless_valid; -extern struct nfsv3_diskless nfsv3_diskless; - -/* mountd RPC */ -static int md_mount(struct sockaddr_in *mdsin, char *path, - u_char *fhp, int *fhsizep, - struct nfs_args *args,struct thread *td); -static int md_lookup_swap(struct sockaddr_in *mdsin,char *path, - u_char *fhp, int *fhsizep, - struct nfs_args *args, - struct thread *td); -static int setfs(struct sockaddr_in *addr, char *path, char *p); -static int getdec(char **ptr); -static char *substr(char *a,char *b); -static void mountopts(struct nfs_args *args, char *p); -static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len); -static int xdr_int_decode(struct mbuf **ptr, int *iptr); -static void print_in_addr(struct in_addr addr); -static void print_sin_addr(struct sockaddr_in *addr); -static void clear_sinaddr(struct sockaddr_in *sin); -static -struct bootpc_ifcontext *allocifctx(struct bootpc_globalcontext *gctx); -static void bootpc_compose_query(struct bootpc_ifcontext *ifctx, - struct bootpc_globalcontext *gctx, - struct thread *td); -static unsigned char *bootpc_tag(struct bootpc_tagcontext *tctx, - struct bootp_packet *bp, int len, int tag); -static void bootpc_tag_helper(struct bootpc_tagcontext *tctx, - unsigned char *start, int len, int tag); - -#ifdef BOOTP_DEBUG -void bootpboot_p_sa(struct sockaddr *sa,struct sockaddr *ma); -void bootpboot_p_ma(struct sockaddr *ma); -void bootpboot_p_rtentry(struct rtentry *rt); -void bootpboot_p_tree(struct radix_node *rn); -void bootpboot_p_rtlist(void); -void bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa); -void bootpboot_p_iflist(void); -#endif - -static int bootpc_call(struct bootpc_globalcontext *gctx, - struct thread *td); - -static int bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx, - struct bootpc_globalcontext *gctx, - struct thread *td); - -static int bootpc_adjust_interface(struct bootpc_ifcontext *ifctx, - struct bootpc_globalcontext *gctx, - struct thread *td); - -static void bootpc_decode_reply(struct nfsv3_diskless *nd, - struct bootpc_ifcontext *ifctx, - struct bootpc_globalcontext *gctx); - -static int bootpc_received(struct bootpc_globalcontext *gctx, - struct bootpc_ifcontext *ifctx); - -static __inline int bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx); -static __inline int bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx); -static __inline int bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx); - -void bootpc_init(void); - -/* - * In order to have multiple active interfaces with address 0.0.0.0 - * and be able to send data to a selected interface, we perform - * some tricks: - * - * - The 'broadcast' address is different for each interface. - * - * - We temporarily add routing pointing 255.255.255.255 to the - * selected interface broadcast address, thus the packet sent - * goes to that interface. - */ - -#ifdef BOOTP_DEBUG -void -bootpboot_p_sa(struct sockaddr *sa, - struct sockaddr *ma) -{ - if (sa == NULL) { - printf("(sockaddr *) "); - return; - } - switch (sa->sa_family) { - case AF_INET: - { - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *) sa; - printf("inet "); - print_sin_addr(sin); - if (ma != NULL) { - sin = (struct sockaddr_in *) ma; - printf(" mask "); - print_sin_addr(sin); - } - } - break; - case AF_LINK: - { - struct sockaddr_dl *sli; - int i; - - sli = (struct sockaddr_dl *) sa; - printf("link %.*s ", sli->sdl_nlen, sli->sdl_data); - for (i = 0; i < sli->sdl_alen; i++) { - if (i > 0) - printf(":"); - printf("%x", ((unsigned char *) LLADDR(sli))[i]); - } - } - break; - default: - printf("af%d", sa->sa_family); - } -} - - -void -bootpboot_p_ma(struct sockaddr *ma) -{ - if (ma == NULL) { - printf(""); - return; - } - printf("%x", *(int *)ma); -} - - -void -bootpboot_p_rtentry(struct rtentry *rt) -{ - bootpboot_p_sa(rt_key(rt), rt_mask(rt)); - printf(" "); - bootpboot_p_ma(rt->rt_genmask); - printf(" "); - bootpboot_p_sa(rt->rt_gateway, NULL); - printf(" "); - printf("flags %x", (unsigned short) rt->rt_flags); - printf(" %d", (int) rt->rt_rmx.rmx_expire); - printf(" %s%d\n", rt->rt_ifp->if_name, rt->rt_ifp->if_unit); -} - - -void -bootpboot_p_tree(struct radix_node *rn) -{ - while (rn != NULL) { - if (rn->rn_bit < 0) { - if ((rn->rn_flags & RNF_ROOT) != 0) { - } else { - bootpboot_p_rtentry((struct rtentry *) rn); - } - rn = rn->rn_dupedkey; - } else { - bootpboot_p_tree(rn->rn_left); - bootpboot_p_tree(rn->rn_right); - return; - } - } -} - - -void -bootpboot_p_rtlist(void) -{ - printf("Routing table:\n"); - bootpboot_p_tree(rt_tables[AF_INET]->rnh_treetop); -} - - -void -bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa) -{ - printf("%s%d flags %x, addr ", - ifp->if_name, - ifp->if_unit, - (unsigned short) ifp->if_flags); - print_sin_addr((struct sockaddr_in *) ifa->ifa_addr); - printf(", broadcast "); - print_sin_addr((struct sockaddr_in *) ifa->ifa_dstaddr); - printf(", netmask "); - print_sin_addr((struct sockaddr_in *) ifa->ifa_netmask); - printf("\n"); -} - - -void -bootpboot_p_iflist(void) -{ - struct ifnet *ifp; - struct ifaddr *ifa; - - printf("Interface list:\n"); - for (ifp = TAILQ_FIRST(&ifnet); - ifp != NULL; - ifp = TAILQ_NEXT(ifp, if_link)) { - for (ifa = TAILQ_FIRST(&ifp->if_addrhead); - ifa != NULL; - ifa = TAILQ_NEXT(ifa, ifa_link)) - if (ifa->ifa_addr->sa_family == AF_INET) - bootpboot_p_if(ifp, ifa); - } -} -#endif /* defined(BOOTP_DEBUG) */ - - -static void -clear_sinaddr(struct sockaddr_in *sin) -{ - bzero(sin, sizeof(*sin)); - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = INADDR_ANY; /* XXX: htonl(INAADDR_ANY) ? */ - sin->sin_port = 0; -} - - -static struct bootpc_ifcontext * -allocifctx(struct bootpc_globalcontext *gctx) -{ - struct bootpc_ifcontext *ifctx; - ifctx = (struct bootpc_ifcontext *) malloc(sizeof(*ifctx), - M_TEMP, M_WAITOK); - if (ifctx == NULL) - panic("Failed to allocate bootp interface context structure"); - - bzero(ifctx, sizeof(*ifctx)); - ifctx->xid = gctx->xid; -#ifdef BOOTP_NO_DHCP - ifctx->state = IF_BOOTP_UNRESOLVED; -#else - ifctx->state = IF_DHCP_UNRESOLVED; -#endif - gctx->xid += 0x100; - return ifctx; -} - - -static __inline int -bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx) -{ - if (ifctx->state == IF_BOOTP_RESOLVED || - ifctx->state == IF_DHCP_RESOLVED) - return 1; - return 0; -} - - -static __inline int -bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx) -{ - if (ifctx->state == IF_BOOTP_UNRESOLVED || - ifctx->state == IF_DHCP_UNRESOLVED) - return 1; - return 0; -} - - -static __inline int -bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx) -{ - if (ifctx->state == IF_BOOTP_FAILED || - ifctx->state == IF_DHCP_FAILED) - return 1; - return 0; -} - - -static int -bootpc_received(struct bootpc_globalcontext *gctx, - struct bootpc_ifcontext *ifctx) -{ - unsigned char dhcpreplytype; - char *p; - /* - * Need timeout for fallback to less - * desirable alternative. - */ - - - /* This call used for the side effect (badopt flag) */ - (void) bootpc_tag(&gctx->tmptag, &gctx->reply, - gctx->replylen, - TAG_END); - - /* If packet is invalid, ignore it */ - if (gctx->tmptag.badopt != 0) - return 0; - - p = bootpc_tag(&gctx->tmptag, &gctx->reply, - gctx->replylen, TAG_DHCP_MSGTYPE); - if (p != NULL) - dhcpreplytype = *p; - else - dhcpreplytype = DHCP_NOMSG; - - switch (ifctx->dhcpquerytype) { - case DHCP_DISCOVER: - if (dhcpreplytype != DHCP_OFFER /* Normal DHCP offer */ -#ifndef BOOTP_FORCE_DHCP - && dhcpreplytype != DHCP_NOMSG /* Fallback to BOOTP */ -#endif - ) - return 0; - break; - case DHCP_REQUEST: - if (dhcpreplytype != DHCP_ACK) - return 0; - case DHCP_NOMSG: - } - - - /* Ignore packet unless it gives us a root tag we didn't have */ - - if ((ifctx->state == IF_BOOTP_RESOLVED || - (ifctx->dhcpquerytype == DHCP_DISCOVER && - (ifctx->state == IF_DHCP_OFFERED || - ifctx->state == IF_DHCP_RESOLVED))) && - (bootpc_tag(&gctx->tmptag, &ifctx->reply, - ifctx->replylen, - TAG_ROOT) != NULL || - bootpc_tag(&gctx->tmptag, &gctx->reply, - gctx->replylen, - TAG_ROOT) == NULL)) - return 0; - - bcopy(&gctx->reply, - &ifctx->reply, - gctx->replylen); - ifctx->replylen = gctx->replylen; - - /* XXX: Only reset if 'perfect' response */ - if (ifctx->state == IF_BOOTP_UNRESOLVED) - ifctx->state = IF_BOOTP_RESOLVED; - else if (ifctx->state == IF_DHCP_UNRESOLVED && - ifctx->dhcpquerytype == DHCP_DISCOVER) { - if (dhcpreplytype == DHCP_OFFER) - ifctx->state = IF_DHCP_OFFERED; - else - ifctx->state = IF_BOOTP_RESOLVED; /* Fallback */ - } else if (ifctx->state == IF_DHCP_OFFERED && - ifctx->dhcpquerytype == DHCP_REQUEST) - ifctx->state = IF_DHCP_RESOLVED; - - - if (ifctx->dhcpquerytype == DHCP_DISCOVER && - ifctx->state != IF_BOOTP_RESOLVED) { - p = bootpc_tag(&gctx->tmptag, &ifctx->reply, - ifctx->replylen, TAG_DHCP_SERVERID); - if (p != NULL && gctx->tmptag.taglen == 4) { - memcpy(&ifctx->dhcpserver, p, 4); - ifctx->gotdhcpserver = 1; - } else - ifctx->gotdhcpserver = 0; - return 1; - } - - ifctx->gotrootpath = (bootpc_tag(&gctx->tmptag, &ifctx->reply, - ifctx->replylen, - TAG_ROOT) != NULL); - ifctx->gotgw = (bootpc_tag(&gctx->tmptag, &ifctx->reply, - ifctx->replylen, - TAG_ROUTERS) != NULL); - ifctx->gotnetmask = (bootpc_tag(&gctx->tmptag, &ifctx->reply, - ifctx->replylen, - TAG_SUBNETMASK) != NULL); - return 1; -} - -static int -bootpc_call(struct bootpc_globalcontext *gctx, - struct thread *td) -{ - struct socket *so; - struct sockaddr_in *sin, dst; - struct uio auio; - struct sockopt sopt; - struct iovec aio; - int error, on, rcvflg, timo, len; - time_t atimo; - time_t rtimo; - struct timeval tv; - struct bootpc_ifcontext *ifctx; - int outstanding; - int gotrootpath; - int retry; - const char *s; - - /* - * Create socket and set its recieve timeout. - */ - error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td); - if (error != 0) - goto out; - - tv.tv_sec = 1; - tv.tv_usec = 0; - bzero(&sopt, sizeof(sopt)); - sopt.sopt_level = SOL_SOCKET; - sopt.sopt_name = SO_RCVTIMEO; - sopt.sopt_val = &tv; - sopt.sopt_valsize = sizeof tv; - - error = sosetopt(so, &sopt); - if (error != 0) - goto out; - - /* - * Enable broadcast. - */ - on = 1; - sopt.sopt_name = SO_BROADCAST; - sopt.sopt_val = &on; - sopt.sopt_valsize = sizeof on; - - error = sosetopt(so, &sopt); - if (error != 0) - goto out; - - /* - * Disable routing. - */ - - on = 1; - sopt.sopt_name = SO_DONTROUTE; - sopt.sopt_val = &on; - sopt.sopt_valsize = sizeof on; - - error = sosetopt(so, &sopt); - if (error != 0) - goto out; - - /* - * Bind the local endpoint to a bootp client port. - */ - sin = &dst; - clear_sinaddr(sin); - sin->sin_port = htons(IPPORT_BOOTPC); - error = sobind(so, (struct sockaddr *)sin, td); - if (error != 0) { - printf("bind failed\n"); - goto out; - } - - /* - * Setup socket address for the server. - */ - sin = &dst; - clear_sinaddr(sin); - sin->sin_addr.s_addr = INADDR_BROADCAST; - sin->sin_port = htons(IPPORT_BOOTPS); - - /* - * Send it, repeatedly, until a reply is received, - * but delay each re-send by an increasing amount. - * If the delay hits the maximum, start complaining. - */ - timo = 0; - rtimo = 0; - for (;;) { - - outstanding = 0; - gotrootpath = 0; - - for (ifctx = gctx->interfaces; - ifctx != NULL; - ifctx = ifctx->next) { - if (bootpc_ifctx_isresolved(ifctx) != 0 && - bootpc_tag(&gctx->tmptag, &ifctx->reply, - ifctx->replylen, - TAG_ROOT) != NULL) - gotrootpath = 1; - } - - for (ifctx = gctx->interfaces; - ifctx != NULL; - ifctx = ifctx->next) { - ifctx->outstanding = 0; - if (bootpc_ifctx_isresolved(ifctx) != 0 && - gotrootpath != 0) { - continue; - } - if (bootpc_ifctx_isfailed(ifctx) != 0) - continue; - - outstanding++; - ifctx->outstanding = 1; - - /* Proceed to next step in DHCP negotiation */ - if ((ifctx->state == IF_DHCP_OFFERED && - ifctx->dhcpquerytype != DHCP_REQUEST) || - (ifctx->state == IF_DHCP_UNRESOLVED && - ifctx->dhcpquerytype != DHCP_DISCOVER) || - (ifctx->state == IF_BOOTP_UNRESOLVED && - ifctx->dhcpquerytype != DHCP_NOMSG)) { - ifctx->sentmsg = 0; - bootpc_compose_query(ifctx, gctx, td); - } - - /* Send BOOTP request (or re-send). */ - - if (ifctx->sentmsg == 0) { - switch(ifctx->dhcpquerytype) { - case DHCP_DISCOVER: - s = "DHCP Discover"; - break; - case DHCP_REQUEST: - s = "DHCP Request"; - break; - case DHCP_NOMSG: - default: - s = "BOOTP Query"; - break; - } - printf("Sending %s packet from " - "interface %s (%*D)\n", - s, - ifctx->ireq.ifr_name, - ifctx->sdl->sdl_alen, - (unsigned char *) LLADDR(ifctx->sdl), - ":"); - ifctx->sentmsg = 1; - } - - aio.iov_base = (caddr_t) &ifctx->call; - aio.iov_len = sizeof(ifctx->call); - - auio.uio_iov = &aio; - auio.uio_iovcnt = 1; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_rw = UIO_WRITE; - auio.uio_offset = 0; - auio.uio_resid = sizeof(ifctx->call); - auio.uio_td = td; - - /* Set netmask to 0.0.0.0 */ - - sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr; - clear_sinaddr(sin); - error = ifioctl(ifctx->so, SIOCSIFNETMASK, - (caddr_t) &ifctx->ireq, td); - if (error != 0) - panic("bootpc_call:" - "set if netmask, error=%d", - error); - - error = sosend(so, (struct sockaddr *) &dst, - &auio, NULL, NULL, 0, td); - if (error != 0) { - printf("bootpc_call: sosend: %d state %08x\n", - error, (int) so->so_state); - } - - /* XXX: Is this needed ? */ - tsleep(&error, PZERO + 8, "bootpw", 10); - - /* Set netmask to 255.0.0.0 */ - - sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr; - clear_sinaddr(sin); - sin->sin_addr.s_addr = htonl(0xff000000u); - error = ifioctl(ifctx->so, SIOCSIFNETMASK, - (caddr_t) &ifctx->ireq, td); - if (error != 0) - panic("bootpc_call:" - "set if netmask, error=%d", - error); - - } - - if (outstanding == 0 && - (rtimo == 0 || time_second >= rtimo)) { - error = 0; - goto gotreply; - } - - /* Determine new timeout. */ - if (timo < MAX_RESEND_DELAY) - timo++; - else { - printf("DHCP/BOOTP timeout for server "); - print_sin_addr(&dst); - printf("\n"); - } - - /* - * Wait for up to timo seconds for a reply. - * The socket receive timeout was set to 1 second. - */ - atimo = timo + time_second; - while (time_second < atimo) { - aio.iov_base = (caddr_t) &gctx->reply; - aio.iov_len = sizeof(gctx->reply); - - auio.uio_iov = &aio; - auio.uio_iovcnt = 1; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_rw = UIO_READ; - auio.uio_offset = 0; - auio.uio_resid = sizeof(gctx->reply); - auio.uio_td = td; - - rcvflg = 0; - error = soreceive(so, NULL, &auio, - NULL, NULL, &rcvflg); - gctx->secs = time_second - gctx->starttime; - for (ifctx = gctx->interfaces; - ifctx != NULL; - ifctx = ifctx->next) { - if (bootpc_ifctx_isresolved(ifctx) != 0 || - bootpc_ifctx_isfailed(ifctx) != 0) - continue; - - ifctx->call.secs = htons(gctx->secs); - } - if (error == EWOULDBLOCK) - continue; - if (error != 0) - goto out; - len = sizeof(gctx->reply) - auio.uio_resid; - - /* Do we have the required number of bytes ? */ - if (len < BOOTP_MIN_LEN) - continue; - gctx->replylen = len; - - /* Is it a reply? */ - if (gctx->reply.op != BOOTP_REPLY) - continue; - - /* Is this an answer to our query */ - for (ifctx = gctx->interfaces; - ifctx != NULL; - ifctx = ifctx->next) { - if (gctx->reply.xid != ifctx->call.xid) - continue; - - /* Same HW address size ? */ - if (gctx->reply.hlen != ifctx->call.hlen) - continue; - - /* Correct HW address ? */ - if (bcmp(gctx->reply.chaddr, - ifctx->call.chaddr, - ifctx->call.hlen) != 0) - continue; - - break; - } - - if (ifctx != NULL) { - s = bootpc_tag(&gctx->tmptag, - &gctx->reply, - gctx->replylen, - TAG_DHCP_MSGTYPE); - if (s != NULL) { - switch (*s) { - case DHCP_OFFER: - s = "DHCP Offer"; - break; - case DHCP_ACK: - s = "DHCP Ack"; - break; - default: - s = "DHCP (unexpected)"; - break; - } - } else - s = "BOOTP Reply"; - - printf("Received %s packet" - " on %s from ", - s, - ifctx->ireq.ifr_name); - print_in_addr(gctx->reply.siaddr); - if (gctx->reply.giaddr.s_addr != - htonl(INADDR_ANY)) { - printf(" via "); - print_in_addr(gctx->reply.giaddr); - } - if (bootpc_received(gctx, ifctx) != 0) { - printf(" (accepted)"); - if (ifctx->outstanding) { - ifctx->outstanding = 0; - outstanding--; - } - /* Network settle delay */ - if (outstanding == 0) - atimo = time_second + - BOOTP_SETTLE_DELAY; - } else - printf(" (ignored)"); - if (ifctx->gotrootpath) { - gotrootpath = 1; - rtimo = time_second + - BOOTP_SETTLE_DELAY; - printf(" (got root path)"); - } else - printf(" (no root path)"); - printf("\n"); - } - } /* while secs */ -#ifdef BOOTP_TIMEOUT - if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0) - break; -#endif - /* Force a retry if halfway in DHCP negotiation */ - retry = 0; - for (ifctx = gctx->interfaces; ifctx != NULL; - ifctx = ifctx->next) { - if (ifctx->state == IF_DHCP_OFFERED) { - if (ifctx->dhcpquerytype == DHCP_DISCOVER) - retry = 1; - else - ifctx->state = IF_DHCP_UNRESOLVED; - } - } - - if (retry != 0) - continue; - - if (gotrootpath != 0) { - gctx->gotrootpath = gotrootpath; - if (rtimo != 0 && time_second >= rtimo) - break; - } - } /* forever send/receive */ - - /* - * XXX: These are errors of varying seriousness being silently - * ignored - */ - - for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { - if (bootpc_ifctx_isresolved(ifctx) == 0) { - printf("%s timeout for interface %s\n", - ifctx->dhcpquerytype != DHCP_NOMSG ? - "DHCP" : "BOOTP", - ifctx->ireq.ifr_name); - } - } - if (gctx->gotrootpath != 0) { -#if 0 - printf("Got a root path, ignoring remaining timeout\n"); -#endif - error = 0; - goto out; - } -#ifndef BOOTP_NFSROOT - for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { - if (bootpc_ifctx_isresolved(ifctx) != 0) { - error = 0; - goto out; - } - } -#endif - error = ETIMEDOUT; - goto out; - -gotreply: -out: - soclose(so); - return error; -} - - -static int -bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx, - struct bootpc_globalcontext *gctx, - struct thread *td) -{ - struct sockaddr_in *sin; - int error; - - struct ifreq *ireq; - struct socket *so; - struct ifaddr *ifa; - struct sockaddr_dl *sdl; - - error = socreate(AF_INET, &ifctx->so, SOCK_DGRAM, 0, td); - if (error != 0) - panic("nfs_boot: socreate, error=%d", error); - - ireq = &ifctx->ireq; - so = ifctx->so; - - /* - * Bring up the interface. - * - * Get the old interface flags and or IFF_UP into them; if - * IFF_UP set blindly, interface selection can be clobbered. - */ - error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, td); - if (error != 0) - panic("bootpc_fakeup_interface: GIFFLAGS, error=%d", error); - ireq->ifr_flags |= IFF_UP; - error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, td); - if (error != 0) - panic("bootpc_fakeup_interface: SIFFLAGS, error=%d", error); - - /* - * Do enough of ifconfig(8) so that the chosen interface - * can talk to the servers. (just set the address) - */ - - /* addr is 0.0.0.0 */ - - sin = (struct sockaddr_in *) &ireq->ifr_addr; - clear_sinaddr(sin); - error = ifioctl(so, SIOCSIFADDR, (caddr_t) ireq, td); - if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces)) - panic("bootpc_fakeup_interface: " - "set if addr, error=%d", error); - - /* netmask is 255.0.0.0 */ - - sin = (struct sockaddr_in *) &ireq->ifr_addr; - clear_sinaddr(sin); - sin->sin_addr.s_addr = htonl(0xff000000u); - error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, td); - if (error != 0) - panic("bootpc_fakeup_interface: set if netmask, error=%d", - error); - - /* Broadcast is 255.255.255.255 */ - - sin = (struct sockaddr_in *)&ireq->ifr_addr; - clear_sinaddr(sin); - clear_sinaddr(&ifctx->broadcast); - sin->sin_addr.s_addr = htonl(INADDR_BROADCAST); - ifctx->broadcast.sin_addr.s_addr = sin->sin_addr.s_addr; - - error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, td); - if (error != 0) - panic("bootpc_fakeup_interface: " - "set if broadcast addr, error=%d", - error); - - /* Get HW address */ - - sdl = NULL; - for (ifa = TAILQ_FIRST(&ifctx->ifp->if_addrhead); - ifa != NULL; - ifa = TAILQ_NEXT(ifa,ifa_link)) - if (ifa->ifa_addr->sa_family == AF_LINK && - (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) != NULL && - sdl->sdl_type == IFT_ETHER) - break; - - if (sdl == NULL) - panic("bootpc: Unable to find HW address for %s", - ifctx->ireq.ifr_name); - ifctx->sdl = sdl; - - return error; -} - - -static int -bootpc_adjust_interface(struct bootpc_ifcontext *ifctx, - struct bootpc_globalcontext *gctx, - struct thread *td) -{ - int error; - struct sockaddr_in defdst; - struct sockaddr_in defmask; - struct sockaddr_in *sin; - - struct ifreq *ireq; - struct socket *so; - struct sockaddr_in *myaddr; - struct sockaddr_in *netmask; - struct sockaddr_in *gw; - - ireq = &ifctx->ireq; - so = ifctx->so; - myaddr = &ifctx->myaddr; - netmask = &ifctx->netmask; - gw = &ifctx->gw; - - if (bootpc_ifctx_isresolved(ifctx) == 0) { - - /* Shutdown interfaces where BOOTP failed */ - - printf("Shutdown interface %s\n", ifctx->ireq.ifr_name); - error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, td); - if (error != 0) - panic("bootpc_adjust_interface: " - "SIOCGIFFLAGS, error=%d", error); - ireq->ifr_flags &= ~IFF_UP; - error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, td); - if (error != 0) - panic("bootpc_adjust_interface: " - "SIOCSIFFLAGS, error=%d", error); - - sin = (struct sockaddr_in *) &ireq->ifr_addr; - clear_sinaddr(sin); - error = ifioctl(so, SIOCDIFADDR, (caddr_t) ireq, td); - if (error != 0 && (error != EEXIST || - ifctx == gctx->interfaces)) - panic("bootpc_adjust_interface: " - "SIOCDIFADDR, error=%d", error); - - return 0; - } - - printf("Adjusted interface %s\n", ifctx->ireq.ifr_name); - /* - * Do enough of ifconfig(8) so that the chosen interface - * can talk to the servers. (just set the address) - */ - bcopy(netmask, &ireq->ifr_addr, sizeof(*netmask)); - error = ifioctl(so, SIOCSIFNETMASK, (caddr_t) ireq, td); - if (error != 0) - panic("bootpc_adjust_interface: " - "set if netmask, error=%d", error); - - /* Broadcast is with host part of IP address all 1's */ - - sin = (struct sockaddr_in *) &ireq->ifr_addr; - clear_sinaddr(sin); - sin->sin_addr.s_addr = myaddr->sin_addr.s_addr | - ~ netmask->sin_addr.s_addr; - error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t) ireq, td); - if (error != 0) - panic("bootpc_adjust_interface: " - "set if broadcast addr, error=%d", error); - - bcopy(myaddr, &ireq->ifr_addr, sizeof(*myaddr)); - error = ifioctl(so, SIOCSIFADDR, (caddr_t) ireq, td); - if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces)) - panic("bootpc_adjust_interface: " - "set if addr, error=%d", error); - - /* Add new default route */ - - if (ifctx->gotgw != 0 || gctx->gotgw == 0) { - clear_sinaddr(&defdst); - clear_sinaddr(&defmask); - error = rtrequest(RTM_ADD, - (struct sockaddr *) &defdst, - (struct sockaddr *) gw, - (struct sockaddr *) &defmask, - (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL); - if (error != 0) { - printf("bootpc_adjust_interface: " - "add net route, error=%d\n", error); - return error; - } - } - - return 0; -} - - -static int -setfs(struct sockaddr_in *addr, char *path, char *p) -{ - unsigned int ip; - int val; - - ip = 0; - if (((val = getdec(&p)) < 0) || (val > 255)) - return 0; - ip = val << 24; - if (*p != '.') - return 0; - p++; - if (((val = getdec(&p)) < 0) || (val > 255)) - return 0; - ip |= (val << 16); - if (*p != '.') - return 0; - p++; - if (((val = getdec(&p)) < 0) || (val > 255)) - return 0; - ip |= (val << 8); - if (*p != '.') - return 0; - p++; - if (((val = getdec(&p)) < 0) || (val > 255)) - return 0; - ip |= val; - if (*p != ':') - return 0; - p++; - - addr->sin_addr.s_addr = htonl(ip); - addr->sin_len = sizeof(struct sockaddr_in); - addr->sin_family = AF_INET; - - strncpy(path, p, MNAMELEN - 1); - return 1; -} - - -static int -getdec(char **ptr) -{ - char *p; - int ret; - - p = *ptr; - ret = 0; - if ((*p < '0') || (*p > '9')) - return -1; - while ((*p >= '0') && (*p <= '9')) { - ret = ret * 10 + (*p - '0'); - p++; - } - *ptr = p; - return ret; -} - - -static char * -substr(char *a, char *b) -{ - char *loc1; - char *loc2; - - while (*a != '\0') { - loc1 = a; - loc2 = b; - while (*loc1 == *loc2++) { - if (*loc1 == '\0') - return 0; - loc1++; - if (*loc2 == '\0') - return loc1; - } - a++; - } - return 0; -} - - -static void -mountopts(struct nfs_args *args, char *p) -{ - char *tmp; - - args->version = NFS_ARGSVERSION; - args->rsize = 8192; - args->wsize = 8192; - args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT; - args->sotype = SOCK_DGRAM; - if (p == NULL) - return; - if ((tmp = (char *)substr(p, "rsize="))) - args->rsize = getdec(&tmp); - if ((tmp = (char *)substr(p, "wsize="))) - args->wsize = getdec(&tmp); - if ((tmp = (char *)substr(p, "intr"))) - args->flags |= NFSMNT_INT; - if ((tmp = (char *)substr(p, "soft"))) - args->flags |= NFSMNT_SOFT; - if ((tmp = (char *)substr(p, "noconn"))) - args->flags |= NFSMNT_NOCONN; - if ((tmp = (char *)substr(p, "tcp"))) - args->sotype = SOCK_STREAM; -} - - -static int -xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len) -{ - struct mbuf *m; - int alignedlen; - - m = *mptr; - alignedlen = ( len + 3 ) & ~3; - - if (m->m_len < alignedlen) { - m = m_pullup(m, alignedlen); - if (m == NULL) { - *mptr = NULL; - return EBADRPC; - } - } - bcopy(mtod(m, u_char *), buf, len); - m_adj(m, alignedlen); - *mptr = m; - return 0; -} - - -static int -xdr_int_decode(struct mbuf **mptr, int *iptr) -{ - u_int32_t i; - if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0) - return EBADRPC; - *iptr = fxdr_unsigned(u_int32_t, i); - return 0; -} - - -static void -print_sin_addr(struct sockaddr_in *sin) -{ - print_in_addr(sin->sin_addr); -} - - -static void -print_in_addr(struct in_addr addr) -{ - unsigned int ip; - - ip = ntohl(addr.s_addr); - printf("%d.%d.%d.%d", - ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255); -} - -static void -bootpc_compose_query(ifctx, gctx, td) - struct bootpc_ifcontext *ifctx; - struct bootpc_globalcontext *gctx; - struct thread *td; -{ - unsigned char *vendp; - uint32_t leasetime; - - ifctx->gotrootpath = 0; - - bzero((caddr_t) &ifctx->call, sizeof(ifctx->call)); - - /* bootpc part */ - ifctx->call.op = BOOTP_REQUEST; /* BOOTREQUEST */ - ifctx->call.htype = 1; /* 10mb ethernet */ - ifctx->call.hlen = ifctx->sdl->sdl_alen;/* Hardware address length */ - ifctx->call.hops = 0; - if (bootpc_ifctx_isunresolved(ifctx) != 0) - ifctx->xid++; - ifctx->call.xid = txdr_unsigned(ifctx->xid); - bcopy(LLADDR(ifctx->sdl), &ifctx->call.chaddr, ifctx->sdl->sdl_alen); - - vendp = ifctx->call.vend; - *vendp++ = 99; /* RFC1048 cookie */ - *vendp++ = 130; - *vendp++ = 83; - *vendp++ = 99; - *vendp++ = TAG_MAXMSGSIZE; - *vendp++ = 2; - *vendp++ = (sizeof(struct bootp_packet) >> 8) & 255; - *vendp++ = sizeof(struct bootp_packet) & 255; - ifctx->dhcpquerytype = DHCP_NOMSG; - switch (ifctx->state) { - case IF_DHCP_UNRESOLVED: - *vendp++ = TAG_DHCP_MSGTYPE; - *vendp++ = 1; - *vendp++ = DHCP_DISCOVER; - ifctx->dhcpquerytype = DHCP_DISCOVER; - ifctx->gotdhcpserver = 0; - break; - case IF_DHCP_OFFERED: - *vendp++ = TAG_DHCP_MSGTYPE; - *vendp++ = 1; - *vendp++ = DHCP_REQUEST; - ifctx->dhcpquerytype = DHCP_REQUEST; - *vendp++ = TAG_DHCP_REQ_ADDR; - *vendp++ = 4; - memcpy(vendp, &ifctx->reply.yiaddr, 4); - vendp += 4; - if (ifctx->gotdhcpserver != 0) { - *vendp++ = TAG_DHCP_SERVERID; - *vendp++ = 4; - memcpy(vendp, &ifctx->dhcpserver, 4); - vendp += 4; - } - *vendp++ = TAG_DHCP_LEASETIME; - *vendp++ = 4; - leasetime = htonl(300); - memcpy(vendp, &leasetime, 4); - vendp += 4; - default: - ; - } - *vendp = TAG_END; - - ifctx->call.secs = 0; - ifctx->call.flags = htons(0x8000); /* We need an broadcast answer */ -} - - -static int -bootpc_hascookie(struct bootp_packet *bp) -{ - return (bp->vend[0] == 99 && bp->vend[1] == 130 && - bp->vend[2] == 83 && bp->vend[3] == 99); -} - - -static void -bootpc_tag_helper(struct bootpc_tagcontext *tctx, - unsigned char *start, - int len, - int tag) -{ - unsigned char *j; - unsigned char *ej; - unsigned char code; - - if (tctx->badtag != 0 || tctx->badopt != 0) - return; - - j = start; - ej = j + len; - - while (j < ej) { - code = *j++; - if (code == TAG_PAD) - continue; - if (code == TAG_END) - return; - if (j >= ej || j + *j + 1 > ej) { - tctx->badopt = 1; - return; - } - len = *j++; - if (code == tag) { - if (tctx->taglen + len > TAG_MAXLEN) { - tctx->badtag = 1; - return; - } - tctx->foundopt = 1; - if (len > 0) - memcpy(tctx->buf + tctx->taglen, - j, len); - tctx->taglen += len; - } - if (code == TAG_OVERLOAD) - tctx->overload = *j; - - j += len; - } -} - - -static unsigned char * -bootpc_tag(struct bootpc_tagcontext *tctx, - struct bootp_packet *bp, - int len, - int tag) -{ - unsigned char *j; - unsigned char *ej; - - tctx->overload = 0; - tctx->badopt = 0; - tctx->badtag = 0; - tctx->foundopt = 0; - tctx->taglen = 0; - - if (bootpc_hascookie(bp) == 0) - return NULL; - - j = &bp->vend[4]; - ej = (unsigned char *) bp + len; - - bootpc_tag_helper(tctx, &bp->vend[4], - (unsigned char *) bp + len - &bp->vend[4], tag); - - if ((tctx->overload & OVERLOAD_FILE) != 0) - bootpc_tag_helper(tctx, - (unsigned char *) bp->file, - sizeof(bp->file), - tag); - if ((tctx->overload & OVERLOAD_SNAME) != 0) - bootpc_tag_helper(tctx, - (unsigned char *) bp->sname, - sizeof(bp->sname), - tag); - - if (tctx->badopt != 0 || tctx->badtag != 0 || tctx->foundopt == 0) - return NULL; - tctx->buf[tctx->taglen] = '\0'; - return tctx->buf; -} - - -static void -bootpc_decode_reply(nd, ifctx, gctx) - struct nfsv3_diskless *nd; - struct bootpc_ifcontext *ifctx; - struct bootpc_globalcontext *gctx; -{ - char *p; - unsigned int ip; - - ifctx->gotgw = 0; - ifctx->gotnetmask = 0; - - clear_sinaddr(&ifctx->myaddr); - clear_sinaddr(&ifctx->netmask); - clear_sinaddr(&ifctx->gw); - - ifctx->myaddr.sin_addr = ifctx->reply.yiaddr; - - ip = ntohl(ifctx->myaddr.sin_addr.s_addr); - snprintf(gctx->lookup_path, sizeof(gctx->lookup_path), - "swap.%d.%d.%d.%d", - ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255); - - printf("%s at ", ifctx->ireq.ifr_name); - print_sin_addr(&ifctx->myaddr); - printf(" server "); - print_in_addr(ifctx->reply.siaddr); - - ifctx->gw.sin_addr = ifctx->reply.giaddr; - if (ifctx->reply.giaddr.s_addr != htonl(INADDR_ANY)) { - printf(" via gateway "); - print_in_addr(ifctx->reply.giaddr); - } - - /* This call used for the side effect (overload flag) */ - (void) bootpc_tag(&gctx->tmptag, - &ifctx->reply, ifctx->replylen, TAG_END); - - if ((gctx->tmptag.overload & OVERLOAD_SNAME) == 0) - if (ifctx->reply.sname[0] != '\0') - printf(" server name %s", ifctx->reply.sname); - if ((gctx->tmptag.overload & OVERLOAD_FILE) == 0) - if (ifctx->reply.file[0] != '\0') - printf(" boot file %s", ifctx->reply.file); - - printf("\n"); - - p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, - TAG_SUBNETMASK); - if (p != NULL) { - if (gctx->tag.taglen != 4) - panic("bootpc: subnet mask len is %d", - gctx->tag.taglen); - bcopy(p, &ifctx->netmask.sin_addr, 4); - ifctx->gotnetmask = 1; - printf("subnet mask "); - print_sin_addr(&ifctx->netmask); - printf(" "); - } - - p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, - TAG_ROUTERS); - if (p != NULL) { - /* Routers */ - if (gctx->tag.taglen % 4) - panic("bootpc: Router Len is %d", gctx->tag.taglen); - if (gctx->tag.taglen > 0) { - bcopy(p, &ifctx->gw.sin_addr, 4); - printf("router "); - print_sin_addr(&ifctx->gw); - printf(" "); - ifctx->gotgw = 1; - gctx->gotgw = 1; - } - } - - p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, - TAG_ROOT); - if (p != NULL) { - if (gctx->setrootfs != NULL) { - printf("rootfs %s (ignored) ", p); - } else if (setfs(&nd->root_saddr, - nd->root_hostnam, p)) { - printf("rootfs %s ",p); - gctx->gotrootpath = 1; - ifctx->gotrootpath = 1; - gctx->setrootfs = ifctx; - - p = bootpc_tag(&gctx->tag, &ifctx->reply, - ifctx->replylen, - TAG_ROOTOPTS); - if (p != NULL) { - mountopts(&nd->root_args, p); - printf("rootopts %s ", p); - } - } else - panic("Failed to set rootfs to %s",p); - } - - p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, - TAG_SWAP); - if (p != NULL) { - if (gctx->setswapfs != NULL) { - printf("swapfs %s (ignored) ", p); - } else if (setfs(&nd->swap_saddr, - nd->swap_hostnam, p)) { - gctx->gotswappath = 1; - gctx->setswapfs = ifctx; - printf("swapfs %s ", p); - - p = bootpc_tag(&gctx->tag, &ifctx->reply, - ifctx->replylen, - TAG_SWAPOPTS); - if (p != NULL) { - /* swap mount options */ - mountopts(&nd->swap_args, p); - printf("swapopts %s ", p); - } - - p = bootpc_tag(&gctx->tag, &ifctx->reply, - ifctx->replylen, - TAG_SWAPSIZE); - if (p != NULL) { - int swaplen; - if (gctx->tag.taglen != 4) - panic("bootpc: " - "Expected 4 bytes for swaplen, " - "not %d bytes", - gctx->tag.taglen); - bcopy(p, &swaplen, 4); - nd->swap_nblks = ntohl(swaplen); - printf("swapsize %d KB ", - nd->swap_nblks); - } - } else - panic("Failed to set swapfs to %s", p); - } - - p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen, - TAG_HOSTNAME); - if (p != NULL) { - if (gctx->tag.taglen >= MAXHOSTNAMELEN) - panic("bootpc: hostname >= %d bytes", - MAXHOSTNAMELEN); - if (gctx->sethostname != NULL) { - printf("hostname %s (ignored) ", p); - } else { - strcpy(nd->my_hostnam, p); - strcpy(hostname, p); - printf("hostname %s ",hostname); - gctx->sethostname = ifctx; - } - } - - printf("\n"); - - if (ifctx->gotnetmask == 0) { - if (IN_CLASSA(ntohl(ifctx->myaddr.sin_addr.s_addr))) - ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET); - else if (IN_CLASSB(ntohl(ifctx->myaddr.sin_addr.s_addr))) - ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET); - else - ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET); - } - if (ifctx->gotgw == 0) { - /* Use proxyarp */ - ifctx->gw.sin_addr.s_addr = ifctx->myaddr.sin_addr.s_addr; - } -} - -void -bootpc_init(void) -{ - struct bootpc_ifcontext *ifctx, *nctx; /* Interface BOOTP contexts */ - struct bootpc_globalcontext *gctx; /* Global BOOTP context */ - struct ifnet *ifp; - int error; - struct nfsv3_diskless *nd; - struct thread *td; - - nd = &nfsv3_diskless; - td = curthread; - - /* - * If already filled in, don't touch it here - */ - if (nfs_diskless_valid != 0) - return; - - /* - * Wait until arp entries can be handled. - */ - while (time_second == 0) - tsleep(&time_second, PZERO + 8, "arpkludge", 10); - - gctx = malloc(sizeof(*gctx), M_TEMP, M_WAITOK); - if (gctx == NULL) - panic("Failed to allocate bootp global context structure"); - - bzero(gctx, sizeof(*gctx)); - gctx->xid = ~0xFFFF; - gctx->starttime = time_second; - - ifctx = allocifctx(gctx); - - /* - * Find a network interface. - */ -#ifdef BOOTP_WIRED_TO - printf("bootpc_init: wired to interface '%s'\n", - __XSTRING(BOOTP_WIRED_TO)); -#endif - bzero(&ifctx->ireq, sizeof(ifctx->ireq)); - for (ifp = TAILQ_FIRST(&ifnet); - ifp != NULL; - ifp = TAILQ_NEXT(ifp, if_link)) { - snprintf(ifctx->ireq.ifr_name, sizeof(ifctx->ireq.ifr_name), - "%s%d", ifp->if_name, ifp->if_unit); -#ifdef BOOTP_WIRED_TO - if (strcmp(ifctx->ireq.ifr_name, - __XSTRING(BOOTP_WIRED_TO)) != 0) - continue; -#else - if ((ifp->if_flags & - (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) != - IFF_BROADCAST) - continue; -#endif - if (gctx->interfaces != NULL) - gctx->lastinterface->next = ifctx; - else - gctx->interfaces = ifctx; - ifctx->ifp = ifp; - gctx->lastinterface = ifctx; - ifctx = allocifctx(gctx); - } - free(ifctx, M_TEMP); - - if (gctx->interfaces == NULL) { -#ifdef BOOTP_WIRED_TO - panic("bootpc_init: Could not find interface specified " - "by BOOTP_WIRED_TO: " - __XSTRING(BOOTP_WIRED_TO)); -#else - panic("bootpc_init: no suitable interface"); -#endif - } - - gctx->gotrootpath = 0; - gctx->gotswappath = 0; - gctx->gotgw = 0; - - for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) - bootpc_fakeup_interface(ifctx, gctx, td); - - for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) - bootpc_compose_query(ifctx, gctx, td); - - ifctx = gctx->interfaces; - error = bootpc_call(gctx, td); - - if (error != 0) { -#ifdef BOOTP_NFSROOT - panic("BOOTP call failed"); -#else - printf("BOOTP call failed\n"); -#endif - } - - mountopts(&nd->root_args, NULL); - - mountopts(&nd->swap_args, NULL); - - for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) - if (bootpc_ifctx_isresolved(ifctx) != 0) - bootpc_decode_reply(nd, ifctx, gctx); - - if (gctx->gotswappath == 0) - nd->swap_nblks = 0; -#ifdef BOOTP_NFSROOT - if (gctx->gotrootpath == 0) - panic("bootpc: No root path offered"); -#endif - - for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { - bootpc_adjust_interface(ifctx, gctx, td); - - soclose(ifctx->so); - } - - for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) - if (ifctx->gotrootpath != 0) - break; - if (ifctx == NULL) { - for (ifctx = gctx->interfaces; - ifctx != NULL; - ifctx = ifctx->next) - if (bootpc_ifctx_isresolved(ifctx) != 0) - break; - } - if (ifctx == NULL) - goto out; - - if (gctx->gotrootpath != 0) { - - error = md_mount(&nd->root_saddr, nd->root_hostnam, - nd->root_fh, &nd->root_fhsize, - &nd->root_args, td); - if (error != 0) - panic("nfs_boot: mountd root, error=%d", error); - - if (gctx->gotswappath != 0) { - - error = md_mount(&nd->swap_saddr, - nd->swap_hostnam, - nd->swap_fh, &nd->swap_fhsize, - &nd->swap_args, td); - if (error != 0) - panic("nfs_boot: mountd swap, error=%d", - error); - - error = md_lookup_swap(&nd->swap_saddr, - gctx->lookup_path, - nd->swap_fh, &nd->swap_fhsize, - &nd->swap_args, td); - if (error != 0) - panic("nfs_boot: lookup swap, error=%d", - error); - } - nfs_diskless_valid = 3; - } - - strcpy(nd->myif.ifra_name, ifctx->ireq.ifr_name); - bcopy(&ifctx->myaddr, &nd->myif.ifra_addr, sizeof(ifctx->myaddr)); - bcopy(&ifctx->myaddr, &nd->myif.ifra_broadaddr, sizeof(ifctx->myaddr)); - ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr = - ifctx->myaddr.sin_addr.s_addr | - ~ ifctx->netmask.sin_addr.s_addr; - bcopy(&ifctx->netmask, &nd->myif.ifra_mask, sizeof(ifctx->netmask)); - -out: - for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = nctx) { - nctx = ifctx->next; - free(ifctx, M_TEMP); - } - free(gctx, M_TEMP); -} - - -/* - * RPC: mountd/mount - * Given a server pathname, get an NFS file handle. - * Also, sets sin->sin_port to the NFS service port. - */ -static int -md_mount(struct sockaddr_in *mdsin, /* mountd server address */ - char *path, - u_char *fhp, - int *fhsizep, - struct nfs_args *args, - struct thread *td) -{ - struct mbuf *m; - int error; - int authunixok; - int authcount; - int authver; - -#ifdef BOOTP_NFSV3 - /* First try NFS v3 */ - /* Get port number for MOUNTD. */ - error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3, - &mdsin->sin_port, td); - if (error == 0) { - m = xdr_string_encode(path, strlen(path)); - - /* Do RPC to mountd. */ - error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3, - RPCMNT_MOUNT, &m, NULL, td); - } - if (error == 0) { - args->flags |= NFSMNT_NFSV3; - } else { -#endif - /* Fallback to NFS v2 */ - - /* Get port number for MOUNTD. */ - error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1, - &mdsin->sin_port, td); - if (error != 0) - return error; - - m = xdr_string_encode(path, strlen(path)); - - /* Do RPC to mountd. */ - error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1, - RPCMNT_MOUNT, &m, NULL, td); - if (error != 0) - return error; /* message already freed */ - -#ifdef BOOTP_NFSV3 - } -#endif - - if (xdr_int_decode(&m, &error) != 0 || error != 0) - goto bad; - - if ((args->flags & NFSMNT_NFSV3) != 0) { - if (xdr_int_decode(&m, fhsizep) != 0 || - *fhsizep > NFSX_V3FHMAX || - *fhsizep <= 0) - goto bad; - } else - *fhsizep = NFSX_V2FH; - - if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0) - goto bad; - - if (args->flags & NFSMNT_NFSV3) { - if (xdr_int_decode(&m, &authcount) != 0) - goto bad; - authunixok = 0; - if (authcount < 0 || authcount > 100) - goto bad; - while (authcount > 0) { - if (xdr_int_decode(&m, &authver) != 0) - goto bad; - if (authver == RPCAUTH_UNIX) - authunixok = 1; - authcount--; - } - if (authunixok == 0) - goto bad; - } - - /* Set port number for NFS use. */ - error = krpc_portmap(mdsin, NFS_PROG, - (args->flags & - NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2, - &mdsin->sin_port, td); - - goto out; - -bad: - error = EBADRPC; - -out: - m_freem(m); - return error; -} - - -static int -md_lookup_swap(struct sockaddr_in *mdsin, /* mountd server address */ - char *path, - u_char *fhp, - int *fhsizep, - struct nfs_args *args, - struct thread *td) -{ - struct mbuf *m; - int error; - int size = -1; - int attribs_present; - int status; - union { - u_int32_t v2[17]; - u_int32_t v3[21]; - } fattribs; - - m = m_get(M_TRYWAIT,MT_DATA); - if (m == NULL) - return ENOBUFS; - - if ((args->flags & NFSMNT_NFSV3) != 0) { - *mtod(m, u_int32_t *) = txdr_unsigned(*fhsizep); - bcopy(fhp, mtod(m, u_char *) + sizeof(u_int32_t), *fhsizep); - m->m_len = *fhsizep + sizeof(u_int32_t); - } else { - bcopy(fhp, mtod(m, u_char *), NFSX_V2FH); - m->m_len = NFSX_V2FH; - } - - m->m_next = xdr_string_encode(path, strlen(path)); - if (m->m_next == NULL) { - error = ENOBUFS; - goto out; - } - - /* Do RPC to nfsd. */ - if ((args->flags & NFSMNT_NFSV3) != 0) - error = krpc_call(mdsin, NFS_PROG, NFS_VER3, - NFSPROC_LOOKUP, &m, NULL, td); - else - error = krpc_call(mdsin, NFS_PROG, NFS_VER2, - NFSV2PROC_LOOKUP, &m, NULL, td); - if (error != 0) - return error; /* message already freed */ - - if (xdr_int_decode(&m, &status) != 0) - goto bad; - if (status != 0) { - error = ENOENT; - goto out; - } - - if ((args->flags & NFSMNT_NFSV3) != 0) { - if (xdr_int_decode(&m, fhsizep) != 0 || - *fhsizep > NFSX_V3FHMAX || - *fhsizep <= 0) - goto bad; - } else - *fhsizep = NFSX_V2FH; - - if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0) - goto bad; - - if ((args->flags & NFSMNT_NFSV3) != 0) { - if (xdr_int_decode(&m, &attribs_present) != 0) - goto bad; - if (attribs_present != 0) { - if (xdr_opaque_decode(&m, (u_char *) &fattribs.v3, - sizeof(u_int32_t) * 21) != 0) - goto bad; - size = fxdr_unsigned(u_int32_t, fattribs.v3[6]); - } - } else { - if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2, - sizeof(u_int32_t) * 17) != 0) - goto bad; - size = fxdr_unsigned(u_int32_t, fattribs.v2[5]); - } - - if (nfsv3_diskless.swap_nblks == 0 && size != -1) { - nfsv3_diskless.swap_nblks = size / 1024; - printf("md_lookup_swap: Swap size is %d KB\n", - nfsv3_diskless.swap_nblks); - } - - goto out; - -bad: - error = EBADRPC; - -out: - m_freem(m); - return error; -} diff --git a/sys/nfs/krpc.h b/sys/nfs/krpc.h deleted file mode 100644 index b6136e3..0000000 --- a/sys/nfs/krpc.h +++ /dev/null @@ -1,31 +0,0 @@ -/* $NetBSD: krpc.h,v 1.4 1995/12/19 23:07:11 cgd Exp $ */ -/* $FreeBSD$ */ - -#include - -struct mbuf; -struct thread; -struct sockaddr; -struct sockaddr_in; - -int krpc_call __P((struct sockaddr_in *_sin, - u_int prog, u_int vers, u_int func, - struct mbuf **data, struct sockaddr **from, struct thread *td)); - -int krpc_portmap __P((struct sockaddr_in *_sin, - u_int prog, u_int vers, u_int16_t *portp,struct thread *td)); - -struct mbuf *xdr_string_encode __P((char *str, int len)); - -/* - * RPC definitions for the portmapper - */ -#define PMAPPORT 111 -#define PMAPPROG 100000 -#define PMAPVERS 2 -#define PMAPPROC_NULL 0 -#define PMAPPROC_SET 1 -#define PMAPPROC_UNSET 2 -#define PMAPPROC_GETPORT 3 -#define PMAPPROC_DUMP 4 -#define PMAPPROC_CALLIT 5 diff --git a/sys/nfs/krpc_subr.c b/sys/nfs/krpc_subr.c deleted file mode 100644 index 709af4a..0000000 --- a/sys/nfs/krpc_subr.c +++ /dev/null @@ -1,487 +0,0 @@ -/* $NetBSD: krpc_subr.c,v 1.12.4.1 1996/06/07 00:52:26 cgd Exp $ */ -/* $FreeBSD$ */ - -/* - * Copyright (c) 1995 Gordon Ross, Adam Glass - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Lawrence Berkeley Laboratory and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * partially based on: - * libnetboot/rpc.c - * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -/* - * Kernel support for Sun RPC - * - * Used currently for bootstrapping in nfs diskless configurations. - */ - -/* - * Generic RPC headers - */ - -struct auth_info { - u_int32_t authtype; /* auth type */ - u_int32_t authlen; /* auth length */ -}; - -struct auth_unix { - int32_t ua_time; - int32_t ua_hostname; /* null */ - int32_t ua_uid; - int32_t ua_gid; - int32_t ua_gidlist; /* null */ -}; - -struct rpc_call { - u_int32_t rp_xid; /* request transaction id */ - int32_t rp_direction; /* call direction (0) */ - u_int32_t rp_rpcvers; /* rpc version (2) */ - u_int32_t rp_prog; /* program */ - u_int32_t rp_vers; /* version */ - u_int32_t rp_proc; /* procedure */ - struct auth_info rpc_auth; - struct auth_unix rpc_unix; - struct auth_info rpc_verf; -}; - -struct rpc_reply { - u_int32_t rp_xid; /* request transaction id */ - int32_t rp_direction; /* call direction (1) */ - int32_t rp_astatus; /* accept status (0: accepted) */ - union { - u_int32_t rpu_errno; - struct { - struct auth_info rok_auth; - u_int32_t rok_status; - } rpu_rok; - } rp_u; -}; -#define rp_errno rp_u.rpu_errno -#define rp_auth rp_u.rpu_rok.rok_auth -#define rp_status rp_u.rpu_rok.rok_status - -#define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */ - -/* - * What is the longest we will wait before re-sending a request? - * Note this is also the frequency of "RPC timeout" messages. - * The re-send loop count sup linearly to this maximum, so the - * first complaint will happen after (1+2+3+4+5)=15 seconds. - */ -#define MAX_RESEND_DELAY 5 /* seconds */ - -/* - * Call portmap to lookup a port number for a particular rpc program - * Returns non-zero error on failure. - */ -int -krpc_portmap(sin, prog, vers, portp, td) - struct sockaddr_in *sin; /* server address */ - u_int prog, vers; /* host order */ - u_int16_t *portp; /* network order */ - struct thread *td; -{ - struct sdata { - u_int32_t prog; /* call program */ - u_int32_t vers; /* call version */ - u_int32_t proto; /* call protocol */ - u_int32_t port; /* call port (unused) */ - } *sdata; - struct rdata { - u_int16_t pad; - u_int16_t port; - } *rdata; - struct mbuf *m; - int error; - - /* The portmapper port is fixed. */ - if (prog == PMAPPROG) { - *portp = htons(PMAPPORT); - return 0; - } - - m = m_get(M_TRYWAIT, MT_DATA); - if (m == NULL) - return ENOBUFS; - sdata = mtod(m, struct sdata *); - m->m_len = sizeof(*sdata); - - /* Do the RPC to get it. */ - sdata->prog = txdr_unsigned(prog); - sdata->vers = txdr_unsigned(vers); - sdata->proto = txdr_unsigned(IPPROTO_UDP); - sdata->port = 0; - - sin->sin_port = htons(PMAPPORT); - error = krpc_call(sin, PMAPPROG, PMAPVERS, - PMAPPROC_GETPORT, &m, NULL, td); - if (error) - return error; - - if (m->m_len < sizeof(*rdata)) { - m = m_pullup(m, sizeof(*rdata)); - if (m == NULL) - return ENOBUFS; - } - rdata = mtod(m, struct rdata *); - *portp = rdata->port; - - m_freem(m); - return 0; -} - -/* - * Do a remote procedure call (RPC) and wait for its reply. - * If from_p is non-null, then we are doing broadcast, and - * the address from whence the response came is saved there. - */ -int -krpc_call(sa, prog, vers, func, data, from_p, td) - struct sockaddr_in *sa; - u_int prog, vers, func; - struct mbuf **data; /* input/output */ - struct sockaddr **from_p; /* output */ - struct thread *td; -{ - struct socket *so; - struct sockaddr_in *sin, ssin; - struct sockaddr *from; - struct mbuf *m, *nam, *mhead; - struct rpc_call *call; - struct rpc_reply *reply; - struct sockopt sopt; - struct timeval tv; - struct uio auio; - int error, rcvflg, timo, secs, len; - static u_int32_t xid = ~0xFF; - u_int16_t tport; - u_int32_t saddr; - - /* - * Validate address family. - * Sorry, this is INET specific... - */ - if (sa->sin_family != AF_INET) - return (EAFNOSUPPORT); - - /* Free at end if not null. */ - nam = mhead = NULL; - from = NULL; - - /* - * Create socket and set its recieve timeout. - */ - if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td))) - goto out; - - tv.tv_sec = 1; - tv.tv_usec = 0; - bzero(&sopt, sizeof sopt); - sopt.sopt_level = SOL_SOCKET; - sopt.sopt_name = SO_RCVTIMEO; - sopt.sopt_val = &tv; - sopt.sopt_valsize = sizeof tv; - - if ((error = sosetopt(so, &sopt)) != 0) - goto out; - - /* - * Enable broadcast if necessary. - */ - if (from_p) { - int on = 1; - sopt.sopt_name = SO_BROADCAST; - sopt.sopt_val = &on; - sopt.sopt_valsize = sizeof on; - if ((error = sosetopt(so, &sopt)) != 0) - goto out; - } - - /* - * Bind the local endpoint to a reserved port, - * because some NFS servers refuse requests from - * non-reserved (non-privileged) ports. - */ - sin = &ssin; - bzero(sin, sizeof *sin); - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = INADDR_ANY; - tport = IPPORT_RESERVED; - do { - tport--; - sin->sin_port = htons(tport); - error = sobind(so, (struct sockaddr *)sin, td); - } while (error == EADDRINUSE && - tport > IPPORT_RESERVED / 2); - if (error) { - printf("bind failed\n"); - goto out; - } - - /* - * Setup socket address for the server. - */ - - /* - * Prepend RPC message header. - */ - mhead = m_gethdr(M_TRYWAIT, MT_DATA); - mhead->m_next = *data; - call = mtod(mhead, struct rpc_call *); - mhead->m_len = sizeof(*call); - bzero((caddr_t)call, sizeof(*call)); - /* rpc_call part */ - xid++; - call->rp_xid = txdr_unsigned(xid); - /* call->rp_direction = 0; */ - call->rp_rpcvers = txdr_unsigned(2); - call->rp_prog = txdr_unsigned(prog); - call->rp_vers = txdr_unsigned(vers); - call->rp_proc = txdr_unsigned(func); - /* rpc_auth part (auth_unix as root) */ - call->rpc_auth.authtype = txdr_unsigned(RPCAUTH_UNIX); - call->rpc_auth.authlen = txdr_unsigned(sizeof(struct auth_unix)); - /* rpc_verf part (auth_null) */ - call->rpc_verf.authtype = 0; - call->rpc_verf.authlen = 0; - - /* - * Setup packet header - */ - len = 0; - m = mhead; - while (m) { - len += m->m_len; - m = m->m_next; - } - mhead->m_pkthdr.len = len; - mhead->m_pkthdr.rcvif = NULL; - - /* - * Send it, repeatedly, until a reply is received, - * but delay each re-send by an increasing amount. - * If the delay hits the maximum, start complaining. - */ - timo = 0; - for (;;) { - /* Send RPC request (or re-send). */ - m = m_copym(mhead, 0, M_COPYALL, M_TRYWAIT); - if (m == NULL) { - error = ENOBUFS; - goto out; - } - error = sosend(so, (struct sockaddr *)sa, NULL, m, - NULL, 0, td); - if (error) { - printf("krpc_call: sosend: %d\n", error); - goto out; - } - m = NULL; - - /* Determine new timeout. */ - if (timo < MAX_RESEND_DELAY) - timo++; - else { - saddr = ntohl(sa->sin_addr.s_addr); - printf("RPC timeout for server %d.%d.%d.%d\n", - (saddr >> 24) & 255, - (saddr >> 16) & 255, - (saddr >> 8) & 255, - saddr & 255); - } - - /* - * Wait for up to timo seconds for a reply. - * The socket receive timeout was set to 1 second. - */ - secs = timo; - while (secs > 0) { - if (from) { - FREE(from, M_SONAME); - from = NULL; - } - if (m) { - m_freem(m); - m = NULL; - } - bzero(&auio,sizeof(auio)); - auio.uio_resid = len = 1<<16; - rcvflg = 0; - error = soreceive(so, &from, &auio, &m, NULL, &rcvflg); - if (error == EWOULDBLOCK) { - secs--; - continue; - } - if (error) - goto out; - len -= auio.uio_resid; - - /* Does the reply contain at least a header? */ - if (len < MIN_REPLY_HDR) - continue; - if (m->m_len < MIN_REPLY_HDR) - continue; - reply = mtod(m, struct rpc_reply *); - - /* Is it the right reply? */ - if (reply->rp_direction != txdr_unsigned(RPC_REPLY)) - continue; - - if (reply->rp_xid != txdr_unsigned(xid)) - continue; - - /* Was RPC accepted? (authorization OK) */ - if (reply->rp_astatus != 0) { - error = fxdr_unsigned(u_int32_t, reply->rp_errno); - printf("rpc denied, error=%d\n", error); - continue; - } - - /* Did the call succeed? */ - if (reply->rp_status != 0) { - error = fxdr_unsigned(u_int32_t, reply->rp_status); - if (error == RPC_PROGMISMATCH) { - error = EBADRPC; - goto out; - } - printf("rpc denied, status=%d\n", error); - continue; - } - - goto gotreply; /* break two levels */ - - } /* while secs */ - } /* forever send/receive */ - - error = ETIMEDOUT; - goto out; - - gotreply: - - /* - * Get RPC reply header into first mbuf, - * get its length, then strip it off. - */ - len = sizeof(*reply); - if (m->m_len < len) { - m = m_pullup(m, len); - if (m == NULL) { - error = ENOBUFS; - goto out; - } - } - reply = mtod(m, struct rpc_reply *); - if (reply->rp_auth.authtype != 0) { - len += fxdr_unsigned(u_int32_t, reply->rp_auth.authlen); - len = (len + 3) & ~3; /* XXX? */ - } - m_adj(m, len); - - /* result */ - *data = m; - if (from_p) { - *from_p = from; - from = NULL; - } - - out: - if (mhead) m_freem(mhead); - if (from) free(from, M_SONAME); - soclose(so); - return error; -} - -/* - * eXternal Data Representation routines. - * (but with non-standard args...) - */ - -/* - * String representation for RPC. - */ -struct xdr_string { - u_int32_t len; /* length without null or padding */ - char data[4]; /* data (longer, of course) */ - /* data is padded to a long-word boundary */ -}; - -struct mbuf * -xdr_string_encode(str, len) - char *str; - int len; -{ - struct mbuf *m; - struct xdr_string *xs; - int dlen; /* padded string length */ - int mlen; /* message length */ - - dlen = (len + 3) & ~3; - mlen = dlen + 4; - - if (mlen > MCLBYTES) /* If too big, we just can't do it. */ - return (NULL); - - m = m_get(M_TRYWAIT, MT_DATA); - if (mlen > MLEN) { - MCLGET(m, M_TRYWAIT); - if ((m->m_flags & M_EXT) == 0) { - (void) m_free(m); /* There can be only one. */ - return (NULL); - } - } - xs = mtod(m, struct xdr_string *); - m->m_len = mlen; - xs->len = txdr_unsigned(len); - bcopy(str, xs->data, len); - return (m); -} diff --git a/sys/nfs/nfs.h b/sys/nfs/nfs.h deleted file mode 100644 index da808f4..0000000 --- a/sys/nfs/nfs.h +++ /dev/null @@ -1,727 +0,0 @@ -/* - * Copyright (c) 1989, 1993, 1995 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfs.h 8.4 (Berkeley) 5/1/95 - * $FreeBSD$ - */ - -#ifndef _NFS_NFS_H_ -#define _NFS_NFS_H_ - -#ifdef _KERNEL -#include "opt_nfs.h" -#endif - -/* - * Tunable constants for nfs - */ - -#define NFS_MAXIOVEC 34 -#define NFS_TICKINTVL 5 /* Desired time for a tick (msec) */ -#define NFS_HZ (hz / nfs_ticks) /* Ticks/sec */ -#define NFS_TIMEO (1 * NFS_HZ) /* Default timeout = 1 second */ -#define NFS_MINTIMEO (1 * NFS_HZ) /* Min timeout to use */ -#define NFS_MAXTIMEO (60 * NFS_HZ) /* Max timeout to backoff to */ -#define NFS_MINIDEMTIMEO (5 * NFS_HZ) /* Min timeout for non-idempotent ops*/ -#define NFS_MAXREXMIT 100 /* Stop counting after this many */ -#define NFS_MAXWINDOW 1024 /* Max number of outstanding requests */ -#define NFS_RETRANS 10 /* Num of retrans for soft mounts */ -#define NFS_MAXGRPS 16 /* Max. size of groups list */ -#ifndef NFS_MINATTRTIMO -#define NFS_MINATTRTIMO 3 /* VREG attrib cache timeout in sec */ -#endif -#ifndef NFS_MAXATTRTIMO -#define NFS_MAXATTRTIMO 60 -#endif -#ifndef NFS_MINDIRATTRTIMO -#define NFS_MINDIRATTRTIMO 30 /* VDIR attrib cache timeout in sec */ -#endif -#ifndef NFS_MAXDIRATTRTIMO -#define NFS_MAXDIRATTRTIMO 60 -#endif -#define NFS_WSIZE 8192 /* Def. write data size <= 8192 */ -#define NFS_RSIZE 8192 /* Def. read data size <= 8192 */ -#define NFS_READDIRSIZE 8192 /* Def. readdir size */ -#define NFS_DEFRAHEAD 1 /* Def. read ahead # blocks */ -#define NFS_MAXRAHEAD 4 /* Max. read ahead # blocks */ -#define NFS_MAXUIDHASH 64 /* Max. # of hashed uid entries/mp */ -#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runnable */ -#define NFS_MAXGATHERDELAY 100 /* Max. write gather delay (msec) */ -#ifndef NFS_GATHERDELAY -#define NFS_GATHERDELAY 10 /* Default write gather delay (msec) */ -#endif -#define NFS_DIRBLKSIZ 4096 /* Must be a multiple of DIRBLKSIZ */ -#ifdef _KERNEL -#define DIRBLKSIZ 512 /* XXX we used to use ufs's DIRBLKSIZ */ -#endif - -/* - * Oddballs - */ -#define NMOD(a) ((a) % nfs_asyncdaemons) -#define NFS_CMPFH(n, f, s) \ - ((n)->n_fhsize == (s) && !bcmp((caddr_t)(n)->n_fhp, (caddr_t)(f), (s))) -#define NFS_ISV3(v) (VFSTONFS((v)->v_mount)->nm_flag & NFSMNT_NFSV3) -#define NFS_SRVMAXDATA(n) \ - (((n)->nd_flag & ND_NFSV3) ? (((n)->nd_nam2) ? \ - NFS_MAXDGRAMDATA : NFS_MAXDATA) : NFS_V2MAXDATA) - -/* - * XXX - * The B_INVAFTERWRITE flag should be set to whatever is required by the - * buffer cache code to say "Invalidate the block after it is written back". - */ -#define B_INVAFTERWRITE B_NOCACHE - -/* - * The IO_METASYNC flag should be implemented for local file systems. - * (Until then, it is nothin at all.) - */ -#ifndef IO_METASYNC -#define IO_METASYNC 0 -#endif - -/* - * Arguments to mount NFS - */ -#define NFS_ARGSVERSION 3 /* change when nfs_args changes */ -struct nfs_args { - int version; /* args structure version number */ - struct sockaddr *addr; /* file server address */ - int addrlen; /* length of address */ - int sotype; /* Socket type */ - int proto; /* and Protocol */ - u_char *fh; /* File handle to be mounted */ - int fhsize; /* Size, in bytes, of fh */ - int flags; /* flags */ - int wsize; /* write size in bytes */ - int rsize; /* read size in bytes */ - int readdirsize; /* readdir size in bytes */ - int timeo; /* initial timeout in .1 secs */ - int retrans; /* times to retry send */ - int maxgrouplist; /* Max. size of group list */ - int readahead; /* # of blocks to readahead */ - int leaseterm; /* Term (sec) of lease */ - int deadthresh; /* Retrans threshold */ - char *hostname; /* server's name */ - int acregmin; /* cache attrs for reg files min time */ - int acregmax; /* cache attrs for reg files max time */ - int acdirmin; /* cache attrs for dirs min time */ - int acdirmax; /* cache attrs for dirs max time */ -}; - -/* - * NFS mount option flags - */ -#define NFSMNT_SOFT 0x00000001 /* soft mount (hard is default) */ -#define NFSMNT_WSIZE 0x00000002 /* set write size */ -#define NFSMNT_RSIZE 0x00000004 /* set read size */ -#define NFSMNT_TIMEO 0x00000008 /* set initial timeout */ -#define NFSMNT_RETRANS 0x00000010 /* set number of request retries */ -#define NFSMNT_MAXGRPS 0x00000020 /* set maximum grouplist size */ -#define NFSMNT_INT 0x00000040 /* allow interrupts on hard mount */ -#define NFSMNT_NOCONN 0x00000080 /* Don't Connect the socket */ -#define NFSMNT_NQNFS 0x00000100 /* Use Nqnfs protocol */ -#define NFSMNT_NFSV3 0x00000200 /* Use NFS Version 3 protocol */ -#define NFSMNT_KERB 0x00000400 /* Use Kerberos authentication */ -#define NFSMNT_DUMBTIMR 0x00000800 /* Don't estimate rtt dynamically */ -#define NFSMNT_LEASETERM 0x00001000 /* set lease term (nqnfs) */ -#define NFSMNT_READAHEAD 0x00002000 /* set read ahead */ -#define NFSMNT_DEADTHRESH 0x00004000 /* set dead server retry thresh */ -#define NFSMNT_RESVPORT 0x00008000 /* Allocate a reserved port */ -#define NFSMNT_RDIRPLUS 0x00010000 /* Use Readdirplus for V3 */ -#define NFSMNT_READDIRSIZE 0x00020000 /* Set readdir size */ -#define NFSMNT_ACREGMIN 0x00040000 -#define NFSMNT_ACREGMAX 0x00080000 -#define NFSMNT_ACDIRMIN 0x00100000 -#define NFSMNT_ACDIRMAX 0x00200000 - -#define NFSSTA_HASWRITEVERF 0x00040000 /* Has write verifier for V3 */ -#define NFSSTA_GOTPATHCONF 0x00080000 /* Got the V3 pathconf info */ -#define NFSSTA_GOTFSINFO 0x00100000 /* Got the V3 fsinfo */ -#define NFSSTA_MNTD 0x00200000 /* Mnt server for mnt point */ -#define NFSSTA_DISMINPROG 0x00400000 /* Dismount in progress */ -#define NFSSTA_DISMNT 0x00800000 /* Dismounted */ -#define NFSSTA_SNDLOCK 0x01000000 /* Send socket lock */ -#define NFSSTA_WANTSND 0x02000000 /* Want above */ -#define NFSSTA_RCVLOCK 0x04000000 /* Rcv socket lock */ -#define NFSSTA_WANTRCV 0x08000000 /* Want above */ -#define NFSSTA_WAITAUTH 0x10000000 /* Wait for authentication */ -#define NFSSTA_HASAUTH 0x20000000 /* Has authenticator */ -#define NFSSTA_WANTAUTH 0x40000000 /* Wants an authenticator */ -#define NFSSTA_AUTHERR 0x80000000 /* Authentication error */ - -/* - * Structures for the nfssvc(2) syscall. Not that anyone but nfsd and mount_nfs - * should ever try and use it. - */ -struct nfsd_args { - int sock; /* Socket to serve */ - caddr_t name; /* Client addr for connection based sockets */ - int namelen; /* Length of name */ -}; - -struct nfsd_srvargs { - struct nfsd *nsd_nfsd; /* Pointer to in kernel nfsd struct */ - uid_t nsd_uid; /* Effective uid mapped to cred */ - u_int32_t nsd_haddr; /* Ip address of client */ - struct xucred nsd_cr; /* Cred. uid maps to */ - u_int nsd_authlen; /* Length of auth string (ret) */ - u_char *nsd_authstr; /* Auth string (ret) */ - u_int nsd_verflen; /* and the verfier */ - u_char *nsd_verfstr; - struct timeval nsd_timestamp; /* timestamp from verifier */ - u_int32_t nsd_ttl; /* credential ttl (sec) */ - NFSKERBKEY_T nsd_key; /* Session key */ -}; - -struct nfsd_cargs { - char *ncd_dirp; /* Mount dir path */ - uid_t ncd_authuid; /* Effective uid */ - int ncd_authtype; /* Type of authenticator */ - u_int ncd_authlen; /* Length of authenticator string */ - u_char *ncd_authstr; /* Authenticator string */ - u_int ncd_verflen; /* and the verifier */ - u_char *ncd_verfstr; - NFSKERBKEY_T ncd_key; /* Session key */ -}; - -/* - * XXX to allow amd to include nfs.h without nfsproto.h - */ -#ifdef NFS_NPROCS -/* - * Stats structure - */ -struct nfsstats { - int attrcache_hits; - int attrcache_misses; - int lookupcache_hits; - int lookupcache_misses; - int direofcache_hits; - int direofcache_misses; - int biocache_reads; - int read_bios; - int read_physios; - int biocache_writes; - int write_bios; - int write_physios; - int biocache_readlinks; - int readlink_bios; - int biocache_readdirs; - int readdir_bios; - int rpccnt[NFS_NPROCS]; - int rpcretries; - int srvrpccnt[NFS_NPROCS]; - int srvrpc_errs; - int srv_errs; - int rpcrequests; - int rpctimeouts; - int rpcunexpected; - int rpcinvalid; - int srvcache_inproghits; - int srvcache_idemdonehits; - int srvcache_nonidemdonehits; - int srvcache_misses; - int srvnqnfs_leases; - int srvnqnfs_maxleases; - int srvnqnfs_getleases; - int srvvop_writes; - int accesscache_hits; - int accesscache_misses; -}; -#endif - -/* - * Flags for nfssvc() system call. - */ -#define NFSSVC_BIOD 0x002 -#define NFSSVC_NFSD 0x004 -#define NFSSVC_ADDSOCK 0x008 -#define NFSSVC_AUTHIN 0x010 -#define NFSSVC_GOTAUTH 0x040 -#define NFSSVC_AUTHINFAIL 0x080 -#define NFSSVC_MNTD 0x100 -#define NFSSVC_LOCKDANS 0x200 - -/* - * fs.nfs sysctl(3) identifiers - */ -#define NFS_NFSSTATS 1 /* struct: struct nfsstats */ -#define NFS_NFSPRIVPORT 2 /* int: prohibit nfs to resvports */ - -#define FS_NFS_NAMES { \ - { 0, 0 }, \ - { "nfsstats", CTLTYPE_STRUCT }, \ - { "nfsprivport", CTLTYPE_INT }, \ -} - -#ifdef _KERNEL - -#ifdef MALLOC_DECLARE -MALLOC_DECLARE(M_NFSREQ); -MALLOC_DECLARE(M_NFSDIROFF); -MALLOC_DECLARE(M_NFSRVDESC); -MALLOC_DECLARE(M_NFSUID); -MALLOC_DECLARE(M_NQLEASE); -MALLOC_DECLARE(M_NFSD); -MALLOC_DECLARE(M_NFSBIGFH); -MALLOC_DECLARE(M_NFSHASH); -#endif - -#ifdef ZONE_INTERRUPT -extern vm_zone_t nfsmount_zone; -#endif - -extern struct callout_handle nfs_timer_handle; - -struct uio; struct buf; struct vattr; struct nameidata; /* XXX */ - -/* - * The set of signals the interrupt an I/O in progress for NFSMNT_INT mounts. - * What should be in this set is open to debate, but I believe that since - * I/O system calls on ufs are never interrupted by signals the set should - * be minimal. My reasoning is that many current programs that use signals - * such as SIGALRM will not expect file I/O system calls to be interrupted - * by them and break. - */ -#define NFSINT_SIGMASK(set) \ - (SIGISMEMBER(set, SIGINT) || SIGISMEMBER(set, SIGTERM) || \ - SIGISMEMBER(set, SIGHUP) || SIGISMEMBER(set, SIGKILL) || \ - SIGISMEMBER(set, SIGQUIT)) - -/* - * Socket errors ignored for connectionless sockets?? - * For now, ignore them all - */ -#define NFSIGNORE_SOERROR(s, e) \ - ((e) != EINTR && (e) != ERESTART && (e) != EWOULDBLOCK && \ - ((s) & PR_CONNREQUIRED) == 0) - -/* - * Nfs outstanding request list element - */ -struct nfsreq { - TAILQ_ENTRY(nfsreq) r_chain; - struct mbuf *r_mreq; - struct mbuf *r_mrep; - struct mbuf *r_md; - caddr_t r_dpos; - struct nfsmount *r_nmp; - struct vnode *r_vp; - u_int32_t r_xid; - int r_flags; /* flags on request, see below */ - int r_retry; /* max retransmission count */ - int r_rexmit; /* current retrans count */ - int r_timer; /* tick counter on reply */ - u_int32_t r_procnum; /* NFS procedure number */ - int r_rtt; /* RTT for rpc */ - struct thread *r_td; /* Proc that did I/O system call */ -}; - -/* - * Queue head for nfsreq's - */ -extern TAILQ_HEAD(nfs_reqq, nfsreq) nfs_reqq; - -/* Flag values for r_flags */ -#define R_TIMING 0x01 /* timing request (in mntp) */ -#define R_SENT 0x02 /* request has been sent */ -#define R_SOFTTERM 0x04 /* soft mnt, too many retries */ -#define R_INTR 0x08 /* intr mnt, signal pending */ -#define R_SOCKERR 0x10 /* Fatal error on socket */ -#define R_TPRINTFMSG 0x20 /* Did a tprintf msg. */ -#define R_MUSTRESEND 0x40 /* Must resend request */ -#define R_GETONEREP 0x80 /* Probe for one reply only */ - -/* - * A list of nfssvc_sock structures is maintained with all the sockets - * that require service by the nfsd. - * The nfsuid structs hang off of the nfssvc_sock structs in both lru - * and uid hash lists. - */ -#ifndef NFS_UIDHASHSIZ -#define NFS_UIDHASHSIZ 29 /* Tune the size of nfssvc_sock with this */ -#endif -#define NUIDHASH(sock, uid) \ - (&(sock)->ns_uidhashtbl[(uid) % NFS_UIDHASHSIZ]) -#ifndef NFS_WDELAYHASHSIZ -#define NFS_WDELAYHASHSIZ 16 /* and with this */ -#endif -#define NWDELAYHASH(sock, f) \ - (&(sock)->ns_wdelayhashtbl[(*((u_int32_t *)(f))) % NFS_WDELAYHASHSIZ]) -#ifndef NFS_MUIDHASHSIZ -#define NFS_MUIDHASHSIZ 63 /* Tune the size of nfsmount with this */ -#endif -#define NMUIDHASH(nmp, uid) \ - (&(nmp)->nm_uidhashtbl[(uid) % NFS_MUIDHASHSIZ]) -#define NFSNOHASH(fhsum) \ - (&nfsnodehashtbl[(fhsum) & nfsnodehash]) - -/* - * Network address hash list element - */ -union nethostaddr { - u_int32_t had_inetaddr; - struct sockaddr *had_nam; -}; - -struct nfsuid { - TAILQ_ENTRY(nfsuid) nu_lru; /* LRU chain */ - LIST_ENTRY(nfsuid) nu_hash; /* Hash list */ - int nu_flag; /* Flags */ - union nethostaddr nu_haddr; /* Host addr. for dgram sockets */ - struct ucred nu_cr; /* Cred uid mapped to */ - int nu_expire; /* Expiry time (sec) */ - struct timeval nu_timestamp; /* Kerb. timestamp */ - u_int32_t nu_nickname; /* Nickname on server */ - NFSKERBKEY_T nu_key; /* and session key */ -}; - -#define nu_inetaddr nu_haddr.had_inetaddr -#define nu_nam nu_haddr.had_nam -/* Bits for nu_flag */ -#define NU_INETADDR 0x1 -#define NU_NAM 0x2 -#define NU_NETFAM(u) (((u)->nu_flag & NU_INETADDR) ? AF_INET : AF_ISO) - -struct nfsrv_rec { - STAILQ_ENTRY(nfsrv_rec) nr_link; - struct sockaddr *nr_address; - struct mbuf *nr_packet; -}; - -struct nfssvc_sock { - TAILQ_ENTRY(nfssvc_sock) ns_chain; /* List of all nfssvc_sock's */ - TAILQ_HEAD(, nfsuid) ns_uidlruhead; - struct file *ns_fp; - struct socket *ns_so; - struct sockaddr *ns_nam; - struct mbuf *ns_raw; - struct mbuf *ns_rawend; - STAILQ_HEAD(, nfsrv_rec) ns_rec; - struct mbuf *ns_frag; - int ns_flag; - int ns_solock; - int ns_cc; - int ns_reclen; - int ns_numuids; - u_int32_t ns_sref; - LIST_HEAD(, nfsrv_descript) ns_tq; /* Write gather lists */ - LIST_HEAD(, nfsuid) ns_uidhashtbl[NFS_UIDHASHSIZ]; - LIST_HEAD(nfsrvw_delayhash, nfsrv_descript) ns_wdelayhashtbl[NFS_WDELAYHASHSIZ]; -}; - -/* Bits for "ns_flag" */ -#define SLP_VALID 0x01 -#define SLP_DOREC 0x02 -#define SLP_NEEDQ 0x04 -#define SLP_DISCONN 0x08 -#define SLP_GETSTREAM 0x10 -#define SLP_LASTFRAG 0x20 -#define SLP_ALLFLAGS 0xff - -extern TAILQ_HEAD(nfssvc_sockhead, nfssvc_sock) nfssvc_sockhead; -extern int nfssvc_sockhead_flag; -#define SLP_INIT 0x01 -#define SLP_WANTINIT 0x02 - -/* - * One of these structures is allocated for each nfsd. - */ -struct nfsd { - TAILQ_ENTRY(nfsd) nfsd_chain; /* List of all nfsd's */ - int nfsd_flag; /* NFSD_ flags */ - struct nfssvc_sock *nfsd_slp; /* Current socket */ - int nfsd_authlen; /* Authenticator len */ - u_char nfsd_authstr[RPCAUTH_MAXSIZ]; /* Authenticator data */ - int nfsd_verflen; /* and the Verifier */ - u_char nfsd_verfstr[RPCVERF_MAXSIZ]; - struct thread *nfsd_td; /* daemon thread ptr */ - struct nfsrv_descript *nfsd_nd; /* Associated nfsrv_descript */ -}; - -/* Bits for "nfsd_flag" */ -#define NFSD_WAITING 0x01 -#define NFSD_REQINPROG 0x02 -#define NFSD_NEEDAUTH 0x04 -#define NFSD_AUTHFAIL 0x08 - -/* - * This structure is used by the server for describing each request. - * Some fields are used only when write request gathering is performed. - */ -struct nfsrv_descript { - u_quad_t nd_time; /* Write deadline (usec) */ - off_t nd_off; /* Start byte offset */ - off_t nd_eoff; /* and end byte offset */ - LIST_ENTRY(nfsrv_descript) nd_hash; /* Hash list */ - LIST_ENTRY(nfsrv_descript) nd_tq; /* and timer list */ - LIST_HEAD(,nfsrv_descript) nd_coalesce; /* coalesced writes */ - struct mbuf *nd_mrep; /* Request mbuf list */ - struct mbuf *nd_md; /* Current dissect mbuf */ - struct mbuf *nd_mreq; /* Reply mbuf list */ - struct sockaddr *nd_nam; /* and socket addr */ - struct sockaddr *nd_nam2; /* return socket addr */ - caddr_t nd_dpos; /* Current dissect pos */ - u_int32_t nd_procnum; /* RPC # */ - int nd_stable; /* storage type */ - int nd_flag; /* nd_flag */ - int nd_len; /* Length of this write */ - int nd_repstat; /* Reply status */ - u_int32_t nd_retxid; /* Reply xid */ - u_int32_t nd_duration; /* Lease duration */ - struct timeval nd_starttime; /* Time RPC initiated */ - fhandle_t nd_fh; /* File handle */ - struct ucred nd_cr; /* Credentials */ -}; - -/* Bits for "nd_flag" */ -#define ND_READ LEASE_READ -#define ND_WRITE LEASE_WRITE -#define ND_CHECK 0x04 -#define ND_LEASE (ND_READ | ND_WRITE | ND_CHECK) -#define ND_NFSV3 0x08 -#define ND_NQNFS 0x10 -#define ND_KERBNICK 0x20 -#define ND_KERBFULL 0x40 -#define ND_KERBAUTH (ND_KERBNICK | ND_KERBFULL) - -extern TAILQ_HEAD(nfsd_head, nfsd) nfsd_head; -extern int nfsd_head_flag; -#define NFSD_CHECKSLP 0x01 - -/* - * These macros compare nfsrv_descript structures. - */ -#define NFSW_CONTIG(o, n) \ - ((o)->nd_eoff >= (n)->nd_off && \ - !bcmp((caddr_t)&(o)->nd_fh, (caddr_t)&(n)->nd_fh, NFSX_V3FH)) - -#define NFSW_SAMECRED(o, n) \ - (((o)->nd_flag & ND_KERBAUTH) == ((n)->nd_flag & ND_KERBAUTH) && \ - !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ - sizeof (struct ucred))) - -/* - * Defines for WebNFS - */ - -#define WEBNFS_ESC_CHAR '%' -#define WEBNFS_SPECCHAR_START 0x80 - -#define WEBNFS_NATIVE_CHAR 0x80 -/* - * .. - * Possibly more here in the future. - */ - -/* - * Macro for converting escape characters in WebNFS pathnames. - * Should really be in libkern. - */ - -#define HEXTOC(c) \ - ((c) >= 'a' ? ((c) - ('a' - 10)) : \ - ((c) >= 'A' ? ((c) - ('A' - 10)) : ((c) - '0'))) -#define HEXSTRTOI(p) \ - ((HEXTOC(p[0]) << 4) + HEXTOC(p[1])) - -#ifdef NFS_DEBUG - -extern int nfs_debug; -#define NFS_DEBUG_ASYNCIO 1 /* asynchronous i/o */ -#define NFS_DEBUG_WG 2 /* server write gathering */ -#define NFS_DEBUG_RC 4 /* server request caching */ - -#define NFS_DPF(cat, args) \ - do { \ - if (nfs_debug & NFS_DEBUG_##cat) printf args; \ - } while (0) - -#else - -#define NFS_DPF(cat, args) - -#endif - -u_quad_t nfs_curusec __P((void)); -int nfs_init __P((struct vfsconf *vfsp)); -int nfs_uninit __P((struct vfsconf *vfsp)); -int nfs_reply __P((struct nfsreq *)); -int nfs_getreq __P((struct nfsrv_descript *,struct nfsd *,int)); -int nfs_send __P((struct socket *, struct sockaddr *, struct mbuf *, - struct nfsreq *)); -int nfs_rephead __P((int, struct nfsrv_descript *, struct nfssvc_sock *, - int, int, u_quad_t *, struct mbuf **, struct mbuf **, - caddr_t *)); -int nfs_sndlock __P((struct nfsreq *)); -void nfs_sndunlock __P((struct nfsreq *)); -int nfs_slplock __P((struct nfssvc_sock *, int)); -void nfs_slpunlock __P((struct nfssvc_sock *)); -int nfs_disct __P((struct mbuf **, caddr_t *, int, int, caddr_t *)); -int nfs_vinvalbuf __P((struct vnode *, int, struct ucred *, struct thread *, - int)); -int nfs_readrpc __P((struct vnode *, struct uio *, struct ucred *)); -int nfs_writerpc __P((struct vnode *, struct uio *, struct ucred *, int *, - int *)); -int nfs_commit __P((struct vnode *vp, u_quad_t offset, int cnt, - struct ucred *cred, struct thread *td)); -int nfs_readdirrpc __P((struct vnode *, struct uio *, struct ucred *)); -int nfs_asyncio __P((struct buf *, struct ucred *, struct thread *)); -int nfs_doio __P((struct buf *, struct ucred *, struct thread *)); -int nfs_readlinkrpc __P((struct vnode *, struct uio *, struct ucred *)); -int nfs_sigintr __P((struct nfsmount *, struct nfsreq *, struct proc *)); -int nfs_readdirplusrpc __P((struct vnode *, struct uio *, struct ucred *)); -int nfsm_disct __P((struct mbuf **, caddr_t *, int, int, caddr_t *)); -void nfsm_srvfattr __P((struct nfsrv_descript *, struct vattr *, - struct nfs_fattr *)); -void nfsm_srvwcc __P((struct nfsrv_descript *, int, struct vattr *, int, - struct vattr *, struct mbuf **, char **)); -void nfsm_srvpostopattr __P((struct nfsrv_descript *, int, struct vattr *, - struct mbuf **, char **)); -int netaddr_match __P((int, union nethostaddr *, struct sockaddr *)); -int nfs_request __P((struct vnode *, struct mbuf *, int, struct thread *, - struct ucred *, struct mbuf **, struct mbuf **, - caddr_t *)); -int nfs_loadattrcache __P((struct vnode **, struct mbuf **, caddr_t *, - struct vattr *, int)); -int nfs_namei __P((struct nameidata *, fhandle_t *, int, - struct nfssvc_sock *, struct sockaddr *, struct mbuf **, - caddr_t *, struct vnode **, struct thread *, int, int)); -void nfsm_adj __P((struct mbuf *, int, int)); -int nfsm_mbuftouio __P((struct mbuf **, struct uio *, int, caddr_t *)); -void nfsrv_initcache __P((void)); -int nfs_getauth __P((struct nfsmount *, struct nfsreq *, struct ucred *, - char **, int *, char *, int *, NFSKERBKEY_T)); -int nfs_getnickauth __P((struct nfsmount *, struct ucred *, char **, - int *, char *, int)); -int nfs_savenickauth __P((struct nfsmount *, struct ucred *, int, - NFSKERBKEY_T, struct mbuf **, char **, - struct mbuf *)); -int nfs_adv __P((struct mbuf **, caddr_t *, int, int)); -void nfs_nhinit __P((void)); -void nfs_timer __P((void*)); -int nfsrv_dorec __P((struct nfssvc_sock *, struct nfsd *, - struct nfsrv_descript **)); -int nfsrv_getcache __P((struct nfsrv_descript *, struct nfssvc_sock *, - struct mbuf **)); -void nfsrv_updatecache __P((struct nfsrv_descript *, int, struct mbuf *)); -void nfsrv_cleancache __P((void)); -int nfs_connect __P((struct nfsmount *, struct nfsreq *)); -void nfs_disconnect __P((struct nfsmount *)); -void nfs_safedisconnect __P((struct nfsmount *)); -int nfs_getattrcache __P((struct vnode *, struct vattr *)); -int nfsm_strtmbuf __P((struct mbuf **, char **, const char *, long)); -int nfs_bioread __P((struct vnode *, struct uio *, int, struct ucred *)); -int nfsm_uiotombuf __P((struct uio *, struct mbuf **, int, caddr_t *)); -void nfsrv_init __P((int)); -void nfs_clearcommit __P((struct mount *)); -int nfsrv_errmap __P((struct nfsrv_descript *, int)); -void nfsrvw_sort __P((gid_t *, int)); -void nfsrv_setcred __P((struct ucred *, struct ucred *)); -int nfs_writebp __P((struct buf *, int, struct thread *)); -int nfsrv_object_create __P((struct vnode *)); -void nfsrv_wakenfsd __P((struct nfssvc_sock *slp)); -int nfsrv_writegather __P((struct nfsrv_descript **, struct nfssvc_sock *, - struct thread *, struct mbuf **)); -int nfs_fsinfo __P((struct nfsmount *, struct vnode *, struct ucred *, - struct thread *td)); - -int nfsrv3_access __P((struct nfsrv_descript *nfsd, - struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_commit __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_create __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_fhtovp __P((fhandle_t *, int, struct vnode **, struct ucred *, - struct nfssvc_sock *, struct sockaddr *, int *, - int, int)); -int nfsrv_setpublicfs __P((struct mount *, struct netexport *, - struct export_args *)); -int nfs_ispublicfh __P((fhandle_t *)); -int nfsrv_fsinfo __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_getattr __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_link __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_lookup __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_mkdir __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_mknod __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_noop __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_null __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_pathconf __P((struct nfsrv_descript *nfsd, - struct nfssvc_sock *slp, struct thread *td, - struct mbuf **mrq)); -int nfsrv_read __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_readdir __P((struct nfsrv_descript *nfsd, - struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_readdirplus __P((struct nfsrv_descript *nfsd, - struct nfssvc_sock *slp, struct thread *td, - struct mbuf **mrq)); -int nfsrv_readlink __P((struct nfsrv_descript *nfsd, - struct nfssvc_sock *slp, struct thread *td, - struct mbuf **mrq)); -int nfsrv_remove __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_rename __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_rmdir __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_setattr __P((struct nfsrv_descript *nfsd, - struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_statfs __P((struct nfsrv_descript *nfsd, - struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_symlink __P((struct nfsrv_descript *nfsd, - struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -int nfsrv_write __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, - struct thread *td, struct mbuf **mrq)); -void nfsrv_rcv __P((struct socket *so, void *arg, int waitflag)); -void nfsrv_slpderef __P((struct nfssvc_sock *slp)); -#endif /* _KERNEL */ - -#endif diff --git a/sys/nfs/nfs_bio.c b/sys/nfs/nfs_bio.c deleted file mode 100644 index fa7274d..0000000 --- a/sys/nfs/nfs_bio.c +++ /dev/null @@ -1,1641 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfs_bio.c 8.9 (Berkeley) 3/30/95 - * $FreeBSD$ - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* - * Just call nfs_writebp() with the force argument set to 1. - * - * NOTE: B_DONE may or may not be set in a_bp on call. - */ -static int -nfs_bwrite(struct buf *bp) -{ - return (nfs_writebp(bp, 1, curthread)); -} - -struct buf_ops buf_ops_nfs = { - "buf_ops_nfs", - nfs_bwrite -}; - - -static struct buf *nfs_getcacheblk __P((struct vnode *vp, daddr_t bn, int size, - struct thread *td)); - -extern int nfs_numasync; -extern int nfs_pbuf_freecnt; -extern struct nfsstats nfsstats; - -/* - * Vnode op for VM getpages. - */ -int -nfs_getpages(ap) - struct vop_getpages_args /* { - struct vnode *a_vp; - vm_page_t *a_m; - int a_count; - int a_reqpage; - vm_ooffset_t a_offset; - } */ *ap; -{ - int i, error, nextoff, size, toff, count, npages; - struct uio uio; - struct iovec iov; - vm_offset_t kva; - struct buf *bp; - struct vnode *vp; - struct thread *td; - struct ucred *cred; - struct nfsmount *nmp; - vm_page_t *pages; - - GIANT_REQUIRED; - - vp = ap->a_vp; - td = curthread; /* XXX */ - cred = curthread->td_proc->p_ucred; /* XXX */ - nmp = VFSTONFS(vp->v_mount); - pages = ap->a_m; - count = ap->a_count; - - if (vp->v_object == NULL) { - printf("nfs_getpages: called with non-merged cache vnode??\n"); - return VM_PAGER_ERROR; - } - - if ((nmp->nm_flag & NFSMNT_NFSV3) != 0 && - (nmp->nm_state & NFSSTA_GOTFSINFO) == 0) { - (void)nfs_fsinfo(nmp, vp, cred, td); - } - - npages = btoc(count); - - /* - * If the requested page is partially valid, just return it and - * allow the pager to zero-out the blanks. Partially valid pages - * can only occur at the file EOF. - */ - - { - vm_page_t m = pages[ap->a_reqpage]; - - if (m->valid != 0) { - /* handled by vm_fault now */ - /* vm_page_zero_invalid(m, TRUE); */ - for (i = 0; i < npages; ++i) { - if (i != ap->a_reqpage) - vm_page_free(pages[i]); - } - return(0); - } - } - - /* - * We use only the kva address for the buffer, but this is extremely - * convienient and fast. - */ - bp = getpbuf(&nfs_pbuf_freecnt); - - kva = (vm_offset_t) bp->b_data; - pmap_qenter(kva, pages, npages); - cnt.v_vnodein++; - cnt.v_vnodepgsin += npages; - - iov.iov_base = (caddr_t) kva; - iov.iov_len = count; - uio.uio_iov = &iov; - uio.uio_iovcnt = 1; - uio.uio_offset = IDX_TO_OFF(pages[0]->pindex); - uio.uio_resid = count; - uio.uio_segflg = UIO_SYSSPACE; - uio.uio_rw = UIO_READ; - uio.uio_td = td; - - error = nfs_readrpc(vp, &uio, cred); - pmap_qremove(kva, npages); - - relpbuf(bp, &nfs_pbuf_freecnt); - - if (error && (uio.uio_resid == count)) { - printf("nfs_getpages: error %d\n", error); - for (i = 0; i < npages; ++i) { - if (i != ap->a_reqpage) - vm_page_free(pages[i]); - } - return VM_PAGER_ERROR; - } - - /* - * Calculate the number of bytes read and validate only that number - * of bytes. Note that due to pending writes, size may be 0. This - * does not mean that the remaining data is invalid! - */ - - size = count - uio.uio_resid; - - for (i = 0, toff = 0; i < npages; i++, toff = nextoff) { - vm_page_t m; - nextoff = toff + PAGE_SIZE; - m = pages[i]; - - m->flags &= ~PG_ZERO; - - if (nextoff <= size) { - /* - * Read operation filled an entire page - */ - m->valid = VM_PAGE_BITS_ALL; - vm_page_undirty(m); - } else if (size > toff) { - /* - * Read operation filled a partial page. - */ - m->valid = 0; - vm_page_set_validclean(m, 0, size - toff); - /* handled by vm_fault now */ - /* vm_page_zero_invalid(m, TRUE); */ - } - - if (i != ap->a_reqpage) { - /* - * Whether or not to leave the page activated is up in - * the air, but we should put the page on a page queue - * somewhere (it already is in the object). Result: - * It appears that emperical results show that - * deactivating pages is best. - */ - - /* - * Just in case someone was asking for this page we - * now tell them that it is ok to use. - */ - if (!error) { - if (m->flags & PG_WANTED) - vm_page_activate(m); - else - vm_page_deactivate(m); - vm_page_wakeup(m); - } else { - vm_page_free(m); - } - } - } - return 0; -} - -/* - * Vnode op for VM putpages. - */ -int -nfs_putpages(ap) - struct vop_putpages_args /* { - struct vnode *a_vp; - vm_page_t *a_m; - int a_count; - int a_sync; - int *a_rtvals; - vm_ooffset_t a_offset; - } */ *ap; -{ - struct uio uio; - struct iovec iov; - vm_offset_t kva; - struct buf *bp; - int iomode, must_commit, i, error, npages, count; - off_t offset; - int *rtvals; - struct vnode *vp; - struct thread *td; - struct ucred *cred; - struct nfsmount *nmp; - struct nfsnode *np; - vm_page_t *pages; - - GIANT_REQUIRED; - - vp = ap->a_vp; - np = VTONFS(vp); - td = curthread; /* XXX */ - cred = curthread->td_proc->p_ucred; /* XXX */ - nmp = VFSTONFS(vp->v_mount); - pages = ap->a_m; - count = ap->a_count; - rtvals = ap->a_rtvals; - npages = btoc(count); - offset = IDX_TO_OFF(pages[0]->pindex); - - GIANT_REQUIRED; - - if ((nmp->nm_flag & NFSMNT_NFSV3) != 0 && - (nmp->nm_state & NFSSTA_GOTFSINFO) == 0) { - (void)nfs_fsinfo(nmp, vp, cred, td); - } - - for (i = 0; i < npages; i++) { - rtvals[i] = VM_PAGER_AGAIN; - } - - /* - * When putting pages, do not extend file past EOF. - */ - - if (offset + count > np->n_size) { - count = np->n_size - offset; - if (count < 0) - count = 0; - } - - /* - * We use only the kva address for the buffer, but this is extremely - * convienient and fast. - */ - bp = getpbuf(&nfs_pbuf_freecnt); - - kva = (vm_offset_t) bp->b_data; - pmap_qenter(kva, pages, npages); - cnt.v_vnodeout++; - cnt.v_vnodepgsout += count; - - iov.iov_base = (caddr_t) kva; - iov.iov_len = count; - uio.uio_iov = &iov; - uio.uio_iovcnt = 1; - uio.uio_offset = offset; - uio.uio_resid = count; - uio.uio_segflg = UIO_SYSSPACE; - uio.uio_rw = UIO_WRITE; - uio.uio_td = td; - - if ((ap->a_sync & VM_PAGER_PUT_SYNC) == 0) - iomode = NFSV3WRITE_UNSTABLE; - else - iomode = NFSV3WRITE_FILESYNC; - - error = nfs_writerpc(vp, &uio, cred, &iomode, &must_commit); - - pmap_qremove(kva, npages); - relpbuf(bp, &nfs_pbuf_freecnt); - - if (!error) { - int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE; - for (i = 0; i < nwritten; i++) { - rtvals[i] = VM_PAGER_OK; - vm_page_undirty(pages[i]); - } - if (must_commit) { - nfs_clearcommit(vp->v_mount); - } - } - return rtvals[0]; -} - -/* - * Vnode op for read using bio - */ -int -nfs_bioread(vp, uio, ioflag, cred) - register struct vnode *vp; - register struct uio *uio; - int ioflag; - struct ucred *cred; -{ - register struct nfsnode *np = VTONFS(vp); - register int biosize, i; - struct buf *bp = 0, *rabp; - struct vattr vattr; - struct thread *td; - struct nfsmount *nmp = VFSTONFS(vp->v_mount); - daddr_t lbn, rabn; - int bcount; - int seqcount; - int nra, error = 0, n = 0, on = 0; - -#ifdef DIAGNOSTIC - if (uio->uio_rw != UIO_READ) - panic("nfs_read mode"); -#endif - if (uio->uio_resid == 0) - return (0); - if (uio->uio_offset < 0) /* XXX VDIR cookies can be negative */ - return (EINVAL); - td = uio->uio_td; - - if ((nmp->nm_flag & NFSMNT_NFSV3) != 0 && - (nmp->nm_state & NFSSTA_GOTFSINFO) == 0) - (void)nfs_fsinfo(nmp, vp, cred, td); - if (vp->v_type != VDIR && - (uio->uio_offset + uio->uio_resid) > nmp->nm_maxfilesize) - return (EFBIG); - biosize = vp->v_mount->mnt_stat.f_iosize; - seqcount = (int)((off_t)(ioflag >> 16) * biosize / BKVASIZE); - /* - * For nfs, cache consistency can only be maintained approximately. - * Although RFC1094 does not specify the criteria, the following is - * believed to be compatible with the reference port. - * For nqnfs, full cache consistency is maintained within the loop. - * For nfs: - * If the file's modify time on the server has changed since the - * last read rpc or you have written to the file, - * you may have lost data cache consistency with the - * server, so flush all of the file's data out of the cache. - * Then force a getattr rpc to ensure that you have up to date - * attributes. - * NB: This implies that cache data can be read when up to - * NFS_ATTRTIMEO seconds out of date. If you find that you need current - * attributes this could be forced by setting n_attrstamp to 0 before - * the VOP_GETATTR() call. - */ - if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) { - if (np->n_flag & NMODIFIED) { - if (vp->v_type != VREG) { - if (vp->v_type != VDIR) - panic("nfs: bioread, not dir"); - nfs_invaldir(vp); - error = nfs_vinvalbuf(vp, V_SAVE, cred, td, 1); - if (error) - return (error); - } - np->n_attrstamp = 0; - error = VOP_GETATTR(vp, &vattr, cred, td); - if (error) - return (error); - np->n_mtime = vattr.va_mtime.tv_sec; - } else { - error = VOP_GETATTR(vp, &vattr, cred, td); - if (error) - return (error); - if (np->n_mtime != vattr.va_mtime.tv_sec) { - if (vp->v_type == VDIR) - nfs_invaldir(vp); - error = nfs_vinvalbuf(vp, V_SAVE, cred, td, 1); - if (error) - return (error); - np->n_mtime = vattr.va_mtime.tv_sec; - } - } - } - do { - - /* - * Get a valid lease. If cached data is stale, flush it. - */ - if (nmp->nm_flag & NFSMNT_NQNFS) { - if (NQNFS_CKINVALID(vp, np, ND_READ)) { - do { - error = nqnfs_getlease(vp, ND_READ, cred, td); - } while (error == NQNFS_EXPIRED); - if (error) - return (error); - if (np->n_lrev != np->n_brev || - (np->n_flag & NQNFSNONCACHE) || - ((np->n_flag & NMODIFIED) && vp->v_type == VDIR)) { - if (vp->v_type == VDIR) - nfs_invaldir(vp); - error = nfs_vinvalbuf(vp, V_SAVE, cred, td, 1); - if (error) - return (error); - np->n_brev = np->n_lrev; - } - } else if (vp->v_type == VDIR && (np->n_flag & NMODIFIED)) { - nfs_invaldir(vp); - error = nfs_vinvalbuf(vp, V_SAVE, cred, td, 1); - if (error) - return (error); - } - } - if (np->n_flag & NQNFSNONCACHE) { - switch (vp->v_type) { - case VREG: - return (nfs_readrpc(vp, uio, cred)); - case VLNK: - return (nfs_readlinkrpc(vp, uio, cred)); - case VDIR: - break; - default: - printf(" NQNFSNONCACHE: type %x unexpected\n", - vp->v_type); - }; - } - switch (vp->v_type) { - case VREG: - nfsstats.biocache_reads++; - lbn = uio->uio_offset / biosize; - on = uio->uio_offset & (biosize - 1); - - /* - * Start the read ahead(s), as required. - */ - if (nfs_numasync > 0 && nmp->nm_readahead > 0) { - for (nra = 0; nra < nmp->nm_readahead && nra < seqcount && - (off_t)(lbn + 1 + nra) * biosize < np->n_size; nra++) { - rabn = lbn + 1 + nra; - if (!incore(vp, rabn)) { - rabp = nfs_getcacheblk(vp, rabn, biosize, td); - if (!rabp) - return (EINTR); - if ((rabp->b_flags & (B_CACHE|B_DELWRI)) == 0) { - rabp->b_flags |= B_ASYNC; - rabp->b_iocmd = BIO_READ; - vfs_busy_pages(rabp, 0); - if (nfs_asyncio(rabp, cred, td)) { - rabp->b_flags |= B_INVAL; - rabp->b_ioflags |= BIO_ERROR; - vfs_unbusy_pages(rabp); - brelse(rabp); - break; - } - } else { - brelse(rabp); - } - } - } - } - - /* - * Obtain the buffer cache block. Figure out the buffer size - * when we are at EOF. If we are modifying the size of the - * buffer based on an EOF condition we need to hold - * nfs_rslock() through obtaining the buffer to prevent - * a potential writer-appender from messing with n_size. - * Otherwise we may accidently truncate the buffer and - * lose dirty data. - * - * Note that bcount is *not* DEV_BSIZE aligned. - */ - -again: - bcount = biosize; - if ((off_t)lbn * biosize >= np->n_size) { - bcount = 0; - } else if ((off_t)(lbn + 1) * biosize > np->n_size) { - bcount = np->n_size - (off_t)lbn * biosize; - } - if (bcount != biosize) { - switch(nfs_rslock(np, td)) { - case ENOLCK: - goto again; - /* not reached */ - case EINTR: - case ERESTART: - return(EINTR); - /* not reached */ - default: - break; - } - } - - bp = nfs_getcacheblk(vp, lbn, bcount, td); - - if (bcount != biosize) - nfs_rsunlock(np, td); - if (!bp) - return (EINTR); - - /* - * If B_CACHE is not set, we must issue the read. If this - * fails, we return an error. - */ - - if ((bp->b_flags & B_CACHE) == 0) { - bp->b_iocmd = BIO_READ; - vfs_busy_pages(bp, 0); - error = nfs_doio(bp, cred, td); - if (error) { - brelse(bp); - return (error); - } - } - - /* - * on is the offset into the current bp. Figure out how many - * bytes we can copy out of the bp. Note that bcount is - * NOT DEV_BSIZE aligned. - * - * Then figure out how many bytes we can copy into the uio. - */ - - n = 0; - if (on < bcount) - n = min((unsigned)(bcount - on), uio->uio_resid); - break; - case VLNK: - nfsstats.biocache_readlinks++; - bp = nfs_getcacheblk(vp, (daddr_t)0, NFS_MAXPATHLEN, td); - if (!bp) - return (EINTR); - if ((bp->b_flags & B_CACHE) == 0) { - bp->b_iocmd = BIO_READ; - vfs_busy_pages(bp, 0); - error = nfs_doio(bp, cred, td); - if (error) { - bp->b_ioflags |= BIO_ERROR; - brelse(bp); - return (error); - } - } - n = min(uio->uio_resid, NFS_MAXPATHLEN - bp->b_resid); - on = 0; - break; - case VDIR: - nfsstats.biocache_readdirs++; - if (np->n_direofoffset - && uio->uio_offset >= np->n_direofoffset) { - return (0); - } - lbn = (uoff_t)uio->uio_offset / NFS_DIRBLKSIZ; - on = uio->uio_offset & (NFS_DIRBLKSIZ - 1); - bp = nfs_getcacheblk(vp, lbn, NFS_DIRBLKSIZ, td); - if (!bp) - return (EINTR); - if ((bp->b_flags & B_CACHE) == 0) { - bp->b_iocmd = BIO_READ; - vfs_busy_pages(bp, 0); - error = nfs_doio(bp, cred, td); - if (error) { - brelse(bp); - } - while (error == NFSERR_BAD_COOKIE) { - printf("got bad cookie vp %p bp %p\n", vp, bp); - nfs_invaldir(vp); - error = nfs_vinvalbuf(vp, 0, cred, td, 1); - /* - * Yuck! The directory has been modified on the - * server. The only way to get the block is by - * reading from the beginning to get all the - * offset cookies. - * - * Leave the last bp intact unless there is an error. - * Loop back up to the while if the error is another - * NFSERR_BAD_COOKIE (double yuch!). - */ - for (i = 0; i <= lbn && !error; i++) { - if (np->n_direofoffset - && (i * NFS_DIRBLKSIZ) >= np->n_direofoffset) - return (0); - bp = nfs_getcacheblk(vp, i, NFS_DIRBLKSIZ, td); - if (!bp) - return (EINTR); - if ((bp->b_flags & B_CACHE) == 0) { - bp->b_iocmd = BIO_READ; - vfs_busy_pages(bp, 0); - error = nfs_doio(bp, cred, td); - /* - * no error + B_INVAL == directory EOF, - * use the block. - */ - if (error == 0 && (bp->b_flags & B_INVAL)) - break; - } - /* - * An error will throw away the block and the - * for loop will break out. If no error and this - * is not the block we want, we throw away the - * block and go for the next one via the for loop. - */ - if (error || i < lbn) - brelse(bp); - } - } - /* - * The above while is repeated if we hit another cookie - * error. If we hit an error and it wasn't a cookie error, - * we give up. - */ - if (error) - return (error); - } - - /* - * If not eof and read aheads are enabled, start one. - * (You need the current block first, so that you have the - * directory offset cookie of the next block.) - */ - if (nfs_numasync > 0 && nmp->nm_readahead > 0 && - (bp->b_flags & B_INVAL) == 0 && - (np->n_direofoffset == 0 || - (lbn + 1) * NFS_DIRBLKSIZ < np->n_direofoffset) && - !(np->n_flag & NQNFSNONCACHE) && - !incore(vp, lbn + 1)) { - rabp = nfs_getcacheblk(vp, lbn + 1, NFS_DIRBLKSIZ, td); - if (rabp) { - if ((rabp->b_flags & (B_CACHE|B_DELWRI)) == 0) { - rabp->b_flags |= B_ASYNC; - rabp->b_iocmd = BIO_READ; - vfs_busy_pages(rabp, 0); - if (nfs_asyncio(rabp, cred, td)) { - rabp->b_flags |= B_INVAL; - rabp->b_ioflags |= BIO_ERROR; - vfs_unbusy_pages(rabp); - brelse(rabp); - } - } else { - brelse(rabp); - } - } - } - /* - * Unlike VREG files, whos buffer size ( bp->b_bcount ) is - * chopped for the EOF condition, we cannot tell how large - * NFS directories are going to be until we hit EOF. So - * an NFS directory buffer is *not* chopped to its EOF. Now, - * it just so happens that b_resid will effectively chop it - * to EOF. *BUT* this information is lost if the buffer goes - * away and is reconstituted into a B_CACHE state ( due to - * being VMIO ) later. So we keep track of the directory eof - * in np->n_direofoffset and chop it off as an extra step - * right here. - */ - n = lmin(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid - on); - if (np->n_direofoffset && n > np->n_direofoffset - uio->uio_offset) - n = np->n_direofoffset - uio->uio_offset; - break; - default: - printf(" nfs_bioread: type %x unexpected\n",vp->v_type); - break; - }; - - if (n > 0) { - error = uiomove(bp->b_data + on, (int)n, uio); - } - switch (vp->v_type) { - case VREG: - break; - case VLNK: - n = 0; - break; - case VDIR: - /* - * Invalidate buffer if caching is disabled, forcing a - * re-read from the remote later. - */ - if (np->n_flag & NQNFSNONCACHE) - bp->b_flags |= B_INVAL; - break; - default: - printf(" nfs_bioread: type %x unexpected\n",vp->v_type); - } - brelse(bp); - } while (error == 0 && uio->uio_resid > 0 && n > 0); - return (error); -} - -/* - * Vnode op for write using bio - */ -int -nfs_write(ap) - struct vop_write_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; - } */ *ap; -{ - int biosize; - struct uio *uio = ap->a_uio; - struct thread *td = uio->uio_td; - struct vnode *vp = ap->a_vp; - struct nfsnode *np = VTONFS(vp); - struct ucred *cred = ap->a_cred; - int ioflag = ap->a_ioflag; - struct buf *bp; - struct vattr vattr; - struct nfsmount *nmp = VFSTONFS(vp->v_mount); - daddr_t lbn; - int bcount; - int n, on, error = 0, iomode, must_commit; - int haverslock = 0; - struct proc *p = td?td->td_proc:NULL; - - GIANT_REQUIRED; - -#ifdef DIAGNOSTIC - if (uio->uio_rw != UIO_WRITE) - panic("nfs_write mode"); - if (uio->uio_segflg == UIO_USERSPACE && uio->uio_td != curthread) - panic("nfs_write proc"); -#endif - if (vp->v_type != VREG) - return (EIO); - if (np->n_flag & NWRITEERR) { - np->n_flag &= ~NWRITEERR; - return (np->n_error); - } - if ((nmp->nm_flag & NFSMNT_NFSV3) != 0 && - (nmp->nm_state & NFSSTA_GOTFSINFO) == 0) - (void)nfs_fsinfo(nmp, vp, cred, td); - - /* - * Synchronously flush pending buffers if we are in synchronous - * mode or if we are appending. - */ - if (ioflag & (IO_APPEND | IO_SYNC)) { - if (np->n_flag & NMODIFIED) { - np->n_attrstamp = 0; - error = nfs_vinvalbuf(vp, V_SAVE, cred, td, 1); - if (error) - return (error); - } - } - - /* - * If IO_APPEND then load uio_offset. We restart here if we cannot - * get the append lock. - */ -restart: - if (ioflag & IO_APPEND) { - np->n_attrstamp = 0; - error = VOP_GETATTR(vp, &vattr, cred, td); - if (error) - return (error); - uio->uio_offset = np->n_size; - } - - if (uio->uio_offset < 0) - return (EINVAL); - if ((uio->uio_offset + uio->uio_resid) > nmp->nm_maxfilesize) - return (EFBIG); - if (uio->uio_resid == 0) - return (0); - - /* - * We need to obtain the rslock if we intend to modify np->n_size - * in order to guarentee the append point with multiple contending - * writers, to guarentee that no other appenders modify n_size - * while we are trying to obtain a truncated buffer (i.e. to avoid - * accidently truncating data written by another appender due to - * the race), and to ensure that the buffer is populated prior to - * our extending of the file. We hold rslock through the entire - * operation. - * - * Note that we do not synchronize the case where someone truncates - * the file while we are appending to it because attempting to lock - * this case may deadlock other parts of the system unexpectedly. - */ - if ((ioflag & IO_APPEND) || - uio->uio_offset + uio->uio_resid > np->n_size) { - switch(nfs_rslock(np, td)) { - case ENOLCK: - goto restart; - /* not reached */ - case EINTR: - case ERESTART: - return(EINTR); - /* not reached */ - default: - break; - } - haverslock = 1; - } - - /* - * Maybe this should be above the vnode op call, but so long as - * file servers have no limits, i don't think it matters - */ - if (p && uio->uio_offset + uio->uio_resid > - p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { - PROC_LOCK(p); - psignal(p, SIGXFSZ); - PROC_UNLOCK(p); - if (haverslock) - nfs_rsunlock(np, td); - return (EFBIG); - } - - biosize = vp->v_mount->mnt_stat.f_iosize; - - do { - /* - * Check for a valid write lease. - */ - if ((nmp->nm_flag & NFSMNT_NQNFS) && - NQNFS_CKINVALID(vp, np, ND_WRITE)) { - do { - error = nqnfs_getlease(vp, ND_WRITE, cred, td); - } while (error == NQNFS_EXPIRED); - if (error) - break; - if (np->n_lrev != np->n_brev || - (np->n_flag & NQNFSNONCACHE)) { - error = nfs_vinvalbuf(vp, V_SAVE, cred, td, 1); - if (error) - break; - np->n_brev = np->n_lrev; - } - } - if ((np->n_flag & NQNFSNONCACHE) && uio->uio_iovcnt == 1) { - iomode = NFSV3WRITE_FILESYNC; - error = nfs_writerpc(vp, uio, cred, &iomode, &must_commit); - if (must_commit) - nfs_clearcommit(vp->v_mount); - break; - } - nfsstats.biocache_writes++; - lbn = uio->uio_offset / biosize; - on = uio->uio_offset & (biosize-1); - n = min((unsigned)(biosize - on), uio->uio_resid); -again: - /* - * Handle direct append and file extension cases, calculate - * unaligned buffer size. - */ - - if (uio->uio_offset == np->n_size && n) { - /* - * Get the buffer (in its pre-append state to maintain - * B_CACHE if it was previously set). Resize the - * nfsnode after we have locked the buffer to prevent - * readers from reading garbage. - */ - bcount = on; - bp = nfs_getcacheblk(vp, lbn, bcount, td); - - if (bp != NULL) { - long save; - - np->n_size = uio->uio_offset + n; - np->n_flag |= NMODIFIED; - vnode_pager_setsize(vp, np->n_size); - - save = bp->b_flags & B_CACHE; - bcount += n; - allocbuf(bp, bcount); - bp->b_flags |= save; - bp->b_magic = B_MAGIC_NFS; - bp->b_op = &buf_ops_nfs; - } - } else { - /* - * Obtain the locked cache block first, and then - * adjust the file's size as appropriate. - */ - bcount = on + n; - if ((off_t)lbn * biosize + bcount < np->n_size) { - if ((off_t)(lbn + 1) * biosize < np->n_size) - bcount = biosize; - else - bcount = np->n_size - (off_t)lbn * biosize; - } - - bp = nfs_getcacheblk(vp, lbn, bcount, td); - - if (uio->uio_offset + n > np->n_size) { - np->n_size = uio->uio_offset + n; - np->n_flag |= NMODIFIED; - vnode_pager_setsize(vp, np->n_size); - } - } - - if (!bp) { - error = EINTR; - break; - } - - /* - * Issue a READ if B_CACHE is not set. In special-append - * mode, B_CACHE is based on the buffer prior to the write - * op and is typically set, avoiding the read. If a read - * is required in special append mode, the server will - * probably send us a short-read since we extended the file - * on our end, resulting in b_resid == 0 and, thusly, - * B_CACHE getting set. - * - * We can also avoid issuing the read if the write covers - * the entire buffer. We have to make sure the buffer state - * is reasonable in this case since we will not be initiating - * I/O. See the comments in kern/vfs_bio.c's getblk() for - * more information. - * - * B_CACHE may also be set due to the buffer being cached - * normally. - */ - - if (on == 0 && n == bcount) { - bp->b_flags |= B_CACHE; - bp->b_flags &= ~B_INVAL; - bp->b_ioflags &= ~BIO_ERROR; - } - - if ((bp->b_flags & B_CACHE) == 0) { - bp->b_iocmd = BIO_READ; - vfs_busy_pages(bp, 0); - error = nfs_doio(bp, cred, td); - if (error) { - brelse(bp); - break; - } - } - if (!bp) { - error = EINTR; - break; - } - if (bp->b_wcred == NOCRED) { - crhold(cred); - bp->b_wcred = cred; - } - np->n_flag |= NMODIFIED; - - /* - * If dirtyend exceeds file size, chop it down. This should - * not normally occur but there is an append race where it - * might occur XXX, so we log it. - * - * If the chopping creates a reverse-indexed or degenerate - * situation with dirtyoff/end, we 0 both of them. - */ - - if (bp->b_dirtyend > bcount) { - printf("NFS append race @%lx:%d\n", - (long)bp->b_blkno * DEV_BSIZE, - bp->b_dirtyend - bcount); - bp->b_dirtyend = bcount; - } - - if (bp->b_dirtyoff >= bp->b_dirtyend) - bp->b_dirtyoff = bp->b_dirtyend = 0; - - /* - * If the new write will leave a contiguous dirty - * area, just update the b_dirtyoff and b_dirtyend, - * otherwise force a write rpc of the old dirty area. - * - * While it is possible to merge discontiguous writes due to - * our having a B_CACHE buffer ( and thus valid read data - * for the hole), we don't because it could lead to - * significant cache coherency problems with multiple clients, - * especially if locking is implemented later on. - * - * as an optimization we could theoretically maintain - * a linked list of discontinuous areas, but we would still - * have to commit them separately so there isn't much - * advantage to it except perhaps a bit of asynchronization. - */ - - if (bp->b_dirtyend > 0 && - (on > bp->b_dirtyend || (on + n) < bp->b_dirtyoff)) { - if (BUF_WRITE(bp) == EINTR) - return (EINTR); - goto again; - } - - /* - * Check for valid write lease and get one as required. - * In case getblk() and/or bwrite() delayed us. - */ - if ((nmp->nm_flag & NFSMNT_NQNFS) && - NQNFS_CKINVALID(vp, np, ND_WRITE)) { - do { - error = nqnfs_getlease(vp, ND_WRITE, cred, td); - } while (error == NQNFS_EXPIRED); - if (error) { - brelse(bp); - break; - } - if (np->n_lrev != np->n_brev || - (np->n_flag & NQNFSNONCACHE)) { - brelse(bp); - error = nfs_vinvalbuf(vp, V_SAVE, cred, td, 1); - if (error) - break; - np->n_brev = np->n_lrev; - goto again; - } - } - - error = uiomove((char *)bp->b_data + on, n, uio); - - /* - * Since this block is being modified, it must be written - * again and not just committed. Since write clustering does - * not work for the stage 1 data write, only the stage 2 - * commit rpc, we have to clear B_CLUSTEROK as well. - */ - bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); - - if (error) { - bp->b_ioflags |= BIO_ERROR; - brelse(bp); - break; - } - - /* - * Only update dirtyoff/dirtyend if not a degenerate - * condition. - */ - if (n) { - if (bp->b_dirtyend > 0) { - bp->b_dirtyoff = min(on, bp->b_dirtyoff); - bp->b_dirtyend = max((on + n), bp->b_dirtyend); - } else { - bp->b_dirtyoff = on; - bp->b_dirtyend = on + n; - } - vfs_bio_set_validclean(bp, on, n); - } - - /* - * If the lease is non-cachable or IO_SYNC do bwrite(). - * - * IO_INVAL appears to be unused. The idea appears to be - * to turn off caching in this case. Very odd. XXX - */ - if ((np->n_flag & NQNFSNONCACHE) || (ioflag & IO_SYNC)) { - if (ioflag & IO_INVAL) - bp->b_flags |= B_NOCACHE; - error = BUF_WRITE(bp); - if (error) - break; - if (np->n_flag & NQNFSNONCACHE) { - error = nfs_vinvalbuf(vp, V_SAVE, cred, td, 1); - if (error) - break; - } - } else if ((n + on) == biosize && - (nmp->nm_flag & NFSMNT_NQNFS) == 0) { - bp->b_flags |= B_ASYNC; - (void)nfs_writebp(bp, 0, 0); - } else { - bdwrite(bp); - } - } while (uio->uio_resid > 0 && n > 0); - - if (haverslock) - nfs_rsunlock(np, td); - - return (error); -} - -/* - * Get an nfs cache block. - * - * Allocate a new one if the block isn't currently in the cache - * and return the block marked busy. If the calling process is - * interrupted by a signal for an interruptible mount point, return - * NULL. - * - * The caller must carefully deal with the possible B_INVAL state of - * the buffer. nfs_doio() clears B_INVAL (and nfs_asyncio() clears it - * indirectly), so synchronous reads can be issued without worrying about - * the B_INVAL state. We have to be a little more careful when dealing - * with writes (see comments in nfs_write()) when extending a file past - * its EOF. - */ -static struct buf * -nfs_getcacheblk(vp, bn, size, td) - struct vnode *vp; - daddr_t bn; - int size; - struct thread *td; -{ - register struct buf *bp; - struct mount *mp; - struct nfsmount *nmp; - - mp = vp->v_mount; - nmp = VFSTONFS(mp); - - if (nmp->nm_flag & NFSMNT_INT) { - bp = getblk(vp, bn, size, PCATCH, 0); - while (bp == (struct buf *)0) { - if (nfs_sigintr(nmp, (struct nfsreq *)0, td->td_proc)) - return ((struct buf *)0); - bp = getblk(vp, bn, size, 0, 2 * hz); - } - } else { - bp = getblk(vp, bn, size, 0, 0); - } - - if (vp->v_type == VREG) { - int biosize; - - biosize = mp->mnt_stat.f_iosize; - bp->b_blkno = bn * (biosize / DEV_BSIZE); - } - return (bp); -} - -/* - * Flush and invalidate all dirty buffers. If another process is already - * doing the flush, just wait for completion. - */ -int -nfs_vinvalbuf(vp, flags, cred, td, intrflg) - struct vnode *vp; - int flags; - struct ucred *cred; - struct thread *td; - int intrflg; -{ - register struct nfsnode *np = VTONFS(vp); - struct nfsmount *nmp = VFSTONFS(vp->v_mount); - int error = 0, slpflag, slptimeo; - - if (vp->v_flag & VXLOCK) { - return (0); - } - - if ((nmp->nm_flag & NFSMNT_INT) == 0) - intrflg = 0; - if (intrflg) { - slpflag = PCATCH; - slptimeo = 2 * hz; - } else { - slpflag = 0; - slptimeo = 0; - } - /* - * First wait for any other process doing a flush to complete. - */ - while (np->n_flag & NFLUSHINPROG) { - np->n_flag |= NFLUSHWANT; - error = tsleep((caddr_t)&np->n_flag, PRIBIO + 2, "nfsvinval", - slptimeo); - if (error && intrflg && nfs_sigintr(nmp, (struct nfsreq *)0, td->td_proc)) - return (EINTR); - } - - /* - * Now, flush as required. - */ - np->n_flag |= NFLUSHINPROG; - error = vinvalbuf(vp, flags, cred, td, slpflag, 0); - while (error) { - if (intrflg && nfs_sigintr(nmp, (struct nfsreq *)0, td->td_proc)) { - np->n_flag &= ~NFLUSHINPROG; - if (np->n_flag & NFLUSHWANT) { - np->n_flag &= ~NFLUSHWANT; - wakeup((caddr_t)&np->n_flag); - } - return (EINTR); - } - error = vinvalbuf(vp, flags, cred, td, 0, slptimeo); - } - np->n_flag &= ~(NMODIFIED | NFLUSHINPROG); - if (np->n_flag & NFLUSHWANT) { - np->n_flag &= ~NFLUSHWANT; - wakeup((caddr_t)&np->n_flag); - } - return (0); -} - -/* - * Initiate asynchronous I/O. Return an error if no nfsiods are available. - * This is mainly to avoid queueing async I/O requests when the nfsiods - * are all hung on a dead server. - * - * Note: nfs_asyncio() does not clear (BIO_ERROR|B_INVAL) but when the bp - * is eventually dequeued by the async daemon, nfs_doio() *will*. - */ -int -nfs_asyncio(bp, cred, td) - register struct buf *bp; - struct ucred *cred; - struct thread *td; -{ - struct nfsmount *nmp; - int i; - int gotiod; - int slpflag = 0; - int slptimeo = 0; - int error; - - /* - * If no async daemons then return EIO to force caller to run the rpc - * synchronously. - */ - if (nfs_numasync == 0) - return (EIO); - - nmp = VFSTONFS(bp->b_vp->v_mount); - - /* - * Commits are usually short and sweet so lets save some cpu and - * leave the async daemons for more important rpc's (such as reads - * and writes). - */ - if (bp->b_iocmd == BIO_WRITE && (bp->b_flags & B_NEEDCOMMIT) && - (nmp->nm_bufqiods > nfs_numasync / 2)) { - return(EIO); - } - -again: - if (nmp->nm_flag & NFSMNT_INT) - slpflag = PCATCH; - gotiod = FALSE; - - /* - * Find a free iod to process this request. - */ - for (i = 0; i < NFS_MAXASYNCDAEMON; i++) - if (nfs_iodwant[i]) { - /* - * Found one, so wake it up and tell it which - * mount to process. - */ - NFS_DPF(ASYNCIO, - ("nfs_asyncio: waking iod %d for mount %p\n", - i, nmp)); - nfs_iodwant[i] = (struct proc *)0; - nfs_iodmount[i] = nmp; - nmp->nm_bufqiods++; - wakeup((caddr_t)&nfs_iodwant[i]); - gotiod = TRUE; - break; - } - - /* - * If none are free, we may already have an iod working on this mount - * point. If so, it will process our request. - */ - if (!gotiod) { - if (nmp->nm_bufqiods > 0) { - NFS_DPF(ASYNCIO, - ("nfs_asyncio: %d iods are already processing mount %p\n", - nmp->nm_bufqiods, nmp)); - gotiod = TRUE; - } - } - - /* - * If we have an iod which can process the request, then queue - * the buffer. - */ - if (gotiod) { - /* - * Ensure that the queue never grows too large. We still want - * to asynchronize so we block rather then return EIO. - */ - while (nmp->nm_bufqlen >= 2*nfs_numasync) { - NFS_DPF(ASYNCIO, - ("nfs_asyncio: waiting for mount %p queue to drain\n", nmp)); - nmp->nm_bufqwant = TRUE; - error = tsleep(&nmp->nm_bufq, slpflag | PRIBIO, - "nfsaio", slptimeo); - if (error) { - if (nfs_sigintr(nmp, NULL, td ? td->td_proc : NULL)) - return (EINTR); - if (slpflag == PCATCH) { - slpflag = 0; - slptimeo = 2 * hz; - } - } - /* - * We might have lost our iod while sleeping, - * so check and loop if nescessary. - */ - if (nmp->nm_bufqiods == 0) { - NFS_DPF(ASYNCIO, - ("nfs_asyncio: no iods after mount %p queue was drained, looping\n", nmp)); - goto again; - } - } - - if (bp->b_iocmd == BIO_READ) { - if (bp->b_rcred == NOCRED && cred != NOCRED) { - crhold(cred); - bp->b_rcred = cred; - } - } else { - bp->b_flags |= B_WRITEINPROG; - if (bp->b_wcred == NOCRED && cred != NOCRED) { - crhold(cred); - bp->b_wcred = cred; - } - } - - BUF_KERNPROC(bp); - TAILQ_INSERT_TAIL(&nmp->nm_bufq, bp, b_freelist); - nmp->nm_bufqlen++; - return (0); - } - - /* - * All the iods are busy on other mounts, so return EIO to - * force the caller to process the i/o synchronously. - */ - NFS_DPF(ASYNCIO, ("nfs_asyncio: no iods available, i/o is synchronous\n")); - return (EIO); -} - -/* - * Do an I/O operation to/from a cache block. This may be called - * synchronously or from an nfsiod. - */ -int -nfs_doio(bp, cr, td) - struct buf *bp; - struct ucred *cr; - struct thread *td; -{ - struct uio *uiop; - struct vnode *vp; - struct nfsnode *np; - struct nfsmount *nmp; - int error = 0, iomode, must_commit = 0; - struct uio uio; - struct iovec io; - struct proc *p = td?td->td_proc:NULL; - - vp = bp->b_vp; - np = VTONFS(vp); - nmp = VFSTONFS(vp->v_mount); - uiop = &uio; - uiop->uio_iov = &io; - uiop->uio_iovcnt = 1; - uiop->uio_segflg = UIO_SYSSPACE; - uiop->uio_td = td; - - /* - * clear BIO_ERROR and B_INVAL state prior to initiating the I/O. We - * do this here so we do not have to do it in all the code that - * calls us. - */ - bp->b_flags &= ~B_INVAL; - bp->b_ioflags &= ~BIO_ERROR; - - KASSERT(!(bp->b_flags & B_DONE), ("nfs_doio: bp %p already marked done", bp)); - - /* - * Historically, paging was done with physio, but no more. - */ - if (bp->b_flags & B_PHYS) { - /* - * ...though reading /dev/drum still gets us here. - */ - io.iov_len = uiop->uio_resid = bp->b_bcount; - /* mapping was done by vmapbuf() */ - io.iov_base = bp->b_data; - uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE; - if (bp->b_iocmd == BIO_READ) { - uiop->uio_rw = UIO_READ; - nfsstats.read_physios++; - error = nfs_readrpc(vp, uiop, cr); - } else { - int com; - - iomode = NFSV3WRITE_DATASYNC; - uiop->uio_rw = UIO_WRITE; - nfsstats.write_physios++; - error = nfs_writerpc(vp, uiop, cr, &iomode, &com); - } - if (error) { - bp->b_ioflags |= BIO_ERROR; - bp->b_error = error; - } - } else if (bp->b_iocmd == BIO_READ) { - io.iov_len = uiop->uio_resid = bp->b_bcount; - io.iov_base = bp->b_data; - uiop->uio_rw = UIO_READ; - switch (vp->v_type) { - case VREG: - uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE; - nfsstats.read_bios++; - error = nfs_readrpc(vp, uiop, cr); - if (!error) { - if (uiop->uio_resid) { - /* - * If we had a short read with no error, we must have - * hit a file hole. We should zero-fill the remainder. - * This can also occur if the server hits the file EOF. - * - * Holes used to be able to occur due to pending - * writes, but that is not possible any longer. - */ - int nread = bp->b_bcount - uiop->uio_resid; - int left = bp->b_bcount - nread; - - if (left > 0) - bzero((char *)bp->b_data + nread, left); - uiop->uio_resid = 0; - } - } - if (p && (vp->v_flag & VTEXT) && - (((nmp->nm_flag & NFSMNT_NQNFS) && - NQNFS_CKINVALID(vp, np, ND_READ) && - np->n_lrev != np->n_brev) || - (!(nmp->nm_flag & NFSMNT_NQNFS) && - np->n_mtime != np->n_vattr.va_mtime.tv_sec))) { - uprintf("Process killed due to text file modification\n"); - PROC_LOCK(p); - psignal(p, SIGKILL); - _PHOLD(p); - PROC_UNLOCK(p); - } - break; - case VLNK: - uiop->uio_offset = (off_t)0; - nfsstats.readlink_bios++; - error = nfs_readlinkrpc(vp, uiop, cr); - break; - case VDIR: - nfsstats.readdir_bios++; - uiop->uio_offset = ((u_quad_t)bp->b_lblkno) * NFS_DIRBLKSIZ; - if (nmp->nm_flag & NFSMNT_RDIRPLUS) { - error = nfs_readdirplusrpc(vp, uiop, cr); - if (error == NFSERR_NOTSUPP) - nmp->nm_flag &= ~NFSMNT_RDIRPLUS; - } - if ((nmp->nm_flag & NFSMNT_RDIRPLUS) == 0) - error = nfs_readdirrpc(vp, uiop, cr); - /* - * end-of-directory sets B_INVAL but does not generate an - * error. - */ - if (error == 0 && uiop->uio_resid == bp->b_bcount) - bp->b_flags |= B_INVAL; - break; - default: - printf("nfs_doio: type %x unexpected\n",vp->v_type); - break; - }; - if (error) { - bp->b_ioflags |= BIO_ERROR; - bp->b_error = error; - } - } else { - /* - * If we only need to commit, try to commit - */ - if (bp->b_flags & B_NEEDCOMMIT) { - int retv; - off_t off; - - off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff; - bp->b_flags |= B_WRITEINPROG; - retv = nfs_commit( - bp->b_vp, off, bp->b_dirtyend-bp->b_dirtyoff, - bp->b_wcred, td); - bp->b_flags &= ~B_WRITEINPROG; - if (retv == 0) { - bp->b_dirtyoff = bp->b_dirtyend = 0; - bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); - bp->b_resid = 0; - bufdone(bp); - return (0); - } - if (retv == NFSERR_STALEWRITEVERF) { - nfs_clearcommit(bp->b_vp->v_mount); - } - } - - /* - * Setup for actual write - */ - - if ((off_t)bp->b_blkno * DEV_BSIZE + bp->b_dirtyend > np->n_size) - bp->b_dirtyend = np->n_size - (off_t)bp->b_blkno * DEV_BSIZE; - - if (bp->b_dirtyend > bp->b_dirtyoff) { - io.iov_len = uiop->uio_resid = bp->b_dirtyend - - bp->b_dirtyoff; - uiop->uio_offset = (off_t)bp->b_blkno * DEV_BSIZE - + bp->b_dirtyoff; - io.iov_base = (char *)bp->b_data + bp->b_dirtyoff; - uiop->uio_rw = UIO_WRITE; - nfsstats.write_bios++; - - if ((bp->b_flags & (B_ASYNC | B_NEEDCOMMIT | B_NOCACHE | B_CLUSTER)) == B_ASYNC) - iomode = NFSV3WRITE_UNSTABLE; - else - iomode = NFSV3WRITE_FILESYNC; - - bp->b_flags |= B_WRITEINPROG; - error = nfs_writerpc(vp, uiop, cr, &iomode, &must_commit); - - /* - * When setting B_NEEDCOMMIT also set B_CLUSTEROK to try - * to cluster the buffers needing commit. This will allow - * the system to submit a single commit rpc for the whole - * cluster. We can do this even if the buffer is not 100% - * dirty (relative to the NFS blocksize), so we optimize the - * append-to-file-case. - * - * (when clearing B_NEEDCOMMIT, B_CLUSTEROK must also be - * cleared because write clustering only works for commit - * rpc's, not for the data portion of the write). - */ - - if (!error && iomode == NFSV3WRITE_UNSTABLE) { - bp->b_flags |= B_NEEDCOMMIT; - if (bp->b_dirtyoff == 0 - && bp->b_dirtyend == bp->b_bcount) - bp->b_flags |= B_CLUSTEROK; - } else { - bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); - } - bp->b_flags &= ~B_WRITEINPROG; - - /* - * For an interrupted write, the buffer is still valid - * and the write hasn't been pushed to the server yet, - * so we can't set BIO_ERROR and report the interruption - * by setting B_EINTR. For the B_ASYNC case, B_EINTR - * is not relevant, so the rpc attempt is essentially - * a noop. For the case of a V3 write rpc not being - * committed to stable storage, the block is still - * dirty and requires either a commit rpc or another - * write rpc with iomode == NFSV3WRITE_FILESYNC before - * the block is reused. This is indicated by setting - * the B_DELWRI and B_NEEDCOMMIT flags. - * - * If the buffer is marked B_PAGING, it does not reside on - * the vp's paging queues so we cannot call bdirty(). The - * bp in this case is not an NFS cache block so we should - * be safe. XXX - */ - if (error == EINTR - || (!error && (bp->b_flags & B_NEEDCOMMIT))) { - int s; - - s = splbio(); - bp->b_flags &= ~(B_INVAL|B_NOCACHE); - if ((bp->b_flags & B_PAGING) == 0) { - bdirty(bp); - bp->b_flags &= ~B_DONE; - } - if (error && (bp->b_flags & B_ASYNC) == 0) - bp->b_flags |= B_EINTR; - splx(s); - } else { - if (error) { - bp->b_ioflags |= BIO_ERROR; - bp->b_error = np->n_error = error; - np->n_flag |= NWRITEERR; - } - bp->b_dirtyoff = bp->b_dirtyend = 0; - } - } else { - bp->b_resid = 0; - bufdone(bp); - return (0); - } - } - bp->b_resid = uiop->uio_resid; - if (must_commit) - nfs_clearcommit(vp->v_mount); - bufdone(bp); - return (error); -} diff --git a/sys/nfs/nfs_common.c b/sys/nfs/nfs_common.c index 4425129..d51edc5 100644 --- a/sys/nfs/nfs_common.c +++ b/sys/nfs/nfs_common.c @@ -34,14 +34,17 @@ * SUCH DAMAGE. * * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 - * $FreeBSD$ */ +#include +__FBSDID("$FreeBSD$"); + /* * These functions support the macros and help fiddle mbuf chains for * the nfs op functions. They do things like create the rpc header and * copy data between mbuf chains and uio lists. */ + #include #include #include @@ -65,729 +68,37 @@ #include #include -#include -#include +#include #include -#include -#include -#include -#include +#include #include -/* - * Data items converted to xdr at startup, since they are constant - * This is kinda hokey, but may save a little time doing byte swaps - */ -u_int32_t nfs_xdrneg1; -u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, - rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, - rpc_auth_kerb; -u_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false; - -/* And other global data */ -static u_int32_t nfs_xid = 0; -static enum vtype nv2tov_type[8]= { - VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON -}; enum vtype nv3tov_type[8]= { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; - -int nfs_ticks; -int nfs_pbuf_freecnt = -1; /* start out unlimited */ - -struct nfs_reqq nfs_reqq; -struct nfssvc_sockhead nfssvc_sockhead; -int nfssvc_sockhead_flag; -struct nfsd_head nfsd_head; -int nfsd_head_flag; -struct nfs_bufq nfs_bufq; -struct nqtimerhead nqtimerhead; -struct nqfhhashhead *nqfhhashtbl; -u_long nqfhhash; - -static void (*nfs_prev_lease_updatetime) __P((int)); -static int nfs_prev_nfssvc_sy_narg; -static sy_call_t *nfs_prev_nfssvc_sy_call; - -#ifndef NFS_NOSERVER - -static vop_t *nfs_prev_vop_lease_check; - -/* - * Mapping of old NFS Version 2 RPC numbers to generic numbers. - */ -int nfsv3_procid[NFS_NPROCS] = { - NFSPROC_NULL, - NFSPROC_GETATTR, - NFSPROC_SETATTR, - NFSPROC_NOOP, - NFSPROC_LOOKUP, - NFSPROC_READLINK, - NFSPROC_READ, - NFSPROC_NOOP, - NFSPROC_WRITE, - NFSPROC_CREATE, - NFSPROC_REMOVE, - NFSPROC_RENAME, - NFSPROC_LINK, - NFSPROC_SYMLINK, - NFSPROC_MKDIR, - NFSPROC_RMDIR, - NFSPROC_READDIR, - NFSPROC_FSSTAT, - NFSPROC_NOOP, - NFSPROC_NOOP, - NFSPROC_NOOP, - NFSPROC_NOOP, - NFSPROC_NOOP, - NFSPROC_NOOP, - NFSPROC_NOOP, - NFSPROC_NOOP -}; - -#endif /* NFS_NOSERVER */ -/* - * and the reverse mapping from generic to Version 2 procedure numbers - */ -int nfsv2_procid[NFS_NPROCS] = { - NFSV2PROC_NULL, - NFSV2PROC_GETATTR, - NFSV2PROC_SETATTR, - NFSV2PROC_LOOKUP, - NFSV2PROC_NOOP, - NFSV2PROC_READLINK, - NFSV2PROC_READ, - NFSV2PROC_WRITE, - NFSV2PROC_CREATE, - NFSV2PROC_MKDIR, - NFSV2PROC_SYMLINK, - NFSV2PROC_CREATE, - NFSV2PROC_REMOVE, - NFSV2PROC_RMDIR, - NFSV2PROC_RENAME, - NFSV2PROC_LINK, - NFSV2PROC_READDIR, - NFSV2PROC_NOOP, - NFSV2PROC_STATFS, - NFSV2PROC_NOOP, - NFSV2PROC_NOOP, - NFSV2PROC_NOOP, - NFSV2PROC_NOOP, - NFSV2PROC_NOOP, - NFSV2PROC_NOOP, - NFSV2PROC_NOOP, -}; - -#ifndef NFS_NOSERVER -/* - * Maps errno values to nfs error numbers. - * Use NFSERR_IO as the catch all for ones not specifically defined in - * RFC 1094. - */ -static u_char nfsrv_v2errmap[ELAST] = { - NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, - NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, - NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO /* << Last is 86 */ -}; - -/* - * Maps errno values to nfs error numbers. - * Although it is not obvious whether or not NFS clients really care if - * a returned error value is in the specified list for the procedure, the - * safest thing to do is filter them appropriately. For Version 2, the - * X/Open XNFS document is the only specification that defines error values - * for each RPC (The RFC simply lists all possible error values for all RPCs), - * so I have decided to not do this for Version 2. - * The first entry is the default error return and the rest are the valid - * errors for that RPC in increasing numeric order. - */ -static short nfsv3err_null[] = { - 0, - 0, -}; - -static short nfsv3err_getattr[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_setattr[] = { - NFSERR_IO, - NFSERR_PERM, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_INVAL, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOT_SYNC, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_lookup[] = { - NFSERR_IO, - NFSERR_NOENT, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_NOTDIR, - NFSERR_NAMETOL, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_access[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_readlink[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_INVAL, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_read[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_NXIO, - NFSERR_ACCES, - NFSERR_INVAL, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_write[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_INVAL, - NFSERR_FBIG, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_create[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_EXIST, - NFSERR_NOTDIR, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_NAMETOL, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_mkdir[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_EXIST, - NFSERR_NOTDIR, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_NAMETOL, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_symlink[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_EXIST, - NFSERR_NOTDIR, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_NAMETOL, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_mknod[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_EXIST, - NFSERR_NOTDIR, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_NAMETOL, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - NFSERR_BADTYPE, - 0, -}; - -static short nfsv3err_remove[] = { - NFSERR_IO, - NFSERR_NOENT, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_NOTDIR, - NFSERR_ROFS, - NFSERR_NAMETOL, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_rmdir[] = { - NFSERR_IO, - NFSERR_NOENT, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_EXIST, - NFSERR_NOTDIR, - NFSERR_INVAL, - NFSERR_ROFS, - NFSERR_NAMETOL, - NFSERR_NOTEMPTY, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_rename[] = { - NFSERR_IO, - NFSERR_NOENT, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_EXIST, - NFSERR_XDEV, - NFSERR_NOTDIR, - NFSERR_ISDIR, - NFSERR_INVAL, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_MLINK, - NFSERR_NAMETOL, - NFSERR_NOTEMPTY, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_link[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_EXIST, - NFSERR_XDEV, - NFSERR_NOTDIR, - NFSERR_INVAL, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_MLINK, - NFSERR_NAMETOL, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_readdir[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_NOTDIR, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_BAD_COOKIE, - NFSERR_TOOSMALL, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_readdirplus[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_NOTDIR, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_BAD_COOKIE, - NFSERR_NOTSUPP, - NFSERR_TOOSMALL, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_fsstat[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_fsinfo[] = { - NFSERR_STALE, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, +nfstype nfsv3_type[9] = { + NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON }; -static short nfsv3err_pathconf[] = { - NFSERR_STALE, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_commit[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short *nfsrv_v3errmap[] = { - nfsv3err_null, - nfsv3err_getattr, - nfsv3err_setattr, - nfsv3err_lookup, - nfsv3err_access, - nfsv3err_readlink, - nfsv3err_read, - nfsv3err_write, - nfsv3err_create, - nfsv3err_mkdir, - nfsv3err_symlink, - nfsv3err_mknod, - nfsv3err_remove, - nfsv3err_rmdir, - nfsv3err_rename, - nfsv3err_link, - nfsv3err_readdir, - nfsv3err_readdirplus, - nfsv3err_fsstat, - nfsv3err_fsinfo, - nfsv3err_pathconf, - nfsv3err_commit, -}; - -#endif /* NFS_NOSERVER */ - -extern struct nfsrtt nfsrtt; -extern time_t nqnfsstarttime; -extern int nqsrv_clockskew; -extern int nqsrv_writeslack; -extern int nqsrv_maxlease; -extern struct nfsstats nfsstats; -extern int nqnfs_piggy[NFS_NPROCS]; -extern nfstype nfsv2_type[9]; -extern nfstype nfsv3_type[9]; -extern struct nfsnodehashhead *nfsnodehashtbl; -extern u_long nfsnodehash; - -struct nfssvc_args; -extern int nfssvc(struct thread *, struct nfssvc_args *, int *); - -LIST_HEAD(nfsnodehashhead, nfsnode); - -int nfs_webnamei __P((struct nameidata *, struct vnode *, struct thread *)); - u_quad_t -nfs_curusec() +nfs_curusec(void) { struct timeval tv; - + getmicrotime(&tv); return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec); } /* - * Create the header for an rpc request packet - * The hsiz is the size of the rest of the nfs request header. - * (just used to decide if a cluster is a good idea) - */ -struct mbuf * -nfsm_reqh(vp, procid, hsiz, bposp) - struct vnode *vp; - u_long procid; - int hsiz; - caddr_t *bposp; -{ - register struct mbuf *mb; - register u_int32_t *tl; - register caddr_t bpos; - struct mbuf *mb2; - struct nfsmount *nmp; - int nqflag; - - MGET(mb, M_TRYWAIT, MT_DATA); - if (hsiz >= MINCLSIZE) - MCLGET(mb, M_TRYWAIT); - mb->m_len = 0; - bpos = mtod(mb, caddr_t); - - /* - * For NQNFS, add lease request. - */ - if (vp) { - nmp = VFSTONFS(vp->v_mount); - if (nmp->nm_flag & NFSMNT_NQNFS) { - nqflag = NQNFS_NEEDLEASE(vp, procid); - if (nqflag) { - nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED); - *tl++ = txdr_unsigned(nqflag); - *tl = txdr_unsigned(nmp->nm_leaseterm); - } else { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); - *tl = 0; - } - } - } - /* Finally, return values */ - *bposp = bpos; - return (mb); -} - -/* - * Build the RPC header and fill in the authorization info. - * The authorization string argument is only used when the credentials - * come from outside of the kernel. - * Returns the head of the mbuf list. - */ -struct mbuf * -nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, - verf_str, mrest, mrest_len, mbp, xidp) - register struct ucred *cr; - int nmflag; - int procid; - int auth_type; - int auth_len; - char *auth_str; - int verf_len; - char *verf_str; - struct mbuf *mrest; - int mrest_len; - struct mbuf **mbp; - u_int32_t *xidp; -{ - register struct mbuf *mb; - register u_int32_t *tl; - register caddr_t bpos; - register int i; - struct mbuf *mreq, *mb2; - int siz, grpsiz, authsiz; - - authsiz = nfsm_rndup(auth_len); - MGETHDR(mb, M_TRYWAIT, MT_DATA); - if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { - MCLGET(mb, M_TRYWAIT); - } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { - MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); - } else { - MH_ALIGN(mb, 8 * NFSX_UNSIGNED); - } - mb->m_len = 0; - mreq = mb; - bpos = mtod(mb, caddr_t); - - /* - * First the RPC header. - */ - nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED); - - /* Get a pretty random xid to start with */ - if (!nfs_xid) - nfs_xid = random(); - /* - * Skip zero xid if it should ever happen. - */ - if (++nfs_xid == 0) - nfs_xid++; - - *tl++ = *xidp = txdr_unsigned(nfs_xid); - *tl++ = rpc_call; - *tl++ = rpc_vers; - if (nmflag & NFSMNT_NQNFS) { - *tl++ = txdr_unsigned(NQNFS_PROG); - *tl++ = txdr_unsigned(NQNFS_VER3); - } else { - *tl++ = txdr_unsigned(NFS_PROG); - if (nmflag & NFSMNT_NFSV3) - *tl++ = txdr_unsigned(NFS_VER3); - else - *tl++ = txdr_unsigned(NFS_VER2); - } - if (nmflag & NFSMNT_NFSV3) - *tl++ = txdr_unsigned(procid); - else - *tl++ = txdr_unsigned(nfsv2_procid[procid]); - - /* - * And then the authorization cred. - */ - *tl++ = txdr_unsigned(auth_type); - *tl = txdr_unsigned(authsiz); - switch (auth_type) { - case RPCAUTH_UNIX: - nfsm_build(tl, u_int32_t *, auth_len); - *tl++ = 0; /* stamp ?? */ - *tl++ = 0; /* NULL hostname */ - *tl++ = txdr_unsigned(cr->cr_uid); - *tl++ = txdr_unsigned(cr->cr_groups[0]); - grpsiz = (auth_len >> 2) - 5; - *tl++ = txdr_unsigned(grpsiz); - for (i = 1; i <= grpsiz; i++) - *tl++ = txdr_unsigned(cr->cr_groups[i]); - break; - case RPCAUTH_KERB4: - siz = auth_len; - while (siz > 0) { - if (M_TRAILINGSPACE(mb) == 0) { - MGET(mb2, M_TRYWAIT, MT_DATA); - if (siz >= MINCLSIZE) - MCLGET(mb2, M_TRYWAIT); - mb->m_next = mb2; - mb = mb2; - mb->m_len = 0; - bpos = mtod(mb, caddr_t); - } - i = min(siz, M_TRAILINGSPACE(mb)); - bcopy(auth_str, bpos, i); - mb->m_len += i; - auth_str += i; - bpos += i; - siz -= i; - } - if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { - for (i = 0; i < siz; i++) - *bpos++ = '\0'; - mb->m_len += siz; - } - break; - }; - - /* - * And the verifier... - */ - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - if (verf_str) { - *tl++ = txdr_unsigned(RPCAUTH_KERB4); - *tl = txdr_unsigned(verf_len); - siz = verf_len; - while (siz > 0) { - if (M_TRAILINGSPACE(mb) == 0) { - MGET(mb2, M_TRYWAIT, MT_DATA); - if (siz >= MINCLSIZE) - MCLGET(mb2, M_TRYWAIT); - mb->m_next = mb2; - mb = mb2; - mb->m_len = 0; - bpos = mtod(mb, caddr_t); - } - i = min(siz, M_TRAILINGSPACE(mb)); - bcopy(verf_str, bpos, i); - mb->m_len += i; - verf_str += i; - bpos += i; - siz -= i; - } - if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { - for (i = 0; i < siz; i++) - *bpos++ = '\0'; - mb->m_len += siz; - } - } else { - *tl++ = txdr_unsigned(RPCAUTH_NULL); - *tl = 0; - } - mb->m_next = mrest; - mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; - mreq->m_pkthdr.rcvif = (struct ifnet *)0; - *mbp = mb; - return (mreq); -} - -/* * copies mbuf chain to the uio scatter/gather list */ int -nfsm_mbuftouio(mrep, uiop, siz, dpos) - struct mbuf **mrep; - register struct uio *uiop; - int siz; - caddr_t *dpos; +nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos) { - register char *mbufcp, *uiocp; - register int xfer, left, len; - register struct mbuf *mp; + char *mbufcp, *uiocp; + int xfer, left, len; + struct mbuf *mp; long uiosiz, rem; int error = 0; @@ -851,106 +162,17 @@ nfsm_mbuftouio(mrep, uiop, siz, dpos) } /* - * copies a uio scatter/gather list to an mbuf chain. - * NOTE: can ony handle iovcnt == 1 - */ -int -nfsm_uiotombuf(uiop, mq, siz, bpos) - register struct uio *uiop; - struct mbuf **mq; - int siz; - caddr_t *bpos; -{ - register char *uiocp; - register struct mbuf *mp, *mp2; - register int xfer, left, mlen; - int uiosiz, clflg, rem; - char *cp; - -#ifdef DIAGNOSTIC - if (uiop->uio_iovcnt != 1) - panic("nfsm_uiotombuf: iovcnt != 1"); -#endif - - if (siz > MLEN) /* or should it >= MCLBYTES ?? */ - clflg = 1; - else - clflg = 0; - rem = nfsm_rndup(siz)-siz; - mp = mp2 = *mq; - while (siz > 0) { - left = uiop->uio_iov->iov_len; - uiocp = uiop->uio_iov->iov_base; - if (left > siz) - left = siz; - uiosiz = left; - while (left > 0) { - mlen = M_TRAILINGSPACE(mp); - if (mlen == 0) { - MGET(mp, M_TRYWAIT, MT_DATA); - if (clflg) - MCLGET(mp, M_TRYWAIT); - mp->m_len = 0; - mp2->m_next = mp; - mp2 = mp; - mlen = M_TRAILINGSPACE(mp); - } - xfer = (left > mlen) ? mlen : left; -#ifdef notdef - /* Not Yet.. */ - if (uiop->uio_iov->iov_op != NULL) - (*(uiop->uio_iov->iov_op)) - (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); - else -#endif - if (uiop->uio_segflg == UIO_SYSSPACE) - bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); - else - copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); - mp->m_len += xfer; - left -= xfer; - uiocp += xfer; - uiop->uio_offset += xfer; - uiop->uio_resid -= xfer; - } - uiop->uio_iov->iov_base += uiosiz; - uiop->uio_iov->iov_len -= uiosiz; - siz -= uiosiz; - } - if (rem > 0) { - if (rem > M_TRAILINGSPACE(mp)) { - MGET(mp, M_TRYWAIT, MT_DATA); - mp->m_len = 0; - mp2->m_next = mp; - } - cp = mtod(mp, caddr_t)+mp->m_len; - for (left = 0; left < rem; left++) - *cp++ = '\0'; - mp->m_len += rem; - *bpos = cp; - } else - *bpos = mtod(mp, caddr_t)+mp->m_len; - *mq = mp; - return (0); -} - -/* * Help break down an mbuf chain by setting the first siz bytes contiguous * pointed to by returned val. * This is used by the macros nfsm_dissect and nfsm_dissecton for tough * cases. (The macros use the vars. dpos and dpos2) */ int -nfsm_disct(mdp, dposp, siz, left, cp2) - struct mbuf **mdp; - caddr_t *dposp; - int siz; - int left; - caddr_t *cp2; +nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2) { - register struct mbuf *mp, *mp2; - register int siz2, xfer; - register caddr_t ptr; + struct mbuf *mp, *mp2; + int siz2, xfer; + caddr_t ptr; mp = *mdp; while (left == 0) { @@ -1004,14 +226,10 @@ nfsm_disct(mdp, dposp, siz, left, cp2) * Advance the position in the mbuf chain. */ int -nfs_adv(mdp, dposp, offs, left) - struct mbuf **mdp; - caddr_t *dposp; - int offs; - int left; +nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left) { - register struct mbuf *m; - register int s; + struct mbuf *m; + int s; m = *mdp; s = left; @@ -1027,1217 +245,70 @@ nfs_adv(mdp, dposp, offs, left) return (0); } -/* - * Copy a string into mbufs for the hard cases... - */ -int -nfsm_strtmbuf(mb, bpos, cp, siz) - struct mbuf **mb; - char **bpos; - const char *cp; - long siz; -{ - register struct mbuf *m1 = NULL, *m2; - long left, xfer, len, tlen; - u_int32_t *tl; - int putsize; - - putsize = 1; - m2 = *mb; - left = M_TRAILINGSPACE(m2); - if (left > 0) { - tl = ((u_int32_t *)(*bpos)); - *tl++ = txdr_unsigned(siz); - putsize = 0; - left -= NFSX_UNSIGNED; - m2->m_len += NFSX_UNSIGNED; - if (left > 0) { - bcopy(cp, (caddr_t) tl, left); - siz -= left; - cp += left; - m2->m_len += left; - left = 0; - } - } - /* Loop around adding mbufs */ - while (siz > 0) { - MGET(m1, M_TRYWAIT, MT_DATA); - if (siz > MLEN) - MCLGET(m1, M_TRYWAIT); - m1->m_len = NFSMSIZ(m1); - m2->m_next = m1; - m2 = m1; - tl = mtod(m1, u_int32_t *); - tlen = 0; - if (putsize) { - *tl++ = txdr_unsigned(siz); - m1->m_len -= NFSX_UNSIGNED; - tlen = NFSX_UNSIGNED; - putsize = 0; - } - if (siz < m1->m_len) { - len = nfsm_rndup(siz); - xfer = siz; - if (xfer < len) - *(tl+(xfer>>2)) = 0; - } else { - xfer = len = m1->m_len; - } - bcopy(cp, (caddr_t) tl, xfer); - m1->m_len = len+tlen; - siz -= xfer; - cp += xfer; - } - *mb = m1; - *bpos = mtod(m1, caddr_t)+m1->m_len; - return (0); -} - -/* - * Called once to initialize data structures... - */ -int -nfs_init(vfsp) - struct vfsconf *vfsp; -{ - register int i; - - nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1); - - nfs_mount_type = vfsp->vfc_typenum; - nfsrtt.pos = 0; - rpc_vers = txdr_unsigned(RPC_VER2); - rpc_call = txdr_unsigned(RPC_CALL); - rpc_reply = txdr_unsigned(RPC_REPLY); - rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); - rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); - rpc_mismatch = txdr_unsigned(RPC_MISMATCH); - rpc_autherr = txdr_unsigned(RPC_AUTHERR); - rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); - rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); - nfs_prog = txdr_unsigned(NFS_PROG); - nqnfs_prog = txdr_unsigned(NQNFS_PROG); - nfs_true = txdr_unsigned(TRUE); - nfs_false = txdr_unsigned(FALSE); - nfs_xdrneg1 = txdr_unsigned(-1); - nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; - if (nfs_ticks < 1) - nfs_ticks = 1; - /* Ensure async daemons disabled */ - for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { - nfs_iodwant[i] = (struct proc *)0; - nfs_iodmount[i] = (struct nfsmount *)0; - } - nfs_nhinit(); /* Init the nfsnode table */ -#ifndef NFS_NOSERVER - nfsrv_init(0); /* Init server data structures */ - nfsrv_initcache(); /* Init the server request cache */ -#endif - - /* - * Initialize the nqnfs server stuff. - */ - if (nqnfsstarttime == 0) { - nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease - + nqsrv_clockskew + nqsrv_writeslack; - NQLOADNOVRAM(nqnfsstarttime); - TAILQ_INIT(&nqtimerhead); - nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); - } - - /* - * Initialize reply list and start timer - */ - TAILQ_INIT(&nfs_reqq); - - nfs_timer(0); - - /* - * Set up lease_check and lease_updatetime so that other parts - * of the system can call us, if we are loadable. - */ -#ifndef NFS_NOSERVER - nfs_prev_vop_lease_check = default_vnodeop_p[VOFFSET(vop_lease)]; - default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check; -#endif - nfs_prev_lease_updatetime = lease_updatetime; - lease_updatetime = nfs_lease_updatetime; - nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg; - sysent[SYS_nfssvc].sy_narg = 2; - nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call; - sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc; - - nfs_pbuf_freecnt = nswbuf / 2 + 1; - - return (0); -} - -int -nfs_uninit(vfsp) - struct vfsconf *vfsp; -{ - - untimeout(nfs_timer, (void *)NULL, nfs_timer_handle); - nfs_mount_type = -1; -#ifndef NFS_NOSERVER - default_vnodeop_p[VOFFSET(vop_lease)] = nfs_prev_vop_lease_check; -#endif - lease_updatetime = nfs_prev_lease_updatetime; - sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg; - sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call; - return (0); -} - -/* - * Attribute cache routines. - * nfs_loadattrcache() - loads or updates the cache contents from attributes - * that are on the mbuf list - * nfs_getattrcache() - returns valid attributes if found in cache, returns - * error otherwise - */ - -/* - * Load the attribute cache (that lives in the nfsnode entry) with - * the values on the mbuf list and - * Iff vap not NULL - * copy the attributes to *vaper - */ -int -nfs_loadattrcache(vpp, mdp, dposp, vaper, dontshrink) - struct vnode **vpp; - struct mbuf **mdp; - caddr_t *dposp; - struct vattr *vaper; - int dontshrink; -{ - register struct vnode *vp = *vpp; - register struct vattr *vap; - register struct nfs_fattr *fp; - register struct nfsnode *np; - register int32_t t1; - caddr_t cp2; - int error = 0, rdev; - struct mbuf *md; - enum vtype vtyp; - u_short vmode; - struct timespec mtime; - int v3 = NFS_ISV3(vp); - - md = *mdp; - t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; - if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) != 0) - return (error); - fp = (struct nfs_fattr *)cp2; - if (v3) { - vtyp = nfsv3tov_type(fp->fa_type); - vmode = fxdr_unsigned(u_short, fp->fa_mode); - rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), - fxdr_unsigned(int, fp->fa3_rdev.specdata2)); - fxdr_nfsv3time(&fp->fa3_mtime, &mtime); - } else { - vtyp = nfsv2tov_type(fp->fa_type); - vmode = fxdr_unsigned(u_short, fp->fa_mode); - /* - * XXX - * - * The duplicate information returned in fa_type and fa_mode - * is an ambiguity in the NFS version 2 protocol. - * - * VREG should be taken literally as a regular file. If a - * server intents to return some type information differently - * in the upper bits of the mode field (e.g. for sockets, or - * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we - * leave the examination of the mode bits even in the VREG - * case to avoid breakage for bogus servers, but we make sure - * that there are actually type bits set in the upper part of - * fa_mode (and failing that, trust the va_type field). - * - * NFSv3 cleared the issue, and requires fa_mode to not - * contain any type information (while also introduing sockets - * and FIFOs for fa_type). - */ - if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) - vtyp = IFTOVT(vmode); - rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); - fxdr_nfsv2time(&fp->fa2_mtime, &mtime); - - /* - * Really ugly NFSv2 kludge. - */ - if (vtyp == VCHR && rdev == 0xffffffff) - vtyp = VFIFO; - } - - /* - * If v_type == VNON it is a new node, so fill in the v_type, - * n_mtime fields. Check to see if it represents a special - * device, and if so, check for a possible alias. Once the - * correct vnode has been obtained, fill in the rest of the - * information. - */ - np = VTONFS(vp); - if (vp->v_type != vtyp) { - vp->v_type = vtyp; - if (vp->v_type == VFIFO) { - vp->v_op = fifo_nfsv2nodeop_p; - } - if (vp->v_type == VCHR || vp->v_type == VBLK) { - vp->v_op = spec_nfsv2nodeop_p; - vp = addaliasu(vp, rdev); - np->n_vnode = vp; - } - np->n_mtime = mtime.tv_sec; - } - vap = &np->n_vattr; - vap->va_type = vtyp; - vap->va_mode = (vmode & 07777); - vap->va_rdev = rdev; - vap->va_mtime = mtime; - vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; - if (v3) { - vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); - vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); - vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); - vap->va_size = fxdr_hyper(&fp->fa3_size); - vap->va_blocksize = NFS_FABLKSIZE; - vap->va_bytes = fxdr_hyper(&fp->fa3_used); - vap->va_fileid = fxdr_unsigned(int32_t, - fp->fa3_fileid.nfsuquad[1]); - fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); - fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); - vap->va_flags = 0; - vap->va_filerev = 0; - } else { - vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); - vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); - vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); - vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); - vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); - vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) - * NFS_FABLKSIZE; - vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); - fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); - vap->va_flags = 0; - vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, - fp->fa2_ctime.nfsv2_sec); - vap->va_ctime.tv_nsec = 0; - vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); - vap->va_filerev = 0; - } - np->n_attrstamp = time_second; - if (vap->va_size != np->n_size) { - if (vap->va_type == VREG) { - if (dontshrink && vap->va_size < np->n_size) { - /* - * We've been told not to shrink the file; - * zero np->n_attrstamp to indicate that - * the attributes are stale. - */ - vap->va_size = np->n_size; - np->n_attrstamp = 0; - } else if (np->n_flag & NMODIFIED) { - if (vap->va_size < np->n_size) - vap->va_size = np->n_size; - else - np->n_size = vap->va_size; - } else { - np->n_size = vap->va_size; - } - vnode_pager_setsize(vp, np->n_size); - } else { - np->n_size = vap->va_size; - } - } - if (vaper != NULL) { - bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); - if (np->n_flag & NCHG) { - if (np->n_flag & NACC) - vaper->va_atime = np->n_atim; - if (np->n_flag & NUPD) - vaper->va_mtime = np->n_mtim; - } - } - return (0); -} - -#ifdef NFS_ACDEBUG -#include -SYSCTL_DECL(_vfs_nfs); -static int nfs_acdebug; -SYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); -#endif - -/* - * Check the time stamp - * If the cache is valid, copy contents to *vap and return 0 - * otherwise return an error - */ -int -nfs_getattrcache(vp, vaper) - register struct vnode *vp; - struct vattr *vaper; -{ - register struct nfsnode *np; - register struct vattr *vap; - struct nfsmount *nmp; - int timeo; - - np = VTONFS(vp); - vap = &np->n_vattr; - nmp = VFSTONFS(vp->v_mount); - /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ - timeo = (time_second - np->n_mtime) / 10; - -#ifdef NFS_ACDEBUG - if (nfs_acdebug>1) - printf("nfs_getattrcache: initial timeo = %d\n", timeo); -#endif - - if (vap->va_type == VDIR) { - if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) - timeo = nmp->nm_acdirmin; - else if (timeo > nmp->nm_acdirmax) - timeo = nmp->nm_acdirmax; - } else { - if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) - timeo = nmp->nm_acregmin; - else if (timeo > nmp->nm_acregmax) - timeo = nmp->nm_acregmax; - } - -#ifdef NFS_ACDEBUG - if (nfs_acdebug > 2) - printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", - nmp->nm_acregmin, nmp->nm_acregmax, - nmp->nm_acdirmin, nmp->nm_acdirmax); - - if (nfs_acdebug) - printf("nfs_getattrcache: age = %d; final timeo = %d\n", - (time_second - np->n_attrstamp), timeo); -#endif - - if ((time_second - np->n_attrstamp) >= timeo) { - nfsstats.attrcache_misses++; - return (ENOENT); - } - nfsstats.attrcache_hits++; - if (vap->va_size != np->n_size) { - if (vap->va_type == VREG) { - if (np->n_flag & NMODIFIED) { - if (vap->va_size < np->n_size) - vap->va_size = np->n_size; - else - np->n_size = vap->va_size; - } else { - np->n_size = vap->va_size; - } - vnode_pager_setsize(vp, np->n_size); - } else { - np->n_size = vap->va_size; - } - } - bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); - if (np->n_flag & NCHG) { - if (np->n_flag & NACC) - vaper->va_atime = np->n_atim; - if (np->n_flag & NUPD) - vaper->va_mtime = np->n_mtim; - } - return (0); -} - -#ifndef NFS_NOSERVER -/* - * Set up nameidata for a lookup() call and do it. - * - * If pubflag is set, this call is done for a lookup operation on the - * public filehandle. In that case we allow crossing mountpoints and - * absolute pathnames. However, the caller is expected to check that - * the lookup result is within the public fs, and deny access if - * it is not. - * - * nfs_namei() clears out garbage fields that namei() might leave garbage. - * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no - * error occurs but the parent was not requested. - * - * dirp may be set whether an error is returned or not, and must be - * released by the caller. - */ -int -nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, td, kerbflag, pubflag) - register struct nameidata *ndp; - fhandle_t *fhp; - int len; - struct nfssvc_sock *slp; - struct sockaddr *nam; - struct mbuf **mdp; - caddr_t *dposp; - struct vnode **retdirp; - struct thread *td; - int kerbflag, pubflag; -{ - register int i, rem; - register struct mbuf *md; - register char *fromcp, *tocp, *cp; - struct iovec aiov; - struct uio auio; - struct vnode *dp; - int error, rdonly, linklen; - struct componentname *cnp = &ndp->ni_cnd; - - *retdirp = (struct vnode *)0; - cnp->cn_pnbuf = zalloc(namei_zone); - - /* - * Copy the name from the mbuf list to ndp->ni_pnbuf - * and set the various ndp fields appropriately. - */ - fromcp = *dposp; - tocp = cnp->cn_pnbuf; - md = *mdp; - rem = mtod(md, caddr_t) + md->m_len - fromcp; - for (i = 0; i < len; i++) { - while (rem == 0) { - md = md->m_next; - if (md == NULL) { - error = EBADRPC; - goto out; - } - fromcp = mtod(md, caddr_t); - rem = md->m_len; - } - if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { - error = EACCES; - goto out; - } - *tocp++ = *fromcp++; - rem--; - } - *tocp = '\0'; - *mdp = md; - *dposp = fromcp; - len = nfsm_rndup(len)-len; - if (len > 0) { - if (rem >= len) - *dposp += len; - else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) - goto out; - } - - /* - * Extract and set starting directory. - */ - error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, - nam, &rdonly, kerbflag, pubflag); - if (error) - goto out; - if (dp->v_type != VDIR) { - vrele(dp); - error = ENOTDIR; - goto out; - } - - if (rdonly) - cnp->cn_flags |= RDONLY; - - /* - * Set return directory. Reference to dp is implicitly transfered - * to the returned pointer - */ - *retdirp = dp; - - if (pubflag) { - /* - * Oh joy. For WebNFS, handle those pesky '%' escapes, - * and the 'native path' indicator. - */ - cp = zalloc(namei_zone); - fromcp = cnp->cn_pnbuf; - tocp = cp; - if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { - switch ((unsigned char)*fromcp) { - case WEBNFS_NATIVE_CHAR: - /* - * 'Native' path for us is the same - * as a path according to the NFS spec, - * just skip the escape char. - */ - fromcp++; - break; - /* - * More may be added in the future, range 0x80-0xff - */ - default: - error = EIO; - zfree(namei_zone, cp); - goto out; - } - } - /* - * Translate the '%' escapes, URL-style. - */ - while (*fromcp != '\0') { - if (*fromcp == WEBNFS_ESC_CHAR) { - if (fromcp[1] != '\0' && fromcp[2] != '\0') { - fromcp++; - *tocp++ = HEXSTRTOI(fromcp); - fromcp += 2; - continue; - } else { - error = ENOENT; - zfree(namei_zone, cp); - goto out; - } - } else - *tocp++ = *fromcp++; - } - *tocp = '\0'; - zfree(namei_zone, cnp->cn_pnbuf); - cnp->cn_pnbuf = cp; - } - - ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; - ndp->ni_segflg = UIO_SYSSPACE; - - if (pubflag) { - ndp->ni_rootdir = rootvnode; - ndp->ni_loopcnt = 0; - if (cnp->cn_pnbuf[0] == '/') - dp = rootvnode; - } else { - cnp->cn_flags |= NOCROSSMOUNT; - } - - /* - * Initialize for scan, set ni_startdir and bump ref on dp again - * becuase lookup() will dereference ni_startdir. - */ - - cnp->cn_thread = td; - VREF(dp); - ndp->ni_startdir = dp; - - for (;;) { - cnp->cn_nameptr = cnp->cn_pnbuf; - /* - * Call lookup() to do the real work. If an error occurs, - * ndp->ni_vp and ni_dvp are left uninitialized or NULL and - * we do not have to dereference anything before returning. - * In either case ni_startdir will be dereferenced and NULLed - * out. - */ - error = lookup(ndp); - if (error) - break; - - /* - * Check for encountering a symbolic link. Trivial - * termination occurs if no symlink encountered. - * Note: zfree is safe because error is 0, so we will - * not zfree it again when we break. - */ - if ((cnp->cn_flags & ISSYMLINK) == 0) { - nfsrv_object_create(ndp->ni_vp); - if (cnp->cn_flags & (SAVENAME | SAVESTART)) - cnp->cn_flags |= HASBUF; - else - zfree(namei_zone, cnp->cn_pnbuf); - break; - } - - /* - * Validate symlink - */ - if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) - VOP_UNLOCK(ndp->ni_dvp, 0, td); - if (!pubflag) { - error = EINVAL; - goto badlink2; - } - - if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { - error = ELOOP; - goto badlink2; - } - if (ndp->ni_pathlen > 1) - cp = zalloc(namei_zone); - else - cp = cnp->cn_pnbuf; - aiov.iov_base = cp; - aiov.iov_len = MAXPATHLEN; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_offset = 0; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_td = (struct thread *)0; - auio.uio_resid = MAXPATHLEN; - error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); - if (error) { - badlink1: - if (ndp->ni_pathlen > 1) - zfree(namei_zone, cp); - badlink2: - vrele(ndp->ni_dvp); - vput(ndp->ni_vp); - break; - } - linklen = MAXPATHLEN - auio.uio_resid; - if (linklen == 0) { - error = ENOENT; - goto badlink1; - } - if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { - error = ENAMETOOLONG; - goto badlink1; - } - - /* - * Adjust or replace path - */ - if (ndp->ni_pathlen > 1) { - bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); - zfree(namei_zone, cnp->cn_pnbuf); - cnp->cn_pnbuf = cp; - } else - cnp->cn_pnbuf[linklen] = '\0'; - ndp->ni_pathlen += linklen; - - /* - * Cleanup refs for next loop and check if root directory - * should replace current directory. Normally ni_dvp - * becomes the new base directory and is cleaned up when - * we loop. Explicitly null pointers after invalidation - * to clarify operation. - */ - vput(ndp->ni_vp); - ndp->ni_vp = NULL; - - if (cnp->cn_pnbuf[0] == '/') { - vrele(ndp->ni_dvp); - ndp->ni_dvp = ndp->ni_rootdir; - VREF(ndp->ni_dvp); - } - ndp->ni_startdir = ndp->ni_dvp; - ndp->ni_dvp = NULL; - } - - /* - * nfs_namei() guarentees that fields will not contain garbage - * whether an error occurs or not. This allows the caller to track - * cleanup state trivially. - */ -out: - if (error) { - zfree(namei_zone, cnp->cn_pnbuf); - ndp->ni_vp = NULL; - ndp->ni_dvp = NULL; - ndp->ni_startdir = NULL; - cnp->cn_flags &= ~HASBUF; - } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { - ndp->ni_dvp = NULL; - } - return (error); -} - -/* - * A fiddled version of m_adj() that ensures null fill to a long - * boundary and only trims off the back end - */ -void -nfsm_adj(mp, len, nul) - struct mbuf *mp; - register int len; - int nul; -{ - register struct mbuf *m; - register int count, i; - register char *cp; - - /* - * Trim from tail. Scan the mbuf chain, - * calculating its length and finding the last mbuf. - * If the adjustment only affects this mbuf, then just - * adjust and return. Otherwise, rescan and truncate - * after the remaining size. - */ - count = 0; - m = mp; - for (;;) { - count += m->m_len; - if (m->m_next == (struct mbuf *)0) - break; - m = m->m_next; - } - if (m->m_len > len) { - m->m_len -= len; - if (nul > 0) { - cp = mtod(m, caddr_t)+m->m_len-nul; - for (i = 0; i < nul; i++) - *cp++ = '\0'; - } - return; - } - count -= len; - if (count < 0) - count = 0; - /* - * Correct length for chain is "count". - * Find the mbuf with last data, adjust its length, - * and toss data from remaining mbufs on chain. - */ - for (m = mp; m; m = m->m_next) { - if (m->m_len >= count) { - m->m_len = count; - if (nul > 0) { - cp = mtod(m, caddr_t)+m->m_len-nul; - for (i = 0; i < nul; i++) - *cp++ = '\0'; - } - break; - } - count -= m->m_len; - } - for (m = m->m_next;m;m = m->m_next) - m->m_len = 0; -} - -/* - * Make these functions instead of macros, so that the kernel text size - * doesn't get too big... - */ -void -nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) - struct nfsrv_descript *nfsd; - int before_ret; - register struct vattr *before_vap; - int after_ret; - struct vattr *after_vap; - struct mbuf **mbp; - char **bposp; -{ - register struct mbuf *mb = *mbp, *mb2; - register char *bpos = *bposp; - register u_int32_t *tl; - - if (before_ret) { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); - *tl = nfs_false; - } else { - nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED); - *tl++ = nfs_true; - txdr_hyper(before_vap->va_size, tl); - tl += 2; - txdr_nfsv3time(&(before_vap->va_mtime), tl); - tl += 2; - txdr_nfsv3time(&(before_vap->va_ctime), tl); - } - *bposp = bpos; - *mbp = mb; - nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); -} - -void -nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) - struct nfsrv_descript *nfsd; - int after_ret; - struct vattr *after_vap; - struct mbuf **mbp; - char **bposp; -{ - register struct mbuf *mb = *mbp, *mb2; - register char *bpos = *bposp; - register u_int32_t *tl; - register struct nfs_fattr *fp; - - if (after_ret) { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); - *tl = nfs_false; - } else { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); - *tl++ = nfs_true; - fp = (struct nfs_fattr *)tl; - nfsm_srvfattr(nfsd, after_vap, fp); - } - *mbp = mb; - *bposp = bpos; -} - void -nfsm_srvfattr(nfsd, vap, fp) - register struct nfsrv_descript *nfsd; - register struct vattr *vap; - register struct nfs_fattr *fp; +nfsm_build_xx(void **a, int s, struct mbuf **mb, caddr_t *bpos) { + struct mbuf *mb2; - fp->fa_nlink = txdr_unsigned(vap->va_nlink); - fp->fa_uid = txdr_unsigned(vap->va_uid); - fp->fa_gid = txdr_unsigned(vap->va_gid); - if (nfsd->nd_flag & ND_NFSV3) { - fp->fa_type = vtonfsv3_type(vap->va_type); - fp->fa_mode = vtonfsv3_mode(vap->va_mode); - txdr_hyper(vap->va_size, &fp->fa3_size); - txdr_hyper(vap->va_bytes, &fp->fa3_used); - fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); - fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); - fp->fa3_fsid.nfsuquad[0] = 0; - fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); - fp->fa3_fileid.nfsuquad[0] = 0; - fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); - txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); - txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); - txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); - } else { - fp->fa_type = vtonfsv2_type(vap->va_type); - fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); - fp->fa2_size = txdr_unsigned(vap->va_size); - fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); - if (vap->va_type == VFIFO) - fp->fa2_rdev = 0xffffffff; - else - fp->fa2_rdev = txdr_unsigned(vap->va_rdev); - fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); - fp->fa2_fsid = txdr_unsigned(vap->va_fsid); - fp->fa2_fileid = txdr_unsigned(vap->va_fileid); - txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); - txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); - txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); - } -} - -/* - * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) - * - look up fsid in mount list (if not found ret error) - * - get vp and export rights by calling VFS_FHTOVP() - * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon - * - if not lockflag unlock it with VOP_UNLOCK() - */ -int -nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) - fhandle_t *fhp; - int lockflag; - struct vnode **vpp; - struct ucred *cred; - struct nfssvc_sock *slp; - struct sockaddr *nam; - int *rdonlyp; - int kerbflag; - int pubflag; -{ - struct thread *td = curthread; /* XXX */ - register struct mount *mp; - register int i; - struct ucred *credanon; - int error, exflags; -#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ - struct sockaddr_int *saddr; -#endif - - *vpp = (struct vnode *)0; - - if (nfs_ispublicfh(fhp)) { - if (!pubflag || !nfs_pub.np_valid) - return (ESTALE); - fhp = &nfs_pub.np_handle; - } - - mp = vfs_getvfs(&fhp->fh_fsid); - if (!mp) - return (ESTALE); - error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); - if (error) - return (error); - error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); - if (error) - return (error); -#ifdef MNT_EXNORESPORT - if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { - saddr = (struct sockaddr_in *)nam; - if (saddr->sin_family == AF_INET && - ntohs(saddr->sin_port) >= IPPORT_RESERVED) { - vput(*vpp); - *vpp = NULL; - return (NFSERR_AUTHERR | AUTH_TOOWEAK); - } - } -#endif - /* - * Check/setup credentials. - */ - if (exflags & MNT_EXKERB) { - if (!kerbflag) { - vput(*vpp); - *vpp = NULL; - return (NFSERR_AUTHERR | AUTH_TOOWEAK); - } - } else if (kerbflag) { - vput(*vpp); - *vpp = NULL; - return (NFSERR_AUTHERR | AUTH_TOOWEAK); - } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { - cred->cr_uid = credanon->cr_uid; - for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) - cred->cr_groups[i] = credanon->cr_groups[i]; - cred->cr_ngroups = i; - } - if (exflags & MNT_EXRDONLY) - *rdonlyp = 1; - else - *rdonlyp = 0; - - nfsrv_object_create(*vpp); - - if (!lockflag) - VOP_UNLOCK(*vpp, 0, td); - return (0); + if (s > M_TRAILINGSPACE(*mb)) { + MGET(mb2, M_TRYWAIT, MT_DATA); + if (s > MLEN) + panic("build > MLEN"); + (*mb)->m_next = mb2; + *mb = mb2; + (*mb)->m_len = 0; + *bpos = mtod(*mb, caddr_t); + } + *a = *bpos; + (*mb)->m_len += s; + *bpos += s; } - -/* - * WebNFS: check if a filehandle is a public filehandle. For v3, this - * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has - * transformed this to all zeroes in both cases, so check for it. - */ -int -nfs_ispublicfh(fhp) - fhandle_t *fhp; -{ - char *cp = (char *)fhp; - int i; - - for (i = 0; i < NFSX_V3FH; i++) - if (*cp++ != 0) - return (FALSE); - return (TRUE); -} - -#endif /* NFS_NOSERVER */ -/* - * This function compares two net addresses by family and returns TRUE - * if they are the same host. - * If there is any doubt, return FALSE. - * The AF_INET family is handled as a special case so that address mbufs - * don't need to be saved to store "struct in_addr", which is only 4 bytes. - */ int -netaddr_match(family, haddr, nam) - int family; - union nethostaddr *haddr; - struct sockaddr *nam; -{ - register struct sockaddr_in *inetaddr; - - switch (family) { - case AF_INET: - inetaddr = (struct sockaddr_in *)nam; - if (inetaddr->sin_family == AF_INET && - inetaddr->sin_addr.s_addr == haddr->had_inetaddr) - return (1); - break; - default: - break; - }; - return (0); -} - -static nfsuint64 nfs_nullcookie = { { 0, 0 } }; -/* - * This function finds the directory cookie that corresponds to the - * logical byte offset given. - */ -nfsuint64 * -nfs_getcookie(np, off, add) - register struct nfsnode *np; - off_t off; - int add; -{ - register struct nfsdmap *dp, *dp2; - register int pos; - - pos = (uoff_t)off / NFS_DIRBLKSIZ; - if (pos == 0 || off < 0) { -#ifdef DIAGNOSTIC - if (add) - panic("nfs getcookie add at <= 0"); -#endif - return (&nfs_nullcookie); - } - pos--; - dp = np->n_cookies.lh_first; - if (!dp) { - if (add) { - MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), - M_NFSDIROFF, M_WAITOK); - dp->ndm_eocookie = 0; - LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); - } else - return ((nfsuint64 *)0); - } - while (pos >= NFSNUMCOOKIES) { - pos -= NFSNUMCOOKIES; - if (dp->ndm_list.le_next) { - if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && - pos >= dp->ndm_eocookie) - return ((nfsuint64 *)0); - dp = dp->ndm_list.le_next; - } else if (add) { - MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), - M_NFSDIROFF, M_WAITOK); - dp2->ndm_eocookie = 0; - LIST_INSERT_AFTER(dp, dp2, ndm_list); - dp = dp2; - } else - return ((nfsuint64 *)0); - } - if (pos >= dp->ndm_eocookie) { - if (add) - dp->ndm_eocookie = pos + 1; - else - return ((nfsuint64 *)0); - } - return (&dp->ndm_cookies[pos]); -} - -/* - * Invalidate cached directory information, except for the actual directory - * blocks (which are invalidated separately). - * Done mainly to avoid the use of stale offset cookies. - */ -void -nfs_invaldir(vp) - register struct vnode *vp; +nfsm_dissect_xx(void **a, int s, struct mbuf **md, caddr_t *dpos) { - register struct nfsnode *np = VTONFS(vp); - -#ifdef DIAGNOSTIC - if (vp->v_type != VDIR) - panic("nfs: invaldir not dir"); -#endif - np->n_direofoffset = 0; - np->n_cookieverf.nfsuquad[0] = 0; - np->n_cookieverf.nfsuquad[1] = 0; - if (np->n_cookies.lh_first) - np->n_cookies.lh_first->ndm_eocookie = 0; + int t1; + char *cp2; + + t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos; + if (t1 >= s) { + *a = *dpos; + *dpos += s; + return 0; + } + t1 = nfsm_disct(md, dpos, s, t1, &cp2); + if (t1 != 0) + return t1; + *a = cp2; + return 0; } -/* - * The write verifier has changed (probably due to a server reboot), so all - * B_NEEDCOMMIT blocks will have to be written again. Since they are on the - * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT - * and B_CLUSTEROK flags. Once done the new write verifier can be set for the - * mount point. - * - * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data - * writes are not clusterable. - */ -void -nfs_clearcommit(mp) - struct mount *mp; -{ - register struct vnode *vp, *nvp; - register struct buf *bp, *nbp; - int s; - - GIANT_REQUIRED; - - s = splbio(); - mtx_lock(&mntvnode_mtx); -loop: - for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) { - if (vp->v_mount != mp) /* Paranoia */ - goto loop; - nvp = LIST_NEXT(vp, v_mntvnodes); - for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { - nbp = TAILQ_NEXT(bp, b_vnbufs); - if (BUF_REFCNT(bp) == 0 && - (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) - == (B_DELWRI | B_NEEDCOMMIT)) - bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); - } - } - mtx_unlock(&mntvnode_mtx); - splx(s); -} - -#ifndef NFS_NOSERVER -/* - * Map errnos to NFS error numbers. For Version 3 also filter out error - * numbers not specified for the associated procedure. - */ int -nfsrv_errmap(nd, err) - struct nfsrv_descript *nd; - register int err; +nfsm_strsiz_xx(int *s, int m, u_int32_t **tl, struct mbuf **mb, caddr_t *bpos) { - register short *defaulterrp, *errp; - - if (nd->nd_flag & ND_NFSV3) { - if (nd->nd_procnum <= NFSPROC_COMMIT) { - errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; - while (*++errp) { - if (*errp == err) - return (err); - else if (*errp > err) - break; - } - return ((int)*defaulterrp); - } else - return (err & 0xffff); - } - if (err <= ELAST) - return ((int)nfsrv_v2errmap[err - 1]); - return (NFSERR_IO); + int ret; + + ret = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, mb, bpos); + if (ret) + return ret; + *s = fxdr_unsigned(int32_t, **tl); + if (*s > m) + return EBADRPC; + return 0; } int -nfsrv_object_create(vp) - struct vnode *vp; +nfsm_adv_xx(int s, u_int32_t **tl, struct mbuf **md, caddr_t *dpos) { + int t1; - if (vp == NULL || vp->v_type != VREG) - return (1); - return (vfs_object_create(vp, curthread, - curthread ? curthread->td_proc->p_ucred : NULL)); -} - -/* - * Sort the group list in increasing numerical order. - * (Insertion sort by Chris Torek, who was grossed out by the bubble sort - * that used to be here.) - */ -void -nfsrvw_sort(list, num) - register gid_t *list; - register int num; -{ - register int i, j; - gid_t v; - - /* Insertion sort. */ - for (i = 1; i < num; i++) { - v = list[i]; - /* find correct slot for value v, moving others up */ - for (j = i; --j >= 0 && v < list[j];) - list[j + 1] = list[j]; - list[j + 1] = v; + t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos; + if (t1 > s) { + *dpos += s; + return 0; } + t1 = nfs_adv(md, dpos, s, t1); + if (t1) + return t1; + return 0; } - -/* - * copy credentials making sure that the result can be compared with bcmp(). - */ -void -nfsrv_setcred(incred, outcred) - register struct ucred *incred, *outcred; -{ - register int i; - - bzero((caddr_t)outcred, sizeof (struct ucred)); - outcred->cr_ref = 1; - outcred->cr_uid = incred->cr_uid; - outcred->cr_ngroups = incred->cr_ngroups; - for (i = 0; i < incred->cr_ngroups; i++) - outcred->cr_groups[i] = incred->cr_groups[i]; - nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); -} -#endif /* NFS_NOSERVER */ diff --git a/sys/nfs/nfs_common.h b/sys/nfs/nfs_common.h index d58ef15..825ab35 100644 --- a/sys/nfs/nfs_common.h +++ b/sys/nfs/nfs_common.h @@ -38,527 +38,86 @@ */ -#ifndef _NFS_NFSM_SUBS_H_ -#define _NFS_NFSM_SUBS_H_ +#ifndef _NFS_NFS_COMMON_H_ +#define _NFS_NFS_COMMON_H_ -struct ucred; -struct vnode; +extern enum vtype nv3tov_type[]; +extern nfstype nfsv3_type[]; -/* - * These macros do strange and peculiar things to mbuf chains for - * the assistance of the nfs code. To attempt to use them for any - * other purpose will be dangerous. (they make weird assumptions) - */ +#define vtonfsv2_mode(t, m) \ + txdr_unsigned(((t) == VFIFO) ? MAKEIMODE(VCHR, (m)) : MAKEIMODE((t), (m))) -/* - * First define what the actual subs. return - */ -struct mbuf *nfsm_reqh __P((struct vnode *vp, u_long procid, int hsiz, - caddr_t *bposp)); -struct mbuf *nfsm_rpchead __P((struct ucred *cr, int nmflag, int procid, - int auth_type, int auth_len, char *auth_str, - int verf_len, char *verf_str, - struct mbuf *mrest, int mrest_len, - struct mbuf **mbp, u_int32_t *xidp)); +#define nfsv3tov_type(a) nv3tov_type[fxdr_unsigned(u_int32_t,(a))&0x7] +#define vtonfsv3_type(a) txdr_unsigned(nfsv3_type[((int32_t)(a))]) -#define M_HASCL(m) ((m)->m_flags & M_EXT) -#define NFSMINOFF(m) \ - do { \ - if (M_HASCL(m)) \ - (m)->m_data = (m)->m_ext.ext_buf; \ - else if ((m)->m_flags & M_PKTHDR) \ - (m)->m_data = (m)->m_pktdat; \ - else \ - (m)->m_data = (m)->m_dat; \ - } while (0) -#define NFSMADV(m, s) \ +#define NFSMADV(m, s) \ do { \ (m)->m_data += (s); \ } while (0) -#define NFSMSIZ(m) ((M_HASCL(m))?MCLBYTES: \ - (((m)->m_flags & M_PKTHDR)?MHLEN:MLEN)) - -/* - * Now for the macros that do the simple stuff and call the functions - * for the hard stuff. - * These macros use several vars. declared in nfsm_reqhead and these - * vars. must not be used elsewhere unless you are careful not to corrupt - * them. The vars. starting with pN and tN (N=1,2,3,..) are temporaries - * that may be used so long as the value is not expected to retained - * after a macro. - * I know, this is kind of dorkey, but it makes the actual op functions - * fairly clean and deals with the mess caused by the xdr discriminating - * unions. - */ - -#define nfsm_build(a,c,s) \ - do { \ - if ((s) > M_TRAILINGSPACE(mb)) { \ - MGET(mb2, M_TRYWAIT, MT_DATA); \ - if ((s) > MLEN) \ - panic("build > MLEN"); \ - mb->m_next = mb2; \ - mb = mb2; \ - mb->m_len = 0; \ - bpos = mtod(mb, caddr_t); \ - } \ - (a) = (c)(bpos); \ - mb->m_len += (s); \ - bpos += (s); \ - } while (0) - -#define nfsm_dissect(a, c, s) \ - do { \ - t1 = mtod(md, caddr_t)+md->m_len-dpos; \ - if (t1 >= (s)) { \ - (a) = (c)(dpos); \ - dpos += (s); \ - } else if ((t1 = nfsm_disct(&md, &dpos, (s), t1, &cp2)) != 0){ \ - error = t1; \ - m_freem(mrep); \ - goto nfsmout; \ - } else { \ - (a) = (c)cp2; \ - } \ - } while (0) - -#define nfsm_fhtom(v, v3) \ - do { \ - if (v3) { \ - t2 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; \ - if (t2 <= M_TRAILINGSPACE(mb)) { \ - nfsm_build(tl, u_int32_t *, t2); \ - *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize); \ - *(tl + ((t2>>2) - 2)) = 0; \ - bcopy((caddr_t)VTONFS(v)->n_fhp,(caddr_t)tl, \ - VTONFS(v)->n_fhsize); \ - } else if ((t2 = nfsm_strtmbuf(&mb, &bpos, \ - (caddr_t)VTONFS(v)->n_fhp, \ - VTONFS(v)->n_fhsize)) != 0) { \ - error = t2; \ - m_freem(mreq); \ - goto nfsmout; \ - } \ - } else { \ - nfsm_build(cp, caddr_t, NFSX_V2FH); \ - bcopy((caddr_t)VTONFS(v)->n_fhp, cp, NFSX_V2FH); \ - } \ - } while (0) - -#define nfsm_srvfhtom(f, v3) \ - do { \ - if (v3) { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FH);\ - *tl++ = txdr_unsigned(NFSX_V3FH); \ - bcopy((caddr_t)(f), (caddr_t)tl, NFSX_V3FH); \ - } else { \ - nfsm_build(cp, caddr_t, NFSX_V2FH); \ - bcopy((caddr_t)(f), cp, NFSX_V2FH); \ - } \ - } while (0) - -#define nfsm_srvpostop_fh(f) \ - do { \ - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED + NFSX_V3FH); \ - *tl++ = nfs_true; \ - *tl++ = txdr_unsigned(NFSX_V3FH); \ - bcopy((caddr_t)(f), (caddr_t)tl, NFSX_V3FH); \ - } while (0) - -#define nfsm_mtofh(d, v, v3, f) \ - do { \ - struct nfsnode *ttnp; nfsfh_t *ttfhp; int ttfhsize; \ - if (v3) { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - (f) = fxdr_unsigned(int, *tl); \ - } else \ - (f) = 1; \ - if (f) { \ - nfsm_getfh(ttfhp, ttfhsize, (v3)); \ - if ((t1 = nfs_nget((d)->v_mount, ttfhp, ttfhsize, \ - &ttnp)) != 0) { \ - error = t1; \ - m_freem(mrep); \ - goto nfsmout; \ - } \ - (v) = NFSTOV(ttnp); \ - } \ - if (v3) { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - if (f) \ - (f) = fxdr_unsigned(int, *tl); \ - else if (fxdr_unsigned(int, *tl)) \ - nfsm_adv(NFSX_V3FATTR); \ - } \ - if (f) \ - nfsm_loadattr((v), (struct vattr *)0); \ - } while (0) - -#define nfsm_getfh(f, s, v3) \ - do { \ - if (v3) { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - if (((s) = fxdr_unsigned(int, *tl)) <= 0 || \ - (s) > NFSX_V3FHMAX) { \ - m_freem(mrep); \ - error = EBADRPC; \ - goto nfsmout; \ - } \ - } else \ - (s) = NFSX_V2FH; \ - nfsm_dissect((f), nfsfh_t *, nfsm_rndup(s)); \ - } while (0) - -#define nfsm_loadattr(v, a) \ - do { \ - struct vnode *ttvp = (v); \ - if ((t1 = nfs_loadattrcache(&ttvp, &md, &dpos, (a), 0)) != 0) { \ - error = t1; \ - m_freem(mrep); \ - goto nfsmout; \ - } \ - (v) = ttvp; \ - } while (0) -#define nfsm_postop_attr(v, f) \ - do { \ - struct vnode *ttvp = (v); \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - if (((f) = fxdr_unsigned(int, *tl)) != 0) { \ - if ((t1 = nfs_loadattrcache(&ttvp, &md, &dpos, \ - (struct vattr *)0, 1)) != 0) { \ - error = t1; \ - (f) = 0; \ - m_freem(mrep); \ - goto nfsmout; \ - } \ - (v) = ttvp; \ - } \ - } while (0) +int nfs_adv(struct mbuf **, caddr_t *, int, int); +void nfsm_build_xx(void **a, int s, struct mbuf **mb, caddr_t *bpos); +int nfsm_dissect_xx(void **a, int s, struct mbuf **md, caddr_t *dpos); +int nfsm_strsiz_xx(int *s, int m, u_int32_t **tl, struct mbuf **mb, + caddr_t *bpos); +int nfsm_adv_xx(int s, u_int32_t **tl, struct mbuf **md, caddr_t *dpos); +u_quad_t nfs_curusec(void); +int nfsm_disct(struct mbuf **, caddr_t *, int, int, caddr_t *); -/* Used as (f) for nfsm_wcc_data() */ -#define NFSV3_WCCRATTR 0 -#define NFSV3_WCCCHK 1 +#define nfsm_build(a, c, s) \ +do { \ + nfsm_build_xx((void **)&(a), (s), &mb, &bpos); \ +} while (0) -#define nfsm_wcc_data(v, f) \ - do { \ - int ttattrf, ttretf = 0; \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - if (*tl == nfs_true) { \ - nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED); \ - if (f) \ - ttretf = (VTONFS(v)->n_mtime == \ - fxdr_unsigned(u_int32_t, *(tl + 2))); \ - } \ - nfsm_postop_attr((v), ttattrf); \ - if (f) { \ - (f) = ttretf; \ - } else { \ - (f) = ttattrf; \ - } \ - } while (0) -/* If full is true, set all fields, otherwise just set mode and time fields */ -#define nfsm_v3attrbuild(a, full) \ - do { \ - if ((a)->va_mode != (mode_t)VNOVAL) { \ - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ - *tl++ = nfs_true; \ - *tl = txdr_unsigned((a)->va_mode); \ - } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ - *tl = nfs_false; \ - } \ - if ((full) && (a)->va_uid != (uid_t)VNOVAL) { \ - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ - *tl++ = nfs_true; \ - *tl = txdr_unsigned((a)->va_uid); \ - } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ - *tl = nfs_false; \ - } \ - if ((full) && (a)->va_gid != (gid_t)VNOVAL) { \ - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ - *tl++ = nfs_true; \ - *tl = txdr_unsigned((a)->va_gid); \ - } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ - *tl = nfs_false; \ - } \ - if ((full) && (a)->va_size != VNOVAL) { \ - nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED); \ - *tl++ = nfs_true; \ - txdr_hyper((a)->va_size, tl); \ - } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ - *tl = nfs_false; \ - } \ - if ((a)->va_atime.tv_sec != VNOVAL) { \ - if ((a)->va_atime.tv_sec != time_second) { \ - nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED);\ - *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);\ - txdr_nfsv3time(&(a)->va_atime, tl); \ - } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ - *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); \ - } \ - } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ - *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); \ - } \ - if ((a)->va_mtime.tv_sec != VNOVAL) { \ - if ((a)->va_mtime.tv_sec != time_second) { \ - nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED);\ - *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);\ - txdr_nfsv3time(&(a)->va_mtime, tl); \ - } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ - *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); \ - } \ - } else { \ - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); \ - *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); \ - } \ - } while (0) - +/* XXX 'c' arg (type) is not used */ +#define nfsm_dissect(a, c, s) \ +do { \ + int t1; \ + t1 = nfsm_dissect_xx((void **)&(a), (s), &md, &dpos); \ + if (t1) { \ + error = t1; \ + m_freem(mrep); \ + mrep = NULL; \ + goto nfsmout; \ + } \ +} while (0) #define nfsm_strsiz(s,m) \ - do { \ - nfsm_dissect(tl,u_int32_t *,NFSX_UNSIGNED); \ - if (((s) = fxdr_unsigned(int32_t,*tl)) > (m)) { \ - m_freem(mrep); \ - error = EBADRPC; \ - goto nfsmout; \ - } \ - } while (0) - -#define nfsm_srvstrsiz(s,m) \ - do { \ - nfsm_dissect(tl,u_int32_t *,NFSX_UNSIGNED); \ - if (((s) = fxdr_unsigned(int32_t,*tl)) > (m) || (s) <= 0) { \ - error = EBADRPC; \ - nfsm_reply(0); \ - } \ - } while (0) - -#define nfsm_srvnamesiz(s) \ - do { \ - nfsm_dissect(tl,u_int32_t *,NFSX_UNSIGNED); \ - if (((s) = fxdr_unsigned(int32_t,*tl)) > NFS_MAXNAMLEN) \ - error = NFSERR_NAMETOL; \ - if ((s) <= 0) \ - error = EBADRPC; \ - if (error) \ - nfsm_reply(0); \ - } while (0) +do { \ + int t1; \ + t1 = nfsm_strsiz_xx(&(s), (m), &tl, &md, &dpos); \ + if (t1) { \ + error = t1; \ + m_freem(mrep); \ + mrep = NULL; \ + goto nfsmout; \ + } \ +} while(0) #define nfsm_mtouio(p,s) \ - do {\ - if ((s) > 0 && \ - (t1 = nfsm_mbuftouio(&md,(p),(s),&dpos)) != 0) { \ - error = t1; \ - m_freem(mrep); \ - goto nfsmout; \ - } \ - } while (0) - -#define nfsm_uiotom(p,s) \ - do { \ - if ((t1 = nfsm_uiotombuf((p),&mb,(s),&bpos)) != 0) { \ - error = t1; \ - m_freem(mreq); \ - goto nfsmout; \ - } \ - } while (0) - -#define nfsm_reqhead(v,a,s) \ - do { \ - mb = mreq = nfsm_reqh((v),(a),(s),&bpos); \ - } while (0) - -#define nfsm_reqdone \ - do { \ +do {\ + int32_t t1; \ + if ((s) > 0 && (t1 = nfsm_mbuftouio(&md, (p), (s), &dpos)) != 0) { \ + error = t1; \ m_freem(mrep); \ - nfsmout: \ - } while (0) + mrep = NULL; \ + goto nfsmout; \ + } \ +} while (0) #define nfsm_rndup(a) (((a)+3)&(~0x3)) -#define nfsm_request(v, t, p, c) \ - do { \ - if ((error = nfs_request((v), mreq, (t), (p), \ - (c), &mrep, &md, &dpos)) != 0) { \ - if (error & NFSERR_RETERR) \ - error &= ~NFSERR_RETERR; \ - else \ - goto nfsmout; \ - } \ - } while (0) - -#define nfsm_strtom(a,s,m) \ - do {\ - if ((s) > (m)) { \ - m_freem(mreq); \ - error = ENAMETOOLONG; \ - goto nfsmout; \ - } \ - t2 = nfsm_rndup(s)+NFSX_UNSIGNED; \ - if (t2 <= M_TRAILINGSPACE(mb)) { \ - nfsm_build(tl,u_int32_t *,t2); \ - *tl++ = txdr_unsigned(s); \ - *(tl+((t2>>2)-2)) = 0; \ - bcopy((const char *)(a), (caddr_t)tl, (s)); \ - } else if ((t2 = nfsm_strtmbuf(&mb, &bpos, (a), (s))) != 0) { \ - error = t2; \ - m_freem(mreq); \ - goto nfsmout; \ - } \ - } while (0) - -#define nfsm_srvdone \ - do { \ - nfsmout: \ - return (error); \ - } while (0) - -#define nfsm_reply(s) \ - do { \ - nfsd->nd_repstat = error; \ - if (error && !(nfsd->nd_flag & ND_NFSV3)) \ - (void) nfs_rephead(0, nfsd, slp, error, cache, &frev, \ - mrq, &mb, &bpos); \ - else \ - (void) nfs_rephead((s), nfsd, slp, error, cache, &frev, \ - mrq, &mb, &bpos); \ - if (mrep != NULL) { \ - m_freem(mrep); \ - mrep = NULL; \ - } \ - mreq = *mrq; \ - if (error && (!(nfsd->nd_flag & ND_NFSV3) || \ - error == EBADRPC)) { \ - error = 0; \ - goto nfsmout; \ - } \ - } while (0) - -#define nfsm_writereply(s, v3) \ - do { \ - nfsd->nd_repstat = error; \ - if (error && !(v3)) \ - (void) nfs_rephead(0, nfsd, slp, error, cache, &frev, \ - &mreq, &mb, &bpos); \ - else \ - (void) nfs_rephead((s), nfsd, slp, error, cache, &frev, \ - &mreq, &mb, &bpos); \ - } while (0) - #define nfsm_adv(s) \ - do { \ - t1 = mtod(md, caddr_t)+md->m_len-dpos; \ - if (t1 >= (s)) { \ - dpos += (s); \ - } else if ((t1 = nfs_adv(&md, &dpos, (s), t1)) != 0) { \ - error = t1; \ - m_freem(mrep); \ - goto nfsmout; \ - } \ - } while (0) - -#define nfsm_srvmtofh(f) \ - do { \ - int fhlen; \ - if (nfsd->nd_flag & ND_NFSV3) { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - fhlen = fxdr_unsigned(int, *tl); \ - if (fhlen != 0 && fhlen != NFSX_V3FH) { \ - error = EBADRPC; \ - nfsm_reply(0); \ - } \ - } else { \ - fhlen = NFSX_V2FH; \ - } \ - if (fhlen != 0) { \ - nfsm_dissect(tl, u_int32_t *, fhlen); \ - bcopy((caddr_t)tl, (caddr_t)(f), fhlen); \ - } else {\ - bzero((caddr_t)(f), NFSX_V3FH); \ - } \ - } while (0) - -#define nfsm_clget \ - do { \ - if (bp >= be) { \ - if (mp == mb) \ - mp->m_len += bp-bpos; \ - MGET(mp, M_TRYWAIT, MT_DATA); \ - MCLGET(mp, M_TRYWAIT); \ - mp->m_len = NFSMSIZ(mp); \ - mp2->m_next = mp; \ - mp2 = mp; \ - bp = mtod(mp, caddr_t); \ - be = bp+mp->m_len; \ - } \ - tl = (u_int32_t *)bp; \ - } while (0) - -#define nfsm_srvfillattr(a, f) \ - do { \ - nfsm_srvfattr(nfsd, (a), (f)); \ - } while (0) - -#define nfsm_srvwcc_data(br, b, ar, a) \ - do { \ - nfsm_srvwcc(nfsd, (br), (b), (ar), (a), &mb, &bpos); \ - } while (0) - -#define nfsm_srvpostop_attr(r, a) \ - do { \ - nfsm_srvpostopattr(nfsd, (r), (a), &mb, &bpos); \ - } while (0) - -#define nfsm_srvsattr(a) \ - do { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - if (*tl == nfs_true) { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - (a)->va_mode = nfstov_mode(*tl); \ - } \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - if (*tl == nfs_true) { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - (a)->va_uid = fxdr_unsigned(uid_t, *tl); \ - } \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - if (*tl == nfs_true) { \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - (a)->va_gid = fxdr_unsigned(gid_t, *tl); \ - } \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - if (*tl == nfs_true) { \ - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ - (a)->va_size = fxdr_hyper(tl); \ - } \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - switch (fxdr_unsigned(int, *tl)) { \ - case NFSV3SATTRTIME_TOCLIENT: \ - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ - fxdr_nfsv3time(tl, &(a)->va_atime); \ - break; \ - case NFSV3SATTRTIME_TOSERVER: \ - getnanotime(&(a)->va_atime); \ - break; \ - }; \ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); \ - switch (fxdr_unsigned(int, *tl)) { \ - case NFSV3SATTRTIME_TOCLIENT: \ - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); \ - fxdr_nfsv3time(tl, &(a)->va_mtime); \ - break; \ - case NFSV3SATTRTIME_TOSERVER: \ - getnanotime(&(a)->va_mtime); \ - break; \ - } \ - } while (0) +do { \ + int t1; \ + t1 = nfsm_adv_xx((s), &tl, &md, &dpos); \ + if (t1) { \ + error = t1; \ + m_freem(mrep); \ + mrep = NULL; \ + goto nfsmout; \ + } \ +} while (0) #endif diff --git a/sys/nfs/nfs_lock.c b/sys/nfs/nfs_lock.c deleted file mode 100644 index b97b3b8..0000000 --- a/sys/nfs/nfs_lock.c +++ /dev/null @@ -1,286 +0,0 @@ -/*- - * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Berkeley Software Design Inc's name may not be used to endorse or - * promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from BSDI nfs_lock.c,v 2.4 1998/12/14 23:49:56 jch Exp - * $FreeBSD$ - */ - -#include -#include -#include -#include /* for hz */ -#include -#include -#include /* for hz */ /* Must come after sys/malloc.h */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#define NFSOWNER_1ST_LEVEL_START 1 /* initial entries */ -#define NFSOWNER_2ND_LEVEL 256 /* some power of 2 */ - -#define NFSOWNER(tbl, i) \ - (tbl)[(i) / NFSOWNER_2ND_LEVEL][(i) % NFSOWNER_2ND_LEVEL] - -/* - * XXX - * We have to let the process know if the call succeeded. I'm using an extra - * field in the p_nlminfo field in the proc structure, as it is already for - * lockd stuff. - */ - -/* - * nfs_advlock -- - * NFS advisory byte-level locks. - */ -int -nfs_dolock(ap) - struct vop_advlock_args /* { - struct vnode *a_vp; - caddr_t a_id; - int a_op; - struct flock *a_fl; - int a_flags; - } */ *ap; -{ - LOCKD_MSG msg; - struct nameidata nd; - struct thread *td; - uid_t saved_uid; - struct vnode *vp, *wvp; - int error, error1; - struct flock *fl; - int fmode, ioflg; - struct proc *p; - - td = curthread; - p = td->td_proc; - - vp = ap->a_vp; - fl = ap->a_fl; - - /* - * the NLM protocol doesn't allow the server to return an error - * on ranges, so we do it. - */ - if (fl->l_whence != SEEK_END) { - if ((fl->l_whence != SEEK_CUR && fl->l_whence != SEEK_SET) || - fl->l_start < 0 || - (fl->l_len < 0 && - (fl->l_start == 0 || fl->l_start + fl->l_len < 0))) - return (EINVAL); - if (fl->l_len > 0 && - (fl->l_len - 1 > OFF_MAX - fl->l_start)) - return (EOVERFLOW); - } - - /* - * Fill in the information structure. - */ - msg.lm_version = LOCKD_MSG_VERSION; - msg.lm_msg_ident.pid = p->p_pid; - /* - * if there is no nfsowner table yet, allocate one. - */ - if (p->p_nlminfo == NULL) { - MALLOC(p->p_nlminfo, struct nlminfo *, - sizeof(struct nlminfo), M_LOCKF, M_WAITOK | M_ZERO); - p->p_nlminfo->pid_start = p->p_stats->p_start; - } - msg.lm_msg_ident.pid_start = p->p_nlminfo->pid_start; - msg.lm_msg_ident.msg_seq = ++(p->p_nlminfo->msg_seq); - - msg.lm_fl = *fl; - msg.lm_wait = ap->a_flags & F_WAIT; - msg.lm_getlk = ap->a_op == F_GETLK; - /* - * XXX -- I think this is wrong for anything other AF_INET. - */ - msg.lm_addr = *(VFSTONFS(vp->v_mount)->nm_nam); - msg.lm_fh_len = NFS_ISV3(vp) ? VTONFS(vp)->n_fhsize : NFSX_V2FH; - bcopy(VTONFS(vp)->n_fhp, msg.lm_fh, msg.lm_fh_len); - msg.lm_nfsv3 = NFS_ISV3(vp); - msg.lm_cred = *(p->p_ucred); - - /* - * Open the lock fifo. If for any reason we don't find the fifo, it - * means that the lock daemon isn't running. Translate any missing - * file error message for the user, otherwise the application will - * complain that the user's file is missing, which isn't the case. - * Note that we use proc0's cred, so the fifo is opened as root. - */ - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, _PATH_LCKFIFO, td); - - /* - * XXX Hack to temporarily allow this process (regardless of it's creds) - * to open the fifo we need to write to. vn_open() really should - * take a ucred (and once it does, this code should be fixed to use - * proc0's ucred. - */ - saved_uid = p->p_ucred->cr_uid; - p->p_ucred->cr_uid = 0; /* temporarly run the vn_open as root */ - - fmode = FFLAGS(O_WRONLY); - error = vn_open(&nd, &fmode, 0); - p->p_ucred->cr_uid = saved_uid; - if (error != 0) { - return (error == ENOENT ? EOPNOTSUPP : error); - } - wvp = nd.ni_vp; - VOP_UNLOCK(wvp, 0, td); /* vn_open leaves it locked */ - - - ioflg = IO_UNIT; - for (;;) { - VOP_LEASE(wvp, td, proc0.p_ucred, LEASE_WRITE); - - error = vn_rdwr(UIO_WRITE, wvp, (caddr_t)&msg, sizeof(msg), 0, - UIO_SYSSPACE, ioflg, proc0.p_ucred, NULL, td); - - if (error && (((ioflg & IO_NDELAY) == 0) || error != EAGAIN)) { - break; - } - /* - * If we're locking a file, wait for an answer. Unlocks succeed - * immediately. - */ - if (fl->l_type == F_UNLCK) - /* - * XXX this isn't exactly correct. The client side - * needs to continue sending it's unlock until - * it gets a responce back. - */ - break; - - /* - * retry after 20 seconds if we haven't gotten a responce yet. - * This number was picked out of thin air... but is longer - * then even a reasonably loaded system should take (at least - * on a local network). XXX Probably should use a back-off - * scheme. - */ - if ((error = tsleep((void *)p->p_nlminfo, - PCATCH | PUSER, "lockd", 20*hz)) != 0) { - if (error == EWOULDBLOCK) { - /* - * We timed out, so we rewrite the request - * to the fifo, but only if it isn't already - * full. - */ - ioflg |= IO_NDELAY; - continue; - } - - break; - } - - if (msg.lm_getlk && p->p_nlminfo->retcode == 0) { - if (p->p_nlminfo->set_getlk_pid) { - fl->l_pid = p->p_nlminfo->getlk_pid; - } else { - fl->l_type = F_UNLCK; - } - } - error = p->p_nlminfo->retcode; - break; - } - - if ((error1 = vn_close(wvp, FWRITE, proc0.p_ucred, td)) && error == 0) - return (error1); - - return (error); -} - -/* - * nfslockdans -- - * NFS advisory byte-level locks answer from the lock daemon. - */ -int -nfslockdans(p, ansp) - struct proc *p; - struct lockd_ans *ansp; -{ - int error; - - /* Let root, or someone who once was root (lockd generally - * switches to the daemon uid once it is done setting up) make - * this call. - * - * XXX This authorization check is probably not right. - */ - if ((error = suser(p)) != 0 && p->p_ucred->cr_svuid != 0) - return (error); - - /* the version should match, or we're out of sync */ - if (ansp->la_vers != LOCKD_ANS_VERSION) - return (EINVAL); - - /* Find the process, set its return errno and wake it up. */ - if ((p = pfind(ansp->la_msg_ident.pid)) == NULL) - return (ESRCH); - - /* verify the pid hasn't been reused (if we can), and it isn't waiting - * for an answer from a more recent request. We return an EPIPE if - * the match fails, because we've already used ESRCH above, and this - * is sort of like writing on a pipe after the reader has closed it. - */ - if (p->p_nlminfo == NULL || - ((ansp->la_msg_ident.msg_seq != -1) && - (timevalcmp(&p->p_nlminfo->pid_start, - &ansp->la_msg_ident.pid_start, !=) || - p->p_nlminfo->msg_seq != ansp->la_msg_ident.msg_seq))) { - PROC_UNLOCK(p); - return (EPIPE); - } - - p->p_nlminfo->retcode = ansp->la_errno; - p->p_nlminfo->set_getlk_pid = ansp->la_set_getlk_pid; - p->p_nlminfo->getlk_pid = ansp->la_getlk_pid; - - (void)wakeup((void *)p->p_nlminfo); - - PROC_UNLOCK(p); - return (0); -} diff --git a/sys/nfs/nfs_lock.h b/sys/nfs/nfs_lock.h deleted file mode 100644 index 64b6c70..0000000 --- a/sys/nfs/nfs_lock.h +++ /dev/null @@ -1,112 +0,0 @@ -/*- - * Copyright (c) 1998 Berkeley Software Design, Inc. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Berkeley Software Design Inc's name may not be used to endorse or - * promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from nfs_lock.h,v 2.2 1998/04/28 19:38:41 don Exp - * $FreeBSD$ - */ - -/* - * lockd uses the nfssvc system call to get the unique kernel services it needs. - * It passes in a request structure with a version number at the start. - * This prevents libc from needing to change if the information passed - * between lockd and the kernel needs to change. - * - * If a structure changes, you must bump the version number. - */ - -#include - - -#define LOCKD_REQ_VERSION 1 - -struct lockd_req { - int vers; /* keep in sync with kernel please */ - int op; /* F_GETLK | F_SETLK | F_UNLCK */ - int owner; /* owner of lock, -1 to allocate one */ - int owner_rel_ok; /* release owner if no locks left ? */ - int *owner_ret; /* owner alloc/free result target */ - void *fh; /* NFS file handle */ - size_t fh_len; /* NFS file handle length */ - u_quad_t offset; /* offset of where to start lock */ - u_quad_t len; /* length of range to lock */ - int type; /* F_RDLCK | F_WRLCK | F_UNLCK */ - struct ucred cred; /* user credentials to use for lock */ - struct sockaddr saddr; /* XXX how about non AF_INET ?? */ - int pid; /* pid of lock requester */ -}; - -/* - * The fifo where the kernel writes requests for locks on remote NFS files, - * and where lockd reads these requests. - * - */ -#define _PATH_LCKFIFO "/var/run/lock" - -/* - * This structure is used to uniquely identify the process which originated - * a particular message to lockd. A sequence number is used to differentiate - * multiple messages from the same process. A process start time is used to - * detect the unlikely, but possible, event of the recycling of a pid. - */ -struct lockd_msg_ident { - pid_t pid; /* The process ID. */ - struct timeval pid_start; /* Start time of process id */ - int msg_seq; /* Sequence number of message */ -}; - -#define LOCKD_MSG_VERSION 1 - -/* - * The structure that the kernel hands us for each lock request. - */ -typedef struct __lock_msg { - int lm_version; /* which version is this */ - struct lockd_msg_ident lm_msg_ident; /* originator of the message */ - struct flock lm_fl; /* The lock request. */ - int lm_wait; /* The F_WAIT flag. */ - int lm_getlk; /* is this a F_GETLK request */ - struct sockaddr lm_addr; /* The address. */ - int lm_nfsv3; /* If NFS version 3. */ - size_t lm_fh_len; /* The file handle length. */ - struct ucred lm_cred; /* user cred for lock req */ - u_int8_t lm_fh[NFS_SMALLFH];/* The file handle. */ -} LOCKD_MSG; - -#define LOCKD_ANS_VERSION 1 - -struct lockd_ans { - int la_vers; - struct lockd_msg_ident la_msg_ident; /* originator of the message */ - int la_errno; - int la_set_getlk_pid; /* use returned pid */ - int la_getlk_pid; /* returned pid for F_GETLK */ -}; - -#ifdef _KERNEL -int nfs_dolock(struct vop_advlock_args *ap); -int nfslockdans(struct proc *p, struct lockd_ans *ansp); -int nfslockdreq(struct proc *p, struct lockd_req *reqp); -#endif diff --git a/sys/nfs/nfs_node.c b/sys/nfs/nfs_node.c deleted file mode 100644 index 5fe3abc..0000000 --- a/sys/nfs/nfs_node.c +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95 - * $FreeBSD$ - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -static vm_zone_t nfsnode_zone; -static LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl; -static u_long nfsnodehash; - -#define TRUE 1 -#define FALSE 0 - -/* - * Grab an atomic snapshot of the nfsnode hash chain lengths - */ -SYSCTL_DECL(_debug_hashstat); -static int -sysctl_debug_hashstat_rawnfsnode(SYSCTL_HANDLER_ARGS) -{ - int error; - struct nfsnodehashhead *nnpp; - struct nfsnode *nnp; - int n_nfsnode; - int count; - - n_nfsnode = nfsnodehash + 1; /* nfsnodehash = max index, not count */ - if (!req->oldptr) - return SYSCTL_OUT(req, 0, n_nfsnode * sizeof(int)); - - /* Scan hash tables for applicable entries */ - for (nnpp = nfsnodehashtbl; n_nfsnode > 0; n_nfsnode--, nnpp++) { - count = 0; - LIST_FOREACH(nnp, nnpp, n_hash) { - count++; - } - error = SYSCTL_OUT(req, (caddr_t)&count, sizeof(count)); - if (error) - return (error); - } - return (0); -} -SYSCTL_PROC(_debug_hashstat, OID_AUTO, rawnfsnode, CTLTYPE_INT|CTLFLAG_RD, - 0, 0, sysctl_debug_hashstat_rawnfsnode, "S,int", "nfsnode chain lengths"); - -static int -sysctl_debug_hashstat_nfsnode(SYSCTL_HANDLER_ARGS) -{ - int error; - struct nfsnodehashhead *nnpp; - struct nfsnode *nnp; - int n_nfsnode; - int count, maxlength, used, pct; - - if (!req->oldptr) - return SYSCTL_OUT(req, 0, 4 * sizeof(int)); - - n_nfsnode = nfsnodehash + 1; /* nfsnodehash = max index, not count */ - used = 0; - maxlength = 0; - - /* Scan hash tables for applicable entries */ - for (nnpp = nfsnodehashtbl; n_nfsnode > 0; n_nfsnode--, nnpp++) { - count = 0; - LIST_FOREACH(nnp, nnpp, n_hash) { - count++; - } - if (count) - used++; - if (maxlength < count) - maxlength = count; - } - n_nfsnode = nfsnodehash + 1; - pct = (used * 100 * 100) / n_nfsnode; - error = SYSCTL_OUT(req, (caddr_t)&n_nfsnode, sizeof(n_nfsnode)); - if (error) - return (error); - error = SYSCTL_OUT(req, (caddr_t)&used, sizeof(used)); - if (error) - return (error); - error = SYSCTL_OUT(req, (caddr_t)&maxlength, sizeof(maxlength)); - if (error) - return (error); - error = SYSCTL_OUT(req, (caddr_t)&pct, sizeof(pct)); - if (error) - return (error); - return (0); -} -SYSCTL_PROC(_debug_hashstat, OID_AUTO, nfsnode, CTLTYPE_INT|CTLFLAG_RD, - 0, 0, sysctl_debug_hashstat_nfsnode, "I", "nfsnode chain lengths"); - -/* - * Initialize hash links for nfsnodes - * and build nfsnode free list. - */ -void -nfs_nhinit() -{ - nfsnode_zone = zinit("NFSNODE", sizeof(struct nfsnode), 0, 0, 1); - nfsnodehashtbl = hashinit(desiredvnodes, M_NFSHASH, &nfsnodehash); -} - -/* - * Look up a vnode/nfsnode by file handle. - * Callers must check for mount points!! - * In all cases, a pointer to a - * nfsnode structure is returned. - */ -static int nfs_node_hash_lock; - -int -nfs_nget(mntp, fhp, fhsize, npp) - struct mount *mntp; - register nfsfh_t *fhp; - int fhsize; - struct nfsnode **npp; -{ - struct thread *td = curthread; /* XXX */ - struct nfsnode *np, *np2; - struct nfsnodehashhead *nhpp; - register struct vnode *vp; - struct vnode *nvp; - int error; - int rsflags; - struct nfsmount *nmp; - - /* - * Calculate nfs mount point and figure out whether the rslock should - * be interruptable or not. - */ - nmp = VFSTONFS(mntp); - if (nmp->nm_flag & NFSMNT_INT) - rsflags = PCATCH; - else - rsflags = 0; - -retry: - nhpp = NFSNOHASH(fnv_32_buf(fhp->fh_bytes, fhsize, FNV1_32_INIT)); -loop: - for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) { - if (mntp != NFSTOV(np)->v_mount || np->n_fhsize != fhsize || - bcmp((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize)) - continue; - vp = NFSTOV(np); - if (vget(vp, LK_EXCLUSIVE, td)) - goto loop; - *npp = np; - return(0); - } - /* - * Obtain a lock to prevent a race condition if the getnewvnode() - * or MALLOC() below happens to block. - */ - if (nfs_node_hash_lock) { - while (nfs_node_hash_lock) { - nfs_node_hash_lock = -1; - tsleep(&nfs_node_hash_lock, PVM, "nfsngt", 0); - } - goto loop; - } - nfs_node_hash_lock = 1; - - /* - * Allocate before getnewvnode since doing so afterward - * might cause a bogus v_data pointer to get dereferenced - * elsewhere if zalloc should block. - */ - np = zalloc(nfsnode_zone); - - error = getnewvnode(VT_NFS, mntp, nfsv2_vnodeop_p, &nvp); - if (error) { - if (nfs_node_hash_lock < 0) - wakeup(&nfs_node_hash_lock); - nfs_node_hash_lock = 0; - *npp = 0; - zfree(nfsnode_zone, np); - return (error); - } - vp = nvp; - bzero((caddr_t)np, sizeof *np); - vp->v_data = np; - np->n_vnode = vp; - /* - * Insert the nfsnode in the hash queue for its new file handle - */ - for (np2 = nhpp->lh_first; np2 != 0; np2 = np2->n_hash.le_next) { - if (mntp != NFSTOV(np2)->v_mount || np2->n_fhsize != fhsize || - bcmp((caddr_t)fhp, (caddr_t)np2->n_fhp, fhsize)) - continue; - vrele(vp); - if (nfs_node_hash_lock < 0) - wakeup(&nfs_node_hash_lock); - nfs_node_hash_lock = 0; - zfree(nfsnode_zone, np); - goto retry; - } - LIST_INSERT_HEAD(nhpp, np, n_hash); - if (fhsize > NFS_SMALLFH) { - MALLOC(np->n_fhp, nfsfh_t *, fhsize, M_NFSBIGFH, M_WAITOK); - } else - np->n_fhp = &np->n_fh; - bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize); - np->n_fhsize = fhsize; - lockinit(&np->n_rslock, PVFS | rsflags, "nfrslk", 0, LK_NOPAUSE); - lockinit(&vp->v_lock, PVFS, "nfsnlk", 0, LK_NOPAUSE); - *npp = np; - - if (nfs_node_hash_lock < 0) - wakeup(&nfs_node_hash_lock); - nfs_node_hash_lock = 0; - - /* - * Lock the new nfsnode. - */ - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - - return (0); -} - -int -nfs_inactive(ap) - struct vop_inactive_args /* { - struct vnode *a_vp; - struct thread *a_td; - } */ *ap; -{ - register struct nfsnode *np; - register struct sillyrename *sp; - struct thread *td = curthread; /* XXX */ - - np = VTONFS(ap->a_vp); - if (prtactive && ap->a_vp->v_usecount != 0) - vprint("nfs_inactive: pushing active", ap->a_vp); - if (ap->a_vp->v_type != VDIR) { - sp = np->n_sillyrename; - np->n_sillyrename = (struct sillyrename *)0; - } else - sp = (struct sillyrename *)0; - if (sp) { - /* - * We need a reference to keep the vnode from being - * recycled by getnewvnode while we do the I/O - * associated with discarding the buffers unless we - * are being forcibly unmounted in which case we already - * have our own reference. - */ - if (ap->a_vp->v_usecount > 0) - (void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, td, 1); - else if (vget(ap->a_vp, 0, td)) - panic("nfs_inactive: lost vnode"); - else { - (void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, td, 1); - vrele(ap->a_vp); - } - /* - * Remove the silly file that was rename'd earlier - */ - nfs_removeit(sp); - crfree(sp->s_cred); - vrele(sp->s_dvp); - FREE((caddr_t)sp, M_NFSREQ); - } - np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NQNFSEVICTED | - NQNFSNONCACHE | NQNFSWRITE); - VOP_UNLOCK(ap->a_vp, 0, ap->a_td); - return (0); -} - -/* - * Reclaim an nfsnode so that it can be used for other purposes. - */ -int -nfs_reclaim(ap) - struct vop_reclaim_args /* { - struct vnode *a_vp; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - register struct nfsnode *np = VTONFS(vp); - register struct nfsmount *nmp = VFSTONFS(vp->v_mount); - register struct nfsdmap *dp, *dp2; - - if (prtactive && vp->v_usecount != 0) - vprint("nfs_reclaim: pushing active", vp); - - if (np->n_hash.le_prev != NULL) - LIST_REMOVE(np, n_hash); - - /* - * For nqnfs, take it off the timer queue as required. - */ - if ((nmp->nm_flag & NFSMNT_NQNFS) && TAILQ_NEXT(np, n_timer) != 0) { - TAILQ_REMOVE(&nmp->nm_timerhead, np, n_timer); - } - - /* - * Free up any directory cookie structures and - * large file handle structures that might be associated with - * this nfs node. - */ - if (vp->v_type == VDIR) { - dp = np->n_cookies.lh_first; - while (dp) { - dp2 = dp; - dp = dp->ndm_list.le_next; - FREE((caddr_t)dp2, M_NFSDIROFF); - } - } - if (np->n_fhsize > NFS_SMALLFH) { - FREE((caddr_t)np->n_fhp, M_NFSBIGFH); - } - - lockdestroy(&np->n_rslock); - - cache_purge(vp); - zfree(nfsnode_zone, vp->v_data); - vp->v_data = (void *)0; - return (0); -} - -#if 0 -/* - * Lock an nfsnode - */ -int -nfs_lock(ap) - struct vop_lock_args /* { - struct vnode *a_vp; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - - /* - * Ugh, another place where interruptible mounts will get hung. - * If you make this sleep interruptible, then you have to fix all - * the VOP_LOCK() calls to expect interruptibility. - */ - while (vp->v_flag & VXLOCK) { - vp->v_flag |= VXWANT; - (void) tsleep((caddr_t)vp, PINOD, "nfslck", 0); - } - if (vp->v_tag == VT_NON) - return (ENOENT); - -#if 0 - /* - * Only lock regular files. If a server crashed while we were - * holding a directory lock, we could easily end up sleeping - * until the server rebooted while holding a lock on the root. - * Locks are only needed for protecting critical sections in - * VMIO at the moment. - * New vnodes will have type VNON but they should be locked - * since they may become VREG. This is checked in loadattrcache - * and unwanted locks are released there. - */ - if (vp->v_type == VREG || vp->v_type == VNON) { - while (np->n_flag & NLOCKED) { - np->n_flag |= NWANTED; - (void) tsleep((caddr_t) np, PINOD, "nfslck2", 0); - /* - * If the vnode has transmuted into a VDIR while we - * were asleep, then skip the lock. - */ - if (vp->v_type != VREG && vp->v_type != VNON) - return (0); - } - np->n_flag |= NLOCKED; - } -#endif - - return (0); -} - -/* - * Unlock an nfsnode - */ -int -nfs_unlock(ap) - struct vop_unlock_args /* { - struct vnode *a_vp; - } */ *ap; -{ -#if 0 - struct vnode* vp = ap->a_vp; - struct nfsnode* np = VTONFS(vp); - - if (vp->v_type == VREG || vp->v_type == VNON) { - if (!(np->n_flag & NLOCKED)) - panic("nfs_unlock: nfsnode not locked"); - np->n_flag &= ~NLOCKED; - if (np->n_flag & NWANTED) { - np->n_flag &= ~NWANTED; - wakeup((caddr_t) np); - } - } -#endif - - return (0); -} - -/* - * Check for a locked nfsnode - */ -int -nfs_islocked(ap) - struct vop_islocked_args /* { - struct vnode *a_vp; - struct thread *a_td; - } */ *ap; -{ - return VTONFS(ap->a_vp)->n_flag & NLOCKED ? 1 : 0; -} -#endif - diff --git a/sys/nfs/nfs_nqlease.c b/sys/nfs/nfs_nqlease.c deleted file mode 100644 index 86b5ef6..0000000 --- a/sys/nfs/nfs_nqlease.c +++ /dev/null @@ -1,1288 +0,0 @@ -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfs_nqlease.c 8.9 (Berkeley) 5/20/95 - * $FreeBSD$ - */ - - -/* - * References: - * Cary G. Gray and David R. Cheriton, "Leases: An Efficient Fault-Tolerant - * Mechanism for Distributed File Cache Consistency", - * In Proc. of the Twelfth ACM Symposium on Operating Systems - * Principals, pg. 202-210, Litchfield Park, AZ, Dec. 1989. - * Michael N. Nelson, Brent B. Welch and John K. Ousterhout, "Caching - * in the Sprite Network File System", ACM TOCS 6(1), - * pages 134-154, February 1988. - * V. Srinivasan and Jeffrey C. Mogul, "Spritely NFS: Implementation and - * Performance of Cache-Consistency Protocols", Digital - * Equipment Corporation WRL Research Report 89/5, May 1989. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static MALLOC_DEFINE(M_NQMHOST, "NQNFS Host", "Nqnfs host address table"); - -time_t nqnfsstarttime = (time_t)0; -int nqsrv_clockskew = NQ_CLOCKSKEW; -int nqsrv_writeslack = NQ_WRITESLACK; -int nqsrv_maxlease = NQ_MAXLEASE; -#ifndef NFS_NOSERVER -static int nqsrv_maxnumlease = NQ_MAXNUMLEASE; -#endif - -struct vop_lease_args; - -#ifndef NFS_NOSERVER -static int nqsrv_cmpnam __P((struct nfssvc_sock *, struct sockaddr *, - struct nqhost *)); -static int nqnfs_vacated __P((struct vnode *vp, struct ucred *cred)); -static void nqsrv_addhost __P((struct nqhost *lph, struct nfssvc_sock *slp, - struct sockaddr *nam)); -static void nqsrv_instimeq __P((struct nqlease *lp, u_int32_t duration)); -static void nqsrv_locklease __P((struct nqlease *lp)); -static void nqsrv_send_eviction __P((struct vnode *vp, struct nqlease *lp, - struct nfssvc_sock *slp, - struct sockaddr *nam, - struct ucred *cred)); -static void nqsrv_unlocklease __P((struct nqlease *lp)); -static void nqsrv_waitfor_expiry __P((struct nqlease *lp)); -#endif -extern void nqnfs_lease_updatetime __P((int deltat)); - -/* - * Signifies which rpcs can have piggybacked lease requests - */ -int nqnfs_piggy[NFS_NPROCS] = { - 0, - 0, - ND_WRITE, - ND_READ, - 0, - ND_READ, - ND_READ, - ND_WRITE, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ND_READ, - ND_READ, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, -}; - -extern nfstype nfsv2_type[9]; -extern nfstype nfsv3_type[9]; -extern int nfsd_waiting; -extern struct nfsstats nfsstats; - -#define TRUE 1 -#define FALSE 0 - -#ifndef NFS_NOSERVER -/* - * Get or check for a lease for "vp", based on ND_CHECK flag. - * The rules are as follows: - * - if a current non-caching lease, reply non-caching - * - if a current lease for same host only, extend lease - * - if a read cachable lease and a read lease request - * add host to list any reply cachable - * - else { set non-cachable for read-write sharing } - * send eviction notice messages to all other hosts that have lease - * wait for lease termination { either by receiving vacated messages - * from all the other hosts or expiry - * via. timeout } - * modify lease to non-cachable - * - else if no current lease, issue new one - * - reply - * - return boolean TRUE iff nam should be m_freem()'d - * NB: Since nqnfs_serverd() is called from a timer, any potential tsleep() - * in here must be framed by nqsrv_locklease() and nqsrv_unlocklease(). - * nqsrv_locklease() is coded such that at least one of LC_LOCKED and - * LC_WANTED is set whenever a process is tsleeping in it. The exception - * is when a new lease is being allocated, since it is not in the timer - * queue yet. (Ditto for the splsoftclock() and splx(s) calls) - */ -int -nqsrv_getlease(vp, duration, flags, slp, td, nam, cachablep, frev, cred) - struct vnode *vp; - u_int32_t *duration; - int flags; - struct nfssvc_sock *slp; - struct thread *td; - struct sockaddr *nam; - int *cachablep; - u_quad_t *frev; - struct ucred *cred; -{ - register struct nqlease *lp; - register struct nqfhhashhead *lpp = NULL; - register struct nqhost *lph = NULL; - struct nqlease *tlp; - struct nqm **lphp; - struct vattr vattr; - fhandle_t fh; - int i, ok, error, s; - - if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) - return (0); - if (*duration > nqsrv_maxlease) - *duration = nqsrv_maxlease; - error = VOP_GETATTR(vp, &vattr, cred, td); - if (error) - return (error); - *frev = vattr.va_filerev; - s = splsoftclock(); - tlp = vp->v_lease; - if ((flags & ND_CHECK) == 0) - nfsstats.srvnqnfs_getleases++; - if (tlp == 0) { - /* - * Find the lease by searching the hash list. - */ - fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; - error = VFS_VPTOFH(vp, &fh.fh_fid); - if (error) { - splx(s); - return (error); - } - lpp = NQFHHASH(fh.fh_fid.fid_data); - for (lp = lpp->lh_first; lp != 0; lp = lp->lc_hash.le_next) - if (fh.fh_fsid.val[0] == lp->lc_fsid.val[0] && - fh.fh_fsid.val[1] == lp->lc_fsid.val[1] && - !bcmp(fh.fh_fid.fid_data, lp->lc_fiddata, - fh.fh_fid.fid_len - sizeof (int32_t))) { - /* Found it */ - lp->lc_vp = vp; - vp->v_lease = lp; - tlp = lp; - break; - } - } else - lp = tlp; - if (lp != 0) { - if ((lp->lc_flag & LC_NONCACHABLE) || - (lp->lc_morehosts == (struct nqm *)0 && - nqsrv_cmpnam(slp, nam, &lp->lc_host))) - goto doreply; - if ((flags & ND_READ) && (lp->lc_flag & LC_WRITE) == 0) { - if (flags & ND_CHECK) - goto doreply; - if (nqsrv_cmpnam(slp, nam, &lp->lc_host)) - goto doreply; - i = 0; - if (lp->lc_morehosts) { - lph = lp->lc_morehosts->lpm_hosts; - lphp = &lp->lc_morehosts->lpm_next; - ok = 1; - } else { - lphp = &lp->lc_morehosts; - ok = 0; - } - while (ok && (lph->lph_flag & LC_VALID)) { - if (nqsrv_cmpnam(slp, nam, lph)) - goto doreply; - if (++i == LC_MOREHOSTSIZ) { - i = 0; - if (*lphp) { - lph = (*lphp)->lpm_hosts; - lphp = &((*lphp)->lpm_next); - } else - ok = 0; - } else - lph++; - } - nqsrv_locklease(lp); - if (!ok) { - *lphp = (struct nqm *) - malloc(sizeof (struct nqm), - M_NQMHOST, M_WAITOK | M_ZERO); - lph = (*lphp)->lpm_hosts; - } - nqsrv_addhost(lph, slp, nam); - nqsrv_unlocklease(lp); - } else { - lp->lc_flag |= LC_NONCACHABLE; - nqsrv_locklease(lp); - nqsrv_send_eviction(vp, lp, slp, nam, cred); - nqsrv_waitfor_expiry(lp); - nqsrv_unlocklease(lp); - } -doreply: - /* - * Update the lease and return - */ - if ((flags & ND_CHECK) == 0) - nqsrv_instimeq(lp, *duration); - if (lp->lc_flag & LC_NONCACHABLE) - *cachablep = 0; - else { - *cachablep = 1; - if (flags & ND_WRITE) - lp->lc_flag |= LC_WRITTEN; - } - splx(s); - return (0); - } - splx(s); - if (flags & ND_CHECK) - return (0); - - /* - * Allocate new lease - * The value of nqsrv_maxnumlease should be set generously, so that - * the following "printf" happens infrequently. - */ - if (nfsstats.srvnqnfs_leases > nqsrv_maxnumlease) { - printf("Nqnfs server, too many leases\n"); - do { - (void) tsleep((caddr_t)&lbolt, PSOCK, - "nqsrvnuml", 0); - } while (nfsstats.srvnqnfs_leases > nqsrv_maxnumlease); - } - MALLOC(lp, struct nqlease *, sizeof (struct nqlease), M_NQLEASE, - M_WAITOK | M_ZERO); - if (flags & ND_WRITE) - lp->lc_flag |= (LC_WRITE | LC_WRITTEN); - nqsrv_addhost(&lp->lc_host, slp, nam); - lp->lc_vp = vp; - lp->lc_fsid = fh.fh_fsid; - bcopy(fh.fh_fid.fid_data, lp->lc_fiddata, - fh.fh_fid.fid_len - sizeof (int32_t)); - if(!lpp) - panic("nfs_nqlease.c: Phoney lpp"); - LIST_INSERT_HEAD(lpp, lp, lc_hash); - vp->v_lease = lp; - s = splsoftclock(); - nqsrv_instimeq(lp, *duration); - splx(s); - *cachablep = 1; - if (++nfsstats.srvnqnfs_leases > nfsstats.srvnqnfs_maxleases) - nfsstats.srvnqnfs_maxleases = nfsstats.srvnqnfs_leases; - return (0); -} - -/* - * Local lease check for server syscalls. - * Just set up args and let nqsrv_getlease() do the rest. - * nqnfs_vop_lease_check() is the VOP_LEASE() form of the same routine. - * Ifdef'd code in nfsnode.h renames these routines to whatever a particular - * OS needs. - */ -void -nqnfs_lease_check(vp, td, cred, flag) - struct vnode *vp; - struct thread *td; - struct ucred *cred; - int flag; -{ - u_int32_t duration = 0; - int cache; - u_quad_t frev; - - (void) nqsrv_getlease(vp, &duration, ND_CHECK | flag, NQLOCALSLP, - td, (struct sockaddr *)0, &cache, &frev, cred); -} - -int -nqnfs_vop_lease_check(ap) - struct vop_lease_args /* { - struct vnode *a_vp; - struct thread *a_td; - struct ucred *a_cred; - int a_flag; - } */ *ap; -{ - u_int32_t duration = 0; - int cache; - u_quad_t frev; - - (void) nqsrv_getlease(ap->a_vp, &duration, ND_CHECK | ap->a_flag, - NQLOCALSLP, ap->a_td, (struct sockaddr *)0, - &cache, &frev, ap->a_cred); - return (0); -} - - -/* - * Add a host to an nqhost structure for a lease. - */ -static void -nqsrv_addhost(lph, slp, nam) - register struct nqhost *lph; - struct nfssvc_sock *slp; - struct sockaddr *nam; -{ - struct sockaddr_in *saddr; - struct socket *nsso; - - if (slp == NQLOCALSLP) { - lph->lph_flag |= (LC_VALID | LC_LOCAL); - return; - } - nsso = slp->ns_so; - lph->lph_slp = slp; - if (nsso && nsso->so_proto->pr_protocol == IPPROTO_UDP) { - saddr = (struct sockaddr_in *)nam; - lph->lph_flag |= (LC_VALID | LC_UDP); - lph->lph_inetaddr = saddr->sin_addr.s_addr; - lph->lph_port = saddr->sin_port; - } else { - lph->lph_flag |= (LC_VALID | LC_SREF); - slp->ns_sref++; - } -} - -/* - * Update the lease expiry time and position it in the timer queue correctly. - */ -static void -nqsrv_instimeq(lp, duration) - register struct nqlease *lp; - u_int32_t duration; -{ - register struct nqlease *tlp; - time_t newexpiry; - - newexpiry = time_second + duration + nqsrv_clockskew; - if (lp->lc_expiry == newexpiry) - return; - if (TAILQ_NEXT(lp, lc_timer) != 0) { - TAILQ_REMOVE(&nqtimerhead, lp, lc_timer); - } - lp->lc_expiry = newexpiry; - - /* - * Find where in the queue it should be. - */ - TAILQ_FOREACH_REVERSE(tlp, &nqtimerhead, nqtimerhead, lc_timer) - if (tlp->lc_expiry <= newexpiry) - break; -#ifdef HASNVRAM - if (tlp == TAILQ_LAST(&nqtimerhead)) - NQSTORENOVRAM(newexpiry); -#endif /* HASNVRAM */ - if (tlp == NULL) { - TAILQ_INSERT_HEAD(&nqtimerhead, lp, lc_timer); - } else { - TAILQ_INSERT_AFTER(&nqtimerhead, tlp, lp, lc_timer); - } -} - -/* - * Compare the requesting host address with the lph entry in the lease. - * Return true iff it is the same. - * This is somewhat messy due to the union in the nqhost structure. - * The local host is indicated by the special value of NQLOCALSLP for slp. - */ -static int -nqsrv_cmpnam(slp, nam, lph) - register struct nfssvc_sock *slp; - struct sockaddr *nam; - register struct nqhost *lph; -{ - register struct sockaddr_in *saddr; - struct sockaddr *addr; - union nethostaddr lhaddr; - struct socket *nsso; - int ret; - - if (slp == NQLOCALSLP) { - if (lph->lph_flag & LC_LOCAL) - return (1); - else - return (0); - } - nsso = slp->ns_so; - if (nsso && nsso->so_proto->pr_protocol == IPPROTO_UDP) { - addr = nam; - } else { - addr = slp->ns_nam; - } - if (lph->lph_flag & LC_UDP) { - ret = netaddr_match(AF_INET, &lph->lph_haddr, addr); - } else { - if ((lph->lph_slp->ns_flag & SLP_VALID) == 0) - return (0); - saddr = (struct sockaddr_in *)lph->lph_slp->ns_nam; - if (saddr->sin_family == AF_INET) - lhaddr.had_inetaddr = saddr->sin_addr.s_addr; - else - lhaddr.had_nam = lph->lph_slp->ns_nam; - ret = netaddr_match(saddr->sin_family, &lhaddr, addr); - } - return (ret); -} - -/* - * Send out eviction notice messages to all other hosts for the lease. - */ -static void -nqsrv_send_eviction(vp, lp, slp, nam, cred) - struct vnode *vp; - register struct nqlease *lp; - struct nfssvc_sock *slp; - struct sockaddr *nam; - struct ucred *cred; -{ - register struct nqhost *lph = &lp->lc_host; - register int siz; - struct nqm *lphnext = lp->lc_morehosts; - struct mbuf *m, *mreq, *mb, *mb2, *mheadend; - struct sockaddr *nam2; - struct sockaddr_in *saddr; - nfsfh_t nfh; - fhandle_t *fhp; - caddr_t bpos, cp; - u_int32_t xid, *tl; - int len = 1, ok = 1, i = 0; - - while (ok && (lph->lph_flag & LC_VALID)) { - if (nqsrv_cmpnam(slp, nam, lph)) { - lph->lph_flag |= LC_VACATED; - } else if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) { - struct socket *so; - int sotype; - int *solockp = NULL; - - so = lph->lph_slp->ns_so; - if (lph->lph_flag & LC_UDP) { - MALLOC(nam2, struct sockaddr *, - sizeof *nam2, M_SONAME, M_WAITOK); - saddr = (struct sockaddr_in *)nam2; - saddr->sin_len = sizeof *saddr; - saddr->sin_family = AF_INET; - saddr->sin_addr.s_addr = lph->lph_inetaddr; - saddr->sin_port = lph->lph_port; - } else if (lph->lph_slp->ns_flag & SLP_VALID) { - nam2 = (struct sockaddr *)0; - } else { - goto nextone; - } - sotype = so->so_type; - if (so->so_proto->pr_flags & PR_CONNREQUIRED) - solockp = &lph->lph_slp->ns_solock; - nfsm_reqhead((struct vnode *)0, NQNFSPROC_EVICTED, - NFSX_V3FH + NFSX_UNSIGNED); - fhp = &nfh.fh_generic; - bzero((caddr_t)fhp, sizeof(nfh)); - fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; - VFS_VPTOFH(vp, &fhp->fh_fid); - nfsm_srvfhtom(fhp, 1); - m = mreq; - siz = 0; - while (m) { - siz += m->m_len; - m = m->m_next; - } - if (siz <= 0 || siz > NFS_MAXPACKET) { - printf("mbuf siz=%d\n",siz); - panic("Bad nfs svc reply"); - } - m = nfsm_rpchead(cred, (NFSMNT_NFSV3 | NFSMNT_NQNFS), - NQNFSPROC_EVICTED, - RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0, - 0, (char *)NULL, mreq, siz, &mheadend, &xid); - /* - * For stream protocols, prepend a Sun RPC - * Record Mark. - */ - if (sotype == SOCK_STREAM) { - M_PREPEND(m, NFSX_UNSIGNED, M_TRYWAIT); - *mtod(m, u_int32_t *) = htonl(0x80000000 | - (m->m_pkthdr.len - NFSX_UNSIGNED)); - } - /* - * nfs_sndlock if PR_CONNREQUIRED XXX - */ - - if ((lph->lph_flag & LC_UDP) == 0 && - ((lph->lph_slp->ns_flag & SLP_VALID) == 0 || - nfs_slplock(lph->lph_slp, 0) == 0)) { - m_freem(m); - } else { - (void) nfs_send(so, nam2, m, - (struct nfsreq *)0); - if (solockp) - nfs_slpunlock(lph->lph_slp); - } - if (lph->lph_flag & LC_UDP) - FREE(nam2, M_SONAME); - } -nextone: - if (++i == len) { - if (lphnext) { - i = 0; - len = LC_MOREHOSTSIZ; - lph = lphnext->lpm_hosts; - lphnext = lphnext->lpm_next; - } else - ok = 0; - } else - lph++; - } -} - -/* - * Wait for the lease to expire. - * This will occur when all clients have sent "vacated" messages to - * this server OR when it expires do to timeout. - */ -static void -nqsrv_waitfor_expiry(lp) - register struct nqlease *lp; -{ - register struct nqhost *lph; - register int i; - struct nqm *lphnext; - int len, ok; - -tryagain: - if (time_second > lp->lc_expiry) - return; - lph = &lp->lc_host; - lphnext = lp->lc_morehosts; - len = 1; - i = 0; - ok = 1; - while (ok && (lph->lph_flag & LC_VALID)) { - if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) { - lp->lc_flag |= LC_EXPIREDWANTED; - (void) tsleep((caddr_t)&lp->lc_flag, PSOCK, - "nqexp", 0); - goto tryagain; - } - if (++i == len) { - if (lphnext) { - i = 0; - len = LC_MOREHOSTSIZ; - lph = lphnext->lpm_hosts; - lphnext = lphnext->lpm_next; - } else - ok = 0; - } else - lph++; - } -} - -/* - * Nqnfs server timer that maintains the server lease queue. - * Scan the lease queue for expired entries: - * - when one is found, wakeup anyone waiting for it - * else dequeue and free - */ -void -nqnfs_serverd() -{ - register struct nqlease *lp; - register struct nqhost *lph; - struct nqlease *nextlp; - struct nqm *lphnext, *olphnext; - int i, len, ok; - - for (lp = TAILQ_FIRST(&nqtimerhead); lp; lp = nextlp) { - if (lp->lc_expiry >= time_second) - break; - nextlp = TAILQ_NEXT(lp, lc_timer); - if (lp->lc_flag & LC_EXPIREDWANTED) { - lp->lc_flag &= ~LC_EXPIREDWANTED; - wakeup((caddr_t)&lp->lc_flag); - } else if ((lp->lc_flag & (LC_LOCKED | LC_WANTED)) == 0) { - /* - * Make a best effort at keeping a write caching lease long - * enough by not deleting it until it has been explicitly - * vacated or there have been no writes in the previous - * write_slack seconds since expiry and the nfsds are not - * all busy. The assumption is that if the nfsds are not - * all busy now (no queue of nfs requests), then the client - * would have been able to do at least one write to the - * file during the last write_slack seconds if it was still - * trying to push writes to the server. - */ - if ((lp->lc_flag & (LC_WRITE | LC_VACATED)) == LC_WRITE && - ((lp->lc_flag & LC_WRITTEN) || nfsd_waiting == 0)) { - lp->lc_flag &= ~LC_WRITTEN; - nqsrv_instimeq(lp, nqsrv_writeslack); - } else { - TAILQ_REMOVE(&nqtimerhead, lp, lc_timer); - LIST_REMOVE(lp, lc_hash); - /* - * This soft reference may no longer be valid, but - * no harm done. The worst case is if the vnode was - * recycled and has another valid lease reference, - * which is dereferenced prematurely. - */ - lp->lc_vp->v_lease = (struct nqlease *)0; - lph = &lp->lc_host; - lphnext = lp->lc_morehosts; - olphnext = (struct nqm *)0; - len = 1; - i = 0; - ok = 1; - while (ok && (lph->lph_flag & LC_VALID)) { - if (lph->lph_flag & LC_SREF) - nfsrv_slpderef(lph->lph_slp); - if (++i == len) { - if (olphnext) { - free((caddr_t)olphnext, M_NQMHOST); - olphnext = (struct nqm *)0; - } - if (lphnext) { - olphnext = lphnext; - i = 0; - len = LC_MOREHOSTSIZ; - lph = lphnext->lpm_hosts; - lphnext = lphnext->lpm_next; - } else - ok = 0; - } else - lph++; - } - FREE((caddr_t)lp, M_NQLEASE); - if (olphnext) - free((caddr_t)olphnext, M_NQMHOST); - nfsstats.srvnqnfs_leases--; - } - } - } -} - -/* - * Called from nfssvc_nfsd() for a getlease rpc request. - * Do the from/to xdr translation and call nqsrv_getlease() to - * do the real work. - */ -int -nqnfsrv_getlease(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - register struct nfs_fattr *fp; - struct vattr va; - register struct vattr *vap = &va; - struct vnode *vp; - nfsfh_t nfh; - fhandle_t *fhp; - register u_int32_t *tl; - register int32_t t1; - u_quad_t frev; - caddr_t bpos; - int error = 0; - char *cp2; - struct mbuf *mb, *mb2, *mreq; - int flags, rdonly, cache; - - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - flags = fxdr_unsigned(int, *tl++); - nfsd->nd_duration = fxdr_unsigned(int, *tl); - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, - (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(0); - goto nfsmout; - } - if (rdonly && flags == ND_WRITE) { - error = EROFS; - vput(vp); - nfsm_reply(0); - } - (void) nqsrv_getlease(vp, &nfsd->nd_duration, flags, slp, td, - nam, &cache, &frev, cred); - error = VOP_GETATTR(vp, vap, cred, td); - vput(vp); - nfsm_reply(NFSX_V3FATTR + 4 * NFSX_UNSIGNED); - nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); - *tl++ = txdr_unsigned(cache); - *tl++ = txdr_unsigned(nfsd->nd_duration); - txdr_hyper(frev, tl); - nfsm_build(fp, struct nfs_fattr *, NFSX_V3FATTR); - nfsm_srvfillattr(vap, fp); - nfsm_srvdone; -} - -/* - * Called from nfssvc_nfsd() when a "vacated" message is received from a - * client. Find the entry and expire it. - */ -int -nqnfsrv_vacated(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - register struct nqlease *lp; - register struct nqhost *lph; - struct nqlease *tlp = (struct nqlease *)0; - nfsfh_t nfh; - fhandle_t *fhp; - register u_int32_t *tl; - register int32_t t1; - struct nqm *lphnext; - struct mbuf *mreq, *mb; - int error = 0, i, len, ok, gotit = 0, cache = 0; - char *cp2, *bpos; - u_quad_t frev; - - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - m_freem(mrep); - /* - * Find the lease by searching the hash list. - */ - for (lp = NQFHHASH(fhp->fh_fid.fid_data)->lh_first; lp != 0; - lp = lp->lc_hash.le_next) - if (fhp->fh_fsid.val[0] == lp->lc_fsid.val[0] && - fhp->fh_fsid.val[1] == lp->lc_fsid.val[1] && - !bcmp(fhp->fh_fid.fid_data, lp->lc_fiddata, - MAXFIDSZ)) { - /* Found it */ - tlp = lp; - break; - } - if (tlp != 0) { - lp = tlp; - len = 1; - i = 0; - lph = &lp->lc_host; - lphnext = lp->lc_morehosts; - ok = 1; - while (ok && (lph->lph_flag & LC_VALID)) { - if (nqsrv_cmpnam(slp, nam, lph)) { - lph->lph_flag |= LC_VACATED; - gotit++; - break; - } - if (++i == len) { - if (lphnext) { - len = LC_MOREHOSTSIZ; - i = 0; - lph = lphnext->lpm_hosts; - lphnext = lphnext->lpm_next; - } else - ok = 0; - } else - lph++; - } - if ((lp->lc_flag & LC_EXPIREDWANTED) && gotit) { - lp->lc_flag &= ~LC_EXPIREDWANTED; - wakeup((caddr_t)&lp->lc_flag); - } -nfsmout: - return (EPERM); - } - return (EPERM); -} - -#endif /* NFS_NOSERVER */ - -/* - * Client get lease rpc function. - */ -int -nqnfs_getlease(vp, rwflag, cred, td) - register struct vnode *vp; - int rwflag; - struct ucred *cred; - struct thread *td; -{ - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - register struct nfsnode *np; - struct nfsmount *nmp = VFSTONFS(vp->v_mount); - caddr_t bpos, dpos, cp2; - time_t reqtime; - int error = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - int cachable; - u_quad_t frev; - - nfsstats.rpccnt[NQNFSPROC_GETLEASE]++; - mb = mreq = nfsm_reqh(vp, NQNFSPROC_GETLEASE, NFSX_V3FH+2*NFSX_UNSIGNED, - &bpos); - nfsm_fhtom(vp, 1); - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - *tl++ = txdr_unsigned(rwflag); - *tl = txdr_unsigned(nmp->nm_leaseterm); - reqtime = time_second; - nfsm_request(vp, NQNFSPROC_GETLEASE, td, cred); - np = VTONFS(vp); - nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED); - cachable = fxdr_unsigned(int, *tl++); - reqtime += fxdr_unsigned(int, *tl++); - if (reqtime > time_second) { - frev = fxdr_hyper(tl); - nqnfs_clientlease(nmp, np, rwflag, cachable, reqtime, frev); - nfsm_loadattr(vp, (struct vattr *)0); - } else - error = NQNFS_EXPIRED; - nfsm_reqdone; - return (error); -} - -#ifndef NFS_NOSERVER -/* - * Client vacated message function. - */ -static int -nqnfs_vacated(vp, cred) - register struct vnode *vp; - struct ucred *cred; -{ - register caddr_t cp; - register int i; - register u_int32_t *tl; - register int32_t t2; - caddr_t bpos; - u_int32_t xid; - int error = 0; - struct mbuf *m, *mreq, *mb, *mb2, *mheadend; - struct nfsmount *nmp; - struct nfsreq myrep; - - nmp = VFSTONFS(vp->v_mount); - nfsstats.rpccnt[NQNFSPROC_VACATED]++; - nfsm_reqhead(vp, NQNFSPROC_VACATED, NFSX_FH(1)); - nfsm_fhtom(vp, 1); - m = mreq; - i = 0; - while (m) { - i += m->m_len; - m = m->m_next; - } - m = nfsm_rpchead(cred, nmp->nm_flag, NQNFSPROC_VACATED, - RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0, - 0, (char *)NULL, mreq, i, &mheadend, &xid); - if (nmp->nm_sotype == SOCK_STREAM) { - M_PREPEND(m, NFSX_UNSIGNED, M_TRYWAIT); - *mtod(m, u_int32_t *) = htonl(0x80000000 | (m->m_pkthdr.len - - NFSX_UNSIGNED)); - } - myrep.r_flags = 0; - myrep.r_nmp = nmp; - if (nmp->nm_soflags & PR_CONNREQUIRED) - (void) nfs_sndlock(&myrep); - (void) nfs_send(nmp->nm_so, nmp->nm_nam, m, &myrep); - if (nmp->nm_soflags & PR_CONNREQUIRED) - nfs_sndunlock(&myrep); -nfsmout: - return (error); -} - -/* - * Called for client side callbacks - */ -int -nqnfs_callback(nmp, mrep, md, dpos) - struct nfsmount *nmp; - struct mbuf *mrep, *md; - caddr_t dpos; -{ - register struct vnode *vp; - register u_int32_t *tl; - register int32_t t1; - nfsfh_t nfh; - fhandle_t *fhp; - struct nfsnode *np; - struct nfsd tnfsd; - struct nfssvc_sock *slp; - struct nfsrv_descript ndesc; - register struct nfsrv_descript *nfsd = &ndesc; - struct mbuf **mrq = (struct mbuf **)0, *mb, *mreq; - int error = 0, cache = 0; - char *cp2, *bpos; - u_quad_t frev; - -#ifndef nolint - slp = NULL; -#endif - nfsd->nd_mrep = mrep; - nfsd->nd_md = md; - nfsd->nd_dpos = dpos; - error = nfs_getreq(nfsd, &tnfsd, FALSE); - if (error) - return (error); - md = nfsd->nd_md; - dpos = nfsd->nd_dpos; - if (nfsd->nd_procnum != NQNFSPROC_EVICTED) { - m_freem(mrep); - return (EPERM); - } - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - m_freem(mrep); - error = nfs_nget(nmp->nm_mountp, (nfsfh_t *)fhp, NFSX_V3FH, &np); - if (error) - return (error); - vp = NFSTOV(np); - if (TAILQ_NEXT(np, n_timer) != 0) { - np->n_expiry = 0; - np->n_flag |= NQNFSEVICTED; - if (TAILQ_FIRST(&nmp->nm_timerhead) != np) { - TAILQ_REMOVE(&nmp->nm_timerhead, np, n_timer); - TAILQ_INSERT_HEAD(&nmp->nm_timerhead, np, n_timer); - } - } - vput(vp); - nfsm_srvdone; -} - - -/* - * Nqnfs client helper daemon. Runs once a second to expire leases. - * It also get authorization strings for "kerb" mounts. - * It must start at the beginning of the list again after any potential - * "sleep" since nfs_reclaim() called from vclean() can pull a node off - * the list asynchronously. - */ -int -nqnfs_clientd(nmp, cred, ncd, flag, argp, td) - register struct nfsmount *nmp; - struct ucred *cred; - struct nfsd_cargs *ncd; - int flag; - caddr_t argp; - struct thread *td; -{ - register struct nfsnode *np; - struct vnode *vp; - struct nfsreq myrep; - struct nfsuid *nuidp, *nnuidp; - int error = 0, vpid; - - /* - * First initialize some variables - */ - - /* - * If an authorization string is being passed in, get it. - */ - if ((flag & NFSSVC_GOTAUTH) && - (nmp->nm_state & (NFSSTA_WAITAUTH | NFSSTA_DISMNT)) == 0) { - if (nmp->nm_state & NFSSTA_HASAUTH) - panic("cld kerb"); - if ((flag & NFSSVC_AUTHINFAIL) == 0) { - if (ncd->ncd_authlen <= nmp->nm_authlen && - ncd->ncd_verflen <= nmp->nm_verflen && - !copyin(ncd->ncd_authstr,nmp->nm_authstr,ncd->ncd_authlen)&& - !copyin(ncd->ncd_verfstr,nmp->nm_verfstr,ncd->ncd_verflen)){ - nmp->nm_authtype = ncd->ncd_authtype; - nmp->nm_authlen = ncd->ncd_authlen; - nmp->nm_verflen = ncd->ncd_verflen; -#ifdef NFSKERB - nmp->nm_key = ncd->ncd_key; -#endif - } else - nmp->nm_state |= NFSSTA_AUTHERR; - } else - nmp->nm_state |= NFSSTA_AUTHERR; - nmp->nm_state |= NFSSTA_HASAUTH; - wakeup((caddr_t)&nmp->nm_authlen); - } else - nmp->nm_state |= NFSSTA_WAITAUTH; - - /* - * Loop every second updating queue until there is a termination sig. - */ - while ((nmp->nm_state & NFSSTA_DISMNT) == 0) { - if (nmp->nm_flag & NFSMNT_NQNFS) { - /* - * If there are no outstanding requests (and therefore no - * processes in nfs_reply) and there is data in the receive - * queue, poke for callbacks. - */ - if (nfs_reqq.tqh_first == 0 && nmp->nm_so && - nmp->nm_so->so_rcv.sb_cc > 0) { - myrep.r_flags = R_GETONEREP; - myrep.r_nmp = nmp; - myrep.r_mrep = (struct mbuf *)0; - myrep.r_td = (struct thread *)0; - (void) nfs_reply(&myrep); - } - - /* - * Loop through the leases, updating as required. - */ - while ((np = TAILQ_FIRST(&nmp->nm_timerhead)) != NULL) { - if (nmp->nm_state & NFSSTA_DISMINPROG) - break; - vp = NFSTOV(np); - vpid = vp->v_id; - if (np->n_expiry < time_second) { - if (vget(vp, LK_EXCLUSIVE, td) == 0) { - nmp->nm_inprog = vp; - if (vpid == vp->v_id) { - TAILQ_REMOVE(&nmp->nm_timerhead, np, n_timer); - TAILQ_NEXT(np, n_timer) = 0; - if (np->n_flag & (NMODIFIED | NQNFSEVICTED)) { - if (np->n_flag & NQNFSEVICTED) { - if (vp->v_type == VDIR) - nfs_invaldir(vp); - cache_purge(vp); - (void) nfs_vinvalbuf(vp, - V_SAVE, cred, td, 0); - np->n_flag &= ~NQNFSEVICTED; - (void) nqnfs_vacated(vp, cred); - } else if (vp->v_type == VREG) { - (void) VOP_FSYNC(vp, cred, - MNT_WAIT, td); - np->n_flag &= ~NMODIFIED; - } - } - } - vput(vp); - nmp->nm_inprog = NULLVP; - } - } else if ((np->n_expiry - NQ_RENEWAL) < time_second) { - if ((np->n_flag & (NQNFSWRITE | NQNFSNONCACHE)) - == NQNFSWRITE && - !TAILQ_EMPTY(&vp->v_dirtyblkhd) && - vget(vp, LK_EXCLUSIVE, td) == 0) { - nmp->nm_inprog = vp; - if (vpid == vp->v_id && - nqnfs_getlease(vp, ND_WRITE, cred, td)==0) - np->n_brev = np->n_lrev; - vput(vp); - nmp->nm_inprog = NULLVP; - } - } else - break; - } - } - - /* - * Get an authorization string, if required. - */ - if ((nmp->nm_state & (NFSSTA_WAITAUTH | NFSSTA_DISMNT | NFSSTA_HASAUTH)) == 0) { - ncd->ncd_authuid = nmp->nm_authuid; - if (copyout((caddr_t)ncd, argp, sizeof (struct nfsd_cargs))) - nmp->nm_state |= NFSSTA_WAITAUTH; - else - return (ENEEDAUTH); - } - - /* - * Wait a bit (no pun) and do it again. - */ - if ((nmp->nm_state & NFSSTA_DISMNT) == 0 && - (nmp->nm_state & (NFSSTA_WAITAUTH | NFSSTA_HASAUTH))) { - error = tsleep((caddr_t)&nmp->nm_authstr, PSOCK | PCATCH, - "nqnfstimr", hz / 3); - if (error == EINTR || error == ERESTART) - (void) dounmount(nmp->nm_mountp, 0, td); - } - } - - /* - * Finally, we can free up the mount structure. - */ - for (nuidp = nmp->nm_uidlruhead.tqh_first; nuidp != 0; nuidp = nnuidp) { - nnuidp = nuidp->nu_lru.tqe_next; - LIST_REMOVE(nuidp, nu_hash); - TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); - free((caddr_t)nuidp, M_NFSUID); - } - zfree(nfsmount_zone, nmp); - if (error == EWOULDBLOCK) - error = 0; - return (error); -} - -#endif /* NFS_NOSERVER */ - -/* - * Adjust all timer queue expiry times when the time of day clock is changed. - * Called from the settimeofday() syscall. - */ -void -nqnfs_lease_updatetime(deltat) - register int deltat; -{ - struct thread *td = curthread; /* XXX */ - struct nqlease *lp; - struct nfsnode *np; - struct mount *mp, *nxtmp; - struct nfsmount *nmp; - int s; - - if (nqnfsstarttime != 0) - nqnfsstarttime += deltat; - s = splsoftclock(); - TAILQ_FOREACH(lp, &nqtimerhead, lc_timer) - lp->lc_expiry += deltat; - splx(s); - - /* - * Search the mount list for all nqnfs mounts and do their timer - * queues. - */ - mtx_lock(&mountlist_mtx); - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nxtmp) { - if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) { - nxtmp = TAILQ_NEXT(mp, mnt_list); - continue; - } - if (mp->mnt_stat.f_type == nfs_mount_type) { - nmp = VFSTONFS(mp); - if (nmp->nm_flag & NFSMNT_NQNFS) { - TAILQ_FOREACH(np, &nmp->nm_timerhead, n_timer) { - np->n_expiry += deltat; - } - } - } - mtx_lock(&mountlist_mtx); - nxtmp = TAILQ_NEXT(mp, mnt_list); - vfs_unbusy(mp, td); - } - mtx_unlock(&mountlist_mtx); -} - -#ifndef NFS_NOSERVER -/* - * Lock a server lease. - */ -static void -nqsrv_locklease(lp) - struct nqlease *lp; -{ - - while (lp->lc_flag & LC_LOCKED) { - lp->lc_flag |= LC_WANTED; - (void) tsleep((caddr_t)lp, PSOCK, "nqlc", 0); - } - lp->lc_flag |= LC_LOCKED; - lp->lc_flag &= ~LC_WANTED; -} - -/* - * Unlock a server lease. - */ -static void -nqsrv_unlocklease(lp) - struct nqlease *lp; -{ - - lp->lc_flag &= ~LC_LOCKED; - if (lp->lc_flag & LC_WANTED) - wakeup((caddr_t)lp); -} -#endif /* NFS_NOSERVER */ - -/* - * Update a client lease. - */ -void -nqnfs_clientlease(nmp, np, rwflag, cachable, expiry, frev) - register struct nfsmount *nmp; - register struct nfsnode *np; - int rwflag, cachable; - time_t expiry; - u_quad_t frev; -{ - register struct nfsnode *tp; - - if (TAILQ_NEXT(np, n_timer) != 0) { - TAILQ_REMOVE(&nmp->nm_timerhead, np, n_timer); - if (rwflag == ND_WRITE) - np->n_flag |= NQNFSWRITE; - } else if (rwflag == ND_READ) - np->n_flag &= ~NQNFSWRITE; - else - np->n_flag |= NQNFSWRITE; - if (cachable) - np->n_flag &= ~NQNFSNONCACHE; - else - np->n_flag |= NQNFSNONCACHE; - np->n_expiry = expiry; - np->n_lrev = frev; - TAILQ_FOREACH_REVERSE(tp, &nmp->nm_timerhead, timhd, n_timer) - if (tp->n_expiry <= np->n_expiry) - break; - if (tp == NULL) { - TAILQ_INSERT_HEAD(&nmp->nm_timerhead, np, n_timer); - } else { - TAILQ_INSERT_AFTER(&nmp->nm_timerhead, tp, np, n_timer); - } -} diff --git a/sys/nfs/nfs_serv.c b/sys/nfs/nfs_serv.c deleted file mode 100644 index 0469388..0000000 --- a/sys/nfs/nfs_serv.c +++ /dev/null @@ -1,4235 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfs_serv.c 8.8 (Berkeley) 7/31/95 - * $FreeBSD$ - */ - -/* - * nfs version 2 and 3 server calls to vnode ops - * - these routines generally have 3 phases - * 1 - break down and validate rpc request in mbuf list - * 2 - do the vnode ops for the request - * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c) - * 3 - build the rpc reply in an mbuf list - * nb: - * - do not mix the phases, since the nfsm_?? macros can return failures - * on a bad rpc or similar and do not do any vrele() or vput()'s - * - * - the nfsm_reply() macro generates an nfs rpc reply with the nfs - * error number iff error != 0 whereas - * returning an error from the server function implies a fatal error - * such as a badly constructed rpc request that should be dropped without - * a reply. - * For Version 3, nfsm_reply() does not return for the error case, since - * most version 3 rpcs return more than the status for error cases. - * - * Other notes: - * Warning: always pay careful attention to resource cleanup on return - * and note that nfsm_*() macros can terminate a procedure on certain - * errors. - * - * lookup() and namei() - * may return garbage in various structural fields/return elements - * if an error is returned, and may garbage up nd.ni_dvp even if no - * error is returned and you did not request LOCKPARENT or WANTPARENT. - * - * We use the ni_cnd.cn_flags 'HASBUF' flag to track whether the name - * buffer has been freed or not. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef NFSRV_DEBUG -#define nfsdbprintf(info) printf info -#else -#define nfsdbprintf(info) -#endif - -#define MAX_COMMIT_COUNT (1024 * 1024) - -#define NUM_HEURISTIC 64 -#define NHUSE_INIT 64 -#define NHUSE_INC 16 -#define NHUSE_MAX 2048 - -static struct nfsheur { - struct vnode *nh_vp; /* vp to match (unreferenced pointer) */ - off_t nh_nextr; /* next offset for sequential detection */ - int nh_use; /* use count for selection */ - int nh_seqcount; /* heuristic */ -} nfsheur[NUM_HEURISTIC]; - -nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, - NFFIFO, NFNON }; -#ifndef NFS_NOSERVER -nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, - NFCHR, NFNON }; -/* Global vars */ -extern u_int32_t nfs_xdrneg1; -extern u_int32_t nfs_false, nfs_true; -extern enum vtype nv3tov_type[8]; -extern struct nfsstats nfsstats; - -int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000; -int nfsrvw_procrastinate_v3 = 0; - -static struct timeval nfsver = { 0 }; - -SYSCTL_DECL(_vfs_nfs); - -static int nfs_async; -SYSCTL_INT(_vfs_nfs, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, ""); -static int nfs_commit_blks; -static int nfs_commit_miss; -SYSCTL_INT(_vfs_nfs, OID_AUTO, commit_blks, CTLFLAG_RW, &nfs_commit_blks, 0, ""); -SYSCTL_INT(_vfs_nfs, OID_AUTO, commit_miss, CTLFLAG_RW, &nfs_commit_miss, 0, ""); - -static int nfsrv_access __P((struct vnode *,int,struct ucred *,int, - struct thread *, int)); -static void nfsrvw_coalesce __P((struct nfsrv_descript *, - struct nfsrv_descript *)); - -/* - * Clear nameidata fields that are tested in nsfmout cleanup code prior - * to using first nfsm macro (that might jump to the cleanup code). - */ - -static __inline -void -ndclear(struct nameidata *nd) -{ - nd->ni_cnd.cn_flags = 0; - nd->ni_vp = NULL; - nd->ni_dvp = NULL; - nd->ni_startdir = NULL; -} - -/* - * nfs v3 access service - */ -int -nfsrv3_access(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - struct vnode *vp = NULL; - nfsfh_t nfh; - fhandle_t *fhp; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, rdonly, cache, getret; - char *cp2; - struct mbuf *mb, *mreq, *mb2; - struct vattr vattr, *vap = &vattr; - u_long testmode, nfsmode; - u_quad_t frev; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - cache = 0; -#endif - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, - (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(NFSX_UNSIGNED); - nfsm_srvpostop_attr(1, (struct vattr *)0); - error = 0; - goto nfsmout; - } - nfsmode = fxdr_unsigned(u_int32_t, *tl); - if ((nfsmode & NFSV3ACCESS_READ) && - nfsrv_access(vp, VREAD, cred, rdonly, td, 0)) - nfsmode &= ~NFSV3ACCESS_READ; - if (vp->v_type == VDIR) - testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND | - NFSV3ACCESS_DELETE); - else - testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND); - if ((nfsmode & testmode) && - nfsrv_access(vp, VWRITE, cred, rdonly, td, 0)) - nfsmode &= ~testmode; - if (vp->v_type == VDIR) - testmode = NFSV3ACCESS_LOOKUP; - else - testmode = NFSV3ACCESS_EXECUTE; - if ((nfsmode & testmode) && - nfsrv_access(vp, VEXEC, cred, rdonly, td, 0)) - nfsmode &= ~testmode; - getret = VOP_GETATTR(vp, vap, cred, td); - vput(vp); - vp = NULL; - nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED); - nfsm_srvpostop_attr(getret, vap); - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); - *tl = txdr_unsigned(nfsmode); -nfsmout: - if (vp) - vput(vp); - return(error); -} - -/* - * nfs getattr service - */ -int -nfsrv_getattr(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - register struct nfs_fattr *fp; - struct vattr va; - register struct vattr *vap = &va; - struct vnode *vp = NULL; - nfsfh_t nfh; - fhandle_t *fhp; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, rdonly, cache; - char *cp2; - struct mbuf *mb, *mb2, *mreq; - u_quad_t frev; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(0); - error = 0; - goto nfsmout; - } - nqsrv_getl(vp, ND_READ); - error = VOP_GETATTR(vp, vap, cred, td); - vput(vp); - vp = NULL; - nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); - if (error) { - error = 0; - goto nfsmout; - } - nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); - nfsm_srvfillattr(vap, fp); - /* fall through */ - -nfsmout: - if (vp) - vput(vp); - return(error); -} - -/* - * nfs setattr service - */ -int -nfsrv_setattr(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - struct vattr va, preat; - register struct vattr *vap = &va; - register struct nfsv2_sattr *sp; - register struct nfs_fattr *fp; - struct vnode *vp = NULL; - nfsfh_t nfh; - fhandle_t *fhp; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1; - int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0; - char *cp2; - struct mbuf *mb, *mb2, *mreq; - u_quad_t frev; - struct timespec guard; - struct mount *mp = NULL; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { - error = ESTALE; - goto out; - } - if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != 0) { - mp = NULL; - goto out; - } - (void) vn_start_write(vp, &mp, V_WAIT); - vput(vp); - vp = NULL; - VATTR_NULL(vap); - if (v3) { - nfsm_srvsattr(vap); - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - gcheck = fxdr_unsigned(int, *tl); - if (gcheck) { - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - fxdr_nfsv3time(tl, &guard); - } - } else { - nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); - /* - * Nah nah nah nah na nah - * There is a bug in the Sun client that puts 0xffff in the mode - * field of sattr when it should put in 0xffffffff. The u_short - * doesn't sign extend. - * --> check the low order 2 bytes for 0xffff - */ - if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) - vap->va_mode = nfstov_mode(sp->sa_mode); - if (sp->sa_uid != nfs_xdrneg1) - vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid); - if (sp->sa_gid != nfs_xdrneg1) - vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid); - if (sp->sa_size != nfs_xdrneg1) - vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size); - if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) { -#ifdef notyet - fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime); -#else - vap->va_atime.tv_sec = - fxdr_unsigned(int32_t, sp->sa_atime.nfsv2_sec); - vap->va_atime.tv_nsec = 0; -#endif - } - if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1) - fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime); - - } - - /* - * Now that we have all the fields, lets do it. - */ - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, - (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(2 * NFSX_UNSIGNED); - nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); - error = 0; - goto nfsmout; - } - - /* - * vp now an active resource, pay careful attention to cleanup - */ - - nqsrv_getl(vp, ND_WRITE); - if (v3) { - error = preat_ret = VOP_GETATTR(vp, &preat, cred, td); - if (!error && gcheck && - (preat.va_ctime.tv_sec != guard.tv_sec || - preat.va_ctime.tv_nsec != guard.tv_nsec)) - error = NFSERR_NOT_SYNC; - if (error) { - vput(vp); - vp = NULL; - nfsm_reply(NFSX_WCCDATA(v3)); - nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); - error = 0; - goto nfsmout; - } - } - - /* - * If the size is being changed write acces is required, otherwise - * just check for a read only file system. - */ - if (vap->va_size == ((u_quad_t)((quad_t) -1))) { - if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { - error = EROFS; - goto out; - } - } else { - if (vp->v_type == VDIR) { - error = EISDIR; - goto out; - } else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly, - td, 0)) != 0) - goto out; - } - error = VOP_SETATTR(vp, vap, cred, td); - postat_ret = VOP_GETATTR(vp, vap, cred, td); - if (!error) - error = postat_ret; -out: - if (vp != NULL) - vput(vp); - vp = NULL; - nfsm_reply(NFSX_WCCORFATTR(v3)); - if (v3) { - nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); - error = 0; - goto nfsmout; - } else { - /* v2 non-error case (see nfsm_reply). */ - nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); - nfsm_srvfillattr(vap, fp); - } - /* fall through */ - -nfsmout: - if (vp) - vput(vp); - vn_finished_write(mp); - return(error); -} - -/* - * nfs lookup rpc - */ -int -nfsrv_lookup(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - register struct nfs_fattr *fp; - struct nameidata nd, ind, *ndp = &nd; - struct vnode *vp, *dirp = NULL; - nfsfh_t nfh; - fhandle_t *fhp; - register caddr_t cp; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, cache, len, dirattr_ret = 1; - int v3 = (nfsd->nd_flag & ND_NFSV3), pubflag; - char *cp2; - struct mbuf *mb, *mb2, *mreq; - struct vattr va, dirattr, *vap = &va; - u_quad_t frev; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - ndclear(&nd); - - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - nfsm_srvnamesiz(len); - - pubflag = nfs_ispublicfh(fhp); - - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = LOOKUP; - nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), pubflag); - - /* - * namei failure, only dirp to cleanup. Clear out garbarge from - * structure in case macros jump to nfsmout. - */ - - if (error) { - if (dirp) { - if (v3) - dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred, - td); - vrele(dirp); - dirp = NULL; - } - nfsm_reply(NFSX_POSTOPATTR(v3)); - nfsm_srvpostop_attr(dirattr_ret, &dirattr); - error = 0; - goto nfsmout; - } - - /* - * Locate index file for public filehandle - * - * error is 0 on entry and 0 on exit from this block. - */ - - if (pubflag) { - if (nd.ni_vp->v_type == VDIR && nfs_pub.np_index != NULL) { - /* - * Setup call to lookup() to see if we can find - * the index file. Arguably, this doesn't belong - * in a kernel.. Ugh. If an error occurs, do not - * try to install an index file and then clear the - * error. - * - * When we replace nd with ind and redirect ndp, - * maintenance of ni_startdir and ni_vp shift to - * ind and we have to clean them up in the old nd. - * However, the cnd resource continues to be maintained - * via the original nd. Confused? You aren't alone! - */ - ind = nd; - VOP_UNLOCK(nd.ni_vp, 0, td); - ind.ni_pathlen = strlen(nfs_pub.np_index); - ind.ni_cnd.cn_nameptr = ind.ni_cnd.cn_pnbuf = - nfs_pub.np_index; - ind.ni_startdir = nd.ni_vp; - VREF(ind.ni_startdir); - - error = lookup(&ind); - ind.ni_dvp = NULL; - - if (error == 0) { - /* - * Found an index file. Get rid of - * the old references. transfer nd.ni_vp' - */ - if (dirp) - vrele(dirp); - dirp = nd.ni_vp; - nd.ni_vp = NULL; - vrele(nd.ni_startdir); - nd.ni_startdir = NULL; - ndp = &ind; - } - error = 0; - } - /* - * If the public filehandle was used, check that this lookup - * didn't result in a filehandle outside the publicly exported - * filesystem. We clear the poor vp here to avoid lockups due - * to NFS I/O. - */ - - if (ndp->ni_vp->v_mount != nfs_pub.np_mount) { - vput(nd.ni_vp); - nd.ni_vp = NULL; - error = EPERM; - } - } - - if (dirp) { - if (v3) - dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred, - td); - vrele(dirp); - dirp = NULL; - } - - /* - * Resources at this point: - * ndp->ni_vp may not be NULL - * - */ - - if (error) { - nfsm_reply(NFSX_POSTOPATTR(v3)); - nfsm_srvpostop_attr(dirattr_ret, &dirattr); - error = 0; - goto nfsmout; - } - - nqsrv_getl(ndp->ni_startdir, ND_READ); - - /* - * Clear out some resources prior to potentially blocking. This - * is not as critical as ni_dvp resources in other routines, but - * it helps. - */ - vrele(ndp->ni_startdir); - ndp->ni_startdir = NULL; - NDFREE(&nd, NDF_ONLY_PNBUF); - - /* - * Get underlying attribute, then release remaining resources ( for - * the same potential blocking reason ) and reply. - */ - vp = ndp->ni_vp; - bzero((caddr_t)fhp, sizeof(nfh)); - fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; - error = VFS_VPTOFH(vp, &fhp->fh_fid); - if (!error) - error = VOP_GETATTR(vp, vap, cred, td); - - vput(vp); - ndp->ni_vp = NULL; - nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3)); - if (error) { - nfsm_srvpostop_attr(dirattr_ret, &dirattr); - error = 0; - goto nfsmout; - } - nfsm_srvfhtom(fhp, v3); - if (v3) { - nfsm_srvpostop_attr(0, vap); - nfsm_srvpostop_attr(dirattr_ret, &dirattr); - } else { - nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); - nfsm_srvfillattr(vap, fp); - } - -nfsmout: - if (dirp) - vrele(dirp); - NDFREE(&nd, NDF_ONLY_PNBUF); - if (ndp->ni_startdir) - vrele(ndp->ni_startdir); - if (ndp->ni_vp) - vput(ndp->ni_vp); - return (error); -} - -/* - * nfs readlink service - */ -int -nfsrv_readlink(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; - register struct iovec *ivp = iv; - register struct mbuf *mp; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, rdonly, cache, i, tlen, len, getret; - int v3 = (nfsd->nd_flag & ND_NFSV3); - char *cp2; - struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; - struct vnode *vp = NULL; - struct vattr attr; - nfsfh_t nfh; - fhandle_t *fhp; - struct uio io, *uiop = &io; - u_quad_t frev; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - mp2 = (struct mbuf *)0; -#endif - mp3 = NULL; - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - len = 0; - i = 0; - while (len < NFS_MAXPATHLEN) { - MGET(mp, M_TRYWAIT, MT_DATA); - MCLGET(mp, M_TRYWAIT); - mp->m_len = NFSMSIZ(mp); - if (len == 0) - mp3 = mp2 = mp; - else { - mp2->m_next = mp; - mp2 = mp; - } - if ((len+mp->m_len) > NFS_MAXPATHLEN) { - mp->m_len = NFS_MAXPATHLEN-len; - len = NFS_MAXPATHLEN; - } else - len += mp->m_len; - ivp->iov_base = mtod(mp, caddr_t); - ivp->iov_len = mp->m_len; - i++; - ivp++; - } - uiop->uio_iov = iv; - uiop->uio_iovcnt = i; - uiop->uio_offset = 0; - uiop->uio_resid = len; - uiop->uio_rw = UIO_READ; - uiop->uio_segflg = UIO_SYSSPACE; - uiop->uio_td = (struct thread *)0; - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(2 * NFSX_UNSIGNED); - nfsm_srvpostop_attr(1, (struct vattr *)0); - error = 0; - goto nfsmout; - } - if (vp->v_type != VLNK) { - if (v3) - error = EINVAL; - else - error = ENXIO; - goto out; - } - nqsrv_getl(vp, ND_READ); - error = VOP_READLINK(vp, uiop, cred); -out: - getret = VOP_GETATTR(vp, &attr, cred, td); - vput(vp); - vp = NULL; - nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED); - if (v3) { - nfsm_srvpostop_attr(getret, &attr); - if (error) { - error = 0; - goto nfsmout; - } - } - if (uiop->uio_resid > 0) { - len -= uiop->uio_resid; - tlen = nfsm_rndup(len); - nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); - } - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); - *tl = txdr_unsigned(len); - mb->m_next = mp3; - mp3 = NULL; -nfsmout: - if (mp3) - m_freem(mp3); - if (vp) - vput(vp); - return(error); -} - -/* - * nfs read service - */ -int -nfsrv_read(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - register struct iovec *iv; - struct iovec *iv2; - register struct mbuf *m; - register struct nfs_fattr *fp; - register u_int32_t *tl; - register int32_t t1; - register int i; - caddr_t bpos; - int error = 0, rdonly, cache, cnt, len, left, siz, tlen, getret; - int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen; - char *cp2; - struct mbuf *mb, *mb2, *mreq; - struct mbuf *m2; - struct vnode *vp = NULL; - nfsfh_t nfh; - fhandle_t *fhp; - struct uio io, *uiop = &io; - struct vattr va, *vap = &va; - struct nfsheur *nh; - off_t off; - int ioflag = 0; - u_quad_t frev; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - if (v3) { - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - off = fxdr_hyper(tl); - } else { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - off = (off_t)fxdr_unsigned(u_int32_t, *tl); - } - nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd)); - - /* - * Reference vp. If an error occurs, vp will be invalid, but we - * have to NULL it just in case. The macros might goto nfsmout - * as well. - */ - - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - vp = NULL; - nfsm_reply(2 * NFSX_UNSIGNED); - nfsm_srvpostop_attr(1, (struct vattr *)0); - error = 0; - goto nfsmout; - } - - if (vp->v_type != VREG) { - if (v3) - error = EINVAL; - else - error = (vp->v_type == VDIR) ? EISDIR : EACCES; - } - if (!error) { - nqsrv_getl(vp, ND_READ); - if ((error = nfsrv_access(vp, VREAD, cred, rdonly, td, 1)) != 0) - error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 1); - } - getret = VOP_GETATTR(vp, vap, cred, td); - if (!error) - error = getret; - if (error) { - vput(vp); - vp = NULL; - nfsm_reply(NFSX_POSTOPATTR(v3)); - nfsm_srvpostop_attr(getret, vap); - error = 0; - goto nfsmout; - } - - /* - * Calculate byte count to read - */ - - if (off >= vap->va_size) - cnt = 0; - else if ((off + reqlen) > vap->va_size) - cnt = vap->va_size - off; - else - cnt = reqlen; - - /* - * Calculate seqcount for heuristic - */ - - { - int hi; - int try = 4; - - /* - * Locate best candidate - */ - - hi = ((int)(vm_offset_t)vp / sizeof(struct vnode)) & (NUM_HEURISTIC - 1); - nh = &nfsheur[hi]; - - while (try--) { - if (nfsheur[hi].nh_vp == vp) { - nh = &nfsheur[hi]; - break; - } - if (nfsheur[hi].nh_use > 0) - --nfsheur[hi].nh_use; - hi = (hi + 1) & (NUM_HEURISTIC - 1); - if (nfsheur[hi].nh_use < nh->nh_use) - nh = &nfsheur[hi]; - } - - if (nh->nh_vp != vp) { - nh->nh_vp = vp; - nh->nh_nextr = off; - nh->nh_use = NHUSE_INIT; - if (off == 0) - nh->nh_seqcount = 4; - else - nh->nh_seqcount = 1; - } - - /* - * Calculate heuristic - */ - - if ((off == 0 && nh->nh_seqcount > 0) || off == nh->nh_nextr) { - if (++nh->nh_seqcount > 127) - nh->nh_seqcount = 127; - } else if (nh->nh_seqcount > 1) { - nh->nh_seqcount = 1; - } else { - nh->nh_seqcount = 0; - } - nh->nh_use += NHUSE_INC; - if (nh->nh_use > NHUSE_MAX) - nh->nh_use = NHUSE_MAX; - ioflag |= nh->nh_seqcount << 16; - } - - nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt)); - if (v3) { - nfsm_build(tl, u_int32_t *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED); - *tl++ = nfs_true; - fp = (struct nfs_fattr *)tl; - tl += (NFSX_V3FATTR / sizeof (u_int32_t)); - } else { - nfsm_build(tl, u_int32_t *, NFSX_V2FATTR + NFSX_UNSIGNED); - fp = (struct nfs_fattr *)tl; - tl += (NFSX_V2FATTR / sizeof (u_int32_t)); - } - len = left = nfsm_rndup(cnt); - if (cnt > 0) { - /* - * Generate the mbuf list with the uio_iov ref. to it. - */ - i = 0; - m = m2 = mb; - while (left > 0) { - siz = min(M_TRAILINGSPACE(m), left); - if (siz > 0) { - left -= siz; - i++; - } - if (left > 0) { - MGET(m, M_TRYWAIT, MT_DATA); - MCLGET(m, M_TRYWAIT); - m->m_len = 0; - m2->m_next = m; - m2 = m; - } - } - MALLOC(iv, struct iovec *, i * sizeof (struct iovec), - M_TEMP, M_WAITOK); - uiop->uio_iov = iv2 = iv; - m = mb; - left = len; - i = 0; - while (left > 0) { - if (m == NULL) - panic("nfsrv_read iov"); - siz = min(M_TRAILINGSPACE(m), left); - if (siz > 0) { - iv->iov_base = mtod(m, caddr_t) + m->m_len; - iv->iov_len = siz; - m->m_len += siz; - left -= siz; - iv++; - i++; - } - m = m->m_next; - } - uiop->uio_iovcnt = i; - uiop->uio_offset = off; - uiop->uio_resid = len; - uiop->uio_rw = UIO_READ; - uiop->uio_segflg = UIO_SYSSPACE; - error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred); - off = uiop->uio_offset; - nh->nh_nextr = off; - FREE((caddr_t)iv2, M_TEMP); - if (error || (getret = VOP_GETATTR(vp, vap, cred, td))) { - if (!error) - error = getret; - m_freem(mreq); - vput(vp); - vp = NULL; - nfsm_reply(NFSX_POSTOPATTR(v3)); - nfsm_srvpostop_attr(getret, vap); - error = 0; - goto nfsmout; - } - } else { - uiop->uio_resid = 0; - } - vput(vp); - vp = NULL; - nfsm_srvfillattr(vap, fp); - tlen = len - uiop->uio_resid; - cnt = cnt < tlen ? cnt : tlen; - tlen = nfsm_rndup(cnt); - if (len != tlen || tlen != cnt) - nfsm_adj(mb, len - tlen, tlen - cnt); - if (v3) { - *tl++ = txdr_unsigned(cnt); - if (len < reqlen) - *tl++ = nfs_true; - else - *tl++ = nfs_false; - } - *tl = txdr_unsigned(cnt); -nfsmout: - if (vp) - vput(vp); - return(error); -} - -/* - * nfs write service - */ -int -nfsrv_write(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - register struct iovec *ivp; - register int i, cnt; - register struct mbuf *mp; - register struct nfs_fattr *fp; - struct iovec *iv; - struct vattr va, forat; - register struct vattr *vap = &va; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, rdonly, cache, len, forat_ret = 1; - int ioflags, aftat_ret = 1, retlen = 0, zeroing, adjust; - int stable = NFSV3WRITE_FILESYNC; - int v3 = (nfsd->nd_flag & ND_NFSV3); - char *cp2; - struct mbuf *mb, *mb2, *mreq; - struct vnode *vp = NULL; - nfsfh_t nfh; - fhandle_t *fhp; - struct uio io, *uiop = &io; - off_t off; - u_quad_t frev; - struct mount *mntp = NULL; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - if (mrep == NULL) { - *mrq = NULL; - error = 0; - goto nfsmout; - } - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - if ((mntp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { - error = ESTALE; - goto ereply; - } - if ((error = VFS_FHTOVP(mntp, &fhp->fh_fid, &vp)) != 0) { - mntp = NULL; - goto ereply; - } - (void) vn_start_write(vp, &mntp, V_WAIT); - vput(vp); - vp = NULL; - if (v3) { - nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED); - off = fxdr_hyper(tl); - tl += 3; - stable = fxdr_unsigned(int, *tl++); - } else { - nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED); - off = (off_t)fxdr_unsigned(u_int32_t, *++tl); - tl += 2; - if (nfs_async) - stable = NFSV3WRITE_UNSTABLE; - } - retlen = len = fxdr_unsigned(int32_t, *tl); - cnt = i = 0; - - /* - * For NFS Version 2, it is not obvious what a write of zero length - * should do, but I might as well be consistent with Version 3, - * which is to return ok so long as there are no permission problems. - */ - if (len > 0) { - zeroing = 1; - mp = mrep; - while (mp) { - if (mp == md) { - zeroing = 0; - adjust = dpos - mtod(mp, caddr_t); - mp->m_len -= adjust; - if (mp->m_len > 0 && adjust > 0) - NFSMADV(mp, adjust); - } - if (zeroing) - mp->m_len = 0; - else if (mp->m_len > 0) { - i += mp->m_len; - if (i > len) { - mp->m_len -= (i - len); - zeroing = 1; - } - if (mp->m_len > 0) - cnt++; - } - mp = mp->m_next; - } - } - if (len > NFS_MAXDATA || len < 0 || i < len) { - error = EIO; - nfsm_reply(2 * NFSX_UNSIGNED); - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); - error = 0; - goto nfsmout; - } - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - vp = NULL; - nfsm_reply(2 * NFSX_UNSIGNED); - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); - error = 0; - goto nfsmout; - } - if (v3) - forat_ret = VOP_GETATTR(vp, &forat, cred, td); - if (vp->v_type != VREG) { - if (v3) - error = EINVAL; - else - error = (vp->v_type == VDIR) ? EISDIR : EACCES; - } - if (!error) { - nqsrv_getl(vp, ND_WRITE); - error = nfsrv_access(vp, VWRITE, cred, rdonly, td, 1); - } - if (error) { - vput(vp); - vp = NULL; - nfsm_reply(NFSX_WCCDATA(v3)); - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); - error = 0; - goto nfsmout; - } - - if (len > 0) { - MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP, - M_WAITOK); - uiop->uio_iov = iv = ivp; - uiop->uio_iovcnt = cnt; - mp = mrep; - while (mp) { - if (mp->m_len > 0) { - ivp->iov_base = mtod(mp, caddr_t); - ivp->iov_len = mp->m_len; - ivp++; - } - mp = mp->m_next; - } - - /* - * XXX - * The IO_METASYNC flag indicates that all metadata (and not just - * enough to ensure data integrity) mus be written to stable storage - * synchronously. - * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.) - */ - if (stable == NFSV3WRITE_UNSTABLE) - ioflags = IO_NODELOCKED; - else if (stable == NFSV3WRITE_DATASYNC) - ioflags = (IO_SYNC | IO_NODELOCKED); - else - ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED); - uiop->uio_resid = len; - uiop->uio_rw = UIO_WRITE; - uiop->uio_segflg = UIO_SYSSPACE; - uiop->uio_td = (struct thread *)0; - uiop->uio_offset = off; - error = VOP_WRITE(vp, uiop, ioflags, cred); - nfsstats.srvvop_writes++; - FREE((caddr_t)iv, M_TEMP); - } - aftat_ret = VOP_GETATTR(vp, vap, cred, td); - vput(vp); - vp = NULL; - if (!error) - error = aftat_ret; -ereply: - nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) + - 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3)); - if (v3) { - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); - if (error) { - error = 0; - goto nfsmout; - } - nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); - *tl++ = txdr_unsigned(retlen); - /* - * If nfs_async is set, then pretend the write was FILESYNC. - */ - if (stable == NFSV3WRITE_UNSTABLE && !nfs_async) - *tl++ = txdr_unsigned(stable); - else - *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC); - /* - * Actually, there is no need to txdr these fields, - * but it may make the values more human readable, - * for debugging purposes. - */ - if (nfsver.tv_sec == 0) - nfsver = boottime; - *tl++ = txdr_unsigned(nfsver.tv_sec); - *tl = txdr_unsigned(nfsver.tv_usec); - } else { - /* v2, non-error case (see nfsm_reply). */ - nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); - nfsm_srvfillattr(vap, fp); - } -nfsmout: - if (vp) - vput(vp); - vn_finished_write(mntp); - return(error); -} - -/* - * NFS write service with write gathering support. Called when - * nfsrvw_procrastinate > 0. - * See: Chet Juszczak, "Improving the Write Performance of an NFS Server", - * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco, - * Jan. 1994. - */ -int -nfsrv_writegather(ndp, slp, td, mrq) - struct nfsrv_descript **ndp; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - register struct iovec *ivp; - register struct mbuf *mp; - register struct nfsrv_descript *wp, *nfsd, *owp, *swp; - register struct nfs_fattr *fp; - register int i; - struct iovec *iov; - struct nfsrvw_delayhash *wpp; - struct ucred *cred; - struct vattr va, forat; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos, dpos; - int error = 0, rdonly, cache, len, forat_ret = 1; - int ioflags, aftat_ret = 1, s, adjust, v3, zeroing; - char *cp2; - struct mbuf *mb, *mb2, *mreq, *mrep, *md; - struct vnode *vp = NULL; - struct uio io, *uiop = &io; - u_quad_t frev, cur_usec; - struct mount *mntp = NULL; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - i = 0; - len = 0; -#endif - *mrq = NULL; - if (*ndp) { - nfsd = *ndp; - *ndp = NULL; - mrep = nfsd->nd_mrep; - md = nfsd->nd_md; - dpos = nfsd->nd_dpos; - cred = &nfsd->nd_cr; - v3 = (nfsd->nd_flag & ND_NFSV3); - LIST_INIT(&nfsd->nd_coalesce); - nfsd->nd_mreq = NULL; - nfsd->nd_stable = NFSV3WRITE_FILESYNC; - cur_usec = nfs_curusec(); - nfsd->nd_time = cur_usec + - (v3 ? nfsrvw_procrastinate_v3 : nfsrvw_procrastinate); - - /* - * Now, get the write header.. - */ - nfsm_srvmtofh(&nfsd->nd_fh); - if (v3) { - nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED); - nfsd->nd_off = fxdr_hyper(tl); - tl += 3; - nfsd->nd_stable = fxdr_unsigned(int, *tl++); - } else { - nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED); - nfsd->nd_off = (off_t)fxdr_unsigned(u_int32_t, *++tl); - tl += 2; - if (nfs_async) - nfsd->nd_stable = NFSV3WRITE_UNSTABLE; - } - len = fxdr_unsigned(int32_t, *tl); - nfsd->nd_len = len; - nfsd->nd_eoff = nfsd->nd_off + len; - - /* - * Trim the header out of the mbuf list and trim off any trailing - * junk so that the mbuf list has only the write data. - */ - zeroing = 1; - i = 0; - mp = mrep; - while (mp) { - if (mp == md) { - zeroing = 0; - adjust = dpos - mtod(mp, caddr_t); - mp->m_len -= adjust; - if (mp->m_len > 0 && adjust > 0) - NFSMADV(mp, adjust); - } - if (zeroing) - mp->m_len = 0; - else { - i += mp->m_len; - if (i > len) { - mp->m_len -= (i - len); - zeroing = 1; - } - } - mp = mp->m_next; - } - if (len > NFS_MAXDATA || len < 0 || i < len) { -nfsmout: - m_freem(mrep); - error = EIO; - nfsm_writereply(2 * NFSX_UNSIGNED, v3); - if (v3) - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); - nfsd->nd_mreq = mreq; - nfsd->nd_mrep = NULL; - nfsd->nd_time = 0; - } - - /* - * Add this entry to the hash and time queues. - */ - s = splsoftclock(); - owp = NULL; - wp = slp->ns_tq.lh_first; - while (wp && wp->nd_time < nfsd->nd_time) { - owp = wp; - wp = wp->nd_tq.le_next; - } - NFS_DPF(WG, ("Q%03x", nfsd->nd_retxid & 0xfff)); - if (owp) { - LIST_INSERT_AFTER(owp, nfsd, nd_tq); - } else { - LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq); - } - if (nfsd->nd_mrep) { - wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data); - owp = NULL; - wp = wpp->lh_first; - while (wp && - bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) { - owp = wp; - wp = wp->nd_hash.le_next; - } - while (wp && wp->nd_off < nfsd->nd_off && - !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) { - owp = wp; - wp = wp->nd_hash.le_next; - } - if (owp) { - LIST_INSERT_AFTER(owp, nfsd, nd_hash); - - /* - * Search the hash list for overlapping entries and - * coalesce. - */ - for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) { - wp = nfsd->nd_hash.le_next; - if (NFSW_SAMECRED(owp, nfsd)) - nfsrvw_coalesce(owp, nfsd); - } - } else { - LIST_INSERT_HEAD(wpp, nfsd, nd_hash); - } - } - splx(s); - } - - /* - * Now, do VOP_WRITE()s for any one(s) that need to be done now - * and generate the associated reply mbuf list(s). - */ -loop1: - cur_usec = nfs_curusec(); - s = splsoftclock(); - for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) { - owp = nfsd->nd_tq.le_next; - if (nfsd->nd_time > cur_usec) - break; - if (nfsd->nd_mreq) - continue; - NFS_DPF(WG, ("P%03x", nfsd->nd_retxid & 0xfff)); - LIST_REMOVE(nfsd, nd_tq); - LIST_REMOVE(nfsd, nd_hash); - splx(s); - mrep = nfsd->nd_mrep; - nfsd->nd_mrep = NULL; - cred = &nfsd->nd_cr; - v3 = (nfsd->nd_flag & ND_NFSV3); - forat_ret = aftat_ret = 1; - error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp, - nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (!error) { - if (v3) - forat_ret = VOP_GETATTR(vp, &forat, cred, td); - if (vp->v_type != VREG) { - if (v3) - error = EINVAL; - else - error = (vp->v_type == VDIR) ? EISDIR : EACCES; - } - } else { - vp = NULL; - } - if (!error) { - nqsrv_getl(vp, ND_WRITE); - error = nfsrv_access(vp, VWRITE, cred, rdonly, td, 1); - } - - if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE) - ioflags = IO_NODELOCKED; - else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC) - ioflags = (IO_SYNC | IO_NODELOCKED); - else - ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED); - uiop->uio_rw = UIO_WRITE; - uiop->uio_segflg = UIO_SYSSPACE; - uiop->uio_td = (struct thread *)0; - uiop->uio_offset = nfsd->nd_off; - uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off; - if (uiop->uio_resid > 0) { - mp = mrep; - i = 0; - while (mp) { - if (mp->m_len > 0) - i++; - mp = mp->m_next; - } - uiop->uio_iovcnt = i; - MALLOC(iov, struct iovec *, i * sizeof (struct iovec), - M_TEMP, M_WAITOK); - uiop->uio_iov = ivp = iov; - mp = mrep; - while (mp) { - if (mp->m_len > 0) { - ivp->iov_base = mtod(mp, caddr_t); - ivp->iov_len = mp->m_len; - ivp++; - } - mp = mp->m_next; - } - if (!error) { - if (vn_start_write(vp, &mntp, V_NOWAIT) != 0) { - VOP_UNLOCK(vp, 0, td); - error = vn_start_write(NULL, &mntp, V_WAIT); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - } - } - if (!error) { - error = VOP_WRITE(vp, uiop, ioflags, cred); - nfsstats.srvvop_writes++; - vn_finished_write(mntp); - } - FREE((caddr_t)iov, M_TEMP); - } - m_freem(mrep); - if (vp) { - aftat_ret = VOP_GETATTR(vp, &va, cred, td); - vput(vp); - vp = NULL; - } - - /* - * Loop around generating replies for all write rpcs that have - * now been completed. - */ - swp = nfsd; - do { - NFS_DPF(WG, ("R%03x", nfsd->nd_retxid & 0xfff)); - if (error) { - nfsm_writereply(NFSX_WCCDATA(v3), v3); - if (v3) { - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); - } - } else { - nfsm_writereply(NFSX_PREOPATTR(v3) + - NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED + - NFSX_WRITEVERF(v3), v3); - if (v3) { - nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); - nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); - *tl++ = txdr_unsigned(nfsd->nd_len); - *tl++ = txdr_unsigned(swp->nd_stable); - /* - * Actually, there is no need to txdr these fields, - * but it may make the values more human readable, - * for debugging purposes. - */ - if (nfsver.tv_sec == 0) - nfsver = boottime; - *tl++ = txdr_unsigned(nfsver.tv_sec); - *tl = txdr_unsigned(nfsver.tv_usec); - } else { - nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); - nfsm_srvfillattr(&va, fp); - } - } - nfsd->nd_mreq = mreq; - if (nfsd->nd_mrep) - panic("nfsrv_write: nd_mrep not free"); - - /* - * Done. Put it at the head of the timer queue so that - * the final phase can return the reply. - */ - s = splsoftclock(); - if (nfsd != swp) { - nfsd->nd_time = 0; - LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq); - } - nfsd = swp->nd_coalesce.lh_first; - if (nfsd) { - LIST_REMOVE(nfsd, nd_tq); - } - splx(s); - } while (nfsd); - s = splsoftclock(); - swp->nd_time = 0; - LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq); - splx(s); - goto loop1; - } - splx(s); - - /* - * Search for a reply to return. - */ - s = splsoftclock(); - for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next) - if (nfsd->nd_mreq) { - NFS_DPF(WG, ("X%03x", nfsd->nd_retxid & 0xfff)); - LIST_REMOVE(nfsd, nd_tq); - *mrq = nfsd->nd_mreq; - *ndp = nfsd; - break; - } - splx(s); - return (0); -} - -/* - * Coalesce the write request nfsd into owp. To do this we must: - * - remove nfsd from the queues - * - merge nfsd->nd_mrep into owp->nd_mrep - * - update the nd_eoff and nd_stable for owp - * - put nfsd on owp's nd_coalesce list - * NB: Must be called at splsoftclock(). - */ -static void -nfsrvw_coalesce(owp, nfsd) - register struct nfsrv_descript *owp; - register struct nfsrv_descript *nfsd; -{ - register int overlap; - register struct mbuf *mp; - struct nfsrv_descript *p; - - NFS_DPF(WG, ("C%03x-%03x", - nfsd->nd_retxid & 0xfff, owp->nd_retxid & 0xfff)); - LIST_REMOVE(nfsd, nd_hash); - LIST_REMOVE(nfsd, nd_tq); - if (owp->nd_eoff < nfsd->nd_eoff) { - overlap = owp->nd_eoff - nfsd->nd_off; - if (overlap < 0) - panic("nfsrv_coalesce: bad off"); - if (overlap > 0) - m_adj(nfsd->nd_mrep, overlap); - mp = owp->nd_mrep; - while (mp->m_next) - mp = mp->m_next; - mp->m_next = nfsd->nd_mrep; - owp->nd_eoff = nfsd->nd_eoff; - } else - m_freem(nfsd->nd_mrep); - nfsd->nd_mrep = NULL; - if (nfsd->nd_stable == NFSV3WRITE_FILESYNC) - owp->nd_stable = NFSV3WRITE_FILESYNC; - else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC && - owp->nd_stable == NFSV3WRITE_UNSTABLE) - owp->nd_stable = NFSV3WRITE_DATASYNC; - LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq); - - /* - * If nfsd had anything else coalesced into it, transfer them - * to owp, otherwise their replies will never get sent. - */ - for (p = nfsd->nd_coalesce.lh_first; p; - p = nfsd->nd_coalesce.lh_first) { - LIST_REMOVE(p, nd_tq); - LIST_INSERT_HEAD(&owp->nd_coalesce, p, nd_tq); - } -} - -/* - * nfs create service - * now does a truncate to 0 length via. setattr if it already exists - */ -int -nfsrv_create(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - register struct nfs_fattr *fp; - struct vattr va, dirfor, diraft; - register struct vattr *vap = &va; - register struct nfsv2_sattr *sp; - register u_int32_t *tl; - struct nameidata nd; - register int32_t t1; - caddr_t bpos; - int error = 0, rdev, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1; - int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0; - caddr_t cp; - char *cp2; - struct mbuf *mb, *mb2, *mreq; - struct vnode *dirp = (struct vnode *)0; - nfsfh_t nfh; - fhandle_t *fhp; - u_quad_t frev, tempsize; - u_char cverf[NFSX_V3CREATEVERF]; - struct mount *mp = NULL; - struct vnode *vp; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - rdev = 0; -#endif - ndclear(&nd); - - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { - error = ESTALE; - goto ereply; - } - if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != 0) { - mp = NULL; - goto ereply; - } - (void) vn_start_write(vp, &mp, V_WAIT); - vput(vp); - nfsm_srvnamesiz(len); - - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = CREATE; - nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; - - /* - * Call namei and do initial cleanup to get a few things - * out of the way. If we get an initial error we cleanup - * and return here to avoid special-casing the invalid nd - * structure through the rest of the case. dirp may be - * set even if an error occurs, but the nd structure will not - * be valid at all if an error occurs so we have to invalidate it - * prior to calling nfsm_reply ( which might goto nfsmout ). - */ - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); - if (dirp) { - if (v3) { - dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, - td); - } else { - vrele(dirp); - dirp = NULL; - } - } - if (error) { - nfsm_reply(NFSX_WCCDATA(v3)); - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - error = 0; - goto nfsmout; - } - - /* - * No error. Continue. State: - * - * startdir is valid ( we release this immediately ) - * dirp may be valid - * nd.ni_vp may be valid - * nd.ni_dvp is valid - * - * The error state is set through the code and we may also do some - * opportunistic releasing of vnodes to avoid holding locks through - * NFS I/O. The cleanup at the end is a catch-all - */ - - VATTR_NULL(vap); - if (v3) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - how = fxdr_unsigned(int, *tl); - switch (how) { - case NFSV3CREATE_GUARDED: - if (nd.ni_vp) { - error = EEXIST; - break; - } - /* fall through */ - case NFSV3CREATE_UNCHECKED: - nfsm_srvsattr(vap); - break; - case NFSV3CREATE_EXCLUSIVE: - nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF); - bcopy(cp, cverf, NFSX_V3CREATEVERF); - exclusive_flag = 1; - if (nd.ni_vp == NULL) - vap->va_mode = 0; - break; - }; - vap->va_type = VREG; - } else { - nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); - vap->va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); - if (vap->va_type == VNON) - vap->va_type = VREG; - vap->va_mode = nfstov_mode(sp->sa_mode); - switch (vap->va_type) { - case VREG: - tsize = fxdr_unsigned(int32_t, sp->sa_size); - if (tsize != -1) - vap->va_size = (u_quad_t)tsize; - break; - case VCHR: - case VBLK: - case VFIFO: - rdev = fxdr_unsigned(long, sp->sa_size); - break; - default: - break; - }; - } - - /* - * Iff doesn't exist, create it - * otherwise just truncate to 0 length - * should I set the mode too ? - * - * The only possible error we can have at this point is EEXIST. - * nd.ni_vp will also be non-NULL in that case. - */ - if (nd.ni_vp == NULL) { - if (vap->va_type == VREG || vap->va_type == VSOCK) { - nqsrv_getl(nd.ni_dvp, ND_WRITE); - error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); - if (error) - NDFREE(&nd, NDF_ONLY_PNBUF); - else { - nfsrv_object_create(nd.ni_vp); - if (exclusive_flag) { - exclusive_flag = 0; - VATTR_NULL(vap); - bcopy(cverf, (caddr_t)&vap->va_atime, - NFSX_V3CREATEVERF); - error = VOP_SETATTR(nd.ni_vp, vap, cred, - td); - } - } - } else if ( - vap->va_type == VCHR || - vap->va_type == VBLK || - vap->va_type == VFIFO - ) { - /* - * Handle SysV FIFO node special cases. All other - * devices require super user to access. - */ - if (vap->va_type == VCHR && rdev == 0xffffffff) - vap->va_type = VFIFO; - if (vap->va_type != VFIFO && - (error = suser_xxx(cred, 0, 0))) { - goto nfsmreply0; - } - vap->va_rdev = rdev; - nqsrv_getl(nd.ni_dvp, ND_WRITE); - - error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); - if (error) { - NDFREE(&nd, NDF_ONLY_PNBUF); - goto nfsmreply0; - } - vput(nd.ni_vp); - nd.ni_vp = NULL; - - /* - * release dvp prior to lookup - */ - vput(nd.ni_dvp); - nd.ni_dvp = NULL; - - /* - * Setup for lookup. - * - * Even though LOCKPARENT was cleared, ni_dvp may - * be garbage. - */ - nd.ni_cnd.cn_nameiop = LOOKUP; - nd.ni_cnd.cn_flags &= ~(LOCKPARENT); - nd.ni_cnd.cn_thread = td; - nd.ni_cnd.cn_cred = cred; - - error = lookup(&nd); - nd.ni_dvp = NULL; - - if (error != 0) { - nfsm_reply(0); - /* fall through on certain errors */ - } - nfsrv_object_create(nd.ni_vp); - if (nd.ni_cnd.cn_flags & ISSYMLINK) { - error = EINVAL; - goto nfsmreply0; - } - } else { - error = ENXIO; - } - } else { - if (vap->va_size != -1) { - error = nfsrv_access(nd.ni_vp, VWRITE, cred, - (nd.ni_cnd.cn_flags & RDONLY), td, 0); - if (!error) { - nqsrv_getl(nd.ni_vp, ND_WRITE); - tempsize = vap->va_size; - VATTR_NULL(vap); - vap->va_size = tempsize; - error = VOP_SETATTR(nd.ni_vp, vap, cred, - td); - } - } - } - - if (!error) { - bzero((caddr_t)fhp, sizeof(nfh)); - fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid; - error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid); - if (!error) - error = VOP_GETATTR(nd.ni_vp, vap, cred, td); - } - if (v3) { - if (exclusive_flag && !error && - bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF)) - error = EEXIST; - diraft_ret = VOP_GETATTR(dirp, &diraft, cred, td); - vrele(dirp); - dirp = NULL; - } -ereply: - nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3)); - if (v3) { - if (!error) { - nfsm_srvpostop_fh(fhp); - nfsm_srvpostop_attr(0, vap); - } - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - error = 0; - } else { - /* v2 non-error case (see nfsm_reply). */ - nfsm_srvfhtom(fhp, v3); - nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); - nfsm_srvfillattr(vap, fp); - } - goto nfsmout; - -nfsmreply0: - nfsm_reply(0); - error = 0; - /* fall through */ - -nfsmout: - if (nd.ni_startdir) { - vrele(nd.ni_startdir); - nd.ni_startdir = NULL; - } - if (dirp) - vrele(dirp); - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - } - if (nd.ni_vp) - vput(nd.ni_vp); - vn_finished_write(mp); - return (error); -} - -/* - * nfs v3 mknod service - */ -int -nfsrv_mknod(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - struct vattr va, dirfor, diraft; - register struct vattr *vap = &va; - register u_int32_t *tl; - struct nameidata nd; - register int32_t t1; - caddr_t bpos; - int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; - u_int32_t major, minor; - enum vtype vtyp; - char *cp2; - struct mbuf *mb, *mb2, *mreq; - struct vnode *vp, *dirp = (struct vnode *)0; - nfsfh_t nfh; - fhandle_t *fhp; - u_quad_t frev; - struct mount *mp = NULL; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - ndclear(&nd); - - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { - error = ESTALE; - goto ereply; - } - if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != 0) { - mp = NULL; - goto ereply; - } - (void) vn_start_write(vp, &mp, V_WAIT); - vput(vp); - vp = NULL; - nfsm_srvnamesiz(len); - - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = CREATE; - nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; - - /* - * Handle nfs_namei() call. If an error occurs, the nd structure - * is not valid. However, nfsm_*() routines may still jump to - * nfsmout. - */ - - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); - if (dirp) - dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, td); - if (error) { - nfsm_reply(NFSX_WCCDATA(1)); - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - error = 0; - goto nfsmout; - } - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - vtyp = nfsv3tov_type(*tl); - if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) { - error = NFSERR_BADTYPE; - goto out; - } - VATTR_NULL(vap); - nfsm_srvsattr(vap); - if (vtyp == VCHR || vtyp == VBLK) { - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - major = fxdr_unsigned(u_int32_t, *tl++); - minor = fxdr_unsigned(u_int32_t, *tl); - vap->va_rdev = makeudev(major, minor); - } - - /* - * Iff doesn't exist, create it. - */ - if (nd.ni_vp) { - error = EEXIST; - goto out; - } - vap->va_type = vtyp; - if (vtyp == VSOCK) { - vrele(nd.ni_startdir); - nd.ni_startdir = NULL; - nqsrv_getl(nd.ni_dvp, ND_WRITE); - error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); - if (error) - NDFREE(&nd, NDF_ONLY_PNBUF); - } else { - if (vtyp != VFIFO && (error = suser_xxx(cred, 0, 0))) - goto out; - nqsrv_getl(nd.ni_dvp, ND_WRITE); - - error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); - if (error) { - NDFREE(&nd, NDF_ONLY_PNBUF); - goto out; - } - vput(nd.ni_vp); - nd.ni_vp = NULL; - - /* - * Release dvp prior to lookup - */ - vput(nd.ni_dvp); - nd.ni_dvp = NULL; - - nd.ni_cnd.cn_nameiop = LOOKUP; - nd.ni_cnd.cn_flags &= ~(LOCKPARENT); - nd.ni_cnd.cn_thread = td; - nd.ni_cnd.cn_cred = td->td_proc->p_ucred; - - error = lookup(&nd); - nd.ni_dvp = NULL; - - if (error) - goto out; - if (nd.ni_cnd.cn_flags & ISSYMLINK) - error = EINVAL; - } - - /* - * send response, cleanup, return. - */ -out: - if (nd.ni_startdir) { - vrele(nd.ni_startdir); - nd.ni_startdir = NULL; - } - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - nd.ni_dvp = NULL; - } - vp = nd.ni_vp; - if (!error) { - bzero((caddr_t)fhp, sizeof(nfh)); - fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; - error = VFS_VPTOFH(vp, &fhp->fh_fid); - if (!error) - error = VOP_GETATTR(vp, vap, cred, td); - vput(vp); - vp = NULL; - nd.ni_vp = NULL; - } - diraft_ret = VOP_GETATTR(dirp, &diraft, cred, td); - if (dirp) { - vrele(dirp); - dirp = NULL; - } -ereply: - nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1)); - if (!error) { - nfsm_srvpostop_fh(fhp); - nfsm_srvpostop_attr(0, vap); - } - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - vn_finished_write(mp); - return (0); -nfsmout: - if (dirp) - vrele(dirp); - if (nd.ni_startdir) - vrele(nd.ni_startdir); - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - } - if (nd.ni_vp) - vput(nd.ni_vp); - vn_finished_write(mp); - return (error); -} - -/* - * nfs remove service - */ -int -nfsrv_remove(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - struct nameidata nd; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; - int v3 = (nfsd->nd_flag & ND_NFSV3); - char *cp2; - struct mbuf *mb, *mreq; - struct vnode *dirp; - struct vattr dirfor, diraft; - nfsfh_t nfh; - fhandle_t *fhp; - u_quad_t frev; - struct mount *mp = NULL; - struct vnode *vp; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - ndclear(&nd); - - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { - error = ESTALE; - goto ereply; - } - if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != 0) { - mp = NULL; - goto ereply; - } - (void) vn_start_write(vp, &mp, V_WAIT); - vput(vp); - vp = NULL; - nfsm_srvnamesiz(len); - - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = DELETE; - nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); - if (dirp) { - if (v3) { - dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, - td); - } else { - vrele(dirp); - dirp = NULL; - } - } - if (error == 0) { - if (nd.ni_vp->v_type == VDIR) { - error = EPERM; /* POSIX */ - goto out; - } - /* - * The root of a mounted filesystem cannot be deleted. - */ - if (nd.ni_vp->v_flag & VROOT) { - error = EBUSY; - goto out; - } -out: - if (!error) { - nqsrv_getl(nd.ni_dvp, ND_WRITE); - nqsrv_getl(nd.ni_vp, ND_WRITE); - error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); - NDFREE(&nd, NDF_ONLY_PNBUF); - } - } - if (dirp && v3) { - diraft_ret = VOP_GETATTR(dirp, &diraft, cred, td); - vrele(dirp); - dirp = NULL; - } -ereply: - nfsm_reply(NFSX_WCCDATA(v3)); - if (v3) { - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - error = 0; - } -nfsmout: - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - } - if (nd.ni_vp) - vput(nd.ni_vp); - vn_finished_write(mp); - return(error); -} - -/* - * nfs rename service - */ -int -nfsrv_rename(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1; - int tdirfor_ret = 1, tdiraft_ret = 1; - int v3 = (nfsd->nd_flag & ND_NFSV3); - char *cp2; - struct mbuf *mb, *mreq; - struct nameidata fromnd, tond; - struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0; - struct vnode *tdirp = (struct vnode *)0; - struct vattr fdirfor, fdiraft, tdirfor, tdiraft; - nfsfh_t fnfh, tnfh; - fhandle_t *ffhp, *tfhp; - u_quad_t frev; - uid_t saved_uid; - struct mount *mp = NULL; - struct vnode *vp; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - fvp = (struct vnode *)0; -#endif - ffhp = &fnfh.fh_generic; - tfhp = &tnfh.fh_generic; - - /* - * Clear fields incase goto nfsmout occurs from macro. - */ - - ndclear(&fromnd); - ndclear(&tond); - - nfsm_srvmtofh(ffhp); - if ((mp = vfs_getvfs(&ffhp->fh_fsid)) == NULL) { - error = ESTALE; - goto out1; - } - if ((error = VFS_FHTOVP(mp, &ffhp->fh_fid, &vp)) != 0) { - mp = NULL; - goto out1; - } - (void) vn_start_write(vp, &mp, V_WAIT); - vput(vp); - vp = NULL; - nfsm_srvnamesiz(len); - /* - * Remember our original uid so that we can reset cr_uid before - * the second nfs_namei() call, in case it is remapped. - */ - saved_uid = cred->cr_uid; - fromnd.ni_cnd.cn_cred = cred; - fromnd.ni_cnd.cn_nameiop = DELETE; - fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; - error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md, - &dpos, &fdirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); - if (fdirp) { - if (v3) { - fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred, - td); - } else { - vrele(fdirp); - fdirp = NULL; - } - } - if (error) { - nfsm_reply(2 * NFSX_WCCDATA(v3)); - nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); - nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); - error = 0; - goto nfsmout; - } - fvp = fromnd.ni_vp; - nfsm_srvmtofh(tfhp); - nfsm_strsiz(len2, NFS_MAXNAMLEN); - cred->cr_uid = saved_uid; - tond.ni_cnd.cn_cred = cred; - tond.ni_cnd.cn_nameiop = RENAME; - tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; - error = nfs_namei(&tond, tfhp, len2, slp, nam, &md, - &dpos, &tdirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); - if (tdirp) { - if (v3) { - tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred, - td); - } else { - vrele(tdirp); - tdirp = NULL; - } - } - if (error) - goto out1; - - tdvp = tond.ni_dvp; - tvp = tond.ni_vp; - if (tvp != NULL) { - if (fvp->v_type == VDIR && tvp->v_type != VDIR) { - if (v3) - error = EEXIST; - else - error = EISDIR; - goto out; - } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { - if (v3) - error = EEXIST; - else - error = ENOTDIR; - goto out; - } - if (tvp->v_type == VDIR && tvp->v_mountedhere) { - if (v3) - error = EXDEV; - else - error = ENOTEMPTY; - goto out; - } - } - if (fvp->v_type == VDIR && fvp->v_mountedhere) { - if (v3) - error = EXDEV; - else - error = ENOTEMPTY; - goto out; - } - if (fvp->v_mount != tdvp->v_mount) { - if (v3) - error = EXDEV; - else - error = ENOTEMPTY; - goto out; - } - if (fvp == tdvp) { - if (v3) - error = EINVAL; - else - error = ENOTEMPTY; - } - /* - * If source is the same as the destination (that is the - * same vnode with the same name in the same directory), - * then there is nothing to do. - */ - if (fvp == tvp && fromnd.ni_dvp == tdvp && - fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && - !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, - fromnd.ni_cnd.cn_namelen)) - error = -1; -out: - if (!error) { - /* - * The VOP_RENAME function releases all vnode references & - * locks prior to returning so we need to clear the pointers - * to bypass cleanup code later on. - */ - nqsrv_getl(fromnd.ni_dvp, ND_WRITE); - nqsrv_getl(tdvp, ND_WRITE); - if (tvp) { - nqsrv_getl(tvp, ND_WRITE); - } - error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, - tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); - fromnd.ni_dvp = NULL; - fromnd.ni_vp = NULL; - tond.ni_dvp = NULL; - tond.ni_vp = NULL; - if (error) { - fromnd.ni_cnd.cn_flags &= ~HASBUF; - tond.ni_cnd.cn_flags &= ~HASBUF; - } - } else { - if (error == -1) - error = 0; - } - /* fall through */ - -out1: - if (fdirp) - fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, td); - if (tdirp) - tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, td); - nfsm_reply(2 * NFSX_WCCDATA(v3)); - if (v3) { - nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); - nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); - } - error = 0; - /* fall through */ - -nfsmout: - /* - * Clear out tond related fields - */ - if (tdirp) - vrele(tdirp); - if (tond.ni_startdir) - vrele(tond.ni_startdir); - NDFREE(&tond, NDF_ONLY_PNBUF); - if (tond.ni_dvp) { - if (tond.ni_dvp == tond.ni_vp) - vrele(tond.ni_dvp); - else - vput(tond.ni_dvp); - } - if (tond.ni_vp) - vput(tond.ni_vp); - - /* - * Clear out fromnd related fields - */ - if (fdirp) - vrele(fdirp); - if (fromnd.ni_startdir) - vrele(fromnd.ni_startdir); - NDFREE(&fromnd, NDF_ONLY_PNBUF); - if (fromnd.ni_dvp) - vrele(fromnd.ni_dvp); - if (fromnd.ni_vp) - vrele(fromnd.ni_vp); - - vn_finished_write(mp); - return (error); -} - -/* - * nfs link service - */ -int -nfsrv_link(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - struct nameidata nd; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1; - int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3); - char *cp2; - struct mbuf *mb, *mreq; - struct vnode *vp = NULL, *xp, *dirp = (struct vnode *)0; - struct vattr dirfor, diraft, at; - nfsfh_t nfh, dnfh; - fhandle_t *fhp, *dfhp; - u_quad_t frev; - struct mount *mp = NULL; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - ndclear(&nd); - - fhp = &nfh.fh_generic; - dfhp = &dnfh.fh_generic; - nfsm_srvmtofh(fhp); - if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { - error = ESTALE; - goto ereply; - } - if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != 0) { - mp = NULL; - goto ereply; - } - (void) vn_start_write(vp, &mp, V_WAIT); - vput(vp); - vp = NULL; - nfsm_srvmtofh(dfhp); - nfsm_srvnamesiz(len); - - error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); - nfsm_srvpostop_attr(getret, &at); - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - vp = NULL; - error = 0; - goto nfsmout; - } - if (vp->v_type == VDIR) { - error = EPERM; /* POSIX */ - goto out1; - } - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = CREATE; - nd.ni_cnd.cn_flags = LOCKPARENT; - error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); - if (dirp) { - if (v3) { - dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, - td); - } else { - vrele(dirp); - dirp = NULL; - } - } - if (error) - goto out1; - - xp = nd.ni_vp; - if (xp != NULL) { - error = EEXIST; - goto out; - } - xp = nd.ni_dvp; - if (vp->v_mount != xp->v_mount) - error = EXDEV; -out: - if (!error) { - nqsrv_getl(vp, ND_WRITE); - nqsrv_getl(xp, ND_WRITE); - error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); - NDFREE(&nd, NDF_ONLY_PNBUF); - } - /* fall through */ - -out1: - if (v3) - getret = VOP_GETATTR(vp, &at, cred, td); - if (dirp) - diraft_ret = VOP_GETATTR(dirp, &diraft, cred, td); -ereply: - nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); - if (v3) { - nfsm_srvpostop_attr(getret, &at); - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - error = 0; - } - /* fall through */ - -nfsmout: - NDFREE(&nd, NDF_ONLY_PNBUF); - if (dirp) - vrele(dirp); - if (vp) - vrele(vp); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - } - if (nd.ni_vp) - vrele(nd.ni_vp); - vn_finished_write(mp); - return(error); -} - -/* - * nfs symbolic link service - */ -int -nfsrv_symlink(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - struct vattr va, dirfor, diraft; - struct nameidata nd; - register struct vattr *vap = &va; - register u_int32_t *tl; - register int32_t t1; - struct nfsv2_sattr *sp; - char *bpos, *pathcp = (char *)0, *cp2; - struct uio io; - struct iovec iv; - int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1; - int v3 = (nfsd->nd_flag & ND_NFSV3); - struct mbuf *mb, *mreq, *mb2; - struct vnode *dirp = (struct vnode *)0; - nfsfh_t nfh; - fhandle_t *fhp; - u_quad_t frev; - struct mount *mp = NULL; - struct vnode *vp; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - ndclear(&nd); - - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { - error = ESTALE; - goto out; - } - if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != 0) { - mp = NULL; - goto out; - } - (void) vn_start_write(vp, &mp, V_WAIT); - vput(vp); - vp = NULL; - nfsm_srvnamesiz(len); - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = CREATE; - nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART; - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); - if (dirp) { - if (v3) { - dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, - td); - } else { - vrele(dirp); - dirp = NULL; - } - } - if (error) - goto out; - - VATTR_NULL(vap); - if (v3) - nfsm_srvsattr(vap); - nfsm_strsiz(len2, NFS_MAXPATHLEN); - MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); - iv.iov_base = pathcp; - iv.iov_len = len2; - io.uio_resid = len2; - io.uio_offset = 0; - io.uio_iov = &iv; - io.uio_iovcnt = 1; - io.uio_segflg = UIO_SYSSPACE; - io.uio_rw = UIO_READ; - io.uio_td = (struct thread *)0; - nfsm_mtouio(&io, len2); - if (!v3) { - nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); - vap->va_mode = fxdr_unsigned(u_int16_t, sp->sa_mode); - } - *(pathcp + len2) = '\0'; - if (nd.ni_vp) { - error = EEXIST; - goto out; - } - - /* - * issue symlink op. SAVESTART is set so the underlying path component - * is only freed by the VOP if an error occurs. - */ - nqsrv_getl(nd.ni_dvp, ND_WRITE); - error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); - if (error) - NDFREE(&nd, NDF_ONLY_PNBUF); - else { - vput(nd.ni_vp); - nd.ni_vp = NULL; - } - /* - * releases directory prior to potential lookup op. - */ - vput(nd.ni_dvp); - nd.ni_dvp = NULL; - - if (error == 0) { - if (v3) { - /* - * Issue lookup. Leave SAVESTART set so we can easily free - * the name buffer later on. - * - * since LOCKPARENT is not set, ni_dvp will be garbage on - * return whether an error occurs or not. - */ - nd.ni_cnd.cn_nameiop = LOOKUP; - nd.ni_cnd.cn_flags &= ~(LOCKPARENT | FOLLOW); - nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF); - nd.ni_cnd.cn_thread = td; - nd.ni_cnd.cn_cred = cred; - - error = lookup(&nd); - nd.ni_dvp = NULL; - - if (error == 0) { - bzero((caddr_t)fhp, sizeof(nfh)); - fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid; - error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid); - if (!error) - error = VOP_GETATTR(nd.ni_vp, vap, cred, - td); - vput(nd.ni_vp); - nd.ni_vp = NULL; - } - } - } -out: - /* - * These releases aren't strictly required, does even doing them - * make any sense? XXX can nfsm_reply() block? - */ - if (pathcp) { - FREE(pathcp, M_TEMP); - pathcp = NULL; - } - if (dirp) { - diraft_ret = VOP_GETATTR(dirp, &diraft, cred, td); - vrele(dirp); - dirp = NULL; - } - if (nd.ni_startdir) { - vrele(nd.ni_startdir); - nd.ni_startdir = NULL; - } - nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); - if (v3) { - if (!error) { - nfsm_srvpostop_fh(fhp); - nfsm_srvpostop_attr(0, vap); - } - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - } - error = 0; - /* fall through */ - -nfsmout: - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - } - if (nd.ni_vp) - vrele(nd.ni_vp); - if (nd.ni_startdir) - vrele(nd.ni_startdir); - if (dirp) - vrele(dirp); - if (pathcp) - FREE(pathcp, M_TEMP); - - vn_finished_write(mp); - return (error); -} - -/* - * nfs mkdir service - */ -int -nfsrv_mkdir(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - struct vattr va, dirfor, diraft; - register struct vattr *vap = &va; - register struct nfs_fattr *fp; - struct nameidata nd; - register caddr_t cp; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; - int v3 = (nfsd->nd_flag & ND_NFSV3); - char *cp2; - struct mbuf *mb, *mb2, *mreq; - struct vnode *dirp = NULL; - int vpexcl = 0; - nfsfh_t nfh; - fhandle_t *fhp; - u_quad_t frev; - struct mount *mp = NULL; - struct vnode *vp; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - ndclear(&nd); - - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { - error = ESTALE; - goto out; - } - if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != 0) { - mp = NULL; - goto out; - } - (void) vn_start_write(vp, &mp, V_WAIT); - vput(vp); - vp = NULL; - nfsm_srvnamesiz(len); - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = CREATE; - nd.ni_cnd.cn_flags = LOCKPARENT; - - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); - if (dirp) { - if (v3) { - dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, - td); - } else { - vrele(dirp); - dirp = NULL; - } - } - if (error) { - nfsm_reply(NFSX_WCCDATA(v3)); - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - error = 0; - goto nfsmout; - } - VATTR_NULL(vap); - if (v3) { - nfsm_srvsattr(vap); - } else { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - vap->va_mode = nfstov_mode(*tl++); - } - - /* - * At this point nd.ni_dvp is referenced and exclusively locked and - * nd.ni_vp, if it exists, is referenced but not locked. - */ - - vap->va_type = VDIR; - if (nd.ni_vp != NULL) { - NDFREE(&nd, NDF_ONLY_PNBUF); - error = EEXIST; - goto out; - } - - /* - * Issue mkdir op. Since SAVESTART is not set, the pathname - * component is freed by the VOP call. This will fill-in - * nd.ni_vp, reference, and exclusively lock it. - */ - nqsrv_getl(nd.ni_dvp, ND_WRITE); - error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); - NDFREE(&nd, NDF_ONLY_PNBUF); - vpexcl = 1; - - vput(nd.ni_dvp); - nd.ni_dvp = NULL; - - if (!error) { - bzero((caddr_t)fhp, sizeof(nfh)); - fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid; - error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid); - if (!error) - error = VOP_GETATTR(nd.ni_vp, vap, cred, td); - } -out: - if (dirp) - diraft_ret = VOP_GETATTR(dirp, &diraft, cred, td); - nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); - if (v3) { - if (!error) { - nfsm_srvpostop_fh(fhp); - nfsm_srvpostop_attr(0, vap); - } - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - } else { - /* v2, non-error case (see nfsm_reply) */ - nfsm_srvfhtom(fhp, v3); - nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); - nfsm_srvfillattr(vap, fp); - } - error = 0; - /* fall through */ - -nfsmout: - if (dirp) - vrele(dirp); - if (nd.ni_dvp) { - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp == nd.ni_vp && vpexcl) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - } - if (nd.ni_vp) { - if (vpexcl) - vput(nd.ni_vp); - else - vrele(nd.ni_vp); - } - vn_finished_write(mp); - return (error); -} - -/* - * nfs rmdir service - */ -int -nfsrv_rmdir(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; - int v3 = (nfsd->nd_flag & ND_NFSV3); - char *cp2; - struct mbuf *mb, *mreq; - struct vnode *vp, *dirp = (struct vnode *)0; - struct vattr dirfor, diraft; - nfsfh_t nfh; - fhandle_t *fhp; - struct nameidata nd; - u_quad_t frev; - struct mount *mp = NULL; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - ndclear(&nd); - - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { - error = ESTALE; - goto out; - } - if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != 0) { - mp = NULL; - goto out; - } - (void) vn_start_write(vp, &mp, V_WAIT); - vput(vp); - vp = NULL; - nfsm_srvnamesiz(len); - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = DELETE; - nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); - if (dirp) { - if (v3) { - dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, - td); - } else { - vrele(dirp); - dirp = NULL; - } - } - if (error) { - nfsm_reply(NFSX_WCCDATA(v3)); - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - error = 0; - goto nfsmout; - } - vp = nd.ni_vp; - if (vp->v_type != VDIR) { - error = ENOTDIR; - goto out; - } - /* - * No rmdir "." please. - */ - if (nd.ni_dvp == vp) { - error = EINVAL; - goto out; - } - /* - * The root of a mounted filesystem cannot be deleted. - */ - if (vp->v_flag & VROOT) - error = EBUSY; -out: - /* - * Issue or abort op. Since SAVESTART is not set, path name - * component is freed by the VOP after either. - */ - if (!error) { - nqsrv_getl(nd.ni_dvp, ND_WRITE); - nqsrv_getl(vp, ND_WRITE); - error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); - } - NDFREE(&nd, NDF_ONLY_PNBUF); - - if (dirp) - diraft_ret = VOP_GETATTR(dirp, &diraft, cred, td); - nfsm_reply(NFSX_WCCDATA(v3)); - if (v3) { - nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - error = 0; - } - /* fall through */ - -nfsmout: - NDFREE(&nd, NDF_ONLY_PNBUF); - if (dirp) - vrele(dirp); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - } - if (nd.ni_vp) - vput(nd.ni_vp); - - vn_finished_write(mp); - return(error); -} - -/* - * nfs readdir service - * - mallocs what it thinks is enough to read - * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR - * - calls VOP_READDIR() - * - loops around building the reply - * if the output generated exceeds count break out of loop - * The nfsm_clget macro is used here so that the reply will be packed - * tightly in mbuf clusters. - * - it only knows that it has encountered eof when the VOP_READDIR() - * reads nothing - * - as such one readdir rpc will return eof false although you are there - * and then the next will return eof - * - it trims out records with d_fileno == 0 - * this doesn't matter for Unix clients, but they might confuse clients - * for other os'. - * NB: It is tempting to set eof to true if the VOP_READDIR() reads less - * than requested, but this may not apply to all filesystems. For - * example, client NFS does not { although it is never remote mounted - * anyhow } - * The alternate call nfsrv_readdirplus() does lookups as well. - * PS: The NFS protocol spec. does not clarify what the "count" byte - * argument is a count of.. just name strings and file id's or the - * entire reply rpc or ... - * I tried just file name and id sizes and it confused the Sun client, - * so I am using the full rpc size now. The "paranoia.." comment refers - * to including the status longwords that are not a part of the dir. - * "entry" structures, but are in the rpc. - */ -struct flrep { - nfsuint64 fl_off; - u_int32_t fl_postopok; - u_int32_t fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)]; - u_int32_t fl_fhok; - u_int32_t fl_fhsize; - u_int32_t fl_nfh[NFSX_V3FH / sizeof (u_int32_t)]; -}; - -int -nfsrv_readdir(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - register char *bp, *be; - register struct mbuf *mp; - register struct dirent *dp; - register caddr_t cp; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - struct mbuf *mb, *mb2, *mreq, *mp2; - char *cpos, *cend, *cp2, *rbuf; - struct vnode *vp = NULL; - struct vattr at; - nfsfh_t nfh; - fhandle_t *fhp; - struct uio io; - struct iovec iv; - int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; - int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies; - int v3 = (nfsd->nd_flag & ND_NFSV3); - u_quad_t frev, off, toff, verf; - u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */ - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - if (v3) { - nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED); - toff = fxdr_hyper(tl); - tl += 2; - verf = fxdr_hyper(tl); - tl += 2; - } else { - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - toff = fxdr_unsigned(u_quad_t, *tl++); - verf = 0; /* shut up gcc */ - } - off = toff; - cnt = fxdr_unsigned(int, *tl); - siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); - xfer = NFS_SRVMAXDATA(nfsd); - if (siz > xfer) - siz = xfer; - fullsiz = siz; - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (!error && vp->v_type != VDIR) { - error = ENOTDIR; - vput(vp); - vp = NULL; - } - if (error) { - nfsm_reply(NFSX_UNSIGNED); - nfsm_srvpostop_attr(getret, &at); - error = 0; - goto nfsmout; - } - - /* - * Obtain lock on vnode for this section of the code - */ - - nqsrv_getl(vp, ND_READ); - if (v3) { - error = getret = VOP_GETATTR(vp, &at, cred, td); -#if 0 - /* - * XXX This check may be too strict for Solaris 2.5 clients. - */ - if (!error && toff && verf && verf != at.va_filerev) - error = NFSERR_BAD_COOKIE; -#endif - } - if (!error) - error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 0); - if (error) { - vput(vp); - vp = NULL; - nfsm_reply(NFSX_POSTOPATTR(v3)); - nfsm_srvpostop_attr(getret, &at); - error = 0; - goto nfsmout; - } - VOP_UNLOCK(vp, 0, td); - - /* - * end section. Allocate rbuf and continue - */ - MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); -again: - iv.iov_base = rbuf; - iv.iov_len = fullsiz; - io.uio_iov = &iv; - io.uio_iovcnt = 1; - io.uio_offset = (off_t)off; - io.uio_resid = fullsiz; - io.uio_segflg = UIO_SYSSPACE; - io.uio_rw = UIO_READ; - io.uio_td = (struct thread *)0; - eofflag = 0; - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - if (cookies) { - free((caddr_t)cookies, M_TEMP); - cookies = NULL; - } - error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); - off = (off_t)io.uio_offset; - if (!cookies && !error) - error = NFSERR_PERM; - if (v3) { - getret = VOP_GETATTR(vp, &at, cred, td); - if (!error) - error = getret; - } - VOP_UNLOCK(vp, 0, td); - if (error) { - vrele(vp); - vp = NULL; - free((caddr_t)rbuf, M_TEMP); - if (cookies) - free((caddr_t)cookies, M_TEMP); - nfsm_reply(NFSX_POSTOPATTR(v3)); - nfsm_srvpostop_attr(getret, &at); - error = 0; - goto nfsmout; - } - if (io.uio_resid) { - siz -= io.uio_resid; - - /* - * If nothing read, return eof - * rpc reply - */ - if (siz == 0) { - vrele(vp); - vp = NULL; - nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + - 2 * NFSX_UNSIGNED); - if (v3) { - nfsm_srvpostop_attr(getret, &at); - nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); - txdr_hyper(at.va_filerev, tl); - tl += 2; - } else - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - *tl++ = nfs_false; - *tl = nfs_true; - FREE((caddr_t)rbuf, M_TEMP); - FREE((caddr_t)cookies, M_TEMP); - error = 0; - goto nfsmout; - } - } - - /* - * Check for degenerate cases of nothing useful read. - * If so go try again - */ - cpos = rbuf; - cend = rbuf + siz; - dp = (struct dirent *)cpos; - cookiep = cookies; - /* - * For some reason FreeBSD's ufs_readdir() chooses to back the - * directory offset up to a block boundary, so it is necessary to - * skip over the records that precede the requested offset. This - * requires the assumption that file offset cookies monotonically - * increase. - */ - while (cpos < cend && ncookies > 0 && - (dp->d_fileno == 0 || dp->d_type == DT_WHT || - ((u_quad_t)(*cookiep)) <= toff)) { - cpos += dp->d_reclen; - dp = (struct dirent *)cpos; - cookiep++; - ncookies--; - } - if (cpos >= cend || ncookies == 0) { - toff = off; - siz = fullsiz; - goto again; - } - - len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ - nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz); - if (v3) { - nfsm_srvpostop_attr(getret, &at); - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - txdr_hyper(at.va_filerev, tl); - } - mp = mp2 = mb; - bp = bpos; - be = bp + M_TRAILINGSPACE(mp); - - /* Loop through the records and build reply */ - while (cpos < cend && ncookies > 0) { - if (dp->d_fileno != 0 && dp->d_type != DT_WHT) { - nlen = dp->d_namlen; - rem = nfsm_rndup(nlen) - nlen; - len += (4 * NFSX_UNSIGNED + nlen + rem); - if (v3) - len += 2 * NFSX_UNSIGNED; - if (len > cnt) { - eofflag = 0; - break; - } - /* - * Build the directory record xdr from - * the dirent entry. - */ - nfsm_clget; - *tl = nfs_true; - bp += NFSX_UNSIGNED; - if (v3) { - nfsm_clget; - *tl = 0; - bp += NFSX_UNSIGNED; - } - nfsm_clget; - *tl = txdr_unsigned(dp->d_fileno); - bp += NFSX_UNSIGNED; - nfsm_clget; - *tl = txdr_unsigned(nlen); - bp += NFSX_UNSIGNED; - - /* And loop around copying the name */ - xfer = nlen; - cp = dp->d_name; - while (xfer > 0) { - nfsm_clget; - if ((bp+xfer) > be) - tsiz = be-bp; - else - tsiz = xfer; - bcopy(cp, bp, tsiz); - bp += tsiz; - xfer -= tsiz; - if (xfer > 0) - cp += tsiz; - } - /* And null pad to a int32_t boundary */ - for (i = 0; i < rem; i++) - *bp++ = '\0'; - nfsm_clget; - - /* Finish off the record */ - if (v3) { - *tl = 0; - bp += NFSX_UNSIGNED; - nfsm_clget; - } - *tl = txdr_unsigned(*cookiep); - bp += NFSX_UNSIGNED; - } - cpos += dp->d_reclen; - dp = (struct dirent *)cpos; - cookiep++; - ncookies--; - } - vrele(vp); - vp = NULL; - nfsm_clget; - *tl = nfs_false; - bp += NFSX_UNSIGNED; - nfsm_clget; - if (eofflag) - *tl = nfs_true; - else - *tl = nfs_false; - bp += NFSX_UNSIGNED; - if (mp != mb) { - if (bp < be) - mp->m_len = bp - mtod(mp, caddr_t); - } else - mp->m_len += bp - bpos; - FREE((caddr_t)rbuf, M_TEMP); - FREE((caddr_t)cookies, M_TEMP); - -nfsmout: - if (vp) - vrele(vp); - return(error); -} - -int -nfsrv_readdirplus(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - register char *bp, *be; - register struct mbuf *mp; - register struct dirent *dp; - register caddr_t cp; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - struct mbuf *mb, *mb2, *mreq, *mp2; - char *cpos, *cend, *cp2, *rbuf; - struct vnode *vp = NULL, *nvp; - struct flrep fl; - nfsfh_t nfh; - fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh; - struct uio io; - struct iovec iv; - struct vattr va, at, *vap = &va; - struct nfs_fattr *fp; - int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; - int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies; - u_quad_t frev, off, toff, verf; - u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */ - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED); - toff = fxdr_hyper(tl); - tl += 2; - verf = fxdr_hyper(tl); - tl += 2; - siz = fxdr_unsigned(int, *tl++); - cnt = fxdr_unsigned(int, *tl); - off = toff; - siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); - xfer = NFS_SRVMAXDATA(nfsd); - if (siz > xfer) - siz = xfer; - fullsiz = siz; - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (!error && vp->v_type != VDIR) { - error = ENOTDIR; - vput(vp); - vp = NULL; - } - if (error) { - nfsm_reply(NFSX_UNSIGNED); - nfsm_srvpostop_attr(getret, &at); - error = 0; - goto nfsmout; - } - error = getret = VOP_GETATTR(vp, &at, cred, td); -#if 0 - /* - * XXX This check may be too strict for Solaris 2.5 clients. - */ - if (!error && toff && verf && verf != at.va_filerev) - error = NFSERR_BAD_COOKIE; -#endif - if (!error) { - nqsrv_getl(vp, ND_READ); - error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 0); - } - if (error) { - vput(vp); - vp = NULL; - nfsm_reply(NFSX_V3POSTOPATTR); - nfsm_srvpostop_attr(getret, &at); - error = 0; - goto nfsmout; - } - VOP_UNLOCK(vp, 0, td); - MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); -again: - iv.iov_base = rbuf; - iv.iov_len = fullsiz; - io.uio_iov = &iv; - io.uio_iovcnt = 1; - io.uio_offset = (off_t)off; - io.uio_resid = fullsiz; - io.uio_segflg = UIO_SYSSPACE; - io.uio_rw = UIO_READ; - io.uio_td = (struct thread *)0; - eofflag = 0; - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - if (cookies) { - free((caddr_t)cookies, M_TEMP); - cookies = NULL; - } - error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); - off = (u_quad_t)io.uio_offset; - getret = VOP_GETATTR(vp, &at, cred, td); - VOP_UNLOCK(vp, 0, td); - if (!cookies && !error) - error = NFSERR_PERM; - if (!error) - error = getret; - if (error) { - vrele(vp); - vp = NULL; - if (cookies) - free((caddr_t)cookies, M_TEMP); - free((caddr_t)rbuf, M_TEMP); - nfsm_reply(NFSX_V3POSTOPATTR); - nfsm_srvpostop_attr(getret, &at); - error = 0; - goto nfsmout; - } - if (io.uio_resid) { - siz -= io.uio_resid; - - /* - * If nothing read, return eof - * rpc reply - */ - if (siz == 0) { - vrele(vp); - vp = NULL; - nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + - 2 * NFSX_UNSIGNED); - nfsm_srvpostop_attr(getret, &at); - nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); - txdr_hyper(at.va_filerev, tl); - tl += 2; - *tl++ = nfs_false; - *tl = nfs_true; - FREE((caddr_t)cookies, M_TEMP); - FREE((caddr_t)rbuf, M_TEMP); - error = 0; - goto nfsmout; - } - } - - /* - * Check for degenerate cases of nothing useful read. - * If so go try again - */ - cpos = rbuf; - cend = rbuf + siz; - dp = (struct dirent *)cpos; - cookiep = cookies; - /* - * For some reason FreeBSD's ufs_readdir() chooses to back the - * directory offset up to a block boundary, so it is necessary to - * skip over the records that precede the requested offset. This - * requires the assumption that file offset cookies monotonically - * increase. - */ - while (cpos < cend && ncookies > 0 && - (dp->d_fileno == 0 || dp->d_type == DT_WHT || - ((u_quad_t)(*cookiep)) <= toff)) { - cpos += dp->d_reclen; - dp = (struct dirent *)cpos; - cookiep++; - ncookies--; - } - if (cpos >= cend || ncookies == 0) { - toff = off; - siz = fullsiz; - goto again; - } - - /* - * Probe one of the directory entries to see if the filesystem - * supports VGET. - */ - if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp) == EOPNOTSUPP) { - error = NFSERR_NOTSUPP; - vrele(vp); - vp = NULL; - free((caddr_t)cookies, M_TEMP); - free((caddr_t)rbuf, M_TEMP); - nfsm_reply(NFSX_V3POSTOPATTR); - nfsm_srvpostop_attr(getret, &at); - error = 0; - goto nfsmout; - } - vput(nvp); - nvp = NULL; - - dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED; - nfsm_reply(cnt); - nfsm_srvpostop_attr(getret, &at); - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - txdr_hyper(at.va_filerev, tl); - mp = mp2 = mb; - bp = bpos; - be = bp + M_TRAILINGSPACE(mp); - - /* Loop through the records and build reply */ - while (cpos < cend && ncookies > 0) { - if (dp->d_fileno != 0 && dp->d_type != DT_WHT) { - nlen = dp->d_namlen; - rem = nfsm_rndup(nlen)-nlen; - - /* - * For readdir_and_lookup get the vnode using - * the file number. - */ - if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) - goto invalid; - bzero((caddr_t)nfhp, NFSX_V3FH); - nfhp->fh_fsid = - nvp->v_mount->mnt_stat.f_fsid; - if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) { - vput(nvp); - nvp = NULL; - goto invalid; - } - if (VOP_GETATTR(nvp, vap, cred, td)) { - vput(nvp); - nvp = NULL; - goto invalid; - } - vput(nvp); - nvp = NULL; - - /* - * If either the dircount or maxcount will be - * exceeded, get out now. Both of these lengths - * are calculated conservatively, including all - * XDR overheads. - */ - len += (8 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH + - NFSX_V3POSTOPATTR); - dirlen += (6 * NFSX_UNSIGNED + nlen + rem); - if (len > cnt || dirlen > fullsiz) { - eofflag = 0; - break; - } - - /* - * Build the directory record xdr from - * the dirent entry. - */ - fp = (struct nfs_fattr *)&fl.fl_fattr; - nfsm_srvfillattr(vap, fp); - fl.fl_fhsize = txdr_unsigned(NFSX_V3FH); - fl.fl_fhok = nfs_true; - fl.fl_postopok = nfs_true; - fl.fl_off.nfsuquad[0] = 0; - fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep); - - nfsm_clget; - *tl = nfs_true; - bp += NFSX_UNSIGNED; - nfsm_clget; - *tl = 0; - bp += NFSX_UNSIGNED; - nfsm_clget; - *tl = txdr_unsigned(dp->d_fileno); - bp += NFSX_UNSIGNED; - nfsm_clget; - *tl = txdr_unsigned(nlen); - bp += NFSX_UNSIGNED; - - /* And loop around copying the name */ - xfer = nlen; - cp = dp->d_name; - while (xfer > 0) { - nfsm_clget; - if ((bp + xfer) > be) - tsiz = be - bp; - else - tsiz = xfer; - bcopy(cp, bp, tsiz); - bp += tsiz; - xfer -= tsiz; - if (xfer > 0) - cp += tsiz; - } - /* And null pad to a int32_t boundary */ - for (i = 0; i < rem; i++) - *bp++ = '\0'; - - /* - * Now copy the flrep structure out. - */ - xfer = sizeof (struct flrep); - cp = (caddr_t)&fl; - while (xfer > 0) { - nfsm_clget; - if ((bp + xfer) > be) - tsiz = be - bp; - else - tsiz = xfer; - bcopy(cp, bp, tsiz); - bp += tsiz; - xfer -= tsiz; - if (xfer > 0) - cp += tsiz; - } - } -invalid: - cpos += dp->d_reclen; - dp = (struct dirent *)cpos; - cookiep++; - ncookies--; - } - vrele(vp); - vp = NULL; - nfsm_clget; - *tl = nfs_false; - bp += NFSX_UNSIGNED; - nfsm_clget; - if (eofflag) - *tl = nfs_true; - else - *tl = nfs_false; - bp += NFSX_UNSIGNED; - if (mp != mb) { - if (bp < be) - mp->m_len = bp - mtod(mp, caddr_t); - } else - mp->m_len += bp - bpos; - FREE((caddr_t)cookies, M_TEMP); - FREE((caddr_t)rbuf, M_TEMP); -nfsmout: - if (vp) - vrele(vp); - return(error); -} - -/* - * nfs commit service - */ -int -nfsrv_commit(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - struct vattr bfor, aft; - struct vnode *vp = NULL; - nfsfh_t nfh; - fhandle_t *fhp; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache; - char *cp2; - struct mbuf *mb, *mb2, *mreq; - u_quad_t frev, off; - struct mount *mp = NULL; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - cache = 0; -#endif - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { - error = ESTALE; - goto ereply; - } - if ((error = VFS_FHTOVP(mp, &fhp->fh_fid, &vp)) != 0) { - mp = NULL; - goto ereply; - } - (void) vn_start_write(vp, &mp, V_WAIT); - vput(vp); - vp = NULL; - nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); - - /* - * XXX At this time VOP_FSYNC() does not accept offset and byte - * count parameters, so these arguments are useless (someday maybe). - */ - off = fxdr_hyper(tl); - tl += 2; - cnt = fxdr_unsigned(int, *tl); - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(2 * NFSX_UNSIGNED); - nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft); - error = 0; - goto nfsmout; - } - for_ret = VOP_GETATTR(vp, &bfor, cred, td); - - if (cnt > MAX_COMMIT_COUNT) { - /* - * Give up and do the whole thing - */ - if (vp->v_object && - (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) { - vm_object_page_clean(vp->v_object, 0, 0, OBJPC_SYNC); - } - error = VOP_FSYNC(vp, cred, MNT_WAIT, td); - } else { - /* - * Locate and synchronously write any buffers that fall - * into the requested range. Note: we are assuming that - * f_iosize is a power of 2. - */ - int iosize = vp->v_mount->mnt_stat.f_iosize; - int iomask = iosize - 1; - int s; - daddr_t lblkno; - - /* - * Align to iosize boundry, super-align to page boundry. - */ - if (off & iomask) { - cnt += off & iomask; - off &= ~(u_quad_t)iomask; - } - if (off & PAGE_MASK) { - cnt += off & PAGE_MASK; - off &= ~(u_quad_t)PAGE_MASK; - } - lblkno = off / iosize; - - if (vp->v_object && - (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) { - vm_object_page_clean(vp->v_object, off / PAGE_SIZE, (cnt + PAGE_MASK) / PAGE_SIZE, OBJPC_SYNC); - } - - s = splbio(); - while (cnt > 0) { - struct buf *bp; - - /* - * If we have a buffer and it is marked B_DELWRI we - * have to lock and write it. Otherwise the prior - * write is assumed to have already been committed. - */ - if ((bp = gbincore(vp, lblkno)) != NULL && (bp->b_flags & B_DELWRI)) { - if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) { - BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL); - continue; /* retry */ - } - bremfree(bp); - bp->b_flags &= ~B_ASYNC; - BUF_WRITE(bp); - ++nfs_commit_miss; - } - ++nfs_commit_blks; - if (cnt < iosize) - break; - cnt -= iosize; - ++lblkno; - } - splx(s); - } - - aft_ret = VOP_GETATTR(vp, &aft, cred, td); - vput(vp); - vp = NULL; -ereply: - nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF); - nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft); - if (!error) { - nfsm_build(tl, u_int32_t *, NFSX_V3WRITEVERF); - if (nfsver.tv_sec == 0) - nfsver = boottime; - *tl++ = txdr_unsigned(nfsver.tv_sec); - *tl = txdr_unsigned(nfsver.tv_usec); - } else { - error = 0; - } -nfsmout: - if (vp) - vput(vp); - vn_finished_write(mp); - return(error); -} - -/* - * nfs statfs service - */ -int -nfsrv_statfs(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - register struct statfs *sf; - register struct nfs_statfs *sfp; - register u_int32_t *tl; - register int32_t t1; - caddr_t bpos; - int error = 0, rdonly, cache, getret = 1; - int v3 = (nfsd->nd_flag & ND_NFSV3); - char *cp2; - struct mbuf *mb, *mb2, *mreq; - struct vnode *vp = NULL; - struct vattr at; - nfsfh_t nfh; - fhandle_t *fhp; - struct statfs statfs; - u_quad_t frev, tval; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - cache = 0; -#endif - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(NFSX_UNSIGNED); - nfsm_srvpostop_attr(getret, &at); - error = 0; - goto nfsmout; - } - sf = &statfs; - error = VFS_STATFS(vp->v_mount, sf, td); - getret = VOP_GETATTR(vp, &at, cred, td); - vput(vp); - vp = NULL; - nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3)); - if (v3) - nfsm_srvpostop_attr(getret, &at); - if (error) { - error = 0; - goto nfsmout; - } - nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3)); - if (v3) { - tval = (u_quad_t)sf->f_blocks; - tval *= (u_quad_t)sf->f_bsize; - txdr_hyper(tval, &sfp->sf_tbytes); - tval = (u_quad_t)sf->f_bfree; - tval *= (u_quad_t)sf->f_bsize; - txdr_hyper(tval, &sfp->sf_fbytes); - tval = (u_quad_t)sf->f_bavail; - tval *= (u_quad_t)sf->f_bsize; - txdr_hyper(tval, &sfp->sf_abytes); - sfp->sf_tfiles.nfsuquad[0] = 0; - sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files); - sfp->sf_ffiles.nfsuquad[0] = 0; - sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree); - sfp->sf_afiles.nfsuquad[0] = 0; - sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree); - sfp->sf_invarsec = 0; - } else { - sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); - sfp->sf_bsize = txdr_unsigned(sf->f_bsize); - sfp->sf_blocks = txdr_unsigned(sf->f_blocks); - sfp->sf_bfree = txdr_unsigned(sf->f_bfree); - sfp->sf_bavail = txdr_unsigned(sf->f_bavail); - } -nfsmout: - if (vp) - vput(vp); - return(error); -} - -/* - * nfs fsinfo service - */ -int -nfsrv_fsinfo(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - register u_int32_t *tl; - register struct nfsv3_fsinfo *sip; - register int32_t t1; - caddr_t bpos; - int error = 0, rdonly, cache, getret = 1, pref; - char *cp2; - struct mbuf *mb, *mb2, *mreq; - struct vnode *vp = NULL; - struct vattr at; - nfsfh_t nfh; - fhandle_t *fhp; - u_quad_t frev, maxfsize; - struct statfs sb; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - cache = 0; -#endif - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(NFSX_UNSIGNED); - nfsm_srvpostop_attr(getret, &at); - error = 0; - goto nfsmout; - } - - /* XXX Try to make a guess on the max file size. */ - VFS_STATFS(vp->v_mount, &sb, td); - maxfsize = (u_quad_t)0x80000000 * sb.f_bsize - 1; - - getret = VOP_GETATTR(vp, &at, cred, td); - vput(vp); - vp = NULL; - nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO); - nfsm_srvpostop_attr(getret, &at); - nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO); - - /* - * XXX - * There should be file system VFS OP(s) to get this information. - * For now, assume ufs. - */ - if (slp->ns_so->so_type == SOCK_DGRAM) - pref = NFS_MAXDGRAMDATA; - else - pref = NFS_MAXDATA; - sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA); - sip->fs_rtpref = txdr_unsigned(pref); - sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE); - sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA); - sip->fs_wtpref = txdr_unsigned(pref); - sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE); - sip->fs_dtpref = txdr_unsigned(pref); - txdr_hyper(maxfsize, &sip->fs_maxfilesize); - sip->fs_timedelta.nfsv3_sec = 0; - sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1); - sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK | - NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS | - NFSV3FSINFO_CANSETTIME); -nfsmout: - if (vp) - vput(vp); - return(error); -} - -/* - * nfs pathconf service - */ -int -nfsrv_pathconf(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; - struct sockaddr *nam = nfsd->nd_nam; - caddr_t dpos = nfsd->nd_dpos; - struct ucred *cred = &nfsd->nd_cr; - register u_int32_t *tl; - register struct nfsv3_pathconf *pc; - register int32_t t1; - caddr_t bpos; - int error = 0, rdonly, cache, getret = 1; - register_t linkmax, namemax, chownres, notrunc; - char *cp2; - struct mbuf *mb, *mb2, *mreq; - struct vnode *vp = NULL; - struct vattr at; - nfsfh_t nfh; - fhandle_t *fhp; - u_quad_t frev; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - cache = 0; -#endif - fhp = &nfh.fh_generic; - nfsm_srvmtofh(fhp); - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); - if (error) { - nfsm_reply(NFSX_UNSIGNED); - nfsm_srvpostop_attr(getret, &at); - error = 0; - goto nfsmout; - } - error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax); - if (!error) - error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax); - if (!error) - error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres); - if (!error) - error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc); - getret = VOP_GETATTR(vp, &at, cred, td); - vput(vp); - vp = NULL; - nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF); - nfsm_srvpostop_attr(getret, &at); - if (error) { - error = 0; - goto nfsmout; - } - nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); - - pc->pc_linkmax = txdr_unsigned(linkmax); - pc->pc_namemax = txdr_unsigned(namemax); - pc->pc_notrunc = txdr_unsigned(notrunc); - pc->pc_chownrestricted = txdr_unsigned(chownres); - - /* - * These should probably be supported by VOP_PATHCONF(), but - * until msdosfs is exportable (why would you want to?), the - * Unix defaults should be ok. - */ - pc->pc_caseinsensitive = nfs_false; - pc->pc_casepreserving = nfs_true; -nfsmout: - if (vp) - vput(vp); - return(error); -} - -/* - * Null operation, used by clients to ping server - */ -/* ARGSUSED */ -int -nfsrv_null(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep; - caddr_t bpos; - int error = NFSERR_RETVOID, cache; - struct mbuf *mb, *mreq; - u_quad_t frev; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - cache = 0; -#endif - nfsm_reply(0); - nfsm_srvdone; -} - -/* - * No operation, used for obsolete procedures - */ -/* ARGSUSED */ -int -nfsrv_noop(nfsd, slp, td, mrq) - struct nfsrv_descript *nfsd; - struct nfssvc_sock *slp; - struct thread *td; - struct mbuf **mrq; -{ - struct mbuf *mrep = nfsd->nd_mrep; - caddr_t bpos; - int error, cache; - struct mbuf *mb, *mreq; - u_quad_t frev; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); -#ifndef nolint - cache = 0; -#endif - if (nfsd->nd_repstat) - error = nfsd->nd_repstat; - else - error = EPROCUNAVAIL; - nfsm_reply(0); - nfsm_srvdone; -} - -/* - * Perform access checking for vnodes obtained from file handles that would - * refer to files already opened by a Unix client. You cannot just use - * vn_writechk() and VOP_ACCESS() for two reasons. - * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case - * 2 - The owner is to be given access irrespective of mode bits for some - * operations, so that processes that chmod after opening a file don't - * break. I don't like this because it opens a security hole, but since - * the nfs server opens a security hole the size of a barn door anyhow, - * what the heck. - * - * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS() - * will return EPERM instead of EACCESS. EPERM is always an error. - */ -static int -nfsrv_access(vp, flags, cred, rdonly, td, override) - register struct vnode *vp; - int flags; - register struct ucred *cred; - int rdonly; - struct thread *td; - int override; -{ - struct vattr vattr; - int error; - - nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - if (flags & VWRITE) { - /* Just vn_writechk() changed to check rdonly */ - /* - * Disallow write attempts on read-only file systems; - * unless the file is a socket or a block or character - * device resident on the file system. - */ - if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { - switch (vp->v_type) { - case VREG: - case VDIR: - case VLNK: - return (EROFS); - default: - break; - } - } - /* - * If there's shared text associated with - * the inode, we can't allow writing. - */ - if (vp->v_flag & VTEXT) - return (ETXTBSY); - } - error = VOP_GETATTR(vp, &vattr, cred, td); - if (error) - return (error); - error = VOP_ACCESS(vp, flags, cred, td); - /* - * Allow certain operations for the owner (reads and writes - * on files that are already open). - */ - if (override && error == EACCES && cred->cr_uid == vattr.va_uid) - error = 0; - return error; -} -#endif /* NFS_NOSERVER */ diff --git a/sys/nfs/nfs_socket.c b/sys/nfs/nfs_socket.c deleted file mode 100644 index 8991672..0000000 --- a/sys/nfs/nfs_socket.c +++ /dev/null @@ -1,2296 +0,0 @@ -/* - * Copyright (c) 1989, 1991, 1993, 1995 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95 - * $FreeBSD$ - */ - -/* - * Socket operations for use by nfs - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TRUE 1 -#define FALSE 0 - -/* - * Estimate rto for an nfs rpc sent via. an unreliable datagram. - * Use the mean and mean deviation of rtt for the appropriate type of rpc - * for the frequent rpcs and a default for the others. - * The justification for doing "other" this way is that these rpcs - * happen so infrequently that timer est. would probably be stale. - * Also, since many of these rpcs are - * non-idempotent, a conservative timeout is desired. - * getattr, lookup - A+2D - * read, write - A+4D - * other - nm_timeo - */ -#define NFS_RTO(n, t) \ - ((t) == 0 ? (n)->nm_timeo : \ - ((t) < 3 ? \ - (((((n)->nm_srtt[t-1] + 3) >> 2) + (n)->nm_sdrtt[t-1] + 1) >> 1) : \ - ((((n)->nm_srtt[t-1] + 7) >> 3) + (n)->nm_sdrtt[t-1] + 1))) -#define NFS_SRTT(r) (r)->r_nmp->nm_srtt[proct[(r)->r_procnum] - 1] -#define NFS_SDRTT(r) (r)->r_nmp->nm_sdrtt[proct[(r)->r_procnum] - 1] -/* - * External data, mostly RPC constants in XDR form - */ -extern u_int32_t rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, - rpc_auth_unix, rpc_msgaccepted, rpc_call, rpc_autherr, - rpc_auth_kerb; -extern u_int32_t nfs_prog, nqnfs_prog; -extern time_t nqnfsstarttime; -extern struct nfsstats nfsstats; -extern int nfsv3_procid[NFS_NPROCS]; -extern int nfs_ticks; - -/* - * Defines which timer to use for the procnum. - * 0 - default - * 1 - getattr - * 2 - lookup - * 3 - read - * 4 - write - */ -static int proct[NFS_NPROCS] = { - 0, 1, 0, 2, 1, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, - 0, 0, 0, -}; - -static int nfs_realign_test; -static int nfs_realign_count; -static int nfs_bufpackets = 4; - -SYSCTL_DECL(_vfs_nfs); - -SYSCTL_INT(_vfs_nfs, OID_AUTO, realign_test, CTLFLAG_RW, &nfs_realign_test, 0, ""); -SYSCTL_INT(_vfs_nfs, OID_AUTO, realign_count, CTLFLAG_RW, &nfs_realign_count, 0, ""); -SYSCTL_INT(_vfs_nfs, OID_AUTO, bufpackets, CTLFLAG_RW, &nfs_bufpackets, 0, ""); - - -/* - * There is a congestion window for outstanding rpcs maintained per mount - * point. The cwnd size is adjusted in roughly the way that: - * Van Jacobson, Congestion avoidance and Control, In "Proceedings of - * SIGCOMM '88". ACM, August 1988. - * describes for TCP. The cwnd size is chopped in half on a retransmit timeout - * and incremented by 1/cwnd when each rpc reply is received and a full cwnd - * of rpcs is in progress. - * (The sent count and cwnd are scaled for integer arith.) - * Variants of "slow start" were tried and were found to be too much of a - * performance hit (ave. rtt 3 times larger), - * I suspect due to the large rtt that nfs rpcs have. - */ -#define NFS_CWNDSCALE 256 -#define NFS_MAXCWND (NFS_CWNDSCALE * 32) -static int nfs_backoff[8] = { 2, 4, 8, 16, 32, 64, 128, 256, }; -int nfsrtton = 0; -struct nfsrtt nfsrtt; -struct callout_handle nfs_timer_handle; - -static int nfs_msg __P((struct thread *,char *,char *)); -static int nfs_rcvlock __P((struct nfsreq *)); -static void nfs_rcvunlock __P((struct nfsreq *)); -static void nfs_realign __P((struct mbuf **pm, int hsiz)); -static int nfs_receive __P((struct nfsreq *rep, struct sockaddr **aname, - struct mbuf **mp)); -static void nfs_softterm __P((struct nfsreq *rep)); -static int nfs_reconnect __P((struct nfsreq *rep)); -#ifndef NFS_NOSERVER -static int nfsrv_getstream __P((struct nfssvc_sock *,int)); - -int (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *nd, - struct nfssvc_sock *slp, - struct thread *td, - struct mbuf **mreqp)) = { - nfsrv_null, - nfsrv_getattr, - nfsrv_setattr, - nfsrv_lookup, - nfsrv3_access, - nfsrv_readlink, - nfsrv_read, - nfsrv_write, - nfsrv_create, - nfsrv_mkdir, - nfsrv_symlink, - nfsrv_mknod, - nfsrv_remove, - nfsrv_rmdir, - nfsrv_rename, - nfsrv_link, - nfsrv_readdir, - nfsrv_readdirplus, - nfsrv_statfs, - nfsrv_fsinfo, - nfsrv_pathconf, - nfsrv_commit, - nqnfsrv_getlease, - nqnfsrv_vacated, - nfsrv_noop, - nfsrv_noop -}; -#endif /* NFS_NOSERVER */ - -/* - * Initialize sockets and congestion for a new NFS connection. - * We do not free the sockaddr if error. - */ -int -nfs_connect(nmp, rep) - register struct nfsmount *nmp; - struct nfsreq *rep; -{ - register struct socket *so; - int s, error, rcvreserve, sndreserve; - int pktscale; - struct sockaddr *saddr; - struct sockaddr_in *sin; - struct thread *td = thread0; /* only used for socreate and sobind */ - - nmp->nm_so = (struct socket *)0; - saddr = nmp->nm_nam; - error = socreate(saddr->sa_family, &nmp->nm_so, nmp->nm_sotype, - nmp->nm_soproto, td); - if (error) - goto bad; - so = nmp->nm_so; - nmp->nm_soflags = so->so_proto->pr_flags; - - /* - * Some servers require that the client port be a reserved port number. - */ - if (saddr->sa_family == AF_INET && (nmp->nm_flag & NFSMNT_RESVPORT)) { - struct sockopt sopt; - int ip; - struct sockaddr_in ssin; - - bzero(&sopt, sizeof sopt); - ip = IP_PORTRANGE_LOW; - sopt.sopt_dir = SOPT_SET; - sopt.sopt_level = IPPROTO_IP; - sopt.sopt_name = IP_PORTRANGE; - sopt.sopt_val = (void *)&ip; - sopt.sopt_valsize = sizeof(ip); - sopt.sopt_td = NULL; - error = sosetopt(so, &sopt); - if (error) - goto bad; - bzero(&ssin, sizeof ssin); - sin = &ssin; - sin->sin_len = sizeof (struct sockaddr_in); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = INADDR_ANY; - sin->sin_port = htons(0); - error = sobind(so, (struct sockaddr *)sin, td); - if (error) - goto bad; - bzero(&sopt, sizeof sopt); - ip = IP_PORTRANGE_DEFAULT; - sopt.sopt_dir = SOPT_SET; - sopt.sopt_level = IPPROTO_IP; - sopt.sopt_name = IP_PORTRANGE; - sopt.sopt_val = (void *)&ip; - sopt.sopt_valsize = sizeof(ip); - sopt.sopt_td = NULL; - error = sosetopt(so, &sopt); - if (error) - goto bad; - } - - /* - * Protocols that do not require connections may be optionally left - * unconnected for servers that reply from a port other than NFS_PORT. - */ - if (nmp->nm_flag & NFSMNT_NOCONN) { - if (nmp->nm_soflags & PR_CONNREQUIRED) { - error = ENOTCONN; - goto bad; - } - } else { - error = soconnect(so, nmp->nm_nam, td); - if (error) - goto bad; - - /* - * Wait for the connection to complete. Cribbed from the - * connect system call but with the wait timing out so - * that interruptible mounts don't hang here for a long time. - */ - s = splnet(); - while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { - (void) tsleep((caddr_t)&so->so_timeo, PSOCK, - "nfscon", 2 * hz); - if ((so->so_state & SS_ISCONNECTING) && - so->so_error == 0 && rep && - (error = nfs_sigintr(nmp, rep, - (rep->r_td ? rep->r_td->td_proc : NULL))) != 0){ - so->so_state &= ~SS_ISCONNECTING; - splx(s); - goto bad; - } - } - if (so->so_error) { - error = so->so_error; - so->so_error = 0; - splx(s); - goto bad; - } - splx(s); - } - if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_INT)) { - so->so_rcv.sb_timeo = (5 * hz); - so->so_snd.sb_timeo = (5 * hz); - } else { - so->so_rcv.sb_timeo = 0; - so->so_snd.sb_timeo = 0; - } - - /* - * Get buffer reservation size from sysctl, but impose reasonable - * limits. - */ - pktscale = nfs_bufpackets; - if (pktscale < 2) - pktscale = 2; - if (pktscale > 64) - pktscale = 64; - - if (nmp->nm_sotype == SOCK_DGRAM) { - sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale; - rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) + - NFS_MAXPKTHDR) * pktscale; - } else if (nmp->nm_sotype == SOCK_SEQPACKET) { - sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale; - rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) + - NFS_MAXPKTHDR) * pktscale; - } else { - if (nmp->nm_sotype != SOCK_STREAM) - panic("nfscon sotype"); - if (so->so_proto->pr_flags & PR_CONNREQUIRED) { - struct sockopt sopt; - int val; - - bzero(&sopt, sizeof sopt); - sopt.sopt_level = SOL_SOCKET; - sopt.sopt_name = SO_KEEPALIVE; - sopt.sopt_val = &val; - sopt.sopt_valsize = sizeof val; - val = 1; - sosetopt(so, &sopt); - } - if (so->so_proto->pr_protocol == IPPROTO_TCP) { - struct sockopt sopt; - int val; - - bzero(&sopt, sizeof sopt); - sopt.sopt_level = IPPROTO_TCP; - sopt.sopt_name = TCP_NODELAY; - sopt.sopt_val = &val; - sopt.sopt_valsize = sizeof val; - val = 1; - sosetopt(so, &sopt); - } - sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR + - sizeof (u_int32_t)) * pktscale; - rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR + - sizeof (u_int32_t)) * pktscale; - } - error = soreserve(so, sndreserve, rcvreserve); - if (error) - goto bad; - so->so_rcv.sb_flags |= SB_NOINTR; - so->so_snd.sb_flags |= SB_NOINTR; - - /* Initialize other non-zero congestion variables */ - nmp->nm_srtt[0] = nmp->nm_srtt[1] = nmp->nm_srtt[2] = - nmp->nm_srtt[3] = (NFS_TIMEO << 3); - nmp->nm_sdrtt[0] = nmp->nm_sdrtt[1] = nmp->nm_sdrtt[2] = - nmp->nm_sdrtt[3] = 0; - nmp->nm_cwnd = NFS_MAXCWND / 2; /* Initial send window */ - nmp->nm_sent = 0; - nmp->nm_timeouts = 0; - return (0); - -bad: - nfs_disconnect(nmp); - return (error); -} - -/* - * Reconnect routine: - * Called when a connection is broken on a reliable protocol. - * - clean up the old socket - * - nfs_connect() again - * - set R_MUSTRESEND for all outstanding requests on mount point - * If this fails the mount point is DEAD! - * nb: Must be called with the nfs_sndlock() set on the mount point. - */ -static int -nfs_reconnect(rep) - register struct nfsreq *rep; -{ - register struct nfsreq *rp; - register struct nfsmount *nmp = rep->r_nmp; - int error; - - nfs_disconnect(nmp); - while ((error = nfs_connect(nmp, rep)) != 0) { - if (error == EINTR || error == ERESTART) - return (EINTR); - (void) tsleep((caddr_t)&lbolt, PSOCK, "nfscon", 0); - } - - /* - * Loop through outstanding request list and fix up all requests - * on old socket. - */ - for (rp = nfs_reqq.tqh_first; rp != 0; rp = rp->r_chain.tqe_next) { - if (rp->r_nmp == nmp) - rp->r_flags |= R_MUSTRESEND; - } - return (0); -} - -/* - * NFS disconnect. Clean up and unlink. - */ -void -nfs_disconnect(nmp) - register struct nfsmount *nmp; -{ - register struct socket *so; - - if (nmp->nm_so) { - so = nmp->nm_so; - nmp->nm_so = (struct socket *)0; - soshutdown(so, 2); - soclose(so); - } -} - -void -nfs_safedisconnect(nmp) - struct nfsmount *nmp; -{ - struct nfsreq dummyreq; - - bzero(&dummyreq, sizeof(dummyreq)); - dummyreq.r_nmp = nmp; - nfs_rcvlock(&dummyreq); - nfs_disconnect(nmp); - nfs_rcvunlock(&dummyreq); -} - -/* - * This is the nfs send routine. For connection based socket types, it - * must be called with an nfs_sndlock() on the socket. - * "rep == NULL" indicates that it has been called from a server. - * For the client side: - * - return EINTR if the RPC is terminated, 0 otherwise - * - set R_MUSTRESEND if the send fails for any reason - * - do any cleanup required by recoverable socket errors (?) - * For the server side: - * - return EINTR or ERESTART if interrupted by a signal - * - return EPIPE if a connection is lost for connection based sockets (TCP...) - * - do any cleanup required by recoverable socket errors (?) - */ -int -nfs_send(so, nam, top, rep) - register struct socket *so; - struct sockaddr *nam; - register struct mbuf *top; - struct nfsreq *rep; -{ - struct sockaddr *sendnam; - int error, soflags, flags; - - if (rep) { - if (rep->r_flags & R_SOFTTERM) { - m_freem(top); - return (EINTR); - } - if ((so = rep->r_nmp->nm_so) == NULL) { - rep->r_flags |= R_MUSTRESEND; - m_freem(top); - return (0); - } - rep->r_flags &= ~R_MUSTRESEND; - soflags = rep->r_nmp->nm_soflags; - } else - soflags = so->so_proto->pr_flags; - if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED)) - sendnam = (struct sockaddr *)0; - else - sendnam = nam; - if (so->so_type == SOCK_SEQPACKET) - flags = MSG_EOR; - else - flags = 0; - - error = so->so_proto->pr_usrreqs->pru_sosend(so, sendnam, 0, top, 0, - flags, curthread /*XXX*/); - /* - * ENOBUFS for dgram sockets is transient and non fatal. - * No need to log, and no need to break a soft mount. - */ - if (error == ENOBUFS && so->so_type == SOCK_DGRAM) { - error = 0; - if (rep) /* do backoff retransmit on client */ - rep->r_flags |= R_MUSTRESEND; - } - - if (error) { - if (rep) { - log(LOG_INFO, "nfs send error %d for server %s\n",error, - rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); - /* - * Deal with errors for the client side. - */ - if (rep->r_flags & R_SOFTTERM) - error = EINTR; - else - rep->r_flags |= R_MUSTRESEND; - } else - log(LOG_INFO, "nfsd send error %d\n", error); - - /* - * Handle any recoverable (soft) socket errors here. (?) - */ - if (error != EINTR && error != ERESTART && - error != EWOULDBLOCK && error != EPIPE) - error = 0; - } - return (error); -} - -/* - * Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all - * done by soreceive(), but for SOCK_STREAM we must deal with the Record - * Mark and consolidate the data into a new mbuf list. - * nb: Sometimes TCP passes the data up to soreceive() in long lists of - * small mbufs. - * For SOCK_STREAM we must be very careful to read an entire record once - * we have read any of it, even if the system call has been interrupted. - */ -static int -nfs_receive(rep, aname, mp) - register struct nfsreq *rep; - struct sockaddr **aname; - struct mbuf **mp; -{ - register struct socket *so; - struct uio auio; - struct iovec aio; - register struct mbuf *m; - struct mbuf *control; - u_int32_t len; - struct sockaddr **getnam; - int error, sotype, rcvflg; - struct thread *td = curthread; /* XXX */ - - /* - * Set up arguments for soreceive() - */ - *mp = (struct mbuf *)0; - *aname = (struct sockaddr *)0; - sotype = rep->r_nmp->nm_sotype; - - /* - * For reliable protocols, lock against other senders/receivers - * in case a reconnect is necessary. - * For SOCK_STREAM, first get the Record Mark to find out how much - * more there is to get. - * We must lock the socket against other receivers - * until we have an entire rpc request/reply. - */ - if (sotype != SOCK_DGRAM) { - error = nfs_sndlock(rep); - if (error) - return (error); -tryagain: - /* - * Check for fatal errors and resending request. - */ - /* - * Ugh: If a reconnect attempt just happened, nm_so - * would have changed. NULL indicates a failed - * attempt that has essentially shut down this - * mount point. - */ - if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) { - nfs_sndunlock(rep); - return (EINTR); - } - so = rep->r_nmp->nm_so; - if (!so) { - error = nfs_reconnect(rep); - if (error) { - nfs_sndunlock(rep); - return (error); - } - goto tryagain; - } - while (rep->r_flags & R_MUSTRESEND) { - m = m_copym(rep->r_mreq, 0, M_COPYALL, M_TRYWAIT); - nfsstats.rpcretries++; - error = nfs_send(so, rep->r_nmp->nm_nam, m, rep); - if (error) { - if (error == EINTR || error == ERESTART || - (error = nfs_reconnect(rep)) != 0) { - nfs_sndunlock(rep); - return (error); - } - goto tryagain; - } - } - nfs_sndunlock(rep); - if (sotype == SOCK_STREAM) { - aio.iov_base = (caddr_t) &len; - aio.iov_len = sizeof(u_int32_t); - auio.uio_iov = &aio; - auio.uio_iovcnt = 1; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_rw = UIO_READ; - auio.uio_offset = 0; - auio.uio_resid = sizeof(u_int32_t); - auio.uio_td = td; - do { - rcvflg = MSG_WAITALL; - error = so->so_proto->pr_usrreqs->pru_soreceive - (so, (struct sockaddr **)0, &auio, - (struct mbuf **)0, (struct mbuf **)0, - &rcvflg); - if (error == EWOULDBLOCK && rep) { - if (rep->r_flags & R_SOFTTERM) - return (EINTR); - } - } while (error == EWOULDBLOCK); - if (!error && auio.uio_resid > 0) { - /* - * Don't log a 0 byte receive; it means - * that the socket has been closed, and - * can happen during normal operation - * (forcible unmount or Solaris server). - */ - if (auio.uio_resid != sizeof (u_int32_t)) - log(LOG_INFO, - "short receive (%d/%d) from nfs server %s\n", - (int)(sizeof(u_int32_t) - auio.uio_resid), - (int)sizeof(u_int32_t), - rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); - error = EPIPE; - } - if (error) - goto errout; - len = ntohl(len) & ~0x80000000; - /* - * This is SERIOUS! We are out of sync with the sender - * and forcing a disconnect/reconnect is all I can do. - */ - if (len > NFS_MAXPACKET) { - log(LOG_ERR, "%s (%d) from nfs server %s\n", - "impossible packet length", - len, - rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); - error = EFBIG; - goto errout; - } - auio.uio_resid = len; - do { - rcvflg = MSG_WAITALL; - error = so->so_proto->pr_usrreqs->pru_soreceive - (so, (struct sockaddr **)0, - &auio, mp, (struct mbuf **)0, &rcvflg); - } while (error == EWOULDBLOCK || error == EINTR || - error == ERESTART); - if (!error && auio.uio_resid > 0) { - if (len != auio.uio_resid) - log(LOG_INFO, - "short receive (%d/%d) from nfs server %s\n", - len - auio.uio_resid, len, - rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); - error = EPIPE; - } - } else { - /* - * NB: Since uio_resid is big, MSG_WAITALL is ignored - * and soreceive() will return when it has either a - * control msg or a data msg. - * We have no use for control msg., but must grab them - * and then throw them away so we know what is going - * on. - */ - auio.uio_resid = len = 100000000; /* Anything Big */ - auio.uio_td = td; - do { - rcvflg = 0; - error = so->so_proto->pr_usrreqs->pru_soreceive - (so, (struct sockaddr **)0, - &auio, mp, &control, &rcvflg); - if (control) - m_freem(control); - if (error == EWOULDBLOCK && rep) { - if (rep->r_flags & R_SOFTTERM) - return (EINTR); - } - } while (error == EWOULDBLOCK || - (!error && *mp == NULL && control)); - if ((rcvflg & MSG_EOR) == 0) - printf("Egad!!\n"); - if (!error && *mp == NULL) - error = EPIPE; - len -= auio.uio_resid; - } -errout: - if (error && error != EINTR && error != ERESTART) { - m_freem(*mp); - *mp = (struct mbuf *)0; - if (error != EPIPE) - log(LOG_INFO, - "receive error %d from nfs server %s\n", - error, - rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname); - error = nfs_sndlock(rep); - if (!error) - error = nfs_reconnect(rep); - if (!error) - goto tryagain; - else - nfs_sndunlock(rep); - } - } else { - if ((so = rep->r_nmp->nm_so) == NULL) - return (EACCES); - if (so->so_state & SS_ISCONNECTED) - getnam = (struct sockaddr **)0; - else - getnam = aname; - auio.uio_resid = len = 1000000; - auio.uio_td = td; - do { - rcvflg = 0; - error = so->so_proto->pr_usrreqs->pru_soreceive - (so, getnam, &auio, mp, - (struct mbuf **)0, &rcvflg); - if (error == EWOULDBLOCK && - (rep->r_flags & R_SOFTTERM)) - return (EINTR); - } while (error == EWOULDBLOCK); - len -= auio.uio_resid; - } - if (error) { - m_freem(*mp); - *mp = (struct mbuf *)0; - } - /* - * Search for any mbufs that are not a multiple of 4 bytes long - * or with m_data not longword aligned. - * These could cause pointer alignment problems, so copy them to - * well aligned mbufs. - */ - nfs_realign(mp, 5 * NFSX_UNSIGNED); - return (error); -} - -/* - * Implement receipt of reply on a socket. - * We must search through the list of received datagrams matching them - * with outstanding requests using the xid, until ours is found. - */ -/* ARGSUSED */ -int -nfs_reply(myrep) - struct nfsreq *myrep; -{ - register struct nfsreq *rep; - register struct nfsmount *nmp = myrep->r_nmp; - register int32_t t1; - struct mbuf *mrep, *md; - struct sockaddr *nam; - u_int32_t rxid, *tl; - caddr_t dpos, cp2; - int error; - - /* - * Loop around until we get our own reply - */ - for (;;) { - /* - * Lock against other receivers so that I don't get stuck in - * sbwait() after someone else has received my reply for me. - * Also necessary for connection based protocols to avoid - * race conditions during a reconnect. - * If nfs_rcvlock() returns EALREADY, that means that - * the reply has already been recieved by another - * process and we can return immediately. In this - * case, the lock is not taken to avoid races with - * other processes. - */ - error = nfs_rcvlock(myrep); - if (error == EALREADY) - return (0); - if (error) - return (error); - /* - * Get the next Rpc reply off the socket - */ - error = nfs_receive(myrep, &nam, &mrep); - nfs_rcvunlock(myrep); - if (error) { - - /* - * Ignore routing errors on connectionless protocols?? - */ - if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) { - nmp->nm_so->so_error = 0; - if (myrep->r_flags & R_GETONEREP) - return (0); - continue; - } - return (error); - } - if (nam) - FREE(nam, M_SONAME); - - /* - * Get the xid and check that it is an rpc reply - */ - md = mrep; - dpos = mtod(md, caddr_t); - nfsm_dissect(tl, u_int32_t *, 2*NFSX_UNSIGNED); - rxid = *tl++; - if (*tl != rpc_reply) { -#ifndef NFS_NOSERVER - if (nmp->nm_flag & NFSMNT_NQNFS) { - if (nqnfs_callback(nmp, mrep, md, dpos)) - nfsstats.rpcinvalid++; - } else { - nfsstats.rpcinvalid++; - m_freem(mrep); - } -#else - nfsstats.rpcinvalid++; - m_freem(mrep); -#endif -nfsmout: - if (myrep->r_flags & R_GETONEREP) - return (0); - continue; - } - - /* - * Loop through the request list to match up the reply - * Iff no match, just drop the datagram - */ - for (rep = nfs_reqq.tqh_first; rep != 0; - rep = rep->r_chain.tqe_next) { - if (rep->r_mrep == NULL && rxid == rep->r_xid) { - /* Found it.. */ - rep->r_mrep = mrep; - rep->r_md = md; - rep->r_dpos = dpos; - if (nfsrtton) { - struct rttl *rt; - - rt = &nfsrtt.rttl[nfsrtt.pos]; - rt->proc = rep->r_procnum; - rt->rto = NFS_RTO(nmp, proct[rep->r_procnum]); - rt->sent = nmp->nm_sent; - rt->cwnd = nmp->nm_cwnd; - rt->srtt = nmp->nm_srtt[proct[rep->r_procnum] - 1]; - rt->sdrtt = nmp->nm_sdrtt[proct[rep->r_procnum] - 1]; - rt->fsid = nmp->nm_mountp->mnt_stat.f_fsid; - getmicrotime(&rt->tstamp); - if (rep->r_flags & R_TIMING) - rt->rtt = rep->r_rtt; - else - rt->rtt = 1000000; - nfsrtt.pos = (nfsrtt.pos + 1) % NFSRTTLOGSIZ; - } - /* - * Update congestion window. - * Do the additive increase of - * one rpc/rtt. - */ - if (nmp->nm_cwnd <= nmp->nm_sent) { - nmp->nm_cwnd += - (NFS_CWNDSCALE * NFS_CWNDSCALE + - (nmp->nm_cwnd >> 1)) / nmp->nm_cwnd; - if (nmp->nm_cwnd > NFS_MAXCWND) - nmp->nm_cwnd = NFS_MAXCWND; - } - if (rep->r_flags & R_SENT) { - rep->r_flags &= ~R_SENT; - nmp->nm_sent -= NFS_CWNDSCALE; - } - /* - * Update rtt using a gain of 0.125 on the mean - * and a gain of 0.25 on the deviation. - */ - if (rep->r_flags & R_TIMING) { - /* - * Since the timer resolution of - * NFS_HZ is so course, it can often - * result in r_rtt == 0. Since - * r_rtt == N means that the actual - * rtt is between N+dt and N+2-dt ticks, - * add 1. - */ - t1 = rep->r_rtt + 1; - t1 -= (NFS_SRTT(rep) >> 3); - NFS_SRTT(rep) += t1; - if (t1 < 0) - t1 = -t1; - t1 -= (NFS_SDRTT(rep) >> 2); - NFS_SDRTT(rep) += t1; - } - nmp->nm_timeouts = 0; - break; - } - } - /* - * If not matched to a request, drop it. - * If it's mine, get out. - */ - if (rep == 0) { - nfsstats.rpcunexpected++; - m_freem(mrep); - } else if (rep == myrep) { - if (rep->r_mrep == NULL) - panic("nfsreply nil"); - return (0); - } - if (myrep->r_flags & R_GETONEREP) - return (0); - } -} - -/* - * nfs_request - goes something like this - * - fill in request struct - * - links it into list - * - calls nfs_send() for first transmit - * - calls nfs_receive() to get reply - * - break down rpc header and return with nfs reply pointed to - * by mrep or error - * nb: always frees up mreq mbuf list - */ -int -nfs_request(vp, mrest, procnum, td, cred, mrp, mdp, dposp) - struct vnode *vp; - struct mbuf *mrest; - int procnum; - struct thread *td; - struct ucred *cred; - struct mbuf **mrp; - struct mbuf **mdp; - caddr_t *dposp; -{ - register struct mbuf *mrep, *m2; - register struct nfsreq *rep; - register u_int32_t *tl; - register int i; - struct nfsmount *nmp; - struct mbuf *m, *md, *mheadend; - struct nfsnode *np; - char nickv[RPCX_NICKVERF]; - time_t reqtime, waituntil; - caddr_t dpos, cp2; - int t1, nqlflag, cachable, s, error = 0, mrest_len, auth_len, auth_type; - int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0, failed_auth = 0; - int verf_len, verf_type; - u_int32_t xid; - u_quad_t frev; - char *auth_str, *verf_str; - NFSKERBKEY_T key; /* save session key */ - - nmp = VFSTONFS(vp->v_mount); - MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK); - rep->r_nmp = nmp; - rep->r_vp = vp; - rep->r_td = td; - rep->r_procnum = procnum; - i = 0; - m = mrest; - while (m) { - i += m->m_len; - m = m->m_next; - } - mrest_len = i; - - /* - * Get the RPC header with authorization. - */ -kerbauth: - verf_str = auth_str = (char *)0; - if (nmp->nm_flag & NFSMNT_KERB) { - verf_str = nickv; - verf_len = sizeof (nickv); - auth_type = RPCAUTH_KERB4; - bzero((caddr_t)key, sizeof (key)); - if (failed_auth || nfs_getnickauth(nmp, cred, &auth_str, - &auth_len, verf_str, verf_len)) { - error = nfs_getauth(nmp, rep, cred, &auth_str, - &auth_len, verf_str, &verf_len, key); - if (error) { - free((caddr_t)rep, M_NFSREQ); - m_freem(mrest); - return (error); - } - } - } else { - auth_type = RPCAUTH_UNIX; - if (cred->cr_ngroups < 1) - panic("nfsreq nogrps"); - auth_len = ((((cred->cr_ngroups - 1) > nmp->nm_numgrps) ? - nmp->nm_numgrps : (cred->cr_ngroups - 1)) << 2) + - 5 * NFSX_UNSIGNED; - } - m = nfsm_rpchead(cred, nmp->nm_flag, procnum, auth_type, auth_len, - auth_str, verf_len, verf_str, mrest, mrest_len, &mheadend, &xid); - if (auth_str) - free(auth_str, M_TEMP); - - /* - * For stream protocols, insert a Sun RPC Record Mark. - */ - if (nmp->nm_sotype == SOCK_STREAM) { - M_PREPEND(m, NFSX_UNSIGNED, M_TRYWAIT); - *mtod(m, u_int32_t *) = htonl(0x80000000 | - (m->m_pkthdr.len - NFSX_UNSIGNED)); - } - rep->r_mreq = m; - rep->r_xid = xid; -tryagain: - if (nmp->nm_flag & NFSMNT_SOFT) - rep->r_retry = nmp->nm_retry; - else - rep->r_retry = NFS_MAXREXMIT + 1; /* past clip limit */ - rep->r_rtt = rep->r_rexmit = 0; - if (proct[procnum] > 0) - rep->r_flags = R_TIMING; - else - rep->r_flags = 0; - rep->r_mrep = NULL; - - /* - * Do the client side RPC. - */ - nfsstats.rpcrequests++; - /* - * Chain request into list of outstanding requests. Be sure - * to put it LAST so timer finds oldest requests first. - */ - s = splsoftclock(); - TAILQ_INSERT_TAIL(&nfs_reqq, rep, r_chain); - - /* Get send time for nqnfs */ - reqtime = time_second; - - /* - * If backing off another request or avoiding congestion, don't - * send this one now but let timer do it. If not timing a request, - * do it now. - */ - if (nmp->nm_so && (nmp->nm_sotype != SOCK_DGRAM || - (nmp->nm_flag & NFSMNT_DUMBTIMR) || - nmp->nm_sent < nmp->nm_cwnd)) { - splx(s); - if (nmp->nm_soflags & PR_CONNREQUIRED) - error = nfs_sndlock(rep); - if (!error) { - m2 = m_copym(m, 0, M_COPYALL, M_TRYWAIT); - error = nfs_send(nmp->nm_so, nmp->nm_nam, m2, rep); - if (nmp->nm_soflags & PR_CONNREQUIRED) - nfs_sndunlock(rep); - } - if (!error && (rep->r_flags & R_MUSTRESEND) == 0) { - nmp->nm_sent += NFS_CWNDSCALE; - rep->r_flags |= R_SENT; - } - } else { - splx(s); - rep->r_rtt = -1; - } - - /* - * Wait for the reply from our send or the timer's. - */ - if (!error || error == EPIPE) - error = nfs_reply(rep); - - /* - * RPC done, unlink the request. - */ - s = splsoftclock(); - TAILQ_REMOVE(&nfs_reqq, rep, r_chain); - splx(s); - - /* - * Decrement the outstanding request count. - */ - if (rep->r_flags & R_SENT) { - rep->r_flags &= ~R_SENT; /* paranoia */ - nmp->nm_sent -= NFS_CWNDSCALE; - } - - /* - * If there was a successful reply and a tprintf msg. - * tprintf a response. - */ - if (!error && (rep->r_flags & R_TPRINTFMSG)) - nfs_msg(rep->r_td, nmp->nm_mountp->mnt_stat.f_mntfromname, - "is alive again"); - mrep = rep->r_mrep; - md = rep->r_md; - dpos = rep->r_dpos; - if (error) { - m_freem(rep->r_mreq); - free((caddr_t)rep, M_NFSREQ); - return (error); - } - - /* - * break down the rpc header and check if ok - */ - nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); - if (*tl++ == rpc_msgdenied) { - if (*tl == rpc_mismatch) - error = EOPNOTSUPP; - else if ((nmp->nm_flag & NFSMNT_KERB) && *tl++ == rpc_autherr) { - if (!failed_auth) { - failed_auth++; - mheadend->m_next = (struct mbuf *)0; - m_freem(mrep); - m_freem(rep->r_mreq); - goto kerbauth; - } else - error = EAUTH; - } else - error = EACCES; - m_freem(mrep); - m_freem(rep->r_mreq); - free((caddr_t)rep, M_NFSREQ); - return (error); - } - - /* - * Grab any Kerberos verifier, otherwise just throw it away. - */ - verf_type = fxdr_unsigned(int, *tl++); - i = fxdr_unsigned(int32_t, *tl); - if ((nmp->nm_flag & NFSMNT_KERB) && verf_type == RPCAUTH_KERB4) { - error = nfs_savenickauth(nmp, cred, i, key, &md, &dpos, mrep); - if (error) - goto nfsmout; - } else if (i > 0) - nfsm_adv(nfsm_rndup(i)); - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - /* 0 == ok */ - if (*tl == 0) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - if (*tl != 0) { - error = fxdr_unsigned(int, *tl); - if ((nmp->nm_flag & NFSMNT_NFSV3) && - error == NFSERR_TRYLATER) { - m_freem(mrep); - error = 0; - waituntil = time_second + trylater_delay; - while (time_second < waituntil) - (void) tsleep((caddr_t)&lbolt, - PSOCK, "nqnfstry", 0); - trylater_delay *= nfs_backoff[trylater_cnt]; - if (trylater_cnt < 7) - trylater_cnt++; - goto tryagain; - } - - /* - * If the File Handle was stale, invalidate the - * lookup cache, just in case. - */ - if (error == ESTALE) - cache_purge(vp); - if (nmp->nm_flag & NFSMNT_NFSV3) { - *mrp = mrep; - *mdp = md; - *dposp = dpos; - error |= NFSERR_RETERR; - } else - m_freem(mrep); - m_freem(rep->r_mreq); - free((caddr_t)rep, M_NFSREQ); - return (error); - } - - /* - * For nqnfs, get any lease in reply - */ - if (nmp->nm_flag & NFSMNT_NQNFS) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - if (*tl) { - np = VTONFS(vp); - nqlflag = fxdr_unsigned(int, *tl); - nfsm_dissect(tl, u_int32_t *, 4*NFSX_UNSIGNED); - cachable = fxdr_unsigned(int, *tl++); - reqtime += fxdr_unsigned(int, *tl++); - if (reqtime > time_second) { - frev = fxdr_hyper(tl); - nqnfs_clientlease(nmp, np, nqlflag, - cachable, reqtime, frev); - } - } - } - *mrp = mrep; - *mdp = md; - *dposp = dpos; - m_freem(rep->r_mreq); - FREE((caddr_t)rep, M_NFSREQ); - return (0); - } - m_freem(mrep); - error = EPROTONOSUPPORT; -nfsmout: - m_freem(rep->r_mreq); - free((caddr_t)rep, M_NFSREQ); - return (error); -} - -#ifndef NFS_NOSERVER -/* - * Generate the rpc reply header - * siz arg. is used to decide if adding a cluster is worthwhile - */ -int -nfs_rephead(siz, nd, slp, err, cache, frev, mrq, mbp, bposp) - int siz; - struct nfsrv_descript *nd; - struct nfssvc_sock *slp; - int err; - int cache; - u_quad_t *frev; - struct mbuf **mrq; - struct mbuf **mbp; - caddr_t *bposp; -{ - register u_int32_t *tl; - register struct mbuf *mreq; - caddr_t bpos; - struct mbuf *mb, *mb2; - - MGETHDR(mreq, M_TRYWAIT, MT_DATA); - mb = mreq; - /* - * If this is a big reply, use a cluster else - * try and leave leading space for the lower level headers. - */ - siz += RPC_REPLYSIZ; - if ((max_hdr + siz) >= MINCLSIZE) { - MCLGET(mreq, M_TRYWAIT); - } else - mreq->m_data += max_hdr; - tl = mtod(mreq, u_int32_t *); - mreq->m_len = 6 * NFSX_UNSIGNED; - bpos = ((caddr_t)tl) + mreq->m_len; - *tl++ = txdr_unsigned(nd->nd_retxid); - *tl++ = rpc_reply; - if (err == ERPCMISMATCH || (err & NFSERR_AUTHERR)) { - *tl++ = rpc_msgdenied; - if (err & NFSERR_AUTHERR) { - *tl++ = rpc_autherr; - *tl = txdr_unsigned(err & ~NFSERR_AUTHERR); - mreq->m_len -= NFSX_UNSIGNED; - bpos -= NFSX_UNSIGNED; - } else { - *tl++ = rpc_mismatch; - *tl++ = txdr_unsigned(RPC_VER2); - *tl = txdr_unsigned(RPC_VER2); - } - } else { - *tl++ = rpc_msgaccepted; - - /* - * For Kerberos authentication, we must send the nickname - * verifier back, otherwise just RPCAUTH_NULL. - */ - if (nd->nd_flag & ND_KERBFULL) { - register struct nfsuid *nuidp; - struct timeval ktvin, ktvout; - - for (nuidp = NUIDHASH(slp, nd->nd_cr.cr_uid)->lh_first; - nuidp != 0; nuidp = nuidp->nu_hash.le_next) { - if (nuidp->nu_cr.cr_uid == nd->nd_cr.cr_uid && - (!nd->nd_nam2 || netaddr_match(NU_NETFAM(nuidp), - &nuidp->nu_haddr, nd->nd_nam2))) - break; - } - if (nuidp) { - ktvin.tv_sec = - txdr_unsigned(nuidp->nu_timestamp.tv_sec - 1); - ktvin.tv_usec = - txdr_unsigned(nuidp->nu_timestamp.tv_usec); - - /* - * Encrypt the timestamp in ecb mode using the - * session key. - */ -#ifdef NFSKERB - XXX -#endif - - *tl++ = rpc_auth_kerb; - *tl++ = txdr_unsigned(3 * NFSX_UNSIGNED); - *tl = ktvout.tv_sec; - nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED); - *tl++ = ktvout.tv_usec; - *tl++ = txdr_unsigned(nuidp->nu_cr.cr_uid); - } else { - *tl++ = 0; - *tl++ = 0; - } - } else { - *tl++ = 0; - *tl++ = 0; - } - switch (err) { - case EPROGUNAVAIL: - *tl = txdr_unsigned(RPC_PROGUNAVAIL); - break; - case EPROGMISMATCH: - *tl = txdr_unsigned(RPC_PROGMISMATCH); - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - if (nd->nd_flag & ND_NQNFS) { - *tl++ = txdr_unsigned(3); - *tl = txdr_unsigned(3); - } else { - *tl++ = txdr_unsigned(2); - *tl = txdr_unsigned(3); - } - break; - case EPROCUNAVAIL: - *tl = txdr_unsigned(RPC_PROCUNAVAIL); - break; - case EBADRPC: - *tl = txdr_unsigned(RPC_GARBAGE); - break; - default: - *tl = 0; - if (err != NFSERR_RETVOID) { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); - if (err) - *tl = txdr_unsigned(nfsrv_errmap(nd, err)); - else - *tl = 0; - } - break; - }; - } - - /* - * For nqnfs, piggyback lease as requested. - */ - if ((nd->nd_flag & ND_NQNFS) && err == 0) { - if (nd->nd_flag & ND_LEASE) { - nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED); - *tl++ = txdr_unsigned(nd->nd_flag & ND_LEASE); - *tl++ = txdr_unsigned(cache); - *tl++ = txdr_unsigned(nd->nd_duration); - txdr_hyper(*frev, tl); - } else { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); - *tl = 0; - } - } - if (mrq != NULL) - *mrq = mreq; - *mbp = mb; - *bposp = bpos; - if (err != 0 && err != NFSERR_RETVOID) - nfsstats.srvrpc_errs++; - return (0); -} - - -#endif /* NFS_NOSERVER */ -/* - * Nfs timer routine - * Scan the nfsreq list and retranmit any requests that have timed out - * To avoid retransmission attempts on STREAM sockets (in the future) make - * sure to set the r_retry field to 0 (implies nm_retry == 0). - */ -void -nfs_timer(arg) - void *arg; /* never used */ -{ - register struct nfsreq *rep; - register struct mbuf *m; - register struct socket *so; - register struct nfsmount *nmp; - register int timeo; - int s, error; -#ifndef NFS_NOSERVER - static long lasttime = 0; - register struct nfssvc_sock *slp; - u_quad_t cur_usec; -#endif /* NFS_NOSERVER */ - struct thread *td = thread0; /* XXX for credentials, will break if sleep */ - - s = splnet(); - for (rep = nfs_reqq.tqh_first; rep != 0; rep = rep->r_chain.tqe_next) { - nmp = rep->r_nmp; - if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) - continue; - if (nfs_sigintr(nmp, rep, - (rep->r_td ? rep->r_td->td_proc : NULL))) { - nfs_softterm(rep); - continue; - } - if (rep->r_rtt >= 0) { - rep->r_rtt++; - if (nmp->nm_flag & NFSMNT_DUMBTIMR) - timeo = nmp->nm_timeo; - else - timeo = NFS_RTO(nmp, proct[rep->r_procnum]); - if (nmp->nm_timeouts > 0) - timeo *= nfs_backoff[nmp->nm_timeouts - 1]; - if (rep->r_rtt <= timeo) - continue; - if (nmp->nm_timeouts < 8) - nmp->nm_timeouts++; - } - /* - * Check for server not responding - */ - if ((rep->r_flags & R_TPRINTFMSG) == 0 && - rep->r_rexmit > nmp->nm_deadthresh) { - nfs_msg(rep->r_td, - nmp->nm_mountp->mnt_stat.f_mntfromname, - "not responding"); - rep->r_flags |= R_TPRINTFMSG; - } - if (rep->r_rexmit >= rep->r_retry) { /* too many */ - nfsstats.rpctimeouts++; - nfs_softterm(rep); - continue; - } - if (nmp->nm_sotype != SOCK_DGRAM) { - if (++rep->r_rexmit > NFS_MAXREXMIT) - rep->r_rexmit = NFS_MAXREXMIT; - continue; - } - if ((so = nmp->nm_so) == NULL) - continue; - - /* - * If there is enough space and the window allows.. - * Resend it - * Set r_rtt to -1 in case we fail to send it now. - */ - rep->r_rtt = -1; - if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len && - ((nmp->nm_flag & NFSMNT_DUMBTIMR) || - (rep->r_flags & R_SENT) || - nmp->nm_sent < nmp->nm_cwnd) && - (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))){ - if ((nmp->nm_flag & NFSMNT_NOCONN) == 0) - error = (*so->so_proto->pr_usrreqs->pru_send) - (so, 0, m, (struct sockaddr *)0, - (struct mbuf *)0, td); - else - error = (*so->so_proto->pr_usrreqs->pru_send) - (so, 0, m, nmp->nm_nam, (struct mbuf *)0, - td); - if (error) { - if (NFSIGNORE_SOERROR(nmp->nm_soflags, error)) - so->so_error = 0; - } else { - /* - * Iff first send, start timing - * else turn timing off, backoff timer - * and divide congestion window by 2. - */ - if (rep->r_flags & R_SENT) { - rep->r_flags &= ~R_TIMING; - if (++rep->r_rexmit > NFS_MAXREXMIT) - rep->r_rexmit = NFS_MAXREXMIT; - nmp->nm_cwnd >>= 1; - if (nmp->nm_cwnd < NFS_CWNDSCALE) - nmp->nm_cwnd = NFS_CWNDSCALE; - nfsstats.rpcretries++; - } else { - rep->r_flags |= R_SENT; - nmp->nm_sent += NFS_CWNDSCALE; - } - rep->r_rtt = 0; - } - } - } -#ifndef NFS_NOSERVER - /* - * Call the nqnfs server timer once a second to handle leases. - */ - if (lasttime != time_second) { - lasttime = time_second; - nqnfs_serverd(); - } - - /* - * Scan the write gathering queues for writes that need to be - * completed now. - */ - cur_usec = nfs_curusec(); - for (slp = nfssvc_sockhead.tqh_first; slp != 0; - slp = slp->ns_chain.tqe_next) { - if (slp->ns_tq.lh_first && slp->ns_tq.lh_first->nd_time<=cur_usec) - nfsrv_wakenfsd(slp); - } -#endif /* NFS_NOSERVER */ - splx(s); - nfs_timer_handle = timeout(nfs_timer, (void *)0, nfs_ticks); -} - -/* - * Flag a request as being about to terminate (due to NFSMNT_INT/NFSMNT_SOFT). - * The nm_send count is decremented now to avoid deadlocks when the process in - * soreceive() hasn't yet managed to send its own request. - */ - -static void -nfs_softterm(rep) - struct nfsreq *rep; -{ - rep->r_flags |= R_SOFTTERM; - - if (rep->r_flags & R_SENT) { - rep->r_nmp->nm_sent -= NFS_CWNDSCALE; - rep->r_flags &= ~R_SENT; - } -} - -/* - * Test for a termination condition pending on the process. - * This is used for NFSMNT_INT mounts. - */ -int -nfs_sigintr(nmp, rep, p) - struct nfsmount *nmp; - struct nfsreq *rep; - register struct proc *p; -{ - sigset_t tmpset; - - if (rep && (rep->r_flags & R_SOFTTERM)) - return (EINTR); - if (!(nmp->nm_flag & NFSMNT_INT)) - return (0); - if (p == NULL) - return (0); - - tmpset = p->p_siglist; - SIGSETNAND(tmpset, p->p_sigmask); - SIGSETNAND(tmpset, p->p_sigignore); - if (SIGNOTEMPTY(p->p_siglist) && NFSINT_SIGMASK(tmpset)) - return (EINTR); - - return (0); -} - -/* - * Lock a socket against others. - * Necessary for STREAM sockets to ensure you get an entire rpc request/reply - * and also to avoid race conditions between the processes with nfs requests - * in progress when a reconnect is necessary. - */ -int -nfs_sndlock(rep) - struct nfsreq *rep; -{ - register int *statep = &rep->r_nmp->nm_state; - struct thread *td; - int slpflag = 0, slptimeo = 0; - - if (rep) { - td = rep->r_td; - if (rep->r_nmp->nm_flag & NFSMNT_INT) - slpflag = PCATCH; - } else - td = (struct thread *)0; - while (*statep & NFSSTA_SNDLOCK) { - if (nfs_sigintr(rep->r_nmp, rep, td ? td->td_proc : NULL)) - return (EINTR); - *statep |= NFSSTA_WANTSND; - (void) tsleep((caddr_t)statep, slpflag | (PZERO - 1), - "nfsndlck", slptimeo); - if (slpflag == PCATCH) { - slpflag = 0; - slptimeo = 2 * hz; - } - } - *statep |= NFSSTA_SNDLOCK; - return (0); -} - -/* - * Unlock the stream socket for others. - */ -void -nfs_sndunlock(rep) - struct nfsreq *rep; -{ - register int *statep = &rep->r_nmp->nm_state; - - if ((*statep & NFSSTA_SNDLOCK) == 0) - panic("nfs sndunlock"); - *statep &= ~NFSSTA_SNDLOCK; - if (*statep & NFSSTA_WANTSND) { - *statep &= ~NFSSTA_WANTSND; - wakeup((caddr_t)statep); - } -} - -static int -nfs_rcvlock(rep) - register struct nfsreq *rep; -{ - register int *statep = &rep->r_nmp->nm_state; - int slpflag, slptimeo = 0; - - if (rep->r_nmp->nm_flag & NFSMNT_INT) - slpflag = PCATCH; - else - slpflag = 0; - while (*statep & NFSSTA_RCVLOCK) { - if (nfs_sigintr(rep->r_nmp, rep, - (rep->r_td ? rep->r_td->td_proc : NULL))) - return (EINTR); - *statep |= NFSSTA_WANTRCV; - (void) tsleep((caddr_t)statep, slpflag | (PZERO - 1), "nfsrcvlk", - slptimeo); - /* - * If our reply was recieved while we were sleeping, - * then just return without taking the lock to avoid a - * situation where a single iod could 'capture' the - * recieve lock. - */ - if (rep->r_mrep != NULL) - return (EALREADY); - if (slpflag == PCATCH) { - slpflag = 0; - slptimeo = 2 * hz; - } - } - *statep |= NFSSTA_RCVLOCK; - return (0); -} - -/* - * Unlock the stream socket for others. - */ -static void -nfs_rcvunlock(rep) - register struct nfsreq *rep; -{ - register int *statep = &rep->r_nmp->nm_state; - - if ((*statep & NFSSTA_RCVLOCK) == 0) - panic("nfs rcvunlock"); - *statep &= ~NFSSTA_RCVLOCK; - if (*statep & NFSSTA_WANTRCV) { - *statep &= ~NFSSTA_WANTRCV; - wakeup((caddr_t)statep); - } -} - -/* - * nfs_realign: - * - * Check for badly aligned mbuf data and realign by copying the unaligned - * portion of the data into a new mbuf chain and freeing the portions - * of the old chain that were replaced. - * - * We cannot simply realign the data within the existing mbuf chain - * because the underlying buffers may contain other rpc commands and - * we cannot afford to overwrite them. - * - * We would prefer to avoid this situation entirely. The situation does - * not occur with NFS/UDP and is supposed to only occassionally occur - * with TCP. Use vfs.nfs.realign_count and realign_test to check this. - */ -static void -nfs_realign(pm, hsiz) - register struct mbuf **pm; - int hsiz; -{ - struct mbuf *m; - struct mbuf *n = NULL; - int off = 0; - - ++nfs_realign_test; - - while ((m = *pm) != NULL) { - if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3)) { - MGET(n, M_TRYWAIT, MT_DATA); - if (m->m_len >= MINCLSIZE) { - MCLGET(n, M_TRYWAIT); - } - n->m_len = 0; - break; - } - pm = &m->m_next; - } - - /* - * If n is non-NULL, loop on m copying data, then replace the - * portion of the chain that had to be realigned. - */ - if (n != NULL) { - ++nfs_realign_count; - while (m) { - m_copyback(n, off, m->m_len, mtod(m, caddr_t)); - off += m->m_len; - m = m->m_next; - } - m_freem(*pm); - *pm = n; - } -} - -#ifndef NFS_NOSERVER - -/* - * Parse an RPC request - * - verify it - * - fill in the cred struct. - */ -int -nfs_getreq(nd, nfsd, has_header) - register struct nfsrv_descript *nd; - struct nfsd *nfsd; - int has_header; -{ - register int len, i; - register u_int32_t *tl; - register int32_t t1; - struct uio uio; - struct iovec iov; - caddr_t dpos, cp2, cp; - u_int32_t nfsvers, auth_type; - uid_t nickuid; - int error = 0, nqnfs = 0, ticklen; - struct mbuf *mrep, *md; - register struct nfsuid *nuidp; - struct timeval tvin, tvout; -#if 0 /* until encrypted keys are implemented */ - NFSKERBKEYSCHED_T keys; /* stores key schedule */ -#endif - - mrep = nd->nd_mrep; - md = nd->nd_md; - dpos = nd->nd_dpos; - if (has_header) { - nfsm_dissect(tl, u_int32_t *, 10 * NFSX_UNSIGNED); - nd->nd_retxid = fxdr_unsigned(u_int32_t, *tl++); - if (*tl++ != rpc_call) { - m_freem(mrep); - return (EBADRPC); - } - } else - nfsm_dissect(tl, u_int32_t *, 8 * NFSX_UNSIGNED); - nd->nd_repstat = 0; - nd->nd_flag = 0; - if (*tl++ != rpc_vers) { - nd->nd_repstat = ERPCMISMATCH; - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - if (*tl != nfs_prog) { - if (*tl == nqnfs_prog) - nqnfs++; - else { - nd->nd_repstat = EPROGUNAVAIL; - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - } - tl++; - nfsvers = fxdr_unsigned(u_int32_t, *tl++); - if (((nfsvers < NFS_VER2 || nfsvers > NFS_VER3) && !nqnfs) || - (nfsvers != NQNFS_VER3 && nqnfs)) { - nd->nd_repstat = EPROGMISMATCH; - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - if (nqnfs) - nd->nd_flag = (ND_NFSV3 | ND_NQNFS); - else if (nfsvers == NFS_VER3) - nd->nd_flag = ND_NFSV3; - nd->nd_procnum = fxdr_unsigned(u_int32_t, *tl++); - if (nd->nd_procnum == NFSPROC_NULL) - return (0); - if (nd->nd_procnum >= NFS_NPROCS || - (!nqnfs && nd->nd_procnum >= NQNFSPROC_GETLEASE) || - (!nd->nd_flag && nd->nd_procnum > NFSV2PROC_STATFS)) { - nd->nd_repstat = EPROCUNAVAIL; - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - if ((nd->nd_flag & ND_NFSV3) == 0) - nd->nd_procnum = nfsv3_procid[nd->nd_procnum]; - auth_type = *tl++; - len = fxdr_unsigned(int, *tl++); - if (len < 0 || len > RPCAUTH_MAXSIZ) { - m_freem(mrep); - return (EBADRPC); - } - - nd->nd_flag &= ~ND_KERBAUTH; - /* - * Handle auth_unix or auth_kerb. - */ - if (auth_type == rpc_auth_unix) { - len = fxdr_unsigned(int, *++tl); - if (len < 0 || len > NFS_MAXNAMLEN) { - m_freem(mrep); - return (EBADRPC); - } - nfsm_adv(nfsm_rndup(len)); - nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); - bzero((caddr_t)&nd->nd_cr, sizeof (struct ucred)); - nd->nd_cr.cr_ref = 1; - nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++); - nd->nd_cr.cr_gid = fxdr_unsigned(gid_t, *tl++); - len = fxdr_unsigned(int, *tl); - if (len < 0 || len > RPCAUTH_UNIXGIDS) { - m_freem(mrep); - return (EBADRPC); - } - nfsm_dissect(tl, u_int32_t *, (len + 2) * NFSX_UNSIGNED); - for (i = 1; i <= len; i++) - if (i < NGROUPS) - nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++); - else - tl++; - nd->nd_cr.cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1); - if (nd->nd_cr.cr_ngroups > 1) - nfsrvw_sort(nd->nd_cr.cr_groups, nd->nd_cr.cr_ngroups); - len = fxdr_unsigned(int, *++tl); - if (len < 0 || len > RPCAUTH_MAXSIZ) { - m_freem(mrep); - return (EBADRPC); - } - if (len > 0) - nfsm_adv(nfsm_rndup(len)); - } else if (auth_type == rpc_auth_kerb) { - switch (fxdr_unsigned(int, *tl++)) { - case RPCAKN_FULLNAME: - ticklen = fxdr_unsigned(int, *tl); - *((u_int32_t *)nfsd->nfsd_authstr) = *tl; - uio.uio_resid = nfsm_rndup(ticklen) + NFSX_UNSIGNED; - nfsd->nfsd_authlen = uio.uio_resid + NFSX_UNSIGNED; - if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) { - m_freem(mrep); - return (EBADRPC); - } - uio.uio_offset = 0; - uio.uio_iov = &iov; - uio.uio_iovcnt = 1; - uio.uio_segflg = UIO_SYSSPACE; - iov.iov_base = (caddr_t)&nfsd->nfsd_authstr[4]; - iov.iov_len = RPCAUTH_MAXSIZ - 4; - nfsm_mtouio(&uio, uio.uio_resid); - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - if (*tl++ != rpc_auth_kerb || - fxdr_unsigned(int, *tl) != 4 * NFSX_UNSIGNED) { - printf("Bad kerb verifier\n"); - nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - nfsm_dissect(cp, caddr_t, 4 * NFSX_UNSIGNED); - tl = (u_int32_t *)cp; - if (fxdr_unsigned(int, *tl) != RPCAKN_FULLNAME) { - printf("Not fullname kerb verifier\n"); - nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - cp += NFSX_UNSIGNED; - bcopy(cp, nfsd->nfsd_verfstr, 3 * NFSX_UNSIGNED); - nfsd->nfsd_verflen = 3 * NFSX_UNSIGNED; - nd->nd_flag |= ND_KERBFULL; - nfsd->nfsd_flag |= NFSD_NEEDAUTH; - break; - case RPCAKN_NICKNAME: - if (len != 2 * NFSX_UNSIGNED) { - printf("Kerb nickname short\n"); - nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADCRED); - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - nickuid = fxdr_unsigned(uid_t, *tl); - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - if (*tl++ != rpc_auth_kerb || - fxdr_unsigned(int, *tl) != 3 * NFSX_UNSIGNED) { - printf("Kerb nick verifier bad\n"); - nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF); - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); - tvin.tv_sec = *tl++; - tvin.tv_usec = *tl; - - for (nuidp = NUIDHASH(nfsd->nfsd_slp,nickuid)->lh_first; - nuidp != 0; nuidp = nuidp->nu_hash.le_next) { - if (nuidp->nu_cr.cr_uid == nickuid && - (!nd->nd_nam2 || - netaddr_match(NU_NETFAM(nuidp), - &nuidp->nu_haddr, nd->nd_nam2))) - break; - } - if (!nuidp) { - nd->nd_repstat = - (NFSERR_AUTHERR|AUTH_REJECTCRED); - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - - /* - * Now, decrypt the timestamp using the session key - * and validate it. - */ -#ifdef NFSKERB - XXX -#endif - - tvout.tv_sec = fxdr_unsigned(long, tvout.tv_sec); - tvout.tv_usec = fxdr_unsigned(long, tvout.tv_usec); - if (nuidp->nu_expire < time_second || - nuidp->nu_timestamp.tv_sec > tvout.tv_sec || - (nuidp->nu_timestamp.tv_sec == tvout.tv_sec && - nuidp->nu_timestamp.tv_usec > tvout.tv_usec)) { - nuidp->nu_expire = 0; - nd->nd_repstat = - (NFSERR_AUTHERR|AUTH_REJECTVERF); - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - nfsrv_setcred(&nuidp->nu_cr, &nd->nd_cr); - nd->nd_flag |= ND_KERBNICK; - }; - } else { - nd->nd_repstat = (NFSERR_AUTHERR | AUTH_REJECTCRED); - nd->nd_procnum = NFSPROC_NOOP; - return (0); - } - - /* - * For nqnfs, get piggybacked lease request. - */ - if (nqnfs && nd->nd_procnum != NQNFSPROC_EVICTED) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - nd->nd_flag |= fxdr_unsigned(int, *tl); - if (nd->nd_flag & ND_LEASE) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - nd->nd_duration = fxdr_unsigned(int32_t, *tl); - } else - nd->nd_duration = NQ_MINLEASE; - } else - nd->nd_duration = NQ_MINLEASE; - nd->nd_md = md; - nd->nd_dpos = dpos; - return (0); -nfsmout: - return (error); -} - -#endif - -static int -nfs_msg(td, server, msg) - struct thread *td; - char *server, *msg; -{ - - tprintf(td->td_proc, LOG_INFO, "nfs server %s: %s\n", server, msg); - return (0); -} - -#ifndef NFS_NOSERVER -/* - * Socket upcall routine for the nfsd sockets. - * The caddr_t arg is a pointer to the "struct nfssvc_sock". - * Essentially do as much as possible non-blocking, else punt and it will - * be called with M_TRYWAIT from an nfsd. - */ -void -nfsrv_rcv(so, arg, waitflag) - struct socket *so; - void *arg; - int waitflag; -{ - register struct nfssvc_sock *slp = (struct nfssvc_sock *)arg; - register struct mbuf *m; - struct mbuf *mp; - struct sockaddr *nam; - struct uio auio; - int flags, error; - - if ((slp->ns_flag & SLP_VALID) == 0) - return; -#ifdef notdef - /* - * Define this to test for nfsds handling this under heavy load. - */ - if (waitflag == M_DONTWAIT) { - slp->ns_flag |= SLP_NEEDQ; goto dorecs; - } -#endif - auio.uio_td = NULL; - if (so->so_type == SOCK_STREAM) { - /* - * If there are already records on the queue, defer soreceive() - * to an nfsd so that there is feedback to the TCP layer that - * the nfs servers are heavily loaded. - */ - if (STAILQ_FIRST(&slp->ns_rec) && waitflag == M_DONTWAIT) { - slp->ns_flag |= SLP_NEEDQ; - goto dorecs; - } - - /* - * Do soreceive(). - */ - auio.uio_resid = 1000000000; - flags = MSG_DONTWAIT; - error = so->so_proto->pr_usrreqs->pru_soreceive - (so, &nam, &auio, &mp, (struct mbuf **)0, &flags); - if (error || mp == (struct mbuf *)0) { - if (error == EWOULDBLOCK) - slp->ns_flag |= SLP_NEEDQ; - else - slp->ns_flag |= SLP_DISCONN; - goto dorecs; - } - m = mp; - if (slp->ns_rawend) { - slp->ns_rawend->m_next = m; - slp->ns_cc += 1000000000 - auio.uio_resid; - } else { - slp->ns_raw = m; - slp->ns_cc = 1000000000 - auio.uio_resid; - } - while (m->m_next) - m = m->m_next; - slp->ns_rawend = m; - - /* - * Now try and parse record(s) out of the raw stream data. - */ - error = nfsrv_getstream(slp, waitflag); - if (error) { - if (error == EPERM) - slp->ns_flag |= SLP_DISCONN; - else - slp->ns_flag |= SLP_NEEDQ; - } - } else { - do { - auio.uio_resid = 1000000000; - flags = MSG_DONTWAIT; - error = so->so_proto->pr_usrreqs->pru_soreceive - (so, &nam, &auio, &mp, - (struct mbuf **)0, &flags); - if (mp) { - struct nfsrv_rec *rec; - rec = malloc(sizeof(struct nfsrv_rec), - M_NFSRVDESC, waitflag); - if (!rec) { - if (nam) - FREE(nam, M_SONAME); - m_freem(mp); - continue; - } - nfs_realign(&mp, 10 * NFSX_UNSIGNED); - rec->nr_address = nam; - rec->nr_packet = mp; - STAILQ_INSERT_TAIL(&slp->ns_rec, rec, nr_link); - } - if (error) { - if ((so->so_proto->pr_flags & PR_CONNREQUIRED) - && error != EWOULDBLOCK) { - slp->ns_flag |= SLP_DISCONN; - goto dorecs; - } - } - } while (mp); - } - - /* - * Now try and process the request records, non-blocking. - */ -dorecs: - if (waitflag == M_DONTWAIT && - (STAILQ_FIRST(&slp->ns_rec) - || (slp->ns_flag & (SLP_NEEDQ | SLP_DISCONN)))) - nfsrv_wakenfsd(slp); -} - -/* - * Try and extract an RPC request from the mbuf data list received on a - * stream socket. The "waitflag" argument indicates whether or not it - * can sleep. - */ -static int -nfsrv_getstream(slp, waitflag) - register struct nfssvc_sock *slp; - int waitflag; -{ - register struct mbuf *m, **mpp; - register char *cp1, *cp2; - register int len; - struct mbuf *om, *m2, *recm = NULL; - u_int32_t recmark; - - if (slp->ns_flag & SLP_GETSTREAM) - panic("nfs getstream"); - slp->ns_flag |= SLP_GETSTREAM; - for (;;) { - if (slp->ns_reclen == 0) { - if (slp->ns_cc < NFSX_UNSIGNED) { - slp->ns_flag &= ~SLP_GETSTREAM; - return (0); - } - m = slp->ns_raw; - if (m->m_len >= NFSX_UNSIGNED) { - bcopy(mtod(m, caddr_t), (caddr_t)&recmark, NFSX_UNSIGNED); - m->m_data += NFSX_UNSIGNED; - m->m_len -= NFSX_UNSIGNED; - } else { - cp1 = (caddr_t)&recmark; - cp2 = mtod(m, caddr_t); - while (cp1 < ((caddr_t)&recmark) + NFSX_UNSIGNED) { - while (m->m_len == 0) { - m = m->m_next; - cp2 = mtod(m, caddr_t); - } - *cp1++ = *cp2++; - m->m_data++; - m->m_len--; - } - } - slp->ns_cc -= NFSX_UNSIGNED; - recmark = ntohl(recmark); - slp->ns_reclen = recmark & ~0x80000000; - if (recmark & 0x80000000) - slp->ns_flag |= SLP_LASTFRAG; - else - slp->ns_flag &= ~SLP_LASTFRAG; - if (slp->ns_reclen > NFS_MAXPACKET) { - slp->ns_flag &= ~SLP_GETSTREAM; - return (EPERM); - } - } - - /* - * Now get the record part. - */ - if (slp->ns_cc == slp->ns_reclen) { - recm = slp->ns_raw; - slp->ns_raw = slp->ns_rawend = (struct mbuf *)0; - slp->ns_cc = slp->ns_reclen = 0; - } else if (slp->ns_cc > slp->ns_reclen) { - len = 0; - m = slp->ns_raw; - om = (struct mbuf *)0; - while (len < slp->ns_reclen) { - if ((len + m->m_len) > slp->ns_reclen) { - m2 = m_copym(m, 0, slp->ns_reclen - len, - waitflag); - if (m2) { - if (om) { - om->m_next = m2; - recm = slp->ns_raw; - } else - recm = m2; - m->m_data += slp->ns_reclen - len; - m->m_len -= slp->ns_reclen - len; - len = slp->ns_reclen; - } else { - slp->ns_flag &= ~SLP_GETSTREAM; - return (EWOULDBLOCK); - } - } else if ((len + m->m_len) == slp->ns_reclen) { - om = m; - len += m->m_len; - m = m->m_next; - recm = slp->ns_raw; - om->m_next = (struct mbuf *)0; - } else { - om = m; - len += m->m_len; - m = m->m_next; - } - } - slp->ns_raw = m; - slp->ns_cc -= len; - slp->ns_reclen = 0; - } else { - slp->ns_flag &= ~SLP_GETSTREAM; - return (0); - } - - /* - * Accumulate the fragments into a record. - */ - mpp = &slp->ns_frag; - while (*mpp) - mpp = &((*mpp)->m_next); - *mpp = recm; - if (slp->ns_flag & SLP_LASTFRAG) { - struct nfsrv_rec *rec; - rec = malloc(sizeof(struct nfsrv_rec), M_NFSRVDESC, waitflag); - if (!rec) { - m_freem(slp->ns_frag); - } else { - nfs_realign(&slp->ns_frag, 10 * NFSX_UNSIGNED); - rec->nr_address = (struct sockaddr *)0; - rec->nr_packet = slp->ns_frag; - STAILQ_INSERT_TAIL(&slp->ns_rec, rec, nr_link); - } - slp->ns_frag = (struct mbuf *)0; - } - } -} - -/* - * Parse an RPC header. - */ -int -nfsrv_dorec(slp, nfsd, ndp) - register struct nfssvc_sock *slp; - struct nfsd *nfsd; - struct nfsrv_descript **ndp; -{ - struct nfsrv_rec *rec; - register struct mbuf *m; - struct sockaddr *nam; - register struct nfsrv_descript *nd; - int error; - - *ndp = NULL; - if ((slp->ns_flag & SLP_VALID) == 0 || !STAILQ_FIRST(&slp->ns_rec)) - return (ENOBUFS); - rec = STAILQ_FIRST(&slp->ns_rec); - STAILQ_REMOVE_HEAD(&slp->ns_rec, nr_link); - nam = rec->nr_address; - m = rec->nr_packet; - free(rec, M_NFSRVDESC); - MALLOC(nd, struct nfsrv_descript *, sizeof (struct nfsrv_descript), - M_NFSRVDESC, M_WAITOK); - nd->nd_md = nd->nd_mrep = m; - nd->nd_nam2 = nam; - nd->nd_dpos = mtod(m, caddr_t); - error = nfs_getreq(nd, nfsd, TRUE); - if (error) { - if (nam) { - FREE(nam, M_SONAME); - } - free((caddr_t)nd, M_NFSRVDESC); - return (error); - } - *ndp = nd; - nfsd->nfsd_nd = nd; - return (0); -} - -/* - * Search for a sleeping nfsd and wake it up. - * SIDE EFFECT: If none found, set NFSD_CHECKSLP flag, so that one of the - * running nfsds will go look for the work in the nfssvc_sock list. - */ -void -nfsrv_wakenfsd(slp) - struct nfssvc_sock *slp; -{ - register struct nfsd *nd; - - if ((slp->ns_flag & SLP_VALID) == 0) - return; - for (nd = nfsd_head.tqh_first; nd != 0; nd = nd->nfsd_chain.tqe_next) { - if (nd->nfsd_flag & NFSD_WAITING) { - nd->nfsd_flag &= ~NFSD_WAITING; - if (nd->nfsd_slp) - panic("nfsd wakeup"); - slp->ns_sref++; - nd->nfsd_slp = slp; - wakeup((caddr_t)nd); - return; - } - } - slp->ns_flag |= SLP_DOREC; - nfsd_head_flag |= NFSD_CHECKSLP; -} -#endif /* NFS_NOSERVER */ diff --git a/sys/nfs/nfs_srvcache.c b/sys/nfs/nfs_srvcache.c deleted file mode 100644 index e7b10dd..0000000 --- a/sys/nfs/nfs_srvcache.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfs_srvcache.c 8.3 (Berkeley) 3/30/95 - * $FreeBSD$ - */ - -/* - * Reference: Chet Juszczak, "Improving the Performance and Correctness - * of an NFS Server", in Proc. Winter 1989 USENIX Conference, - * pages 53-63. San Diego, February 1989. - */ -#include -#include -#include -#include -#include -#include -#include /* for dup_sockaddr */ - -#include -#include -#include -#include -#include - -#ifndef NFS_NOSERVER -extern struct nfsstats nfsstats; -extern int nfsv2_procid[NFS_NPROCS]; -static long numnfsrvcache; -static long desirednfsrvcache = NFSRVCACHESIZ; - -#define NFSRCHASH(xid) \ - (&nfsrvhashtbl[((xid) + ((xid) >> 24)) & nfsrvhash]) -static LIST_HEAD(nfsrvhash, nfsrvcache) *nfsrvhashtbl; -static TAILQ_HEAD(nfsrvlru, nfsrvcache) nfsrvlruhead; -static u_long nfsrvhash; - -#define TRUE 1 -#define FALSE 0 - -#define NETFAMILY(rp) \ - (((rp)->rc_flag & RC_INETADDR) ? AF_INET : AF_ISO) - -/* - * Static array that defines which nfs rpc's are nonidempotent - */ -static int nonidempotent[NFS_NPROCS] = { - FALSE, - FALSE, - TRUE, - FALSE, - FALSE, - FALSE, - FALSE, - TRUE, - TRUE, - TRUE, - TRUE, - TRUE, - TRUE, - TRUE, - TRUE, - TRUE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, -}; - -/* True iff the rpc reply is an nfs status ONLY! */ -static int nfsv2_repstat[NFS_NPROCS] = { - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - FALSE, - TRUE, - TRUE, - TRUE, - TRUE, - FALSE, - TRUE, - FALSE, - FALSE, -}; - -/* - * Initialize the server request cache list - */ -void -nfsrv_initcache() -{ - - nfsrvhashtbl = hashinit(desirednfsrvcache, M_NFSD, &nfsrvhash); - TAILQ_INIT(&nfsrvlruhead); -} - -/* - * Look for the request in the cache - * If found then - * return action and optionally reply - * else - * insert it in the cache - * - * The rules are as follows: - * - if in progress, return DROP request - * - if completed within DELAY of the current time, return DROP it - * - if completed a longer time ago return REPLY if the reply was cached or - * return DOIT - * Update/add new request at end of lru list - */ -int -nfsrv_getcache(nd, slp, repp) - register struct nfsrv_descript *nd; - struct nfssvc_sock *slp; - struct mbuf **repp; -{ - register struct nfsrvcache *rp; - struct mbuf *mb; - struct sockaddr_in *saddr; - caddr_t bpos; - int ret; - - /* - * Don't cache recent requests for reliable transport protocols. - * (Maybe we should for the case of a reconnect, but..) - */ - if (!nd->nd_nam2) - return (RC_DOIT); -loop: - for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0; - rp = rp->rc_hash.le_next) { - if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc && - netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) { - NFS_DPF(RC, ("H%03x", rp->rc_xid & 0xfff)); - if ((rp->rc_flag & RC_LOCKED) != 0) { - rp->rc_flag |= RC_WANTED; - (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0); - goto loop; - } - rp->rc_flag |= RC_LOCKED; - /* If not at end of LRU chain, move it there */ - if (rp->rc_lru.tqe_next) { - TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru); - TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru); - } - if (rp->rc_state == RC_UNUSED) - panic("nfsrv cache"); - if (rp->rc_state == RC_INPROG) { - nfsstats.srvcache_inproghits++; - ret = RC_DROPIT; - } else if (rp->rc_flag & RC_REPSTATUS) { - nfsstats.srvcache_nonidemdonehits++; - nfs_rephead(0, nd, slp, rp->rc_status, - 0, (u_quad_t *)0, repp, &mb, &bpos); - ret = RC_REPLY; - } else if (rp->rc_flag & RC_REPMBUF) { - nfsstats.srvcache_nonidemdonehits++; - *repp = m_copym(rp->rc_reply, 0, M_COPYALL, - M_TRYWAIT); - ret = RC_REPLY; - } else { - nfsstats.srvcache_idemdonehits++; - rp->rc_state = RC_INPROG; - ret = RC_DOIT; - } - rp->rc_flag &= ~RC_LOCKED; - if (rp->rc_flag & RC_WANTED) { - rp->rc_flag &= ~RC_WANTED; - wakeup((caddr_t)rp); - } - return (ret); - } - } - nfsstats.srvcache_misses++; - NFS_DPF(RC, ("M%03x", nd->nd_retxid & 0xfff)); - if (numnfsrvcache < desirednfsrvcache) { - rp = (struct nfsrvcache *)malloc((u_long)sizeof *rp, - M_NFSD, M_WAITOK | M_ZERO); - numnfsrvcache++; - rp->rc_flag = RC_LOCKED; - } else { - rp = nfsrvlruhead.tqh_first; - while ((rp->rc_flag & RC_LOCKED) != 0) { - rp->rc_flag |= RC_WANTED; - (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0); - rp = nfsrvlruhead.tqh_first; - } - rp->rc_flag |= RC_LOCKED; - LIST_REMOVE(rp, rc_hash); - TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru); - if (rp->rc_flag & RC_REPMBUF) - m_freem(rp->rc_reply); - if (rp->rc_flag & RC_NAM) - FREE(rp->rc_nam, M_SONAME); - rp->rc_flag &= (RC_LOCKED | RC_WANTED); - } - TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru); - rp->rc_state = RC_INPROG; - rp->rc_xid = nd->nd_retxid; - saddr = (struct sockaddr_in *)nd->nd_nam; - switch (saddr->sin_family) { - case AF_INET: - rp->rc_flag |= RC_INETADDR; - rp->rc_inetaddr = saddr->sin_addr.s_addr; - break; - case AF_ISO: - default: - rp->rc_flag |= RC_NAM; - rp->rc_nam = dup_sockaddr(nd->nd_nam, 1); - break; - }; - rp->rc_proc = nd->nd_procnum; - LIST_INSERT_HEAD(NFSRCHASH(nd->nd_retxid), rp, rc_hash); - rp->rc_flag &= ~RC_LOCKED; - if (rp->rc_flag & RC_WANTED) { - rp->rc_flag &= ~RC_WANTED; - wakeup((caddr_t)rp); - } - return (RC_DOIT); -} - -/* - * Update a request cache entry after the rpc has been done - */ -void -nfsrv_updatecache(nd, repvalid, repmbuf) - register struct nfsrv_descript *nd; - int repvalid; - struct mbuf *repmbuf; -{ - register struct nfsrvcache *rp; - - if (!nd->nd_nam2) - return; -loop: - for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0; - rp = rp->rc_hash.le_next) { - if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc && - netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) { - NFS_DPF(RC, ("U%03x", rp->rc_xid & 0xfff)); - if ((rp->rc_flag & RC_LOCKED) != 0) { - rp->rc_flag |= RC_WANTED; - (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0); - goto loop; - } - rp->rc_flag |= RC_LOCKED; - if (rp->rc_state == RC_DONE) { - /* - * This can occur if the cache is too small. - * Retransmits of the same request aren't - * dropped so we may see the operation - * complete more then once. - */ - if (rp->rc_flag & RC_REPMBUF) { - m_freem(rp->rc_reply); - rp->rc_flag &= ~RC_REPMBUF; - } - } - rp->rc_state = RC_DONE; - /* - * If we have a valid reply update status and save - * the reply for non-idempotent rpc's. - */ - if (repvalid && nonidempotent[nd->nd_procnum]) { - if ((nd->nd_flag & ND_NFSV3) == 0 && - nfsv2_repstat[nfsv2_procid[nd->nd_procnum]]) { - rp->rc_status = nd->nd_repstat; - rp->rc_flag |= RC_REPSTATUS; - } else { - rp->rc_reply = m_copym(repmbuf, - 0, M_COPYALL, M_TRYWAIT); - rp->rc_flag |= RC_REPMBUF; - } - } - rp->rc_flag &= ~RC_LOCKED; - if (rp->rc_flag & RC_WANTED) { - rp->rc_flag &= ~RC_WANTED; - wakeup((caddr_t)rp); - } - return; - } - } - NFS_DPF(RC, ("L%03x", nd->nd_retxid & 0xfff)); -} - -/* - * Clean out the cache. Called when the last nfsd terminates. - */ -void -nfsrv_cleancache() -{ - register struct nfsrvcache *rp, *nextrp; - - for (rp = nfsrvlruhead.tqh_first; rp != 0; rp = nextrp) { - nextrp = rp->rc_lru.tqe_next; - LIST_REMOVE(rp, rc_hash); - TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru); - if (rp->rc_flag & RC_REPMBUF) - m_freem(rp->rc_reply); - if (rp->rc_flag & RC_NAM) - free(rp->rc_nam, M_SONAME); - free(rp, M_NFSD); - } - numnfsrvcache = 0; -} - -#endif /* NFS_NOSERVER */ diff --git a/sys/nfs/nfs_subs.c b/sys/nfs/nfs_subs.c deleted file mode 100644 index 4425129..0000000 --- a/sys/nfs/nfs_subs.c +++ /dev/null @@ -1,2243 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 - * $FreeBSD$ - */ - -/* - * These functions support the macros and help fiddle mbuf chains for - * the nfs op functions. They do things like create the rpc header and - * copy data between mbuf chains and uio lists. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * Data items converted to xdr at startup, since they are constant - * This is kinda hokey, but may save a little time doing byte swaps - */ -u_int32_t nfs_xdrneg1; -u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, - rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, - rpc_auth_kerb; -u_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false; - -/* And other global data */ -static u_int32_t nfs_xid = 0; -static enum vtype nv2tov_type[8]= { - VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON -}; -enum vtype nv3tov_type[8]= { - VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO -}; - -int nfs_ticks; -int nfs_pbuf_freecnt = -1; /* start out unlimited */ - -struct nfs_reqq nfs_reqq; -struct nfssvc_sockhead nfssvc_sockhead; -int nfssvc_sockhead_flag; -struct nfsd_head nfsd_head; -int nfsd_head_flag; -struct nfs_bufq nfs_bufq; -struct nqtimerhead nqtimerhead; -struct nqfhhashhead *nqfhhashtbl; -u_long nqfhhash; - -static void (*nfs_prev_lease_updatetime) __P((int)); -static int nfs_prev_nfssvc_sy_narg; -static sy_call_t *nfs_prev_nfssvc_sy_call; - -#ifndef NFS_NOSERVER - -static vop_t *nfs_prev_vop_lease_check; - -/* - * Mapping of old NFS Version 2 RPC numbers to generic numbers. - */ -int nfsv3_procid[NFS_NPROCS] = { - NFSPROC_NULL, - NFSPROC_GETATTR, - NFSPROC_SETATTR, - NFSPROC_NOOP, - NFSPROC_LOOKUP, - NFSPROC_READLINK, - NFSPROC_READ, - NFSPROC_NOOP, - NFSPROC_WRITE, - NFSPROC_CREATE, - NFSPROC_REMOVE, - NFSPROC_RENAME, - NFSPROC_LINK, - NFSPROC_SYMLINK, - NFSPROC_MKDIR, - NFSPROC_RMDIR, - NFSPROC_READDIR, - NFSPROC_FSSTAT, - NFSPROC_NOOP, - NFSPROC_NOOP, - NFSPROC_NOOP, - NFSPROC_NOOP, - NFSPROC_NOOP, - NFSPROC_NOOP, - NFSPROC_NOOP, - NFSPROC_NOOP -}; - -#endif /* NFS_NOSERVER */ -/* - * and the reverse mapping from generic to Version 2 procedure numbers - */ -int nfsv2_procid[NFS_NPROCS] = { - NFSV2PROC_NULL, - NFSV2PROC_GETATTR, - NFSV2PROC_SETATTR, - NFSV2PROC_LOOKUP, - NFSV2PROC_NOOP, - NFSV2PROC_READLINK, - NFSV2PROC_READ, - NFSV2PROC_WRITE, - NFSV2PROC_CREATE, - NFSV2PROC_MKDIR, - NFSV2PROC_SYMLINK, - NFSV2PROC_CREATE, - NFSV2PROC_REMOVE, - NFSV2PROC_RMDIR, - NFSV2PROC_RENAME, - NFSV2PROC_LINK, - NFSV2PROC_READDIR, - NFSV2PROC_NOOP, - NFSV2PROC_STATFS, - NFSV2PROC_NOOP, - NFSV2PROC_NOOP, - NFSV2PROC_NOOP, - NFSV2PROC_NOOP, - NFSV2PROC_NOOP, - NFSV2PROC_NOOP, - NFSV2PROC_NOOP, -}; - -#ifndef NFS_NOSERVER -/* - * Maps errno values to nfs error numbers. - * Use NFSERR_IO as the catch all for ones not specifically defined in - * RFC 1094. - */ -static u_char nfsrv_v2errmap[ELAST] = { - NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, - NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, - NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, - NFSERR_IO /* << Last is 86 */ -}; - -/* - * Maps errno values to nfs error numbers. - * Although it is not obvious whether or not NFS clients really care if - * a returned error value is in the specified list for the procedure, the - * safest thing to do is filter them appropriately. For Version 2, the - * X/Open XNFS document is the only specification that defines error values - * for each RPC (The RFC simply lists all possible error values for all RPCs), - * so I have decided to not do this for Version 2. - * The first entry is the default error return and the rest are the valid - * errors for that RPC in increasing numeric order. - */ -static short nfsv3err_null[] = { - 0, - 0, -}; - -static short nfsv3err_getattr[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_setattr[] = { - NFSERR_IO, - NFSERR_PERM, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_INVAL, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOT_SYNC, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_lookup[] = { - NFSERR_IO, - NFSERR_NOENT, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_NOTDIR, - NFSERR_NAMETOL, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_access[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_readlink[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_INVAL, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_read[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_NXIO, - NFSERR_ACCES, - NFSERR_INVAL, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_write[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_INVAL, - NFSERR_FBIG, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_create[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_EXIST, - NFSERR_NOTDIR, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_NAMETOL, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_mkdir[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_EXIST, - NFSERR_NOTDIR, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_NAMETOL, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_symlink[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_EXIST, - NFSERR_NOTDIR, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_NAMETOL, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_mknod[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_EXIST, - NFSERR_NOTDIR, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_NAMETOL, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - NFSERR_BADTYPE, - 0, -}; - -static short nfsv3err_remove[] = { - NFSERR_IO, - NFSERR_NOENT, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_NOTDIR, - NFSERR_ROFS, - NFSERR_NAMETOL, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_rmdir[] = { - NFSERR_IO, - NFSERR_NOENT, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_EXIST, - NFSERR_NOTDIR, - NFSERR_INVAL, - NFSERR_ROFS, - NFSERR_NAMETOL, - NFSERR_NOTEMPTY, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_rename[] = { - NFSERR_IO, - NFSERR_NOENT, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_EXIST, - NFSERR_XDEV, - NFSERR_NOTDIR, - NFSERR_ISDIR, - NFSERR_INVAL, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_MLINK, - NFSERR_NAMETOL, - NFSERR_NOTEMPTY, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_link[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_EXIST, - NFSERR_XDEV, - NFSERR_NOTDIR, - NFSERR_INVAL, - NFSERR_NOSPC, - NFSERR_ROFS, - NFSERR_MLINK, - NFSERR_NAMETOL, - NFSERR_DQUOT, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_NOTSUPP, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_readdir[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_NOTDIR, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_BAD_COOKIE, - NFSERR_TOOSMALL, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_readdirplus[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_ACCES, - NFSERR_NOTDIR, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_BAD_COOKIE, - NFSERR_NOTSUPP, - NFSERR_TOOSMALL, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_fsstat[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_fsinfo[] = { - NFSERR_STALE, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_pathconf[] = { - NFSERR_STALE, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short nfsv3err_commit[] = { - NFSERR_IO, - NFSERR_IO, - NFSERR_STALE, - NFSERR_BADHANDLE, - NFSERR_SERVERFAULT, - 0, -}; - -static short *nfsrv_v3errmap[] = { - nfsv3err_null, - nfsv3err_getattr, - nfsv3err_setattr, - nfsv3err_lookup, - nfsv3err_access, - nfsv3err_readlink, - nfsv3err_read, - nfsv3err_write, - nfsv3err_create, - nfsv3err_mkdir, - nfsv3err_symlink, - nfsv3err_mknod, - nfsv3err_remove, - nfsv3err_rmdir, - nfsv3err_rename, - nfsv3err_link, - nfsv3err_readdir, - nfsv3err_readdirplus, - nfsv3err_fsstat, - nfsv3err_fsinfo, - nfsv3err_pathconf, - nfsv3err_commit, -}; - -#endif /* NFS_NOSERVER */ - -extern struct nfsrtt nfsrtt; -extern time_t nqnfsstarttime; -extern int nqsrv_clockskew; -extern int nqsrv_writeslack; -extern int nqsrv_maxlease; -extern struct nfsstats nfsstats; -extern int nqnfs_piggy[NFS_NPROCS]; -extern nfstype nfsv2_type[9]; -extern nfstype nfsv3_type[9]; -extern struct nfsnodehashhead *nfsnodehashtbl; -extern u_long nfsnodehash; - -struct nfssvc_args; -extern int nfssvc(struct thread *, struct nfssvc_args *, int *); - -LIST_HEAD(nfsnodehashhead, nfsnode); - -int nfs_webnamei __P((struct nameidata *, struct vnode *, struct thread *)); - -u_quad_t -nfs_curusec() -{ - struct timeval tv; - - getmicrotime(&tv); - return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec); -} - -/* - * Create the header for an rpc request packet - * The hsiz is the size of the rest of the nfs request header. - * (just used to decide if a cluster is a good idea) - */ -struct mbuf * -nfsm_reqh(vp, procid, hsiz, bposp) - struct vnode *vp; - u_long procid; - int hsiz; - caddr_t *bposp; -{ - register struct mbuf *mb; - register u_int32_t *tl; - register caddr_t bpos; - struct mbuf *mb2; - struct nfsmount *nmp; - int nqflag; - - MGET(mb, M_TRYWAIT, MT_DATA); - if (hsiz >= MINCLSIZE) - MCLGET(mb, M_TRYWAIT); - mb->m_len = 0; - bpos = mtod(mb, caddr_t); - - /* - * For NQNFS, add lease request. - */ - if (vp) { - nmp = VFSTONFS(vp->v_mount); - if (nmp->nm_flag & NFSMNT_NQNFS) { - nqflag = NQNFS_NEEDLEASE(vp, procid); - if (nqflag) { - nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED); - *tl++ = txdr_unsigned(nqflag); - *tl = txdr_unsigned(nmp->nm_leaseterm); - } else { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); - *tl = 0; - } - } - } - /* Finally, return values */ - *bposp = bpos; - return (mb); -} - -/* - * Build the RPC header and fill in the authorization info. - * The authorization string argument is only used when the credentials - * come from outside of the kernel. - * Returns the head of the mbuf list. - */ -struct mbuf * -nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, - verf_str, mrest, mrest_len, mbp, xidp) - register struct ucred *cr; - int nmflag; - int procid; - int auth_type; - int auth_len; - char *auth_str; - int verf_len; - char *verf_str; - struct mbuf *mrest; - int mrest_len; - struct mbuf **mbp; - u_int32_t *xidp; -{ - register struct mbuf *mb; - register u_int32_t *tl; - register caddr_t bpos; - register int i; - struct mbuf *mreq, *mb2; - int siz, grpsiz, authsiz; - - authsiz = nfsm_rndup(auth_len); - MGETHDR(mb, M_TRYWAIT, MT_DATA); - if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { - MCLGET(mb, M_TRYWAIT); - } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { - MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); - } else { - MH_ALIGN(mb, 8 * NFSX_UNSIGNED); - } - mb->m_len = 0; - mreq = mb; - bpos = mtod(mb, caddr_t); - - /* - * First the RPC header. - */ - nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED); - - /* Get a pretty random xid to start with */ - if (!nfs_xid) - nfs_xid = random(); - /* - * Skip zero xid if it should ever happen. - */ - if (++nfs_xid == 0) - nfs_xid++; - - *tl++ = *xidp = txdr_unsigned(nfs_xid); - *tl++ = rpc_call; - *tl++ = rpc_vers; - if (nmflag & NFSMNT_NQNFS) { - *tl++ = txdr_unsigned(NQNFS_PROG); - *tl++ = txdr_unsigned(NQNFS_VER3); - } else { - *tl++ = txdr_unsigned(NFS_PROG); - if (nmflag & NFSMNT_NFSV3) - *tl++ = txdr_unsigned(NFS_VER3); - else - *tl++ = txdr_unsigned(NFS_VER2); - } - if (nmflag & NFSMNT_NFSV3) - *tl++ = txdr_unsigned(procid); - else - *tl++ = txdr_unsigned(nfsv2_procid[procid]); - - /* - * And then the authorization cred. - */ - *tl++ = txdr_unsigned(auth_type); - *tl = txdr_unsigned(authsiz); - switch (auth_type) { - case RPCAUTH_UNIX: - nfsm_build(tl, u_int32_t *, auth_len); - *tl++ = 0; /* stamp ?? */ - *tl++ = 0; /* NULL hostname */ - *tl++ = txdr_unsigned(cr->cr_uid); - *tl++ = txdr_unsigned(cr->cr_groups[0]); - grpsiz = (auth_len >> 2) - 5; - *tl++ = txdr_unsigned(grpsiz); - for (i = 1; i <= grpsiz; i++) - *tl++ = txdr_unsigned(cr->cr_groups[i]); - break; - case RPCAUTH_KERB4: - siz = auth_len; - while (siz > 0) { - if (M_TRAILINGSPACE(mb) == 0) { - MGET(mb2, M_TRYWAIT, MT_DATA); - if (siz >= MINCLSIZE) - MCLGET(mb2, M_TRYWAIT); - mb->m_next = mb2; - mb = mb2; - mb->m_len = 0; - bpos = mtod(mb, caddr_t); - } - i = min(siz, M_TRAILINGSPACE(mb)); - bcopy(auth_str, bpos, i); - mb->m_len += i; - auth_str += i; - bpos += i; - siz -= i; - } - if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { - for (i = 0; i < siz; i++) - *bpos++ = '\0'; - mb->m_len += siz; - } - break; - }; - - /* - * And the verifier... - */ - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - if (verf_str) { - *tl++ = txdr_unsigned(RPCAUTH_KERB4); - *tl = txdr_unsigned(verf_len); - siz = verf_len; - while (siz > 0) { - if (M_TRAILINGSPACE(mb) == 0) { - MGET(mb2, M_TRYWAIT, MT_DATA); - if (siz >= MINCLSIZE) - MCLGET(mb2, M_TRYWAIT); - mb->m_next = mb2; - mb = mb2; - mb->m_len = 0; - bpos = mtod(mb, caddr_t); - } - i = min(siz, M_TRAILINGSPACE(mb)); - bcopy(verf_str, bpos, i); - mb->m_len += i; - verf_str += i; - bpos += i; - siz -= i; - } - if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { - for (i = 0; i < siz; i++) - *bpos++ = '\0'; - mb->m_len += siz; - } - } else { - *tl++ = txdr_unsigned(RPCAUTH_NULL); - *tl = 0; - } - mb->m_next = mrest; - mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; - mreq->m_pkthdr.rcvif = (struct ifnet *)0; - *mbp = mb; - return (mreq); -} - -/* - * copies mbuf chain to the uio scatter/gather list - */ -int -nfsm_mbuftouio(mrep, uiop, siz, dpos) - struct mbuf **mrep; - register struct uio *uiop; - int siz; - caddr_t *dpos; -{ - register char *mbufcp, *uiocp; - register int xfer, left, len; - register struct mbuf *mp; - long uiosiz, rem; - int error = 0; - - mp = *mrep; - mbufcp = *dpos; - len = mtod(mp, caddr_t)+mp->m_len-mbufcp; - rem = nfsm_rndup(siz)-siz; - while (siz > 0) { - if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) - return (EFBIG); - left = uiop->uio_iov->iov_len; - uiocp = uiop->uio_iov->iov_base; - if (left > siz) - left = siz; - uiosiz = left; - while (left > 0) { - while (len == 0) { - mp = mp->m_next; - if (mp == NULL) - return (EBADRPC); - mbufcp = mtod(mp, caddr_t); - len = mp->m_len; - } - xfer = (left > len) ? len : left; -#ifdef notdef - /* Not Yet.. */ - if (uiop->uio_iov->iov_op != NULL) - (*(uiop->uio_iov->iov_op)) - (mbufcp, uiocp, xfer); - else -#endif - if (uiop->uio_segflg == UIO_SYSSPACE) - bcopy(mbufcp, uiocp, xfer); - else - copyout(mbufcp, uiocp, xfer); - left -= xfer; - len -= xfer; - mbufcp += xfer; - uiocp += xfer; - uiop->uio_offset += xfer; - uiop->uio_resid -= xfer; - } - if (uiop->uio_iov->iov_len <= siz) { - uiop->uio_iovcnt--; - uiop->uio_iov++; - } else { - uiop->uio_iov->iov_base += uiosiz; - uiop->uio_iov->iov_len -= uiosiz; - } - siz -= uiosiz; - } - *dpos = mbufcp; - *mrep = mp; - if (rem > 0) { - if (len < rem) - error = nfs_adv(mrep, dpos, rem, len); - else - *dpos += rem; - } - return (error); -} - -/* - * copies a uio scatter/gather list to an mbuf chain. - * NOTE: can ony handle iovcnt == 1 - */ -int -nfsm_uiotombuf(uiop, mq, siz, bpos) - register struct uio *uiop; - struct mbuf **mq; - int siz; - caddr_t *bpos; -{ - register char *uiocp; - register struct mbuf *mp, *mp2; - register int xfer, left, mlen; - int uiosiz, clflg, rem; - char *cp; - -#ifdef DIAGNOSTIC - if (uiop->uio_iovcnt != 1) - panic("nfsm_uiotombuf: iovcnt != 1"); -#endif - - if (siz > MLEN) /* or should it >= MCLBYTES ?? */ - clflg = 1; - else - clflg = 0; - rem = nfsm_rndup(siz)-siz; - mp = mp2 = *mq; - while (siz > 0) { - left = uiop->uio_iov->iov_len; - uiocp = uiop->uio_iov->iov_base; - if (left > siz) - left = siz; - uiosiz = left; - while (left > 0) { - mlen = M_TRAILINGSPACE(mp); - if (mlen == 0) { - MGET(mp, M_TRYWAIT, MT_DATA); - if (clflg) - MCLGET(mp, M_TRYWAIT); - mp->m_len = 0; - mp2->m_next = mp; - mp2 = mp; - mlen = M_TRAILINGSPACE(mp); - } - xfer = (left > mlen) ? mlen : left; -#ifdef notdef - /* Not Yet.. */ - if (uiop->uio_iov->iov_op != NULL) - (*(uiop->uio_iov->iov_op)) - (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); - else -#endif - if (uiop->uio_segflg == UIO_SYSSPACE) - bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); - else - copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); - mp->m_len += xfer; - left -= xfer; - uiocp += xfer; - uiop->uio_offset += xfer; - uiop->uio_resid -= xfer; - } - uiop->uio_iov->iov_base += uiosiz; - uiop->uio_iov->iov_len -= uiosiz; - siz -= uiosiz; - } - if (rem > 0) { - if (rem > M_TRAILINGSPACE(mp)) { - MGET(mp, M_TRYWAIT, MT_DATA); - mp->m_len = 0; - mp2->m_next = mp; - } - cp = mtod(mp, caddr_t)+mp->m_len; - for (left = 0; left < rem; left++) - *cp++ = '\0'; - mp->m_len += rem; - *bpos = cp; - } else - *bpos = mtod(mp, caddr_t)+mp->m_len; - *mq = mp; - return (0); -} - -/* - * Help break down an mbuf chain by setting the first siz bytes contiguous - * pointed to by returned val. - * This is used by the macros nfsm_dissect and nfsm_dissecton for tough - * cases. (The macros use the vars. dpos and dpos2) - */ -int -nfsm_disct(mdp, dposp, siz, left, cp2) - struct mbuf **mdp; - caddr_t *dposp; - int siz; - int left; - caddr_t *cp2; -{ - register struct mbuf *mp, *mp2; - register int siz2, xfer; - register caddr_t ptr; - - mp = *mdp; - while (left == 0) { - *mdp = mp = mp->m_next; - if (mp == NULL) - return (EBADRPC); - left = mp->m_len; - *dposp = mtod(mp, caddr_t); - } - if (left >= siz) { - *cp2 = *dposp; - *dposp += siz; - } else if (mp->m_next == NULL) { - return (EBADRPC); - } else if (siz > MHLEN) { - panic("nfs S too big"); - } else { - MGET(mp2, M_TRYWAIT, MT_DATA); - mp2->m_next = mp->m_next; - mp->m_next = mp2; - mp->m_len -= left; - mp = mp2; - *cp2 = ptr = mtod(mp, caddr_t); - bcopy(*dposp, ptr, left); /* Copy what was left */ - siz2 = siz-left; - ptr += left; - mp2 = mp->m_next; - /* Loop around copying up the siz2 bytes */ - while (siz2 > 0) { - if (mp2 == NULL) - return (EBADRPC); - xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; - if (xfer > 0) { - bcopy(mtod(mp2, caddr_t), ptr, xfer); - NFSMADV(mp2, xfer); - mp2->m_len -= xfer; - ptr += xfer; - siz2 -= xfer; - } - if (siz2 > 0) - mp2 = mp2->m_next; - } - mp->m_len = siz; - *mdp = mp2; - *dposp = mtod(mp2, caddr_t); - } - return (0); -} - -/* - * Advance the position in the mbuf chain. - */ -int -nfs_adv(mdp, dposp, offs, left) - struct mbuf **mdp; - caddr_t *dposp; - int offs; - int left; -{ - register struct mbuf *m; - register int s; - - m = *mdp; - s = left; - while (s < offs) { - offs -= s; - m = m->m_next; - if (m == NULL) - return (EBADRPC); - s = m->m_len; - } - *mdp = m; - *dposp = mtod(m, caddr_t)+offs; - return (0); -} - -/* - * Copy a string into mbufs for the hard cases... - */ -int -nfsm_strtmbuf(mb, bpos, cp, siz) - struct mbuf **mb; - char **bpos; - const char *cp; - long siz; -{ - register struct mbuf *m1 = NULL, *m2; - long left, xfer, len, tlen; - u_int32_t *tl; - int putsize; - - putsize = 1; - m2 = *mb; - left = M_TRAILINGSPACE(m2); - if (left > 0) { - tl = ((u_int32_t *)(*bpos)); - *tl++ = txdr_unsigned(siz); - putsize = 0; - left -= NFSX_UNSIGNED; - m2->m_len += NFSX_UNSIGNED; - if (left > 0) { - bcopy(cp, (caddr_t) tl, left); - siz -= left; - cp += left; - m2->m_len += left; - left = 0; - } - } - /* Loop around adding mbufs */ - while (siz > 0) { - MGET(m1, M_TRYWAIT, MT_DATA); - if (siz > MLEN) - MCLGET(m1, M_TRYWAIT); - m1->m_len = NFSMSIZ(m1); - m2->m_next = m1; - m2 = m1; - tl = mtod(m1, u_int32_t *); - tlen = 0; - if (putsize) { - *tl++ = txdr_unsigned(siz); - m1->m_len -= NFSX_UNSIGNED; - tlen = NFSX_UNSIGNED; - putsize = 0; - } - if (siz < m1->m_len) { - len = nfsm_rndup(siz); - xfer = siz; - if (xfer < len) - *(tl+(xfer>>2)) = 0; - } else { - xfer = len = m1->m_len; - } - bcopy(cp, (caddr_t) tl, xfer); - m1->m_len = len+tlen; - siz -= xfer; - cp += xfer; - } - *mb = m1; - *bpos = mtod(m1, caddr_t)+m1->m_len; - return (0); -} - -/* - * Called once to initialize data structures... - */ -int -nfs_init(vfsp) - struct vfsconf *vfsp; -{ - register int i; - - nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1); - - nfs_mount_type = vfsp->vfc_typenum; - nfsrtt.pos = 0; - rpc_vers = txdr_unsigned(RPC_VER2); - rpc_call = txdr_unsigned(RPC_CALL); - rpc_reply = txdr_unsigned(RPC_REPLY); - rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); - rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); - rpc_mismatch = txdr_unsigned(RPC_MISMATCH); - rpc_autherr = txdr_unsigned(RPC_AUTHERR); - rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); - rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); - nfs_prog = txdr_unsigned(NFS_PROG); - nqnfs_prog = txdr_unsigned(NQNFS_PROG); - nfs_true = txdr_unsigned(TRUE); - nfs_false = txdr_unsigned(FALSE); - nfs_xdrneg1 = txdr_unsigned(-1); - nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; - if (nfs_ticks < 1) - nfs_ticks = 1; - /* Ensure async daemons disabled */ - for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { - nfs_iodwant[i] = (struct proc *)0; - nfs_iodmount[i] = (struct nfsmount *)0; - } - nfs_nhinit(); /* Init the nfsnode table */ -#ifndef NFS_NOSERVER - nfsrv_init(0); /* Init server data structures */ - nfsrv_initcache(); /* Init the server request cache */ -#endif - - /* - * Initialize the nqnfs server stuff. - */ - if (nqnfsstarttime == 0) { - nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease - + nqsrv_clockskew + nqsrv_writeslack; - NQLOADNOVRAM(nqnfsstarttime); - TAILQ_INIT(&nqtimerhead); - nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); - } - - /* - * Initialize reply list and start timer - */ - TAILQ_INIT(&nfs_reqq); - - nfs_timer(0); - - /* - * Set up lease_check and lease_updatetime so that other parts - * of the system can call us, if we are loadable. - */ -#ifndef NFS_NOSERVER - nfs_prev_vop_lease_check = default_vnodeop_p[VOFFSET(vop_lease)]; - default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check; -#endif - nfs_prev_lease_updatetime = lease_updatetime; - lease_updatetime = nfs_lease_updatetime; - nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg; - sysent[SYS_nfssvc].sy_narg = 2; - nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call; - sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc; - - nfs_pbuf_freecnt = nswbuf / 2 + 1; - - return (0); -} - -int -nfs_uninit(vfsp) - struct vfsconf *vfsp; -{ - - untimeout(nfs_timer, (void *)NULL, nfs_timer_handle); - nfs_mount_type = -1; -#ifndef NFS_NOSERVER - default_vnodeop_p[VOFFSET(vop_lease)] = nfs_prev_vop_lease_check; -#endif - lease_updatetime = nfs_prev_lease_updatetime; - sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg; - sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call; - return (0); -} - -/* - * Attribute cache routines. - * nfs_loadattrcache() - loads or updates the cache contents from attributes - * that are on the mbuf list - * nfs_getattrcache() - returns valid attributes if found in cache, returns - * error otherwise - */ - -/* - * Load the attribute cache (that lives in the nfsnode entry) with - * the values on the mbuf list and - * Iff vap not NULL - * copy the attributes to *vaper - */ -int -nfs_loadattrcache(vpp, mdp, dposp, vaper, dontshrink) - struct vnode **vpp; - struct mbuf **mdp; - caddr_t *dposp; - struct vattr *vaper; - int dontshrink; -{ - register struct vnode *vp = *vpp; - register struct vattr *vap; - register struct nfs_fattr *fp; - register struct nfsnode *np; - register int32_t t1; - caddr_t cp2; - int error = 0, rdev; - struct mbuf *md; - enum vtype vtyp; - u_short vmode; - struct timespec mtime; - int v3 = NFS_ISV3(vp); - - md = *mdp; - t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; - if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) != 0) - return (error); - fp = (struct nfs_fattr *)cp2; - if (v3) { - vtyp = nfsv3tov_type(fp->fa_type); - vmode = fxdr_unsigned(u_short, fp->fa_mode); - rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), - fxdr_unsigned(int, fp->fa3_rdev.specdata2)); - fxdr_nfsv3time(&fp->fa3_mtime, &mtime); - } else { - vtyp = nfsv2tov_type(fp->fa_type); - vmode = fxdr_unsigned(u_short, fp->fa_mode); - /* - * XXX - * - * The duplicate information returned in fa_type and fa_mode - * is an ambiguity in the NFS version 2 protocol. - * - * VREG should be taken literally as a regular file. If a - * server intents to return some type information differently - * in the upper bits of the mode field (e.g. for sockets, or - * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we - * leave the examination of the mode bits even in the VREG - * case to avoid breakage for bogus servers, but we make sure - * that there are actually type bits set in the upper part of - * fa_mode (and failing that, trust the va_type field). - * - * NFSv3 cleared the issue, and requires fa_mode to not - * contain any type information (while also introduing sockets - * and FIFOs for fa_type). - */ - if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) - vtyp = IFTOVT(vmode); - rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); - fxdr_nfsv2time(&fp->fa2_mtime, &mtime); - - /* - * Really ugly NFSv2 kludge. - */ - if (vtyp == VCHR && rdev == 0xffffffff) - vtyp = VFIFO; - } - - /* - * If v_type == VNON it is a new node, so fill in the v_type, - * n_mtime fields. Check to see if it represents a special - * device, and if so, check for a possible alias. Once the - * correct vnode has been obtained, fill in the rest of the - * information. - */ - np = VTONFS(vp); - if (vp->v_type != vtyp) { - vp->v_type = vtyp; - if (vp->v_type == VFIFO) { - vp->v_op = fifo_nfsv2nodeop_p; - } - if (vp->v_type == VCHR || vp->v_type == VBLK) { - vp->v_op = spec_nfsv2nodeop_p; - vp = addaliasu(vp, rdev); - np->n_vnode = vp; - } - np->n_mtime = mtime.tv_sec; - } - vap = &np->n_vattr; - vap->va_type = vtyp; - vap->va_mode = (vmode & 07777); - vap->va_rdev = rdev; - vap->va_mtime = mtime; - vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; - if (v3) { - vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); - vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); - vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); - vap->va_size = fxdr_hyper(&fp->fa3_size); - vap->va_blocksize = NFS_FABLKSIZE; - vap->va_bytes = fxdr_hyper(&fp->fa3_used); - vap->va_fileid = fxdr_unsigned(int32_t, - fp->fa3_fileid.nfsuquad[1]); - fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); - fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); - vap->va_flags = 0; - vap->va_filerev = 0; - } else { - vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); - vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); - vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); - vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); - vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); - vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) - * NFS_FABLKSIZE; - vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); - fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); - vap->va_flags = 0; - vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, - fp->fa2_ctime.nfsv2_sec); - vap->va_ctime.tv_nsec = 0; - vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); - vap->va_filerev = 0; - } - np->n_attrstamp = time_second; - if (vap->va_size != np->n_size) { - if (vap->va_type == VREG) { - if (dontshrink && vap->va_size < np->n_size) { - /* - * We've been told not to shrink the file; - * zero np->n_attrstamp to indicate that - * the attributes are stale. - */ - vap->va_size = np->n_size; - np->n_attrstamp = 0; - } else if (np->n_flag & NMODIFIED) { - if (vap->va_size < np->n_size) - vap->va_size = np->n_size; - else - np->n_size = vap->va_size; - } else { - np->n_size = vap->va_size; - } - vnode_pager_setsize(vp, np->n_size); - } else { - np->n_size = vap->va_size; - } - } - if (vaper != NULL) { - bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); - if (np->n_flag & NCHG) { - if (np->n_flag & NACC) - vaper->va_atime = np->n_atim; - if (np->n_flag & NUPD) - vaper->va_mtime = np->n_mtim; - } - } - return (0); -} - -#ifdef NFS_ACDEBUG -#include -SYSCTL_DECL(_vfs_nfs); -static int nfs_acdebug; -SYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); -#endif - -/* - * Check the time stamp - * If the cache is valid, copy contents to *vap and return 0 - * otherwise return an error - */ -int -nfs_getattrcache(vp, vaper) - register struct vnode *vp; - struct vattr *vaper; -{ - register struct nfsnode *np; - register struct vattr *vap; - struct nfsmount *nmp; - int timeo; - - np = VTONFS(vp); - vap = &np->n_vattr; - nmp = VFSTONFS(vp->v_mount); - /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ - timeo = (time_second - np->n_mtime) / 10; - -#ifdef NFS_ACDEBUG - if (nfs_acdebug>1) - printf("nfs_getattrcache: initial timeo = %d\n", timeo); -#endif - - if (vap->va_type == VDIR) { - if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) - timeo = nmp->nm_acdirmin; - else if (timeo > nmp->nm_acdirmax) - timeo = nmp->nm_acdirmax; - } else { - if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) - timeo = nmp->nm_acregmin; - else if (timeo > nmp->nm_acregmax) - timeo = nmp->nm_acregmax; - } - -#ifdef NFS_ACDEBUG - if (nfs_acdebug > 2) - printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", - nmp->nm_acregmin, nmp->nm_acregmax, - nmp->nm_acdirmin, nmp->nm_acdirmax); - - if (nfs_acdebug) - printf("nfs_getattrcache: age = %d; final timeo = %d\n", - (time_second - np->n_attrstamp), timeo); -#endif - - if ((time_second - np->n_attrstamp) >= timeo) { - nfsstats.attrcache_misses++; - return (ENOENT); - } - nfsstats.attrcache_hits++; - if (vap->va_size != np->n_size) { - if (vap->va_type == VREG) { - if (np->n_flag & NMODIFIED) { - if (vap->va_size < np->n_size) - vap->va_size = np->n_size; - else - np->n_size = vap->va_size; - } else { - np->n_size = vap->va_size; - } - vnode_pager_setsize(vp, np->n_size); - } else { - np->n_size = vap->va_size; - } - } - bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); - if (np->n_flag & NCHG) { - if (np->n_flag & NACC) - vaper->va_atime = np->n_atim; - if (np->n_flag & NUPD) - vaper->va_mtime = np->n_mtim; - } - return (0); -} - -#ifndef NFS_NOSERVER -/* - * Set up nameidata for a lookup() call and do it. - * - * If pubflag is set, this call is done for a lookup operation on the - * public filehandle. In that case we allow crossing mountpoints and - * absolute pathnames. However, the caller is expected to check that - * the lookup result is within the public fs, and deny access if - * it is not. - * - * nfs_namei() clears out garbage fields that namei() might leave garbage. - * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no - * error occurs but the parent was not requested. - * - * dirp may be set whether an error is returned or not, and must be - * released by the caller. - */ -int -nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, td, kerbflag, pubflag) - register struct nameidata *ndp; - fhandle_t *fhp; - int len; - struct nfssvc_sock *slp; - struct sockaddr *nam; - struct mbuf **mdp; - caddr_t *dposp; - struct vnode **retdirp; - struct thread *td; - int kerbflag, pubflag; -{ - register int i, rem; - register struct mbuf *md; - register char *fromcp, *tocp, *cp; - struct iovec aiov; - struct uio auio; - struct vnode *dp; - int error, rdonly, linklen; - struct componentname *cnp = &ndp->ni_cnd; - - *retdirp = (struct vnode *)0; - cnp->cn_pnbuf = zalloc(namei_zone); - - /* - * Copy the name from the mbuf list to ndp->ni_pnbuf - * and set the various ndp fields appropriately. - */ - fromcp = *dposp; - tocp = cnp->cn_pnbuf; - md = *mdp; - rem = mtod(md, caddr_t) + md->m_len - fromcp; - for (i = 0; i < len; i++) { - while (rem == 0) { - md = md->m_next; - if (md == NULL) { - error = EBADRPC; - goto out; - } - fromcp = mtod(md, caddr_t); - rem = md->m_len; - } - if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { - error = EACCES; - goto out; - } - *tocp++ = *fromcp++; - rem--; - } - *tocp = '\0'; - *mdp = md; - *dposp = fromcp; - len = nfsm_rndup(len)-len; - if (len > 0) { - if (rem >= len) - *dposp += len; - else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) - goto out; - } - - /* - * Extract and set starting directory. - */ - error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, - nam, &rdonly, kerbflag, pubflag); - if (error) - goto out; - if (dp->v_type != VDIR) { - vrele(dp); - error = ENOTDIR; - goto out; - } - - if (rdonly) - cnp->cn_flags |= RDONLY; - - /* - * Set return directory. Reference to dp is implicitly transfered - * to the returned pointer - */ - *retdirp = dp; - - if (pubflag) { - /* - * Oh joy. For WebNFS, handle those pesky '%' escapes, - * and the 'native path' indicator. - */ - cp = zalloc(namei_zone); - fromcp = cnp->cn_pnbuf; - tocp = cp; - if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { - switch ((unsigned char)*fromcp) { - case WEBNFS_NATIVE_CHAR: - /* - * 'Native' path for us is the same - * as a path according to the NFS spec, - * just skip the escape char. - */ - fromcp++; - break; - /* - * More may be added in the future, range 0x80-0xff - */ - default: - error = EIO; - zfree(namei_zone, cp); - goto out; - } - } - /* - * Translate the '%' escapes, URL-style. - */ - while (*fromcp != '\0') { - if (*fromcp == WEBNFS_ESC_CHAR) { - if (fromcp[1] != '\0' && fromcp[2] != '\0') { - fromcp++; - *tocp++ = HEXSTRTOI(fromcp); - fromcp += 2; - continue; - } else { - error = ENOENT; - zfree(namei_zone, cp); - goto out; - } - } else - *tocp++ = *fromcp++; - } - *tocp = '\0'; - zfree(namei_zone, cnp->cn_pnbuf); - cnp->cn_pnbuf = cp; - } - - ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; - ndp->ni_segflg = UIO_SYSSPACE; - - if (pubflag) { - ndp->ni_rootdir = rootvnode; - ndp->ni_loopcnt = 0; - if (cnp->cn_pnbuf[0] == '/') - dp = rootvnode; - } else { - cnp->cn_flags |= NOCROSSMOUNT; - } - - /* - * Initialize for scan, set ni_startdir and bump ref on dp again - * becuase lookup() will dereference ni_startdir. - */ - - cnp->cn_thread = td; - VREF(dp); - ndp->ni_startdir = dp; - - for (;;) { - cnp->cn_nameptr = cnp->cn_pnbuf; - /* - * Call lookup() to do the real work. If an error occurs, - * ndp->ni_vp and ni_dvp are left uninitialized or NULL and - * we do not have to dereference anything before returning. - * In either case ni_startdir will be dereferenced and NULLed - * out. - */ - error = lookup(ndp); - if (error) - break; - - /* - * Check for encountering a symbolic link. Trivial - * termination occurs if no symlink encountered. - * Note: zfree is safe because error is 0, so we will - * not zfree it again when we break. - */ - if ((cnp->cn_flags & ISSYMLINK) == 0) { - nfsrv_object_create(ndp->ni_vp); - if (cnp->cn_flags & (SAVENAME | SAVESTART)) - cnp->cn_flags |= HASBUF; - else - zfree(namei_zone, cnp->cn_pnbuf); - break; - } - - /* - * Validate symlink - */ - if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) - VOP_UNLOCK(ndp->ni_dvp, 0, td); - if (!pubflag) { - error = EINVAL; - goto badlink2; - } - - if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { - error = ELOOP; - goto badlink2; - } - if (ndp->ni_pathlen > 1) - cp = zalloc(namei_zone); - else - cp = cnp->cn_pnbuf; - aiov.iov_base = cp; - aiov.iov_len = MAXPATHLEN; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_offset = 0; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_td = (struct thread *)0; - auio.uio_resid = MAXPATHLEN; - error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); - if (error) { - badlink1: - if (ndp->ni_pathlen > 1) - zfree(namei_zone, cp); - badlink2: - vrele(ndp->ni_dvp); - vput(ndp->ni_vp); - break; - } - linklen = MAXPATHLEN - auio.uio_resid; - if (linklen == 0) { - error = ENOENT; - goto badlink1; - } - if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { - error = ENAMETOOLONG; - goto badlink1; - } - - /* - * Adjust or replace path - */ - if (ndp->ni_pathlen > 1) { - bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); - zfree(namei_zone, cnp->cn_pnbuf); - cnp->cn_pnbuf = cp; - } else - cnp->cn_pnbuf[linklen] = '\0'; - ndp->ni_pathlen += linklen; - - /* - * Cleanup refs for next loop and check if root directory - * should replace current directory. Normally ni_dvp - * becomes the new base directory and is cleaned up when - * we loop. Explicitly null pointers after invalidation - * to clarify operation. - */ - vput(ndp->ni_vp); - ndp->ni_vp = NULL; - - if (cnp->cn_pnbuf[0] == '/') { - vrele(ndp->ni_dvp); - ndp->ni_dvp = ndp->ni_rootdir; - VREF(ndp->ni_dvp); - } - ndp->ni_startdir = ndp->ni_dvp; - ndp->ni_dvp = NULL; - } - - /* - * nfs_namei() guarentees that fields will not contain garbage - * whether an error occurs or not. This allows the caller to track - * cleanup state trivially. - */ -out: - if (error) { - zfree(namei_zone, cnp->cn_pnbuf); - ndp->ni_vp = NULL; - ndp->ni_dvp = NULL; - ndp->ni_startdir = NULL; - cnp->cn_flags &= ~HASBUF; - } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { - ndp->ni_dvp = NULL; - } - return (error); -} - -/* - * A fiddled version of m_adj() that ensures null fill to a long - * boundary and only trims off the back end - */ -void -nfsm_adj(mp, len, nul) - struct mbuf *mp; - register int len; - int nul; -{ - register struct mbuf *m; - register int count, i; - register char *cp; - - /* - * Trim from tail. Scan the mbuf chain, - * calculating its length and finding the last mbuf. - * If the adjustment only affects this mbuf, then just - * adjust and return. Otherwise, rescan and truncate - * after the remaining size. - */ - count = 0; - m = mp; - for (;;) { - count += m->m_len; - if (m->m_next == (struct mbuf *)0) - break; - m = m->m_next; - } - if (m->m_len > len) { - m->m_len -= len; - if (nul > 0) { - cp = mtod(m, caddr_t)+m->m_len-nul; - for (i = 0; i < nul; i++) - *cp++ = '\0'; - } - return; - } - count -= len; - if (count < 0) - count = 0; - /* - * Correct length for chain is "count". - * Find the mbuf with last data, adjust its length, - * and toss data from remaining mbufs on chain. - */ - for (m = mp; m; m = m->m_next) { - if (m->m_len >= count) { - m->m_len = count; - if (nul > 0) { - cp = mtod(m, caddr_t)+m->m_len-nul; - for (i = 0; i < nul; i++) - *cp++ = '\0'; - } - break; - } - count -= m->m_len; - } - for (m = m->m_next;m;m = m->m_next) - m->m_len = 0; -} - -/* - * Make these functions instead of macros, so that the kernel text size - * doesn't get too big... - */ -void -nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) - struct nfsrv_descript *nfsd; - int before_ret; - register struct vattr *before_vap; - int after_ret; - struct vattr *after_vap; - struct mbuf **mbp; - char **bposp; -{ - register struct mbuf *mb = *mbp, *mb2; - register char *bpos = *bposp; - register u_int32_t *tl; - - if (before_ret) { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); - *tl = nfs_false; - } else { - nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED); - *tl++ = nfs_true; - txdr_hyper(before_vap->va_size, tl); - tl += 2; - txdr_nfsv3time(&(before_vap->va_mtime), tl); - tl += 2; - txdr_nfsv3time(&(before_vap->va_ctime), tl); - } - *bposp = bpos; - *mbp = mb; - nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); -} - -void -nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) - struct nfsrv_descript *nfsd; - int after_ret; - struct vattr *after_vap; - struct mbuf **mbp; - char **bposp; -{ - register struct mbuf *mb = *mbp, *mb2; - register char *bpos = *bposp; - register u_int32_t *tl; - register struct nfs_fattr *fp; - - if (after_ret) { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); - *tl = nfs_false; - } else { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); - *tl++ = nfs_true; - fp = (struct nfs_fattr *)tl; - nfsm_srvfattr(nfsd, after_vap, fp); - } - *mbp = mb; - *bposp = bpos; -} - -void -nfsm_srvfattr(nfsd, vap, fp) - register struct nfsrv_descript *nfsd; - register struct vattr *vap; - register struct nfs_fattr *fp; -{ - - fp->fa_nlink = txdr_unsigned(vap->va_nlink); - fp->fa_uid = txdr_unsigned(vap->va_uid); - fp->fa_gid = txdr_unsigned(vap->va_gid); - if (nfsd->nd_flag & ND_NFSV3) { - fp->fa_type = vtonfsv3_type(vap->va_type); - fp->fa_mode = vtonfsv3_mode(vap->va_mode); - txdr_hyper(vap->va_size, &fp->fa3_size); - txdr_hyper(vap->va_bytes, &fp->fa3_used); - fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); - fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); - fp->fa3_fsid.nfsuquad[0] = 0; - fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); - fp->fa3_fileid.nfsuquad[0] = 0; - fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); - txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); - txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); - txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); - } else { - fp->fa_type = vtonfsv2_type(vap->va_type); - fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); - fp->fa2_size = txdr_unsigned(vap->va_size); - fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); - if (vap->va_type == VFIFO) - fp->fa2_rdev = 0xffffffff; - else - fp->fa2_rdev = txdr_unsigned(vap->va_rdev); - fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); - fp->fa2_fsid = txdr_unsigned(vap->va_fsid); - fp->fa2_fileid = txdr_unsigned(vap->va_fileid); - txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); - txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); - txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); - } -} - -/* - * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) - * - look up fsid in mount list (if not found ret error) - * - get vp and export rights by calling VFS_FHTOVP() - * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon - * - if not lockflag unlock it with VOP_UNLOCK() - */ -int -nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) - fhandle_t *fhp; - int lockflag; - struct vnode **vpp; - struct ucred *cred; - struct nfssvc_sock *slp; - struct sockaddr *nam; - int *rdonlyp; - int kerbflag; - int pubflag; -{ - struct thread *td = curthread; /* XXX */ - register struct mount *mp; - register int i; - struct ucred *credanon; - int error, exflags; -#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ - struct sockaddr_int *saddr; -#endif - - *vpp = (struct vnode *)0; - - if (nfs_ispublicfh(fhp)) { - if (!pubflag || !nfs_pub.np_valid) - return (ESTALE); - fhp = &nfs_pub.np_handle; - } - - mp = vfs_getvfs(&fhp->fh_fsid); - if (!mp) - return (ESTALE); - error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); - if (error) - return (error); - error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); - if (error) - return (error); -#ifdef MNT_EXNORESPORT - if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { - saddr = (struct sockaddr_in *)nam; - if (saddr->sin_family == AF_INET && - ntohs(saddr->sin_port) >= IPPORT_RESERVED) { - vput(*vpp); - *vpp = NULL; - return (NFSERR_AUTHERR | AUTH_TOOWEAK); - } - } -#endif - /* - * Check/setup credentials. - */ - if (exflags & MNT_EXKERB) { - if (!kerbflag) { - vput(*vpp); - *vpp = NULL; - return (NFSERR_AUTHERR | AUTH_TOOWEAK); - } - } else if (kerbflag) { - vput(*vpp); - *vpp = NULL; - return (NFSERR_AUTHERR | AUTH_TOOWEAK); - } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { - cred->cr_uid = credanon->cr_uid; - for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) - cred->cr_groups[i] = credanon->cr_groups[i]; - cred->cr_ngroups = i; - } - if (exflags & MNT_EXRDONLY) - *rdonlyp = 1; - else - *rdonlyp = 0; - - nfsrv_object_create(*vpp); - - if (!lockflag) - VOP_UNLOCK(*vpp, 0, td); - return (0); -} - - -/* - * WebNFS: check if a filehandle is a public filehandle. For v3, this - * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has - * transformed this to all zeroes in both cases, so check for it. - */ -int -nfs_ispublicfh(fhp) - fhandle_t *fhp; -{ - char *cp = (char *)fhp; - int i; - - for (i = 0; i < NFSX_V3FH; i++) - if (*cp++ != 0) - return (FALSE); - return (TRUE); -} - -#endif /* NFS_NOSERVER */ -/* - * This function compares two net addresses by family and returns TRUE - * if they are the same host. - * If there is any doubt, return FALSE. - * The AF_INET family is handled as a special case so that address mbufs - * don't need to be saved to store "struct in_addr", which is only 4 bytes. - */ -int -netaddr_match(family, haddr, nam) - int family; - union nethostaddr *haddr; - struct sockaddr *nam; -{ - register struct sockaddr_in *inetaddr; - - switch (family) { - case AF_INET: - inetaddr = (struct sockaddr_in *)nam; - if (inetaddr->sin_family == AF_INET && - inetaddr->sin_addr.s_addr == haddr->had_inetaddr) - return (1); - break; - default: - break; - }; - return (0); -} - -static nfsuint64 nfs_nullcookie = { { 0, 0 } }; -/* - * This function finds the directory cookie that corresponds to the - * logical byte offset given. - */ -nfsuint64 * -nfs_getcookie(np, off, add) - register struct nfsnode *np; - off_t off; - int add; -{ - register struct nfsdmap *dp, *dp2; - register int pos; - - pos = (uoff_t)off / NFS_DIRBLKSIZ; - if (pos == 0 || off < 0) { -#ifdef DIAGNOSTIC - if (add) - panic("nfs getcookie add at <= 0"); -#endif - return (&nfs_nullcookie); - } - pos--; - dp = np->n_cookies.lh_first; - if (!dp) { - if (add) { - MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), - M_NFSDIROFF, M_WAITOK); - dp->ndm_eocookie = 0; - LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); - } else - return ((nfsuint64 *)0); - } - while (pos >= NFSNUMCOOKIES) { - pos -= NFSNUMCOOKIES; - if (dp->ndm_list.le_next) { - if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && - pos >= dp->ndm_eocookie) - return ((nfsuint64 *)0); - dp = dp->ndm_list.le_next; - } else if (add) { - MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), - M_NFSDIROFF, M_WAITOK); - dp2->ndm_eocookie = 0; - LIST_INSERT_AFTER(dp, dp2, ndm_list); - dp = dp2; - } else - return ((nfsuint64 *)0); - } - if (pos >= dp->ndm_eocookie) { - if (add) - dp->ndm_eocookie = pos + 1; - else - return ((nfsuint64 *)0); - } - return (&dp->ndm_cookies[pos]); -} - -/* - * Invalidate cached directory information, except for the actual directory - * blocks (which are invalidated separately). - * Done mainly to avoid the use of stale offset cookies. - */ -void -nfs_invaldir(vp) - register struct vnode *vp; -{ - register struct nfsnode *np = VTONFS(vp); - -#ifdef DIAGNOSTIC - if (vp->v_type != VDIR) - panic("nfs: invaldir not dir"); -#endif - np->n_direofoffset = 0; - np->n_cookieverf.nfsuquad[0] = 0; - np->n_cookieverf.nfsuquad[1] = 0; - if (np->n_cookies.lh_first) - np->n_cookies.lh_first->ndm_eocookie = 0; -} - -/* - * The write verifier has changed (probably due to a server reboot), so all - * B_NEEDCOMMIT blocks will have to be written again. Since they are on the - * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT - * and B_CLUSTEROK flags. Once done the new write verifier can be set for the - * mount point. - * - * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data - * writes are not clusterable. - */ -void -nfs_clearcommit(mp) - struct mount *mp; -{ - register struct vnode *vp, *nvp; - register struct buf *bp, *nbp; - int s; - - GIANT_REQUIRED; - - s = splbio(); - mtx_lock(&mntvnode_mtx); -loop: - for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) { - if (vp->v_mount != mp) /* Paranoia */ - goto loop; - nvp = LIST_NEXT(vp, v_mntvnodes); - for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { - nbp = TAILQ_NEXT(bp, b_vnbufs); - if (BUF_REFCNT(bp) == 0 && - (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) - == (B_DELWRI | B_NEEDCOMMIT)) - bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); - } - } - mtx_unlock(&mntvnode_mtx); - splx(s); -} - -#ifndef NFS_NOSERVER -/* - * Map errnos to NFS error numbers. For Version 3 also filter out error - * numbers not specified for the associated procedure. - */ -int -nfsrv_errmap(nd, err) - struct nfsrv_descript *nd; - register int err; -{ - register short *defaulterrp, *errp; - - if (nd->nd_flag & ND_NFSV3) { - if (nd->nd_procnum <= NFSPROC_COMMIT) { - errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; - while (*++errp) { - if (*errp == err) - return (err); - else if (*errp > err) - break; - } - return ((int)*defaulterrp); - } else - return (err & 0xffff); - } - if (err <= ELAST) - return ((int)nfsrv_v2errmap[err - 1]); - return (NFSERR_IO); -} - -int -nfsrv_object_create(vp) - struct vnode *vp; -{ - - if (vp == NULL || vp->v_type != VREG) - return (1); - return (vfs_object_create(vp, curthread, - curthread ? curthread->td_proc->p_ucred : NULL)); -} - -/* - * Sort the group list in increasing numerical order. - * (Insertion sort by Chris Torek, who was grossed out by the bubble sort - * that used to be here.) - */ -void -nfsrvw_sort(list, num) - register gid_t *list; - register int num; -{ - register int i, j; - gid_t v; - - /* Insertion sort. */ - for (i = 1; i < num; i++) { - v = list[i]; - /* find correct slot for value v, moving others up */ - for (j = i; --j >= 0 && v < list[j];) - list[j + 1] = list[j]; - list[j + 1] = v; - } -} - -/* - * copy credentials making sure that the result can be compared with bcmp(). - */ -void -nfsrv_setcred(incred, outcred) - register struct ucred *incred, *outcred; -{ - register int i; - - bzero((caddr_t)outcred, sizeof (struct ucred)); - outcred->cr_ref = 1; - outcred->cr_uid = incred->cr_uid; - outcred->cr_ngroups = incred->cr_ngroups; - for (i = 0; i < incred->cr_ngroups; i++) - outcred->cr_groups[i] = incred->cr_groups[i]; - nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); -} -#endif /* NFS_NOSERVER */ diff --git a/sys/nfs/nfs_syscalls.c b/sys/nfs/nfs_syscalls.c deleted file mode 100644 index 657f299..0000000 --- a/sys/nfs/nfs_syscalls.c +++ /dev/null @@ -1,1214 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 - * $FreeBSD$ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static MALLOC_DEFINE(M_NFSSVC, "NFS srvsock", "Nfs server structure"); - -/* Global defs. */ -extern int32_t (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *nd, - struct nfssvc_sock *slp, - struct thread *td, - struct mbuf **mreqp)); -extern int nfs_numasync; -extern time_t nqnfsstarttime; -extern int nqsrv_writeslack; -extern int nfsrtton; -extern struct nfsstats nfsstats; -extern int nfsrvw_procrastinate; -extern int nfsrvw_procrastinate_v3; -static int nuidhash_max = NFS_MAXUIDHASH; - -#ifndef NFS_NOSERVER -static void nfsrv_zapsock __P((struct nfssvc_sock *slp)); -#endif -static int nfssvc_iod __P((struct thread *)); - -#define TRUE 1 -#define FALSE 0 - -static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; - -SYSCTL_DECL(_vfs_nfs); - -#ifndef NFS_NOSERVER -int nfsd_waiting = 0; -static struct nfsdrt nfsdrt; -static int nfs_numnfsd = 0; -static int notstarted = 1; -static int modify_flag = 0; -static void nfsd_rt __P((int sotype, struct nfsrv_descript *nd, - int cacherep)); -static int nfssvc_addsock __P((struct file *, struct sockaddr *, - struct thread *)); -static int nfssvc_nfsd __P((struct nfsd_srvargs *,caddr_t, - struct thread *)); - -static int nfs_privport = 0; -SYSCTL_INT(_vfs_nfs, NFS_NFSPRIVPORT, nfs_privport, CTLFLAG_RW, &nfs_privport, 0, ""); -SYSCTL_INT(_vfs_nfs, OID_AUTO, gatherdelay, CTLFLAG_RW, &nfsrvw_procrastinate, 0, ""); -SYSCTL_INT(_vfs_nfs, OID_AUTO, gatherdelay_v3, CTLFLAG_RW, &nfsrvw_procrastinate_v3, 0, ""); - -/* - * NFS server system calls - */ - -#endif /* NFS_NOSERVER */ -/* - * Nfs server psuedo system call for the nfsd's - * Based on the flag value it either: - * - adds a socket to the selection list - * - remains in the kernel as an nfsd - * - remains in the kernel as an nfsiod - */ -#ifndef _SYS_SYSPROTO_H_ -struct nfssvc_args { - int flag; - caddr_t argp; -}; -#endif -/* - * MPSAFE - */ -int -nfssvc(td, uap) - struct thread *td; - register struct nfssvc_args *uap; -{ -#ifndef NFS_NOSERVER - struct nameidata nd; - struct file *fp; - struct sockaddr *nam; - struct nfsd_args nfsdarg; - struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs; - struct nfsd_cargs ncd; - struct nfsd *nfsd; - struct nfssvc_sock *slp; - struct nfsuid *nuidp; - struct nfsmount *nmp; -#endif /* NFS_NOSERVER */ - int error; - - mtx_lock(&Giant); - - if ((uap->flag & NFSSVC_LOCKDANS) != 0) { - struct lockd_ans la; - - error = copyin(uap->argp, &la, sizeof(la)); - if (error == 0) - error = nfslockdans(td->td_proc, &la); - goto done2; - } - /* - * Must be super user - */ - error = suser_td(td); - if (error) - goto done2; - while (nfssvc_sockhead_flag & SLP_INIT) { - nfssvc_sockhead_flag |= SLP_WANTINIT; - (void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0); - } - if (uap->flag & NFSSVC_BIOD) - error = nfssvc_iod(td); -#ifdef NFS_NOSERVER - else - error = ENXIO; -#else /* !NFS_NOSERVER */ - else if (uap->flag & NFSSVC_MNTD) { - error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)); - if (error) - goto done2; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, - ncd.ncd_dirp, td); - error = namei(&nd); - if (error) - goto done2; - NDFREE(&nd, NDF_ONLY_PNBUF); - if ((nd.ni_vp->v_flag & VROOT) == 0) - error = EINVAL; - nmp = VFSTONFS(nd.ni_vp->v_mount); - vput(nd.ni_vp); - if (error) - goto done2; - if ((nmp->nm_state & NFSSTA_MNTD) && - (uap->flag & NFSSVC_GOTAUTH) == 0) { - error = 0; - goto done2; - } - nmp->nm_state |= NFSSTA_MNTD; - error = nqnfs_clientd(nmp, td->td_proc->p_ucred, &ncd, uap->flag, - uap->argp, td); - } else if (uap->flag & NFSSVC_ADDSOCK) { - error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg)); - if (error) - goto done2; - error = holdsock(td->td_proc->p_fd, nfsdarg.sock, &fp); - if (error) - goto done2; - /* - * Get the client address for connected sockets. - */ - if (nfsdarg.name == NULL || nfsdarg.namelen == 0) - nam = (struct sockaddr *)0; - else { - error = getsockaddr(&nam, nfsdarg.name, - nfsdarg.namelen); - if (error) { - fdrop(fp, td); - goto done2; - } - } - error = nfssvc_addsock(fp, nam, td); - fdrop(fp, td); - } else { - error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd)); - if (error) - goto done2; - if ((uap->flag & NFSSVC_AUTHIN) && - ((nfsd = nsd->nsd_nfsd)) != NULL && - (nfsd->nfsd_slp->ns_flag & SLP_VALID)) { - slp = nfsd->nfsd_slp; - - /* - * First check to see if another nfsd has already - * added this credential. - */ - for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first; - nuidp != 0; nuidp = nuidp->nu_hash.le_next) { - if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid && - (!nfsd->nfsd_nd->nd_nam2 || - netaddr_match(NU_NETFAM(nuidp), - &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2))) - break; - } - if (nuidp) { - nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr); - nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; - } else { - /* - * Nope, so we will. - */ - if (slp->ns_numuids < nuidhash_max) { - slp->ns_numuids++; - nuidp = (struct nfsuid *) - malloc(sizeof (struct nfsuid), M_NFSUID, - M_WAITOK); - } else - nuidp = (struct nfsuid *)0; - if ((slp->ns_flag & SLP_VALID) == 0) { - if (nuidp) - free((caddr_t)nuidp, M_NFSUID); - } else { - if (nuidp == (struct nfsuid *)0) { - nuidp = slp->ns_uidlruhead.tqh_first; - LIST_REMOVE(nuidp, nu_hash); - TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, - nu_lru); - if (nuidp->nu_flag & NU_NAM) - FREE(nuidp->nu_nam, M_SONAME); - } - nuidp->nu_flag = 0; - bzero(&nuidp->nu_cr, sizeof(nuidp->nu_cr)); - nuidp->nu_cr.cr_uid = nsd->nsd_cr.cr_uid; - nuidp->nu_cr.cr_ngroups = - nsd->nsd_cr.cr_ngroups; - bcopy(nsd->nsd_cr.cr_groups, - nuidp->nu_cr.cr_groups, - sizeof(nuidp->nu_cr.cr_groups)); - if (nuidp->nu_cr.cr_ngroups > NGROUPS) - nuidp->nu_cr.cr_ngroups = NGROUPS; - nuidp->nu_cr.cr_ref = 1; - nuidp->nu_timestamp = nsd->nsd_timestamp; - nuidp->nu_expire = time_second + nsd->nsd_ttl; - /* - * and save the session key in nu_key. - */ - bcopy(nsd->nsd_key, nuidp->nu_key, - sizeof (nsd->nsd_key)); - if (nfsd->nfsd_nd->nd_nam2) { - struct sockaddr_in *saddr; - - saddr = (struct sockaddr_in *) - nfsd->nfsd_nd->nd_nam2; - switch (saddr->sin_family) { - case AF_INET: - nuidp->nu_flag |= NU_INETADDR; - nuidp->nu_inetaddr = - saddr->sin_addr.s_addr; - break; - case AF_ISO: - default: - nuidp->nu_flag |= NU_NAM; - nuidp->nu_nam = - dup_sockaddr(nfsd->nfsd_nd-> - nd_nam2, 1); - break; - }; - } - TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp, - nu_lru); - LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid), - nuidp, nu_hash); - nfsrv_setcred(&nuidp->nu_cr, - &nfsd->nfsd_nd->nd_cr); - nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; - } - } - } - if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd)) - nfsd->nfsd_flag |= NFSD_AUTHFAIL; - error = nfssvc_nfsd(nsd, uap->argp, td); - } -#endif /* NFS_NOSERVER */ - if (error == EINTR || error == ERESTART) - error = 0; -done2: - mtx_unlock(&Giant); - return (error); -} - -#ifndef NFS_NOSERVER -/* - * Adds a socket to the list for servicing by nfsds. - */ -static int -nfssvc_addsock(fp, mynam, td) - struct file *fp; - struct sockaddr *mynam; - struct thread *td; -{ - register int siz; - register struct nfssvc_sock *slp; - register struct socket *so; - int error, s; - - so = (struct socket *)fp->f_data; -#if 0 - tslp = (struct nfssvc_sock *)0; - /* - * Add it to the list, as required. - */ - if (so->so_proto->pr_protocol == IPPROTO_UDP) { - tslp = nfs_udpsock; - if (tslp->ns_flag & SLP_VALID) { - if (mynam != NULL) - FREE(mynam, M_SONAME); - return (EPERM); - } - } -#endif - if (so->so_type == SOCK_STREAM) - siz = NFS_MAXPACKET + sizeof (u_long); - else - siz = NFS_MAXPACKET; - error = soreserve(so, siz, siz); - if (error) { - if (mynam != NULL) - FREE(mynam, M_SONAME); - return (error); - } - - /* - * Set protocol specific options { for now TCP only } and - * reserve some space. For datagram sockets, this can get called - * repeatedly for the same socket, but that isn't harmful. - */ - if (so->so_type == SOCK_STREAM) { - struct sockopt sopt; - int val; - - bzero(&sopt, sizeof sopt); - sopt.sopt_level = SOL_SOCKET; - sopt.sopt_name = SO_KEEPALIVE; - sopt.sopt_val = &val; - sopt.sopt_valsize = sizeof val; - val = 1; - sosetopt(so, &sopt); - } - if (so->so_proto->pr_domain->dom_family == AF_INET && - so->so_proto->pr_protocol == IPPROTO_TCP) { - struct sockopt sopt; - int val; - - bzero(&sopt, sizeof sopt); - sopt.sopt_level = IPPROTO_TCP; - sopt.sopt_name = TCP_NODELAY; - sopt.sopt_val = &val; - sopt.sopt_valsize = sizeof val; - val = 1; - sosetopt(so, &sopt); - } - so->so_rcv.sb_flags &= ~SB_NOINTR; - so->so_rcv.sb_timeo = 0; - so->so_snd.sb_flags &= ~SB_NOINTR; - so->so_snd.sb_timeo = 0; - - slp = (struct nfssvc_sock *) - malloc(sizeof (struct nfssvc_sock), M_NFSSVC, - M_WAITOK | M_ZERO); - STAILQ_INIT(&slp->ns_rec); - TAILQ_INIT(&slp->ns_uidlruhead); - TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); - - slp->ns_so = so; - slp->ns_nam = mynam; - fp->f_count++; - slp->ns_fp = fp; - s = splnet(); - so->so_upcallarg = (caddr_t)slp; - so->so_upcall = nfsrv_rcv; - so->so_rcv.sb_flags |= SB_UPCALL; - slp->ns_flag = (SLP_VALID | SLP_NEEDQ); - nfsrv_wakenfsd(slp); - splx(s); - return (0); -} - -/* - * Called by nfssvc() for nfsds. Just loops around servicing rpc requests - * until it is killed by a signal. - */ -static int -nfssvc_nfsd(nsd, argp, td) - struct nfsd_srvargs *nsd; - caddr_t argp; - struct thread *td; -{ - register int siz; - register struct nfssvc_sock *slp; - struct nfsd *nfsd = nsd->nsd_nfsd; - struct nfsrv_descript *nd = NULL; - struct mbuf *m, *mreq; - int error = 0, cacherep, s, sotype, writes_todo; - int procrastinate; - u_quad_t cur_usec; - -#ifndef nolint - cacherep = RC_DOIT; - writes_todo = 0; -#endif - if (nfsd == (struct nfsd *)0) { - nsd->nsd_nfsd = nfsd = (struct nfsd *) - malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK | M_ZERO); - s = splnet(); - nfsd->nfsd_td = td; - TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain); - nfs_numnfsd++; - } else - s = splnet(); - - /* - * Loop getting rpc requests until SIGKILL. - */ - for (;;) { - if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) { - while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && - (nfsd_head_flag & NFSD_CHECKSLP) == 0) { - nfsd->nfsd_flag |= NFSD_WAITING; - nfsd_waiting++; - error = tsleep((caddr_t)nfsd, PSOCK | PCATCH, - "nfsd", 0); - nfsd_waiting--; - if (error) - goto done; - } - if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 && - (nfsd_head_flag & NFSD_CHECKSLP) != 0) { - for (slp = nfssvc_sockhead.tqh_first; slp != 0; - slp = slp->ns_chain.tqe_next) { - if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) - == (SLP_VALID | SLP_DOREC)) { - slp->ns_flag &= ~SLP_DOREC; - slp->ns_sref++; - nfsd->nfsd_slp = slp; - break; - } - } - if (slp == 0) - nfsd_head_flag &= ~NFSD_CHECKSLP; - } - if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0) - continue; - if (slp->ns_flag & SLP_VALID) { - if (slp->ns_flag & SLP_DISCONN) - nfsrv_zapsock(slp); - else if (slp->ns_flag & SLP_NEEDQ) { - slp->ns_flag &= ~SLP_NEEDQ; - (void) nfs_slplock(slp, 1); - nfsrv_rcv(slp->ns_so, (caddr_t)slp, - M_TRYWAIT); - nfs_slpunlock(slp); - } - error = nfsrv_dorec(slp, nfsd, &nd); - cur_usec = nfs_curusec(); - if (error && slp->ns_tq.lh_first && - slp->ns_tq.lh_first->nd_time <= cur_usec) { - error = 0; - cacherep = RC_DOIT; - writes_todo = 1; - } else - writes_todo = 0; - nfsd->nfsd_flag |= NFSD_REQINPROG; - } - } else { - error = 0; - slp = nfsd->nfsd_slp; - } - if (error || (slp->ns_flag & SLP_VALID) == 0) { - if (nd) { - free((caddr_t)nd, M_NFSRVDESC); - nd = NULL; - } - nfsd->nfsd_slp = (struct nfssvc_sock *)0; - nfsd->nfsd_flag &= ~NFSD_REQINPROG; - nfsrv_slpderef(slp); - continue; - } - splx(s); - sotype = slp->ns_so->so_type; - if (nd) { - getmicrotime(&nd->nd_starttime); - if (nd->nd_nam2) - nd->nd_nam = nd->nd_nam2; - else - nd->nd_nam = slp->ns_nam; - - /* - * Check to see if authorization is needed. - */ - if (nfsd->nfsd_flag & NFSD_NEEDAUTH) { - nfsd->nfsd_flag &= ~NFSD_NEEDAUTH; - nsd->nsd_haddr = - ((struct sockaddr_in *) - nd->nd_nam)->sin_addr.s_addr; - nsd->nsd_authlen = nfsd->nfsd_authlen; - nsd->nsd_verflen = nfsd->nfsd_verflen; - if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr, - nfsd->nfsd_authlen) && - !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr, - nfsd->nfsd_verflen) && - !copyout((caddr_t)nsd, argp, sizeof (*nsd))) - return (ENEEDAUTH); - cacherep = RC_DROPIT; - } else - cacherep = nfsrv_getcache(nd, slp, &mreq); - - /* - * Check for just starting up for NQNFS and send - * fake "try again later" replies to the NQNFS clients. - */ - if (notstarted && nqnfsstarttime <= time_second) { - if (modify_flag) { - nqnfsstarttime = time_second + nqsrv_writeslack; - modify_flag = 0; - } else - notstarted = 0; - } - if (notstarted) { - if ((nd->nd_flag & ND_NQNFS) == 0) - cacherep = RC_DROPIT; - else if (nd->nd_procnum != NFSPROC_WRITE) { - nd->nd_procnum = NFSPROC_NOOP; - nd->nd_repstat = NQNFS_TRYLATER; - cacherep = RC_DOIT; - } else - modify_flag = 1; - } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) { - nfsd->nfsd_flag &= ~NFSD_AUTHFAIL; - nd->nd_procnum = NFSPROC_NOOP; - nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); - cacherep = RC_DOIT; - } else if (nfs_privport) { - /* Check if source port is privileged */ - u_short port; - struct sockaddr *nam = nd->nd_nam; - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *)nam; - port = ntohs(sin->sin_port); - if (port >= IPPORT_RESERVED && - nd->nd_procnum != NFSPROC_NULL) { - nd->nd_procnum = NFSPROC_NOOP; - nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); - cacherep = RC_DOIT; - printf("NFS request from unprivileged port (%s:%d)\n", - inet_ntoa(sin->sin_addr), port); - } - } - - } - - /* - * Loop to get all the write rpc relies that have been - * gathered together. - */ - do { - switch (cacherep) { - case RC_DOIT: - if (nd && (nd->nd_flag & ND_NFSV3)) - procrastinate = nfsrvw_procrastinate_v3; - else - procrastinate = nfsrvw_procrastinate; - if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE && - procrastinate > 0 && !notstarted)) - error = nfsrv_writegather(&nd, slp, - nfsd->nfsd_td, &mreq); - else - error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, - slp, nfsd->nfsd_td, &mreq); - if (mreq == NULL) - break; - if (error != 0 && error != NFSERR_RETVOID) { - if (nd->nd_procnum != NQNFSPROC_VACATED) - nfsstats.srv_errs++; - nfsrv_updatecache(nd, FALSE, mreq); - if (nd->nd_nam2) - FREE(nd->nd_nam2, M_SONAME); - break; - } - nfsstats.srvrpccnt[nd->nd_procnum]++; - nfsrv_updatecache(nd, TRUE, mreq); - nd->nd_mrep = (struct mbuf *)0; - case RC_REPLY: - m = mreq; - siz = 0; - while (m) { - siz += m->m_len; - m = m->m_next; - } - if (siz <= 0 || siz > NFS_MAXPACKET) { - printf("mbuf siz=%d\n",siz); - panic("Bad nfs svc reply"); - } - m = mreq; - m->m_pkthdr.len = siz; - m->m_pkthdr.rcvif = (struct ifnet *)0; - /* - * For stream protocols, prepend a Sun RPC - * Record Mark. - */ - if (sotype == SOCK_STREAM) { - M_PREPEND(m, NFSX_UNSIGNED, M_TRYWAIT); - *mtod(m, u_int32_t *) = htonl(0x80000000 | siz); - } - if (slp->ns_so->so_proto->pr_flags & PR_CONNREQUIRED) - (void) nfs_slplock(slp, 1); - if (slp->ns_flag & SLP_VALID) - error = nfs_send(slp->ns_so, nd->nd_nam2, m, NULL); - else { - error = EPIPE; - m_freem(m); - } - if (nfsrtton) - nfsd_rt(sotype, nd, cacherep); - if (nd->nd_nam2) - FREE(nd->nd_nam2, M_SONAME); - if (nd->nd_mrep) - m_freem(nd->nd_mrep); - if (error == EPIPE) - nfsrv_zapsock(slp); - if (slp->ns_so->so_proto->pr_flags & PR_CONNREQUIRED) - nfs_slpunlock(slp); - if (error == EINTR || error == ERESTART) { - free((caddr_t)nd, M_NFSRVDESC); - nfsrv_slpderef(slp); - s = splnet(); - goto done; - } - break; - case RC_DROPIT: - if (nfsrtton) - nfsd_rt(sotype, nd, cacherep); - m_freem(nd->nd_mrep); - if (nd->nd_nam2) - FREE(nd->nd_nam2, M_SONAME); - break; - }; - if (nd) { - FREE((caddr_t)nd, M_NFSRVDESC); - nd = NULL; - } - - /* - * Check to see if there are outstanding writes that - * need to be serviced. - */ - cur_usec = nfs_curusec(); - s = splsoftclock(); - if (slp->ns_tq.lh_first && - slp->ns_tq.lh_first->nd_time <= cur_usec) { - cacherep = RC_DOIT; - writes_todo = 1; - } else - writes_todo = 0; - splx(s); - } while (writes_todo); - s = splnet(); - if (nfsrv_dorec(slp, nfsd, &nd)) { - nfsd->nfsd_flag &= ~NFSD_REQINPROG; - nfsd->nfsd_slp = NULL; - nfsrv_slpderef(slp); - } - } -done: - TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain); - splx(s); - free((caddr_t)nfsd, M_NFSD); - nsd->nsd_nfsd = (struct nfsd *)0; - if (--nfs_numnfsd == 0) - nfsrv_init(TRUE); /* Reinitialize everything */ - return (error); -} - -/* - * Shut down a socket associated with an nfssvc_sock structure. - * Should be called with the send lock set, if required. - * The trick here is to increment the sref at the start, so that the nfsds - * will stop using it and clear ns_flag at the end so that it will not be - * reassigned during cleanup. - */ -static void -nfsrv_zapsock(slp) - register struct nfssvc_sock *slp; -{ - register struct nfsuid *nuidp, *nnuidp; - register struct nfsrv_descript *nwp, *nnwp; - struct socket *so; - struct file *fp; - struct nfsrv_rec *rec; - int s; - - slp->ns_flag &= ~SLP_ALLFLAGS; - fp = slp->ns_fp; - if (fp) { - slp->ns_fp = (struct file *)0; - so = slp->ns_so; - so->so_rcv.sb_flags &= ~SB_UPCALL; - so->so_upcall = NULL; - so->so_upcallarg = NULL; - soshutdown(so, 2); - closef(fp, (struct thread *)0); - if (slp->ns_nam) - FREE(slp->ns_nam, M_SONAME); - m_freem(slp->ns_raw); - while ((rec = STAILQ_FIRST(&slp->ns_rec)) != NULL) { - STAILQ_REMOVE_HEAD(&slp->ns_rec, nr_link); - if (rec->nr_address) - FREE(rec->nr_address, M_SONAME); - m_freem(rec->nr_packet); - free(rec, M_NFSRVDESC); - } - for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0; - nuidp = nnuidp) { - nnuidp = nuidp->nu_lru.tqe_next; - LIST_REMOVE(nuidp, nu_hash); - TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru); - if (nuidp->nu_flag & NU_NAM) - FREE(nuidp->nu_nam, M_SONAME); - free((caddr_t)nuidp, M_NFSUID); - } - s = splsoftclock(); - for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) { - nnwp = nwp->nd_tq.le_next; - LIST_REMOVE(nwp, nd_tq); - free((caddr_t)nwp, M_NFSRVDESC); - } - LIST_INIT(&slp->ns_tq); - splx(s); - } -} - -/* - * Derefence a server socket structure. If it has no more references and - * is no longer valid, you can throw it away. - */ -void -nfsrv_slpderef(slp) - register struct nfssvc_sock *slp; -{ - if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) { - TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); - free((caddr_t)slp, M_NFSSVC); - } -} - -/* - * Lock a socket against others. - */ -int -nfs_slplock(slp, wait) - register struct nfssvc_sock *slp; - int wait; -{ - int *statep = &slp->ns_solock; - - if (!wait && (*statep & NFSSTA_SNDLOCK)) - return(0); /* already locked, fail */ - while (*statep & NFSSTA_SNDLOCK) { - *statep |= NFSSTA_WANTSND; - (void) tsleep((caddr_t)statep, PZERO - 1, "nfsslplck", 0); - } - *statep |= NFSSTA_SNDLOCK; - return (1); -} - -/* - * Unlock the stream socket for others. - */ -void -nfs_slpunlock(slp) - register struct nfssvc_sock *slp; -{ - int *statep = &slp->ns_solock; - - if ((*statep & NFSSTA_SNDLOCK) == 0) - panic("nfs slpunlock"); - *statep &= ~NFSSTA_SNDLOCK; - if (*statep & NFSSTA_WANTSND) { - *statep &= ~NFSSTA_WANTSND; - wakeup((caddr_t)statep); - } -} - -/* - * Initialize the data structures for the server. - * Handshake with any new nfsds starting up to avoid any chance of - * corruption. - */ -void -nfsrv_init(terminating) - int terminating; -{ - register struct nfssvc_sock *slp, *nslp; - - if (nfssvc_sockhead_flag & SLP_INIT) - panic("nfsd init"); - nfssvc_sockhead_flag |= SLP_INIT; - if (terminating) { - for (slp = nfssvc_sockhead.tqh_first; slp != 0; slp = nslp) { - nslp = slp->ns_chain.tqe_next; - if (slp->ns_flag & SLP_VALID) - nfsrv_zapsock(slp); - TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); - free((caddr_t)slp, M_NFSSVC); - } - nfsrv_cleancache(); /* And clear out server cache */ - } else - nfs_pub.np_valid = 0; - - TAILQ_INIT(&nfssvc_sockhead); - nfssvc_sockhead_flag &= ~SLP_INIT; - if (nfssvc_sockhead_flag & SLP_WANTINIT) { - nfssvc_sockhead_flag &= ~SLP_WANTINIT; - wakeup((caddr_t)&nfssvc_sockhead); - } - - TAILQ_INIT(&nfsd_head); - nfsd_head_flag &= ~NFSD_CHECKSLP; - -#if 0 - nfs_udpsock = (struct nfssvc_sock *) - malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK | M_ZERO); - STAILQ_INIT(&nfs_udpsock->ns_rec); - TAILQ_INIT(&nfs_udpsock->ns_uidlruhead); - TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain); - - nfs_cltpsock = (struct nfssvc_sock *) - malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK | M_ZERO); - STAILQ_INIT(&nfs_cltpsock->ns_rec); - TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead); - TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain); -#endif -} - -/* - * Add entries to the server monitor log. - */ -static void -nfsd_rt(sotype, nd, cacherep) - int sotype; - register struct nfsrv_descript *nd; - int cacherep; -{ - register struct drt *rt; - - rt = &nfsdrt.drt[nfsdrt.pos]; - if (cacherep == RC_DOIT) - rt->flag = 0; - else if (cacherep == RC_REPLY) - rt->flag = DRT_CACHEREPLY; - else - rt->flag = DRT_CACHEDROP; - if (sotype == SOCK_STREAM) - rt->flag |= DRT_TCP; - if (nd->nd_flag & ND_NQNFS) - rt->flag |= DRT_NQNFS; - else if (nd->nd_flag & ND_NFSV3) - rt->flag |= DRT_NFSV3; - rt->proc = nd->nd_procnum; - if (nd->nd_nam->sa_family == AF_INET) - rt->ipadr = ((struct sockaddr_in *)nd->nd_nam)->sin_addr.s_addr; - else - rt->ipadr = INADDR_ANY; - rt->resptime = nfs_curusec() - (nd->nd_starttime.tv_sec * 1000000 + nd->nd_starttime.tv_usec); - getmicrotime(&rt->tstamp); - nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ; -} -#endif /* NFS_NOSERVER */ - -static int nfs_defect = 0; -SYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, ""); - -/* - * Asynchronous I/O daemons for client nfs. - * They do read-ahead and write-behind operations on the block I/O cache. - * Never returns unless it fails or gets killed. - */ -static int -nfssvc_iod(td) - struct thread *td; -{ - register struct buf *bp; - register int i, myiod; - struct nfsmount *nmp; - int error = 0; - - /* - * Assign my position or return error if too many already running - */ - myiod = -1; - for (i = 0; i < NFS_MAXASYNCDAEMON; i++) - if (nfs_asyncdaemon[i] == 0) { - nfs_asyncdaemon[i]++; - myiod = i; - break; - } - if (myiod == -1) - return (EBUSY); - nfs_numasync++; - /* - * Just loop around doin our stuff until SIGKILL - */ - for (;;) { - while (((nmp = nfs_iodmount[myiod]) == NULL - || nmp->nm_bufq.tqh_first == NULL) - && error == 0) { - if (nmp) - nmp->nm_bufqiods--; - nfs_iodwant[myiod] = td->td_proc; - nfs_iodmount[myiod] = NULL; - error = tsleep((caddr_t)&nfs_iodwant[myiod], - PWAIT | PCATCH, "nfsidl", 0); - } - if (error) { - nfs_asyncdaemon[myiod] = 0; - if (nmp) - nmp->nm_bufqiods--; - nfs_iodwant[myiod] = NULL; - nfs_iodmount[myiod] = NULL; - nfs_numasync--; - return (error); - } - while ((bp = nmp->nm_bufq.tqh_first) != NULL) { - /* Take one off the front of the list */ - TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist); - nmp->nm_bufqlen--; - if (nmp->nm_bufqwant && nmp->nm_bufqlen <= nfs_numasync) { - nmp->nm_bufqwant = FALSE; - wakeup(&nmp->nm_bufq); - } - if (bp->b_iocmd == BIO_READ) - (void) nfs_doio(bp, bp->b_rcred, (struct thread *)0); - else - (void) nfs_doio(bp, bp->b_wcred, (struct thread *)0); - /* - * If there are more than one iod on this mount, then defect - * so that the iods can be shared out fairly between the mounts - */ - if (nfs_defect && nmp->nm_bufqiods > 1) { - NFS_DPF(ASYNCIO, - ("nfssvc_iod: iod %d defecting from mount %p\n", - myiod, nmp)); - nfs_iodmount[myiod] = NULL; - nmp->nm_bufqiods--; - break; - } - } - } -} - - -/* - * Get an authorization string for the uid by having the mount_nfs sitting - * on this mount point porpous out of the kernel and do it. - */ -int -nfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key) - register struct nfsmount *nmp; - struct nfsreq *rep; - struct ucred *cred; - char **auth_str; - int *auth_len; - char *verf_str; - int *verf_len; - NFSKERBKEY_T key; /* return session key */ -{ - int error = 0; - - while ((nmp->nm_state & NFSSTA_WAITAUTH) == 0) { - nmp->nm_state |= NFSSTA_WANTAUTH; - (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK, - "nfsauth1", 2 * hz); - error = nfs_sigintr(nmp, rep, rep->r_td->td_proc); - if (error) { - nmp->nm_state &= ~NFSSTA_WANTAUTH; - return (error); - } - } - nmp->nm_state &= ~(NFSSTA_WAITAUTH | NFSSTA_WANTAUTH); - nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK); - nmp->nm_authlen = RPCAUTH_MAXSIZ; - nmp->nm_verfstr = verf_str; - nmp->nm_verflen = *verf_len; - nmp->nm_authuid = cred->cr_uid; - wakeup((caddr_t)&nmp->nm_authstr); - - /* - * And wait for mount_nfs to do its stuff. - */ - while ((nmp->nm_state & NFSSTA_HASAUTH) == 0 && error == 0) { - (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK, - "nfsauth2", 2 * hz); - error = nfs_sigintr(nmp, rep, rep->r_td->td_proc); - } - if (nmp->nm_state & NFSSTA_AUTHERR) { - nmp->nm_state &= ~NFSSTA_AUTHERR; - error = EAUTH; - } - if (error) - free((caddr_t)*auth_str, M_TEMP); - else { - *auth_len = nmp->nm_authlen; - *verf_len = nmp->nm_verflen; - bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key)); - } - nmp->nm_state &= ~NFSSTA_HASAUTH; - nmp->nm_state |= NFSSTA_WAITAUTH; - if (nmp->nm_state & NFSSTA_WANTAUTH) { - nmp->nm_state &= ~NFSSTA_WANTAUTH; - wakeup((caddr_t)&nmp->nm_authtype); - } - return (error); -} - -/* - * Get a nickname authenticator and verifier. - */ -int -nfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len) - struct nfsmount *nmp; - struct ucred *cred; - char **auth_str; - int *auth_len; - char *verf_str; - int verf_len; -{ - register struct nfsuid *nuidp; - register u_int32_t *nickp, *verfp; - struct timeval ktvin, ktvout; - -#ifdef DIAGNOSTIC - if (verf_len < (4 * NFSX_UNSIGNED)) - panic("nfs_getnickauth verf too small"); -#endif - for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first; - nuidp != 0; nuidp = nuidp->nu_hash.le_next) { - if (nuidp->nu_cr.cr_uid == cred->cr_uid) - break; - } - if (!nuidp || nuidp->nu_expire < time_second) - return (EACCES); - - /* - * Move to the end of the lru list (end of lru == most recently used). - */ - TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); - TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru); - - nickp = (u_int32_t *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK); - *nickp++ = txdr_unsigned(RPCAKN_NICKNAME); - *nickp = txdr_unsigned(nuidp->nu_nickname); - *auth_str = (char *)nickp; - *auth_len = 2 * NFSX_UNSIGNED; - - /* - * Now we must encrypt the verifier and package it up. - */ - verfp = (u_int32_t *)verf_str; - *verfp++ = txdr_unsigned(RPCAKN_NICKNAME); - if (time_second > nuidp->nu_timestamp.tv_sec || - (time_second == nuidp->nu_timestamp.tv_sec && - time_second > nuidp->nu_timestamp.tv_usec)) - getmicrotime(&nuidp->nu_timestamp); - else - nuidp->nu_timestamp.tv_usec++; - ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec); - ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec); - - /* - * Now encrypt the timestamp verifier in ecb mode using the session - * key. - */ -#ifdef NFSKERB - XXX -#endif - - *verfp++ = ktvout.tv_sec; - *verfp++ = ktvout.tv_usec; - *verfp = 0; - return (0); -} - -/* - * Save the current nickname in a hash list entry on the mount point. - */ -int -nfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep) - register struct nfsmount *nmp; - struct ucred *cred; - int len; - NFSKERBKEY_T key; - struct mbuf **mdp; - char **dposp; - struct mbuf *mrep; -{ - register struct nfsuid *nuidp; - register u_int32_t *tl; - register int32_t t1; - struct mbuf *md = *mdp; - struct timeval ktvin, ktvout; - u_int32_t nick; - char *dpos = *dposp, *cp2; - int deltasec, error = 0; - - if (len == (3 * NFSX_UNSIGNED)) { - nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); - ktvin.tv_sec = *tl++; - ktvin.tv_usec = *tl++; - nick = fxdr_unsigned(u_int32_t, *tl); - - /* - * Decrypt the timestamp in ecb mode. - */ -#ifdef NFSKERB - XXX -#endif - ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec); - ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec); - deltasec = time_second - ktvout.tv_sec; - if (deltasec < 0) - deltasec = -deltasec; - /* - * If ok, add it to the hash list for the mount point. - */ - if (deltasec <= NFS_KERBCLOCKSKEW) { - if (nmp->nm_numuids < nuidhash_max) { - nmp->nm_numuids++; - nuidp = (struct nfsuid *) - malloc(sizeof (struct nfsuid), M_NFSUID, - M_WAITOK); - } else { - nuidp = nmp->nm_uidlruhead.tqh_first; - LIST_REMOVE(nuidp, nu_hash); - TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, - nu_lru); - } - nuidp->nu_flag = 0; - nuidp->nu_cr.cr_uid = cred->cr_uid; - nuidp->nu_expire = time_second + NFS_KERBTTL; - nuidp->nu_timestamp = ktvout; - nuidp->nu_nickname = nick; - bcopy(key, nuidp->nu_key, sizeof (key)); - TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, - nu_lru); - LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid), - nuidp, nu_hash); - } - } else - nfsm_adv(nfsm_rndup(len)); -nfsmout: - *mdp = md; - *dposp = dpos; - return (error); -} diff --git a/sys/nfs/nfs_vfsops.c b/sys/nfs/nfs_vfsops.c deleted file mode 100644 index c70600f..0000000 --- a/sys/nfs/nfs_vfsops.c +++ /dev/null @@ -1,1075 +0,0 @@ -/* - * Copyright (c) 1989, 1993, 1995 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95 - * $FreeBSD$ - */ - -#include "opt_bootp.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern int nfs_mountroot __P((struct mount *mp)); - -extern int nfs_ticks; - -MALLOC_DEFINE(M_NFSREQ, "NFS req", "NFS request header"); -MALLOC_DEFINE(M_NFSBIGFH, "NFSV3 bigfh", "NFS version 3 file handle"); -MALLOC_DEFINE(M_NFSD, "NFS daemon", "Nfs server daemon structure"); -MALLOC_DEFINE(M_NFSDIROFF, "NFSV3 diroff", "NFS directory offset data"); -MALLOC_DEFINE(M_NFSRVDESC, "NFSV3 srvdesc", "NFS server socket descriptor"); -MALLOC_DEFINE(M_NFSUID, "NFS uid", "Nfs uid mapping structure"); -MALLOC_DEFINE(M_NQLEASE, "NQNFS Lease", "Nqnfs lease"); -MALLOC_DEFINE(M_NFSHASH, "NFS hash", "NFS hash tables"); - -vm_zone_t nfsmount_zone; - -struct nfsstats nfsstats; -SYSCTL_NODE(_vfs, OID_AUTO, nfs, CTLFLAG_RW, 0, "NFS filesystem"); -SYSCTL_STRUCT(_vfs_nfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RD, - &nfsstats, nfsstats, ""); -#ifdef NFS_DEBUG -int nfs_debug; -SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0, ""); -#endif - -static int nfs_iosize __P((struct nfsmount *nmp)); -static void nfs_decode_args __P((struct nfsmount *nmp, - struct nfs_args *argp)); -static int mountnfs __P((struct nfs_args *,struct mount *, - struct sockaddr *,char *,char *,struct vnode **)); -static int nfs_mount __P(( struct mount *mp, char *path, caddr_t data, - struct nameidata *ndp, struct thread *p)); -static int nfs_unmount __P(( struct mount *mp, int mntflags, - struct thread *p)); -static int nfs_root __P(( struct mount *mp, struct vnode **vpp)); -static int nfs_statfs __P(( struct mount *mp, struct statfs *sbp, - struct thread *p)); -static int nfs_sync __P(( struct mount *mp, int waitfor, - struct ucred *cred, struct thread *p)); - -/* - * nfs vfs operations. - */ -static struct vfsops nfs_vfsops = { - nfs_mount, - vfs_stdstart, - nfs_unmount, - nfs_root, - vfs_stdquotactl, - nfs_statfs, - nfs_sync, - vfs_stdvget, - vfs_stdfhtovp, /* shouldn't happen */ - vfs_stdcheckexp, - vfs_stdvptofh, /* shouldn't happen */ - nfs_init, - nfs_uninit, - vfs_stdextattrctl, -}; -VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK); - -/* - * This structure must be filled in by a primary bootstrap or bootstrap - * server for a diskless/dataless machine. It is initialized below just - * to ensure that it is allocated to initialized data (.data not .bss). - */ -struct nfs_diskless nfs_diskless = { { { 0 } } }; -struct nfsv3_diskless nfsv3_diskless = { { { 0 } } }; -int nfs_diskless_valid = 0; - -SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD, - &nfs_diskless_valid, 0, ""); - -SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD, - nfsv3_diskless.root_hostnam, 0, ""); - -SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD, - &nfsv3_diskless.root_saddr, sizeof nfsv3_diskless.root_saddr, - "%Ssockaddr_in", ""); - -SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_swappath, CTLFLAG_RD, - nfsv3_diskless.swap_hostnam, 0, ""); - -SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_swapaddr, CTLFLAG_RD, - &nfsv3_diskless.swap_saddr, sizeof nfsv3_diskless.swap_saddr, - "%Ssockaddr_in",""); - - -void nfsargs_ntoh __P((struct nfs_args *)); -static int nfs_mountdiskless __P((char *, char *, int, - struct sockaddr_in *, struct nfs_args *, - struct thread *, struct vnode **, - struct mount **)); -static void nfs_convert_diskless __P((void)); -static void nfs_convert_oargs __P((struct nfs_args *args, - struct onfs_args *oargs)); - -static int -nfs_iosize(nmp) - struct nfsmount* nmp; -{ - int iosize; - - /* - * Calculate the size used for io buffers. Use the larger - * of the two sizes to minimise nfs requests but make sure - * that it is at least one VM page to avoid wasting buffer - * space. - */ - iosize = max(nmp->nm_rsize, nmp->nm_wsize); - if (iosize < PAGE_SIZE) iosize = PAGE_SIZE; - return iosize; -} - -static void -nfs_convert_oargs(args, oargs) - struct nfs_args *args; - struct onfs_args *oargs; -{ - args->version = NFS_ARGSVERSION; - args->addr = oargs->addr; - args->addrlen = oargs->addrlen; - args->sotype = oargs->sotype; - args->proto = oargs->proto; - args->fh = oargs->fh; - args->fhsize = oargs->fhsize; - args->flags = oargs->flags; - args->wsize = oargs->wsize; - args->rsize = oargs->rsize; - args->readdirsize = oargs->readdirsize; - args->timeo = oargs->timeo; - args->retrans = oargs->retrans; - args->maxgrouplist = oargs->maxgrouplist; - args->readahead = oargs->readahead; - args->leaseterm = oargs->leaseterm; - args->deadthresh = oargs->deadthresh; - args->hostname = oargs->hostname; -} - -static void -nfs_convert_diskless() -{ - bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif, - sizeof(struct ifaliasreq)); - bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway, - sizeof(struct sockaddr_in)); - nfs_convert_oargs(&nfsv3_diskless.swap_args,&nfs_diskless.swap_args); - nfsv3_diskless.swap_fhsize = NFSX_V2FH; - bcopy(nfs_diskless.swap_fh,nfsv3_diskless.swap_fh,NFSX_V2FH); - bcopy(&nfs_diskless.swap_saddr,&nfsv3_diskless.swap_saddr, - sizeof(struct sockaddr_in)); - bcopy(nfs_diskless.swap_hostnam,nfsv3_diskless.swap_hostnam, MNAMELEN); - nfsv3_diskless.swap_nblks = nfs_diskless.swap_nblks; - bcopy(&nfs_diskless.swap_ucred, &nfsv3_diskless.swap_ucred, - sizeof(struct ucred)); - nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args); - nfsv3_diskless.root_fhsize = NFSX_V2FH; - bcopy(nfs_diskless.root_fh,nfsv3_diskless.root_fh,NFSX_V2FH); - bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr, - sizeof(struct sockaddr_in)); - bcopy(nfs_diskless.root_hostnam,nfsv3_diskless.root_hostnam, MNAMELEN); - nfsv3_diskless.root_time = nfs_diskless.root_time; - bcopy(nfs_diskless.my_hostnam,nfsv3_diskless.my_hostnam, - MAXHOSTNAMELEN); - nfs_diskless_valid = 3; -} - -/* - * nfs statfs call - */ -int -nfs_statfs(mp, sbp, td) - struct mount *mp; - register struct statfs *sbp; - struct thread *td; -{ - register struct vnode *vp; - register struct nfs_statfs *sfp; - register caddr_t cp; - register u_int32_t *tl; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; - struct nfsmount *nmp = VFSTONFS(mp); - int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - struct nfsnode *np; - u_quad_t tquad; - -#ifndef nolint - sfp = (struct nfs_statfs *)0; -#endif - error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np); - if (error) - return (error); - vp = NFSTOV(np); - if (v3 && (nmp->nm_state & NFSSTA_GOTFSINFO) == 0) - (void)nfs_fsinfo(nmp, vp, td->td_proc->p_ucred, td); - nfsstats.rpccnt[NFSPROC_FSSTAT]++; - nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3)); - nfsm_fhtom(vp, v3); - nfsm_request(vp, NFSPROC_FSSTAT, td, td->td_proc->p_ucred); - if (v3) - nfsm_postop_attr(vp, retattr); - if (error) { - if (mrep != NULL) - m_freem(mrep); - goto nfsmout; - } - nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3)); - sbp->f_flags = nmp->nm_flag; - sbp->f_iosize = nfs_iosize(nmp); - if (v3) { - sbp->f_bsize = NFS_FABLKSIZE; - tquad = fxdr_hyper(&sfp->sf_tbytes); - sbp->f_blocks = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE)); - tquad = fxdr_hyper(&sfp->sf_fbytes); - sbp->f_bfree = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE)); - tquad = fxdr_hyper(&sfp->sf_abytes); - sbp->f_bavail = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE)); - sbp->f_files = (fxdr_unsigned(int32_t, - sfp->sf_tfiles.nfsuquad[1]) & 0x7fffffff); - sbp->f_ffree = (fxdr_unsigned(int32_t, - sfp->sf_ffiles.nfsuquad[1]) & 0x7fffffff); - } else { - sbp->f_bsize = fxdr_unsigned(int32_t, sfp->sf_bsize); - sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks); - sbp->f_bfree = fxdr_unsigned(int32_t, sfp->sf_bfree); - sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail); - sbp->f_files = 0; - sbp->f_ffree = 0; - } - if (sbp != &mp->mnt_stat) { - sbp->f_type = mp->mnt_vfc->vfc_typenum; - bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); - bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); - } - nfsm_reqdone; - vput(vp); - return (error); -} - -/* - * nfs version 3 fsinfo rpc call - */ -int -nfs_fsinfo(nmp, vp, cred, td) - register struct nfsmount *nmp; - register struct vnode *vp; - struct ucred *cred; - struct thread *td; -{ - register struct nfsv3_fsinfo *fsp; - register caddr_t cp; - register int32_t t1, t2; - register u_int32_t *tl, pref, max; - caddr_t bpos, dpos, cp2; - int error = 0, retattr; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - u_int64_t maxfsize; - - nfsstats.rpccnt[NFSPROC_FSINFO]++; - nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1)); - nfsm_fhtom(vp, 1); - nfsm_request(vp, NFSPROC_FSINFO, td, cred); - nfsm_postop_attr(vp, retattr); - if (!error) { - nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO); - pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref); - if (pref < nmp->nm_wsize && pref >= NFS_FABLKSIZE) - nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) & - ~(NFS_FABLKSIZE - 1); - max = fxdr_unsigned(u_int32_t, fsp->fs_wtmax); - if (max < nmp->nm_wsize && max > 0) { - nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1); - if (nmp->nm_wsize == 0) - nmp->nm_wsize = max; - } - pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref); - if (pref < nmp->nm_rsize && pref >= NFS_FABLKSIZE) - nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) & - ~(NFS_FABLKSIZE - 1); - max = fxdr_unsigned(u_int32_t, fsp->fs_rtmax); - if (max < nmp->nm_rsize && max > 0) { - nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1); - if (nmp->nm_rsize == 0) - nmp->nm_rsize = max; - } - pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref); - if (pref < nmp->nm_readdirsize && pref >= NFS_DIRBLKSIZ) - nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) & - ~(NFS_DIRBLKSIZ - 1); - if (max < nmp->nm_readdirsize && max > 0) { - nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1); - if (nmp->nm_readdirsize == 0) - nmp->nm_readdirsize = max; - } - maxfsize = fxdr_hyper(&fsp->fs_maxfilesize); - if (maxfsize > 0 && maxfsize < nmp->nm_maxfilesize) - nmp->nm_maxfilesize = maxfsize; - nmp->nm_state |= NFSSTA_GOTFSINFO; - } - nfsm_reqdone; - return (error); -} - -/* - * Mount a remote root fs via. nfs. This depends on the info in the - * nfs_diskless structure that has been filled in properly by some primary - * bootstrap. - * It goes something like this: - * - do enough of "ifconfig" by calling ifioctl() so that the system - * can talk to the server - * - If nfs_diskless.mygateway is filled in, use that address as - * a default gateway. - * - build the rootfs mount point and call mountnfs() to do the rest. - */ -int -nfs_mountroot(mp) - struct mount *mp; -{ - struct mount *swap_mp; - struct nfsv3_diskless *nd = &nfsv3_diskless; - struct socket *so; - struct vnode *vp; - struct thread *td = curthread; /* XXX */ - int error, i; - u_long l; - char buf[128]; - -#if defined(BOOTP_NFSROOT) && defined(BOOTP) - bootpc_init(); /* use bootp to get nfs_diskless filled in */ -#endif - - /* - * XXX time must be non-zero when we init the interface or else - * the arp code will wedge... - */ - while (time_second == 0) - tsleep(&time_second, PZERO+8, "arpkludge", 10); - - if (nfs_diskless_valid==1) - nfs_convert_diskless(); - - /* - * XXX splnet, so networks will receive... - */ - splnet(); - -#ifdef notyet - /* Set up swap credentials. */ - proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid); - proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid); - if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) > - NGROUPS) - proc0.p_ucred->cr_ngroups = NGROUPS; - for (i = 0; i < proc0.p_ucred->cr_ngroups; i++) - proc0.p_ucred->cr_groups[i] = ntohl(nd->swap_ucred.cr_groups[i]); -#endif - - /* - * Do enough of ifconfig(8) so that the critical net interface can - * talk to the server. - */ - error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0, td); - if (error) - panic("nfs_mountroot: socreate(%04x): %d", - nd->myif.ifra_addr.sa_family, error); - -#if 0 /* XXX Bad idea */ - /* - * We might not have been told the right interface, so we pass - * over the first ten interfaces of the same kind, until we get - * one of them configured. - */ - - for (i = strlen(nd->myif.ifra_name) - 1; - nd->myif.ifra_name[i] >= '0' && - nd->myif.ifra_name[i] <= '9'; - nd->myif.ifra_name[i] ++) { - error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); - if(!error) - break; - } -#endif - error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); - if (error) - panic("nfs_mountroot: SIOCAIFADDR: %d", error); - soclose(so); - - /* - * If the gateway field is filled in, set it as the default route. - */ - if (nd->mygateway.sin_len != 0) { - struct sockaddr_in mask, sin; - - bzero((caddr_t)&mask, sizeof(mask)); - sin = mask; - sin.sin_family = AF_INET; - sin.sin_len = sizeof(sin); - error = rtrequest(RTM_ADD, (struct sockaddr *)&sin, - (struct sockaddr *)&nd->mygateway, - (struct sockaddr *)&mask, - RTF_UP | RTF_GATEWAY, (struct rtentry **)0); - if (error) - panic("nfs_mountroot: RTM_ADD: %d", error); - } - - /* - * Create the rootfs mount point. - */ - nd->root_args.fh = nd->root_fh; - nd->root_args.fhsize = nd->root_fhsize; - l = ntohl(nd->root_saddr.sin_addr.s_addr); - snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", - (l >> 24) & 0xff, (l >> 16) & 0xff, - (l >> 8) & 0xff, (l >> 0) & 0xff,nd->root_hostnam); - printf("NFS ROOT: %s\n",buf); - if ((error = nfs_mountdiskless(buf, "/", MNT_RDONLY, - &nd->root_saddr, &nd->root_args, td, &vp, &mp)) != 0) { - if (swap_mp) { - mp->mnt_vfc->vfc_refcount--; - free(swap_mp, M_MOUNT); - } - return (error); - } - - swap_mp = NULL; - if (nd->swap_nblks) { - - /* Convert to DEV_BSIZE instead of Kilobyte */ - nd->swap_nblks *= 2; - - /* - * Create a fake mount point just for the swap vnode so that the - * swap file can be on a different server from the rootfs. - */ - nd->swap_args.fh = nd->swap_fh; - nd->swap_args.fhsize = nd->swap_fhsize; - l = ntohl(nd->swap_saddr.sin_addr.s_addr); - snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", - (l >> 24) & 0xff, (l >> 16) & 0xff, - (l >> 8) & 0xff, (l >> 0) & 0xff,nd->swap_hostnam); - printf("NFS SWAP: %s\n",buf); - if ((error = nfs_mountdiskless(buf, "/swap", 0, - &nd->swap_saddr, &nd->swap_args, td, &vp, &swap_mp)) != 0) - return (error); - vfs_unbusy(swap_mp, td); - - VTONFS(vp)->n_size = VTONFS(vp)->n_vattr.va_size = - nd->swap_nblks * DEV_BSIZE ; - - /* - * Since the swap file is not the root dir of a file system, - * hack it to a regular file. - */ - vp->v_type = VREG; - vp->v_flag = 0; - VREF(vp); - swaponvp(td, vp, NODEV, nd->swap_nblks); - } - - mp->mnt_flag |= MNT_ROOTFS; - mp->mnt_vnodecovered = NULLVP; - rootvp = vp; - vfs_unbusy(mp, td); - - /* - * This is not really an nfs issue, but it is much easier to - * set hostname here and then let the "/etc/rc.xxx" files - * mount the right /var based upon its preset value. - */ - bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN); - hostname[MAXHOSTNAMELEN - 1] = '\0'; - for (i = 0; i < MAXHOSTNAMELEN; i++) - if (hostname[i] == '\0') - break; - inittodr(ntohl(nd->root_time)); - return (0); -} - -/* - * Internal version of mount system call for diskless setup. - */ -static int -nfs_mountdiskless(path, which, mountflag, sin, args, td, vpp, mpp) - char *path; - char *which; - int mountflag; - struct sockaddr_in *sin; - struct nfs_args *args; - struct thread *td; - struct vnode **vpp; - struct mount **mpp; -{ - struct mount *mp; - struct sockaddr *nam; - int error; - - mp = *mpp; - - if (!mp && (error = vfs_rootmountalloc("nfs", path, &mp))) { - printf("nfs_mountroot: NFS not configured"); - return (error); - } - - mp->mnt_kern_flag = 0; - mp->mnt_flag = mountflag; - nam = dup_sockaddr((struct sockaddr *)sin, 1); - if ((error = mountnfs(args, mp, nam, which, path, vpp)) != 0) { - printf("nfs_mountroot: mount %s on %s: %d", path, which, error); - mp->mnt_vfc->vfc_refcount--; - vfs_unbusy(mp, td); - free(mp, M_MOUNT); - FREE(nam, M_SONAME); - return (error); - } - (void) copystr(which, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0); - *mpp = mp; - return (0); -} - -static void -nfs_decode_args(nmp, argp) - struct nfsmount *nmp; - struct nfs_args *argp; -{ - int s; - int adjsock; - int maxio; - - s = splnet(); - /* - * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes - * no sense in that context. - */ - if (argp->sotype == SOCK_STREAM) - nmp->nm_flag &= ~NFSMNT_NOCONN; - - /* Also clear RDIRPLUS if not NFSv3, it crashes some servers */ - if ((argp->flags & NFSMNT_NFSV3) == 0) - nmp->nm_flag &= ~NFSMNT_RDIRPLUS; - - /* Re-bind if rsrvd port requested and wasn't on one */ - adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT) - && (argp->flags & NFSMNT_RESVPORT); - /* Also re-bind if we're switching to/from a connected UDP socket */ - adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) != - (argp->flags & NFSMNT_NOCONN)); - - /* Update flags atomically. Don't change the lock bits. */ - nmp->nm_flag = argp->flags | nmp->nm_flag; - splx(s); - - if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { - nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; - if (nmp->nm_timeo < NFS_MINTIMEO) - nmp->nm_timeo = NFS_MINTIMEO; - else if (nmp->nm_timeo > NFS_MAXTIMEO) - nmp->nm_timeo = NFS_MAXTIMEO; - } - - if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { - nmp->nm_retry = argp->retrans; - if (nmp->nm_retry > NFS_MAXREXMIT) - nmp->nm_retry = NFS_MAXREXMIT; - } - - if (argp->flags & NFSMNT_NFSV3) { - if (argp->sotype == SOCK_DGRAM) - maxio = NFS_MAXDGRAMDATA; - else - maxio = NFS_MAXDATA; - } else - maxio = NFS_V2MAXDATA; - - if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { - nmp->nm_wsize = argp->wsize; - /* Round down to multiple of blocksize */ - nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); - if (nmp->nm_wsize <= 0) - nmp->nm_wsize = NFS_FABLKSIZE; - } - if (nmp->nm_wsize > maxio) - nmp->nm_wsize = maxio; - if (nmp->nm_wsize > MAXBSIZE) - nmp->nm_wsize = MAXBSIZE; - - if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { - nmp->nm_rsize = argp->rsize; - /* Round down to multiple of blocksize */ - nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); - if (nmp->nm_rsize <= 0) - nmp->nm_rsize = NFS_FABLKSIZE; - } - if (nmp->nm_rsize > maxio) - nmp->nm_rsize = maxio; - if (nmp->nm_rsize > MAXBSIZE) - nmp->nm_rsize = MAXBSIZE; - - if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { - nmp->nm_readdirsize = argp->readdirsize; - } - if (nmp->nm_readdirsize > maxio) - nmp->nm_readdirsize = maxio; - if (nmp->nm_readdirsize > nmp->nm_rsize) - nmp->nm_readdirsize = nmp->nm_rsize; - - if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0) - nmp->nm_acregmin = argp->acregmin; - else - nmp->nm_acregmin = NFS_MINATTRTIMO; - if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0) - nmp->nm_acregmax = argp->acregmax; - else - nmp->nm_acregmax = NFS_MAXATTRTIMO; - if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0) - nmp->nm_acdirmin = argp->acdirmin; - else - nmp->nm_acdirmin = NFS_MINDIRATTRTIMO; - if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0) - nmp->nm_acdirmax = argp->acdirmax; - else - nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO; - if (nmp->nm_acdirmin > nmp->nm_acdirmax) - nmp->nm_acdirmin = nmp->nm_acdirmax; - if (nmp->nm_acregmin > nmp->nm_acregmax) - nmp->nm_acregmin = nmp->nm_acregmax; - - if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0) { - if (argp->maxgrouplist <= NFS_MAXGRPS) - nmp->nm_numgrps = argp->maxgrouplist; - else - nmp->nm_numgrps = NFS_MAXGRPS; - } - if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) { - if (argp->readahead <= NFS_MAXRAHEAD) - nmp->nm_readahead = argp->readahead; - else - nmp->nm_readahead = NFS_MAXRAHEAD; - } - if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2) { - if (argp->leaseterm <= NQ_MAXLEASE) - nmp->nm_leaseterm = argp->leaseterm; - else - nmp->nm_leaseterm = NQ_MAXLEASE; - } - if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1) { - if (argp->deadthresh <= NQ_NEVERDEAD) - nmp->nm_deadthresh = argp->deadthresh; - else - nmp->nm_deadthresh = NQ_NEVERDEAD; - } - - adjsock |= ((nmp->nm_sotype != argp->sotype) || - (nmp->nm_soproto != argp->proto)); - nmp->nm_sotype = argp->sotype; - nmp->nm_soproto = argp->proto; - - if (nmp->nm_so && adjsock) { - nfs_safedisconnect(nmp); - if (nmp->nm_sotype == SOCK_DGRAM) - while (nfs_connect(nmp, (struct nfsreq *)0)) { - printf("nfs_args: retrying connect\n"); - (void) tsleep((caddr_t)&lbolt, - PSOCK, "nfscon", 0); - } - } -} - -/* - * VFS Operations. - * - * mount system call - * It seems a bit dumb to copyinstr() the host and path here and then - * bcopy() them in mountnfs(), but I wanted to detect errors before - * doing the sockargs() call because sockargs() allocates an mbuf and - * an error after that means that I have to release the mbuf. - */ -/* ARGSUSED */ -static int -nfs_mount(mp, path, data, ndp, td) - struct mount *mp; - char *path; - caddr_t data; - struct nameidata *ndp; - struct thread *td; -{ - int error; - struct nfs_args args; - struct sockaddr *nam; - struct vnode *vp; - char hst[MNAMELEN]; - size_t len; - u_char nfh[NFSX_V3FHMAX]; - - if (path == NULL) { - nfs_mountroot(mp); - return (0); - } - error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)); - if (error) - return (error); - if (args.version != NFS_ARGSVERSION) { -#ifdef COMPAT_PRELITE2 - /* - * If the argument version is unknown, then assume the - * caller is a pre-lite2 4.4BSD client and convert its - * arguments. - */ - struct onfs_args oargs; - error = copyin(data, (caddr_t)&oargs, sizeof (struct onfs_args)); - if (error) - return (error); - nfs_convert_oargs(&args,&oargs); -#else /* !COMPAT_PRELITE2 */ - return (EPROGMISMATCH); -#endif /* COMPAT_PRELITE2 */ - } - if (mp->mnt_flag & MNT_UPDATE) { - register struct nfsmount *nmp = VFSTONFS(mp); - - if (nmp == NULL) - return (EIO); - /* - * When doing an update, we can't change from or to - * v3 and/or nqnfs, or change cookie translation - */ - args.flags = (args.flags & - ~(NFSMNT_NFSV3|NFSMNT_NQNFS /*|NFSMNT_XLATECOOKIE*/)) | - (nmp->nm_flag & - (NFSMNT_NFSV3|NFSMNT_NQNFS /*|NFSMNT_XLATECOOKIE*/)); - nfs_decode_args(nmp, &args); - return (0); - } - if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) - return (EINVAL); - error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize); - if (error) - return (error); - error = copyinstr(args.hostname, hst, MNAMELEN-1, &len); - if (error) - return (error); - bzero(&hst[len], MNAMELEN - len); - /* sockargs() call must be after above copyin() calls */ - error = getsockaddr(&nam, (caddr_t)args.addr, args.addrlen); - if (error) - return (error); - args.fh = nfh; - error = mountnfs(&args, mp, nam, path, hst, &vp); - return (error); -} - -/* - * Common code for mount and mountroot - */ -static int -mountnfs(argp, mp, nam, pth, hst, vpp) - register struct nfs_args *argp; - register struct mount *mp; - struct sockaddr *nam; - char *pth, *hst; - struct vnode **vpp; -{ - register struct nfsmount *nmp; - struct nfsnode *np; - int error; - struct vattr attrs; - - if (mp->mnt_flag & MNT_UPDATE) { - nmp = VFSTONFS(mp); - /* update paths, file handles, etc, here XXX */ - FREE(nam, M_SONAME); - return (0); - } else { - nmp = zalloc(nfsmount_zone); - bzero((caddr_t)nmp, sizeof (struct nfsmount)); - TAILQ_INIT(&nmp->nm_uidlruhead); - TAILQ_INIT(&nmp->nm_bufq); - mp->mnt_data = (qaddr_t)nmp; - } - vfs_getnewfsid(mp); - nmp->nm_mountp = mp; - if (argp->flags & NFSMNT_NQNFS) - /* - * We have to set mnt_maxsymlink to a non-zero value so - * that COMPAT_43 routines will know that we are setting - * the d_type field in directories (and can zero it for - * unsuspecting binaries). - */ - mp->mnt_maxsymlinklen = 1; - - /* - * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too - * high, depending on whether we end up with negative offsets in - * the client or server somewhere. 2GB-1 may be safer. - * - * For V3, nfs_fsinfo will adjust this as necessary. Assume maximum - * that we can handle until we find out otherwise. - * XXX Our "safe" limit on the client is what we can store in our - * buffer cache using signed(!) block numbers. - */ - if ((argp->flags & NFSMNT_NFSV3) == 0) - nmp->nm_maxfilesize = 0xffffffffLL; - else - nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1; - - nmp->nm_timeo = NFS_TIMEO; - nmp->nm_retry = NFS_RETRANS; - nmp->nm_wsize = NFS_WSIZE; - nmp->nm_rsize = NFS_RSIZE; - nmp->nm_readdirsize = NFS_READDIRSIZE; - nmp->nm_numgrps = NFS_MAXGRPS; - nmp->nm_readahead = NFS_DEFRAHEAD; - nmp->nm_leaseterm = NQ_DEFLEASE; - nmp->nm_deadthresh = NQ_DEADTHRESH; - TAILQ_INIT(&nmp->nm_timerhead); - nmp->nm_inprog = NULLVP; - nmp->nm_fhsize = argp->fhsize; - bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); - bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); - bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); - nmp->nm_nam = nam; - /* Set up the sockets and per-host congestion */ - nmp->nm_sotype = argp->sotype; - nmp->nm_soproto = argp->proto; - - nfs_decode_args(nmp, argp); - - /* - * For Connection based sockets (TCP,...) defer the connect until - * the first request, in case the server is not responding. - */ - if (nmp->nm_sotype == SOCK_DGRAM && - (error = nfs_connect(nmp, (struct nfsreq *)0))) - goto bad; - - /* - * This is silly, but it has to be set so that vinifod() works. - * We do not want to do an nfs_statfs() here since we can get - * stuck on a dead server and we are holding a lock on the mount - * point. - */ - mp->mnt_stat.f_iosize = nfs_iosize(nmp); - /* - * A reference count is needed on the nfsnode representing the - * remote root. If this object is not persistent, then backward - * traversals of the mount point (i.e. "..") will not work if - * the nfsnode gets flushed out of the cache. Ufs does not have - * this problem, because one can identify root inodes by their - * number == ROOTINO (2). - */ - error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np); - if (error) - goto bad; - *vpp = NFSTOV(np); - - /* - * Get file attributes for the mountpoint. This has the side - * effect of filling in (*vpp)->v_type with the correct value. - */ - VOP_GETATTR(*vpp, &attrs, curthread->td_proc->p_ucred, curthread); - - /* - * Lose the lock but keep the ref. - */ - VOP_UNLOCK(*vpp, 0, curthread); - - return (0); -bad: - nfs_disconnect(nmp); - zfree(nfsmount_zone, nmp); - FREE(nam, M_SONAME); - return (error); -} - -/* - * unmount system call - */ -static int -nfs_unmount(mp, mntflags, td) - struct mount *mp; - int mntflags; - struct thread *td; -{ - register struct nfsmount *nmp; - int error, flags = 0; - - if (mntflags & MNT_FORCE) - flags |= FORCECLOSE; - nmp = VFSTONFS(mp); - /* - * Goes something like this.. - * - Call vflush() to clear out vnodes for this file system - * - Close the socket - * - Free up the data structures - */ - /* - * Must handshake with nqnfs_clientd() if it is active. - */ - nmp->nm_state |= NFSSTA_DISMINPROG; - while (nmp->nm_inprog != NULLVP) - (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0); - - /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */ - error = vflush(mp, 1, flags); - if (error) { - nmp->nm_state &= ~NFSSTA_DISMINPROG; - return (error); - } - - /* - * We are now committed to the unmount. - * For NQNFS, let the server daemon free the nfsmount structure. - */ - if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) - nmp->nm_state |= NFSSTA_DISMNT; - - nfs_disconnect(nmp); - FREE(nmp->nm_nam, M_SONAME); - - if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0) - zfree(nfsmount_zone, nmp); - return (0); -} - -/* - * Return root of a filesystem - */ -static int -nfs_root(mp, vpp) - struct mount *mp; - struct vnode **vpp; -{ - register struct vnode *vp; - struct nfsmount *nmp; - struct nfsnode *np; - int error; - - nmp = VFSTONFS(mp); - error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np); - if (error) - return (error); - vp = NFSTOV(np); - if (vp->v_type == VNON) - vp->v_type = VDIR; - vp->v_flag = VROOT; - *vpp = vp; - return (0); -} - -extern int syncprt; - -/* - * Flush out the buffer cache - */ -/* ARGSUSED */ -static int -nfs_sync(mp, waitfor, cred, td) - struct mount *mp; - int waitfor; - struct ucred *cred; - struct thread *td; -{ - struct vnode *vp, *vnp; - int error, allerror = 0; - - /* - * Force stale buffer cache information to be flushed. - */ - mtx_lock(&mntvnode_mtx); -loop: - for (vp = LIST_FIRST(&mp->mnt_vnodelist); - vp != NULL; - vp = vnp) { - /* - * If the vnode that we are about to sync is no longer - * associated with this mount point, start over. - */ - if (vp->v_mount != mp) - goto loop; - vnp = LIST_NEXT(vp, v_mntvnodes); - mtx_unlock(&mntvnode_mtx); - mtx_lock(&vp->v_interlock); - if (VOP_ISLOCKED(vp, NULL) || TAILQ_EMPTY(&vp->v_dirtyblkhd) || - waitfor == MNT_LAZY) { - mtx_unlock(&vp->v_interlock); - mtx_lock(&mntvnode_mtx); - continue; - } - if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { - mtx_lock(&mntvnode_mtx); - goto loop; - } - error = VOP_FSYNC(vp, cred, waitfor, td); - if (error) - allerror = error; - vput(vp); - mtx_lock(&mntvnode_mtx); - } - mtx_unlock(&mntvnode_mtx); - return (allerror); -} - diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c deleted file mode 100644 index 8f9ff7d..0000000 --- a/sys/nfs/nfs_vnops.c +++ /dev/null @@ -1,3344 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95 - * $FreeBSD$ - */ - - -/* - * vnode op calls for Sun NFS version 2 and 3 - */ - -#include "opt_inet.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* Defs */ -#define TRUE 1 -#define FALSE 0 - -/* - * Ifdef for FreeBSD-current merged buffer cache. It is unfortunate that these - * calls are not in getblk() and brelse() so that they would not be necessary - * here. - */ -#ifndef B_VMIO -#define vfs_busy_pages(bp, f) -#endif - -static int nfsspec_read __P((struct vop_read_args *)); -static int nfsspec_write __P((struct vop_write_args *)); -static int nfsfifo_read __P((struct vop_read_args *)); -static int nfsfifo_write __P((struct vop_write_args *)); -static int nfsspec_close __P((struct vop_close_args *)); -static int nfsfifo_close __P((struct vop_close_args *)); -#define nfs_poll vop_nopoll -static int nfs_flush __P((struct vnode *,struct ucred *,int,struct thread *,int)); -static int nfs_setattrrpc __P((struct vnode *,struct vattr *,struct ucred *,struct thread *)); -static int nfs_lookup __P((struct vop_lookup_args *)); -static int nfs_create __P((struct vop_create_args *)); -static int nfs_mknod __P((struct vop_mknod_args *)); -static int nfs_open __P((struct vop_open_args *)); -static int nfs_close __P((struct vop_close_args *)); -static int nfs_access __P((struct vop_access_args *)); -static int nfs_getattr __P((struct vop_getattr_args *)); -static int nfs_setattr __P((struct vop_setattr_args *)); -static int nfs_read __P((struct vop_read_args *)); -static int nfs_fsync __P((struct vop_fsync_args *)); -static int nfs_remove __P((struct vop_remove_args *)); -static int nfs_link __P((struct vop_link_args *)); -static int nfs_rename __P((struct vop_rename_args *)); -static int nfs_mkdir __P((struct vop_mkdir_args *)); -static int nfs_rmdir __P((struct vop_rmdir_args *)); -static int nfs_symlink __P((struct vop_symlink_args *)); -static int nfs_readdir __P((struct vop_readdir_args *)); -static int nfs_strategy __P((struct vop_strategy_args *)); -static int nfs_lookitup __P((struct vnode *, const char *, int, - struct ucred *, struct thread *, struct nfsnode **)); -static int nfs_sillyrename __P((struct vnode *,struct vnode *,struct componentname *)); -static int nfsspec_access __P((struct vop_access_args *)); -static int nfs_readlink __P((struct vop_readlink_args *)); -static int nfs_print __P((struct vop_print_args *)); -static int nfs_advlock __P((struct vop_advlock_args *)); -/* - * Global vfs data structures for nfs - */ -vop_t **nfsv2_vnodeop_p; -static struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { - { &vop_default_desc, (vop_t *) vop_defaultop }, - { &vop_access_desc, (vop_t *) nfs_access }, - { &vop_advlock_desc, (vop_t *) nfs_advlock }, - { &vop_close_desc, (vop_t *) nfs_close }, - { &vop_create_desc, (vop_t *) nfs_create }, - { &vop_fsync_desc, (vop_t *) nfs_fsync }, - { &vop_getattr_desc, (vop_t *) nfs_getattr }, - { &vop_getpages_desc, (vop_t *) nfs_getpages }, - { &vop_putpages_desc, (vop_t *) nfs_putpages }, - { &vop_inactive_desc, (vop_t *) nfs_inactive }, - { &vop_islocked_desc, (vop_t *) vop_stdislocked }, - { &vop_lease_desc, (vop_t *) vop_null }, - { &vop_link_desc, (vop_t *) nfs_link }, - { &vop_lock_desc, (vop_t *) vop_sharedlock }, - { &vop_lookup_desc, (vop_t *) nfs_lookup }, - { &vop_mkdir_desc, (vop_t *) nfs_mkdir }, - { &vop_mknod_desc, (vop_t *) nfs_mknod }, - { &vop_open_desc, (vop_t *) nfs_open }, - { &vop_poll_desc, (vop_t *) nfs_poll }, - { &vop_print_desc, (vop_t *) nfs_print }, - { &vop_read_desc, (vop_t *) nfs_read }, - { &vop_readdir_desc, (vop_t *) nfs_readdir }, - { &vop_readlink_desc, (vop_t *) nfs_readlink }, - { &vop_reclaim_desc, (vop_t *) nfs_reclaim }, - { &vop_remove_desc, (vop_t *) nfs_remove }, - { &vop_rename_desc, (vop_t *) nfs_rename }, - { &vop_rmdir_desc, (vop_t *) nfs_rmdir }, - { &vop_setattr_desc, (vop_t *) nfs_setattr }, - { &vop_strategy_desc, (vop_t *) nfs_strategy }, - { &vop_symlink_desc, (vop_t *) nfs_symlink }, - { &vop_unlock_desc, (vop_t *) vop_stdunlock }, - { &vop_write_desc, (vop_t *) nfs_write }, - { NULL, NULL } -}; -static struct vnodeopv_desc nfsv2_vnodeop_opv_desc = - { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries }; -VNODEOP_SET(nfsv2_vnodeop_opv_desc); - -/* - * Special device vnode ops - */ -vop_t **spec_nfsv2nodeop_p; -static struct vnodeopv_entry_desc nfsv2_specop_entries[] = { - { &vop_default_desc, (vop_t *) spec_vnoperate }, - { &vop_access_desc, (vop_t *) nfsspec_access }, - { &vop_close_desc, (vop_t *) nfsspec_close }, - { &vop_fsync_desc, (vop_t *) nfs_fsync }, - { &vop_getattr_desc, (vop_t *) nfs_getattr }, - { &vop_islocked_desc, (vop_t *) vop_stdislocked }, - { &vop_inactive_desc, (vop_t *) nfs_inactive }, - { &vop_lock_desc, (vop_t *) vop_sharedlock }, - { &vop_print_desc, (vop_t *) nfs_print }, - { &vop_read_desc, (vop_t *) nfsspec_read }, - { &vop_reclaim_desc, (vop_t *) nfs_reclaim }, - { &vop_setattr_desc, (vop_t *) nfs_setattr }, - { &vop_unlock_desc, (vop_t *) vop_stdunlock }, - { &vop_write_desc, (vop_t *) nfsspec_write }, - { NULL, NULL } -}; -static struct vnodeopv_desc spec_nfsv2nodeop_opv_desc = - { &spec_nfsv2nodeop_p, nfsv2_specop_entries }; -VNODEOP_SET(spec_nfsv2nodeop_opv_desc); - -vop_t **fifo_nfsv2nodeop_p; -static struct vnodeopv_entry_desc nfsv2_fifoop_entries[] = { - { &vop_default_desc, (vop_t *) fifo_vnoperate }, - { &vop_access_desc, (vop_t *) nfsspec_access }, - { &vop_close_desc, (vop_t *) nfsfifo_close }, - { &vop_fsync_desc, (vop_t *) nfs_fsync }, - { &vop_getattr_desc, (vop_t *) nfs_getattr }, - { &vop_inactive_desc, (vop_t *) nfs_inactive }, - { &vop_islocked_desc, (vop_t *) vop_stdislocked }, - { &vop_lock_desc, (vop_t *) vop_sharedlock }, - { &vop_print_desc, (vop_t *) nfs_print }, - { &vop_read_desc, (vop_t *) nfsfifo_read }, - { &vop_reclaim_desc, (vop_t *) nfs_reclaim }, - { &vop_setattr_desc, (vop_t *) nfs_setattr }, - { &vop_unlock_desc, (vop_t *) vop_stdunlock }, - { &vop_write_desc, (vop_t *) nfsfifo_write }, - { NULL, NULL } -}; -static struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc = - { &fifo_nfsv2nodeop_p, nfsv2_fifoop_entries }; -VNODEOP_SET(fifo_nfsv2nodeop_opv_desc); - -static int nfs_mknodrpc __P((struct vnode *dvp, struct vnode **vpp, - struct componentname *cnp, - struct vattr *vap)); -static int nfs_removerpc __P((struct vnode *dvp, const char *name, - int namelen, - struct ucred *cred, struct thread *td)); -static int nfs_renamerpc __P((struct vnode *fdvp, const char *fnameptr, - int fnamelen, struct vnode *tdvp, - const char *tnameptr, int tnamelen, - struct ucred *cred, struct thread *td)); -static int nfs_renameit __P((struct vnode *sdvp, - struct componentname *scnp, - struct sillyrename *sp)); - -/* - * Global variables - */ -extern u_int32_t nfs_true, nfs_false; -extern u_int32_t nfs_xdrneg1; -extern struct nfsstats nfsstats; -extern nfstype nfsv3_type[9]; -struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; -struct nfsmount *nfs_iodmount[NFS_MAXASYNCDAEMON]; -int nfs_numasync = 0; -#define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) - -SYSCTL_DECL(_vfs_nfs); - -static int nfsaccess_cache_timeout = NFS_MAXATTRTIMO; -SYSCTL_INT(_vfs_nfs, OID_AUTO, access_cache_timeout, CTLFLAG_RW, - &nfsaccess_cache_timeout, 0, "NFS ACCESS cache timeout"); - -static int nfsv3_commit_on_close = 0; -SYSCTL_INT(_vfs_nfs, OID_AUTO, nfsv3_commit_on_close, CTLFLAG_RW, - &nfsv3_commit_on_close, 0, "write+commit on close, else only write"); -#if 0 -SYSCTL_INT(_vfs_nfs, OID_AUTO, access_cache_hits, CTLFLAG_RD, - &nfsstats.accesscache_hits, 0, "NFS ACCESS cache hit count"); - -SYSCTL_INT(_vfs_nfs, OID_AUTO, access_cache_misses, CTLFLAG_RD, - &nfsstats.accesscache_misses, 0, "NFS ACCESS cache miss count"); -#endif - -#define NFSV3ACCESS_ALL (NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY \ - | NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE \ - | NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP) -static int -nfs3_access_otw(struct vnode *vp, - int wmode, - struct thread *td, - struct ucred *cred) -{ - const int v3 = 1; - u_int32_t *tl; - int error = 0, attrflag; - - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - caddr_t bpos, dpos, cp2; - register int32_t t1, t2; - register caddr_t cp; - u_int32_t rmode; - struct nfsnode *np = VTONFS(vp); - - nfsstats.rpccnt[NFSPROC_ACCESS]++; - nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED); - nfsm_fhtom(vp, v3); - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); - *tl = txdr_unsigned(wmode); - nfsm_request(vp, NFSPROC_ACCESS, td, cred); - nfsm_postop_attr(vp, attrflag); - if (!error) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - rmode = fxdr_unsigned(u_int32_t, *tl); - np->n_mode = rmode; - np->n_modeuid = cred->cr_uid; - np->n_modestamp = time_second; - } - nfsm_reqdone; - return error; -} - -/* - * nfs access vnode op. - * For nfs version 2, just return ok. File accesses may fail later. - * For nfs version 3, use the access rpc to check accessibility. If file modes - * are changed on the server, accesses might still fail later. - */ -static int -nfs_access(ap) - struct vop_access_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct thread *a_td; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - int error = 0; - u_int32_t mode, wmode; - int v3 = NFS_ISV3(vp); - struct nfsnode *np = VTONFS(vp); - - /* - * Disallow write attempts on filesystems mounted read-only; - * unless the file is a socket, fifo, or a block or character - * device resident on the filesystem. - */ - if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { - switch (vp->v_type) { - case VREG: - case VDIR: - case VLNK: - return (EROFS); - default: - break; - } - } - /* - * For nfs v3, check to see if we have done this recently, and if - * so return our cached result instead of making an ACCESS call. - * If not, do an access rpc, otherwise you are stuck emulating - * ufs_access() locally using the vattr. This may not be correct, - * since the server may apply other access criteria such as - * client uid-->server uid mapping that we do not know about. - */ - if (v3) { - if (ap->a_mode & VREAD) - mode = NFSV3ACCESS_READ; - else - mode = 0; - if (vp->v_type != VDIR) { - if (ap->a_mode & VWRITE) - mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND); - if (ap->a_mode & VEXEC) - mode |= NFSV3ACCESS_EXECUTE; - } else { - if (ap->a_mode & VWRITE) - mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND | - NFSV3ACCESS_DELETE); - if (ap->a_mode & VEXEC) - mode |= NFSV3ACCESS_LOOKUP; - } - /* XXX safety belt, only make blanket request if caching */ - if (nfsaccess_cache_timeout > 0) { - wmode = NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY | - NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE | - NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP; - } else { - wmode = mode; - } - - /* - * Does our cached result allow us to give a definite yes to - * this request? - */ - if ((time_second < (np->n_modestamp + nfsaccess_cache_timeout)) && - (ap->a_cred->cr_uid == np->n_modeuid) && - ((np->n_mode & mode) == mode)) { - nfsstats.accesscache_hits++; - } else { - /* - * Either a no, or a don't know. Go to the wire. - */ - nfsstats.accesscache_misses++; - error = nfs3_access_otw(vp, wmode, ap->a_td,ap->a_cred); - if (!error) { - if ((np->n_mode & mode) != mode) { - error = EACCES; - } - } - } - return (error); - } else { - if ((error = nfsspec_access(ap)) != 0) - return (error); - - /* - * Attempt to prevent a mapped root from accessing a file - * which it shouldn't. We try to read a byte from the file - * if the user is root and the file is not zero length. - * After calling nfsspec_access, we should have the correct - * file size cached. - */ - if (ap->a_cred->cr_uid == 0 && (ap->a_mode & VREAD) - && VTONFS(vp)->n_size > 0) { - struct iovec aiov; - struct uio auio; - char buf[1]; - - aiov.iov_base = buf; - aiov.iov_len = 1; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_offset = 0; - auio.uio_resid = 1; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_rw = UIO_READ; - auio.uio_td = ap->a_td; - - if (vp->v_type == VREG) - error = nfs_readrpc(vp, &auio, ap->a_cred); - else if (vp->v_type == VDIR) { - char* bp; - bp = malloc(NFS_DIRBLKSIZ, M_TEMP, M_WAITOK); - aiov.iov_base = bp; - aiov.iov_len = auio.uio_resid = NFS_DIRBLKSIZ; - error = nfs_readdirrpc(vp, &auio, ap->a_cred); - free(bp, M_TEMP); - } else if (vp->v_type == VLNK) - error = nfs_readlinkrpc(vp, &auio, ap->a_cred); - else - error = EACCES; - } - return (error); - } -} - -/* - * nfs open vnode op - * Check to see if the type is ok - * and that deletion is not in progress. - * For paged in text files, you will need to flush the page cache - * if consistency is lost. - */ -/* ARGSUSED */ -static int -nfs_open(ap) - struct vop_open_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct thread *a_td; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - struct nfsnode *np = VTONFS(vp); - struct nfsmount *nmp = VFSTONFS(vp->v_mount); - struct vattr vattr; - int error; - - if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) { -#ifdef DIAGNOSTIC - printf("open eacces vtyp=%d\n",vp->v_type); -#endif - return (EACCES); - } - /* - * Get a valid lease. If cached data is stale, flush it. - */ - if (nmp->nm_flag & NFSMNT_NQNFS) { - if (NQNFS_CKINVALID(vp, np, ND_READ)) { - do { - error = nqnfs_getlease(vp, ND_READ, ap->a_cred, - ap->a_td); - } while (error == NQNFS_EXPIRED); - if (error) - return (error); - if (np->n_lrev != np->n_brev || - (np->n_flag & NQNFSNONCACHE)) { - if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, - ap->a_td, 1)) == EINTR) - return (error); - np->n_brev = np->n_lrev; - } - } - } else { - if (np->n_flag & NMODIFIED) { - if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, - ap->a_td, 1)) == EINTR) - return (error); - np->n_attrstamp = 0; - if (vp->v_type == VDIR) - np->n_direofoffset = 0; - error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td); - if (error) - return (error); - np->n_mtime = vattr.va_mtime.tv_sec; - } else { - error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td); - if (error) - return (error); - if (np->n_mtime != vattr.va_mtime.tv_sec) { - if (vp->v_type == VDIR) - np->n_direofoffset = 0; - if ((error = nfs_vinvalbuf(vp, V_SAVE, - ap->a_cred, ap->a_td, 1)) == EINTR) - return (error); - np->n_mtime = vattr.va_mtime.tv_sec; - } - } - } - if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) - np->n_attrstamp = 0; /* For Open/Close consistency */ - return (0); -} - -/* - * nfs close vnode op - * What an NFS client should do upon close after writing is a debatable issue. - * Most NFS clients push delayed writes to the server upon close, basically for - * two reasons: - * 1 - So that any write errors may be reported back to the client process - * doing the close system call. By far the two most likely errors are - * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure. - * 2 - To put a worst case upper bound on cache inconsistency between - * multiple clients for the file. - * There is also a consistency problem for Version 2 of the protocol w.r.t. - * not being able to tell if other clients are writing a file concurrently, - * since there is no way of knowing if the changed modify time in the reply - * is only due to the write for this client. - * (NFS Version 3 provides weak cache consistency data in the reply that - * should be sufficient to detect and handle this case.) - * - * The current code does the following: - * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers - * for NFS Version 3 - flush dirty buffers to the server but don't invalidate - * or commit them (this satisfies 1 and 2 except for the - * case where the server crashes after this close but - * before the commit RPC, which is felt to be "good - * enough". Changing the last argument to nfs_flush() to - * a 1 would force a commit operation, if it is felt a - * commit is necessary now. - * for NQNFS - do nothing now, since 2 is dealt with via leases and - * 1 should be dealt with via an fsync() system call for - * cases where write errors are important. - */ -/* ARGSUSED */ -static int -nfs_close(ap) - struct vop_close_args /* { - struct vnodeop_desc *a_desc; - struct vnode *a_vp; - int a_fflag; - struct ucred *a_cred; - struct thread *a_td; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - register struct nfsnode *np = VTONFS(vp); - int error = 0; - - if (vp->v_type == VREG) { - if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 && - (np->n_flag & NMODIFIED)) { - if (NFS_ISV3(vp)) { - /* - * Under NFSv3 we have dirty buffers to dispose of. We - * must flush them to the NFS server. We have the option - * of waiting all the way through the commit rpc or just - * waiting for the initial write. The default is to only - * wait through the initial write so the data is in the - * server's cache, which is roughly similar to the state - * a standard disk subsystem leaves the file in on close(). - * - * We cannot clear the NMODIFIED bit in np->n_flag due to - * potential races with other processes, and certainly - * cannot clear it if we don't commit. - */ - int cm = nfsv3_commit_on_close ? 1 : 0; - error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_td, cm); - /* np->n_flag &= ~NMODIFIED; */ - } else { - error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_td, 1); - } - np->n_attrstamp = 0; - } - if (np->n_flag & NWRITEERR) { - np->n_flag &= ~NWRITEERR; - error = np->n_error; - } - } - return (error); -} - -/* - * nfs getattr call from vfs. - */ -static int -nfs_getattr(ap) - struct vop_getattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct thread *a_td; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - register struct nfsnode *np = VTONFS(vp); - register caddr_t cp; - register u_int32_t *tl; - register int32_t t1, t2; - caddr_t bpos, dpos; - int error = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - int v3 = NFS_ISV3(vp); - - /* - * Update local times for special files. - */ - if (np->n_flag & (NACC | NUPD)) - np->n_flag |= NCHG; - /* - * First look in the cache. - */ - if (nfs_getattrcache(vp, ap->a_vap) == 0) - return (0); - - if (v3 && nfsaccess_cache_timeout > 0) { - nfsstats.accesscache_misses++; - nfs3_access_otw(vp, NFSV3ACCESS_ALL, ap->a_td, ap->a_cred); - if (nfs_getattrcache(vp, ap->a_vap) == 0) - return (0); - } - - nfsstats.rpccnt[NFSPROC_GETATTR]++; - nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3)); - nfsm_fhtom(vp, v3); - nfsm_request(vp, NFSPROC_GETATTR, ap->a_td, ap->a_cred); - if (!error) { - nfsm_loadattr(vp, ap->a_vap); - } - nfsm_reqdone; - return (error); -} - -/* - * nfs setattr call. - */ -static int -nfs_setattr(ap) - struct vop_setattr_args /* { - struct vnodeop_desc *a_desc; - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct thread *a_td; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - register struct nfsnode *np = VTONFS(vp); - register struct vattr *vap = ap->a_vap; - int error = 0; - u_quad_t tsize; - -#ifndef nolint - tsize = (u_quad_t)0; -#endif - - /* - * Setting of flags is not supported. - */ - if (vap->va_flags != VNOVAL) - return (EOPNOTSUPP); - - /* - * Disallow write attempts if the filesystem is mounted read-only. - */ - if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || - vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || - vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && - (vp->v_mount->mnt_flag & MNT_RDONLY)) - return (EROFS); - if (vap->va_size != VNOVAL) { - switch (vp->v_type) { - case VDIR: - return (EISDIR); - case VCHR: - case VBLK: - case VSOCK: - case VFIFO: - if (vap->va_mtime.tv_sec == VNOVAL && - vap->va_atime.tv_sec == VNOVAL && - vap->va_mode == (mode_t)VNOVAL && - vap->va_uid == (uid_t)VNOVAL && - vap->va_gid == (gid_t)VNOVAL) - return (0); - vap->va_size = VNOVAL; - break; - default: - /* - * Disallow write attempts if the filesystem is - * mounted read-only. - */ - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); - vnode_pager_setsize(vp, vap->va_size); - if (np->n_flag & NMODIFIED) { - if (vap->va_size == 0) - error = nfs_vinvalbuf(vp, 0, - ap->a_cred, ap->a_td, 1); - else - error = nfs_vinvalbuf(vp, V_SAVE, - ap->a_cred, ap->a_td, 1); - if (error) { - vnode_pager_setsize(vp, np->n_size); - return (error); - } - } - tsize = np->n_size; - np->n_size = np->n_vattr.va_size = vap->va_size; - }; - } else if ((vap->va_mtime.tv_sec != VNOVAL || - vap->va_atime.tv_sec != VNOVAL) && (np->n_flag & NMODIFIED) && - vp->v_type == VREG && - (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, - ap->a_td, 1)) == EINTR) - return (error); - error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_td); - if (error && vap->va_size != VNOVAL) { - np->n_size = np->n_vattr.va_size = tsize; - vnode_pager_setsize(vp, np->n_size); - } - return (error); -} - -/* - * Do an nfs setattr rpc. - */ -static int -nfs_setattrrpc(vp, vap, cred, td) - register struct vnode *vp; - register struct vattr *vap; - struct ucred *cred; - struct thread *td; -{ - register struct nfsv2_sattr *sp; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; - u_int32_t *tl; - int error = 0, wccflag = NFSV3_WCCRATTR; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - int v3 = NFS_ISV3(vp); - - nfsstats.rpccnt[NFSPROC_SETATTR]++; - nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3)); - nfsm_fhtom(vp, v3); - if (v3) { - nfsm_v3attrbuild(vap, TRUE); - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); - *tl = nfs_false; - } else { - nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); - if (vap->va_mode == (mode_t)VNOVAL) - sp->sa_mode = nfs_xdrneg1; - else - sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode); - if (vap->va_uid == (uid_t)VNOVAL) - sp->sa_uid = nfs_xdrneg1; - else - sp->sa_uid = txdr_unsigned(vap->va_uid); - if (vap->va_gid == (gid_t)VNOVAL) - sp->sa_gid = nfs_xdrneg1; - else - sp->sa_gid = txdr_unsigned(vap->va_gid); - sp->sa_size = txdr_unsigned(vap->va_size); - txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); - txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); - } - nfsm_request(vp, NFSPROC_SETATTR, td, cred); - if (v3) { - nfsm_wcc_data(vp, wccflag); - } else - nfsm_loadattr(vp, (struct vattr *)0); - nfsm_reqdone; - return (error); -} - -/* - * nfs lookup call, one step at a time... - * First look in cache - * If not found, unlock the directory nfsnode and do the rpc - */ -static int -nfs_lookup(ap) - struct vop_lookup_args /* { - struct vnodeop_desc *a_desc; - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - } */ *ap; -{ - struct componentname *cnp = ap->a_cnp; - struct vnode *dvp = ap->a_dvp; - struct vnode **vpp = ap->a_vpp; - int flags = cnp->cn_flags; - struct vnode *newvp; - u_int32_t *tl; - caddr_t cp; - int32_t t1, t2; - struct nfsmount *nmp; - caddr_t bpos, dpos, cp2; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - long len; - nfsfh_t *fhp; - struct nfsnode *np; - int lockparent, wantparent, error = 0, attrflag, fhsize; - int v3 = NFS_ISV3(dvp); - struct thread *td = cnp->cn_thread; - - *vpp = NULLVP; - cnp->cn_flags &= ~PDIRUNLOCK; - if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && - (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) - return (EROFS); - if (dvp->v_type != VDIR) - return (ENOTDIR); - lockparent = flags & LOCKPARENT; - wantparent = flags & (LOCKPARENT|WANTPARENT); - nmp = VFSTONFS(dvp->v_mount); - np = VTONFS(dvp); - if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) { - struct vattr vattr; - int vpid; - - if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) { - *vpp = NULLVP; - return (error); - } - - newvp = *vpp; - vpid = newvp->v_id; - /* - * See the comment starting `Step through' in ufs/ufs_lookup.c - * for an explanation of the locking protocol - */ - if (dvp == newvp) { - VREF(newvp); - error = 0; - } else if (flags & ISDOTDOT) { - VOP_UNLOCK(dvp, 0, td); - cnp->cn_flags |= PDIRUNLOCK; - error = vget(newvp, LK_EXCLUSIVE, td); - if (!error && lockparent && (flags & ISLASTCN)) { - error = vn_lock(dvp, LK_EXCLUSIVE, td); - if (error == 0) - cnp->cn_flags &= ~PDIRUNLOCK; - } - } else { - error = vget(newvp, LK_EXCLUSIVE, td); - if (!lockparent || error || !(flags & ISLASTCN)) { - VOP_UNLOCK(dvp, 0, td); - cnp->cn_flags |= PDIRUNLOCK; - } - } - if (!error) { - if (vpid == newvp->v_id) { - if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, td) - && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) { - nfsstats.lookupcache_hits++; - if (cnp->cn_nameiop != LOOKUP && - (flags & ISLASTCN)) - cnp->cn_flags |= SAVENAME; - return (0); - } - cache_purge(newvp); - } - vput(newvp); - if (lockparent && dvp != newvp && (flags & ISLASTCN)) - VOP_UNLOCK(dvp, 0, td); - } - error = vn_lock(dvp, LK_EXCLUSIVE, td); - *vpp = NULLVP; - if (error) { - cnp->cn_flags |= PDIRUNLOCK; - return (error); - } - cnp->cn_flags &= ~PDIRUNLOCK; - } - error = 0; - newvp = NULLVP; - nfsstats.lookupcache_misses++; - nfsstats.rpccnt[NFSPROC_LOOKUP]++; - len = cnp->cn_namelen; - nfsm_reqhead(dvp, NFSPROC_LOOKUP, - NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); - nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_thread, cnp->cn_cred); - if (error) { - nfsm_postop_attr(dvp, attrflag); - m_freem(mrep); - goto nfsmout; - } - nfsm_getfh(fhp, fhsize, v3); - - /* - * Handle RENAME case... - */ - if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) { - if (NFS_CMPFH(np, fhp, fhsize)) { - m_freem(mrep); - return (EISDIR); - } - error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); - if (error) { - m_freem(mrep); - return (error); - } - newvp = NFSTOV(np); - if (v3) { - nfsm_postop_attr(newvp, attrflag); - nfsm_postop_attr(dvp, attrflag); - } else - nfsm_loadattr(newvp, (struct vattr *)0); - *vpp = newvp; - m_freem(mrep); - cnp->cn_flags |= SAVENAME; - if (!lockparent) { - VOP_UNLOCK(dvp, 0, td); - cnp->cn_flags |= PDIRUNLOCK; - } - return (0); - } - - if (flags & ISDOTDOT) { - VOP_UNLOCK(dvp, 0, td); - error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); - if (error) { - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); - return (error); - } - newvp = NFSTOV(np); - if (lockparent && (flags & ISLASTCN)) { - error = vn_lock(dvp, LK_EXCLUSIVE, td); - if (error) { - cnp->cn_flags |= PDIRUNLOCK; - vput(newvp); - return (error); - } - } else - cnp->cn_flags |= PDIRUNLOCK; - } else if (NFS_CMPFH(np, fhp, fhsize)) { - VREF(dvp); - newvp = dvp; - } else { - error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); - if (error) { - m_freem(mrep); - return (error); - } - if (!lockparent || !(flags & ISLASTCN)) { - cnp->cn_flags |= PDIRUNLOCK; - VOP_UNLOCK(dvp, 0, td); - } - newvp = NFSTOV(np); - } - if (v3) { - nfsm_postop_attr(newvp, attrflag); - nfsm_postop_attr(dvp, attrflag); - } else - nfsm_loadattr(newvp, (struct vattr *)0); - if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) - cnp->cn_flags |= SAVENAME; - if ((cnp->cn_flags & MAKEENTRY) && - (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) { - np->n_ctime = np->n_vattr.va_ctime.tv_sec; - cache_enter(dvp, newvp, cnp); - } - *vpp = newvp; - nfsm_reqdone; - if (error) { - if (newvp != NULLVP) { - vrele(newvp); - *vpp = NULLVP; - } - if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && - (flags & ISLASTCN) && error == ENOENT) { - if (!lockparent) { - VOP_UNLOCK(dvp, 0, td); - cnp->cn_flags |= PDIRUNLOCK; - } - if (dvp->v_mount->mnt_flag & MNT_RDONLY) - error = EROFS; - else - error = EJUSTRETURN; - } - if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) - cnp->cn_flags |= SAVENAME; - } - return (error); -} - -/* - * nfs read call. - * Just call nfs_bioread() to do the work. - */ -static int -nfs_read(ap) - struct vop_read_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - - if (vp->v_type != VREG) - return (EPERM); - return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred)); -} - -/* - * nfs readlink call - */ -static int -nfs_readlink(ap) - struct vop_readlink_args /* { - struct vnode *a_vp; - struct uio *a_uio; - struct ucred *a_cred; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - - if (vp->v_type != VLNK) - return (EINVAL); - return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred)); -} - -/* - * Do a readlink rpc. - * Called by nfs_doio() from below the buffer cache. - */ -int -nfs_readlinkrpc(vp, uiop, cred) - register struct vnode *vp; - struct uio *uiop; - struct ucred *cred; -{ - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; - int error = 0, len, attrflag; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - int v3 = NFS_ISV3(vp); - - nfsstats.rpccnt[NFSPROC_READLINK]++; - nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3)); - nfsm_fhtom(vp, v3); - nfsm_request(vp, NFSPROC_READLINK, uiop->uio_td, cred); - if (v3) - nfsm_postop_attr(vp, attrflag); - if (!error) { - nfsm_strsiz(len, NFS_MAXPATHLEN); - if (len == NFS_MAXPATHLEN) { - struct nfsnode *np = VTONFS(vp); - if (np->n_size && np->n_size < NFS_MAXPATHLEN) - len = np->n_size; - } - nfsm_mtouio(uiop, len); - } - nfsm_reqdone; - return (error); -} - -/* - * nfs read rpc call - * Ditto above - */ -int -nfs_readrpc(vp, uiop, cred) - register struct vnode *vp; - struct uio *uiop; - struct ucred *cred; -{ - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - struct nfsmount *nmp; - int error = 0, len, retlen, tsiz, eof, attrflag; - int v3 = NFS_ISV3(vp); - -#ifndef nolint - eof = 0; -#endif - nmp = VFSTONFS(vp->v_mount); - tsiz = uiop->uio_resid; - if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize) - return (EFBIG); - while (tsiz > 0) { - nfsstats.rpccnt[NFSPROC_READ]++; - len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; - nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3); - nfsm_fhtom(vp, v3); - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED * 3); - if (v3) { - txdr_hyper(uiop->uio_offset, tl); - *(tl + 2) = txdr_unsigned(len); - } else { - *tl++ = txdr_unsigned(uiop->uio_offset); - *tl++ = txdr_unsigned(len); - *tl = 0; - } - nfsm_request(vp, NFSPROC_READ, uiop->uio_td, cred); - if (v3) { - nfsm_postop_attr(vp, attrflag); - if (error) { - m_freem(mrep); - goto nfsmout; - } - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - eof = fxdr_unsigned(int, *(tl + 1)); - } else - nfsm_loadattr(vp, (struct vattr *)0); - nfsm_strsiz(retlen, nmp->nm_rsize); - nfsm_mtouio(uiop, retlen); - m_freem(mrep); - tsiz -= retlen; - if (v3) { - if (eof || retlen == 0) - tsiz = 0; - } else if (retlen < len) - tsiz = 0; - } -nfsmout: - return (error); -} - -/* - * nfs write call - */ -int -nfs_writerpc(vp, uiop, cred, iomode, must_commit) - register struct vnode *vp; - register struct uio *uiop; - struct ucred *cred; - int *iomode, *must_commit; -{ - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2, backup; - caddr_t bpos, dpos, cp2; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - struct nfsmount *nmp = VFSTONFS(vp->v_mount); - int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit; - int v3 = NFS_ISV3(vp), committed = NFSV3WRITE_FILESYNC; - -#ifndef DIAGNOSTIC - if (uiop->uio_iovcnt != 1) - panic("nfs: writerpc iovcnt > 1"); -#endif - *must_commit = 0; - tsiz = uiop->uio_resid; - if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize) - return (EFBIG); - while (tsiz > 0) { - nfsstats.rpccnt[NFSPROC_WRITE]++; - len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz; - nfsm_reqhead(vp, NFSPROC_WRITE, - NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len)); - nfsm_fhtom(vp, v3); - if (v3) { - nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED); - txdr_hyper(uiop->uio_offset, tl); - tl += 2; - *tl++ = txdr_unsigned(len); - *tl++ = txdr_unsigned(*iomode); - *tl = txdr_unsigned(len); - } else { - register u_int32_t x; - - nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); - /* Set both "begin" and "current" to non-garbage. */ - x = txdr_unsigned((u_int32_t)uiop->uio_offset); - *tl++ = x; /* "begin offset" */ - *tl++ = x; /* "current offset" */ - x = txdr_unsigned(len); - *tl++ = x; /* total to this offset */ - *tl = x; /* size of this write */ - } - nfsm_uiotom(uiop, len); - nfsm_request(vp, NFSPROC_WRITE, uiop->uio_td, cred); - if (v3) { - wccflag = NFSV3_WCCCHK; - nfsm_wcc_data(vp, wccflag); - if (!error) { - nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED - + NFSX_V3WRITEVERF); - rlen = fxdr_unsigned(int, *tl++); - if (rlen == 0) { - error = NFSERR_IO; - m_freem(mrep); - break; - } else if (rlen < len) { - backup = len - rlen; - uiop->uio_iov->iov_base -= backup; - uiop->uio_iov->iov_len += backup; - uiop->uio_offset -= backup; - uiop->uio_resid += backup; - len = rlen; - } - commit = fxdr_unsigned(int, *tl++); - - /* - * Return the lowest committment level - * obtained by any of the RPCs. - */ - if (committed == NFSV3WRITE_FILESYNC) - committed = commit; - else if (committed == NFSV3WRITE_DATASYNC && - commit == NFSV3WRITE_UNSTABLE) - committed = commit; - if ((nmp->nm_state & NFSSTA_HASWRITEVERF) == 0){ - bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf, - NFSX_V3WRITEVERF); - nmp->nm_state |= NFSSTA_HASWRITEVERF; - } else if (bcmp((caddr_t)tl, - (caddr_t)nmp->nm_verf, NFSX_V3WRITEVERF)) { - *must_commit = 1; - bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf, - NFSX_V3WRITEVERF); - } - } - } else - nfsm_loadattr(vp, (struct vattr *)0); - if (wccflag) - VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec; - m_freem(mrep); - if (error) - break; - tsiz -= len; - } -nfsmout: - if (vp->v_mount->mnt_flag & MNT_ASYNC) - committed = NFSV3WRITE_FILESYNC; - *iomode = committed; - if (error) - uiop->uio_resid = tsiz; - return (error); -} - -/* - * nfs mknod rpc - * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the - * mode set to specify the file type and the size field for rdev. - */ -static int -nfs_mknodrpc(dvp, vpp, cnp, vap) - register struct vnode *dvp; - register struct vnode **vpp; - register struct componentname *cnp; - register struct vattr *vap; -{ - register struct nfsv2_sattr *sp; - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - struct vnode *newvp = (struct vnode *)0; - struct nfsnode *np = (struct nfsnode *)0; - struct vattr vattr; - char *cp2; - caddr_t bpos, dpos; - int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - u_int32_t rdev; - int v3 = NFS_ISV3(dvp); - - if (vap->va_type == VCHR || vap->va_type == VBLK) - rdev = txdr_unsigned(vap->va_rdev); - else if (vap->va_type == VFIFO || vap->va_type == VSOCK) - rdev = nfs_xdrneg1; - else { - return (EOPNOTSUPP); - } - if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread)) != 0) { - return (error); - } - nfsstats.rpccnt[NFSPROC_MKNOD]++; - nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED + - + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); - if (v3) { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); - *tl++ = vtonfsv3_type(vap->va_type); - nfsm_v3attrbuild(vap, FALSE); - if (vap->va_type == VCHR || vap->va_type == VBLK) { - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - *tl++ = txdr_unsigned(umajor(vap->va_rdev)); - *tl = txdr_unsigned(uminor(vap->va_rdev)); - } - } else { - nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); - sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); - sp->sa_uid = nfs_xdrneg1; - sp->sa_gid = nfs_xdrneg1; - sp->sa_size = rdev; - txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); - txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); - } - nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_thread, cnp->cn_cred); - if (!error) { - nfsm_mtofh(dvp, newvp, v3, gotvp); - if (!gotvp) { - if (newvp) { - vput(newvp); - newvp = (struct vnode *)0; - } - error = nfs_lookitup(dvp, cnp->cn_nameptr, - cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread, &np); - if (!error) - newvp = NFSTOV(np); - } - } - if (v3) - nfsm_wcc_data(dvp, wccflag); - nfsm_reqdone; - if (error) { - if (newvp) - vput(newvp); - } else { - if (cnp->cn_flags & MAKEENTRY) - cache_enter(dvp, newvp, cnp); - *vpp = newvp; - } - VTONFS(dvp)->n_flag |= NMODIFIED; - if (!wccflag) - VTONFS(dvp)->n_attrstamp = 0; - return (error); -} - -/* - * nfs mknod vop - * just call nfs_mknodrpc() to do the work. - */ -/* ARGSUSED */ -static int -nfs_mknod(ap) - struct vop_mknod_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vattr *a_vap; - } */ *ap; -{ - return nfs_mknodrpc(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap); -} - -static u_long create_verf; -/* - * nfs file create call - */ -static int -nfs_create(ap) - struct vop_create_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vattr *a_vap; - } */ *ap; -{ - register struct vnode *dvp = ap->a_dvp; - register struct vattr *vap = ap->a_vap; - register struct componentname *cnp = ap->a_cnp; - register struct nfsv2_sattr *sp; - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - struct nfsnode *np = (struct nfsnode *)0; - struct vnode *newvp = (struct vnode *)0; - caddr_t bpos, dpos, cp2; - int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - struct vattr vattr; - int v3 = NFS_ISV3(dvp); - - /* - * Oops, not for me.. - */ - if (vap->va_type == VSOCK) - return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap)); - - if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread)) != 0) { - return (error); - } - if (vap->va_vaflags & VA_EXCLUSIVE) - fmode |= O_EXCL; -again: - nfsstats.rpccnt[NFSPROC_CREATE]++; - nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED + - nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); - if (v3) { - nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); - if (fmode & O_EXCL) { - *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE); - nfsm_build(tl, u_int32_t *, NFSX_V3CREATEVERF); -#ifdef INET - if (!TAILQ_EMPTY(&in_ifaddrhead)) - *tl++ = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr.s_addr; - else -#endif - *tl++ = create_verf; - *tl = ++create_verf; - } else { - *tl = txdr_unsigned(NFSV3CREATE_UNCHECKED); - nfsm_v3attrbuild(vap, FALSE); - } - } else { - nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); - sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); - sp->sa_uid = nfs_xdrneg1; - sp->sa_gid = nfs_xdrneg1; - sp->sa_size = 0; - txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); - txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); - } - nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_thread, cnp->cn_cred); - if (!error) { - nfsm_mtofh(dvp, newvp, v3, gotvp); - if (!gotvp) { - if (newvp) { - vput(newvp); - newvp = (struct vnode *)0; - } - error = nfs_lookitup(dvp, cnp->cn_nameptr, - cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread, &np); - if (!error) - newvp = NFSTOV(np); - } - } - if (v3) - nfsm_wcc_data(dvp, wccflag); - nfsm_reqdone; - if (error) { - if (v3 && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) { - fmode &= ~O_EXCL; - goto again; - } - if (newvp) - vput(newvp); - } else if (v3 && (fmode & O_EXCL)) { - /* - * We are normally called with only a partially initialized - * VAP. Since the NFSv3 spec says that server may use the - * file attributes to store the verifier, the spec requires - * us to do a SETATTR RPC. FreeBSD servers store the verifier - * in atime, but we can't really assume that all servers will - * so we ensure that our SETATTR sets both atime and mtime. - */ - if (vap->va_mtime.tv_sec == VNOVAL) - vfs_timestamp(&vap->va_mtime); - if (vap->va_atime.tv_sec == VNOVAL) - vap->va_atime = vap->va_mtime; - error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_thread); - } - if (!error) { - if (cnp->cn_flags & MAKEENTRY) - cache_enter(dvp, newvp, cnp); - *ap->a_vpp = newvp; - } - VTONFS(dvp)->n_flag |= NMODIFIED; - if (!wccflag) - VTONFS(dvp)->n_attrstamp = 0; - return (error); -} - -/* - * nfs file remove call - * To try and make nfs semantics closer to ufs semantics, a file that has - * other processes using the vnode is renamed instead of removed and then - * removed later on the last close. - * - If v_usecount > 1 - * If a rename is not already in the works - * call nfs_sillyrename() to set it up - * else - * do the remove rpc - */ -static int -nfs_remove(ap) - struct vop_remove_args /* { - struct vnodeop_desc *a_desc; - struct vnode * a_dvp; - struct vnode * a_vp; - struct componentname * a_cnp; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - register struct vnode *dvp = ap->a_dvp; - register struct componentname *cnp = ap->a_cnp; - register struct nfsnode *np = VTONFS(vp); - int error = 0; - struct vattr vattr; - -#ifndef DIAGNOSTIC - if ((cnp->cn_flags & HASBUF) == 0) - panic("nfs_remove: no name"); - if (vp->v_usecount < 1) - panic("nfs_remove: bad v_usecount"); -#endif - if (vp->v_type == VDIR) - error = EPERM; - else if (vp->v_usecount == 1 || (np->n_sillyrename && - VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_thread) == 0 && - vattr.va_nlink > 1)) { - /* - * Purge the name cache so that the chance of a lookup for - * the name succeeding while the remove is in progress is - * minimized. Without node locking it can still happen, such - * that an I/O op returns ESTALE, but since you get this if - * another host removes the file.. - */ - cache_purge(vp); - /* - * throw away biocache buffers, mainly to avoid - * unnecessary delayed writes later. - */ - error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_thread, 1); - /* Do the rpc */ - if (error != EINTR) - error = nfs_removerpc(dvp, cnp->cn_nameptr, - cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread); - /* - * Kludge City: If the first reply to the remove rpc is lost.. - * the reply to the retransmitted request will be ENOENT - * since the file was in fact removed - * Therefore, we cheat and return success. - */ - if (error == ENOENT) - error = 0; - } else if (!np->n_sillyrename) - error = nfs_sillyrename(dvp, vp, cnp); - np->n_attrstamp = 0; - return (error); -} - -/* - * nfs file remove rpc called from nfs_inactive - */ -int -nfs_removeit(sp) - register struct sillyrename *sp; -{ - - return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred, - (struct thread *)0)); -} - -/* - * Nfs remove rpc, called from nfs_remove() and nfs_removeit(). - */ -static int -nfs_removerpc(dvp, name, namelen, cred, td) - register struct vnode *dvp; - const char *name; - int namelen; - struct ucred *cred; - struct thread *td; -{ - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; - int error = 0, wccflag = NFSV3_WCCRATTR; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - int v3 = NFS_ISV3(dvp); - - nfsstats.rpccnt[NFSPROC_REMOVE]++; - nfsm_reqhead(dvp, NFSPROC_REMOVE, - NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(name, namelen, NFS_MAXNAMLEN); - nfsm_request(dvp, NFSPROC_REMOVE, td, cred); - if (v3) - nfsm_wcc_data(dvp, wccflag); - nfsm_reqdone; - VTONFS(dvp)->n_flag |= NMODIFIED; - if (!wccflag) - VTONFS(dvp)->n_attrstamp = 0; - return (error); -} - -/* - * nfs file rename call - */ -static int -nfs_rename(ap) - struct vop_rename_args /* { - struct vnode *a_fdvp; - struct vnode *a_fvp; - struct componentname *a_fcnp; - struct vnode *a_tdvp; - struct vnode *a_tvp; - struct componentname *a_tcnp; - } */ *ap; -{ - register struct vnode *fvp = ap->a_fvp; - register struct vnode *tvp = ap->a_tvp; - register struct vnode *fdvp = ap->a_fdvp; - register struct vnode *tdvp = ap->a_tdvp; - register struct componentname *tcnp = ap->a_tcnp; - register struct componentname *fcnp = ap->a_fcnp; - int error; - -#ifndef DIAGNOSTIC - if ((tcnp->cn_flags & HASBUF) == 0 || - (fcnp->cn_flags & HASBUF) == 0) - panic("nfs_rename: no name"); -#endif - /* Check for cross-device rename */ - if ((fvp->v_mount != tdvp->v_mount) || - (tvp && (fvp->v_mount != tvp->v_mount))) { - error = EXDEV; - goto out; - } - - /* - * We have to flush B_DELWRI data prior to renaming - * the file. If we don't, the delayed-write buffers - * can be flushed out later after the file has gone stale - * under NFSV3. NFSV2 does not have this problem because - * ( as far as I can tell ) it flushes dirty buffers more - * often. - */ - - VOP_FSYNC(fvp, fcnp->cn_cred, MNT_WAIT, fcnp->cn_thread); - if (tvp) - VOP_FSYNC(tvp, tcnp->cn_cred, MNT_WAIT, tcnp->cn_thread); - - /* - * If the tvp exists and is in use, sillyrename it before doing the - * rename of the new file over it. - * XXX Can't sillyrename a directory. - */ - if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename && - tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) { - vput(tvp); - tvp = NULL; - } - - error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen, - tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred, - tcnp->cn_thread); - - if (fvp->v_type == VDIR) { - if (tvp != NULL && tvp->v_type == VDIR) - cache_purge(tdvp); - cache_purge(fdvp); - } - -out: - if (tdvp == tvp) - vrele(tdvp); - else - vput(tdvp); - if (tvp) - vput(tvp); - vrele(fdvp); - vrele(fvp); - /* - * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. - */ - if (error == ENOENT) - error = 0; - return (error); -} - -/* - * nfs file rename rpc called from nfs_remove() above - */ -static int -nfs_renameit(sdvp, scnp, sp) - struct vnode *sdvp; - struct componentname *scnp; - register struct sillyrename *sp; -{ - return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen, - sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_thread)); -} - -/* - * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit(). - */ -static int -nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, td) - register struct vnode *fdvp; - const char *fnameptr; - int fnamelen; - register struct vnode *tdvp; - const char *tnameptr; - int tnamelen; - struct ucred *cred; - struct thread *td; -{ - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; - int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - int v3 = NFS_ISV3(fdvp); - - nfsstats.rpccnt[NFSPROC_RENAME]++; - nfsm_reqhead(fdvp, NFSPROC_RENAME, - (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) + - nfsm_rndup(tnamelen)); - nfsm_fhtom(fdvp, v3); - nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN); - nfsm_fhtom(tdvp, v3); - nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN); - nfsm_request(fdvp, NFSPROC_RENAME, td, cred); - if (v3) { - nfsm_wcc_data(fdvp, fwccflag); - nfsm_wcc_data(tdvp, twccflag); - } - nfsm_reqdone; - VTONFS(fdvp)->n_flag |= NMODIFIED; - VTONFS(tdvp)->n_flag |= NMODIFIED; - if (!fwccflag) - VTONFS(fdvp)->n_attrstamp = 0; - if (!twccflag) - VTONFS(tdvp)->n_attrstamp = 0; - return (error); -} - -/* - * nfs hard link create call - */ -static int -nfs_link(ap) - struct vop_link_args /* { - struct vnode *a_tdvp; - struct vnode *a_vp; - struct componentname *a_cnp; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - register struct vnode *tdvp = ap->a_tdvp; - register struct componentname *cnp = ap->a_cnp; - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; - int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - int v3; - - if (vp->v_mount != tdvp->v_mount) { - return (EXDEV); - } - - /* - * Push all writes to the server, so that the attribute cache - * doesn't get "out of sync" with the server. - * XXX There should be a better way! - */ - VOP_FSYNC(vp, cnp->cn_cred, MNT_WAIT, cnp->cn_thread); - - v3 = NFS_ISV3(vp); - nfsstats.rpccnt[NFSPROC_LINK]++; - nfsm_reqhead(vp, NFSPROC_LINK, - NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen)); - nfsm_fhtom(vp, v3); - nfsm_fhtom(tdvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); - nfsm_request(vp, NFSPROC_LINK, cnp->cn_thread, cnp->cn_cred); - if (v3) { - nfsm_postop_attr(vp, attrflag); - nfsm_wcc_data(tdvp, wccflag); - } - nfsm_reqdone; - VTONFS(tdvp)->n_flag |= NMODIFIED; - if (!attrflag) - VTONFS(vp)->n_attrstamp = 0; - if (!wccflag) - VTONFS(tdvp)->n_attrstamp = 0; - /* - * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. - */ - if (error == EEXIST) - error = 0; - return (error); -} - -/* - * nfs symbolic link create call - */ -static int -nfs_symlink(ap) - struct vop_symlink_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vattr *a_vap; - char *a_target; - } */ *ap; -{ - register struct vnode *dvp = ap->a_dvp; - register struct vattr *vap = ap->a_vap; - register struct componentname *cnp = ap->a_cnp; - register struct nfsv2_sattr *sp; - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; - int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - struct vnode *newvp = (struct vnode *)0; - int v3 = NFS_ISV3(dvp); - - nfsstats.rpccnt[NFSPROC_SYMLINK]++; - slen = strlen(ap->a_target); - nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED + - nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); - if (v3) { - nfsm_v3attrbuild(vap, FALSE); - } - nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN); - if (!v3) { - nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); - sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode); - sp->sa_uid = nfs_xdrneg1; - sp->sa_gid = nfs_xdrneg1; - sp->sa_size = nfs_xdrneg1; - txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); - txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); - } - - /* - * Issue the NFS request and get the rpc response. - * - * Only NFSv3 responses returning an error of 0 actually return - * a file handle that can be converted into newvp without having - * to do an extra lookup rpc. - */ - nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_thread, cnp->cn_cred); - if (v3) { - if (error == 0) - nfsm_mtofh(dvp, newvp, v3, gotvp); - nfsm_wcc_data(dvp, wccflag); - } - - /* - * out code jumps -> here, mrep is also freed. - */ - - nfsm_reqdone; - - /* - * If we get an EEXIST error, silently convert it to no-error - * in case of an NFS retry. - */ - if (error == EEXIST) - error = 0; - - /* - * If we do not have (or no longer have) an error, and we could - * not extract the newvp from the response due to the request being - * NFSv2 or the error being EEXIST. We have to do a lookup in order - * to obtain a newvp to return. - */ - if (error == 0 && newvp == NULL) { - struct nfsnode *np = NULL; - - error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen, - cnp->cn_cred, cnp->cn_thread, &np); - if (!error) - newvp = NFSTOV(np); - } - if (error) { - if (newvp) - vput(newvp); - } else { - *ap->a_vpp = newvp; - } - VTONFS(dvp)->n_flag |= NMODIFIED; - if (!wccflag) - VTONFS(dvp)->n_attrstamp = 0; - return (error); -} - -/* - * nfs make dir call - */ -static int -nfs_mkdir(ap) - struct vop_mkdir_args /* { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vattr *a_vap; - } */ *ap; -{ - register struct vnode *dvp = ap->a_dvp; - register struct vattr *vap = ap->a_vap; - register struct componentname *cnp = ap->a_cnp; - register struct nfsv2_sattr *sp; - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - register int len; - struct nfsnode *np = (struct nfsnode *)0; - struct vnode *newvp = (struct vnode *)0; - caddr_t bpos, dpos, cp2; - int error = 0, wccflag = NFSV3_WCCRATTR; - int gotvp = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - struct vattr vattr; - int v3 = NFS_ISV3(dvp); - - if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread)) != 0) { - return (error); - } - len = cnp->cn_namelen; - nfsstats.rpccnt[NFSPROC_MKDIR]++; - nfsm_reqhead(dvp, NFSPROC_MKDIR, - NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); - if (v3) { - nfsm_v3attrbuild(vap, FALSE); - } else { - nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); - sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode); - sp->sa_uid = nfs_xdrneg1; - sp->sa_gid = nfs_xdrneg1; - sp->sa_size = nfs_xdrneg1; - txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); - txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); - } - nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_thread, cnp->cn_cred); - if (!error) - nfsm_mtofh(dvp, newvp, v3, gotvp); - if (v3) - nfsm_wcc_data(dvp, wccflag); - nfsm_reqdone; - VTONFS(dvp)->n_flag |= NMODIFIED; - if (!wccflag) - VTONFS(dvp)->n_attrstamp = 0; - /* - * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry - * if we can succeed in looking up the directory. - */ - if (error == EEXIST || (!error && !gotvp)) { - if (newvp) { - vrele(newvp); - newvp = (struct vnode *)0; - } - error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred, - cnp->cn_thread, &np); - if (!error) { - newvp = NFSTOV(np); - if (newvp->v_type != VDIR) - error = EEXIST; - } - } - if (error) { - if (newvp) - vrele(newvp); - } else - *ap->a_vpp = newvp; - return (error); -} - -/* - * nfs remove directory call - */ -static int -nfs_rmdir(ap) - struct vop_rmdir_args /* { - struct vnode *a_dvp; - struct vnode *a_vp; - struct componentname *a_cnp; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - register struct vnode *dvp = ap->a_dvp; - register struct componentname *cnp = ap->a_cnp; - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - caddr_t bpos, dpos, cp2; - int error = 0, wccflag = NFSV3_WCCRATTR; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - int v3 = NFS_ISV3(dvp); - - if (dvp == vp) - return (EINVAL); - nfsstats.rpccnt[NFSPROC_RMDIR]++; - nfsm_reqhead(dvp, NFSPROC_RMDIR, - NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); - nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_thread, cnp->cn_cred); - if (v3) - nfsm_wcc_data(dvp, wccflag); - nfsm_reqdone; - VTONFS(dvp)->n_flag |= NMODIFIED; - if (!wccflag) - VTONFS(dvp)->n_attrstamp = 0; - cache_purge(dvp); - cache_purge(vp); - /* - * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. - */ - if (error == ENOENT) - error = 0; - return (error); -} - -/* - * nfs readdir call - */ -static int -nfs_readdir(ap) - struct vop_readdir_args /* { - struct vnode *a_vp; - struct uio *a_uio; - struct ucred *a_cred; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - register struct nfsnode *np = VTONFS(vp); - register struct uio *uio = ap->a_uio; - int tresid, error; - struct vattr vattr; - - if (vp->v_type != VDIR) - return (EPERM); - /* - * First, check for hit on the EOF offset cache - */ - if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset && - (np->n_flag & NMODIFIED) == 0) { - if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { - if (NQNFS_CKCACHABLE(vp, ND_READ)) { - nfsstats.direofcache_hits++; - return (0); - } - } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_td) == 0 && - np->n_mtime == vattr.va_mtime.tv_sec) { - nfsstats.direofcache_hits++; - return (0); - } - } - - /* - * Call nfs_bioread() to do the real work. - */ - tresid = uio->uio_resid; - error = nfs_bioread(vp, uio, 0, ap->a_cred); - - if (!error && uio->uio_resid == tresid) - nfsstats.direofcache_misses++; - return (error); -} - -/* - * Readdir rpc call. - * Called from below the buffer cache by nfs_doio(). - */ -int -nfs_readdirrpc(vp, uiop, cred) - struct vnode *vp; - register struct uio *uiop; - struct ucred *cred; - -{ - register int len, left; - register struct dirent *dp = NULL; - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - register nfsuint64 *cookiep; - caddr_t bpos, dpos, cp2; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - nfsuint64 cookie; - struct nfsmount *nmp = VFSTONFS(vp->v_mount); - struct nfsnode *dnp = VTONFS(vp); - u_quad_t fileno; - int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; - int attrflag; - int v3 = NFS_ISV3(vp); - -#ifndef DIAGNOSTIC - if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) || - (uiop->uio_resid & (DIRBLKSIZ - 1))) - panic("nfs readdirrpc bad uio"); -#endif - - /* - * If there is no cookie, assume directory was stale. - */ - cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0); - if (cookiep) - cookie = *cookiep; - else - return (NFSERR_BAD_COOKIE); - /* - * Loop around doing readdir rpc's of size nm_readdirsize - * truncated to a multiple of DIRBLKSIZ. - * The stopping criteria is EOF or buffer full. - */ - while (more_dirs && bigenough) { - nfsstats.rpccnt[NFSPROC_READDIR]++; - nfsm_reqhead(vp, NFSPROC_READDIR, NFSX_FH(v3) + - NFSX_READDIR(v3)); - nfsm_fhtom(vp, v3); - if (v3) { - nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED); - *tl++ = cookie.nfsuquad[0]; - *tl++ = cookie.nfsuquad[1]; - *tl++ = dnp->n_cookieverf.nfsuquad[0]; - *tl++ = dnp->n_cookieverf.nfsuquad[1]; - } else { - nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - *tl++ = cookie.nfsuquad[0]; - } - *tl = txdr_unsigned(nmp->nm_readdirsize); - nfsm_request(vp, NFSPROC_READDIR, uiop->uio_td, cred); - if (v3) { - nfsm_postop_attr(vp, attrflag); - if (!error) { - nfsm_dissect(tl, u_int32_t *, - 2 * NFSX_UNSIGNED); - dnp->n_cookieverf.nfsuquad[0] = *tl++; - dnp->n_cookieverf.nfsuquad[1] = *tl; - } else { - m_freem(mrep); - goto nfsmout; - } - } - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - more_dirs = fxdr_unsigned(int, *tl); - - /* loop thru the dir entries, doctoring them to 4bsd form */ - while (more_dirs && bigenough) { - if (v3) { - nfsm_dissect(tl, u_int32_t *, - 3 * NFSX_UNSIGNED); - fileno = fxdr_hyper(tl); - len = fxdr_unsigned(int, *(tl + 2)); - } else { - nfsm_dissect(tl, u_int32_t *, - 2 * NFSX_UNSIGNED); - fileno = fxdr_unsigned(u_quad_t, *tl++); - len = fxdr_unsigned(int, *tl); - } - if (len <= 0 || len > NFS_MAXNAMLEN) { - error = EBADRPC; - m_freem(mrep); - goto nfsmout; - } - tlen = nfsm_rndup(len); - if (tlen == len) - tlen += 4; /* To ensure null termination */ - left = DIRBLKSIZ - blksiz; - if ((tlen + DIRHDSIZ) > left) { - dp->d_reclen += left; - uiop->uio_iov->iov_base += left; - uiop->uio_iov->iov_len -= left; - uiop->uio_offset += left; - uiop->uio_resid -= left; - blksiz = 0; - } - if ((tlen + DIRHDSIZ) > uiop->uio_resid) - bigenough = 0; - if (bigenough) { - dp = (struct dirent *)uiop->uio_iov->iov_base; - dp->d_fileno = (int)fileno; - dp->d_namlen = len; - dp->d_reclen = tlen + DIRHDSIZ; - dp->d_type = DT_UNKNOWN; - blksiz += dp->d_reclen; - if (blksiz == DIRBLKSIZ) - blksiz = 0; - uiop->uio_offset += DIRHDSIZ; - uiop->uio_resid -= DIRHDSIZ; - uiop->uio_iov->iov_base += DIRHDSIZ; - uiop->uio_iov->iov_len -= DIRHDSIZ; - nfsm_mtouio(uiop, len); - cp = uiop->uio_iov->iov_base; - tlen -= len; - *cp = '\0'; /* null terminate */ - uiop->uio_iov->iov_base += tlen; - uiop->uio_iov->iov_len -= tlen; - uiop->uio_offset += tlen; - uiop->uio_resid -= tlen; - } else - nfsm_adv(nfsm_rndup(len)); - if (v3) { - nfsm_dissect(tl, u_int32_t *, - 3 * NFSX_UNSIGNED); - } else { - nfsm_dissect(tl, u_int32_t *, - 2 * NFSX_UNSIGNED); - } - if (bigenough) { - cookie.nfsuquad[0] = *tl++; - if (v3) - cookie.nfsuquad[1] = *tl++; - } else if (v3) - tl += 2; - else - tl++; - more_dirs = fxdr_unsigned(int, *tl); - } - /* - * If at end of rpc data, get the eof boolean - */ - if (!more_dirs) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - more_dirs = (fxdr_unsigned(int, *tl) == 0); - } - m_freem(mrep); - } - /* - * Fill last record, iff any, out to a multiple of DIRBLKSIZ - * by increasing d_reclen for the last record. - */ - if (blksiz > 0) { - left = DIRBLKSIZ - blksiz; - dp->d_reclen += left; - uiop->uio_iov->iov_base += left; - uiop->uio_iov->iov_len -= left; - uiop->uio_offset += left; - uiop->uio_resid -= left; - } - - /* - * We are now either at the end of the directory or have filled the - * block. - */ - if (bigenough) - dnp->n_direofoffset = uiop->uio_offset; - else { - if (uiop->uio_resid > 0) - printf("EEK! readdirrpc resid > 0\n"); - cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1); - *cookiep = cookie; - } -nfsmout: - return (error); -} - -/* - * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc(). - */ -int -nfs_readdirplusrpc(vp, uiop, cred) - struct vnode *vp; - register struct uio *uiop; - struct ucred *cred; -{ - register int len, left; - register struct dirent *dp; - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - register struct vnode *newvp; - register nfsuint64 *cookiep; - caddr_t bpos, dpos, cp2, dpossav1, dpossav2; - struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2; - struct nameidata nami, *ndp = &nami; - struct componentname *cnp = &ndp->ni_cnd; - nfsuint64 cookie; - struct nfsmount *nmp = VFSTONFS(vp->v_mount); - struct nfsnode *dnp = VTONFS(vp), *np; - nfsfh_t *fhp; - u_quad_t fileno; - int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i; - int attrflag, fhsize; - -#ifndef nolint - dp = (struct dirent *)0; -#endif -#ifndef DIAGNOSTIC - if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) || - (uiop->uio_resid & (DIRBLKSIZ - 1))) - panic("nfs readdirplusrpc bad uio"); -#endif - ndp->ni_dvp = vp; - newvp = NULLVP; - - /* - * If there is no cookie, assume directory was stale. - */ - cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0); - if (cookiep) - cookie = *cookiep; - else - return (NFSERR_BAD_COOKIE); - /* - * Loop around doing readdir rpc's of size nm_readdirsize - * truncated to a multiple of DIRBLKSIZ. - * The stopping criteria is EOF or buffer full. - */ - while (more_dirs && bigenough) { - nfsstats.rpccnt[NFSPROC_READDIRPLUS]++; - nfsm_reqhead(vp, NFSPROC_READDIRPLUS, - NFSX_FH(1) + 6 * NFSX_UNSIGNED); - nfsm_fhtom(vp, 1); - nfsm_build(tl, u_int32_t *, 6 * NFSX_UNSIGNED); - *tl++ = cookie.nfsuquad[0]; - *tl++ = cookie.nfsuquad[1]; - *tl++ = dnp->n_cookieverf.nfsuquad[0]; - *tl++ = dnp->n_cookieverf.nfsuquad[1]; - *tl++ = txdr_unsigned(nmp->nm_readdirsize); - *tl = txdr_unsigned(nmp->nm_rsize); - nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_td, cred); - nfsm_postop_attr(vp, attrflag); - if (error) { - m_freem(mrep); - goto nfsmout; - } - nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); - dnp->n_cookieverf.nfsuquad[0] = *tl++; - dnp->n_cookieverf.nfsuquad[1] = *tl++; - more_dirs = fxdr_unsigned(int, *tl); - - /* loop thru the dir entries, doctoring them to 4bsd form */ - while (more_dirs && bigenough) { - nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); - fileno = fxdr_hyper(tl); - len = fxdr_unsigned(int, *(tl + 2)); - if (len <= 0 || len > NFS_MAXNAMLEN) { - error = EBADRPC; - m_freem(mrep); - goto nfsmout; - } - tlen = nfsm_rndup(len); - if (tlen == len) - tlen += 4; /* To ensure null termination*/ - left = DIRBLKSIZ - blksiz; - if ((tlen + DIRHDSIZ) > left) { - dp->d_reclen += left; - uiop->uio_iov->iov_base += left; - uiop->uio_iov->iov_len -= left; - uiop->uio_offset += left; - uiop->uio_resid -= left; - blksiz = 0; - } - if ((tlen + DIRHDSIZ) > uiop->uio_resid) - bigenough = 0; - if (bigenough) { - dp = (struct dirent *)uiop->uio_iov->iov_base; - dp->d_fileno = (int)fileno; - dp->d_namlen = len; - dp->d_reclen = tlen + DIRHDSIZ; - dp->d_type = DT_UNKNOWN; - blksiz += dp->d_reclen; - if (blksiz == DIRBLKSIZ) - blksiz = 0; - uiop->uio_offset += DIRHDSIZ; - uiop->uio_resid -= DIRHDSIZ; - uiop->uio_iov->iov_base += DIRHDSIZ; - uiop->uio_iov->iov_len -= DIRHDSIZ; - cnp->cn_nameptr = uiop->uio_iov->iov_base; - cnp->cn_namelen = len; - nfsm_mtouio(uiop, len); - cp = uiop->uio_iov->iov_base; - tlen -= len; - *cp = '\0'; - uiop->uio_iov->iov_base += tlen; - uiop->uio_iov->iov_len -= tlen; - uiop->uio_offset += tlen; - uiop->uio_resid -= tlen; - } else - nfsm_adv(nfsm_rndup(len)); - nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); - if (bigenough) { - cookie.nfsuquad[0] = *tl++; - cookie.nfsuquad[1] = *tl++; - } else - tl += 2; - - /* - * Since the attributes are before the file handle - * (sigh), we must skip over the attributes and then - * come back and get them. - */ - attrflag = fxdr_unsigned(int, *tl); - if (attrflag) { - dpossav1 = dpos; - mdsav1 = md; - nfsm_adv(NFSX_V3FATTR); - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - doit = fxdr_unsigned(int, *tl); - if (doit) { - nfsm_getfh(fhp, fhsize, 1); - if (NFS_CMPFH(dnp, fhp, fhsize)) { - VREF(vp); - newvp = vp; - np = dnp; - } else { - error = nfs_nget(vp->v_mount, fhp, - fhsize, &np); - if (error) - doit = 0; - else - newvp = NFSTOV(np); - } - } - if (doit && bigenough) { - dpossav2 = dpos; - dpos = dpossav1; - mdsav2 = md; - md = mdsav1; - nfsm_loadattr(newvp, (struct vattr *)0); - dpos = dpossav2; - md = mdsav2; - dp->d_type = - IFTODT(VTTOIF(np->n_vattr.va_type)); - ndp->ni_vp = newvp; - cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp); - } - } else { - /* Just skip over the file handle */ - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - i = fxdr_unsigned(int, *tl); - nfsm_adv(nfsm_rndup(i)); - } - if (newvp != NULLVP) { - if (newvp == vp) - vrele(newvp); - else - vput(newvp); - newvp = NULLVP; - } - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - more_dirs = fxdr_unsigned(int, *tl); - } - /* - * If at end of rpc data, get the eof boolean - */ - if (!more_dirs) { - nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); - more_dirs = (fxdr_unsigned(int, *tl) == 0); - } - m_freem(mrep); - } - /* - * Fill last record, iff any, out to a multiple of DIRBLKSIZ - * by increasing d_reclen for the last record. - */ - if (blksiz > 0) { - left = DIRBLKSIZ - blksiz; - dp->d_reclen += left; - uiop->uio_iov->iov_base += left; - uiop->uio_iov->iov_len -= left; - uiop->uio_offset += left; - uiop->uio_resid -= left; - } - - /* - * We are now either at the end of the directory or have filled the - * block. - */ - if (bigenough) - dnp->n_direofoffset = uiop->uio_offset; - else { - if (uiop->uio_resid > 0) - printf("EEK! readdirplusrpc resid > 0\n"); - cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1); - *cookiep = cookie; - } -nfsmout: - if (newvp != NULLVP) { - if (newvp == vp) - vrele(newvp); - else - vput(newvp); - newvp = NULLVP; - } - return (error); -} - -/* - * 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... - */ -static int -nfs_sillyrename(dvp, vp, cnp) - struct vnode *dvp, *vp; - struct componentname *cnp; -{ - register struct sillyrename *sp; - struct nfsnode *np; - int error; - short pid; - - cache_purge(dvp); - np = VTONFS(vp); -#ifndef DIAGNOSTIC - if (vp->v_type == VDIR) - panic("nfs: sillyrename dir"); -#endif - MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), - M_NFSREQ, M_WAITOK); - sp->s_cred = crdup(cnp->cn_cred); - sp->s_dvp = dvp; - VREF(dvp); - - /* Fudge together a funny name */ - pid = cnp->cn_thread->td_proc->p_pid; - sp->s_namlen = sprintf(sp->s_name, ".nfsA%04x4.4", pid); - - /* Try lookitups until we get one that isn't there */ - while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, - cnp->cn_thread, (struct nfsnode **)0) == 0) { - sp->s_name[4]++; - if (sp->s_name[4] > 'z') { - error = EINVAL; - goto bad; - } - } - error = nfs_renameit(dvp, cnp, sp); - if (error) - goto bad; - error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, - cnp->cn_thread, &np); - np->n_sillyrename = sp; - return (0); -bad: - vrele(sp->s_dvp); - crfree(sp->s_cred); - free((caddr_t)sp, M_NFSREQ); - return (error); -} - -/* - * Look up a file name and optionally either update the file handle or - * allocate an nfsnode, depending on the value of npp. - * npp == NULL --> just do the lookup - * *npp == NULL --> allocate a new nfsnode and make sure attributes are - * handled too - * *npp != NULL --> update the file handle in the vnode - */ -static int -nfs_lookitup(dvp, name, len, cred, td, npp) - register struct vnode *dvp; - const char *name; - int len; - struct ucred *cred; - struct thread *td; - struct nfsnode **npp; -{ - register u_int32_t *tl; - register caddr_t cp; - register int32_t t1, t2; - struct vnode *newvp = (struct vnode *)0; - struct nfsnode *np, *dnp = VTONFS(dvp); - caddr_t bpos, dpos, cp2; - int error = 0, fhlen, attrflag; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - nfsfh_t *nfhp; - int v3 = NFS_ISV3(dvp); - - nfsstats.rpccnt[NFSPROC_LOOKUP]++; - nfsm_reqhead(dvp, NFSPROC_LOOKUP, - NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len)); - nfsm_fhtom(dvp, v3); - nfsm_strtom(name, len, NFS_MAXNAMLEN); - nfsm_request(dvp, NFSPROC_LOOKUP, td, cred); - if (npp && !error) { - nfsm_getfh(nfhp, fhlen, v3); - if (*npp) { - np = *npp; - if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) { - free((caddr_t)np->n_fhp, M_NFSBIGFH); - np->n_fhp = &np->n_fh; - } else if (np->n_fhsize <= NFS_SMALLFH && fhlen>NFS_SMALLFH) - np->n_fhp =(nfsfh_t *)malloc(fhlen,M_NFSBIGFH,M_WAITOK); - bcopy((caddr_t)nfhp, (caddr_t)np->n_fhp, fhlen); - np->n_fhsize = fhlen; - newvp = NFSTOV(np); - } else if (NFS_CMPFH(dnp, nfhp, fhlen)) { - VREF(dvp); - newvp = dvp; - } else { - error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np); - if (error) { - m_freem(mrep); - return (error); - } - newvp = NFSTOV(np); - } - if (v3) { - nfsm_postop_attr(newvp, attrflag); - if (!attrflag && *npp == NULL) { - m_freem(mrep); - if (newvp == dvp) - vrele(newvp); - else - vput(newvp); - return (ENOENT); - } - } else - nfsm_loadattr(newvp, (struct vattr *)0); - } - nfsm_reqdone; - if (npp && *npp == NULL) { - if (error) { - if (newvp) { - if (newvp == dvp) - vrele(newvp); - else - vput(newvp); - } - } else - *npp = np; - } - return (error); -} - -/* - * Nfs Version 3 commit rpc - */ -int -nfs_commit(vp, offset, cnt, cred, td) - struct vnode *vp; - u_quad_t offset; - int cnt; - struct ucred *cred; - struct thread *td; -{ - register caddr_t cp; - register u_int32_t *tl; - register int32_t t1, t2; - register struct nfsmount *nmp = VFSTONFS(vp->v_mount); - caddr_t bpos, dpos, cp2; - int error = 0, wccflag = NFSV3_WCCRATTR; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - - if ((nmp->nm_state & NFSSTA_HASWRITEVERF) == 0) - return (0); - nfsstats.rpccnt[NFSPROC_COMMIT]++; - nfsm_reqhead(vp, NFSPROC_COMMIT, NFSX_FH(1)); - nfsm_fhtom(vp, 1); - nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED); - txdr_hyper(offset, tl); - tl += 2; - *tl = txdr_unsigned(cnt); - nfsm_request(vp, NFSPROC_COMMIT, td, cred); - nfsm_wcc_data(vp, wccflag); - if (!error) { - nfsm_dissect(tl, u_int32_t *, NFSX_V3WRITEVERF); - if (bcmp((caddr_t)nmp->nm_verf, (caddr_t)tl, - NFSX_V3WRITEVERF)) { - bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf, - NFSX_V3WRITEVERF); - error = NFSERR_STALEWRITEVERF; - } - } - nfsm_reqdone; - return (error); -} - -/* - * Strategy routine. - * For async requests when nfsiod(s) are running, queue the request by - * calling nfs_asyncio(), otherwise just all nfs_doio() to do the - * request. - */ -static int -nfs_strategy(ap) - struct vop_strategy_args *ap; -{ - register struct buf *bp = ap->a_bp; - struct ucred *cr; - struct thread *td; - int error = 0; - - KASSERT(!(bp->b_flags & B_DONE), ("nfs_strategy: buffer %p unexpectedly marked B_DONE", bp)); - KASSERT(BUF_REFCNT(bp) > 0, ("nfs_strategy: buffer %p not locked", bp)); - - if (bp->b_flags & B_PHYS) - panic("nfs physio"); - - if (bp->b_flags & B_ASYNC) - td = (struct thread *)0; - else - td = curthread; /* XXX */ - - if (bp->b_iocmd == BIO_READ) - cr = bp->b_rcred; - else - cr = bp->b_wcred; - - /* - * If the op is asynchronous and an i/o daemon is waiting - * queue the request, wake it up and wait for completion - * otherwise just do it ourselves. - */ - if ((bp->b_flags & B_ASYNC) == 0 || - nfs_asyncio(bp, NOCRED, td)) - error = nfs_doio(bp, cr, td); - return (error); -} - -/* - * fsync vnode op. Just call nfs_flush() with commit == 1. - */ -/* ARGSUSED */ -static int -nfs_fsync(ap) - struct vop_fsync_args /* { - struct vnodeop_desc *a_desc; - struct vnode * a_vp; - struct ucred * a_cred; - int a_waitfor; - struct thread * a_td; - } */ *ap; -{ - - return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1)); -} - -/* - * Flush all the blocks associated with a vnode. - * Walk through the buffer pool and push any dirty pages - * associated with the vnode. - */ -static int -nfs_flush(vp, cred, waitfor, td, commit) - register struct vnode *vp; - struct ucred *cred; - int waitfor; - struct thread *td; - int commit; -{ - register struct nfsnode *np = VTONFS(vp); - register struct buf *bp; - register int i; - struct buf *nbp; - struct nfsmount *nmp = VFSTONFS(vp->v_mount); - int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos; - int passone = 1; - u_quad_t off, endoff, toff; - struct ucred* wcred = NULL; - struct buf **bvec = NULL; -#ifndef NFS_COMMITBVECSIZ -#define NFS_COMMITBVECSIZ 20 -#endif - struct buf *bvec_on_stack[NFS_COMMITBVECSIZ]; - int bvecsize = 0, bveccount; - - if (nmp->nm_flag & NFSMNT_INT) - slpflag = PCATCH; - if (!commit) - passone = 0; - /* - * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the - * server, but nas not been committed to stable storage on the server - * yet. On the first pass, the byte range is worked out and the commit - * rpc is done. On the second pass, nfs_writebp() is called to do the - * job. - */ -again: - off = (u_quad_t)-1; - endoff = 0; - bvecpos = 0; - if (NFS_ISV3(vp) && commit) { - s = splbio(); - /* - * Count up how many buffers waiting for a commit. - */ - bveccount = 0; - for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { - nbp = TAILQ_NEXT(bp, b_vnbufs); - if (BUF_REFCNT(bp) == 0 && - (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) - == (B_DELWRI | B_NEEDCOMMIT)) - bveccount++; - } - /* - * Allocate space to remember the list of bufs to commit. It is - * important to use M_NOWAIT here to avoid a race with nfs_write. - * If we can't get memory (for whatever reason), we will end up - * committing the buffers one-by-one in the loop below. - */ - if (bvec != NULL && bvec != bvec_on_stack) - free(bvec, M_TEMP); - if (bveccount > NFS_COMMITBVECSIZ) { - bvec = (struct buf **) - malloc(bveccount * sizeof(struct buf *), - M_TEMP, M_NOWAIT); - if (bvec == NULL) { - bvec = bvec_on_stack; - bvecsize = NFS_COMMITBVECSIZ; - } else - bvecsize = bveccount; - } else { - bvec = bvec_on_stack; - bvecsize = NFS_COMMITBVECSIZ; - } - for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { - nbp = TAILQ_NEXT(bp, b_vnbufs); - if (bvecpos >= bvecsize) - break; - if ((bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) != - (B_DELWRI | B_NEEDCOMMIT) || - BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) - continue; - bremfree(bp); - /* - * Work out if all buffers are using the same cred - * so we can deal with them all with one commit. - * - * NOTE: we are not clearing B_DONE here, so we have - * to do it later on in this routine if we intend to - * initiate I/O on the bp. - * - * Note: to avoid loopback deadlocks, we do not - * assign b_runningbufspace. - */ - if (wcred == NULL) - wcred = bp->b_wcred; - else if (wcred != bp->b_wcred) - wcred = NOCRED; - bp->b_flags |= B_WRITEINPROG; - vfs_busy_pages(bp, 1); - - /* - * bp is protected by being locked, but nbp is not - * and vfs_busy_pages() may sleep. We have to - * recalculate nbp. - */ - nbp = TAILQ_NEXT(bp, b_vnbufs); - - /* - * A list of these buffers is kept so that the - * second loop knows which buffers have actually - * been committed. This is necessary, since there - * may be a race between the commit rpc and new - * uncommitted writes on the file. - */ - bvec[bvecpos++] = bp; - toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + - bp->b_dirtyoff; - if (toff < off) - off = toff; - toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff); - if (toff > endoff) - endoff = toff; - } - splx(s); - } - if (bvecpos > 0) { - /* - * Commit data on the server, as required. - * If all bufs are using the same wcred, then use that with - * one call for all of them, otherwise commit each one - * separately. - */ - if (wcred != NOCRED) - retv = nfs_commit(vp, off, (int)(endoff - off), - wcred, td); - else { - retv = 0; - for (i = 0; i < bvecpos; i++) { - off_t off, size; - bp = bvec[i]; - off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + - bp->b_dirtyoff; - size = (u_quad_t)(bp->b_dirtyend - - bp->b_dirtyoff); - retv = nfs_commit(vp, off, (int)size, - bp->b_wcred, td); - if (retv) break; - } - } - - if (retv == NFSERR_STALEWRITEVERF) - nfs_clearcommit(vp->v_mount); - - /* - * Now, either mark the blocks I/O done or mark the - * blocks dirty, depending on whether the commit - * succeeded. - */ - for (i = 0; i < bvecpos; i++) { - bp = bvec[i]; - bp->b_flags &= ~(B_NEEDCOMMIT | B_WRITEINPROG | B_CLUSTEROK); - if (retv) { - /* - * Error, leave B_DELWRI intact - */ - vfs_unbusy_pages(bp); - brelse(bp); - } else { - /* - * Success, remove B_DELWRI ( bundirty() ). - * - * b_dirtyoff/b_dirtyend seem to be NFS - * specific. We should probably move that - * into bundirty(). XXX - */ - s = splbio(); - vp->v_numoutput++; - bp->b_flags |= B_ASYNC; - bundirty(bp); - bp->b_flags &= ~B_DONE; - bp->b_ioflags &= ~BIO_ERROR; - bp->b_dirtyoff = bp->b_dirtyend = 0; - splx(s); - bufdone(bp); - } - } - } - - /* - * Start/do any write(s) that are required. - */ -loop: - s = splbio(); - for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { - nbp = TAILQ_NEXT(bp, b_vnbufs); - if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) { - if (waitfor != MNT_WAIT || passone) - continue; - error = BUF_TIMELOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL, - "nfsfsync", slpflag, slptimeo); - splx(s); - if (error == 0) - panic("nfs_fsync: inconsistent lock"); - if (error == ENOLCK) - goto loop; - if (nfs_sigintr(nmp, (struct nfsreq *)0, td->td_proc)) { - error = EINTR; - goto done; - } - if (slpflag == PCATCH) { - slpflag = 0; - slptimeo = 2 * hz; - } - goto loop; - } - if ((bp->b_flags & B_DELWRI) == 0) - panic("nfs_fsync: not dirty"); - if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT)) { - BUF_UNLOCK(bp); - continue; - } - bremfree(bp); - if (passone || !commit) - bp->b_flags |= B_ASYNC; - else - bp->b_flags |= B_ASYNC | B_WRITEINPROG; - splx(s); - BUF_WRITE(bp); - goto loop; - } - splx(s); - if (passone) { - passone = 0; - goto again; - } - if (waitfor == MNT_WAIT) { - while (vp->v_numoutput) { - vp->v_flag |= VBWAIT; - error = tsleep((caddr_t)&vp->v_numoutput, - slpflag | (PRIBIO + 1), "nfsfsync", slptimeo); - if (error) { - if (nfs_sigintr(nmp, (struct nfsreq *)0, td->td_proc)) { - error = EINTR; - goto done; - } - if (slpflag == PCATCH) { - slpflag = 0; - slptimeo = 2 * hz; - } - } - } - if (!TAILQ_EMPTY(&vp->v_dirtyblkhd) && commit) { - goto loop; - } - } - if (np->n_flag & NWRITEERR) { - error = np->n_error; - np->n_flag &= ~NWRITEERR; - } -done: - if (bvec != NULL && bvec != bvec_on_stack) - free(bvec, M_TEMP); - return (error); -} - -/* - * NFS advisory byte-level locks. - */ -static int -nfs_advlock(ap) - struct vop_advlock_args /* { - struct vnode *a_vp; - caddr_t a_id; - int a_op; - struct flock *a_fl; - int a_flags; - } */ *ap; -{ - - return (nfs_dolock(ap)); -} - -/* - * Print out the contents of an nfsnode. - */ -static int -nfs_print(ap) - struct vop_print_args /* { - struct vnode *a_vp; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - register struct nfsnode *np = VTONFS(vp); - - printf("tag VT_NFS, fileid %ld fsid 0x%x", - np->n_vattr.va_fileid, np->n_vattr.va_fsid); - if (vp->v_type == VFIFO) - fifo_printinfo(vp); - printf("\n"); - return (0); -} - -/* - * This is the "real" nfs::bwrite(struct buf*). - * B_WRITEINPROG isn't set unless the force flag is one and it - * handles the B_NEEDCOMMIT flag. - * We set B_CACHE if this is a VMIO buffer. - */ -int -nfs_writebp(bp, force, td) - register struct buf *bp; - int force; - struct thread *td; -{ - int s; - int oldflags = bp->b_flags; -#if 0 - int retv = 1; - off_t off; -#endif - - if (BUF_REFCNT(bp) == 0) - panic("bwrite: buffer is not locked???"); - - if (bp->b_flags & B_INVAL) { - brelse(bp); - return(0); - } - - bp->b_flags |= B_CACHE; - - /* - * Undirty the bp. We will redirty it later if the I/O fails. - */ - - s = splbio(); - bundirty(bp); - bp->b_flags &= ~B_DONE; - bp->b_ioflags &= ~BIO_ERROR; - bp->b_iocmd = BIO_WRITE; - - bp->b_vp->v_numoutput++; - curthread->td_proc->p_stats->p_ru.ru_oublock++; - splx(s); - - /* - * Note: to avoid loopback deadlocks, we do not - * assign b_runningbufspace. - */ - vfs_busy_pages(bp, 1); - - if (force) - bp->b_flags |= B_WRITEINPROG; - BUF_KERNPROC(bp); - BUF_STRATEGY(bp); - - if( (oldflags & B_ASYNC) == 0) { - int rtval = bufwait(bp); - - if (oldflags & B_DELWRI) { - s = splbio(); - reassignbuf(bp, bp->b_vp); - splx(s); - } - - brelse(bp); - return (rtval); - } - - return (0); -} - -/* - * nfs special file access vnode op. - * Essentially just get vattr and then imitate iaccess() since the device is - * local to the client. - */ -static int -nfsspec_access(ap) - struct vop_access_args /* { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct thread *a_td; - } */ *ap; -{ - register struct vattr *vap; - register gid_t *gp; - register struct ucred *cred = ap->a_cred; - struct vnode *vp = ap->a_vp; - mode_t mode = ap->a_mode; - struct vattr vattr; - register int i; - int error; - - /* - * Disallow write attempts on filesystems mounted read-only; - * unless the file is a socket, fifo, or a block or character - * device resident on the filesystem. - */ - if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { - switch (vp->v_type) { - case VREG: - case VDIR: - case VLNK: - return (EROFS); - default: - break; - } - } - /* - * If you're the super-user, - * you always get access. - */ - if (cred->cr_uid == 0) - return (0); - vap = &vattr; - error = VOP_GETATTR(vp, vap, cred, ap->a_td); - if (error) - return (error); - /* - * 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) { - mode >>= 3; - gp = cred->cr_groups; - for (i = 0; i < cred->cr_ngroups; i++, gp++) - if (vap->va_gid == *gp) - goto found; - mode >>= 3; -found: - ; - } - error = (vap->va_mode & mode) == mode ? 0 : EACCES; - return (error); -} - -/* - * Read wrapper for special devices. - */ -static int -nfsspec_read(ap) - struct vop_read_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; - } */ *ap; -{ - register struct nfsnode *np = VTONFS(ap->a_vp); - - /* - * Set access flag. - */ - np->n_flag |= NACC; - getnanotime(&np->n_atim); - return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap)); -} - -/* - * Write wrapper for special devices. - */ -static int -nfsspec_write(ap) - struct vop_write_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; - } */ *ap; -{ - register struct nfsnode *np = VTONFS(ap->a_vp); - - /* - * Set update flag. - */ - np->n_flag |= NUPD; - getnanotime(&np->n_mtim); - return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap)); -} - -/* - * Close wrapper for special devices. - * - * Update the times on the nfsnode then do device close. - */ -static int -nfsspec_close(ap) - struct vop_close_args /* { - struct vnode *a_vp; - int a_fflag; - struct ucred *a_cred; - struct thread *a_td; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - register struct nfsnode *np = VTONFS(vp); - struct vattr vattr; - - if (np->n_flag & (NACC | NUPD)) { - np->n_flag |= NCHG; - if (vp->v_usecount == 1 && - (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { - VATTR_NULL(&vattr); - if (np->n_flag & NACC) - vattr.va_atime = np->n_atim; - if (np->n_flag & NUPD) - vattr.va_mtime = np->n_mtim; - (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_td); - } - } - return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap)); -} - -/* - * Read wrapper for fifos. - */ -static int -nfsfifo_read(ap) - struct vop_read_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; - } */ *ap; -{ - register struct nfsnode *np = VTONFS(ap->a_vp); - - /* - * Set access flag. - */ - np->n_flag |= NACC; - getnanotime(&np->n_atim); - return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap)); -} - -/* - * Write wrapper for fifos. - */ -static int -nfsfifo_write(ap) - struct vop_write_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; - } */ *ap; -{ - register struct nfsnode *np = VTONFS(ap->a_vp); - - /* - * Set update flag. - */ - np->n_flag |= NUPD; - getnanotime(&np->n_mtim); - return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap)); -} - -/* - * Close wrapper for fifos. - * - * Update the times on the nfsnode then do fifo close. - */ -static int -nfsfifo_close(ap) - struct vop_close_args /* { - struct vnode *a_vp; - int a_fflag; - struct ucred *a_cred; - struct thread *a_td; - } */ *ap; -{ - register struct vnode *vp = ap->a_vp; - register struct nfsnode *np = VTONFS(vp); - struct vattr vattr; - struct timespec ts; - - if (np->n_flag & (NACC | NUPD)) { - getnanotime(&ts); - if (np->n_flag & NACC) - np->n_atim = ts; - if (np->n_flag & NUPD) - np->n_mtim = ts; - np->n_flag |= NCHG; - if (vp->v_usecount == 1 && - (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { - VATTR_NULL(&vattr); - if (np->n_flag & NACC) - vattr.va_atime = np->n_atim; - if (np->n_flag & NUPD) - vattr.va_mtime = np->n_mtim; - (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_td); - } - } - return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap)); -} diff --git a/sys/nfs/nfsdiskless.h b/sys/nfs/nfsdiskless.h deleted file mode 100644 index 487e0bf..0000000 --- a/sys/nfs/nfsdiskless.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfsdiskless.h 8.2 (Berkeley) 3/30/95 - * $FreeBSD$ - */ - - -#ifndef _NFS_NFSDISKLESS_H_ -#define _NFS_NFSDISKLESS_H_ - -/* - * Structure that must be initialized for a diskless nfs client. - * This structure is used by nfs_mountroot() to set up the root vnode, - * and to do a partial ifconfig(8) and route(8) so that the critical net - * interface can communicate with the server. - * The primary bootstrap is expected to fill in the appropriate fields before - * starting the kernel. Whether or not the swap area is nfs mounted is - * determined by the value in swdevt[0]. (equal to NODEV --> swap over nfs) - * Currently only works for AF_INET protocols. - * NB: All fields are stored in net byte order to avoid hassles with - * client/server byte ordering differences. - */ - -/* - * I have defined a new structure that can handle an NFS Version 3 file handle - * but the kernel still expects the old Version 2 one to be provided. The - * changes required in nfs_vfsops.c for using the new are documented there in - * comments. (I felt that breaking network booting code by changing this - * structure would not be prudent at this time, since almost all servers are - * still Version 2 anyhow.) - */ -struct nfsv3_diskless { - struct ifaliasreq myif; /* Default interface */ - struct sockaddr_in mygateway; /* Default gateway */ - struct nfs_args swap_args; /* Mount args for swap file */ - int swap_fhsize; /* Size of file handle */ - u_char swap_fh[NFSX_V3FHMAX]; /* Swap file's file handle */ - struct sockaddr_in swap_saddr; /* Address of swap server */ - char swap_hostnam[MNAMELEN]; /* Host name for mount pt */ - int swap_nblks; /* Size of server swap file */ - struct ucred swap_ucred; /* Swap credentials */ - struct nfs_args root_args; /* Mount args for root fs */ - int root_fhsize; /* Size of root file handle */ - u_char root_fh[NFSX_V3FHMAX]; /* File handle of root dir */ - struct sockaddr_in root_saddr; /* Address of root server */ - char root_hostnam[MNAMELEN]; /* Host name for mount pt */ - long root_time; /* Timestamp of root fs */ - char my_hostnam[MAXHOSTNAMELEN]; /* Client host name */ -}; - -/* - * Old arguments to mount NFS - */ -struct onfs_args { - struct sockaddr *addr; /* file server address */ - int addrlen; /* length of address */ - int sotype; /* Socket type */ - int proto; /* and Protocol */ - u_char *fh; /* File handle to be mounted */ - int fhsize; /* Size, in bytes, of fh */ - int flags; /* flags */ - int wsize; /* write size in bytes */ - int rsize; /* read size in bytes */ - int readdirsize; /* readdir size in bytes */ - int timeo; /* initial timeout in .1 secs */ - int retrans; /* times to retry send */ - int maxgrouplist; /* Max. size of group list */ - int readahead; /* # of blocks to readahead */ - int leaseterm; /* Term (sec) of lease */ - int deadthresh; /* Retrans threshold */ - char *hostname; /* server's name */ -}; - -struct nfs_diskless { - struct ifaliasreq myif; /* Default interface */ - struct sockaddr_in mygateway; /* Default gateway */ - struct onfs_args swap_args; /* Mount args for swap file */ - u_char swap_fh[NFSX_V2FH]; /* Swap file's file handle */ - struct sockaddr_in swap_saddr; /* Address of swap server */ - char swap_hostnam[MNAMELEN]; /* Host name for mount pt */ - int swap_nblks; /* Size of server swap file */ - struct ucred swap_ucred; /* Swap credentials */ - struct onfs_args root_args; /* Mount args for root fs */ - u_char root_fh[NFSX_V2FH]; /* File handle of root dir */ - struct sockaddr_in root_saddr; /* Address of root server */ - char root_hostnam[MNAMELEN]; /* Host name for mount pt */ - long root_time; /* Timestamp of root fs */ - char my_hostnam[MAXHOSTNAMELEN]; /* Client host name */ -}; - -#endif diff --git a/sys/nfs/nfsmount.h b/sys/nfs/nfsmount.h deleted file mode 100644 index d6f8a8b..0000000 --- a/sys/nfs/nfsmount.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfsmount.h 8.3 (Berkeley) 3/30/95 - * $FreeBSD$ - */ - - -#ifndef _NFS_NFSMOUNT_H_ -#define _NFS_NFSMOUNT_H_ - -/* - * Mount structure. - * One allocated on every NFS mount. - * Holds NFS specific information for mount. - */ -struct nfsmount { - int nm_flag; /* Flags for soft/hard... */ - int nm_state; /* Internal state flags */ - struct mount *nm_mountp; /* Vfs structure for this filesystem */ - int nm_numgrps; /* Max. size of groupslist */ - u_char nm_fh[NFSX_V3FHMAX]; /* File handle of root dir */ - int nm_fhsize; /* Size of root file handle */ - struct socket *nm_so; /* Rpc socket */ - int nm_sotype; /* Type of socket */ - int nm_soproto; /* and protocol */ - int nm_soflags; /* pr_flags for socket protocol */ - struct sockaddr *nm_nam; /* Addr of server */ - int nm_timeo; /* Init timer for NFSMNT_DUMBTIMR */ - int nm_retry; /* Max retries */ - int nm_srtt[4]; /* Timers for rpcs */ - int nm_sdrtt[4]; - int nm_sent; /* Request send count */ - int nm_cwnd; /* Request send window */ - int nm_timeouts; /* Request timeouts */ - int nm_deadthresh; /* Threshold of timeouts-->dead server*/ - int nm_rsize; /* Max size of read rpc */ - int nm_wsize; /* Max size of write rpc */ - int nm_readdirsize; /* Size of a readdir rpc */ - int nm_readahead; /* Num. of blocks to readahead */ - int nm_leaseterm; /* Term (sec) for NQNFS lease */ - int nm_acdirmin; /* Directory attr cache min lifetime */ - int nm_acdirmax; /* Directory attr cache max lifetime */ - int nm_acregmin; /* Reg file attr cache min lifetime */ - int nm_acregmax; /* Reg file attr cache max lifetime */ - TAILQ_HEAD(timhd, nfsnode) nm_timerhead; /* Head of lease timer queue */ - struct vnode *nm_inprog; /* Vnode in prog by nqnfs_clientd() */ - uid_t nm_authuid; /* Uid for authenticator */ - int nm_authtype; /* Authenticator type */ - int nm_authlen; /* and length */ - char *nm_authstr; /* Authenticator string */ - char *nm_verfstr; /* and the verifier */ - int nm_verflen; - u_char nm_verf[NFSX_V3WRITEVERF]; /* V3 write verifier */ - NFSKERBKEY_T nm_key; /* and the session key */ - int nm_numuids; /* Number of nfsuid mappings */ - TAILQ_HEAD(, nfsuid) nm_uidlruhead; /* Lists of nfsuid mappings */ - LIST_HEAD(, nfsuid) nm_uidhashtbl[NFS_MUIDHASHSIZ]; - TAILQ_HEAD(, buf) nm_bufq; /* async io buffer queue */ - short nm_bufqlen; /* number of buffers in queue */ - short nm_bufqwant; /* process wants to add to the queue */ - int nm_bufqiods; /* number of iods processing queue */ - u_int64_t nm_maxfilesize; /* maximum file size */ -}; - -#if defined(_KERNEL) -/* - * Convert mount ptr to nfsmount ptr. - */ -#define VFSTONFS(mp) ((struct nfsmount *)((mp)->mnt_data)) - -#endif - -#endif diff --git a/sys/nfs/nfsproto.h b/sys/nfs/nfsproto.h index cbb2832..8f62ab1 100644 --- a/sys/nfs/nfsproto.h +++ b/sys/nfs/nfsproto.h @@ -169,14 +169,8 @@ #define NFSPROC_FSINFO 19 #define NFSPROC_PATHCONF 20 #define NFSPROC_COMMIT 21 - -/* And leasing (nqnfs) procedure numbers (must be last) */ -#define NQNFSPROC_GETLEASE 22 -#define NQNFSPROC_VACATED 23 -#define NQNFSPROC_EVICTED 24 - -#define NFSPROC_NOOP 25 -#define NFS_NPROCS 26 +#define NFSPROC_NOOP 22 +#define NFS_NPROCS 23 /* Actual Version 2 procedure numbers */ #define NFSV2PROC_NULL 0 @@ -226,17 +220,6 @@ #define NFSV3FSINFO_HOMOGENEOUS 0x08 #define NFSV3FSINFO_CANSETTIME 0x10 -/* Conversion macros */ -#define vtonfsv2_mode(t,m) \ - txdr_unsigned(((t) == VFIFO) ? MAKEIMODE(VCHR, (m)) : \ - MAKEIMODE((t), (m))) -#define vtonfsv3_mode(m) txdr_unsigned((m) & ALLPERMS) -#define nfstov_mode(a) (fxdr_unsigned(u_int32_t, (a)) & ALLPERMS) -#define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((int32_t)(a))]) -#define vtonfsv3_type(a) txdr_unsigned(nfsv3_type[((int32_t)(a))]) -#define nfsv2tov_type(a) nv2tov_type[fxdr_unsigned(u_int32_t,(a))&0x7] -#define nfsv3tov_type(a) nv3tov_type[fxdr_unsigned(u_int32_t,(a))&0x7] - /* File types */ typedef enum { NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 } nfstype; diff --git a/sys/nfs/nfsrtt.h b/sys/nfs/nfsrtt.h deleted file mode 100644 index 4473086..0000000 --- a/sys/nfs/nfsrtt.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfsrtt.h 8.2 (Berkeley) 3/30/95 - * $FreeBSD$ - */ - - -#ifndef _NFS_NFSRTT_H_ -#define _NFS_NFSRTT_H_ - -/* - * Definitions for performance monitor. - * The client and server logging are turned on by setting the global - * constant "nfsrtton" to 1. - */ -#define NFSRTTLOGSIZ 128 - -/* - * Circular log of client side rpc activity. Each log entry is for one - * rpc filled in upon completion. (ie. in order of completion) - * The "pos" is the table index for the "next" entry, therefore the - * list goes from nfsrtt.rttl[pos] --> nfsrtt.rttl[pos - 1] in - * chronological order of completion. - */ -struct nfsrtt { - int pos; /* Position in array for next entry */ - struct rttl { - u_int32_t proc; /* NFS procedure number */ - int rtt; /* Measured round trip time */ - int rto; /* Round Trip Timeout */ - int sent; /* # rpcs in progress */ - int cwnd; /* Send window */ - int srtt; /* Ave Round Trip Time */ - int sdrtt; /* Ave mean deviation of RTT */ - fsid_t fsid; /* Fsid for mount point */ - struct timeval tstamp; /* Timestamp of log entry */ - } rttl[NFSRTTLOGSIZ]; -}; - -/* - * And definitions for server side performance monitor. - * The log organization is the same as above except it is filled in at the - * time the server sends the rpc reply. - */ - -/* - * Bits for the flags field. - */ -#define DRT_NQNFS 0x01 /* Rpc used Nqnfs protocol */ -#define DRT_TCP 0x02 /* Client used TCP transport */ -#define DRT_CACHEREPLY 0x04 /* Reply was from recent request cache */ -#define DRT_CACHEDROP 0x08 /* Rpc request dropped, due to recent reply */ -#define DRT_NFSV3 0x10 /* Rpc used NFS Version 3 */ - -/* - * Server log structure - * NB: ipadr == INADDR_ANY indicates a client using a non IP protocol. - * (ISO perhaps?) - */ -struct nfsdrt { - int pos; /* Position of next log entry */ - struct drt { - int flag; /* Bits as defined above */ - u_int32_t proc; /* NFS procedure number */ - u_int32_t ipadr; /* IP address of client */ - int resptime; /* Response time (usec) */ - struct timeval tstamp; /* Timestamp of log entry */ - } drt[NFSRTTLOGSIZ]; -}; - -#endif diff --git a/sys/nfs/nfsrvcache.h b/sys/nfs/nfsrvcache.h deleted file mode 100644 index eec5850..0000000 --- a/sys/nfs/nfsrvcache.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfsrvcache.h 8.3 (Berkeley) 3/30/95 - * $FreeBSD$ - */ - - -#ifndef _NFS_NFSRVCACHE_H_ -#define _NFS_NFSRVCACHE_H_ - -#include - -/* - * Definitions for the server recent request cache - */ - -#define NFSRVCACHESIZ 64 - -struct nfsrvcache { - TAILQ_ENTRY(nfsrvcache) rc_lru; /* LRU chain */ - LIST_ENTRY(nfsrvcache) rc_hash; /* Hash chain */ - u_int32_t rc_xid; /* rpc id number */ - union { - struct mbuf *ru_repmb; /* Reply mbuf list OR */ - int ru_repstat; /* Reply status */ - } rc_un; - union nethostaddr rc_haddr; /* Host address */ - u_int32_t rc_proc; /* rpc proc number */ - u_char rc_state; /* Current state of request */ - u_char rc_flag; /* Flag bits */ -}; - -#define rc_reply rc_un.ru_repmb -#define rc_status rc_un.ru_repstat -#define rc_inetaddr rc_haddr.had_inetaddr -#define rc_nam rc_haddr.had_nam - -/* Cache entry states */ -#define RC_UNUSED 0 -#define RC_INPROG 1 -#define RC_DONE 2 - -/* Return values */ -#define RC_DROPIT 0 -#define RC_REPLY 1 -#define RC_DOIT 2 -#define RC_CHECKIT 3 - -/* Flag bits */ -#define RC_LOCKED 0x01 -#define RC_WANTED 0x02 -#define RC_REPSTATUS 0x04 -#define RC_REPMBUF 0x08 -#define RC_NQNFS 0x10 -#define RC_INETADDR 0x20 -#define RC_NAM 0x40 - -#endif diff --git a/sys/nfs/nfsv2.h b/sys/nfs/nfsv2.h deleted file mode 100644 index 6f8f85e..0000000 --- a/sys/nfs/nfsv2.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfsv2.h 8.1 (Berkeley) 6/10/93 - * $FreeBSD$ - */ - -#include diff --git a/sys/nfs/nlminfo.h b/sys/nfs/nlminfo.h deleted file mode 100644 index 79c6e17..0000000 --- a/sys/nfs/nlminfo.h +++ /dev/null @@ -1,45 +0,0 @@ -/*- - * Copyright (c) 1998 Berkeley Software Design, Inc. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Berkeley Software Design Inc's name may not be used to endorse or - * promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from BSDI nlminfo.h,v 2.1 1998/03/18 01:30:38 don Exp - * $FreeBSD$ - */ - -/* - * Misc NLM informationi, some needed for the master lockd process, and some - * needed by every process doing nlm based locking. - */ -struct nlminfo { - /* these are used by any process doing nlm locking */ - int msg_seq; /* sequence counter for lock requests */ - int retcode; /* return code for lock requests */ - int set_getlk_pid; - int getlk_pid; - struct timeval pid_start; /* process starting time */ -}; - -extern void nlminfo_release __P((struct proc *p)); - diff --git a/sys/nfs/nqnfs.h b/sys/nfs/nqnfs.h deleted file mode 100644 index ce8d692..0000000 --- a/sys/nfs/nqnfs.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nqnfs.h 8.3 (Berkeley) 3/30/95 - * $FreeBSD$ - */ - - -#ifndef _NFS_NQNFS_H_ -#define _NFS_NQNFS_H_ - -/* - * Definitions for NQNFS (Not Quite NFS) cache consistency protocol. - */ - -/* Tunable constants */ -#define NQ_CLOCKSKEW 3 /* Clock skew factor (sec) */ -#define NQ_WRITESLACK 5 /* Delay for write cache flushing */ -#define NQ_MAXLEASE 60 /* Max lease duration (sec) */ -#define NQ_MINLEASE 5 /* Min lease duration (sec) */ -#define NQ_DEFLEASE 30 /* Default lease duration (sec) */ -#define NQ_RENEWAL 3 /* Time before expiry (sec) to renew */ -#define NQ_TRYLATERDEL 15 /* Initial try later delay (sec) */ -#define NQ_MAXNUMLEASE 2048 /* Upper bound on number of server leases */ -#define NQ_DEADTHRESH NQ_NEVERDEAD /* Default nm_deadthresh */ -#define NQ_NEVERDEAD 9 /* Greater than max. nm_timeouts */ -#define NQLCHSZ 256 /* Server hash table size */ - -#define NQNFS_PROG 300105 /* As assigned by Sun */ -#define NQNFS_VER3 3 -#define NQNFS_EVICTSIZ 156 /* Size of eviction request in bytes */ - -#if defined(_KERNEL) -/* - * Definitions used for saving the "last lease expires" time in Non-volatile - * RAM on the server. The default definitions below assume that NOVRAM is not - * available. - */ -#ifdef HASNVRAM -# undef HASNVRAM -#endif -#define NQSTORENOVRAM(t) -#define NQLOADNOVRAM(t) - -/* - * Defn and structs used on the server to maintain state for current leases. - * The list of host(s) that hold the lease are kept as nqhost structures. - * The first one lives in nqlease and any others are held in a linked - * list of nqm structures hanging off of nqlease. - * - * Each nqlease structure is chained into two lists. The first is a list - * ordered by increasing expiry time for nqsrv_timer() and the second is a chain - * hashed on lc_fh. - */ -#define LC_MOREHOSTSIZ 10 - -struct nqhost { - u_int16_t lph_flag; - u_int16_t lph_port; - struct nfssvc_sock *lph_slp; - - union { - struct { - union nethostaddr udp_haddr; - } un_udp; - struct { - int dummy; - } un_conn; - } lph_un; -}; -#define lph_haddr lph_un.un_udp.udp_haddr -#define lph_inetaddr lph_un.un_udp.udp_haddr.had_inetaddr - -struct nqlease { - LIST_ENTRY(nqlease) lc_hash; /* Fhandle hash list */ - TAILQ_ENTRY(nqlease) lc_timer; /* Timer queue list */ - time_t lc_expiry; /* Expiry time (sec) */ - struct nqhost lc_host; /* Host that got lease */ - struct nqm *lc_morehosts; /* Other hosts that share read lease */ - fsid_t lc_fsid; /* Fhandle */ - char lc_fiddata[MAXFIDSZ]; - struct vnode *lc_vp; /* Soft reference to associated vnode */ -}; -#define lc_flag lc_host.lph_flag - -/* lc_flag bits */ -#define LC_VALID 0x0001 /* Host address valid */ -#define LC_WRITE 0x0002 /* Write cache */ -#define LC_NONCACHABLE 0x0004 /* Non-cachable lease */ -#define LC_LOCKED 0x0008 /* Locked */ -#define LC_WANTED 0x0010 /* Lock wanted */ -#define LC_EXPIREDWANTED 0x0020 /* Want lease when expired */ -#define LC_UDP 0x0040 /* Host address for udp socket */ -/* 0x0080 free */ -#define LC_LOCAL 0x0100 /* Host is server */ -#define LC_VACATED 0x0200 /* Host has vacated lease */ -#define LC_WRITTEN 0x0400 /* Recently wrote to the leased file */ -#define LC_SREF 0x0800 /* Holds a nfssvc_sock reference */ - -struct nqm { - struct nqm *lpm_next; - struct nqhost lpm_hosts[LC_MOREHOSTSIZ]; -}; - -/* - * Special value for slp for local server calls. - */ -#define NQLOCALSLP ((struct nfssvc_sock *) -1) - -/* - * Server side macros. - */ -#define nqsrv_getl(v, l) \ - (void) nqsrv_getlease((v), &nfsd->nd_duration, \ - ((nfsd->nd_flag & ND_LEASE) ? (nfsd->nd_flag & ND_LEASE) : \ - ((l) | ND_CHECK)), \ - slp, td, nfsd->nd_nam, &cache, &frev, cred) - -/* - * Client side macros that check for a valid lease. - */ -#define NQNFS_CKINVALID(v, n, f) \ - ((time_second > (n)->n_expiry && \ - VFSTONFS((v)->v_mount)->nm_timeouts < VFSTONFS((v)->v_mount)->nm_deadthresh) \ - || ((f) == ND_WRITE && ((n)->n_flag & NQNFSWRITE) == 0)) - -#define NQNFS_CKCACHABLE(v, f) \ - ((time_second <= VTONFS(v)->n_expiry || \ - VFSTONFS((v)->v_mount)->nm_timeouts >= VFSTONFS((v)->v_mount)->nm_deadthresh) \ - && (VTONFS(v)->n_flag & NQNFSNONCACHE) == 0 && \ - ((f) == ND_READ || (VTONFS(v)->n_flag & NQNFSWRITE))) - -#define NQNFS_NEEDLEASE(v, p) \ - (time_second > VTONFS(v)->n_expiry ? \ - ((VTONFS(v)->n_flag & NQNFSEVICTED) ? 0 : nqnfs_piggy[p]) : \ - (((time_second + NQ_RENEWAL) > VTONFS(v)->n_expiry && \ - nqnfs_piggy[p]) ? \ - ((VTONFS(v)->n_flag & NQNFSWRITE) ? \ - ND_WRITE : nqnfs_piggy[p]) : 0)) - -/* - * List head for timer queue. - */ -extern TAILQ_HEAD(nqtimerhead, nqlease) nqtimerhead; - -/* - * List head for the file handle hash table. - */ -#define NQFHHASH(f) \ - (&nqfhhashtbl[(*((u_int32_t *)(f))) & nqfhhash]) -extern LIST_HEAD(nqfhhashhead, nqlease) *nqfhhashtbl; -extern u_long nqfhhash; - -/* - * Nqnfs return status numbers. - */ -#define NQNFS_EXPIRED 500 -#define NQNFS_TRYLATER 501 - -void nqnfs_lease_check __P((struct vnode *, struct thread *, struct ucred *, int)); -void nqnfs_lease_updatetime __P((int)); -int nqsrv_getlease __P((struct vnode *, u_int32_t *, int, - struct nfssvc_sock *, struct thread *, - struct sockaddr *, int *, u_quad_t *, - struct ucred *)); -int nqnfs_getlease __P((struct vnode *,int,struct ucred *,struct thread *)); -int nqnfs_callback __P((struct nfsmount *,struct mbuf *,struct mbuf *,caddr_t)); -int nqnfs_clientd __P((struct nfsmount *,struct ucred *,struct nfsd_cargs *,int,caddr_t,struct thread *)); -struct nfsnode; -void nqnfs_clientlease __P((struct nfsmount *, struct nfsnode *, int, int, time_t, u_quad_t)); -void nqnfs_serverd __P((void)); -int nqnfsrv_getlease __P((struct nfsrv_descript *, struct nfssvc_sock *, struct thread *, struct mbuf **)); -int nqnfsrv_vacated __P((struct nfsrv_descript *, struct nfssvc_sock *, struct thread *, struct mbuf **)); -#endif - -#endif diff --git a/sys/nfs/rpcv2.h b/sys/nfs/rpcv2.h index 525df09..977a8d3 100644 --- a/sys/nfs/rpcv2.h +++ b/sys/nfs/rpcv2.h @@ -53,8 +53,6 @@ #define RPCAUTH_NULL 0 #define RPCAUTH_UNIX 1 #define RPCAUTH_SHORT 2 -#define RPCAUTH_KERB4 4 -#define RPCAUTH_NQNFS 300000 #define RPCAUTH_MAXSIZ 400 #define RPCVERF_MAXSIZ 12 /* For Kerb, can actually be 400 */ #define RPCAUTH_UNIXGIDS 16 @@ -101,43 +99,4 @@ #define RPCMNT_PATHLEN 1024 #define RPCPROG_NFS 100003 -/* - * Structures used for RPCAUTH_KERB4. - */ -struct nfsrpc_fullverf { - u_int32_t t1; - u_int32_t t2; - u_int32_t w2; -}; - -struct nfsrpc_fullblock { - u_int32_t t1; - u_int32_t t2; - u_int32_t w1; - u_int32_t w2; -}; - -struct nfsrpc_nickverf { - u_int32_t kind; - struct nfsrpc_fullverf verf; -}; - -/* - * and their sizes in bytes.. If sizeof (struct nfsrpc_xx) != these - * constants, well then things will break in mount_nfs and nfsd. - */ -#define RPCX_FULLVERF 12 -#define RPCX_FULLBLOCK 16 -#define RPCX_NICKVERF 16 - -#ifdef NFSKERB -XXX -#else -typedef u_char NFSKERBKEY_T[2]; -typedef u_char NFSKERBKEYSCHED_T[2]; -#endif -#define NFS_KERBSRV "rcmd" /* Kerberos Service for NFS */ -#define NFS_KERBTTL (30 * 60) /* Credential ttl (sec) */ -#define NFS_KERBCLOCKSKEW (5 * 60) /* Clock skew (sec) */ -#define NFS_KERBW1(t) (*((u_long *)(&((t).dat[((t).length + 3) & ~0x3])))) #endif -- cgit v1.1