export.c 5.8 KB
Newer Older
D
David Teigland 已提交
1 2
/*
 * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
3
 * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
D
David Teigland 已提交
4 5 6
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
7
 * of the GNU General Public License version 2.
D
David Teigland 已提交
8 9 10 11 12 13
 */

#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
14
#include <linux/exportfs.h>
15
#include <linux/gfs2_ondisk.h>
16
#include <linux/crc32.h>
D
David Teigland 已提交
17 18

#include "gfs2.h"
19
#include "incore.h"
D
David Teigland 已提交
20 21 22 23
#include "dir.h"
#include "glock.h"
#include "glops.h"
#include "inode.h"
24
#include "super.h"
D
David Teigland 已提交
25
#include "rgrp.h"
26
#include "util.h"
D
David Teigland 已提交
27

28
#define GFS2_SMALL_FH_SIZE 4
29
#define GFS2_LARGE_FH_SIZE 8
30
#define GFS2_OLD_FH_SIZE 10
31

A
Al Viro 已提交
32
static int gfs2_encode_fh(struct dentry *dentry, __u32 *p, int *len,
D
David Teigland 已提交
33 34
			  int connectable)
{
A
Al Viro 已提交
35
	__be32 *fh = (__force __be32 *)p;
D
David Teigland 已提交
36
	struct inode *inode = dentry->d_inode;
S
Steven Whitehouse 已提交
37
	struct super_block *sb = inode->i_sb;
38
	struct gfs2_inode *ip = GFS2_I(inode);
D
David Teigland 已提交
39

40 41
	if (*len < GFS2_SMALL_FH_SIZE ||
	    (connectable && *len < GFS2_LARGE_FH_SIZE))
D
David Teigland 已提交
42 43
		return 255;

44 45 46 47
	fh[0] = cpu_to_be32(ip->i_no_formal_ino >> 32);
	fh[1] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
	fh[2] = cpu_to_be32(ip->i_no_addr >> 32);
	fh[3] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF);
48
	*len = GFS2_SMALL_FH_SIZE;
D
David Teigland 已提交
49

S
Steven Whitehouse 已提交
50
	if (!connectable || inode == sb->s_root->d_inode)
D
David Teigland 已提交
51 52 53 54
		return *len;

	spin_lock(&dentry->d_lock);
	inode = dentry->d_parent->d_inode;
55 56
	ip = GFS2_I(inode);
	igrab(inode);
D
David Teigland 已提交
57 58
	spin_unlock(&dentry->d_lock);

59 60 61 62
	fh[4] = cpu_to_be32(ip->i_no_formal_ino >> 32);
	fh[5] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
	fh[6] = cpu_to_be32(ip->i_no_addr >> 32);
	fh[7] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF);
63
	*len = GFS2_LARGE_FH_SIZE;
D
David Teigland 已提交
64

65
	iput(inode);
D
David Teigland 已提交
66 67 68 69 70

	return *len;
}

struct get_name_filldir {
A
Al Viro 已提交
71
	struct gfs2_inum_host inum;
D
David Teigland 已提交
72 73 74
	char *name;
};

75 76
static int get_name_filldir(void *opaque, const char *name, int length,
			    loff_t offset, u64 inum, unsigned int type)
D
David Teigland 已提交
77
{
78
	struct get_name_filldir *gnfd = opaque;
D
David Teigland 已提交
79

80
	if (inum != gnfd->inum.no_addr)
D
David Teigland 已提交
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
		return 0;

	memcpy(gnfd->name, name, length);
	gnfd->name[length] = 0;

	return 1;
}

static int gfs2_get_name(struct dentry *parent, char *name,
			 struct dentry *child)
{
	struct inode *dir = parent->d_inode;
	struct inode *inode = child->d_inode;
	struct gfs2_inode *dip, *ip;
	struct get_name_filldir gnfd;
	struct gfs2_holder gh;
97
	u64 offset = 0;
D
David Teigland 已提交
98 99 100 101 102 103 104 105
	int error;

	if (!dir)
		return -EINVAL;

	if (!S_ISDIR(dir->i_mode) || !inode)
		return -EINVAL;

106 107
	dip = GFS2_I(dir);
	ip = GFS2_I(inode);
D
David Teigland 已提交
108 109

	*name = 0;
110 111
	gnfd.inum.no_addr = ip->i_no_addr;
	gnfd.inum.no_formal_ino = ip->i_no_formal_ino;
D
David Teigland 已提交
112 113 114 115 116 117
	gnfd.name = name;

	error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh);
	if (error)
		return error;

118
	error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir);
D
David Teigland 已提交
119 120 121 122 123 124 125 126 127 128 129

	gfs2_glock_dq_uninit(&gh);

	if (!error && !*name)
		error = -ENOENT;

	return error;
}

