2018-06-06 05:42:14 +03:00
// SPDX-License-Identifier: GPL-2.0
2013-04-03 09:11:18 +04:00
/*
* Copyright ( c ) 2000 - 2006 Silicon Graphics , Inc .
* Copyright ( c ) 2012 - 2013 Red Hat , Inc .
* All rights reserved .
*/
# include "xfs.h"
2013-10-23 03:50:10 +04:00
# include "xfs_shared.h"
2013-04-03 09:11:18 +04:00
# include "xfs_fs.h"
2013-08-12 14:49:26 +04:00
# include "xfs_format.h"
2013-10-23 03:50:10 +04:00
# include "xfs_log_format.h"
# include "xfs_trans_resv.h"
2013-04-03 09:11:18 +04:00
# include "xfs_bit.h"
# include "xfs_mount.h"
2013-08-12 14:49:37 +04:00
# include "xfs_dir2.h"
2013-04-03 09:11:18 +04:00
# include "xfs_inode.h"
# include "xfs_bmap.h"
2013-10-23 03:51:50 +04:00
# include "xfs_bmap_btree.h"
2013-04-03 09:11:18 +04:00
# include "xfs_quota.h"
2019-11-07 04:19:33 +03:00
# include "xfs_symlink.h"
2013-04-03 09:11:18 +04:00
# include "xfs_trans_space.h"
# include "xfs_trace.h"
2013-10-23 03:50:10 +04:00
# include "xfs_trans.h"
2021-06-02 03:48:24 +03:00
# include "xfs_ialloc.h"
2021-12-15 23:07:41 +03:00
# include "xfs_error.h"
2013-04-03 09:11:18 +04:00
/* ----- Kernel only functions below ----- */
2017-06-16 21:00:15 +03:00
int
xfs_readlink_bmap_ilocked (
2013-04-03 09:11:19 +04:00
struct xfs_inode * ip ,
char * link )
2013-04-03 09:11:18 +04:00
{
2013-04-03 09:11:19 +04:00
struct xfs_mount * mp = ip - > i_mount ;
struct xfs_bmbt_irec mval [ XFS_SYMLINK_MAPS ] ;
struct xfs_buf * bp ;
xfs_daddr_t d ;
char * cur_chunk ;
2021-03-29 21:11:40 +03:00
int pathlen = ip - > i_disk_size ;
2013-04-03 09:11:19 +04:00
int nmaps = XFS_SYMLINK_MAPS ;
int byte_cnt ;
int n ;
int error = 0 ;
int fsblocks = 0 ;
int offset ;
2013-04-03 09:11:18 +04:00
2017-07-13 22:14:34 +03:00
ASSERT ( xfs_isilocked ( ip , XFS_ILOCK_SHARED | XFS_ILOCK_EXCL ) ) ;
2013-04-03 09:11:19 +04:00
fsblocks = xfs_symlink_blocks ( mp , pathlen ) ;
error = xfs_bmapi_read ( ip , 0 , fsblocks , mval , & nmaps , 0 ) ;
2013-04-03 09:11:18 +04:00
if ( error )
goto out ;
2013-04-03 09:11:19 +04:00
offset = 0 ;
2013-04-03 09:11:18 +04:00
for ( n = 0 ; n < nmaps ; n + + ) {
d = XFS_FSB_TO_DADDR ( mp , mval [ n ] . br_startblock ) ;
byte_cnt = XFS_FSB_TO_B ( mp , mval [ n ] . br_blockcount ) ;
2020-01-24 04:01:17 +03:00
error = xfs_buf_read ( mp - > m_ddev_targp , d , BTOBB ( byte_cnt ) , 0 ,
& bp , & xfs_symlink_buf_ops ) ;
if ( error )
return error ;
2013-04-03 09:11:19 +04:00
byte_cnt = XFS_SYMLINK_BUF_SPACE ( mp , byte_cnt ) ;
2013-04-03 09:11:18 +04:00
if ( pathlen < byte_cnt )
byte_cnt = pathlen ;
2013-04-03 09:11:19 +04:00
cur_chunk = bp - > b_addr ;
2021-08-19 04:46:37 +03:00
if ( xfs_has_crc ( mp ) ) {
2014-04-14 13:05:43 +04:00
if ( ! xfs_symlink_hdr_ok ( ip - > i_ino , offset ,
2013-04-03 09:11:19 +04:00
byte_cnt , bp ) ) {
2014-06-25 08:58:08 +04:00
error = - EFSCORRUPTED ;
2013-04-03 09:11:19 +04:00
xfs_alert ( mp ,
" symlink header does not match required off/len/owner (0x%x/Ox%x,0x%llx) " ,
offset , byte_cnt , ip - > i_ino ) ;
xfs_buf_relse ( bp ) ;
goto out ;
}
cur_chunk + = sizeof ( struct xfs_dsymlink_hdr ) ;
}
2015-06-22 02:42:48 +03:00
memcpy ( link + offset , cur_chunk , byte_cnt ) ;
2013-04-03 09:11:19 +04:00
2013-04-03 09:11:18 +04:00
pathlen - = byte_cnt ;
2013-04-03 09:11:19 +04:00
offset + = byte_cnt ;
2013-04-03 09:11:18 +04:00
xfs_buf_relse ( bp ) ;
}
2013-04-03 09:11:19 +04:00
ASSERT ( pathlen = = 0 ) ;
2013-04-03 09:11:18 +04:00
2021-03-29 21:11:40 +03:00
link [ ip - > i_disk_size ] = ' \0 ' ;
2013-04-03 09:11:18 +04:00
error = 0 ;
out :
return error ;
}
int
xfs_readlink (
2021-12-15 23:07:41 +03:00
struct xfs_inode * ip ,
char * link )
2013-04-03 09:11:18 +04:00
{
2021-12-15 23:07:41 +03:00
struct xfs_mount * mp = ip - > i_mount ;
xfs_fsize_t pathlen ;
int error = - EFSCORRUPTED ;
2013-04-03 09:11:18 +04:00
trace_xfs_readlink ( ip ) ;
2021-08-19 04:46:53 +03:00
if ( xfs_is_shutdown ( mp ) )
2014-06-25 08:58:08 +04:00
return - EIO ;
2013-04-03 09:11:18 +04:00
xfs_ilock ( ip , XFS_ILOCK_SHARED ) ;
2021-03-29 21:11:40 +03:00
pathlen = ip - > i_disk_size ;
2013-04-03 09:11:18 +04:00
if ( ! pathlen )
goto out ;
2017-07-07 18:37:26 +03:00
if ( pathlen < 0 | | pathlen > XFS_SYMLINK_MAXLEN ) {
2013-04-03 09:11:18 +04:00
xfs_alert ( mp , " %s: inode (%llu) bad symlink length (%lld) " ,
__func__ , ( unsigned long long ) ip - > i_ino ,
( long long ) pathlen ) ;
ASSERT ( 0 ) ;
goto out ;
}
2021-12-15 23:07:41 +03:00
if ( ip - > i_df . if_format = = XFS_DINODE_FMT_LOCAL ) {
/*
* The VFS crashes on a NULL pointer , so return - EFSCORRUPTED
* if if_data is junk .
*/
if ( XFS_IS_CORRUPT ( ip - > i_mount , ! ip - > i_df . if_u1 . if_data ) )
goto out ;
memcpy ( link , ip - > i_df . if_u1 . if_data , pathlen + 1 ) ;
error = 0 ;
} else {
error = xfs_readlink_bmap_ilocked ( ip , link ) ;
}
2013-04-03 09:11:18 +04:00
out :
xfs_iunlock ( ip , XFS_ILOCK_SHARED ) ;
return error ;
}
int
xfs_symlink (
2023-01-13 14:49:25 +03:00
struct mnt_idmap * idmap ,
2013-04-03 09:11:19 +04:00
struct xfs_inode * dp ,
2013-04-03 09:11:18 +04:00
struct xfs_name * link_name ,
const char * target_path ,
umode_t mode ,
2013-04-03 09:11:19 +04:00
struct xfs_inode * * ipp )
2013-04-03 09:11:18 +04:00
{
2013-04-03 09:11:19 +04:00
struct xfs_mount * mp = dp - > i_mount ;
struct xfs_trans * tp = NULL ;
struct xfs_inode * ip = NULL ;
int error = 0 ;
2013-04-03 09:11:18 +04:00
int pathlen ;
2015-02-23 14:38:08 +03:00
bool unlock_dp_on_error = false ;
2013-04-03 09:11:18 +04:00
xfs_fileoff_t first_fsb ;
xfs_filblks_t fs_blocks ;
int nmaps ;
2013-04-03 09:11:19 +04:00
struct xfs_bmbt_irec mval [ XFS_SYMLINK_MAPS ] ;
2013-04-03 09:11:18 +04:00
xfs_daddr_t d ;
const char * cur_chunk ;
int byte_cnt ;
int n ;
2020-12-17 03:07:34 +03:00
struct xfs_buf * bp ;
2013-04-03 09:11:18 +04:00
prid_t prid ;
2013-06-28 02:25:07 +04:00
struct xfs_dquot * udqp = NULL ;
struct xfs_dquot * gdqp = NULL ;
2013-07-11 09:00:40 +04:00
struct xfs_dquot * pdqp = NULL ;
2013-04-03 09:11:18 +04:00
uint resblks ;
2021-06-02 03:48:24 +03:00
xfs_ino_t ino ;
2013-04-03 09:11:18 +04:00
* ipp = NULL ;
trace_xfs_symlink ( dp , link_name ) ;
2021-08-19 04:46:53 +03:00
if ( xfs_is_shutdown ( mp ) )
2014-06-25 08:58:08 +04:00
return - EIO ;
2013-04-03 09:11:18 +04:00
/*
* Check component lengths of the target path name .
*/
pathlen = strlen ( target_path ) ;
2017-07-07 18:37:26 +03:00
if ( pathlen > = XFS_SYMLINK_MAXLEN ) /* total string too long */
2014-06-25 08:58:08 +04:00
return - ENAMETOOLONG ;
2018-12-12 19:46:21 +03:00
ASSERT ( pathlen > 0 ) ;
2013-04-03 09:11:18 +04:00
2013-12-18 04:22:39 +04:00
prid = xfs_get_initial_prid ( dp ) ;
2013-04-03 09:11:18 +04:00
/*
* Make sure that we have allocated dquot ( s ) on disk .
*/
2023-01-13 14:49:31 +03:00
error = xfs_qm_vop_dqalloc ( dp , mapped_fsuid ( idmap , & init_user_ns ) ,
mapped_fsgid ( idmap , & init_user_ns ) , prid ,
2013-08-15 22:08:01 +04:00
XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT ,
& udqp , & gdqp , & pdqp ) ;
2013-04-03 09:11:18 +04:00
if ( error )
2015-02-23 14:38:08 +03:00
return error ;
2013-04-03 09:11:18 +04:00
/*
* The symlink will fit into the inode data fork ?
* There can ' t be any attributes so we get the whole variable part .
*/
2020-03-18 18:15:10 +03:00
if ( pathlen < = XFS_LITINO ( mp ) )
2013-04-03 09:11:18 +04:00
fs_blocks = 0 ;
else
2013-05-27 10:38:20 +04:00
fs_blocks = xfs_symlink_blocks ( mp , pathlen ) ;
2013-04-03 09:11:18 +04:00
resblks = XFS_SYMLINK_SPACE_RES ( mp , link_name - > len , fs_blocks ) ;
2016-04-06 02:19:55 +03:00
2021-01-27 23:07:57 +03:00
error = xfs_trans_alloc_icreate ( mp , & M_RES ( mp ) - > tr_symlink , udqp , gdqp ,
pdqp , resblks , & tp ) ;
2015-06-04 06:47:56 +03:00
if ( error )
2021-01-27 23:07:57 +03:00
goto out_release_dquots ;
2013-04-03 09:11:18 +04:00
2016-11-30 06:33:25 +03:00
xfs_ilock ( dp , XFS_ILOCK_EXCL | XFS_ILOCK_PARENT ) ;
2013-04-03 09:11:18 +04:00
unlock_dp_on_error = true ;
/*
* Check whether the directory allows new symlinks or not .
*/
2021-03-29 21:11:44 +03:00
if ( dp - > i_diflags & XFS_DIFLAG_NOSYMLINKS ) {
2014-06-25 08:58:08 +04:00
error = - EPERM ;
2015-02-23 14:38:08 +03:00
goto out_trans_cancel ;
2013-04-03 09:11:18 +04:00
}
/*
* Allocate an inode for the symlink .
*/
2021-06-02 03:48:24 +03:00
error = xfs_dialloc ( & tp , dp - > i_ino , S_IFLNK , & ino ) ;
if ( ! error )
2023-01-13 14:49:25 +03:00
error = xfs_init_new_inode ( idmap , tp , dp , ino ,
2021-06-02 03:48:24 +03:00
S_IFLNK | ( mode & ~ S_IFMT ) , 1 , 0 , prid ,
false , & ip ) ;
2015-02-23 14:38:08 +03:00
if ( error )
goto out_trans_cancel ;
2013-04-03 09:11:18 +04:00
/*
2015-02-23 14:38:08 +03:00
* Now we join the directory inode to the transaction . We do not do it
* earlier because xfs_dir_ialloc might commit the previous transaction
* ( and release all the locks ) . An error from here on will result in
* the transaction cancel unlocking dp so don ' t do it explicitly in the
2013-04-03 09:11:18 +04:00
* error path .
*/
2016-11-30 06:33:25 +03:00
xfs_trans_ijoin ( tp , dp , XFS_ILOCK_EXCL ) ;
2013-04-03 09:11:18 +04:00
unlock_dp_on_error = false ;
/*
* Also attach the dquot ( s ) to it , if applicable .
*/
2013-07-11 09:00:40 +04:00
xfs_qm_vop_create_dqattach ( tp , ip , udqp , gdqp , pdqp ) ;
2013-04-03 09:11:18 +04:00
2020-04-23 07:54:31 +03:00
resblks - = XFS_IALLOC_SPACE_RES ( mp ) ;
2013-04-03 09:11:18 +04:00
/*
* If the symlink will fit into the inode , write it inline .
*/
2022-07-09 20:56:07 +03:00
if ( pathlen < = xfs_inode_data_fork_size ( ip ) ) {
2016-04-06 00:41:43 +03:00
xfs_init_local_fork ( ip , XFS_DATA_FORK , target_path , pathlen ) ;
2013-04-03 09:11:18 +04:00
2021-03-29 21:11:40 +03:00
ip - > i_disk_size = pathlen ;
2020-05-18 20:28:05 +03:00
ip - > i_df . if_format = XFS_DINODE_FMT_LOCAL ;
2013-04-03 09:11:18 +04:00
xfs_trans_log_inode ( tp , ip , XFS_ILOG_DDATA | XFS_ILOG_CORE ) ;
} else {
2013-04-03 09:11:19 +04:00
int offset ;
2013-04-03 09:11:18 +04:00
first_fsb = 0 ;
nmaps = XFS_SYMLINK_MAPS ;
error = xfs_bmapi_write ( tp , ip , first_fsb , fs_blocks ,
2018-07-12 08:26:25 +03:00
XFS_BMAPI_METADATA , resblks , mval , & nmaps ) ;
2013-04-03 09:11:18 +04:00
if ( error )
2018-07-24 23:43:13 +03:00
goto out_trans_cancel ;
2013-04-03 09:11:18 +04:00
2020-04-23 07:54:31 +03:00
resblks - = fs_blocks ;
2021-03-29 21:11:40 +03:00
ip - > i_disk_size = pathlen ;
2013-04-03 09:11:18 +04:00
xfs_trans_log_inode ( tp , ip , XFS_ILOG_CORE ) ;
cur_chunk = target_path ;
2013-04-03 09:11:19 +04:00
offset = 0 ;
2013-04-03 09:11:18 +04:00
for ( n = 0 ; n < nmaps ; n + + ) {
2013-05-27 10:38:20 +04:00
char * buf ;
2013-04-03 09:11:19 +04:00
2013-04-03 09:11:18 +04:00
d = XFS_FSB_TO_DADDR ( mp , mval [ n ] . br_startblock ) ;
byte_cnt = XFS_FSB_TO_B ( mp , mval [ n ] . br_blockcount ) ;
2020-01-24 04:01:18 +03:00
error = xfs_trans_get_buf ( tp , mp - > m_ddev_targp , d ,
BTOBB ( byte_cnt ) , 0 , & bp ) ;
if ( error )
2018-07-24 23:43:13 +03:00
goto out_trans_cancel ;
2013-04-03 09:11:19 +04:00
bp - > b_ops = & xfs_symlink_buf_ops ;
byte_cnt = XFS_SYMLINK_BUF_SPACE ( mp , byte_cnt ) ;
2013-05-27 10:38:20 +04:00
byte_cnt = min ( byte_cnt , pathlen ) ;
2013-04-03 09:11:18 +04:00
2013-04-03 09:11:19 +04:00
buf = bp - > b_addr ;
buf + = xfs_symlink_hdr_set ( mp , ip - > i_ino , offset ,
byte_cnt , bp ) ;
memcpy ( buf , cur_chunk , byte_cnt ) ;
2013-04-03 09:11:18 +04:00
cur_chunk + = byte_cnt ;
2013-04-03 09:11:19 +04:00
pathlen - = byte_cnt ;
offset + = byte_cnt ;
2013-04-03 09:11:18 +04:00
2013-09-02 04:32:00 +04:00
xfs_trans_buf_set_type ( tp , bp , XFS_BLFT_SYMLINK_BUF ) ;
2013-04-03 09:11:19 +04:00
xfs_trans_log_buf ( tp , bp , 0 , ( buf + byte_cnt - 1 ) -
( char * ) bp - > b_addr ) ;
2013-04-03 09:11:18 +04:00
}
2013-05-27 10:38:20 +04:00
ASSERT ( pathlen = = 0 ) ;
2013-04-03 09:11:18 +04:00
}
2021-03-29 21:11:40 +03:00
i_size_write ( VFS_I ( ip ) , ip - > i_disk_size ) ;
2013-04-03 09:11:18 +04:00
/*
* Create the directory entry for the symlink .
*/
2018-07-12 08:26:21 +03:00
error = xfs_dir_createname ( tp , dp , link_name , ip - > i_ino , resblks ) ;
2013-04-03 09:11:18 +04:00
if ( error )
2018-07-24 23:43:13 +03:00
goto out_trans_cancel ;
2013-04-03 09:11:18 +04:00
xfs_trans_ichgtime ( tp , dp , XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG ) ;
xfs_trans_log_inode ( tp , dp , XFS_ILOG_CORE ) ;
/*
* If this is a synchronous mount , make sure that the
* symlink transaction goes to disk before returning to
* the user .
*/
2021-08-19 04:46:52 +03:00
if ( xfs_has_wsync ( mp ) | | xfs_has_dirsync ( mp ) )
2013-04-03 09:11:18 +04:00
xfs_trans_set_sync ( tp ) ;
2015-06-04 06:48:08 +03:00
error = xfs_trans_commit ( tp ) ;
2015-02-23 14:38:08 +03:00
if ( error )
goto out_release_inode ;
2013-04-03 09:11:18 +04:00
xfs_qm_dqrele ( udqp ) ;
xfs_qm_dqrele ( gdqp ) ;
2013-07-11 09:00:40 +04:00
xfs_qm_dqrele ( pdqp ) ;
2013-04-03 09:11:18 +04:00
* ipp = ip ;
return 0 ;
2015-02-23 14:38:08 +03:00
out_trans_cancel :
2015-06-04 06:47:56 +03:00
xfs_trans_cancel ( tp ) ;
2015-02-23 14:38:08 +03:00
out_release_inode :
/*
* Wait until after the current transaction is aborted to finish the
* setup of the inode and release the inode . This prevents recursive
* transactions and deadlocks from xfs_inactive .
*/
if ( ip ) {
xfs_finish_inode_setup ( ip ) ;
2018-07-25 22:52:32 +03:00
xfs_irele ( ip ) ;
2015-02-23 14:38:08 +03:00
}
2021-01-27 23:07:57 +03:00
out_release_dquots :
2013-04-03 09:11:18 +04:00
xfs_qm_dqrele ( udqp ) ;
xfs_qm_dqrele ( gdqp ) ;
2013-07-11 09:00:40 +04:00
xfs_qm_dqrele ( pdqp ) ;
2013-04-03 09:11:18 +04:00
if ( unlock_dp_on_error )
2016-11-30 06:33:25 +03:00
xfs_iunlock ( dp , XFS_ILOCK_EXCL ) ;
2013-04-03 09:11:18 +04:00
return error ;
}
/*
* Free a symlink that has blocks associated with it .
2018-12-12 19:46:21 +03:00
*
* Note : zero length symlinks are not allowed to exist . When we set the size to
* zero , also change it to a regular file so that it does not get written to
* disk as a zero length symlink . The inode is on the unlinked list already , so
* userspace cannot find this inode anymore , so this change is not user visible
* but allows us to catch corrupt zero - length symlinks in the verifiers .
2013-04-03 09:11:18 +04:00
*/
2013-06-18 00:35:57 +04:00
STATIC int
2013-04-03 09:11:18 +04:00
xfs_inactive_symlink_rmt (
2013-09-20 19:06:09 +04:00
struct xfs_inode * ip )
2013-04-03 09:11:18 +04:00
{
2020-12-17 03:07:34 +03:00
struct xfs_buf * bp ;
2013-04-03 09:11:18 +04:00
int done ;
int error ;
int i ;
xfs_mount_t * mp ;
xfs_bmbt_irec_t mval [ XFS_SYMLINK_MAPS ] ;
int nmaps ;
int size ;
xfs_trans_t * tp ;
mp = ip - > i_mount ;
2021-04-13 21:15:12 +03:00
ASSERT ( ! xfs_need_iread_extents ( & ip - > i_df ) ) ;
2013-04-03 09:11:18 +04:00
/*
* We ' re freeing a symlink that has some
* blocks allocated to it . Free the
* blocks here . We know that we ' ve got
* either 1 or 2 extents and that we can
* free them all in one bunmapi call .
*/
2020-05-18 20:27:22 +03:00
ASSERT ( ip - > i_df . if_nextents > 0 & & ip - > i_df . if_nextents < = 2 ) ;
2013-04-03 09:11:18 +04:00
2016-04-06 02:19:55 +03:00
error = xfs_trans_alloc ( mp , & M_RES ( mp ) - > tr_itruncate , 0 , 0 , 0 , & tp ) ;
if ( error )
2013-09-20 19:06:09 +04:00
return error ;
xfs_ilock ( ip , XFS_ILOCK_EXCL ) ;
xfs_trans_ijoin ( tp , ip , 0 ) ;
2013-04-03 09:11:18 +04:00
/*
2018-12-12 19:46:21 +03:00
* Lock the inode , fix the size , turn it into a regular file and join it
* to the transaction . Hold it so in the normal path , we still have it
* locked for the second transaction . In the error paths we need it
2013-04-03 09:11:18 +04:00
* held so the cancel won ' t rele it , see below .
*/
2021-03-29 21:11:40 +03:00
size = ( int ) ip - > i_disk_size ;
ip - > i_disk_size = 0 ;
2018-12-12 19:46:21 +03:00
VFS_I ( ip ) - > i_mode = ( VFS_I ( ip ) - > i_mode & ~ S_IFMT ) | S_IFREG ;
2013-04-03 09:11:18 +04:00
xfs_trans_log_inode ( tp , ip , XFS_ILOG_CORE ) ;
/*
* Find the block ( s ) so we can inval and unmap them .
*/
done = 0 ;
nmaps = ARRAY_SIZE ( mval ) ;
2013-04-03 09:11:19 +04:00
error = xfs_bmapi_read ( ip , 0 , xfs_symlink_blocks ( mp , size ) ,
2013-04-03 09:11:18 +04:00
mval , & nmaps , 0 ) ;
if ( error )
2013-09-20 19:06:09 +04:00
goto error_trans_cancel ;
2013-04-03 09:11:18 +04:00
/*
2013-04-03 09:11:19 +04:00
* Invalidate the block ( s ) . No validation is done .
2013-04-03 09:11:18 +04:00
*/
for ( i = 0 ; i < nmaps ; i + + ) {
2020-01-24 04:01:18 +03:00
error = xfs_trans_get_buf ( tp , mp - > m_ddev_targp ,
XFS_FSB_TO_DADDR ( mp , mval [ i ] . br_startblock ) ,
XFS_FSB_TO_BB ( mp , mval [ i ] . br_blockcount ) , 0 ,
& bp ) ;
if ( error )
2018-07-24 23:43:13 +03:00
goto error_trans_cancel ;
2013-04-03 09:11:18 +04:00
xfs_trans_binval ( tp , bp ) ;
}
/*
2016-08-03 04:19:29 +03:00
* Unmap the dead block ( s ) to the dfops .
2013-04-03 09:11:18 +04:00
*/
2018-07-12 08:26:25 +03:00
error = xfs_bunmapi ( tp , ip , 0 , size , 0 , nmaps , & done ) ;
2013-09-20 19:06:09 +04:00
if ( error )
2018-07-24 23:43:13 +03:00
goto error_trans_cancel ;
2013-04-03 09:11:18 +04:00
ASSERT ( done ) ;
2018-05-09 17:49:09 +03:00
2013-04-03 09:11:18 +04:00
/*
2018-07-24 23:43:13 +03:00
* Commit the transaction . This first logs the EFI and the inode , then
* rolls and commits the transaction that frees the extents .
2013-04-03 09:11:18 +04:00
*/
2018-05-09 17:49:09 +03:00
xfs_trans_log_inode ( tp , ip , XFS_ILOG_CORE ) ;
2015-06-04 06:48:08 +03:00
error = xfs_trans_commit ( tp ) ;
2013-04-03 09:11:18 +04:00
if ( error ) {
2021-08-19 04:46:53 +03:00
ASSERT ( xfs_is_shutdown ( mp ) ) ;
2013-09-20 19:06:09 +04:00
goto error_unlock ;
2013-04-03 09:11:18 +04:00
}
/*
* Remove the memory for extent descriptions ( just bookkeeping ) .
*/
if ( ip - > i_df . if_bytes )
xfs_idata_realloc ( ip , - ip - > i_df . if_bytes , XFS_DATA_FORK ) ;
ASSERT ( ip - > i_df . if_bytes = = 0 ) ;
2013-09-20 19:06:09 +04:00
xfs_iunlock ( ip , XFS_ILOCK_EXCL ) ;
2013-04-03 09:11:18 +04:00
return 0 ;
2013-09-20 19:06:09 +04:00
error_trans_cancel :
2015-06-04 06:47:56 +03:00
xfs_trans_cancel ( tp ) ;
2013-09-20 19:06:09 +04:00
error_unlock :
xfs_iunlock ( ip , XFS_ILOCK_EXCL ) ;
2013-04-03 09:11:18 +04:00
return error ;
}
2013-06-18 00:35:57 +04:00
/*
* xfs_inactive_symlink - free a symlink
*/
int
xfs_inactive_symlink (
2013-09-20 19:06:09 +04:00
struct xfs_inode * ip )
2013-06-18 00:35:57 +04:00
{
struct xfs_mount * mp = ip - > i_mount ;
int pathlen ;
trace_xfs_inactive_symlink ( ip ) ;
2021-08-19 04:46:53 +03:00
if ( xfs_is_shutdown ( mp ) )
2014-06-25 08:58:08 +04:00
return - EIO ;
2013-06-18 00:35:57 +04:00
2013-09-20 19:06:09 +04:00
xfs_ilock ( ip , XFS_ILOCK_EXCL ) ;
2021-03-29 21:11:40 +03:00
pathlen = ( int ) ip - > i_disk_size ;
2018-12-12 19:46:21 +03:00
ASSERT ( pathlen ) ;
2013-06-18 00:35:57 +04:00
2018-12-12 19:46:21 +03:00
if ( pathlen < = 0 | | pathlen > XFS_SYMLINK_MAXLEN ) {
2013-06-18 00:35:57 +04:00
xfs_alert ( mp , " %s: inode (0x%llx) bad symlink length (%d) " ,
__func__ , ( unsigned long long ) ip - > i_ino , pathlen ) ;
2013-09-20 19:06:09 +04:00
xfs_iunlock ( ip , XFS_ILOCK_EXCL ) ;
2013-06-18 00:35:57 +04:00
ASSERT ( 0 ) ;
2014-06-25 08:58:08 +04:00
return - EFSCORRUPTED ;
2013-06-18 00:35:57 +04:00
}
2018-12-12 19:46:21 +03:00
/*
* Inline fork state gets removed by xfs_difree ( ) so we have nothing to
* do here in that case .
*/
2021-04-13 21:15:11 +03:00
if ( ip - > i_df . if_format = = XFS_DINODE_FMT_LOCAL ) {
2013-09-20 19:06:09 +04:00
xfs_iunlock ( ip , XFS_ILOCK_EXCL ) ;
2013-06-18 00:35:57 +04:00
return 0 ;
}
2013-09-20 19:06:09 +04:00
xfs_iunlock ( ip , XFS_ILOCK_EXCL ) ;
2013-06-18 00:35:57 +04:00
/* remove the remote symlink */
2013-09-20 19:06:09 +04:00
return xfs_inactive_symlink_rmt ( ip ) ;
2013-06-18 00:35:57 +04:00
}