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_LEN);
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_LEN - 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_LEN);
M
Mike Marshall 已提交
137 138 139 140 141 142 143 144

	gossip_debug(GOSSIP_NAME_DEBUG,
		     "%s: doing lookup on %s under %pU,%d (follow=%s)\n",
		     __func__,
		     new_op->upcall.req.lookup.d_name,
		     &new_op->upcall.req.lookup.parent_refn.khandle,
		     new_op->upcall.req.lookup.parent_refn.fs_id,
		     ((new_op->upcall.req.lookup.sym_follow ==
145
		       ORANGEFS_LOOKUP_LINK_FOLLOW) ? "yes" : "no"));
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 "
M
Mike Marshall 已提交
172 173 174 175 176 177 178 179 180 181 182 183 184 185
				     "%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;
	}

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

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

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

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

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

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

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

	if (!symname)
		return -EINVAL;

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

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

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

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

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

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

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

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

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

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

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

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

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

	gossip_debug(GOSSIP_NAME_DEBUG,
355
		     "Mkdir Got ORANGEFS handle %pU on fsid %d\n",
M
Mike Marshall 已提交
356 357 358 359 360 361 362 363 364 365
		     &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;
	}

366
	inode = orangefs_new_inode(dir->i_sb, dir, S_IFDIR | mode, 0,
M
Mike Marshall 已提交
367 368
				&new_op->downcall.resp.mkdir.refn);
	if (IS_ERR(inode)) {
369
		gossip_err("*** Failed to allocate orangefs dir inode\n");
M
Mike Marshall 已提交
370 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
		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;
}

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

	gossip_debug(GOSSIP_NAME_DEBUG,
407
		     "orangefs_rename: called (%s/%s => %s/%s) ct=%d\n",
M
Mike Marshall 已提交
408 409 410 411 412 413
		     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));

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

418 419
	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 已提交
420 421 422

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

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

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

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

	op_release(new_op);
	return ret;
}

443 444 445 446 447 448 449 450 451 452 453 454 455
/* 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 已提交
456 457 458
	.setxattr = generic_setxattr,
	.getxattr = generic_getxattr,
	.removexattr = generic_removexattr,
459
	.listxattr = orangefs_listxattr,
460
	.permission = orangefs_permission,
M
Mike Marshall 已提交
461
};