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;

A
Al Viro 已提交
27
	gossip_debug(GOSSIP_NAME_DEBUG, "%s: %pd\n",
28
		     __func__,
A
Al Viro 已提交
29
		     dentry);
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,
A
Al Viro 已提交
46
		     "%s: %pd: handle:%pU: fsid:%d: new_op:%p: ret:%d:\n",
47
		     __func__,
A
Al Viro 已提交
48
		     dentry,
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)) {
A
Al Viro 已提交
60
		gossip_err("%s: Failed to allocate inode for file :%pd:\n",
61
			   __func__,
A
Al Viro 已提交
62
			   dentry);
M
Mike Marshall 已提交
63 64 65 66 67
		ret = PTR_ERR(inode);
		goto out;
	}

	gossip_debug(GOSSIP_NAME_DEBUG,
A
Al Viro 已提交
68
		     "%s: Assigned inode :%pU: for file :%pd:\n",
69 70
		     __func__,
		     get_khandle_from_ino(inode),
A
Al Viro 已提交
71
		     dentry);
M
Mike Marshall 已提交
72 73 74

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);
M
Miklos Szeredi 已提交
75
	orangefs_set_timeout(dentry);
76
	ORANGEFS_I(inode)->getattr_time = jiffies - 1;
M
Mike Marshall 已提交
77 78

	gossip_debug(GOSSIP_NAME_DEBUG,
A
Al Viro 已提交
79
		     "%s: dentry instantiated for %pd\n",
80
		     __func__,
A
Al Viro 已提交
81
		     dentry);
M
Mike Marshall 已提交
82 83

	SetMtimeFlag(parent);
84
	dir->i_mtime = dir->i_ctime = current_time(dir);
M
Mike Marshall 已提交
85 86 87 88
	mark_inode_dirty_sync(dir);
	ret = 0;
out:
	op_release(new_op);
89
	gossip_debug(GOSSIP_NAME_DEBUG,
A
Al Viro 已提交
90
		     "%s: %pd: returning %d\n",
91
		     __func__,
A
Al Viro 已提交
92
		     dentry,
93
		     ret);
M
Mike Marshall 已提交
94 95 96 97 98 99 100
	return ret;
}

/*
 * Attempt to resolve an object name (dentry->d_name), parent handle, and
 * fsid into a handle for the object.
 */
101
static struct dentry *orangefs_lookup(struct inode *dir, struct dentry *dentry,
M
Mike Marshall 已提交
102 103
				   unsigned int flags)
{
104 105
	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
	struct orangefs_kernel_op_s *new_op;
M
Mike Marshall 已提交
106 107 108 109 110 111 112 113 114 115 116 117
	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)
	 */
A
Al Viro 已提交
118 119
	gossip_debug(GOSSIP_NAME_DEBUG, "%s called on %pd\n",
		     __func__, dentry);
M
Mike Marshall 已提交
120

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

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

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

	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,
138
		ORANGEFS_NAME_MAX);
M
Mike Marshall 已提交
139 140

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

	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,
171
				     "orangefs_lookup: Adding *negative* dentry "
A
Al Viro 已提交
172
				     "%p for %pd\n",
M
Mike Marshall 已提交
173
				     dentry,
A
Al Viro 已提交
174
				     dentry);
M
Mike Marshall 已提交
175 176 177 178 179 180 181 182 183 184 185

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

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

M
Miklos Szeredi 已提交
186
	orangefs_set_timeout(dentry);
187

188
	inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn);
M
Mike Marshall 已提交
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
	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 */
217
static int orangefs_unlink(struct inode *dir, struct dentry *dentry)
M
Mike Marshall 已提交
218 219
{
	struct inode *inode = dentry->d_inode;
220 221
	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
	struct orangefs_kernel_op_s *new_op;
M
Mike Marshall 已提交
222 223 224
	int ret;

	gossip_debug(GOSSIP_NAME_DEBUG,
A
Al Viro 已提交
225
		     "%s: called on %pd\n"
M
Mike Marshall 已提交
226 227
		     "  (inode %pU): Parent is %pU | fs_id %d\n",
		     __func__,
A
Al Viro 已提交
228
		     dentry,
M
Mike Marshall 已提交
229 230 231 232
		     get_khandle_from_ino(inode),
		     &parent->refn.khandle,
		     parent->refn.fs_id);

233
	new_op = op_alloc(ORANGEFS_VFS_OP_REMOVE);
M
Mike Marshall 已提交
234 235 236 237 238
	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,
239
		ORANGEFS_NAME_MAX);
