LCOV - code coverage report
Current view: top level - fs/nfs - nfsroot.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 56 0.0 %
Date: 2014-02-18 Functions: 0 6 0.0 %
Branches: 0 48 0.0 %

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

Generated by: LCOV version 1.9