ops_export.c 6.3 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 7 8 9 10 11 12 13 14
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License v.2.
 */

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

#include "gfs2.h"
19 20
#include "lm_interface.h"
#include "incore.h"
D
David Teigland 已提交
21 22 23 24 25 26
#include "dir.h"
#include "glock.h"
#include "glops.h"
#include "inode.h"
#include "ops_export.h"
#include "rgrp.h"
27
#include "util.h"
D
David Teigland 已提交
28 29 30 31 32 33 34 35 36

static struct dentry *gfs2_decode_fh(struct super_block *sb,
				     __u32 *fh,
				     int fh_len,
				     int fh_type,
				     int (*acceptable)(void *context,
						       struct dentry *dentry),
				     void *context)
{
W
Wendy Cheng 已提交
37 38
	struct gfs2_fh_obj fh_obj;
	struct gfs2_inum *this, parent;
D
David Teigland 已提交
39 40 41 42

	if (fh_type != fh_len)
		return NULL;

W
Wendy Cheng 已提交
43 44
	this 		= &fh_obj.this;
	fh_obj.imode 	= DT_UNKNOWN;
D
David Teigland 已提交
45 46 47
	memset(&parent, 0, sizeof(struct gfs2_inum));

	switch (fh_type) {
W
Wendy Cheng 已提交
48
	case 10:
D
David Teigland 已提交
49 50 51 52
		parent.no_formal_ino = ((uint64_t)be32_to_cpu(fh[4])) << 32;
		parent.no_formal_ino |= be32_to_cpu(fh[5]);
		parent.no_addr = ((uint64_t)be32_to_cpu(fh[6])) << 32;
		parent.no_addr |= be32_to_cpu(fh[7]);
W
Wendy Cheng 已提交
53
		fh_obj.imode = be32_to_cpu(fh[8]);
D
David Teigland 已提交
54
	case 4:
W
Wendy Cheng 已提交
55 56 57 58
		this->no_formal_ino = ((uint64_t)be32_to_cpu(fh[0])) << 32;
		this->no_formal_ino |= be32_to_cpu(fh[1]);
		this->no_addr = ((uint64_t)be32_to_cpu(fh[2])) << 32;
		this->no_addr |= be32_to_cpu(fh[3]);
D
David Teigland 已提交
59 60 61 62 63
		break;
	default:
		return NULL;
	}

W
Wendy Cheng 已提交
64
	return gfs2_export_ops.find_exported_dentry(sb, &fh_obj, &parent,
D
David Teigland 已提交
65 66 67 68 69 70 71
						    acceptable, context);
}

static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
			  int connectable)
{
	struct inode *inode = dentry->d_inode;
S
Steven Whitehouse 已提交
72
	struct super_block *sb = inode->i_sb;
73
	struct gfs2_inode *ip = GFS2_I(inode);
D
David Teigland 已提交
74

W
Wendy Cheng 已提交
75
	if (*len < 4 || (connectable && *len < 10))
D
David Teigland 已提交
76 77 78 79 80 81 82 83 84 85 86 87
		return 255;

	fh[0] = ip->i_num.no_formal_ino >> 32;
	fh[0] = cpu_to_be32(fh[0]);
	fh[1] = ip->i_num.no_formal_ino & 0xFFFFFFFF;
	fh[1] = cpu_to_be32(fh[1]);
	fh[2] = ip->i_num.no_addr >> 32;
	fh[2] = cpu_to_be32(fh[2]);
	fh[3] = ip->i_num.no_addr & 0xFFFFFFFF;
	fh[3] = cpu_to_be32(fh[3]);
	*len = 4;

S
Steven Whitehouse 已提交
88
	if (!connectable || inode == sb->s_root->d_inode)
D
David Teigland 已提交
89 90 91 92
		return *len;

	spin_lock(&dentry->d_lock);
	inode = dentry->d_parent->d_inode;
93 94
	ip = GFS2_I(inode);
	igrab(inode);
D
David Teigland 已提交
95 96 97 98 99 100 101 102 103 104
	spin_unlock(&dentry->d_lock);

	fh[4] = ip->i_num.no_formal_ino >> 32;
	fh[4] = cpu_to_be32(fh[4]);
	fh[5] = ip->i_num.no_formal_ino & 0xFFFFFFFF;
	fh[5] = cpu_to_be32(fh[5]);
	fh[6] = ip->i_num.no_addr >> 32;
	fh[6] = cpu_to_be32(fh[6]);
	fh[7] = ip->i_num.no_addr & 0xFFFFFFFF;
	fh[7] = cpu_to_be32(fh[7]);
W
Wendy Cheng 已提交
105 106 107 108

	fh[8]  = cpu_to_be32(inode->i_mode);
	fh[9]  = 0;	/* pad to double word */
	*len = 10;
D
David Teigland 已提交
109

110
	iput(inode);
D
David Teigland 已提交
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151

	return *len;
}

