📄 nfsroot.c
字号:
printk("local=%s, ", IN_NTOA(myaddr.sin_addr.s_addr)); printk("server=%s, ", IN_NTOA(server.sin_addr.s_addr)); printk("gw=%s, ", IN_NTOA(gateway.sin_addr.s_addr)); printk("mask=%s, ", IN_NTOA(netmask.sin_addr.s_addr)); printk("host=%s, domain=%s\n", system_utsname.nodename[0] ? system_utsname.nodename : "none", system_utsname.domainname[0] ? system_utsname.domainname : "none"); printk(KERN_NOTICE "Root-NFS: Mounting %s on server %s as root\n", nfs_path, nfs_data.hostname); printk(KERN_NOTICE "Root-NFS: rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", nfs_data.rsize, nfs_data.wsize, nfs_data.timeo, nfs_data.retrans); printk(KERN_NOTICE "Root-NFS: acreg (min,max) = (%d,%d), acdir (min,max) = (%d,%d)\n", nfs_data.acregmin, nfs_data.acregmax, nfs_data.acdirmin, nfs_data.acdirmax); printk(KERN_NOTICE "Root-NFS: port = %d, flags = %08x\n", nfs_port, nfs_data.flags);#undef IN_NTOA}#endif/* * Decode any IP configuration options in the "nfsaddrs" kernel command * line parameter. It consists of option fields separated by colons in * the following order: * * <client-ip>:<server-ip>:<gw-ip>:<netmask>:<host name>:<device>:<bootp|rarp> * * Any of the fields can be empty which means to use a default value: * <client-ip> - address given by BOOTP or RARP * <server-ip> - address of host returning BOOTP or RARP packet * <gw-ip> - none, or the address returned by BOOTP * <netmask> - automatically determined from <client-ip>, or the * one returned by BOOTP * <host name> - <client-ip> in ASCII notation, or the name returned * by BOOTP * <device> - use all available devices for RARP and the first * one for BOOTP * <bootp|rarp> - use both protocols to determine my own address */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 = rarp_serv.sin_family = gateway.sin_family = netmask.sin_family = AF_INET; myaddr.sin_addr.s_addr = server.sin_addr.s_addr = rarp_serv.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'; user_dev_name[0] = '\0'; bootp_flag = rarp_flag = 1; /* The following is just a shortcut for automatic IP configuration */ if (!strcmp(addrs, "bootp")) { rarp_flag = 0; return; } else if (!strcmp(addrs, "rarp")) { bootp_flag = 0; return; } else if (!strcmp(addrs, "both")) { return; } /* Parse the whole string */ ip = addrs; while (ip && *ip) { if ((cp = strchr(ip, ':'))) *cp++ = '\0'; if (strlen(ip) > 0) {#ifdef NFSROOT_DEBUG printk(KERN_NOTICE "Root-NFS: Config string num %d is \"%s\"\n", num, ip);#endif switch (num) { case 0: if ((myaddr.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY) myaddr.sin_addr.s_addr = INADDR_NONE; break; case 1: if ((server.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY) server.sin_addr.s_addr = INADDR_NONE; break; case 2: if ((gateway.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY) gateway.sin_addr.s_addr = INADDR_NONE; break; case 3: if ((netmask.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY) netmask.sin_addr.s_addr = INADDR_NONE; 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; case 5: strncpy(user_dev_name, ip, IFNAMSIZ); user_dev_name[IFNAMSIZ-1] = '\0'; break; case 6: if (!strcmp(ip, "rarp")) bootp_flag = 0; else if (!strcmp(ip, "bootp")) rarp_flag = 0; else if (strcmp(ip, "both")) bootp_flag = rarp_flag = 0; break; default: break; } } ip = cp; num++; } rarp_serv = server;}/* * Set the interface address and configure a route to the server. */static int root_nfs_setup(void){ struct rtentry route; /* 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'; } /* 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 = netmask.sin_addr.s_addr; root_dev->pa_brdaddr = root_dev->pa_addr | ~root_dev->pa_mask; root_dev->pa_dstaddr = 0; /* * Now add a route to the server. If there is no gateway given, * the server is on the same subnet, so we establish only a route to * the local network. Otherwise we create a route to the gateway (the * same local network router as in the former case) and then setup a * gatewayed default route. Note that this gives sufficient network * setup even for full system operation in all common cases. */ memset(&route, 0, sizeof(route)); /* Local subnet route */ route.rt_dev = root_dev->name; route.rt_mss = root_dev->mtu; route.rt_flags = RTF_UP; *((struct sockaddr_in *) &(route.rt_dst)) = myaddr; (((struct sockaddr_in *) &(route.rt_dst)))->sin_addr.s_addr &= netmask.sin_addr.s_addr; *((struct sockaddr_in *) &(route.rt_genmask)) = netmask; if (ip_rt_new(&route)) { printk(KERN_ERR "Root-NFS: Adding of local route failed!\n"); return -1; } if (gateway.sin_addr.s_addr != INADDR_NONE) { /* Default route */ (((struct sockaddr_in *) &(route.rt_dst)))->sin_addr.s_addr = INADDR_ANY; (((struct sockaddr_in *) &(route.rt_genmask)))->sin_addr.s_addr = INADDR_ANY; *((struct sockaddr_in *) &(route.rt_gateway)) = gateway; route.rt_flags |= RTF_GATEWAY; if ((gateway.sin_addr.s_addr ^ myaddr.sin_addr.s_addr) & netmask.sin_addr.s_addr) { printk(KERN_ERR "Root-NFS: Gateway not on local network!\n"); return -1; } if (ip_rt_new(&route)) { printk(KERN_ERR "Root-NFS: Adding of default route failed!\n"); return -1; } } else if ((server.sin_addr.s_addr ^ myaddr.sin_addr.s_addr) & netmask.sin_addr.s_addr) { printk(KERN_ERR "Root-NFS: Boot server not on local network and no default gateway configured!\n"); return -1; } return 0;}/* * Get the necessary IP addresses and prepare for mounting the required * NFS filesystem. */int nfs_root_init(char *nfsname, char *nfsaddrs){ /* * Decode IP addresses and other configuration info contained * in the nfsaddrs string (which came from the kernel command * line). */ root_nfs_addrs(nfsaddrs); /* * Setup all network devices */ if (root_dev_open() < 0) return -1; /* * If the config information is insufficient (e.g., our IP address or * IP address of the boot server is missing or we have multiple network * interfaces and no default was set), use BOOTP or RARP to get the * missing values. * * Note that we don't try to set up correct routes for multiple * interfaces (could be solved by trying icmp echo requests), because * it's only necessary in the rare case of multiple ethernet devices * in the (diskless) system and if the server is on another subnet. * If only one interface is installed, the routing is obvious. */ if ((myaddr.sin_addr.s_addr == INADDR_NONE || server.sin_addr.s_addr == INADDR_NONE || (open_base != NULL && open_base->next != NULL))#ifdef CONFIG_RNFS_DYNAMIC && root_auto_config() < 0#endif ) { 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 "Root-NFS: Multiple devices and no server\n"); root_dev_close(); return -1; } } /* * Close all network devices except the device which connects to * server */ root_dev_close(); /* * Decode the root directory path name and NFS options from * the kernel command line. This has to go here in order to * be able to use the client IP address for the remote root * directory (necessary for pure RARP booting). */ if (root_nfs_name(nfsname) < 0) return -1; /* * Setup devices and routes. The server directory is actually * mounted after init() has been started. */ if (root_nfs_setup() < 0) return -1;#ifdef NFSROOT_DEBUG root_nfs_print();#endif return 0;}/*************************************************************************** Routines to actually mount the root directory ***************************************************************************/static struct file *nfs_file; /* File descriptor pointing to inode */static struct inode *nfs_sock_inode; /* Inode containing socket */static int *rpc_packet = NULL; /* RPC packet *//* * Open a UDP socket. */static int root_nfs_open(void){ /* Open the socket */ if ((nfs_data.fd = sys_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { printk(KERN_ERR "Root-NFS: Cannot open UDP socket for NFS!\n"); return -1; } nfs_file = current->files->fd[nfs_data.fd]; nfs_sock_inode = nfs_file->f_inode; return 0;}/* * Close the UDP file descriptor. If nfs_read_super is successful, it * increases the reference count, so we can simply close the file, and * the socket keeps open. */static void root_nfs_close(void){ /* * The following close doesn't touch the server structure, which * now contains a file pointer pointing into nowhere. The system * _should_ crash as soon as someone tries to select on the root * filesystem. Haven't tried it yet - we can still change it back * to the old way of keeping a static copy of all important data * structures, including their pointers. At least this should be * checked out _carefully_ before going into a public release * kernel. - GK */ sys_close(nfs_data.fd);}/* * Find a suitable listening port and bind to it */static int root_nfs_bind(void){ int res = -1; short port = STARTPORT; struct sockaddr_in *sin = &myaddr; int i; if (nfs_sock_inode->u.socket_i.ops->bind) { for (i = 0; i < NPORTS && res < 0; i++) { sin->sin_port = htons(port++); if (port > ENDPORT) { port = STARTPORT; } res = nfs_sock_inode->u.socket_i.ops->bind(&nfs_sock_inode->u.socket_i, (struct sockaddr *)sin, sizeof(struct sockaddr_in)); } } if (res < 0) { printk(KERN_ERR "Root-NFS: Cannot find a suitable listening port\n"); root_nfs_close(); return -1; }#ifdef NFSROOT_DEBUG printk(KERN_NOTICE "Root-NFS: Binding to listening port %d\n", port);#endif return 0;}/* * Send an RPC request and wait for the answer */static int *root_nfs_call(int *end){ struct socket *sock; int dummylen; static struct nfs_server s = { 0, /* struct file * */ 0, /* struct rsock * */ { 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" }; s.file = nfs_file; sock = &((nfs_file->f_inode)->u.socket_i); /* 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(nfs_file); s.flags = nfs_data.flags; s.rsize = nfs_data.rsize; s.wsize = nfs_data.wsize; s.timeo = nfs_data.timeo * HZ / 10; s.retrans = nfs_data.retrans; strcpy(s.hostname, nfs_data.hostname); /* * First connect the UDP socket to a server port, then send the * packet out, and finally check whether the answer is OK. */ if (nfs_sock_inode->u.socket_i.ops->connect && nfs_sock_inode->u.socket_i.ops->connect(&nfs_sock_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);}/* * 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))) { printk(KERN_ERR "Root-NFS: Cannot allocate UDP buffer\n"); return NULL; } } return rpc_header(rpc_packet, proc, program, version, 0, 0, groups);}/* * 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 */ 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 */ *p++ = htonl(program); *p++ = htonl(version); *p++ = htonl(IPPROTO_UDP); *p++ = 0; /* Send request to server portmapper */ if ((p = root_nfs_call(p)) == NULL) return -1; return ntohl(*p);}/* * 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) { printk(KERN_ERR "Root-NFS: Unable to get nfsd port number from server, using default\n"); port = NFS_NFS_PORT; } nfs_port = port;#ifdef NFSROOT_DEBUG printk(KERN_NOTICE "Root-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) { printk(KERN_ERR "Root-NFS: Unable to get mountd port number from server, using default\n"); port = NFS_MOUNT_PORT; } server.sin_port = htons(port);#ifdef NFSROOT_DEBUG printk(KERN_NOTICE "Root-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 */static int root_nfs_get_handle(void){ int len, status, *p; /* Prepare header for mountd request */ p = root_nfs_header(NFS_MOUNT_PROC, NFS_MOUNT_PROGRAM, NFS_MOUNT_VERSION); if (!p) { root_nfs_close(); return -1; } /* Set arguments for mountd */ len = strlen(nfs_path); *p++ = htonl(len); memcpy(p, nfs_path, len); len = (len + 3) >> 2; p[len] = 0; p += len; /* Send request to server mountd */ if ((p = root_nfs_call(p)) == NULL) { root_nfs_close(); return -1; } status = ntohl(*p++); if (status == 0) { nfs_data.root = *((struct nfs_fh *) p); printk(KERN_NOTICE "Root-NFS: Got file handle for %s via RPC\n", nfs_path); } else { printk(KERN_ERR "Root-NFS: Server returned error %d while mounting %s\n", status, nfs_path); root_nfs_close(); return -1; } return 0;}/* * 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 */ server.sin_port = htons(nfs_port); nfs_data.addr = server; if (nfs_sock_inode->u.socket_i.ops->connect && nfs_sock_inode->u.socket_i.ops->connect(&nfs_sock_inode->u.socket_i, (struct sockaddr *) &server, sizeof(struct sockaddr_in), nfs_file->f_flags) < 0) { root_nfs_close(); return -1; } /* Now (finally ;-)) read the super block for mounting */ if (nfs_read_super(sb, &nfs_data, 1) == NULL) { root_nfs_close(); return -1; } return 0;}/* * 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) return -1; if (root_nfs_bind() < 0) return -1; if (root_nfs_ports() < 0) return -1; if (root_nfs_get_handle() < 0) return -1; if (root_nfs_do_mount(sb) < 0) return -1; root_nfs_close(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -