linux/fs/xfs/linux-2.6/xfs_export.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2004-2005 Silicon Graphics, Inc.
   3 * All Rights Reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it would be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write the Free Software Foundation,
  16 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17 */
  18#include "xfs.h"
  19#include "xfs_types.h"
  20#include "xfs_inum.h"
  21#include "xfs_log.h"
  22#include "xfs_trans.h"
  23#include "xfs_sb.h"
  24#include "xfs_ag.h"
  25#include "xfs_dmapi.h"
  26#include "xfs_mount.h"
  27#include "xfs_export.h"
  28#include "xfs_vnodeops.h"
  29#include "xfs_bmap_btree.h"
  30#include "xfs_inode.h"
  31#include "xfs_vfsops.h"
  32
  33static struct dentry dotdot = { .d_name.name = "..", .d_name.len = 2, };
  34
  35/*
  36 * Note that we only accept fileids which are long enough rather than allow
  37 * the parent generation number to default to zero.  XFS considers zero a
  38 * valid generation number not an invalid/wildcard value.
  39 */
  40static int xfs_fileid_length(int fileid_type)
  41{
  42        switch (fileid_type) {
  43        case FILEID_INO32_GEN:
  44                return 2;
  45        case FILEID_INO32_GEN_PARENT:
  46                return 4;
  47        case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
  48                return 3;
  49        case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
  50                return 6;
  51        }
  52        return 255; /* invalid */
  53}
  54
  55STATIC int
  56xfs_fs_encode_fh(
  57        struct dentry           *dentry,
  58        __u32                   *fh,
  59        int                     *max_len,
  60        int                     connectable)
  61{
  62        struct fid              *fid = (struct fid *)fh;
  63        struct xfs_fid64        *fid64 = (struct xfs_fid64 *)fh;
  64        struct inode            *inode = dentry->d_inode;
  65        int                     fileid_type;
  66        int                     len;
  67
  68        /* Directories don't need their parent encoded, they have ".." */
  69        if (S_ISDIR(inode->i_mode))
  70                fileid_type = FILEID_INO32_GEN;
  71        else
  72                fileid_type = FILEID_INO32_GEN_PARENT;
  73
  74        /* filesystem may contain 64bit inode numbers */
  75        if (!(XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_SMALL_INUMS))
  76                fileid_type |= XFS_FILEID_TYPE_64FLAG;
  77
  78        /*
  79         * Only encode if there is enough space given.  In practice
  80         * this means we can't export a filesystem with 64bit inodes
  81         * over NFSv2 with the subtree_check export option; the other
  82         * seven combinations work.  The real answer is "don't use v2".
  83         */
  84        len = xfs_fileid_length(fileid_type);
  85        if (*max_len < len)
  86                return 255;
  87        *max_len = len;
  88
  89        switch (fileid_type) {
  90        case FILEID_INO32_GEN_PARENT:
  91                spin_lock(&dentry->d_lock);
  92                fid->i32.parent_ino = dentry->d_parent->d_inode->i_ino;
  93                fid->i32.parent_gen = dentry->d_parent->d_inode->i_generation;
  94                spin_unlock(&dentry->d_lock);
  95                /*FALLTHRU*/
  96        case FILEID_INO32_GEN:
  97                fid->i32.ino = inode->i_ino;
  98                fid->i32.gen = inode->i_generation;
  99                break;
 100        case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
 101                spin_lock(&dentry->d_lock);
 102                fid64->parent_ino = dentry->d_parent->d_inode->i_ino;
 103                fid64->parent_gen = dentry->d_parent->d_inode->i_generation;
 104                spin_unlock(&dentry->d_lock);
 105                /*FALLTHRU*/
 106        case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
 107                fid64->ino = inode->i_ino;
 108                fid64->gen = inode->i_generation;
 109                break;
 110        }
 111
 112        return fileid_type;
 113}
 114
 115STATIC struct inode *
 116xfs_nfs_get_inode(
 117        struct super_block      *sb,
 118        u64                     ino,
 119        u32                     generation)
 120 {
 121        xfs_fid_t               xfid;
 122        bhv_vnode_t             *vp;
 123        int                     error;
 124
 125        xfid.fid_len = sizeof(xfs_fid_t) - sizeof(xfid.fid_len);
 126        xfid.fid_pad = 0;
 127        xfid.fid_ino = ino;
 128        xfid.fid_gen = generation;
 129
 130        error = xfs_vget(XFS_M(sb), &vp, &xfid);
 131        if (error)
 132                return ERR_PTR(-error);
 133
 134        return vp ? vn_to_inode(vp) : NULL;
 135}
 136
 137STATIC struct dentry *
 138xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
 139                 int fh_len, int fileid_type)
 140{
 141        struct xfs_fid64        *fid64 = (struct xfs_fid64 *)fid;
 142        struct inode            *inode = NULL;
 143        struct dentry           *result;
 144
 145        if (fh_len < xfs_fileid_length(fileid_type))
 146                return NULL;
 147
 148        switch (fileid_type) {
 149        case FILEID_INO32_GEN_PARENT:
 150        case FILEID_INO32_GEN:
 151                inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen);
 152                break;
 153        case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
 154        case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
 155                inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen);
 156                break;
 157        }
 158
 159        if (!inode)
 160                return NULL;
 161        if (IS_ERR(inode))
 162                return ERR_PTR(PTR_ERR(inode));
 163        result = d_alloc_anon(inode);
 164        if (!result) {
 165                iput(inode);
 166                return ERR_PTR(-ENOMEM);
 167        }
 168        return result;
 169}
 170
 171STATIC struct dentry *
 172xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
 173                 int fh_len, int fileid_type)
 174{
 175        struct xfs_fid64        *fid64 = (struct xfs_fid64 *)fid;
 176        struct inode            *inode = NULL;
 177        struct dentry           *result;
 178
 179        switch (fileid_type) {
 180        case FILEID_INO32_GEN_PARENT:
 181                inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino,
 182                                              fid->i32.parent_gen);
 183                break;
 184        case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
 185                inode = xfs_nfs_get_inode(sb, fid64->parent_ino,
 186                                              fid64->parent_gen);
 187                break;
 188        }
 189
 190        if (!inode)
 191                return NULL;
 192        if (IS_ERR(inode))
 193                return ERR_PTR(PTR_ERR(inode));
 194        result = d_alloc_anon(inode);
 195        if (!result) {
 196                iput(inode);
 197                return ERR_PTR(-ENOMEM);
 198        }
 199        return result;
 200}
 201
 202STATIC struct dentry *
 203xfs_fs_get_parent(
 204        struct dentry           *child)
 205{
 206        int                     error;
 207        bhv_vnode_t             *cvp;
 208        struct dentry           *parent;
 209
 210        cvp = NULL;
 211        error = xfs_lookup(XFS_I(child->d_inode), &dotdot, &cvp);
 212        if (unlikely(error))
 213                return ERR_PTR(-error);
 214
 215        parent = d_alloc_anon(vn_to_inode(cvp));
 216        if (unlikely(!parent)) {
 217                VN_RELE(cvp);
 218                return ERR_PTR(-ENOMEM);
 219        }
 220        return parent;
 221}
 222
 223const struct export_operations xfs_export_operations = {
 224        .encode_fh              = xfs_fs_encode_fh,
 225        .fh_to_dentry           = xfs_fs_fh_to_dentry,
 226        .fh_to_parent           = xfs_fs_fh_to_parent,
 227        .get_parent             = xfs_fs_get_parent,
 228};
 229