252 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 allow22 * the parent generation number to default to zero. XFS considers zero a23 * valid generation number not an invalid/wildcard value.24 */25static int xfs_fileid_length(int fileid_type)26{27 switch (fileid_type) {28 case FILEID_INO32_GEN:29 return 2;30 case FILEID_INO32_GEN_PARENT:31 return 4;32 case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:33 return 3;34 case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:35 return 6;36 }37 return FILEID_INVALID;38}39 40STATIC int41xfs_fs_encode_fh(42 struct inode *inode,43 __u32 *fh,44 int *max_len,45 struct inode *parent)46{47 struct xfs_mount *mp = XFS_M(inode->i_sb);48 struct fid *fid = (struct fid *)fh;49 struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fh;50 int fileid_type;51 int len;52 53 /* Directories don't need their parent encoded, they have ".." */54 if (!parent)55 fileid_type = FILEID_INO32_GEN;56 else57 fileid_type = FILEID_INO32_GEN_PARENT;58 59 /*60 * If the filesystem may contain 64bit inode numbers, we need61 * to use larger file handles that can represent them.62 *63 * While we only allocate inodes that do not fit into 32 bits any64 * large enough filesystem may contain them, thus the slightly65 * confusing looking conditional below.66 */67 if (!xfs_has_small_inums(mp) || xfs_is_inode32(mp))68 fileid_type |= XFS_FILEID_TYPE_64FLAG;69 70 /*71 * Only encode if there is enough space given. In practice72 * this means we can't export a filesystem with 64bit inodes73 * over NFSv2 with the subtree_check export option; the other74 * seven combinations work. The real answer is "don't use v2".75 */76 len = xfs_fileid_length(fileid_type);77 if (*max_len < len) {78 *max_len = len;79 return FILEID_INVALID;80 }81 *max_len = len;82 83 switch (fileid_type) {84 case FILEID_INO32_GEN_PARENT:85 fid->i32.parent_ino = XFS_I(parent)->i_ino;86 fid->i32.parent_gen = parent->i_generation;87 fallthrough;88 case FILEID_INO32_GEN:89 fid->i32.ino = XFS_I(inode)->i_ino;90 fid->i32.gen = inode->i_generation;91 break;92 case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:93 fid64->parent_ino = XFS_I(parent)->i_ino;94 fid64->parent_gen = parent->i_generation;95 fallthrough;96 case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:97 fid64->ino = XFS_I(inode)->i_ino;98 fid64->gen = inode->i_generation;99 break;100 }101 102 return fileid_type;103}104 105struct inode *106xfs_nfs_get_inode(107 struct super_block *sb,108 u64 ino,109 u32 generation)110{111 xfs_mount_t *mp = XFS_M(sb);112 xfs_inode_t *ip;113 int error;114 115 /*116 * NFS can sometimes send requests for ino 0. Fail them gracefully.117 */118 if (ino == 0)119 return ERR_PTR(-ESTALE);120 121 /*122 * The XFS_IGET_UNTRUSTED means that an invalid inode number is just123 * fine and not an indication of a corrupted filesystem as clients can124 * send invalid file handles and we have to handle it gracefully..125 */126 error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED, 0, &ip);127 if (error) {128 129 /*130 * EINVAL means the inode cluster doesn't exist anymore.131 * EFSCORRUPTED means the metadata pointing to the inode cluster132 * or the inode cluster itself is corrupt. This implies the133 * filehandle is stale, so we should translate it here.134 * We don't use ESTALE directly down the chain to not135 * confuse applications using bulkstat that expect EINVAL.136 */137 switch (error) {138 case -EINVAL:139 case -ENOENT:140 case -EFSCORRUPTED:141 error = -ESTALE;142 break;143 default:144 break;145 }146 return ERR_PTR(error);147 }148 149 /*150 * Reload the incore unlinked list to avoid failure in inodegc.151 * Use an unlocked check here because unrecovered unlinked inodes152 * should be somewhat rare.153 */154 if (xfs_inode_unlinked_incomplete(ip)) {155 error = xfs_inode_reload_unlinked(ip);156 if (error) {157 xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);158 xfs_irele(ip);159 return ERR_PTR(error);160 }161 }162 163 if (VFS_I(ip)->i_generation != generation || IS_PRIVATE(VFS_I(ip))) {164 xfs_irele(ip);165 return ERR_PTR(-ESTALE);166 }167 168 return VFS_I(ip);169}170 171STATIC struct dentry *172xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,173 int fh_len, int fileid_type)174{175 struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid;176 struct inode *inode = NULL;177 178 if (fh_len < xfs_fileid_length(fileid_type))179 return NULL;180 181 switch (fileid_type) {182 case FILEID_INO32_GEN_PARENT:183 case FILEID_INO32_GEN:184 inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen);185 break;186 case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:187 case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:188 inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen);189 break;190 }191 192 return d_obtain_alias(inode);193}194 195STATIC struct dentry *196xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,197 int fh_len, int fileid_type)198{199 struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid;200 struct inode *inode = NULL;201 202 if (fh_len < xfs_fileid_length(fileid_type))203 return NULL;204 205 switch (fileid_type) {206 case FILEID_INO32_GEN_PARENT:207 inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino,208 fid->i32.parent_gen);209 break;210 case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:211 inode = xfs_nfs_get_inode(sb, fid64->parent_ino,212 fid64->parent_gen);213 break;214 }215 216 return d_obtain_alias(inode);217}218 219STATIC struct dentry *220xfs_fs_get_parent(221 struct dentry *child)222{223 int error;224 struct xfs_inode *cip;225 226 error = xfs_lookup(XFS_I(d_inode(child)), &xfs_name_dotdot, &cip, NULL);227 if (unlikely(error))228 return ERR_PTR(error);229 230 return d_obtain_alias(VFS_I(cip));231}232 233STATIC int234xfs_fs_nfs_commit_metadata(235 struct inode *inode)236{237 return xfs_log_force_inode(XFS_I(inode));238}239 240const struct export_operations xfs_export_operations = {241 .encode_fh = xfs_fs_encode_fh,242 .fh_to_dentry = xfs_fs_fh_to_dentry,243 .fh_to_parent = xfs_fs_fh_to_parent,244 .get_parent = xfs_fs_get_parent,245 .commit_metadata = xfs_fs_nfs_commit_metadata,246#ifdef CONFIG_EXPORTFS_BLOCK_OPS247 .get_uuid = xfs_fs_get_uuid,248 .map_blocks = xfs_fs_map_blocks,249 .commit_blocks = xfs_fs_commit_blocks,250#endif251};252