ops_export.c 6.6 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>
17
#include <linux/lm_interface.h>
D
David Teigland 已提交
18 19

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

30
#define GFS2_SMALL_FH_SIZE 4
31
#define GFS2_LARGE_FH_SIZE 8
32
#define GFS2_OLD_FH_SIZE 10
33

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

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

46 47 48 49
	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);
50
	*len = GFS2_SMALL_FH_SIZE;
D
David Teigland 已提交
51

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

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

61 62 63 64
	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);
65
	*len = GFS2_LARGE_FH_SIZE;
D
David Teigland 已提交
66

67
	iput(inode);
D
David Teigland 已提交
68 69 70 71 72

	return *len;
}

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

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

82
	if (inum != gnfd->inum.no_addr)
D
David Teigland 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
		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;
99
	u64 offset = 0;
D
David Teigland 已提交
100 101 102 103 104 105 106 107
	int error;

	if (!dir)
		return -EINVAL;

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

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

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

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

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

	gfs2_glock_dq_uninit(&gh);

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

	return error;
}

static struct dentry *gfs2_get_parent(struct dentry *child)
{
132
	struct qstr dotdot;
D
David Teigland 已提交
133 134 135
	struct inode *inode;
	struct dentry *dentry;

136
	gfs2_str2qstr(&dotdot, "..");
137 138 139 140
	inode = gfs2_lookupi(child->d_inode, &dotdot, 1, NULL);

	if (!inode)
		return ERR_PTR(-ENOENT);
141 142 143 144
	/*
	 * In case of an error, @inode carries the error value, and we
	 * have to return that as a(n invalid) pointer to dentry.
	 */
145 146
	if (IS_ERR(inode))
		return ERR_PTR(PTR_ERR(inode));
D
David Teigland 已提交
147 148 149 150 151 152 153

	dentry = d_alloc_anon(inode);
	if (!dentry) {
		iput(inode);
		return ERR_PTR(-ENOMEM);
	}

154
	dentry->d_op = &gfs2_dops;
D
David Teigland 已提交
155 156 157
	return dentry;
}

C
Christoph Hellwig 已提交
158 159
static struct dentry *gfs2_get_dentry(struct super_block *sb,
		struct gfs2_inum_host *inum)
D
David Teigland 已提交
160
{
161
	struct gfs2_sbd *sdp = sb->s_fs_info;
D
David Teigland 已提交
162 163 164 165 166 167 168 169
	struct gfs2_holder i_gh, ri_gh, rgd_gh;
	struct gfs2_rgrpd *rgd;
	struct inode *inode;
	struct dentry *dentry;
	int error;

	/* System files? */

170
	inode = gfs2_ilookup(sb, inum->no_addr);
D
David Teigland 已提交
171
	if (inode) {
172
		if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) {
D
David Teigland 已提交
173 174 175 176 177 178
			iput(inode);
			return ERR_PTR(-ESTALE);
		}
		goto out_inode;
	}

179
	error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops,
180
				  LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
D
David Teigland 已提交
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
	if (error)
		return ERR_PTR(error);

	error = gfs2_rindex_hold(sdp, &ri_gh);
	if (error)
		goto fail;

	error = -EINVAL;
	rgd = gfs2_blk2rgrpd(sdp, inum->no_addr);
	if (!rgd)
		goto fail_rindex;

	error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh);
	if (error)
		goto fail_rindex;

	error = -ESTALE;
	if (gfs2_get_block_type(rgd, inum->no_addr) != GFS2_BLKST_DINODE)
		goto fail_rgd;

	gfs2_glock_dq_uninit(&rgd_gh);
	gfs2_glock_dq_uninit(&ri_gh);

204
	inode = gfs2_inode_lookup(sb, DT_UNKNOWN,
205
					inum->no_addr,
206
					0, 0);
207 208 209 210
	if (!inode)
		goto fail;
	if (IS_ERR(inode)) {
		error = PTR_ERR(inode);
D
David Teigland 已提交
211
		goto fail;
212
	}
D
David Teigland 已提交
213

214
	error = gfs2_inode_refresh(GFS2_I(inode));
D
David Teigland 已提交
215
	if (error) {
216
		iput(inode);
D
David Teigland 已提交
217 218
		goto fail;
	}
219 220 221 222 223

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

224 225 226 227
	if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) {
		iput(inode);
		goto fail;
	}
D
David Teigland 已提交
228 229

	error = -EIO;
230 231
	if (GFS2_I(inode)->i_di.di_flags & GFS2_DIF_SYSTEM) {
		iput(inode);
D
David Teigland 已提交
232 233 234 235 236
		goto fail;
	}

	gfs2_glock_dq_uninit(&i_gh);

237
out_inode:
D
David Teigland 已提交
238 239 240 241 242 243
	dentry = d_alloc_anon(inode);
	if (!dentry) {
		iput(inode);
		return ERR_PTR(-ENOMEM);
	}

244
	dentry->d_op = &gfs2_dops;
D
David Teigland 已提交
245 246
	return dentry;

247
fail_rgd:
D
David Teigland 已提交
248 249
	gfs2_glock_dq_uninit(&rgd_gh);

250
fail_rindex:
D
David Teigland 已提交
251 252
	gfs2_glock_dq_uninit(&ri_gh);

253
fail:
D
David Teigland 已提交
254 255 256 257
	gfs2_glock_dq_uninit(&i_gh);
	return ERR_PTR(error);
}

C
Christoph Hellwig 已提交
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
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;
	}
}

297
const struct export_operations gfs2_export_ops = {
D
David Teigland 已提交
298
	.encode_fh = gfs2_encode_fh,
C
Christoph Hellwig 已提交
299 300
	.fh_to_dentry = gfs2_fh_to_dentry,
	.fh_to_parent = gfs2_fh_to_parent,
D
David Teigland 已提交
301 302 303 304
	.get_name = gfs2_get_name,
	.get_parent = gfs2_get_parent,
};