xfs_iget.c 18.9 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2 3
 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
 * All Rights Reserved.
L
Linus Torvalds 已提交
4
 *
5 6
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
L
Linus Torvalds 已提交
7 8
 * published by the Free Software Foundation.
 *
9 10 11 12
 * This program is distributed in the hope that it would be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
L
Linus Torvalds 已提交
13
 *
14 15 16
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write the Free Software Foundation,
 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
L
Linus Torvalds 已提交
17 18
 */
#include "xfs.h"
19
#include "xfs_fs.h"
L
Linus Torvalds 已提交
20
#include "xfs_types.h"
21
#include "xfs_bit.h"
L
Linus Torvalds 已提交
22
#include "xfs_log.h"
23
#include "xfs_inum.h"
L
Linus Torvalds 已提交
24 25 26 27 28 29 30
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
31
#include "xfs_alloc_btree.h"
L
Linus Torvalds 已提交
32 33
#include "xfs_ialloc_btree.h"
#include "xfs_dir2_sf.h"
34
#include "xfs_attr_sf.h"
L
Linus Torvalds 已提交
35 36
#include "xfs_dinode.h"
#include "xfs_inode.h"
37 38
#include "xfs_btree.h"
#include "xfs_ialloc.h"
L
Linus Torvalds 已提交
39 40 41 42 43
#include "xfs_quota.h"
#include "xfs_utils.h"

/*
 * Look up an inode by number in the given file system.
44 45 46
 * The inode is looked up in the cache held in each AG.
 * If the inode is found in the cache, attach it to the provided
 * vnode.
L
Linus Torvalds 已提交
47
 *
48 49
 * If it is not in core, read it in from the file system's device,
 * add it to the cache and attach the provided vnode.
L
Linus Torvalds 已提交
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
 *
 * The inode is locked according to the value of the lock_flags parameter.
 * This flag parameter indicates how and if the inode's IO lock and inode lock
 * should be taken.
 *
 * mp -- the mount point structure for the current file system.  It points
 *       to the inode hash table.
 * tp -- a pointer to the current transaction if there is one.  This is
 *       simply passed through to the xfs_iread() call.
 * ino -- the number of the inode desired.  This is the unique identifier
 *        within the file system for the inode being requested.
 * lock_flags -- flags indicating how to lock the inode.  See the comment
 *		 for xfs_ilock() for a list of valid values.
 * bno -- the block number starting the buffer containing the inode,
 *	  if known (as by bulkstat), else 0.
 */
