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

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

Generated by: LCOV version 1.9