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"
2008-04-10 06:22:07 +04:00
# include "xfs_dir2.h"
2007-08-28 08:00:13 +04:00
# 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-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 ".." */
2008-03-06 05:45:16 +03:00
if ( S_ISDIR ( inode - > i_mode ) | | ! connectable )
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 )
{
2007-12-18 08:26:55 +03:00
xfs_mount_t * mp = XFS_M ( sb ) ;
xfs_inode_t * ip ;
2005-04-17 02:20:36 +04:00
int error ;
2007-12-18 08:26:55 +03:00
/*
* NFS can sometimes send requests for ino 0. Fail them gracefully .
*/
if ( ino = = 0 )
return ERR_PTR ( - ESTALE ) ;
2005-04-17 02:20:36 +04:00
2007-12-18 08:26:55 +03:00
error = xfs_iget ( mp , NULL , ino , 0 , XFS_ILOCK_SHARED , & ip , 0 ) ;
2007-10-22 03:42:11 +04:00
if ( error )
return ERR_PTR ( - error ) ;
2007-12-18 08:26:55 +03:00
if ( ! ip )
return ERR_PTR ( - EIO ) ;
2008-04-22 11:33:40 +04:00
if ( ip - > i_d . di_gen ! = generation ) {
2007-12-18 08:26:55 +03:00
xfs_iput_new ( ip , XFS_ILOCK_SHARED ) ;
return ERR_PTR ( - ENOENT ) ;
}
2007-10-22 03:42:11 +04:00
2007-12-18 08:26:55 +03:00
xfs_iunlock ( ip , XFS_ILOCK_SHARED ) ;
2008-08-13 09:45:15 +04:00
return VFS_I ( ip ) ;
2007-10-22 03:42:11 +04:00
}
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 ) )
2008-08-13 10:09:25 +04:00
return ERR_CAST ( inode ) ;
2007-10-22 03:42:11 +04:00
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 ) )
2008-08-13 10:09:25 +04:00
return ERR_CAST ( 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 ;
2008-03-06 05:46:25 +03:00
struct xfs_inode * cip ;
2005-04-17 02:20:36 +04:00
struct dentry * parent ;
2008-05-21 10:58:22 +04:00
error = xfs_lookup ( XFS_I ( child - > d_inode ) , & xfs_name_dotdot , & cip , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( unlikely ( error ) )
return ERR_PTR ( - error ) ;
2008-08-13 09:45:15 +04:00
parent = d_alloc_anon ( VFS_I ( cip ) ) ;
2005-04-17 02:20:36 +04:00
if ( unlikely ( ! parent ) ) {
2008-08-13 09:45:15 +04:00
iput ( VFS_I ( cip ) ) ;
2005-04-17 02:20:36 +04:00
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
} ;