STATIC int
xfs_iget_core(
68
	struct inode	*inode,
L
Linus Torvalds 已提交
69 70 71 72 73 74 75 76
	xfs_mount_t	*mp,
	xfs_trans_t	*tp,
	xfs_ino_t	ino,
	uint		flags,
	uint		lock_flags,
	xfs_inode_t	**ipp,
	xfs_daddr_t	bno)
{
77
	struct inode	*old_inode;
L
Linus Torvalds 已提交
78 79
	xfs_inode_t	*ip;
	int		error;
80 81 82 83 84 85 86 87 88 89 90 91 92 93
	unsigned long	first_index, mask;
	xfs_perag_t	*pag;
	xfs_agino_t	agino;

	/* the radix tree exists only in inode capable AGs */
	if (XFS_INO_TO_AGNO(mp, ino) >= mp->m_maxagi)
		return EINVAL;

	/* get the perag structure and ensure that it's inode capable */
	pag = xfs_get_perag(mp, ino);
	if (!pag->pagi_inodeok)
		return EINVAL;
	ASSERT(pag->pag_ici_init);
	agino = XFS_INO_TO_AGINO(mp, ino);
L
Linus Torvalds 已提交
94 95

again:
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
	read_lock(&pag->pag_ici_lock);
	ip = radix_tree_lookup(&pag->pag_ici_root, agino);

	if (ip != NULL) {
		/*
		 * If INEW is set this inode is being set up
		 * we need to pause and try again.
		 */
		if (xfs_iflags_test(ip, XFS_INEW)) {
			read_unlock(&pag->pag_ici_lock);
			delay(1);
			XFS_STATS_INC(xs_ig_frecycle);

			goto again;
		}
L
Linus Torvalds 已提交
111

112 113
		old_inode = ip->i_vnode;
		if (old_inode == NULL) {
L
Linus Torvalds 已提交
114
			/*
115 116
			 * If IRECLAIM is set this inode is
			 * on its way out of the system,
L
Linus Torvalds 已提交
117 118
			 * we need to pause and try again.
			 */
119 120
			if (xfs_iflags_test(ip, XFS_IRECLAIM)) {
				read_unlock(&pag->pag_ici_lock);
L
Linus Torvalds 已提交
121 122 123 124 125
				delay(1);
				XFS_STATS_INC(xs_ig_frecycle);

				goto again;
			}
126
			ASSERT(xfs_iflags_test(ip, XFS_IRECLAIMABLE));
L
Linus Torvalds 已提交
127

128 129 130 131 132 133 134 135 136 137 138 139
			/*
			 * If lookup is racing with unlink, then we
			 * should return an error immediately so we
			 * don't remove it from the reclaim list and
			 * potentially leak the inode.
			 */
			if ((ip->i_d.di_mode == 0) &&
			    !(flags & XFS_IGET_CREATE)) {
				read_unlock(&pag->pag_ici_lock);
				xfs_put_perag(mp, pag);
				return ENOENT;
			}
L
Linus Torvalds 已提交
140

141
			xfs_itrace_exit_tag(ip, "xfs_iget.alloc");
L
Linus Torvalds 已提交
142

143 144 145
			XFS_STATS_INC(xs_ig_found);
			xfs_iflags_clear(ip, XFS_IRECLAIMABLE);
			read_unlock(&pag->pag_ici_lock);
L
Linus Torvalds 已提交
146

147 148 149
			XFS_MOUNT_ILOCK(mp);
			list_del_init(&ip->i_reclaim);
			XFS_MOUNT_IUNLOCK(mp);
L
Linus Torvalds 已提交
150

151
			goto finish_inode;
L
Linus Torvalds 已提交
152

153
		} else if (inode != old_inode) {
154 155
			/* The inode is being torn down, pause and
			 * try again.
156
			 */
157
			if (old_inode->i_state & (I_FREEING | I_CLEAR)) {
158 159 160
				read_unlock(&pag->pag_ici_lock);
				delay(1);
				XFS_STATS_INC(xs_ig_frecycle);
L
Linus Torvalds 已提交
161

162
				goto again;
L
Linus Torvalds 已提交
163
			}
164 165 166 167 168 169
/* Chances are the other vnode (the one in the inode) is being torn
* down right now, and we landed on top of it. Question is, what do
* we do? Unhook the old inode and hook up the new one?
*/
			cmn_err(CE_PANIC,
		"xfs_iget_core: ambiguous vns: vp/0x%p, invp/0x%p",
170
					old_inode, inode);
171
		}
172

173 174 175 176 177
		/*
		 * Inode cache hit
		 */
		read_unlock(&pag->pag_ici_lock);
		XFS_STATS_INC(xs_ig_found);
L
Linus Torvalds 已提交
178

179
finish_inode:
C
Christoph Hellwig 已提交
180 181 182
		if (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) {
			xfs_put_perag(mp, pag);
			return ENOENT;
L
Linus Torvalds 已提交
183
		}
184 185 186 187 188

		if (lock_flags != 0)
			xfs_ilock(ip, lock_flags);

		xfs_iflags_clear(ip, XFS_ISTALE);
189
		xfs_itrace_exit_tag(ip, "xfs_iget.found");
190
		goto return_ip;
L
Linus Torvalds 已提交
191 192 193
	}

	/*
194
	 * Inode cache miss
L
Linus Torvalds 已提交
195
	 */
196
	read_unlock(&pag->pag_ici_lock);
L
Linus Torvalds 已提交
197 198 199 200 201 202
	XFS_STATS_INC(xs_ig_missed);

	/*
	 * Read the disk inode attributes into a new inode structure and get
	 * a new vnode for it. This should also initialize i_ino and i_mount.
	 */
203 204
	error = xfs_iread(mp, tp, ino, &ip, bno,
			  (flags & XFS_IGET_BULKSTAT) ? XFS_IMAP_BULKSTAT : 0);
205 206
	if (error) {
		xfs_put_perag(mp, pag);
L
Linus Torvalds 已提交
207
		return error;
208
	}
L
Linus Torvalds 已提交
209

210
	xfs_itrace_exit_tag(ip, "xfs_iget.alloc");
L
Linus Torvalds 已提交
211

212
	if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) {
L
Linus Torvalds 已提交
213
		xfs_idestroy(ip);
214
		xfs_put_perag(mp, pag);
L
Linus Torvalds 已提交
215 216 217 218
		return ENOENT;
	}

	/*
219 220
	 * Preload the radix tree so we can insert safely under the
	 * write spinlock.
L
Linus Torvalds 已提交
221
	 */
