2005-04-17 02:20:36 +04:00
/*
* Copyright ( c ) 2000 - 2001 Christoph Hellwig .
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions , and the following disclaimer ,
* without modification .
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* Alternatively , this software may be distributed under the terms of the
* GNU General Public License ( " GPL " ) .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ` ` AS IS ' ' AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*/
/*
* 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"
2006-12-07 07:33:20 +03:00
struct kmem_cache * vxfs_inode_cachep ;
2005-04-17 02:20:36 +04:00
# 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
/**
* 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 .
*/
struct vxfs_inode_info *
vxfs_blkiget ( struct super_block * sbp , u_long extent , ino_t ino )
{
struct buffer_head * bp ;
u_long block , offset ;
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 ) ) {
2005-04-17 02:20:36 +04:00
struct vxfs_inode_info * vip ;
struct vxfs_dinode * dip ;
2006-12-07 07:33:17 +03:00
if ( ! ( vip = kmem_cache_alloc ( vxfs_inode_cachep , GFP_KERNEL ) ) )
2005-04-17 02:20:36 +04:00
goto fail ;
dip = ( struct vxfs_dinode * ) ( bp - > b_data + offset ) ;
memcpy ( vip , dip , sizeof ( * vip ) ) ;
# ifdef DIAGNOSTIC
vxfs_dumpi ( vip , ino ) ;
# endif
brelse ( bp ) ;
return ( vip ) ;
}
fail :
printk ( KERN_WARNING " vxfs: unable to read block %ld \n " , block ) ;
brelse ( bp ) ;
return NULL ;
}
/**
* __vxfs_iget - generic find inode facility
* @ sbp : VFS superblock
* @ ino : inode number
* @ ilistp : inode list
*
* Description :
* Search the for inode number @ ino in the filesystem
* described by @ sbp . Use the specified inode table ( @ ilistp ) .
2008-02-07 11:15:39 +03:00
* Returns the matching VxFS inode on success , else an error code .
2005-04-17 02:20:36 +04:00
*/
static struct vxfs_inode_info *
__vxfs_iget ( ino_t ino , struct inode * ilistp )
{
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_inode_info * vip ;
struct vxfs_dinode * dip ;
caddr_t kaddr = ( char * ) page_address ( pp ) ;
2006-12-07 07:33:17 +03:00
if ( ! ( vip = kmem_cache_alloc ( vxfs_inode_cachep , GFP_KERNEL ) ) )
2005-04-17 02:20:36 +04:00
goto fail ;
dip = ( struct vxfs_dinode * ) ( kaddr + offset ) ;
memcpy ( vip , dip , sizeof ( * vip ) ) ;
# ifdef DIAGNOSTIC
vxfs_dumpi ( vip , ino ) ;
# endif
vxfs_put_page ( pp ) ;
return ( vip ) ;
}
printk ( KERN_WARNING " vxfs: error on page %p \n " , pp ) ;
2008-02-07 11:15:39 +03:00
return ERR_CAST ( pp ) ;
2005-04-17 02:20:36 +04:00
fail :
printk ( KERN_WARNING " vxfs: unable to read inode %ld \n " , ( unsigned long ) ino ) ;
vxfs_put_page ( pp ) ;
2008-02-07 11:15:39 +03:00
return ERR_PTR ( - ENOMEM ) ;
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 .
* Returns the matching VxFS inode on success , else a NULL pointer .
*/
struct vxfs_inode_info *
vxfs_stiget ( struct super_block * sbp , ino_t ino )
{
2008-02-07 11:15:39 +03:00
struct vxfs_inode_info * vip ;
vip = __vxfs_iget ( ino , VXFS_SBI ( sbp ) - > vsi_stilist ) ;
return IS_ERR ( vip ) ? NULL : vip ;
2005-04-17 02:20:36 +04: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 .
*/
2011-07-26 11:30:54 +04:00
static __inline__ umode_t
2005-04-17 02:20:36 +04:00
vxfs_transmod ( struct vxfs_inode_info * vip )
{
2011-07-26 11:30:54 +04:00
umode_t ret = vip - > vii_mode & ~ VXFS_TYPE_MASK ;
2005-04-17 02:20:36 +04:00
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 ) ;
}
/**
* vxfs_iinit - helper to fill inode fields
* @ ip : VFS inode
* @ vip : VxFS inode
*
* Description :
* vxfs_instino is a helper function to fill in all relevant
* fields in @ ip from @ vip .
*/
static void
vxfs_iinit ( struct inode * ip , struct vxfs_inode_info * vip )
{
ip - > i_mode = vxfs_transmod ( vip ) ;
2012-02-10 23:26:34 +04:00
i_uid_write ( ip , ( uid_t ) vip - > vii_uid ) ;
i_gid_write ( ip , ( gid_t ) vip - > vii_gid ) ;
2005-04-17 02:20:36 +04:00
2011-10-28 16:13:29 +04:00
set_nlink ( ip , vip - > vii_nlink ) ;
2005-04-17 02:20:36 +04:00
ip - > i_size = vip - > vii_size ;
ip - > i_atime . tv_sec = vip - > vii_atime ;
ip - > i_ctime . tv_sec = vip - > vii_ctime ;
ip - > i_mtime . tv_sec = vip - > vii_mtime ;
ip - > i_atime . tv_nsec = 0 ;
ip - > i_ctime . tv_nsec = 0 ;
ip - > i_mtime . tv_nsec = 0 ;
ip - > i_blocks = vip - > vii_blocks ;
ip - > i_generation = vip - > vii_gen ;
2006-09-27 12:50:46 +04:00
ip - > i_private = vip ;
2005-04-17 02:20:36 +04:00
}
/**
* vxfs_get_fake_inode - get fake inode structure
* @ sbp : filesystem superblock
* @ vip : fspriv inode
*
* Description :
* vxfs_fake_inode gets a fake inode ( not in the inode hash ) for a
* superblock , vxfs_inode pair .
* Returns the filled VFS inode .
*/
struct inode *
vxfs_get_fake_inode ( struct super_block * sbp , struct vxfs_inode_info * vip )
{
struct inode * ip = NULL ;
if ( ( ip = new_inode ( sbp ) ) ) {
2010-10-23 19:19:54 +04:00
ip - > i_ino = get_next_ino ( ) ;
2005-04-17 02:20:36 +04:00
vxfs_iinit ( ip , vip ) ;
ip - > i_mapping - > a_ops = & vxfs_aops ;
}
return ( ip ) ;
}
/**
* vxfs_put_fake_inode - free faked inode
* * ip : VFS inode
*
* Description :
2011-05-10 12:16:21 +04:00
* vxfs_put_fake_inode frees all data associated with @ ip .
2005-04-17 02:20:36 +04:00
*/
void
vxfs_put_fake_inode ( struct inode * ip )
{
iput ( ip ) ;
}
/**
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 ;
ip = iget_locked ( sbp , ino ) ;
if ( ! ip )
return ERR_PTR ( - ENOMEM ) ;
if ( ! ( ip - > i_state & I_NEW ) )
return ip ;
vip = __vxfs_iget ( ino , VXFS_SBI ( sbp ) - > vsi_ilist ) ;
if ( IS_ERR ( vip ) ) {
iget_failed ( ip ) ;
return ERR_CAST ( vip ) ;
}
2005-04-17 02:20:36 +04:00
vxfs_iinit ( ip , vip ) ;
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 ;
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
}
2011-01-07 09:49:49 +03:00
static void vxfs_i_callback ( struct rcu_head * head )
{
struct inode * inode = container_of ( head , struct inode , i_rcu ) ;
kmem_cache_free ( vxfs_inode_cachep , inode - > i_private ) ;
}
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 ) ;
2011-01-07 09:49:49 +03:00
call_rcu ( & ip - > i_rcu , vxfs_i_callback ) ;
2005-04-17 02:20:36 +04:00
}