static struct dentry *gfs2_get_parent(struct dentry *child)
{
130
	struct qstr dotdot;
D
David Teigland 已提交
131 132
	struct dentry *dentry;

133
	/*
134 135
	 * XXX(hch): it would be a good idea to keep this around as a
	 *	     static variable.
136
	 */
137
	gfs2_str2qstr(&dotdot, "..");
D
David Teigland 已提交
138

139 140 141
	dentry = d_obtain_alias(gfs2_lookupi(child->d_inode, &dotdot, 1));
	if (!IS_ERR(dentry))
		dentry->d_op = &gfs2_dops;
D
David Teigland 已提交
142 143 144
	return dentry;
}

C
Christoph Hellwig 已提交
145
static struct dentry *gfs2_get_dentry(struct super_block *sb,
146
				      struct gfs2_inum_host *inum)
D
David Teigland 已提交
147
{
148
	struct gfs2_sbd *sdp = sb->s_fs_info;
149
	struct gfs2_holder i_gh;
D
David Teigland 已提交
150 151 152 153
	struct inode *inode;
	struct dentry *dentry;
	int error;

154
	inode = gfs2_ilookup(sb, inum->no_addr);
D
David Teigland 已提交
155
	if (inode) {
156
		if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) {
D
David Teigland 已提交
157 158 159 160 161 162
			iput(inode);
			return ERR_PTR(-ESTALE);
		}
		goto out_inode;
	}

163
	error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops,
164
				  LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
D
David Teigland 已提交
165 166 167
	if (error)
		return ERR_PTR(error);

168
	error = gfs2_check_blk_type(sdp, inum->no_addr, GFS2_BLKST_DINODE);
D
David Teigland 已提交
169 170 171
	if (error)
		goto fail;

B
Bob Peterson 已提交
172
	inode = gfs2_inode_lookup(sb, DT_UNKNOWN, inum->no_addr, 0);
173 174
	if (IS_ERR(inode)) {
		error = PTR_ERR(inode);
D
David Teigland 已提交
175
		goto fail;
176
	}
D
David Teigland 已提交
177

178
	error = gfs2_inode_refresh(GFS2_I(inode));
D
David Teigland 已提交
179
	if (error) {
180
		iput(inode);
D
David Teigland 已提交
181 182
		goto fail;
	}
183 184 185 186 187

	/* Pick up the works we bypass in gfs2_inode_lookup */
	if (inode->i_state & I_NEW) 
		gfs2_set_iop(inode);

188 189 190 191
	if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) {
		iput(inode);
		goto fail;
	}
D
David Teigland 已提交
192 193

	error = -EIO;
194
	if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM) {
195
		iput(inode);
D
David Teigland 已提交
196 197 198 199 200
		goto fail;
	}

	gfs2_glock_dq_uninit(&i_gh);

201
out_inode:
202 203 204
	dentry = d_obtain_alias(inode);
	if (!IS_ERR(dentry))
		dentry->d_op = &gfs2_dops;
D
David Teigland 已提交
205
	return dentry;
206
fail:
D
David Teigland 已提交
207 208 209 210
	gfs2_glock_dq_uninit(&i_gh);
	return ERR_PTR(error);
}

C
Christoph Hellwig 已提交
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
		int fh_len, int fh_type)
{
	struct gfs2_inum_host this;
	__be32 *fh = (__force __be32 *)fid->raw;

	switch (fh_type) {
	case GFS2_SMALL_FH_SIZE:
	case GFS2_LARGE_FH_SIZE:
	case GFS2_OLD_FH_SIZE:
		this.no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32;
		this.no_formal_ino |= be32_to_cpu(fh[1]);
		this.no_addr = ((u64)be32_to_cpu(fh[2])) << 32;
		this.no_addr |= be32_to_cpu(fh[3]);
		return gfs2_get_dentry(sb, &this);
	default:
		return NULL;
	}
}

static struct dentry *gfs2_fh_to_parent(struct super_block *sb, struct fid *fid,
		int fh_len, int fh_type)
{
	struct gfs2_inum_host parent;
	__be32 *fh = (__force __be32 *)fid->raw;

	switch (fh_type) {
	case GFS2_LARGE_FH_SIZE:
	case GFS2_OLD_FH_SIZE:
		parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32;
		parent.no_formal_ino |= be32_to_cpu(fh[5]);
		parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32;
		parent.no_addr |= be32_to_cpu(fh[7]);
		return gfs2_get_dentry(sb, &parent);
	default:
		return NULL;
	}
}

250
const struct export_operations gfs2_export_ops = {
D
David Teigland 已提交
251
	.encode_fh = gfs2_encode_fh,
C
Christoph Hellwig 已提交
252 253
	.fh_to_dentry = gfs2_fh_to_dentry,
	.fh_to_parent = gfs2_fh_to_parent,
D
David Teigland 已提交
254 255 256 257
	.get_name = gfs2_get_name,
	.get_parent = gfs2_get_parent,
};