linux/fs/gfs2/export.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
   3 * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
   4 *
   5 * This copyrighted material is made available to anyone wishing to use,
   6 * modify, copy, or redistribute it subject to the terms and conditions
   7 * of the GNU General Public License version 2.
   8 */
   9
  10#include <linux/slab.h>
  11#include <linux/spinlock.h>
  12#include <linux/completion.h>
  13#include <linux/buffer_head.h>
  14#include <linux/exportfs.h>
  15#include <linux/gfs2_ondisk.h>
  16#include <linux/crc32.h>
  17
  18#include "gfs2.h"
  19#include "incore.h"
  20#include "dir.h"
  21#include "glock.h"
  22#include "glops.h"
  23#include "inode.h"
  24#include "super.h"
  25#include "rgrp.h"
  26#include "util.h"
  27
  28#define GFS2_SMALL_FH_SIZE 4
  29#define GFS2_LARGE_FH_SIZE 8
  30#define GFS2_OLD_FH_SIZE 10
  31
  32static int gfs2_encode_fh(struct dentry *dentry, __u32 *p, int *len,
  33                          int connectable)
  34{
  35        __be32 *fh = (__force __be32 *)p;
  36        struct inode *inode = dentry->d_inode;
  37        struct super_block *sb = inode->i_sb;
  38        struct gfs2_inode *ip = GFS2_I(inode);
  39
  40        if (*len < GFS2_SMALL_FH_SIZE ||
  41            (connectable && *len < GFS2_LARGE_FH_SIZE))
  42                return 255;
  43
  44        fh[0] = cpu_to_be32(ip->i_no_formal_ino >> 32);
  45        fh[1] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
  46        fh[2] = cpu_to_be32(ip->i_no_addr >> 32);
  47        fh[3] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF);
  48        *len = GFS2_SMALL_FH_SIZE;
  49
  50        if (!connectable || inode == sb->s_root->d_inode)
  51                return *len;
  52
  53        spin_lock(&dentry->d_lock);
  54        inode = dentry->d_parent->d_inode;
  55        ip = GFS2_I(inode);
  56        igrab(inode);
  57        spin_unlock(&dentry->d_lock);
  58
  59        fh[4] = cpu_to_be32(ip->i_no_formal_ino >> 32);
  60        fh[5] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
  61        fh[6] = cpu_to_be32(ip->i_no_addr >> 32);
  62        fh[7] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF);
  63        *len = GFS2_LARGE_FH_SIZE;
  64
  65        iput(inode);
  66
  67        return *len;
  68}
  69
  70struct get_name_filldir {
  71        struct gfs2_inum_host inum;
  72        char *name;
  73};
  74
  75static int get_name_filldir(void *opaque, const char *name, int length,
  76                            loff_t offset, u64 inum, unsigned int type)
  77{
  78        struct get_name_filldir *gnfd = opaque;
  79
  80        if (inum != gnfd->inum.no_addr)
  81                return 0;
  82
  83        memcpy(gnfd->name, name, length);
  84        gnfd->name[length] = 0;
  85
  86        return 1;
  87}
  88
  89static int gfs2_get_name(struct dentry *parent, char *name,
  90                         struct dentry *child)
  91{
  92        struct inode *dir = parent->d_inode;
  93        struct inode *inode = child->d_inode;
  94        struct gfs2_inode *dip, *ip;
  95        struct get_name_filldir gnfd;
  96        struct gfs2_holder gh;
  97        u64 offset = 0;
  98        int error;
  99
 100        if (!dir)
 101                return -EINVAL;
 102
 103        if (!S_ISDIR(dir->i_mode) || !inode)
 104                return -EINVAL;
 105
 106        dip = GFS2_I(dir);
 107        ip = GFS2_I(inode);
 108
 109        *name = 0;
 110        gnfd.inum.no_addr = ip->i_no_addr;
 111        gnfd.inum.no_formal_ino = ip->i_no_formal_ino;
 112        gnfd.name = name;
 113
 114        error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh);
 115        if (error)
 116                return error;
 117
 118        error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir);
 119
 120        gfs2_glock_dq_uninit(&gh);
 121
 122        if (!error && !*name)
 123                error = -ENOENT;
 124
 125        return error;
 126}
 127
 128static struct dentry *gfs2_get_parent(struct dentry *child)
 129{
 130        struct qstr dotdot;
 131        struct dentry *dentry;
 132
 133        /*
 134         * XXX(hch): it would be a good idea to keep this around as a
 135         *           static variable.
 136         */
 137        gfs2_str2qstr(&dotdot, "..");
 138
 139        dentry = d_obtain_alias(gfs2_lookupi(child->d_inode, &dotdot, 1));
 140        if (!IS_ERR(dentry))
 141                dentry->d_op = &gfs2_dops;
 142        return dentry;
 143}
 144
 145static struct dentry *gfs2_get_dentry(struct super_block *sb,
 146                                      struct gfs2_inum_host *inum)
 147{
 148        struct gfs2_sbd *sdp = sb->s_fs_info;
 149        struct gfs2_holder i_gh;
 150        struct inode *inode;
 151        struct dentry *dentry;
 152        int error;
 153
 154        inode = gfs2_ilookup(sb, inum->no_addr);
 155        if (inode) {
 156                if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) {
 157                        iput(inode);
 158                        return ERR_PTR(-ESTALE);
 159                }
 160                goto out_inode;
 161        }
 162
 163        error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops,
 164                                  LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
 165        if (error)
 166                return ERR_PTR(error);
 167
 168        error = gfs2_check_blk_type(sdp, inum->no_addr, GFS2_BLKST_DINODE);
 169        if (error)
 170                goto fail;
 171
 172        inode = gfs2_inode_lookup(sb, DT_UNKNOWN, inum->no_addr, 0, 0);
 173        if (IS_ERR(inode)) {
 174                error = PTR_ERR(inode);
 175                goto fail;
 176        }
 177
 178        error = gfs2_inode_refresh(GFS2_I(inode));
 179        if (error) {
 180                iput(inode);
 181                goto fail;
 182        }
 183
 184        /* Pick up the works we bypass in gfs2_inode_lookup */
 185        if (inode->i_state & I_NEW) 
 186                gfs2_set_iop(inode);
 187
 188        if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) {
 189                iput(inode);
 190                goto fail;
 191        }
 192
 193        error = -EIO;
 194        if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM) {
 195                iput(inode);
 196                goto fail;
 197        }
 198
 199        gfs2_glock_dq_uninit(&i_gh);
 200
 201out_inode:
 202        dentry = d_obtain_alias(inode);
 203        if (!IS_ERR(dentry))
 204                dentry->d_op = &gfs2_dops;
 205        return dentry;
 206fail:
 207        gfs2_glock_dq_uninit(&i_gh);
 208        return ERR_PTR(error);
 209}
 210
 211static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
 212                int fh_len, int fh_type)
 213{
 214        struct gfs2_inum_host this;
 215        __be32 *fh = (__force __be32 *)fid->raw;
 216
 217        switch (fh_type) {
 218        case GFS2_SMALL_FH_SIZE:
 219        case GFS2_LARGE_FH_SIZE:
 220        case GFS2_OLD_FH_SIZE:
 221                this.no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32;
 222                this.no_formal_ino |= be32_to_cpu(fh[1]);
 223                this.no_addr = ((u64)be32_to_cpu(fh[2])) << 32;
 224                this.no_addr |= be32_to_cpu(fh[3]);
 225                return gfs2_get_dentry(sb, &this);
 226        default:
 227                return NULL;
 228        }
 229}
 230
 231static struct dentry *gfs2_fh_to_parent(struct super_block *sb, struct fid *fid,
 232                int fh_len, int fh_type)
 233{
 234        struct gfs2_inum_host parent;
 235        __be32 *fh = (__force __be32 *)fid->raw;
 236
 237        switch (fh_type) {
 238        case GFS2_LARGE_FH_SIZE:
 239        case GFS2_OLD_FH_SIZE:
 240                parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32;
 241                parent.no_formal_ino |= be32_to_cpu(fh[5]);
 242                parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32;
 243                parent.no_addr |= be32_to_cpu(fh[7]);
 244                return gfs2_get_dentry(sb, &parent);
 245        default:
 246                return NULL;
 247        }
 248}
 249
 250const struct export_operations gfs2_export_ops = {
 251        .encode_fh = gfs2_encode_fh,
 252        .fh_to_dentry = gfs2_fh_to_dentry,
 253        .fh_to_parent = gfs2_fh_to_parent,
 254        .get_name = gfs2_get_name,
 255        .get_parent = gfs2_get_parent,
 256};
 257
 258