222
	if (radix_tree_preload(GFP_KERNEL)) {
223
		xfs_idestroy(ip);
224 225 226
		delay(1);
		goto again;
	}
227 228 229 230

	if (lock_flags)
		xfs_ilock(ip, lock_flags);

231 232 233 234 235 236 237 238 239 240 241
	mask = ~(((XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog)) - 1);
	first_index = agino & mask;
	write_lock(&pag->pag_ici_lock);
	/*
	 * insert the new inode
	 */
	error = radix_tree_insert(&pag->pag_ici_root, agino, ip);
	if (unlikely(error)) {
		BUG_ON(error != -EEXIST);
		write_unlock(&pag->pag_ici_lock);
		radix_tree_preload_end();
242 243
		if (lock_flags)
			xfs_iunlock(ip, lock_flags);
244 245 246
		xfs_idestroy(ip);
		XFS_STATS_INC(xs_ig_dup);
		goto again;
L
Linus Torvalds 已提交
247 248 249
	}

	/*
250
	 * These values _must_ be set before releasing the radix tree lock!
L
Linus Torvalds 已提交
251 252
	 */
	ip->i_udquot = ip->i_gdquot = NULL;
253
	xfs_iflags_set(ip, XFS_INEW);
L
Linus Torvalds 已提交
254

255 256 257
	write_unlock(&pag->pag_ici_lock);
	radix_tree_preload_end();
	xfs_put_perag(mp, pag);
L
Linus Torvalds 已提交
258 259 260 261 262

 return_ip:
	ASSERT(ip->i_df.if_ext_max ==
	       XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t));

263
	xfs_iflags_set(ip, XFS_IMODIFIED);
L
Linus Torvalds 已提交
264 265
	*ipp = ip;

266 267 268 269 270 271
	/*
	 * Set up the Linux with the Linux inode.
	 */
	ip->i_vnode = inode;
	inode->i_private = ip;

L
Linus Torvalds 已提交
272 273 274 275
	/*
	 * If we have a real type for an on-disk inode, we can set ops(&unlock)
	 * now.	 If it's a new inode being created, xfs_ialloc will handle it.
	 */
276 277
	if (ip->i_d.di_mode != 0)
		xfs_setup_inode(ip);
L
Linus Torvalds 已提交
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
	return 0;
}


/*
 * The 'normal' internal xfs_iget, if needed it will
 * 'allocate', or 'get', the vnode.
 */
int
xfs_iget(
	xfs_mount_t	*mp,
	xfs_trans_t	*tp,
	xfs_ino_t	ino,
	uint		flags,
	uint		lock_flags,
	xfs_inode_t	**ipp,
	xfs_daddr_t	bno)
{
	struct inode	*inode;
297
	xfs_inode_t	*ip;
L
Linus Torvalds 已提交
298 299 300 301
	int		error;

	XFS_STATS_INC(xs_ig_attempts);

302
retry:
C
Christoph Hellwig 已提交
303
	inode = iget_locked(mp->m_super, ino);
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
	if (!inode)
		/* If we got no inode we are out of memory */
		return ENOMEM;

	if (inode->i_state & I_NEW) {
		XFS_STATS_INC(vn_active);
		XFS_STATS_INC(vn_alloc);

		error = xfs_iget_core(inode, mp, tp, ino, flags,
				lock_flags, ipp, bno);
		if (error) {
			make_bad_inode(inode);
			if (inode->i_state & I_NEW)
				unlock_new_inode(inode);
			iput(inode);
L
Linus Torvalds 已提交
319
		}
320 321
		return error;
	}
L
Linus Torvalds 已提交
322

323 324 325 326 327 328 329 330 331 332 333 334 335
	/*
	 * If the inode is not fully constructed due to
	 * filehandle mismatches wait for the inode to go
	 * away and try again.
	 *
	 * iget_locked will call __wait_on_freeing_inode
	 * to wait for the inode to go away.
	 */
	if (is_bad_inode(inode)) {
		iput(inode);
		delay(1);
		goto retry;
	}
L
Linus Torvalds 已提交
336

337 338 339 340 341 342 343 344 345 346 347 348
	ip = XFS_I(inode);
	if (!ip) {
		iput(inode);
		delay(1);
		goto retry;
	}

	if (lock_flags != 0)
		xfs_ilock(ip, lock_flags);
	XFS_STATS_INC(xs_ig_found);
	*ipp = ip;
	return 0;
L
Linus Torvalds 已提交
349 350 351 352 353 354 355 356 357 358 359 360 361
}

