Blame view
fs/nfs/nfsroot.c
9.71 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
1da177e4c Linux-2.6.12-rc2 |
2 |
/* |
1da177e4c Linux-2.6.12-rc2 |
3 4 5 6 |
* Copyright (C) 1995, 1996 Gero Kuhlmann <gero@gkminix.han.de> * * Allow an NFS filesystem to be mounted as root. The way this works is: * (1) Use the IP autoconfig mechanism to set local IP addresses and routes. |
56463e50d NFS: Use super.c ... |
7 8 9 10 |
* (2) Construct the device string and the options string using DHCP * option 17 and/or kernel command line options. * (3) When mount_root() sets up the root file system, pass these strings * to the NFS client's regular mount interface via sys_mount(). |
1da177e4c Linux-2.6.12-rc2 |
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
* * * Changes: * * Alan Cox : Removed get_address name clash with FPU. * Alan Cox : Reformatted a bit. * Gero Kuhlmann : Code cleanup * Michael Rausch : Fixed recognition of an incoming RARP answer. * Martin Mares : (2.0) Auto-configuration via BOOTP supported. * Martin Mares : Manual selection of interface & BOOTP/RARP. * Martin Mares : Using network routes instead of host routes, * allowing the default configuration to be used * for normal operation of the host. * Martin Mares : Randomized timer with exponential backoff * installed to minimize network congestion. * Martin Mares : Code cleanup. * Martin Mares : (2.1) BOOTP and RARP made configuration options. * Martin Mares : Server hostname generation fixed. * Gerd Knorr : Fixed wired inode handling * Martin Mares : (2.2) "0.0.0.0" addresses from command line ignored. * Martin Mares : RARP replies not tested for server address. * Gero Kuhlmann : (2.3) Some bug fixes and code cleanup again (please * send me your new patches _before_ bothering * Linus so that I don' always have to cleanup * _afterwards_ - thanks) * Gero Kuhlmann : Last changes of Martin Mares undone. * Gero Kuhlmann : RARP replies are tested for specified server * again. However, it's now possible to have * different RARP and NFS servers. * Gero Kuhlmann : "0.0.0.0" addresses from command line are * now mapped to INADDR_NONE. * Gero Kuhlmann : Fixed a bug which prevented BOOTP path name * from being used (thanks to Leo Spiekman) * Andy Walker : Allow to specify the NFS server in nfs_root * without giving a path name |
96de0e252 Convert files to ... |
46 |
* Swen Thümmler : Allow to specify the NFS options in nfs_root |
1da177e4c Linux-2.6.12-rc2 |
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
* without giving a path name. Fix BOOTP request * for domainname (domainname is NIS domain, not * DNS domain!). Skip dummy devices for BOOTP. * Jacek Zapala : Fixed a bug which prevented server-ip address * from nfsroot parameter from being used. * Olaf Kirch : Adapted to new NFS code. * Jakub Jelinek : Free used code segment. * Marko Kohtala : Fixed some bugs. * Martin Mares : Debug message cleanup * Martin Mares : Changed to use the new generic IP layer autoconfig * code. BOOTP and RARP moved there. * Martin Mares : Default path now contains host name instead of * host IP address (but host name defaults to IP * address anyway). * Martin Mares : Use root_server_addr appropriately during setup. * Martin Mares : Rewrote parameter parsing, now hopefully giving * correct overriding. * Trond Myklebust : Add in preliminary support for NFSv3 and TCP. * Fix bug in root_nfs_addr(). nfs_data.namlen * is NOT for the length of the hostname. * Hua Qin : Support for mounting root file system via * NFS over TCP. * Fabian Frederick: Option parser rebuilt (using parser lib) |
56463e50d NFS: Use super.c ... |
70 |
* Chuck Lever : Use super.c's text-based mount option parsing |
306a07536 NFS: Allow NFSROO... |
71 |
* Chuck Lever : Add "nfsrootdebug". |
56463e50d NFS: Use super.c ... |
72 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
73 |
|
1da177e4c Linux-2.6.12-rc2 |
74 75 |
#include <linux/types.h> #include <linux/string.h> |
1da177e4c Linux-2.6.12-rc2 |
76 |
#include <linux/init.h> |
1da177e4c Linux-2.6.12-rc2 |
77 78 |
#include <linux/nfs.h> #include <linux/nfs_fs.h> |
1da177e4c Linux-2.6.12-rc2 |
79 |
#include <linux/utsname.h> |
1da177e4c Linux-2.6.12-rc2 |
80 81 |
#include <linux/root_dev.h> #include <net/ipconfig.h> |
1da177e4c Linux-2.6.12-rc2 |
82 |
|
146ec944b NFS: Move declara... |
83 |
#include "internal.h" |
1da177e4c Linux-2.6.12-rc2 |
84 85 86 87 |
#define NFSDBG_FACILITY NFSDBG_ROOT /* Default path we try to mount. "%s" gets replaced by our IP address */ #define NFS_ROOT "/tftpboot/%s" |
53d473758 NFS: NFSROOT shou... |
88 |
/* Default NFSROOT mount options. */ |
3fc2bfa36 nfsroot: Default ... |
89 |
#if defined(CONFIG_NFS_V2) |
89c8023fd nfsroot: set tcp ... |
90 |
#define NFS_DEF_OPTIONS "vers=2,tcp,rsize=4096,wsize=4096" |
3fc2bfa36 nfsroot: Default ... |
91 92 93 94 95 |
#elif defined(CONFIG_NFS_V3) #define NFS_DEF_OPTIONS "vers=3,tcp,rsize=4096,wsize=4096" #else #define NFS_DEF_OPTIONS "vers=4,tcp,rsize=4096,wsize=4096" #endif |
53d473758 NFS: NFSROOT shou... |
96 |
|
1da177e4c Linux-2.6.12-rc2 |
97 |
/* Parameters passed from the kernel command line */ |
c64661935 nfsroot: make nfs... |
98 |
static char nfs_root_parms[NFS_MAXPATHLEN + 1] __initdata = ""; |
1da177e4c Linux-2.6.12-rc2 |
99 |
|
56463e50d NFS: Use super.c ... |
100 |
/* Text-based mount options passed to super.c */ |
53d473758 NFS: NFSROOT shou... |
101 |
static char nfs_root_options[256] __initdata = NFS_DEF_OPTIONS; |
56463e50d NFS: Use super.c ... |
102 |
|
1da177e4c Linux-2.6.12-rc2 |
103 |
/* Address of NFS server */ |
8d2321037 NFS: Clean up nfs... |
104 |
static __be32 servaddr __initdata = htonl(INADDR_NONE); |
1da177e4c Linux-2.6.12-rc2 |
105 106 |
/* Name of directory to mount */ |
56463e50d NFS: Use super.c ... |
107 108 109 110 |
static char nfs_export_path[NFS_MAXPATHLEN + 1] __initdata = ""; /* server:export path string passed to super.c */ static char nfs_root_device[NFS_MAXPATHLEN + 1] __initdata = ""; |
1da177e4c Linux-2.6.12-rc2 |
111 |
|
e27d359e9 SUNRPC/NFS: Add K... |
112 |
#ifdef NFS_DEBUG |
1da177e4c Linux-2.6.12-rc2 |
113 |
/* |
306a07536 NFS: Allow NFSROO... |
114 115 116 117 118 119 120 121 122 123 |
* When the "nfsrootdebug" kernel command line option is specified, * enable debugging messages for NFSROOT. */ static int __init nfs_root_debug(char *__unused) { nfs_debug |= NFSDBG_ROOT | NFSDBG_MOUNT; return 1; } __setup("nfsrootdebug", nfs_root_debug); |
036a10759 NFS: Fix a compil... |
124 |
#endif |
306a07536 NFS: Allow NFSROO... |
125 126 |
/* |
1da177e4c Linux-2.6.12-rc2 |
127 128 |
* Parse NFS server and directory information passed on the kernel * command line. |
60ac03685 NFS: Clean up NFS... |
129 130 131 132 133 |
* * nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>] * * If there is a "%s" token in the <root-dir> string, it is replaced * by the ASCII-representation of the client's IP address. |
1da177e4c Linux-2.6.12-rc2 |
134 135 136 137 |
*/ static int __init nfs_root_setup(char *line) { ROOT_DEV = Root_NFS; |
60ac03685 NFS: Clean up NFS... |
138 |
|
1da177e4c Linux-2.6.12-rc2 |
139 |
if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) { |
60ac03685 NFS: Clean up NFS... |
140 |
strlcpy(nfs_root_parms, line, sizeof(nfs_root_parms)); |
1da177e4c Linux-2.6.12-rc2 |
141 |
} else { |
60ac03685 NFS: Clean up NFS... |
142 143 144 145 |
size_t n = strlen(line) + sizeof(NFS_ROOT) - 1; if (n >= sizeof(nfs_root_parms)) line[sizeof(nfs_root_parms) - sizeof(NFS_ROOT) - 2] = '\0'; sprintf(nfs_root_parms, NFS_ROOT, line); |
1da177e4c Linux-2.6.12-rc2 |
146 |
} |
60ac03685 NFS: Clean up NFS... |
147 148 149 150 151 152 153 154 155 |
/* * Extract the IP address of the NFS server containing our * root file system, if one was specified. * * Note: root_nfs_parse_addr() removes the server-ip from * nfs_root_parms, if it exists. */ root_server_addr = root_nfs_parse_addr(nfs_root_parms); |
1da177e4c Linux-2.6.12-rc2 |
156 157 158 159 |
return 1; } __setup("nfsroot=", nfs_root_setup); |
56463e50d NFS: Use super.c ... |
160 161 162 163 164 165 166 167 168 |
static int __init root_nfs_copy(char *dest, const char *src, const size_t destlen) { if (strlcpy(dest, src, destlen) > destlen) return -1; return 0; } static int __init root_nfs_cat(char *dest, const char *src, |
53d473758 NFS: NFSROOT shou... |
169 |
const size_t destlen) |
56463e50d NFS: Use super.c ... |
170 |
{ |
53d473758 NFS: NFSROOT shou... |
171 172 173 174 175 |
size_t len = strlen(dest); if (len && dest[len - 1] != ',') if (strlcat(dest, ",", destlen) > destlen) return -1; |
56463e50d NFS: Use super.c ... |
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
if (strlcat(dest, src, destlen) > destlen) return -1; return 0; } /* * Parse out root export path and mount options from * passed-in string @incoming. * * Copy the export path into @exppath. */ static int __init root_nfs_parse_options(char *incoming, char *exppath, const size_t exppathlen) { char *p; /* * Set the NFS remote path */ p = strsep(&incoming, ","); if (*p != '\0' && strcmp(p, "default") != 0) if (root_nfs_copy(exppath, p, exppathlen)) return -1; /* * @incoming now points to the rest of the string; if it * contains something, append it to our root options buffer */ if (incoming != NULL && *incoming != '\0') if (root_nfs_cat(nfs_root_options, incoming, sizeof(nfs_root_options))) return -1; |
56463e50d NFS: Use super.c ... |
208 209 210 211 212 213 214 215 216 217 218 219 220 |
return 0; } /* * Decode the export directory path name and NFS options from * the kernel command line. This has to be done late in order to * use a dynamically acquired client IP address for the remote * root directory path. * * Returns zero if successful; otherwise -1 is returned. */ static int __init root_nfs_data(char *cmdline) { |
53d473758 NFS: NFSROOT shou... |
221 |
char mand_options[sizeof("nolock,addr=") + INET_ADDRSTRLEN + 1]; |
56463e50d NFS: Use super.c ... |
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
int len, retval = -1; char *tmp = NULL; const size_t tmplen = sizeof(nfs_export_path); tmp = kzalloc(tmplen, GFP_KERNEL); if (tmp == NULL) goto out_nomem; strcpy(tmp, NFS_ROOT); if (root_server_path[0] != '\0') { dprintk("Root-NFS: DHCPv4 option 17: %s ", root_server_path); if (root_nfs_parse_options(root_server_path, tmp, tmplen)) goto out_optionstoolong; } if (cmdline[0] != '\0') { dprintk("Root-NFS: nfsroot=%s ", cmdline); if (root_nfs_parse_options(cmdline, tmp, tmplen)) goto out_optionstoolong; } /* * Append mandatory options for nfsroot so they override * what has come before */ |
53d473758 NFS: NFSROOT shou... |
250 |
snprintf(mand_options, sizeof(mand_options), "nolock,addr=%pI4", |
56463e50d NFS: Use super.c ... |
251 |
&servaddr); |
53d473758 NFS: NFSROOT shou... |
252 |
if (root_nfs_cat(nfs_root_options, mand_options, |
56463e50d NFS: Use super.c ... |
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
sizeof(nfs_root_options))) goto out_optionstoolong; /* * Set up nfs_root_device. For NFS mounts, this looks like * * server:/path * * At this point, utsname()->nodename contains our local * IP address or hostname, set by ipconfig. If "%s" exists * in tmp, substitute the nodename, then shovel the whole * mess into nfs_root_device. */ len = snprintf(nfs_export_path, sizeof(nfs_export_path), tmp, utsname()->nodename); |
c7c545d4a NFS: a couple off... |
268 |
if (len >= (int)sizeof(nfs_export_path)) |
56463e50d NFS: Use super.c ... |
269 270 271 |
goto out_devnametoolong; len = snprintf(nfs_root_device, sizeof(nfs_root_device), "%pI4:%s", &servaddr, nfs_export_path); |
c7c545d4a NFS: a couple off... |
272 |
if (len >= (int)sizeof(nfs_root_device)) |
56463e50d NFS: Use super.c ... |
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
goto out_devnametoolong; retval = 0; out: kfree(tmp); return retval; out_nomem: printk(KERN_ERR "Root-NFS: could not allocate memory "); goto out; out_optionstoolong: printk(KERN_ERR "Root-NFS: mount options string too long "); goto out; out_devnametoolong: printk(KERN_ERR "Root-NFS: root device name too long. "); goto out; } /** * nfs_root_data - Return prepared 'data' for NFSROOT mount * @root_device: OUT: address of string containing NFSROOT device * @root_data: OUT: address of string containing NFSROOT mount options * * Returns zero and sets @root_device and @root_data if successful, * otherwise -1 is returned. */ int __init nfs_root_data(char **root_device, char **root_data) { |
56463e50d NFS: Use super.c ... |
304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
servaddr = root_server_addr; if (servaddr == htonl(INADDR_NONE)) { printk(KERN_ERR "Root-NFS: no NFS server address "); return -1; } if (root_nfs_data(nfs_root_parms) < 0) return -1; *root_device = nfs_root_device; *root_data = nfs_root_options; return 0; } |