namei.c 11.9 KB
Newer Older
M
Mike Marshall 已提交
1 2 3 4 5 6 7 8 9 10 11
/*
 * (C) 2001 Clemson University and The University of Chicago
 *
 * See COPYING in top-level directory.
 */

/*
 *  Linux VFS namei operations.
 */

#include "protocol.h"
12
#include "orangefs-kernel.h"
M
Mike Marshall 已提交
13 14 15 16

/*
 * Get a newly allocated inode to go with a negative dentry.
 */
17
static int orangefs_create(struct inode *dir,
M
Mike Marshall 已提交
18 19 20 21
			struct dentry *dentry,
			umode_t mode,
			bool exclusive)
{
22 23
	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
	struct orangefs_kernel_op_s *new_op;
M
Mike Marshall 已提交
24 25 26
	struct inode *inode;
	int ret;

27 28 29
	gossip_debug(GOSSIP_NAME_DEBUG, "%s: %s\n",
		     __func__,
		     dentry->d_name.name);
M
Mike Marshall 已提交
30

31
	new_op = op_alloc(ORANGEFS_VFS_OP_CREATE);
M
Mike Marshall 已提交
32 33 34 35 36 37
	if (!new_op)
		return -ENOMEM;

	new_op->upcall.req.create.parent_refn = parent->refn;

	fill_default_sys_attrs(new_op->upcall.req.create.attributes,
38
			       ORANGEFS_TYPE_METAFILE, mode);
M
Mike Marshall 已提交
39 40

	strncpy(new_op->upcall.req.create.d_name,
41
		dentry->d_name.name, ORANGEFS_NAME_MAX);
M
Mike Marshall 已提交
42 43 44 45

	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));

	gossip_debug(GOSSIP_NAME_DEBUG,
46 47 48
		     "%s: %s: handle:%pU: fsid:%d: new_op:%p: ret:%d:\n",
		     __func__,
		     dentry->d_name.name,
M
Mike Marshall 已提交
49
		     &new_op->downcall.resp.create.refn.khandle,
50 51 52
		     new_op->downcall.resp.create.refn.fs_id,
		     new_op,
		     ret);
M
Mike Marshall 已提交
53

54
	if (ret < 0)
M
Mike Marshall 已提交
55 56
		goto out;

57
	inode = orangefs_new_inode(dir->i_sb, dir, S_IFREG | mode, 0,
M
Mike Marshall 已提交
58 59
				&new_op->downcall.resp.create.refn);
	if (IS_ERR(inode)) {
60 61 62
		gossip_err("%s: Failed to allocate inode for file :%s:\n",
			   __func__,
			   dentry->d_name.name);
M
Mike Marshall 已提交
63 64 65 66 67
		ret = PTR_ERR(inode);
		goto out;
	}

	gossip_debug(GOSSIP_NAME_DEBUG,
68 69 70 71
		     "%s: Assigned inode :%pU: for file :%s:\n",
		     __func__,
		     get_khandle_from_ino(inode),
		     dentry->d_name.name);
M
Mike Marshall 已提交
72 73 74 75 76

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);

	gossip_debug(GOSSIP_NAME_DEBUG,
77 78
		     "%s: dentry instantiated for %s\n",
		     __func__,
M
Mike Marshall 已提交
79 80 81 82 83 84 85 86
		     dentry->d_name.name);

	SetMtimeFlag(parent);
	dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
	mark_inode_dirty_sync(dir);
	ret = 0;
out:
	op_release(new_op);
87 88 89 90 91
	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s: %s: returning %d\n",
		     __func__,
		     dentry->d_name.name,
		     ret);
M
Mike Marshall 已提交
92 93 94 95 96 97 98
	return ret;
}

/*
 * Attempt to resolve an object name (dentry->d_name), parent handle, and
 * fsid into a handle for the object.
 */
99
static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
M
Mike Marshall 已提交
100 101
				   unsigned int flags)
{
102 103
	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
	struct orangefs_kernel_op_s *new_op;
M
Mike Marshall 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
	struct inode *inode;
	struct dentry *res;
	int ret = -EINVAL;

	/*
	 * in theory we could skip a lookup here (if the intent is to
	 * create) in order to avoid a potentially failed lookup, but
	 * leaving it in can skip a valid lookup and try to create a file
	 * that already exists (e.g. the vfs already handles checking for
	 * -EEXIST on O_EXCL opens, which is broken if we skip this lookup
	 * in the create path)
	 */
	gossip_debug(GOSSIP_NAME_DEBUG, "%s called on %s\n",
		     __func__, dentry->d_name.name);

119
	if (dentry->d_name.len > (ORANGEFS_NAME_MAX - 1))
M
Mike Marshall 已提交
120 121
		return ERR_PTR(-ENAMETOOLONG);

122
	new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP);