/*
 * Look for the inode corresponding to the given ino in the hash table.
 * If it is there and its i_transp pointer matches tp, return it.
 * Otherwise, return NULL.
 */
xfs_inode_t *
xfs_inode_incore(xfs_mount_t	*mp,
		 xfs_ino_t	ino,
		 xfs_trans_t	*tp)
{
	xfs_inode_t	*ip;
362 363 364 365 366 367 368 369 370 371 372 373
	xfs_perag_t	*pag;

	pag = xfs_get_perag(mp, ino);
	read_lock(&pag->pag_ici_lock);
	ip = radix_tree_lookup(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, ino));
	read_unlock(&pag->pag_ici_lock);
	xfs_put_perag(mp, pag);

	/* the returned inode must match the transaction */
	if (ip && (ip->i_transp != tp))
		return NULL;
	return ip;
L
Linus Torvalds 已提交
374 375 376 377 378 379 380 381 382 383 384 385 386 387
}

/*
 * Decrement reference count of an inode structure and unlock it.
 *
 * ip -- the inode being released
 * lock_flags -- this parameter indicates the inode's locks to be
 *       to be released.  See the comment on xfs_iunlock() for a list
 *	 of valid values.
 */
void
xfs_iput(xfs_inode_t	*ip,
	 uint		lock_flags)
{
388
	xfs_itrace_entry(ip);
L
Linus Torvalds 已提交
389
	xfs_iunlock(ip, lock_flags);
390
	IRELE(ip);
L
Linus Torvalds 已提交
391 392 393 394 395 396
}

/*
 * Special iput for brand-new inodes that are still locked
 */
void
397 398 399
xfs_iput_new(
	xfs_inode_t	*ip,
	uint		lock_flags)
L
Linus Torvalds 已提交
400
{
401
	struct inode	*inode = VFS_I(ip);
L
Linus Torvalds 已提交
402

403
	xfs_itrace_entry(ip);
L
Linus Torvalds 已提交
404 405

	if ((ip->i_d.di_mode == 0)) {
406
		ASSERT(!xfs_iflags_test(ip, XFS_IRECLAIMABLE));
407
		make_bad_inode(inode);
L
Linus Torvalds 已提交
408 409 410 411 412
	}
	if (inode->i_state & I_NEW)
		unlock_new_inode(inode);
	if (lock_flags)
		xfs_iunlock(ip, lock_flags);
413
	IRELE(ip);
L
Linus Torvalds 已提交
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
}


/*
 * This routine embodies the part of the reclaim code that pulls
 * the inode from the inode hash table and the mount structure's
 * inode list.
 * This should only be called from xfs_reclaim().
 */
