patch-1.3.45 linux/fs/nfs/nfsroot.c
Next file: linux/fs/open.c
Previous file: linux/fs/namei.c
Back to the patch index
Back to the overall index
- Lines: 1294
- Date:
Mon Nov 27 09:24:50 1995
- Orig file:
v1.3.44/linux/fs/nfs/nfsroot.c
- Orig date:
Sat Nov 25 19:04:47 1995
diff -u --recursive --new-file v1.3.44/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c
@@ -6,20 +6,21 @@
* Allow an NFS filesystem to be mounted as root. The way this works
* is to first determine the local IP address via RARP. Then handle
* the RPC negotiation with the system which replied to the RARP. The
- * actual mounting is done later, when init() is running.
+ * actual mounting is done later, when init() is running. In addition
+ * it's possible to avoid using RARP if the necessary addresses are
+ * provided on the kernel command line. This is necessary to use boot-
+ * roms which use bootp instead of RARP.
*
- * Changes:
+ * Changes:
*
* Alan Cox : Removed get_address name clash with FPU.
* Alan Cox : Reformatted a bit.
*
- * TODO:
- * Support bootp and dhcp as well as rarp.
*/
/* Define this to allow debugging output */
-#define NFSROOT_DEBUG 1
+#undef NFSROOT_DEBUG 1
/* Define the timeout for waiting for a RARP reply */
#define RARP_TIMEOUT 30 /* 30 seconds */
@@ -46,12 +47,12 @@
#include <linux/skbuff.h>
#include <linux/socket.h>
#include <linux/route.h>
-#include <net/route.h>
#include <linux/nfs.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
+#include <netinet/in.h>
+#include <net/route.h>
-#define IPPORT_RESERVED 1024
/* Range of privileged ports */
#define STARTPORT 600
@@ -60,8 +61,7 @@
-struct open_dev
-{
+struct open_dev {
struct device *dev;
unsigned short old_flags;
struct open_dev *next;
@@ -71,6 +71,8 @@
static struct device *root_dev = NULL;
static struct sockaddr_in myaddr; /* My IP address */
static struct sockaddr_in server; /* Server IP address */
+static struct sockaddr_in gateway; /* Gateway IP address */
+static struct sockaddr_in netmask; /* Netmask for local subnet */
static struct nfs_mount_data nfs_data; /* NFS mount info */
static char nfs_path[NFS_MAXPATHLEN]; /* Name of directory to mount */
static int nfs_port; /* Port to connect to for NFS service */
@@ -79,63 +81,28 @@
/***************************************************************************
- RARP Subroutines
+ Device Handling Subroutines
***************************************************************************/
-extern void arp_send(int type, int ptype, unsigned long target_ip,
- struct device *dev, unsigned long src_ip,
- unsigned char *dest_hw, unsigned char *src_hw,
- unsigned char *target_hw);
-
-static int root_rarp_recv(struct sk_buff *skb, struct device *dev,
- struct packet_type *pt);
-
-
-static struct packet_type rarp_packet_type =
-{
- 0, /* Should be: __constant_htons(ETH_P_RARP) - but this _doesn't_ come out constant! */
- NULL, /* Listen to all devices */
- root_rarp_recv,
- NULL,
- NULL
-};
-
-
/*
- * For receiving rarp packets a packet type has to be registered. Also
- * initialize all devices for usage by RARP.
+ * Setup and initialize all network devices
*/
-
-static int root_rarp_open(void)
+static int root_dev_open(void)
{
struct open_dev *openp;
struct device *dev;
unsigned short old_flags;
- int num;
+ int num = 0;
- /*
- * Register the packet type
- */
-
- rarp_packet_type.type=htons(ETH_P_RARP);
- dev_add_pack(&rarp_packet_type);
-
- /*
- * Open all devices which allow RARP
- */
-
- for (dev = dev_base, num = 0; dev != NULL; dev = dev->next)
- {
+ for (dev = dev_base; dev != NULL; dev = dev->next) {
if (dev->type < ARPHRD_SLIP &&
- dev->family == AF_INET &&
- !(dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_NOARP)))
- {
+ dev->family == AF_INET &&
+ !(dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {
/* First up the interface */
old_flags = dev->flags;
dev->flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
- if (!(old_flags & IFF_UP) && dev_open(dev))
- {
+ if (!(old_flags & IFF_UP) && dev_open(dev)) {
dev->flags = old_flags;
continue;
}
@@ -150,40 +117,32 @@
num++;
}
}
- return num;
+
+ if (num == 0) {
+ printk(KERN_ERR "NFS: Unable to open at least one network device\n");
+ return -1;
+ }
+#ifdef NFSROOT_DEBUG
+ printk(KERN_NOTICE "NFS: Opened %d network interfaces\n", num);
+#endif
+ return 0;
}
/*
- * Remove the packet type again when all rarp packets have been received
- * and restore the state of the device. However, keep the root device
- * open for the upcoming mount.
+ * Restore the state of all devices. However, keep the root device open
+ * for the upcoming mount.
*/
-
-static void root_rarp_close(void)
+static void root_dev_close(void)
{
struct open_dev *openp;
struct open_dev *nextp;
- /*
- * Deregister the packet type
- */
-
- rarp_packet_type.type=htons(ETH_P_RARP);
- dev_remove_pack(&rarp_packet_type);
-
- /*
- * Deactivate all previously opened devices except that one which is
- * able to connect to a suitable server
- */
-
openp = open_base;
- while (openp != NULL)
- {
+ while (openp != NULL) {
nextp = openp->next;
openp->next = NULL;
- if (openp->dev != root_dev)
- {
+ if (openp->dev != root_dev) {
if (!(openp->old_flags & IFF_UP))
dev_close(openp->dev);
openp->dev->flags = openp->old_flags;
@@ -194,55 +153,86 @@
}
+
+
+/***************************************************************************
+
+ RARP Subroutines
+
+ ***************************************************************************/
+
+extern void arp_send(int type, int ptype, unsigned long target_ip,
+ struct device *dev, unsigned long src_ip,
+ unsigned char *dest_hw, unsigned char *src_hw,
+ unsigned char *target_hw);
+
+static int root_rarp_recv(struct sk_buff *skb, struct device *dev,
+ struct packet_type *pt);
+
+
+static struct packet_type rarp_packet_type = {
+ 0, /* Should be: __constant_htons(ETH_P_RARP)
+ * - but this _doesn't_ come out constant! */
+ NULL, /* Listen to all devices */
+ root_rarp_recv,
+ NULL,
+ NULL
+};
+
+
+/*
+ * Register the packet type for RARP
+ */
+static void root_rarp_open(void)
+{
+ rarp_packet_type.type = htons(ETH_P_RARP);
+ dev_add_pack(&rarp_packet_type);
+}
+
+
/*
- * Receive RARP packets.
+ * Deregister the RARP packet type
+ */
+static void root_rarp_close(void)
+{
+ rarp_packet_type.type = htons(ETH_P_RARP);
+ dev_remove_pack(&rarp_packet_type);
+}
+
+
+/*
+ * Receive RARP packets.
*/
-
static int root_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
struct arphdr *rarp = (struct arphdr *)skb->h.raw;
- unsigned char *rarp_ptr = (unsigned char *)(rarp+1);
+ unsigned char *rarp_ptr = (unsigned char *) (rarp + 1);
unsigned long sip, tip;
unsigned char *sha, *tha; /* s for "source", t for "target" */
-
- /*
- * If this test doesn't pass, its not IP, or we should ignore it anyway
- */
-
- if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd))
- {
+
+ /* If this test doesn't pass, its not IP, or we should ignore it anyway */
+ if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) {
kfree_skb(skb, FREE_READ);
return 0;
}
- /*
- * If it's not a RARP reply, delete it.
- */
-
- if (rarp->ar_op != htons(ARPOP_RREPLY))
- {
+ /* If it's not a RARP reply, delete it. */
+ if (rarp->ar_op != htons(ARPOP_RREPLY)) {
kfree_skb(skb, FREE_READ);
return 0;
}
- /*
- * If it's not ethernet or AX25, delete it.
- */
-
- if ((rarp->ar_pro != htons(ETH_P_IP) && dev->type != ARPHRD_AX25) ||
+ /* If it's not ethernet or AX25, delete it. */
+ if ((rarp->ar_pro != htons(ETH_P_IP) && dev->type != ARPHRD_AX25) ||
#ifdef CONFIG_AX25
- (rarp->ar_pro != htons(AX25_P_IP) && dev->type == ARPHRD_AX25) ||
+ (rarp->ar_pro != htons(AX25_P_IP) && dev->type == ARPHRD_AX25) ||
#endif
- rarp->ar_pln != 4)
- {
+ rarp->ar_pln != 4) {
kfree_skb(skb, FREE_READ);
return 0;
}
-
- /*
- * Extract variable width fields
- */
-
+
+ /* Extract variable width fields */
sha = rarp_ptr;
rarp_ptr += dev->addr_len;
memcpy(&sip, rarp_ptr, 4);
@@ -251,23 +241,24 @@
rarp_ptr += dev->addr_len;
memcpy(&tip, rarp_ptr, 4);
- /*
- * Discard packets which are not meant for us.
- */
-
- if (memcmp(tha, dev->dev_addr, dev->addr_len))
- {
+ /* Discard packets which are not meant for us. */
+ if (memcmp(tha, dev->dev_addr, dev->addr_len)) {
+ kfree_skb(skb, FREE_READ);
+ return 0;
+ }
+ /* Discard packets which are not from specified server. */
+ if (server.sin_addr.s_addr != INADDR_NONE &&
+ server.sin_addr.s_addr != sip) {
kfree_skb(skb, FREE_READ);
return 0;
}
/*
- * The packet is what we were looking for. Setup the global variables.
+ * The packet is what we were looking for. Setup the global
+ * variables.
*/
-
cli();
- if (root_dev != NULL)
- {
+ if (root_dev != NULL) {
sti();
kfree_skb(skb, FREE_READ);
return 0;
@@ -275,83 +266,82 @@
root_dev = dev;
sti();
- myaddr.sin_family = dev->family;
- myaddr.sin_addr.s_addr = tip;
- server.sin_family = dev->family;
- if (!server.sin_addr.s_addr)
+ if (myaddr.sin_addr.s_addr == INADDR_NONE) {
+ myaddr.sin_family = dev->family;
+ myaddr.sin_addr.s_addr = tip;
+ }
+ if (server.sin_addr.s_addr == INADDR_NONE) {
+ server.sin_family = dev->family;
server.sin_addr.s_addr = sip;
-
+ }
kfree_skb(skb, FREE_READ);
return 0;
}
/*
- * Send RARP request packet over all devices which allow RARP.
+ * Send RARP request packet over all devices which allow RARP.
*/
-
-static void root_rarp_send(void)
+static int root_rarp_send(void)
{
struct open_dev *openp;
struct device *dev;
+ int num = 0;
#ifdef NFSROOT_DEBUG
printk(KERN_NOTICE "NFS: Sending RARP request...\n");
#endif
- for (openp = open_base; openp != NULL; openp = openp->next)
- {
+ for (openp = open_base; openp != NULL; openp = openp->next) {
dev = openp->dev;
- arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL,
- dev->dev_addr, dev->dev_addr);
+ if (!(dev->flags & IFF_NOARP)) {
+ arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL,
+ dev->dev_addr, dev->dev_addr);
+ num++;
+ }
}
+
+ if (num == 0) {
+ printk(KERN_ERR "NFS: Couldn't find device to send RARP request to\n");
+ return -1;
+ }
+ return 0;
}
/*
- * Determine client and server IP numbers and appropriate device by using
- * the RARP protocol.
+ * Determine client and server IP numbers and appropriate device by using
+ * the RARP protocol.
*/
-
static int do_rarp(void)
{
int retries = 0;
- unsigned long timeout;
+ unsigned long timeout = 0;
- /*
- * Open all devices and setup RARP protocol
- */
-
- if (!root_rarp_open())
- {
- printk(KERN_ERR "NFS: No network device found to send RARP request to\n");
- return -1;
- }
+ /* Setup RARP protocol */
+ root_rarp_open();
/*
- * Send RARP request and wait, until we get an answer. This loop seems
- * to be a terrible waste of cpu time, but actually there is no process
- * running at all, so we don't need to use any scheduler functions.
- * [Actually we could now, but the nothing else running note still
- * applies.. - AC]
- */
-
- for (retries = 0; retries < RARP_RETRIES && root_dev == NULL; retries++)
- {
- root_rarp_send();
+ * Send RARP request and wait, until we get an answer. This loop
+ * seems to be a terrible waste of cpu time, but actually there is
+ * no process running at all, so we don't need to use any
+ * scheduler functions.
+ * [Actually we could now, but the nothing else running note still
+ * applies.. - AC]
+ */
+ for (retries = 0; retries < RARP_RETRIES && root_dev == NULL; retries++) {
+ if (root_rarp_send() < 0)
+ break;
timeout = jiffies + (RARP_TIMEOUT * HZ);
while (jiffies < timeout && root_dev == NULL)
;;
}
- if (root_dev == NULL)
- {
+ root_rarp_close();
+ if (root_dev == NULL && timeout > 0) {
printk(KERN_ERR "NFS: Timed out while waiting for RARP answer\n");
return -1;
}
-
- root_rarp_close();
-
printk(KERN_NOTICE "NFS: ");
printk("Got RARP answer from %s, ", in_ntoa(server.sin_addr.s_addr));
printk("my address is %s\n", in_ntoa(myaddr.sin_addr.s_addr));
@@ -368,17 +358,12 @@
***************************************************************************/
-extern void ip_rt_add(short flags, unsigned long addr, unsigned long mask,
- unsigned long gw, struct device *dev,
- unsigned short mss, unsigned long window);
/*
- * The following integer options are recognized
+ * The following integer options are recognized
*/
-
-static struct nfs_int_opts
-{
+static struct nfs_int_opts {
char *name;
int *val;
} root_int_opts[] = {
@@ -391,15 +376,14 @@
{ "acregmax", &nfs_data.acregmax },
{ "acdirmin", &nfs_data.acdirmin },
{ "acdirmax", &nfs_data.acdirmax },
- { NULL, NULL }};
+ { NULL, NULL }
+};
/*
- * And now the flag options
+ * And now the flag options
*/
-
-static struct nfs_bool_opts
-{
+static struct nfs_bool_opts {
char *name;
int and_mask;
int or_mask;
@@ -418,78 +402,42 @@
};
-static unsigned long nfs_get_address (char **str)
-{
- unsigned long l;
- unsigned int val;
- int i;
-
- l = 0;
- for (i = 0; i < 4; i++)
- {
- l <<= 8;
- if (**str != '\0')
- {
- val = 0;
- while (**str != '\0' && **str != '.' && **str != ':')
- {
- val *= 10;
- val += **str - '0';
- (*str)++;
- }
- l |= val;
- if (**str != '\0')
- (*str)++;
- }
- }
- return(htonl(l));
-}
-
/*
- * Prepare the NFS data structure and parse any options
+ * Prepare the NFS data structure and parse any options
*/
-
static int root_nfs_parse(char *name)
{
char buf[NFS_MAXPATHLEN];
char *cp, *options, *val;
- /*
- * Get the host ip number
- */
-
- if (*name >= '0' && *name <= '9')
- {
- server.sin_addr.s_addr = nfs_get_address (&name);
+ /* Set the default system name in case none was previously found */
+ if (!system_utsname.nodename[0]) {
+ strncpy(system_utsname.nodename, in_ntoa(myaddr.sin_addr.s_addr), __NEW_UTS_LEN);
+ system_utsname.nodename[__NEW_UTS_LEN] = '\0';
+ }
+ /* It is possible to override the host IP number here */
+ if (*name >= '0' && *name <= '9' && (cp = strchr(name, ':')) != NULL) {
+ *cp++ = '\0';
+ server.sin_addr.s_addr = in_aton(name);
+ name = cp;
}
- /*
- * Setup the server hostname
- */
-
+ /* Setup the server hostname */
cp = in_ntoa(server.sin_addr.s_addr);
strncpy(nfs_data.hostname, cp, 255);
- nfs_data.addr = server;
- /*
- * Set the name of the directory to mount
- */
-
+ /* Set the name of the directory to mount */
cp = in_ntoa(myaddr.sin_addr.s_addr);
strncpy(buf, name, 255);
if ((options = strchr(buf, ',')))
*options++ = '\0';
- if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN)
- {
+ if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) {
printk(KERN_ERR "NFS: Pathname for remote directory too long\n");
return -1;
}
sprintf(nfs_path, buf, cp);
- /*
- * Set some default values
- */
-
+ /* Set some default values */
nfs_port = -1;
nfs_data.version = NFS_MOUNT_VERSION;
nfs_data.flags = 0;
@@ -502,31 +450,22 @@
nfs_data.acdirmin = 30;
nfs_data.acdirmax = 60;
- /*
- * Process any options
- */
-
- if (options)
- {
+ /* Process any options */
+ if (options) {
cp = strtok(options, ",");
- while (cp)
- {
- if ((val = strchr(cp, '=')))
- {
+ while (cp) {
+ if ((val = strchr(cp, '='))) {
struct nfs_int_opts *opts = root_int_opts;
*val++ = '\0';
while (opts->name && strcmp(opts->name, cp))
opts++;
if (opts->name)
*(opts->val) = (int) simple_strtoul(val, NULL, 10);
- }
- else
- {
+ } else {
struct nfs_bool_opts *opts = root_bool_opts;
while (opts->name && strcmp(opts->name, cp))
opts++;
- if (opts->name)
- {
+ if (opts->name) {
nfs_data.flags &= opts->and_mask;
nfs_data.flags |= opts->or_mask;
}
@@ -539,9 +478,8 @@
/*
- * Tell the user what's going on.
+ * Tell the user what's going on.
*/
-
static void root_nfs_print(void)
{
#ifdef NFSROOT_DEBUG
@@ -559,59 +497,164 @@
/*
- * Set the interface address and configure a route to the server.
+ * Parse any IP addresses
+ */
+static void root_nfs_addrs(char *addrs)
+{
+ char *cp, *ip, *dp;
+ int num = 0;
+
+ /* Clear all addresses and strings */
+ myaddr.sin_family = server.sin_family =
+ gateway.sin_family = netmask.sin_family = AF_INET;
+ myaddr.sin_addr.s_addr = server.sin_addr.s_addr =
+ gateway.sin_addr.s_addr = netmask.sin_addr.s_addr = INADDR_NONE;
+ system_utsname.nodename[0] = '\0';
+ system_utsname.domainname[0] = '\0';
+
+ /*
+ * Parse the address field. It contains 4 IP addresses which are
+ * separated by colons: Field 0 = my own address Field 1 = server
+ * address Field 2 = gateway address Field 3 = netmask address
+ * Field 4 = client host name
+ */
+ ip = addrs;
+ while (ip && *ip) {
+ if ((cp = strchr(ip, ':')))
+ *cp++ = '\0';
+ if (strlen(ip) > 0) {
+#ifdef NFSROOT_DEBUG
+ printk(KERN_NOTICE "NFS: IP address num %d is \"%s\"\n", num, ip);
+#endif
+ switch (num) {
+ case 0:
+ myaddr.sin_addr.s_addr = in_aton(ip);
+ break;
+ case 1:
+ server.sin_addr.s_addr = in_aton(ip);
+ break;
+ case 2:
+ gateway.sin_addr.s_addr = in_aton(ip);
+ break;
+ case 3:
+ netmask.sin_addr.s_addr = in_aton(ip);
+ break;
+ case 4:
+ if ((dp = strchr(ip, '.'))) {
+ *dp++ = '\0';
+ strncpy(system_utsname.domainname, dp, __NEW_UTS_LEN);
+ system_utsname.domainname[__NEW_UTS_LEN] = '\0';
+ }
+ strncpy(system_utsname.nodename, ip, __NEW_UTS_LEN);
+ system_utsname.nodename[__NEW_UTS_LEN] = '\0';
+ break;
+ default:
+ break;
+ }
+ }
+ ip = cp;
+ num++;
+ }
+}
+
+
+/*
+ * Set the interface address and configure a route to the server.
*/
static void root_nfs_setup(void)
{
- struct rtentry server_route;
- struct sockaddr_in *sin;
+ struct rtentry route;
- /*
- * Setup the device correctly
- */
-
+ /* Set the correct netmask */
+ if (netmask.sin_addr.s_addr == INADDR_NONE)
+ netmask.sin_addr.s_addr = ip_get_mask(myaddr.sin_addr.s_addr);
+
+ /* Setup the device correctly */
root_dev->family = myaddr.sin_family;
root_dev->pa_addr = myaddr.sin_addr.s_addr;
- root_dev->pa_mask = ip_get_mask(myaddr.sin_addr.s_addr);
+ root_dev->pa_mask = netmask.sin_addr.s_addr;
root_dev->pa_brdaddr = root_dev->pa_addr | ~root_dev->pa_mask;
root_dev->pa_dstaddr = 0;
- sin=(struct sockaddr_in *)&server_route.rt_dst;
- *sin=server;
- sin=(struct sockaddr_in *)&server_route.rt_genmask;
- sin->sin_family=AF_INET;
- sin->sin_addr.s_addr= root_dev->pa_mask;
- server_route.rt_dev=NULL;
- server_route.rt_flags=RTF_HOST|RTF_UP;
-
/*
- * Now add a route to the server
- */
-
- if(ip_rt_new(&server_route)==-1)
- printk("Unable to add NFS server route.\n");
+ * Now add a route to the server. If there is no gateway given,
+ * the server is on our own local network, so a host route is
+ * sufficient. Otherwise we first have to create a host route to
+ * the gateway, and then setup a gatewayed host route to the
+ * server. Note that it's not possible to setup a network route
+ * because we don't know the network mask of the server network.
+ */
+ memset(&route, 0, sizeof(route));
+ route.rt_dev = root_dev->name;
+ route.rt_mss = root_dev->mtu;
+ route.rt_flags = RTF_HOST | RTF_UP;
+ *((struct sockaddr_in *) &(route.rt_genmask)) = netmask;
+
+ if (gateway.sin_addr.s_addr == INADDR_NONE ||
+ gateway.sin_addr.s_addr == server.sin_addr.s_addr ||
+ !((server.sin_addr.s_addr ^ root_dev->pa_addr) & root_dev->pa_mask)) {
+ *((struct sockaddr_in *) &(route.rt_dst)) = server;
+ ip_rt_new(&route);
+ } else {
+ *((struct sockaddr_in *) &(route.rt_dst)) = gateway;
+ ip_rt_new(&route);
+ route.rt_flags |= RTF_GATEWAY;
+ *((struct sockaddr_in *) &(route.rt_gateway)) = gateway;
+ *((struct sockaddr_in *) &(route.rt_dst)) = server;
+ ip_rt_new(&route);
+ }
}
/*
- * Get the necessary IP addresses and prepare for mounting the required
- * NFS filesystem.
- */
-
-int nfs_root_init(char *nfsname)
-{
+ * Get the necessary IP addresses and prepare for mounting the required
+ * NFS filesystem.
+ */
+int nfs_root_init(char *nfsname, char *nfsaddrs)
+{
+ /* Setup all network devices */
+ if (root_dev_open() < 0)
+ return -1;
+
+ /*
+ * Get local and server IP address. First check for addresses in
+ * command line parameter. If one of the IP addresses is missing,
+ * or there's more than one network interface in the system, use
+ * RARP to get the missing values and routing information. If all
+ * addresses are given, the best way to find a proper routing is
+ * to use icmp echo requests ("ping"), but that would add a lot of
+ * code to this module, which is only really necessary in the rare
+ * case of multiple ethernet devices in the (diskless) system and
+ * if the server is on another subnet (otherwise RARP can serve as
+ * a ping substitute). If only one device is installed the routing
+ * is obvious.
+ */
+ root_nfs_addrs(nfsaddrs);
+ if ((myaddr.sin_addr.s_addr == INADDR_NONE ||
+ server.sin_addr.s_addr == INADDR_NONE ||
+ (open_base != NULL && open_base->next != NULL)) && do_rarp() < 0) {
+ root_dev_close();
+ return -1;
+ }
+ if (root_dev == NULL) {
+ if (open_base != NULL && open_base->next == NULL) {
+ root_dev = open_base->dev;
+ } else {
+ printk(KERN_ERR "NFS: Unable to find routing to server\n");
+ root_dev_close();
+ return -1;
+ }
+ }
/*
- * Initialize network device and get local and server IP address
+ * Close all network devices except the device which connects to
+ * server
*/
-
- if (do_rarp() < 0)
- return -1;
+ root_dev_close();
/*
- * Initialize the global variables necessary for NFS. The server
- * directory is actually mounted after init() has been started.
+ * Initialize the global variables necessary for NFS. The server
+ * directory is actually mounted after init() has been started.
*/
-
if (root_nfs_parse(nfsname) < 0)
return -1;
root_nfs_print();
@@ -619,6 +662,9 @@
return 0;
}
+
+
+
/***************************************************************************
Routines to actually mount the root directory
@@ -630,35 +676,27 @@
static int *rpc_packet = NULL; /* RPC packet */
extern asmlinkage int sys_socketcall(int call, unsigned long *args);
-extern struct socket *socki_lookup(struct inode *inode);
/*
- * Open a UDP socket.
+ * Open a UDP socket.
*/
-
static int root_nfs_open(void)
{
struct file *filp;
unsigned long opt[] = { AF_INET, SOCK_DGRAM, IPPROTO_UDP };
- /*
- * Open the socket
- */
-
- if ((nfs_data.fd = sys_socketcall(SYS_SOCKET, opt)) < 0)
- {
+ /* Open the socket */
+ if ((nfs_data.fd = sys_socketcall(SYS_SOCKET, opt)) < 0) {
printk(KERN_ERR "NFS: Cannot open UDP socket\n");
return -1;
}
-
- /*
- * Copy the file and inode data area so that we can remove the
- * file lateron without killing the socket. After all this the
- * closing routine just needs to remove the file pointer from
- * the init-task descriptor.
+ /*
+ * Copy the file and inode data area so that we can remove the
+ * file lateron without killing the socket. After all this the
+ * closing routine just needs to remove the file pointer from the
+ * init-task descriptor.
*/
-
filp = current->files->fd[nfs_data.fd];
memcpy(&nfs_file, filp, sizeof(struct file));
nfs_file.f_next = nfs_file.f_prev = NULL;
@@ -678,35 +716,28 @@
/*
- * Close the UDP file descriptor. The main part of preserving the socket
- * has already been done after opening it. Now we have to remove the
- * file descriptor from the init task.
+ * Close the UDP file descriptor. The main part of preserving the socket
+ * has already been done after opening it. Now we have to remove the file
+ * descriptor from the init task.
*/
-
static void root_nfs_close(int close_all)
{
- /*
- * Remove the file from the list of open files
- */
-
+ /* Remove the file from the list of open files */
current->files->fd[nfs_data.fd] = NULL;
if (current->files->count > 0)
current->files->count--;
- /*
- * Clear memory use by the RPC packet
- */
-
+ /* Clear memory used by the RPC packet */
if (rpc_packet != NULL)
kfree_s(rpc_packet, nfs_data.wsize + 1024);
/*
- * In case of an error we also have to close the socket again (sigh)
+ * In case of an error we also have to close the socket again
+ * (sigh)
*/
-
- if (close_all)
- {
- nfs_inode.u.socket_i.inode = NULL; /* The inode is already cleared */
+ if (close_all) {
+ nfs_inode.u.socket_i.inode = NULL; /* The inode is already
+ * cleared */
if (nfs_file.f_op->release)
nfs_file.f_op->release(&nfs_inode, &nfs_file);
}
@@ -714,9 +745,8 @@
/*
- * Find a suitable listening port and bind to it
+ * Find a suitable listening port and bind to it
*/
-
static int root_nfs_bind(void)
{
int res = -1;
@@ -724,21 +754,17 @@
struct sockaddr_in *sin = &myaddr;
int i;
- if (nfs_inode.u.socket_i.ops->bind)
- {
- for (i = 0; i < NPORTS && res < 0; i++)
- {
+ if (nfs_inode.u.socket_i.ops->bind) {
+ for (i = 0; i < NPORTS && res < 0; i++) {
sin->sin_port = htons(port++);
- if (port > ENDPORT)
- {
+ if (port > ENDPORT) {
port = STARTPORT;
}
res = nfs_inode.u.socket_i.ops->bind(&nfs_inode.u.socket_i,
- (struct sockaddr *) sin, sizeof(struct sockaddr_in));
+ (struct sockaddr *)sin, sizeof(struct sockaddr_in));
}
}
- if (res < 0)
- {
+ if (res < 0) {
printk(KERN_ERR "NFS: Cannot find a suitable listening port\n");
root_nfs_close(1);
return -1;
@@ -751,42 +777,38 @@
/*
- * Send an RPC request and wait for the answer
+ * Send an RPC request and wait for the answer
*/
-
static int *root_nfs_call(int *end)
{
struct file *filp;
struct socket *sock;
int dummylen;
static struct nfs_server s = {
- &nfs_file, /* struct file * */
- 0, /* struct rsock * */
+ &nfs_file, /* struct file * */
+ 0, /* struct rsock * */
{
- 0, "",
- }, /* toaddr */
- 0, /* lock */
- NULL, /* wait queue */
- NFS_MOUNT_SOFT, /* flags - this seems a ___BAD___ default - AC */
- 0, 0, /* rsize, wsize */
- 0, /* timeo */
- 0, /* retrans */
- 3*HZ, 60*HZ, 30*HZ, 60*HZ, "\0"
+ 0, "",
+ }, /* toaddr */
+ 0, /* lock */
+ NULL, /* wait queue */
+ NFS_MOUNT_SOFT, /* flags */
+ 0, 0, /* rsize, wsize */
+ 0, /* timeo */
+ 0, /* retrans */
+ 3 * HZ, 60 * HZ, 30 * HZ, 60 * HZ, "\0"
};
filp = &nfs_file;
sock = &((filp->f_inode)->u.socket_i);
-
- /*
- * extract the other end of the socket into server->toaddr
- */
-
- sock->ops->getname(sock, &(s.toaddr), &dummylen, 1) ;
+
+ /* extract the other end of the socket into s->toaddr */
+ sock->ops->getname(sock, &(s.toaddr), &dummylen, 1);
((struct sockaddr_in *) &s.toaddr)->sin_port = server.sin_port;
((struct sockaddr_in *) &s.toaddr)->sin_family = server.sin_family;
((struct sockaddr_in *) &s.toaddr)->sin_addr.s_addr = server.sin_addr.s_addr;
-
- s.rsock = rpc_makesock(filp);
+
+ s.rsock = rpc_makesock(filp);
s.flags = nfs_data.flags;
s.rsize = nfs_data.rsize;
s.wsize = nfs_data.wsize;
@@ -795,18 +817,15 @@
strcpy(s.hostname, nfs_data.hostname);
/*
- * First connect the UDP socket to a server port, then send the packet
- * out, and finally check wether the answer is OK.
+ * First connect the UDP socket to a server port, then send the
+ * packet out, and finally check wether the answer is OK.
*/
-
if (nfs_inode.u.socket_i.ops->connect &&
- nfs_inode.u.socket_i.ops->connect(&nfs_inode.u.socket_i,
- (struct sockaddr *) &server, sizeof(struct sockaddr_in),
- nfs_file.f_flags) < 0)
- {
- return NULL;
- }
-
+ nfs_inode.u.socket_i.ops->connect(&nfs_inode.u.socket_i,
+ (struct sockaddr *) &server,
+ sizeof(struct sockaddr_in),
+ nfs_file.f_flags) < 0)
+ return NULL;
if (nfs_rpc_call(&s, rpc_packet, end, nfs_data.wsize) < 0)
return NULL;
return rpc_verify(rpc_packet);
@@ -814,56 +833,42 @@
/*
- * Create an RPC packet header
+ * Create an RPC packet header
*/
-
static int *root_nfs_header(int proc, int program, int version)
{
int groups[] = { 0, NOGROUP };
- if (rpc_packet == NULL)
- {
- if (!(rpc_packet = kmalloc(nfs_data.wsize + 1024, GFP_NFS)))
- {
+ if (rpc_packet == NULL) {
+ if (!(rpc_packet = kmalloc(nfs_data.wsize + 1024, GFP_NFS))) {
printk(KERN_ERR "NFS: Cannot allocate UDP buffer\n");
return NULL;
}
}
- strcpy(system_utsname.nodename, in_ntoa(myaddr.sin_addr.s_addr));
return rpc_header(rpc_packet, proc, program, version, 0, 0, groups);
}
/*
- * Query server portmapper for the port of a daemon program
+ * Query server portmapper for the port of a daemon program
*/
-
static int root_nfs_get_port(int program, int version)
{
int *p;
- /*
- * Prepare header for portmap request
- */
-
+ /* Prepare header for portmap request */
server.sin_port = htons(NFS_PMAP_PORT);
p = root_nfs_header(NFS_PMAP_PROC, NFS_PMAP_PROGRAM, NFS_PMAP_VERSION);
if (!p)
return -1;
- /*
- * Set arguments for portmapper
- */
-
+ /* Set arguments for portmapper */
*p++ = htonl(program);
*p++ = htonl(version);
*p++ = htonl(IPPROTO_UDP);
*p++ = 0;
- /*
- * Send request to server portmapper
- */
-
+ /* Send request to server portmapper */
if ((p = root_nfs_call(p)) == NULL)
return -1;
@@ -872,17 +877,14 @@
/*
- * Get portnumbers for mountd and nfsd from server
+ * Get portnumbers for mountd and nfsd from server
*/
-
static int root_nfs_ports(void)
{
int port;
- if (nfs_port < 0)
- {
- if ((port = root_nfs_get_port(NFS_NFS_PROGRAM, NFS_NFS_VERSION)) < 0)
- {
+ if (nfs_port < 0) {
+ if ((port = root_nfs_get_port(NFS_NFS_PROGRAM, NFS_NFS_VERSION)) < 0) {
printk(KERN_ERR "NFS: Unable to get nfsd port number from server, using default\n");
port = NFS_NFS_PORT;
}
@@ -891,9 +893,7 @@
printk(KERN_NOTICE "NFS: Portmapper on server returned %d as nfsd port\n", port);
#endif
}
-
- if ((port = root_nfs_get_port(NFS_MOUNT_PROGRAM, NFS_MOUNT_VERSION)) < 0)
- {
+ if ((port = root_nfs_get_port(NFS_MOUNT_PROGRAM, NFS_MOUNT_VERSION)) < 0) {
printk(KERN_ERR "NFS: Unable to get mountd port number from server, using default\n");
port = NFS_MOUNT_PORT;
}
@@ -901,33 +901,26 @@
#ifdef NFSROOT_DEBUG
printk(KERN_NOTICE "NFS: Portmapper on server returned %d as mountd port\n", port);
#endif
+
return 0;
}
/*
- * Get a file handle from the server for the directory which is to be mounted
+ * Get a file handle from the server for the directory which is to be
+ * mounted
*/
-
static int root_nfs_get_handle(void)
{
int len, status, *p;
- /*
- * Prepare header for mountd request
- */
-
+ /* Prepare header for mountd request */
p = root_nfs_header(NFS_MOUNT_PROC, NFS_MOUNT_PROGRAM, NFS_MOUNT_VERSION);
- if (!p)
- {
+ if (!p) {
root_nfs_close(1);
return -1;
}
-
- /*
- * Set arguments for mountd
- */
-
+ /* Set arguments for mountd */
len = strlen(nfs_path);
*p++ = htonl(len);
memcpy(p, nfs_path, len);
@@ -935,72 +928,56 @@
p[len] = 0;
p += len;
- /*
- * Send request to server portmapper
- */
-
- if ((p = root_nfs_call(p)) == NULL)
- {
+ /* Send request to server mountd */
+ if ((p = root_nfs_call(p)) == NULL) {
root_nfs_close(1);
return -1;
}
-
status = ntohl(*p++);
- if (status == 0)
- {
+ if (status == 0) {
nfs_data.root = *((struct nfs_fh *) p);
- }
- else
- {
+ printk(KERN_NOTICE "NFS: ");
+ printk("Got file handle for %s via RPC\n", nfs_path);
+ } else {
printk(KERN_ERR "NFS: Server returned error %d while mounting %s\n",
status, nfs_path);
root_nfs_close(1);
return -1;
}
+
return 0;
}
/*
- * Now actually mount the given directory
+ * Now actually mount the given directory
*/
-
static int root_nfs_do_mount(struct super_block *sb)
{
- /*
- * First connect to the nfsd port on the server
- */
-
+ /* First connect to the nfsd port on the server */
server.sin_port = htons(nfs_port);
nfs_data.addr = server;
if (nfs_inode.u.socket_i.ops->connect &&
- nfs_inode.u.socket_i.ops->connect(&nfs_inode.u.socket_i,
- (struct sockaddr *) &server, sizeof(struct sockaddr_in),
- nfs_file.f_flags) < 0)
- {
+ nfs_inode.u.socket_i.ops->connect(&nfs_inode.u.socket_i,
+ (struct sockaddr *) &server,
+ sizeof(struct sockaddr_in),
+ nfs_file.f_flags) < 0) {
root_nfs_close(1);
return -1;
}
-
- /*
- * Now (finally ;-)) read the super block for mounting
- */
-
- if (nfs_read_super(sb, &nfs_data, 1) == NULL)
- {
+ /* Now (finally ;-)) read the super block for mounting */
+ if (nfs_read_super(sb, &nfs_data, 1) == NULL) {
root_nfs_close(1);
return -1;
}
-
return 0;
}
/*
- * Get the NFS port numbers and file handle, and then read the super-
- * block for mounting.
+ * Get the NFS port numbers and file handle, and then read the super-
+ * block for mounting.
*/
-
int nfs_root_mount(struct super_block *sb)
{
if (root_nfs_open() < 0)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this