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>
# 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"
2007-03-05 04:49:48 +03:00
static const struct file_operations v9fs_cached_file_operations ;
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 ;
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
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " inode: %p file: %p \n " , inode , file ) ;
v9ses = v9fs_inode2v9ses ( inode ) ;
2008-06-25 02:39:39 +04:00
omode = v9fs_uflags2omode ( file - > f_flags , v9fs_extended ( 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 ;
}
2007-07-13 22:01:27 +04:00
if ( omode & P9_OTRUNC ) {
inode - > i_size = 0 ;
inode - > i_blocks = 0 ;
}
2008-06-25 02:39:39 +04:00
if ( ( file - > f_flags & O_APPEND ) & & ( ! v9fs_extended ( v9ses ) ) )
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 ;
if ( ( fid - > qid . version ) & & ( v9ses - > cache ) ) {
P9_DPRINTK ( P9_DEBUG_VFS , " cached " ) ;
2007-02-11 22:21:39 +03:00
/* enable cached file options */
if ( file - > f_op = = & v9fs_file_operations )
file - > f_op = & v9fs_cached_file_operations ;
}
2006-03-02 13:54:30 +03:00
return 0 ;
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 */
2007-10-02 01:41:13 +04:00
if ( __mandatory_lock ( inode ) )
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 ;
}
/**
2008-10-14 05:36:16 +04:00
* v9fs_file_readn - read from a file
2008-03-05 16:08:09 +03:00
* @ filp : file pointer 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
v9fs_file_readn ( struct file * filp , char * data , char __user * udata , u32 count ,
u64 offset )
{
int n , total ;
struct p9_fid * fid = filp - > private_data ;
2008-10-16 17:30:07 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " fid %d offset %llu count %d \n " , fid - > fid ,
2008-10-14 05:36:16 +04:00
( long long unsigned ) offset , count ) ;
n = 0 ;
total = 0 ;
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 ;
} while ( count > 0 & & n = = ( fid - > clnt - > msize - P9_IOHDRSZ ) ) ;
if ( n < 0 )
total = n ;
return total ;
}
/**
* 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 ;
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
if ( count > ( fid - > clnt - > msize - P9_IOHDRSZ ) )
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
}
/**
2005-10-11 19:29:03 +04:00
* v9fs_file_write - write to a file
2008-03-05 16:08:09 +03:00
* @ filp : file pointer to write
2005-09-10 00:04:18 +04:00
* @ data : data buffer to write data from
* @ count : size of buffer
* @ offset : offset at which to write data
*
*/
static ssize_t
2005-10-11 19:29:03 +04:00
v9fs_file_write ( struct file * filp , const char __user * data ,
size_t count , loff_t * offset )
2005-09-10 00:04:18 +04:00
{
2008-10-14 05:36:16 +04:00
int n , rsize , total = 0 ;
2007-07-11 02:57:28 +04:00
struct p9_fid * fid ;
2008-10-14 05:36:16 +04:00
struct p9_client * clnt ;
2007-07-13 22:01:27 +04:00
struct inode * inode = filp - > f_path . dentry - > d_inode ;
2008-10-14 05:36:16 +04:00
int origin = * offset ;
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
2007-07-11 02:57:28 +04:00
fid = filp - > private_data ;
2008-10-14 05:36:16 +04:00
clnt = fid - > clnt ;
rsize = fid - > iounit ;
if ( ! rsize | | rsize > clnt - > msize - P9_IOHDRSZ )
rsize = clnt - > msize - P9_IOHDRSZ ;
do {
if ( count < rsize )
rsize = count ;
n = p9_client_write ( fid , NULL , data + total , * offset + total ,
rsize ) ;
if ( n < = 0 )
break ;
count - = n ;
total + = n ;
} while ( count > 0 ) ;
if ( total > 0 ) {
invalidate_inode_pages2_range ( inode - > i_mapping , origin ,
origin + total ) ;
* offset + = total ;
2007-10-17 23:31:07 +04:00
}
2005-09-10 00:04:18 +04:00
2007-07-13 22:01:27 +04:00
if ( * offset > inode - > i_size ) {
inode - > i_size = * offset ;
inode - > i_blocks = ( inode - > i_size + 512 - 1 ) > > 9 ;
}
2008-10-14 05:36:16 +04:00
if ( n < 0 )
return n ;
return total ;
2005-09-10 00:04:18 +04:00
}
2007-03-05 04:49:48 +03:00
static const struct file_operations v9fs_cached_file_operations = {
2007-02-11 22:21:39 +03:00
. llseek = generic_file_llseek ,
. read = do_sync_read ,
. aio_read = generic_file_aio_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 ,
2007-02-11 22:21:39 +03: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 ,
2005-09-10 00:04:18 +04:00
} ;