void
xfs_ireclaim(xfs_inode_t *ip)
{
	/*
	 * Remove from old hash list and mount list.
	 */
	XFS_STATS_INC(xs_ig_reclaims);

	xfs_iextract(ip);

	/*
D
David Chinner 已提交
434 435 436 437 438 439 440
	 * Here we do a spurious inode lock in order to coordinate with inode
	 * cache radix tree lookups.  This is because the lookup can reference
	 * the inodes in the cache without taking references.  We make that OK
	 * here by ensuring that we wait until the inode is unlocked after the
	 * lookup before we go ahead and free it.  We get both the ilock and
	 * the iolock because the code may need to drop the ilock one but will
	 * still hold the iolock.
L
Linus Torvalds 已提交
441 442 443 444 445 446 447 448 449 450 451 452
	 */
	xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);

	/*
	 * Release dquots (and their references) if any. An inode may escape
	 * xfs_inactive and get here via vn_alloc->vn_reclaim path.
	 */
	XFS_QM_DQDETACH(ip->i_mount, ip);

	/*
	 * Pull our behavior descriptor from the vnode chain.
	 */
453 454
	if (ip->i_vnode) {
		ip->i_vnode->i_private = NULL;
455
		ip->i_vnode = NULL;
L
Linus Torvalds 已提交
456 457 458 459 460
	}

	/*
	 * Free all memory associated with the inode.
	 */
T
Tim Shimmin 已提交
461
	xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
L
Linus Torvalds 已提交
462 463 464 465 466 467 468 469 470 471 472 473
	xfs_idestroy(ip);
}

/*
 * This routine removes an about-to-be-destroyed inode from
 * all of the lists in which it is located with the exception
 * of the behavior chain.
 */
void
xfs_iextract(
	xfs_inode_t	*ip)
{
474 475 476 477 478 479 480
	xfs_mount_t	*mp = ip->i_mount;
	xfs_perag_t	*pag = xfs_get_perag(mp, ip->i_ino);

	write_lock(&pag->pag_ici_lock);
	radix_tree_delete(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, ip->i_ino));
	write_unlock(&pag->pag_ici_lock);
	xfs_put_perag(mp, pag);
L
Linus Torvalds 已提交
481 482

	/* Deal with the deleted inodes list */
D
David Chinner 已提交
483
	XFS_MOUNT_ILOCK(mp);
L
Linus Torvalds 已提交
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
	list_del_init(&ip->i_reclaim);
	mp->m_ireclaims++;
	XFS_MOUNT_IUNLOCK(mp);
}

/*
 * This is a wrapper routine around the xfs_ilock() routine
 * used to centralize some grungy code.  It is used in places
 * that wish to lock the inode solely for reading the extents.
 * The reason these places can't just call xfs_ilock(SHARED)
 * is that the inode lock also guards to bringing in of the
 * extents from disk for a file in b-tree format.  If the inode
 * is in b-tree format, then we need to lock the inode exclusively
 * until the extents are read in.  Locking it exclusively all
 * the time would limit our parallelism unnecessarily, though.
 * What we do instead is check to see if the extents have been
 * read in yet, and only lock the inode exclusively if they
 * have not.
 *
 * The function returns a value which should be given to the
 * corresponding xfs_iunlock_map_shared().  This value is
 * the mode in which the lock was actually taken.
 */
uint
xfs_ilock_map_shared(
	xfs_inode_t	*ip)
{
	uint	lock_mode;

	if ((ip->i_d.di_format == XFS_DINODE_FMT_BTREE) &&
	    ((ip->i_df.if_flags & XFS_IFEXTENTS) == 0)) {
		lock_mode = XFS_ILOCK_EXCL;
	} else {
		lock_mode = XFS_ILOCK_SHARED;
	}

	xfs_ilock(ip, lock_mode);

	return lock_mode;
}

/*
 * This is simply the unlock routine to go with xfs_ilock_map_shared().
 * All it does is call xfs_iunlock() with the given lock_mode.
 */
void
xfs_iunlock_map_shared(
	xfs_inode_t	*ip,
	unsigned int	lock_mode)
{
	xfs_iunlock(ip, lock_mode);
}

/*
 * The xfs inode contains 2 locks: a multi-reader lock called the
 * i_iolock and a multi-reader lock called the i_lock.  This routine
 * allows either or both of the locks to be obtained.
 *
 * The 2 locks should always be ordered so that the IO lock is
 * obtained first in order to prevent deadlock.
 *
 * ip -- the inode being locked
 * lock_flags -- this parameter indicates the inode's locks
 *       to be locked.  It can be:
 *		XFS_IOLOCK_SHARED,
 *		XFS_IOLOCK_EXCL,
 *		XFS_ILOCK_SHARED,
 *		XFS_ILOCK_EXCL,
 *		XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED,
 *		XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL,
 *		XFS_IOLOCK_EXCL | XFS_ILOCK_SHARED,
 *		XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL
 */
