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/slab.h>
# include <linux/spinlock.h>
# include <linux/completion.h>
# include <linux/buffer_head.h>
# include <linux/pagemap.h>
# include <linux/uio.h>
# include <linux/blkdev.h>
# include <linux/mm.h>
2008-07-02 23:12:01 +04:00
# include <linux/mount.h>
2006-02-08 14:50:51 +03:00
# include <linux/fs.h>
2006-02-28 01:23:27 +03:00
# include <linux/gfs2_ondisk.h>
2006-03-28 23:14:04 +04:00
# include <linux/ext2_fs.h>
# include <linux/crc32.h>
2006-11-30 18:14:32 +03:00
# include <linux/writeback.h>
2006-01-16 19:50:04 +03:00
# include <asm/uaccess.h>
2009-01-12 13:43:39 +03:00
# include <linux/dlm.h>
# include <linux/dlm_plock.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 "bmap.h"
# include "dir.h"
# include "glock.h"
# include "glops.h"
# include "inode.h"
# include "log.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"
2006-01-16 19:50:04 +03:00
/**
* gfs2_llseek - seek to a location in a file
* @ file : the file
* @ offset : the offset
* @ origin : Where to seek from ( SEEK_SET , SEEK_CUR , or SEEK_END )
*
* SEEK_END requires the glock for the file because it references the
* file ' s size .
*
* Returns : The new offset , or errno
*/
static loff_t gfs2_llseek ( struct file * file , loff_t offset , int origin )
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( file - > f_mapping - > host ) ;
2006-01-16 19:50:04 +03:00
struct gfs2_holder i_gh ;
loff_t error ;
if ( origin = = 2 ) {
error = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_SHARED , LM_FLAG_ANY ,
& i_gh ) ;
if ( ! error ) {
2008-06-27 13:05:24 +04:00
error = generic_file_llseek_unlocked ( file , offset , origin ) ;
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( & i_gh ) ;
}
} else
2008-06-27 13:05:24 +04:00
error = generic_file_llseek_unlocked ( file , offset , origin ) ;
2006-01-16 19:50:04 +03:00
return error ;
}
/**
2006-09-20 00:41:11 +04:00
* gfs2_readdir - Read directory entries from a directory
2006-01-16 19:50:04 +03:00
* @ file : The directory to read from
* @ dirent : Buffer for dirents
* @ filldir : Function used to do the copying
*
* Returns : errno
*/
2006-09-20 00:41:11 +04:00
static int gfs2_readdir ( struct file * file , void * dirent , filldir_t filldir )
2006-01-16 19:50:04 +03:00
{
2006-03-28 23:14:04 +04:00
struct inode * dir = file - > f_mapping - > host ;
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 ;
2006-09-04 20:49:07 +04:00
u64 offset = file - > f_pos ;
2006-01-16 19:50:04 +03:00
int error ;
2008-09-18 16:53:59 +04:00
gfs2_holder_init ( dip - > i_gl , LM_ST_SHARED , 0 , & d_gh ) ;
error = gfs2_glock_nq ( & d_gh ) ;
2006-01-16 19:50:04 +03:00
if ( error ) {
gfs2_holder_uninit ( & d_gh ) ;
return error ;
}
2007-01-17 18:09:20 +03:00
error = gfs2_dir_read ( dir , & offset , dirent , filldir ) ;
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( & d_gh ) ;
file - > f_pos = offset ;
return error ;
}
2006-10-02 19:24:43 +04:00
/**
* fsflags_cvt
* @ table : A table of 32 u32 flags
* @ val : a 32 bit value to convert
*
* This function can be used to convert between fsflags values and
* GFS2 ' s own flags values .
*
* Returns : the converted flags
*/
static u32 fsflags_cvt ( const u32 * table , u32 val )
{
u32 res = 0 ;
while ( val ) {
if ( val & 1 )
res | = * table ;
table + + ;
val > > = 1 ;
}
return res ;
}
2006-01-16 19:50:04 +03:00
2006-10-02 19:24:43 +04:00
static const u32 fsflags_to_gfs2 [ 32 ] = {
[ 3 ] = GFS2_DIF_SYNC ,
[ 4 ] = GFS2_DIF_IMMUTABLE ,
[ 5 ] = GFS2_DIF_APPENDONLY ,
[ 7 ] = GFS2_DIF_NOATIME ,
[ 12 ] = GFS2_DIF_EXHASH ,
2007-07-18 14:40:06 +04:00
[ 14 ] = GFS2_DIF_INHERIT_JDATA ,
2006-03-28 23:14:04 +04:00
} ;
2006-10-02 19:24:43 +04:00
static const u32 gfs2_to_fsflags [ 32 ] = {
[ gfs2fl_Sync ] = FS_SYNC_FL ,
[ gfs2fl_Immutable ] = FS_IMMUTABLE_FL ,
[ gfs2fl_AppendOnly ] = FS_APPEND_FL ,
[ gfs2fl_NoAtime ] = FS_NOATIME_FL ,
[ gfs2fl_ExHash ] = FS_INDEX_FL ,
[ gfs2fl_InheritJdata ] = FS_JOURNAL_DATA_FL ,
2006-04-01 00:01:28 +04:00
} ;
2006-03-28 23:14:04 +04:00
2006-04-07 19:17:32 +04:00
static int gfs2_get_flags ( struct file * filp , u32 __user * ptr )
2006-03-28 23:14:04 +04:00
{
2006-12-08 13:37:03 +03:00
struct inode * inode = filp - > f_path . dentry - > d_inode ;
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( inode ) ;
2006-03-28 23:14:04 +04:00
struct gfs2_holder gh ;
int error ;
2006-10-02 19:24:43 +04:00
u32 fsflags ;
2006-03-28 23:14:04 +04:00
2008-09-18 16:53:59 +04:00
gfs2_holder_init ( ip - > i_gl , LM_ST_SHARED , 0 , & gh ) ;
error = gfs2_glock_nq ( & gh ) ;
2006-03-28 23:14:04 +04:00
if ( error )
return error ;
2006-09-25 17:26:04 +04:00
2008-11-04 13:05:22 +03:00
fsflags = fsflags_cvt ( gfs2_to_fsflags , ip - > i_diskflags ) ;
if ( ! S_ISDIR ( inode - > i_mode ) & & ip - > i_diskflags & GFS2_DIF_JDATA )
2008-07-10 19:09:29 +04:00
fsflags | = FS_JOURNAL_DATA_FL ;
2006-10-02 19:24:43 +04:00
if ( put_user ( fsflags , ptr ) )
2006-03-28 23:14:04 +04:00
error = - EFAULT ;
2007-10-15 18:40:33 +04:00
gfs2_glock_dq ( & gh ) ;
2006-03-28 23:14:04 +04:00
gfs2_holder_uninit ( & gh ) ;
return error ;
}
2006-11-08 20:51:06 +03:00
void gfs2_set_inode_flags ( struct inode * inode )
{
struct gfs2_inode * ip = GFS2_I ( inode ) ;
unsigned int flags = inode - > i_flags ;
flags & = ~ ( S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME | S_DIRSYNC ) ;
2008-11-04 13:05:22 +03:00
if ( ip - > i_diskflags & GFS2_DIF_IMMUTABLE )
2006-11-08 20:51:06 +03:00
flags | = S_IMMUTABLE ;
2008-11-04 13:05:22 +03:00
if ( ip - > i_diskflags & GFS2_DIF_APPENDONLY )
2006-11-08 20:51:06 +03:00
flags | = S_APPEND ;
2008-11-04 13:05:22 +03:00
if ( ip - > i_diskflags & GFS2_DIF_NOATIME )
2006-11-08 20:51:06 +03:00
flags | = S_NOATIME ;
2008-11-04 13:05:22 +03:00
if ( ip - > i_diskflags & GFS2_DIF_SYNC )
2006-11-08 20:51:06 +03:00
flags | = S_SYNC ;
inode - > i_flags = flags ;
}
2006-03-28 23:14:04 +04:00
/* Flags that can be set by user space */
# define GFS2_FLAGS_USER_SET (GFS2_DIF_JDATA| \
GFS2_DIF_IMMUTABLE | \
GFS2_DIF_APPENDONLY | \
GFS2_DIF_NOATIME | \
GFS2_DIF_SYNC | \
GFS2_DIF_SYSTEM | \
GFS2_DIF_INHERIT_JDATA )
/**
* gfs2_set_flags - set flags on an inode
* @ inode : The inode
* @ flags : The flags to set
* @ mask : Indicates which flags are valid
*
*/
2006-04-07 19:17:32 +04:00
static int do_gfs2_set_flags ( struct file * filp , u32 reqflags , u32 mask )
2006-03-28 23:14:04 +04:00
{
2006-12-08 13:37:03 +03:00
struct inode * inode = filp - > f_path . dentry - > d_inode ;
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( inode ) ;
struct gfs2_sbd * sdp = GFS2_SB ( inode ) ;
2006-03-28 23:14:04 +04:00
struct buffer_head * bh ;
struct gfs2_holder gh ;
int error ;
2006-04-04 22:29:30 +04:00
u32 new_flags , flags ;
2006-03-28 23:14:04 +04:00
2008-07-02 23:12:01 +04:00
error = mnt_want_write ( filp - > f_path . mnt ) ;
2006-07-21 10:03:21 +04:00
if ( error )
2006-03-28 23:14:04 +04:00
return error ;
2008-07-02 23:12:01 +04:00
error = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_EXCLUSIVE , 0 , & gh ) ;
if ( error )
goto out_drop_write ;
2008-11-04 13:05:22 +03:00
flags = ip - > i_diskflags ;
2006-04-04 22:29:30 +04:00
new_flags = ( flags & ~ mask ) | ( reqflags & mask ) ;
2006-03-28 23:14:04 +04:00
if ( ( new_flags ^ flags ) = = 0 )
goto out ;
error = - EINVAL ;
if ( ( new_flags ^ flags ) & ~ GFS2_FLAGS_USER_SET )
goto out ;
error = - EPERM ;
if ( IS_IMMUTABLE ( inode ) & & ( new_flags & GFS2_DIF_IMMUTABLE ) )
goto out ;
if ( IS_APPEND ( inode ) & & ( new_flags & GFS2_DIF_APPENDONLY ) )
goto out ;
2006-09-25 17:26:04 +04:00
if ( ( ( new_flags ^ flags ) & GFS2_DIF_IMMUTABLE ) & &
2006-05-13 01:07:56 +04:00
! capable ( CAP_LINUX_IMMUTABLE ) )
2006-03-28 23:14:04 +04:00
goto out ;
2006-05-13 01:07:56 +04:00
if ( ! IS_IMMUTABLE ( inode ) ) {
2008-07-02 23:12:01 +04:00
error = gfs2_permission ( inode , MAY_WRITE ) ;
2006-05-13 01:07:56 +04:00
if ( error )
goto out ;
}
2007-10-17 11:47:38 +04:00
if ( ( flags ^ new_flags ) & GFS2_DIF_JDATA ) {
if ( flags & GFS2_DIF_JDATA )
gfs2_log_flush ( sdp , ip - > i_gl ) ;
error = filemap_fdatawrite ( inode - > i_mapping ) ;
if ( error )
goto out ;
error = filemap_fdatawait ( inode - > i_mapping ) ;
if ( error )
goto out ;
}
2006-04-04 22:29:30 +04:00
error = gfs2_trans_begin ( sdp , RES_DINODE , 0 ) ;
2006-03-28 23:14:04 +04:00
if ( error )
goto out ;
2006-04-04 22:29:30 +04:00
error = gfs2_meta_inode_buffer ( ip , & bh ) ;
if ( error )
goto out_trans_end ;
2006-03-28 23:14:04 +04:00
gfs2_trans_add_bh ( ip - > i_gl , bh , 1 ) ;
2008-11-04 13:05:22 +03:00
ip - > i_diskflags = new_flags ;
2006-10-31 23:07:05 +03:00
gfs2_dinode_out ( ip , bh - > b_data ) ;
2006-03-28 23:14:04 +04:00
brelse ( bh ) ;
2006-11-08 20:51:06 +03:00
gfs2_set_inode_flags ( inode ) ;
2007-10-17 11:47:38 +04:00
gfs2_set_aops ( inode ) ;
2006-04-04 22:29:30 +04:00
out_trans_end :
gfs2_trans_end ( sdp ) ;
2006-03-28 23:14:04 +04:00
out :
gfs2_glock_dq_uninit ( & gh ) ;
2008-07-02 23:12:01 +04:00
out_drop_write :
mnt_drop_write ( filp - > f_path . mnt ) ;
2006-03-28 23:14:04 +04:00
return error ;
}
2006-04-07 19:17:32 +04:00
static int gfs2_set_flags ( struct file * filp , u32 __user * ptr )
2006-03-28 23:14:04 +04:00
{
2007-07-18 14:40:06 +04:00
struct inode * inode = filp - > f_path . dentry - > d_inode ;
2006-10-02 19:24:43 +04:00
u32 fsflags , gfsflags ;
if ( get_user ( fsflags , ptr ) )
2006-03-28 23:14:04 +04:00
return - EFAULT ;
2006-10-02 19:24:43 +04:00
gfsflags = fsflags_cvt ( fsflags_to_gfs2 , fsflags ) ;
2007-07-18 14:40:06 +04:00
if ( ! S_ISDIR ( inode - > i_mode ) ) {
if ( gfsflags & GFS2_DIF_INHERIT_JDATA )
gfsflags ^ = ( GFS2_DIF_JDATA | GFS2_DIF_INHERIT_JDATA ) ;
return do_gfs2_set_flags ( filp , gfsflags , ~ 0 ) ;
}
return do_gfs2_set_flags ( filp , gfsflags , ~ GFS2_DIF_JDATA ) ;
2006-03-28 23:14:04 +04:00
}
2006-04-07 19:17:32 +04:00
static long gfs2_ioctl ( struct file * filp , unsigned int cmd , unsigned long arg )
2006-03-28 23:14:04 +04:00
{
switch ( cmd ) {
2006-10-02 19:24:43 +04:00
case FS_IOC_GETFLAGS :
2006-04-07 19:17:32 +04:00
return gfs2_get_flags ( filp , ( u32 __user * ) arg ) ;
2006-10-02 19:24:43 +04:00
case FS_IOC_SETFLAGS :
2006-04-07 19:17:32 +04:00
return gfs2_set_flags ( filp , ( u32 __user * ) arg ) ;
2006-03-28 23:14:04 +04:00
}
return - ENOTTY ;
}
2007-10-15 18:40:33 +04:00
/**
* gfs2_allocate_page_backing - Use bmap to allocate blocks
* @ page : The ( locked ) page to allocate backing for
*
* We try to allocate all the blocks required for the page in
* one go . This might fail for various reasons , so we keep
* trying until all the blocks to back this page are allocated .
* If some of the blocks are already allocated , thats ok too .
*/
static int gfs2_allocate_page_backing ( struct page * page )
{
struct inode * inode = page - > mapping - > host ;
struct buffer_head bh ;
unsigned long size = PAGE_CACHE_SIZE ;
u64 lblock = page - > index < < ( PAGE_CACHE_SHIFT - inode - > i_blkbits ) ;
do {
bh . b_state = 0 ;
bh . b_size = size ;
2007-12-10 23:13:27 +03:00
gfs2_block_map ( inode , lblock , & bh , 1 ) ;
2007-10-15 18:40:33 +04:00
if ( ! buffer_mapped ( & bh ) )
return - EIO ;
size - = bh . b_size ;
lblock + = ( bh . b_size > > inode - > i_blkbits ) ;
} while ( size > 0 ) ;
return 0 ;
}
/**
* gfs2_page_mkwrite - Make a shared , mmap ( ) ed , page writable
* @ vma : The virtual memory area
* @ page : The page which is about to become writable
*
* When the page becomes writable , we need to ensure that we have
* blocks allocated on disk to back that page .
*/
2009-04-01 02:23:21 +04:00
static int gfs2_page_mkwrite ( struct vm_area_struct * vma , struct vm_fault * vmf )
2007-10-15 18:40:33 +04:00
{
2009-04-01 02:23:21 +04:00
struct page * page = vmf - > page ;
2007-10-15 18:40:33 +04:00
struct inode * inode = vma - > vm_file - > f_path . dentry - > d_inode ;
struct gfs2_inode * ip = GFS2_I ( inode ) ;
struct gfs2_sbd * sdp = GFS2_SB ( inode ) ;
unsigned long last_index ;
2009-01-06 19:47:50 +03:00
u64 pos = page - > index < < PAGE_CACHE_SHIFT ;
2007-10-15 18:40:33 +04:00
unsigned int data_blocks , ind_blocks , rblocks ;
int alloc_required = 0 ;
struct gfs2_holder gh ;
struct gfs2_alloc * al ;
int ret ;
2008-09-18 16:53:59 +04:00
gfs2_holder_init ( ip - > i_gl , LM_ST_EXCLUSIVE , 0 , & gh ) ;
ret = gfs2_glock_nq ( & gh ) ;
2007-10-15 18:40:33 +04:00
if ( ret )
goto out ;
2009-03-19 16:15:44 +03:00
set_bit ( GLF_DIRTY , & ip - > i_gl - > gl_flags ) ;
set_bit ( GIF_SW_PAGED , & ip - > i_flags ) ;
2007-10-15 18:40:33 +04:00
ret = gfs2_write_alloc_required ( ip , pos , PAGE_CACHE_SIZE , & alloc_required ) ;
if ( ret | | ! alloc_required )
goto out_unlock ;
2008-01-10 18:18:55 +03:00
ret = - ENOMEM ;
2007-10-15 18:40:33 +04:00
al = gfs2_alloc_get ( ip ) ;
2008-01-10 18:18:55 +03:00
if ( al = = NULL )
goto out_unlock ;
2008-03-10 18:34:50 +03:00
ret = gfs2_quota_lock_check ( ip ) ;
2007-10-15 18:40:33 +04:00
if ( ret )
goto out_alloc_put ;
2008-12-10 13:28:10 +03:00
gfs2_write_calc_reserv ( ip , PAGE_CACHE_SIZE , & data_blocks , & ind_blocks ) ;
2007-10-15 18:40:33 +04:00
al - > al_requested = data_blocks + ind_blocks ;
ret = gfs2_inplace_reserve ( ip ) ;
if ( ret )
goto out_quota_unlock ;
rblocks = RES_DINODE + ind_blocks ;
if ( gfs2_is_jdata ( ip ) )
rblocks + = data_blocks ? data_blocks : 1 ;
if ( ind_blocks | | data_blocks )
rblocks + = RES_STATFS + RES_QUOTA ;
ret = gfs2_trans_begin ( sdp , rblocks , 0 ) ;
if ( ret )
goto out_trans_fail ;
lock_page ( page ) ;
ret = - EINVAL ;
last_index = ip - > i_inode . i_size > > PAGE_CACHE_SHIFT ;
if ( page - > index > last_index )
goto out_unlock_page ;
2008-01-17 18:12:03 +03:00
ret = 0 ;
2007-10-15 18:40:33 +04:00
if ( ! PageUptodate ( page ) | | page - > mapping ! = ip - > i_inode . i_mapping )
goto out_unlock_page ;
if ( gfs2_is_stuffed ( ip ) ) {
ret = gfs2_unstuff_dinode ( ip , page ) ;
if ( ret )
goto out_unlock_page ;
}
ret = gfs2_allocate_page_backing ( page ) ;
out_unlock_page :
unlock_page ( page ) ;
gfs2_trans_end ( sdp ) ;
out_trans_fail :
gfs2_inplace_release ( ip ) ;
out_quota_unlock :
gfs2_quota_unlock ( ip ) ;
out_alloc_put :
gfs2_alloc_put ( ip ) ;
out_unlock :
gfs2_glock_dq ( & gh ) ;
out :
gfs2_holder_uninit ( & gh ) ;
2009-04-20 12:45:54 +04:00
if ( ret = = - ENOMEM )
ret = VM_FAULT_OOM ;
else if ( ret )
2009-04-01 02:23:21 +04:00
ret = VM_FAULT_SIGBUS ;
2007-10-15 18:40:33 +04:00
return ret ;
}
2009-09-27 22:29:37 +04:00
static const struct vm_operations_struct gfs2_vm_ops = {
2007-10-15 18:40:33 +04:00
. fault = filemap_fault ,
. page_mkwrite = gfs2_page_mkwrite ,
} ;
2006-01-16 19:50:04 +03:00
/**
* gfs2_mmap -
* @ file : The file to map
* @ vma : The VMA which described the mapping
*
2009-04-29 16:59:35 +04:00
* There is no need to get a lock here unless we should be updating
* atime . We ignore any locking errors since the only consequence is
* a missed atime update ( which will just be deferred until later ) .
*
* Returns : 0
2006-01-16 19:50:04 +03:00
*/
static int gfs2_mmap ( struct file * file , struct vm_area_struct * vma )
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( file - > f_mapping - > host ) ;
2006-01-16 19:50:04 +03:00
2009-04-29 16:59:35 +04:00
if ( ! ( file - > f_flags & O_NOATIME ) ) {
struct gfs2_holder i_gh ;
int error ;
2006-01-16 19:50:04 +03:00
2009-04-29 16:59:35 +04:00
gfs2_holder_init ( ip - > i_gl , LM_ST_EXCLUSIVE , 0 , & i_gh ) ;
error = gfs2_glock_nq ( & i_gh ) ;
file_accessed ( file ) ;
if ( error = = 0 )
gfs2_glock_dq_uninit ( & i_gh ) ;
}
2007-10-15 18:40:33 +04:00
vma - > vm_ops = & gfs2_vm_ops ;
2009-04-29 16:59:35 +04:00
vma - > vm_flags | = VM_CAN_NONLINEAR ;
2006-01-16 19:50:04 +03:00
2009-04-29 16:59:35 +04:00
return 0 ;
2006-01-16 19:50:04 +03:00
}
/**
* gfs2_open - open a file
* @ inode : the inode to open
* @ file : the struct file for this opening
*
* Returns : errno
*/
static int gfs2_open ( struct inode * inode , struct file * file )
{
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 ;
struct gfs2_file * fp ;
int error ;
fp = kzalloc ( sizeof ( struct gfs2_file ) , GFP_KERNEL ) ;
if ( ! fp )
return - ENOMEM ;
2006-02-21 15:51:39 +03:00
mutex_init ( & fp - > f_fl_mutex ) ;
2006-01-16 19:50:04 +03:00
2006-06-14 23:32:57 +04:00
gfs2_assert_warn ( GFS2_SB ( inode ) , ! file - > private_data ) ;
2006-02-28 01:23:27 +03:00
file - > private_data = fp ;
2006-01-16 19:50:04 +03:00
2006-11-01 20:22:46 +03:00
if ( S_ISREG ( ip - > i_inode . i_mode ) ) {
2006-01-16 19:50:04 +03:00
error = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_SHARED , LM_FLAG_ANY ,
& i_gh ) ;
if ( error )
goto fail ;
if ( ! ( file - > f_flags & O_LARGEFILE ) & &
2008-11-04 12:47:33 +03:00
ip - > i_disksize > MAX_NON_LFS ) {
2007-10-17 10:30:22 +04:00
error = - EOVERFLOW ;
2006-01-16 19:50:04 +03:00
goto fail_gunlock ;
}
gfs2_glock_dq_uninit ( & i_gh ) ;
}
return 0 ;
2006-07-31 23:42:17 +04:00
fail_gunlock :
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( & i_gh ) ;
2006-07-31 23:42:17 +04:00
fail :
2006-02-28 01:23:27 +03:00
file - > private_data = NULL ;
2006-01-16 19:50:04 +03:00
kfree ( fp ) ;
return error ;
}
/**
* gfs2_close - called to close a struct file
* @ inode : the inode the struct file belongs to
* @ file : the struct file being closed
*
* Returns : errno
*/
static int gfs2_close ( struct inode * inode , struct file * file )
{
2006-02-28 01:23:27 +03:00
struct gfs2_sbd * sdp = inode - > i_sb - > s_fs_info ;
2006-01-16 19:50:04 +03:00
struct gfs2_file * fp ;
2006-02-28 01:23:27 +03:00
fp = file - > private_data ;
file - > private_data = NULL ;
2006-01-16 19:50:04 +03:00
if ( gfs2_assert_warn ( sdp , fp ) )
return - EIO ;
kfree ( fp ) ;
return 0 ;
}
/**
* gfs2_fsync - sync the dirty data for a file ( across the cluster )
* @ file : the file that points to the dentry ( we ignore this )
* @ dentry : the dentry that points to the inode to sync
*
2006-11-30 18:14:32 +03:00
* The VFS will flush " normal " data for us . We only need to worry
* about metadata here . For journaled data , we just do a log flush
* as we can ' t avoid it . Otherwise we can just bale out if datasync
* is set . For stuffed inodes we must flush the log in order to
* ensure that all data is on disk .
*
2006-12-07 17:13:14 +03:00
* The call to write_inode_now ( ) is there to write back metadata and
* the inode itself . It does also try and write the data , but thats
* ( hopefully ) a no - op due to the VFS having already called filemap_fdatawrite ( )
* for us .
*
2006-01-16 19:50:04 +03:00
* Returns : errno
*/
static int gfs2_fsync ( struct file * file , struct dentry * dentry , int datasync )
{
2006-11-30 18:14:32 +03:00
struct inode * inode = dentry - > d_inode ;
int sync_state = inode - > i_state & ( I_DIRTY_SYNC | I_DIRTY_DATASYNC ) ;
int ret = 0 ;
if ( gfs2_is_jdata ( GFS2_I ( inode ) ) ) {
gfs2_log_flush ( GFS2_SB ( inode ) , GFS2_I ( inode ) - > i_gl ) ;
return 0 ;
}
2006-01-16 19:50:04 +03:00
2006-11-30 18:14:32 +03:00
if ( sync_state ! = 0 ) {
if ( ! datasync )
2006-12-07 17:13:14 +03:00
ret = write_inode_now ( inode , 0 ) ;
2006-01-16 19:50:04 +03:00
2006-11-30 18:14:32 +03:00
if ( gfs2_is_stuffed ( GFS2_I ( inode ) ) )
gfs2_log_flush ( GFS2_SB ( inode ) , GFS2_I ( inode ) - > i_gl ) ;
}
return ret ;
2006-01-16 19:50:04 +03:00
}
2009-12-08 13:25:33 +03:00
/**
* gfs2_file_aio_write - Perform a write to a file
* @ iocb : The io context
* @ iov : The data to write
* @ nr_segs : Number of @ iov segments
* @ pos : The file position
*
* We have to do a lock / unlock here to refresh the inode size for
* O_APPEND writes , otherwise we can land up writing at the wrong
* offset . There is still a race , but provided the app is using its
* own file locking , this will make O_APPEND work as expected .
*
*/
static ssize_t gfs2_file_aio_write ( struct kiocb * iocb , const struct iovec * iov ,
unsigned long nr_segs , loff_t pos )
{
struct file * file = iocb - > ki_filp ;
if ( file - > f_flags & O_APPEND ) {
struct dentry * dentry = file - > f_dentry ;
struct gfs2_inode * ip = GFS2_I ( dentry - > d_inode ) ;
struct gfs2_holder gh ;
int ret ;
ret = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_SHARED , 0 , & gh ) ;
if ( ret )
return ret ;
gfs2_glock_dq_uninit ( & gh ) ;
}
return generic_file_aio_write ( iocb , iov , nr_segs , pos ) ;
}
2009-01-12 13:43:39 +03:00
# ifdef CONFIG_GFS2_FS_LOCKING_DLM
2007-01-16 02:33:36 +03:00
/**
* gfs2_setlease - acquire / release a file lease
* @ file : the file pointer
* @ arg : lease type
* @ fl : file lock
*
2009-01-12 13:43:39 +03:00
* We don ' t currently have a way to enforce a lease across the whole
* cluster ; until we do , disable leases ( by just returning - EINVAL ) ,
* unless the administrator has requested purely local locking .
*
2007-01-16 02:33:36 +03:00
* Returns : errno
*/
static int gfs2_setlease ( struct file * file , long arg , struct file_lock * * fl )
{
2009-01-12 13:43:39 +03:00
return - EINVAL ;
2008-01-30 18:34:04 +03:00
}
2006-01-16 19:50:04 +03:00
/**
* gfs2_lock - acquire / release a posix lock on a file
* @ file : the file pointer
* @ cmd : either modify or retrieve lock state , possibly wait
* @ fl : type and range of lock
*
* Returns : errno
*/
static int gfs2_lock ( struct file * file , int cmd , struct file_lock * fl )
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( file - > f_mapping - > host ) ;
struct gfs2_sbd * sdp = GFS2_SB ( file - > f_mapping - > host ) ;
2009-01-12 13:43:39 +03:00
struct lm_lockstruct * ls = & sdp - > sd_lockstruct ;
2006-01-16 19:50:04 +03:00
if ( ! ( fl - > fl_flags & FL_POSIX ) )
return - ENOLCK ;
2007-10-02 01:41:13 +04:00
if ( __mandatory_lock ( & ip - > i_inode ) )
2006-01-16 19:50:04 +03:00
return - ENOLCK ;
2006-11-15 00:37:25 +03:00
if ( cmd = = F_CANCELLK ) {
/* Hack: */
cmd = F_SETLK ;
fl - > fl_type = F_UNLCK ;
}
2009-01-12 13:43:39 +03:00
if ( unlikely ( test_bit ( SDF_SHUTDOWN , & sdp - > sd_flags ) ) )
return - EIO ;
2006-01-16 19:50:04 +03:00
if ( IS_GETLK ( cmd ) )
2009-01-12 13:43:39 +03:00
return dlm_posix_get ( ls - > ls_dlm , ip - > i_no_addr , file , fl ) ;
2006-01-16 19:50:04 +03:00
else if ( fl - > fl_type = = F_UNLCK )
2009-01-12 13:43:39 +03:00
return dlm_posix_unlock ( ls - > ls_dlm , ip - > i_no_addr , file , fl ) ;
2006-01-16 19:50:04 +03:00
else
2009-01-12 13:43:39 +03:00
return dlm_posix_lock ( ls - > ls_dlm , ip - > i_no_addr , file , cmd , fl ) ;
2006-01-16 19:50:04 +03:00
}
static int do_flock ( struct file * file , int cmd , struct file_lock * fl )
{
2006-02-28 01:23:27 +03:00
struct gfs2_file * fp = file - > private_data ;
2006-01-16 19:50:04 +03:00
struct gfs2_holder * fl_gh = & fp - > f_fl_gh ;
2006-12-08 13:37:03 +03:00
struct gfs2_inode * ip = GFS2_I ( file - > f_path . dentry - > d_inode ) ;
2006-01-16 19:50:04 +03:00
struct gfs2_glock * gl ;
unsigned int state ;
int flags ;
int error = 0 ;
state = ( fl - > fl_type = = F_WRLCK ) ? LM_ST_EXCLUSIVE : LM_ST_SHARED ;
2008-05-21 20:03:22 +04:00
flags = ( IS_SETLKW ( cmd ) ? 0 : LM_FLAG_TRY ) | GL_EXACT | GL_NOCACHE ;
2006-01-16 19:50:04 +03:00
2006-02-21 15:51:39 +03:00
mutex_lock ( & fp - > f_fl_mutex ) ;
2006-01-16 19:50:04 +03:00
gl = fl_gh - > gh_gl ;
if ( gl ) {
if ( fl_gh - > gh_state = = state )
goto out ;
flock_lock_file_wait ( file ,
2006-09-25 17:26:04 +04:00
& ( struct file_lock ) { . fl_type = F_UNLCK } ) ;
2007-09-14 08:35:27 +04:00
gfs2_glock_dq_wait ( fl_gh ) ;
gfs2_holder_reinit ( state , flags , fl_gh ) ;
2006-01-16 19:50:04 +03:00
} else {
2008-05-21 20:03:22 +04:00
error = gfs2_glock_get ( GFS2_SB ( & ip - > i_inode ) , ip - > i_no_addr ,
& gfs2_flock_glops , CREATE , & gl ) ;
2006-01-16 19:50:04 +03:00
if ( error )
goto out ;
2007-09-14 08:35:27 +04:00
gfs2_holder_init ( gl , state , flags , fl_gh ) ;
gfs2_glock_put ( gl ) ;
2006-01-16 19:50:04 +03:00
}
error = gfs2_glock_nq ( fl_gh ) ;
if ( error ) {
gfs2_holder_uninit ( fl_gh ) ;
if ( error = = GLR_TRYFAILED )
error = - EAGAIN ;
} else {
error = flock_lock_file_wait ( file , fl ) ;
2006-06-14 23:32:57 +04:00
gfs2_assert_warn ( GFS2_SB ( & ip - > i_inode ) , ! error ) ;
2006-01-16 19:50:04 +03:00
}
2006-07-31 23:42:17 +04:00
out :
2006-02-21 15:51:39 +03:00
mutex_unlock ( & fp - > f_fl_mutex ) ;
2006-01-16 19:50:04 +03:00
return error ;
}
static void do_unflock ( struct file * file , struct file_lock * fl )
{
2006-02-28 01:23:27 +03:00
struct gfs2_file * fp = file - > private_data ;
2006-01-16 19:50:04 +03:00
struct gfs2_holder * fl_gh = & fp - > f_fl_gh ;
2006-02-21 15:51:39 +03:00
mutex_lock ( & fp - > f_fl_mutex ) ;
2006-01-16 19:50:04 +03:00
flock_lock_file_wait ( file , fl ) ;
if ( fl_gh - > gh_gl )
gfs2_glock_dq_uninit ( fl_gh ) ;
2006-02-21 15:51:39 +03:00
mutex_unlock ( & fp - > f_fl_mutex ) ;
2006-01-16 19:50:04 +03:00
}
/**
* gfs2_flock - acquire / release a flock lock on a file
* @ file : the file pointer
* @ cmd : either modify or retrieve lock state , possibly wait
* @ fl : type and range of lock
*
* Returns : errno
*/
static int gfs2_flock ( struct file * file , int cmd , struct file_lock * fl )
{
if ( ! ( fl - > fl_flags & FL_FLOCK ) )
return - ENOLCK ;
2009-06-01 21:30:03 +04:00
if ( fl - > fl_type & LOCK_MAND )
return - EOPNOTSUPP ;
2006-01-16 19:50:04 +03:00
if ( fl - > fl_type = = F_UNLCK ) {
do_unflock ( file , fl ) ;
return 0 ;
2006-10-02 18:28:05 +04:00
} else {
2006-01-16 19:50:04 +03:00
return do_flock ( file , cmd , fl ) ;
2006-10-02 18:28:05 +04:00
}
2006-01-16 19:50:04 +03:00
}
2009-04-07 21:42:17 +04:00
const struct file_operations gfs2_file_fops = {
2006-09-04 23:32:10 +04:00
. llseek = gfs2_llseek ,
2006-10-02 18:28:05 +04:00
. read = do_sync_read ,
2006-09-04 23:32:10 +04:00
. aio_read = generic_file_aio_read ,
2006-10-02 18:28:05 +04:00
. write = do_sync_write ,
2009-12-08 13:25:33 +03:00
. aio_write = gfs2_file_aio_write ,
2006-09-04 23:32:10 +04:00
. unlocked_ioctl = gfs2_ioctl ,
. mmap = gfs2_mmap ,
. open = gfs2_open ,
. release = gfs2_close ,
. fsync = gfs2_fsync ,
. lock = gfs2_lock ,
. flock = gfs2_flock ,
. splice_read = generic_file_splice_read ,
. splice_write = generic_file_splice_write ,
2007-01-16 02:33:36 +03:00
. setlease = gfs2_setlease ,
2006-01-16 19:50:04 +03:00
} ;
2009-04-07 21:42:17 +04:00
const struct file_operations gfs2_dir_fops = {
2006-09-04 23:32:10 +04:00
. readdir = gfs2_readdir ,
. unlocked_ioctl = gfs2_ioctl ,
. open = gfs2_open ,
. release = gfs2_close ,
. fsync = gfs2_fsync ,
. lock = gfs2_lock ,
. flock = gfs2_flock ,
2006-01-16 19:50:04 +03:00
} ;
2009-01-12 13:43:39 +03:00
# endif /* CONFIG_GFS2_FS_LOCKING_DLM */
2009-04-07 21:42:17 +04:00
const struct file_operations gfs2_file_fops_nolock = {
2007-11-30 01:56:51 +03:00
. llseek = gfs2_llseek ,
. read = do_sync_read ,
. aio_read = generic_file_aio_read ,
. write = do_sync_write ,
2009-12-08 13:25:33 +03:00
. aio_write = gfs2_file_aio_write ,
2007-11-30 01:56:51 +03:00
. unlocked_ioctl = gfs2_ioctl ,
. mmap = gfs2_mmap ,
. open = gfs2_open ,
. release = gfs2_close ,
. fsync = gfs2_fsync ,
. splice_read = generic_file_splice_read ,
. splice_write = generic_file_splice_write ,
2009-01-12 13:43:39 +03:00
. setlease = generic_setlease ,
2007-11-30 01:56:51 +03:00
} ;
2009-04-07 21:42:17 +04:00
const struct file_operations gfs2_dir_fops_nolock = {
2007-11-30 01:56:51 +03:00
. readdir = gfs2_readdir ,
. unlocked_ioctl = gfs2_ioctl ,
. open = gfs2_open ,
. release = gfs2_close ,
. fsync = gfs2_fsync ,
} ;