2006-01-16 19:50:04 +03:00
/*
* Copyright ( C ) Sistina Software , Inc . 1997 - 2003 All rights reserved .
2006-05-18 23:09:15 +04:00
* Copyright ( C ) 2004 - 2006 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/sched.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/completion.h>
# include <linux/buffer_head.h>
# include <linux/posix_acl.h>
# include <linux/sort.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>
2006-09-19 09:56:29 +04:00
# include <linux/lm_interface.h>
2006-10-03 19:57:35 +04:00
# include <linux/security.h>
2006-01-16 19:50:04 +03:00
# 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"
# include "eattr.h"
# include "glock.h"
# include "glops.h"
# include "inode.h"
# include "log.h"
# include "meta_io.h"
# include "ops_address.h"
# include "ops_file.h"
# include "ops_inode.h"
# include "quota.h"
# include "rgrp.h"
# include "trans.h"
2006-02-28 01:23:27 +03:00
# include "util.h"
2006-01-16 19:50:04 +03:00
2007-06-01 17:11:58 +04:00
struct gfs2_inum_range_host {
u64 ir_start ;
u64 ir_length ;
} ;
2006-06-14 23:32:57 +04:00
static int iget_test ( struct inode * inode , void * opaque )
{
struct gfs2_inode * ip = GFS2_I ( inode ) ;
2007-05-15 18:37:50 +04:00
u64 * no_addr = opaque ;
2006-06-14 23:32:57 +04:00
2007-05-15 18:37:50 +04:00
if ( ip - > i_no_addr = = * no_addr & &
2007-03-01 13:00:53 +03:00
inode - > i_private ! = NULL )
2006-06-14 23:32:57 +04:00
return 1 ;
2006-01-16 19:50:04 +03:00
2006-06-14 23:32:57 +04:00
return 0 ;
}
static int iget_set ( struct inode * inode , void * opaque )
2006-01-16 19:50:04 +03:00
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( inode ) ;
2007-05-15 18:37:50 +04:00
u64 * no_addr = opaque ;
2006-01-16 19:50:04 +03:00
2007-05-15 18:37:50 +04:00
inode - > i_ino = ( unsigned long ) * no_addr ;
ip - > i_no_addr = * no_addr ;
2006-06-14 23:32:57 +04:00
return 0 ;
}
2006-01-16 19:50:04 +03:00
2007-05-15 18:37:50 +04:00
struct inode * gfs2_ilookup ( struct super_block * sb , u64 no_addr )
2006-06-14 23:32:57 +04:00
{
2007-05-15 18:37:50 +04:00
unsigned long hash = ( unsigned long ) no_addr ;
return ilookup5 ( sb , hash , iget_test , & no_addr ) ;
2006-06-14 23:32:57 +04:00
}
2006-01-16 19:50:04 +03:00
2007-05-15 18:37:50 +04:00
static struct inode * gfs2_iget ( struct super_block * sb , u64 no_addr )
2006-06-14 23:32:57 +04:00
{
2007-05-15 18:37:50 +04:00
unsigned long hash = ( unsigned long ) no_addr ;
return iget5_locked ( sb , hash , iget_test , iget_set , & no_addr ) ;
2006-01-16 19:50:04 +03:00
}
2007-06-28 01:07:53 +04:00
/**
* GFS2 lookup code fills in vfs inode contents based on info obtained
* from directory entry inside gfs2_inode_lookup ( ) . This has caused issues
* with NFS code path since its get_dentry routine doesn ' t have the relevant
* directory entry when gfs2_inode_lookup ( ) is invoked . Part of the code
* segment inside gfs2_inode_lookup code needs to get moved around .
*
* Clean up I_LOCK and I_NEW as well .
* */
void gfs2_set_iop ( struct inode * inode )
{
umode_t mode = inode - > i_mode ;
if ( S_ISREG ( mode ) ) {
inode - > i_op = & gfs2_file_iops ;
inode - > i_fop = & gfs2_file_fops ;
inode - > i_mapping - > a_ops = & gfs2_file_aops ;
} else if ( S_ISDIR ( mode ) ) {
inode - > i_op = & gfs2_dir_iops ;
inode - > i_fop = & gfs2_dir_fops ;
} else if ( S_ISLNK ( mode ) ) {
inode - > i_op = & gfs2_symlink_iops ;
} else {
inode - > i_op = & gfs2_dev_iops ;
}
unlock_new_inode ( inode ) ;
}
2006-01-16 19:50:04 +03:00
/**
2006-06-14 23:32:57 +04:00
* gfs2_inode_lookup - Lookup an inode
* @ sb : The super block
2007-05-15 18:37:50 +04:00
* @ no_addr : The inode number
2006-06-14 23:32:57 +04:00
* @ type : The type of the inode
2006-01-16 19:50:04 +03:00
*
2006-06-14 23:32:57 +04:00
* Returns : A VFS inode , or an error
2006-01-16 19:50:04 +03:00
*/
2007-06-28 01:07:08 +04:00
struct inode * gfs2_inode_lookup ( struct super_block * sb ,
unsigned int type ,
u64 no_addr ,
u64 no_formal_ino )
2006-01-16 19:50:04 +03:00
{
2007-05-15 18:37:50 +04:00
struct inode * inode = gfs2_iget ( sb , no_addr ) ;
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( inode ) ;
struct gfs2_glock * io_gl ;
int error ;
2006-01-16 19:50:04 +03:00
2006-10-31 00:59:08 +03:00
if ( ! inode )
return ERR_PTR ( - ENOBUFS ) ;
2006-06-14 23:32:57 +04:00
if ( inode - > i_state & I_NEW ) {
struct gfs2_sbd * sdp = GFS2_SB ( inode ) ;
2006-09-27 12:50:31 +04:00
inode - > i_private = ip ;
2007-06-28 01:07:08 +04:00
ip - > i_no_formal_ino = no_formal_ino ;
2006-01-16 19:50:04 +03:00
2007-05-15 18:37:50 +04:00
error = gfs2_glock_get ( sdp , no_addr , & gfs2_inode_glops , CREATE , & ip - > i_gl ) ;
2006-06-14 23:32:57 +04:00
if ( unlikely ( error ) )
goto fail ;
ip - > i_gl - > gl_object = ip ;
2006-01-16 19:50:04 +03:00
2007-05-15 18:37:50 +04:00
error = gfs2_glock_get ( sdp , no_addr , & gfs2_iopen_glops , CREATE , & io_gl ) ;
2006-06-14 23:32:57 +04:00
if ( unlikely ( error ) )
goto fail_put ;
2006-01-16 19:50:04 +03:00
2006-11-02 00:05:38 +03:00
set_bit ( GIF_INVALID , & ip - > i_flags ) ;
2006-06-14 23:32:57 +04:00
error = gfs2_glock_nq_init ( io_gl , LM_ST_SHARED , GL_EXACT , & ip - > i_iopen_gh ) ;
if ( unlikely ( error ) )
goto fail_iopen ;
2007-06-11 11:22:32 +04:00
ip - > i_iopen_gh . gh_gl - > gl_object = ip ;
2006-01-16 19:50:04 +03:00
2006-06-14 23:32:57 +04:00
gfs2_glock_put ( io_gl ) ;
2007-06-08 13:05:33 +04:00
2007-06-28 01:07:53 +04:00
if ( ( type = = DT_UNKNOWN ) & & ( no_formal_ino = = 0 ) )
goto gfs2_nfsbypass ;
inode - > i_mode = DT2IF ( type ) ;
2007-06-08 13:05:33 +04:00
/*
* We must read the inode in order to work out its type in
* this case . Note that this doesn ' t happen often as we normally
* know the type beforehand . This code path only occurs during
* unlinked inode recovery ( where it is safe to do this glock ,
* which is not true in the general case ) .
*/
if ( type = = DT_UNKNOWN ) {
struct gfs2_holder gh ;
error = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_EXCLUSIVE , 0 , & gh ) ;
if ( unlikely ( error ) )
goto fail_glock ;
/* Inode is now uptodate */
gfs2_glock_dq_uninit ( & gh ) ;
}
2007-06-28 01:07:53 +04:00
gfs2_set_iop ( inode ) ;
2006-06-14 23:32:57 +04:00
}
2006-01-16 19:50:04 +03:00
2007-06-28 01:07:53 +04:00
gfs2_nfsbypass :
2006-01-16 19:50:04 +03:00
return inode ;
2007-06-08 13:05:33 +04:00
fail_glock :
gfs2_glock_dq ( & ip - > i_iopen_gh ) ;
2006-06-14 23:32:57 +04:00
fail_iopen :
gfs2_glock_put ( io_gl ) ;
fail_put :
ip - > i_gl - > gl_object = NULL ;
gfs2_glock_put ( ip - > i_gl ) ;
fail :
iput ( inode ) ;
return ERR_PTR ( error ) ;
2006-01-16 19:50:04 +03:00
}
2006-11-01 18:34:15 +03:00
static int gfs2_dinode_in ( struct gfs2_inode * ip , const void * buf )
2006-10-31 23:28:00 +03:00
{
struct gfs2_dinode_host * di = & ip - > i_di ;
const struct gfs2_dinode * str = buf ;
2007-05-15 18:37:50 +04:00
if ( ip - > i_no_addr ! = be64_to_cpu ( str - > di_num . no_addr ) ) {
2006-11-01 18:34:15 +03:00
if ( gfs2_consist_inode ( ip ) )
gfs2_dinode_print ( ip ) ;
return - EIO ;
}
2007-05-15 18:37:50 +04:00
ip - > i_no_formal_ino = be64_to_cpu ( str - > di_num . no_formal_ino ) ;
2006-11-01 20:22:46 +03:00
ip - > i_inode . i_mode = be32_to_cpu ( str - > di_mode ) ;
2006-11-01 05:45:08 +03:00
ip - > i_inode . i_rdev = 0 ;
2006-11-01 20:22:46 +03:00
switch ( ip - > i_inode . i_mode & S_IFMT ) {
2006-11-01 05:45:08 +03:00
case S_IFBLK :
case S_IFCHR :
ip - > i_inode . i_rdev = MKDEV ( be32_to_cpu ( str - > di_major ) ,
be32_to_cpu ( str - > di_minor ) ) ;
break ;
} ;
2006-11-01 21:23:29 +03:00
ip - > i_inode . i_uid = be32_to_cpu ( str - > di_uid ) ;
ip - > i_inode . i_gid = be32_to_cpu ( str - > di_gid ) ;
2006-11-01 22:04:17 +03:00
/*
* We will need to review setting the nlink count here in the
* light of the forthcoming ro bind mount work . This is a reminder
* to do that .
*/
ip - > i_inode . i_nlink = be32_to_cpu ( str - > di_nlink ) ;
2006-10-31 23:28:00 +03:00
di - > di_size = be64_to_cpu ( str - > di_size ) ;
2006-11-08 23:45:46 +03:00
i_size_write ( & ip - > i_inode , di - > di_size ) ;
2006-10-31 23:28:00 +03:00
di - > di_blocks = be64_to_cpu ( str - > di_blocks ) ;
2006-11-08 23:45:46 +03:00
gfs2_set_inode_blocks ( & ip - > i_inode ) ;
2006-11-01 22:35:17 +03:00
ip - > i_inode . i_atime . tv_sec = be64_to_cpu ( str - > di_atime ) ;
2007-06-05 12:39:18 +04:00
ip - > i_inode . i_atime . tv_nsec = be32_to_cpu ( str - > di_atime_nsec ) ;
2006-11-01 22:35:17 +03:00
ip - > i_inode . i_mtime . tv_sec = be64_to_cpu ( str - > di_mtime ) ;
2007-06-05 12:39:18 +04:00
ip - > i_inode . i_mtime . tv_nsec = be32_to_cpu ( str - > di_mtime_nsec ) ;
2006-11-01 22:35:17 +03:00
ip - > i_inode . i_ctime . tv_sec = be64_to_cpu ( str - > di_ctime ) ;
2007-06-05 12:39:18 +04:00
ip - > i_inode . i_ctime . tv_nsec = be32_to_cpu ( str - > di_ctime_nsec ) ;
2006-10-31 23:28:00 +03:00
di - > di_goal_meta = be64_to_cpu ( str - > di_goal_meta ) ;
di - > di_goal_data = be64_to_cpu ( str - > di_goal_data ) ;
di - > di_generation = be64_to_cpu ( str - > di_generation ) ;
di - > di_flags = be32_to_cpu ( str - > di_flags ) ;
2006-11-08 20:51:06 +03:00
gfs2_set_inode_flags ( & ip - > i_inode ) ;
2006-10-31 23:28:00 +03:00
di - > di_height = be16_to_cpu ( str - > di_height ) ;
di - > di_depth = be16_to_cpu ( str - > di_depth ) ;
di - > di_entries = be32_to_cpu ( str - > di_entries ) ;
di - > di_eattr = be64_to_cpu ( str - > di_eattr ) ;
2006-11-01 18:34:15 +03:00
return 0 ;
2006-10-31 23:28:00 +03:00
}
2007-08-24 17:15:01 +04:00
static void gfs2_inode_bh ( struct gfs2_inode * ip , struct buffer_head * bh )
{
ip - > i_cache [ 0 ] = bh ;
}
2006-01-16 19:50:04 +03:00
/**
* gfs2_inode_refresh - Refresh the incore copy of the dinode
* @ ip : The GFS2 inode
*
* Returns : errno
*/
int gfs2_inode_refresh ( struct gfs2_inode * ip )
{
struct buffer_head * dibh ;
int error ;
error = gfs2_meta_inode_buffer ( ip , & dibh ) ;
if ( error )
return error ;
2006-06-14 23:32:57 +04:00
if ( gfs2_metatype_check ( GFS2_SB ( & ip - > i_inode ) , dibh , GFS2_METATYPE_DI ) ) {
2006-01-16 19:50:04 +03:00
brelse ( dibh ) ;
return - EIO ;
}
2006-11-01 18:34:15 +03:00
error = gfs2_dinode_in ( ip , dibh - > b_data ) ;
2006-01-16 19:50:04 +03:00
brelse ( dibh ) ;
2006-11-02 00:05:38 +03:00
clear_bit ( GIF_INVALID , & ip - > i_flags ) ;
2006-01-16 19:50:04 +03:00
2006-11-01 18:34:15 +03:00
return error ;
2006-01-16 19:50:04 +03:00
}
2006-06-14 23:32:57 +04:00
int gfs2_dinode_dealloc ( struct gfs2_inode * ip )
2006-01-16 19:50:04 +03:00
{
2006-06-14 23:32:57 +04:00
struct gfs2_sbd * sdp = GFS2_SB ( & ip - > i_inode ) ;
2006-01-16 19:50:04 +03:00
struct gfs2_alloc * al ;
struct gfs2_rgrpd * rgd ;
int error ;
if ( ip - > i_di . di_blocks ! = 1 ) {
if ( gfs2_consist_inode ( ip ) )
2006-11-01 03:00:24 +03:00
gfs2_dinode_print ( ip ) ;
2006-01-16 19:50:04 +03:00
return - EIO ;
}
al = gfs2_alloc_get ( ip ) ;
error = gfs2_quota_hold ( ip , NO_QUOTA_CHANGE , NO_QUOTA_CHANGE ) ;
if ( error )
goto out ;
error = gfs2_rindex_hold ( sdp , & al - > al_ri_gh ) ;
if ( error )
goto out_qs ;
2007-05-15 18:37:50 +04:00
rgd = gfs2_blk2rgrpd ( sdp , ip - > i_no_addr ) ;
2006-01-16 19:50:04 +03:00
if ( ! rgd ) {
gfs2_consist_inode ( ip ) ;
error = - EIO ;
goto out_rindex_relse ;
}
error = gfs2_glock_nq_init ( rgd - > rd_gl , LM_ST_EXCLUSIVE , 0 ,
& al - > al_rgd_gh ) ;
if ( error )
goto out_rindex_relse ;
2006-07-31 23:42:17 +04:00
error = gfs2_trans_begin ( sdp , RES_RG_BIT + RES_STATFS + RES_QUOTA , 1 ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_rg_gunlock ;
gfs2_trans_add_gl ( ip - > i_gl ) ;
gfs2_free_di ( rgd , ip ) ;
gfs2_trans_end ( sdp ) ;
clear_bit ( GLF_STICKY , & ip - > i_gl - > gl_flags ) ;
2006-06-14 23:32:57 +04:00
out_rg_gunlock :
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( & al - > al_rgd_gh ) ;
2006-06-14 23:32:57 +04:00
out_rindex_relse :
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( & al - > al_ri_gh ) ;
2006-06-14 23:32:57 +04:00
out_qs :
2006-01-16 19:50:04 +03:00
gfs2_quota_unhold ( ip ) ;
2006-04-28 18:46:21 +04:00
out :
2006-06-14 23:32:57 +04:00
gfs2_alloc_put ( ip ) ;
2006-01-16 19:50:04 +03:00
return error ;
}
/**
2007-01-19 00:07:03 +03:00
* gfs2_change_nlink - Change nlink count on inode
2006-01-16 19:50:04 +03:00
* @ ip : The GFS2 inode
* @ diff : The change in the nlink count required
*
* Returns : errno
*/
2007-01-19 00:07:03 +03:00
int gfs2_change_nlink ( struct gfs2_inode * ip , int diff )
2006-01-16 19:50:04 +03:00
{
struct buffer_head * dibh ;
2006-09-04 20:49:07 +04:00
u32 nlink ;
2006-01-16 19:50:04 +03:00
int error ;
2006-11-01 22:04:17 +03:00
BUG_ON ( diff ! = 1 & & diff ! = - 1 ) ;
nlink = ip - > i_inode . i_nlink + diff ;
2006-01-16 19:50:04 +03:00
/* If we are reducing the nlink count, but the new value ends up being
bigger than the old one , we must have underflowed . */
2006-11-01 22:04:17 +03:00
if ( diff < 0 & & nlink > ip - > i_inode . i_nlink ) {
2006-01-16 19:50:04 +03:00
if ( gfs2_consist_inode ( ip ) )
2006-11-01 03:00:24 +03:00
gfs2_dinode_print ( ip ) ;
2006-01-16 19:50:04 +03:00
return - EIO ;
}
error = gfs2_meta_inode_buffer ( ip , & dibh ) ;
if ( error )
return error ;
2006-11-01 22:04:17 +03:00
if ( diff > 0 )
inc_nlink ( & ip - > i_inode ) ;
else
drop_nlink ( & ip - > i_inode ) ;
2007-06-05 12:39:18 +04:00
ip - > i_inode . i_ctime = CURRENT_TIME ;
2006-01-16 19:50:04 +03:00
2006-01-18 14:19:28 +03:00
gfs2_trans_add_bh ( ip - > i_gl , dibh , 1 ) ;
2006-10-31 23:07:05 +03:00
gfs2_dinode_out ( ip , dibh - > b_data ) ;
2006-01-16 19:50:04 +03:00
brelse ( dibh ) ;
2006-06-14 23:32:57 +04:00
mark_inode_dirty ( & ip - > i_inode ) ;
2006-01-16 19:50:04 +03:00
2007-01-19 00:07:03 +03:00
if ( ip - > i_inode . i_nlink = = 0 )
2007-01-30 02:13:44 +03:00
gfs2_unlink_di ( & ip - > i_inode ) ; /* mark inode unlinked */
2007-01-19 00:07:03 +03:00
2007-01-18 23:56:34 +03:00
return error ;
}
2006-03-20 20:30:04 +03:00
struct inode * gfs2_lookup_simple ( struct inode * dip , const char * name )
{
struct qstr qstr ;
2007-01-09 02:47:51 +03:00
struct inode * inode ;
2006-03-28 23:14:04 +04:00
gfs2_str2qstr ( & qstr , name ) ;
2007-01-09 02:47:51 +03:00
inode = gfs2_lookupi ( dip , & qstr , 1 , NULL ) ;
/* 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 ;
2006-03-20 20:30:04 +03:00
}
2006-01-16 19:50:04 +03:00
/**
* 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
*
2007-01-25 20:14:59 +03:00
* 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 .
2006-01-16 19:50:04 +03:00
*
* Returns : errno
*/
2006-06-14 23:32:57 +04:00
struct inode * gfs2_lookupi ( struct inode * dir , const struct qstr * name ,
int is_root , struct nameidata * nd )
2006-01-16 19:50:04 +03:00
{
2006-03-01 23:31:02 +03:00
struct super_block * sb = dir - > i_sb ;
2006-06-14 23:32:57 +04:00
struct gfs2_inode * dip = GFS2_I ( dir ) ;
2006-01-16 19:50:04 +03:00
struct gfs2_holder d_gh ;
2007-06-09 03:42:14 +04:00
int error = 0 ;
2006-03-20 20:30:04 +03:00
struct inode * inode = NULL ;
2007-01-25 20:14:59 +03:00
int unlock = 0 ;
2006-01-16 19:50:04 +03:00
if ( ! name - > len | | name - > len > GFS2_FNAMESIZE )
2006-03-20 20:30:04 +03:00
return ERR_PTR ( - ENAMETOOLONG ) ;
2006-01-16 19:50:04 +03:00
2006-03-20 20:30:04 +03:00
if ( ( name - > len = = 1 & & memcmp ( name - > name , " . " , 1 ) = = 0 ) | |
( name - > len = = 2 & & memcmp ( name - > name , " .. " , 2 ) = = 0 & &
dir = = sb - > s_root - > d_inode ) ) {
2006-05-19 00:25:27 +04:00
igrab ( dir ) ;
return dir ;
2006-01-16 19:50:04 +03:00
}
2007-01-25 20:14:59 +03:00
if ( gfs2_glock_is_locked_by_me ( dip - > i_gl ) = = 0 ) {
error = gfs2_glock_nq_init ( dip - > i_gl , LM_ST_SHARED , 0 , & d_gh ) ;
if ( error )
return ERR_PTR ( error ) ;
unlock = 1 ;
}
2006-01-16 19:50:04 +03:00
if ( ! is_root ) {
2006-06-22 18:59:10 +04:00
error = permission ( dir , MAY_EXEC , NULL ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out ;
}
2007-05-15 18:37:50 +04:00
inode = gfs2_dir_search ( dir , name ) ;
if ( IS_ERR ( inode ) )
error = PTR_ERR ( inode ) ;
2006-02-13 15:27:43 +03:00
out :
2007-01-25 20:14:59 +03:00
if ( unlock )
gfs2_glock_dq_uninit ( & d_gh ) ;
2006-03-20 20:30:04 +03:00
if ( error = = - ENOENT )
return NULL ;
2007-01-25 20:14:59 +03:00
return inode ? inode : ERR_PTR ( error ) ;
2006-01-16 19:50:04 +03:00
}
2007-06-01 17:11:58 +04:00
static void gfs2_inum_range_in ( struct gfs2_inum_range_host * ir , const void * buf )
{
const struct gfs2_inum_range * str = buf ;
ir - > ir_start = be64_to_cpu ( str - > ir_start ) ;
ir - > ir_length = be64_to_cpu ( str - > ir_length ) ;
}
static void gfs2_inum_range_out ( const struct gfs2_inum_range_host * ir , void * buf )
{
struct gfs2_inum_range * str = buf ;
str - > ir_start = cpu_to_be64 ( ir - > ir_start ) ;
str - > ir_length = cpu_to_be64 ( ir - > ir_length ) ;
}
2006-09-04 20:49:07 +04:00
static int pick_formal_ino_1 ( struct gfs2_sbd * sdp , u64 * formal_ino )
2006-01-16 19:50:04 +03:00
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( sdp - > sd_ir_inode ) ;
2006-01-16 19:50:04 +03:00
struct buffer_head * bh ;
2006-10-14 05:29:46 +04:00
struct gfs2_inum_range_host ir ;
2006-01-16 19:50:04 +03:00
int error ;
error = gfs2_trans_begin ( sdp , RES_DINODE , 0 ) ;
if ( error )
return error ;
2006-02-21 15:51:39 +03:00
mutex_lock ( & sdp - > sd_inum_mutex ) ;
2006-01-16 19:50:04 +03:00
error = gfs2_meta_inode_buffer ( ip , & bh ) ;
if ( error ) {
2006-02-21 15:51:39 +03:00
mutex_unlock ( & sdp - > sd_inum_mutex ) ;
2006-01-16 19:50:04 +03:00
gfs2_trans_end ( sdp ) ;
return error ;
}
gfs2_inum_range_in ( & ir , bh - > b_data + sizeof ( struct gfs2_dinode ) ) ;
if ( ir . ir_length ) {
* formal_ino = ir . ir_start + + ;
ir . ir_length - - ;
2006-01-18 14:19:28 +03:00
gfs2_trans_add_bh ( ip - > i_gl , bh , 1 ) ;
2006-01-16 19:50:04 +03:00
gfs2_inum_range_out ( & ir ,
bh - > b_data + sizeof ( struct gfs2_dinode ) ) ;
brelse ( bh ) ;
2006-02-21 15:51:39 +03:00
mutex_unlock ( & sdp - > sd_inum_mutex ) ;
2006-01-16 19:50:04 +03:00
gfs2_trans_end ( sdp ) ;
return 0 ;
}
brelse ( bh ) ;
2006-02-21 15:51:39 +03:00
mutex_unlock ( & sdp - > sd_inum_mutex ) ;
2006-01-16 19:50:04 +03:00
gfs2_trans_end ( sdp ) ;
return 1 ;
}
2006-09-04 20:49:07 +04:00
static int pick_formal_ino_2 ( struct gfs2_sbd * sdp , u64 * formal_ino )
2006-01-16 19:50:04 +03:00
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( sdp - > sd_ir_inode ) ;
struct gfs2_inode * m_ip = GFS2_I ( sdp - > sd_inum_inode ) ;
2006-01-16 19:50:04 +03:00
struct gfs2_holder gh ;
struct buffer_head * bh ;
2006-10-14 05:29:46 +04:00
struct gfs2_inum_range_host ir ;
2006-01-16 19:50:04 +03:00
int error ;
error = gfs2_glock_nq_init ( m_ip - > i_gl , LM_ST_EXCLUSIVE , 0 , & gh ) ;
if ( error )
return error ;
error = gfs2_trans_begin ( sdp , 2 * RES_DINODE , 0 ) ;
if ( error )
goto out ;
2006-02-21 15:51:39 +03:00
mutex_lock ( & sdp - > sd_inum_mutex ) ;
2006-01-16 19:50:04 +03:00
error = gfs2_meta_inode_buffer ( ip , & bh ) ;
if ( error )
goto out_end_trans ;
2006-09-25 17:26:04 +04:00
2006-01-16 19:50:04 +03:00
gfs2_inum_range_in ( & ir , bh - > b_data + sizeof ( struct gfs2_dinode ) ) ;
if ( ! ir . ir_length ) {
struct buffer_head * m_bh ;
2006-09-04 20:49:07 +04:00
u64 x , y ;
2006-10-14 18:46:30 +04:00
__be64 z ;
2006-01-16 19:50:04 +03:00
error = gfs2_meta_inode_buffer ( m_ip , & m_bh ) ;
if ( error )
goto out_brelse ;
2006-10-14 18:46:30 +04:00
z = * ( __be64 * ) ( m_bh - > b_data + sizeof ( struct gfs2_dinode ) ) ;
x = y = be64_to_cpu ( z ) ;
2006-01-16 19:50:04 +03:00
ir . ir_start = x ;
ir . ir_length = GFS2_INUM_QUANTUM ;
x + = GFS2_INUM_QUANTUM ;
if ( x < y )
gfs2_consist_inode ( m_ip ) ;
2006-10-14 18:46:30 +04:00
z = cpu_to_be64 ( x ) ;
2006-01-18 14:19:28 +03:00
gfs2_trans_add_bh ( m_ip - > i_gl , m_bh , 1 ) ;
2006-10-14 18:46:30 +04:00
* ( __be64 * ) ( m_bh - > b_data + sizeof ( struct gfs2_dinode ) ) = z ;
2006-01-16 19:50:04 +03:00
brelse ( m_bh ) ;
}
* formal_ino = ir . ir_start + + ;
ir . ir_length - - ;
2006-01-18 14:19:28 +03:00
gfs2_trans_add_bh ( ip - > i_gl , bh , 1 ) ;
2006-01-16 19:50:04 +03:00
gfs2_inum_range_out ( & ir , bh - > b_data + sizeof ( struct gfs2_dinode ) ) ;
2006-07-31 23:42:17 +04:00
out_brelse :
2006-01-16 19:50:04 +03:00
brelse ( bh ) ;
2006-07-31 23:42:17 +04:00
out_end_trans :
2006-02-21 15:51:39 +03:00
mutex_unlock ( & sdp - > sd_inum_mutex ) ;
2006-01-16 19:50:04 +03:00
gfs2_trans_end ( sdp ) ;
2006-07-31 23:42:17 +04:00
out :
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( & gh ) ;
return error ;
}
2006-09-04 20:49:07 +04:00
static int pick_formal_ino ( struct gfs2_sbd * sdp , u64 * inum )
2006-01-16 19:50:04 +03:00
{
int error ;
error = pick_formal_ino_1 ( sdp , inum ) ;
if ( error < = 0 )
return error ;
error = pick_formal_ino_2 ( sdp , inum ) ;
return 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
*/
2006-06-14 23:32:57 +04:00
static int create_ok ( struct gfs2_inode * dip , const struct qstr * name ,
2006-01-16 19:50:04 +03:00
unsigned int mode )
{
int error ;
2006-06-22 18:59:10 +04:00
error = permission ( & dip - > i_inode , MAY_WRITE | MAY_EXEC , NULL ) ;
2006-01-16 19:50:04 +03:00
if ( error )
return error ;
/* Don't create entries in an unlinked directory */
2006-11-01 22:04:17 +03:00
if ( ! dip - > i_inode . i_nlink )
2006-01-16 19:50:04 +03:00
return - EPERM ;
2007-05-15 18:37:50 +04:00
error = gfs2_dir_check ( & dip - > i_inode , name , NULL ) ;
2006-01-16 19:50:04 +03:00
switch ( error ) {
case - ENOENT :
error = 0 ;
break ;
case 0 :
return - EEXIST ;
default :
return error ;
}
2006-09-04 20:49:07 +04:00
if ( dip - > i_di . di_entries = = ( u32 ) - 1 )
2006-01-16 19:50:04 +03:00
return - EFBIG ;
2006-11-01 22:04:17 +03:00
if ( S_ISDIR ( mode ) & & dip - > i_inode . i_nlink = = ( u32 ) - 1 )
2006-01-16 19:50:04 +03:00
return - EMLINK ;
return 0 ;
}
static void munge_mode_uid_gid ( struct gfs2_inode * dip , unsigned int * mode ,
unsigned int * uid , unsigned int * gid )
{
2006-06-14 23:32:57 +04:00
if ( GFS2_SB ( & dip - > i_inode ) - > sd_args . ar_suiddir & &
2006-11-01 21:23:29 +03:00
( dip - > i_inode . i_mode & S_ISUID ) & & dip - > i_inode . i_uid ) {
2006-01-16 19:50:04 +03:00
if ( S_ISDIR ( * mode ) )
* mode | = S_ISUID ;
2006-11-01 21:23:29 +03:00
else if ( dip - > i_inode . i_uid ! = current - > fsuid )
2006-01-16 19:50:04 +03:00
* mode & = ~ 07111 ;
2006-11-01 21:23:29 +03:00
* uid = dip - > i_inode . i_uid ;
2006-01-16 19:50:04 +03:00
} else
* uid = current - > fsuid ;
2006-11-01 20:22:46 +03:00
if ( dip - > i_inode . i_mode & S_ISGID ) {
2006-01-16 19:50:04 +03:00
if ( S_ISDIR ( * mode ) )
* mode | = S_ISGID ;
2006-11-01 21:23:29 +03:00
* gid = dip - > i_inode . i_gid ;
2006-01-16 19:50:04 +03:00
} else
* gid = current - > fsgid ;
}
2007-05-15 18:37:50 +04:00
static int alloc_dinode ( struct gfs2_inode * dip , u64 * no_addr , u64 * generation )
2006-01-16 19:50:04 +03:00
{
2006-06-14 23:32:57 +04:00
struct gfs2_sbd * sdp = GFS2_SB ( & dip - > i_inode ) ;
2006-01-16 19:50:04 +03:00
int error ;
gfs2_alloc_get ( dip ) ;
dip - > i_alloc . al_requested = RES_DINODE ;
error = gfs2_inplace_reserve ( dip ) ;
if ( error )
goto out ;
2006-06-14 23:32:57 +04:00
error = gfs2_trans_begin ( sdp , RES_RG_BIT + RES_STATFS , 0 ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_ipreserv ;
2007-05-15 18:37:50 +04:00
* no_addr = gfs2_alloc_di ( dip , generation ) ;
2006-01-16 19:50:04 +03:00
gfs2_trans_end ( sdp ) ;
2006-07-11 17:46:33 +04:00
out_ipreserv :
2006-01-16 19:50:04 +03:00
gfs2_inplace_release ( dip ) ;
2006-07-11 17:46:33 +04:00
out :
2006-01-16 19:50:04 +03:00
gfs2_alloc_put ( dip ) ;
return error ;
}
/**
* init_dinode - Fill in a new dinode structure
* @ dip : the directory this inode is being created in
* @ gl : The glock covering the new inode
* @ inum : the inode number
* @ mode : the file permissions
* @ uid :
* @ gid :
*
*/
static void init_dinode ( struct gfs2_inode * dip , struct gfs2_glock * gl ,
2006-10-14 06:51:24 +04:00
const struct gfs2_inum_host * inum , unsigned int mode ,
2006-07-11 17:46:33 +04:00
unsigned int uid , unsigned int gid ,
2007-08-24 17:15:01 +04:00
const u64 * generation , dev_t dev , struct buffer_head * * bhp )
2006-01-16 19:50:04 +03:00
{
2006-06-14 23:32:57 +04:00
struct gfs2_sbd * sdp = GFS2_SB ( & dip - > i_inode ) ;
2006-01-18 13:57:10 +03:00
struct gfs2_dinode * di ;
2006-01-16 19:50:04 +03:00
struct buffer_head * dibh ;
2007-06-05 12:39:18 +04:00
struct timespec tv = CURRENT_TIME ;
2006-01-16 19:50:04 +03:00
dibh = gfs2_meta_new ( gl , inum - > no_addr ) ;
2006-01-18 14:19:28 +03:00
gfs2_trans_add_bh ( gl , dibh , 1 ) ;
2006-01-16 19:50:04 +03:00
gfs2_metatype_set ( dibh , GFS2_METATYPE_DI , GFS2_FORMAT_DI ) ;
gfs2_buffer_clear_tail ( dibh , sizeof ( struct gfs2_dinode ) ) ;
2006-01-18 13:57:10 +03:00
di = ( struct gfs2_dinode * ) dibh - > b_data ;
2006-01-30 14:49:32 +03:00
di - > di_num . no_formal_ino = cpu_to_be64 ( inum - > no_formal_ino ) ;
di - > di_num . no_addr = cpu_to_be64 ( inum - > no_addr ) ;
2006-01-18 13:57:10 +03:00
di - > di_mode = cpu_to_be32 ( mode ) ;
di - > di_uid = cpu_to_be32 ( uid ) ;
di - > di_gid = cpu_to_be32 ( gid ) ;
2006-11-02 19:59:28 +03:00
di - > di_nlink = 0 ;
di - > di_size = 0 ;
2006-01-18 13:57:10 +03:00
di - > di_blocks = cpu_to_be64 ( 1 ) ;
2007-06-05 12:39:18 +04:00
di - > di_atime = di - > di_mtime = di - > di_ctime = cpu_to_be64 ( tv . tv_sec ) ;
2006-11-01 05:45:08 +03:00
di - > di_major = cpu_to_be32 ( MAJOR ( dev ) ) ;
di - > di_minor = cpu_to_be32 ( MINOR ( dev ) ) ;
2006-01-18 13:57:10 +03:00
di - > di_goal_meta = di - > di_goal_data = cpu_to_be64 ( inum - > no_addr ) ;
2006-07-11 17:46:33 +04:00
di - > di_generation = cpu_to_be64 ( * generation ) ;
2006-11-02 19:59:28 +03:00
di - > di_flags = 0 ;
2006-01-16 19:50:04 +03:00
if ( S_ISREG ( mode ) ) {
if ( ( dip - > i_di . di_flags & GFS2_DIF_INHERIT_JDATA ) | |
gfs2_tune_get ( sdp , gt_new_files_jdata ) )
2006-01-18 13:57:10 +03:00
di - > di_flags | = cpu_to_be32 ( GFS2_DIF_JDATA ) ;
2006-01-16 19:50:04 +03:00
if ( ( dip - > i_di . di_flags & GFS2_DIF_INHERIT_DIRECTIO ) | |
gfs2_tune_get ( sdp , gt_new_files_directio ) )
2006-01-18 13:57:10 +03:00
di - > di_flags | = cpu_to_be32 ( GFS2_DIF_DIRECTIO ) ;
2006-01-16 19:50:04 +03:00
} else if ( S_ISDIR ( mode ) ) {
2006-02-27 20:00:42 +03:00
di - > di_flags | = cpu_to_be32 ( dip - > i_di . di_flags &
GFS2_DIF_INHERIT_DIRECTIO ) ;
di - > di_flags | = cpu_to_be32 ( dip - > i_di . di_flags &
GFS2_DIF_INHERIT_JDATA ) ;
2006-01-16 19:50:04 +03:00
}
2006-01-18 13:57:10 +03:00
di - > __pad1 = 0 ;
2006-11-02 04:09:14 +03:00
di - > di_payload_format = cpu_to_be32 ( S_ISDIR ( mode ) ? GFS2_FORMAT_DE : 0 ) ;
2006-11-02 19:59:28 +03:00
di - > di_height = 0 ;
2006-01-18 13:57:10 +03:00
di - > __pad2 = 0 ;
di - > __pad3 = 0 ;
2006-11-02 19:59:28 +03:00
di - > di_depth = 0 ;
di - > di_entries = 0 ;
2006-01-18 13:57:10 +03:00
memset ( & di - > __pad4 , 0 , sizeof ( di - > __pad4 ) ) ;
2006-11-02 19:59:28 +03:00
di - > di_eattr = 0 ;
2007-06-05 12:39:18 +04:00
di - > di_atime_nsec = cpu_to_be32 ( tv . tv_nsec ) ;
di - > di_mtime_nsec = cpu_to_be32 ( tv . tv_nsec ) ;
di - > di_ctime_nsec = cpu_to_be32 ( tv . tv_nsec ) ;
2006-01-18 13:57:10 +03:00
memset ( & di - > di_reserved , 0 , sizeof ( di - > di_reserved ) ) ;
2007-08-24 17:15:01 +04:00
set_buffer_uptodate ( dibh ) ;
2006-01-18 13:57:10 +03:00
2007-08-24 17:15:01 +04:00
* bhp = dibh ;
2006-01-16 19:50:04 +03:00
}
static int make_dinode ( struct gfs2_inode * dip , struct gfs2_glock * gl ,
2006-10-14 06:51:24 +04:00
unsigned int mode , const struct gfs2_inum_host * inum ,
2007-08-24 17:15:01 +04:00
const u64 * generation , dev_t dev , struct buffer_head * * bhp )
2006-01-16 19:50:04 +03:00
{
2006-06-14 23:32:57 +04:00
struct gfs2_sbd * sdp = GFS2_SB ( & dip - > i_inode ) ;
2006-01-16 19:50:04 +03:00
unsigned int uid , gid ;
int error ;
munge_mode_uid_gid ( dip , & mode , & uid , & gid ) ;
gfs2_alloc_get ( dip ) ;
error = gfs2_quota_lock ( dip , uid , gid ) ;
if ( error )
goto out ;
error = gfs2_quota_check ( dip , uid , gid ) ;
if ( error )
goto out_quota ;
2006-06-14 23:32:57 +04:00
error = gfs2_trans_begin ( sdp , RES_DINODE + RES_QUOTA , 0 ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out_quota ;
2007-08-24 17:15:01 +04:00
init_dinode ( dip , gl , inum , mode , uid , gid , generation , dev , bhp ) ;
2006-01-16 19:50:04 +03:00
gfs2_quota_change ( dip , + 1 , uid , gid ) ;
gfs2_trans_end ( sdp ) ;
2006-06-14 23:32:57 +04:00
out_quota :
2006-01-16 19:50:04 +03:00
gfs2_quota_unlock ( dip ) ;
2006-06-14 23:32:57 +04:00
out :
2006-01-16 19:50:04 +03:00
gfs2_alloc_put ( dip ) ;
return error ;
}
2006-06-14 23:32:57 +04:00
static int link_dinode ( struct gfs2_inode * dip , const struct qstr * name ,
struct gfs2_inode * ip )
2006-01-16 19:50:04 +03:00
{
2006-06-14 23:32:57 +04:00
struct gfs2_sbd * sdp = GFS2_SB ( & dip - > i_inode ) ;
2006-01-16 19:50:04 +03:00
struct gfs2_alloc * al ;
int alloc_required ;
struct buffer_head * dibh ;
int error ;
al = gfs2_alloc_get ( dip ) ;
error = gfs2_quota_lock ( dip , NO_QUOTA_CHANGE , NO_QUOTA_CHANGE ) ;
if ( error )
goto fail ;
2006-06-14 23:32:57 +04:00
error = alloc_required = gfs2_diradd_alloc_required ( & dip - > i_inode , name ) ;
2006-03-20 20:30:04 +03:00
if ( alloc_required < 0 )
goto fail ;
2006-01-16 19:50:04 +03:00
if ( alloc_required ) {
2006-11-01 21:23:29 +03:00
error = gfs2_quota_check ( dip , dip - > i_inode . i_uid , dip - > i_inode . i_gid ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto fail_quota_locks ;
al - > al_requested = sdp - > sd_max_dirres ;
error = gfs2_inplace_reserve ( dip ) ;
if ( error )
goto fail_quota_locks ;
2006-05-19 00:25:27 +04:00
error = gfs2_trans_begin ( sdp , sdp - > sd_max_dirres +
2007-06-01 17:11:58 +04:00
al - > al_rgd - > rd_length +
2006-09-25 17:26:04 +04:00
2 * RES_DINODE +
2006-01-16 19:50:04 +03:00
RES_STATFS + RES_QUOTA , 0 ) ;
if ( error )
goto fail_ipreserv ;
} else {
2006-06-14 23:32:57 +04:00
error = gfs2_trans_begin ( sdp , RES_LEAF + 2 * RES_DINODE , 0 ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto fail_quota_locks ;
}
2007-05-15 18:37:50 +04:00
error = gfs2_dir_add ( & dip - > i_inode , name , ip , IF2DT ( ip - > i_inode . i_mode ) ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto fail_end_trans ;
error = gfs2_meta_inode_buffer ( ip , & dibh ) ;
if ( error )
goto fail_end_trans ;
2006-11-01 22:04:17 +03:00
ip - > i_inode . i_nlink = 1 ;
2006-01-18 14:19:28 +03:00
gfs2_trans_add_bh ( ip - > i_gl , dibh , 1 ) ;
2006-10-31 23:07:05 +03:00
gfs2_dinode_out ( ip , dibh - > b_data ) ;
2006-01-16 19:50:04 +03:00
brelse ( dibh ) ;
return 0 ;
2006-05-19 00:25:27 +04:00
fail_end_trans :
2006-01-16 19:50:04 +03:00
gfs2_trans_end ( sdp ) ;
2006-05-19 00:25:27 +04:00
fail_ipreserv :
2006-01-16 19:50:04 +03:00
if ( dip - > i_alloc . al_rgd )
gfs2_inplace_release ( dip ) ;
2006-05-19 00:25:27 +04:00
fail_quota_locks :
2006-01-16 19:50:04 +03:00
gfs2_quota_unlock ( dip ) ;
2006-05-19 00:25:27 +04:00
fail :
2006-01-16 19:50:04 +03:00
gfs2_alloc_put ( dip ) ;
return error ;
}
2006-10-03 19:57:35 +04:00
static int gfs2_security_init ( struct gfs2_inode * dip , struct gfs2_inode * ip )
{
int err ;
size_t len ;
void * value ;
char * name ;
struct gfs2_ea_request er ;
err = security_inode_init_security ( & ip - > i_inode , & dip - > i_inode ,
& name , & value , & len ) ;
if ( err ) {
if ( err = = - EOPNOTSUPP )
return 0 ;
return err ;
}
memset ( & er , 0 , sizeof ( struct gfs2_ea_request ) ) ;
er . er_type = GFS2_EATYPE_SECURITY ;
er . er_name = name ;
er . er_data = value ;
er . er_name_len = strlen ( name ) ;
er . er_data_len = len ;
err = gfs2_ea_set_i ( ip , & er ) ;
kfree ( value ) ;
kfree ( name ) ;
return err ;
}
2006-01-16 19:50:04 +03:00
/**
* gfs2_createi - Create a new inode
* @ ghs : An array of two holders
* @ name : The name of the new file
* @ mode : the permissions on the new inode
*
* @ ghs [ 0 ] is an initialized holder for the directory
* @ ghs [ 1 ] is the holder for the inode lock
*
2006-02-13 15:27:43 +03:00
* If the return value is not NULL , the glocks on both the directory and the new
2006-01-16 19:50:04 +03:00
* file are held . A transaction has been started and an inplace reservation
* is held , as well .
*
2006-02-13 15:27:43 +03:00
* Returns : An inode
2006-01-16 19:50:04 +03:00
*/
2006-06-14 23:32:57 +04:00
struct inode * gfs2_createi ( struct gfs2_holder * ghs , const struct qstr * name ,
2006-11-01 05:45:08 +03:00
unsigned int mode , dev_t dev )
2006-01-16 19:50:04 +03:00
{
2007-06-07 14:47:52 +04:00
struct inode * inode = NULL ;
2006-02-28 01:23:27 +03:00
struct gfs2_inode * dip = ghs - > gh_gl - > gl_object ;
2006-06-14 23:32:57 +04:00
struct inode * dir = & dip - > i_inode ;
struct gfs2_sbd * sdp = GFS2_SB ( & dip - > i_inode ) ;
2007-05-15 18:37:50 +04:00
struct gfs2_inum_host inum = { . no_addr = 0 , . no_formal_ino = 0 } ;
2006-01-16 19:50:04 +03:00
int error ;
2006-07-11 17:46:33 +04:00
u64 generation ;
2007-08-24 17:15:01 +04:00
struct buffer_head * bh = NULL ;
2006-01-16 19:50:04 +03:00
if ( ! name - > len | | name - > len > GFS2_FNAMESIZE )
2006-02-13 15:27:43 +03:00
return ERR_PTR ( - ENAMETOOLONG ) ;
2006-01-16 19:50:04 +03:00
gfs2_holder_reinit ( LM_ST_EXCLUSIVE , 0 , ghs ) ;
error = gfs2_glock_nq ( ghs ) ;
if ( error )
goto fail ;
error = create_ok ( dip , name , mode ) ;
if ( error )
goto fail_gunlock ;
2006-06-14 23:32:57 +04:00
error = pick_formal_ino ( sdp , & inum . no_formal_ino ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto fail_gunlock ;
2007-05-15 18:37:50 +04:00
error = alloc_dinode ( dip , & inum . no_addr , & generation ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto fail_gunlock ;
2006-11-22 19:13:21 +03:00
error = gfs2_glock_nq_num ( sdp , inum . no_addr , & gfs2_inode_glops ,
LM_ST_EXCLUSIVE , GL_SKIP , ghs + 1 ) ;
if ( error )
goto fail_gunlock ;
2006-01-16 19:50:04 +03:00
2007-08-24 17:15:01 +04:00
error = make_dinode ( dip , ghs [ 1 ] . gh_gl , mode , & inum , & generation , dev , & bh ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto fail_gunlock2 ;
2007-06-28 01:07:08 +04:00
inode = gfs2_inode_lookup ( dir - > i_sb , IF2DT ( mode ) ,
inum . no_addr ,
inum . no_formal_ino ) ;
2006-06-14 23:32:57 +04:00
if ( IS_ERR ( inode ) )
2006-01-16 19:50:04 +03:00
goto fail_gunlock2 ;
2007-08-24 17:15:01 +04:00
gfs2_inode_bh ( GFS2_I ( inode ) , bh ) ;
2006-06-14 23:32:57 +04:00
error = gfs2_inode_refresh ( GFS2_I ( inode ) ) ;
2006-01-16 19:50:04 +03:00
if ( error )
2007-06-07 14:47:52 +04:00
goto fail_gunlock2 ;
2006-01-16 19:50:04 +03:00
2006-06-14 23:32:57 +04:00
error = gfs2_acl_create ( dip , GFS2_I ( inode ) ) ;
2006-01-16 19:50:04 +03:00
if ( error )
2007-06-07 14:47:52 +04:00
goto fail_gunlock2 ;
2006-01-16 19:50:04 +03:00
2006-10-03 19:57:35 +04:00
error = gfs2_security_init ( dip , GFS2_I ( inode ) ) ;
if ( error )
2007-06-07 14:47:52 +04:00
goto fail_gunlock2 ;
2006-10-03 19:57:35 +04:00
2006-06-14 23:32:57 +04:00
error = link_dinode ( dip , name , GFS2_I ( inode ) ) ;
2006-01-16 19:50:04 +03:00
if ( error )
2007-06-07 14:47:52 +04:00
goto fail_gunlock2 ;
2006-01-16 19:50:04 +03:00
2006-02-13 15:27:43 +03:00
if ( ! inode )
return ERR_PTR ( - ENOMEM ) ;
return inode ;
2006-01-16 19:50:04 +03:00
2006-05-19 00:25:27 +04:00
fail_gunlock2 :
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( ghs + 1 ) ;
2007-06-07 14:47:52 +04:00
if ( inode )
iput ( inode ) ;
2006-05-19 00:25:27 +04:00
fail_gunlock :
2006-01-16 19:50:04 +03:00
gfs2_glock_dq ( ghs ) ;
2006-05-19 00:25:27 +04:00
fail :
2006-02-13 15:27:43 +03:00
return ERR_PTR ( error ) ;
2006-01-16 19:50:04 +03:00
}
/**
* gfs2_rmdiri - Remove a directory
* @ dip : The parent directory of the directory to be removed
* @ name : The name of the directory to be removed
* @ ip : The GFS2 inode of the directory to be removed
*
* Assumes Glocks on dip and ip are held
*
* Returns : errno
*/
2006-06-14 23:32:57 +04:00
int gfs2_rmdiri ( struct gfs2_inode * dip , const struct qstr * name ,
struct gfs2_inode * ip )
2006-01-16 19:50:04 +03:00
{
struct qstr dotname ;
int error ;
if ( ip - > i_di . di_entries ! = 2 ) {
if ( gfs2_consist_inode ( ip ) )
2006-11-01 03:00:24 +03:00
gfs2_dinode_print ( ip ) ;
2006-01-16 19:50:04 +03:00
return - EIO ;
}
error = gfs2_dir_del ( dip , name ) ;
if ( error )
return error ;
error = gfs2_change_nlink ( dip , - 1 ) ;
if ( error )
return error ;
2006-03-28 23:14:04 +04:00
gfs2_str2qstr ( & dotname , " . " ) ;
2006-01-16 19:50:04 +03:00
error = gfs2_dir_del ( ip , & dotname ) ;
if ( error )
return error ;
2006-06-14 23:32:57 +04:00
gfs2_str2qstr ( & dotname , " .. " ) ;
2006-01-16 19:50:04 +03:00
error = gfs2_dir_del ( ip , & dotname ) ;
if ( error )
return error ;
2006-11-01 22:04:17 +03:00
/* It looks odd, but it really should be done twice */
error = gfs2_change_nlink ( ip , - 1 ) ;
if ( error )
return error ;
error = gfs2_change_nlink ( ip , - 1 ) ;
2006-01-16 19:50:04 +03:00
if ( error )
return error ;
return error ;
}
/*
* 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
*/
2006-06-14 23:32:57 +04:00
int gfs2_unlink_ok ( struct gfs2_inode * dip , const struct qstr * name ,
2007-05-15 18:37:50 +04:00
const struct gfs2_inode * ip )
2006-01-16 19:50:04 +03:00
{
int error ;
2006-06-14 23:32:57 +04:00
if ( IS_IMMUTABLE ( & ip - > i_inode ) | | IS_APPEND ( & ip - > i_inode ) )
2006-01-16 19:50:04 +03:00
return - EPERM ;
2006-11-01 20:22:46 +03:00
if ( ( dip - > i_inode . i_mode & S_ISVTX ) & &
2006-11-01 21:23:29 +03:00
dip - > i_inode . i_uid ! = current - > fsuid & &
ip - > i_inode . i_uid ! = current - > fsuid & & ! capable ( CAP_FOWNER ) )
2006-01-16 19:50:04 +03:00
return - EPERM ;
2006-06-14 23:32:57 +04:00
if ( IS_APPEND ( & dip - > i_inode ) )
2006-01-16 19:50:04 +03:00
return - EPERM ;
2006-06-22 18:59:10 +04:00
error = permission ( & dip - > i_inode , MAY_WRITE | MAY_EXEC , NULL ) ;
2006-01-16 19:50:04 +03:00
if ( error )
return error ;
2007-05-15 18:37:50 +04:00
error = gfs2_dir_check ( & dip - > i_inode , name , ip ) ;
2006-01-16 19:50:04 +03:00
if ( error )
return error ;
return 0 ;
}
/*
* 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
*/
int gfs2_ok_to_move ( struct gfs2_inode * this , struct gfs2_inode * to )
{
2006-06-14 23:32:57 +04:00
struct inode * dir = & to - > i_inode ;
2006-03-01 23:31:02 +03:00
struct super_block * sb = dir - > i_sb ;
2006-02-13 15:27:43 +03:00
struct inode * tmp ;
2006-01-16 19:50:04 +03:00
struct qstr dotdot ;
int error = 0 ;
2006-03-28 23:14:04 +04:00
gfs2_str2qstr ( & dotdot , " .. " ) ;
2006-01-16 19:50:04 +03:00
2006-02-13 15:27:43 +03:00
igrab ( dir ) ;
2006-01-16 19:50:04 +03:00
for ( ; ; ) {
2006-06-14 23:32:57 +04:00
if ( dir = = & this - > i_inode ) {
2006-01-16 19:50:04 +03:00
error = - EINVAL ;
break ;
}
2006-03-01 23:31:02 +03:00
if ( dir = = sb - > s_root - > d_inode ) {
2006-01-16 19:50:04 +03:00
error = 0 ;
break ;
}
2006-03-20 20:30:04 +03:00
tmp = gfs2_lookupi ( dir , & dotdot , 1 , NULL ) ;
if ( IS_ERR ( tmp ) ) {
error = PTR_ERR ( tmp ) ;
2006-01-16 19:50:04 +03:00
break ;
2006-03-20 20:30:04 +03:00
}
2006-01-16 19:50:04 +03:00
2006-02-13 15:27:43 +03:00
iput ( dir ) ;
dir = tmp ;
2006-01-16 19:50:04 +03:00
}
2006-02-13 15:27:43 +03:00
iput ( dir ) ;
2006-01-16 19:50:04 +03:00
return error ;
}
/**
* gfs2_readlinki - return the contents of a symlink
* @ ip : the symlink ' s inode
* @ buf : a pointer to the buffer to be filled
* @ len : a pointer to the length of @ buf
*
* If @ buf is too small , a piece of memory is kmalloc ( ) ed and needs
* to be freed by the caller .
*
* Returns : errno
*/
int gfs2_readlinki ( struct gfs2_inode * ip , char * * buf , unsigned int * len )
{
struct gfs2_holder i_gh ;
struct buffer_head * dibh ;
unsigned int x ;
int error ;
gfs2_holder_init ( ip - > i_gl , LM_ST_SHARED , GL_ATIME , & i_gh ) ;
error = gfs2_glock_nq_atime ( & i_gh ) ;
if ( error ) {
gfs2_holder_uninit ( & i_gh ) ;
return error ;
}
if ( ! ip - > i_di . di_size ) {
gfs2_consist_inode ( ip ) ;
error = - EIO ;
goto out ;
}
error = gfs2_meta_inode_buffer ( ip , & dibh ) ;
if ( error )
goto out ;
x = ip - > i_di . di_size + 1 ;
if ( x > * len ) {
* buf = kmalloc ( x , GFP_KERNEL ) ;
if ( ! * buf ) {
error = - ENOMEM ;
goto out_brelse ;
}
}
memcpy ( * buf , dibh - > b_data + sizeof ( struct gfs2_dinode ) , x ) ;
* len = x ;
2006-06-14 23:32:57 +04:00
out_brelse :
2006-01-16 19:50:04 +03:00
brelse ( dibh ) ;
2006-06-14 23:32:57 +04:00
out :
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( & i_gh ) ;
return error ;
}
/**
* gfs2_glock_nq_atime - Acquire a hold on an inode ' s glock , and
* conditionally update the inode ' s atime
* @ gh : the holder to acquire
*
* Tests atime ( access time ) for gfs2_read , gfs2_readdir and gfs2_mmap
* Update if the difference between the current time and the inode ' s current
* atime is greater than an interval specified at mount .
*
* Returns : errno
*/
int gfs2_glock_nq_atime ( struct gfs2_holder * gh )
{
struct gfs2_glock * gl = gh - > gh_gl ;
struct gfs2_sbd * sdp = gl - > gl_sbd ;
2006-02-28 01:23:27 +03:00
struct gfs2_inode * ip = gl - > gl_object ;
2007-06-05 12:39:18 +04:00
s64 quantum = gfs2_tune_get ( sdp , gt_atime_quantum ) ;
2006-01-16 19:50:04 +03:00
unsigned int state ;
int flags ;
int error ;
2007-06-05 12:39:18 +04:00
struct timespec tv = CURRENT_TIME ;
2006-01-16 19:50:04 +03:00
if ( gfs2_assert_warn ( sdp , gh - > gh_flags & GL_ATIME ) | |
gfs2_assert_warn ( sdp , ! ( gh - > gh_flags & GL_ASYNC ) ) | |
gfs2_assert_warn ( sdp , gl - > gl_ops = = & gfs2_inode_glops ) )
return - EINVAL ;
state = gh - > gh_state ;
flags = gh - > gh_flags ;
error = gfs2_glock_nq ( gh ) ;
if ( error )
return error ;
if ( test_bit ( SDF_NOATIME , & sdp - > sd_flags ) | |
( sdp - > sd_vfs - > s_flags & MS_RDONLY ) )
return 0 ;
2007-06-05 12:39:18 +04:00
if ( tv . tv_sec - ip - > i_inode . i_atime . tv_sec > = quantum ) {
2006-01-16 19:50:04 +03:00
gfs2_glock_dq ( gh ) ;
2006-05-06 00:59:11 +04:00
gfs2_holder_reinit ( LM_ST_EXCLUSIVE , gh - > gh_flags & ~ LM_FLAG_ANY ,
gh ) ;
2006-01-16 19:50:04 +03:00
error = gfs2_glock_nq ( gh ) ;
if ( error )
return error ;
/* Verify that atime hasn't been updated while we were
trying to get exclusive lock . */
2007-06-05 12:39:18 +04:00
tv = CURRENT_TIME ;
if ( tv . tv_sec - ip - > i_inode . i_atime . tv_sec > = quantum ) {
2006-01-16 19:50:04 +03:00
struct buffer_head * dibh ;
2006-10-02 20:39:19 +04:00
struct gfs2_dinode * di ;
2006-01-16 19:50:04 +03:00
error = gfs2_trans_begin ( sdp , RES_DINODE , 0 ) ;
if ( error = = - EROFS )
return 0 ;
if ( error )
goto fail ;
error = gfs2_meta_inode_buffer ( ip , & dibh ) ;
if ( error )
goto fail_end_trans ;
2007-06-05 12:39:18 +04:00
ip - > i_inode . i_atime = tv ;
2006-01-16 19:50:04 +03:00
2006-01-18 14:19:28 +03:00
gfs2_trans_add_bh ( ip - > i_gl , dibh , 1 ) ;
2006-10-02 20:39:19 +04:00
di = ( struct gfs2_dinode * ) dibh - > b_data ;
2006-11-01 22:35:17 +03:00
di - > di_atime = cpu_to_be64 ( ip - > i_inode . i_atime . tv_sec ) ;
2007-06-05 12:39:18 +04:00
di - > di_atime_nsec = cpu_to_be32 ( ip - > i_inode . i_atime . tv_nsec ) ;
2006-01-16 19:50:04 +03:00
brelse ( dibh ) ;
gfs2_trans_end ( sdp ) ;
}
/* If someone else has asked for the glock,
unlock and let them have it . Then reacquire
in the original state . */
if ( gfs2_glock_is_blocking ( gl ) ) {
gfs2_glock_dq ( gh ) ;
gfs2_holder_reinit ( state , flags , gh ) ;
return gfs2_glock_nq ( gh ) ;
}
}
return 0 ;
2006-06-14 23:32:57 +04:00
fail_end_trans :
2006-01-16 19:50:04 +03:00
gfs2_trans_end ( sdp ) ;
2006-06-14 23:32:57 +04:00
fail :
2006-01-16 19:50:04 +03:00
gfs2_glock_dq ( gh ) ;
return error ;
}
static int
__gfs2_setattr_simple ( struct gfs2_inode * ip , struct iattr * attr )
{
struct buffer_head * dibh ;
int error ;
error = gfs2_meta_inode_buffer ( ip , & dibh ) ;
if ( ! error ) {
2006-06-14 23:32:57 +04:00
error = inode_setattr ( & ip - > i_inode , attr ) ;
gfs2_assert_warn ( GFS2_SB ( & ip - > i_inode ) , ! error ) ;
2006-01-18 14:19:28 +03:00
gfs2_trans_add_bh ( ip - > i_gl , dibh , 1 ) ;
2006-10-31 23:07:05 +03:00
gfs2_dinode_out ( ip , dibh - > b_data ) ;
2006-01-16 19:50:04 +03:00
brelse ( dibh ) ;
}
return error ;
}
/**
* gfs2_setattr_simple -
* @ ip :
* @ attr :
*
* Called with a reference on the vnode .
*
* Returns : errno
*/
int gfs2_setattr_simple ( struct gfs2_inode * ip , struct iattr * attr )
{
int error ;
2006-02-28 01:23:27 +03:00
if ( current - > journal_info )
2006-01-16 19:50:04 +03:00
return __gfs2_setattr_simple ( ip , attr ) ;
2006-06-14 23:32:57 +04:00
error = gfs2_trans_begin ( GFS2_SB ( & ip - > i_inode ) , RES_DINODE , 0 ) ;
2006-01-16 19:50:04 +03:00
if ( error )
return error ;
error = __gfs2_setattr_simple ( ip , attr ) ;
2006-06-14 23:32:57 +04:00
gfs2_trans_end ( GFS2_SB ( & ip - > i_inode ) ) ;
2006-01-16 19:50:04 +03:00
return error ;
}
2007-06-01 17:11:58 +04:00
void gfs2_dinode_out ( const struct gfs2_inode * ip , void * buf )
{
const struct gfs2_dinode_host * di = & ip - > i_di ;
struct gfs2_dinode * str = buf ;
str - > di_header . mh_magic = cpu_to_be32 ( GFS2_MAGIC ) ;
str - > di_header . mh_type = cpu_to_be32 ( GFS2_METATYPE_DI ) ;
str - > di_header . __pad0 = 0 ;
str - > di_header . mh_format = cpu_to_be32 ( GFS2_FORMAT_DI ) ;
str - > di_header . __pad1 = 0 ;
str - > di_num . no_addr = cpu_to_be64 ( ip - > i_no_addr ) ;
str - > di_num . no_formal_ino = cpu_to_be64 ( ip - > i_no_formal_ino ) ;
str - > di_mode = cpu_to_be32 ( ip - > i_inode . i_mode ) ;
str - > di_uid = cpu_to_be32 ( ip - > i_inode . i_uid ) ;
str - > di_gid = cpu_to_be32 ( ip - > i_inode . i_gid ) ;
str - > di_nlink = cpu_to_be32 ( ip - > i_inode . i_nlink ) ;
str - > di_size = cpu_to_be64 ( di - > di_size ) ;
str - > di_blocks = cpu_to_be64 ( di - > di_blocks ) ;
str - > di_atime = cpu_to_be64 ( ip - > i_inode . i_atime . tv_sec ) ;
str - > di_mtime = cpu_to_be64 ( ip - > i_inode . i_mtime . tv_sec ) ;
str - > di_ctime = cpu_to_be64 ( ip - > i_inode . i_ctime . tv_sec ) ;
str - > di_goal_meta = cpu_to_be64 ( di - > di_goal_meta ) ;
str - > di_goal_data = cpu_to_be64 ( di - > di_goal_data ) ;
str - > di_generation = cpu_to_be64 ( di - > di_generation ) ;
str - > di_flags = cpu_to_be32 ( di - > di_flags ) ;
str - > di_height = cpu_to_be16 ( di - > di_height ) ;
str - > di_payload_format = cpu_to_be32 ( S_ISDIR ( ip - > i_inode . i_mode ) & &
! ( ip - > i_di . di_flags & GFS2_DIF_EXHASH ) ?
GFS2_FORMAT_DE : 0 ) ;
str - > di_depth = cpu_to_be16 ( di - > di_depth ) ;
str - > di_entries = cpu_to_be32 ( di - > di_entries ) ;
str - > di_eattr = cpu_to_be64 ( di - > di_eattr ) ;
2007-06-05 12:39:18 +04:00
str - > di_atime_nsec = cpu_to_be32 ( ip - > i_inode . i_atime . tv_nsec ) ;
str - > di_mtime_nsec = cpu_to_be32 ( ip - > i_inode . i_mtime . tv_nsec ) ;
str - > di_ctime_nsec = cpu_to_be32 ( ip - > i_inode . i_ctime . tv_nsec ) ;
2007-06-01 17:11:58 +04:00
}
void gfs2_dinode_print ( const struct gfs2_inode * ip )
{
const struct gfs2_dinode_host * di = & ip - > i_di ;
printk ( KERN_INFO " no_formal_ino = %llu \n " ,
( unsigned long long ) ip - > i_no_formal_ino ) ;
printk ( KERN_INFO " no_addr = %llu \n " ,
( unsigned long long ) ip - > i_no_addr ) ;
printk ( KERN_INFO " di_size = %llu \n " , ( unsigned long long ) di - > di_size ) ;
printk ( KERN_INFO " di_blocks = %llu \n " ,
( unsigned long long ) di - > di_blocks ) ;
printk ( KERN_INFO " di_goal_meta = %llu \n " ,
( unsigned long long ) di - > di_goal_meta ) ;
printk ( KERN_INFO " di_goal_data = %llu \n " ,
( unsigned long long ) di - > di_goal_data ) ;
printk ( KERN_INFO " di_flags = 0x%.8X \n " , di - > di_flags ) ;
printk ( KERN_INFO " di_height = %u \n " , di - > di_height ) ;
printk ( KERN_INFO " di_depth = %u \n " , di - > di_depth ) ;
printk ( KERN_INFO " di_entries = %u \n " , di - > di_entries ) ;
printk ( KERN_INFO " di_eattr = %llu \n " ,
( unsigned long long ) di - > di_eattr ) ;
}