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>
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-09-19 09:56:29 +04:00
# include <linux/lm_interface.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>
# 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 "lm.h"
# include "log.h"
# include "meta_io.h"
# include "ops_file.h"
# include "ops_vm.h"
# include "quota.h"
# include "rgrp.h"
# include "trans.h"
2006-02-28 01:23:27 +03:00
# include "util.h"
2006-03-28 23:14:04 +04:00
# include "eaops.h"
2006-01-16 19:50:04 +03:00
2006-02-15 13:15:18 +03:00
/*
* Most fields left uninitialised to catch anybody who tries to
* use them . f_flags set to prevent file_accessed ( ) from touching
* any other part of this . Its use is purely as a flag so that we
* know ( in readpage ( ) ) whether or not do to locking .
*/
2006-09-04 22:53:30 +04:00
struct file gfs2_internal_file_sentinel = {
2006-02-15 13:15:18 +03:00
. f_flags = O_NOATIME | O_RDONLY ,
} ;
2006-02-08 14:50:51 +03:00
static int gfs2_read_actor ( read_descriptor_t * desc , struct page * page ,
unsigned long offset , unsigned long size )
{
char * kaddr ;
unsigned long count = desc - > count ;
if ( size > count )
size = count ;
kaddr = kmap ( page ) ;
2006-10-14 07:49:23 +04:00
memcpy ( desc - > arg . data , kaddr + offset , size ) ;
2006-09-04 23:32:10 +04:00
kunmap ( page ) ;
2006-02-08 14:50:51 +03:00
2006-09-04 23:32:10 +04:00
desc - > count = count - size ;
desc - > written + = size ;
desc - > arg . buf + = size ;
return size ;
2006-02-08 14:50:51 +03:00
}
int gfs2_internal_read ( struct gfs2_inode * ip , struct file_ra_state * ra_state ,
char * buf , loff_t * pos , unsigned size )
{
2006-06-14 23:32:57 +04:00
struct inode * inode = & ip - > i_inode ;
2006-02-08 14:50:51 +03:00
read_descriptor_t desc ;
desc . written = 0 ;
2006-10-14 07:49:23 +04:00
desc . arg . data = buf ;
2006-02-08 14:50:51 +03:00
desc . count = size ;
desc . error = 0 ;
2006-02-15 13:15:18 +03:00
do_generic_mapping_read ( inode - > i_mapping , ra_state ,
2006-09-04 22:53:30 +04:00
& gfs2_internal_file_sentinel , pos , & desc ,
2006-02-15 13:15:18 +03:00
gfs2_read_actor ) ;
2006-02-08 14:50:51 +03:00
return desc . written ? desc . written : desc . error ;
}
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 ) {
error = remote_llseek ( file , offset , origin ) ;
gfs2_glock_dq_uninit ( & i_gh ) ;
}
} else
error = remote_llseek ( file , offset , origin ) ;
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 ;
gfs2_holder_init ( dip - > i_gl , LM_ST_SHARED , GL_ATIME , & d_gh ) ;
error = gfs2_glock_nq_atime ( & d_gh ) ;
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 ,
[ 14 ] = GFS2_DIF_JDATA ,
[ 20 ] = GFS2_DIF_DIRECTIO ,
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_Jdata ] = FS_JOURNAL_DATA_FL ,
[ gfs2fl_Directio ] = FS_DIRECTIO_FL ,
[ gfs2fl_InheritDirectio ] = FS_DIRECTIO_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
gfs2_holder_init ( ip - > i_gl , LM_ST_SHARED , GL_ATIME , & gh ) ;
2006-11-16 19:08:16 +03:00
error = gfs2_glock_nq_atime ( & gh ) ;
2006-03-28 23:14:04 +04:00
if ( error )
return error ;
2006-09-25 17:26:04 +04:00
2006-10-02 19:24:43 +04:00
fsflags = fsflags_cvt ( gfs2_to_fsflags , ip - > i_di . di_flags ) ;
if ( put_user ( fsflags , ptr ) )
2006-03-28 23:14:04 +04:00
error = - EFAULT ;
gfs2_glock_dq_m ( 1 , & gh ) ;
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 ) ;
struct gfs2_dinode_host * di = & ip - > i_di ;
unsigned int flags = inode - > i_flags ;
flags & = ~ ( S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME | S_DIRSYNC ) ;
if ( di - > di_flags & GFS2_DIF_IMMUTABLE )
flags | = S_IMMUTABLE ;
if ( di - > di_flags & GFS2_DIF_APPENDONLY )
flags | = S_APPEND ;
if ( di - > di_flags & GFS2_DIF_NOATIME )
flags | = S_NOATIME ;
if ( di - > di_flags & GFS2_DIF_SYNC )
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_DIRECTIO | \
GFS2_DIF_IMMUTABLE | \
GFS2_DIF_APPENDONLY | \
GFS2_DIF_NOATIME | \
GFS2_DIF_SYNC | \
GFS2_DIF_SYSTEM | \
GFS2_DIF_INHERIT_DIRECTIO | \
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
error = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_EXCLUSIVE , 0 , & gh ) ;
2006-07-21 10:03:21 +04:00
if ( error )
2006-03-28 23:14:04 +04:00
return error ;
2006-04-04 22:29:30 +04:00
flags = ip - > i_di . di_flags ;
new_flags = ( flags & ~ mask ) | ( reqflags & mask ) ;
2006-03-28 23:14:04 +04:00
if ( ( new_flags ^ flags ) = = 0 )
goto out ;
2006-04-25 21:20:27 +04:00
if ( S_ISDIR ( inode - > i_mode ) ) {
if ( ( new_flags ^ flags ) & GFS2_DIF_JDATA )
new_flags ^ = ( GFS2_DIF_JDATA | GFS2_DIF_INHERIT_JDATA ) ;
if ( ( new_flags ^ flags ) & GFS2_DIF_DIRECTIO )
new_flags ^ = ( GFS2_DIF_DIRECTIO | GFS2_DIF_INHERIT_DIRECTIO ) ;
}
2006-03-28 23:14:04 +04:00
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 ) ) {
2006-06-22 18:59:10 +04:00
error = permission ( inode , MAY_WRITE , NULL ) ;
2006-05-13 01:07:56 +04:00
if ( error )
goto out ;
}
2006-03-28 23:14:04 +04:00
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 ) ;
ip - > i_di . di_flags = 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 ) ;
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 ) ;
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
{
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 ) ;
2006-04-07 19:17:32 +04:00
return do_gfs2_set_flags ( filp , gfsflags , ~ 0 ) ;
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 ;
}
2006-01-16 19:50:04 +03:00
/**
* gfs2_mmap -
* @ file : The file to map
* @ vma : The VMA which described the mapping
*
* Returns : 0 or error code
*/
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
struct gfs2_holder i_gh ;
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 ;
}
2006-02-08 14:50:51 +03:00
/* This is VM_MAYWRITE instead of VM_WRITE because a call
to mprotect ( ) can turn on VM_WRITE later . */
if ( ( vma - > vm_flags & ( VM_MAYSHARE | VM_MAYWRITE ) ) = =
( VM_MAYSHARE | VM_MAYWRITE ) )
vma - > vm_ops = & gfs2_vm_ops_sharewrite ;
else
vma - > vm_ops = & gfs2_vm_ops_private ;
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( & i_gh ) ;
return error ;
}
/**
* 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 ) & &
ip - > i_di . di_size > MAX_NON_LFS ) {
error = - EFBIG ;
goto fail_gunlock ;
}
/* Listen to the Direct I/O flag */
if ( ip - > i_di . di_flags & GFS2_DIF_DIRECTIO )
file - > f_flags | = O_DIRECT ;
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
}
/**
* 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 ) ;
2006-01-16 19:50:04 +03:00
struct lm_lockname name =
{ . ln_number = ip - > i_num . no_addr ,
. ln_type = LM_TYPE_PLOCK } ;
if ( ! ( fl - > fl_flags & FL_POSIX ) )
return - ENOLCK ;
2006-11-01 20:22:46 +03:00
if ( ( ip - > i_inode . i_mode & ( S_ISGID | S_IXGRP ) ) = = S_ISGID )
2006-01-16 19:50:04 +03:00
return - ENOLCK ;
if ( sdp - > sd_args . ar_localflocks ) {
if ( IS_GETLK ( cmd ) ) {
2007-02-21 08:55:18 +03:00
posix_test_lock ( file , fl ) ;
2006-01-16 19:50:04 +03:00
return 0 ;
} else {
2006-04-01 01:48:41 +04:00
return posix_lock_file_wait ( file , fl ) ;
2006-01-16 19:50:04 +03:00
}
}
2006-11-15 00:37:25 +03:00
if ( cmd = = F_CANCELLK ) {
/* Hack: */
cmd = F_SETLK ;
fl - > fl_type = F_UNLCK ;
}
2006-01-16 19:50:04 +03:00
if ( IS_GETLK ( cmd ) )
return gfs2_lm_plock_get ( sdp , & name , file , fl ) ;
else if ( fl - > fl_type = = F_UNLCK )
return gfs2_lm_punlock ( sdp , & name , file , fl ) ;
else
return gfs2_lm_plock ( sdp , & name , file , cmd , fl ) ;
}
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 ;
2006-09-04 23:32:10 +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 ;
gfs2_glock_hold ( gl ) ;
flock_lock_file_wait ( file ,
2006-09-25 17:26:04 +04:00
& ( struct file_lock ) { . fl_type = F_UNLCK } ) ;
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( fl_gh ) ;
} else {
2006-06-14 23:32:57 +04:00
error = gfs2_glock_get ( GFS2_SB ( & ip - > i_inode ) ,
2006-01-16 19:50:04 +03:00
ip - > i_num . no_addr , & gfs2_flock_glops ,
CREATE , & gl ) ;
if ( error )
goto out ;
}
gfs2_holder_init ( gl , state , flags , fl_gh ) ;
gfs2_glock_put ( gl ) ;
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 )
{
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 ) ;
2006-01-16 19:50:04 +03:00
if ( ! ( fl - > fl_flags & FL_FLOCK ) )
return - ENOLCK ;
2006-11-01 20:22:46 +03:00
if ( ( ip - > i_inode . i_mode & ( S_ISGID | S_IXGRP ) ) = = S_ISGID )
2006-01-16 19:50:04 +03:00
return - ENOLCK ;
if ( sdp - > sd_args . ar_localflocks )
return flock_lock_file_wait ( file , fl ) ;
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
}
2006-07-03 21:47:02 +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 ,
2006-09-04 23:32:10 +04:00
. aio_write = generic_file_aio_write ,
. unlocked_ioctl = gfs2_ioctl ,
. mmap = gfs2_mmap ,
. open = gfs2_open ,
. release = gfs2_close ,
. fsync = gfs2_fsync ,
. lock = gfs2_lock ,
. sendfile = generic_file_sendfile ,
. flock = gfs2_flock ,
. splice_read = generic_file_splice_read ,
. splice_write = generic_file_splice_write ,
2006-01-16 19:50:04 +03:00
} ;
2006-07-03 21:47:02 +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
} ;