LCOV - code coverage report
Current view: top level - fs/nfs - nfs4file.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 55 0.0 %
Date: 2022-04-01 14:58:12 Functions: 0 2 0.0 %
Branches: 0 28 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  *  linux/fs/nfs/file.c
       4                 :            :  *
       5                 :            :  *  Copyright (C) 1992  Rick Sladkey
       6                 :            :  */
       7                 :            : #include <linux/fs.h>
       8                 :            : #include <linux/file.h>
       9                 :            : #include <linux/falloc.h>
      10                 :            : #include <linux/mount.h>
      11                 :            : #include <linux/nfs_fs.h>
      12                 :            : #include "delegation.h"
      13                 :            : #include "internal.h"
      14                 :            : #include "iostat.h"
      15                 :            : #include "fscache.h"
      16                 :            : #include "pnfs.h"
      17                 :            : 
      18                 :            : #include "nfstrace.h"
      19                 :            : 
      20                 :            : #ifdef CONFIG_NFS_V4_2
      21                 :            : #include "nfs42.h"
      22                 :            : #endif
      23                 :            : 
      24                 :            : #define NFSDBG_FACILITY         NFSDBG_FILE
      25                 :            : 
      26                 :            : static int
      27                 :          0 : nfs4_file_open(struct inode *inode, struct file *filp)
      28                 :            : {
      29                 :          0 :         struct nfs_open_context *ctx;
      30         [ #  # ]:          0 :         struct dentry *dentry = file_dentry(filp);
      31                 :          0 :         struct dentry *parent = NULL;
      32                 :          0 :         struct inode *dir;
      33                 :          0 :         unsigned openflags = filp->f_flags;
      34                 :          0 :         struct iattr attr;
      35                 :          0 :         int err;
      36                 :            : 
      37                 :            :         /*
      38                 :            :          * If no cached dentry exists or if it's negative, NFSv4 handled the
      39                 :            :          * opens in ->lookup() or ->create().
      40                 :            :          *
      41                 :            :          * We only get this far for a cached positive dentry.  We skipped
      42                 :            :          * revalidation, so handle it here by dropping the dentry and returning
      43                 :            :          * -EOPENSTALE.  The VFS will retry the lookup/create/open.
      44                 :            :          */
      45                 :            : 
      46                 :          0 :         dprintk("NFS: open file(%pd2)\n", dentry);
      47                 :            : 
      48                 :          0 :         err = nfs_check_flags(openflags);
      49         [ #  # ]:          0 :         if (err)
      50                 :            :                 return err;
      51                 :            : 
      52         [ #  # ]:          0 :         if ((openflags & O_ACCMODE) == 3)
      53                 :          0 :                 return nfs_open(inode, filp);
      54                 :            : 
      55                 :            :         /* We can't create new files here */
      56                 :          0 :         openflags &= ~(O_CREAT|O_EXCL);
      57                 :            : 
      58                 :          0 :         parent = dget_parent(dentry);
      59         [ #  # ]:          0 :         dir = d_inode(parent);
      60                 :            : 
      61         [ #  # ]:          0 :         ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode, filp);
      62         [ #  # ]:          0 :         err = PTR_ERR(ctx);
      63         [ #  # ]:          0 :         if (IS_ERR(ctx))
      64                 :          0 :                 goto out;
      65                 :            : 
      66                 :          0 :         attr.ia_valid = ATTR_OPEN;
      67         [ #  # ]:          0 :         if (openflags & O_TRUNC) {
      68                 :          0 :                 attr.ia_valid |= ATTR_SIZE;
      69                 :          0 :                 attr.ia_size = 0;
      70                 :          0 :                 filemap_write_and_wait(inode->i_mapping);
      71                 :            :         }
      72                 :            : 
      73                 :          0 :         inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr, NULL);
      74         [ #  # ]:          0 :         if (IS_ERR(inode)) {
      75         [ #  # ]:          0 :                 err = PTR_ERR(inode);
      76         [ #  # ]:          0 :                 switch (err) {
      77                 :          0 :                 default:
      78                 :          0 :                         goto out_put_ctx;
      79                 :          0 :                 case -ENOENT:
      80                 :            :                 case -ESTALE:
      81                 :            :                 case -EISDIR:
      82                 :            :                 case -ENOTDIR:
      83                 :            :                 case -ELOOP:
      84                 :          0 :                         goto out_drop;
      85                 :            :                 }
      86                 :            :         }
      87         [ #  # ]:          0 :         if (inode != d_inode(dentry))
      88                 :          0 :                 goto out_drop;
      89                 :            : 
      90                 :          0 :         nfs_file_set_open_context(filp, ctx);
      91                 :          0 :         nfs_fscache_open_file(inode, filp);
      92                 :          0 :         err = 0;
      93                 :            : 
      94                 :          0 : out_put_ctx:
      95                 :          0 :         put_nfs_open_context(ctx);
      96                 :          0 : out:
      97                 :          0 :         dput(parent);
      98                 :          0 :         return err;
      99                 :            : 
     100                 :          0 : out_drop:
     101                 :          0 :         d_drop(dentry);
     102                 :          0 :         err = -EOPENSTALE;
     103                 :          0 :         goto out_put_ctx;
     104                 :            : }
     105                 :            : 
     106                 :            : /*
     107                 :            :  * Flush all dirty pages, and check for write errors.
     108                 :            :  */
     109                 :            : static int
     110                 :          0 : nfs4_file_flush(struct file *file, fl_owner_t id)
     111                 :            : {
     112                 :          0 :         struct inode    *inode = file_inode(file);
     113                 :            : 
     114                 :          0 :         dprintk("NFS: flush(%pD2)\n", file);
     115                 :            : 
     116                 :          0 :         nfs_inc_stats(inode, NFSIOS_VFSFLUSH);
     117         [ #  # ]:          0 :         if ((file->f_mode & FMODE_WRITE) == 0)
     118                 :            :                 return 0;
     119                 :            : 
     120                 :            :         /*
     121                 :            :          * If we're holding a write delegation, then check if we're required
     122                 :            :          * to flush the i/o on close. If not, then just start the i/o now.
     123                 :            :          */
     124         [ #  # ]:          0 :         if (!nfs4_delegation_flush_on_close(inode))
     125                 :          0 :                 return filemap_fdatawrite(file->f_mapping);
     126                 :            : 
     127                 :            :         /* Flush writes to the server and return any errors */
     128                 :          0 :         return nfs_wb_all(inode);
     129                 :            : }
     130                 :            : 
     131                 :            : #ifdef CONFIG_NFS_V4_2
     132                 :            : static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
     133                 :            :                                       struct file *file_out, loff_t pos_out,
     134                 :            :                                       size_t count, unsigned int flags)
     135                 :            : {
     136                 :            :         struct nfs42_copy_notify_res *cn_resp = NULL;
     137                 :            :         struct nl4_server *nss = NULL;
     138                 :            :         nfs4_stateid *cnrs = NULL;
     139                 :            :         ssize_t ret;
     140                 :            :         bool sync = false;
     141                 :            : 
     142                 :            :         /* Only offload copy if superblock is the same */
     143                 :            :         if (file_in->f_op != &nfs4_file_operations)
     144                 :            :                 return -EXDEV;
     145                 :            :         if (!nfs_server_capable(file_inode(file_out), NFS_CAP_COPY))
     146                 :            :                 return -EOPNOTSUPP;
     147                 :            :         if (file_inode(file_in) == file_inode(file_out))
     148                 :            :                 return -EOPNOTSUPP;
     149                 :            :         /* if the copy size if smaller than 2 RPC payloads, make it
     150                 :            :          * synchronous
     151                 :            :          */
     152                 :            :         if (count <= 2 * NFS_SERVER(file_inode(file_in))->rsize)
     153                 :            :                 sync = true;
     154                 :            : retry:
     155                 :            :         if (!nfs42_files_from_same_server(file_in, file_out)) {
     156                 :            :                 /* for inter copy, if copy size if smaller than 12 RPC
     157                 :            :                  * payloads, fallback to traditional copy. There are
     158                 :            :                  * 14 RPCs during an NFSv4.x mount between source/dest
     159                 :            :                  * servers.
     160                 :            :                  */
     161                 :            :                 if (sync ||
     162                 :            :                         count <= 14 * NFS_SERVER(file_inode(file_in))->rsize)
     163                 :            :                         return -EOPNOTSUPP;
     164                 :            :                 cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res),
     165                 :            :                                 GFP_NOFS);
     166                 :            :                 if (unlikely(cn_resp == NULL))
     167                 :            :                         return -ENOMEM;
     168                 :            : 
     169                 :            :                 ret = nfs42_proc_copy_notify(file_in, file_out, cn_resp);
     170                 :            :                 if (ret) {
     171                 :            :                         ret = -EOPNOTSUPP;
     172                 :            :                         goto out;
     173                 :            :                 }
     174                 :            :                 nss = &cn_resp->cnr_src;
     175                 :            :                 cnrs = &cn_resp->cnr_stateid;
     176                 :            :         }
     177                 :            :         ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count,
     178                 :            :                                 nss, cnrs, sync);
     179                 :            : out:
     180                 :            :         if (!nfs42_files_from_same_server(file_in, file_out))
     181                 :            :                 kfree(cn_resp);
     182                 :            :         if (ret == -EAGAIN)
     183                 :            :                 goto retry;
     184                 :            :         return ret;
     185                 :            : }
     186                 :            : 
     187                 :            : static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
     188                 :            :                                     struct file *file_out, loff_t pos_out,
     189                 :            :                                     size_t count, unsigned int flags)
     190                 :            : {
     191                 :            :         ssize_t ret;
     192                 :            : 
     193                 :            :         ret = __nfs4_copy_file_range(file_in, pos_in, file_out, pos_out, count,
     194                 :            :                                      flags);
     195                 :            :         if (ret == -EOPNOTSUPP || ret == -EXDEV)
     196                 :            :                 ret = generic_copy_file_range(file_in, pos_in, file_out,
     197                 :            :                                               pos_out, count, flags);
     198                 :            :         return ret;
     199                 :            : }
     200                 :            : 
     201                 :            : static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
     202                 :            : {
     203                 :            :         loff_t ret;
     204                 :            : 
     205                 :            :         switch (whence) {
     206                 :            :         case SEEK_HOLE:
     207                 :            :         case SEEK_DATA:
     208                 :            :                 ret = nfs42_proc_llseek(filep, offset, whence);
     209                 :            :                 if (ret != -ENOTSUPP)
     210                 :            :                         return ret;
     211                 :            :                 /* Fall through */
     212                 :            :         default:
     213                 :            :                 return nfs_file_llseek(filep, offset, whence);
     214                 :            :         }
     215                 :            : }
     216                 :            : 
     217                 :            : static long nfs42_fallocate(struct file *filep, int mode, loff_t offset, loff_t len)
     218                 :            : {
     219                 :            :         struct inode *inode = file_inode(filep);
     220                 :            :         long ret;
     221                 :            : 
     222                 :            :         if (!S_ISREG(inode->i_mode))
     223                 :            :                 return -EOPNOTSUPP;
     224                 :            : 
     225                 :            :         if ((mode != 0) && (mode != (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE)))
     226                 :            :                 return -EOPNOTSUPP;
     227                 :            : 
     228                 :            :         ret = inode_newsize_ok(inode, offset + len);
     229                 :            :         if (ret < 0)
     230                 :            :                 return ret;
     231                 :            : 
     232                 :            :         if (mode & FALLOC_FL_PUNCH_HOLE)
     233                 :            :                 return nfs42_proc_deallocate(filep, offset, len);
     234                 :            :         return nfs42_proc_allocate(filep, offset, len);
     235                 :            : }
     236                 :            : 
     237                 :            : static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off,
     238                 :            :                 struct file *dst_file, loff_t dst_off, loff_t count,
     239                 :            :                 unsigned int remap_flags)
     240                 :            : {
     241                 :            :         struct inode *dst_inode = file_inode(dst_file);
     242                 :            :         struct nfs_server *server = NFS_SERVER(dst_inode);
     243                 :            :         struct inode *src_inode = file_inode(src_file);
     244                 :            :         unsigned int bs = server->clone_blksize;
     245                 :            :         bool same_inode = false;
     246                 :            :         int ret;
     247                 :            : 
     248                 :            :         /* NFS does not support deduplication. */
     249                 :            :         if (remap_flags & REMAP_FILE_DEDUP)
     250                 :            :                 return -EOPNOTSUPP;
     251                 :            : 
     252                 :            :         if (remap_flags & ~REMAP_FILE_ADVISORY)
     253                 :            :                 return -EINVAL;
     254                 :            : 
     255                 :            :         /* check alignment w.r.t. clone_blksize */
     256                 :            :         ret = -EINVAL;
     257                 :            :         if (bs) {
     258                 :            :                 if (!IS_ALIGNED(src_off, bs) || !IS_ALIGNED(dst_off, bs))
     259                 :            :                         goto out;
     260                 :            :                 if (!IS_ALIGNED(count, bs) && i_size_read(src_inode) != (src_off + count))
     261                 :            :                         goto out;
     262                 :            :         }
     263                 :            : 
     264                 :            :         if (src_inode == dst_inode)
     265                 :            :                 same_inode = true;
     266                 :            : 
     267                 :            :         /* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */
     268                 :            :         if (same_inode) {
     269                 :            :                 inode_lock(src_inode);
     270                 :            :         } else if (dst_inode < src_inode) {
     271                 :            :                 inode_lock_nested(dst_inode, I_MUTEX_PARENT);
     272                 :            :                 inode_lock_nested(src_inode, I_MUTEX_CHILD);
     273                 :            :         } else {
     274                 :            :                 inode_lock_nested(src_inode, I_MUTEX_PARENT);
     275                 :            :                 inode_lock_nested(dst_inode, I_MUTEX_CHILD);
     276                 :            :         }
     277                 :            : 
     278                 :            :         /* flush all pending writes on both src and dst so that server
     279                 :            :          * has the latest data */
     280                 :            :         ret = nfs_sync_inode(src_inode);
     281                 :            :         if (ret)
     282                 :            :                 goto out_unlock;
     283                 :            :         ret = nfs_sync_inode(dst_inode);
     284                 :            :         if (ret)
     285                 :            :                 goto out_unlock;
     286                 :            : 
     287                 :            :         ret = nfs42_proc_clone(src_file, dst_file, src_off, dst_off, count);
     288                 :            : 
     289                 :            :         /* truncate inode page cache of the dst range so that future reads can fetch
     290                 :            :          * new data from server */
     291                 :            :         if (!ret)
     292                 :            :                 truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1);
     293                 :            : 
     294                 :            : out_unlock:
     295                 :            :         if (same_inode) {
     296                 :            :                 inode_unlock(src_inode);
     297                 :            :         } else if (dst_inode < src_inode) {
     298                 :            :                 inode_unlock(src_inode);
     299                 :            :                 inode_unlock(dst_inode);
     300                 :            :         } else {
     301                 :            :                 inode_unlock(dst_inode);
     302                 :            :                 inode_unlock(src_inode);
     303                 :            :         }
     304                 :            : out:
     305                 :            :         return ret < 0 ? ret : count;
     306                 :            : }
     307                 :            : 
     308                 :            : static int read_name_gen = 1;
     309                 :            : #define SSC_READ_NAME_BODY "ssc_read_%d"
     310                 :            : 
     311                 :            : struct file *
     312                 :            : nfs42_ssc_open(struct vfsmount *ss_mnt, struct nfs_fh *src_fh,
     313                 :            :                 nfs4_stateid *stateid)
     314                 :            : {
     315                 :            :         struct nfs_fattr fattr;
     316                 :            :         struct file *filep, *res;
     317                 :            :         struct nfs_server *server;
     318                 :            :         struct inode *r_ino = NULL;
     319                 :            :         struct nfs_open_context *ctx;
     320                 :            :         struct nfs4_state_owner *sp;
     321                 :            :         char *read_name = NULL;
     322                 :            :         int len, status = 0;
     323                 :            : 
     324                 :            :         server = NFS_SERVER(ss_mnt->mnt_root->d_inode);
     325                 :            : 
     326                 :            :         nfs_fattr_init(&fattr);
     327                 :            : 
     328                 :            :         status = nfs4_proc_getattr(server, src_fh, &fattr, NULL, NULL);
     329                 :            :         if (status < 0) {
     330                 :            :                 res = ERR_PTR(status);
     331                 :            :                 goto out;
     332                 :            :         }
     333                 :            : 
     334                 :            :         res = ERR_PTR(-ENOMEM);
     335                 :            :         len = strlen(SSC_READ_NAME_BODY) + 16;
     336                 :            :         read_name = kzalloc(len, GFP_NOFS);
     337                 :            :         if (read_name == NULL)
     338                 :            :                 goto out;
     339                 :            :         snprintf(read_name, len, SSC_READ_NAME_BODY, read_name_gen++);
     340                 :            : 
     341                 :            :         r_ino = nfs_fhget(ss_mnt->mnt_root->d_inode->i_sb, src_fh, &fattr,
     342                 :            :                         NULL);
     343                 :            :         if (IS_ERR(r_ino)) {
     344                 :            :                 res = ERR_CAST(r_ino);
     345                 :            :                 goto out_free_name;
     346                 :            :         }
     347                 :            : 
     348                 :            :         filep = alloc_file_pseudo(r_ino, ss_mnt, read_name, FMODE_READ,
     349                 :            :                                      r_ino->i_fop);
     350                 :            :         if (IS_ERR(filep)) {
     351                 :            :                 res = ERR_CAST(filep);
     352                 :            :                 goto out_free_name;
     353                 :            :         }
     354                 :            :         filep->f_mode |= FMODE_READ;
     355                 :            : 
     356                 :            :         ctx = alloc_nfs_open_context(filep->f_path.dentry, filep->f_mode,
     357                 :            :                                         filep);
     358                 :            :         if (IS_ERR(ctx)) {
     359                 :            :                 res = ERR_CAST(ctx);
     360                 :            :                 goto out_filep;
     361                 :            :         }
     362                 :            : 
     363                 :            :         res = ERR_PTR(-EINVAL);
     364                 :            :         sp = nfs4_get_state_owner(server, ctx->cred, GFP_KERNEL);
     365                 :            :         if (sp == NULL)
     366                 :            :                 goto out_ctx;
     367                 :            : 
     368                 :            :         ctx->state = nfs4_get_open_state(r_ino, sp);
     369                 :            :         if (ctx->state == NULL)
     370                 :            :                 goto out_stateowner;
     371                 :            : 
     372                 :            :         set_bit(NFS_SRV_SSC_COPY_STATE, &ctx->state->flags);
     373                 :            :         set_bit(NFS_OPEN_STATE, &ctx->state->flags);
     374                 :            :         memcpy(&ctx->state->open_stateid.other, &stateid->other,
     375                 :            :                NFS4_STATEID_OTHER_SIZE);
     376                 :            :         update_open_stateid(ctx->state, stateid, NULL, filep->f_mode);
     377                 :            : 
     378                 :            :         nfs_file_set_open_context(filep, ctx);
     379                 :            :         put_nfs_open_context(ctx);
     380                 :            : 
     381                 :            :         file_ra_state_init(&filep->f_ra, filep->f_mapping->host->i_mapping);
     382                 :            :         res = filep;
     383                 :            : out_free_name:
     384                 :            :         kfree(read_name);
     385                 :            : out:
     386                 :            :         return res;
     387                 :            : out_stateowner:
     388                 :            :         nfs4_put_state_owner(sp);
     389                 :            : out_ctx:
     390                 :            :         put_nfs_open_context(ctx);
     391                 :            : out_filep:
     392                 :            :         fput(filep);
     393                 :            :         goto out_free_name;
     394                 :            : }
     395                 :            : EXPORT_SYMBOL_GPL(nfs42_ssc_open);
     396                 :            : void nfs42_ssc_close(struct file *filep)
     397                 :            : {
     398                 :            :         struct nfs_open_context *ctx = nfs_file_open_context(filep);
     399                 :            : 
     400                 :            :         ctx->state->flags = 0;
     401                 :            : }
     402                 :            : EXPORT_SYMBOL_GPL(nfs42_ssc_close);
     403                 :            : #endif /* CONFIG_NFS_V4_2 */
     404                 :            : 
     405                 :            : const struct file_operations nfs4_file_operations = {
     406                 :            :         .read_iter      = nfs_file_read,
     407                 :            :         .write_iter     = nfs_file_write,
     408                 :            :         .mmap           = nfs_file_mmap,
     409                 :            :         .open           = nfs4_file_open,
     410                 :            :         .flush          = nfs4_file_flush,
     411                 :            :         .release        = nfs_file_release,
     412                 :            :         .fsync          = nfs_file_fsync,
     413                 :            :         .lock           = nfs_lock,
     414                 :            :         .flock          = nfs_flock,
     415                 :            :         .splice_read    = generic_file_splice_read,
     416                 :            :         .splice_write   = iter_file_splice_write,
     417                 :            :         .check_flags    = nfs_check_flags,
     418                 :            :         .setlease       = simple_nosetlease,
     419                 :            : #ifdef CONFIG_NFS_V4_2
     420                 :            :         .copy_file_range = nfs4_copy_file_range,
     421                 :            :         .llseek         = nfs4_file_llseek,
     422                 :            :         .fallocate      = nfs42_fallocate,
     423                 :            :         .remap_file_range = nfs42_remap_file_range,
     424                 :            : #else
     425                 :            :         .llseek         = nfs_file_llseek,
     426                 :            : #endif
     427                 :            : };

Generated by: LCOV version 1.14