LCOV - code coverage report
Current view: top level - fs/nfs - nfsroot.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 74 0.0 %
Date: 2022-04-01 14:35:51 Functions: 0 6 0.0 %
Branches: 0 50 0.0 %

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

Generated by: LCOV version 1.14