2005-04-17 02:20:36 +04:00
/*
* linux / fs / sysv / inode . c
*
* minix / inode . c
* Copyright ( C ) 1991 , 1992 Linus Torvalds
*
* xenix / inode . c
* Copyright ( C ) 1992 Doug Evans
*
* coh / inode . c
* Copyright ( C ) 1993 Pascal Haible , Bruno Haible
*
* sysv / inode . c
* Copyright ( C ) 1993 Paul B . Monday
*
* sysv / inode . c
* Copyright ( C ) 1993 Bruno Haible
* Copyright ( C ) 1997 , 1998 Krzysztof G . Baranowski
*
* This file contains code for allocating / freeing inodes and for read / writing
* the superblock .
*/
# include <linux/highuid.h>
# include <linux/slab.h>
# include <linux/init.h>
# include <linux/buffer_head.h>
# include <linux/vfs.h>
2010-03-05 11:21:37 +03:00
# include <linux/writeback.h>
2008-12-19 23:47:16 +03:00
# include <linux/namei.h>
2005-04-17 02:20:36 +04:00
# include <asm/byteorder.h>
# include "sysv.h"
2009-06-08 12:07:45 +04:00
static int sysv_sync_fs ( struct super_block * sb , int wait )
2005-04-17 02:20:36 +04:00
{
struct sysv_sb_info * sbi = SYSV_SB ( sb ) ;
unsigned long time = get_seconds ( ) , old_time ;
2012-10-06 14:41:46 +04:00
mutex_lock ( & sbi - > s_lock ) ;
2005-04-17 02:20:36 +04:00
/*
* If we are going to write out the super block ,
* then attach current time stamp .
* But if the filesystem was marked clean , keep it clean .
*/
old_time = fs32_to_cpu ( sbi , * sbi - > s_sb_time ) ;
if ( sbi - > s_type = = FSTYPE_SYSV4 ) {
if ( * sbi - > s_sb_state = = cpu_to_fs32 ( sbi , 0x7c269d38 - old_time ) )
* sbi - > s_sb_state = cpu_to_fs32 ( sbi , 0x7c269d38 - time ) ;
* sbi - > s_sb_time = cpu_to_fs32 ( sbi , time ) ;
mark_buffer_dirty ( sbi - > s_bh2 ) ;
}
2009-06-08 12:07:45 +04:00
2012-10-06 14:41:46 +04:00
mutex_unlock ( & sbi - > s_lock ) ;
2009-06-08 12:07:45 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
static int sysv_remount ( struct super_block * sb , int * flags , char * data )
{
struct sysv_sb_info * sbi = SYSV_SB ( sb ) ;
2012-07-03 17:43:27 +04:00
2014-03-13 18:14:33 +04:00
sync_filesystem ( sb ) ;
2005-04-17 02:20:36 +04:00
if ( sbi - > s_forced_ro )
* flags | = MS_RDONLY ;
return 0 ;
}
static void sysv_put_super ( struct super_block * sb )
{
struct sysv_sb_info * sbi = SYSV_SB ( sb ) ;
2017-07-17 10:45:34 +03:00
if ( ! sb_rdonly ( sb ) ) {
2005-04-17 02:20:36 +04:00
/* XXX ext2 also updates the state here */
mark_buffer_dirty ( sbi - > s_bh1 ) ;
if ( sbi - > s_bh1 ! = sbi - > s_bh2 )
mark_buffer_dirty ( sbi - > s_bh2 ) ;
}
brelse ( sbi - > s_bh1 ) ;
if ( sbi - > s_bh1 ! = sbi - > s_bh2 )
brelse ( sbi - > s_bh2 ) ;
kfree ( sbi ) ;
}
2006-06-23 13:02:58 +04:00
static int sysv_statfs ( struct dentry * dentry , struct kstatfs * buf )
2005-04-17 02:20:36 +04:00
{
2006-06-23 13:02:58 +04:00
struct super_block * sb = dentry - > d_sb ;
2005-04-17 02:20:36 +04:00
struct sysv_sb_info * sbi = SYSV_SB ( sb ) ;
2009-04-03 03:59:43 +04:00
u64 id = huge_encode_dev ( sb - > s_bdev - > bd_dev ) ;
2005-04-17 02:20:36 +04:00
buf - > f_type = sb - > s_magic ;
buf - > f_bsize = sb - > s_blocksize ;
buf - > f_blocks = sbi - > s_ndatazones ;
buf - > f_bavail = buf - > f_bfree = sysv_count_free_blocks ( sb ) ;
buf - > f_files = sbi - > s_ninodes ;
buf - > f_ffree = sysv_count_free_inodes ( sb ) ;
buf - > f_namelen = SYSV_NAMELEN ;
2009-04-03 03:59:43 +04:00
buf - > f_fsid . val [ 0 ] = ( u32 ) id ;
buf - > f_fsid . val [ 1 ] = ( u32 ) ( id > > 32 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* NXI < - > N0XI for PDP , XIN < - > XIN0 for le32 , NIX < - > 0 NIX for be32
*/
static inline void read3byte ( struct sysv_sb_info * sbi ,
unsigned char * from , unsigned char * to )
{
if ( sbi - > s_bytesex = = BYTESEX_PDP ) {
to [ 0 ] = from [ 0 ] ;
to [ 1 ] = 0 ;
to [ 2 ] = from [ 1 ] ;
to [ 3 ] = from [ 2 ] ;
} else if ( sbi - > s_bytesex = = BYTESEX_LE ) {
to [ 0 ] = from [ 0 ] ;
to [ 1 ] = from [ 1 ] ;
to [ 2 ] = from [ 2 ] ;
to [ 3 ] = 0 ;
} else {
to [ 0 ] = 0 ;
to [ 1 ] = from [ 0 ] ;
to [ 2 ] = from [ 1 ] ;
to [ 3 ] = from [ 2 ] ;
}
}
static inline void write3byte ( struct sysv_sb_info * sbi ,
unsigned char * from , unsigned char * to )
{
if ( sbi - > s_bytesex = = BYTESEX_PDP ) {
to [ 0 ] = from [ 0 ] ;
to [ 1 ] = from [ 2 ] ;
to [ 2 ] = from [ 3 ] ;
} else if ( sbi - > s_bytesex = = BYTESEX_LE ) {
to [ 0 ] = from [ 0 ] ;
to [ 1 ] = from [ 1 ] ;
to [ 2 ] = from [ 2 ] ;
} else {
to [ 0 ] = from [ 1 ] ;
to [ 1 ] = from [ 2 ] ;
to [ 2 ] = from [ 3 ] ;
}
}
2007-02-12 11:55:40 +03:00
static const struct inode_operations sysv_symlink_inode_operations = {
2015-11-17 18:20:54 +03:00
. get_link = page_get_link ,
2005-04-17 02:20:36 +04:00
. getattr = sysv_getattr ,
} ;
void sysv_set_inode ( struct inode * inode , dev_t rdev )
{
if ( S_ISREG ( inode - > i_mode ) ) {
inode - > i_op = & sysv_file_inode_operations ;
inode - > i_fop = & sysv_file_operations ;
inode - > i_mapping - > a_ops = & sysv_aops ;
} else if ( S_ISDIR ( inode - > i_mode ) ) {
inode - > i_op = & sysv_dir_inode_operations ;
inode - > i_fop = & sysv_dir_operations ;
inode - > i_mapping - > a_ops = & sysv_aops ;
} else if ( S_ISLNK ( inode - > i_mode ) ) {
2015-11-24 05:11:08 +03:00
inode - > i_op = & sysv_symlink_inode_operations ;
2015-11-17 09:07:57 +03:00
inode_nohighmem ( inode ) ;
2015-11-24 05:11:08 +03:00
inode - > i_mapping - > a_ops = & sysv_aops ;
2005-04-17 02:20:36 +04:00
} else
init_special_inode ( inode , inode - > i_mode , rdev ) ;
}
2008-02-07 11:15:47 +03:00
struct inode * sysv_iget ( struct super_block * sb , unsigned int ino )
2005-04-17 02:20:36 +04:00
{
struct sysv_sb_info * sbi = SYSV_SB ( sb ) ;
struct buffer_head * bh ;
struct sysv_inode * raw_inode ;
struct sysv_inode_info * si ;
2008-02-07 11:15:47 +03:00
struct inode * inode ;
unsigned int block ;
2005-04-17 02:20:36 +04:00
if ( ! ino | | ino > sbi - > s_ninodes ) {
printk ( " Bad inode number on dev %s: %d is out of range \n " ,
2008-02-07 11:15:47 +03:00
sb - > s_id , ino ) ;
return ERR_PTR ( - EIO ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-07 11:15:47 +03:00
inode = iget_locked ( sb , ino ) ;
if ( ! inode )
return ERR_PTR ( - ENOMEM ) ;
if ( ! ( inode - > i_state & I_NEW ) )
return inode ;
2005-04-17 02:20:36 +04:00
raw_inode = sysv_raw_inode ( sb , ino , & bh ) ;
if ( ! raw_inode ) {
printk ( " Major problem: unable to read inode from dev %s \n " ,
inode - > i_sb - > s_id ) ;
goto bad_inode ;
}
/* SystemV FS: kludge permissions if ino==SYSV_ROOT_INO ?? */
inode - > i_mode = fs16_to_cpu ( sbi , raw_inode - > i_mode ) ;
2012-02-11 00:19:23 +04:00
i_uid_write ( inode , ( uid_t ) fs16_to_cpu ( sbi , raw_inode - > i_uid ) ) ;
i_gid_write ( inode , ( gid_t ) fs16_to_cpu ( sbi , raw_inode - > i_gid ) ) ;
2011-10-28 16:13:29 +04:00
set_nlink ( inode , fs16_to_cpu ( sbi , raw_inode - > i_nlink ) ) ;
2005-04-17 02:20:36 +04:00
inode - > i_size = fs32_to_cpu ( sbi , raw_inode - > i_size ) ;
inode - > i_atime . tv_sec = fs32_to_cpu ( sbi , raw_inode - > i_atime ) ;
inode - > i_mtime . tv_sec = fs32_to_cpu ( sbi , raw_inode - > i_mtime ) ;
inode - > i_ctime . tv_sec = fs32_to_cpu ( sbi , raw_inode - > i_ctime ) ;
inode - > i_ctime . tv_nsec = 0 ;
inode - > i_atime . tv_nsec = 0 ;
inode - > i_mtime . tv_nsec = 0 ;
2006-09-27 12:50:49 +04:00
inode - > i_blocks = 0 ;
2005-04-17 02:20:36 +04:00
si = SYSV_I ( inode ) ;
for ( block = 0 ; block < 10 + 1 + 1 + 1 ; block + + )
read3byte ( sbi , & raw_inode - > i_data [ 3 * block ] ,
( u8 * ) & si - > i_data [ block ] ) ;
brelse ( bh ) ;
si - > i_dir_start_lookup = 0 ;
if ( S_ISCHR ( inode - > i_mode ) | | S_ISBLK ( inode - > i_mode ) )
sysv_set_inode ( inode ,
old_decode_dev ( fs32_to_cpu ( sbi , si - > i_data [ 0 ] ) ) ) ;
else
sysv_set_inode ( inode , 0 ) ;
2008-02-07 11:15:47 +03:00
unlock_new_inode ( inode ) ;
return inode ;
2005-04-17 02:20:36 +04:00
bad_inode :
2008-02-07 11:15:47 +03:00
iget_failed ( inode ) ;
return ERR_PTR ( - EIO ) ;
2005-04-17 02:20:36 +04:00
}
2010-03-05 11:21:37 +03:00
static int __sysv_write_inode ( struct inode * inode , int wait )
2005-04-17 02:20:36 +04:00
{
struct super_block * sb = inode - > i_sb ;
struct sysv_sb_info * sbi = SYSV_SB ( sb ) ;
struct buffer_head * bh ;
struct sysv_inode * raw_inode ;
struct sysv_inode_info * si ;
unsigned int ino , block ;
2009-06-07 23:29:45 +04:00
int err = 0 ;
2005-04-17 02:20:36 +04:00
ino = inode - > i_ino ;
if ( ! ino | | ino > sbi - > s_ninodes ) {
printk ( " Bad inode number on dev %s: %d is out of range \n " ,
inode - > i_sb - > s_id , ino ) ;
2009-06-07 23:29:45 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
raw_inode = sysv_raw_inode ( sb , ino , & bh ) ;
if ( ! raw_inode ) {
printk ( " unable to read i-node block \n " ) ;
2009-06-07 23:29:45 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
raw_inode - > i_mode = cpu_to_fs16 ( sbi , inode - > i_mode ) ;
2012-02-11 00:19:23 +04:00
raw_inode - > i_uid = cpu_to_fs16 ( sbi , fs_high2lowuid ( i_uid_read ( inode ) ) ) ;
raw_inode - > i_gid = cpu_to_fs16 ( sbi , fs_high2lowgid ( i_gid_read ( inode ) ) ) ;
2005-04-17 02:20:36 +04:00
raw_inode - > i_nlink = cpu_to_fs16 ( sbi , inode - > i_nlink ) ;
raw_inode - > i_size = cpu_to_fs32 ( sbi , inode - > i_size ) ;
raw_inode - > i_atime = cpu_to_fs32 ( sbi , inode - > i_atime . tv_sec ) ;
raw_inode - > i_mtime = cpu_to_fs32 ( sbi , inode - > i_mtime . tv_sec ) ;
raw_inode - > i_ctime = cpu_to_fs32 ( sbi , inode - > i_ctime . tv_sec ) ;
si = SYSV_I ( inode ) ;
if ( S_ISCHR ( inode - > i_mode ) | | S_ISBLK ( inode - > i_mode ) )
si - > i_data [ 0 ] = cpu_to_fs32 ( sbi , old_encode_dev ( inode - > i_rdev ) ) ;
for ( block = 0 ; block < 10 + 1 + 1 + 1 ; block + + )
write3byte ( sbi , ( u8 * ) & si - > i_data [ block ] ,
& raw_inode - > i_data [ 3 * block ] ) ;
mark_buffer_dirty ( bh ) ;
2009-06-07 23:29:45 +04:00
if ( wait ) {
sync_dirty_buffer ( bh ) ;
if ( buffer_req ( bh ) & & ! buffer_uptodate ( bh ) ) {
printk ( " IO error syncing sysv inode [%s:%08x] \n " ,
sb - > s_id , ino ) ;
err = - EIO ;
}
}
2005-04-17 02:20:36 +04:00
brelse ( bh ) ;
return 0 ;
}
2010-03-05 11:21:37 +03:00
int sysv_write_inode ( struct inode * inode , struct writeback_control * wbc )
{
return __sysv_write_inode ( inode , wbc - > sync_mode = = WB_SYNC_ALL ) ;
}
2009-06-07 23:29:45 +04:00
int sysv_sync_inode ( struct inode * inode )
2005-04-17 02:20:36 +04:00
{
2010-03-05 11:21:37 +03:00
return __sysv_write_inode ( inode , 1 ) ;
2005-04-17 02:20:36 +04:00
}
2010-06-06 03:16:20 +04:00
static void sysv_evict_inode ( struct inode * inode )
2005-04-17 02:20:36 +04:00
{
2014-04-04 01:47:49 +04:00
truncate_inode_pages_final ( & inode - > i_data ) ;
2010-06-06 03:16:20 +04:00
if ( ! inode - > i_nlink ) {
inode - > i_size = 0 ;
sysv_truncate ( inode ) ;
}
invalidate_inode_buffers ( inode ) ;
2012-05-03 16:48:02 +04:00
clear_inode ( inode ) ;
2010-06-06 03:16:20 +04:00
if ( ! inode - > i_nlink )
sysv_free_inode ( inode ) ;
2005-04-17 02:20:36 +04:00
}
2006-12-07 07:33:20 +03:00
static struct kmem_cache * sysv_inode_cachep ;
2005-04-17 02:20:36 +04:00
static struct inode * sysv_alloc_inode ( struct super_block * sb )
{
struct sysv_inode_info * si ;
2006-12-07 07:33:17 +03:00
si = kmem_cache_alloc ( sysv_inode_cachep , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! si )
return NULL ;
return & si - > vfs_inode ;
}
2011-01-07 09:49:49 +03:00
static void sysv_i_callback ( struct rcu_head * head )
2005-04-17 02:20:36 +04:00
{
2011-01-07 09:49:49 +03:00
struct inode * inode = container_of ( head , struct inode , i_rcu ) ;
2005-04-17 02:20:36 +04:00
kmem_cache_free ( sysv_inode_cachep , SYSV_I ( inode ) ) ;
}
2011-01-07 09:49:49 +03:00
static void sysv_destroy_inode ( struct inode * inode )
{
call_rcu ( & inode - > i_rcu , sysv_i_callback ) ;
}
2008-07-26 06:45:34 +04:00
static void init_once ( void * p )
2005-04-17 02:20:36 +04:00
{
struct sysv_inode_info * si = ( struct sysv_inode_info * ) p ;
2007-05-17 09:10:57 +04:00
inode_init_once ( & si - > vfs_inode ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:55:41 +03:00
const struct super_operations sysv_sops = {
2005-04-17 02:20:36 +04:00
. alloc_inode = sysv_alloc_inode ,
. destroy_inode = sysv_destroy_inode ,
. write_inode = sysv_write_inode ,
2010-06-06 03:16:20 +04:00
. evict_inode = sysv_evict_inode ,
2005-04-17 02:20:36 +04:00
. put_super = sysv_put_super ,
2009-06-08 12:07:45 +04:00
. sync_fs = sysv_sync_fs ,
2005-04-17 02:20:36 +04:00
. remount_fs = sysv_remount ,
. statfs = sysv_statfs ,
} ;
int __init sysv_init_icache ( void )
{
sysv_inode_cachep = kmem_cache_create ( " sysv_inode_cache " ,
sizeof ( struct sysv_inode_info ) , 0 ,
2016-01-15 02:18:21 +03:00
SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD | SLAB_ACCOUNT ,
2007-07-20 05:11:58 +04:00
init_once ) ;
2005-04-17 02:20:36 +04:00
if ( ! sysv_inode_cachep )
return - ENOMEM ;
return 0 ;
}
void sysv_destroy_icache ( void )
{
2012-09-26 05:33:07 +04:00
/*
* Make sure all delayed rcu free inodes are flushed before we
* destroy cache .
*/
rcu_barrier ( ) ;
2005-04-17 02:20:36 +04:00
kmem_cache_destroy ( sysv_inode_cachep ) ;
}