fs/xfs/libxfs/xfs_btree.c

Source file repositories/reference/linux-study-clean/fs/xfs/libxfs/xfs_btree.c

File Facts

System
Linux kernel
Corpus path
fs/xfs/libxfs/xfs_btree.c
Extension
.c
Size
150022 bytes
Lines
5651
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct xfs_btree_split_args {
	struct xfs_btree_cur	*cur;
	int			level;
	union xfs_btree_ptr	*ptrp;
	union xfs_btree_key	*key;
	struct xfs_btree_cur	**curp;
	int			*stat;		/* success/failure */
	int			result;
	bool			kswapd;	/* allocation in kswapd context */
	struct completion	*done;
	struct work_struct	work;
};

/*
 * Stack switching interfaces for allocation
 */
static void
xfs_btree_split_worker(
	struct work_struct	*work)
{
	struct xfs_btree_split_args	*args = container_of(work,
						struct xfs_btree_split_args, work);
	unsigned long		pflags;
	unsigned long		new_pflags = 0;

	/*
	 * we are in a transaction context here, but may also be doing work
	 * in kswapd context, and hence we may need to inherit that state
	 * temporarily to ensure that we don't block waiting for memory reclaim
	 * in any way.
	 */
	if (args->kswapd)
		new_pflags |= PF_MEMALLOC | PF_KSWAPD;

	current_set_flags_nested(&pflags, new_pflags);
	xfs_trans_set_context(args->cur->bc_tp);

	args->result = __xfs_btree_split(args->cur, args->level, args->ptrp,
					 args->key, args->curp, args->stat);

	xfs_trans_clear_context(args->cur->bc_tp);
	current_restore_flags_nested(&pflags, new_pflags);

	/*
	 * Do not access args after complete() has run here. We don't own args
	 * and the owner may run and free args before we return here.
	 */
	complete(args->done);

}

/*
 * BMBT split requests often come in with little stack to work on so we push
 * them off to a worker thread so there is lots of stack to use. For the other
 * btree types, just call directly to avoid the context switch overhead here.
 *
 * Care must be taken here - the work queue rescuer thread introduces potential
 * AGF <> worker queue deadlocks if the BMBT block allocation has to lock new
 * AGFs to allocate blocks. A task being run by the rescuer could attempt to
 * lock an AGF that is already locked by a task queued to run by the rescuer,
 * resulting in an ABBA deadlock as the rescuer cannot run the lock holder to
 * release it until the current thread it is running gains the lock.
 *
 * To avoid this issue, we only ever queue BMBT splits that don't have an AGF
 * already locked to allocate from. The only place that doesn't hold an AGF
 * locked is unwritten extent conversion at IO completion, but that has already
 * been offloaded to a worker thread and hence has no stack consumption issues
 * we have to worry about.
 */
STATIC int					/* error */
xfs_btree_split(
	struct xfs_btree_cur	*cur,
	int			level,
	union xfs_btree_ptr	*ptrp,
	union xfs_btree_key	*key,
	struct xfs_btree_cur	**curp,
	int			*stat)		/* success/failure */
{
	struct xfs_btree_split_args	args;
	DECLARE_COMPLETION_ONSTACK(done);

	if (!xfs_btree_is_bmap(cur->bc_ops) ||
	    cur->bc_tp->t_highest_agno == NULLAGNUMBER)
		return __xfs_btree_split(cur, level, ptrp, key, curp, stat);

	args.cur = cur;
	args.level = level;
	args.ptrp = ptrp;
	args.key = key;
	args.curp = curp;

Annotation

Implementation Notes