void cpu_rootconf() { bootpc_init(); rootdevnames[0] = "nfs:"; }
/* * Perform a BOOTP request and update "standard" files in /etc * with the results. */ void rtems_bsdnet_do_bootp_and_rootfs (void) { bool ok; rtems_bsdnet_semaphore_obtain (); ok = bootpc_init (true, true); rtems_bsdnet_semaphore_release (); if (!ok) panic ("rtems_bsdnet_do_bootp_and_rootfs: bootp failed"); }
/* * 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(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 (mycpu->gd_time_seconds == 0) tsleep(mycpu, 0, "arpkludge", 10); /* * The boot code may have passed us a diskless structure. */ kprintf("DISKLESS %d\n", nfs_diskless_valid); if (nfs_diskless_valid == 1) nfs_convert_diskless(); /* * NFSv3 is required. */ nd->root_args.flags |= NFSMNT_NFSV3 | NFSMNT_RDIRPLUS; nd->swap_args.flags |= NFSMNT_NFSV3; #define SINP(sockaddr) ((struct sockaddr_in *)(sockaddr)) kprintf("nfs_mountroot: interface %s ip %s", nd->myif.ifra_name, inet_ntoa(SINP(&nd->myif.ifra_addr)->sin_addr)); kprintf(" bcast %s", inet_ntoa(SINP(&nd->myif.ifra_broadaddr)->sin_addr)); kprintf(" mask %s\n", inet_ntoa(SINP(&nd->myif.ifra_mask)->sin_addr)); #undef SINP /* * XXX splnet, so networks will receive... */ crit_enter(); /* * BOOTP does not necessarily have to be compiled into the kernel * for an NFS root to work. If we inherited the network * configuration for PXEBOOT then pxe_setup_nfsdiskless() has figured * out our interface for us and all we need to do is ifconfig the * interface. We only do this if the interface has not already been * ifconfig'd by e.g. BOOTP. */ 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); } error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, proc0.p_ucred); if (error) panic("nfs_mountroot: SIOCAIFADDR: %d", error); soclose(so, FNONBLOCK); /* * 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); kprintf("nfs_mountroot: gateway %s\n", inet_ntoa(nd->mygateway.sin_addr)); error = rtrequest_global(RTM_ADD, (struct sockaddr *)&sin, (struct sockaddr *)&nd->mygateway, (struct sockaddr *)&mask, RTF_UP | RTF_GATEWAY); if (error) kprintf("nfs_mountroot: unable to set gateway, error %d, continuing anyway\n", 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); ksnprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", (l >> 24) & 0xff, (l >> 16) & 0xff, (l >> 8) & 0xff, (l >> 0) & 0xff,nd->root_hostnam); kprintf("NFS_ROOT: %s\n",buf); error = nfs_mountdiskless(buf, "/", MNT_RDONLY, &nd->root_saddr, &nd->root_args, td, &vp, &mp); if (error) { mp->mnt_vfc->vfc_refcount--; crit_exit(); 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); ksnprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", (l >> 24) & 0xff, (l >> 16) & 0xff, (l >> 8) & 0xff, (l >> 0) & 0xff,nd->swap_hostnam); kprintf("NFS SWAP: %s\n",buf); error = nfs_mountdiskless(buf, "/swap", 0, &nd->swap_saddr, &nd->swap_args, td, &vp, &swap_mp); if (error) { crit_exit(); return (error); } vfs_unbusy(swap_mp); 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. */ vclrflags(vp, VROOT); vref(vp); nfs_setvtype(vp, VREG); swaponvp(td, vp, nd->swap_nblks); }
/* * 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. * * It is assumed to be safe to read, modify, and write the nfsv3_diskless * structure, as well as other global NFS client variables here, as * nfs_mountroot() will be called once in the boot before any other NFS * client activity occurs. */ int nfs_mountroot(struct mount *mp) { struct thread *td = curthread; struct nfsv3_diskless *nd = &nfsv3_diskless; struct socket *so; struct vnode *vp; struct ifreq ir; int error; u_long l; char buf[128]; char *cp; #if defined(BOOTP_NFSROOT) && defined(BOOTP) bootpc_init(); /* use bootp to get nfs_diskless filled in */ #elif defined(NFS_ROOT) nfs_setup_diskless(); #endif if (nfs_diskless_valid == 0) { return (-1); } if (nfs_diskless_valid == 1) nfs_convert_diskless(); /* * XXX splnet, so networks will receive... */ splnet(); /* * 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, nd->root_args.sotype, 0, td->td_ucred, 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); if ((cp = getenv("boot.netif.mtu")) != NULL) { ir.ifr_mtu = strtol(cp, NULL, 10); bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ); freeenv(cp); error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td); if (error) printf("nfs_mountroot: SIOCSIFMTU: %d", error); } soclose(so); /* * If the gateway field is filled in, set it as the default route. * Note that pxeboot will set a default route of 0 if the route * is not set by the DHCP server. Check also for a value of 0 * to avoid panicking inappropriately in that situation. */ if (nd->mygateway.sin_len != 0 && nd->mygateway.sin_addr.s_addr != 0) { struct sockaddr_in mask, sin; bzero((caddr_t)&mask, sizeof(mask)); sin = mask; sin.sin_family = AF_INET; sin.sin_len = sizeof(sin); /* XXX MRT use table 0 for this sort of thing */ CURVNET_SET(TD_TO_VNET(td)); error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin, (struct sockaddr *)&nd->mygateway, (struct sockaddr *)&mask, RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB); CURVNET_RESTORE(); 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); nd->root_args.hostname = buf; if ((error = nfs_mountdiskless(buf, &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) { return (error); } /* * 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. */ mtx_lock(&prison0.pr_mtx); strlcpy(prison0.pr_hostname, nd->my_hostnam, sizeof (prison0.pr_hostname)); mtx_unlock(&prison0.pr_mtx); inittodr(ntohl(nd->root_time)); return (0); }
/* * vfs_mountrootfs * * Common entry point for root mounts * * PARAMETERS: * NONE * * RETURNS: 0 Success * !0 error number (errno.h) * * LOCK STATE: * ENTRY * <no locks held> * EXIT * <no locks held> * * NOTES: * This code is currently supported only for use for * the FFS file system type. This is a matter of * fixing the other file systems, not this code! */ static void vfs_mountrootfs(void *unused) { struct mount *mp; int i, err; struct proc *p = curproc; /* XXX */ dev_t orootdev; #ifdef BOOTP bootpc_init(); #endif /* * New root mount structure */ if ((err = vfs_rootmountalloc(mountrootfsname, ROOTNAME, &mp))) { printf("error %d: ", err); panic("cannot mount root\n"); return ; } mp->mnt_flag |= MNT_ROOTFS; /* * Attempt the mount */ err = ENXIO; orootdev = rootdev; if (rootdevs[0] == NODEV) rootdevs[0] = rootdev; for (i = 0; i < sizeof(rootdevs) / sizeof(rootdevs[0]); i++) { if (rootdevs[i] == NODEV) break; rootdev = rootdevs[i]; if (rootdev != orootdev) { printf("changing root device to %s\n", rootdevnames[i]); orootdev = rootdev; } strncpy(mp->mnt_stat.f_mntfromname, rootdevnames[i] ? rootdevnames[i] : ROOTNAME, MNAMELEN - 1); err = VFS_MOUNT(mp, NULL, NULL, NULL, p); if (err != ENXIO) break; } if (err) { /* * XXX should ask the user for the name in some cases. * Why do we call vfs_unbusy() here and not after ENXIO * is returned above? */ vfs_unbusy(mp, p); /* * free mount struct before failing * (hardly worthwhile with the PANIC eh?) */ free( mp, M_MOUNT); printf("error %d: ", err); panic("cannot mount root (2)\n"); return; } simple_lock(&mountlist_slock); /* * Add fs to list of mounted file systems */ CIRCLEQ_INSERT_HEAD(&mountlist, mp, mnt_list); simple_unlock(&mountlist_slock); vfs_unbusy(mp, p); /* root mount, update system time from FS specific data*/ inittodr(mp->mnt_time); return; }