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-08-29 04:58:01 +04:00
# include "xfs_vnodeops.h"
# include "xfs_bmap_btree.h"
# include "xfs_inode.h"
2007-08-30 11:20:39 +04:00
# include "xfs_vfsops.h"
2005-04-17 02:20:36 +04:00
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
/*
2007-10-22 03:42:11 +04:00
* 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 .
2005-04-17 02:20:36 +04:00
*/
2007-10-22 03:42:11 +04:00
static int xfs_fileid_length ( int fileid_type )
2005-04-17 02:20:36 +04:00
{
2007-10-22 03:42:11 +04:00
switch ( fileid_type ) {
case FILEID_INO32_GEN :
return 2 ;
case FILEID_INO32_GEN_PARENT :
return 4 ;
case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG :
return 3 ;
case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG :
return 6 ;
2005-04-17 02:20:36 +04:00
}
2007-10-22 03:42:11 +04:00
return 255 ; /* invalid */
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 )
{
2007-10-22 03:42:11 +04:00
struct fid * fid = ( struct fid * ) fh ;
struct xfs_fid64 * fid64 = ( struct xfs_fid64 * ) fh ;
2005-04-17 02:20:36 +04:00
struct inode * inode = dentry - > d_inode ;
2007-10-22 03:42:11 +04:00
int fileid_type ;
2005-04-17 02:20:36 +04:00
int len ;
/* Directories don't need their parent encoded, they have ".." */
if ( S_ISDIR ( inode - > i_mode ) )
2007-10-22 03:42:11 +04:00
fileid_type = FILEID_INO32_GEN ;
else
fileid_type = FILEID_INO32_GEN_PARENT ;
/* filesystem may contain 64bit inode numbers */
if ( ! ( XFS_M ( inode - > i_sb ) - > m_flags & XFS_MOUNT_SMALL_INUMS ) )
fileid_type | = XFS_FILEID_TYPE_64FLAG ;
2005-04-17 02:20:36 +04:00
/*
* 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 " .
*/
2007-10-22 03:42:11 +04:00
len = xfs_fileid_length ( fileid_type ) ;
2005-04-17 02:20:36 +04:00
if ( * max_len < len )
return 255 ;
* max_len = len ;
2007-10-22 03:42:11 +04:00
switch ( fileid_type ) {
case FILEID_INO32_GEN_PARENT :
2005-04-17 02:20:36 +04:00
spin_lock ( & dentry - > d_lock ) ;
2007-10-22 03:42:11 +04:00
fid - > i32 . parent_ino = dentry - > d_parent - > d_inode - > i_ino ;
fid - > i32 . parent_gen = dentry - > d_parent - > d_inode - > i_generation ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & dentry - > d_lock ) ;
2007-10-22 03:42:11 +04:00
/*FALLTHRU*/
case FILEID_INO32_GEN :
fid - > i32 . ino = inode - > i_ino ;
fid - > i32 . gen = inode - > i_generation ;
break ;
case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG :
spin_lock ( & dentry - > d_lock ) ;
fid64 - > parent_ino = dentry - > d_parent - > d_inode - > i_ino ;
fid64 - > parent_gen = dentry - > d_parent - > d_inode - > i_generation ;
spin_unlock ( & dentry - > d_lock ) ;
/*FALLTHRU*/
case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG :
fid64 - > ino = inode - > i_ino ;
fid64 - > gen = inode - > i_generation ;
break ;
2005-04-17 02:20:36 +04:00
}
2007-10-22 03:42:11 +04:00
return fileid_type ;
2005-04-17 02:20:36 +04:00
}
2007-10-22 03:42:11 +04:00
STATIC struct inode *
xfs_nfs_get_inode (
2005-04-17 02:20:36 +04:00
struct super_block * sb ,
2007-10-22 03:42:11 +04:00
u64 ino ,
u32 generation )
{
xfs_fid_t xfid ;
2006-06-09 11:00:52 +04:00
bhv_vnode_t * vp ;
2005-04-17 02:20:36 +04:00
int error ;
2007-10-22 03:42:11 +04:00
xfid . fid_len = sizeof ( xfs_fid_t ) - sizeof ( xfid . fid_len ) ;
xfid . fid_pad = 0 ;
xfid . fid_ino = ino ;
xfid . fid_gen = generation ;
2005-04-17 02:20:36 +04:00
2007-10-22 03:42:11 +04:00
error = xfs_vget ( XFS_M ( sb ) , & vp , & xfid ) ;
if ( error )
return ERR_PTR ( - error ) ;
return vp ? vn_to_inode ( vp ) : NULL ;
}
STATIC struct dentry *
xfs_fs_fh_to_dentry ( struct super_block * sb , struct fid * fid ,
int fh_len , int fileid_type )
{
struct xfs_fid64 * fid64 = ( struct xfs_fid64 * ) fid ;
struct inode * inode = NULL ;
struct dentry * result ;
if ( fh_len < xfs_fileid_length ( fileid_type ) )
return NULL ;
switch ( fileid_type ) {
case FILEID_INO32_GEN_PARENT :
case FILEID_INO32_GEN :
inode = xfs_nfs_get_inode ( sb , fid - > i32 . ino , fid - > i32 . gen ) ;
break ;
case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG :
case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG :
inode = xfs_nfs_get_inode ( sb , fid64 - > ino , fid64 - > gen ) ;
break ;
}
if ( ! inode )
return NULL ;
if ( IS_ERR ( inode ) )
return ERR_PTR ( PTR_ERR ( inode ) ) ;
result = d_alloc_anon ( inode ) ;
if ( ! result ) {
iput ( inode ) ;
return ERR_PTR ( - ENOMEM ) ;
}
return result ;
}
STATIC struct dentry *
xfs_fs_fh_to_parent ( struct super_block * sb , struct fid * fid ,
int fh_len , int fileid_type )
{
struct xfs_fid64 * fid64 = ( struct xfs_fid64 * ) fid ;
struct inode * inode = NULL ;
struct dentry * result ;
switch ( fileid_type ) {
case FILEID_INO32_GEN_PARENT :
inode = xfs_nfs_get_inode ( sb , fid - > i32 . parent_ino ,
fid - > i32 . parent_gen ) ;
break ;
case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG :
inode = xfs_nfs_get_inode ( sb , fid64 - > parent_ino ,
fid64 - > parent_gen ) ;
break ;
}
if ( ! inode )
return NULL ;
if ( IS_ERR ( inode ) )
return ERR_PTR ( PTR_ERR ( inode ) ) ;
2005-04-17 02:20:36 +04:00
result = d_alloc_anon ( inode ) ;
2007-10-22 03:42:11 +04:00
if ( ! result ) {
2005-04-17 02:20:36 +04:00
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 ;
2007-08-29 04:58:01 +04:00
bhv_vnode_t * cvp ;
2005-04-17 02:20:36 +04:00
struct dentry * parent ;
cvp = NULL ;
2007-08-29 04:58:01 +04:00
error = xfs_lookup ( XFS_I ( child - > d_inode ) , & dotdot , & cvp ) ;
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 ;
}
2007-10-22 03:42:17 +04:00
const struct export_operations xfs_export_operations = {
2006-03-14 06:06:18 +03:00
. encode_fh = xfs_fs_encode_fh ,
2007-10-22 03:42:11 +04:00
. fh_to_dentry = xfs_fs_fh_to_dentry ,
. fh_to_parent = xfs_fs_fh_to_parent ,
2006-03-14 06:06:18 +03:00
. get_parent = xfs_fs_get_parent ,
2005-04-17 02:20:36 +04:00
} ;