2006-01-16 19:50:04 +03:00
/*
* Copyright ( C ) Sistina Software , Inc . 1997 - 2003 All rights reserved .
2011-05-13 15:11:17 +04:00
* Copyright ( C ) 2004 - 2011 Red Hat , Inc . All rights reserved .
2006-01-16 19:50:04 +03:00
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2006-09-01 19:05:15 +04:00
* of the GNU General Public License version 2.
2006-01-16 19:50:04 +03:00
*/
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/completion.h>
# include <linux/buffer_head.h>
# include <linux/namei.h>
# include <linux/mm.h>
# include <linux/xattr.h>
# include <linux/posix_acl.h>
2006-02-28 01:23:27 +03:00
# include <linux/gfs2_ondisk.h>
2006-03-28 23:14:04 +04:00
# include <linux/crc32.h>
2008-10-14 17:43:29 +04:00
# include <linux/fiemap.h>
2011-05-09 17:06:38 +04:00
# include <linux/security.h>
2006-01-16 19:50:04 +03:00
# include <asm/uaccess.h>
# include "gfs2.h"
2006-02-28 01:23:27 +03:00
# include "incore.h"
2006-01-16 19:50:04 +03:00
# include "acl.h"
# include "bmap.h"
# include "dir.h"
2009-08-26 21:51:04 +04:00
# include "xattr.h"
2006-01-16 19:50:04 +03:00
# include "glock.h"
# include "inode.h"
# include "meta_io.h"
# include "quota.h"
# include "rgrp.h"
# include "trans.h"
2006-02-28 01:23:27 +03:00
# include "util.h"
2008-10-14 19:05:55 +04:00
# include "super.h"
2011-05-09 17:06:38 +04:00
# include "glops.h"
2015-03-27 16:25:41 +03:00
struct inode * gfs2_ilookup ( struct super_block * sb , u64 no_addr )
2011-05-09 17:06:38 +04:00
{
2015-03-27 16:25:41 +03:00
return ilookup ( sb , ( unsigned long ) no_addr ) ;
2011-05-09 17:06:38 +04:00
}
/**
* gfs2_set_iop - Sets inode operations
* @ inode : The inode with correct i_mode filled in
*
* GFS2 lookup code fills in vfs inode contents based on info obtained
* from directory entry inside gfs2_inode_lookup ( ) .
*/
static void gfs2_set_iop ( struct inode * inode )
{
struct gfs2_sbd * sdp = GFS2_SB ( inode ) ;
umode_t mode = inode - > i_mode ;
if ( S_ISREG ( mode ) ) {
inode - > i_op = & gfs2_file_iops ;
if ( gfs2_localflocks ( sdp ) )
inode - > i_fop = & gfs2_file_fops_nolock ;
else
inode - > i_fop = & gfs2_file_fops ;
} else if ( S_ISDIR ( mode ) ) {
inode - > i_op = & gfs2_dir_iops ;
if ( gfs2_localflocks ( sdp ) )
inode - > i_fop = & gfs2_dir_fops_nolock ;
else
inode - > i_fop = & gfs2_dir_fops ;
} else if ( S_ISLNK ( mode ) ) {
inode - > i_op = & gfs2_symlink_iops ;
} else {
inode - > i_op = & gfs2_file_iops ;
init_special_inode ( inode , inode - > i_mode , inode - > i_rdev ) ;
}
}
/**
* gfs2_inode_lookup - Lookup an inode
* @ sb : The super block
* @ no_addr : The inode number
* @ type : The type of the inode
*
* Returns : A VFS inode , or an error
*/
struct inode * gfs2_inode_lookup ( struct super_block * sb , unsigned int type ,
2015-12-18 20:44:49 +03:00
u64 no_addr , u64 no_formal_ino )
2011-05-09 17:06:38 +04:00
{
struct inode * inode ;
struct gfs2_inode * ip ;
struct gfs2_glock * io_gl = NULL ;
int error ;
2015-03-27 16:25:41 +03:00
inode = iget_locked ( sb , ( unsigned long ) no_addr ) ;
2011-05-09 17:06:38 +04:00
if ( ! inode )
2014-01-16 14:31:13 +04:00
return ERR_PTR ( - ENOMEM ) ;
2011-05-09 17:06:38 +04:00
2016-04-12 23:14:26 +03:00
ip = GFS2_I ( inode ) ;
ip - > i_no_addr = no_addr ;
2011-05-09 17:06:38 +04:00
if ( inode - > i_state & I_NEW ) {
struct gfs2_sbd * sdp = GFS2_SB ( inode ) ;
ip - > i_no_formal_ino = no_formal_ino ;
error = gfs2_glock_get ( sdp , no_addr , & gfs2_inode_glops , CREATE , & ip - > i_gl ) ;
if ( unlikely ( error ) )
goto fail ;
ip - > i_gl - > gl_object = ip ;
error = gfs2_glock_get ( sdp , no_addr , & gfs2_iopen_glops , CREATE , & io_gl ) ;
if ( unlikely ( error ) )
goto fail_put ;
set_bit ( GIF_INVALID , & ip - > i_flags ) ;
error = gfs2_glock_nq_init ( io_gl , LM_ST_SHARED , GL_EXACT , & ip - > i_iopen_gh ) ;
if ( unlikely ( error ) )
goto fail_iopen ;
ip - > i_iopen_gh . gh_gl - > gl_object = ip ;
gfs2_glock_put ( io_gl ) ;
io_gl = NULL ;
if ( type = = DT_UNKNOWN ) {
/* Inode glock must be locked already */
error = gfs2_inode_refresh ( GFS2_I ( inode ) ) ;
if ( error )
goto fail_refresh ;
} else {
inode - > i_mode = DT2IF ( type ) ;
}
gfs2_set_iop ( inode ) ;
unlock_new_inode ( inode ) ;
}
return inode ;
fail_refresh :
2013-05-29 19:51:52 +04:00
ip - > i_iopen_gh . gh_flags | = GL_NOCACHE ;
2011-05-09 17:06:38 +04:00
ip - > i_iopen_gh . gh_gl - > gl_object = NULL ;
2015-12-08 00:10:42 +03:00
gfs2_glock_dq_wait ( & ip - > i_iopen_gh ) ;
gfs2_holder_uninit ( & ip - > i_iopen_gh ) ;
2011-05-09 17:06:38 +04:00
fail_iopen :
if ( io_gl )
gfs2_glock_put ( io_gl ) ;
fail_put :
ip - > i_gl - > gl_object = NULL ;
fail :
iget_failed ( inode ) ;
return ERR_PTR ( error ) ;
}
struct inode * gfs2_lookup_by_inum ( struct gfs2_sbd * sdp , u64 no_addr ,
u64 * no_formal_ino , unsigned int blktype )
{
struct super_block * sb = sdp - > sd_vfs ;
struct gfs2_holder i_gh ;
struct inode * inode = NULL ;
int error ;
/* Must not read in block until block type is verified */
error = gfs2_glock_nq_num ( sdp , no_addr , & gfs2_inode_glops ,
LM_ST_EXCLUSIVE , GL_SKIP , & i_gh ) ;
if ( error )
return ERR_PTR ( error ) ;
error = gfs2_check_blk_type ( sdp , no_addr , blktype ) ;
if ( error )
goto fail ;
2015-12-18 20:44:49 +03:00
inode = gfs2_inode_lookup ( sb , DT_UNKNOWN , no_addr , 0 ) ;
2011-05-09 17:06:38 +04:00
if ( IS_ERR ( inode ) )
goto fail ;
/* Two extra checks for NFS only */
if ( no_formal_ino ) {
error = - ESTALE ;
if ( GFS2_I ( inode ) - > i_no_formal_ino ! = * no_formal_ino )
goto fail_iput ;
error = - EIO ;
if ( GFS2_I ( inode ) - > i_diskflags & GFS2_DIF_SYSTEM )
goto fail_iput ;
error = 0 ;
}
fail :
gfs2_glock_dq_uninit ( & i_gh ) ;
return error ? ERR_PTR ( error ) : inode ;
fail_iput :
iput ( inode ) ;
goto fail ;
}
struct inode * gfs2_lookup_simple ( struct inode * dip , const char * name )
{
struct qstr qstr ;
struct inode * inode ;
gfs2_str2qstr ( & qstr , name ) ;
inode = gfs2_lookupi ( dip , & qstr , 1 ) ;
/* gfs2_lookupi has inconsistent callers: vfs
* related routines expect NULL for no entry found ,
* gfs2_lookup_simple callers expect ENOENT
* and do not check for NULL .
*/
if ( inode = = NULL )
return ERR_PTR ( - ENOENT ) ;
else
return inode ;
}
/**
* gfs2_lookupi - Look up a filename in a directory and return its inode
* @ d_gh : An initialized holder for the directory glock
* @ name : The name of the inode to look for
* @ is_root : If 1 , ignore the caller ' s permissions
* @ i_gh : An uninitialized holder for the new inode glock
*
* This can be called via the VFS filldir function when NFS is doing
* a readdirplus and the inode which its intending to stat isn ' t
* already in cache . In this case we must not take the directory glock
* again , since the readdir call will have already taken that lock .
*
* Returns : errno
*/
struct inode * gfs2_lookupi ( struct inode * dir , const struct qstr * name ,
int is_root )
{
struct super_block * sb = dir - > i_sb ;
struct gfs2_inode * dip = GFS2_I ( dir ) ;
struct gfs2_holder d_gh ;
int error = 0 ;
struct inode * inode = NULL ;
int unlock = 0 ;
if ( ! name - > len | | name - > len > GFS2_FNAMESIZE )
return ERR_PTR ( - ENAMETOOLONG ) ;
if ( ( name - > len = = 1 & & memcmp ( name - > name , " . " , 1 ) = = 0 ) | |
( name - > len = = 2 & & memcmp ( name - > name , " .. " , 2 ) = = 0 & &
2015-03-18 01:25:59 +03:00
dir = = d_inode ( sb - > s_root ) ) ) {
2011-05-09 17:06:38 +04:00
igrab ( dir ) ;
return dir ;
}
if ( gfs2_glock_is_locked_by_me ( dip - > i_gl ) = = NULL ) {
error = gfs2_glock_nq_init ( dip - > i_gl , LM_ST_SHARED , 0 , & d_gh ) ;
if ( error )
return ERR_PTR ( error ) ;
unlock = 1 ;
}
if ( ! is_root ) {
2011-06-21 03:28:19 +04:00
error = gfs2_permission ( dir , MAY_EXEC ) ;
2011-05-09 17:06:38 +04:00
if ( error )
goto out ;
}
2013-06-11 16:45:29 +04:00
inode = gfs2_dir_search ( dir , name , false ) ;
2011-05-09 17:06:38 +04:00
if ( IS_ERR ( inode ) )
error = PTR_ERR ( inode ) ;
out :
if ( unlock )
gfs2_glock_dq_uninit ( & d_gh ) ;
if ( error = = - ENOENT )
return NULL ;
return inode ? inode : ERR_PTR ( error ) ;
}
/**
* create_ok - OK to create a new on - disk inode here ?
* @ dip : Directory in which dinode is to be created
* @ name : Name of new dinode
* @ mode :
*
* Returns : errno
*/
static int create_ok ( struct gfs2_inode * dip , const struct qstr * name ,
2011-07-26 11:30:54 +04:00
umode_t mode )
2011-05-09 17:06:38 +04:00
{
int error ;
2011-06-21 03:28:19 +04:00
error = gfs2_permission ( & dip - > i_inode , MAY_WRITE | MAY_EXEC ) ;
2011-05-09 17:06:38 +04:00
if ( error )
return error ;
/* Don't create entries in an unlinked directory */
if ( ! dip - > i_inode . i_nlink )
return - ENOENT ;
if ( dip - > i_entries = = ( u32 ) - 1 )
return - EFBIG ;
if ( S_ISDIR ( mode ) & & dip - > i_inode . i_nlink = = ( u32 ) - 1 )
return - EMLINK ;
return 0 ;
}
2012-10-31 14:30:22 +04:00
static void munge_mode_uid_gid ( const struct gfs2_inode * dip ,
struct inode * inode )
2011-05-09 17:06:38 +04:00
{
if ( GFS2_SB ( & dip - > i_inode ) - > sd_args . ar_suiddir & &
2013-02-01 09:56:13 +04:00
( dip - > i_inode . i_mode & S_ISUID ) & &
! uid_eq ( dip - > i_inode . i_uid , GLOBAL_ROOT_UID ) ) {
2012-10-31 14:30:22 +04:00
if ( S_ISDIR ( inode - > i_mode ) )
inode - > i_mode | = S_ISUID ;
2013-02-01 09:56:13 +04:00
else if ( ! uid_eq ( dip - > i_inode . i_uid , current_fsuid ( ) ) )
2012-10-31 14:30:22 +04:00
inode - > i_mode & = ~ 07111 ;
inode - > i_uid = dip - > i_inode . i_uid ;
2011-05-09 17:06:38 +04:00
} else
2012-10-31 14:30:22 +04:00
inode - > i_uid = current_fsuid ( ) ;
2011-05-09 17:06:38 +04:00
if ( dip - > i_inode . i_mode & S_ISGID ) {
2012-10-31 14:30:22 +04:00
if ( S_ISDIR ( inode - > i_mode ) )
inode - > i_mode | = S_ISGID ;
inode - > i_gid = dip - > i_inode . i_gid ;
2011-05-09 17:06:38 +04:00
} else
2012-10-31 14:30:22 +04:00
inode - > i_gid = current_fsgid ( ) ;
2011-05-09 17:06:38 +04:00
}
2014-02-04 19:45:11 +04:00
static int alloc_dinode ( struct gfs2_inode * ip , u32 flags , unsigned * dblocks )
2011-05-09 17:06:38 +04:00
{
2012-10-31 14:30:22 +04:00
struct gfs2_sbd * sdp = GFS2_SB ( & ip - > i_inode ) ;
2014-02-04 19:45:11 +04:00
struct gfs2_alloc_parms ap = { . target = * dblocks , . aflags = flags , } ;
2011-05-09 17:06:38 +04:00
int error ;
2015-03-18 20:03:41 +03:00
error = gfs2_quota_lock_check ( ip , & ap ) ;
2011-05-09 17:06:38 +04:00
if ( error )
goto out ;
2013-10-02 14:13:25 +04:00
error = gfs2_inplace_reserve ( ip , & ap ) ;
2013-02-26 20:15:20 +04:00
if ( error )
goto out_quota ;
2014-02-04 19:45:11 +04:00
error = gfs2_trans_begin ( sdp , ( * dblocks * RES_RG_BIT ) + RES_STATFS + RES_QUOTA , 0 ) ;
2011-05-09 17:06:38 +04:00
if ( error )
goto out_ipreserv ;
2014-02-04 19:45:11 +04:00
error = gfs2_alloc_blocks ( ip , & ip - > i_no_addr , dblocks , 1 , & ip - > i_generation ) ;
2012-10-31 14:30:22 +04:00
ip - > i_no_formal_ino = ip - > i_generation ;
ip - > i_inode . i_ino = ip - > i_no_addr ;
ip - > i_goal = ip - > i_no_addr ;
2011-05-09 17:06:38 +04:00
gfs2_trans_end ( sdp ) ;
out_ipreserv :
2012-10-31 14:30:22 +04:00
gfs2_inplace_release ( ip ) ;
2013-02-26 20:15:20 +04:00
out_quota :
gfs2_quota_unlock ( ip ) ;
2011-05-09 17:06:38 +04:00
out :
return error ;
}
2011-05-13 15:11:17 +04:00
static void gfs2_init_dir ( struct buffer_head * dibh ,
const struct gfs2_inode * parent )
2011-05-13 12:55:55 +04:00
{
struct gfs2_dinode * di = ( struct gfs2_dinode * ) dibh - > b_data ;
struct gfs2_dirent * dent = ( struct gfs2_dirent * ) ( di + 1 ) ;
gfs2_qstr2dirent ( & gfs2_qdot , GFS2_DIRENT_SIZE ( gfs2_qdot . len ) , dent ) ;
dent - > de_inum = di - > di_num ; /* already GFS2 endian */
dent - > de_type = cpu_to_be16 ( DT_DIR ) ;
dent = ( struct gfs2_dirent * ) ( ( char * ) dent + GFS2_DIRENT_SIZE ( 1 ) ) ;
gfs2_qstr2dirent ( & gfs2_qdotdot , dibh - > b_size - GFS2_DIRENT_SIZE ( 1 ) - sizeof ( struct gfs2_dinode ) , dent ) ;
gfs2_inum_out ( parent , dent ) ;
dent - > de_type = cpu_to_be16 ( DT_DIR ) ;
}
2014-02-04 19:45:11 +04:00
/**
* gfs2_init_xattr - Initialise an xattr block for a new inode
* @ ip : The inode in question
*
* This sets up an empty xattr block for a new inode , ready to
* take any ACLs , LSM xattrs , etc .
*/
static void gfs2_init_xattr ( struct gfs2_inode * ip )
{
struct gfs2_sbd * sdp = GFS2_SB ( & ip - > i_inode ) ;
struct buffer_head * bh ;
struct gfs2_ea_header * ea ;
bh = gfs2_meta_new ( ip - > i_gl , ip - > i_eattr ) ;
gfs2_trans_add_meta ( ip - > i_gl , bh ) ;
gfs2_metatype_set ( bh , GFS2_METATYPE_EA , GFS2_FORMAT_EA ) ;
gfs2_buffer_clear_tail ( bh , sizeof ( struct gfs2_meta_header ) ) ;
ea = GFS2_EA_BH2FIRST ( bh ) ;
ea - > ea_rec_len = cpu_to_be32 ( sdp - > sd_jbsize ) ;
ea - > ea_type = GFS2_EATYPE_UNUSED ;
ea - > ea_flags = GFS2_EAFLAG_LAST ;
brelse ( bh ) ;
}
2011-05-09 17:06:38 +04:00
/**
* init_dinode - Fill in a new dinode structure
2011-05-13 15:11:17 +04:00
* @ dip : The directory this inode is being created in
2012-10-31 14:30:22 +04:00
* @ ip : The inode
2011-05-13 15:11:17 +04:00
* @ symname : The symlink destination ( if a symlink )
* @ bhp : The buffer head ( returned to caller )
2011-05-09 17:06:38 +04:00
*
*/
2012-10-31 14:30:22 +04:00
static void init_dinode ( struct gfs2_inode * dip , struct gfs2_inode * ip ,
2013-03-01 13:29:12 +04:00
const char * symname )
2011-05-09 17:06:38 +04:00
{
struct gfs2_dinode * di ;
struct buffer_head * dibh ;
2012-10-31 14:30:22 +04:00
dibh = gfs2_meta_new ( ip - > i_gl , ip - > i_no_addr ) ;
2012-12-14 16:36:02 +04:00
gfs2_trans_add_meta ( ip - > i_gl , dibh ) ;
2011-05-09 17:06:38 +04:00
di = ( struct gfs2_dinode * ) dibh - > b_data ;
2013-03-01 13:29:12 +04:00
gfs2_dinode_out ( ip , di ) ;
2011-05-09 17:06:38 +04:00
2012-10-31 14:30:22 +04:00
di - > di_major = cpu_to_be32 ( MAJOR ( ip - > i_inode . i_rdev ) ) ;
di - > di_minor = cpu_to_be32 ( MINOR ( ip - > i_inode . i_rdev ) ) ;
2011-05-09 17:06:38 +04:00
di - > __pad1 = 0 ;
di - > __pad2 = 0 ;
di - > __pad3 = 0 ;
memset ( & di - > __pad4 , 0 , sizeof ( di - > __pad4 ) ) ;
memset ( & di - > di_reserved , 0 , sizeof ( di - > di_reserved ) ) ;
2013-03-01 13:29:12 +04:00
gfs2_buffer_clear_tail ( dibh , sizeof ( struct gfs2_dinode ) ) ;
2011-05-13 13:34:59 +04:00
2012-10-31 14:30:22 +04:00
switch ( ip - > i_inode . i_mode & S_IFMT ) {
2011-05-13 13:34:59 +04:00
case S_IFDIR :
2011-05-13 12:55:55 +04:00
gfs2_init_dir ( dibh , dip ) ;
2011-05-13 13:34:59 +04:00
break ;
case S_IFLNK :
2012-10-31 14:30:22 +04:00
memcpy ( dibh - > b_data + sizeof ( struct gfs2_dinode ) , symname , ip - > i_inode . i_size ) ;
2011-05-13 13:34:59 +04:00
break ;
2011-05-13 12:55:55 +04:00
}
2011-05-09 17:06:38 +04:00
set_buffer_uptodate ( dibh ) ;
2013-03-01 13:29:12 +04:00
brelse ( dibh ) ;
2011-05-09 17:06:38 +04:00
}
2014-01-06 16:03:05 +04:00
/**
* gfs2_trans_da_blocks - Calculate number of blocks to link inode
* @ dip : The directory we are linking into
* @ da : The dir add information
* @ nr_inodes : The number of inodes involved
*
* This calculate the number of blocks we need to reserve in a
* transaction to link @ nr_inodes into a directory . In most cases
* @ nr_inodes will be 2 ( the directory plus the inode being linked in )
* but in case of rename , 4 may be required .
*
* Returns : Number of blocks
*/
static unsigned gfs2_trans_da_blks ( const struct gfs2_inode * dip ,
const struct gfs2_diradd * da ,
unsigned nr_inodes )
{
return da - > nr_blocks + gfs2_rg_blocks ( dip , da - > nr_blocks ) +
( nr_inodes * RES_DINODE ) + RES_QUOTA + RES_STATFS ;
}
2011-05-09 17:06:38 +04:00
static int link_dinode ( struct gfs2_inode * dip , const struct qstr * name ,
2014-01-06 15:28:41 +04:00
struct gfs2_inode * ip , struct gfs2_diradd * da )
2011-05-09 17:06:38 +04:00
{
struct gfs2_sbd * sdp = GFS2_SB ( & dip - > i_inode ) ;
2014-01-06 15:28:41 +04:00
struct gfs2_alloc_parms ap = { . target = da - > nr_blocks , } ;
2011-05-09 17:06:38 +04:00
int error ;
2014-01-06 15:28:41 +04:00
if ( da - > nr_blocks ) {
2015-03-18 20:03:41 +03:00
error = gfs2_quota_lock_check ( dip , & ap ) ;
2011-05-09 17:06:38 +04:00
if ( error )
goto fail_quota_locks ;
2013-10-02 14:13:25 +04:00
error = gfs2_inplace_reserve ( dip , & ap ) ;
2011-05-09 17:06:38 +04:00
if ( error )
goto fail_quota_locks ;
2014-01-06 16:03:05 +04:00
error = gfs2_trans_begin ( sdp , gfs2_trans_da_blks ( dip , da , 2 ) , 0 ) ;
2011-05-09 17:06:38 +04:00
if ( error )
goto fail_ipreserv ;
} else {
error = gfs2_trans_begin ( sdp , RES_LEAF + 2 * RES_DINODE , 0 ) ;
if ( error )
goto fail_quota_locks ;
}
2014-01-06 16:49:43 +04:00
error = gfs2_dir_add ( & dip - > i_inode , name , ip , da ) ;
2011-05-09 17:06:38 +04:00
gfs2_trans_end ( sdp ) ;
fail_ipreserv :
2013-02-26 20:15:20 +04:00
gfs2_inplace_release ( dip ) ;
2011-05-09 17:06:38 +04:00
fail_quota_locks :
gfs2_quota_unlock ( dip ) ;
return error ;
}
2011-09-24 02:51:32 +04:00
static int gfs2_initxattrs ( struct inode * inode , const struct xattr * xattr_array ,
2011-06-06 23:29:25 +04:00
void * fs_info )
2011-05-09 17:06:38 +04:00
{
2011-06-06 23:29:25 +04:00
const struct xattr * xattr ;
int err = 0 ;
for ( xattr = xattr_array ; xattr - > name ! = NULL ; xattr + + ) {
err = __gfs2_xattr_set ( inode , xattr - > name , xattr - > value ,
xattr - > value_len , 0 ,
GFS2_EATYPE_SECURITY ) ;
if ( err < 0 )
break ;
2011-05-09 17:06:38 +04:00
}
return err ;
}
2006-01-16 19:50:04 +03:00
2011-05-09 17:06:38 +04:00
/**
2011-05-13 15:11:17 +04:00
* gfs2_create_inode - Create a new inode
* @ dir : The parent directory
* @ dentry : The new dentry
2013-06-14 14:17:15 +04:00
* @ file : If non - NULL , the file which is being opened
2011-05-13 15:11:17 +04:00
* @ mode : The permissions on the new inode
* @ dev : For device nodes , this is the device number
* @ symname : For symlinks , this is the link destination
* @ size : The initial size of the inode ( ignored for directories )
2011-05-09 17:06:38 +04:00
*
2011-05-13 15:11:17 +04:00
* Returns : 0 on success , or error code
2011-05-09 17:06:38 +04:00
*/
2011-05-13 15:11:17 +04:00
static int gfs2_create_inode ( struct inode * dir , struct dentry * dentry ,
2013-06-14 14:17:15 +04:00
struct file * file ,
2011-07-26 11:30:54 +04:00
umode_t mode , dev_t dev , const char * symname ,
2013-06-14 14:17:15 +04:00
unsigned int size , int excl , int * opened )
2011-05-09 17:06:38 +04:00
{
2011-05-13 15:11:17 +04:00
const struct qstr * name = & dentry - > d_name ;
2013-12-20 17:16:52 +04:00
struct posix_acl * default_acl , * acl ;
2011-05-13 15:11:17 +04:00
struct gfs2_holder ghs [ 2 ] ;
2011-05-09 17:06:38 +04:00
struct inode * inode = NULL ;
2012-07-19 16:12:40 +04:00
struct gfs2_inode * dip = GFS2_I ( dir ) , * ip ;
2011-05-09 17:06:38 +04:00
struct gfs2_sbd * sdp = GFS2_SB ( & dip - > i_inode ) ;
2015-12-08 01:24:27 +03:00
struct gfs2_glock * io_gl = NULL ;
2015-12-04 19:19:14 +03:00
int error , free_vfs_inode = 1 ;
2012-10-31 14:37:10 +04:00
u32 aflags = 0 ;
2014-02-04 19:45:11 +04:00
unsigned blocks = 1 ;
2014-09-29 16:52:04 +04:00
struct gfs2_diradd da = { . bh = NULL , . save_loc = 1 , } ;
2011-05-09 17:06:38 +04:00
if ( ! name - > len | | name - > len > GFS2_FNAMESIZE )
2011-05-13 15:11:17 +04:00
return - ENAMETOOLONG ;
2011-05-09 17:06:38 +04:00
2015-10-26 18:40:28 +03:00
error = gfs2_rsqa_alloc ( dip ) ;
2012-06-06 14:17:59 +04:00
if ( error )
return error ;
2013-02-26 20:15:20 +04:00
error = gfs2_rindex_update ( sdp ) ;
if ( error )
return error ;
2011-05-13 15:11:17 +04:00
error = gfs2_glock_nq_init ( dip - > i_gl , LM_ST_EXCLUSIVE , 0 , ghs ) ;
2011-05-09 17:06:38 +04:00
if ( error )
goto fail ;
error = create_ok ( dip , name , mode ) ;
2013-06-11 16:45:29 +04:00
if ( error )
goto fail_gunlock ;
inode = gfs2_dir_search ( dir , & dentry - > d_name , ! S_ISREG ( mode ) | | excl ) ;
error = PTR_ERR ( inode ) ;
if ( ! IS_ERR ( inode ) ) {
2014-11-19 22:34:49 +03:00
if ( S_ISDIR ( inode - > i_mode ) ) {
iput ( inode ) ;
inode = ERR_PTR ( - EISDIR ) ;
goto fail_gunlock ;
}
2014-11-19 22:35:24 +03:00
d_instantiate ( dentry , inode ) ;
2013-06-14 14:17:15 +04:00
error = 0 ;
2013-09-16 16:52:00 +04:00
if ( file ) {
2014-11-19 22:35:24 +03:00
if ( S_ISREG ( inode - > i_mode ) )
2013-09-23 16:21:04 +04:00
error = finish_open ( file , dentry , gfs2_open_common , opened ) ;
2014-11-19 22:35:24 +03:00
else
error = finish_no_open ( file , NULL ) ;
2013-06-14 14:17:15 +04:00
}
2011-08-18 17:35:53 +04:00
gfs2_glock_dq_uninit ( ghs ) ;
2013-06-14 14:17:15 +04:00
return error ;
2013-06-11 16:45:29 +04:00
} else if ( error ! = - ENOENT ) {
2011-05-09 17:06:38 +04:00
goto fail_gunlock ;
2013-06-11 16:45:29 +04:00
}
2011-05-09 17:06:38 +04:00
2014-01-06 15:28:41 +04:00
error = gfs2_diradd_alloc_required ( dir , name , & da ) ;
2013-02-26 20:15:20 +04:00
if ( error < 0 )
goto fail_gunlock ;
2012-10-31 14:30:22 +04:00
inode = new_inode ( sdp - > sd_vfs ) ;
2013-02-26 20:15:20 +04:00
error = - ENOMEM ;
if ( ! inode )
goto fail_gunlock ;
2013-12-20 17:16:52 +04:00
error = posix_acl_create ( dir , & mode , & default_acl , & acl ) ;
if ( error )
2015-12-04 19:19:14 +03:00
goto fail_gunlock ;
2013-12-20 17:16:52 +04:00
2012-10-31 14:30:22 +04:00
ip = GFS2_I ( inode ) ;
2015-10-26 18:40:28 +03:00
error = gfs2_rsqa_alloc ( ip ) ;
2011-05-09 17:06:38 +04:00
if ( error )
2013-12-20 17:16:52 +04:00
goto fail_free_acls ;
2012-10-31 14:30:22 +04:00
inode - > i_mode = mode ;
2013-03-01 13:29:12 +04:00
set_nlink ( inode , S_ISDIR ( mode ) ? 2 : 1 ) ;
2012-10-31 14:30:22 +04:00
inode - > i_rdev = dev ;
inode - > i_size = size ;
2013-02-26 20:15:20 +04:00
inode - > i_atime = inode - > i_mtime = inode - > i_ctime = CURRENT_TIME ;
2013-02-26 23:09:35 +04:00
gfs2_set_inode_blocks ( inode , 1 ) ;
2012-10-31 14:30:22 +04:00
munge_mode_uid_gid ( dip , inode ) ;
2014-09-19 06:40:28 +04:00
check_and_update_goal ( dip ) ;
2012-10-31 14:30:22 +04:00
ip - > i_goal = dip - > i_goal ;
2013-02-26 23:09:35 +04:00
ip - > i_diskflags = 0 ;
ip - > i_eattr = 0 ;
ip - > i_height = 0 ;
ip - > i_depth = 0 ;
ip - > i_entries = 0 ;
switch ( mode & S_IFMT ) {
case S_IFREG :
if ( ( dip - > i_diskflags & GFS2_DIF_INHERIT_JDATA ) | |
gfs2_tune_get ( sdp , gt_new_files_jdata ) )
ip - > i_diskflags | = GFS2_DIF_JDATA ;
gfs2_set_aops ( inode ) ;
break ;
case S_IFDIR :
ip - > i_diskflags | = ( dip - > i_diskflags & GFS2_DIF_INHERIT_JDATA ) ;
ip - > i_diskflags | = GFS2_DIF_JDATA ;
ip - > i_entries = 2 ;
break ;
}
2015-11-11 00:07:26 +03:00
/* Force SYSTEM flag on all files and subdirs of a SYSTEM directory */
if ( dip - > i_diskflags & GFS2_DIF_SYSTEM )
ip - > i_diskflags | = GFS2_DIF_SYSTEM ;
2013-02-26 23:09:35 +04:00
gfs2_set_inode_flags ( inode ) ;
2011-05-09 17:06:38 +04:00
2015-03-18 01:25:59 +03:00
if ( ( GFS2_I ( d_inode ( sdp - > sd_root_dir ) ) = = dip ) | |
2012-10-31 14:37:10 +04:00
( dip - > i_diskflags & GFS2_DIF_TOPDIR ) )
aflags | = GFS2_AF_ORLOV ;
2014-02-04 19:45:11 +04:00
if ( default_acl | | acl )
blocks + + ;
error = alloc_dinode ( ip , aflags , & blocks ) ;
2011-05-09 17:06:38 +04:00
if ( error )
2012-10-31 14:30:22 +04:00
goto fail_free_inode ;
2011-05-09 17:06:38 +04:00
2014-02-04 19:45:11 +04:00
gfs2_set_inode_blocks ( inode , blocks ) ;
2012-10-31 14:30:22 +04:00
error = gfs2_glock_get ( sdp , ip - > i_no_addr , & gfs2_inode_glops , CREATE , & ip - > i_gl ) ;
2011-05-09 17:06:38 +04:00
if ( error )
2012-10-31 14:30:22 +04:00
goto fail_free_inode ;
2011-05-09 17:06:38 +04:00
2012-11-21 18:56:00 +04:00
ip - > i_gl - > gl_object = ip ;
2012-10-31 14:30:22 +04:00
error = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_EXCLUSIVE , GL_SKIP , ghs + 1 ) ;
if ( error )
goto fail_free_inode ;
2014-02-04 19:45:11 +04:00
error = gfs2_trans_begin ( sdp , blocks , 0 ) ;
2012-10-31 14:30:22 +04:00
if ( error )
2011-05-09 17:06:38 +04:00
goto fail_gunlock2 ;
2014-02-04 19:45:11 +04:00
if ( blocks > 1 ) {
ip - > i_eattr = ip - > i_no_addr + 1 ;
gfs2_init_xattr ( ip ) ;
}
2013-03-01 13:29:12 +04:00
init_dinode ( dip , ip , symname ) ;
2013-02-26 20:15:20 +04:00
gfs2_trans_end ( sdp ) ;
2012-10-31 14:30:22 +04:00
error = gfs2_glock_get ( sdp , ip - > i_no_addr , & gfs2_iopen_glops , CREATE , & io_gl ) ;
2011-05-09 17:06:38 +04:00
if ( error )
goto fail_gunlock2 ;
2015-12-08 01:24:27 +03:00
BUG_ON ( test_and_set_bit ( GLF_INODE_CREATING , & io_gl - > gl_flags ) ) ;
2012-10-31 14:30:22 +04:00
error = gfs2_glock_nq_init ( io_gl , LM_ST_SHARED , GL_EXACT , & ip - > i_iopen_gh ) ;
2012-09-10 13:03:50 +04:00
if ( error )
goto fail_gunlock2 ;
2012-06-06 14:17:59 +04:00
2012-10-31 14:30:22 +04:00
ip - > i_iopen_gh . gh_gl - > gl_object = ip ;
gfs2_glock_put ( io_gl ) ;
gfs2_set_iop ( inode ) ;
insert_inode_hash ( inode ) ;
2015-12-04 19:19:14 +03:00
free_vfs_inode = 0 ; /* After this point, the inode is no longer
considered free . Any failures need to undo
the gfs2 structures . */
2013-12-20 17:16:52 +04:00
if ( default_acl ) {
2016-05-13 04:59:17 +03:00
error = __gfs2_set_acl ( inode , default_acl , ACL_TYPE_DEFAULT ) ;
2013-12-20 17:16:52 +04:00
posix_acl_release ( default_acl ) ;
}
if ( acl ) {
if ( ! error )
2016-05-13 04:59:17 +03:00
error = __gfs2_set_acl ( inode , acl , ACL_TYPE_ACCESS ) ;
2013-12-20 17:16:52 +04:00
posix_acl_release ( acl ) ;
}
2011-05-09 17:06:38 +04:00
if ( error )
2012-10-31 14:30:22 +04:00
goto fail_gunlock3 ;
2011-05-09 17:06:38 +04:00
2014-03-19 17:37:00 +04:00
error = security_inode_init_security ( & ip - > i_inode , & dip - > i_inode , name ,
& gfs2_initxattrs , NULL ) ;
2011-05-09 17:06:38 +04:00
if ( error )
2012-10-31 14:30:22 +04:00
goto fail_gunlock3 ;
2011-05-09 17:06:38 +04:00
2014-01-06 15:28:41 +04:00
error = link_dinode ( dip , name , ip , & da ) ;
2011-05-09 17:06:38 +04:00
if ( error )
2012-10-31 14:30:22 +04:00
goto fail_gunlock3 ;
2011-05-09 17:06:38 +04:00
2013-03-01 13:29:12 +04:00
mark_inode_dirty ( inode ) ;
2013-06-14 14:17:15 +04:00
d_instantiate ( dentry , inode ) ;
2013-09-16 16:52:03 +04:00
if ( file ) {
* opened | = FILE_CREATED ;
2013-06-14 14:17:15 +04:00
error = finish_open ( file , dentry , gfs2_open_common , opened ) ;
2013-09-16 16:52:03 +04:00
}
2013-02-26 23:09:35 +04:00
gfs2_glock_dq_uninit ( ghs ) ;
gfs2_glock_dq_uninit ( ghs + 1 ) ;
2015-12-08 01:24:27 +03:00
clear_bit ( GLF_INODE_CREATING , & io_gl - > gl_flags ) ;
2013-06-14 14:17:15 +04:00
return error ;
2011-05-09 17:06:38 +04:00
2012-10-31 14:30:22 +04:00
fail_gunlock3 :
2015-12-04 19:19:14 +03:00
gfs2_glock_dq_uninit ( & ip - > i_iopen_gh ) ;
gfs2_glock_put ( io_gl ) ;
2011-05-09 17:06:38 +04:00
fail_gunlock2 :
2015-12-08 01:24:27 +03:00
if ( io_gl )
clear_bit ( GLF_INODE_CREATING , & io_gl - > gl_flags ) ;
2011-05-09 17:06:38 +04:00
gfs2_glock_dq_uninit ( ghs + 1 ) ;
2012-10-31 14:30:22 +04:00
fail_free_inode :
if ( ip - > i_gl )
gfs2_glock_put ( ip - > i_gl ) ;
2015-10-26 18:40:28 +03:00
gfs2_rsqa_delete ( ip , NULL ) ;
2013-12-20 17:16:52 +04:00
fail_free_acls :
if ( default_acl )
posix_acl_release ( default_acl ) ;
if ( acl )
posix_acl_release ( acl ) ;
2011-05-09 17:06:38 +04:00
fail_gunlock :
2014-01-06 16:49:43 +04:00
gfs2_dir_no_add ( & da ) ;
2011-05-13 15:11:17 +04:00
gfs2_glock_dq_uninit ( ghs ) ;
2011-08-02 16:17:27 +04:00
if ( inode & & ! IS_ERR ( inode ) ) {
2013-03-01 13:29:12 +04:00
clear_nlink ( inode ) ;
2014-03-31 19:33:17 +04:00
if ( ! free_vfs_inode )
mark_inode_dirty ( inode ) ;
set_bit ( free_vfs_inode ? GIF_FREE_VFS_INODE : GIF_ALLOC_FAILED ,
& GFS2_I ( inode ) - > i_flags ) ;
2011-08-02 16:17:27 +04:00
iput ( inode ) ;
}
2011-05-09 17:06:38 +04:00
fail :
2011-05-13 15:11:17 +04:00
return error ;
2011-05-09 17:06:38 +04:00
}
2011-05-13 15:11:17 +04:00
2006-01-16 19:50:04 +03:00
/**
* gfs2_create - Create a file
* @ dir : The directory in which to create the file
* @ dentry : The dentry of the new file
* @ mode : The mode of the new file
*
* Returns : errno
*/
static int gfs2_create ( struct inode * dir , struct dentry * dentry ,
2012-06-11 02:05:36 +04:00
umode_t mode , bool excl )
2006-01-16 19:50:04 +03:00
{
2013-06-14 14:17:15 +04:00
return gfs2_create_inode ( dir , dentry , NULL , S_IFREG | mode , 0 , NULL , 0 , excl , NULL ) ;
2006-01-16 19:50:04 +03:00
}
/**
2013-06-14 14:17:15 +04:00
* __gfs2_lookup - Look up a filename in a directory and return its inode
2006-01-16 19:50:04 +03:00
* @ dir : The directory inode
* @ dentry : The dentry of the new inode
2013-06-14 14:17:15 +04:00
* @ file : File to be opened
* @ opened : atomic_open flags
2006-01-16 19:50:04 +03:00
*
*
* Returns : errno
*/
2013-06-14 14:17:15 +04:00
static struct dentry * __gfs2_lookup ( struct inode * dir , struct dentry * dentry ,
struct file * file , int * opened )
2006-01-16 19:50:04 +03:00
{
2013-06-14 14:17:15 +04:00
struct inode * inode ;
struct dentry * d ;
struct gfs2_holder gh ;
struct gfs2_glock * gl ;
int error ;
inode = gfs2_lookupi ( dir , & dentry - > d_name , 0 ) ;
2014-09-10 22:09:20 +04:00
if ( inode = = NULL ) {
d_add ( dentry , NULL ) ;
2013-06-14 14:17:15 +04:00
return NULL ;
2014-09-10 22:09:20 +04:00
}
2013-06-14 14:17:15 +04:00
if ( IS_ERR ( inode ) )
return ERR_CAST ( inode ) ;
gl = GFS2_I ( inode ) - > i_gl ;
error = gfs2_glock_nq_init ( gl , LM_ST_SHARED , LM_FLAG_ANY , & gh ) ;
if ( error ) {
iput ( inode ) ;
return ERR_PTR ( error ) ;
2008-01-08 11:14:30 +03:00
}
2013-06-14 14:17:15 +04:00
d = d_splice_alias ( inode , dentry ) ;
2014-01-16 22:51:07 +04:00
if ( IS_ERR ( d ) ) {
gfs2_glock_dq_uninit ( & gh ) ;
return d ;
}
2013-06-14 14:17:15 +04:00
if ( file & & S_ISREG ( inode - > i_mode ) )
error = finish_open ( file , dentry , gfs2_open_common , opened ) ;
gfs2_glock_dq_uninit ( & gh ) ;
2013-09-23 16:21:04 +04:00
if ( error ) {
dput ( d ) ;
2013-06-14 14:17:15 +04:00
return ERR_PTR ( error ) ;
2013-09-23 16:21:04 +04:00
}
2013-06-14 14:17:15 +04:00
return d ;
}
static struct dentry * gfs2_lookup ( struct inode * dir , struct dentry * dentry ,
unsigned flags )
{
return __gfs2_lookup ( dir , dentry , NULL , NULL ) ;
2006-01-16 19:50:04 +03:00
}
/**
* gfs2_link - Link to a file
* @ old_dentry : The inode to link
* @ dir : Add link to this directory
* @ dentry : The name of the link
*
* Link the inode in " old_dentry " into the directory " dir " with the
* name in " dentry " .
*
* Returns : errno
*/
static int gfs2_link ( struct dentry * old_dentry , struct inode * dir ,
struct dentry * dentry )
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * dip = GFS2_I ( dir ) ;
struct gfs2_sbd * sdp = GFS2_SB ( dir ) ;
2015-03-18 01:25:59 +03:00
struct inode * inode = d_inode ( old_dentry ) ;
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( inode ) ;
2006-01-16 19:50:04 +03:00
struct gfs2_holder ghs [ 2 ] ;
2011-05-09 15:08:36 +04:00
struct buffer_head * dibh ;
2014-09-29 16:52:04 +04:00
struct gfs2_diradd da = { . bh = NULL , . save_loc = 1 , } ;
2006-01-16 19:50:04 +03:00
int error ;
2006-11-01 20:22:46 +03:00
if ( S_ISDIR ( inode - > i_mode ) )
2006-01-16 19:50:04 +03:00
return - EPERM ;
2015-10-26 18:40:28 +03:00
error = gfs2_rsqa_alloc ( dip ) ;
2012-06-06 14:17:59 +04:00
if ( error )
return error ;
2006-01-16 19:50:04 +03:00
gfs2_holder_init ( dip - > i_gl , LM_ST_EXCLUSIVE , 0 , ghs ) ;
gfs2_holder_init ( ip - > i_gl , LM_ST_EXCLUSIVE , 0 , ghs + 1 ) ;
2008-08-12 22:39:29 +04:00
error = gfs2_glock_nq ( ghs ) ; /* parent */
if ( error )
goto out_parent ;
error = gfs2_glock_nq ( ghs + 1 ) ; /* child */
2006-01-16 19:50:04 +03:00
if ( error )
2008-08-12 22:39:29 +04:00
goto out_child ;
2006-01-16 19:50:04 +03:00
2011-05-05 15:35:40 +04:00
error = - ENOENT ;
if ( inode - > i_nlink = = 0 )
goto out_gunlock ;
2011-06-21 03:28:19 +04:00
error = gfs2_permission ( dir , MAY_WRITE | MAY_EXEC ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_gunlock ;
2007-05-15 18:37:50 +04:00
error = gfs2_dir_check ( dir , & dentry - > d_name , NULL ) ;
2006-01-16 19:50:04 +03:00
switch ( error ) {
case - ENOENT :
break ;
case 0 :
error = - EEXIST ;
default :
goto out_gunlock ;
}
error = - EINVAL ;
2006-11-01 22:04:17 +03:00
if ( ! dip - > i_inode . i_nlink )
2006-01-16 19:50:04 +03:00
goto out_gunlock ;
error = - EFBIG ;
2008-11-03 16:59:19 +03:00
if ( dip - > i_entries = = ( u32 ) - 1 )
2006-01-16 19:50:04 +03:00
goto out_gunlock ;
error = - EPERM ;
if ( IS_IMMUTABLE ( inode ) | | IS_APPEND ( inode ) )
goto out_gunlock ;
error = - EINVAL ;
2006-11-01 22:04:17 +03:00
if ( ! ip - > i_inode . i_nlink )
2006-01-16 19:50:04 +03:00
goto out_gunlock ;
error = - EMLINK ;
2006-11-01 22:04:17 +03:00
if ( ip - > i_inode . i_nlink = = ( u32 ) - 1 )
2006-01-16 19:50:04 +03:00
goto out_gunlock ;
2014-01-06 15:28:41 +04:00
error = gfs2_diradd_alloc_required ( dir , & dentry - > d_name , & da ) ;
2006-03-20 20:30:04 +03:00
if ( error < 0 )
2006-01-16 19:50:04 +03:00
goto out_gunlock ;
2014-01-06 15:28:41 +04:00
if ( da . nr_blocks ) {
struct gfs2_alloc_parms ap = { . target = da . nr_blocks , } ;
2015-03-18 20:03:41 +03:00
error = gfs2_quota_lock_check ( dip , & ap ) ;
2006-01-16 19:50:04 +03:00
if ( error )
2012-05-18 17:28:23 +04:00
goto out_gunlock ;
2006-01-16 19:50:04 +03:00
2013-10-02 14:13:25 +04:00
error = gfs2_inplace_reserve ( dip , & ap ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_gunlock_q ;
2014-01-06 16:03:05 +04:00
error = gfs2_trans_begin ( sdp , gfs2_trans_da_blks ( dip , & da , 2 ) , 0 ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_ipres ;
} else {
error = gfs2_trans_begin ( sdp , 2 * RES_DINODE + RES_LEAF , 0 ) ;
if ( error )
goto out_ipres ;
}
2011-05-09 15:08:36 +04:00
error = gfs2_meta_inode_buffer ( ip , & dibh ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_end_trans ;
2014-01-06 16:49:43 +04:00
error = gfs2_dir_add ( dir , & dentry - > d_name , ip , & da ) ;
2011-05-09 15:08:36 +04:00
if ( error )
goto out_brelse ;
2012-12-14 16:36:02 +04:00
gfs2_trans_add_meta ( ip - > i_gl , dibh ) ;
2011-05-09 15:08:36 +04:00
inc_nlink ( & ip - > i_inode ) ;
ip - > i_inode . i_ctime = CURRENT_TIME ;
2011-08-15 17:20:36 +04:00
ihold ( inode ) ;
d_instantiate ( dentry , inode ) ;
mark_inode_dirty ( inode ) ;
2006-01-16 19:50:04 +03:00
2011-05-09 15:08:36 +04:00
out_brelse :
brelse ( dibh ) ;
2006-06-14 23:32:57 +04:00
out_end_trans :
2006-01-16 19:50:04 +03:00
gfs2_trans_end ( sdp ) ;
2006-06-14 23:32:57 +04:00
out_ipres :
2014-01-06 15:28:41 +04:00
if ( da . nr_blocks )
2006-01-16 19:50:04 +03:00
gfs2_inplace_release ( dip ) ;
2006-06-14 23:32:57 +04:00
out_gunlock_q :
2014-01-06 15:28:41 +04:00
if ( da . nr_blocks )
2006-01-16 19:50:04 +03:00
gfs2_quota_unlock ( dip ) ;
2006-06-14 23:32:57 +04:00
out_gunlock :
2014-01-06 16:49:43 +04:00
gfs2_dir_no_add ( & da ) ;
2008-08-12 22:39:29 +04:00
gfs2_glock_dq ( ghs + 1 ) ;
out_child :
gfs2_glock_dq ( ghs ) ;
out_parent :
2006-01-16 19:50:04 +03:00
gfs2_holder_uninit ( ghs ) ;
gfs2_holder_uninit ( ghs + 1 ) ;
return error ;
}
2009-05-22 13:54:50 +04:00
/*
* gfs2_unlink_ok - check to see that a inode is still in a directory
* @ dip : the directory
* @ name : the name of the file
* @ ip : the inode
*
* Assumes that the lock on ( at least ) @ dip is held .
*
* Returns : 0 if the parent / child relationship is correct , errno if it isn ' t
*/
static int gfs2_unlink_ok ( struct gfs2_inode * dip , const struct qstr * name ,
const struct gfs2_inode * ip )
{
int error ;
if ( IS_IMMUTABLE ( & ip - > i_inode ) | | IS_APPEND ( & ip - > i_inode ) )
return - EPERM ;
if ( ( dip - > i_inode . i_mode & S_ISVTX ) & &
2013-02-01 09:56:13 +04:00
! uid_eq ( dip - > i_inode . i_uid , current_fsuid ( ) ) & &
! uid_eq ( ip - > i_inode . i_uid , current_fsuid ( ) ) & & ! capable ( CAP_FOWNER ) )
2009-05-22 13:54:50 +04:00
return - EPERM ;
if ( IS_APPEND ( & dip - > i_inode ) )
return - EPERM ;
2011-06-21 03:28:19 +04:00
error = gfs2_permission ( & dip - > i_inode , MAY_WRITE | MAY_EXEC ) ;
2009-05-22 13:54:50 +04:00
if ( error )
return error ;
2014-10-10 00:49:21 +04:00
return gfs2_dir_check ( & dip - > i_inode , name , ip ) ;
2009-05-22 13:54:50 +04:00
}
2006-01-16 19:50:04 +03:00
/**
2011-05-09 19:42:37 +04:00
* gfs2_unlink_inode - Removes an inode from its parent dir and unlinks it
* @ dip : The parent directory
* @ name : The name of the entry in the parent directory
* @ inode : The inode to be removed
*
* Called with all the locks and in a transaction . This will only be
* called for a directory after it has been checked to ensure it is empty .
*
* Returns : 0 on success , or an error
*/
static int gfs2_unlink_inode ( struct gfs2_inode * dip ,
2012-11-12 22:03:29 +04:00
const struct dentry * dentry )
2011-05-09 19:42:37 +04:00
{
2015-03-18 01:25:59 +03:00
struct inode * inode = d_inode ( dentry ) ;
2011-05-09 19:42:37 +04:00
struct gfs2_inode * ip = GFS2_I ( inode ) ;
int error ;
error = gfs2_dir_del ( dip , dentry ) ;
if ( error )
return error ;
ip - > i_entries = 0 ;
inode - > i_ctime = CURRENT_TIME ;
if ( S_ISDIR ( inode - > i_mode ) )
clear_nlink ( inode ) ;
else
drop_nlink ( inode ) ;
mark_inode_dirty ( inode ) ;
if ( inode - > i_nlink = = 0 )
gfs2_unlink_di ( inode ) ;
return 0 ;
}
/**
* gfs2_unlink - Unlink an inode ( this does rmdir as well )
* @ dir : The inode of the directory containing the inode to unlink
2006-01-16 19:50:04 +03:00
* @ dentry : The file itself
*
2011-05-09 19:42:37 +04:00
* This routine uses the type of the inode as a flag to figure out
* whether this is an unlink or an rmdir .
2006-01-16 19:50:04 +03:00
*
* Returns : errno
*/
static int gfs2_unlink ( struct inode * dir , struct dentry * dentry )
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * dip = GFS2_I ( dir ) ;
struct gfs2_sbd * sdp = GFS2_SB ( dir ) ;
2015-03-18 01:25:59 +03:00
struct inode * inode = d_inode ( dentry ) ;
2011-05-09 19:42:37 +04:00
struct gfs2_inode * ip = GFS2_I ( inode ) ;
2007-01-30 02:13:44 +03:00
struct gfs2_holder ghs [ 3 ] ;
struct gfs2_rgrpd * rgd ;
2012-04-05 06:11:16 +04:00
int error ;
error = gfs2_rindex_update ( sdp ) ;
if ( error )
return error ;
error = - EROFS ;
2006-01-16 19:50:04 +03:00
gfs2_holder_init ( dip - > i_gl , LM_ST_EXCLUSIVE , 0 , ghs ) ;
2007-01-30 02:13:44 +03:00
gfs2_holder_init ( ip - > i_gl , LM_ST_EXCLUSIVE , 0 , ghs + 1 ) ;
2006-01-16 19:50:04 +03:00
2012-02-08 16:58:32 +04:00
rgd = gfs2_blk2rgrpd ( sdp , ip - > i_no_addr , 1 ) ;
2012-02-24 19:09:14 +04:00
if ( ! rgd )
2011-11-08 18:04:20 +04:00
goto out_inodes ;
2012-02-24 19:09:14 +04:00
2007-01-30 02:13:44 +03:00
gfs2_holder_init ( rgd - > rd_gl , LM_ST_EXCLUSIVE , 0 , ghs + 2 ) ;
2007-08-26 17:23:56 +04:00
error = gfs2_glock_nq ( ghs ) ; /* parent */
2006-01-16 19:50:04 +03:00
if ( error )
2007-08-26 17:23:56 +04:00
goto out_parent ;
error = gfs2_glock_nq ( ghs + 1 ) ; /* child */
if ( error )
goto out_child ;
2011-05-05 15:35:40 +04:00
error = - ENOENT ;
2011-05-09 19:42:37 +04:00
if ( inode - > i_nlink = = 0 )
2011-05-05 15:35:40 +04:00
goto out_rgrp ;
2011-05-09 19:42:37 +04:00
if ( S_ISDIR ( inode - > i_mode ) ) {
error = - ENOTEMPTY ;
if ( ip - > i_entries > 2 | | inode - > i_nlink > 2 )
goto out_rgrp ;
}
2007-08-26 17:23:56 +04:00
error = gfs2_glock_nq ( ghs + 2 ) ; /* rgrp */
if ( error )
goto out_rgrp ;
2006-01-16 19:50:04 +03:00
error = gfs2_unlink_ok ( dip , & dentry - > d_name , ip ) ;
if ( error )
2008-08-12 22:39:29 +04:00
goto out_gunlock ;
2006-01-16 19:50:04 +03:00
2011-05-09 19:42:37 +04:00
error = gfs2_trans_begin ( sdp , 2 * RES_DINODE + 3 * RES_LEAF + RES_RG_BIT , 0 ) ;
if ( error )
goto out_end_trans ;
2006-01-16 19:50:04 +03:00
2012-11-12 22:03:29 +04:00
error = gfs2_unlink_inode ( dip , dentry ) ;
2006-01-16 19:50:04 +03:00
2006-06-14 23:32:57 +04:00
out_end_trans :
gfs2_trans_end ( sdp ) ;
2008-08-12 22:39:29 +04:00
out_gunlock :
2007-08-26 17:23:56 +04:00
gfs2_glock_dq ( ghs + 2 ) ;
out_rgrp :
gfs2_glock_dq ( ghs + 1 ) ;
out_child :
gfs2_glock_dq ( ghs ) ;
out_parent :
2011-11-08 18:04:20 +04:00
gfs2_holder_uninit ( ghs + 2 ) ;
out_inodes :
gfs2_holder_uninit ( ghs + 1 ) ;
2007-08-26 17:23:56 +04:00
gfs2_holder_uninit ( ghs ) ;
2006-01-16 19:50:04 +03:00
return error ;
}
/**
* gfs2_symlink - Create a symlink
* @ dir : The directory to create the symlink in
* @ dentry : The dentry to put the symlink in
* @ symname : The thing which the link points to
*
* Returns : errno
*/
static int gfs2_symlink ( struct inode * dir , struct dentry * dentry ,
const char * symname )
{
2006-06-14 23:32:57 +04:00
struct gfs2_sbd * sdp = GFS2_SB ( dir ) ;
2011-05-13 13:34:59 +04:00
unsigned int size ;
2006-01-16 19:50:04 +03:00
size = strlen ( symname ) ;
if ( size > sdp - > sd_sb . sb_bsize - sizeof ( struct gfs2_dinode ) - 1 )
return - ENAMETOOLONG ;
2013-06-14 14:17:15 +04:00
return gfs2_create_inode ( dir , dentry , NULL , S_IFLNK | S_IRWXUGO , 0 , symname , size , 0 , NULL ) ;
2006-01-16 19:50:04 +03:00
}
/**
* gfs2_mkdir - Make a directory
* @ dir : The parent directory of the new one
* @ dentry : The dentry of the new directory
* @ mode : The mode of the new directory
*
* Returns : errno
*/
2011-07-26 09:41:39 +04:00
static int gfs2_mkdir ( struct inode * dir , struct dentry * dentry , umode_t mode )
2006-01-16 19:50:04 +03:00
{
2013-02-26 23:09:35 +04:00
struct gfs2_sbd * sdp = GFS2_SB ( dir ) ;
unsigned dsize = sdp - > sd_sb . sb_bsize - sizeof ( struct gfs2_dinode ) ;
2013-06-14 14:17:15 +04:00
return gfs2_create_inode ( dir , dentry , NULL , S_IFDIR | mode , 0 , NULL , dsize , 0 , NULL ) ;
2006-01-16 19:50:04 +03:00
}
/**
* gfs2_mknod - Make a special file
* @ dir : The directory in which the special file will reside
* @ dentry : The dentry of the special file
* @ mode : The mode of the special file
2011-05-13 15:11:17 +04:00
* @ dev : The device specification of the special file
2006-01-16 19:50:04 +03:00
*
*/
2011-07-26 09:52:52 +04:00
static int gfs2_mknod ( struct inode * dir , struct dentry * dentry , umode_t mode ,
2006-01-16 19:50:04 +03:00
dev_t dev )
{
2013-06-14 14:17:15 +04:00
return gfs2_create_inode ( dir , dentry , NULL , mode , dev , NULL , 0 , 0 , NULL ) ;
}
/**
* gfs2_atomic_open - Atomically open a file
* @ dir : The directory
* @ dentry : The proposed new entry
* @ file : The proposed new struct file
* @ flags : open flags
* @ mode : File mode
* @ opened : Flag to say whether the file has been opened or not
*
* Returns : error code or 0 for success
*/
static int gfs2_atomic_open ( struct inode * dir , struct dentry * dentry ,
2015-05-01 20:54:38 +03:00
struct file * file , unsigned flags ,
umode_t mode , int * opened )
2013-06-14 14:17:15 +04:00
{
struct dentry * d ;
bool excl = ! ! ( flags & O_EXCL ) ;
2014-09-13 02:21:05 +04:00
if ( ! d_unhashed ( dentry ) )
goto skip_lookup ;
2013-06-14 14:17:15 +04:00
d = __gfs2_lookup ( dir , dentry , file , opened ) ;
if ( IS_ERR ( d ) )
return PTR_ERR ( d ) ;
2013-09-23 16:21:04 +04:00
if ( d ! = NULL )
dentry = d ;
2015-03-18 01:25:59 +03:00
if ( d_really_is_positive ( dentry ) ) {
2014-11-19 22:35:58 +03:00
if ( ! ( * opened & FILE_OPENED ) )
return finish_no_open ( file , d ) ;
2013-09-23 16:21:04 +04:00
dput ( d ) ;
2013-06-14 14:17:15 +04:00
return 0 ;
}
2013-09-23 16:21:04 +04:00
BUG_ON ( d ! = NULL ) ;
2014-09-13 02:21:05 +04:00
skip_lookup :
2013-06-14 14:17:15 +04:00
if ( ! ( flags & O_CREAT ) )
return - ENOENT ;
return gfs2_create_inode ( dir , dentry , file , S_IFREG | mode , 0 , NULL , 0 , excl , opened ) ;
2006-01-16 19:50:04 +03:00
}
2008-08-26 12:38:26 +04:00
/*
* gfs2_ok_to_move - check if it ' s ok to move a directory to another directory
* @ this : move this
* @ to : to here
*
* Follow @ to back to the root and make sure we don ' t encounter @ this
* Assumes we already hold the rename lock .
*
* Returns : errno
*/
static int gfs2_ok_to_move ( struct gfs2_inode * this , struct gfs2_inode * to )
{
struct inode * dir = & to - > i_inode ;
struct super_block * sb = dir - > i_sb ;
struct inode * tmp ;
int error = 0 ;
igrab ( dir ) ;
for ( ; ; ) {
if ( dir = = & this - > i_inode ) {
error = - EINVAL ;
break ;
}
2015-03-18 01:25:59 +03:00
if ( dir = = d_inode ( sb - > s_root ) ) {
2008-08-26 12:38:26 +04:00
error = 0 ;
break ;
}
2010-09-17 15:30:23 +04:00
tmp = gfs2_lookupi ( dir , & gfs2_qdotdot , 1 ) ;
2014-03-12 12:41:44 +04:00
if ( ! tmp ) {
error = - ENOENT ;
break ;
}
2008-08-26 12:38:26 +04:00
if ( IS_ERR ( tmp ) ) {
error = PTR_ERR ( tmp ) ;
break ;
}
iput ( dir ) ;
dir = tmp ;
}
iput ( dir ) ;
return error ;
}
2015-05-05 20:12:19 +03:00
/**
* update_moved_ino - Update an inode that ' s being moved
* @ ip : The inode being moved
* @ ndip : The parent directory of the new filename
* @ dir_rename : True of ip is a directory
*
* Returns : errno
*/
static int update_moved_ino ( struct gfs2_inode * ip , struct gfs2_inode * ndip ,
int dir_rename )
{
int error ;
struct buffer_head * dibh ;
if ( dir_rename )
return gfs2_dir_mvino ( ip , & gfs2_qdotdot , ndip , DT_DIR ) ;
error = gfs2_meta_inode_buffer ( ip , & dibh ) ;
if ( error )
return error ;
ip - > i_inode . i_ctime = CURRENT_TIME ;
gfs2_trans_add_meta ( ip - > i_gl , dibh ) ;
gfs2_dinode_out ( ip , dibh - > b_data ) ;
brelse ( dibh ) ;
return 0 ;
}
2006-01-16 19:50:04 +03:00
/**
* gfs2_rename - Rename a file
* @ odir : Parent directory of old file name
* @ odentry : The old dentry of the file
* @ ndir : Parent directory of new file name
* @ ndentry : The new dentry of the file
*
* Returns : errno
*/
static int gfs2_rename ( struct inode * odir , struct dentry * odentry ,
struct inode * ndir , struct dentry * ndentry )
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * odip = GFS2_I ( odir ) ;
struct gfs2_inode * ndip = GFS2_I ( ndir ) ;
2015-03-18 01:25:59 +03:00
struct gfs2_inode * ip = GFS2_I ( d_inode ( odentry ) ) ;
2006-01-16 19:50:04 +03:00
struct gfs2_inode * nip = NULL ;
2006-06-14 23:32:57 +04:00
struct gfs2_sbd * sdp = GFS2_SB ( odir ) ;
2011-08-31 19:38:29 +04:00
struct gfs2_holder ghs [ 5 ] , r_gh = { . gh_gl = NULL , } ;
2007-01-30 02:13:44 +03:00
struct gfs2_rgrpd * nrgd ;
2006-01-16 19:50:04 +03:00
unsigned int num_gh ;
int dir_rename = 0 ;
2014-09-29 16:52:04 +04:00
struct gfs2_diradd da = { . nr_blocks = 0 , . save_loc = 0 , } ;
2006-01-16 19:50:04 +03:00
unsigned int x ;
int error ;
2015-03-18 01:25:59 +03:00
if ( d_really_is_positive ( ndentry ) ) {
nip = GFS2_I ( d_inode ( ndentry ) ) ;
2006-01-16 19:50:04 +03:00
if ( ip = = nip )
return 0 ;
}
2012-04-05 06:11:16 +04:00
error = gfs2_rindex_update ( sdp ) ;
if ( error )
return error ;
2015-10-26 18:40:28 +03:00
error = gfs2_rsqa_alloc ( ndip ) ;
2012-06-06 14:17:59 +04:00
if ( error )
return error ;
2008-08-26 12:38:26 +04:00
if ( odip ! = ndip ) {
error = gfs2_glock_nq_init ( sdp - > sd_rename_gl , LM_ST_EXCLUSIVE ,
0 , & r_gh ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out ;
2008-08-26 12:38:26 +04:00
if ( S_ISDIR ( ip - > i_inode . i_mode ) ) {
dir_rename = 1 ;
2015-05-05 20:12:19 +03:00
/* don't move a directory into its subdir */
2008-08-26 12:38:26 +04:00
error = gfs2_ok_to_move ( ip , ndip ) ;
if ( error )
goto out_gunlock_r ;
}
2006-01-16 19:50:04 +03:00
}
2006-06-21 23:38:17 +04:00
num_gh = 1 ;
2006-01-16 19:50:04 +03:00
gfs2_holder_init ( odip - > i_gl , LM_ST_EXCLUSIVE , 0 , ghs ) ;
2006-06-21 23:38:17 +04:00
if ( odip ! = ndip ) {
gfs2_holder_init ( ndip - > i_gl , LM_ST_EXCLUSIVE , 0 , ghs + num_gh ) ;
num_gh + + ;
}
gfs2_holder_init ( ip - > i_gl , LM_ST_EXCLUSIVE , 0 , ghs + num_gh ) ;
num_gh + + ;
2006-01-16 19:50:04 +03:00
2006-06-21 23:38:17 +04:00
if ( nip ) {
gfs2_holder_init ( nip - > i_gl , LM_ST_EXCLUSIVE , 0 , ghs + num_gh ) ;
num_gh + + ;
2007-01-30 02:13:44 +03:00
/* grab the resource lock for unlink flag twiddling
* this is the case of the target file already existing
* so we unlink before doing the rename
*/
2012-02-08 16:58:32 +04:00
nrgd = gfs2_blk2rgrpd ( sdp , nip - > i_no_addr , 1 ) ;
2007-01-30 02:13:44 +03:00
if ( nrgd )
gfs2_holder_init ( nrgd - > rd_gl , LM_ST_EXCLUSIVE , 0 , ghs + num_gh + + ) ;
2006-06-21 23:38:17 +04:00
}
2006-01-16 19:50:04 +03:00
2008-08-12 22:39:29 +04:00
for ( x = 0 ; x < num_gh ; x + + ) {
error = gfs2_glock_nq ( ghs + x ) ;
if ( error )
goto out_gunlock ;
}
2006-01-16 19:50:04 +03:00
2011-05-05 15:35:40 +04:00
error = - ENOENT ;
if ( ip - > i_inode . i_nlink = = 0 )
goto out_gunlock ;
2006-01-16 19:50:04 +03:00
/* Check out the old directory */
error = gfs2_unlink_ok ( odip , & odentry - > d_name , ip ) ;
if ( error )
goto out_gunlock ;
/* Check out the new directory */
if ( nip ) {
error = gfs2_unlink_ok ( ndip , & ndentry - > d_name , nip ) ;
if ( error )
goto out_gunlock ;
2011-05-05 15:35:40 +04:00
if ( nip - > i_inode . i_nlink = = 0 ) {
error = - EAGAIN ;
goto out_gunlock ;
}
2006-11-01 20:22:46 +03:00
if ( S_ISDIR ( nip - > i_inode . i_mode ) ) {
2008-11-03 16:59:19 +03:00
if ( nip - > i_entries < 2 ) {
2011-05-09 16:36:10 +04:00
gfs2_consist_inode ( nip ) ;
2006-01-16 19:50:04 +03:00
error = - EIO ;
goto out_gunlock ;
}
2008-11-03 16:59:19 +03:00
if ( nip - > i_entries > 2 ) {
2006-01-16 19:50:04 +03:00
error = - ENOTEMPTY ;
goto out_gunlock ;
}
}
} else {
2011-06-21 03:28:19 +04:00
error = gfs2_permission ( ndir , MAY_WRITE | MAY_EXEC ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_gunlock ;
2007-05-15 18:37:50 +04:00
error = gfs2_dir_check ( ndir , & ndentry - > d_name , NULL ) ;
2006-01-16 19:50:04 +03:00
switch ( error ) {
case - ENOENT :
error = 0 ;
break ;
case 0 :
error = - EEXIST ;
default :
goto out_gunlock ;
} ;
if ( odip ! = ndip ) {
2006-11-01 22:04:17 +03:00
if ( ! ndip - > i_inode . i_nlink ) {
2011-05-05 15:35:40 +04:00
error = - ENOENT ;
2006-01-16 19:50:04 +03:00
goto out_gunlock ;
}
2008-11-03 16:59:19 +03:00
if ( ndip - > i_entries = = ( u32 ) - 1 ) {
2006-01-16 19:50:04 +03:00
error = - EFBIG ;
goto out_gunlock ;
}
2006-11-01 20:22:46 +03:00
if ( S_ISDIR ( ip - > i_inode . i_mode ) & &
2006-11-01 22:04:17 +03:00
ndip - > i_inode . i_nlink = = ( u32 ) - 1 ) {
2006-01-16 19:50:04 +03:00
error = - EMLINK ;
goto out_gunlock ;
}
}
}
/* Check out the dir to be renamed */
if ( dir_rename ) {
2015-03-18 01:25:59 +03:00
error = gfs2_permission ( d_inode ( odentry ) , MAY_WRITE ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_gunlock ;
}
2014-01-06 15:28:41 +04:00
if ( nip = = NULL ) {
error = gfs2_diradd_alloc_required ( ndir , & ndentry - > d_name , & da ) ;
if ( error )
goto out_gunlock ;
}
2006-01-16 19:50:04 +03:00
2014-01-06 15:28:41 +04:00
if ( da . nr_blocks ) {
struct gfs2_alloc_parms ap = { . target = da . nr_blocks , } ;
2015-03-18 20:03:41 +03:00
error = gfs2_quota_lock_check ( ndip , & ap ) ;
2006-01-16 19:50:04 +03:00
if ( error )
2012-05-18 17:28:23 +04:00
goto out_gunlock ;
2006-01-16 19:50:04 +03:00
2013-10-02 14:13:25 +04:00
error = gfs2_inplace_reserve ( ndip , & ap ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_gunlock_q ;
2014-01-06 16:03:05 +04:00
error = gfs2_trans_begin ( sdp , gfs2_trans_da_blks ( ndip , & da , 4 ) +
4 * RES_LEAF + 4 , 0 ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_ipreserv ;
} else {
error = gfs2_trans_begin ( sdp , 4 * RES_DINODE +
2007-01-19 00:07:03 +03:00
5 * RES_LEAF + 4 , 0 ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_gunlock ;
}
/* Remove the target file, if it exists */
2012-11-12 22:03:29 +04:00
if ( nip )
error = gfs2_unlink_inode ( ndip , ndentry ) ;
2006-01-16 19:50:04 +03:00
2015-05-05 20:12:19 +03:00
error = update_moved_ino ( ip , ndip , dir_rename ) ;
if ( error )
goto out_end_trans ;
2006-01-16 19:50:04 +03:00
2011-05-09 19:42:37 +04:00
error = gfs2_dir_del ( odip , odentry ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_end_trans ;
2014-01-06 16:49:43 +04:00
error = gfs2_dir_add ( ndir , & ndentry - > d_name , ip , & da ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_end_trans ;
2006-06-14 23:32:57 +04:00
out_end_trans :
2006-01-16 19:50:04 +03:00
gfs2_trans_end ( sdp ) ;
2006-06-14 23:32:57 +04:00
out_ipreserv :
2014-01-06 15:28:41 +04:00
if ( da . nr_blocks )
2006-01-16 19:50:04 +03:00
gfs2_inplace_release ( ndip ) ;
2006-06-14 23:32:57 +04:00
out_gunlock_q :
2014-01-06 15:28:41 +04:00
if ( da . nr_blocks )
2006-01-16 19:50:04 +03:00
gfs2_quota_unlock ( ndip ) ;
2006-06-14 23:32:57 +04:00
out_gunlock :
2014-01-06 16:49:43 +04:00
gfs2_dir_no_add ( & da ) ;
2008-08-12 22:39:29 +04:00
while ( x - - ) {
gfs2_glock_dq ( ghs + x ) ;
2006-01-16 19:50:04 +03:00
gfs2_holder_uninit ( ghs + x ) ;
2008-08-12 22:39:29 +04:00
}
2006-06-14 23:32:57 +04:00
out_gunlock_r :
2008-08-26 12:38:26 +04:00
if ( r_gh . gh_gl )
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( & r_gh ) ;
2006-06-14 23:32:57 +04:00
out :
2006-01-16 19:50:04 +03:00
return error ;
}
2015-05-05 20:12:19 +03:00
/**
* gfs2_exchange - exchange two files
* @ odir : Parent directory of old file name
* @ odentry : The old dentry of the file
* @ ndir : Parent directory of new file name
* @ ndentry : The new dentry of the file
* @ flags : The rename flags
*
* Returns : errno
*/
static int gfs2_exchange ( struct inode * odir , struct dentry * odentry ,
struct inode * ndir , struct dentry * ndentry ,
unsigned int flags )
{
struct gfs2_inode * odip = GFS2_I ( odir ) ;
struct gfs2_inode * ndip = GFS2_I ( ndir ) ;
struct gfs2_inode * oip = GFS2_I ( odentry - > d_inode ) ;
struct gfs2_inode * nip = GFS2_I ( ndentry - > d_inode ) ;
struct gfs2_sbd * sdp = GFS2_SB ( odir ) ;
struct gfs2_holder ghs [ 5 ] , r_gh = { . gh_gl = NULL , } ;
unsigned int num_gh ;
unsigned int x ;
umode_t old_mode = oip - > i_inode . i_mode ;
umode_t new_mode = nip - > i_inode . i_mode ;
int error ;
error = gfs2_rindex_update ( sdp ) ;
if ( error )
return error ;
if ( odip ! = ndip ) {
error = gfs2_glock_nq_init ( sdp - > sd_rename_gl , LM_ST_EXCLUSIVE ,
0 , & r_gh ) ;
if ( error )
goto out ;
if ( S_ISDIR ( old_mode ) ) {
/* don't move a directory into its subdir */
error = gfs2_ok_to_move ( oip , ndip ) ;
if ( error )
goto out_gunlock_r ;
}
if ( S_ISDIR ( new_mode ) ) {
/* don't move a directory into its subdir */
error = gfs2_ok_to_move ( nip , odip ) ;
if ( error )
goto out_gunlock_r ;
}
}
num_gh = 1 ;
gfs2_holder_init ( odip - > i_gl , LM_ST_EXCLUSIVE , 0 , ghs ) ;
if ( odip ! = ndip ) {
gfs2_holder_init ( ndip - > i_gl , LM_ST_EXCLUSIVE , 0 , ghs + num_gh ) ;
num_gh + + ;
}
gfs2_holder_init ( oip - > i_gl , LM_ST_EXCLUSIVE , 0 , ghs + num_gh ) ;
num_gh + + ;
gfs2_holder_init ( nip - > i_gl , LM_ST_EXCLUSIVE , 0 , ghs + num_gh ) ;
num_gh + + ;
for ( x = 0 ; x < num_gh ; x + + ) {
error = gfs2_glock_nq ( ghs + x ) ;
if ( error )
goto out_gunlock ;
}
error = - ENOENT ;
if ( oip - > i_inode . i_nlink = = 0 | | nip - > i_inode . i_nlink = = 0 )
goto out_gunlock ;
error = gfs2_unlink_ok ( odip , & odentry - > d_name , oip ) ;
if ( error )
goto out_gunlock ;
error = gfs2_unlink_ok ( ndip , & ndentry - > d_name , nip ) ;
if ( error )
goto out_gunlock ;
if ( S_ISDIR ( old_mode ) ) {
error = gfs2_permission ( odentry - > d_inode , MAY_WRITE ) ;
if ( error )
goto out_gunlock ;
}
if ( S_ISDIR ( new_mode ) ) {
error = gfs2_permission ( ndentry - > d_inode , MAY_WRITE ) ;
if ( error )
goto out_gunlock ;
}
error = gfs2_trans_begin ( sdp , 4 * RES_DINODE + 4 * RES_LEAF , 0 ) ;
if ( error )
goto out_gunlock ;
error = update_moved_ino ( oip , ndip , S_ISDIR ( old_mode ) ) ;
if ( error )
goto out_end_trans ;
error = update_moved_ino ( nip , odip , S_ISDIR ( new_mode ) ) ;
if ( error )
goto out_end_trans ;
error = gfs2_dir_mvino ( ndip , & ndentry - > d_name , oip ,
IF2DT ( old_mode ) ) ;
if ( error )
goto out_end_trans ;
error = gfs2_dir_mvino ( odip , & odentry - > d_name , nip ,
IF2DT ( new_mode ) ) ;
if ( error )
goto out_end_trans ;
if ( odip ! = ndip ) {
if ( S_ISDIR ( new_mode ) & & ! S_ISDIR ( old_mode ) ) {
inc_nlink ( & odip - > i_inode ) ;
drop_nlink ( & ndip - > i_inode ) ;
} else if ( S_ISDIR ( old_mode ) & & ! S_ISDIR ( new_mode ) ) {
inc_nlink ( & ndip - > i_inode ) ;
drop_nlink ( & odip - > i_inode ) ;
}
}
mark_inode_dirty ( & ndip - > i_inode ) ;
if ( odip ! = ndip )
mark_inode_dirty ( & odip - > i_inode ) ;
out_end_trans :
gfs2_trans_end ( sdp ) ;
out_gunlock :
while ( x - - ) {
gfs2_glock_dq ( ghs + x ) ;
gfs2_holder_uninit ( ghs + x ) ;
}
out_gunlock_r :
if ( r_gh . gh_gl )
gfs2_glock_dq_uninit ( & r_gh ) ;
out :
return error ;
}
static int gfs2_rename2 ( struct inode * odir , struct dentry * odentry ,
struct inode * ndir , struct dentry * ndentry ,
unsigned int flags )
{
flags & = ~ RENAME_NOREPLACE ;
if ( flags & ~ RENAME_EXCHANGE )
return - EINVAL ;
if ( flags & RENAME_EXCHANGE )
return gfs2_exchange ( odir , odentry , ndir , ndentry , flags ) ;
return gfs2_rename ( odir , odentry , ndir , ndentry ) ;
}
2009-05-22 13:48:59 +04:00
/**
2015-11-17 18:20:54 +03:00
* gfs2_get_link - Follow a symbolic link
2010-01-14 08:59:16 +03:00
* @ dentry : The dentry of the link
2015-11-17 18:20:54 +03:00
* @ inode : The inode of the link
2015-12-29 23:58:39 +03:00
* @ done : destructor for return value
2009-05-22 13:48:59 +04:00
*
2010-01-14 08:59:16 +03:00
* This can handle symlinks of any size .
2009-05-22 13:48:59 +04:00
*
2010-01-14 08:59:16 +03:00
* Returns : 0 on success or error code
2009-05-22 13:48:59 +04:00
*/
2015-11-17 18:20:54 +03:00
static const char * gfs2_get_link ( struct dentry * dentry ,
2015-12-29 23:58:39 +03:00
struct inode * inode ,
struct delayed_call * done )
2009-05-22 13:48:59 +04:00
{
2015-11-17 18:20:54 +03:00
struct gfs2_inode * ip = GFS2_I ( inode ) ;
2009-05-22 13:48:59 +04:00
struct gfs2_holder i_gh ;
struct buffer_head * dibh ;
2011-05-13 13:34:59 +04:00
unsigned int size ;
2010-01-14 08:59:16 +03:00
char * buf ;
2009-05-22 13:48:59 +04:00
int error ;
2015-11-17 18:20:54 +03:00
if ( ! dentry )
return ERR_PTR ( - ECHILD ) ;
2009-05-22 13:48:59 +04:00
gfs2_holder_init ( ip - > i_gl , LM_ST_SHARED , 0 , & i_gh ) ;
error = gfs2_glock_nq ( & i_gh ) ;
if ( error ) {
gfs2_holder_uninit ( & i_gh ) ;
2015-05-02 20:32:22 +03:00
return ERR_PTR ( error ) ;
2009-05-22 13:48:59 +04:00
}
2010-08-11 12:53:11 +04:00
size = ( unsigned int ) i_size_read ( & ip - > i_inode ) ;
if ( size = = 0 ) {
2009-05-22 13:48:59 +04:00
gfs2_consist_inode ( ip ) ;
2010-01-14 08:59:16 +03:00
buf = ERR_PTR ( - EIO ) ;
2009-05-22 13:48:59 +04:00
goto out ;
}
error = gfs2_meta_inode_buffer ( ip , & dibh ) ;
2010-01-14 08:59:16 +03:00
if ( error ) {
buf = ERR_PTR ( error ) ;
2009-05-22 13:48:59 +04:00
goto out ;
}
2011-05-13 13:34:59 +04:00
buf = kzalloc ( size + 1 , GFP_NOFS ) ;
2010-01-14 08:59:16 +03:00
if ( ! buf )
buf = ERR_PTR ( - ENOMEM ) ;
else
2011-05-13 13:34:59 +04:00
memcpy ( buf , dibh - > b_data + sizeof ( struct gfs2_dinode ) , size ) ;
2009-05-22 13:48:59 +04:00
brelse ( dibh ) ;
out :
gfs2_glock_dq_uninit ( & i_gh ) ;
2015-05-02 20:32:22 +03:00
if ( ! IS_ERR ( buf ) )
2015-12-29 23:58:39 +03:00
set_delayed_call ( done , kfree_link , buf ) ;
2015-05-02 20:32:22 +03:00
return buf ;
2006-01-16 19:50:04 +03:00
}
/**
* gfs2_permission -
2011-01-19 12:42:40 +03:00
* @ inode : The inode
* @ mask : The mask to be tested
* @ flags : Indicates whether this is an RCU path walk or not
2006-01-16 19:50:04 +03:00
*
2006-11-27 17:55:28 +03:00
* This may be called from the VFS directly , or from within GFS2 with the
* inode locked , so we look to see if the glock is already locked and only
* lock the glock if its not already been done .
*
2006-01-16 19:50:04 +03:00
* Returns : errno
*/
2011-06-21 03:28:19 +04:00
int gfs2_permission ( struct inode * inode , int mask )
2006-01-16 19:50:04 +03:00
{
2011-01-07 09:49:58 +03:00
struct gfs2_inode * ip ;
2006-01-16 19:50:04 +03:00
struct gfs2_holder i_gh ;
int error ;
2006-11-27 17:55:28 +03:00
int unlock = 0 ;
2006-01-16 19:50:04 +03:00
2011-01-07 09:49:58 +03:00
ip = GFS2_I ( inode ) ;
2008-02-22 19:07:18 +03:00
if ( gfs2_glock_is_locked_by_me ( ip - > i_gl ) = = NULL ) {
2014-11-14 05:42:04 +03:00
if ( mask & MAY_NOT_BLOCK )
return - ECHILD ;
error = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_SHARED , LM_FLAG_ANY , & i_gh ) ;
if ( error )
return error ;
unlock = 1 ;
2006-11-27 17:55:28 +03:00
}
2006-01-16 19:50:04 +03:00
2008-07-02 23:12:01 +04:00
if ( ( mask & MAY_WRITE ) & & IS_IMMUTABLE ( inode ) )
error = - EACCES ;
else
2011-06-21 03:16:29 +04:00
error = generic_permission ( inode , mask ) ;
2006-11-27 17:55:28 +03:00
if ( unlock )
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( & i_gh ) ;
return error ;
}
2011-08-15 17:20:36 +04:00
static int __gfs2_setattr_simple ( struct inode * inode , struct iattr * attr )
2011-05-09 17:06:38 +04:00
{
setattr_copy ( inode , attr ) ;
mark_inode_dirty ( inode ) ;
return 0 ;
}
/**
* gfs2_setattr_simple -
* @ ip :
* @ attr :
*
* Returns : errno
*/
2011-08-15 17:20:36 +04:00
int gfs2_setattr_simple ( struct inode * inode , struct iattr * attr )
2011-05-09 17:06:38 +04:00
{
int error ;
if ( current - > journal_info )
2011-08-15 17:20:36 +04:00
return __gfs2_setattr_simple ( inode , attr ) ;
2011-05-09 17:06:38 +04:00
2011-08-15 17:20:36 +04:00
error = gfs2_trans_begin ( GFS2_SB ( inode ) , RES_DINODE , 0 ) ;
2011-05-09 17:06:38 +04:00
if ( error )
return error ;
2011-08-15 17:20:36 +04:00
error = __gfs2_setattr_simple ( inode , attr ) ;
gfs2_trans_end ( GFS2_SB ( inode ) ) ;
2011-05-09 17:06:38 +04:00
return error ;
}
2006-01-16 19:50:04 +03:00
static int setattr_chown ( struct inode * inode , struct iattr * attr )
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( inode ) ;
struct gfs2_sbd * sdp = GFS2_SB ( inode ) ;
2013-02-01 08:27:54 +04:00
kuid_t ouid , nuid ;
kgid_t ogid , ngid ;
2006-01-16 19:50:04 +03:00
int error ;
2015-03-18 20:03:41 +03:00
struct gfs2_alloc_parms ap ;
2006-01-16 19:50:04 +03:00
2006-11-01 21:23:29 +03:00
ouid = inode - > i_uid ;
ogid = inode - > i_gid ;
2006-01-16 19:50:04 +03:00
nuid = attr - > ia_uid ;
ngid = attr - > ia_gid ;
2013-02-01 09:56:13 +04:00
if ( ! ( attr - > ia_valid & ATTR_UID ) | | uid_eq ( ouid , nuid ) )
2013-02-01 05:49:26 +04:00
ouid = nuid = NO_UID_QUOTA_CHANGE ;
2013-02-01 09:56:13 +04:00
if ( ! ( attr - > ia_valid & ATTR_GID ) | | gid_eq ( ogid , ngid ) )
2013-02-01 05:49:26 +04:00
ogid = ngid = NO_GID_QUOTA_CHANGE ;
2006-01-16 19:50:04 +03:00
2015-10-26 18:40:28 +03:00
error = gfs2_rsqa_alloc ( ip ) ;
2014-01-07 02:16:01 +04:00
if ( error )
goto out ;
error = gfs2_rindex_update ( sdp ) ;
if ( error )
goto out ;
error = gfs2_quota_lock ( ip , nuid , ngid ) ;
if ( error )
goto out ;
2015-03-18 20:03:41 +03:00
ap . target = gfs2_get_inode_blocks ( & ip - > i_inode ) ;
2013-02-01 09:56:13 +04:00
if ( ! uid_eq ( ouid , NO_UID_QUOTA_CHANGE ) | |
! gid_eq ( ogid , NO_GID_QUOTA_CHANGE ) ) {
2015-03-18 20:03:41 +03:00
error = gfs2_quota_check ( ip , nuid , ngid , & ap ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_gunlock_q ;
}
error = gfs2_trans_begin ( sdp , RES_DINODE + 2 * RES_QUOTA , 0 ) ;
if ( error )
goto out_gunlock_q ;
2011-08-15 17:20:36 +04:00
error = gfs2_setattr_simple ( inode , attr ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_end_trans ;
2013-02-01 09:56:13 +04:00
if ( ! uid_eq ( ouid , NO_UID_QUOTA_CHANGE ) | |
! gid_eq ( ogid , NO_GID_QUOTA_CHANGE ) ) {
2015-06-02 19:02:24 +03:00
gfs2_quota_change ( ip , - ( s64 ) ap . target , ouid , ogid ) ;
2015-03-18 20:03:41 +03:00
gfs2_quota_change ( ip , ap . target , nuid , ngid ) ;
2006-01-16 19:50:04 +03:00
}
2006-09-04 20:04:26 +04:00
out_end_trans :
2006-01-16 19:50:04 +03:00
gfs2_trans_end ( sdp ) ;
2006-09-04 20:04:26 +04:00
out_gunlock_q :
2006-01-16 19:50:04 +03:00
gfs2_quota_unlock ( ip ) ;
2014-01-07 02:16:01 +04:00
out :
2006-01-16 19:50:04 +03:00
return error ;
}
/**
* gfs2_setattr - Change attributes on an inode
* @ dentry : The dentry which is changing
* @ attr : The structure describing the change
*
* The VFS layer wants to change one or more of an inodes attributes . Write
* that change out to disk .
*
* Returns : errno
*/
static int gfs2_setattr ( struct dentry * dentry , struct iattr * attr )
{
2015-03-18 01:25:59 +03:00
struct inode * inode = d_inode ( dentry ) ;
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( inode ) ;
2006-01-16 19:50:04 +03:00
struct gfs2_holder i_gh ;
int error ;
2015-10-26 18:40:28 +03:00
error = gfs2_rsqa_alloc ( ip ) ;
2012-06-06 14:17:59 +04:00
if ( error )
return error ;
2006-01-16 19:50:04 +03:00
error = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_EXCLUSIVE , 0 , & i_gh ) ;
if ( error )
return error ;
error = - EPERM ;
if ( IS_IMMUTABLE ( inode ) | | IS_APPEND ( inode ) )
goto out ;
error = inode_change_ok ( inode , attr ) ;
if ( error )
goto out ;
if ( attr - > ia_valid & ATTR_SIZE )
2010-08-11 12:37:53 +04:00
error = gfs2_setattr_size ( inode , attr - > ia_size ) ;
2006-01-16 19:50:04 +03:00
else if ( attr - > ia_valid & ( ATTR_UID | ATTR_GID ) )
error = setattr_chown ( inode , attr ) ;
2013-12-20 17:16:52 +04:00
else {
2011-08-15 17:20:36 +04:00
error = gfs2_setattr_simple ( inode , attr ) ;
2013-12-20 17:16:52 +04:00
if ( ! error & & attr - > ia_valid & ATTR_MODE )
error = posix_acl_chmod ( inode , inode - > i_mode ) ;
}
2006-01-16 19:50:04 +03:00
2006-09-04 20:04:26 +04:00
out :
2006-01-16 19:50:04 +03:00
if ( ! error )
mark_inode_dirty ( inode ) ;
2011-08-15 17:20:36 +04:00
gfs2_glock_dq_uninit ( & i_gh ) ;
2006-01-16 19:50:04 +03:00
return error ;
}
/**
* gfs2_getattr - Read out an inode ' s attributes
2006-09-04 23:32:10 +04:00
* @ mnt : The vfsmount the inode is being accessed from
2006-01-16 19:50:04 +03:00
* @ dentry : The dentry to stat
* @ stat : The inode ' s stats
*
2006-11-27 18:12:05 +03:00
* This may be called from the VFS directly , or from within GFS2 with the
* inode locked , so we look to see if the glock is already locked and only
* lock the glock if its not already been done . Note that its the NFS
* readdirplus operation which causes this to be called ( from filldir )
* with the glock already held .
*
2006-01-16 19:50:04 +03:00
* Returns : errno
*/
static int gfs2_getattr ( struct vfsmount * mnt , struct dentry * dentry ,
struct kstat * stat )
{
2015-03-18 01:25:59 +03:00
struct inode * inode = d_inode ( dentry ) ;
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( inode ) ;
2006-01-16 19:50:04 +03:00
struct gfs2_holder gh ;
int error ;
2006-11-27 18:12:05 +03:00
int unlock = 0 ;
2006-01-16 19:50:04 +03:00
2008-02-22 19:07:18 +03:00
if ( gfs2_glock_is_locked_by_me ( ip - > i_gl ) = = NULL ) {
2014-11-14 05:42:04 +03:00
error = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_SHARED , LM_FLAG_ANY , & gh ) ;
if ( error )
return error ;
unlock = 1 ;
2006-01-16 19:50:04 +03:00
}
2006-11-27 18:12:05 +03:00
generic_fillattr ( inode , stat ) ;
2007-01-25 20:14:59 +03:00
if ( unlock )
2006-11-27 18:12:05 +03:00
gfs2_glock_dq_uninit ( & gh ) ;
return 0 ;
2006-01-16 19:50:04 +03:00
}
2008-10-14 17:43:29 +04:00
static int gfs2_fiemap ( struct inode * inode , struct fiemap_extent_info * fieinfo ,
u64 start , u64 len )
{
struct gfs2_inode * ip = GFS2_I ( inode ) ;
struct gfs2_holder gh ;
int ret ;
ret = fiemap_check_flags ( fieinfo , FIEMAP_FLAG_SYNC ) ;
if ( ret )
return ret ;
2016-01-22 23:40:57 +03:00
inode_lock ( inode ) ;
2008-10-14 17:43:29 +04:00
ret = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_SHARED , 0 , & gh ) ;
if ( ret )
goto out ;
if ( gfs2_is_stuffed ( ip ) ) {
u64 phys = ip - > i_no_addr < < inode - > i_blkbits ;
u64 size = i_size_read ( inode ) ;
u32 flags = FIEMAP_EXTENT_LAST | FIEMAP_EXTENT_NOT_ALIGNED |
FIEMAP_EXTENT_DATA_INLINE ;
phys + = sizeof ( struct gfs2_dinode ) ;
phys + = start ;
if ( start + len > size )
len = size - start ;
if ( start < size )
ret = fiemap_fill_next_extent ( fieinfo , start , phys ,
len , flags ) ;
if ( ret = = 1 )
ret = 0 ;
} else {
ret = __generic_block_fiemap ( inode , fieinfo , start , len ,
gfs2_block_map ) ;
}
gfs2_glock_dq_uninit ( & gh ) ;
out :
2016-01-22 23:40:57 +03:00
inode_unlock ( inode ) ;
2008-10-14 17:43:29 +04:00
return ret ;
}
2007-02-12 11:55:39 +03:00
const struct inode_operations gfs2_file_iops = {
2008-07-16 05:03:57 +04:00
. permission = gfs2_permission ,
2006-01-16 19:50:04 +03:00
. setattr = gfs2_setattr ,
. getattr = gfs2_getattr ,
2016-05-13 04:59:17 +03:00
. setxattr = generic_setxattr ,
. getxattr = generic_getxattr ,
2006-01-16 19:50:04 +03:00
. listxattr = gfs2_listxattr ,
2016-05-13 04:59:17 +03:00
. removexattr = generic_removexattr ,
2008-10-14 17:43:29 +04:00
. fiemap = gfs2_fiemap ,
2011-07-23 19:37:31 +04:00
. get_acl = gfs2_get_acl ,
2013-12-20 17:16:52 +04:00
. set_acl = gfs2_set_acl ,
2006-01-16 19:50:04 +03:00
} ;
2007-02-12 11:55:39 +03:00
const struct inode_operations gfs2_dir_iops = {
2006-01-16 19:50:04 +03:00
. create = gfs2_create ,
. lookup = gfs2_lookup ,
. link = gfs2_link ,
. unlink = gfs2_unlink ,
. symlink = gfs2_symlink ,
. mkdir = gfs2_mkdir ,
2011-05-09 19:42:37 +04:00
. rmdir = gfs2_unlink ,
2006-01-16 19:50:04 +03:00
. mknod = gfs2_mknod ,
2015-05-05 20:12:19 +03:00
. rename2 = gfs2_rename2 ,
2008-07-16 05:03:57 +04:00
. permission = gfs2_permission ,
2006-01-16 19:50:04 +03:00
. setattr = gfs2_setattr ,
. getattr = gfs2_getattr ,
2016-05-13 04:59:17 +03:00
. setxattr = generic_setxattr ,
. getxattr = generic_getxattr ,
2006-01-16 19:50:04 +03:00
. listxattr = gfs2_listxattr ,
2016-05-13 04:59:17 +03:00
. removexattr = generic_removexattr ,
2008-10-14 17:43:29 +04:00
. fiemap = gfs2_fiemap ,
2011-07-23 19:37:31 +04:00
. get_acl = gfs2_get_acl ,
2013-12-20 17:16:52 +04:00
. set_acl = gfs2_set_acl ,
2013-06-14 14:17:15 +04:00
. atomic_open = gfs2_atomic_open ,
2006-01-16 19:50:04 +03:00
} ;
2007-02-12 11:55:39 +03:00
const struct inode_operations gfs2_symlink_iops = {
2010-01-14 08:59:16 +03:00
. readlink = generic_readlink ,
2015-11-17 18:20:54 +03:00
. get_link = gfs2_get_link ,
2008-07-16 05:03:57 +04:00
. permission = gfs2_permission ,
2006-01-16 19:50:04 +03:00
. setattr = gfs2_setattr ,
. getattr = gfs2_getattr ,
2016-05-13 04:59:17 +03:00
. setxattr = generic_setxattr ,
. getxattr = generic_getxattr ,
2006-01-16 19:50:04 +03:00
. listxattr = gfs2_listxattr ,
2016-05-13 04:59:17 +03:00
. removexattr = generic_removexattr ,
2008-10-14 17:43:29 +04:00
. fiemap = gfs2_fiemap ,
2006-01-16 19:50:04 +03:00
} ;