M
Mike Marshall 已提交
240

241
	ret = service_operation(new_op, "orangefs_unlink",
M
Mike Marshall 已提交
242 243
				get_interruptible_flag(inode));

244 245 246 247 248
	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s: service_operation returned:%d:\n",
		     __func__,
		     ret);

M
Mike Marshall 已提交
249 250 251 252 253 254
	op_release(new_op);

	if (!ret) {
		drop_nlink(inode);

		SetMtimeFlag(parent);
255
		dir->i_mtime = dir->i_ctime = current_time(dir);
M
Mike Marshall 已提交
256 257 258 259 260
		mark_inode_dirty_sync(dir);
	}
	return ret;
}

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

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

	if (!symname)
		return -EINVAL;

276 277 278
	if (strlen(symname)+1 > ORANGEFS_NAME_MAX)
		return -ENAMETOOLONG;

279
	new_op = op_alloc(ORANGEFS_VFS_OP_SYMLINK);
M
Mike Marshall 已提交
280 281 282 283 284 285
	if (!new_op)
		return -ENOMEM;

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

	fill_default_sys_attrs(new_op->upcall.req.sym.attributes,
286
			       ORANGEFS_TYPE_SYMLINK,
M
Mike Marshall 已提交
287 288 289 290
			       mode);

	strncpy(new_op->upcall.req.sym.entry_name,
		dentry->d_name.name,
291 292
		ORANGEFS_NAME_MAX);
	strncpy(new_op->upcall.req.sym.target, symname, ORANGEFS_NAME_MAX);
M
Mike Marshall 已提交
293 294 295 296

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

	gossip_debug(GOSSIP_NAME_DEBUG,
297
		     "Symlink Got ORANGEFS handle %pU on fsid %d (ret=%d)\n",
M
Mike Marshall 已提交
298 299 300 301 302 303 304 305 306 307
		     &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;
	}

308
	inode = orangefs_new_inode(dir->i_sb, dir, S_IFLNK | mode, 0,
M
Mike Marshall 已提交
309 310 311
				&new_op->downcall.resp.sym.refn);
	if (IS_ERR(inode)) {
		gossip_err
312
		    ("*** Failed to allocate orangefs symlink inode\n");
M
Mike Marshall 已提交
313 314 315 316 317 318 319 320 321 322
		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);
M
Miklos Szeredi 已提交
323
	orangefs_set_timeout(dentry);
324
	ORANGEFS_I(inode)->getattr_time = jiffies - 1;
M
Mike Marshall 已提交
325 326

	gossip_debug(GOSSIP_NAME_DEBUG,
A
Al Viro 已提交
327
		     "Inode (Symlink) %pU -> %pd\n",
M
Mike Marshall 已提交
328
		     get_khandle_from_ino(inode),
A
Al Viro 已提交
329
		     dentry);
M
Mike Marshall 已提交
330 331

	SetMtimeFlag(parent);
332
	dir->i_mtime = dir->i_ctime = current_time(dir);
M
Mike Marshall 已提交
333 334 335 336 337 338 339
	mark_inode_dirty_sync(dir);
	ret = 0;
out:
	op_release(new_op);
	return ret;
}

