LCOV - code coverage report
Current view: top level - fs/nfs/filelayout - filelayout.c (source / functions) Hit Total Coverage
Test: Real Lines: 3 386 0.8 %
Date: 2020-10-17 15:46:16 Functions: 0 41 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  *  Module for the pnfs nfs4 file layout driver.
       3                 :            :  *  Defines all I/O and Policy interface operations, plus code
       4                 :            :  *  to register itself with the pNFS client.
       5                 :            :  *
       6                 :            :  *  Copyright (c) 2002
       7                 :            :  *  The Regents of the University of Michigan
       8                 :            :  *  All Rights Reserved
       9                 :            :  *
      10                 :            :  *  Dean Hildebrand <dhildebz@umich.edu>
      11                 :            :  *
      12                 :            :  *  Permission is granted to use, copy, create derivative works, and
      13                 :            :  *  redistribute this software and such derivative works for any purpose,
      14                 :            :  *  so long as the name of the University of Michigan is not used in
      15                 :            :  *  any advertising or publicity pertaining to the use or distribution
      16                 :            :  *  of this software without specific, written prior authorization. If
      17                 :            :  *  the above copyright notice or any other identification of the
      18                 :            :  *  University of Michigan is included in any copy of any portion of
      19                 :            :  *  this software, then the disclaimer below must also be included.
      20                 :            :  *
      21                 :            :  *  This software is provided as is, without representation or warranty
      22                 :            :  *  of any kind either express or implied, including without limitation
      23                 :            :  *  the implied warranties of merchantability, fitness for a particular
      24                 :            :  *  purpose, or noninfringement.  The Regents of the University of
      25                 :            :  *  Michigan shall not be liable for any damages, including special,
      26                 :            :  *  indirect, incidental, or consequential damages, with respect to any
      27                 :            :  *  claim arising out of or in connection with the use of the software,
      28                 :            :  *  even if it has been or is hereafter advised of the possibility of
      29                 :            :  *  such damages.
      30                 :            :  */
      31                 :            : 
      32                 :            : #include <linux/nfs_fs.h>
      33                 :            : #include <linux/nfs_page.h>
      34                 :            : #include <linux/module.h>
      35                 :            : #include <linux/backing-dev.h>
      36                 :            : 
      37                 :            : #include <linux/sunrpc/metrics.h>
      38                 :            : 
      39                 :            : #include "../nfs4session.h"
      40                 :            : #include "../internal.h"
      41                 :            : #include "../delegation.h"
      42                 :            : #include "filelayout.h"
      43                 :            : #include "../nfs4trace.h"
      44                 :            : 
      45                 :            : #define NFSDBG_FACILITY         NFSDBG_PNFS_LD
      46                 :            : 
      47                 :            : MODULE_LICENSE("GPL");
      48                 :            : MODULE_AUTHOR("Dean Hildebrand <dhildebz@umich.edu>");
      49                 :            : MODULE_DESCRIPTION("The NFSv4 file layout driver");
      50                 :            : 
      51                 :            : #define FILELAYOUT_POLL_RETRY_MAX     (15*HZ)
      52                 :            : 
      53                 :            : static loff_t
      54                 :          0 : filelayout_get_dense_offset(struct nfs4_filelayout_segment *flseg,
      55                 :            :                             loff_t offset)
      56                 :            : {
      57                 :          0 :         u32 stripe_width = flseg->stripe_unit * flseg->dsaddr->stripe_count;
      58                 :            :         u64 stripe_no;
      59                 :            :         u32 rem;
      60                 :            : 
      61                 :          0 :         offset -= flseg->pattern_offset;
      62                 :            :         stripe_no = div_u64(offset, stripe_width);
      63                 :          0 :         div_u64_rem(offset, flseg->stripe_unit, &rem);
      64                 :            : 
      65                 :          0 :         return stripe_no * flseg->stripe_unit + rem;
      66                 :            : }
      67                 :            : 
      68                 :            : /* This function is used by the layout driver to calculate the
      69                 :            :  * offset of the file on the dserver based on whether the
      70                 :            :  * layout type is STRIPE_DENSE or STRIPE_SPARSE
      71                 :            :  */
      72                 :            : static loff_t
      73                 :          0 : filelayout_get_dserver_offset(struct pnfs_layout_segment *lseg, loff_t offset)
      74                 :            : {
      75                 :            :         struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
      76                 :            : 
      77                 :          0 :         switch (flseg->stripe_type) {
      78                 :            :         case STRIPE_SPARSE:
      79                 :            :                 return offset;
      80                 :            : 
      81                 :            :         case STRIPE_DENSE:
      82                 :          0 :                 return filelayout_get_dense_offset(flseg, offset);
      83                 :            :         }
      84                 :            : 
      85                 :          0 :         BUG();
      86                 :            : }
      87                 :            : 
      88                 :          0 : static void filelayout_reset_write(struct nfs_pgio_header *hdr)
      89                 :            : {
      90                 :            :         struct rpc_task *task = &hdr->task;
      91                 :            : 
      92                 :          0 :         if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
      93                 :            :                 dprintk("%s Reset task %5u for i/o through MDS "
      94                 :            :                         "(req %s/%llu, %u bytes @ offset %llu)\n", __func__,
      95                 :            :                         hdr->task.tk_pid,
      96                 :            :                         hdr->inode->i_sb->s_id,
      97                 :            :                         (unsigned long long)NFS_FILEID(hdr->inode),
      98                 :            :                         hdr->args.count,
      99                 :            :                         (unsigned long long)hdr->args.offset);
     100                 :            : 
     101                 :          0 :                 task->tk_status = pnfs_write_done_resend_to_mds(hdr);
     102                 :            :         }
     103                 :          0 : }
     104                 :            : 
     105                 :          0 : static void filelayout_reset_read(struct nfs_pgio_header *hdr)
     106                 :            : {
     107                 :            :         struct rpc_task *task = &hdr->task;
     108                 :            : 
     109                 :          0 :         if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
     110                 :            :                 dprintk("%s Reset task %5u for i/o through MDS "
     111                 :            :                         "(req %s/%llu, %u bytes @ offset %llu)\n", __func__,
     112                 :            :                         hdr->task.tk_pid,
     113                 :            :                         hdr->inode->i_sb->s_id,
     114                 :            :                         (unsigned long long)NFS_FILEID(hdr->inode),
     115                 :            :                         hdr->args.count,
     116                 :            :                         (unsigned long long)hdr->args.offset);
     117                 :            : 
     118                 :          0 :                 task->tk_status = pnfs_read_done_resend_to_mds(hdr);
     119                 :            :         }
     120                 :          0 : }
     121                 :            : 
     122                 :          0 : static int filelayout_async_handle_error(struct rpc_task *task,
     123                 :            :                                          struct nfs4_state *state,
     124                 :            :                                          struct nfs_client *clp,
     125                 :            :                                          struct pnfs_layout_segment *lseg)
     126                 :            : {
     127                 :          0 :         struct pnfs_layout_hdr *lo = lseg->pls_layout;
     128                 :          0 :         struct inode *inode = lo->plh_inode;
     129                 :            :         struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
     130                 :          0 :         struct nfs4_slot_table *tbl = &clp->cl_session->fc_slot_table;
     131                 :            : 
     132                 :          0 :         if (task->tk_status >= 0)
     133                 :            :                 return 0;
     134                 :            : 
     135                 :          0 :         switch (task->tk_status) {
     136                 :            :         /* DS session errors */
     137                 :            :         case -NFS4ERR_BADSESSION:
     138                 :            :         case -NFS4ERR_BADSLOT:
     139                 :            :         case -NFS4ERR_BAD_HIGH_SLOT:
     140                 :            :         case -NFS4ERR_DEADSESSION:
     141                 :            :         case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
     142                 :            :         case -NFS4ERR_SEQ_FALSE_RETRY:
     143                 :            :         case -NFS4ERR_SEQ_MISORDERED:
     144                 :            :                 dprintk("%s ERROR %d, Reset session. Exchangeid "
     145                 :            :                         "flags 0x%x\n", __func__, task->tk_status,
     146                 :            :                         clp->cl_exchange_flags);
     147                 :          0 :                 nfs4_schedule_session_recovery(clp->cl_session, task->tk_status);
     148                 :          0 :                 break;
     149                 :            :         case -NFS4ERR_DELAY:
     150                 :            :         case -NFS4ERR_GRACE:
     151                 :          0 :                 rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX);
     152                 :          0 :                 break;
     153                 :            :         case -NFS4ERR_RETRY_UNCACHED_REP:
     154                 :            :                 break;
     155                 :            :         /* Invalidate Layout errors */
     156                 :            :         case -NFS4ERR_ACCESS:
     157                 :            :         case -NFS4ERR_PNFS_NO_LAYOUT:
     158                 :            :         case -ESTALE:           /* mapped NFS4ERR_STALE */
     159                 :            :         case -EBADHANDLE:       /* mapped NFS4ERR_BADHANDLE */
     160                 :            :         case -EISDIR:           /* mapped NFS4ERR_ISDIR */
     161                 :            :         case -NFS4ERR_FHEXPIRED:
     162                 :            :         case -NFS4ERR_WRONG_TYPE:
     163                 :            :                 dprintk("%s Invalid layout error %d\n", __func__,
     164                 :            :                         task->tk_status);
     165                 :            :                 /*
     166                 :            :                  * Destroy layout so new i/o will get a new layout.
     167                 :            :                  * Layout will not be destroyed until all current lseg
     168                 :            :                  * references are put. Mark layout as invalid to resend failed
     169                 :            :                  * i/o and all i/o waiting on the slot table to the MDS until
     170                 :            :                  * layout is destroyed and a new valid layout is obtained.
     171                 :            :                  */
     172                 :          0 :                 pnfs_destroy_layout(NFS_I(inode));
     173                 :          0 :                 rpc_wake_up(&tbl->slot_tbl_waitq);
     174                 :          0 :                 goto reset;
     175                 :            :         /* RPC connection errors */
     176                 :            :         case -ECONNREFUSED:
     177                 :            :         case -EHOSTDOWN:
     178                 :            :         case -EHOSTUNREACH:
     179                 :            :         case -ENETUNREACH:
     180                 :            :         case -EIO:
     181                 :            :         case -ETIMEDOUT:
     182                 :            :         case -EPIPE:
     183                 :            :                 dprintk("%s DS connection error %d\n", __func__,
     184                 :            :                         task->tk_status);
     185                 :          0 :                 nfs4_mark_deviceid_unavailable(devid);
     186                 :          0 :                 pnfs_error_mark_layout_for_return(inode, lseg);
     187                 :          0 :                 pnfs_set_lo_fail(lseg);
     188                 :          0 :                 rpc_wake_up(&tbl->slot_tbl_waitq);
     189                 :            :                 /* fall through */
     190                 :            :         default:
     191                 :            : reset:
     192                 :            :                 dprintk("%s Retry through MDS. Error %d\n", __func__,
     193                 :            :                         task->tk_status);
     194                 :            :                 return -NFS4ERR_RESET_TO_MDS;
     195                 :            :         }
     196                 :          0 :         task->tk_status = 0;
     197                 :          0 :         return -EAGAIN;
     198                 :            : }
     199                 :            : 
     200                 :            : /* NFS_PROTO call done callback routines */
     201                 :            : 
     202                 :          0 : static int filelayout_read_done_cb(struct rpc_task *task,
     203                 :            :                                 struct nfs_pgio_header *hdr)
     204                 :            : {
     205                 :            :         int err;
     206                 :            : 
     207                 :          0 :         trace_nfs4_pnfs_read(hdr, task->tk_status);
     208                 :          0 :         err = filelayout_async_handle_error(task, hdr->args.context->state,
     209                 :            :                                             hdr->ds_clp, hdr->lseg);
     210                 :            : 
     211                 :          0 :         switch (err) {
     212                 :            :         case -NFS4ERR_RESET_TO_MDS:
     213                 :          0 :                 filelayout_reset_read(hdr);
     214                 :          0 :                 return task->tk_status;
     215                 :            :         case -EAGAIN:
     216                 :          0 :                 rpc_restart_call_prepare(task);
     217                 :          0 :                 return -EAGAIN;
     218                 :            :         }
     219                 :            : 
     220                 :            :         return 0;
     221                 :            : }
     222                 :            : 
     223                 :            : /*
     224                 :            :  * We reference the rpc_cred of the first WRITE that triggers the need for
     225                 :            :  * a LAYOUTCOMMIT, and use it to send the layoutcommit compound.
     226                 :            :  * rfc5661 is not clear about which credential should be used.
     227                 :            :  */
     228                 :            : static void
     229                 :          0 : filelayout_set_layoutcommit(struct nfs_pgio_header *hdr)
     230                 :            : {
     231                 :            :         loff_t end_offs = 0;
     232                 :            : 
     233                 :          0 :         if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds ||
     234                 :          0 :             hdr->res.verf->committed == NFS_FILE_SYNC)
     235                 :          0 :                 return;
     236                 :          0 :         if (hdr->res.verf->committed == NFS_DATA_SYNC)
     237                 :          0 :                 end_offs = hdr->mds_offset + (loff_t)hdr->res.count;
     238                 :            : 
     239                 :            :         /* Note: if the write is unstable, don't set end_offs until commit */
     240                 :          0 :         pnfs_set_layoutcommit(hdr->inode, hdr->lseg, end_offs);
     241                 :            :         dprintk("%s inode %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino,
     242                 :            :                 (unsigned long) NFS_I(hdr->inode)->layout->plh_lwb);
     243                 :            : }
     244                 :            : 
     245                 :            : bool
     246                 :          0 : filelayout_test_devid_unavailable(struct nfs4_deviceid_node *node)
     247                 :            : {
     248                 :          0 :         return filelayout_test_devid_invalid(node) ||
     249                 :          0 :                 nfs4_test_deviceid_unavailable(node);
     250                 :            : }
     251                 :            : 
     252                 :            : static bool
     253                 :            : filelayout_reset_to_mds(struct pnfs_layout_segment *lseg)
     254                 :            : {
     255                 :            :         struct nfs4_deviceid_node *node = FILELAYOUT_DEVID_NODE(lseg);
     256                 :            : 
     257                 :          0 :         return filelayout_test_devid_unavailable(node);
     258                 :            : }
     259                 :            : 
     260                 :            : /*
     261                 :            :  * Call ops for the async read/write cases
     262                 :            :  * In the case of dense layouts, the offset needs to be reset to its
     263                 :            :  * original value.
     264                 :            :  */
     265                 :          0 : static void filelayout_read_prepare(struct rpc_task *task, void *data)
     266                 :            : {
     267                 :            :         struct nfs_pgio_header *hdr = data;
     268                 :            : 
     269                 :          0 :         if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) {
     270                 :          0 :                 rpc_exit(task, -EIO);
     271                 :          0 :                 return;
     272                 :            :         }
     273                 :          0 :         if (filelayout_reset_to_mds(hdr->lseg)) {
     274                 :            :                 dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid);
     275                 :          0 :                 filelayout_reset_read(hdr);
     276                 :          0 :                 rpc_exit(task, 0);
     277                 :          0 :                 return;
     278                 :            :         }
     279                 :          0 :         hdr->pgio_done_cb = filelayout_read_done_cb;
     280                 :            : 
     281                 :          0 :         if (nfs4_setup_sequence(hdr->ds_clp,
     282                 :            :                         &hdr->args.seq_args,
     283                 :            :                         &hdr->res.seq_res,
     284                 :            :                         task))
     285                 :            :                 return;
     286                 :          0 :         if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context,
     287                 :          0 :                         hdr->args.lock_context, FMODE_READ) == -EIO)
     288                 :          0 :                 rpc_exit(task, -EIO); /* lost lock, terminate I/O */
     289                 :            : }
     290                 :            : 
     291                 :          0 : static void filelayout_read_call_done(struct rpc_task *task, void *data)
     292                 :            : {
     293                 :            :         struct nfs_pgio_header *hdr = data;
     294                 :            : 
     295                 :            :         dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status);
     296                 :            : 
     297                 :          0 :         if (test_bit(NFS_IOHDR_REDO, &hdr->flags) &&
     298                 :          0 :             task->tk_status == 0) {
     299                 :          0 :                 nfs41_sequence_done(task, &hdr->res.seq_res);
     300                 :          0 :                 return;
     301                 :            :         }
     302                 :            : 
     303                 :            :         /* Note this may cause RPC to be resent */
     304                 :          0 :         hdr->mds_ops->rpc_call_done(task, data);
     305                 :            : }
     306                 :            : 
     307                 :          0 : static void filelayout_read_count_stats(struct rpc_task *task, void *data)
     308                 :            : {
     309                 :            :         struct nfs_pgio_header *hdr = data;
     310                 :            : 
     311                 :          0 :         rpc_count_iostats(task, NFS_SERVER(hdr->inode)->client->cl_metrics);
     312                 :          0 : }
     313                 :            : 
     314                 :          0 : static int filelayout_write_done_cb(struct rpc_task *task,
     315                 :            :                                 struct nfs_pgio_header *hdr)
     316                 :            : {
     317                 :            :         int err;
     318                 :            : 
     319                 :          0 :         trace_nfs4_pnfs_write(hdr, task->tk_status);
     320                 :          0 :         err = filelayout_async_handle_error(task, hdr->args.context->state,
     321                 :            :                                             hdr->ds_clp, hdr->lseg);
     322                 :            : 
     323                 :          0 :         switch (err) {
     324                 :            :         case -NFS4ERR_RESET_TO_MDS:
     325                 :          0 :                 filelayout_reset_write(hdr);
     326                 :          0 :                 return task->tk_status;
     327                 :            :         case -EAGAIN:
     328                 :          0 :                 rpc_restart_call_prepare(task);
     329                 :          0 :                 return -EAGAIN;
     330                 :            :         }
     331                 :            : 
     332                 :          0 :         filelayout_set_layoutcommit(hdr);
     333                 :            : 
     334                 :            :         /* zero out the fattr */
     335                 :          0 :         hdr->fattr.valid = 0;
     336                 :          0 :         if (task->tk_status >= 0)
     337                 :          0 :                 nfs_writeback_update_inode(hdr);
     338                 :            : 
     339                 :            :         return 0;
     340                 :            : }
     341                 :            : 
     342                 :          0 : static int filelayout_commit_done_cb(struct rpc_task *task,
     343                 :            :                                      struct nfs_commit_data *data)
     344                 :            : {
     345                 :            :         int err;
     346                 :            : 
     347                 :          0 :         trace_nfs4_pnfs_commit_ds(data, task->tk_status);
     348                 :          0 :         err = filelayout_async_handle_error(task, NULL, data->ds_clp,
     349                 :            :                                             data->lseg);
     350                 :            : 
     351                 :          0 :         switch (err) {
     352                 :            :         case -NFS4ERR_RESET_TO_MDS:
     353                 :          0 :                 pnfs_generic_prepare_to_resend_writes(data);
     354                 :          0 :                 return -EAGAIN;
     355                 :            :         case -EAGAIN:
     356                 :          0 :                 rpc_restart_call_prepare(task);
     357                 :          0 :                 return -EAGAIN;
     358                 :            :         }
     359                 :            : 
     360                 :          0 :         pnfs_set_layoutcommit(data->inode, data->lseg, data->lwb);
     361                 :            : 
     362                 :          0 :         return 0;
     363                 :            : }
     364                 :            : 
     365                 :          0 : static void filelayout_write_prepare(struct rpc_task *task, void *data)
     366                 :            : {
     367                 :            :         struct nfs_pgio_header *hdr = data;
     368                 :            : 
     369                 :          0 :         if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) {
     370                 :          0 :                 rpc_exit(task, -EIO);
     371                 :          0 :                 return;
     372                 :            :         }
     373                 :          0 :         if (filelayout_reset_to_mds(hdr->lseg)) {
     374                 :            :                 dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid);
     375                 :          0 :                 filelayout_reset_write(hdr);
     376                 :          0 :                 rpc_exit(task, 0);
     377                 :          0 :                 return;
     378                 :            :         }
     379                 :          0 :         if (nfs4_setup_sequence(hdr->ds_clp,
     380                 :            :                         &hdr->args.seq_args,
     381                 :            :                         &hdr->res.seq_res,
     382                 :            :                         task))
     383                 :            :                 return;
     384                 :          0 :         if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context,
     385                 :          0 :                         hdr->args.lock_context, FMODE_WRITE) == -EIO)
     386                 :          0 :                 rpc_exit(task, -EIO); /* lost lock, terminate I/O */
     387                 :            : }
     388                 :            : 
     389                 :          0 : static void filelayout_write_call_done(struct rpc_task *task, void *data)
     390                 :            : {
     391                 :            :         struct nfs_pgio_header *hdr = data;
     392                 :            : 
     393                 :          0 :         if (test_bit(NFS_IOHDR_REDO, &hdr->flags) &&
     394                 :          0 :             task->tk_status == 0) {
     395                 :          0 :                 nfs41_sequence_done(task, &hdr->res.seq_res);
     396                 :          0 :                 return;
     397                 :            :         }
     398                 :            : 
     399                 :            :         /* Note this may cause RPC to be resent */
     400                 :          0 :         hdr->mds_ops->rpc_call_done(task, data);
     401                 :            : }
     402                 :            : 
     403                 :          0 : static void filelayout_write_count_stats(struct rpc_task *task, void *data)
     404                 :            : {
     405                 :            :         struct nfs_pgio_header *hdr = data;
     406                 :            : 
     407                 :          0 :         rpc_count_iostats(task, NFS_SERVER(hdr->inode)->client->cl_metrics);
     408                 :          0 : }
     409                 :            : 
     410                 :          0 : static void filelayout_commit_prepare(struct rpc_task *task, void *data)
     411                 :            : {
     412                 :            :         struct nfs_commit_data *wdata = data;
     413                 :            : 
     414                 :          0 :         nfs4_setup_sequence(wdata->ds_clp,
     415                 :            :                         &wdata->args.seq_args,
     416                 :            :                         &wdata->res.seq_res,
     417                 :            :                         task);
     418                 :          0 : }
     419                 :            : 
     420                 :          0 : static void filelayout_commit_count_stats(struct rpc_task *task, void *data)
     421                 :            : {
     422                 :            :         struct nfs_commit_data *cdata = data;
     423                 :            : 
     424                 :          0 :         rpc_count_iostats(task, NFS_SERVER(cdata->inode)->client->cl_metrics);
     425                 :          0 : }
     426                 :            : 
     427                 :            : static const struct rpc_call_ops filelayout_read_call_ops = {
     428                 :            :         .rpc_call_prepare = filelayout_read_prepare,
     429                 :            :         .rpc_call_done = filelayout_read_call_done,
     430                 :            :         .rpc_count_stats = filelayout_read_count_stats,
     431                 :            :         .rpc_release = pnfs_generic_rw_release,
     432                 :            : };
     433                 :            : 
     434                 :            : static const struct rpc_call_ops filelayout_write_call_ops = {
     435                 :            :         .rpc_call_prepare = filelayout_write_prepare,
     436                 :            :         .rpc_call_done = filelayout_write_call_done,
     437                 :            :         .rpc_count_stats = filelayout_write_count_stats,
     438                 :            :         .rpc_release = pnfs_generic_rw_release,
     439                 :            : };
     440                 :            : 
     441                 :            : static const struct rpc_call_ops filelayout_commit_call_ops = {
     442                 :            :         .rpc_call_prepare = filelayout_commit_prepare,
     443                 :            :         .rpc_call_done = pnfs_generic_write_commit_done,
     444                 :            :         .rpc_count_stats = filelayout_commit_count_stats,
     445                 :            :         .rpc_release = pnfs_generic_commit_release,
     446                 :            : };
     447                 :            : 
     448                 :            : static enum pnfs_try_status
     449                 :          0 : filelayout_read_pagelist(struct nfs_pgio_header *hdr)
     450                 :            : {
     451                 :          0 :         struct pnfs_layout_segment *lseg = hdr->lseg;
     452                 :            :         struct nfs4_pnfs_ds *ds;
     453                 :            :         struct rpc_clnt *ds_clnt;
     454                 :          0 :         loff_t offset = hdr->args.offset;
     455                 :            :         u32 j, idx;
     456                 :            :         struct nfs_fh *fh;
     457                 :            : 
     458                 :            :         dprintk("--> %s ino %lu pgbase %u req %zu@%llu\n",
     459                 :            :                 __func__, hdr->inode->i_ino,
     460                 :            :                 hdr->args.pgbase, (size_t)hdr->args.count, offset);
     461                 :            : 
     462                 :            :         /* Retrieve the correct rpc_client for the byte range */
     463                 :          0 :         j = nfs4_fl_calc_j_index(lseg, offset);
     464                 :          0 :         idx = nfs4_fl_calc_ds_index(lseg, j);
     465                 :          0 :         ds = nfs4_fl_prepare_ds(lseg, idx);
     466                 :          0 :         if (!ds)
     467                 :            :                 return PNFS_NOT_ATTEMPTED;
     468                 :            : 
     469                 :          0 :         ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, hdr->inode);
     470                 :          0 :         if (IS_ERR(ds_clnt))
     471                 :            :                 return PNFS_NOT_ATTEMPTED;
     472                 :            : 
     473                 :            :         dprintk("%s USE DS: %s cl_count %d\n", __func__,
     474                 :            :                 ds->ds_remotestr, refcount_read(&ds->ds_clp->cl_count));
     475                 :            : 
     476                 :            :         /* No multipath support. Use first DS */
     477                 :          0 :         refcount_inc(&ds->ds_clp->cl_count);
     478                 :          0 :         hdr->ds_clp = ds->ds_clp;
     479                 :          0 :         hdr->ds_commit_idx = idx;
     480                 :          0 :         fh = nfs4_fl_select_ds_fh(lseg, j);
     481                 :          0 :         if (fh)
     482                 :          0 :                 hdr->args.fh = fh;
     483                 :            : 
     484                 :          0 :         hdr->args.offset = filelayout_get_dserver_offset(lseg, offset);
     485                 :          0 :         hdr->mds_offset = offset;
     486                 :            : 
     487                 :            :         /* Perform an asynchronous read to ds */
     488                 :          0 :         nfs_initiate_pgio(ds_clnt, hdr, hdr->cred,
     489                 :          0 :                           NFS_PROTO(hdr->inode), &filelayout_read_call_ops,
     490                 :            :                           0, RPC_TASK_SOFTCONN);
     491                 :          0 :         return PNFS_ATTEMPTED;
     492                 :            : }
     493                 :            : 
     494                 :            : /* Perform async writes. */
     495                 :            : static enum pnfs_try_status
     496                 :          0 : filelayout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
     497                 :            : {
     498                 :          0 :         struct pnfs_layout_segment *lseg = hdr->lseg;
     499                 :            :         struct nfs4_pnfs_ds *ds;
     500                 :            :         struct rpc_clnt *ds_clnt;
     501                 :          0 :         loff_t offset = hdr->args.offset;
     502                 :            :         u32 j, idx;
     503                 :            :         struct nfs_fh *fh;
     504                 :            : 
     505                 :            :         /* Retrieve the correct rpc_client for the byte range */
     506                 :          0 :         j = nfs4_fl_calc_j_index(lseg, offset);
     507                 :          0 :         idx = nfs4_fl_calc_ds_index(lseg, j);
     508                 :          0 :         ds = nfs4_fl_prepare_ds(lseg, idx);
     509                 :          0 :         if (!ds)
     510                 :            :                 return PNFS_NOT_ATTEMPTED;
     511                 :            : 
     512                 :          0 :         ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, hdr->inode);
     513                 :          0 :         if (IS_ERR(ds_clnt))
     514                 :            :                 return PNFS_NOT_ATTEMPTED;
     515                 :            : 
     516                 :            :         dprintk("%s ino %lu sync %d req %zu@%llu DS: %s cl_count %d\n",
     517                 :            :                 __func__, hdr->inode->i_ino, sync, (size_t) hdr->args.count,
     518                 :            :                 offset, ds->ds_remotestr, refcount_read(&ds->ds_clp->cl_count));
     519                 :            : 
     520                 :          0 :         hdr->pgio_done_cb = filelayout_write_done_cb;
     521                 :          0 :         refcount_inc(&ds->ds_clp->cl_count);
     522                 :          0 :         hdr->ds_clp = ds->ds_clp;
     523                 :          0 :         hdr->ds_commit_idx = idx;
     524                 :          0 :         fh = nfs4_fl_select_ds_fh(lseg, j);
     525                 :          0 :         if (fh)
     526                 :          0 :                 hdr->args.fh = fh;
     527                 :          0 :         hdr->args.offset = filelayout_get_dserver_offset(lseg, offset);
     528                 :            : 
     529                 :            :         /* Perform an asynchronous write */
     530                 :          0 :         nfs_initiate_pgio(ds_clnt, hdr, hdr->cred,
     531                 :          0 :                           NFS_PROTO(hdr->inode), &filelayout_write_call_ops,
     532                 :            :                           sync, RPC_TASK_SOFTCONN);
     533                 :          0 :         return PNFS_ATTEMPTED;
     534                 :            : }
     535                 :            : 
     536                 :            : static int
     537                 :          0 : filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
     538                 :            :                           struct nfs4_filelayout_segment *fl,
     539                 :            :                           gfp_t gfp_flags)
     540                 :            : {
     541                 :            :         struct nfs4_deviceid_node *d;
     542                 :            :         struct nfs4_file_layout_dsaddr *dsaddr;
     543                 :            :         int status = -EINVAL;
     544                 :            : 
     545                 :            :         /* Is the deviceid already set? If so, we're good. */
     546                 :          0 :         if (fl->dsaddr != NULL)
     547                 :            :                 return 0;
     548                 :            : 
     549                 :            :         /* find and reference the deviceid */
     550                 :          0 :         d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &fl->deviceid,
     551                 :            :                         lo->plh_lc_cred, gfp_flags);
     552                 :          0 :         if (d == NULL)
     553                 :            :                 goto out;
     554                 :            : 
     555                 :            :         dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
     556                 :            :         /* Found deviceid is unavailable */
     557                 :          0 :         if (filelayout_test_devid_unavailable(&dsaddr->id_node))
     558                 :            :                 goto out_put;
     559                 :            : 
     560                 :          0 :         if (fl->first_stripe_index >= dsaddr->stripe_count) {
     561                 :            :                 dprintk("%s Bad first_stripe_index %u\n",
     562                 :            :                                 __func__, fl->first_stripe_index);
     563                 :            :                 goto out_put;
     564                 :            :         }
     565                 :            : 
     566                 :          0 :         if ((fl->stripe_type == STRIPE_SPARSE &&
     567                 :          0 :             fl->num_fh > 1 && fl->num_fh != dsaddr->ds_num) ||
     568                 :          0 :             (fl->stripe_type == STRIPE_DENSE &&
     569                 :          0 :             fl->num_fh != dsaddr->stripe_count)) {
     570                 :            :                 dprintk("%s num_fh %u not valid for given packing\n",
     571                 :            :                         __func__, fl->num_fh);
     572                 :            :                 goto out_put;
     573                 :            :         }
     574                 :            :         status = 0;
     575                 :            : 
     576                 :            :         /*
     577                 :            :          * Atomic compare and xchange to ensure we don't scribble
     578                 :            :          * over a non-NULL pointer.
     579                 :            :          */
     580                 :          0 :         if (cmpxchg(&fl->dsaddr, NULL, dsaddr) != NULL)
     581                 :            :                 goto out_put;
     582                 :            : out:
     583                 :          0 :         return status;
     584                 :            : out_put:
     585                 :          0 :         nfs4_fl_put_deviceid(dsaddr);
     586                 :          0 :         goto out;
     587                 :            : }
     588                 :            : 
     589                 :            : /*
     590                 :            :  * filelayout_check_layout()
     591                 :            :  *
     592                 :            :  * Make sure layout segment parameters are sane WRT the device.
     593                 :            :  * At this point no generic layer initialization of the lseg has occurred,
     594                 :            :  * and nothing has been added to the layout_hdr cache.
     595                 :            :  *
     596                 :            :  */
     597                 :            : static int
     598                 :            : filelayout_check_layout(struct pnfs_layout_hdr *lo,
     599                 :            :                         struct nfs4_filelayout_segment *fl,
     600                 :            :                         struct nfs4_layoutget_res *lgr,
     601                 :            :                         gfp_t gfp_flags)
     602                 :            : {
     603                 :            :         int status = -EINVAL;
     604                 :            : 
     605                 :            :         dprintk("--> %s\n", __func__);
     606                 :            : 
     607                 :            :         /* FIXME: remove this check when layout segment support is added */
     608                 :          0 :         if (lgr->range.offset != 0 ||
     609                 :          0 :             lgr->range.length != NFS4_MAX_UINT64) {
     610                 :            :                 dprintk("%s Only whole file layouts supported. Use MDS i/o\n",
     611                 :            :                         __func__);
     612                 :            :                 goto out;
     613                 :            :         }
     614                 :            : 
     615                 :          0 :         if (fl->pattern_offset > lgr->range.offset) {
     616                 :            :                 dprintk("%s pattern_offset %lld too large\n",
     617                 :            :                                 __func__, fl->pattern_offset);
     618                 :            :                 goto out;
     619                 :            :         }
     620                 :            : 
     621                 :          0 :         if (!fl->stripe_unit) {
     622                 :            :                 dprintk("%s Invalid stripe unit (%u)\n",
     623                 :            :                         __func__, fl->stripe_unit);
     624                 :            :                 goto out;
     625                 :            :         }
     626                 :            : 
     627                 :            :         status = 0;
     628                 :            : out:
     629                 :            :         dprintk("--> %s returns %d\n", __func__, status);
     630                 :            :         return status;
     631                 :            : }
     632                 :            : 
     633                 :          0 : static void _filelayout_free_lseg(struct nfs4_filelayout_segment *fl)
     634                 :            : {
     635                 :            :         int i;
     636                 :            : 
     637                 :          0 :         if (fl->fh_array) {
     638                 :          0 :                 for (i = 0; i < fl->num_fh; i++) {
     639                 :          0 :                         if (!fl->fh_array[i])
     640                 :            :                                 break;
     641                 :          0 :                         kfree(fl->fh_array[i]);
     642                 :            :                 }
     643                 :          0 :                 kfree(fl->fh_array);
     644                 :            :         }
     645                 :          0 :         kfree(fl);
     646                 :          0 : }
     647                 :            : 
     648                 :            : static int
     649                 :          0 : filelayout_decode_layout(struct pnfs_layout_hdr *flo,
     650                 :            :                          struct nfs4_filelayout_segment *fl,
     651                 :            :                          struct nfs4_layoutget_res *lgr,
     652                 :            :                          gfp_t gfp_flags)
     653                 :            : {
     654                 :            :         struct xdr_stream stream;
     655                 :            :         struct xdr_buf buf;
     656                 :            :         struct page *scratch;
     657                 :            :         __be32 *p;
     658                 :            :         uint32_t nfl_util;
     659                 :            :         int i;
     660                 :            : 
     661                 :            :         dprintk("%s: set_layout_map Begin\n", __func__);
     662                 :            : 
     663                 :            :         scratch = alloc_page(gfp_flags);
     664                 :          0 :         if (!scratch)
     665                 :            :                 return -ENOMEM;
     666                 :            : 
     667                 :          0 :         xdr_init_decode_pages(&stream, &buf, lgr->layoutp->pages, lgr->layoutp->len);
     668                 :          0 :         xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
     669                 :            : 
     670                 :            :         /* 20 = ufl_util (4), first_stripe_index (4), pattern_offset (8),
     671                 :            :          * num_fh (4) */
     672                 :          0 :         p = xdr_inline_decode(&stream, NFS4_DEVICEID4_SIZE + 20);
     673                 :          0 :         if (unlikely(!p))
     674                 :            :                 goto out_err;
     675                 :            : 
     676                 :          0 :         memcpy(&fl->deviceid, p, sizeof(fl->deviceid));
     677                 :            :         p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
     678                 :            :         nfs4_print_deviceid(&fl->deviceid);
     679                 :            : 
     680                 :            :         nfl_util = be32_to_cpup(p++);
     681                 :          0 :         if (nfl_util & NFL4_UFLG_COMMIT_THRU_MDS)
     682                 :          0 :                 fl->commit_through_mds = 1;
     683                 :          0 :         if (nfl_util & NFL4_UFLG_DENSE)
     684                 :          0 :                 fl->stripe_type = STRIPE_DENSE;
     685                 :            :         else
     686                 :          0 :                 fl->stripe_type = STRIPE_SPARSE;
     687                 :          0 :         fl->stripe_unit = nfl_util & ~NFL4_UFLG_MASK;
     688                 :            : 
     689                 :          0 :         fl->first_stripe_index = be32_to_cpup(p++);
     690                 :            :         p = xdr_decode_hyper(p, &fl->pattern_offset);
     691                 :          0 :         fl->num_fh = be32_to_cpup(p++);
     692                 :            : 
     693                 :            :         dprintk("%s: nfl_util 0x%X num_fh %u fsi %u po %llu\n",
     694                 :            :                 __func__, nfl_util, fl->num_fh, fl->first_stripe_index,
     695                 :            :                 fl->pattern_offset);
     696                 :            : 
     697                 :            :         /* Note that a zero value for num_fh is legal for STRIPE_SPARSE.
     698                 :            :          * Futher checking is done in filelayout_check_layout */
     699                 :          0 :         if (fl->num_fh >
     700                 :            :             max(NFS4_PNFS_MAX_STRIPE_CNT, NFS4_PNFS_MAX_MULTI_CNT))
     701                 :            :                 goto out_err;
     702                 :            : 
     703                 :          0 :         if (fl->num_fh > 0) {
     704                 :          0 :                 fl->fh_array = kcalloc(fl->num_fh, sizeof(fl->fh_array[0]),
     705                 :            :                                        gfp_flags);
     706                 :          0 :                 if (!fl->fh_array)
     707                 :            :                         goto out_err;
     708                 :            :         }
     709                 :            : 
     710                 :          0 :         for (i = 0; i < fl->num_fh; i++) {
     711                 :            :                 /* Do we want to use a mempool here? */
     712                 :          0 :                 fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), gfp_flags);
     713                 :          0 :                 if (!fl->fh_array[i])
     714                 :            :                         goto out_err;
     715                 :            : 
     716                 :          0 :                 p = xdr_inline_decode(&stream, 4);
     717                 :          0 :                 if (unlikely(!p))
     718                 :            :                         goto out_err;
     719                 :          0 :                 fl->fh_array[i]->size = be32_to_cpup(p++);
     720                 :          0 :                 if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
     721                 :          0 :                         printk(KERN_ERR "NFS: Too big fh %d received %d\n",
     722                 :          0 :                                i, fl->fh_array[i]->size);
     723                 :          0 :                         goto out_err;
     724                 :            :                 }
     725                 :            : 
     726                 :          0 :                 p = xdr_inline_decode(&stream, fl->fh_array[i]->size);
     727                 :          0 :                 if (unlikely(!p))
     728                 :            :                         goto out_err;
     729                 :          0 :                 memcpy(fl->fh_array[i]->data, p, fl->fh_array[i]->size);
     730                 :            :                 dprintk("DEBUG: %s: fh len %d\n", __func__,
     731                 :            :                         fl->fh_array[i]->size);
     732                 :            :         }
     733                 :            : 
     734                 :          0 :         __free_page(scratch);
     735                 :          0 :         return 0;
     736                 :            : 
     737                 :            : out_err:
     738                 :          0 :         __free_page(scratch);
     739                 :          0 :         return -EIO;
     740                 :            : }
     741                 :            : 
     742                 :            : static void
     743                 :          0 : filelayout_free_lseg(struct pnfs_layout_segment *lseg)
     744                 :            : {
     745                 :            :         struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
     746                 :            : 
     747                 :            :         dprintk("--> %s\n", __func__);
     748                 :          0 :         if (fl->dsaddr != NULL)
     749                 :          0 :                 nfs4_fl_put_deviceid(fl->dsaddr);
     750                 :            :         /* This assumes a single RW lseg */
     751                 :          0 :         if (lseg->pls_range.iomode == IOMODE_RW) {
     752                 :            :                 struct nfs4_filelayout *flo;
     753                 :            : 
     754                 :          0 :                 flo = FILELAYOUT_FROM_HDR(lseg->pls_layout);
     755                 :          0 :                 flo->commit_info.nbuckets = 0;
     756                 :          0 :                 kfree(flo->commit_info.buckets);
     757                 :          0 :                 flo->commit_info.buckets = NULL;
     758                 :            :         }
     759                 :          0 :         _filelayout_free_lseg(fl);
     760                 :          0 : }
     761                 :            : 
     762                 :            : static int
     763                 :          0 : filelayout_alloc_commit_info(struct pnfs_layout_segment *lseg,
     764                 :            :                              struct nfs_commit_info *cinfo,
     765                 :            :                              gfp_t gfp_flags)
     766                 :            : {
     767                 :            :         struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
     768                 :            :         struct pnfs_commit_bucket *buckets;
     769                 :            :         int size, i;
     770                 :            : 
     771                 :          0 :         if (fl->commit_through_mds)
     772                 :            :                 return 0;
     773                 :            : 
     774                 :          0 :         size = (fl->stripe_type == STRIPE_SPARSE) ?
     775                 :          0 :                 fl->dsaddr->ds_num : fl->dsaddr->stripe_count;
     776                 :            : 
     777                 :          0 :         if (cinfo->ds->nbuckets >= size) {
     778                 :            :                 /* This assumes there is only one IOMODE_RW lseg.  What
     779                 :            :                  * we really want to do is have a layout_hdr level
     780                 :            :                  * dictionary of <multipath_list4, fh> keys, each
     781                 :            :                  * associated with a struct list_head, populated by calls
     782                 :            :                  * to filelayout_write_pagelist().
     783                 :            :                  * */
     784                 :            :                 return 0;
     785                 :            :         }
     786                 :            : 
     787                 :          0 :         buckets = kcalloc(size, sizeof(struct pnfs_commit_bucket),
     788                 :            :                           gfp_flags);
     789                 :          0 :         if (!buckets)
     790                 :            :                 return -ENOMEM;
     791                 :          0 :         for (i = 0; i < size; i++) {
     792                 :          0 :                 INIT_LIST_HEAD(&buckets[i].written);
     793                 :          0 :                 INIT_LIST_HEAD(&buckets[i].committing);
     794                 :            :                 /* mark direct verifier as unset */
     795                 :          0 :                 buckets[i].direct_verf.committed = NFS_INVALID_STABLE_HOW;
     796                 :            :         }
     797                 :            : 
     798                 :          0 :         spin_lock(&cinfo->inode->i_lock);
     799                 :          0 :         if (cinfo->ds->nbuckets >= size)
     800                 :            :                 goto out;
     801                 :          0 :         for (i = 0; i < cinfo->ds->nbuckets; i++) {
     802                 :          0 :                 list_splice(&cinfo->ds->buckets[i].written,
     803                 :          0 :                             &buckets[i].written);
     804                 :          0 :                 list_splice(&cinfo->ds->buckets[i].committing,
     805                 :            :                             &buckets[i].committing);
     806                 :          0 :                 buckets[i].direct_verf.committed =
     807                 :          0 :                         cinfo->ds->buckets[i].direct_verf.committed;
     808                 :          0 :                 buckets[i].wlseg = cinfo->ds->buckets[i].wlseg;
     809                 :          0 :                 buckets[i].clseg = cinfo->ds->buckets[i].clseg;
     810                 :            :         }
     811                 :          0 :         swap(cinfo->ds->buckets, buckets);
     812                 :          0 :         cinfo->ds->nbuckets = size;
     813                 :            : out:
     814                 :          0 :         spin_unlock(&cinfo->inode->i_lock);
     815                 :          0 :         kfree(buckets);
     816                 :          0 :         return 0;
     817                 :            : }
     818                 :            : 
     819                 :            : static struct pnfs_layout_segment *
     820                 :          0 : filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
     821                 :            :                       struct nfs4_layoutget_res *lgr,
     822                 :            :                       gfp_t gfp_flags)
     823                 :            : {
     824                 :            :         struct nfs4_filelayout_segment *fl;
     825                 :            :         int rc;
     826                 :            : 
     827                 :            :         dprintk("--> %s\n", __func__);
     828                 :          0 :         fl = kzalloc(sizeof(*fl), gfp_flags);
     829                 :          0 :         if (!fl)
     830                 :            :                 return NULL;
     831                 :            : 
     832                 :          0 :         rc = filelayout_decode_layout(layoutid, fl, lgr, gfp_flags);
     833                 :          0 :         if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, gfp_flags)) {
     834                 :          0 :                 _filelayout_free_lseg(fl);
     835                 :          0 :                 return NULL;
     836                 :            :         }
     837                 :          0 :         return &fl->generic_hdr;
     838                 :            : }
     839                 :            : 
     840                 :            : /*
     841                 :            :  * filelayout_pg_test(). Called by nfs_can_coalesce_requests()
     842                 :            :  *
     843                 :            :  * Return 0 if @req cannot be coalesced into @pgio, otherwise return the number
     844                 :            :  * of bytes (maximum @req->wb_bytes) that can be coalesced.
     845                 :            :  */
     846                 :            : static size_t
     847                 :          0 : filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
     848                 :            :                    struct nfs_page *req)
     849                 :            : {
     850                 :            :         unsigned int size;
     851                 :            :         u64 p_stripe, r_stripe;
     852                 :            :         u32 stripe_offset;
     853                 :          0 :         u64 segment_offset = pgio->pg_lseg->pls_range.offset;
     854                 :          0 :         u32 stripe_unit = FILELAYOUT_LSEG(pgio->pg_lseg)->stripe_unit;
     855                 :            : 
     856                 :            :         /* calls nfs_generic_pg_test */
     857                 :          0 :         size = pnfs_generic_pg_test(pgio, prev, req);
     858                 :          0 :         if (!size)
     859                 :            :                 return 0;
     860                 :            : 
     861                 :            :         /* see if req and prev are in the same stripe */
     862                 :          0 :         if (prev) {
     863                 :          0 :                 p_stripe = (u64)req_offset(prev) - segment_offset;
     864                 :          0 :                 r_stripe = (u64)req_offset(req) - segment_offset;
     865                 :          0 :                 do_div(p_stripe, stripe_unit);
     866                 :          0 :                 do_div(r_stripe, stripe_unit);
     867                 :            : 
     868                 :          0 :                 if (p_stripe != r_stripe)
     869                 :            :                         return 0;
     870                 :            :         }
     871                 :            : 
     872                 :            :         /* calculate remaining bytes in the current stripe */
     873                 :          0 :         div_u64_rem((u64)req_offset(req) - segment_offset,
     874                 :            :                         stripe_unit,
     875                 :            :                         &stripe_offset);
     876                 :          0 :         WARN_ON_ONCE(stripe_offset > stripe_unit);
     877                 :          0 :         if (stripe_offset >= stripe_unit)
     878                 :            :                 return 0;
     879                 :          0 :         return min(stripe_unit - (unsigned int)stripe_offset, size);
     880                 :            : }
     881                 :            : 
     882                 :            : static struct pnfs_layout_segment *
     883                 :          0 : fl_pnfs_update_layout(struct inode *ino,
     884                 :            :                       struct nfs_open_context *ctx,
     885                 :            :                       loff_t pos,
     886                 :            :                       u64 count,
     887                 :            :                       enum pnfs_iomode iomode,
     888                 :            :                       bool strict_iomode,
     889                 :            :                       gfp_t gfp_flags)
     890                 :            : {
     891                 :            :         struct pnfs_layout_segment *lseg = NULL;
     892                 :            :         struct pnfs_layout_hdr *lo;
     893                 :            :         struct nfs4_filelayout_segment *fl;
     894                 :            :         int status;
     895                 :            : 
     896                 :          0 :         lseg = pnfs_update_layout(ino, ctx, pos, count, iomode, strict_iomode,
     897                 :            :                                   gfp_flags);
     898                 :          0 :         if (IS_ERR_OR_NULL(lseg))
     899                 :            :                 goto out;
     900                 :            : 
     901                 :          0 :         lo = NFS_I(ino)->layout;
     902                 :            :         fl = FILELAYOUT_LSEG(lseg);
     903                 :            : 
     904                 :          0 :         status = filelayout_check_deviceid(lo, fl, gfp_flags);
     905                 :          0 :         if (status) {
     906                 :          0 :                 pnfs_put_lseg(lseg);
     907                 :            :                 lseg = NULL;
     908                 :            :         }
     909                 :            : out:
     910                 :          0 :         return lseg;
     911                 :            : }
     912                 :            : 
     913                 :            : static void
     914                 :          0 : filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
     915                 :            :                         struct nfs_page *req)
     916                 :            : {
     917                 :          0 :         pnfs_generic_pg_check_layout(pgio);
     918                 :          0 :         if (!pgio->pg_lseg) {
     919                 :          0 :                 pgio->pg_lseg = fl_pnfs_update_layout(pgio->pg_inode,
     920                 :            :                                                       nfs_req_openctx(req),
     921                 :            :                                                       0,
     922                 :            :                                                       NFS4_MAX_UINT64,
     923                 :            :                                                       IOMODE_READ,
     924                 :            :                                                       false,
     925                 :            :                                                       GFP_KERNEL);
     926                 :          0 :                 if (IS_ERR(pgio->pg_lseg)) {
     927                 :          0 :                         pgio->pg_error = PTR_ERR(pgio->pg_lseg);
     928                 :          0 :                         pgio->pg_lseg = NULL;
     929                 :          0 :                         return;
     930                 :            :                 }
     931                 :            :         }
     932                 :            :         /* If no lseg, fall back to read through mds */
     933                 :          0 :         if (pgio->pg_lseg == NULL)
     934                 :          0 :                 nfs_pageio_reset_read_mds(pgio);
     935                 :            : }
     936                 :            : 
     937                 :            : static void
     938                 :          0 : filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
     939                 :            :                          struct nfs_page *req)
     940                 :            : {
     941                 :            :         struct nfs_commit_info cinfo;
     942                 :            :         int status;
     943                 :            : 
     944                 :          0 :         pnfs_generic_pg_check_layout(pgio);
     945                 :          0 :         if (!pgio->pg_lseg) {
     946                 :          0 :                 pgio->pg_lseg = fl_pnfs_update_layout(pgio->pg_inode,
     947                 :            :                                                       nfs_req_openctx(req),
     948                 :            :                                                       0,
     949                 :            :                                                       NFS4_MAX_UINT64,
     950                 :            :                                                       IOMODE_RW,
     951                 :            :                                                       false,
     952                 :            :                                                       GFP_NOFS);
     953                 :          0 :                 if (IS_ERR(pgio->pg_lseg)) {
     954                 :          0 :                         pgio->pg_error = PTR_ERR(pgio->pg_lseg);
     955                 :          0 :                         pgio->pg_lseg = NULL;
     956                 :          0 :                         return;
     957                 :            :                 }
     958                 :            :         }
     959                 :            : 
     960                 :            :         /* If no lseg, fall back to write through mds */
     961                 :          0 :         if (pgio->pg_lseg == NULL)
     962                 :            :                 goto out_mds;
     963                 :          0 :         nfs_init_cinfo(&cinfo, pgio->pg_inode, pgio->pg_dreq);
     964                 :          0 :         status = filelayout_alloc_commit_info(pgio->pg_lseg, &cinfo, GFP_NOFS);
     965                 :          0 :         if (status < 0) {
     966                 :          0 :                 pnfs_put_lseg(pgio->pg_lseg);
     967                 :          0 :                 pgio->pg_lseg = NULL;
     968                 :          0 :                 goto out_mds;
     969                 :            :         }
     970                 :            :         return;
     971                 :            : out_mds:
     972                 :          0 :         nfs_pageio_reset_write_mds(pgio);
     973                 :            : }
     974                 :            : 
     975                 :            : static const struct nfs_pageio_ops filelayout_pg_read_ops = {
     976                 :            :         .pg_init = filelayout_pg_init_read,
     977                 :            :         .pg_test = filelayout_pg_test,
     978                 :            :         .pg_doio = pnfs_generic_pg_readpages,
     979                 :            :         .pg_cleanup = pnfs_generic_pg_cleanup,
     980                 :            : };
     981                 :            : 
     982                 :            : static const struct nfs_pageio_ops filelayout_pg_write_ops = {
     983                 :            :         .pg_init = filelayout_pg_init_write,
     984                 :            :         .pg_test = filelayout_pg_test,
     985                 :            :         .pg_doio = pnfs_generic_pg_writepages,
     986                 :            :         .pg_cleanup = pnfs_generic_pg_cleanup,
     987                 :            : };
     988                 :            : 
     989                 :            : static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j)
     990                 :            : {
     991                 :          0 :         if (fl->stripe_type == STRIPE_SPARSE)
     992                 :          0 :                 return nfs4_fl_calc_ds_index(&fl->generic_hdr, j);
     993                 :            :         else
     994                 :            :                 return j;
     995                 :            : }
     996                 :            : 
     997                 :            : static void
     998                 :          0 : filelayout_mark_request_commit(struct nfs_page *req,
     999                 :            :                                struct pnfs_layout_segment *lseg,
    1000                 :            :                                struct nfs_commit_info *cinfo,
    1001                 :            :                                u32 ds_commit_idx)
    1002                 :            : 
    1003                 :            : {
    1004                 :            :         struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
    1005                 :            :         u32 i, j;
    1006                 :            : 
    1007                 :          0 :         if (fl->commit_through_mds) {
    1008                 :          0 :                 nfs_request_add_commit_list(req, cinfo);
    1009                 :            :         } else {
    1010                 :            :                 /* Note that we are calling nfs4_fl_calc_j_index on each page
    1011                 :            :                  * that ends up being committed to a data server.  An attractive
    1012                 :            :                  * alternative is to add a field to nfs_write_data and nfs_page
    1013                 :            :                  * to store the value calculated in filelayout_write_pagelist
    1014                 :            :                  * and just use that here.
    1015                 :            :                  */
    1016                 :          0 :                 j = nfs4_fl_calc_j_index(lseg, req_offset(req));
    1017                 :            :                 i = select_bucket_index(fl, j);
    1018                 :          0 :                 pnfs_layout_mark_request_commit(req, lseg, cinfo, i);
    1019                 :            :         }
    1020                 :          0 : }
    1021                 :            : 
    1022                 :            : static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i)
    1023                 :            : {
    1024                 :            :         struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
    1025                 :            : 
    1026                 :          0 :         if (flseg->stripe_type == STRIPE_SPARSE)
    1027                 :            :                 return i;
    1028                 :            :         else
    1029                 :          0 :                 return nfs4_fl_calc_ds_index(lseg, i);
    1030                 :            : }
    1031                 :            : 
    1032                 :            : static struct nfs_fh *
    1033                 :            : select_ds_fh_from_commit(struct pnfs_layout_segment *lseg, u32 i)
    1034                 :            : {
    1035                 :            :         struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
    1036                 :            : 
    1037                 :          0 :         if (flseg->stripe_type == STRIPE_SPARSE) {
    1038                 :          0 :                 if (flseg->num_fh == 1)
    1039                 :            :                         i = 0;
    1040                 :          0 :                 else if (flseg->num_fh == 0)
    1041                 :            :                         /* Use the MDS OPEN fh set in nfs_read_rpcsetup */
    1042                 :            :                         return NULL;
    1043                 :            :         }
    1044                 :          0 :         return flseg->fh_array[i];
    1045                 :            : }
    1046                 :            : 
    1047                 :          0 : static int filelayout_initiate_commit(struct nfs_commit_data *data, int how)
    1048                 :            : {
    1049                 :          0 :         struct pnfs_layout_segment *lseg = data->lseg;
    1050                 :            :         struct nfs4_pnfs_ds *ds;
    1051                 :            :         struct rpc_clnt *ds_clnt;
    1052                 :            :         u32 idx;
    1053                 :            :         struct nfs_fh *fh;
    1054                 :            : 
    1055                 :          0 :         idx = calc_ds_index_from_commit(lseg, data->ds_commit_index);
    1056                 :          0 :         ds = nfs4_fl_prepare_ds(lseg, idx);
    1057                 :          0 :         if (!ds)
    1058                 :            :                 goto out_err;
    1059                 :            : 
    1060                 :          0 :         ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, data->inode);
    1061                 :          0 :         if (IS_ERR(ds_clnt))
    1062                 :            :                 goto out_err;
    1063                 :            : 
    1064                 :            :         dprintk("%s ino %lu, how %d cl_count %d\n", __func__,
    1065                 :            :                 data->inode->i_ino, how, refcount_read(&ds->ds_clp->cl_count));
    1066                 :          0 :         data->commit_done_cb = filelayout_commit_done_cb;
    1067                 :          0 :         refcount_inc(&ds->ds_clp->cl_count);
    1068                 :          0 :         data->ds_clp = ds->ds_clp;
    1069                 :          0 :         fh = select_ds_fh_from_commit(lseg, data->ds_commit_index);
    1070                 :          0 :         if (fh)
    1071                 :          0 :                 data->args.fh = fh;
    1072                 :          0 :         return nfs_initiate_commit(ds_clnt, data, NFS_PROTO(data->inode),
    1073                 :            :                                    &filelayout_commit_call_ops, how,
    1074                 :            :                                    RPC_TASK_SOFTCONN);
    1075                 :            : out_err:
    1076                 :          0 :         pnfs_generic_prepare_to_resend_writes(data);
    1077                 :          0 :         pnfs_generic_commit_release(data);
    1078                 :          0 :         return -EAGAIN;
    1079                 :            : }
    1080                 :            : 
    1081                 :            : /* filelayout_search_commit_reqs - Search lists in @cinfo for the head reqest
    1082                 :            :  *                                 for @page
    1083                 :            :  * @cinfo - commit info for current inode
    1084                 :            :  * @page - page to search for matching head request
    1085                 :            :  *
    1086                 :            :  * Returns a the head request if one is found, otherwise returns NULL.
    1087                 :            :  */
    1088                 :            : static struct nfs_page *
    1089                 :          0 : filelayout_search_commit_reqs(struct nfs_commit_info *cinfo, struct page *page)
    1090                 :            : {
    1091                 :            :         struct nfs_page *freq, *t;
    1092                 :            :         struct pnfs_commit_bucket *b;
    1093                 :            :         int i;
    1094                 :            : 
    1095                 :            :         /* Linearly search the commit lists for each bucket until a matching
    1096                 :            :          * request is found */
    1097                 :          0 :         for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {
    1098                 :          0 :                 list_for_each_entry_safe(freq, t, &b->written, wb_list) {
    1099                 :          0 :                         if (freq->wb_page == page)
    1100                 :          0 :                                 return freq->wb_head;
    1101                 :            :                 }
    1102                 :          0 :                 list_for_each_entry_safe(freq, t, &b->committing, wb_list) {
    1103                 :          0 :                         if (freq->wb_page == page)
    1104                 :          0 :                                 return freq->wb_head;
    1105                 :            :                 }
    1106                 :            :         }
    1107                 :            : 
    1108                 :            :         return NULL;
    1109                 :            : }
    1110                 :            : 
    1111                 :            : static int
    1112                 :          0 : filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
    1113                 :            :                            int how, struct nfs_commit_info *cinfo)
    1114                 :            : {
    1115                 :          0 :         return pnfs_generic_commit_pagelist(inode, mds_pages, how, cinfo,
    1116                 :            :                                             filelayout_initiate_commit);
    1117                 :            : }
    1118                 :            : 
    1119                 :            : static struct nfs4_deviceid_node *
    1120                 :          0 : filelayout_alloc_deviceid_node(struct nfs_server *server,
    1121                 :            :                 struct pnfs_device *pdev, gfp_t gfp_flags)
    1122                 :            : {
    1123                 :            :         struct nfs4_file_layout_dsaddr *dsaddr;
    1124                 :            : 
    1125                 :          0 :         dsaddr = nfs4_fl_alloc_deviceid_node(server, pdev, gfp_flags);
    1126                 :          0 :         if (!dsaddr)
    1127                 :            :                 return NULL;
    1128                 :          0 :         return &dsaddr->id_node;
    1129                 :            : }
    1130                 :            : 
    1131                 :            : static void
    1132                 :          0 : filelayout_free_deviceid_node(struct nfs4_deviceid_node *d)
    1133                 :            : {
    1134                 :          0 :         nfs4_fl_free_deviceid(container_of(d, struct nfs4_file_layout_dsaddr, id_node));
    1135                 :          0 : }
    1136                 :            : 
    1137                 :            : static struct pnfs_layout_hdr *
    1138                 :          0 : filelayout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags)
    1139                 :            : {
    1140                 :            :         struct nfs4_filelayout *flo;
    1141                 :            : 
    1142                 :          0 :         flo = kzalloc(sizeof(*flo), gfp_flags);
    1143                 :          0 :         return flo != NULL ? &flo->generic_hdr : NULL;
    1144                 :            : }
    1145                 :            : 
    1146                 :            : static void
    1147                 :          0 : filelayout_free_layout_hdr(struct pnfs_layout_hdr *lo)
    1148                 :            : {
    1149                 :          0 :         kfree(FILELAYOUT_FROM_HDR(lo));
    1150                 :          0 : }
    1151                 :            : 
    1152                 :            : static struct pnfs_ds_commit_info *
    1153                 :          0 : filelayout_get_ds_info(struct inode *inode)
    1154                 :            : {
    1155                 :          0 :         struct pnfs_layout_hdr *layout = NFS_I(inode)->layout;
    1156                 :            : 
    1157                 :          0 :         if (layout == NULL)
    1158                 :            :                 return NULL;
    1159                 :            :         else
    1160                 :          0 :                 return &FILELAYOUT_FROM_HDR(layout)->commit_info;
    1161                 :            : }
    1162                 :            : 
    1163                 :            : static struct pnfs_layoutdriver_type filelayout_type = {
    1164                 :            :         .id                     = LAYOUT_NFSV4_1_FILES,
    1165                 :            :         .name                   = "LAYOUT_NFSV4_1_FILES",
    1166                 :            :         .owner                  = THIS_MODULE,
    1167                 :            :         .flags                  = PNFS_LAYOUTGET_ON_OPEN,
    1168                 :            :         .max_layoutget_response = 4096, /* 1 page or so... */
    1169                 :            :         .alloc_layout_hdr       = filelayout_alloc_layout_hdr,
    1170                 :            :         .free_layout_hdr        = filelayout_free_layout_hdr,
    1171                 :            :         .alloc_lseg             = filelayout_alloc_lseg,
    1172                 :            :         .free_lseg              = filelayout_free_lseg,
    1173                 :            :         .pg_read_ops            = &filelayout_pg_read_ops,
    1174                 :            :         .pg_write_ops           = &filelayout_pg_write_ops,
    1175                 :            :         .get_ds_info            = &filelayout_get_ds_info,
    1176                 :            :         .mark_request_commit    = filelayout_mark_request_commit,
    1177                 :            :         .clear_request_commit   = pnfs_generic_clear_request_commit,
    1178                 :            :         .scan_commit_lists      = pnfs_generic_scan_commit_lists,
    1179                 :            :         .recover_commit_reqs    = pnfs_generic_recover_commit_reqs,
    1180                 :            :         .search_commit_reqs     = filelayout_search_commit_reqs,
    1181                 :            :         .commit_pagelist        = filelayout_commit_pagelist,
    1182                 :            :         .read_pagelist          = filelayout_read_pagelist,
    1183                 :            :         .write_pagelist         = filelayout_write_pagelist,
    1184                 :            :         .alloc_deviceid_node    = filelayout_alloc_deviceid_node,
    1185                 :            :         .free_deviceid_node     = filelayout_free_deviceid_node,
    1186                 :            :         .sync                   = pnfs_nfs_generic_sync,
    1187                 :            : };
    1188                 :            : 
    1189                 :          3 : static int __init nfs4filelayout_init(void)
    1190                 :            : {
    1191                 :          3 :         printk(KERN_INFO "%s: NFSv4 File Layout Driver Registering...\n",
    1192                 :            :                __func__);
    1193                 :          3 :         return pnfs_register_layoutdriver(&filelayout_type);
    1194                 :            : }
    1195                 :            : 
    1196                 :          0 : static void __exit nfs4filelayout_exit(void)
    1197                 :            : {
    1198                 :          0 :         printk(KERN_INFO "%s: NFSv4 File Layout Driver Unregistering...\n",
    1199                 :            :                __func__);
    1200                 :          0 :         pnfs_unregister_layoutdriver(&filelayout_type);
    1201                 :          0 : }
    1202                 :            : 
    1203                 :            : MODULE_ALIAS("nfs-layouttype4-1");
    1204                 :            : 
    1205                 :            : module_init(nfs4filelayout_init);
    1206                 :            : module_exit(nfs4filelayout_exit);
    

Generated by: LCOV version 1.14