M
Mike Marshall 已提交
123 124 125
	if (!new_op)
		return ERR_PTR(-ENOMEM);

126
	new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW;
M
Mike Marshall 已提交
127 128 129 130 131 132 133 134 135

	gossip_debug(GOSSIP_NAME_DEBUG, "%s:%s:%d using parent %pU\n",
		     __FILE__,
		     __func__,
		     __LINE__,
		     &parent->refn.khandle);
	new_op->upcall.req.lookup.parent_refn = parent->refn;

	strncpy(new_op->upcall.req.lookup.d_name, dentry->d_name.name,
136
		ORANGEFS_NAME_MAX);
M
Mike Marshall 已提交
137 138

	gossip_debug(GOSSIP_NAME_DEBUG,
139
		     "%s: doing lookup on %s under %pU,%d\n",
M
Mike Marshall 已提交
140 141 142
		     __func__,
		     new_op->upcall.req.lookup.d_name,
		     &new_op->upcall.req.lookup.parent_refn.khandle,
143
		     new_op->upcall.req.lookup.parent_refn.fs_id);
M
Mike Marshall 已提交
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168

	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Lookup Got %pU, fsid %d (ret=%d)\n",
		     &new_op->downcall.resp.lookup.refn.khandle,
		     new_op->downcall.resp.lookup.refn.fs_id,
		     ret);

	if (ret < 0) {
		if (ret == -ENOENT) {
			/*
			 * if no inode was found, add a negative dentry to
			 * dcache anyway; if we don't, we don't hold expected
			 * lookup semantics and we most noticeably break
			 * during directory renames.
			 *
			 * however, if the operation failed or exited, do not
			 * add the dentry (e.g. in the case that a touch is
			 * issued on a file that already exists that was
			 * interrupted during this lookup -- no need to add
			 * another negative dentry for an existing file)
			 */

			gossip_debug(GOSSIP_NAME_DEBUG,
169
				     "orangefs_lookup: Adding *negative* dentry "
M
Mike Marshall 已提交
170 171 172 173 174 175 176 177 178 179 180 181 182 183
				     "%p for %s\n",
				     dentry,
				     dentry->d_name.name);

			d_add(dentry, NULL);
			res = NULL;
			goto out;
		}

		/* must be a non-recoverable error */
		res = ERR_PTR(ret);
		goto out;
	}

184
	inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn);
M
Mike Marshall 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
	if (IS_ERR(inode)) {
		gossip_debug(GOSSIP_NAME_DEBUG,
			"error %ld from iget\n", PTR_ERR(inode));
		res = ERR_CAST(inode);
		goto out;
	}

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s:%s:%d "
		     "Found good inode [%lu] with count [%d]\n",
		     __FILE__,
		     __func__,
		     __LINE__,
		     inode->i_ino,
		     (int)atomic_read(&inode->i_count));

	/* update dentry/inode pair into dcache */
	res = d_splice_alias(inode, dentry);

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Lookup success (inode ct = %d)\n",
		     (int)atomic_read(&inode->i_count));
out:
	op_release(new_op);
	return res;
}

/* return 0 on success; non-zero otherwise */
213
static int orangefs_unlink(struct inode *dir, struct dentry *dentry)
M
Mike Marshall 已提交
214 215
{
	struct inode *inode = dentry->d_inode;
216 217
	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
	struct orangefs_kernel_op_s *new_op;
M
Mike Marshall 已提交
218 219 220 221 222 223 224 225 226 227 228
	int ret;

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s: called on %s\n"
		     "  (inode %pU): Parent is %pU | fs_id %d\n",
		     __func__,
		     dentry->d_name.name,
		     get_khandle_from_ino(inode),
		     &parent->refn.khandle,
		     parent->refn.fs_id);

229
	new_op = op_alloc(ORANGEFS_VFS_OP_REMOVE);
M
Mike Marshall 已提交
230 231 232 233 234
	if (!new_op)
		return -ENOMEM;

	new_op->upcall.req.remove.parent_refn = parent->refn;
	strncpy(new_op->upcall.req.remove.d_name, dentry->d_name.name,
235
		ORANGEFS_NAME_MAX);
