2005-04-17 02:20:36 +04:00
/* cnode related routines for the coda kernel code
( C ) 1996 Peter Braam
*/
# include <linux/types.h>
# include <linux/string.h>
# include <linux/time.h>
# include <linux/coda.h>
# include <linux/coda_psdev.h>
2011-01-13 00:36:09 +03:00
# include "coda_linux.h"
2005-04-17 02:20:36 +04:00
static inline int coda_fideq ( struct CodaFid * fid1 , struct CodaFid * fid2 )
{
return memcmp ( fid1 , fid2 , sizeof ( * fid1 ) ) = = 0 ;
}
2007-02-12 11:55:38 +03:00
static const struct inode_operations coda_symlink_inode_operations = {
2005-04-17 02:20:36 +04:00
. readlink = generic_readlink ,
. follow_link = page_follow_link_light ,
. put_link = page_put_link ,
. setattr = coda_setattr ,
} ;
/* cnode.c */
static void coda_fill_inode ( struct inode * inode , struct coda_vattr * attr )
{
coda_vattr_to_iattr ( inode , attr ) ;
if ( S_ISREG ( inode - > i_mode ) ) {
inode - > i_op = & coda_file_inode_operations ;
inode - > i_fop = & coda_file_operations ;
} else if ( S_ISDIR ( inode - > i_mode ) ) {
inode - > i_op = & coda_dir_inode_operations ;
inode - > i_fop = & coda_dir_operations ;
} else if ( S_ISLNK ( inode - > i_mode ) ) {
inode - > i_op = & coda_symlink_inode_operations ;
inode - > i_data . a_ops = & coda_symlink_aops ;
inode - > i_mapping = & inode - > i_data ;
} else
init_special_inode ( inode , inode - > i_mode , huge_decode_dev ( attr - > va_rdev ) ) ;
}
static int coda_test_inode ( struct inode * inode , void * data )
{
struct CodaFid * fid = ( struct CodaFid * ) data ;
2010-10-25 10:03:44 +04:00
struct coda_inode_info * cii = ITOC ( inode ) ;
return coda_fideq ( & cii - > c_fid , fid ) ;
2005-04-17 02:20:36 +04:00
}
static int coda_set_inode ( struct inode * inode , void * data )
{
struct CodaFid * fid = ( struct CodaFid * ) data ;
2010-10-25 10:03:44 +04:00
struct coda_inode_info * cii = ITOC ( inode ) ;
cii - > c_fid = * fid ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
struct inode * coda_iget ( struct super_block * sb , struct CodaFid * fid ,
struct coda_vattr * attr )
{
struct inode * inode ;
struct coda_inode_info * cii ;
unsigned long hash = coda_f2i ( fid ) ;
inode = iget5_locked ( sb , hash , coda_test_inode , coda_set_inode , fid ) ;
if ( ! inode )
return ERR_PTR ( - ENOMEM ) ;
if ( inode - > i_state & I_NEW ) {
cii = ITOC ( inode ) ;
/* we still need to set i_ino for things like stat(2) */
inode - > i_ino = hash ;
2010-10-25 10:03:44 +04:00
/* inode is locked and unique, no need to grab cii->c_lock */
2005-04-17 02:20:36 +04:00
cii - > c_mapcount = 0 ;
unlock_new_inode ( inode ) ;
}
/* always replace the attributes, type might have changed */
coda_fill_inode ( inode , attr ) ;
return inode ;
}
/* this is effectively coda_iget:
- get attributes ( might be cached )
- get the inode for the fid using vfs iget
- link the two up if this is needed
- fill in the attributes
*/
2012-01-10 20:11:49 +04:00
struct inode * coda_cnode_make ( struct CodaFid * fid , struct super_block * sb )
2005-04-17 02:20:36 +04:00
{
struct coda_vattr attr ;
2012-01-10 20:11:49 +04:00
struct inode * inode ;
2005-04-17 02:20:36 +04:00
int error ;
/* We get inode numbers from Venus -- see venus source */
error = venus_getattr ( sb , fid , & attr ) ;
2012-01-10 20:11:49 +04:00
if ( error )
return ERR_PTR ( error ) ;
2005-04-17 02:20:36 +04:00
2012-01-10 20:11:49 +04:00
inode = coda_iget ( sb , fid , & attr ) ;
if ( IS_ERR ( inode ) )
2005-04-17 02:20:36 +04:00
printk ( " coda_cnode_make: coda_iget failed \n " ) ;
2012-01-10 20:11:49 +04:00
return inode ;
2005-04-17 02:20:36 +04:00
}
2010-10-25 10:03:44 +04:00
/* Although we treat Coda file identifiers as immutable, there is one
* special case for files created during a disconnection where they may
* not be globally unique . When an identifier collision is detected we
* first try to flush the cached inode from the kernel and finally
* resort to renaming / rehashing in - place . Userspace remembers both old
* and new values of the identifier to handle any in - flight upcalls .
* The real solution is to use globally unique UUIDs as identifiers , but
* retrofitting the existing userspace code for this is non - trivial . */
2005-04-17 02:20:36 +04:00
void coda_replace_fid ( struct inode * inode , struct CodaFid * oldfid ,
struct CodaFid * newfid )
{
2010-10-25 10:03:44 +04:00
struct coda_inode_info * cii = ITOC ( inode ) ;
2005-04-17 02:20:36 +04:00
unsigned long hash = coda_f2i ( newfid ) ;
2006-03-24 20:42:13 +03:00
BUG_ON ( ! coda_fideq ( & cii - > c_fid , oldfid ) ) ;
2005-04-17 02:20:36 +04:00
/* replace fid and rehash inode */
/* XXX we probably need to hold some lock here! */
remove_inode_hash ( inode ) ;
cii - > c_fid = * newfid ;
inode - > i_ino = hash ;
__insert_inode_hash ( inode , hash ) ;
}
/* convert a fid to an inode. */
struct inode * coda_fid_to_inode ( struct CodaFid * fid , struct super_block * sb )
{
struct inode * inode ;
unsigned long hash = coda_f2i ( fid ) ;
if ( ! sb ) {
printk ( " coda_fid_to_inode: no sb! \n " ) ;
return NULL ;
}
2007-07-19 12:48:44 +04:00
inode = ilookup5 ( sb , hash , coda_test_inode , fid ) ;
2005-04-17 02:20:36 +04:00
if ( ! inode )
return NULL ;
/* we should never see newly created inodes because we intentionally
* fail in the initialization callback */
BUG_ON ( inode - > i_state & I_NEW ) ;
return inode ;
}
/* the CONTROL inode is made without asking attributes from Venus */
2012-01-10 19:46:03 +04:00
struct inode * coda_cnode_makectl ( struct super_block * sb )
2005-04-17 02:20:36 +04:00
{
2012-01-10 19:46:03 +04:00
struct inode * inode = new_inode ( sb ) ;
if ( inode ) {
inode - > i_ino = CTL_INO ;
inode - > i_op = & coda_ioctl_inode_operations ;
inode - > i_fop = & coda_ioctl_operations ;
inode - > i_mode = 0444 ;
return inode ;
2005-04-17 02:20:36 +04:00
}
2012-01-10 19:46:03 +04:00
return ERR_PTR ( - ENOMEM ) ;
2005-04-17 02:20:36 +04:00
}