2005-09-10 00:04:18 +04:00
/*
* linux / fs / 9 p / vfs_dir . c
*
* This file contains vfs directory ops for the 9 P2000 protocol .
*
* 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>
# include <linux/file.h>
# include <linux/stat.h>
# include <linux/string.h>
# include <linux/smp_lock.h>
# include <linux/inet.h>
# include <linux/idr.h>
# include "debug.h"
# include "v9fs.h"
# include "9p.h"
# include "conv.h"
2006-01-08 12:05:00 +03:00
# include "v9fs_vfs.h"
2005-09-10 00:04:18 +04:00
# include "fid.h"
/**
* dt_type - return file type
* @ mistat : mistat structure
*
*/
static inline int dt_type ( struct v9fs_stat * mistat )
{
unsigned long perm = mistat - > mode ;
int rettype = DT_REG ;
if ( perm & V9FS_DMDIR )
rettype = DT_DIR ;
if ( perm & V9FS_DMSYMLINK )
rettype = DT_LNK ;
return rettype ;
}
/**
* v9fs_dir_readdir - read a directory
* @ filep : opened file structure
* @ dirent : directory structure ? ? ?
* @ filldir : function to populate directory structure ? ? ?
*
*/
static int v9fs_dir_readdir ( struct file * filp , void * dirent , filldir_t filldir )
{
struct v9fs_fcall * fcall = NULL ;
struct inode * inode = filp - > f_dentry - > d_inode ;
struct v9fs_session_info * v9ses = v9fs_inode2v9ses ( inode ) ;
struct v9fs_fid * file = filp - > private_data ;
2006-01-08 12:04:58 +03:00
unsigned int i , n , s ;
2005-09-10 00:04:18 +04:00
int fid = - 1 ;
int ret = 0 ;
2006-01-08 12:05:00 +03:00
struct v9fs_stat stat ;
2005-09-10 00:04:18 +04:00
int over = 0 ;
dprintk ( DEBUG_VFS , " name %s \n " , filp - > f_dentry - > d_name . name ) ;
fid = file - > fid ;
if ( file - > rdir_fcall & & ( filp - > f_pos ! = file - > rdir_pos ) ) {
kfree ( file - > rdir_fcall ) ;
file - > rdir_fcall = NULL ;
}
if ( file - > rdir_fcall ) {
n = file - > rdir_fcall - > params . rread . count ;
i = file - > rdir_fpos ;
while ( i < n ) {
2006-01-08 12:04:58 +03:00
s = v9fs_deserialize_stat (
file - > rdir_fcall - > params . rread . data + i ,
2006-01-08 12:05:00 +03:00
n - i , & stat , v9ses - > extended ) ;
2005-09-10 00:04:18 +04:00
if ( s = = 0 ) {
dprintk ( DEBUG_ERROR ,
2006-01-08 12:05:00 +03:00
" error while deserializing stat \n " ) ;
2005-09-10 00:04:18 +04:00
ret = - EIO ;
goto FreeStructs ;
}
2006-01-08 12:05:00 +03:00
over = filldir ( dirent , stat . name . str , stat . name . len ,
filp - > f_pos , v9fs_qid2ino ( & stat . qid ) ,
dt_type ( & stat ) ) ;
2005-09-10 00:04:18 +04:00
if ( over ) {
file - > rdir_fpos = i ;
file - > rdir_pos = filp - > f_pos ;
break ;
}
i + = s ;
filp - > f_pos + = s ;
}
if ( ! over ) {
kfree ( file - > rdir_fcall ) ;
file - > rdir_fcall = NULL ;
}
}
while ( ! over ) {
ret = v9fs_t_read ( v9ses , fid , filp - > f_pos ,
2006-01-08 12:05:00 +03:00
v9ses - > maxdata - V9FS_IOHDRSZ , & fcall ) ;
2005-09-10 00:04:18 +04:00
if ( ret < 0 ) {
dprintk ( DEBUG_ERROR , " error while reading: %d: %p \n " ,
ret , fcall ) ;
goto FreeStructs ;
} else if ( ret = = 0 )
break ;
n = ret ;
i = 0 ;
while ( i < n ) {
2006-01-08 12:04:58 +03:00
s = v9fs_deserialize_stat ( fcall - > params . rread . data + i ,
2006-01-08 12:05:00 +03:00
n - i , & stat , v9ses - > extended ) ;
2005-09-10 00:04:18 +04:00
if ( s = = 0 ) {
dprintk ( DEBUG_ERROR ,
2006-01-08 12:05:00 +03:00
" error while deserializing stat \n " ) ;
2005-09-10 00:04:18 +04:00
return - EIO ;
}
2006-01-08 12:05:00 +03:00
over = filldir ( dirent , stat . name . str , stat . name . len ,
filp - > f_pos , v9fs_qid2ino ( & stat . qid ) ,
dt_type ( & stat ) ) ;
2005-09-10 00:04:18 +04:00
if ( over ) {
file - > rdir_fcall = fcall ;
file - > rdir_fpos = i ;
file - > rdir_pos = filp - > f_pos ;
fcall = NULL ;
break ;
}
i + = s ;
filp - > f_pos + = s ;
}
kfree ( fcall ) ;
}
FreeStructs :
kfree ( fcall ) ;
return ret ;
}
/**
* v9fs_dir_release - close a directory
* @ inode : inode of the directory
* @ filp : file pointer to a directory
*
*/
int v9fs_dir_release ( struct inode * inode , struct file * filp )
{
struct v9fs_session_info * v9ses = v9fs_inode2v9ses ( inode ) ;
struct v9fs_fid * fid = filp - > private_data ;
int fidnum = - 1 ;
dprintk ( DEBUG_VFS , " inode: %p filp: %p fid: %d \n " , inode , filp ,
fid - > fid ) ;
fidnum = fid - > fid ;
[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 ) ;
2005-09-10 00:04:18 +04:00
if ( fidnum > = 0 ) {
dprintk ( DEBUG_VFS , " fidopen: %d v9f->fid: %d \n " , fid - > fidopen ,
fid - > fid ) ;
2006-01-08 12:04:58 +03:00
if ( v9fs_t_clunk ( v9ses , fidnum ) )
2005-09-28 08:45:24 +04:00
dprintk ( DEBUG_ERROR , " clunk failed \n " ) ;
2005-09-10 00:04:18 +04:00
kfree ( fid - > rdir_fcall ) ;
2005-09-28 08:45:24 +04:00
kfree ( fid ) ;
2005-09-10 00:04:18 +04:00
filp - > private_data = NULL ;
}
return 0 ;
}
struct file_operations v9fs_dir_operations = {
. read = generic_read_dir ,
. readdir = v9fs_dir_readdir ,
. open = v9fs_file_open ,
. release = v9fs_dir_release ,
} ;