M
Mike Marshall 已提交
236

237
	ret = service_operation(new_op, "orangefs_unlink",
M
Mike Marshall 已提交
238 239
				get_interruptible_flag(inode));

240 241 242 243 244
	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s: service_operation returned:%d:\n",
		     __func__,
		     ret);

M
Mike Marshall 已提交
245 246 247 248 249 250 251 252 253 254 255 256
	op_release(new_op);

	if (!ret) {
		drop_nlink(inode);

		SetMtimeFlag(parent);
		dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
		mark_inode_dirty_sync(dir);
	}
	return ret;
}

257
static int orangefs_symlink(struct inode *dir,
M
Mike Marshall 已提交
258 259 260
			 struct dentry *dentry,
			 const char *symname)
{
261 262
	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
	struct orangefs_kernel_op_s *new_op;
M
Mike Marshall 已提交
263 264 265 266 267 268 269 270 271
	struct inode *inode;
	int mode = 755;
	int ret;

	gossip_debug(GOSSIP_NAME_DEBUG, "%s: called\n", __func__);

	if (!symname)
		return -EINVAL;

272 273 274
	if (strlen(symname)+1 > ORANGEFS_NAME_MAX)
		return -ENAMETOOLONG;

275
	new_op = op_alloc(ORANGEFS_VFS_OP_SYMLINK);
M
Mike Marshall 已提交
276 277 278 279 280 281
	if (!new_op)
		return -ENOMEM;

	new_op->upcall.req.sym.parent_refn = parent->refn;

	fill_default_sys_attrs(new_op->upcall.req.sym.attributes,
282
			       ORANGEFS_TYPE_SYMLINK,
M
Mike Marshall 已提交
283 284 285 286
			       mode);

	strncpy(new_op->upcall.req.sym.entry_name,
		dentry->d_name.name,
287 288
		ORANGEFS_NAME_MAX);
	strncpy(new_op->upcall.req.sym.target, symname, ORANGEFS_NAME_MAX);
M
Mike Marshall 已提交
289 290 291 292

	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));

	gossip_debug(GOSSIP_NAME_DEBUG,
293
		     "Symlink Got ORANGEFS handle %pU on fsid %d (ret=%d)\n",
M
Mike Marshall 已提交
294 295 296 297 298 299 300 301 302 303
		     &new_op->downcall.resp.sym.refn.khandle,
		     new_op->downcall.resp.sym.refn.fs_id, ret);

	if (ret < 0) {
		gossip_debug(GOSSIP_NAME_DEBUG,
			    "%s: failed with error code %d\n",
			    __func__, ret);
		goto out;
	}

304
	inode = orangefs_new_inode(dir->i_sb, dir, S_IFLNK | mode, 0,
M
Mike Marshall 已提交
305 306 307
				&new_op->downcall.resp.sym.refn);
	if (IS_ERR(inode)) {
		gossip_err
308
		    ("*** Failed to allocate orangefs symlink inode\n");
M
Mike Marshall 已提交
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
		ret = PTR_ERR(inode);
		goto out;
	}

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Assigned symlink inode new number of %pU\n",
		     get_khandle_from_ino(inode));

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Inode (Symlink) %pU -> %s\n",
		     get_khandle_from_ino(inode),
		     dentry->d_name.name);

	SetMtimeFlag(parent);
	dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
	mark_inode_dirty_sync(dir);
	ret = 0;
out:
	op_release(new_op);
	return ret;
}

