LCOV - code coverage report
Current view: top level - fs/xfs - xfs_export.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-acha @ Mon Jul 31 20:08:06 PDT 2023 Lines: 53 88 60.2 %
Date: 2023-07-31 20:08:07 Functions: 5 7 71.4 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (c) 2004-2005 Silicon Graphics, Inc.
       4             :  * All Rights Reserved.
       5             :  */
       6             : #include "xfs.h"
       7             : #include "xfs_shared.h"
       8             : #include "xfs_format.h"
       9             : #include "xfs_log_format.h"
      10             : #include "xfs_trans_resv.h"
      11             : #include "xfs_mount.h"
      12             : #include "xfs_dir2.h"
      13             : #include "xfs_export.h"
      14             : #include "xfs_inode.h"
      15             : #include "xfs_trans.h"
      16             : #include "xfs_inode_item.h"
      17             : #include "xfs_icache.h"
      18             : #include "xfs_pnfs.h"
      19             : 
      20             : /*
      21             :  * Note that we only accept fileids which are long enough rather than allow
      22             :  * the parent generation number to default to zero.  XFS considers zero a
      23             :  * valid generation number not an invalid/wildcard value.
      24             :  */
      25   191556313 : static int xfs_fileid_length(int fileid_type)
      26             : {
      27   191556313 :         switch (fileid_type) {
      28             :         case FILEID_INO32_GEN:
      29             :                 return 2;
      30           0 :         case FILEID_INO32_GEN_PARENT:
      31           0 :                 return 4;
      32   191556313 :         case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
      33   191556313 :                 return 3;
      34           0 :         case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
      35           0 :                 return 6;
      36             :         }
      37           0 :         return FILEID_INVALID;
      38             : }
      39             : 
      40             : STATIC int
      41       31820 : xfs_fs_encode_fh(
      42             :         struct inode    *inode,
      43             :         __u32           *fh,
      44             :         int             *max_len,
      45             :         struct inode    *parent)
      46             : {
      47       31820 :         struct xfs_mount        *mp = XFS_M(inode->i_sb);
      48       31820 :         struct fid              *fid = (struct fid *)fh;
      49       31820 :         struct xfs_fid64        *fid64 = (struct xfs_fid64 *)fh;
      50       31820 :         int                     fileid_type;
      51       31820 :         int                     len;
      52             : 
      53             :         /* Directories don't need their parent encoded, they have ".." */
      54       31820 :         if (!parent)
      55             :                 fileid_type = FILEID_INO32_GEN;
      56             :         else
      57           0 :                 fileid_type = FILEID_INO32_GEN_PARENT;
      58             : 
      59             :         /*
      60             :          * If the filesystem may contain 64bit inode numbers, we need
      61             :          * to use larger file handles that can represent them.
      62             :          *
      63             :          * While we only allocate inodes that do not fit into 32 bits any
      64             :          * large enough filesystem may contain them, thus the slightly
      65             :          * confusing looking conditional below.
      66             :          */
      67       31820 :         if (!xfs_has_small_inums(mp) || xfs_is_inode32(mp))
      68       31820 :                 fileid_type |= XFS_FILEID_TYPE_64FLAG;
      69             : 
      70             :         /*
      71             :          * Only encode if there is enough space given.  In practice
      72             :          * this means we can't export a filesystem with 64bit inodes
      73             :          * over NFSv2 with the subtree_check export option; the other
      74             :          * seven combinations work.  The real answer is "don't use v2".
      75             :          */
      76       31820 :         len = xfs_fileid_length(fileid_type);
      77       31820 :         if (*max_len < len) {
      78           0 :                 *max_len = len;
      79           0 :                 return FILEID_INVALID;
      80             :         }
      81       31820 :         *max_len = len;
      82             : 
      83       31820 :         switch (fileid_type) {
      84             :         case FILEID_INO32_GEN_PARENT:
      85           0 :                 fid->i32.parent_ino = XFS_I(parent)->i_ino;
      86           0 :                 fid->i32.parent_gen = parent->i_generation;
      87           0 :                 fallthrough;
      88           0 :         case FILEID_INO32_GEN:
      89           0 :                 fid->i32.ino = XFS_I(inode)->i_ino;
      90           0 :                 fid->i32.gen = inode->i_generation;
      91           0 :                 break;
      92             :         case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
      93           0 :                 fid64->parent_ino = XFS_I(parent)->i_ino;
      94           0 :                 fid64->parent_gen = parent->i_generation;
      95       31820 :                 fallthrough;
      96       31820 :         case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
      97       31820 :                 fid64->ino = XFS_I(inode)->i_ino;
      98       31820 :                 fid64->gen = inode->i_generation;
      99       31820 :                 break;
     100             :         }
     101             : 
     102             :         return fileid_type;
     103             : }
     104             : 
     105             : STATIC struct inode *
     106   191525406 : xfs_nfs_get_inode(
     107             :         struct super_block      *sb,
     108             :         u64                     ino,
     109             :         u32                     generation)
     110             : {
     111   191525406 :         xfs_mount_t             *mp = XFS_M(sb);
     112   191525406 :         xfs_inode_t             *ip;
     113   191525406 :         int                     error;
     114             : 
     115             :         /*
     116             :          * NFS can sometimes send requests for ino 0.  Fail them gracefully.
     117             :          */
     118   191525406 :         if (ino == 0)
     119             :                 return ERR_PTR(-ESTALE);
     120             : 
     121             :         /*
     122             :          * The XFS_IGET_UNTRUSTED means that an invalid inode number is just
     123             :          * fine and not an indication of a corrupted filesystem as clients can
     124             :          * send invalid file handles and we have to handle it gracefully..
     125             :          */
     126   191527337 :         error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED, 0, &ip);
     127   191527493 :         if (error) {
     128             : 
     129             :                 /*
     130             :                  * EINVAL means the inode cluster doesn't exist anymore.
     131             :                  * EFSCORRUPTED means the metadata pointing to the inode cluster
     132             :                  * or the inode cluster itself is corrupt.  This implies the
     133             :                  * filehandle is stale, so we should translate it here.
     134             :                  * We don't use ESTALE directly down the chain to not
     135             :                  * confuse applications using bulkstat that expect EINVAL.
     136             :                  */
     137        4312 :                 switch (error) {
     138        4312 :                 case -EINVAL:
     139             :                 case -ENOENT:
     140             :                 case -EFSCORRUPTED:
     141        4312 :                         error = -ESTALE;
     142        4312 :                         break;
     143             :                 default:
     144             :                         break;
     145             :                 }
     146        4312 :                 return ERR_PTR(error);
     147             :         }
     148             : 
     149   191523181 :         if (VFS_I(ip)->i_generation != generation || IS_PRIVATE(VFS_I(ip))) {
     150          56 :                 xfs_irele(ip);
     151          56 :                 return ERR_PTR(-ESTALE);
     152             :         }
     153             : 
     154   191523125 :         return VFS_I(ip);
     155             : }
     156             : 
     157             : STATIC struct dentry *
     158   191525412 : xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
     159             :                  int fh_len, int fileid_type)
     160             : {
     161   191525412 :         struct xfs_fid64        *fid64 = (struct xfs_fid64 *)fid;
     162   191525412 :         struct inode            *inode = NULL;
     163             : 
     164   191525412 :         if (fh_len < xfs_fileid_length(fileid_type))
     165             :                 return NULL;
     166             : 
     167   191525412 :         switch (fileid_type) {
     168           0 :         case FILEID_INO32_GEN_PARENT:
     169             :         case FILEID_INO32_GEN:
     170           0 :                 inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen);
     171           0 :                 break;
     172   191525412 :         case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
     173             :         case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
     174   191525412 :                 inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen);
     175   191525412 :                 break;
     176             :         }
     177             : 
     178   191529828 :         return d_obtain_alias(inode);
     179             : }
     180             : 
     181             : STATIC struct dentry *
     182           0 : xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
     183             :                  int fh_len, int fileid_type)
     184             : {
     185           0 :         struct xfs_fid64        *fid64 = (struct xfs_fid64 *)fid;
     186           0 :         struct inode            *inode = NULL;
     187             : 
     188           0 :         if (fh_len < xfs_fileid_length(fileid_type))
     189             :                 return NULL;
     190             : 
     191           0 :         switch (fileid_type) {
     192           0 :         case FILEID_INO32_GEN_PARENT:
     193           0 :                 inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino,
     194             :                                               fid->i32.parent_gen);
     195           0 :                 break;
     196           0 :         case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
     197           0 :                 inode = xfs_nfs_get_inode(sb, fid64->parent_ino,
     198             :                                               fid64->parent_gen);
     199           0 :                 break;
     200             :         }
     201             : 
     202           0 :         return d_obtain_alias(inode);
     203             : }
     204             : 
     205             : STATIC struct dentry *
     206     2850711 : xfs_fs_get_parent(
     207             :         struct dentry           *child)
     208             : {
     209     2850711 :         int                     error;
     210     2850711 :         struct xfs_inode        *cip;
     211             : 
     212     2850711 :         error = xfs_lookup(XFS_I(d_inode(child)), &xfs_name_dotdot, &cip, NULL);
     213     2850727 :         if (unlikely(error))
     214           0 :                 return ERR_PTR(error);
     215             : 
     216     2850727 :         return d_obtain_alias(VFS_I(cip));
     217             : }
     218             : 
     219             : STATIC int
     220           0 : xfs_fs_nfs_commit_metadata(
     221             :         struct inode            *inode)
     222             : {
     223           0 :         return xfs_log_force_inode(XFS_I(inode));
     224             : }
     225             : 
     226             : const struct export_operations xfs_export_operations = {
     227             :         .encode_fh              = xfs_fs_encode_fh,
     228             :         .fh_to_dentry           = xfs_fs_fh_to_dentry,
     229             :         .fh_to_parent           = xfs_fs_fh_to_parent,
     230             :         .get_parent             = xfs_fs_get_parent,
     231             :         .commit_metadata        = xfs_fs_nfs_commit_metadata,
     232             : #ifdef CONFIG_EXPORTFS_BLOCK_OPS
     233             :         .get_uuid               = xfs_fs_get_uuid,
     234             :         .map_blocks             = xfs_fs_map_blocks,
     235             :         .commit_blocks          = xfs_fs_commit_blocks,
     236             : #endif
     237             : };

Generated by: LCOV version 1.14