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>
2006-10-18 21:55:46 +04:00
# include <linux/sched.h>
2005-09-10 00:04:18 +04:00
# include <linux/inet.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"
2006-01-08 12:05:00 +03:00
# include "v9fs_vfs.h"
2005-09-10 00:04:18 +04:00
# include "fid.h"
2009-11-02 17:39:28 +03:00
/**
* struct p9_rdir - readdir accounting
* @ mutex : mutex protecting readdir
* @ head : start offset of current dirread buffer
* @ tail : end offset of current dirread buffer
* @ buf : dirread buffer
*
* private structure for keeping track of readdir
* allocated on demand
*/
struct p9_rdir {
struct mutex mutex ;
int head ;
int tail ;
uint8_t * buf ;
} ;
2005-09-10 00:04:18 +04:00
/**
* dt_type - return file type
* @ mistat : mistat structure
*
*/
2008-10-16 17:29:30 +04:00
static inline int dt_type ( struct p9_wstat * mistat )
2005-09-10 00:04:18 +04:00
{
unsigned long perm = mistat - > mode ;
int rettype = DT_REG ;
2007-07-11 02:57:28 +04:00
if ( perm & P9_DMDIR )
2005-09-10 00:04:18 +04:00
rettype = DT_DIR ;
2007-07-11 02:57:28 +04:00
if ( perm & P9_DMSYMLINK )
2005-09-10 00:04:18 +04:00
rettype = DT_LNK ;
return rettype ;
}
/**
* v9fs_dir_readdir - read a directory
2008-03-05 16:08:09 +03:00
* @ filp : opened file structure
2005-09-10 00:04:18 +04:00
* @ dirent : directory structure ? ? ?
* @ filldir : function to populate directory structure ? ? ?
*
*/
static int v9fs_dir_readdir ( struct file * filp , void * dirent , filldir_t filldir )
{
2007-07-11 02:57:28 +04:00
int over ;
2008-10-16 17:29:30 +04:00
struct p9_wstat st ;
2009-11-02 17:39:28 +03:00
int err = 0 ;
2007-07-11 02:57:28 +04:00
struct p9_fid * fid ;
2008-10-14 05:36:15 +04:00
int buflen ;
2009-11-02 17:39:28 +03:00
int reclen = 0 ;
struct p9_rdir * rdir ;
2007-07-11 02:57:28 +04:00
P9_DPRINTK ( P9_DEBUG_VFS , " name %s \n " , filp - > f_path . dentry - > d_name . name ) ;
fid = filp - > private_data ;
2008-10-14 05:36:15 +04:00
buflen = fid - > clnt - > msize - P9_IOHDRSZ ;
2009-11-02 17:39:28 +03:00
/* allocate rdir on demand */
if ( ! fid - > rdir ) {
rdir = kmalloc ( sizeof ( struct p9_rdir ) + buflen , GFP_KERNEL ) ;
if ( rdir = = NULL ) {
err = - ENOMEM ;
goto exit ;
}
spin_lock ( & filp - > f_dentry - > d_lock ) ;
if ( ! fid - > rdir ) {
rdir - > buf = ( uint8_t * ) rdir + sizeof ( struct p9_rdir ) ;
mutex_init ( & rdir - > mutex ) ;
rdir - > head = rdir - > tail = 0 ;
fid - > rdir = ( void * ) rdir ;
rdir = NULL ;
}
spin_unlock ( & filp - > f_dentry - > d_lock ) ;
kfree ( rdir ) ;
}
rdir = ( struct p9_rdir * ) fid - > rdir ;
err = mutex_lock_interruptible ( & rdir - > mutex ) ;
while ( err = = 0 ) {
if ( rdir - > tail = = rdir - > head ) {
err = v9fs_file_readn ( filp , rdir - > buf , NULL ,
buflen , filp - > f_pos ) ;
if ( err < = 0 )
goto unlock_and_exit ;
rdir - > head = 0 ;
rdir - > tail = err ;
}
while ( rdir - > head < rdir - > tail ) {
err = p9stat_read ( rdir - > buf + rdir - > head ,
buflen - rdir - > head , & st ,
2010-03-05 21:50:14 +03:00
fid - > clnt - > proto_version ) ;
2008-10-16 17:29:30 +04:00
if ( err ) {
P9_DPRINTK ( P9_DEBUG_VFS , " returned %d \n " , err ) ;
2008-10-14 05:36:15 +04:00
err = - EIO ;
2008-10-16 17:29:30 +04:00
p9stat_free ( & st ) ;
2009-11-02 17:39:28 +03:00
goto unlock_and_exit ;
2008-10-14 05:36:15 +04:00
}
2009-11-02 17:39:28 +03:00
reclen = st . size + 2 ;
2008-10-14 05:36:15 +04:00
2008-10-16 17:29:30 +04:00
over = filldir ( dirent , st . name , strlen ( st . name ) ,
2008-10-14 05:36:15 +04:00
filp - > f_pos , v9fs_qid2ino ( & st . qid ) , dt_type ( & st ) ) ;
2008-10-16 17:29:30 +04:00
p9stat_free ( & st ) ;
2008-10-14 05:36:15 +04:00
if ( over ) {
err = 0 ;
2009-11-02 17:39:28 +03:00
goto unlock_and_exit ;
2008-10-14 05:36:15 +04:00
}
2009-11-02 17:39:28 +03:00
rdir - > head + = reclen ;
filp - > f_pos + = reclen ;
2008-10-14 05:36:15 +04:00
}
2005-09-10 00:04:18 +04:00
}
2009-11-02 17:39:28 +03:00
unlock_and_exit :
mutex_unlock ( & rdir - > mutex ) ;
exit :
2008-10-14 05:36:15 +04:00
return err ;
2005-09-10 00:04:18 +04:00
}
2007-07-11 02:57:28 +04:00
2005-09-10 00:04:18 +04:00
/**
* 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 )
{
2007-07-11 02:57:28 +04:00
struct p9_fid * fid ;
2005-09-10 00:04:18 +04:00
2007-07-11 02:57:28 +04:00
fid = filp - > private_data ;
P9_DPRINTK ( P9_DEBUG_VFS ,
" inode: %p filp: %p fid: %d \n " , inode , filp , 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 ) ;
2007-07-11 02:57:28 +04:00
p9_client_clunk ( fid ) ;
2005-09-10 00:04:18 +04:00
return 0 ;
}
2006-03-28 13:56:42 +04:00
const struct file_operations v9fs_dir_operations = {
2005-09-10 00:04:18 +04:00
. read = generic_read_dir ,
2008-08-24 15:24:41 +04:00
. llseek = generic_file_llseek ,
2005-09-10 00:04:18 +04:00
. readdir = v9fs_dir_readdir ,
. open = v9fs_file_open ,
. release = v9fs_dir_release ,
} ;