void
C
Christoph Hellwig 已提交
558 559 560
xfs_ilock(
	xfs_inode_t		*ip,
	uint			lock_flags)
L
Linus Torvalds 已提交
561 562 563 564 565 566 567 568 569 570
{
	/*
	 * You can't set both SHARED and EXCL for the same lock,
	 * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
	 * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
	 */
	ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
	       (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
	ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
	       (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
571
	ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
L
Linus Torvalds 已提交
572

C
Christoph Hellwig 已提交
573
	if (lock_flags & XFS_IOLOCK_EXCL)
574
		mrupdate_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags));
C
Christoph Hellwig 已提交
575
	else if (lock_flags & XFS_IOLOCK_SHARED)
576
		mraccess_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags));
C
Christoph Hellwig 已提交
577 578

	if (lock_flags & XFS_ILOCK_EXCL)
579
		mrupdate_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags));
C
Christoph Hellwig 已提交
580
	else if (lock_flags & XFS_ILOCK_SHARED)
581
		mraccess_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags));
C
Christoph Hellwig 已提交
582

L
Linus Torvalds 已提交
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
	xfs_ilock_trace(ip, 1, lock_flags, (inst_t *)__return_address);
}

/*
 * This is just like xfs_ilock(), except that the caller
 * is guaranteed not to sleep.  It returns 1 if it gets
 * the requested locks and 0 otherwise.  If the IO lock is
 * obtained but the inode lock cannot be, then the IO lock
 * is dropped before returning.
 *
 * ip -- the inode being locked
 * lock_flags -- this parameter indicates the inode's locks to be
 *       to be locked.  See the comment for xfs_ilock() for a list
 *	 of valid values.
 */
int
C
Christoph Hellwig 已提交
599 600 601
xfs_ilock_nowait(
	xfs_inode_t		*ip,
	uint			lock_flags)