struct get_name_filldir {
	struct gfs2_inum inum;
	char *name;
};

static int get_name_filldir(void *opaque, const char *name, unsigned int length,
			    uint64_t offset, struct gfs2_inum *inum,
			    unsigned int type)
{
	struct get_name_filldir *gnfd = (struct get_name_filldir *)opaque;

	if (!gfs2_inum_equal(inum, &gnfd->inum))
		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;
	uint64_t offset = 0;
	int error;

	if (!dir)
		return -EINVAL;

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

152 153
	dip = GFS2_I(dir);
	ip = GFS2_I(inode);
D
David Teigland 已提交
154 155 156 157 158 159 160 161 162

	*name = 0;
	gnfd.inum = ip->i_num;
	gnfd.name = name;

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

163
	error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir);
D
David Teigland 已提交
164 165 166 167 168 169 170 171 172 173 174

	gfs2_glock_dq_uninit(&gh);

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

	return error;
}

static struct dentry *gfs2_get_parent(struct dentry *child)
{
175
	struct qstr dotdot;
D
David Teigland 已提交
176 177 178
	struct inode *inode;
	struct dentry *dentry;

179
	gfs2_str2qstr(&dotdot, "..");
180 181 182 183 184 185
	inode = gfs2_lookupi(child->d_inode, &dotdot, 1, NULL);

	if (!inode)
		return ERR_PTR(-ENOENT);
	if (IS_ERR(inode))
		return ERR_PTR(PTR_ERR(inode));
D
David Teigland 已提交
186 187 188 189 190 191 192 193 194 195

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

	return dentry;
}

W
Wendy Cheng 已提交
196
static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj)
D
David Teigland 已提交
197
{
198
	struct gfs2_sbd *sdp = sb->s_fs_info;
W
Wendy Cheng 已提交
199 200
	struct gfs2_fh_obj *fh_obj = (struct gfs2_fh_obj *)inum_obj;
	struct gfs2_inum *inum = &fh_obj->this;
D
David Teigland 已提交
201 202 203 204 205 206 207 208
	struct gfs2_holder i_gh, ri_gh, rgd_gh;
	struct gfs2_rgrpd *rgd;
	struct inode *inode;
	struct dentry *dentry;
	int error;

	/* System files? */

209
	inode = gfs2_ilookup(sb, inum);
D
David Teigland 已提交
210
	if (inode) {
211
		if (GFS2_I(inode)->i_num.no_formal_ino != inum->no_formal_ino) {
D
David Teigland 已提交
212 213 214 215 216 217
			iput(inode);
			return ERR_PTR(-ESTALE);
		}
		goto out_inode;
	}

218
	error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops,
D
David Teigland 已提交
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
				  LM_ST_SHARED, LM_FLAG_ANY | GL_LOCAL_EXCL,
				  &i_gh);
	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);

W
Wendy Cheng 已提交
244
	inode = gfs2_inode_lookup(sb, inum, fh_obj->imode);
245 246 247 248
	if (!inode)
		goto fail;
	if (IS_ERR(inode)) {
		error = PTR_ERR(inode);
D
David Teigland 已提交
249
		goto fail;
250
	}
D
David Teigland 已提交
251

252
	error = gfs2_inode_refresh(GFS2_I(inode));
D
David Teigland 已提交
253
	if (error) {
254
		iput(inode);
D
David Teigland 已提交
255 256 257 258
		goto fail;
	}

	error = -EIO;
259 260
	if (GFS2_I(inode)->i_di.di_flags & GFS2_DIF_SYSTEM) {
		iput(inode);
D
David Teigland 已提交
261 262 263 264 265
		goto fail;
	}

	gfs2_glock_dq_uninit(&i_gh);

266
out_inode:
D
David Teigland 已提交
267 268 269 270 271 272 273 274
	dentry = d_alloc_anon(inode);
	if (!dentry) {
		iput(inode);
		return ERR_PTR(-ENOMEM);
	}

	return dentry;

275
fail_rgd:
D
David Teigland 已提交
276 277
	gfs2_glock_dq_uninit(&rgd_gh);

278
fail_rindex:
D
David Teigland 已提交
279 280
	gfs2_glock_dq_uninit(&ri_gh);

281
fail:
D
David Teigland 已提交
282 283 284 285 286 287 288 289 290 291 292 293
	gfs2_glock_dq_uninit(&i_gh);
	return ERR_PTR(error);
}

struct export_operations gfs2_export_ops = {
	.decode_fh = gfs2_decode_fh,
	.encode_fh = gfs2_encode_fh,
	.get_name = gfs2_get_name,
	.get_parent = gfs2_get_parent,
	.get_dentry = gfs2_get_dentry,
};