2019-07-31 18:57:31 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2018-07-26 15:21:48 +03:00
/*
* Copyright ( C ) 2017 - 2018 HUAWEI , Inc .
* http : //www.huawei.com/
* Created by Gao Xiang < gaoxiang25 @ huawei . com >
*/
2018-07-26 15:21:52 +03:00
# include "xattr.h"
2018-07-26 15:21:48 +03:00
2018-07-26 15:21:55 +03:00
# include <trace/events/erofs.h>
2018-07-26 15:21:48 +03:00
/* no locking */
static int read_inode ( struct inode * inode , void * data )
{
struct erofs_vnode * vi = EROFS_V ( inode ) ;
2019-09-04 05:08:54 +03:00
struct erofs_inode_compact * dic = data ;
struct erofs_inode_extended * die ;
const unsigned int ifmt = le16_to_cpu ( dic - > i_format ) ;
struct erofs_sb_info * sbi = EROFS_SB ( inode - > i_sb ) ;
2019-05-28 06:19:43 +03:00
erofs_blk_t nblks = 0 ;
2018-07-26 15:21:48 +03:00
2019-09-04 05:08:54 +03:00
vi - > datalayout = erofs_inode_datalayout ( ifmt ) ;
2018-07-26 15:21:48 +03:00
2019-09-04 05:08:54 +03:00
if ( vi - > datalayout > = EROFS_INODE_DATALAYOUT_MAX ) {
errln ( " unsupported datalayout %u of nid %llu " ,
vi - > datalayout , vi - > nid ) ;
2018-07-26 15:21:48 +03:00
DBG_BUGON ( 1 ) ;
2019-08-14 13:37:04 +03:00
return - EOPNOTSUPP ;
2018-07-26 15:21:48 +03:00
}
2019-09-04 05:08:54 +03:00
switch ( erofs_inode_version ( ifmt ) ) {
case EROFS_INODE_LAYOUT_EXTENDED :
die = data ;
2018-07-26 15:21:48 +03:00
2019-09-04 05:08:54 +03:00
vi - > inode_isize = sizeof ( struct erofs_inode_extended ) ;
vi - > xattr_isize = erofs_xattr_ibody_size ( die - > i_xattr_icount ) ;
2018-07-26 15:21:48 +03:00
2019-09-04 05:08:54 +03:00
inode - > i_mode = le16_to_cpu ( die - > i_mode ) ;
switch ( inode - > i_mode & S_IFMT ) {
case S_IFREG :
case S_IFDIR :
case S_IFLNK :
vi - > raw_blkaddr = le32_to_cpu ( die - > i_u . raw_blkaddr ) ;
break ;
case S_IFCHR :
case S_IFBLK :
2018-07-26 15:21:53 +03:00
inode - > i_rdev =
2019-09-04 05:08:54 +03:00
new_decode_dev ( le32_to_cpu ( die - > i_u . rdev ) ) ;
break ;
case S_IFIFO :
case S_IFSOCK :
2018-07-26 15:21:53 +03:00
inode - > i_rdev = 0 ;
2019-09-04 05:08:54 +03:00
break ;
default :
2019-08-14 13:37:03 +03:00
goto bogusimode ;
2019-09-04 05:08:54 +03:00
}
i_uid_write ( inode , le32_to_cpu ( die - > i_uid ) ) ;
i_gid_write ( inode , le32_to_cpu ( die - > i_gid ) ) ;
set_nlink ( inode , le32_to_cpu ( die - > i_nlink ) ) ;
2018-07-26 15:21:48 +03:00
/* ns timestamp */
inode - > i_mtime . tv_sec = inode - > i_ctime . tv_sec =
2019-09-04 05:08:54 +03:00
le64_to_cpu ( die - > i_ctime ) ;
2018-07-26 15:21:48 +03:00
inode - > i_mtime . tv_nsec = inode - > i_ctime . tv_nsec =
2019-09-04 05:08:54 +03:00
le32_to_cpu ( die - > i_ctime_nsec ) ;
2018-07-26 15:21:48 +03:00
2019-09-04 05:08:54 +03:00
inode - > i_size = le64_to_cpu ( die - > i_size ) ;
2019-05-28 06:19:43 +03:00
/* total blocks for compressed files */
2019-09-04 05:08:54 +03:00
if ( erofs_inode_is_data_compressed ( vi - > datalayout ) )
nblks = le32_to_cpu ( die - > i_u . compressed_blocks ) ;
break ;
case EROFS_INODE_LAYOUT_COMPACT :
vi - > inode_isize = sizeof ( struct erofs_inode_compact ) ;
vi - > xattr_isize = erofs_xattr_ibody_size ( dic - > i_xattr_icount ) ;
inode - > i_mode = le16_to_cpu ( dic - > i_mode ) ;
switch ( inode - > i_mode & S_IFMT ) {
case S_IFREG :
case S_IFDIR :
case S_IFLNK :
vi - > raw_blkaddr = le32_to_cpu ( dic - > i_u . raw_blkaddr ) ;
break ;
case S_IFCHR :
case S_IFBLK :
2018-07-26 15:21:53 +03:00
inode - > i_rdev =
2019-09-04 05:08:54 +03:00
new_decode_dev ( le32_to_cpu ( dic - > i_u . rdev ) ) ;
break ;
case S_IFIFO :
case S_IFSOCK :
2018-07-26 15:21:53 +03:00
inode - > i_rdev = 0 ;
2019-09-04 05:08:54 +03:00
break ;
default :
2019-08-14 13:37:03 +03:00
goto bogusimode ;
2019-09-04 05:08:54 +03:00
}
i_uid_write ( inode , le16_to_cpu ( dic - > i_uid ) ) ;
i_gid_write ( inode , le16_to_cpu ( dic - > i_gid ) ) ;
set_nlink ( inode , le16_to_cpu ( dic - > i_nlink ) ) ;
2018-07-26 15:21:48 +03:00
/* use build time to derive all file time */
inode - > i_mtime . tv_sec = inode - > i_ctime . tv_sec =
sbi - > build_time ;
inode - > i_mtime . tv_nsec = inode - > i_ctime . tv_nsec =
sbi - > build_time_nsec ;
2019-09-04 05:08:54 +03:00
inode - > i_size = le32_to_cpu ( dic - > i_size ) ;
if ( erofs_inode_is_data_compressed ( vi - > datalayout ) )
nblks = le32_to_cpu ( dic - > i_u . compressed_blocks ) ;
break ;
default :
2018-07-26 15:21:48 +03:00
errln ( " unsupported on-disk inode version %u of nid %llu " ,
2019-09-04 05:08:54 +03:00
erofs_inode_version ( ifmt ) , vi - > nid ) ;
2018-07-26 15:21:48 +03:00
DBG_BUGON ( 1 ) ;
2019-08-14 13:37:04 +03:00
return - EOPNOTSUPP ;
2018-07-26 15:21:48 +03:00
}
2019-05-28 06:19:43 +03:00
if ( ! nblks )
/* measure inode.i_blocks as generic filesystems */
inode - > i_blocks = roundup ( inode - > i_size , EROFS_BLKSIZ ) > > 9 ;
else
inode - > i_blocks = nblks < < LOG_SECTORS_PER_BLOCK ;
2018-07-26 15:21:48 +03:00
return 0 ;
2019-08-14 13:37:03 +03:00
bogusimode :
errln ( " bogus i_mode (%o) @ nid %llu " , inode - > i_mode , vi - > nid ) ;
DBG_BUGON ( 1 ) ;
return - EFSCORRUPTED ;
2018-07-26 15:21:48 +03:00
}
/*
* try_lock can be required since locking order is :
* file data ( fs_inode )
* meta ( bd_inode )
* but the majority of the callers is " iget " ,
* in that case we are pretty sure no deadlock since
* no data operations exist . However I tend to
* try_lock since it takes no much overhead and
* will success immediately .
*/
2018-09-10 22:41:14 +03:00
static int fill_inline_data ( struct inode * inode , void * data ,
unsigned int m_pofs )
2018-07-26 15:21:48 +03:00
{
struct erofs_vnode * vi = EROFS_V ( inode ) ;
2018-07-26 15:21:54 +03:00
struct erofs_sb_info * sbi = EROFS_I_SB ( inode ) ;
2018-07-26 15:21:48 +03:00
2019-09-04 05:08:54 +03:00
/* should be tail-packing data inline */
if ( vi - > datalayout ! = EROFS_INODE_FLAT_INLINE )
2018-07-26 15:21:48 +03:00
return 0 ;
/* fast symlink (following ext4) */
if ( S_ISLNK ( inode - > i_mode ) & & inode - > i_size < PAGE_SIZE ) {
2018-07-26 15:21:54 +03:00
char * lnk = erofs_kmalloc ( sbi , inode - > i_size + 1 , GFP_KERNEL ) ;
2018-07-26 15:21:48 +03:00
2019-08-29 19:38:27 +03:00
if ( ! lnk )
2018-07-26 15:21:48 +03:00
return - ENOMEM ;
m_pofs + = vi - > inode_isize + vi - > xattr_isize ;
2018-12-05 16:23:13 +03:00
/* inline symlink data shouldn't across page boundary as well */
2019-08-29 19:38:27 +03:00
if ( m_pofs + inode - > i_size > PAGE_SIZE ) {
2018-12-05 16:23:13 +03:00
kfree ( lnk ) ;
2019-08-14 13:37:03 +03:00
errln ( " inline data cross block boundary @ nid %llu " ,
vi - > nid ) ;
DBG_BUGON ( 1 ) ;
return - EFSCORRUPTED ;
2018-12-05 16:23:13 +03:00
}
2018-07-26 15:21:48 +03:00
/* get in-page inline data */
memcpy ( lnk , data + m_pofs , inode - > i_size ) ;
lnk [ inode - > i_size ] = ' \0 ' ;
inode - > i_link = lnk ;
set_inode_fast_symlink ( inode ) ;
}
2019-06-27 12:46:15 +03:00
return 0 ;
2018-07-26 15:21:48 +03:00
}
static int fill_inode ( struct inode * inode , int isdir )
{
struct erofs_sb_info * sbi = EROFS_SB ( inode - > i_sb ) ;
struct erofs_vnode * vi = EROFS_V ( inode ) ;
struct page * page ;
void * data ;
int err ;
erofs_blk_t blkaddr ;
2018-09-10 22:41:14 +03:00
unsigned int ofs ;
2019-08-13 23:38:40 +03:00
erofs_off_t inode_loc ;
2018-07-26 15:21:48 +03:00
2018-07-26 15:21:55 +03:00
trace_erofs_fill_inode ( inode , isdir ) ;
2019-08-13 23:38:40 +03:00
inode_loc = iloc ( sbi , vi - > nid ) ;
blkaddr = erofs_blknr ( inode_loc ) ;
ofs = erofs_blkoff ( inode_loc ) ;
2018-07-26 15:21:48 +03:00
debugln ( " %s, reading inode nid %llu at %u of blkaddr %u " ,
__func__ , vi - > nid , ofs , blkaddr ) ;
page = erofs_get_meta_page ( inode - > i_sb , blkaddr , isdir ) ;
if ( IS_ERR ( page ) ) {
errln ( " failed to get inode (nid: %llu) page, err %ld " ,
2019-03-19 02:58:41 +03:00
vi - > nid , PTR_ERR ( page ) ) ;
2018-07-26 15:21:48 +03:00
return PTR_ERR ( page ) ;
}
2018-12-05 16:23:13 +03:00
DBG_BUGON ( ! PageUptodate ( page ) ) ;
2018-07-26 15:21:48 +03:00
data = page_address ( page ) ;
err = read_inode ( inode , data + ofs ) ;
if ( ! err ) {
/* setup the new inode */
2019-08-30 12:56:15 +03:00
switch ( inode - > i_mode & S_IFMT ) {
case S_IFREG :
2019-01-14 14:40:24 +03:00
inode - > i_op = & erofs_generic_iops ;
2018-07-26 15:21:48 +03:00
inode - > i_fop = & generic_ro_fops ;
2019-08-30 12:56:15 +03:00
break ;
case S_IFDIR :
2019-01-14 14:40:24 +03:00
inode - > i_op = & erofs_dir_iops ;
2018-07-26 15:21:48 +03:00
inode - > i_fop = & erofs_dir_fops ;
2019-08-30 12:56:15 +03:00
break ;
case S_IFLNK :
2018-07-26 15:21:48 +03:00
/* by default, page_get_link is used for symlink */
2019-01-14 14:40:24 +03:00
inode - > i_op = & erofs_symlink_iops ;
2018-07-26 15:21:48 +03:00
inode_nohighmem ( inode ) ;
2019-08-30 12:56:15 +03:00
break ;
case S_IFCHR :
case S_IFBLK :
case S_IFIFO :
case S_IFSOCK :
2019-01-14 14:40:24 +03:00
inode - > i_op = & erofs_generic_iops ;
2018-07-26 15:21:53 +03:00
init_special_inode ( inode , inode - > i_mode , inode - > i_rdev ) ;
2019-06-28 06:42:34 +03:00
goto out_unlock ;
2019-08-30 12:56:15 +03:00
default :
2019-08-14 13:37:03 +03:00
err = - EFSCORRUPTED ;
2018-07-26 15:21:48 +03:00
goto out_unlock ;
}
2019-09-04 05:08:54 +03:00
if ( erofs_inode_is_data_compressed ( vi - > datalayout ) ) {
2019-06-24 10:22:52 +03:00
err = z_erofs_fill_inode ( inode ) ;
2018-07-26 15:21:48 +03:00
goto out_unlock ;
}
inode - > i_mapping - > a_ops = & erofs_raw_access_aops ;
/* fill last page if inline data is available */
2019-06-27 12:46:15 +03:00
err = fill_inline_data ( inode , data , ofs ) ;
2018-07-26 15:21:48 +03:00
}
out_unlock :
unlock_page ( page ) ;
put_page ( page ) ;
return err ;
}
2018-10-09 17:07:13 +03:00
/*
* erofs nid is 64 bits , but i_ino is ' unsigned long ' , therefore
* we should do more for 32 - bit platform to find the right inode .
*/
# if BITS_PER_LONG == 32
static int erofs_ilookup_test_actor ( struct inode * inode , void * opaque )
{
const erofs_nid_t nid = * ( erofs_nid_t * ) opaque ;
return EROFS_V ( inode ) - > nid = = nid ;
}
static int erofs_iget_set_actor ( struct inode * inode , void * opaque )
{
const erofs_nid_t nid = * ( erofs_nid_t * ) opaque ;
inode - > i_ino = erofs_inode_hash ( nid ) ;
return 0 ;
}
# endif
static inline struct inode * erofs_iget_locked ( struct super_block * sb ,
erofs_nid_t nid )
{
const unsigned long hashval = erofs_inode_hash ( nid ) ;
# if BITS_PER_LONG >= 64
/* it is safe to use iget_locked for >= 64-bit platform */
return iget_locked ( sb , hashval ) ;
# else
return iget5_locked ( sb , hashval , erofs_ilookup_test_actor ,
erofs_iget_set_actor , & nid ) ;
# endif
}
2018-07-26 15:21:48 +03:00
struct inode * erofs_iget ( struct super_block * sb ,
2019-03-19 02:58:41 +03:00
erofs_nid_t nid ,
bool isdir )
2018-07-26 15:21:48 +03:00
{
2018-10-09 17:07:13 +03:00
struct inode * inode = erofs_iget_locked ( sb , nid ) ;
2018-07-26 15:21:48 +03:00
2019-08-29 19:38:27 +03:00
if ( ! inode )
2018-07-26 15:21:48 +03:00
return ERR_PTR ( - ENOMEM ) ;
if ( inode - > i_state & I_NEW ) {
int err ;
struct erofs_vnode * vi = EROFS_V ( inode ) ;
2019-03-09 20:08:53 +03:00
2018-07-26 15:21:48 +03:00
vi - > nid = nid ;
err = fill_inode ( inode , isdir ) ;
2019-08-29 19:38:27 +03:00
if ( ! err )
2018-07-26 15:21:48 +03:00
unlock_new_inode ( inode ) ;
else {
iget_failed ( inode ) ;
inode = ERR_PTR ( err ) ;
}
}
return inode ;
}
2019-05-28 06:19:42 +03:00
int erofs_getattr ( const struct path * path , struct kstat * stat ,
u32 request_mask , unsigned int query_flags )
{
struct inode * const inode = d_inode ( path - > dentry ) ;
2019-09-04 05:08:54 +03:00
if ( erofs_inode_is_data_compressed ( EROFS_V ( inode ) - > datalayout ) )
2019-05-28 06:19:42 +03:00
stat - > attributes | = STATX_ATTR_COMPRESSED ;
stat - > attributes | = STATX_ATTR_IMMUTABLE ;
stat - > attributes_mask | = ( STATX_ATTR_COMPRESSED |
STATX_ATTR_IMMUTABLE ) ;
generic_fillattr ( inode , stat ) ;
return 0 ;
}
2019-01-14 14:40:24 +03:00
const struct inode_operations erofs_generic_iops = {
2019-05-28 06:19:42 +03:00
. getattr = erofs_getattr ,
2018-07-26 15:21:52 +03:00
# ifdef CONFIG_EROFS_FS_XATTR
. listxattr = erofs_listxattr ,
2019-01-14 14:40:24 +03:00
# endif
2019-01-29 11:35:20 +03:00
. get_acl = erofs_get_acl ,
2018-07-26 15:21:52 +03:00
} ;
2019-01-14 14:40:24 +03:00
const struct inode_operations erofs_symlink_iops = {
2018-07-26 15:21:52 +03:00
. get_link = page_get_link ,
2019-05-28 06:19:42 +03:00
. getattr = erofs_getattr ,
2019-01-14 14:40:24 +03:00
# ifdef CONFIG_EROFS_FS_XATTR
2018-07-26 15:21:52 +03:00
. listxattr = erofs_listxattr ,
2019-01-14 14:40:24 +03:00
# endif
2019-01-29 11:35:20 +03:00
. get_acl = erofs_get_acl ,
2018-07-26 15:21:52 +03:00
} ;
2019-01-14 14:40:24 +03:00
const struct inode_operations erofs_fast_symlink_iops = {
2018-07-26 15:21:52 +03:00
. get_link = simple_get_link ,
2019-05-28 06:19:42 +03:00
. getattr = erofs_getattr ,
2019-01-14 14:40:24 +03:00
# ifdef CONFIG_EROFS_FS_XATTR
2018-07-26 15:21:52 +03:00
. listxattr = erofs_listxattr ,
# endif
2019-01-29 11:35:20 +03:00
. get_acl = erofs_get_acl ,
2019-01-14 14:40:24 +03:00
} ;
2018-07-26 15:21:52 +03:00