File: [Development] / xfs-linux / linux-2.6 / xfs_export.c (download)
Revision 1.2, Wed Mar 2 00:47:52 2005 UTC (12 years, 7 months ago) by gnb.longdrop.melbourne.sgi.com
Branch: MAIN
Changes since 1.1: +97 -22
lines
Make XFS provide encoding and decoding callbacks from knfsd which encode
the fileid portion of the NFS filehandle differently than the default
functions. The new fileid formats allow filesystems mounted with "inode64"
to be exported over NFSv3 (and NFSv2 if you also use the "no_subtree_check"
export option). For filesystems without "inode64", the file handles are
binary compatible with the old ones, so it should be possible to upgrade a
server without unmounting clients.
Merge of xfs-linux-melb:xfs-kern:21686a by kenmcd.
Fix interaction between XFS with 64 bit inodes enabled and NFS.
|
/*
* Copyright (c) 2004-2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* 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.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write the Free Software Foundation, Inc., 59
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
*/
#include "xfs.h"
#include "xfs_types.h"
#include "xfs_dmapi.h"
#include "xfs_log.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_dir.h"
#include "xfs_mount.h"
#include "xfs_export.h"
/*
* XFS encode and decodes the fileid portion of NFS filehandles
* 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 *
linvfs_decode_fh(
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;
}
fh = (__u32 *)&ifid;
return find_exported_dentry(sb, fh, parent, acceptable, context);
}
STATIC int
linvfs_encode_fh(
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
vfs_t *vfs = LINVFS_GET_VFS(inode->i_sb);
xfs_mount_t *mp = XFS_VFSTOM(vfs);
if (!(mp->m_flags & XFS_MOUNT_32BITINOOPT)) {
/* 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 64bit 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 *
linvfs_get_dentry(
struct super_block *sb,
void *data)
{
vnode_t *vp;
struct inode *inode;
struct dentry *result;
vfs_t *vfsp = LINVFS_GET_VFS(sb);
int error;
VFS_VGET(vfsp, &vp, (fid_t *)data, error);
if (error || vp == NULL)
return ERR_PTR(-ESTALE) ;
inode = LINVFS_GET_IP(vp);
result = d_alloc_anon(inode);
if (!result) {
iput(inode);
return ERR_PTR(-ENOMEM);
}
return result;
}
STATIC struct dentry *
linvfs_get_parent(
struct dentry *child)
{
int error;
vnode_t *vp, *cvp;
struct dentry *parent;
struct dentry dotdot;
dotdot.d_name.name = "..";
dotdot.d_name.len = 2;
dotdot.d_inode = NULL;
cvp = NULL;
vp = LINVFS_GET_VP(child->d_inode);
VOP_LOOKUP(vp, &dotdot, &cvp, 0, NULL, NULL, error);
if (unlikely(error))
return ERR_PTR(-error);
parent = d_alloc_anon(LINVFS_GET_IP(cvp));
if (unlikely(!parent)) {
VN_RELE(cvp);
return ERR_PTR(-ENOMEM);
}
return parent;
}
struct export_operations linvfs_export_ops = {
.decode_fh = linvfs_decode_fh,
.encode_fh = linvfs_encode_fh,
.get_parent = linvfs_get_parent,
.get_dentry = linvfs_get_dentry,
};