2005-09-10 00:04:18 +04:00
/*
* linux / fs / 9 p / vfs_file . c
*
* This file contians vfs file ops for 9 P2000 .
*
* Copyright ( C ) 2004 by Eric Van Hensbergen < ericvh @ gmail . com >
* Copyright ( C ) 2002 by Ron Minnich < rminnich @ lanl . gov >
*
* This program is free software ; you can redistribute it and / or modify
2006-03-25 14:07:28 +03:00
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation .
2005-09-10 00:04:18 +04:00
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to :
* Free Software Foundation
* 51 Franklin Street , Fifth Floor
* Boston , MA 02111 - 1301 USA
*
*/
# include <linux/module.h>
# include <linux/errno.h>
# include <linux/fs.h>
2006-10-18 21:55:46 +04:00
# include <linux/sched.h>
2005-09-10 00:04:18 +04:00
# include <linux/file.h>
# include <linux/stat.h>
# include <linux/string.h>
# include <linux/inet.h>
# include <linux/list.h>
2009-09-22 20:34:05 +04:00
# include <linux/pagemap.h>
9p: Implement TLOCK
Synopsis
size[4] TLock tag[2] fid[4] flock[n]
size[4] RLock tag[2] status[1]
Description
Tlock is used to acquire/release byte range posix locks on a file
identified by given fid. The reply contains status of the lock request
flock structure:
type[1] - Type of lock: F_RDLCK, F_WRLCK, F_UNLCK
flags[4] - Flags could be either of
P9_LOCK_FLAGS_BLOCK - Blocked lock request, if there is a
conflicting lock exists, wait for that lock to be released.
P9_LOCK_FLAGS_RECLAIM - Reclaim lock request, used when client is
trying to reclaim a lock after a server restrart (due to crash)
start[8] - Starting offset for lock
length[8] - Number of bytes to lock
If length is 0, lock all bytes starting at the location 'start'
through to the end of file
pid[4] - PID of the process that wants to take lock
client_id[4] - Unique client id
status[1] - Status of the lock request, can be
P9_LOCK_SUCCESS(0), P9_LOCK_BLOCKED(1), P9_LOCK_ERROR(2) or
P9_LOCK_GRACE(3)
P9_LOCK_SUCCESS - Request was successful
P9_LOCK_BLOCKED - A conflicting lock is held by another process
P9_LOCK_ERROR - Error while processing the lock request
P9_LOCK_GRACE - Server is in grace period, it can't accept new lock
requests in this period (except locks with
P9_LOCK_FLAGS_RECLAIM flag set)
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
2010-09-27 10:04:24 +04:00
# include <linux/utsname.h>
2005-09-10 00:04:18 +04:00
# include <asm/uaccess.h>
# include <linux/idr.h>
2007-07-11 02:57:28 +04:00
# include <net/9p/9p.h>
# include <net/9p/client.h>
2005-09-10 00:04:18 +04:00
# include "v9fs.h"
# include "v9fs_vfs.h"
# include "fid.h"
2009-09-23 22:00:27 +04:00
# include "cache.h"
2005-09-10 00:04:18 +04:00
2011-02-28 14:33:58 +03:00
static const struct vm_operations_struct v9fs_file_vm_ops ;
2005-09-10 00:04:18 +04:00
/**
* v9fs_file_open - open a file ( or directory )
* @ inode : inode to be opened
* @ file : file being opened
*
*/
int v9fs_file_open ( struct inode * inode , struct file * file )
{
2006-03-02 13:54:30 +03:00
int err ;
2011-02-28 14:34:03 +03:00
struct v9fs_inode * v9inode ;
2007-07-11 02:57:28 +04:00
struct v9fs_session_info * v9ses ;
struct p9_fid * fid ;
int omode ;
2005-09-10 00:04:18 +04:00
2010-06-22 18:17:50 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " inode: %p file: %p \n " , inode , file ) ;
2011-02-28 14:34:03 +03:00
v9inode = V9FS_I ( inode ) ;
2007-07-11 02:57:28 +04:00
v9ses = v9fs_inode2v9ses ( inode ) ;
2010-06-22 18:17:50 +04:00
if ( v9fs_proto_dotl ( v9ses ) )
2011-08-03 18:25:32 +04:00
omode = v9fs_open_to_dotl_flags ( file - > f_flags ) ;
2010-06-22 18:17:50 +04:00
else
omode = v9fs_uflags2omode ( file - > f_flags ,
v9fs_proto_dotu ( v9ses ) ) ;
2007-07-11 02:57:28 +04:00
fid = file - > private_data ;
if ( ! fid ) {
fid = v9fs_fid_clone ( file - > f_path . dentry ) ;
if ( IS_ERR ( fid ) )
return PTR_ERR ( fid ) ;
err = p9_client_open ( fid , omode ) ;
2007-07-13 22:01:27 +04:00
if ( err < 0 ) {
2007-07-11 02:57:28 +04:00
p9_client_clunk ( fid ) ;
return err ;
}
2010-06-22 18:17:50 +04:00
if ( file - > f_flags & O_TRUNC ) {
2009-09-22 20:34:05 +04:00
i_size_write ( inode , 0 ) ;
2007-07-13 22:01:27 +04:00
inode - > i_blocks = 0 ;
}
2010-06-22 18:17:50 +04:00
if ( ( file - > f_flags & O_APPEND ) & &
( ! v9fs_proto_dotu ( v9ses ) & & ! v9fs_proto_dotl ( v9ses ) ) )
2008-06-25 02:39:39 +04:00
generic_file_llseek ( file , 0 , SEEK_END ) ;
2006-03-02 13:54:30 +03:00
}
2005-09-10 00:04:18 +04:00
2007-07-11 02:57:28 +04:00
file - > private_data = fid ;
2011-03-08 14:09:46 +03:00
mutex_lock ( & v9inode - > v_mutex ) ;
2011-03-08 14:09:49 +03:00
if ( v9ses - > cache & & ! v9inode - > writeback_fid & &
( ( file - > f_flags & O_ACCMODE ) ! = O_RDONLY ) ) {
2011-02-28 14:33:57 +03:00
/*
2011-02-28 14:34:03 +03:00
* clone a fid and add it to writeback_fid
2011-02-28 14:33:57 +03:00
* we do it during open time instead of
* page dirty time via write_begin / page_mkwrite
* because we want write after unlink usecase
* to work .
*/
fid = v9fs_writeback_fid ( file - > f_path . dentry ) ;
if ( IS_ERR ( fid ) ) {
err = PTR_ERR ( fid ) ;
2011-03-08 14:09:46 +03:00
mutex_unlock ( & v9inode - > v_mutex ) ;
2011-02-28 14:33:57 +03:00
goto out_error ;
}
2011-02-28 14:34:03 +03:00
v9inode - > writeback_fid = ( void * ) fid ;
2011-02-28 14:33:57 +03:00
}
2011-03-08 14:09:46 +03:00
mutex_unlock ( & v9inode - > v_mutex ) ;
2011-02-28 14:33:54 +03:00
# ifdef CONFIG_9P_FSCACHE
2011-02-28 14:33:55 +03:00
if ( v9ses - > cache )
2009-09-23 22:00:27 +04:00
v9fs_cache_inode_set_cookie ( inode , file ) ;
2011-02-28 14:33:54 +03:00
# endif
2006-03-02 13:54:30 +03:00
return 0 ;
2011-02-28 14:33:57 +03:00
out_error :
p9_client_clunk ( file - > private_data ) ;
file - > private_data = NULL ;
return err ;
2005-09-10 00:04:18 +04:00
}
/**
* v9fs_file_lock - lock a file ( or directory )
2008-03-05 16:08:09 +03:00
* @ filp : file to be locked
* @ cmd : lock command
* @ fl : file lock structure
2005-09-10 00:04:18 +04:00
*
2008-03-05 16:08:09 +03:00
* Bugs : this looks like a local only lock , we should extend into 9 P
2005-09-10 00:04:18 +04:00
* by using open exclusive
*/
static int v9fs_file_lock ( struct file * filp , int cmd , struct file_lock * fl )
{
int res = 0 ;
2006-12-08 13:36:45 +03:00
struct inode * inode = filp - > f_path . dentry - > d_inode ;
2005-09-10 00:04:18 +04:00
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " filp: %p lock: %p \n " , filp , fl ) ;
2005-09-10 00:04:18 +04:00
/* No mandatory locks */
2010-03-13 18:03:55 +03:00
if ( __mandatory_lock ( inode ) & & fl - > fl_type ! = F_UNLCK )
2005-09-10 00:04:18 +04:00
return - ENOLCK ;
if ( ( IS_SETLK ( cmd ) | | IS_SETLKW ( cmd ) ) & & fl - > fl_type ! = F_UNLCK ) {
[PATCH] Fix and add EXPORT_SYMBOL(filemap_write_and_wait)
This patch add EXPORT_SYMBOL(filemap_write_and_wait) and use it.
See mm/filemap.c:
And changes the filemap_write_and_wait() and filemap_write_and_wait_range().
Current filemap_write_and_wait() doesn't wait if filemap_fdatawrite()
returns error. However, even if filemap_fdatawrite() returned an
error, it may have submitted the partially data pages to the device.
(e.g. in the case of -ENOSPC)
<quotation>
Andrew Morton writes,
If filemap_fdatawrite() returns an error, this might be due to some
I/O problem: dead disk, unplugged cable, etc. Given the generally
crappy quality of the kernel's handling of such exceptions, there's a
good chance that the filemap_fdatawait() will get stuck in D state
forever.
</quotation>
So, this patch doesn't wait if filemap_fdatawrite() returns the -EIO.
Trond, could you please review the nfs part? Especially I'm not sure,
nfs must use the "filemap_fdatawrite(inode->i_mapping) == 0", or not.
Acked-by: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-08 12:02:14 +03:00
filemap_write_and_wait ( inode - > i_mapping ) ;
2007-02-10 12:45:39 +03:00
invalidate_mapping_pages ( & inode - > i_data , 0 , - 1 ) ;
2005-09-10 00:04:18 +04:00
}
return res ;
}
9p: Implement TLOCK
Synopsis
size[4] TLock tag[2] fid[4] flock[n]
size[4] RLock tag[2] status[1]
Description
Tlock is used to acquire/release byte range posix locks on a file
identified by given fid. The reply contains status of the lock request
flock structure:
type[1] - Type of lock: F_RDLCK, F_WRLCK, F_UNLCK
flags[4] - Flags could be either of
P9_LOCK_FLAGS_BLOCK - Blocked lock request, if there is a
conflicting lock exists, wait for that lock to be released.
P9_LOCK_FLAGS_RECLAIM - Reclaim lock request, used when client is
trying to reclaim a lock after a server restrart (due to crash)
start[8] - Starting offset for lock
length[8] - Number of bytes to lock
If length is 0, lock all bytes starting at the location 'start'
through to the end of file
pid[4] - PID of the process that wants to take lock
client_id[4] - Unique client id
status[1] - Status of the lock request, can be
P9_LOCK_SUCCESS(0), P9_LOCK_BLOCKED(1), P9_LOCK_ERROR(2) or
P9_LOCK_GRACE(3)
P9_LOCK_SUCCESS - Request was successful
P9_LOCK_BLOCKED - A conflicting lock is held by another process
P9_LOCK_ERROR - Error while processing the lock request
P9_LOCK_GRACE - Server is in grace period, it can't accept new lock
requests in this period (except locks with
P9_LOCK_FLAGS_RECLAIM flag set)
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
2010-09-27 10:04:24 +04:00
static int v9fs_file_do_lock ( struct file * filp , int cmd , struct file_lock * fl )
{
struct p9_flock flock ;
struct p9_fid * fid ;
uint8_t status ;
int res = 0 ;
unsigned char fl_type ;
fid = filp - > private_data ;
BUG_ON ( fid = = NULL ) ;
if ( ( fl - > fl_flags & FL_POSIX ) ! = FL_POSIX )
BUG ( ) ;
res = posix_lock_file_wait ( filp , fl ) ;
if ( res < 0 )
goto out ;
/* convert posix lock to p9 tlock args */
memset ( & flock , 0 , sizeof ( flock ) ) ;
2011-08-20 22:51:18 +04:00
/* map the lock type */
switch ( fl - > fl_type ) {
case F_RDLCK :
flock . type = P9_LOCK_TYPE_RDLCK ;
break ;
case F_WRLCK :
flock . type = P9_LOCK_TYPE_WRLCK ;
break ;
case F_UNLCK :
flock . type = P9_LOCK_TYPE_UNLCK ;
break ;
}
9p: Implement TLOCK
Synopsis
size[4] TLock tag[2] fid[4] flock[n]
size[4] RLock tag[2] status[1]
Description
Tlock is used to acquire/release byte range posix locks on a file
identified by given fid. The reply contains status of the lock request
flock structure:
type[1] - Type of lock: F_RDLCK, F_WRLCK, F_UNLCK
flags[4] - Flags could be either of
P9_LOCK_FLAGS_BLOCK - Blocked lock request, if there is a
conflicting lock exists, wait for that lock to be released.
P9_LOCK_FLAGS_RECLAIM - Reclaim lock request, used when client is
trying to reclaim a lock after a server restrart (due to crash)
start[8] - Starting offset for lock
length[8] - Number of bytes to lock
If length is 0, lock all bytes starting at the location 'start'
through to the end of file
pid[4] - PID of the process that wants to take lock
client_id[4] - Unique client id
status[1] - Status of the lock request, can be
P9_LOCK_SUCCESS(0), P9_LOCK_BLOCKED(1), P9_LOCK_ERROR(2) or
P9_LOCK_GRACE(3)
P9_LOCK_SUCCESS - Request was successful
P9_LOCK_BLOCKED - A conflicting lock is held by another process
P9_LOCK_ERROR - Error while processing the lock request
P9_LOCK_GRACE - Server is in grace period, it can't accept new lock
requests in this period (except locks with
P9_LOCK_FLAGS_RECLAIM flag set)
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
2010-09-27 10:04:24 +04:00
flock . start = fl - > fl_start ;
if ( fl - > fl_end = = OFFSET_MAX )
flock . length = 0 ;
else
flock . length = fl - > fl_end - fl - > fl_start + 1 ;
flock . proc_id = fl - > fl_pid ;
flock . client_id = utsname ( ) - > nodename ;
if ( IS_SETLKW ( cmd ) )
flock . flags = P9_LOCK_FLAGS_BLOCK ;
/*
* if its a blocked request and we get P9_LOCK_BLOCKED as the status
* for lock request , keep on trying
*/
for ( ; ; ) {
res = p9_client_lock_dotl ( fid , & flock , & status ) ;
if ( res < 0 )
break ;
if ( status ! = P9_LOCK_BLOCKED )
break ;
if ( status = = P9_LOCK_BLOCKED & & ! IS_SETLKW ( cmd ) )
break ;
schedule_timeout_interruptible ( P9_LOCK_TIMEOUT ) ;
}
/* map 9p status to VFS status */
switch ( status ) {
case P9_LOCK_SUCCESS :
res = 0 ;
break ;
case P9_LOCK_BLOCKED :
res = - EAGAIN ;
break ;
case P9_LOCK_ERROR :
case P9_LOCK_GRACE :
res = - ENOLCK ;
break ;
default :
BUG ( ) ;
}
/*
* incase server returned error for lock request , revert
* it locally
*/
if ( res < 0 & & fl - > fl_type ! = F_UNLCK ) {
fl_type = fl - > fl_type ;
fl - > fl_type = F_UNLCK ;
res = posix_lock_file_wait ( filp , fl ) ;
fl - > fl_type = fl_type ;
}
out :
return res ;
}
2010-09-27 10:52:13 +04:00
static int v9fs_file_getlock ( struct file * filp , struct file_lock * fl )
{
struct p9_getlock glock ;
struct p9_fid * fid ;
int res = 0 ;
fid = filp - > private_data ;
BUG_ON ( fid = = NULL ) ;
posix_test_lock ( filp , fl ) ;
/*
* if we have a conflicting lock locally , no need to validate
* with server
*/
if ( fl - > fl_type ! = F_UNLCK )
return res ;
/* convert posix lock to p9 tgetlock args */
memset ( & glock , 0 , sizeof ( glock ) ) ;
2011-08-20 22:51:18 +04:00
glock . type = P9_LOCK_TYPE_UNLCK ;
2010-09-27 10:52:13 +04:00
glock . start = fl - > fl_start ;
if ( fl - > fl_end = = OFFSET_MAX )
glock . length = 0 ;
else
glock . length = fl - > fl_end - fl - > fl_start + 1 ;
glock . proc_id = fl - > fl_pid ;
glock . client_id = utsname ( ) - > nodename ;
res = p9_client_getlock_dotl ( fid , & glock ) ;
if ( res < 0 )
return res ;
2011-08-20 22:51:18 +04:00
/* map 9p lock type to os lock type */
switch ( glock . type ) {
case P9_LOCK_TYPE_RDLCK :
fl - > fl_type = F_RDLCK ;
break ;
case P9_LOCK_TYPE_WRLCK :
fl - > fl_type = F_WRLCK ;
break ;
case P9_LOCK_TYPE_UNLCK :
fl - > fl_type = F_UNLCK ;
break ;
}
if ( glock . type ! = P9_LOCK_TYPE_UNLCK ) {
2010-09-27 10:52:13 +04:00
fl - > fl_start = glock . start ;
if ( glock . length = = 0 )
fl - > fl_end = OFFSET_MAX ;
else
fl - > fl_end = glock . start + glock . length - 1 ;
fl - > fl_pid = glock . proc_id ;
2011-08-20 22:51:18 +04:00
}
2010-09-27 10:52:13 +04:00
return res ;
}
9p: Implement TLOCK
Synopsis
size[4] TLock tag[2] fid[4] flock[n]
size[4] RLock tag[2] status[1]
Description
Tlock is used to acquire/release byte range posix locks on a file
identified by given fid. The reply contains status of the lock request
flock structure:
type[1] - Type of lock: F_RDLCK, F_WRLCK, F_UNLCK
flags[4] - Flags could be either of
P9_LOCK_FLAGS_BLOCK - Blocked lock request, if there is a
conflicting lock exists, wait for that lock to be released.
P9_LOCK_FLAGS_RECLAIM - Reclaim lock request, used when client is
trying to reclaim a lock after a server restrart (due to crash)
start[8] - Starting offset for lock
length[8] - Number of bytes to lock
If length is 0, lock all bytes starting at the location 'start'
through to the end of file
pid[4] - PID of the process that wants to take lock
client_id[4] - Unique client id
status[1] - Status of the lock request, can be
P9_LOCK_SUCCESS(0), P9_LOCK_BLOCKED(1), P9_LOCK_ERROR(2) or
P9_LOCK_GRACE(3)
P9_LOCK_SUCCESS - Request was successful
P9_LOCK_BLOCKED - A conflicting lock is held by another process
P9_LOCK_ERROR - Error while processing the lock request
P9_LOCK_GRACE - Server is in grace period, it can't accept new lock
requests in this period (except locks with
P9_LOCK_FLAGS_RECLAIM flag set)
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
2010-09-27 10:04:24 +04:00
/**
* v9fs_file_lock_dotl - lock a file ( or directory )
* @ filp : file to be locked
* @ cmd : lock command
* @ fl : file lock structure
*
*/
static int v9fs_file_lock_dotl ( struct file * filp , int cmd , struct file_lock * fl )
{
struct inode * inode = filp - > f_path . dentry - > d_inode ;
int ret = - ENOLCK ;
P9_DPRINTK ( P9_DEBUG_VFS , " filp: %p cmd:%d lock: %p name: %s \n " , filp ,
cmd , fl , filp - > f_path . dentry - > d_name . name ) ;
/* No mandatory locks */
if ( __mandatory_lock ( inode ) & & fl - > fl_type ! = F_UNLCK )
goto out_err ;
if ( ( IS_SETLK ( cmd ) | | IS_SETLKW ( cmd ) ) & & fl - > fl_type ! = F_UNLCK ) {
filemap_write_and_wait ( inode - > i_mapping ) ;
invalidate_mapping_pages ( & inode - > i_data , 0 , - 1 ) ;
}
if ( IS_SETLK ( cmd ) | | IS_SETLKW ( cmd ) )
ret = v9fs_file_do_lock ( filp , cmd , fl ) ;
2010-09-27 10:52:13 +04:00
else if ( IS_GETLK ( cmd ) )
ret = v9fs_file_getlock ( filp , fl ) ;
9p: Implement TLOCK
Synopsis
size[4] TLock tag[2] fid[4] flock[n]
size[4] RLock tag[2] status[1]
Description
Tlock is used to acquire/release byte range posix locks on a file
identified by given fid. The reply contains status of the lock request
flock structure:
type[1] - Type of lock: F_RDLCK, F_WRLCK, F_UNLCK
flags[4] - Flags could be either of
P9_LOCK_FLAGS_BLOCK - Blocked lock request, if there is a
conflicting lock exists, wait for that lock to be released.
P9_LOCK_FLAGS_RECLAIM - Reclaim lock request, used when client is
trying to reclaim a lock after a server restrart (due to crash)
start[8] - Starting offset for lock
length[8] - Number of bytes to lock
If length is 0, lock all bytes starting at the location 'start'
through to the end of file
pid[4] - PID of the process that wants to take lock
client_id[4] - Unique client id
status[1] - Status of the lock request, can be
P9_LOCK_SUCCESS(0), P9_LOCK_BLOCKED(1), P9_LOCK_ERROR(2) or
P9_LOCK_GRACE(3)
P9_LOCK_SUCCESS - Request was successful
P9_LOCK_BLOCKED - A conflicting lock is held by another process
P9_LOCK_ERROR - Error while processing the lock request
P9_LOCK_GRACE - Server is in grace period, it can't accept new lock
requests in this period (except locks with
P9_LOCK_FLAGS_RECLAIM flag set)
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
2010-09-27 10:04:24 +04:00
else
ret = - EINVAL ;
out_err :
return ret ;
}
/**
* v9fs_file_flock_dotl - lock a file
* @ filp : file to be locked
* @ cmd : lock command
* @ fl : file lock structure
*
*/
static int v9fs_file_flock_dotl ( struct file * filp , int cmd ,
struct file_lock * fl )
{
struct inode * inode = filp - > f_path . dentry - > d_inode ;
int ret = - ENOLCK ;
P9_DPRINTK ( P9_DEBUG_VFS , " filp: %p cmd:%d lock: %p name: %s \n " , filp ,
cmd , fl , filp - > f_path . dentry - > d_name . name ) ;
/* No mandatory locks */
if ( __mandatory_lock ( inode ) & & fl - > fl_type ! = F_UNLCK )
goto out_err ;
if ( ! ( fl - > fl_flags & FL_FLOCK ) )
goto out_err ;
if ( ( IS_SETLK ( cmd ) | | IS_SETLKW ( cmd ) ) & & fl - > fl_type ! = F_UNLCK ) {
filemap_write_and_wait ( inode - > i_mapping ) ;
invalidate_mapping_pages ( & inode - > i_data , 0 , - 1 ) ;
}
/* Convert flock to posix lock */
fl - > fl_owner = ( fl_owner_t ) filp ;
fl - > fl_start = 0 ;
fl - > fl_end = OFFSET_MAX ;
fl - > fl_flags | = FL_POSIX ;
fl - > fl_flags ^ = FL_FLOCK ;
if ( IS_SETLK ( cmd ) | IS_SETLKW ( cmd ) )
ret = v9fs_file_do_lock ( filp , cmd , fl ) ;
else
ret = - EINVAL ;
out_err :
return ret ;
}
2005-09-10 00:04:18 +04:00
/**
2011-02-28 14:33:56 +03:00
* v9fs_fid_readn - read from a fid
* @ fid : fid to read
2005-09-10 00:04:18 +04:00
* @ data : data buffer to read data into
2008-10-14 05:36:16 +04:00
* @ udata : user data buffer to read data into
2005-09-10 00:04:18 +04:00
* @ count : size of buffer
* @ offset : offset at which to read data
*
*/
2008-10-14 05:36:16 +04:00
ssize_t
2011-02-28 14:33:56 +03:00
v9fs_fid_readn ( struct p9_fid * fid , char * data , char __user * udata , u32 count ,
2008-10-14 05:36:16 +04:00
u64 offset )
{
2010-06-04 15:59:07 +04:00
int n , total , size ;
2008-10-14 05:36:16 +04:00
2008-10-16 17:30:07 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " fid %d offset %llu count %d \n " , fid - > fid ,
2011-02-28 14:33:56 +03:00
( long long unsigned ) offset , count ) ;
2008-10-14 05:36:16 +04:00
n = 0 ;
total = 0 ;
2010-06-04 15:59:07 +04:00
size = fid - > iounit ? fid - > iounit : fid - > clnt - > msize - P9_IOHDRSZ ;
2008-10-14 05:36:16 +04:00
do {
n = p9_client_read ( fid , data , udata , offset , count ) ;
if ( n < = 0 )
break ;
if ( data )
data + = n ;
if ( udata )
udata + = n ;
offset + = n ;
count - = n ;
total + = n ;
2010-06-04 15:59:07 +04:00
} while ( count > 0 & & n = = size ) ;
2008-10-14 05:36:16 +04:00
if ( n < 0 )
total = n ;
return total ;
}
2011-02-28 14:33:56 +03:00
/**
* v9fs_file_readn - read from a file
* @ filp : file pointer to read
* @ data : data buffer to read data into
* @ udata : user data buffer to read data into
* @ count : size of buffer
* @ offset : offset at which to read data
*
*/
ssize_t
v9fs_file_readn ( struct file * filp , char * data , char __user * udata , u32 count ,
u64 offset )
{
return v9fs_fid_readn ( filp - > private_data , data , udata , count , offset ) ;
}
2008-10-14 05:36:16 +04:00
/**
* v9fs_file_read - read from a file
* @ filp : file pointer to read
* @ udata : user data buffer to read data into
* @ count : size of buffer
* @ offset : offset at which to read data
*
*/
2005-09-10 00:04:18 +04:00
static ssize_t
2008-10-14 05:36:16 +04:00
v9fs_file_read ( struct file * filp , char __user * udata , size_t count ,
2005-10-11 19:29:03 +04:00
loff_t * offset )
2005-09-10 00:04:18 +04:00
{
2007-07-11 02:57:28 +04:00
int ret ;
struct p9_fid * fid ;
2010-06-04 15:59:07 +04:00
size_t size ;
2005-09-10 00:04:18 +04:00
2008-10-23 03:48:45 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " count %zu offset %lld \n " , count , * offset ) ;
2007-07-11 02:57:28 +04:00
fid = filp - > private_data ;
2008-10-14 05:36:16 +04:00
2010-06-04 15:59:07 +04:00
size = fid - > iounit ? fid - > iounit : fid - > clnt - > msize - P9_IOHDRSZ ;
if ( count > size )
2008-10-14 05:36:16 +04:00
ret = v9fs_file_readn ( filp , NULL , udata , count , * offset ) ;
else
ret = p9_client_read ( fid , NULL , udata , * offset , count ) ;
2007-07-11 02:57:28 +04:00
if ( ret > 0 )
* offset + = ret ;
2005-09-10 00:04:18 +04:00
2007-07-11 02:57:28 +04:00
return ret ;
2005-09-10 00:04:18 +04:00
}
2011-02-28 14:33:56 +03:00
ssize_t
v9fs_file_write_internal ( struct inode * inode , struct p9_fid * fid ,
const char __user * data , size_t count ,
loff_t * offset , int invalidate )
2005-09-10 00:04:18 +04:00
{
2010-08-30 22:23:20 +04:00
int n ;
2011-02-28 14:34:04 +03:00
loff_t i_size ;
2011-02-28 14:33:56 +03:00
size_t total = 0 ;
2008-10-14 05:36:16 +04:00
struct p9_client * clnt ;
2010-03-09 01:07:02 +03:00
loff_t origin = * offset ;
2009-09-22 20:34:05 +04:00
unsigned long pg_start , pg_end ;
2005-09-10 00:04:18 +04:00
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " data %p count %d offset %x \n " , data ,
( int ) count , ( int ) * offset ) ;
2005-09-10 00:04:18 +04:00
2008-10-14 05:36:16 +04:00
clnt = fid - > clnt ;
do {
2010-08-30 22:23:20 +04:00
n = p9_client_write ( fid , NULL , data + total , origin + total , count ) ;
2008-10-14 05:36:16 +04:00
if ( n < = 0 )
break ;
count - = n ;
total + = n ;
} while ( count > 0 ) ;
2011-02-28 14:33:56 +03:00
if ( invalidate & & ( total > 0 ) ) {
2009-09-22 20:34:05 +04:00
pg_start = origin > > PAGE_CACHE_SHIFT ;
pg_end = ( origin + total - 1 ) > > PAGE_CACHE_SHIFT ;
2009-09-23 22:00:27 +04:00
if ( inode - > i_mapping & & inode - > i_mapping - > nrpages )
invalidate_inode_pages2_range ( inode - > i_mapping ,
pg_start , pg_end ) ;
2008-10-14 05:36:16 +04:00
* offset + = total ;
2011-02-28 14:34:04 +03:00
i_size = i_size_read ( inode ) ;
if ( * offset > i_size ) {
inode_add_bytes ( inode , * offset - i_size ) ;
i_size_write ( inode , * offset ) ;
}
2007-07-13 22:01:27 +04:00
}
2008-10-14 05:36:16 +04:00
if ( n < 0 )
2011-02-28 14:33:56 +03:00
return n ;
return total ;
}
/**
* v9fs_file_write - write to a file
* @ filp : file pointer to write
* @ data : data buffer to write data from
* @ count : size of buffer
* @ offset : offset at which to write data
*
*/
static ssize_t
v9fs_file_write ( struct file * filp , const char __user * data ,
size_t count , loff_t * offset )
{
ssize_t retval = 0 ;
loff_t origin = * offset ;
retval = generic_write_checks ( filp , & origin , & count , 0 ) ;
if ( retval )
goto out ;
retval = - EINVAL ;
if ( ( ssize_t ) count < 0 )
goto out ;
retval = 0 ;
if ( ! count )
goto out ;
2011-03-16 19:10:49 +03:00
retval = v9fs_file_write_internal ( filp - > f_path . dentry - > d_inode ,
2011-02-28 14:33:56 +03:00
filp - > private_data ,
2011-03-16 19:10:49 +03:00
data , count , & origin , 1 ) ;
/* update offset on successful write */
if ( retval > 0 )
* offset = origin ;
2010-08-03 15:55:40 +04:00
out :
return retval ;
2005-09-10 00:04:18 +04:00
}
2011-02-28 14:33:58 +03:00
2011-07-17 04:44:56 +04:00
static int v9fs_file_fsync ( struct file * filp , loff_t start , loff_t end ,
int datasync )
2010-02-09 00:36:48 +03:00
{
struct p9_fid * fid ;
2011-07-17 04:44:56 +04:00
struct inode * inode = filp - > f_mapping - > host ;
2010-02-09 00:36:48 +03:00
struct p9_wstat wstat ;
int retval ;
2011-07-17 04:44:56 +04:00
retval = filemap_write_and_wait_range ( inode - > i_mapping , start , end ) ;
if ( retval )
return retval ;
mutex_lock ( & inode - > i_mutex ) ;
2010-05-26 19:53:25 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " filp %p datasync %x \n " , filp , datasync ) ;
2010-02-09 00:36:48 +03:00
fid = filp - > private_data ;
v9fs_blank_wstat ( & wstat ) ;
retval = p9_client_wstat ( fid , & wstat ) ;
2011-07-17 04:44:56 +04:00
mutex_unlock ( & inode - > i_mutex ) ;
2010-02-09 00:36:48 +03:00
return retval ;
}
2011-07-17 04:44:56 +04:00
int v9fs_file_fsync_dotl ( struct file * filp , loff_t start , loff_t end ,
int datasync )
2010-09-23 04:19:19 +04:00
{
struct p9_fid * fid ;
2011-07-17 04:44:56 +04:00
struct inode * inode = filp - > f_mapping - > host ;
2010-09-23 04:19:19 +04:00
int retval ;
2011-07-17 04:44:56 +04:00
retval = filemap_write_and_wait_range ( inode - > i_mapping , start , end ) ;
if ( retval )
return retval ;
mutex_lock ( & inode - > i_mutex ) ;
2010-09-23 04:19:19 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " v9fs_file_fsync_dotl: filp %p datasync %x \n " ,
filp , datasync ) ;
fid = filp - > private_data ;
2010-10-22 21:13:12 +04:00
retval = p9_client_fsync ( fid , datasync ) ;
2011-07-17 04:44:56 +04:00
mutex_unlock ( & inode - > i_mutex ) ;
2010-09-23 04:19:19 +04:00
return retval ;
}
2011-02-28 14:33:58 +03:00
static int
v9fs_file_mmap ( struct file * file , struct vm_area_struct * vma )
{
int retval ;
retval = generic_file_mmap ( file , vma ) ;
if ( ! retval )
vma - > vm_ops = & v9fs_file_vm_ops ;
return retval ;
}
static int
v9fs_vm_page_mkwrite ( struct vm_area_struct * vma , struct vm_fault * vmf )
{
2011-02-28 14:34:03 +03:00
struct v9fs_inode * v9inode ;
2011-02-28 14:33:58 +03:00
struct page * page = vmf - > page ;
struct file * filp = vma - > vm_file ;
struct inode * inode = filp - > f_path . dentry - > d_inode ;
P9_DPRINTK ( P9_DEBUG_VFS , " page %p fid %lx \n " ,
page , ( unsigned long ) filp - > private_data ) ;
2011-02-28 14:34:03 +03:00
v9inode = V9FS_I ( inode ) ;
2011-02-28 14:33:58 +03:00
/* make sure the cache has finished storing the page */
v9fs_fscache_wait_on_page_write ( inode , page ) ;
2011-02-28 14:34:03 +03:00
BUG_ON ( ! v9inode - > writeback_fid ) ;
2011-02-28 14:33:58 +03:00
lock_page ( page ) ;
if ( page - > mapping ! = inode - > i_mapping )
goto out_unlock ;
return VM_FAULT_LOCKED ;
out_unlock :
unlock_page ( page ) ;
return VM_FAULT_NOPAGE ;
}
2011-02-28 14:34:04 +03:00
static ssize_t
v9fs_direct_read ( struct file * filp , char __user * udata , size_t count ,
loff_t * offsetp )
{
loff_t size , offset ;
struct inode * inode ;
struct address_space * mapping ;
offset = * offsetp ;
mapping = filp - > f_mapping ;
inode = mapping - > host ;
if ( ! count )
return 0 ;
size = i_size_read ( inode ) ;
if ( offset < size )
filemap_write_and_wait_range ( mapping , offset ,
offset + count - 1 ) ;
return v9fs_file_read ( filp , udata , count , offsetp ) ;
}
/**
* v9fs_cached_file_read - read from a file
* @ filp : file pointer to read
* @ udata : user data buffer to read data into
* @ count : size of buffer
* @ offset : offset at which to read data
*
*/
static ssize_t
v9fs_cached_file_read ( struct file * filp , char __user * data , size_t count ,
loff_t * offset )
{
if ( filp - > f_flags & O_DIRECT )
return v9fs_direct_read ( filp , data , count , offset ) ;
return do_sync_read ( filp , data , count , offset ) ;
}
static ssize_t
v9fs_direct_write ( struct file * filp , const char __user * data ,
size_t count , loff_t * offsetp )
{
loff_t offset ;
ssize_t retval ;
struct inode * inode ;
struct address_space * mapping ;
offset = * offsetp ;
mapping = filp - > f_mapping ;
inode = mapping - > host ;
if ( ! count )
return 0 ;
mutex_lock ( & inode - > i_mutex ) ;
retval = filemap_write_and_wait_range ( mapping , offset ,
offset + count - 1 ) ;
if ( retval )
goto err_out ;
/*
* After a write we want buffered reads to be sure to go to disk to get
* the new data . We invalidate clean cached page from the region we ' re
* about to write . We do this * before * the write so that if we fail
* here we fall back to buffered write
*/
if ( mapping - > nrpages ) {
pgoff_t pg_start = offset > > PAGE_CACHE_SHIFT ;
pgoff_t pg_end = ( offset + count - 1 ) > > PAGE_CACHE_SHIFT ;
retval = invalidate_inode_pages2_range ( mapping ,
pg_start , pg_end ) ;
/*
* If a page can not be invalidated , fall back
* to buffered write .
*/
if ( retval ) {
if ( retval = = - EBUSY )
goto buff_write ;
goto err_out ;
}
}
retval = v9fs_file_write ( filp , data , count , offsetp ) ;
err_out :
mutex_unlock ( & inode - > i_mutex ) ;
return retval ;
buff_write :
mutex_unlock ( & inode - > i_mutex ) ;
return do_sync_write ( filp , data , count , offsetp ) ;
}
/**
* v9fs_cached_file_write - write to a file
* @ filp : file pointer to write
* @ data : data buffer to write data from
* @ count : size of buffer
* @ offset : offset at which to write data
*
*/
static ssize_t
v9fs_cached_file_write ( struct file * filp , const char __user * data ,
size_t count , loff_t * offset )
{
if ( filp - > f_flags & O_DIRECT )
return v9fs_direct_write ( filp , data , count , offset ) ;
return do_sync_write ( filp , data , count , offset ) ;
}
2011-02-28 14:33:58 +03:00
static const struct vm_operations_struct v9fs_file_vm_ops = {
. fault = filemap_fault ,
. page_mkwrite = v9fs_vm_page_mkwrite ,
} ;
2011-02-28 14:34:04 +03:00
2011-02-28 14:33:54 +03:00
const struct file_operations v9fs_cached_file_operations = {
2007-02-11 22:21:39 +03:00
. llseek = generic_file_llseek ,
2011-02-28 14:34:04 +03:00
. read = v9fs_cached_file_read ,
. write = v9fs_cached_file_write ,
2007-02-11 22:21:39 +03:00
. aio_read = generic_file_aio_read ,
2011-02-28 14:33:58 +03:00
. aio_write = generic_file_aio_write ,
2007-02-11 22:21:39 +03:00
. open = v9fs_file_open ,
. release = v9fs_dir_release ,
. lock = v9fs_file_lock ,
2011-02-28 14:33:58 +03:00
. mmap = v9fs_file_mmap ,
2010-02-09 00:36:48 +03:00
. fsync = v9fs_file_fsync ,
2007-02-11 22:21:39 +03:00
} ;
2011-02-28 14:33:54 +03:00
const struct file_operations v9fs_cached_file_operations_dotl = {
2010-09-23 03:30:52 +04:00
. llseek = generic_file_llseek ,
2011-02-28 14:34:04 +03:00
. read = v9fs_cached_file_read ,
. write = v9fs_cached_file_write ,
2010-09-23 03:30:52 +04:00
. aio_read = generic_file_aio_read ,
2011-02-28 14:33:58 +03:00
. aio_write = generic_file_aio_write ,
2010-09-23 03:30:52 +04:00
. open = v9fs_file_open ,
. release = v9fs_dir_release ,
9p: Implement TLOCK
Synopsis
size[4] TLock tag[2] fid[4] flock[n]
size[4] RLock tag[2] status[1]
Description
Tlock is used to acquire/release byte range posix locks on a file
identified by given fid. The reply contains status of the lock request
flock structure:
type[1] - Type of lock: F_RDLCK, F_WRLCK, F_UNLCK
flags[4] - Flags could be either of
P9_LOCK_FLAGS_BLOCK - Blocked lock request, if there is a
conflicting lock exists, wait for that lock to be released.
P9_LOCK_FLAGS_RECLAIM - Reclaim lock request, used when client is
trying to reclaim a lock after a server restrart (due to crash)
start[8] - Starting offset for lock
length[8] - Number of bytes to lock
If length is 0, lock all bytes starting at the location 'start'
through to the end of file
pid[4] - PID of the process that wants to take lock
client_id[4] - Unique client id
status[1] - Status of the lock request, can be
P9_LOCK_SUCCESS(0), P9_LOCK_BLOCKED(1), P9_LOCK_ERROR(2) or
P9_LOCK_GRACE(3)
P9_LOCK_SUCCESS - Request was successful
P9_LOCK_BLOCKED - A conflicting lock is held by another process
P9_LOCK_ERROR - Error while processing the lock request
P9_LOCK_GRACE - Server is in grace period, it can't accept new lock
requests in this period (except locks with
P9_LOCK_FLAGS_RECLAIM flag set)
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
2010-09-27 10:04:24 +04:00
. lock = v9fs_file_lock_dotl ,
. flock = v9fs_file_flock_dotl ,
2011-02-28 14:33:58 +03:00
. mmap = v9fs_file_mmap ,
2010-09-23 04:19:19 +04:00
. fsync = v9fs_file_fsync_dotl ,
2010-09-23 03:30:52 +04:00
} ;
2006-03-28 13:56:42 +04:00
const struct file_operations v9fs_file_operations = {
2005-09-10 00:04:18 +04:00
. llseek = generic_file_llseek ,
. read = v9fs_file_read ,
. write = v9fs_file_write ,
. open = v9fs_file_open ,
. release = v9fs_dir_release ,
. lock = v9fs_file_lock ,
2008-02-07 04:25:05 +03:00
. mmap = generic_file_readonly_mmap ,
2010-02-09 00:36:48 +03:00
. fsync = v9fs_file_fsync ,
2005-09-10 00:04:18 +04:00
} ;
2010-03-25 15:41:54 +03:00
const struct file_operations v9fs_file_operations_dotl = {
. llseek = generic_file_llseek ,
. read = v9fs_file_read ,
. write = v9fs_file_write ,
. open = v9fs_file_open ,
. release = v9fs_dir_release ,
9p: Implement TLOCK
Synopsis
size[4] TLock tag[2] fid[4] flock[n]
size[4] RLock tag[2] status[1]
Description
Tlock is used to acquire/release byte range posix locks on a file
identified by given fid. The reply contains status of the lock request
flock structure:
type[1] - Type of lock: F_RDLCK, F_WRLCK, F_UNLCK
flags[4] - Flags could be either of
P9_LOCK_FLAGS_BLOCK - Blocked lock request, if there is a
conflicting lock exists, wait for that lock to be released.
P9_LOCK_FLAGS_RECLAIM - Reclaim lock request, used when client is
trying to reclaim a lock after a server restrart (due to crash)
start[8] - Starting offset for lock
length[8] - Number of bytes to lock
If length is 0, lock all bytes starting at the location 'start'
through to the end of file
pid[4] - PID of the process that wants to take lock
client_id[4] - Unique client id
status[1] - Status of the lock request, can be
P9_LOCK_SUCCESS(0), P9_LOCK_BLOCKED(1), P9_LOCK_ERROR(2) or
P9_LOCK_GRACE(3)
P9_LOCK_SUCCESS - Request was successful
P9_LOCK_BLOCKED - A conflicting lock is held by another process
P9_LOCK_ERROR - Error while processing the lock request
P9_LOCK_GRACE - Server is in grace period, it can't accept new lock
requests in this period (except locks with
P9_LOCK_FLAGS_RECLAIM flag set)
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
2010-09-27 10:04:24 +04:00
. lock = v9fs_file_lock_dotl ,
. flock = v9fs_file_flock_dotl ,
2010-03-25 15:41:54 +03:00
. mmap = generic_file_readonly_mmap ,
2010-09-23 04:19:19 +04:00
. fsync = v9fs_file_fsync_dotl ,
2010-03-25 15:41:54 +03:00
} ;