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

	d_instantiate(dentry, inode);
	unlock_new_inode(inode);
75
	dentry->d_time = jiffies + HZ;
M
Mike Marshall 已提交
76 77

	gossip_debug(GOSSIP_NAME_DEBUG,
78 79
		     "%s: dentry instantiated for %s\n",
		     __func__,
M
Mike Marshall 已提交
80 81 82 83 84 85 86 87
		     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);
88 89 90 91 92
	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s: %s: returning %d\n",
		     __func__,
		     dentry->d_name.name,
		     ret);
M
Mike Marshall 已提交
93 94 95 96 97 98 99
	return ret;
}

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

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

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

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

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

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

	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,
170
				     "orangefs_lookup: Adding *negative* dentry "
M
Mike Marshall 已提交
171 172 173 174 175 176 177 178 179 180 181 182 183 184
				     "%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;
	}

185 186
	dentry->d_time = jiffies + HZ;

187
	inode = orangefs_iget(dir->i_sb, &new_op->downcall.resp.lookup.refn);
M
Mike Marshall 已提交
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 213 214 215
	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 */
216
static int orangefs_unlink(struct inode *dir, struct dentry *dentry)
M
Mike Marshall 已提交
217 218
{
	struct inode *inode = dentry->d_inode;
219 220
	struct orangefs_inode_s *parent = ORANGEFS_I(dir);
	struct orangefs_kernel_op_s *new_op;
M
Mike Marshall 已提交
221 222 223 224 225 226 227 228 229 230 231
	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);

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

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

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

M
Mike Marshall 已提交
248 249 250 251 252 253 254 255 256 257 258 259
	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;
}

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

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

	if (!symname)
		return -EINVAL;

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

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

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

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

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

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

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

307
	inode = orangefs_new_inode(dir->i_sb, dir, S_IFLNK | mode, 0,
M
Mike Marshall 已提交
308 309 310
				&new_op->downcall.resp.sym.refn);
	if (IS_ERR(inode)) {
		gossip_err
311
		    ("*** Failed to allocate orangefs symlink inode\n");
M
Mike Marshall 已提交
312 313 314 315 316 317 318 319 320 321
		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);
322
	dentry->d_time = jiffies + HZ;
M
Mike Marshall 已提交
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337

	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;
}

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

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

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

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

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

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

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

371
	inode = orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0,
M
Mike Marshall 已提交
372 373
				&new_op->downcall.resp.mkdir.refn);
	if (IS_ERR(inode)) {
374
		gossip_err("*** Failed to allocate orangefs dir inode\n");
M
Mike Marshall 已提交
375 376 377 378 379 380 381 382 383 384
		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);
385
	dentry->d_time = jiffies + HZ;
M
Mike Marshall 已提交
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403

	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;
}

404
static int orangefs_rename(struct inode *old_dir,
M
Mike Marshall 已提交
405 406 407 408
			struct dentry *old_dentry,
			struct inode *new_dir,
			struct dentry *new_dentry)
{
409
	struct orangefs_kernel_op_s *new_op;
M
Mike Marshall 已提交
410 411 412
	int ret;

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

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

420 421
	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 已提交
422 423 424

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

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

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

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

	op_release(new_op);
	return ret;
}

445
/* ORANGEFS implementation of VFS inode operations for directories */
A
Al Viro 已提交
446
const struct inode_operations orangefs_dir_inode_operations = {
447 448 449 450 451 452 453 454 455 456 457
	.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 已提交
458 459 460
	.setxattr = generic_setxattr,
	.getxattr = generic_getxattr,
	.removexattr = generic_removexattr,
461
	.listxattr = orangefs_listxattr,
462
	.permission = orangefs_permission,
M
Mike Marshall 已提交
463
};