2005-04-17 02:20:36 +04:00
/*
* Mostly platform independent upcall operations to Venus :
* - - upcalls
* - - upcall routines
*
* Linux 2.0 version
* Copyright ( C ) 1996 Peter J . Braam < braam @ maths . ox . ac . uk > ,
* Michael Callahan < callahan @ maths . ox . ac . uk >
*
* Redone for Linux 2.1
* Copyright ( C ) 1997 Carnegie Mellon University
*
* Carnegie Mellon University encourages users of this code to contribute
* improvements to the Coda project . Contact Peter Braam < coda @ cs . cmu . edu > .
*/
# include <asm/system.h>
# include <linux/signal.h>
Detach sched.h from mm.h
First thing mm.h does is including sched.h solely for can_do_mlock() inline
function which has "current" dereference inside. By dealing with can_do_mlock()
mm.h can be detached from sched.h which is good. See below, why.
This patch
a) removes unconditional inclusion of sched.h from mm.h
b) makes can_do_mlock() normal function in mm/mlock.c
c) exports can_do_mlock() to not break compilation
d) adds sched.h inclusions back to files that were getting it indirectly.
e) adds less bloated headers to some files (asm/signal.h, jiffies.h) that were
getting them indirectly
Net result is:
a) mm.h users would get less code to open, read, preprocess, parse, ... if
they don't need sched.h
b) sched.h stops being dependency for significant number of files:
on x86_64 allmodconfig touching sched.h results in recompile of 4083 files,
after patch it's only 3744 (-8.3%).
Cross-compile tested on
all arm defconfigs, all mips defconfigs, all powerpc defconfigs,
alpha alpha-up
arm
i386 i386-up i386-defconfig i386-allnoconfig
ia64 ia64-up
m68k
mips
parisc parisc-up
powerpc powerpc-up
s390 s390-up
sparc sparc-up
sparc64 sparc64-up
um-x86_64
x86_64 x86_64-up x86_64-defconfig x86_64-allnoconfig
as well as my two usual configs.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-21 01:22:52 +04:00
# include <linux/sched.h>
2005-04-17 02:20:36 +04:00
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/time.h>
# include <linux/fs.h>
# include <linux/file.h>
# include <linux/stat.h>
# include <linux/errno.h>
# include <linux/string.h>
# include <asm/uaccess.h>
# include <linux/vmalloc.h>
# include <linux/vfs.h>
# include <linux/coda.h>
# include <linux/coda_linux.h>
# include <linux/coda_psdev.h>
# include <linux/coda_fs_i.h>
# include <linux/coda_cache.h>
2007-07-19 12:48:51 +04:00
# include "coda_int.h"
2005-04-17 02:20:36 +04:00
2007-07-19 12:48:50 +04:00
static int coda_upcall ( struct venus_comm * vc , int inSize , int * outSize ,
2005-04-17 02:20:36 +04:00
union inputArgs * buffer ) ;
static void * alloc_upcall ( int opcode , int size )
{
union inputArgs * inp ;
CODA_ALLOC ( inp , union inputArgs * , size ) ;
if ( ! inp )
return ERR_PTR ( - ENOMEM ) ;
inp - > ih . opcode = opcode ;
inp - > ih . pid = current - > pid ;
2007-10-19 10:39:46 +04:00
inp - > ih . pgid = task_pgrp_nr ( current ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_CODA_FS_OLD_API
memset ( & inp - > ih . cred , 0 , sizeof ( struct coda_cred ) ) ;
inp - > ih . cred . cr_fsuid = current - > fsuid ;
# else
inp - > ih . uid = current - > fsuid ;
# endif
return ( void * ) inp ;
}
# define UPARG(op)\
do { \
inp = ( union inputArgs * ) alloc_upcall ( op , insize ) ; \
if ( IS_ERR ( inp ) ) { return PTR_ERR ( inp ) ; } \
outp = ( union outputArgs * ) ( inp ) ; \
outsize = insize ; \
} while ( 0 )
# define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
# define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
# define SIZE(tag) max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
/* the upcalls */
int venus_rootfid ( struct super_block * sb , struct CodaFid * fidp )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
insize = SIZE ( root ) ;
UPARG ( CODA_ROOT ) ;
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2007-07-19 12:48:48 +04:00
if ( ! error )
2005-04-17 02:20:36 +04:00
* fidp = outp - > coda_root . VFid ;
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_getattr ( struct super_block * sb , struct CodaFid * fid ,
struct coda_vattr * attr )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
insize = SIZE ( getattr ) ;
UPARG ( CODA_GETATTR ) ;
inp - > coda_getattr . VFid = * fid ;
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2007-07-19 12:48:48 +04:00
if ( ! error )
* attr = outp - > coda_getattr . attr ;
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_setattr ( struct super_block * sb , struct CodaFid * fid ,
struct coda_vattr * vattr )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
insize = SIZE ( setattr ) ;
UPARG ( CODA_SETATTR ) ;
inp - > coda_setattr . VFid = * fid ;
inp - > coda_setattr . attr = * vattr ;
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_lookup ( struct super_block * sb , struct CodaFid * fid ,
const char * name , int length , int * type ,
struct CodaFid * resfid )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
int offset ;
offset = INSIZE ( lookup ) ;
insize = max_t ( unsigned int , offset + length + 1 , OUTSIZE ( lookup ) ) ;
UPARG ( CODA_LOOKUP ) ;
inp - > coda_lookup . VFid = * fid ;
inp - > coda_lookup . name = offset ;
inp - > coda_lookup . flags = CLU_CASE_SENSITIVE ;
/* send Venus a null terminated string */
memcpy ( ( char * ) ( inp ) + offset , name , length ) ;
* ( ( char * ) inp + offset + length ) = ' \0 ' ;
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2007-07-19 12:48:48 +04:00
if ( ! error ) {
* resfid = outp - > coda_lookup . VFid ;
* type = outp - > coda_lookup . vtype ;
}
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_close ( struct super_block * sb , struct CodaFid * fid , int flags ,
2007-07-21 15:37:26 +04:00
vuid_t uid )
2005-04-17 02:20:36 +04:00
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
# ifdef CONFIG_CODA_FS_OLD_API
struct coda_cred cred = { 0 , } ;
cred . cr_fsuid = uid ;
# endif
insize = SIZE ( release ) ;
UPARG ( CODA_CLOSE ) ;
# ifdef CONFIG_CODA_FS_OLD_API
memcpy ( & ( inp - > ih . cred ) , & cred , sizeof ( cred ) ) ;
# else
inp - > ih . uid = uid ;
# endif
inp - > coda_close . VFid = * fid ;
inp - > coda_close . flags = flags ;
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_open ( struct super_block * sb , struct CodaFid * fid ,
int flags , struct file * * fh )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
insize = SIZE ( open_by_fd ) ;
UPARG ( CODA_OPEN_BY_FD ) ;
2007-07-19 12:48:41 +04:00
inp - > coda_open_by_fd . VFid = * fid ;
inp - > coda_open_by_fd . flags = flags ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2007-07-19 12:48:41 +04:00
if ( ! error )
* fh = outp - > coda_open_by_fd . fh ;
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_mkdir ( struct super_block * sb , struct CodaFid * dirfid ,
const char * name , int length ,
struct CodaFid * newfid , struct coda_vattr * attrs )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
int offset ;
offset = INSIZE ( mkdir ) ;
insize = max_t ( unsigned int , offset + length + 1 , OUTSIZE ( mkdir ) ) ;
UPARG ( CODA_MKDIR ) ;
inp - > coda_mkdir . VFid = * dirfid ;
inp - > coda_mkdir . attr = * attrs ;
inp - > coda_mkdir . name = offset ;
/* Venus must get null terminated string */
memcpy ( ( char * ) ( inp ) + offset , name , length ) ;
* ( ( char * ) inp + offset + length ) = ' \0 ' ;
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2007-07-19 12:48:48 +04:00
if ( ! error ) {
* attrs = outp - > coda_mkdir . attr ;
* newfid = outp - > coda_mkdir . VFid ;
}
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_rename ( struct super_block * sb , struct CodaFid * old_fid ,
struct CodaFid * new_fid , size_t old_length ,
size_t new_length , const char * old_name ,
const char * new_name )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
int offset , s ;
offset = INSIZE ( rename ) ;
insize = max_t ( unsigned int , offset + new_length + old_length + 8 ,
OUTSIZE ( rename ) ) ;
UPARG ( CODA_RENAME ) ;
inp - > coda_rename . sourceFid = * old_fid ;
inp - > coda_rename . destFid = * new_fid ;
inp - > coda_rename . srcname = offset ;
/* Venus must receive an null terminated string */
s = ( old_length & ~ 0x3 ) + 4 ; /* round up to word boundary */
memcpy ( ( char * ) ( inp ) + offset , old_name , old_length ) ;
* ( ( char * ) inp + offset + old_length ) = ' \0 ' ;
/* another null terminated string for Venus */
offset + = s ;
inp - > coda_rename . destname = offset ;
s = ( new_length & ~ 0x3 ) + 4 ; /* round up to word boundary */
memcpy ( ( char * ) ( inp ) + offset , new_name , new_length ) ;
* ( ( char * ) inp + offset + new_length ) = ' \0 ' ;
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_create ( struct super_block * sb , struct CodaFid * dirfid ,
const char * name , int length , int excl , int mode ,
struct CodaFid * newfid , struct coda_vattr * attrs )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
int offset ;
offset = INSIZE ( create ) ;
insize = max_t ( unsigned int , offset + length + 1 , OUTSIZE ( create ) ) ;
UPARG ( CODA_CREATE ) ;
inp - > coda_create . VFid = * dirfid ;
inp - > coda_create . attr . va_mode = mode ;
inp - > coda_create . excl = excl ;
inp - > coda_create . mode = mode ;
inp - > coda_create . name = offset ;
/* Venus must get null terminated string */
memcpy ( ( char * ) ( inp ) + offset , name , length ) ;
* ( ( char * ) inp + offset + length ) = ' \0 ' ;
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2007-07-19 12:48:48 +04:00
if ( ! error ) {
* attrs = outp - > coda_create . attr ;
* newfid = outp - > coda_create . VFid ;
}
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_rmdir ( struct super_block * sb , struct CodaFid * dirfid ,
const char * name , int length )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
int offset ;
offset = INSIZE ( rmdir ) ;
insize = max_t ( unsigned int , offset + length + 1 , OUTSIZE ( rmdir ) ) ;
UPARG ( CODA_RMDIR ) ;
inp - > coda_rmdir . VFid = * dirfid ;
inp - > coda_rmdir . name = offset ;
memcpy ( ( char * ) ( inp ) + offset , name , length ) ;
* ( ( char * ) inp + offset + length ) = ' \0 ' ;
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_remove ( struct super_block * sb , struct CodaFid * dirfid ,
const char * name , int length )
{
union inputArgs * inp ;
union outputArgs * outp ;
int error = 0 , insize , outsize , offset ;
offset = INSIZE ( remove ) ;
insize = max_t ( unsigned int , offset + length + 1 , OUTSIZE ( remove ) ) ;
UPARG ( CODA_REMOVE ) ;
inp - > coda_remove . VFid = * dirfid ;
inp - > coda_remove . name = offset ;
memcpy ( ( char * ) ( inp ) + offset , name , length ) ;
* ( ( char * ) inp + offset + length ) = ' \0 ' ;
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_readlink ( struct super_block * sb , struct CodaFid * fid ,
char * buffer , int * length )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
int retlen ;
char * result ;
insize = max_t ( unsigned int ,
INSIZE ( readlink ) , OUTSIZE ( readlink ) + * length + 1 ) ;
UPARG ( CODA_READLINK ) ;
inp - > coda_readlink . VFid = * fid ;
2007-07-19 12:48:48 +04:00
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2007-07-19 12:48:48 +04:00
if ( ! error ) {
retlen = outp - > coda_readlink . count ;
2005-04-17 02:20:36 +04:00
if ( retlen > * length )
2007-07-19 12:48:48 +04:00
retlen = * length ;
2005-04-17 02:20:36 +04:00
* length = retlen ;
result = ( char * ) outp + ( long ) outp - > coda_readlink . data ;
memcpy ( buffer , result , retlen ) ;
* ( buffer + retlen ) = ' \0 ' ;
}
2007-07-19 12:48:48 +04:00
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_link ( struct super_block * sb , struct CodaFid * fid ,
struct CodaFid * dirfid , const char * name , int len )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
int offset ;
offset = INSIZE ( link ) ;
insize = max_t ( unsigned int , offset + len + 1 , OUTSIZE ( link ) ) ;
UPARG ( CODA_LINK ) ;
inp - > coda_link . sourceFid = * fid ;
inp - > coda_link . destFid = * dirfid ;
inp - > coda_link . tname = offset ;
/* make sure strings are null terminated */
memcpy ( ( char * ) ( inp ) + offset , name , len ) ;
* ( ( char * ) inp + offset + len ) = ' \0 ' ;
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_symlink ( struct super_block * sb , struct CodaFid * fid ,
const char * name , int len ,
const char * symname , int symlen )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
int offset , s ;
offset = INSIZE ( symlink ) ;
insize = max_t ( unsigned int , offset + len + symlen + 8 , OUTSIZE ( symlink ) ) ;
UPARG ( CODA_SYMLINK ) ;
/* inp->coda_symlink.attr = *tva; XXXXXX */
inp - > coda_symlink . VFid = * fid ;
/* Round up to word boundary and null terminate */
inp - > coda_symlink . srcname = offset ;
s = ( symlen & ~ 0x3 ) + 4 ;
memcpy ( ( char * ) ( inp ) + offset , symname , symlen ) ;
* ( ( char * ) inp + offset + symlen ) = ' \0 ' ;
/* Round up to word boundary and null terminate */
offset + = s ;
inp - > coda_symlink . tname = offset ;
s = ( len & ~ 0x3 ) + 4 ;
memcpy ( ( char * ) ( inp ) + offset , name , len ) ;
* ( ( char * ) inp + offset + len ) = ' \0 ' ;
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_fsync ( struct super_block * sb , struct CodaFid * fid )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
insize = SIZE ( fsync ) ;
UPARG ( CODA_FSYNC ) ;
2007-07-19 12:48:50 +04:00
inp - > coda_fsync . VFid = * fid ;
error = coda_upcall ( coda_vcp ( sb ) , sizeof ( union inputArgs ) ,
& outsize , inp ) ;
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_access ( struct super_block * sb , struct CodaFid * fid , int mask )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
insize = SIZE ( access ) ;
UPARG ( CODA_ACCESS ) ;
inp - > coda_access . VFid = * fid ;
inp - > coda_access . flags = mask ;
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , insize , & outsize , inp ) ;
2005-04-17 02:20:36 +04:00
CODA_FREE ( inp , insize ) ;
return error ;
}
int venus_pioctl ( struct super_block * sb , struct CodaFid * fid ,
unsigned int cmd , struct PioctlData * data )
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
int iocsize ;
insize = VC_MAXMSGSIZE ;
UPARG ( CODA_IOCTL ) ;
/* build packet for Venus */
if ( data - > vi . in_size > VC_MAXDATASIZE ) {
error = - EINVAL ;
goto exit ;
}
if ( data - > vi . out_size > VC_MAXDATASIZE ) {
error = - EINVAL ;
goto exit ;
}
inp - > coda_ioctl . VFid = * fid ;
/* the cmd field was mutated by increasing its size field to
* reflect the path and follow args . We need to subtract that
* out before sending the command to Venus . */
inp - > coda_ioctl . cmd = ( cmd & ~ ( PIOCPARM_MASK < < 16 ) ) ;
iocsize = ( ( cmd > > 16 ) & PIOCPARM_MASK ) - sizeof ( char * ) - sizeof ( int ) ;
inp - > coda_ioctl . cmd | = ( iocsize & PIOCPARM_MASK ) < < 16 ;
/* in->coda_ioctl.rwflag = flag; */
inp - > coda_ioctl . len = data - > vi . in_size ;
inp - > coda_ioctl . data = ( char * ) ( INSIZE ( ioctl ) ) ;
/* get the data out of user space */
if ( copy_from_user ( ( char * ) inp + ( long ) inp - > coda_ioctl . data ,
data - > vi . in , data - > vi . in_size ) ) {
error = - EINVAL ;
goto exit ;
}
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( sb ) , SIZE ( ioctl ) + data - > vi . in_size ,
& outsize , inp ) ;
2005-04-17 02:20:36 +04:00
if ( error ) {
printk ( " coda_pioctl: Venus returns: %d for %s \n " ,
error , coda_f2s ( fid ) ) ;
goto exit ;
}
if ( outsize < ( long ) outp - > coda_ioctl . data + outp - > coda_ioctl . len ) {
error = - EINVAL ;
goto exit ;
}
/* Copy out the OUT buffer. */
if ( outp - > coda_ioctl . len > data - > vi . out_size ) {
error = - EINVAL ;
goto exit ;
}
/* Copy out the OUT buffer. */
if ( copy_to_user ( data - > vi . out ,
( char * ) outp + ( long ) outp - > coda_ioctl . data ,
outp - > coda_ioctl . len ) ) {
error = - EFAULT ;
goto exit ;
}
exit :
CODA_FREE ( inp , insize ) ;
return error ;
}
2006-06-23 13:02:58 +04:00
int venus_statfs ( struct dentry * dentry , struct kstatfs * sfs )
2005-04-17 02:20:36 +04:00
{
union inputArgs * inp ;
union outputArgs * outp ;
int insize , outsize , error ;
insize = max_t ( unsigned int , INSIZE ( statfs ) , OUTSIZE ( statfs ) ) ;
UPARG ( CODA_STATFS ) ;
2007-07-19 12:48:50 +04:00
error = coda_upcall ( coda_vcp ( dentry - > d_sb ) , insize , & outsize , inp ) ;
2007-07-19 12:48:48 +04:00
if ( ! error ) {
2005-04-17 02:20:36 +04:00
sfs - > f_blocks = outp - > coda_statfs . stat . f_blocks ;
sfs - > f_bfree = outp - > coda_statfs . stat . f_bfree ;
sfs - > f_bavail = outp - > coda_statfs . stat . f_bavail ;
sfs - > f_files = outp - > coda_statfs . stat . f_files ;
sfs - > f_ffree = outp - > coda_statfs . stat . f_ffree ;
}
CODA_FREE ( inp , insize ) ;
return error ;
}
/*
* coda_upcall and coda_downcall routines .
*/
2007-07-20 03:23:31 +04:00
static void coda_block_signals ( sigset_t * old )
2007-07-19 12:48:46 +04:00
{
spin_lock_irq ( & current - > sighand - > siglock ) ;
* old = current - > blocked ;
sigfillset ( & current - > blocked ) ;
sigdelset ( & current - > blocked , SIGKILL ) ;
sigdelset ( & current - > blocked , SIGSTOP ) ;
sigdelset ( & current - > blocked , SIGINT ) ;
recalc_sigpending ( ) ;
spin_unlock_irq ( & current - > sighand - > siglock ) ;
}
2007-07-20 03:23:31 +04:00
static void coda_unblock_signals ( sigset_t * old )
2007-07-19 12:48:46 +04:00
{
spin_lock_irq ( & current - > sighand - > siglock ) ;
current - > blocked = * old ;
recalc_sigpending ( ) ;
spin_unlock_irq ( & current - > sighand - > siglock ) ;
}
/* Don't allow signals to interrupt the following upcalls before venus
* has seen them ,
* - CODA_CLOSE or CODA_RELEASE upcall ( to avoid reference count problems )
* - CODA_STORE ( to avoid data loss )
*/
# define CODA_INTERRUPTIBLE(r) (!coda_hard && \
( ( ( r ) - > uc_opcode ! = CODA_CLOSE & & \
( r ) - > uc_opcode ! = CODA_STORE & & \
( r ) - > uc_opcode ! = CODA_RELEASE ) | | \
( r ) - > uc_flags & REQ_READ ) )
2005-04-17 02:20:36 +04:00
2007-07-19 12:48:46 +04:00
static inline void coda_waitfor_upcall ( struct upc_req * req )
2005-04-17 02:20:36 +04:00
{
DECLARE_WAITQUEUE ( wait , current ) ;
2007-07-19 12:48:46 +04:00
unsigned long timeout = jiffies + coda_timeout * HZ ;
sigset_t old ;
int blocked ;
2005-04-17 02:20:36 +04:00
2007-07-20 03:23:31 +04:00
coda_block_signals ( & old ) ;
2007-07-19 12:48:46 +04:00
blocked = 1 ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:48:46 +04:00
add_wait_queue ( & req - > uc_sleep , & wait ) ;
2005-04-17 02:20:36 +04:00
for ( ; ; ) {
2007-07-19 12:48:46 +04:00
if ( CODA_INTERRUPTIBLE ( req ) )
2005-04-17 02:20:36 +04:00
set_current_state ( TASK_INTERRUPTIBLE ) ;
else
set_current_state ( TASK_UNINTERRUPTIBLE ) ;
/* got a reply */
2007-07-19 12:48:46 +04:00
if ( req - > uc_flags & ( REQ_WRITE | REQ_ABORT ) )
2005-04-17 02:20:36 +04:00
break ;
2007-07-19 12:48:46 +04:00
if ( blocked & & time_after ( jiffies , timeout ) & &
CODA_INTERRUPTIBLE ( req ) )
{
2007-07-20 03:23:31 +04:00
coda_unblock_signals ( & old ) ;
2007-07-19 12:48:46 +04:00
blocked = 0 ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:48:46 +04:00
if ( signal_pending ( current ) ) {
list_del ( & req - > uc_chain ) ;
break ;
}
if ( blocked )
schedule_timeout ( HZ ) ;
else
schedule ( ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:48:46 +04:00
if ( blocked )
2007-07-20 03:23:31 +04:00
coda_unblock_signals ( & old ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:48:46 +04:00
remove_wait_queue ( & req - > uc_sleep , & wait ) ;
set_current_state ( TASK_RUNNING ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:48:50 +04:00
/*
* coda_upcall will return an error in the case of
2005-04-17 02:20:36 +04:00
* failed communication with Venus _or_ will peek at Venus
* reply and return Venus ' error .
*
* As venus has 2 types of errors , normal errors ( positive ) and internal
* errors ( negative ) , normal errors are negated , while internal errors
* are all mapped to - EINTR , while showing a nice warning message . ( jh )
*/
2007-07-19 12:48:50 +04:00
static int coda_upcall ( struct venus_comm * vcp ,
2007-07-19 12:48:46 +04:00
int inSize , int * outSize ,
union inputArgs * buffer )
2005-04-17 02:20:36 +04:00
{
union outputArgs * out ;
2007-07-19 12:48:46 +04:00
union inputArgs * sig_inputArgs ;
struct upc_req * req , * sig_req ;
2005-04-17 02:20:36 +04:00
int error = 0 ;
2007-07-19 12:48:50 +04:00
if ( ! vcp - > vc_inuse ) {
2007-07-19 12:48:46 +04:00
printk ( KERN_NOTICE " coda: Venus dead, not sending upcall \n " ) ;
return - ENXIO ;
2005-04-17 02:20:36 +04:00
}
/* Format the request message. */
2007-07-19 12:48:48 +04:00
req = kmalloc ( sizeof ( struct upc_req ) , GFP_KERNEL ) ;
2007-07-19 12:48:46 +04:00
if ( ! req )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2007-07-19 12:48:46 +04:00
2005-04-17 02:20:36 +04:00
req - > uc_data = ( void * ) buffer ;
req - > uc_flags = 0 ;
req - > uc_inSize = inSize ;
req - > uc_outSize = * outSize ? * outSize : inSize ;
req - > uc_opcode = ( ( union inputArgs * ) buffer ) - > ih . opcode ;
2007-07-19 12:48:50 +04:00
req - > uc_unique = + + vcp - > vc_seq ;
2005-04-17 02:20:36 +04:00
init_waitqueue_head ( & req - > uc_sleep ) ;
2007-07-19 12:48:46 +04:00
2005-04-17 02:20:36 +04:00
/* Fill in the common input args. */
( ( union inputArgs * ) buffer ) - > ih . unique = req - > uc_unique ;
/* Append msg to pending queue and poke Venus. */
2007-07-19 12:48:50 +04:00
list_add_tail ( & req - > uc_chain , & vcp - > vc_pending ) ;
2007-07-19 12:48:46 +04:00
2007-07-19 12:48:50 +04:00
wake_up_interruptible ( & vcp - > vc_waitq ) ;
2005-04-17 02:20:36 +04:00
/* We can be interrupted while we wait for Venus to process
* our request . If the interrupt occurs before Venus has read
* the request , we dequeue and return . If it occurs after the
* read but before the reply , we dequeue , send a signal
* message , and return . If it occurs after the reply we ignore
* it . In no case do we want to restart the syscall . If it
* was interrupted by a venus shutdown ( psdev_close ) , return
* ENODEV . */
/* Go to sleep. Wake up on signals only after the timeout. */
2007-07-19 12:48:45 +04:00
coda_waitfor_upcall ( req ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:48:46 +04:00
/* Op went through, interrupt or not... */
if ( req - > uc_flags & REQ_WRITE ) {
2005-04-17 02:20:36 +04:00
out = ( union outputArgs * ) req - > uc_data ;
/* here we map positive Venus errors to kernel errors */
error = - out - > oh . result ;
* outSize = req - > uc_outSize ;
goto exit ;
2007-07-19 12:48:46 +04:00
}
error = - EINTR ;
if ( ( req - > uc_flags & REQ_ABORT ) | | ! signal_pending ( current ) ) {
printk ( KERN_WARNING " coda: Unexpected interruption. \n " ) ;
2005-04-17 02:20:36 +04:00
goto exit ;
}
2007-07-19 12:48:46 +04:00
/* Interrupted before venus read it. */
if ( ! ( req - > uc_flags & REQ_READ ) )
goto exit ;
/* Venus saw the upcall, make sure we can send interrupt signal */
2007-07-19 12:48:50 +04:00
if ( ! vcp - > vc_inuse ) {
2007-07-19 12:48:46 +04:00
printk ( KERN_INFO " coda: Venus dead, not sending signal. \n " ) ;
goto exit ;
}
error = - ENOMEM ;
2007-07-19 12:48:48 +04:00
sig_req = kmalloc ( sizeof ( struct upc_req ) , GFP_KERNEL ) ;
2007-07-19 12:48:46 +04:00
if ( ! sig_req ) goto exit ;
CODA_ALLOC ( ( sig_req - > uc_data ) , char * , sizeof ( struct coda_in_hdr ) ) ;
if ( ! sig_req - > uc_data ) {
2007-07-19 12:48:48 +04:00
kfree ( sig_req ) ;
2007-07-19 12:48:46 +04:00
goto exit ;
}
error = - EINTR ;
sig_inputArgs = ( union inputArgs * ) sig_req - > uc_data ;
sig_inputArgs - > ih . opcode = CODA_SIGNAL ;
sig_inputArgs - > ih . unique = req - > uc_unique ;
sig_req - > uc_flags = REQ_ASYNC ;
sig_req - > uc_opcode = sig_inputArgs - > ih . opcode ;
sig_req - > uc_unique = sig_inputArgs - > ih . unique ;
sig_req - > uc_inSize = sizeof ( struct coda_in_hdr ) ;
sig_req - > uc_outSize = sizeof ( struct coda_in_hdr ) ;
/* insert at head of queue! */
2007-07-19 12:48:50 +04:00
list_add ( & ( sig_req - > uc_chain ) , & vcp - > vc_pending ) ;
wake_up_interruptible ( & vcp - > vc_waitq ) ;
2007-07-19 12:48:46 +04:00
exit :
2007-07-19 12:48:48 +04:00
kfree ( req ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
/*
The statements below are part of the Coda opportunistic
programming - - taken from the Mach / BSD kernel code for Coda .
You don ' t get correct semantics by stating what needs to be
done without guaranteeing the invariants needed for it to happen .
When will be have time to find out what exactly is going on ? ( pjb )
*/
/*
* There are 7 cases where cache invalidations occur . The semantics
* of each is listed here :
*
* CODA_FLUSH - - flush all entries from the name cache and the cnode cache .
* CODA_PURGEUSER - - flush all entries from the name cache for a specific user
* This call is a result of token expiration .
*
* The next arise as the result of callbacks on a file or directory .
* CODA_ZAPFILE - - flush the cached attributes for a file .
* CODA_ZAPDIR - - flush the attributes for the dir and
* force a new lookup for all the children
of this dir .
*
* The next is a result of Venus detecting an inconsistent file .
* CODA_PURGEFID - - flush the attribute for the file
* purge it and its children from the dcache
*
* The last allows Venus to replace local fids with global ones
* during reintegration .
*
* CODA_REPLACE - - replace one CodaFid with another throughout the name cache */
int coda_downcall ( int opcode , union outputArgs * out , struct super_block * sb )
{
2007-07-19 12:48:49 +04:00
struct inode * inode = NULL ;
struct CodaFid * fid , * newfid ;
2005-04-17 02:20:36 +04:00
/* Handle invalidation requests. */
2007-07-19 12:48:49 +04:00
if ( ! sb | | ! sb - > s_root )
return 0 ;
switch ( opcode ) {
case CODA_FLUSH :
coda_cache_clear_all ( sb ) ;
shrink_dcache_sb ( sb ) ;
if ( sb - > s_root - > d_inode )
coda_flag_inode ( sb - > s_root - > d_inode , C_FLUSH ) ;
break ;
case CODA_PURGEUSER :
coda_cache_clear_all ( sb ) ;
break ;
case CODA_ZAPDIR :
fid = & out - > coda_zapdir . CodaFid ;
inode = coda_fid_to_inode ( fid , sb ) ;
if ( inode ) {
coda_flag_inode_children ( inode , C_PURGE ) ;
coda_flag_inode ( inode , C_VATTR ) ;
}
break ;
case CODA_ZAPFILE :
fid = & out - > coda_zapfile . CodaFid ;
inode = coda_fid_to_inode ( fid , sb ) ;
if ( inode )
coda_flag_inode ( inode , C_VATTR ) ;
break ;
case CODA_PURGEFID :
fid = & out - > coda_purgefid . CodaFid ;
inode = coda_fid_to_inode ( fid , sb ) ;
if ( inode ) {
2005-04-17 02:20:36 +04:00
coda_flag_inode_children ( inode , C_PURGE ) ;
/* catch the dentries later if some are still busy */
coda_flag_inode ( inode , C_PURGE ) ;
d_prune_aliases ( inode ) ;
2007-07-19 12:48:49 +04:00
}
break ;
case CODA_REPLACE :
fid = & out - > coda_replace . OldFid ;
newfid = & out - > coda_replace . NewFid ;
inode = coda_fid_to_inode ( fid , sb ) ;
if ( inode )
coda_replace_fid ( inode , fid , newfid ) ;
break ;
}
if ( inode )
iput ( inode ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}