2018-06-06 05:42:14 +03:00
// SPDX-License-Identifier: GPL-2.0
2013-08-12 14:49:35 +04:00
/*
* Copyright ( c ) 2000 - 2006 Silicon Graphics , Inc .
* All Rights Reserved .
*/
# include "xfs.h"
# include "xfs_fs.h"
2013-10-23 03:36:05 +04:00
# include "xfs_shared.h"
2013-10-23 03:50:10 +04:00
# include "xfs_format.h"
# include "xfs_log_format.h"
# include "xfs_trans_resv.h"
2013-08-12 14:49:35 +04:00
# include "xfs_mount.h"
# include "xfs_inode.h"
2017-10-31 22:04:49 +03:00
# include "xfs_errortag.h"
2013-08-12 14:49:35 +04:00
# include "xfs_error.h"
# include "xfs_icache.h"
2013-10-23 03:50:10 +04:00
# include "xfs_trans.h"
2013-10-23 03:51:50 +04:00
# include "xfs_ialloc.h"
2017-01-17 22:41:44 +03:00
# include "xfs_dir2.h"
2013-08-12 14:49:35 +04:00
2017-12-11 14:35:19 +03:00
# include <linux/iversion.h>
2013-08-12 14:49:35 +04:00
/*
* Check that none of the inode ' s in the buffer have a next
* unlinked field of 0.
*/
# if defined(DEBUG)
void
xfs_inobp_check (
xfs_mount_t * mp ,
xfs_buf_t * bp )
{
int i ;
xfs_dinode_t * dip ;
2019-06-05 21:19:36 +03:00
for ( i = 0 ; i < M_IGEO ( mp ) - > inodes_per_cluster ; i + + ) {
2015-06-22 02:44:29 +03:00
dip = xfs_buf_offset ( bp , i * mp - > m_sb . sb_inodesize ) ;
2013-08-12 14:49:35 +04:00
if ( ! dip - > di_next_unlinked ) {
xfs_alert ( mp ,
2013-09-03 15:47:38 +04:00
" Detected bogus zero next_unlinked field in inode %d buffer 0x%llx. " ,
i , ( long long ) bp - > b_bn ) ;
2013-08-12 14:49:35 +04:00
}
}
}
# endif
2013-08-27 05:39:37 +04:00
/*
* If we are doing readahead on an inode buffer , we might be in log recovery
* reading an inode allocation buffer that hasn ' t yet been replayed , and hence
* has not had the inode cores stamped into it . Hence for readahead , the buffer
* may be potentially invalid .
*
2016-01-11 23:03:44 +03:00
* If the readahead buffer is invalid , we need to mark it with an error and
* clear the DONE status of the buffer so that a followup read will re - read it
* from disk . We don ' t report the error otherwise to avoid warnings during log
* recovery and we don ' t get unnecssary panics on debug kernels . We use EIO here
* because all we want to do is say readahead failed ; there is no - one to report
* the error to , so this will distinguish it from a non - ra verifier failure .
2016-01-11 23:04:01 +03:00
* Changes to this readahead error behavour also need to be reflected in
* xfs_dquot_buf_readahead_verify ( ) .
2013-08-27 05:39:37 +04:00
*/
2013-08-12 14:49:35 +04:00
static void
xfs_inode_buf_verify (
2013-08-27 05:39:37 +04:00
struct xfs_buf * bp ,
bool readahead )
2013-08-12 14:49:35 +04:00
{
2019-06-29 05:27:29 +03:00
struct xfs_mount * mp = bp - > b_mount ;
2018-03-23 20:06:56 +03:00
xfs_agnumber_t agno ;
2013-08-12 14:49:35 +04:00
int i ;
int ni ;
/*
* Validate the magic number and version of every inode in the buffer
*/
2018-03-23 20:06:56 +03:00
agno = xfs_daddr_to_agno ( mp , XFS_BUF_ADDR ( bp ) ) ;
2013-08-12 14:49:35 +04:00
ni = XFS_BB_TO_FSB ( mp , bp - > b_length ) * mp - > m_sb . sb_inopblock ;
for ( i = 0 ; i < ni ; i + + ) {
int di_ok ;
xfs_dinode_t * dip ;
2018-03-23 20:06:56 +03:00
xfs_agino_t unlinked_ino ;
2013-08-12 14:49:35 +04:00
2015-06-22 02:44:29 +03:00
dip = xfs_buf_offset ( bp , ( i < < mp - > m_sb . sb_inodelog ) ) ;
2018-03-23 20:06:56 +03:00
unlinked_ino = be32_to_cpu ( dip - > di_next_unlinked ) ;
2019-02-16 22:47:28 +03:00
di_ok = xfs_verify_magic16 ( bp , dip - > di_magic ) & &
2020-03-18 18:15:09 +03:00
xfs_dinode_good_version ( & mp - > m_sb , dip - > di_version ) & &
2019-02-07 21:37:13 +03:00
xfs_verify_agino_or_null ( mp , agno , unlinked_ino ) ;
2013-08-12 14:49:35 +04:00
if ( unlikely ( XFS_TEST_ERROR ( ! di_ok , mp ,
2017-06-21 03:54:47 +03:00
XFS_ERRTAG_ITOBP_INOTOBP ) ) ) {
2013-08-27 05:39:37 +04:00
if ( readahead ) {
bp - > b_flags & = ~ XBF_DONE ;
2016-01-11 23:03:44 +03:00
xfs_buf_ioerror ( bp , - EIO ) ;
2013-08-27 05:39:37 +04:00
return ;
}
2013-08-12 14:49:35 +04:00
# ifdef DEBUG
2013-09-03 15:47:38 +04:00
xfs_alert ( mp ,
2013-08-12 14:49:35 +04:00
" bad inode magic/vsn daddr %lld #%d (magic=%x) " ,
( unsigned long long ) bp - > b_bn , i ,
be16_to_cpu ( dip - > di_magic ) ) ;
# endif
2018-03-23 20:06:53 +03:00
xfs_buf_verifier_error ( bp , - EFSCORRUPTED ,
__func__ , dip , sizeof ( * dip ) ,
NULL ) ;
2018-03-23 20:06:56 +03:00
return ;
2013-08-12 14:49:35 +04:00
}
}
}
static void
xfs_inode_buf_read_verify (
struct xfs_buf * bp )
{
2013-08-27 05:39:37 +04:00
xfs_inode_buf_verify ( bp , false ) ;
}
static void
xfs_inode_buf_readahead_verify (
struct xfs_buf * bp )
{
xfs_inode_buf_verify ( bp , true ) ;
2013-08-12 14:49:35 +04:00
}
static void
xfs_inode_buf_write_verify (
struct xfs_buf * bp )
{
2013-08-27 05:39:37 +04:00
xfs_inode_buf_verify ( bp , false ) ;
2013-08-12 14:49:35 +04:00
}
const struct xfs_buf_ops xfs_inode_buf_ops = {
2016-01-04 08:10:19 +03:00
. name = " xfs_inode " ,
2019-02-16 22:47:28 +03:00
. magic16 = { cpu_to_be16 ( XFS_DINODE_MAGIC ) ,
cpu_to_be16 ( XFS_DINODE_MAGIC ) } ,
2013-08-12 14:49:35 +04:00
. verify_read = xfs_inode_buf_read_verify ,
. verify_write = xfs_inode_buf_write_verify ,
} ;
2013-08-27 05:39:37 +04:00
const struct xfs_buf_ops xfs_inode_buf_ra_ops = {
2019-02-07 21:45:45 +03:00
. name = " xfs_inode_ra " ,
2019-02-16 22:47:28 +03:00
. magic16 = { cpu_to_be16 ( XFS_DINODE_MAGIC ) ,
cpu_to_be16 ( XFS_DINODE_MAGIC ) } ,
2013-08-27 05:39:37 +04:00
. verify_read = xfs_inode_buf_readahead_verify ,
. verify_write = xfs_inode_buf_write_verify ,
} ;
2013-08-12 14:49:35 +04:00
/*
* This routine is called to map an inode to the buffer containing the on - disk
* version of the inode . It returns a pointer to the buffer containing the
* on - disk inode in the bpp parameter , and in the dipp parameter it returns a
* pointer to the on - disk inode within that buffer .
*
* If a non - zero error is returned , then the contents of bpp and dipp are
* undefined .
*/
int
xfs_imap_to_bp (
struct xfs_mount * mp ,
struct xfs_trans * tp ,
struct xfs_imap * imap ,
struct xfs_dinode * * dipp ,
struct xfs_buf * * bpp ,
2020-05-06 23:29:20 +03:00
uint buf_flags )
2013-08-12 14:49:35 +04:00
{
struct xfs_buf * bp ;
int error ;
buf_flags | = XBF_UNMAPPED ;
error = xfs_trans_read_buf ( mp , tp , mp - > m_ddev_targp , imap - > im_blkno ,
( int ) imap - > im_len , buf_flags , & bp ,
& xfs_inode_buf_ops ) ;
if ( error ) {
2020-05-06 23:25:20 +03:00
ASSERT ( error ! = - EAGAIN | | ( buf_flags & XBF_TRYLOCK ) ) ;
2013-08-12 14:49:35 +04:00
return error ;
}
* bpp = bp ;
2015-06-22 02:44:29 +03:00
* dipp = xfs_buf_offset ( bp , imap - > im_boffset ) ;
2013-08-12 14:49:35 +04:00
return 0 ;
}
2020-05-15 00:00:02 +03:00
int
2016-02-09 08:54:58 +03:00
xfs_inode_from_disk (
struct xfs_inode * ip ,
2016-02-09 08:54:58 +03:00
struct xfs_dinode * from )
2013-08-12 14:49:35 +04:00
{
2016-02-09 08:54:58 +03:00
struct xfs_icdinode * to = & ip - > i_d ;
struct inode * inode = VFS_I ( ip ) ;
2020-05-15 00:01:17 +03:00
int error ;
2020-05-15 00:01:18 +03:00
xfs_failaddr_t fa ;
2020-05-15 00:01:17 +03:00
ASSERT ( ip - > i_cowfp = = NULL ) ;
ASSERT ( ip - > i_afp = = NULL ) ;
2016-02-09 08:54:58 +03:00
2020-05-15 00:01:18 +03:00
fa = xfs_dinode_verify ( ip - > i_mount , ip - > i_ino , from ) ;
if ( fa ) {
xfs_inode_verifier_error ( ip , - EFSCORRUPTED , " dinode " , from ,
sizeof ( * from ) , fa ) ;
return - EFSCORRUPTED ;
}
2020-05-15 00:01:17 +03:00
/*
* First get the permanent information that is needed to allocate an
* inode . If the inode is unused , mode is zero and we shouldn ' t mess
* with the unitialized part of it .
*/
to - > di_flushiter = be16_to_cpu ( from - > di_flushiter ) ;
inode - > i_generation = be32_to_cpu ( from - > di_gen ) ;
inode - > i_mode = be16_to_cpu ( from - > di_mode ) ;
if ( ! inode - > i_mode )
return 0 ;
2016-02-09 08:54:58 +03:00
/*
* Convert v1 inodes immediately to v2 inode format as this is the
* minimum inode version format we support in the rest of the code .
2020-03-18 18:15:11 +03:00
* They will also be unconditionally written back to disk as v2 inodes .
2016-02-09 08:54:58 +03:00
*/
2020-03-18 18:15:11 +03:00
if ( unlikely ( from - > di_version = = 1 ) ) {
2016-02-09 08:54:58 +03:00
set_nlink ( inode , be16_to_cpu ( from - > di_onlink ) ) ;
2019-11-12 19:22:54 +03:00
to - > di_projid = 0 ;
2016-02-09 08:54:58 +03:00
} else {
2016-02-09 08:54:58 +03:00
set_nlink ( inode , be32_to_cpu ( from - > di_nlink ) ) ;
2019-11-12 19:22:54 +03:00
to - > di_projid = ( prid_t ) be16_to_cpu ( from - > di_projid_hi ) < < 16 |
be16_to_cpu ( from - > di_projid_lo ) ;
2016-02-09 08:54:58 +03:00
}
2020-02-21 19:31:27 +03:00
i_uid_write ( inode , be32_to_cpu ( from - > di_uid ) ) ;
i_gid_write ( inode , be32_to_cpu ( from - > di_gid ) ) ;
2016-02-09 08:54:58 +03:00
/*
* Time is signed , so need to convert to signed 32 bit before
* storing in inode timestamp which may be 64 bit . Otherwise
* a time before epoch is converted to a time long after epoch
* on 64 bit systems .
*/
inode - > i_atime . tv_sec = ( int ) be32_to_cpu ( from - > di_atime . t_sec ) ;
inode - > i_atime . tv_nsec = ( int ) be32_to_cpu ( from - > di_atime . t_nsec ) ;
inode - > i_mtime . tv_sec = ( int ) be32_to_cpu ( from - > di_mtime . t_sec ) ;
inode - > i_mtime . tv_nsec = ( int ) be32_to_cpu ( from - > di_mtime . t_nsec ) ;
inode - > i_ctime . tv_sec = ( int ) be32_to_cpu ( from - > di_ctime . t_sec ) ;
inode - > i_ctime . tv_nsec = ( int ) be32_to_cpu ( from - > di_ctime . t_nsec ) ;
2013-08-12 14:49:35 +04:00
to - > di_size = be64_to_cpu ( from - > di_size ) ;
to - > di_nblocks = be64_to_cpu ( from - > di_nblocks ) ;
to - > di_extsize = be32_to_cpu ( from - > di_extsize ) ;
to - > di_forkoff = from - > di_forkoff ;
to - > di_dmevmask = be32_to_cpu ( from - > di_dmevmask ) ;
to - > di_dmstate = be16_to_cpu ( from - > di_dmstate ) ;
to - > di_flags = be16_to_cpu ( from - > di_flags ) ;
2020-03-18 18:15:11 +03:00
if ( xfs_sb_version_has_v3inode ( & ip - > i_mount - > m_sb ) ) {
2017-12-11 14:35:19 +03:00
inode_set_iversion_queried ( inode ,
be64_to_cpu ( from - > di_changecount ) ) ;
2019-11-12 19:20:42 +03:00
to - > di_crtime . tv_sec = be32_to_cpu ( from - > di_crtime . t_sec ) ;
to - > di_crtime . tv_nsec = be32_to_cpu ( from - > di_crtime . t_nsec ) ;
2013-08-12 14:49:35 +04:00
to - > di_flags2 = be64_to_cpu ( from - > di_flags2 ) ;
2016-10-03 19:11:43 +03:00
to - > di_cowextsize = be32_to_cpu ( from - > di_cowextsize ) ;
2013-08-12 14:49:35 +04:00
}
2020-05-15 00:00:02 +03:00
2020-05-15 00:01:17 +03:00
error = xfs_iformat_data_fork ( ip , from ) ;
if ( error )
return error ;
2020-05-18 20:27:21 +03:00
if ( from - > di_forkoff ) {
2020-05-15 00:01:17 +03:00
error = xfs_iformat_attr_fork ( ip , from ) ;
if ( error )
goto out_destroy_data_fork ;
}
if ( xfs_is_reflink_inode ( ip ) )
xfs_ifork_init_cow ( ip ) ;
return 0 ;
out_destroy_data_fork :
xfs_idestroy_fork ( ip , XFS_DATA_FORK ) ;
return error ;
2013-08-12 14:49:35 +04:00
}
void
2016-02-09 08:54:58 +03:00
xfs_inode_to_disk (
struct xfs_inode * ip ,
2016-02-09 08:54:58 +03:00
struct xfs_dinode * to ,
xfs_lsn_t lsn )
2016-02-09 08:54:58 +03:00
{
struct xfs_icdinode * from = & ip - > i_d ;
struct inode * inode = VFS_I ( ip ) ;
2016-02-09 08:54:58 +03:00
to - > di_magic = cpu_to_be16 ( XFS_DINODE_MAGIC ) ;
2016-02-09 08:54:58 +03:00
to - > di_onlink = 0 ;
2016-02-09 08:54:58 +03:00
2020-05-18 20:28:05 +03:00
to - > di_format = xfs_ifork_format ( & ip - > i_df ) ;
2020-02-21 19:31:27 +03:00
to - > di_uid = cpu_to_be32 ( i_uid_read ( inode ) ) ;
to - > di_gid = cpu_to_be32 ( i_gid_read ( inode ) ) ;
2019-11-12 19:22:54 +03:00
to - > di_projid_lo = cpu_to_be16 ( from - > di_projid & 0xffff ) ;
to - > di_projid_hi = cpu_to_be16 ( from - > di_projid > > 16 ) ;
2016-02-09 08:54:58 +03:00
2016-02-09 08:54:58 +03:00
memset ( to - > di_pad , 0 , sizeof ( to - > di_pad ) ) ;
2016-02-09 08:54:58 +03:00
to - > di_atime . t_sec = cpu_to_be32 ( inode - > i_atime . tv_sec ) ;
to - > di_atime . t_nsec = cpu_to_be32 ( inode - > i_atime . tv_nsec ) ;
to - > di_mtime . t_sec = cpu_to_be32 ( inode - > i_mtime . tv_sec ) ;
to - > di_mtime . t_nsec = cpu_to_be32 ( inode - > i_mtime . tv_nsec ) ;
to - > di_ctime . t_sec = cpu_to_be32 ( inode - > i_ctime . tv_sec ) ;
to - > di_ctime . t_nsec = cpu_to_be32 ( inode - > i_ctime . tv_nsec ) ;
2016-02-09 08:54:58 +03:00
to - > di_nlink = cpu_to_be32 ( inode - > i_nlink ) ;
2016-02-09 08:54:58 +03:00
to - > di_gen = cpu_to_be32 ( inode - > i_generation ) ;
2016-02-09 08:54:58 +03:00
to - > di_mode = cpu_to_be16 ( inode - > i_mode ) ;
2016-02-09 08:54:58 +03:00
to - > di_size = cpu_to_be64 ( from - > di_size ) ;
to - > di_nblocks = cpu_to_be64 ( from - > di_nblocks ) ;
to - > di_extsize = cpu_to_be32 ( from - > di_extsize ) ;
2020-05-18 20:27:22 +03:00
to - > di_nextents = cpu_to_be32 ( xfs_ifork_nextents ( & ip - > i_df ) ) ;
to - > di_anextents = cpu_to_be16 ( xfs_ifork_nextents ( ip - > i_afp ) ) ;
2016-02-09 08:54:58 +03:00
to - > di_forkoff = from - > di_forkoff ;
2020-05-18 20:28:05 +03:00
to - > di_aformat = xfs_ifork_format ( ip - > i_afp ) ;
2016-02-09 08:54:58 +03:00
to - > di_dmevmask = cpu_to_be32 ( from - > di_dmevmask ) ;
to - > di_dmstate = cpu_to_be16 ( from - > di_dmstate ) ;
to - > di_flags = cpu_to_be16 ( from - > di_flags ) ;
2020-03-18 18:15:11 +03:00
if ( xfs_sb_version_has_v3inode ( & ip - > i_mount - > m_sb ) ) {
to - > di_version = 3 ;
2017-12-11 14:35:19 +03:00
to - > di_changecount = cpu_to_be64 ( inode_peek_iversion ( inode ) ) ;
2019-11-12 19:20:42 +03:00
to - > di_crtime . t_sec = cpu_to_be32 ( from - > di_crtime . tv_sec ) ;
to - > di_crtime . t_nsec = cpu_to_be32 ( from - > di_crtime . tv_nsec ) ;
2016-02-09 08:54:58 +03:00
to - > di_flags2 = cpu_to_be64 ( from - > di_flags2 ) ;
2016-10-03 19:11:43 +03:00
to - > di_cowextsize = cpu_to_be32 ( from - > di_cowextsize ) ;
2016-02-09 08:54:58 +03:00
to - > di_ino = cpu_to_be64 ( ip - > i_ino ) ;
to - > di_lsn = cpu_to_be64 ( lsn ) ;
memset ( to - > di_pad2 , 0 , sizeof ( to - > di_pad2 ) ) ;
uuid_copy ( & to - > di_uuid , & ip - > i_mount - > m_sb . sb_meta_uuid ) ;
2016-02-09 08:54:58 +03:00
to - > di_flushiter = 0 ;
} else {
2020-03-18 18:15:11 +03:00
to - > di_version = 2 ;
2016-02-09 08:54:58 +03:00
to - > di_flushiter = cpu_to_be16 ( from - > di_flushiter ) ;
}
}
void
xfs_log_dinode_to_disk (
struct xfs_log_dinode * from ,
struct xfs_dinode * to )
2013-08-12 14:49:35 +04:00
{
to - > di_magic = cpu_to_be16 ( from - > di_magic ) ;
to - > di_mode = cpu_to_be16 ( from - > di_mode ) ;
2016-02-09 08:54:58 +03:00
to - > di_version = from - > di_version ;
2013-08-12 14:49:35 +04:00
to - > di_format = from - > di_format ;
2016-02-09 08:54:58 +03:00
to - > di_onlink = 0 ;
2013-08-12 14:49:35 +04:00
to - > di_uid = cpu_to_be32 ( from - > di_uid ) ;
to - > di_gid = cpu_to_be32 ( from - > di_gid ) ;
to - > di_nlink = cpu_to_be32 ( from - > di_nlink ) ;
to - > di_projid_lo = cpu_to_be16 ( from - > di_projid_lo ) ;
to - > di_projid_hi = cpu_to_be16 ( from - > di_projid_hi ) ;
memcpy ( to - > di_pad , from - > di_pad , sizeof ( to - > di_pad ) ) ;
2016-02-09 08:54:58 +03:00
2013-08-12 14:49:35 +04:00
to - > di_atime . t_sec = cpu_to_be32 ( from - > di_atime . t_sec ) ;
to - > di_atime . t_nsec = cpu_to_be32 ( from - > di_atime . t_nsec ) ;
to - > di_mtime . t_sec = cpu_to_be32 ( from - > di_mtime . t_sec ) ;
to - > di_mtime . t_nsec = cpu_to_be32 ( from - > di_mtime . t_nsec ) ;
to - > di_ctime . t_sec = cpu_to_be32 ( from - > di_ctime . t_sec ) ;
to - > di_ctime . t_nsec = cpu_to_be32 ( from - > di_ctime . t_nsec ) ;
2016-02-09 08:54:58 +03:00
2013-08-12 14:49:35 +04:00
to - > di_size = cpu_to_be64 ( from - > di_size ) ;
to - > di_nblocks = cpu_to_be64 ( from - > di_nblocks ) ;
to - > di_extsize = cpu_to_be32 ( from - > di_extsize ) ;
to - > di_nextents = cpu_to_be32 ( from - > di_nextents ) ;
to - > di_anextents = cpu_to_be16 ( from - > di_anextents ) ;
to - > di_forkoff = from - > di_forkoff ;
to - > di_aformat = from - > di_aformat ;
to - > di_dmevmask = cpu_to_be32 ( from - > di_dmevmask ) ;
to - > di_dmstate = cpu_to_be16 ( from - > di_dmstate ) ;
to - > di_flags = cpu_to_be16 ( from - > di_flags ) ;
to - > di_gen = cpu_to_be32 ( from - > di_gen ) ;
if ( from - > di_version = = 3 ) {
to - > di_changecount = cpu_to_be64 ( from - > di_changecount ) ;
to - > di_crtime . t_sec = cpu_to_be32 ( from - > di_crtime . t_sec ) ;
to - > di_crtime . t_nsec = cpu_to_be32 ( from - > di_crtime . t_nsec ) ;
to - > di_flags2 = cpu_to_be64 ( from - > di_flags2 ) ;
2016-10-03 19:11:43 +03:00
to - > di_cowextsize = cpu_to_be32 ( from - > di_cowextsize ) ;
2013-08-12 14:49:35 +04:00
to - > di_ino = cpu_to_be64 ( from - > di_ino ) ;
to - > di_lsn = cpu_to_be64 ( from - > di_lsn ) ;
memcpy ( to - > di_pad2 , from - > di_pad2 , sizeof ( to - > di_pad2 ) ) ;
uuid_copy ( & to - > di_uuid , & from - > di_uuid ) ;
to - > di_flushiter = 0 ;
} else {
to - > di_flushiter = cpu_to_be16 ( from - > di_flushiter ) ;
}
}
2018-06-22 09:25:57 +03:00
static xfs_failaddr_t
xfs_dinode_verify_fork (
struct xfs_dinode * dip ,
struct xfs_mount * mp ,
int whichfork )
{
uint32_t di_nextents = XFS_DFORK_NEXTENTS ( dip , whichfork ) ;
switch ( XFS_DFORK_FORMAT ( dip , whichfork ) ) {
case XFS_DINODE_FMT_LOCAL :
/*
* no local regular files yet
*/
if ( whichfork = = XFS_DATA_FORK ) {
if ( S_ISREG ( be16_to_cpu ( dip - > di_mode ) ) )
return __this_address ;
if ( be64_to_cpu ( dip - > di_size ) >
XFS_DFORK_SIZE ( dip , mp , whichfork ) )
return __this_address ;
}
if ( di_nextents )
return __this_address ;
break ;
case XFS_DINODE_FMT_EXTENTS :
if ( di_nextents > XFS_DFORK_MAXEXT ( dip , mp , whichfork ) )
return __this_address ;
break ;
case XFS_DINODE_FMT_BTREE :
if ( whichfork = = XFS_ATTR_FORK ) {
if ( di_nextents > MAXAEXTNUM )
return __this_address ;
} else if ( di_nextents > MAXEXTNUM ) {
return __this_address ;
}
break ;
default :
return __this_address ;
}
return NULL ;
}
2018-09-29 06:50:13 +03:00
static xfs_failaddr_t
xfs_dinode_verify_forkoff (
struct xfs_dinode * dip ,
struct xfs_mount * mp )
{
2020-05-18 20:27:21 +03:00
if ( ! dip - > di_forkoff )
2018-09-29 06:50:13 +03:00
return NULL ;
switch ( dip - > di_format ) {
case XFS_DINODE_FMT_DEV :
if ( dip - > di_forkoff ! = ( roundup ( sizeof ( xfs_dev_t ) , 8 ) > > 3 ) )
return __this_address ;
break ;
case XFS_DINODE_FMT_LOCAL : /* fall through ... */
case XFS_DINODE_FMT_EXTENTS : /* fall through ... */
case XFS_DINODE_FMT_BTREE :
2020-03-18 18:15:10 +03:00
if ( dip - > di_forkoff > = ( XFS_LITINO ( mp ) > > 3 ) )
2018-09-29 06:50:13 +03:00
return __this_address ;
break ;
default :
return __this_address ;
}
return NULL ;
}
2018-01-08 21:51:03 +03:00
xfs_failaddr_t
2013-08-12 14:49:35 +04:00
xfs_dinode_verify (
struct xfs_mount * mp ,
2016-11-08 03:56:06 +03:00
xfs_ino_t ino ,
2013-08-12 14:49:35 +04:00
struct xfs_dinode * dip )
{
2018-06-05 20:06:44 +03:00
xfs_failaddr_t fa ;
2017-01-17 22:41:41 +03:00
uint16_t mode ;
2016-10-03 19:11:50 +03:00
uint16_t flags ;
uint64_t flags2 ;
2018-01-08 21:51:04 +03:00
uint64_t di_size ;
2016-10-03 19:11:50 +03:00
2013-08-12 14:49:35 +04:00
if ( dip - > di_magic ! = cpu_to_be16 ( XFS_DINODE_MAGIC ) )
2018-01-08 21:51:03 +03:00
return __this_address ;
2013-08-12 14:49:35 +04:00
2018-01-08 21:51:04 +03:00
/* Verify v3 integrity information first */
if ( dip - > di_version > = 3 ) {
2020-03-18 18:15:09 +03:00
if ( ! xfs_sb_version_has_v3inode ( & mp - > m_sb ) )
2018-01-08 21:51:04 +03:00
return __this_address ;
if ( ! xfs_verify_cksum ( ( char * ) dip , mp - > m_sb . sb_inodesize ,
XFS_DINODE_CRC_OFF ) )
return __this_address ;
if ( be64_to_cpu ( dip - > di_ino ) ! = ino )
return __this_address ;
if ( ! uuid_equal ( & dip - > di_uuid , & mp - > m_sb . sb_meta_uuid ) )
return __this_address ;
}
2013-08-12 14:49:35 +04:00
2016-12-05 04:38:38 +03:00
/* don't allow invalid i_size */
2018-01-08 21:51:04 +03:00
di_size = be64_to_cpu ( dip - > di_size ) ;
if ( di_size & ( 1ULL < < 63 ) )
2018-01-08 21:51:03 +03:00
return __this_address ;
2016-12-05 04:38:38 +03:00
2017-01-17 22:41:41 +03:00
mode = be16_to_cpu ( dip - > di_mode ) ;
2017-01-17 22:41:44 +03:00
if ( mode & & xfs_mode_to_ftype ( mode ) = = XFS_DIR3_FT_UNKNOWN )
2018-01-08 21:51:03 +03:00
return __this_address ;
2017-01-17 22:41:41 +03:00
/* No zero-length symlinks/dirs. */
2018-01-08 21:51:04 +03:00
if ( ( S_ISLNK ( mode ) | | S_ISDIR ( mode ) ) & & di_size = = 0 )
2018-01-08 21:51:03 +03:00
return __this_address ;
2016-12-05 04:38:38 +03:00
2018-01-08 21:51:04 +03:00
/* Fork checks carried over from xfs_iformat_fork */
if ( mode & &
be32_to_cpu ( dip - > di_nextents ) + be16_to_cpu ( dip - > di_anextents ) >
be64_to_cpu ( dip - > di_nblocks ) )
return __this_address ;
if ( mode & & XFS_DFORK_BOFF ( dip ) > mp - > m_sb . sb_inodesize )
return __this_address ;
flags = be16_to_cpu ( dip - > di_flags ) ;
if ( mode & & ( flags & XFS_DIFLAG_REALTIME ) & & ! mp - > m_rtdev_targp )
return __this_address ;
2018-09-29 06:50:13 +03:00
/* check for illegal values of forkoff */
fa = xfs_dinode_verify_forkoff ( dip , mp ) ;
if ( fa )
return fa ;
2018-01-08 21:51:04 +03:00
/* Do we have appropriate data fork formats for the mode? */
switch ( mode & S_IFMT ) {
case S_IFIFO :
case S_IFCHR :
case S_IFBLK :
case S_IFSOCK :
if ( dip - > di_format ! = XFS_DINODE_FMT_DEV )
return __this_address ;
break ;
case S_IFREG :
case S_IFLNK :
case S_IFDIR :
2018-06-22 09:25:57 +03:00
fa = xfs_dinode_verify_fork ( dip , mp , XFS_DATA_FORK ) ;
if ( fa )
return fa ;
2018-01-08 21:51:04 +03:00
break ;
case 0 :
/* Uninitialized inode ok. */
break ;
default :
return __this_address ;
}
2020-05-18 20:27:21 +03:00
if ( dip - > di_forkoff ) {
2018-06-22 09:25:57 +03:00
fa = xfs_dinode_verify_fork ( dip , mp , XFS_ATTR_FORK ) ;
if ( fa )
return fa ;
2018-04-17 09:06:53 +03:00
} else {
/*
* If there is no fork offset , this may be a freshly - made inode
* in a new disk cluster , in which case di_aformat is zeroed .
* Otherwise , such an inode must be in EXTENTS format ; this goes
* for freed inodes as well .
*/
switch ( dip - > di_aformat ) {
case 0 :
case XFS_DINODE_FMT_EXTENTS :
break ;
default :
return __this_address ;
}
if ( dip - > di_anextents )
return __this_address ;
2018-01-08 21:51:04 +03:00
}
2016-12-05 04:38:38 +03:00
2018-06-05 20:06:44 +03:00
/* extent size hint validation */
fa = xfs_inode_validate_extsize ( mp , be32_to_cpu ( dip - > di_extsize ) ,
mode , flags ) ;
if ( fa )
return fa ;
2013-08-12 14:49:35 +04:00
/* only version 3 or greater inodes are extensively verified here */
if ( dip - > di_version < 3 )
2018-01-08 21:51:03 +03:00
return NULL ;
2016-10-03 19:11:50 +03:00
flags2 = be64_to_cpu ( dip - > di_flags2 ) ;
/* don't allow reflink/cowextsize if we don't have reflink */
if ( ( flags2 & ( XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE ) ) & &
2018-06-05 20:06:44 +03:00
! xfs_sb_version_hasreflink ( & mp - > m_sb ) )
2018-01-08 21:51:03 +03:00
return __this_address ;
2016-10-03 19:11:50 +03:00
2018-01-08 21:51:04 +03:00
/* only regular files get reflink */
if ( ( flags2 & XFS_DIFLAG2_REFLINK ) & & ( mode & S_IFMT ) ! = S_IFREG )
return __this_address ;
2016-10-03 19:11:50 +03:00
/* don't let reflink and realtime mix */
if ( ( flags2 & XFS_DIFLAG2_REFLINK ) & & ( flags & XFS_DIFLAG_REALTIME ) )
2018-01-08 21:51:03 +03:00
return __this_address ;
2016-10-03 19:11:50 +03:00
2016-10-03 19:11:50 +03:00
/* don't let reflink and dax mix */
if ( ( flags2 & XFS_DIFLAG2_REFLINK ) & & ( flags2 & XFS_DIFLAG2_DAX ) )
2018-01-08 21:51:03 +03:00
return __this_address ;
2016-10-03 19:11:50 +03:00
2018-06-05 20:09:33 +03:00
/* COW extent size hint validation */
fa = xfs_inode_validate_cowextsize ( mp , be32_to_cpu ( dip - > di_cowextsize ) ,
mode , flags , flags2 ) ;
if ( fa )
return fa ;
2018-01-08 21:51:03 +03:00
return NULL ;
2013-08-12 14:49:35 +04:00
}
void
xfs_dinode_calc_crc (
struct xfs_mount * mp ,
struct xfs_dinode * dip )
{
2017-06-16 21:00:05 +03:00
uint32_t crc ;
2013-08-12 14:49:35 +04:00
if ( dip - > di_version < 3 )
return ;
ASSERT ( xfs_sb_version_hascrc ( & mp - > m_sb ) ) ;
2016-12-05 06:40:32 +03:00
crc = xfs_start_cksum_update ( ( char * ) dip , mp - > m_sb . sb_inodesize ,
2014-02-27 08:15:27 +04:00
XFS_DINODE_CRC_OFF ) ;
2013-08-12 14:49:35 +04:00
dip - > di_crc = xfs_end_cksum ( crc ) ;
}
2018-03-23 20:06:55 +03:00
/*
* Validate di_extsize hint .
*
* The rules are documented at xfs_ioctl_setattr_check_extsize ( ) .
* These functions must be kept in sync with each other .
*/
xfs_failaddr_t
xfs_inode_validate_extsize (
struct xfs_mount * mp ,
uint32_t extsize ,
uint16_t mode ,
uint16_t flags )
{
bool rt_flag ;
bool hint_flag ;
bool inherit_flag ;
uint32_t extsize_bytes ;
uint32_t blocksize_bytes ;
rt_flag = ( flags & XFS_DIFLAG_REALTIME ) ;
hint_flag = ( flags & XFS_DIFLAG_EXTSIZE ) ;
inherit_flag = ( flags & XFS_DIFLAG_EXTSZINHERIT ) ;
extsize_bytes = XFS_FSB_TO_B ( mp , extsize ) ;
if ( rt_flag )
blocksize_bytes = mp - > m_sb . sb_rextsize < < mp - > m_sb . sb_blocklog ;
else
blocksize_bytes = mp - > m_sb . sb_blocksize ;
if ( ( hint_flag | | inherit_flag ) & & ! ( S_ISDIR ( mode ) | | S_ISREG ( mode ) ) )
return __this_address ;
if ( hint_flag & & ! S_ISREG ( mode ) )
return __this_address ;
if ( inherit_flag & & ! S_ISDIR ( mode ) )
return __this_address ;
if ( ( hint_flag | | inherit_flag ) & & extsize = = 0 )
return __this_address ;
2018-07-24 21:34:52 +03:00
/* free inodes get flags set to zero but extsize remains */
if ( mode & & ! ( hint_flag | | inherit_flag ) & & extsize ! = 0 )
2018-03-23 20:06:55 +03:00
return __this_address ;
if ( extsize_bytes % blocksize_bytes )
return __this_address ;
if ( extsize > MAXEXTLEN )
return __this_address ;
if ( ! rt_flag & & extsize > mp - > m_sb . sb_agblocks / 2 )
return __this_address ;
return NULL ;
}
/*
* Validate di_cowextsize hint .
*
* The rules are documented at xfs_ioctl_setattr_check_cowextsize ( ) .
* These functions must be kept in sync with each other .
*/
xfs_failaddr_t
xfs_inode_validate_cowextsize (
struct xfs_mount * mp ,
uint32_t cowextsize ,
uint16_t mode ,
uint16_t flags ,
uint64_t flags2 )
{
bool rt_flag ;
bool hint_flag ;
uint32_t cowextsize_bytes ;
rt_flag = ( flags & XFS_DIFLAG_REALTIME ) ;
hint_flag = ( flags2 & XFS_DIFLAG2_COWEXTSIZE ) ;
cowextsize_bytes = XFS_FSB_TO_B ( mp , cowextsize ) ;
if ( hint_flag & & ! xfs_sb_version_hasreflink ( & mp - > m_sb ) )
return __this_address ;
if ( hint_flag & & ! ( S_ISDIR ( mode ) | | S_ISREG ( mode ) ) )
return __this_address ;
if ( hint_flag & & cowextsize = = 0 )
return __this_address ;
2018-07-24 21:34:52 +03:00
/* free inodes get flags set to zero but cowextsize remains */
if ( mode & & ! hint_flag & & cowextsize ! = 0 )
2018-03-23 20:06:55 +03:00
return __this_address ;
if ( hint_flag & & rt_flag )
return __this_address ;
if ( cowextsize_bytes % mp - > m_sb . sb_blocksize )
return __this_address ;
if ( cowextsize > MAXEXTLEN )
return __this_address ;
if ( cowextsize > mp - > m_sb . sb_agblocks / 2 )
return __this_address ;
return NULL ;
}