2022-05-16 16:38:25 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2005-04-17 02:20:36 +04:00
/*
* Copyright ( c ) 2000 - 2001 Christoph Hellwig .
2016-06-01 10:25:12 +03:00
* Copyright ( c ) 2016 Krzysztof Blaszkowski
2005-04-17 02:20:36 +04:00
*/
/*
* Veritas filesystem driver - inode routines .
*/
# include <linux/fs.h>
# include <linux/buffer_head.h>
# include <linux/pagemap.h>
# include <linux/kernel.h>
# include <linux/slab.h>
2015-05-02 17:43:25 +03:00
# include <linux/namei.h>
2005-04-17 02:20:36 +04:00
# include "vxfs.h"
# include "vxfs_inode.h"
# include "vxfs_extern.h"
# ifdef DIAGNOSTIC
/*
* Dump inode contents ( partially ) .
*/
void
vxfs_dumpi ( struct vxfs_inode_info * vip , ino_t ino )
{
printk ( KERN_DEBUG " \n \n " ) ;
if ( ino )
printk ( KERN_DEBUG " dumping vxfs inode %ld \n " , ino ) ;
else
printk ( KERN_DEBUG " dumping unknown vxfs inode \n " ) ;
printk ( KERN_DEBUG " --------------------------- \n " ) ;
printk ( KERN_DEBUG " mode is %x \n " , vip - > vii_mode ) ;
printk ( KERN_DEBUG " nlink:%u, uid:%u, gid:%u \n " ,
vip - > vii_nlink , vip - > vii_uid , vip - > vii_gid ) ;
printk ( KERN_DEBUG " size:%Lx, blocks:%u \n " ,
vip - > vii_size , vip - > vii_blocks ) ;
printk ( KERN_DEBUG " orgtype:%u \n " , vip - > vii_orgtype ) ;
}
# endif
2016-06-01 09:44:45 +03:00
/**
* vxfs_transmod - mode for a VxFS inode
* @ vip : VxFS inode
*
* Description :
* vxfs_transmod returns a Linux mode_t for a given
* VxFS inode structure .
*/
static __inline__ umode_t
vxfs_transmod ( struct vxfs_inode_info * vip )
{
umode_t ret = vip - > vii_mode & ~ VXFS_TYPE_MASK ;
if ( VXFS_ISFIFO ( vip ) )
ret | = S_IFIFO ;
if ( VXFS_ISCHR ( vip ) )
ret | = S_IFCHR ;
if ( VXFS_ISDIR ( vip ) )
ret | = S_IFDIR ;
if ( VXFS_ISBLK ( vip ) )
ret | = S_IFBLK ;
if ( VXFS_ISLNK ( vip ) )
ret | = S_IFLNK ;
if ( VXFS_ISREG ( vip ) )
ret | = S_IFREG ;
if ( VXFS_ISSOC ( vip ) )
ret | = S_IFSOCK ;
return ( ret ) ;
}
2016-05-31 09:45:13 +03:00
static inline void dip2vip_cpy ( struct vxfs_sb_info * sbi ,
struct vxfs_inode_info * vip , struct vxfs_dinode * dip )
{
2016-06-01 09:44:45 +03:00
struct inode * inode = & vip - > vfs_inode ;
2016-05-31 09:45:13 +03:00
vip - > vii_mode = fs32_to_cpu ( sbi , dip - > vdi_mode ) ;
vip - > vii_nlink = fs32_to_cpu ( sbi , dip - > vdi_nlink ) ;
vip - > vii_uid = fs32_to_cpu ( sbi , dip - > vdi_uid ) ;
vip - > vii_gid = fs32_to_cpu ( sbi , dip - > vdi_gid ) ;
vip - > vii_size = fs64_to_cpu ( sbi , dip - > vdi_size ) ;
vip - > vii_atime = fs32_to_cpu ( sbi , dip - > vdi_atime ) ;
vip - > vii_autime = fs32_to_cpu ( sbi , dip - > vdi_autime ) ;
vip - > vii_mtime = fs32_to_cpu ( sbi , dip - > vdi_mtime ) ;
vip - > vii_mutime = fs32_to_cpu ( sbi , dip - > vdi_mutime ) ;
vip - > vii_ctime = fs32_to_cpu ( sbi , dip - > vdi_ctime ) ;
vip - > vii_cutime = fs32_to_cpu ( sbi , dip - > vdi_cutime ) ;
vip - > vii_orgtype = dip - > vdi_orgtype ;
vip - > vii_blocks = fs32_to_cpu ( sbi , dip - > vdi_blocks ) ;
vip - > vii_gen = fs32_to_cpu ( sbi , dip - > vdi_gen ) ;
if ( VXFS_ISDIR ( vip ) )
vip - > vii_dotdot = fs32_to_cpu ( sbi , dip - > vdi_dotdot ) ;
else if ( ! VXFS_ISREG ( vip ) & & ! VXFS_ISLNK ( vip ) )
vip - > vii_rdev = fs32_to_cpu ( sbi , dip - > vdi_rdev ) ;
/* don't endian swap the fields that differ by orgtype */
memcpy ( & vip - > vii_org , & dip - > vdi_org , sizeof ( vip - > vii_org ) ) ;
2016-06-01 09:44:45 +03:00
inode - > i_mode = vxfs_transmod ( vip ) ;
i_uid_write ( inode , ( uid_t ) vip - > vii_uid ) ;
i_gid_write ( inode , ( gid_t ) vip - > vii_gid ) ;
set_nlink ( inode , vip - > vii_nlink ) ;
inode - > i_size = vip - > vii_size ;
2023-10-04 21:52:23 +03:00
inode_set_atime ( inode , vip - > vii_atime , 0 ) ;
2023-07-05 22:01:10 +03:00
inode_set_ctime ( inode , vip - > vii_ctime , 0 ) ;
2023-10-04 21:52:23 +03:00
inode_set_mtime ( inode , vip - > vii_mtime , 0 ) ;
2016-06-01 09:44:45 +03:00
inode - > i_blocks = vip - > vii_blocks ;
inode - > i_generation = vip - > vii_gen ;
2016-05-31 09:45:13 +03:00
}
2005-04-17 02:20:36 +04:00
/**
* vxfs_blkiget - find inode based on extent #
* @ sbp : superblock of the filesystem we search in
* @ extent : number of the extent to search
* @ ino : inode number to search
*
* Description :
* vxfs_blkiget searches inode @ ino in the filesystem described by
* @ sbp in the extent @ extent .
* Returns the matching VxFS inode on success , else a NULL pointer .
*
* NOTE :
* While __vxfs_iget uses the pagecache vxfs_blkiget uses the
* buffercache . This function should not be used outside the
* read_super ( ) method , otherwise the data may be incoherent .
*/
2016-06-01 09:56:04 +03:00
struct inode *
2005-04-17 02:20:36 +04:00
vxfs_blkiget ( struct super_block * sbp , u_long extent , ino_t ino )
{
struct buffer_head * bp ;
2016-06-01 09:56:04 +03:00
struct inode * inode ;
2005-04-17 02:20:36 +04:00
u_long block , offset ;
2016-06-01 09:44:45 +03:00
inode = new_inode ( sbp ) ;
if ( ! inode )
return NULL ;
inode - > i_ino = get_next_ino ( ) ;
2005-04-17 02:20:36 +04:00
block = extent + ( ( ino * VXFS_ISIZE ) / sbp - > s_blocksize ) ;
offset = ( ( ino % ( sbp - > s_blocksize / VXFS_ISIZE ) ) * VXFS_ISIZE ) ;
bp = sb_bread ( sbp , block ) ;
2007-05-08 11:24:34 +04:00
if ( bp & & buffer_mapped ( bp ) ) {
2016-06-01 09:44:45 +03:00
struct vxfs_inode_info * vip = VXFS_INO ( inode ) ;
2005-04-17 02:20:36 +04:00
struct vxfs_dinode * dip ;
dip = ( struct vxfs_dinode * ) ( bp - > b_data + offset ) ;
2016-05-31 09:45:13 +03:00
dip2vip_cpy ( VXFS_SBI ( sbp ) , vip , dip ) ;
2016-06-01 09:44:45 +03:00
vip - > vfs_inode . i_mapping - > a_ops = & vxfs_aops ;
2005-04-17 02:20:36 +04:00
# ifdef DIAGNOSTIC
vxfs_dumpi ( vip , ino ) ;
# endif
brelse ( bp ) ;
2016-06-01 09:56:04 +03:00
return inode ;
2005-04-17 02:20:36 +04:00
}
printk ( KERN_WARNING " vxfs: unable to read block %ld \n " , block ) ;
brelse ( bp ) ;
2016-06-01 09:44:45 +03:00
iput ( inode ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
/**
* __vxfs_iget - generic find inode facility
* @ ilistp : inode list
2016-06-01 09:44:45 +03:00
* @ vip : VxFS inode to fill in
* @ ino : inode number
2005-04-17 02:20:36 +04:00
*
* Description :
* Search the for inode number @ ino in the filesystem
* described by @ sbp . Use the specified inode table ( @ ilistp ) .
2016-06-01 09:56:04 +03:00
* Returns the matching inode on success , else an error code .
2005-04-17 02:20:36 +04:00
*/
2016-06-01 09:44:45 +03:00
static int
__vxfs_iget ( struct inode * ilistp , struct vxfs_inode_info * vip , ino_t ino )
2005-04-17 02:20:36 +04:00
{
struct page * pp ;
u_long offset ;
offset = ( ino % ( PAGE_SIZE / VXFS_ISIZE ) ) * VXFS_ISIZE ;
pp = vxfs_get_page ( ilistp - > i_mapping , ino * VXFS_ISIZE / PAGE_SIZE ) ;
if ( ! IS_ERR ( pp ) ) {
struct vxfs_dinode * dip ;
caddr_t kaddr = ( char * ) page_address ( pp ) ;
dip = ( struct vxfs_dinode * ) ( kaddr + offset ) ;
2016-05-31 09:45:13 +03:00
dip2vip_cpy ( VXFS_SBI ( ilistp - > i_sb ) , vip , dip ) ;
2016-06-01 09:44:45 +03:00
vip - > vfs_inode . i_mapping - > a_ops = & vxfs_aops ;
2005-04-17 02:20:36 +04:00
# ifdef DIAGNOSTIC
vxfs_dumpi ( vip , ino ) ;
# endif
vxfs_put_page ( pp ) ;
2016-06-01 09:44:45 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2016-06-01 09:44:45 +03:00
printk ( KERN_WARNING " vxfs: error on page 0x%p for inode %ld \n " ,
pp , ( unsigned long ) ino ) ;
return PTR_ERR ( pp ) ;
2005-04-17 02:20:36 +04:00
}
/**
* vxfs_stiget - find inode using the structural inode list
* @ sbp : VFS superblock
* @ ino : inode #
*
* Description :
* Find inode @ ino in the filesystem described by @ sbp using
* the structural inode list .
2016-06-01 09:56:04 +03:00
* Returns the matching inode on success , else a NULL pointer .
2005-04-17 02:20:36 +04:00
*/
2016-06-01 09:56:04 +03:00
struct inode *
2005-04-17 02:20:36 +04:00
vxfs_stiget ( struct super_block * sbp , ino_t ino )
{
2016-06-01 09:56:04 +03:00
struct inode * inode ;
2016-06-01 09:44:45 +03:00
int error ;
2008-02-07 11:15:39 +03:00
2016-06-01 09:44:45 +03:00
inode = new_inode ( sbp ) ;
2016-06-01 09:56:04 +03:00
if ( ! inode )
2016-06-01 09:44:45 +03:00
return NULL ;
inode - > i_ino = get_next_ino ( ) ;
2005-04-17 02:20:36 +04:00
2016-06-01 09:44:45 +03:00
error = __vxfs_iget ( VXFS_SBI ( sbp ) - > vsi_stilist , VXFS_INO ( inode ) , ino ) ;
if ( error ) {
iput ( inode ) ;
return NULL ;
2005-04-17 02:20:36 +04:00
}
2016-06-01 09:44:45 +03:00
return inode ;
2005-04-17 02:20:36 +04:00
}
/**
2008-02-07 11:15:39 +03:00
* vxfs_iget - get an inode
* @ sbp : the superblock to get the inode for
* @ ino : the number of the inode to get
2005-04-17 02:20:36 +04:00
*
* Description :
2008-02-07 11:15:39 +03:00
* vxfs_read_inode creates an inode , reads the disk inode for @ ino and fills
* in all relevant fields in the new inode .
2005-04-17 02:20:36 +04:00
*/
2008-02-07 11:15:39 +03:00
struct inode *
vxfs_iget ( struct super_block * sbp , ino_t ino )
2005-04-17 02:20:36 +04:00
{
struct vxfs_inode_info * vip ;
2006-06-28 15:26:44 +04:00
const struct address_space_operations * aops ;
2008-02-07 11:15:39 +03:00
struct inode * ip ;
2016-06-01 09:44:45 +03:00
int error ;
2008-02-07 11:15:39 +03:00
ip = iget_locked ( sbp , ino ) ;
if ( ! ip )
return ERR_PTR ( - ENOMEM ) ;
if ( ! ( ip - > i_state & I_NEW ) )
return ip ;
2016-06-01 09:44:45 +03:00
vip = VXFS_INO ( ip ) ;
error = __vxfs_iget ( VXFS_SBI ( sbp ) - > vsi_ilist , vip , ino ) ;
if ( error ) {
2008-02-07 11:15:39 +03:00
iget_failed ( ip ) ;
2016-06-01 09:44:45 +03:00
return ERR_PTR ( error ) ;
2008-02-07 11:15:39 +03:00
}
2005-04-17 02:20:36 +04:00
if ( VXFS_ISIMMED ( vip ) )
aops = & vxfs_immed_aops ;
else
aops = & vxfs_aops ;
if ( S_ISREG ( ip - > i_mode ) ) {
2005-11-07 11:59:45 +03:00
ip - > i_fop = & generic_ro_fops ;
2005-04-17 02:20:36 +04:00
ip - > i_mapping - > a_ops = aops ;
} else if ( S_ISDIR ( ip - > i_mode ) ) {
ip - > i_op = & vxfs_dir_inode_ops ;
ip - > i_fop = & vxfs_dir_operations ;
ip - > i_mapping - > a_ops = aops ;
} else if ( S_ISLNK ( ip - > i_mode ) ) {
if ( ! VXFS_ISIMMED ( vip ) ) {
ip - > i_op = & page_symlink_inode_operations ;
2015-11-17 09:07:57 +03:00
inode_nohighmem ( ip ) ;
2005-04-17 02:20:36 +04:00
ip - > i_mapping - > a_ops = & vxfs_aops ;
2008-12-19 23:47:17 +03:00
} else {
2015-05-02 17:43:25 +03:00
ip - > i_op = & simple_symlink_inode_operations ;
ip - > i_link = vip - > vii_immed . vi_immed ;
nd_terminate_link ( ip - > i_link , ip - > i_size ,
sizeof ( vip - > vii_immed . vi_immed ) - 1 ) ;
2008-12-19 23:47:17 +03:00
}
2005-04-17 02:20:36 +04:00
} else
init_special_inode ( ip , ip - > i_mode , old_decode_dev ( vip - > vii_rdev ) ) ;
2008-02-07 11:15:39 +03:00
unlock_new_inode ( ip ) ;
return ip ;
2005-04-17 02:20:36 +04:00
}
/**
2010-06-07 22:34:48 +04:00
* vxfs_evict_inode - remove inode from main memory
2005-04-17 02:20:36 +04:00
* @ ip : inode to discard .
*
* Description :
2010-06-07 22:34:48 +04:00
* vxfs_evict_inode ( ) is called on the final iput and frees the private
2005-04-17 02:20:36 +04:00
* inode area .
*/
void
2010-06-07 22:34:48 +04:00
vxfs_evict_inode ( struct inode * ip )
2005-04-17 02:20:36 +04:00
{
2014-04-04 01:47:49 +04:00
truncate_inode_pages_final ( & ip - > i_data ) ;
2012-05-03 16:48:02 +04:00
clear_inode ( ip ) ;
2005-04-17 02:20:36 +04:00
}