LCOV - code coverage report
Current view: top level - fs/nfs - nfs4client.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 0 429 0.0 %
Date: 2020-09-30 20:25:40 Functions: 0 37 0.0 %
Branches: 0 238 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
       4                 :            :  * Written by David Howells (dhowells@redhat.com)
       5                 :            :  */
       6                 :            : #include <linux/module.h>
       7                 :            : #include <linux/nfs_fs.h>
       8                 :            : #include <linux/nfs_mount.h>
       9                 :            : #include <linux/sunrpc/addr.h>
      10                 :            : #include <linux/sunrpc/auth.h>
      11                 :            : #include <linux/sunrpc/xprt.h>
      12                 :            : #include <linux/sunrpc/bc_xprt.h>
      13                 :            : #include <linux/sunrpc/rpc_pipe_fs.h>
      14                 :            : #include "internal.h"
      15                 :            : #include "callback.h"
      16                 :            : #include "delegation.h"
      17                 :            : #include "nfs4session.h"
      18                 :            : #include "nfs4idmap.h"
      19                 :            : #include "pnfs.h"
      20                 :            : #include "netns.h"
      21                 :            : 
      22                 :            : #define NFSDBG_FACILITY         NFSDBG_CLIENT
      23                 :            : 
      24                 :            : /*
      25                 :            :  * Get a unique NFSv4.0 callback identifier which will be used
      26                 :            :  * by the V4.0 callback service to lookup the nfs_client struct
      27                 :            :  */
      28                 :          0 : static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
      29                 :            : {
      30                 :            :         int ret = 0;
      31                 :          0 :         struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
      32                 :            : 
      33   [ #  #  #  # ]:          0 :         if (clp->rpc_ops->version != 4 || minorversion != 0)
      34                 :            :                 return ret;
      35                 :          0 :         idr_preload(GFP_KERNEL);
      36                 :            :         spin_lock(&nn->nfs_client_lock);
      37                 :          0 :         ret = idr_alloc(&nn->cb_ident_idr, clp, 1, 0, GFP_NOWAIT);
      38         [ #  # ]:          0 :         if (ret >= 0)
      39                 :          0 :                 clp->cl_cb_ident = ret;
      40                 :            :         spin_unlock(&nn->nfs_client_lock);
      41                 :            :         idr_preload_end();
      42                 :          0 :         return ret < 0 ? ret : 0;
      43                 :            : }
      44                 :            : 
      45                 :            : #ifdef CONFIG_NFS_V4_1
      46                 :            : /*
      47                 :            :  * Per auth flavor data server rpc clients
      48                 :            :  */
      49                 :            : struct nfs4_ds_server {
      50                 :            :         struct list_head        list;   /* ds_clp->cl_ds_clients */
      51                 :            :         struct rpc_clnt         *rpc_clnt;
      52                 :            : };
      53                 :            : 
      54                 :            : /**
      55                 :            :  * nfs4_find_ds_client - Common lookup case for DS I/O
      56                 :            :  * @ds_clp: pointer to the DS's nfs_client
      57                 :            :  * @flavor: rpc auth flavour to match
      58                 :            :  */
      59                 :            : static struct nfs4_ds_server *
      60                 :          0 : nfs4_find_ds_client(struct nfs_client *ds_clp, rpc_authflavor_t flavor)
      61                 :            : {
      62                 :            :         struct nfs4_ds_server *dss;
      63                 :            : 
      64                 :            :         rcu_read_lock();
      65         [ #  # ]:          0 :         list_for_each_entry_rcu(dss, &ds_clp->cl_ds_clients, list) {
      66         [ #  # ]:          0 :                 if (dss->rpc_clnt->cl_auth->au_flavor != flavor)
      67                 :          0 :                         continue;
      68                 :            :                 goto out;
      69                 :            :         }
      70                 :            :         dss = NULL;
      71                 :            : out:
      72                 :            :         rcu_read_unlock();
      73                 :          0 :         return dss;
      74                 :            : }
      75                 :            : 
      76                 :            : static struct nfs4_ds_server *
      77                 :          0 : nfs4_add_ds_client(struct nfs_client *ds_clp, rpc_authflavor_t flavor,
      78                 :            :                            struct nfs4_ds_server *new)
      79                 :            : {
      80                 :            :         struct nfs4_ds_server *dss;
      81                 :            : 
      82                 :            :         spin_lock(&ds_clp->cl_lock);
      83         [ #  # ]:          0 :         list_for_each_entry(dss, &ds_clp->cl_ds_clients, list) {
      84         [ #  # ]:          0 :                 if (dss->rpc_clnt->cl_auth->au_flavor != flavor)
      85                 :          0 :                         continue;
      86                 :            :                 goto out;
      87                 :            :         }
      88         [ #  # ]:          0 :         if (new)
      89                 :          0 :                 list_add_rcu(&new->list, &ds_clp->cl_ds_clients);
      90                 :            :         dss = new;
      91                 :            : out:
      92                 :            :         spin_unlock(&ds_clp->cl_lock); /* need some lock to protect list */
      93                 :          0 :         return dss;
      94                 :            : }
      95                 :            : 
      96                 :            : static struct nfs4_ds_server *
      97                 :          0 : nfs4_alloc_ds_server(struct nfs_client *ds_clp, rpc_authflavor_t flavor)
      98                 :            : {
      99                 :            :         struct nfs4_ds_server *dss;
     100                 :            : 
     101                 :            :         dss = kmalloc(sizeof(*dss), GFP_NOFS);
     102         [ #  # ]:          0 :         if (dss == NULL)
     103                 :            :                 return ERR_PTR(-ENOMEM);
     104                 :            : 
     105                 :          0 :         dss->rpc_clnt = rpc_clone_client_set_auth(ds_clp->cl_rpcclient, flavor);
     106         [ #  # ]:          0 :         if (IS_ERR(dss->rpc_clnt)) {
     107                 :            :                 int err = PTR_ERR(dss->rpc_clnt);
     108                 :          0 :                 kfree (dss);
     109                 :          0 :                 return ERR_PTR(err);
     110                 :            :         }
     111                 :          0 :         INIT_LIST_HEAD(&dss->list);
     112                 :            : 
     113                 :          0 :         return dss;
     114                 :            : }
     115                 :            : 
     116                 :            : static void
     117                 :            : nfs4_free_ds_server(struct nfs4_ds_server *dss)
     118                 :            : {
     119                 :          0 :         rpc_release_client(dss->rpc_clnt);
     120                 :          0 :         kfree(dss);
     121                 :            : }
     122                 :            : 
     123                 :            : /**
     124                 :            :  * nfs4_find_or_create_ds_client - Find or create a DS rpc client
     125                 :            :  * @ds_clp: pointer to the DS's nfs_client
     126                 :            :  * @inode: pointer to the inode
     127                 :            :  *
     128                 :            :  * Find or create a DS rpc client with th MDS server rpc client auth flavor
     129                 :            :  * in the nfs_client cl_ds_clients list.
     130                 :            :  */
     131                 :            : struct rpc_clnt *
     132                 :          0 : nfs4_find_or_create_ds_client(struct nfs_client *ds_clp, struct inode *inode)
     133                 :            : {
     134                 :            :         struct nfs4_ds_server *dss, *new;
     135                 :          0 :         rpc_authflavor_t flavor = NFS_SERVER(inode)->client->cl_auth->au_flavor;
     136                 :            : 
     137                 :          0 :         dss = nfs4_find_ds_client(ds_clp, flavor);
     138         [ #  # ]:          0 :         if (dss != NULL)
     139                 :            :                 goto out;
     140                 :          0 :         new = nfs4_alloc_ds_server(ds_clp, flavor);
     141         [ #  # ]:          0 :         if (IS_ERR(new))
     142                 :            :                 return ERR_CAST(new);
     143                 :          0 :         dss = nfs4_add_ds_client(ds_clp, flavor, new);
     144         [ #  # ]:          0 :         if (dss != new)
     145                 :            :                 nfs4_free_ds_server(new);
     146                 :            : out:
     147                 :          0 :         return dss->rpc_clnt;
     148                 :            : }
     149                 :            : EXPORT_SYMBOL_GPL(nfs4_find_or_create_ds_client);
     150                 :            : 
     151                 :            : static void
     152                 :          0 : nfs4_shutdown_ds_clients(struct nfs_client *clp)
     153                 :            : {
     154                 :            :         struct nfs4_ds_server *dss;
     155                 :            : 
     156         [ #  # ]:          0 :         while (!list_empty(&clp->cl_ds_clients)) {
     157                 :          0 :                 dss = list_entry(clp->cl_ds_clients.next,
     158                 :            :                                         struct nfs4_ds_server, list);
     159                 :            :                 list_del(&dss->list);
     160                 :          0 :                 rpc_shutdown_client(dss->rpc_clnt);
     161                 :          0 :                 kfree (dss);
     162                 :            :         }
     163                 :          0 : }
     164                 :            : 
     165                 :            : static void
     166                 :          0 : nfs4_cleanup_callback(struct nfs_client *clp)
     167                 :            : {
     168                 :            :         struct nfs4_copy_state *cp_state;
     169                 :            : 
     170         [ #  # ]:          0 :         while (!list_empty(&clp->pending_cb_stateids)) {
     171                 :          0 :                 cp_state = list_entry(clp->pending_cb_stateids.next,
     172                 :            :                                         struct nfs4_copy_state, copies);
     173                 :            :                 list_del(&cp_state->copies);
     174                 :          0 :                 kfree(cp_state);
     175                 :            :         }
     176                 :          0 : }
     177                 :            : 
     178                 :          0 : void nfs41_shutdown_client(struct nfs_client *clp)
     179                 :            : {
     180         [ #  # ]:          0 :         if (nfs4_has_session(clp)) {
     181                 :          0 :                 nfs4_cleanup_callback(clp);
     182                 :          0 :                 nfs4_shutdown_ds_clients(clp);
     183                 :          0 :                 nfs4_destroy_session(clp->cl_session);
     184                 :          0 :                 nfs4_destroy_clientid(clp);
     185                 :            :         }
     186                 :            : 
     187                 :          0 : }
     188                 :            : #endif  /* CONFIG_NFS_V4_1 */
     189                 :            : 
     190                 :          0 : void nfs40_shutdown_client(struct nfs_client *clp)
     191                 :            : {
     192         [ #  # ]:          0 :         if (clp->cl_slot_tbl) {
     193                 :          0 :                 nfs4_shutdown_slot_table(clp->cl_slot_tbl);
     194                 :          0 :                 kfree(clp->cl_slot_tbl);
     195                 :            :         }
     196                 :          0 : }
     197                 :            : 
     198                 :          0 : struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
     199                 :            : {
     200                 :            :         int err;
     201                 :          0 :         struct nfs_client *clp = nfs_alloc_client(cl_init);
     202         [ #  # ]:          0 :         if (IS_ERR(clp))
     203                 :            :                 return clp;
     204                 :            : 
     205                 :          0 :         err = nfs_get_cb_ident_idr(clp, cl_init->minorversion);
     206         [ #  # ]:          0 :         if (err)
     207                 :            :                 goto error;
     208                 :            : 
     209         [ #  # ]:          0 :         if (cl_init->minorversion > NFS4_MAX_MINOR_VERSION) {
     210                 :            :                 err = -EINVAL;
     211                 :            :                 goto error;
     212                 :            :         }
     213                 :            : 
     214                 :          0 :         spin_lock_init(&clp->cl_lock);
     215                 :          0 :         INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
     216                 :          0 :         INIT_LIST_HEAD(&clp->cl_ds_clients);
     217                 :          0 :         rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
     218                 :          0 :         clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
     219                 :          0 :         clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion];
     220                 :          0 :         clp->cl_mig_gen = 1;
     221                 :            : #if IS_ENABLED(CONFIG_NFS_V4_1)
     222                 :          0 :         init_waitqueue_head(&clp->cl_lock_waitq);
     223                 :            : #endif
     224                 :          0 :         INIT_LIST_HEAD(&clp->pending_cb_stateids);
     225                 :          0 :         return clp;
     226                 :            : 
     227                 :            : error:
     228                 :          0 :         nfs_free_client(clp);
     229                 :          0 :         return ERR_PTR(err);
     230                 :            : }
     231                 :            : 
     232                 :            : /*
     233                 :            :  * Destroy the NFS4 callback service
     234                 :            :  */
     235                 :          0 : static void nfs4_destroy_callback(struct nfs_client *clp)
     236                 :            : {
     237         [ #  # ]:          0 :         if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
     238                 :          0 :                 nfs_callback_down(clp->cl_mvops->minor_version, clp->cl_net);
     239                 :          0 : }
     240                 :            : 
     241                 :          0 : static void nfs4_shutdown_client(struct nfs_client *clp)
     242                 :            : {
     243         [ #  # ]:          0 :         if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))
     244                 :          0 :                 nfs4_kill_renewd(clp);
     245                 :          0 :         clp->cl_mvops->shutdown_client(clp);
     246                 :          0 :         nfs4_destroy_callback(clp);
     247         [ #  # ]:          0 :         if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))
     248                 :          0 :                 nfs_idmap_delete(clp);
     249                 :            : 
     250                 :          0 :         rpc_destroy_wait_queue(&clp->cl_rpcwaitq);
     251                 :          0 :         kfree(clp->cl_serverowner);
     252                 :          0 :         kfree(clp->cl_serverscope);
     253                 :          0 :         kfree(clp->cl_implid);
     254                 :          0 :         kfree(clp->cl_owner_id);
     255                 :          0 : }
     256                 :            : 
     257                 :          0 : void nfs4_free_client(struct nfs_client *clp)
     258                 :            : {
     259                 :          0 :         nfs4_shutdown_client(clp);
     260                 :          0 :         nfs_free_client(clp);
     261                 :          0 : }
     262                 :            : 
     263                 :            : /*
     264                 :            :  * Initialize the NFS4 callback service
     265                 :            :  */
     266                 :          0 : static int nfs4_init_callback(struct nfs_client *clp)
     267                 :            : {
     268                 :            :         struct rpc_xprt *xprt;
     269                 :            :         int error;
     270                 :            : 
     271                 :          0 :         xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt);
     272                 :            : 
     273         [ #  # ]:          0 :         if (nfs4_has_session(clp)) {
     274                 :          0 :                 error = xprt_setup_backchannel(xprt, NFS41_BC_MIN_CALLBACKS);
     275         [ #  # ]:          0 :                 if (error < 0)
     276                 :            :                         return error;
     277                 :            :         }
     278                 :            : 
     279                 :          0 :         error = nfs_callback_up(clp->cl_mvops->minor_version, xprt);
     280         [ #  # ]:          0 :         if (error < 0) {
     281                 :            :                 dprintk("%s: failed to start callback. Error = %d\n",
     282                 :            :                         __func__, error);
     283                 :            :                 return error;
     284                 :            :         }
     285                 :            :         __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state);
     286                 :            : 
     287                 :          0 :         return 0;
     288                 :            : }
     289                 :            : 
     290                 :            : /**
     291                 :            :  * nfs40_init_client - nfs_client initialization tasks for NFSv4.0
     292                 :            :  * @clp: nfs_client to initialize
     293                 :            :  *
     294                 :            :  * Returns zero on success, or a negative errno if some error occurred.
     295                 :            :  */
     296                 :          0 : int nfs40_init_client(struct nfs_client *clp)
     297                 :            : {
     298                 :            :         struct nfs4_slot_table *tbl;
     299                 :            :         int ret;
     300                 :            : 
     301                 :          0 :         tbl = kzalloc(sizeof(*tbl), GFP_NOFS);
     302         [ #  # ]:          0 :         if (tbl == NULL)
     303                 :            :                 return -ENOMEM;
     304                 :            : 
     305                 :          0 :         ret = nfs4_setup_slot_table(tbl, NFS4_MAX_SLOT_TABLE,
     306                 :            :                                         "NFSv4.0 transport Slot table");
     307         [ #  # ]:          0 :         if (ret) {
     308                 :          0 :                 kfree(tbl);
     309                 :          0 :                 return ret;
     310                 :            :         }
     311                 :            : 
     312                 :          0 :         clp->cl_slot_tbl = tbl;
     313                 :          0 :         return 0;
     314                 :            : }
     315                 :            : 
     316                 :            : #if defined(CONFIG_NFS_V4_1)
     317                 :            : 
     318                 :            : /**
     319                 :            :  * nfs41_init_client - nfs_client initialization tasks for NFSv4.1+
     320                 :            :  * @clp: nfs_client to initialize
     321                 :            :  *
     322                 :            :  * Returns zero on success, or a negative errno if some error occurred.
     323                 :            :  */
     324                 :          0 : int nfs41_init_client(struct nfs_client *clp)
     325                 :            : {
     326                 :            :         struct nfs4_session *session = NULL;
     327                 :            : 
     328                 :            :         /*
     329                 :            :          * Create the session and mark it expired.
     330                 :            :          * When a SEQUENCE operation encounters the expired session
     331                 :            :          * it will do session recovery to initialize it.
     332                 :            :          */
     333                 :          0 :         session = nfs4_alloc_session(clp);
     334         [ #  # ]:          0 :         if (!session)
     335                 :            :                 return -ENOMEM;
     336                 :            : 
     337                 :          0 :         clp->cl_session = session;
     338                 :            : 
     339                 :            :         /*
     340                 :            :          * The create session reply races with the server back
     341                 :            :          * channel probe. Mark the client NFS_CS_SESSION_INITING
     342                 :            :          * so that the client back channel can find the
     343                 :            :          * nfs_client struct
     344                 :            :          */
     345                 :          0 :         nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING);
     346                 :          0 :         return 0;
     347                 :            : }
     348                 :            : 
     349                 :            : #endif  /* CONFIG_NFS_V4_1 */
     350                 :            : 
     351                 :            : /*
     352                 :            :  * Initialize the minor version specific parts of an NFS4 client record
     353                 :            :  */
     354                 :          0 : static int nfs4_init_client_minor_version(struct nfs_client *clp)
     355                 :            : {
     356                 :            :         int ret;
     357                 :            : 
     358                 :          0 :         ret = clp->cl_mvops->init_client(clp);
     359         [ #  # ]:          0 :         if (ret)
     360                 :            :                 return ret;
     361                 :          0 :         return nfs4_init_callback(clp);
     362                 :            : }
     363                 :            : 
     364                 :            : /**
     365                 :            :  * nfs4_init_client - Initialise an NFS4 client record
     366                 :            :  *
     367                 :            :  * @clp: nfs_client to initialise
     368                 :            :  * @cl_init: pointer to nfs_client_initdata
     369                 :            :  *
     370                 :            :  * Returns pointer to an NFS client, or an ERR_PTR value.
     371                 :            :  */
     372                 :          0 : struct nfs_client *nfs4_init_client(struct nfs_client *clp,
     373                 :            :                                     const struct nfs_client_initdata *cl_init)
     374                 :            : {
     375                 :            :         char buf[INET6_ADDRSTRLEN + 1];
     376                 :          0 :         const char *ip_addr = cl_init->ip_addr;
     377                 :            :         struct nfs_client *old;
     378                 :            :         int error;
     379                 :            : 
     380         [ #  # ]:          0 :         if (clp->cl_cons_state == NFS_CS_READY)
     381                 :            :                 /* the client is initialised already */
     382                 :            :                 return clp;
     383                 :            : 
     384                 :            :         /* Check NFS protocol revision and initialize RPC op vector */
     385                 :          0 :         clp->rpc_ops = &nfs_v4_clientops;
     386                 :            : 
     387         [ #  # ]:          0 :         if (clp->cl_minorversion != 0)
     388                 :            :                 __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags);
     389                 :          0 :         __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
     390                 :            :         __set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags);
     391                 :            : 
     392                 :          0 :         error = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_GSS_KRB5I);
     393         [ #  # ]:          0 :         if (error == -EINVAL)
     394                 :          0 :                 error = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_UNIX);
     395         [ #  # ]:          0 :         if (error < 0)
     396                 :            :                 goto error;
     397                 :            : 
     398                 :            :         /* If no clientaddr= option was specified, find a usable cb address */
     399         [ #  # ]:          0 :         if (ip_addr == NULL) {
     400                 :            :                 struct sockaddr_storage cb_addr;
     401                 :            :                 struct sockaddr *sap = (struct sockaddr *)&cb_addr;
     402                 :            : 
     403                 :          0 :                 error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr));
     404         [ #  # ]:          0 :                 if (error < 0)
     405                 :            :                         goto error;
     406                 :          0 :                 error = rpc_ntop(sap, buf, sizeof(buf));
     407         [ #  # ]:          0 :                 if (error < 0)
     408                 :            :                         goto error;
     409                 :            :                 ip_addr = (const char *)buf;
     410                 :            :         }
     411                 :          0 :         strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
     412                 :            : 
     413                 :          0 :         error = nfs_idmap_new(clp);
     414         [ #  # ]:          0 :         if (error < 0) {
     415                 :            :                 dprintk("%s: failed to create idmapper. Error = %d\n",
     416                 :            :                         __func__, error);
     417                 :            :                 goto error;
     418                 :            :         }
     419                 :            :         __set_bit(NFS_CS_IDMAP, &clp->cl_res_state);
     420                 :            : 
     421                 :          0 :         error = nfs4_init_client_minor_version(clp);
     422         [ #  # ]:          0 :         if (error < 0)
     423                 :            :                 goto error;
     424                 :            : 
     425                 :          0 :         error = nfs4_discover_server_trunking(clp, &old);
     426         [ #  # ]:          0 :         if (error < 0)
     427                 :            :                 goto error;
     428                 :            : 
     429         [ #  # ]:          0 :         if (clp != old) {
     430                 :          0 :                 clp->cl_preserve_clid = true;
     431                 :            :                 /*
     432                 :            :                  * Mark the client as having failed initialization so other
     433                 :            :                  * processes walking the nfs_client_list in nfs_match_client()
     434                 :            :                  * won't try to use it.
     435                 :            :                  */
     436                 :          0 :                 nfs_mark_client_ready(clp, -EPERM);
     437                 :            :         }
     438                 :          0 :         nfs_put_client(clp);
     439                 :          0 :         clear_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags);
     440                 :          0 :         return old;
     441                 :            : 
     442                 :            : error:
     443                 :          0 :         nfs_mark_client_ready(clp, error);
     444                 :          0 :         nfs_put_client(clp);
     445                 :          0 :         return ERR_PTR(error);
     446                 :            : }
     447                 :            : 
     448                 :            : /*
     449                 :            :  * SETCLIENTID just did a callback update with the callback ident in
     450                 :            :  * "drop," but server trunking discovery claims "drop" and "keep" are
     451                 :            :  * actually the same server.  Swap the callback IDs so that "keep"
     452                 :            :  * will continue to use the callback ident the server now knows about,
     453                 :            :  * and so that "keep"'s original callback ident is destroyed when
     454                 :            :  * "drop" is freed.
     455                 :            :  */
     456                 :          0 : static void nfs4_swap_callback_idents(struct nfs_client *keep,
     457                 :            :                                       struct nfs_client *drop)
     458                 :            : {
     459                 :          0 :         struct nfs_net *nn = net_generic(keep->cl_net, nfs_net_id);
     460                 :          0 :         unsigned int save = keep->cl_cb_ident;
     461                 :            : 
     462         [ #  # ]:          0 :         if (keep->cl_cb_ident == drop->cl_cb_ident)
     463                 :          0 :                 return;
     464                 :            : 
     465                 :            :         dprintk("%s: keeping callback ident %u and dropping ident %u\n",
     466                 :            :                 __func__, keep->cl_cb_ident, drop->cl_cb_ident);
     467                 :            : 
     468                 :            :         spin_lock(&nn->nfs_client_lock);
     469                 :            : 
     470                 :          0 :         idr_replace(&nn->cb_ident_idr, keep, drop->cl_cb_ident);
     471                 :          0 :         keep->cl_cb_ident = drop->cl_cb_ident;
     472                 :            : 
     473                 :          0 :         idr_replace(&nn->cb_ident_idr, drop, save);
     474                 :          0 :         drop->cl_cb_ident = save;
     475                 :            : 
     476                 :            :         spin_unlock(&nn->nfs_client_lock);
     477                 :            : }
     478                 :            : 
     479                 :          0 : static bool nfs4_match_client_owner_id(const struct nfs_client *clp1,
     480                 :            :                 const struct nfs_client *clp2)
     481                 :            : {
     482   [ #  #  #  # ]:          0 :         if (clp1->cl_owner_id == NULL || clp2->cl_owner_id == NULL)
     483                 :            :                 return true;
     484                 :          0 :         return strcmp(clp1->cl_owner_id, clp2->cl_owner_id) == 0;
     485                 :            : }
     486                 :            : 
     487                 :            : static bool nfs4_same_verifier(nfs4_verifier *v1, nfs4_verifier *v2)
     488                 :            : {
     489                 :          0 :         return memcmp(v1->data, v2->data, sizeof(v1->data)) == 0;
     490                 :            : }
     491                 :            : 
     492                 :          0 : static int nfs4_match_client(struct nfs_client  *pos,  struct nfs_client *new,
     493                 :            :                              struct nfs_client **prev, struct nfs_net *nn)
     494                 :            : {
     495                 :            :         int status;
     496                 :            : 
     497         [ #  # ]:          0 :         if (pos->rpc_ops != new->rpc_ops)
     498                 :            :                 return 1;
     499                 :            : 
     500         [ #  # ]:          0 :         if (pos->cl_minorversion != new->cl_minorversion)
     501                 :            :                 return 1;
     502                 :            : 
     503                 :            :         /* If "pos" isn't marked ready, we can't trust the
     504                 :            :          * remaining fields in "pos", especially the client
     505                 :            :          * ID and serverowner fields.  Wait for CREATE_SESSION
     506                 :            :          * to finish. */
     507         [ #  # ]:          0 :         if (pos->cl_cons_state > NFS_CS_READY) {
     508                 :          0 :                 refcount_inc(&pos->cl_count);
     509                 :            :                 spin_unlock(&nn->nfs_client_lock);
     510                 :            : 
     511                 :          0 :                 nfs_put_client(*prev);
     512                 :          0 :                 *prev = pos;
     513                 :            : 
     514                 :          0 :                 status = nfs_wait_client_init_complete(pos);
     515                 :            :                 spin_lock(&nn->nfs_client_lock);
     516                 :            : 
     517         [ #  # ]:          0 :                 if (status < 0)
     518                 :            :                         return status;
     519                 :            :         }
     520                 :            : 
     521         [ #  # ]:          0 :         if (pos->cl_cons_state != NFS_CS_READY)
     522                 :            :                 return 1;
     523                 :            : 
     524         [ #  # ]:          0 :         if (pos->cl_clientid != new->cl_clientid)
     525                 :            :                 return 1;
     526                 :            : 
     527                 :            :         /* NFSv4.1 always uses the uniform string, however someone
     528                 :            :          * might switch the uniquifier string on us.
     529                 :            :          */
     530         [ #  # ]:          0 :         if (!nfs4_match_client_owner_id(pos, new))
     531                 :            :                 return 1;
     532                 :            : 
     533                 :          0 :         return 0;
     534                 :            : }
     535                 :            : 
     536                 :            : /**
     537                 :            :  * nfs40_walk_client_list - Find server that recognizes a client ID
     538                 :            :  *
     539                 :            :  * @new: nfs_client with client ID to test
     540                 :            :  * @result: OUT: found nfs_client, or new
     541                 :            :  * @cred: credential to use for trunking test
     542                 :            :  *
     543                 :            :  * Returns zero, a negative errno, or a negative NFS4ERR status.
     544                 :            :  * If zero is returned, an nfs_client pointer is planted in "result."
     545                 :            :  *
     546                 :            :  * NB: nfs40_walk_client_list() relies on the new nfs_client being
     547                 :            :  *     the last nfs_client on the list.
     548                 :            :  */
     549                 :          0 : int nfs40_walk_client_list(struct nfs_client *new,
     550                 :            :                            struct nfs_client **result,
     551                 :            :                            const struct cred *cred)
     552                 :            : {
     553                 :          0 :         struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
     554                 :          0 :         struct nfs_client *pos, *prev = NULL;
     555                 :          0 :         struct nfs4_setclientid_res clid = {
     556                 :          0 :                 .clientid       = new->cl_clientid,
     557                 :            :                 .confirm        = new->cl_confirm,
     558                 :            :         };
     559                 :            :         int status = -NFS4ERR_STALE_CLIENTID;
     560                 :            : 
     561                 :            :         spin_lock(&nn->nfs_client_lock);
     562         [ #  # ]:          0 :         list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
     563                 :            : 
     564         [ #  # ]:          0 :                 if (pos == new)
     565                 :            :                         goto found;
     566                 :            : 
     567                 :          0 :                 status = nfs4_match_client(pos, new, &prev, nn);
     568         [ #  # ]:          0 :                 if (status < 0)
     569                 :            :                         goto out_unlock;
     570         [ #  # ]:          0 :                 if (status != 0)
     571                 :          0 :                         continue;
     572                 :            :                 /*
     573                 :            :                  * We just sent a new SETCLIENTID, which should have
     574                 :            :                  * caused the server to return a new cl_confirm.  So if
     575                 :            :                  * cl_confirm is the same, then this is a different
     576                 :            :                  * server that just returned the same cl_confirm by
     577                 :            :                  * coincidence:
     578                 :            :                  */
     579   [ #  #  #  # ]:          0 :                 if ((new != pos) && nfs4_same_verifier(&pos->cl_confirm,
     580                 :            :                                                        &new->cl_confirm))
     581                 :          0 :                         continue;
     582                 :            :                 /*
     583                 :            :                  * But if the cl_confirm's are different, then the only
     584                 :            :                  * way that a SETCLIENTID_CONFIRM to pos can succeed is
     585                 :            :                  * if new and pos point to the same server:
     586                 :            :                  */
     587                 :            : found:
     588                 :          0 :                 refcount_inc(&pos->cl_count);
     589                 :            :                 spin_unlock(&nn->nfs_client_lock);
     590                 :            : 
     591                 :          0 :                 nfs_put_client(prev);
     592                 :          0 :                 prev = pos;
     593                 :            : 
     594                 :          0 :                 status = nfs4_proc_setclientid_confirm(pos, &clid, cred);
     595   [ #  #  #  # ]:          0 :                 switch (status) {
     596                 :            :                 case -NFS4ERR_STALE_CLIENTID:
     597                 :            :                         break;
     598                 :            :                 case 0:
     599                 :          0 :                         nfs4_swap_callback_idents(pos, new);
     600                 :          0 :                         pos->cl_confirm = new->cl_confirm;
     601                 :          0 :                         nfs_mark_client_ready(pos, NFS_CS_READY);
     602                 :            : 
     603                 :          0 :                         prev = NULL;
     604                 :          0 :                         *result = pos;
     605                 :          0 :                         goto out;
     606                 :            :                 case -ERESTARTSYS:
     607                 :            :                 case -ETIMEDOUT:
     608                 :            :                         /* The callback path may have been inadvertently
     609                 :            :                          * changed. Schedule recovery!
     610                 :            :                          */
     611                 :          0 :                         nfs4_schedule_path_down_recovery(pos);
     612                 :            :                 default:
     613                 :            :                         goto out;
     614                 :            :                 }
     615                 :            : 
     616                 :            :                 spin_lock(&nn->nfs_client_lock);
     617                 :            :         }
     618                 :            : out_unlock:
     619                 :            :         spin_unlock(&nn->nfs_client_lock);
     620                 :            : 
     621                 :            :         /* No match found. The server lost our clientid */
     622                 :            : out:
     623                 :          0 :         nfs_put_client(prev);
     624                 :          0 :         return status;
     625                 :            : }
     626                 :            : 
     627                 :            : #ifdef CONFIG_NFS_V4_1
     628                 :            : /*
     629                 :            :  * Returns true if the server major ids match
     630                 :            :  */
     631                 :            : static bool
     632                 :            : nfs4_check_serverowner_major_id(struct nfs41_server_owner *o1,
     633                 :            :                                 struct nfs41_server_owner *o2)
     634                 :            : {
     635   [ #  #  #  # ]:          0 :         if (o1->major_id_sz != o2->major_id_sz)
     636                 :            :                 return false;
     637                 :          0 :         return memcmp(o1->major_id, o2->major_id, o1->major_id_sz) == 0;
     638                 :            : }
     639                 :            : 
     640                 :            : /*
     641                 :            :  * Returns true if the server scopes match
     642                 :            :  */
     643                 :            : static bool
     644                 :            : nfs4_check_server_scope(struct nfs41_server_scope *s1,
     645                 :            :                         struct nfs41_server_scope *s2)
     646                 :            : {
     647         [ #  # ]:          0 :         if (s1->server_scope_sz != s2->server_scope_sz)
     648                 :            :                 return false;
     649                 :          0 :         return memcmp(s1->server_scope, s2->server_scope,
     650                 :            :                                         s1->server_scope_sz) == 0;
     651                 :            : }
     652                 :            : 
     653                 :            : /**
     654                 :            :  * nfs4_detect_session_trunking - Checks for session trunking.
     655                 :            :  * @clp:    original mount nfs_client
     656                 :            :  * @res:    result structure from an exchange_id using the original mount
     657                 :            :  *          nfs_client with a new multi_addr transport
     658                 :            :  * @xprt:   pointer to the transport to add.
     659                 :            :  *
     660                 :            :  * Called after a successful EXCHANGE_ID on a multi-addr connection.
     661                 :            :  * Upon success, add the transport.
     662                 :            :  *
     663                 :            :  * Returns zero on success, otherwise -EINVAL
     664                 :            :  *
     665                 :            :  * Note: since the exchange_id for the new multi_addr transport uses the
     666                 :            :  * same nfs_client from the original mount, the cl_owner_id is reused,
     667                 :            :  * so eir_clientowner is the same.
     668                 :            :  */
     669                 :          0 : int nfs4_detect_session_trunking(struct nfs_client *clp,
     670                 :            :                                  struct nfs41_exchange_id_res *res,
     671                 :            :                                  struct rpc_xprt *xprt)
     672                 :            : {
     673                 :            :         /* Check eir_clientid */
     674         [ #  # ]:          0 :         if (clp->cl_clientid != res->clientid)
     675                 :            :                 goto out_err;
     676                 :            : 
     677                 :            :         /* Check eir_server_owner so_major_id */
     678         [ #  # ]:          0 :         if (!nfs4_check_serverowner_major_id(clp->cl_serverowner,
     679                 :            :                                              res->server_owner))
     680                 :            :                 goto out_err;
     681                 :            : 
     682                 :            :         /* Check eir_server_owner so_minor_id */
     683         [ #  # ]:          0 :         if (clp->cl_serverowner->minor_id != res->server_owner->minor_id)
     684                 :            :                 goto out_err;
     685                 :            : 
     686                 :            :         /* Check eir_server_scope */
     687         [ #  # ]:          0 :         if (!nfs4_check_server_scope(clp->cl_serverscope, res->server_scope))
     688                 :            :                 goto out_err;
     689                 :            : 
     690                 :          0 :         pr_info("NFS:  %s: Session trunking succeeded for %s\n",
     691                 :            :                 clp->cl_hostname,
     692                 :            :                 xprt->address_strings[RPC_DISPLAY_ADDR]);
     693                 :            : 
     694                 :          0 :         return 0;
     695                 :            : out_err:
     696                 :          0 :         pr_info("NFS:  %s: Session trunking failed for %s\n", clp->cl_hostname,
     697                 :            :                 xprt->address_strings[RPC_DISPLAY_ADDR]);
     698                 :            : 
     699                 :          0 :         return -EINVAL;
     700                 :            : }
     701                 :            : 
     702                 :            : /**
     703                 :            :  * nfs41_walk_client_list - Find nfs_client that matches a client/server owner
     704                 :            :  *
     705                 :            :  * @new: nfs_client with client ID to test
     706                 :            :  * @result: OUT: found nfs_client, or new
     707                 :            :  * @cred: credential to use for trunking test
     708                 :            :  *
     709                 :            :  * Returns zero, a negative errno, or a negative NFS4ERR status.
     710                 :            :  * If zero is returned, an nfs_client pointer is planted in "result."
     711                 :            :  *
     712                 :            :  * NB: nfs41_walk_client_list() relies on the new nfs_client being
     713                 :            :  *     the last nfs_client on the list.
     714                 :            :  */
     715                 :          0 : int nfs41_walk_client_list(struct nfs_client *new,
     716                 :            :                            struct nfs_client **result,
     717                 :            :                            const struct cred *cred)
     718                 :            : {
     719                 :          0 :         struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
     720                 :          0 :         struct nfs_client *pos, *prev = NULL;
     721                 :            :         int status = -NFS4ERR_STALE_CLIENTID;
     722                 :            : 
     723                 :            :         spin_lock(&nn->nfs_client_lock);
     724         [ #  # ]:          0 :         list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
     725                 :            : 
     726         [ #  # ]:          0 :                 if (pos == new)
     727                 :            :                         goto found;
     728                 :            : 
     729                 :          0 :                 status = nfs4_match_client(pos, new, &prev, nn);
     730         [ #  # ]:          0 :                 if (status < 0)
     731                 :            :                         goto out;
     732         [ #  # ]:          0 :                 if (status != 0)
     733                 :          0 :                         continue;
     734                 :            : 
     735                 :            :                 /*
     736                 :            :                  * Note that session trunking is just a special subcase of
     737                 :            :                  * client id trunking. In either case, we want to fall back
     738                 :            :                  * to using the existing nfs_client.
     739                 :            :                  */
     740         [ #  # ]:          0 :                 if (!nfs4_check_serverowner_major_id(pos->cl_serverowner,
     741                 :            :                                                      new->cl_serverowner))
     742                 :          0 :                         continue;
     743                 :            : 
     744                 :            : found:
     745                 :          0 :                 refcount_inc(&pos->cl_count);
     746                 :          0 :                 *result = pos;
     747                 :            :                 status = 0;
     748                 :          0 :                 break;
     749                 :            :         }
     750                 :            : 
     751                 :            : out:
     752                 :            :         spin_unlock(&nn->nfs_client_lock);
     753                 :          0 :         nfs_put_client(prev);
     754                 :          0 :         return status;
     755                 :            : }
     756                 :            : #endif  /* CONFIG_NFS_V4_1 */
     757                 :            : 
     758                 :          0 : static void nfs4_destroy_server(struct nfs_server *server)
     759                 :            : {
     760                 :          0 :         LIST_HEAD(freeme);
     761                 :            : 
     762                 :          0 :         nfs_server_return_all_delegations(server);
     763                 :          0 :         unset_pnfs_layoutdriver(server);
     764                 :          0 :         nfs4_purge_state_owners(server, &freeme);
     765                 :          0 :         nfs4_free_state_owners(&freeme);
     766                 :          0 : }
     767                 :            : 
     768                 :            : /*
     769                 :            :  * NFSv4.0 callback thread helper
     770                 :            :  *
     771                 :            :  * Find a client by callback identifier
     772                 :            :  */
     773                 :            : struct nfs_client *
     774                 :          0 : nfs4_find_client_ident(struct net *net, int cb_ident)
     775                 :            : {
     776                 :            :         struct nfs_client *clp;
     777                 :          0 :         struct nfs_net *nn = net_generic(net, nfs_net_id);
     778                 :            : 
     779                 :            :         spin_lock(&nn->nfs_client_lock);
     780                 :          0 :         clp = idr_find(&nn->cb_ident_idr, cb_ident);
     781         [ #  # ]:          0 :         if (clp)
     782                 :          0 :                 refcount_inc(&clp->cl_count);
     783                 :            :         spin_unlock(&nn->nfs_client_lock);
     784                 :          0 :         return clp;
     785                 :            : }
     786                 :            : 
     787                 :            : #if defined(CONFIG_NFS_V4_1)
     788                 :            : /* Common match routine for v4.0 and v4.1 callback services */
     789                 :          0 : static bool nfs4_cb_match_client(const struct sockaddr *addr,
     790                 :            :                 struct nfs_client *clp, u32 minorversion)
     791                 :            : {
     792                 :          0 :         struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
     793                 :            : 
     794                 :            :         /* Don't match clients that failed to initialise */
     795         [ #  # ]:          0 :         if (!(clp->cl_cons_state == NFS_CS_READY ||
     796                 :            :             clp->cl_cons_state == NFS_CS_SESSION_INITING))
     797                 :            :                 return false;
     798                 :            : 
     799                 :          0 :         smp_rmb();
     800                 :            : 
     801                 :            :         /* Match the version and minorversion */
     802   [ #  #  #  # ]:          0 :         if (clp->rpc_ops->version != 4 ||
     803                 :          0 :             clp->cl_minorversion != minorversion)
     804                 :            :                 return false;
     805                 :            : 
     806                 :            :         /* Match only the IP address, not the port number */
     807                 :          0 :         return rpc_cmp_addr(addr, clap);
     808                 :            : }
     809                 :            : 
     810                 :            : /*
     811                 :            :  * NFSv4.1 callback thread helper
     812                 :            :  * For CB_COMPOUND calls, find a client by IP address, protocol version,
     813                 :            :  * minorversion, and sessionID
     814                 :            :  *
     815                 :            :  * Returns NULL if no such client
     816                 :            :  */
     817                 :            : struct nfs_client *
     818                 :          0 : nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
     819                 :            :                            struct nfs4_sessionid *sid, u32 minorversion)
     820                 :            : {
     821                 :            :         struct nfs_client *clp;
     822                 :          0 :         struct nfs_net *nn = net_generic(net, nfs_net_id);
     823                 :            : 
     824                 :            :         spin_lock(&nn->nfs_client_lock);
     825         [ #  # ]:          0 :         list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
     826         [ #  # ]:          0 :                 if (!nfs4_cb_match_client(addr, clp, minorversion))
     827                 :          0 :                         continue;
     828                 :            : 
     829         [ #  # ]:          0 :                 if (!nfs4_has_session(clp))
     830                 :          0 :                         continue;
     831                 :            : 
     832                 :            :                 /* Match sessionid*/
     833         [ #  # ]:          0 :                 if (memcmp(clp->cl_session->sess_id.data,
     834                 :          0 :                     sid->data, NFS4_MAX_SESSIONID_LEN) != 0)
     835                 :          0 :                         continue;
     836                 :            : 
     837                 :          0 :                 refcount_inc(&clp->cl_count);
     838                 :            :                 spin_unlock(&nn->nfs_client_lock);
     839                 :          0 :                 return clp;
     840                 :            :         }
     841                 :            :         spin_unlock(&nn->nfs_client_lock);
     842                 :          0 :         return NULL;
     843                 :            : }
     844                 :            : 
     845                 :            : #else /* CONFIG_NFS_V4_1 */
     846                 :            : 
     847                 :            : struct nfs_client *
     848                 :            : nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
     849                 :            :                            struct nfs4_sessionid *sid, u32 minorversion)
     850                 :            : {
     851                 :            :         return NULL;
     852                 :            : }
     853                 :            : #endif /* CONFIG_NFS_V4_1 */
     854                 :            : 
     855                 :            : /*
     856                 :            :  * Set up an NFS4 client
     857                 :            :  */
     858                 :          0 : static int nfs4_set_client(struct nfs_server *server,
     859                 :            :                 const char *hostname,
     860                 :            :                 const struct sockaddr *addr,
     861                 :            :                 const size_t addrlen,
     862                 :            :                 const char *ip_addr,
     863                 :            :                 int proto, const struct rpc_timeout *timeparms,
     864                 :            :                 u32 minorversion, unsigned int nconnect,
     865                 :            :                 struct net *net)
     866                 :            : {
     867                 :          0 :         struct nfs_client_initdata cl_init = {
     868                 :            :                 .hostname = hostname,
     869                 :            :                 .addr = addr,
     870                 :            :                 .addrlen = addrlen,
     871                 :            :                 .ip_addr = ip_addr,
     872                 :            :                 .nfs_mod = &nfs_v4,
     873                 :            :                 .proto = proto,
     874                 :            :                 .minorversion = minorversion,
     875                 :            :                 .net = net,
     876                 :            :                 .timeparms = timeparms,
     877                 :          0 :                 .cred = server->cred,
     878                 :            :         };
     879                 :            :         struct nfs_client *clp;
     880                 :            : 
     881         [ #  # ]:          0 :         if (minorversion > 0 && proto == XPRT_TRANSPORT_TCP)
     882                 :          0 :                 cl_init.nconnect = nconnect;
     883         [ #  # ]:          0 :         if (server->flags & NFS_MOUNT_NORESVPORT)
     884                 :          0 :                 set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
     885         [ #  # ]:          0 :         if (server->options & NFS_OPTION_MIGRATION)
     886                 :          0 :                 set_bit(NFS_CS_MIGRATION, &cl_init.init_flags);
     887         [ #  # ]:          0 :         if (test_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status))
     888                 :          0 :                 set_bit(NFS_CS_TSM_POSSIBLE, &cl_init.init_flags);
     889                 :          0 :         server->port = rpc_get_port(addr);
     890                 :            : 
     891                 :            :         /* Allocate or find a client reference we can use */
     892                 :          0 :         clp = nfs_get_client(&cl_init);
     893         [ #  # ]:          0 :         if (IS_ERR(clp))
     894                 :          0 :                 return PTR_ERR(clp);
     895                 :            : 
     896         [ #  # ]:          0 :         if (server->nfs_client == clp) {
     897                 :          0 :                 nfs_put_client(clp);
     898                 :          0 :                 return -ELOOP;
     899                 :            :         }
     900                 :            : 
     901                 :            :         /*
     902                 :            :          * Query for the lease time on clientid setup or renewal
     903                 :            :          *
     904                 :            :          * Note that this will be set on nfs_clients that were created
     905                 :            :          * only for the DS role and did not set this bit, but now will
     906                 :            :          * serve a dual role.
     907                 :            :          */
     908                 :          0 :         set_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state);
     909                 :            : 
     910                 :          0 :         server->nfs_client = clp;
     911                 :          0 :         return 0;
     912                 :            : }
     913                 :            : 
     914                 :            : /*
     915                 :            :  * Set up a pNFS Data Server client.
     916                 :            :  *
     917                 :            :  * Return any existing nfs_client that matches server address,port,version
     918                 :            :  * and minorversion.
     919                 :            :  *
     920                 :            :  * For a new nfs_client, use a soft mount (default), a low retrans and a
     921                 :            :  * low timeout interval so that if a connection is lost, we retry through
     922                 :            :  * the MDS.
     923                 :            :  */
     924                 :          0 : struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
     925                 :            :                 const struct sockaddr *ds_addr, int ds_addrlen,
     926                 :            :                 int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans,
     927                 :            :                 u32 minor_version)
     928                 :            : {
     929                 :            :         struct rpc_timeout ds_timeout;
     930                 :          0 :         struct nfs_client *mds_clp = mds_srv->nfs_client;
     931                 :          0 :         struct nfs_client_initdata cl_init = {
     932                 :            :                 .addr = ds_addr,
     933                 :            :                 .addrlen = ds_addrlen,
     934                 :          0 :                 .nodename = mds_clp->cl_rpcclient->cl_nodename,
     935                 :          0 :                 .ip_addr = mds_clp->cl_ipaddr,
     936                 :            :                 .nfs_mod = &nfs_v4,
     937                 :            :                 .proto = ds_proto,
     938                 :            :                 .minorversion = minor_version,
     939                 :          0 :                 .net = mds_clp->cl_net,
     940                 :            :                 .timeparms = &ds_timeout,
     941                 :          0 :                 .cred = mds_srv->cred,
     942                 :            :         };
     943                 :            :         char buf[INET6_ADDRSTRLEN + 1];
     944                 :            : 
     945         [ #  # ]:          0 :         if (rpc_ntop(ds_addr, buf, sizeof(buf)) <= 0)
     946                 :            :                 return ERR_PTR(-EINVAL);
     947                 :          0 :         cl_init.hostname = buf;
     948                 :            : 
     949   [ #  #  #  # ]:          0 :         if (mds_clp->cl_nconnect > 1 && ds_proto == XPRT_TRANSPORT_TCP)
     950                 :          0 :                 cl_init.nconnect = mds_clp->cl_nconnect;
     951                 :            : 
     952         [ #  # ]:          0 :         if (mds_srv->flags & NFS_MOUNT_NORESVPORT)
     953                 :            :                 __set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
     954                 :            : 
     955                 :            :         /*
     956                 :            :          * Set an authflavor equual to the MDS value. Use the MDS nfs_client
     957                 :            :          * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS
     958                 :            :          * (section 13.1 RFC 5661).
     959                 :            :          */
     960                 :          0 :         nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans);
     961                 :          0 :         return nfs_get_client(&cl_init);
     962                 :            : }
     963                 :            : EXPORT_SYMBOL_GPL(nfs4_set_ds_client);
     964                 :            : 
     965                 :            : /*
     966                 :            :  * Session has been established, and the client marked ready.
     967                 :            :  * Limit the mount rsize, wsize and dtsize using negotiated fore
     968                 :            :  * channel attributes.
     969                 :            :  */
     970                 :          0 : static void nfs4_session_limit_rwsize(struct nfs_server *server)
     971                 :            : {
     972                 :            : #ifdef CONFIG_NFS_V4_1
     973                 :            :         struct nfs4_session *sess;
     974                 :            :         u32 server_resp_sz;
     975                 :            :         u32 server_rqst_sz;
     976                 :            : 
     977         [ #  # ]:          0 :         if (!nfs4_has_session(server->nfs_client))
     978                 :          0 :                 return;
     979                 :            :         sess = server->nfs_client->cl_session;
     980                 :          0 :         server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead;
     981                 :          0 :         server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead;
     982                 :            : 
     983         [ #  # ]:          0 :         if (server->dtsize > server_resp_sz)
     984                 :          0 :                 server->dtsize = server_resp_sz;
     985         [ #  # ]:          0 :         if (server->rsize > server_resp_sz)
     986                 :          0 :                 server->rsize = server_resp_sz;
     987         [ #  # ]:          0 :         if (server->wsize > server_rqst_sz)
     988                 :          0 :                 server->wsize = server_rqst_sz;
     989                 :            : #endif /* CONFIG_NFS_V4_1 */
     990                 :            : }
     991                 :            : 
     992                 :          0 : static int nfs4_server_common_setup(struct nfs_server *server,
     993                 :            :                 struct nfs_fh *mntfh, bool auth_probe)
     994                 :            : {
     995                 :            :         struct nfs_fattr *fattr;
     996                 :            :         int error;
     997                 :            : 
     998                 :            :         /* data servers support only a subset of NFSv4.1 */
     999         [ #  # ]:          0 :         if (is_ds_only_client(server->nfs_client))
    1000                 :            :                 return -EPROTONOSUPPORT;
    1001                 :            : 
    1002                 :          0 :         fattr = nfs_alloc_fattr();
    1003         [ #  # ]:          0 :         if (fattr == NULL)
    1004                 :            :                 return -ENOMEM;
    1005                 :            : 
    1006                 :            :         /* We must ensure the session is initialised first */
    1007                 :          0 :         error = nfs4_init_session(server->nfs_client);
    1008         [ #  # ]:          0 :         if (error < 0)
    1009                 :            :                 goto out;
    1010                 :            : 
    1011                 :            :         /* Set the basic capabilities */
    1012                 :          0 :         server->caps |= server->nfs_client->cl_mvops->init_caps;
    1013         [ #  # ]:          0 :         if (server->flags & NFS_MOUNT_NORDIRPLUS)
    1014                 :          0 :                         server->caps &= ~NFS_CAP_READDIRPLUS;
    1015                 :            :         /*
    1016                 :            :          * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
    1017                 :            :          * authentication.
    1018                 :            :          */
    1019   [ #  #  #  # ]:          0 :         if (nfs4_disable_idmapping &&
    1020                 :          0 :                         server->client->cl_auth->au_flavor == RPC_AUTH_UNIX)
    1021                 :          0 :                 server->caps |= NFS_CAP_UIDGID_NOMAP;
    1022                 :            : 
    1023                 :            : 
    1024                 :            :         /* Probe the root fh to retrieve its FSID and filehandle */
    1025                 :          0 :         error = nfs4_get_rootfh(server, mntfh, auth_probe);
    1026         [ #  # ]:          0 :         if (error < 0)
    1027                 :            :                 goto out;
    1028                 :            : 
    1029                 :            :         dprintk("Server FSID: %llx:%llx\n",
    1030                 :            :                         (unsigned long long) server->fsid.major,
    1031                 :            :                         (unsigned long long) server->fsid.minor);
    1032                 :            :         nfs_display_fhandle(mntfh, "Pseudo-fs root FH");
    1033                 :            : 
    1034                 :          0 :         error = nfs_probe_fsinfo(server, mntfh, fattr);
    1035         [ #  # ]:          0 :         if (error < 0)
    1036                 :            :                 goto out;
    1037                 :            : 
    1038                 :          0 :         nfs4_session_limit_rwsize(server);
    1039                 :            : 
    1040         [ #  # ]:          0 :         if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
    1041                 :          0 :                 server->namelen = NFS4_MAXNAMLEN;
    1042                 :            : 
    1043                 :          0 :         nfs_server_insert_lists(server);
    1044                 :          0 :         server->mount_time = jiffies;
    1045                 :          0 :         server->destroy = nfs4_destroy_server;
    1046                 :            : out:
    1047                 :            :         nfs_free_fattr(fattr);
    1048                 :          0 :         return error;
    1049                 :            : }
    1050                 :            : 
    1051                 :            : /*
    1052                 :            :  * Create a version 4 volume record
    1053                 :            :  */
    1054                 :          0 : static int nfs4_init_server(struct nfs_server *server,
    1055                 :            :                 struct nfs_parsed_mount_data *data)
    1056                 :            : {
    1057                 :            :         struct rpc_timeout timeparms;
    1058                 :            :         int error;
    1059                 :            : 
    1060                 :          0 :         nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
    1061                 :          0 :                         data->timeo, data->retrans);
    1062                 :            : 
    1063                 :            :         /* Initialise the client representation from the mount data */
    1064                 :          0 :         server->flags = data->flags;
    1065                 :          0 :         server->options = data->options;
    1066                 :          0 :         server->auth_info = data->auth_info;
    1067                 :            : 
    1068                 :            :         /* Use the first specified auth flavor. If this flavor isn't
    1069                 :            :          * allowed by the server, use the SECINFO path to try the
    1070                 :            :          * other specified flavors */
    1071         [ #  # ]:          0 :         if (data->auth_info.flavor_len >= 1)
    1072                 :          0 :                 data->selected_flavor = data->auth_info.flavors[0];
    1073                 :            :         else
    1074                 :          0 :                 data->selected_flavor = RPC_AUTH_UNIX;
    1075                 :            : 
    1076                 :            :         /* Get a client record */
    1077                 :          0 :         error = nfs4_set_client(server,
    1078                 :          0 :                         data->nfs_server.hostname,
    1079                 :          0 :                         (const struct sockaddr *)&data->nfs_server.address,
    1080                 :            :                         data->nfs_server.addrlen,
    1081                 :          0 :                         data->client_address,
    1082                 :          0 :                         data->nfs_server.protocol,
    1083                 :            :                         &timeparms,
    1084                 :            :                         data->minorversion,
    1085                 :          0 :                         data->nfs_server.nconnect,
    1086                 :            :                         data->net);
    1087         [ #  # ]:          0 :         if (error < 0)
    1088                 :            :                 return error;
    1089                 :            : 
    1090         [ #  # ]:          0 :         if (data->rsize)
    1091                 :          0 :                 server->rsize = nfs_block_size(data->rsize, NULL);
    1092         [ #  # ]:          0 :         if (data->wsize)
    1093                 :          0 :                 server->wsize = nfs_block_size(data->wsize, NULL);
    1094                 :            : 
    1095                 :          0 :         server->acregmin = data->acregmin * HZ;
    1096                 :          0 :         server->acregmax = data->acregmax * HZ;
    1097                 :          0 :         server->acdirmin = data->acdirmin * HZ;
    1098                 :          0 :         server->acdirmax = data->acdirmax * HZ;
    1099                 :          0 :         server->port     = data->nfs_server.port;
    1100                 :            : 
    1101                 :          0 :         return nfs_init_server_rpcclient(server, &timeparms,
    1102                 :            :                                          data->selected_flavor);
    1103                 :            : }
    1104                 :            : 
    1105                 :            : /*
    1106                 :            :  * Create a version 4 volume record
    1107                 :            :  * - keyed on server and FSID
    1108                 :            :  */
    1109                 :            : /*struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
    1110                 :            :                                       struct nfs_fh *mntfh)*/
    1111                 :          0 : struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
    1112                 :            :                                       struct nfs_subversion *nfs_mod)
    1113                 :            : {
    1114                 :            :         struct nfs_server *server;
    1115                 :            :         bool auth_probe;
    1116                 :            :         int error;
    1117                 :            : 
    1118                 :          0 :         server = nfs_alloc_server();
    1119         [ #  # ]:          0 :         if (!server)
    1120                 :            :                 return ERR_PTR(-ENOMEM);
    1121                 :            : 
    1122                 :          0 :         server->cred = get_cred(current_cred());
    1123                 :            : 
    1124                 :          0 :         auth_probe = mount_info->parsed->auth_info.flavor_len < 1;
    1125                 :            : 
    1126                 :            :         /* set up the general RPC client */
    1127                 :          0 :         error = nfs4_init_server(server, mount_info->parsed);
    1128         [ #  # ]:          0 :         if (error < 0)
    1129                 :            :                 goto error;
    1130                 :            : 
    1131                 :          0 :         error = nfs4_server_common_setup(server, mount_info->mntfh, auth_probe);
    1132         [ #  # ]:          0 :         if (error < 0)
    1133                 :            :                 goto error;
    1134                 :            : 
    1135                 :            :         return server;
    1136                 :            : 
    1137                 :            : error:
    1138                 :          0 :         nfs_free_server(server);
    1139                 :          0 :         return ERR_PTR(error);
    1140                 :            : }
    1141                 :            : 
    1142                 :            : /*
    1143                 :            :  * Create an NFS4 referral server record
    1144                 :            :  */
    1145                 :          0 : struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
    1146                 :            :                                                struct nfs_fh *mntfh)
    1147                 :            : {
    1148                 :            :         struct nfs_client *parent_client;
    1149                 :            :         struct nfs_server *server, *parent_server;
    1150                 :            :         bool auth_probe;
    1151                 :            :         int error;
    1152                 :            : 
    1153                 :          0 :         server = nfs_alloc_server();
    1154         [ #  # ]:          0 :         if (!server)
    1155                 :            :                 return ERR_PTR(-ENOMEM);
    1156                 :            : 
    1157                 :          0 :         parent_server = NFS_SB(data->sb);
    1158                 :          0 :         parent_client = parent_server->nfs_client;
    1159                 :            : 
    1160                 :          0 :         server->cred = get_cred(parent_server->cred);
    1161                 :            : 
    1162                 :            :         /* Initialise the client representation from the parent server */
    1163                 :          0 :         nfs_server_copy_userdata(server, parent_server);
    1164                 :            : 
    1165                 :            :         /* Get a client representation */
    1166                 :            : #if IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA)
    1167                 :            :         rpc_set_port(data->addr, NFS_RDMA_PORT);
    1168                 :            :         error = nfs4_set_client(server, data->hostname,
    1169                 :            :                                 data->addr,
    1170                 :            :                                 data->addrlen,
    1171                 :            :                                 parent_client->cl_ipaddr,
    1172                 :            :                                 XPRT_TRANSPORT_RDMA,
    1173                 :            :                                 parent_server->client->cl_timeout,
    1174                 :            :                                 parent_client->cl_mvops->minor_version,
    1175                 :            :                                 parent_client->cl_nconnect,
    1176                 :            :                                 parent_client->cl_net);
    1177                 :            :         if (!error)
    1178                 :            :                 goto init_server;
    1179                 :            : #endif  /* IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA) */
    1180                 :            : 
    1181                 :          0 :         rpc_set_port(data->addr, NFS_PORT);
    1182                 :          0 :         error = nfs4_set_client(server, data->hostname,
    1183                 :          0 :                                 data->addr,
    1184                 :            :                                 data->addrlen,
    1185                 :          0 :                                 parent_client->cl_ipaddr,
    1186                 :            :                                 XPRT_TRANSPORT_TCP,
    1187                 :          0 :                                 parent_server->client->cl_timeout,
    1188                 :          0 :                                 parent_client->cl_mvops->minor_version,
    1189                 :            :                                 parent_client->cl_nconnect,
    1190                 :            :                                 parent_client->cl_net);
    1191         [ #  # ]:          0 :         if (error < 0)
    1192                 :            :                 goto error;
    1193                 :            : 
    1194                 :            : #if IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA)
    1195                 :            : init_server:
    1196                 :            : #endif
    1197                 :          0 :         error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor);
    1198         [ #  # ]:          0 :         if (error < 0)
    1199                 :            :                 goto error;
    1200                 :            : 
    1201                 :          0 :         auth_probe = parent_server->auth_info.flavor_len < 1;
    1202                 :            : 
    1203                 :          0 :         error = nfs4_server_common_setup(server, mntfh, auth_probe);
    1204         [ #  # ]:          0 :         if (error < 0)
    1205                 :            :                 goto error;
    1206                 :            : 
    1207                 :            :         return server;
    1208                 :            : 
    1209                 :            : error:
    1210                 :          0 :         nfs_free_server(server);
    1211                 :          0 :         return ERR_PTR(error);
    1212                 :            : }
    1213                 :            : 
    1214                 :            : /*
    1215                 :            :  * Grab the destination's particulars, including lease expiry time.
    1216                 :            :  *
    1217                 :            :  * Returns zero if probe succeeded and retrieved FSID matches the FSID
    1218                 :            :  * we have cached.
    1219                 :            :  */
    1220                 :          0 : static int nfs_probe_destination(struct nfs_server *server)
    1221                 :            : {
    1222                 :          0 :         struct inode *inode = d_inode(server->super->s_root);
    1223                 :            :         struct nfs_fattr *fattr;
    1224                 :            :         int error;
    1225                 :            : 
    1226                 :          0 :         fattr = nfs_alloc_fattr();
    1227         [ #  # ]:          0 :         if (fattr == NULL)
    1228                 :            :                 return -ENOMEM;
    1229                 :            : 
    1230                 :            :         /* Sanity: the probe won't work if the destination server
    1231                 :            :          * does not recognize the migrated FH. */
    1232                 :          0 :         error = nfs_probe_fsinfo(server, NFS_FH(inode), fattr);
    1233                 :            : 
    1234                 :            :         nfs_free_fattr(fattr);
    1235                 :          0 :         return error;
    1236                 :            : }
    1237                 :            : 
    1238                 :            : /**
    1239                 :            :  * nfs4_update_server - Move an nfs_server to a different nfs_client
    1240                 :            :  *
    1241                 :            :  * @server: represents FSID to be moved
    1242                 :            :  * @hostname: new end-point's hostname
    1243                 :            :  * @sap: new end-point's socket address
    1244                 :            :  * @salen: size of "sap"
    1245                 :            :  * @net: net namespace
    1246                 :            :  *
    1247                 :            :  * The nfs_server must be quiescent before this function is invoked.
    1248                 :            :  * Either its session is drained (NFSv4.1+), or its transport is
    1249                 :            :  * plugged and drained (NFSv4.0).
    1250                 :            :  *
    1251                 :            :  * Returns zero on success, or a negative errno value.
    1252                 :            :  */
    1253                 :          0 : int nfs4_update_server(struct nfs_server *server, const char *hostname,
    1254                 :            :                        struct sockaddr *sap, size_t salen, struct net *net)
    1255                 :            : {
    1256                 :          0 :         struct nfs_client *clp = server->nfs_client;
    1257                 :          0 :         struct rpc_clnt *clnt = server->client;
    1258                 :          0 :         struct xprt_create xargs = {
    1259                 :          0 :                 .ident          = clp->cl_proto,
    1260                 :            :                 .net            = net,
    1261                 :            :                 .dstaddr        = sap,
    1262                 :            :                 .addrlen        = salen,
    1263                 :            :                 .servername     = hostname,
    1264                 :            :         };
    1265                 :            :         char buf[INET6_ADDRSTRLEN + 1];
    1266                 :            :         struct sockaddr_storage address;
    1267                 :            :         struct sockaddr *localaddr = (struct sockaddr *)&address;
    1268                 :            :         int error;
    1269                 :            : 
    1270                 :          0 :         error = rpc_switch_client_transport(clnt, &xargs, clnt->cl_timeout);
    1271         [ #  # ]:          0 :         if (error != 0)
    1272                 :            :                 return error;
    1273                 :            : 
    1274                 :          0 :         error = rpc_localaddr(clnt, localaddr, sizeof(address));
    1275         [ #  # ]:          0 :         if (error != 0)
    1276                 :            :                 return error;
    1277                 :            : 
    1278         [ #  # ]:          0 :         if (rpc_ntop(localaddr, buf, sizeof(buf)) == 0)
    1279                 :            :                 return -EAFNOSUPPORT;
    1280                 :            : 
    1281                 :          0 :         nfs_server_remove_lists(server);
    1282                 :          0 :         set_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
    1283                 :          0 :         error = nfs4_set_client(server, hostname, sap, salen, buf,
    1284                 :            :                                 clp->cl_proto, clnt->cl_timeout,
    1285                 :            :                                 clp->cl_minorversion,
    1286                 :            :                                 clp->cl_nconnect, net);
    1287                 :          0 :         clear_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
    1288         [ #  # ]:          0 :         if (error != 0) {
    1289                 :          0 :                 nfs_server_insert_lists(server);
    1290                 :          0 :                 return error;
    1291                 :            :         }
    1292                 :          0 :         nfs_put_client(clp);
    1293                 :            : 
    1294         [ #  # ]:          0 :         if (server->nfs_client->cl_hostname == NULL)
    1295                 :          0 :                 server->nfs_client->cl_hostname = kstrdup(hostname, GFP_KERNEL);
    1296                 :          0 :         nfs_server_insert_lists(server);
    1297                 :            : 
    1298                 :          0 :         return nfs_probe_destination(server);
    1299                 :            : }

Generated by: LCOV version 1.14