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

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Common NFS I/O  operations for the pnfs file based
       4                 :            :  * layout drivers.
       5                 :            :  *
       6                 :            :  * Copyright (c) 2014, Primary Data, Inc. All rights reserved.
       7                 :            :  *
       8                 :            :  * Tom Haynes <loghyr@primarydata.com>
       9                 :            :  */
      10                 :            : 
      11                 :            : #include <linux/nfs_fs.h>
      12                 :            : #include <linux/nfs_page.h>
      13                 :            : #include <linux/sunrpc/addr.h>
      14                 :            : #include <linux/module.h>
      15                 :            : 
      16                 :            : #include "nfs4session.h"
      17                 :            : #include "internal.h"
      18                 :            : #include "pnfs.h"
      19                 :            : 
      20                 :            : #define NFSDBG_FACILITY         NFSDBG_PNFS
      21                 :            : 
      22                 :          0 : void pnfs_generic_rw_release(void *data)
      23                 :            : {
      24                 :            :         struct nfs_pgio_header *hdr = data;
      25                 :            : 
      26                 :          0 :         nfs_put_client(hdr->ds_clp);
      27                 :          0 :         hdr->mds_ops->rpc_release(data);
      28                 :          0 : }
      29                 :            : EXPORT_SYMBOL_GPL(pnfs_generic_rw_release);
      30                 :            : 
      31                 :            : /* Fake up some data that will cause nfs_commit_release to retry the writes. */
      32                 :          0 : void pnfs_generic_prepare_to_resend_writes(struct nfs_commit_data *data)
      33                 :            : {
      34                 :          0 :         struct nfs_writeverf *verf = data->res.verf;
      35                 :            : 
      36                 :          0 :         data->task.tk_status = 0;
      37                 :          0 :         memset(&verf->verifier, 0, sizeof(verf->verifier));
      38                 :          0 :         verf->committed = NFS_UNSTABLE;
      39                 :          0 : }
      40                 :            : EXPORT_SYMBOL_GPL(pnfs_generic_prepare_to_resend_writes);
      41                 :            : 
      42                 :          0 : void pnfs_generic_write_commit_done(struct rpc_task *task, void *data)
      43                 :            : {
      44                 :            :         struct nfs_commit_data *wdata = data;
      45                 :            : 
      46                 :            :         /* Note this may cause RPC to be resent */
      47                 :          0 :         wdata->mds_ops->rpc_call_done(task, data);
      48                 :          0 : }
      49                 :            : EXPORT_SYMBOL_GPL(pnfs_generic_write_commit_done);
      50                 :            : 
      51                 :          0 : void pnfs_generic_commit_release(void *calldata)
      52                 :            : {
      53                 :            :         struct nfs_commit_data *data = calldata;
      54                 :            : 
      55                 :          0 :         data->completion_ops->completion(data);
      56                 :          0 :         pnfs_put_lseg(data->lseg);
      57                 :          0 :         nfs_put_client(data->ds_clp);
      58                 :          0 :         nfs_commitdata_release(data);
      59                 :          0 : }
      60                 :            : EXPORT_SYMBOL_GPL(pnfs_generic_commit_release);
      61                 :            : 
      62                 :            : /* The generic layer is about to remove the req from the commit list.
      63                 :            :  * If this will make the bucket empty, it will need to put the lseg reference.
      64                 :            :  * Note this must be called holding nfsi->commit_mutex
      65                 :            :  */
      66                 :            : void
      67                 :          0 : pnfs_generic_clear_request_commit(struct nfs_page *req,
      68                 :            :                                   struct nfs_commit_info *cinfo)
      69                 :            : {
      70                 :            :         struct pnfs_layout_segment *freeme = NULL;
      71                 :            : 
      72         [ #  # ]:          0 :         if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags))
      73                 :            :                 goto out;
      74                 :          0 :         cinfo->ds->nwritten--;
      75         [ #  # ]:          0 :         if (list_is_singular(&req->wb_list)) {
      76                 :            :                 struct pnfs_commit_bucket *bucket;
      77                 :            : 
      78                 :          0 :                 bucket = list_first_entry(&req->wb_list,
      79                 :            :                                           struct pnfs_commit_bucket,
      80                 :            :                                           written);
      81                 :          0 :                 freeme = bucket->wlseg;
      82                 :          0 :                 bucket->wlseg = NULL;
      83                 :            :         }
      84                 :            : out:
      85                 :          0 :         nfs_request_remove_commit_list(req, cinfo);
      86                 :          0 :         pnfs_put_lseg(freeme);
      87                 :          0 : }
      88                 :            : EXPORT_SYMBOL_GPL(pnfs_generic_clear_request_commit);
      89                 :            : 
      90                 :            : static int
      91                 :          0 : pnfs_generic_scan_ds_commit_list(struct pnfs_commit_bucket *bucket,
      92                 :            :                                  struct nfs_commit_info *cinfo,
      93                 :            :                                  int max)
      94                 :            : {
      95                 :          0 :         struct list_head *src = &bucket->written;
      96                 :          0 :         struct list_head *dst = &bucket->committing;
      97                 :            :         int ret;
      98                 :            : 
      99                 :            :         lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex);
     100                 :          0 :         ret = nfs_scan_commit_list(src, dst, cinfo, max);
     101         [ #  # ]:          0 :         if (ret) {
     102                 :          0 :                 cinfo->ds->nwritten -= ret;
     103                 :          0 :                 cinfo->ds->ncommitting += ret;
     104         [ #  # ]:          0 :                 if (bucket->clseg == NULL)
     105                 :          0 :                         bucket->clseg = pnfs_get_lseg(bucket->wlseg);
     106         [ #  # ]:          0 :                 if (list_empty(src)) {
     107                 :          0 :                         pnfs_put_lseg(bucket->wlseg);
     108                 :          0 :                         bucket->wlseg = NULL;
     109                 :            :                 }
     110                 :            :         }
     111                 :          0 :         return ret;
     112                 :            : }
     113                 :            : 
     114                 :            : /* Move reqs from written to committing lists, returning count
     115                 :            :  * of number moved.
     116                 :            :  */
     117                 :          0 : int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo,
     118                 :            :                                    int max)
     119                 :            : {
     120                 :            :         int i, rv = 0, cnt;
     121                 :            : 
     122                 :            :         lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex);
     123   [ #  #  #  # ]:          0 :         for (i = 0; i < cinfo->ds->nbuckets && max != 0; i++) {
     124                 :          0 :                 cnt = pnfs_generic_scan_ds_commit_list(&cinfo->ds->buckets[i],
     125                 :            :                                                        cinfo, max);
     126                 :          0 :                 max -= cnt;
     127                 :          0 :                 rv += cnt;
     128                 :            :         }
     129                 :          0 :         return rv;
     130                 :            : }
     131                 :            : EXPORT_SYMBOL_GPL(pnfs_generic_scan_commit_lists);
     132                 :            : 
     133                 :            : /* Pull everything off the committing lists and dump into @dst.  */
     134                 :          0 : void pnfs_generic_recover_commit_reqs(struct list_head *dst,
     135                 :            :                                       struct nfs_commit_info *cinfo)
     136                 :            : {
     137                 :            :         struct pnfs_commit_bucket *b;
     138                 :            :         struct pnfs_layout_segment *freeme;
     139                 :            :         int nwritten;
     140                 :            :         int i;
     141                 :            : 
     142                 :            :         lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex);
     143                 :            : restart:
     144         [ #  # ]:          0 :         for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {
     145                 :          0 :                 nwritten = nfs_scan_commit_list(&b->written, dst, cinfo, 0);
     146         [ #  # ]:          0 :                 if (!nwritten)
     147                 :          0 :                         continue;
     148                 :          0 :                 cinfo->ds->nwritten -= nwritten;
     149         [ #  # ]:          0 :                 if (list_empty(&b->written)) {
     150                 :          0 :                         freeme = b->wlseg;
     151                 :          0 :                         b->wlseg = NULL;
     152                 :          0 :                         pnfs_put_lseg(freeme);
     153                 :          0 :                         goto restart;
     154                 :            :                 }
     155                 :            :         }
     156                 :          0 : }
     157                 :            : EXPORT_SYMBOL_GPL(pnfs_generic_recover_commit_reqs);
     158                 :            : 
     159                 :          0 : static void pnfs_generic_retry_commit(struct nfs_commit_info *cinfo, int idx)
     160                 :            : {
     161                 :          0 :         struct pnfs_ds_commit_info *fl_cinfo = cinfo->ds;
     162                 :            :         struct pnfs_commit_bucket *bucket;
     163                 :            :         struct pnfs_layout_segment *freeme;
     164                 :            :         struct list_head *pos;
     165                 :          0 :         LIST_HEAD(pages);
     166                 :            :         int i;
     167                 :            : 
     168                 :          0 :         mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
     169         [ #  # ]:          0 :         for (i = idx; i < fl_cinfo->nbuckets; i++) {
     170                 :          0 :                 bucket = &fl_cinfo->buckets[i];
     171         [ #  # ]:          0 :                 if (list_empty(&bucket->committing))
     172                 :          0 :                         continue;
     173                 :          0 :                 freeme = bucket->clseg;
     174                 :          0 :                 bucket->clseg = NULL;
     175         [ #  # ]:          0 :                 list_for_each(pos, &bucket->committing)
     176                 :          0 :                         cinfo->ds->ncommitting--;
     177                 :            :                 list_splice_init(&bucket->committing, &pages);
     178                 :          0 :                 mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
     179                 :          0 :                 nfs_retry_commit(&pages, freeme, cinfo, i);
     180                 :          0 :                 pnfs_put_lseg(freeme);
     181                 :          0 :                 mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
     182                 :            :         }
     183                 :          0 :         mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
     184                 :          0 : }
     185                 :            : 
     186                 :            : static unsigned int
     187                 :          0 : pnfs_generic_alloc_ds_commits(struct nfs_commit_info *cinfo,
     188                 :            :                               struct list_head *list)
     189                 :            : {
     190                 :            :         struct pnfs_ds_commit_info *fl_cinfo;
     191                 :            :         struct pnfs_commit_bucket *bucket;
     192                 :            :         struct nfs_commit_data *data;
     193                 :            :         int i;
     194                 :            :         unsigned int nreq = 0;
     195                 :            : 
     196                 :          0 :         fl_cinfo = cinfo->ds;
     197                 :          0 :         bucket = fl_cinfo->buckets;
     198         [ #  # ]:          0 :         for (i = 0; i < fl_cinfo->nbuckets; i++, bucket++) {
     199         [ #  # ]:          0 :                 if (list_empty(&bucket->committing))
     200                 :          0 :                         continue;
     201                 :          0 :                 data = nfs_commitdata_alloc(false);
     202         [ #  # ]:          0 :                 if (!data)
     203                 :            :                         break;
     204                 :          0 :                 data->ds_commit_index = i;
     205                 :          0 :                 list_add(&data->pages, list);
     206                 :          0 :                 nreq++;
     207                 :            :         }
     208                 :            : 
     209                 :            :         /* Clean up on error */
     210                 :          0 :         pnfs_generic_retry_commit(cinfo, i);
     211                 :          0 :         return nreq;
     212                 :            : }
     213                 :            : 
     214                 :            : static inline
     215                 :          0 : void pnfs_fetch_commit_bucket_list(struct list_head *pages,
     216                 :            :                 struct nfs_commit_data *data,
     217                 :            :                 struct nfs_commit_info *cinfo)
     218                 :            : {
     219                 :            :         struct pnfs_commit_bucket *bucket;
     220                 :            :         struct list_head *pos;
     221                 :            : 
     222                 :          0 :         bucket = &cinfo->ds->buckets[data->ds_commit_index];
     223                 :          0 :         mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
     224         [ #  # ]:          0 :         list_for_each(pos, &bucket->committing)
     225                 :          0 :                 cinfo->ds->ncommitting--;
     226                 :          0 :         list_splice_init(&bucket->committing, pages);
     227                 :          0 :         data->lseg = bucket->clseg;
     228                 :          0 :         bucket->clseg = NULL;
     229                 :          0 :         mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
     230                 :            : 
     231                 :          0 : }
     232                 :            : 
     233                 :            : /* Helper function for pnfs_generic_commit_pagelist to catch an empty
     234                 :            :  * page list. This can happen when two commits race.
     235                 :            :  *
     236                 :            :  * This must be called instead of nfs_init_commit - call one or the other, but
     237                 :            :  * not both!
     238                 :            :  */
     239                 :            : static bool
     240                 :          0 : pnfs_generic_commit_cancel_empty_pagelist(struct list_head *pages,
     241                 :            :                                           struct nfs_commit_data *data,
     242                 :            :                                           struct nfs_commit_info *cinfo)
     243                 :            : {
     244         [ #  # ]:          0 :         if (list_empty(pages)) {
     245         [ #  # ]:          0 :                 if (atomic_dec_and_test(&cinfo->mds->rpcs_out))
     246                 :          0 :                         wake_up_var(&cinfo->mds->rpcs_out);
     247                 :            :                 /* don't call nfs_commitdata_release - it tries to put
     248                 :            :                  * the open_context which is not acquired until nfs_init_commit
     249                 :            :                  * which has not been called on @data */
     250   [ #  #  #  # ]:          0 :                 WARN_ON_ONCE(data->context);
     251                 :          0 :                 nfs_commit_free(data);
     252                 :          0 :                 return true;
     253                 :            :         }
     254                 :            : 
     255                 :            :         return false;
     256                 :            : }
     257                 :            : 
     258                 :            : /* This follows nfs_commit_list pretty closely */
     259                 :            : int
     260                 :          0 : pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
     261                 :            :                              int how, struct nfs_commit_info *cinfo,
     262                 :            :                              int (*initiate_commit)(struct nfs_commit_data *data,
     263                 :            :                                                     int how))
     264                 :            : {
     265                 :            :         struct nfs_commit_data *data, *tmp;
     266                 :          0 :         LIST_HEAD(list);
     267                 :            :         unsigned int nreq = 0;
     268                 :            : 
     269         [ #  # ]:          0 :         if (!list_empty(mds_pages)) {
     270                 :          0 :                 data = nfs_commitdata_alloc(true);
     271                 :          0 :                 data->ds_commit_index = -1;
     272                 :          0 :                 list_add(&data->pages, &list);
     273                 :            :                 nreq++;
     274                 :            :         }
     275                 :            : 
     276                 :          0 :         nreq += pnfs_generic_alloc_ds_commits(cinfo, &list);
     277                 :            : 
     278         [ #  # ]:          0 :         if (nreq == 0)
     279                 :            :                 goto out;
     280                 :            : 
     281                 :          0 :         atomic_add(nreq, &cinfo->mds->rpcs_out);
     282                 :            : 
     283         [ #  # ]:          0 :         list_for_each_entry_safe(data, tmp, &list, pages) {
     284                 :            :                 list_del_init(&data->pages);
     285         [ #  # ]:          0 :                 if (data->ds_commit_index < 0) {
     286                 :            :                         /* another commit raced with us */
     287         [ #  # ]:          0 :                         if (pnfs_generic_commit_cancel_empty_pagelist(mds_pages,
     288                 :            :                                 data, cinfo))
     289                 :          0 :                                 continue;
     290                 :            : 
     291                 :          0 :                         nfs_init_commit(data, mds_pages, NULL, cinfo);
     292                 :          0 :                         nfs_initiate_commit(NFS_CLIENT(inode), data,
     293                 :          0 :                                             NFS_PROTO(data->inode),
     294                 :            :                                             data->mds_ops, how, 0);
     295                 :            :                 } else {
     296                 :          0 :                         LIST_HEAD(pages);
     297                 :            : 
     298                 :          0 :                         pnfs_fetch_commit_bucket_list(&pages, data, cinfo);
     299                 :            : 
     300                 :            :                         /* another commit raced with us */
     301         [ #  # ]:          0 :                         if (pnfs_generic_commit_cancel_empty_pagelist(&pages,
     302                 :            :                                 data, cinfo))
     303                 :          0 :                                 continue;
     304                 :            : 
     305                 :          0 :                         nfs_init_commit(data, &pages, data->lseg, cinfo);
     306                 :          0 :                         initiate_commit(data, how);
     307                 :            :                 }
     308                 :            :         }
     309                 :            : out:
     310                 :          0 :         return PNFS_ATTEMPTED;
     311                 :            : }
     312                 :            : EXPORT_SYMBOL_GPL(pnfs_generic_commit_pagelist);
     313                 :            : 
     314                 :            : /*
     315                 :            :  * Data server cache
     316                 :            :  *
     317                 :            :  * Data servers can be mapped to different device ids.
     318                 :            :  * nfs4_pnfs_ds reference counting
     319                 :            :  *   - set to 1 on allocation
     320                 :            :  *   - incremented when a device id maps a data server already in the cache.
     321                 :            :  *   - decremented when deviceid is removed from the cache.
     322                 :            :  */
     323                 :            : static DEFINE_SPINLOCK(nfs4_ds_cache_lock);
     324                 :            : static LIST_HEAD(nfs4_data_server_cache);
     325                 :            : 
     326                 :            : /* Debug routines */
     327                 :            : static void
     328                 :            : print_ds(struct nfs4_pnfs_ds *ds)
     329                 :            : {
     330                 :            :         if (ds == NULL) {
     331                 :            :                 printk(KERN_WARNING "%s NULL device\n", __func__);
     332                 :            :                 return;
     333                 :            :         }
     334                 :            :         printk(KERN_WARNING "        ds %s\n"
     335                 :            :                 "        ref count %d\n"
     336                 :            :                 "        client %p\n"
     337                 :            :                 "        cl_exchange_flags %x\n",
     338                 :            :                 ds->ds_remotestr,
     339                 :            :                 refcount_read(&ds->ds_count), ds->ds_clp,
     340                 :            :                 ds->ds_clp ? ds->ds_clp->cl_exchange_flags : 0);
     341                 :            : }
     342                 :            : 
     343                 :            : static bool
     344                 :          0 : same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2)
     345                 :            : {
     346                 :            :         struct sockaddr_in *a, *b;
     347                 :            :         struct sockaddr_in6 *a6, *b6;
     348                 :            : 
     349         [ #  # ]:          0 :         if (addr1->sa_family != addr2->sa_family)
     350                 :            :                 return false;
     351                 :            : 
     352      [ #  #  # ]:          0 :         switch (addr1->sa_family) {
     353                 :            :         case AF_INET:
     354                 :            :                 a = (struct sockaddr_in *)addr1;
     355                 :            :                 b = (struct sockaddr_in *)addr2;
     356                 :            : 
     357   [ #  #  #  # ]:          0 :                 if (a->sin_addr.s_addr == b->sin_addr.s_addr &&
     358                 :          0 :                     a->sin_port == b->sin_port)
     359                 :            :                         return true;
     360                 :            :                 break;
     361                 :            : 
     362                 :            :         case AF_INET6:
     363                 :            :                 a6 = (struct sockaddr_in6 *)addr1;
     364                 :            :                 b6 = (struct sockaddr_in6 *)addr2;
     365                 :            : 
     366                 :            :                 /* LINKLOCAL addresses must have matching scope_id */
     367         [ #  # ]:          0 :                 if (ipv6_addr_src_scope(&a6->sin6_addr) ==
     368         [ #  # ]:          0 :                     IPV6_ADDR_SCOPE_LINKLOCAL &&
     369                 :          0 :                     a6->sin6_scope_id != b6->sin6_scope_id)
     370                 :            :                         return false;
     371                 :            : 
     372   [ #  #  #  # ]:          0 :                 if (ipv6_addr_equal(&a6->sin6_addr, &b6->sin6_addr) &&
     373                 :          0 :                     a6->sin6_port == b6->sin6_port)
     374                 :            :                         return true;
     375                 :            :                 break;
     376                 :            : 
     377                 :            :         default:
     378                 :            :                 dprintk("%s: unhandled address family: %u\n",
     379                 :            :                         __func__, addr1->sa_family);
     380                 :            :                 return false;
     381                 :            :         }
     382                 :            : 
     383                 :            :         return false;
     384                 :            : }
     385                 :            : 
     386                 :            : /*
     387                 :            :  * Checks if 'dsaddrs1' contains a subset of 'dsaddrs2'. If it does,
     388                 :            :  * declare a match.
     389                 :            :  */
     390                 :            : static bool
     391                 :          0 : _same_data_server_addrs_locked(const struct list_head *dsaddrs1,
     392                 :            :                                const struct list_head *dsaddrs2)
     393                 :            : {
     394                 :            :         struct nfs4_pnfs_ds_addr *da1, *da2;
     395                 :            :         struct sockaddr *sa1, *sa2;
     396                 :            :         bool match = false;
     397                 :            : 
     398         [ #  # ]:          0 :         list_for_each_entry(da1, dsaddrs1, da_node) {
     399                 :          0 :                 sa1 = (struct sockaddr *)&da1->da_addr;
     400                 :            :                 match = false;
     401         [ #  # ]:          0 :                 list_for_each_entry(da2, dsaddrs2, da_node) {
     402                 :          0 :                         sa2 = (struct sockaddr *)&da2->da_addr;
     403                 :          0 :                         match = same_sockaddr(sa1, sa2);
     404         [ #  # ]:          0 :                         if (match)
     405                 :            :                                 break;
     406                 :            :                 }
     407         [ #  # ]:          0 :                 if (!match)
     408                 :            :                         break;
     409                 :            :         }
     410                 :          0 :         return match;
     411                 :            : }
     412                 :            : 
     413                 :            : /*
     414                 :            :  * Lookup DS by addresses.  nfs4_ds_cache_lock is held
     415                 :            :  */
     416                 :            : static struct nfs4_pnfs_ds *
     417                 :          0 : _data_server_lookup_locked(const struct list_head *dsaddrs)
     418                 :            : {
     419                 :            :         struct nfs4_pnfs_ds *ds;
     420                 :            : 
     421         [ #  # ]:          0 :         list_for_each_entry(ds, &nfs4_data_server_cache, ds_node)
     422         [ #  # ]:          0 :                 if (_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs))
     423                 :          0 :                         return ds;
     424                 :            :         return NULL;
     425                 :            : }
     426                 :            : 
     427                 :          0 : static void destroy_ds(struct nfs4_pnfs_ds *ds)
     428                 :            : {
     429                 :            :         struct nfs4_pnfs_ds_addr *da;
     430                 :            : 
     431                 :            :         dprintk("--> %s\n", __func__);
     432                 :            :         ifdebug(FACILITY)
     433                 :            :                 print_ds(ds);
     434                 :            : 
     435                 :          0 :         nfs_put_client(ds->ds_clp);
     436                 :            : 
     437         [ #  # ]:          0 :         while (!list_empty(&ds->ds_addrs)) {
     438                 :          0 :                 da = list_first_entry(&ds->ds_addrs,
     439                 :            :                                       struct nfs4_pnfs_ds_addr,
     440                 :            :                                       da_node);
     441                 :          0 :                 list_del_init(&da->da_node);
     442                 :          0 :                 kfree(da->da_remotestr);
     443                 :          0 :                 kfree(da);
     444                 :            :         }
     445                 :            : 
     446                 :          0 :         kfree(ds->ds_remotestr);
     447                 :          0 :         kfree(ds);
     448                 :          0 : }
     449                 :            : 
     450                 :          0 : void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds)
     451                 :            : {
     452         [ #  # ]:          0 :         if (refcount_dec_and_lock(&ds->ds_count,
     453                 :            :                                 &nfs4_ds_cache_lock)) {
     454                 :          0 :                 list_del_init(&ds->ds_node);
     455                 :            :                 spin_unlock(&nfs4_ds_cache_lock);
     456                 :          0 :                 destroy_ds(ds);
     457                 :            :         }
     458                 :          0 : }
     459                 :            : EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_put);
     460                 :            : 
     461                 :            : /*
     462                 :            :  * Create a string with a human readable address and port to avoid
     463                 :            :  * complicated setup around many dprinks.
     464                 :            :  */
     465                 :            : static char *
     466                 :          0 : nfs4_pnfs_remotestr(struct list_head *dsaddrs, gfp_t gfp_flags)
     467                 :            : {
     468                 :            :         struct nfs4_pnfs_ds_addr *da;
     469                 :            :         char *remotestr;
     470                 :            :         size_t len;
     471                 :            :         char *p;
     472                 :            : 
     473                 :            :         len = 3;        /* '{', '}' and eol */
     474         [ #  # ]:          0 :         list_for_each_entry(da, dsaddrs, da_node) {
     475                 :          0 :                 len += strlen(da->da_remotestr) + 1;    /* string plus comma */
     476                 :            :         }
     477                 :            : 
     478                 :          0 :         remotestr = kzalloc(len, gfp_flags);
     479         [ #  # ]:          0 :         if (!remotestr)
     480                 :            :                 return NULL;
     481                 :            : 
     482                 :            :         p = remotestr;
     483                 :          0 :         *(p++) = '{';
     484                 :          0 :         len--;
     485         [ #  # ]:          0 :         list_for_each_entry(da, dsaddrs, da_node) {
     486                 :          0 :                 size_t ll = strlen(da->da_remotestr);
     487                 :            : 
     488         [ #  # ]:          0 :                 if (ll > len)
     489                 :            :                         goto out_err;
     490                 :            : 
     491                 :          0 :                 memcpy(p, da->da_remotestr, ll);
     492                 :          0 :                 p += ll;
     493                 :          0 :                 len -= ll;
     494                 :            : 
     495         [ #  # ]:          0 :                 if (len < 1)
     496                 :            :                         goto out_err;
     497                 :          0 :                 (*p++) = ',';
     498                 :          0 :                 len--;
     499                 :            :         }
     500         [ #  # ]:          0 :         if (len < 2)
     501                 :            :                 goto out_err;
     502                 :          0 :         *(p++) = '}';
     503                 :          0 :         *p = '\0';
     504                 :          0 :         return remotestr;
     505                 :            : out_err:
     506                 :          0 :         kfree(remotestr);
     507                 :          0 :         return NULL;
     508                 :            : }
     509                 :            : 
     510                 :            : /*
     511                 :            :  * Given a list of multipath struct nfs4_pnfs_ds_addr, add it to ds cache if
     512                 :            :  * uncached and return cached struct nfs4_pnfs_ds.
     513                 :            :  */
     514                 :            : struct nfs4_pnfs_ds *
     515                 :          0 : nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags)
     516                 :            : {
     517                 :            :         struct nfs4_pnfs_ds *tmp_ds, *ds = NULL;
     518                 :            :         char *remotestr;
     519                 :            : 
     520         [ #  # ]:          0 :         if (list_empty(dsaddrs)) {
     521                 :            :                 dprintk("%s: no addresses defined\n", __func__);
     522                 :            :                 goto out;
     523                 :            :         }
     524                 :            : 
     525                 :          0 :         ds = kzalloc(sizeof(*ds), gfp_flags);
     526         [ #  # ]:          0 :         if (!ds)
     527                 :            :                 goto out;
     528                 :            : 
     529                 :            :         /* this is only used for debugging, so it's ok if its NULL */
     530                 :          0 :         remotestr = nfs4_pnfs_remotestr(dsaddrs, gfp_flags);
     531                 :            : 
     532                 :            :         spin_lock(&nfs4_ds_cache_lock);
     533                 :          0 :         tmp_ds = _data_server_lookup_locked(dsaddrs);
     534         [ #  # ]:          0 :         if (tmp_ds == NULL) {
     535                 :          0 :                 INIT_LIST_HEAD(&ds->ds_addrs);
     536                 :            :                 list_splice_init(dsaddrs, &ds->ds_addrs);
     537                 :          0 :                 ds->ds_remotestr = remotestr;
     538                 :            :                 refcount_set(&ds->ds_count, 1);
     539                 :          0 :                 INIT_LIST_HEAD(&ds->ds_node);
     540                 :          0 :                 ds->ds_clp = NULL;
     541                 :            :                 list_add(&ds->ds_node, &nfs4_data_server_cache);
     542                 :            :                 dprintk("%s add new data server %s\n", __func__,
     543                 :            :                         ds->ds_remotestr);
     544                 :            :         } else {
     545                 :          0 :                 kfree(remotestr);
     546                 :          0 :                 kfree(ds);
     547                 :          0 :                 refcount_inc(&tmp_ds->ds_count);
     548                 :            :                 dprintk("%s data server %s found, inc'ed ds_count to %d\n",
     549                 :            :                         __func__, tmp_ds->ds_remotestr,
     550                 :            :                         refcount_read(&tmp_ds->ds_count));
     551                 :            :                 ds = tmp_ds;
     552                 :            :         }
     553                 :            :         spin_unlock(&nfs4_ds_cache_lock);
     554                 :            : out:
     555                 :          0 :         return ds;
     556                 :            : }
     557                 :            : EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_add);
     558                 :            : 
     559                 :            : static void nfs4_wait_ds_connect(struct nfs4_pnfs_ds *ds)
     560                 :            : {
     561                 :          0 :         might_sleep();
     562                 :          0 :         wait_on_bit(&ds->ds_state, NFS4DS_CONNECTING,
     563                 :            :                         TASK_KILLABLE);
     564                 :            : }
     565                 :            : 
     566                 :          0 : static void nfs4_clear_ds_conn_bit(struct nfs4_pnfs_ds *ds)
     567                 :            : {
     568                 :          0 :         smp_mb__before_atomic();
     569                 :          0 :         clear_bit(NFS4DS_CONNECTING, &ds->ds_state);
     570                 :          0 :         smp_mb__after_atomic();
     571                 :          0 :         wake_up_bit(&ds->ds_state, NFS4DS_CONNECTING);
     572                 :          0 : }
     573                 :            : 
     574                 :            : static struct nfs_client *(*get_v3_ds_connect)(
     575                 :            :                         struct nfs_server *mds_srv,
     576                 :            :                         const struct sockaddr *ds_addr,
     577                 :            :                         int ds_addrlen,
     578                 :            :                         int ds_proto,
     579                 :            :                         unsigned int ds_timeo,
     580                 :            :                         unsigned int ds_retrans);
     581                 :            : 
     582                 :          0 : static bool load_v3_ds_connect(void)
     583                 :            : {
     584         [ #  # ]:          0 :         if (!get_v3_ds_connect) {
     585         [ #  # ]:          0 :                 get_v3_ds_connect = symbol_request(nfs3_set_ds_client);
     586   [ #  #  #  # ]:          0 :                 WARN_ON_ONCE(!get_v3_ds_connect);
     587                 :            :         }
     588                 :            : 
     589                 :          0 :         return(get_v3_ds_connect != NULL);
     590                 :            : }
     591                 :            : 
     592                 :          0 : void nfs4_pnfs_v3_ds_connect_unload(void)
     593                 :            : {
     594         [ #  # ]:          0 :         if (get_v3_ds_connect) {
     595                 :          0 :                 symbol_put(nfs3_set_ds_client);
     596                 :          0 :                 get_v3_ds_connect = NULL;
     597                 :            :         }
     598                 :          0 : }
     599                 :            : 
     600                 :          0 : static int _nfs4_pnfs_v3_ds_connect(struct nfs_server *mds_srv,
     601                 :            :                                  struct nfs4_pnfs_ds *ds,
     602                 :            :                                  unsigned int timeo,
     603                 :            :                                  unsigned int retrans)
     604                 :            : {
     605                 :            :         struct nfs_client *clp = ERR_PTR(-EIO);
     606                 :            :         struct nfs4_pnfs_ds_addr *da;
     607                 :            :         int status = 0;
     608                 :            : 
     609                 :            :         dprintk("--> %s DS %s\n", __func__, ds->ds_remotestr);
     610                 :            : 
     611         [ #  # ]:          0 :         if (!load_v3_ds_connect())
     612                 :            :                 goto out;
     613                 :            : 
     614         [ #  # ]:          0 :         list_for_each_entry(da, &ds->ds_addrs, da_node) {
     615                 :            :                 dprintk("%s: DS %s: trying address %s\n",
     616                 :            :                         __func__, ds->ds_remotestr, da->da_remotestr);
     617                 :            : 
     618         [ #  # ]:          0 :                 if (!IS_ERR(clp)) {
     619                 :          0 :                         struct xprt_create xprt_args = {
     620                 :            :                                 .ident = XPRT_TRANSPORT_TCP,
     621                 :          0 :                                 .net = clp->cl_net,
     622                 :          0 :                                 .dstaddr = (struct sockaddr *)&da->da_addr,
     623                 :          0 :                                 .addrlen = da->da_addrlen,
     624                 :          0 :                                 .servername = clp->cl_hostname,
     625                 :            :                         };
     626                 :            :                         /* Add this address as an alias */
     627                 :          0 :                         rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
     628                 :            :                                         rpc_clnt_test_and_add_xprt, NULL);
     629                 :          0 :                         continue;
     630                 :            :                 }
     631                 :          0 :                 clp = get_v3_ds_connect(mds_srv,
     632                 :          0 :                                 (struct sockaddr *)&da->da_addr,
     633                 :          0 :                                 da->da_addrlen, IPPROTO_TCP,
     634                 :            :                                 timeo, retrans);
     635         [ #  # ]:          0 :                 if (IS_ERR(clp))
     636                 :          0 :                         continue;
     637                 :          0 :                 clp->cl_rpcclient->cl_softerr = 0;
     638                 :          0 :                 clp->cl_rpcclient->cl_softrtry = 0;
     639                 :            :         }
     640                 :            : 
     641         [ #  # ]:          0 :         if (IS_ERR(clp)) {
     642                 :            :                 status = PTR_ERR(clp);
     643                 :          0 :                 goto out;
     644                 :            :         }
     645                 :            : 
     646                 :          0 :         smp_wmb();
     647                 :          0 :         ds->ds_clp = clp;
     648                 :            :         dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
     649                 :            : out:
     650                 :          0 :         return status;
     651                 :            : }
     652                 :            : 
     653                 :          0 : static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
     654                 :            :                                  struct nfs4_pnfs_ds *ds,
     655                 :            :                                  unsigned int timeo,
     656                 :            :                                  unsigned int retrans,
     657                 :            :                                  u32 minor_version)
     658                 :            : {
     659                 :            :         struct nfs_client *clp = ERR_PTR(-EIO);
     660                 :            :         struct nfs4_pnfs_ds_addr *da;
     661                 :            :         int status = 0;
     662                 :            : 
     663                 :            :         dprintk("--> %s DS %s\n", __func__, ds->ds_remotestr);
     664                 :            : 
     665         [ #  # ]:          0 :         list_for_each_entry(da, &ds->ds_addrs, da_node) {
     666                 :            :                 dprintk("%s: DS %s: trying address %s\n",
     667                 :            :                         __func__, ds->ds_remotestr, da->da_remotestr);
     668                 :            : 
     669   [ #  #  #  # ]:          0 :                 if (!IS_ERR(clp) && clp->cl_mvops->session_trunk) {
     670                 :          0 :                         struct xprt_create xprt_args = {
     671                 :            :                                 .ident = XPRT_TRANSPORT_TCP,
     672                 :          0 :                                 .net = clp->cl_net,
     673                 :          0 :                                 .dstaddr = (struct sockaddr *)&da->da_addr,
     674                 :          0 :                                 .addrlen = da->da_addrlen,
     675                 :          0 :                                 .servername = clp->cl_hostname,
     676                 :            :                         };
     677                 :          0 :                         struct nfs4_add_xprt_data xprtdata = {
     678                 :            :                                 .clp = clp,
     679                 :          0 :                                 .cred = nfs4_get_clid_cred(clp),
     680                 :            :                         };
     681                 :          0 :                         struct rpc_add_xprt_test rpcdata = {
     682                 :          0 :                                 .add_xprt_test = clp->cl_mvops->session_trunk,
     683                 :            :                                 .data = &xprtdata,
     684                 :            :                         };
     685                 :            : 
     686                 :            :                         /**
     687                 :            :                         * Test this address for session trunking and
     688                 :            :                         * add as an alias
     689                 :            :                         */
     690                 :          0 :                         rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
     691                 :            :                                           rpc_clnt_setup_test_and_add_xprt,
     692                 :            :                                           &rpcdata);
     693         [ #  # ]:          0 :                         if (xprtdata.cred)
     694                 :          0 :                                 put_cred(xprtdata.cred);
     695                 :            :                 } else {
     696                 :          0 :                         clp = nfs4_set_ds_client(mds_srv,
     697                 :          0 :                                                 (struct sockaddr *)&da->da_addr,
     698                 :          0 :                                                 da->da_addrlen, IPPROTO_TCP,
     699                 :            :                                                 timeo, retrans, minor_version);
     700         [ #  # ]:          0 :                         if (IS_ERR(clp))
     701                 :          0 :                                 continue;
     702                 :            : 
     703                 :          0 :                         status = nfs4_init_ds_session(clp,
     704                 :          0 :                                         mds_srv->nfs_client->cl_lease_time);
     705         [ #  # ]:          0 :                         if (status) {
     706                 :          0 :                                 nfs_put_client(clp);
     707                 :            :                                 clp = ERR_PTR(-EIO);
     708                 :          0 :                                 continue;
     709                 :            :                         }
     710                 :            : 
     711                 :            :                 }
     712                 :            :         }
     713                 :            : 
     714         [ #  # ]:          0 :         if (IS_ERR(clp)) {
     715                 :            :                 status = PTR_ERR(clp);
     716                 :          0 :                 goto out;
     717                 :            :         }
     718                 :            : 
     719                 :          0 :         smp_wmb();
     720                 :          0 :         ds->ds_clp = clp;
     721                 :            :         dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
     722                 :            : out:
     723                 :          0 :         return status;
     724                 :            : }
     725                 :            : 
     726                 :            : /*
     727                 :            :  * Create an rpc connection to the nfs4_pnfs_ds data server.
     728                 :            :  * Currently only supports IPv4 and IPv6 addresses.
     729                 :            :  * If connection fails, make devid unavailable and return a -errno.
     730                 :            :  */
     731                 :          0 : int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
     732                 :            :                           struct nfs4_deviceid_node *devid, unsigned int timeo,
     733                 :            :                           unsigned int retrans, u32 version, u32 minor_version)
     734                 :            : {
     735                 :            :         int err;
     736                 :            : 
     737                 :            : again:
     738                 :            :         err = 0;
     739         [ #  # ]:          0 :         if (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) == 0) {
     740         [ #  # ]:          0 :                 if (version == 3) {
     741                 :          0 :                         err = _nfs4_pnfs_v3_ds_connect(mds_srv, ds, timeo,
     742                 :            :                                                        retrans);
     743         [ #  # ]:          0 :                 } else if (version == 4) {
     744                 :          0 :                         err = _nfs4_pnfs_v4_ds_connect(mds_srv, ds, timeo,
     745                 :            :                                                        retrans, minor_version);
     746                 :            :                 } else {
     747                 :            :                         dprintk("%s: unsupported DS version %d\n", __func__,
     748                 :            :                                 version);
     749                 :            :                         err = -EPROTONOSUPPORT;
     750                 :            :                 }
     751                 :            : 
     752                 :          0 :                 nfs4_clear_ds_conn_bit(ds);
     753                 :            :         } else {
     754                 :            :                 nfs4_wait_ds_connect(ds);
     755                 :            : 
     756                 :            :                 /* what was waited on didn't connect AND didn't mark unavail */
     757   [ #  #  #  # ]:          0 :                 if (!ds->ds_clp && !nfs4_test_deviceid_unavailable(devid))
     758                 :            :                         goto again;
     759                 :            :         }
     760                 :            : 
     761                 :            :         /*
     762                 :            :          * At this point the ds->ds_clp should be ready, but it might have
     763                 :            :          * hit an error.
     764                 :            :          */
     765         [ #  # ]:          0 :         if (!err) {
     766   [ #  #  #  # ]:          0 :                 if (!ds->ds_clp || !nfs_client_init_is_complete(ds->ds_clp)) {
     767   [ #  #  #  #  :          0 :                         WARN_ON_ONCE(ds->ds_clp ||
             #  #  #  # ]
     768                 :            :                                 !nfs4_test_deviceid_unavailable(devid));
     769                 :            :                         return -EINVAL;
     770                 :            :                 }
     771                 :          0 :                 err = nfs_client_init_status(ds->ds_clp);
     772                 :            :         }
     773                 :            : 
     774                 :          0 :         return err;
     775                 :            : }
     776                 :            : EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_connect);
     777                 :            : 
     778                 :            : /*
     779                 :            :  * Currently only supports ipv4, ipv6 and one multi-path address.
     780                 :            :  */
     781                 :            : struct nfs4_pnfs_ds_addr *
     782                 :          0 : nfs4_decode_mp_ds_addr(struct net *net, struct xdr_stream *xdr, gfp_t gfp_flags)
     783                 :            : {
     784                 :            :         struct nfs4_pnfs_ds_addr *da = NULL;
     785                 :            :         char *buf, *portstr;
     786                 :            :         __be16 port;
     787                 :            :         int nlen, rlen;
     788                 :            :         int tmp[2];
     789                 :            :         __be32 *p;
     790                 :            :         char *netid, *match_netid;
     791                 :            :         size_t len, match_netid_len;
     792                 :            :         char *startsep = "";
     793                 :            :         char *endsep = "";
     794                 :            : 
     795                 :            : 
     796                 :            :         /* r_netid */
     797                 :          0 :         p = xdr_inline_decode(xdr, 4);
     798         [ #  # ]:          0 :         if (unlikely(!p))
     799                 :            :                 goto out_err;
     800                 :          0 :         nlen = be32_to_cpup(p++);
     801                 :            : 
     802                 :          0 :         p = xdr_inline_decode(xdr, nlen);
     803         [ #  # ]:          0 :         if (unlikely(!p))
     804                 :            :                 goto out_err;
     805                 :            : 
     806                 :          0 :         netid = kmalloc(nlen+1, gfp_flags);
     807         [ #  # ]:          0 :         if (unlikely(!netid))
     808                 :            :                 goto out_err;
     809                 :            : 
     810                 :          0 :         netid[nlen] = '\0';
     811                 :          0 :         memcpy(netid, p, nlen);
     812                 :            : 
     813                 :            :         /* r_addr: ip/ip6addr with port in dec octets - see RFC 5665 */
     814                 :          0 :         p = xdr_inline_decode(xdr, 4);
     815         [ #  # ]:          0 :         if (unlikely(!p))
     816                 :            :                 goto out_free_netid;
     817                 :          0 :         rlen = be32_to_cpup(p);
     818                 :            : 
     819                 :          0 :         p = xdr_inline_decode(xdr, rlen);
     820         [ #  # ]:          0 :         if (unlikely(!p))
     821                 :            :                 goto out_free_netid;
     822                 :            : 
     823                 :            :         /* port is ".ABC.DEF", 8 chars max */
     824         [ #  # ]:          0 :         if (rlen > INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN + 8) {
     825                 :            :                 dprintk("%s: Invalid address, length %d\n", __func__,
     826                 :            :                         rlen);
     827                 :            :                 goto out_free_netid;
     828                 :            :         }
     829                 :          0 :         buf = kmalloc(rlen + 1, gfp_flags);
     830         [ #  # ]:          0 :         if (!buf) {
     831                 :            :                 dprintk("%s: Not enough memory\n", __func__);
     832                 :            :                 goto out_free_netid;
     833                 :            :         }
     834                 :          0 :         buf[rlen] = '\0';
     835                 :          0 :         memcpy(buf, p, rlen);
     836                 :            : 
     837                 :            :         /* replace port '.' with '-' */
     838                 :          0 :         portstr = strrchr(buf, '.');
     839         [ #  # ]:          0 :         if (!portstr) {
     840                 :            :                 dprintk("%s: Failed finding expected dot in port\n",
     841                 :            :                         __func__);
     842                 :            :                 goto out_free_buf;
     843                 :            :         }
     844                 :          0 :         *portstr = '-';
     845                 :            : 
     846                 :            :         /* find '.' between address and port */
     847                 :          0 :         portstr = strrchr(buf, '.');
     848         [ #  # ]:          0 :         if (!portstr) {
     849                 :            :                 dprintk("%s: Failed finding expected dot between address and "
     850                 :            :                         "port\n", __func__);
     851                 :            :                 goto out_free_buf;
     852                 :            :         }
     853                 :          0 :         *portstr = '\0';
     854                 :            : 
     855                 :          0 :         da = kzalloc(sizeof(*da), gfp_flags);
     856         [ #  # ]:          0 :         if (unlikely(!da))
     857                 :            :                 goto out_free_buf;
     858                 :            : 
     859                 :          0 :         INIT_LIST_HEAD(&da->da_node);
     860                 :            : 
     861         [ #  # ]:          0 :         if (!rpc_pton(net, buf, portstr-buf, (struct sockaddr *)&da->da_addr,
     862                 :            :                       sizeof(da->da_addr))) {
     863                 :            :                 dprintk("%s: error parsing address %s\n", __func__, buf);
     864                 :            :                 goto out_free_da;
     865                 :            :         }
     866                 :            : 
     867                 :          0 :         portstr++;
     868                 :          0 :         sscanf(portstr, "%d-%d", &tmp[0], &tmp[1]);
     869                 :          0 :         port = htons((tmp[0] << 8) | (tmp[1]));
     870                 :            : 
     871      [ #  #  # ]:          0 :         switch (da->da_addr.ss_family) {
     872                 :            :         case AF_INET:
     873                 :          0 :                 ((struct sockaddr_in *)&da->da_addr)->sin_port = port;
     874                 :          0 :                 da->da_addrlen = sizeof(struct sockaddr_in);
     875                 :            :                 match_netid = "tcp";
     876                 :            :                 match_netid_len = 3;
     877                 :          0 :                 break;
     878                 :            : 
     879                 :            :         case AF_INET6:
     880                 :          0 :                 ((struct sockaddr_in6 *)&da->da_addr)->sin6_port = port;
     881                 :          0 :                 da->da_addrlen = sizeof(struct sockaddr_in6);
     882                 :            :                 match_netid = "tcp6";
     883                 :            :                 match_netid_len = 4;
     884                 :            :                 startsep = "[";
     885                 :            :                 endsep = "]";
     886                 :          0 :                 break;
     887                 :            : 
     888                 :            :         default:
     889                 :            :                 dprintk("%s: unsupported address family: %u\n",
     890                 :            :                         __func__, da->da_addr.ss_family);
     891                 :            :                 goto out_free_da;
     892                 :            :         }
     893                 :            : 
     894   [ #  #  #  # ]:          0 :         if (nlen != match_netid_len || strncmp(netid, match_netid, nlen)) {
     895                 :            :                 dprintk("%s: ERROR: r_netid \"%s\" != \"%s\"\n",
     896                 :            :                         __func__, netid, match_netid);
     897                 :            :                 goto out_free_da;
     898                 :            :         }
     899                 :            : 
     900                 :            :         /* save human readable address */
     901                 :          0 :         len = strlen(startsep) + strlen(buf) + strlen(endsep) + 7;
     902                 :          0 :         da->da_remotestr = kzalloc(len, gfp_flags);
     903                 :            : 
     904                 :            :         /* NULL is ok, only used for dprintk */
     905         [ #  # ]:          0 :         if (da->da_remotestr)
     906                 :          0 :                 snprintf(da->da_remotestr, len, "%s%s%s:%u", startsep,
     907                 :          0 :                          buf, endsep, ntohs(port));
     908                 :            : 
     909                 :            :         dprintk("%s: Parsed DS addr %s\n", __func__, da->da_remotestr);
     910                 :          0 :         kfree(buf);
     911                 :          0 :         kfree(netid);
     912                 :          0 :         return da;
     913                 :            : 
     914                 :            : out_free_da:
     915                 :          0 :         kfree(da);
     916                 :            : out_free_buf:
     917                 :            :         dprintk("%s: Error parsing DS addr: %s\n", __func__, buf);
     918                 :          0 :         kfree(buf);
     919                 :            : out_free_netid:
     920                 :          0 :         kfree(netid);
     921                 :            : out_err:
     922                 :            :         return NULL;
     923                 :            : }
     924                 :            : EXPORT_SYMBOL_GPL(nfs4_decode_mp_ds_addr);
     925                 :            : 
     926                 :            : void
     927                 :          0 : pnfs_layout_mark_request_commit(struct nfs_page *req,
     928                 :            :                                 struct pnfs_layout_segment *lseg,
     929                 :            :                                 struct nfs_commit_info *cinfo,
     930                 :            :                                 u32 ds_commit_idx)
     931                 :            : {
     932                 :            :         struct list_head *list;
     933                 :            :         struct pnfs_commit_bucket *buckets;
     934                 :            : 
     935                 :          0 :         mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
     936                 :          0 :         buckets = cinfo->ds->buckets;
     937                 :          0 :         list = &buckets[ds_commit_idx].written;
     938         [ #  # ]:          0 :         if (list_empty(list)) {
     939         [ #  # ]:          0 :                 if (!pnfs_is_valid_lseg(lseg)) {
     940                 :          0 :                         mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
     941                 :          0 :                         cinfo->completion_ops->resched_write(cinfo, req);
     942                 :          0 :                         return;
     943                 :            :                 }
     944                 :            :                 /* Non-empty buckets hold a reference on the lseg.  That ref
     945                 :            :                  * is normally transferred to the COMMIT call and released
     946                 :            :                  * there.  It could also be released if the last req is pulled
     947                 :            :                  * off due to a rewrite, in which case it will be done in
     948                 :            :                  * pnfs_common_clear_request_commit
     949                 :            :                  */
     950   [ #  #  #  # ]:          0 :                 WARN_ON_ONCE(buckets[ds_commit_idx].wlseg != NULL);
     951                 :          0 :                 buckets[ds_commit_idx].wlseg = pnfs_get_lseg(lseg);
     952                 :            :         }
     953                 :          0 :         set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
     954                 :          0 :         cinfo->ds->nwritten++;
     955                 :            : 
     956                 :          0 :         nfs_request_add_commit_list_locked(req, list, cinfo);
     957                 :          0 :         mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
     958                 :          0 :         nfs_mark_page_unstable(req->wb_page, cinfo);
     959                 :            : }
     960                 :            : EXPORT_SYMBOL_GPL(pnfs_layout_mark_request_commit);
     961                 :            : 
     962                 :            : int
     963                 :          0 : pnfs_nfs_generic_sync(struct inode *inode, bool datasync)
     964                 :            : {
     965                 :            :         int ret;
     966                 :            : 
     967         [ #  # ]:          0 :         if (!pnfs_layoutcommit_outstanding(inode))
     968                 :            :                 return 0;
     969                 :          0 :         ret = nfs_commit_inode(inode, FLUSH_SYNC);
     970         [ #  # ]:          0 :         if (ret < 0)
     971                 :            :                 return ret;
     972         [ #  # ]:          0 :         if (datasync)
     973                 :            :                 return 0;
     974                 :          0 :         return pnfs_layoutcommit_inode(inode, true);
     975                 :            : }
     976                 :            : EXPORT_SYMBOL_GPL(pnfs_nfs_generic_sync);
     977                 :            : 

Generated by: LCOV version 1.14