L
Linus Torvalds 已提交
602 603 604 605 606 607 608 609 610 611
{
	/*
	 * You can't set both SHARED and EXCL for the same lock,
	 * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
	 * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
	 */
	ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
	       (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
	ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
	       (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
612
	ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
L
Linus Torvalds 已提交
613 614

	if (lock_flags & XFS_IOLOCK_EXCL) {
C
Christoph Hellwig 已提交
615 616
		if (!mrtryupdate(&ip->i_iolock))
			goto out;
L
Linus Torvalds 已提交
617
	} else if (lock_flags & XFS_IOLOCK_SHARED) {
C
Christoph Hellwig 已提交
618 619
		if (!mrtryaccess(&ip->i_iolock))
			goto out;
L
Linus Torvalds 已提交
620 621
	}
	if (lock_flags & XFS_ILOCK_EXCL) {
C
Christoph Hellwig 已提交
622 623
		if (!mrtryupdate(&ip->i_lock))
			goto out_undo_iolock;
L
Linus Torvalds 已提交
624
	} else if (lock_flags & XFS_ILOCK_SHARED) {
C
Christoph Hellwig 已提交
625 626
		if (!mrtryaccess(&ip->i_lock))
			goto out_undo_iolock;
L
Linus Torvalds 已提交
627 628 629
	}
	xfs_ilock_trace(ip, 2, lock_flags, (inst_t *)__return_address);
	return 1;
C
Christoph Hellwig 已提交
630 631 632 633 634 635 636 637

 out_undo_iolock:
	if (lock_flags & XFS_IOLOCK_EXCL)
		mrunlock_excl(&ip->i_iolock);
	else if (lock_flags & XFS_IOLOCK_SHARED)
		mrunlock_shared(&ip->i_iolock);
 out:
	return 0;
L
Linus Torvalds 已提交
638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
}

/*
 * xfs_iunlock() is used to drop the inode locks acquired with
 * xfs_ilock() and xfs_ilock_nowait().  The caller must pass
 * in the flags given to xfs_ilock() or xfs_ilock_nowait() so
 * that we know which locks to drop.
 *
 * ip -- the inode being unlocked
 * lock_flags -- this parameter indicates the inode's locks to be
 *       to be unlocked.  See the comment for xfs_ilock() for a list
 *	 of valid values for this parameter.
 *
 */
void
C
Christoph Hellwig 已提交
653 654 655
xfs_iunlock(
	xfs_inode_t		*ip,
	uint			lock_flags)
L
Linus Torvalds 已提交
656 657 658 659 660 661 662 663 664 665
{
	/*
	 * You can't set both SHARED and EXCL for the same lock,
	 * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
	 * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
	 */
	ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
	       (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
	ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
	       (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
666 667
	ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_IUNLOCK_NONOTIFY |
			XFS_LOCK_DEP_MASK)) == 0);
L
Linus Torvalds 已提交
668 669
	ASSERT(lock_flags != 0);

C
Christoph Hellwig 已提交
670 671 672 673
	if (lock_flags & XFS_IOLOCK_EXCL)
		mrunlock_excl(&ip->i_iolock);
	else if (lock_flags & XFS_IOLOCK_SHARED)
		mrunlock_shared(&ip->i_iolock);
L
Linus Torvalds 已提交
674

C
Christoph Hellwig 已提交
675 676 677 678
	if (lock_flags & XFS_ILOCK_EXCL)
		mrunlock_excl(&ip->i_lock);
	else if (lock_flags & XFS_ILOCK_SHARED)
		mrunlock_shared(&ip->i_lock);
L
Linus Torvalds 已提交
679

C
Christoph Hellwig 已提交
680 681
	if ((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) &&
	    !(lock_flags & XFS_IUNLOCK_NONOTIFY) && ip->i_itemp) {
L
Linus Torvalds 已提交
682 683 684 685 686
		/*
		 * Let the AIL know that this item has been unlocked in case
		 * it is in the AIL and anyone is waiting on it.  Don't do
		 * this if the caller has asked us not to.
		 */
C
Christoph Hellwig 已提交
687 688
		xfs_trans_unlocked_item(ip->i_mount,
					(xfs_log_item_t*)(ip->i_itemp));
L
Linus Torvalds 已提交
689 690 691 692 693 694 695 696 697
	}
	xfs_ilock_trace(ip, 3, lock_flags, (inst_t *)__return_address);
}

/*
 * give up write locks.  the i/o lock cannot be held nested
 * if it is being demoted.
 */
void
C
Christoph Hellwig 已提交
698 699 700
xfs_ilock_demote(
	xfs_inode_t		*ip,
	uint			lock_flags)
L
Linus Torvalds 已提交
701 702 703 704
{
	ASSERT(lock_flags & (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL));
	ASSERT((lock_flags & ~(XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)) == 0);

C
Christoph Hellwig 已提交
705
	if (lock_flags & XFS_ILOCK_EXCL)
L
Linus Torvalds 已提交
706
		mrdemote(&ip->i_lock);
C
Christoph Hellwig 已提交
707
	if (lock_flags & XFS_IOLOCK_EXCL)
L
Linus Torvalds 已提交
708
		mrdemote(&ip->i_iolock);
C
Christoph Hellwig 已提交
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
}

#ifdef DEBUG
/*
 * Debug-only routine, without additional rw_semaphore APIs, we can
 * now only answer requests regarding whether we hold the lock for write
 * (reader state is outside our visibility, we only track writer state).
 *
 * Note: this means !xfs_isilocked would give false positives, so don't do that.
 */
int
xfs_isilocked(
	xfs_inode_t		*ip,
	uint			lock_flags)
{
	if ((lock_flags & (XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)) ==
			XFS_ILOCK_EXCL) {
		if (!ip->i_lock.mr_writer)
			return 0;
L
Linus Torvalds 已提交
728
	}
C
Christoph Hellwig 已提交
729 730 731 732 733 734 735 736

	if ((lock_flags & (XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)) ==
			XFS_IOLOCK_EXCL) {
		if (!ip->i_iolock.mr_writer)
			return 0;
	}

	return 1;
L
Linus Torvalds 已提交
737
}
C
Christoph Hellwig 已提交
738
#endif
L
Linus Torvalds 已提交
739