Changeset View
Standalone View
sys/nfs/nfs_diskless.c
Show First 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | else if (strncmp(o, "rsize=", 6) == 0) { | ||||
} | } | ||||
} else | } else | ||||
printf("%s: skipping unknown option \"%s\"\n", | printf("%s: skipping unknown option \"%s\"\n", | ||||
__func__, o); | __func__, o); | ||||
} | } | ||||
free(opts, M_TEMP); | free(opts, M_TEMP); | ||||
} | } | ||||
static u_int | |||||
nfs_setup_diskless_ifa_cb(void *arg, struct sockaddr_dl *sdl, u_int count) | |||||
{ | |||||
struct sockaddr_dl *ourdl = arg; | |||||
if ((sdl->sdl_type == ourdl->sdl_type) && | |||||
(sdl->sdl_alen == ourdl->sdl_alen) && | |||||
!bcmp(LLADDR(sdl), LLADDR(ourdl), sdl->sdl_alen)) | |||||
return (1); | |||||
melifaro: Nit: maybe a bit more descriptive name? It's a bit hard (at least for me) to understand what… | |||||
Done Inline ActionsWe need to pass down 'ourdl', and pass back up 'ifp'. The API doesn't provide 'in' vs 'out'. jhibbits: We need to pass down 'ourdl', and pass back up 'ifp'. The API doesn't provide 'in' vs 'out'. | |||||
Done Inline ActionsIt would be nice to have lambdas or blocks in the kernel, since most of these callback loops end up being rather trivial. jhibbits: It would be nice to have lambdas or blocks in the kernel, since most of these callback loops… | |||||
Not Done Inline ActionsI'd love to have that. Not with C, unfortunately. melifaro: I'd love to have that. Not with C, unfortunately.
I toyed with the idea of providing iterator… | |||||
Not Done Inline ActionsLooked into the iterator part once again. Technically it can be simpler (just using if_next() with the iterator struct zeroed initially), but I see two benefits in this approach:
What do you think? Public KPI: struct if_iter { void *_ptr[4]; } void if_get_iter(struct if_iter *iter); struct ifnet *if_next(struct if_iter *iter); void if_free_iter(struct if_iter *iter); Usage: struct if_iter iter; if_get_iter(&iter); while ((struct ifnet *ifp = if_next(&iter)) != NULL) { ... } if_free_iter(&iter); Implementation: struct if_iter_private { struct ifnet *cur_ifp; struct ifnet *next_ifp; }; Static_assert(sizeof(struct if_iter_private) < sizeof(struct if_iter)); void if_get_iter(struct if_iter *_iter) { NET_EPOCH_ASSERT(); struct if_iter_private *iter = _iter; bzero(iter, sizeof(*iter)); iter->cur_ifp = CK_STAILQ_FIRST(&V_ifnet, if_link); if (iter->cur_ifp != NULL) iter->next_ifp = CK_STAILQ_NEXT(iter->cur_ifp, if_link); } struct ifnet * if_next(struct if_iter *_iter) { struct if_iter_private *iter = _iter; struct ifnet *ifp = iter->cur_ifp; iter->cur_ifp = iter->next_ifp; if (iter->cur_ifp != NULL) iter->next_ifp = CK_STAILQ_NEXT(iter->cur_ifp, if_link); return (ifp); } void if_free_iter(struct if_iter *iter __unused) { } melifaro: Looked into the iterator part once again.
Wild idea - something like that can work for… | |||||
Not Done Inline ActionsSorry for not being clear - I meant the following: static u_int nfs_setup_diskless_ifa_cb(void *arg, struct sockaddr_dl *sdl, u_int count) { struct sockaddr_dl *outdl = arg; ... count = if_foreach_lladdr(ifp, nfs_setup_diskless_ifa_cb, cbs->ourdl); melifaro: Sorry for not being clear - I meant the following:
```
static u_int
nfs_setup_diskless_ifa_cb… | |||||
return (0); | |||||
} | |||||
/* | /* | ||||
* Populate the essential fields in the nfsv3_diskless structure. | * Populate the essential fields in the nfsv3_diskless structure. | ||||
* | * | ||||
* The loader is expected to export the following environment variables: | * The loader is expected to export the following environment variables: | ||||
* | * | ||||
* boot.netif.name name of boot interface | * boot.netif.name name of boot interface | ||||
* boot.netif.ip IP address on boot interface | * boot.netif.ip IP address on boot interface | ||||
* boot.netif.netmask netmask on boot interface | * boot.netif.netmask netmask on boot interface | ||||
* boot.netif.gateway default gateway (optional) | * boot.netif.gateway default gateway (optional) | ||||
* boot.netif.hwaddr hardware address of boot interface | * boot.netif.hwaddr hardware address of boot interface | ||||
* boot.netif.mtu interface mtu from bootp/dhcp (optional) | * boot.netif.mtu interface mtu from bootp/dhcp (optional) | ||||
* boot.nfsroot.server IP address of root filesystem server | * boot.nfsroot.server IP address of root filesystem server | ||||
* boot.nfsroot.path path of the root filesystem on server | * boot.nfsroot.path path of the root filesystem on server | ||||
* boot.nfsroot.nfshandle NFS handle for root filesystem on server | * boot.nfsroot.nfshandle NFS handle for root filesystem on server | ||||
* boot.nfsroot.nfshandlelen and length of this handle (for NFSv3 only) | * boot.nfsroot.nfshandlelen and length of this handle (for NFSv3 only) | ||||
* boot.nfsroot.options NFS options for the root filesystem | * boot.nfsroot.options NFS options for the root filesystem | ||||
*/ | */ | ||||
void | void | ||||
nfs_setup_diskless(void) | nfs_setup_diskless(void) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
struct if_iter iter; | |||||
struct nfs_diskless *nd = &nfs_diskless; | struct nfs_diskless *nd = &nfs_diskless; | ||||
struct nfsv3_diskless *nd3 = &nfsv3_diskless; | struct nfsv3_diskless *nd3 = &nfsv3_diskless; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
struct ifaddr *ifa; | struct sockaddr_dl ourdl; | ||||
struct sockaddr_dl *sdl, ourdl; | |||||
struct sockaddr_in myaddr, netmask; | struct sockaddr_in myaddr, netmask; | ||||
char *cp; | char *cp; | ||||
int cnt, fhlen, is_nfsv3; | int cnt, fhlen, is_nfsv3; | ||||
uint32_t len; | uint32_t len; | ||||
time_t timeout_at; | time_t timeout_at; | ||||
u_int count; | |||||
if (nfs_diskless_valid != 0) | if (nfs_diskless_valid != 0) | ||||
return; | return; | ||||
/* get handle size. If this succeeds, it's an NFSv3 setup. */ | /* get handle size. If this succeeds, it's an NFSv3 setup. */ | ||||
if ((cp = kern_getenv("boot.nfsroot.nfshandlelen")) != NULL) { | if ((cp = kern_getenv("boot.nfsroot.nfshandlelen")) != NULL) { | ||||
cnt = sscanf(cp, "%d", &len); | cnt = sscanf(cp, "%d", &len); | ||||
freeenv(cp); | freeenv(cp); | ||||
Show All 27 Lines | ((struct sockaddr_in *) | ||||
myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr; | myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr; | ||||
bcopy(&netmask, &nd->myif.ifra_mask, sizeof(netmask)); | bcopy(&netmask, &nd->myif.ifra_mask, sizeof(netmask)); | ||||
} | } | ||||
if (hwaddr_to_sockaddr("boot.netif.hwaddr", &ourdl)) { | if (hwaddr_to_sockaddr("boot.netif.hwaddr", &ourdl)) { | ||||
printf("nfs_diskless: no hardware address\n"); | printf("nfs_diskless: no hardware address\n"); | ||||
return; | return; | ||||
} | } | ||||
ifa = NULL; | |||||
timeout_at = time_uptime + NFS_IFACE_TIMEOUT_SECS; | timeout_at = time_uptime + NFS_IFACE_TIMEOUT_SECS; | ||||
retry: | retry: | ||||
Not Done Inline ActionsNit: maybe use C11 initializer here? melifaro: Nit: maybe use C11 initializer here? | |||||
CURVNET_SET(TD_TO_VNET(curthread)); | CURVNET_SET(TD_TO_VNET(curthread)); | ||||
IFNET_RLOCK(); | NET_EPOCH_ENTER(et); | ||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { | |||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | for (ifp = if_iter_start(&iter); ifp != NULL; ifp = if_iter_next(&iter)) { | ||||
if (ifa->ifa_addr->sa_family == AF_LINK) { | count = if_foreach_lladdr(ifp, nfs_setup_diskless_ifa_cb, &ourdl); | ||||
sdl = (struct sockaddr_dl *)ifa->ifa_addr; | |||||
if ((sdl->sdl_type == ourdl.sdl_type) && | if (count > 0) | ||||
(sdl->sdl_alen == ourdl.sdl_alen) && | break; | ||||
!bcmp(LLADDR(sdl), | |||||
LLADDR(&ourdl), | } | ||||
sdl->sdl_alen)) { | if_iter_finish(&iter); | ||||
IFNET_RUNLOCK(); | NET_EPOCH_EXIT(et); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
if (cnt > 0) { | |||||
goto match_done; | goto match_done; | ||||
} | } | ||||
} | |||||
} | |||||
} | |||||
IFNET_RUNLOCK(); | |||||
CURVNET_RESTORE(); | |||||
if (time_uptime < timeout_at) { | if (time_uptime < timeout_at) { | ||||
pause("nfssdl", hz / 5); | pause("nfssdl", hz / 5); | ||||
goto retry; | goto retry; | ||||
} | } | ||||
printf("nfs_diskless: no interface\n"); | printf("nfs_diskless: no interface\n"); | ||||
return; /* no matching interface */ | return; /* no matching interface */ | ||||
match_done: | match_done: | ||||
kern_setenv("boot.netif.name", ifp->if_xname); | kern_setenv("boot.netif.name", if_name(ifp)); | ||||
if (is_nfsv3 != 0) { | if (is_nfsv3 != 0) { | ||||
strlcpy(nd3->myif.ifra_name, ifp->if_xname, | strlcpy(nd3->myif.ifra_name, if_name(ifp), | ||||
sizeof(nd3->myif.ifra_name)); | sizeof(nd3->myif.ifra_name)); | ||||
/* set up gateway */ | /* set up gateway */ | ||||
inaddr_to_sockaddr("boot.netif.gateway", &nd3->mygateway); | inaddr_to_sockaddr("boot.netif.gateway", &nd3->mygateway); | ||||
/* set up root mount */ | /* set up root mount */ | ||||
nd3->root_args.rsize = 32768; /* XXX tunable? */ | nd3->root_args.rsize = 32768; /* XXX tunable? */ | ||||
nd3->root_args.wsize = 32768; | nd3->root_args.wsize = 32768; | ||||
Show All 22 Lines | if (is_nfsv3 != 0) { | ||||
} | } | ||||
if ((cp = kern_getenv("boot.nfsroot.options")) != NULL) { | if ((cp = kern_getenv("boot.nfsroot.options")) != NULL) { | ||||
nfs_parse_options(cp, &nd3->root_args); | nfs_parse_options(cp, &nd3->root_args); | ||||
freeenv(cp); | freeenv(cp); | ||||
} | } | ||||
nfs_diskless_valid = 3; | nfs_diskless_valid = 3; | ||||
} else { | } else { | ||||
strlcpy(nd->myif.ifra_name, ifp->if_xname, | strlcpy(nd->myif.ifra_name, if_name(ifp), | ||||
sizeof(nd->myif.ifra_name)); | sizeof(nd->myif.ifra_name)); | ||||
/* set up gateway */ | /* set up gateway */ | ||||
inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway); | inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway); | ||||
/* set up root mount */ | /* set up root mount */ | ||||
nd->root_args.rsize = 8192; /* XXX tunable? */ | nd->root_args.rsize = 8192; /* XXX tunable? */ | ||||
nd->root_args.wsize = 8192; | nd->root_args.wsize = 8192; | ||||
▲ Show 20 Lines • Show All 137 Lines • Show Last 20 Lines |
Nit: maybe a bit more descriptive name? It's a bit hard (at least for me) to understand what cbs is.
Also: do we need to propagate struct nfs_setup_ifa_s here instead of just ourdl?