340
static int orangefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
M
Mike Marshall 已提交
341
{
342 343
	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
	struct orangefs_kernel_op_s *new_op;
M
Mike Marshall 已提交
344 345 346
	struct inode *inode;
	int ret;

347
	new_op = op_alloc(ORANGEFS_VFS_OP_MKDIR);
M
Mike Marshall 已提交
348 349 350 351 352 353
	if (!new_op)
		return -ENOMEM;

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

	fill_default_sys_attrs(new_op->upcall.req.mkdir.attributes,
354
			      ORANGEFS_TYPE_DIRECTORY, mode);
M
Mike Marshall 已提交
355 356

	strncpy(new_op->upcall.req.mkdir.d_name,
357
		dentry->d_name.name, ORANGEFS_NAME_MAX);
M
Mike Marshall 已提交
358 359 360 361

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

	gossip_debug(GOSSIP_NAME_DEBUG,
362
		     "Mkdir Got ORANGEFS handle %pU on fsid %d\n",
M
Mike Marshall 已提交
363 364 365 366 367 368 369 370 371 372
		     &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;
	}

373
	inode = orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0,
M
Mike Marshall 已提交
374 375
				&new_op->downcall.resp.mkdir.refn);
	if (IS_ERR(inode)) {
376
		gossip_err("*** Failed to allocate orangefs dir inode\n");
M
Mike Marshall 已提交
377 378 379 380 381 382 383 384 385 386
		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);
M
Miklos Szeredi 已提交
387
	orangefs_set_timeout(dentry);
388
	ORANGEFS_I(inode)->getattr_time = jiffies - 1;
M
Mike Marshall 已提交
389 390

	gossip_debug(GOSSIP_NAME_DEBUG,
A
Al Viro 已提交
391
		     "Inode (Directory) %pU -> %pd\n",
M
Mike Marshall 已提交
392
		     get_khandle_from_ino(inode),
A
Al Viro 已提交
393
		     dentry);
M
Mike Marshall 已提交
394 395 396 397 398 399

	/*
	 * NOTE: we have no good way to keep nlink consistent for directories
	 * across clients; keep constant at 1.
	 */
	SetMtimeFlag(parent);
400
	dir->i_mtime = dir->i_ctime = current_time(dir);
M
Mike Marshall 已提交
401 402 403 404 405 406
	mark_inode_dirty_sync(dir);
out:
	op_release(new_op);
	return ret;
}

407
static int orangefs_rename(struct inode *old_dir,
M
Mike Marshall 已提交
408 409
			struct dentry *old_dentry,
			struct inode *new_dir,
410 411
			struct dentry *new_dentry,
			unsigned int flags)
M
Mike Marshall 已提交
412
{
413
	struct orangefs_kernel_op_s *new_op;
M
Mike Marshall 已提交
414 415
	int ret;

416 417 418
	if (flags)
		return -EINVAL;

M
Mike Marshall 已提交
419
	gossip_debug(GOSSIP_NAME_DEBUG,
A
Al Viro 已提交
420 421
		     "orangefs_rename: called (%pd2 => %pd2) ct=%d\n",
		     old_dentry, new_dentry, d_count(new_dentry));
M
Mike Marshall 已提交
422

423
	ORANGEFS_I(new_dentry->d_parent->d_inode)->getattr_time = jiffies - 1;
424

425
	new_op = op_alloc(ORANGEFS_VFS_OP_RENAME);
M
Mike Marshall 已提交
426 427 428
	if (!new_op)
		return -EINVAL;

429 430
	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 已提交
431 432 433

	strncpy(new_op->upcall.req.rename.d_old_name,
		old_dentry->d_name.name,
434
		ORANGEFS_NAME_MAX);
M
Mike Marshall 已提交
435 436
	strncpy(new_op->upcall.req.rename.d_new_name,
		new_dentry->d_name.name,
437
		ORANGEFS_NAME_MAX);
M
Mike Marshall 已提交
438 439

	ret = service_operation(new_op,
440
				"orangefs_rename",
M
Mike Marshall 已提交
441 442 443
				get_interruptible_flag(old_dentry->d_inode));

	gossip_debug(GOSSIP_NAME_DEBUG,
444
		     "orangefs_rename: got downcall status %d\n",
M
Mike Marshall 已提交
445 446 447
		     ret);

	if (new_dentry->d_inode)
448
		new_dentry->d_inode->i_ctime = current_time(new_dentry->d_inode);
M
Mike Marshall 已提交
449 450 451 452 453

	op_release(new_op);
	return ret;
}

454
/* ORANGEFS implementation of VFS inode operations for directories */
A
Al Viro 已提交
455
const struct inode_operations orangefs_dir_inode_operations = {
456 457 458 459 460 461 462 463 464 465 466 467
	.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,
	.listxattr = orangefs_listxattr,
468
	.permission = orangefs_permission,
M
Mike Marshall 已提交
469
};