334
static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
M
Mike Marshall 已提交
335
{
336 337
	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
	struct orangefs_kernel_op_s *new_op;
M
Mike Marshall 已提交
338 339 340
	struct inode *inode;
	int ret;

341
	new_op = op_alloc(ORANGEFS_VFS_OP_MKDIR);
M
Mike Marshall 已提交
342 343 344 345 346 347
	if (!new_op)
		return -ENOMEM;

	new_op->upcall.req.mkdir.parent_refn = parent->refn;

	fill_default_sys_attrs(new_op->upcall.req.mkdir.attributes,
348
			      ORANGEFS_TYPE_DIRECTORY, mode);
M
Mike Marshall 已提交
349 350

	strncpy(new_op->upcall.req.mkdir.d_name,
351
		dentry->d_name.name, ORANGEFS_NAME_MAX);
M
Mike Marshall 已提交
352 353 354 355

	ret = service_operation(new_op, __func__, get_interruptible_flag(dir));

	gossip_debug(GOSSIP_NAME_DEBUG,
356
		     "Mkdir Got ORANGEFS handle %pU on fsid %d\n",
M
Mike Marshall 已提交
357 358 359 360 361 362 363 364 365 366
		     &new_op->downcall.resp.mkdir.refn.khandle,
		     new_op->downcall.resp.mkdir.refn.fs_id);

	if (ret < 0) {
		gossip_debug(GOSSIP_NAME_DEBUG,
			     "%s: failed with error code %d\n",
			     __func__, ret);
		goto out;
	}

367
	inode = orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0,
M
Mike Marshall 已提交
368 369
				&new_op->downcall.resp.mkdir.refn);
	if (IS_ERR(inode)) {
370
		gossip_err("*** Failed to allocate orangefs dir inode\n");
M
Mike Marshall 已提交
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
		ret = PTR_ERR(inode);
		goto out;
	}

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Assigned dir inode new number of %pU\n",
		     get_khandle_from_ino(inode));

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "Inode (Directory) %pU -> %s\n",
		     get_khandle_from_ino(inode),
		     dentry->d_name.name);

	/*
	 * NOTE: we have no good way to keep nlink consistent for directories
	 * across clients; keep constant at 1.
	 */
	SetMtimeFlag(parent);
	dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
	mark_inode_dirty_sync(dir);
out:
	op_release(new_op);
	return ret;
}

399
static int orangefs_rename(struct inode *old_dir,
M
Mike Marshall 已提交
400 401 402 403
			struct dentry *old_dentry,
			struct inode *new_dir,
			struct dentry *new_dentry)
{
404
	struct orangefs_kernel_op_s *new_op;
M
Mike Marshall 已提交
405 406 407
	int ret;

	gossip_debug(GOSSIP_NAME_DEBUG,
408
		     "orangefs_rename: called (%s/%s => %s/%s) ct=%d\n",
M
Mike Marshall 已提交
409 410 411 412 413 414
		     old_dentry->d_parent->d_name.name,
		     old_dentry->d_name.name,
		     new_dentry->d_parent->d_name.name,
		     new_dentry->d_name.name,
		     d_count(new_dentry));

415
	new_op = op_alloc(ORANGEFS_VFS_OP_RENAME);
M
Mike Marshall 已提交
416 417 418
	if (!new_op)
		return -EINVAL;

419 420
	new_op->upcall.req.rename.old_parent_refn = ORANGEFS_I(old_dir)->refn;
	new_op->upcall.req.rename.new_parent_refn = ORANGEFS_I(new_dir)->refn;
M
Mike Marshall 已提交
421 422 423

	strncpy(new_op->upcall.req.rename.d_old_name,
		old_dentry->d_name.name,
424
		ORANGEFS_NAME_MAX);
M
Mike Marshall 已提交
425 426
	strncpy(new_op->upcall.req.rename.d_new_name,
		new_dentry->d_name.name,
427
		ORANGEFS_NAME_MAX);
M
Mike Marshall 已提交
428 429

	ret = service_operation(new_op,
430
				"orangefs_rename",
M
Mike Marshall 已提交
431 432 433
				get_interruptible_flag(old_dentry->d_inode));

	gossip_debug(GOSSIP_NAME_DEBUG,
434
		     "orangefs_rename: got downcall status %d\n",
M
Mike Marshall 已提交
435 436 437 438 439 440 441 442 443
		     ret);

	if (new_dentry->d_inode)
		new_dentry->d_inode->i_ctime = CURRENT_TIME;

	op_release(new_op);
	return ret;
}

444 445 446 447 448 449 450 451 452 453 454 455 456
/* ORANGEFS implementation of VFS inode operations for directories */
struct inode_operations orangefs_dir_inode_operations = {
	.lookup = orangefs_lookup,
	.get_acl = orangefs_get_acl,
	.set_acl = orangefs_set_acl,
	.create = orangefs_create,
	.unlink = orangefs_unlink,
	.symlink = orangefs_symlink,
	.mkdir = orangefs_mkdir,
	.rmdir = orangefs_unlink,
	.rename = orangefs_rename,
	.setattr = orangefs_setattr,
	.getattr = orangefs_getattr,
M
Mike Marshall 已提交
457 458 459
	.setxattr = generic_setxattr,
	.getxattr = generic_getxattr,
	.removexattr = generic_removexattr,
460
	.listxattr = orangefs_listxattr,
461
	.permission = orangefs_permission,
M
Mike Marshall 已提交
462
};