2005-04-17 02:20:36 +04:00
/*
2005-11-02 06:58:39 +03:00
* Copyright ( c ) 2004 - 2005 Silicon Graphics , Inc .
* All Rights Reserved .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
2005-04-17 02:20:36 +04:00
* published by the Free Software Foundation .
*
2005-11-02 06:58:39 +03:00
* This program is distributed in the hope that it would 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 .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-04-17 02:20:36 +04:00
*/
# include "xfs.h"
# include "xfs_types.h"
2007-08-28 08:00:13 +04:00
# include "xfs_inum.h"
2005-04-17 02:20:36 +04:00
# include "xfs_log.h"
# include "xfs_trans.h"
# include "xfs_sb.h"
2007-08-28 08:00:13 +04:00
# include "xfs_ag.h"
# include "xfs_dmapi.h"
2005-04-17 02:20:36 +04:00
# include "xfs_mount.h"
# include "xfs_export.h"
2007-02-10 10:34:56 +03:00
static struct dentry dotdot = { . d_name . name = " .. " , . d_name . len = 2 , } ;
2006-03-14 05:32:54 +03:00
2005-04-17 02:20:36 +04:00
/*
2005-11-02 06:58:39 +03:00
* XFS encodes and decodes the fileid portion of NFS filehandles
2005-04-17 02:20:36 +04:00
* itself instead of letting the generic NFS code do it . This
* allows filesystems with 64 bit inode numbers to be exported .
*
* Note that a side effect is that xfs_vget ( ) won ' t be passed a
* zero inode / generation pair under normal circumstances . As
* however a malicious client could send us such data , the check
* remains in that code .
*/
STATIC struct dentry *
2006-03-14 06:06:18 +03:00
xfs_fs_decode_fh (
2005-04-17 02:20:36 +04:00
struct super_block * sb ,
__u32 * fh ,
int fh_len ,
int fileid_type ,
int ( * acceptable ) (
void * context ,
struct dentry * de ) ,
void * context )
{
xfs_fid2_t ifid ;
xfs_fid2_t pfid ;
void * parent = NULL ;
int is64 = 0 ;
__u32 * p = fh ;
# if XFS_BIG_INUMS
is64 = ( fileid_type & XFS_FILEID_TYPE_64FLAG ) ;
fileid_type & = ~ XFS_FILEID_TYPE_64FLAG ;
# endif
/*
* Note that we only accept fileids which are long enough
* rather than allow the parent generation number to default
* to zero . XFS considers zero a valid generation number not
* an invalid / wildcard value . There ' s little point printk ' ing
* a warning here as we don ' t have the client information
* which would make such a warning useful .
*/
if ( fileid_type > 2 | |
fh_len < xfs_fileid_length ( ( fileid_type = = 2 ) , is64 ) )
return NULL ;
p = xfs_fileid_decode_fid2 ( p , & ifid , is64 ) ;
if ( fileid_type = = 2 ) {
p = xfs_fileid_decode_fid2 ( p , & pfid , is64 ) ;
parent = & pfid ;
}
2005-11-02 06:58:39 +03:00
2005-04-17 02:20:36 +04:00
fh = ( __u32 * ) & ifid ;
2006-03-14 05:02:13 +03:00
return sb - > s_export_op - > find_exported_dentry ( sb , fh , parent , acceptable , context ) ;
2005-04-17 02:20:36 +04:00
}
STATIC int
2006-03-14 06:06:18 +03:00
xfs_fs_encode_fh (
2005-04-17 02:20:36 +04:00
struct dentry * dentry ,
__u32 * fh ,
int * max_len ,
int connectable )
{
struct inode * inode = dentry - > d_inode ;
int type = 1 ;
__u32 * p = fh ;
int len ;
int is64 = 0 ;
# if XFS_BIG_INUMS
2006-06-09 10:48:30 +04:00
bhv_vfs_t * vfs = vfs_from_sb ( inode - > i_sb ) ;
2005-11-02 06:58:39 +03:00
2005-11-02 07:11:45 +03:00
if ( ! ( vfs - > vfs_flag & VFS_32BITINODES ) ) {
2005-04-17 02:20:36 +04:00
/* filesystem may contain 64bit inode numbers */
is64 = XFS_FILEID_TYPE_64FLAG ;
}
# endif
/* Directories don't need their parent encoded, they have ".." */
if ( S_ISDIR ( inode - > i_mode ) )
connectable = 0 ;
/*
* Only encode if there is enough space given . In practice
* this means we can ' t export a filesystem with 64 bit inodes
* over NFSv2 with the subtree_check export option ; the other
* seven combinations work . The real answer is " don't use v2 " .
*/
len = xfs_fileid_length ( connectable , is64 ) ;
if ( * max_len < len )
return 255 ;
* max_len = len ;
p = xfs_fileid_encode_inode ( p , inode , is64 ) ;
if ( connectable ) {
spin_lock ( & dentry - > d_lock ) ;
p = xfs_fileid_encode_inode ( p , dentry - > d_parent - > d_inode , is64 ) ;
spin_unlock ( & dentry - > d_lock ) ;
type = 2 ;
}
BUG_ON ( ( p - fh ) ! = len ) ;
return type | is64 ;
}
STATIC struct dentry *
2006-03-14 06:06:18 +03:00
xfs_fs_get_dentry (
2005-04-17 02:20:36 +04:00
struct super_block * sb ,
void * data )
{
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ;
2005-04-17 02:20:36 +04:00
struct inode * inode ;
struct dentry * result ;
2006-06-09 10:48:30 +04:00
bhv_vfs_t * vfsp = vfs_from_sb ( sb ) ;
2005-04-17 02:20:36 +04:00
int error ;
2006-06-09 10:48:30 +04:00
error = bhv_vfs_vget ( vfsp , & vp , ( fid_t * ) data ) ;
2005-04-17 02:20:36 +04:00
if ( error | | vp = = NULL )
return ERR_PTR ( - ESTALE ) ;
2006-03-17 09:25:36 +03:00
inode = vn_to_inode ( vp ) ;
2005-04-17 02:20:36 +04:00
result = d_alloc_anon ( inode ) ;
if ( ! result ) {
iput ( inode ) ;
return ERR_PTR ( - ENOMEM ) ;
}
return result ;
}
STATIC struct dentry *
2006-03-14 06:06:18 +03:00
xfs_fs_get_parent (
2005-04-17 02:20:36 +04:00
struct dentry * child )
{
int error ;
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp , * cvp ;
2005-04-17 02:20:36 +04:00
struct dentry * parent ;
cvp = NULL ;
2006-03-17 09:25:36 +03:00
vp = vn_from_inode ( child - > d_inode ) ;
2006-06-09 11:00:52 +04:00
error = bhv_vop_lookup ( vp , & dotdot , & cvp , 0 , NULL , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( unlikely ( error ) )
return ERR_PTR ( - error ) ;
2006-03-17 09:25:36 +03:00
parent = d_alloc_anon ( vn_to_inode ( cvp ) ) ;
2005-04-17 02:20:36 +04:00
if ( unlikely ( ! parent ) ) {
VN_RELE ( cvp ) ;
return ERR_PTR ( - ENOMEM ) ;
}
return parent ;
}
2006-03-14 06:06:18 +03:00
struct export_operations xfs_export_operations = {
. decode_fh = xfs_fs_decode_fh ,
. encode_fh = xfs_fs_encode_fh ,
. get_parent = xfs_fs_get_parent ,
. get_dentry = xfs_fs_get_dentry ,
2005-04-17 02:20:36 +04:00
} ;