fs/afs/fs_operation.c

Source file repositories/reference/linux-study-clean/fs/afs/fs_operation.c

File Facts

System
Linux kernel
Corpus path
fs/afs/fs_operation.c
Extension
.c
Size
8869 bytes
Lines
378
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 afs_io_locker {
	struct list_head	link;
	struct task_struct	*task;
	unsigned long		have_lock;
};

/*
 * Unlock the I/O lock on a vnode.
 */
static void afs_unlock_for_io(struct afs_vnode *vnode)
{
	struct afs_io_locker *locker;

	spin_lock(&vnode->lock);
	locker = list_first_entry_or_null(&vnode->io_lock_waiters,
					  struct afs_io_locker, link);
	if (locker) {
		list_del(&locker->link);
		smp_store_release(&locker->have_lock, 1); /* The unlock barrier. */
		smp_mb__after_atomic(); /* Store have_lock before task state */
		wake_up_process(locker->task);
	} else {
		clear_bit(AFS_VNODE_IO_LOCK, &vnode->flags);
	}
	spin_unlock(&vnode->lock);
}

/*
 * Lock the I/O lock on a vnode uninterruptibly.  We can't use an ordinary
 * mutex as lockdep will complain if we unlock it in the wrong thread.
 */
static void afs_lock_for_io(struct afs_vnode *vnode)
{
	struct afs_io_locker myself = { .task = current, };

	spin_lock(&vnode->lock);

	if (!test_and_set_bit(AFS_VNODE_IO_LOCK, &vnode->flags)) {
		spin_unlock(&vnode->lock);
		return;
	}

	list_add_tail(&myself.link, &vnode->io_lock_waiters);
	spin_unlock(&vnode->lock);

	for (;;) {
		set_current_state(TASK_UNINTERRUPTIBLE);
		if (smp_load_acquire(&myself.have_lock)) /* The lock barrier */
			break;
		schedule();
	}
	__set_current_state(TASK_RUNNING);
}

/*
 * Lock the I/O lock on a vnode interruptibly.  We can't use an ordinary mutex
 * as lockdep will complain if we unlock it in the wrong thread.
 */
static int afs_lock_for_io_interruptible(struct afs_vnode *vnode)
{
	struct afs_io_locker myself = { .task = current, };
	int ret = 0;

	spin_lock(&vnode->lock);

	if (!test_and_set_bit(AFS_VNODE_IO_LOCK, &vnode->flags)) {
		spin_unlock(&vnode->lock);
		return 0;
	}

	list_add_tail(&myself.link, &vnode->io_lock_waiters);
	spin_unlock(&vnode->lock);

	for (;;) {
		set_current_state(TASK_INTERRUPTIBLE);
		if (smp_load_acquire(&myself.have_lock) || /* The lock barrier */
		    signal_pending(current))
			break;
		schedule();
	}
	__set_current_state(TASK_RUNNING);

	/* If we got a signal, try to transfer the lock onto the next
	 * waiter.
	 */
	if (unlikely(signal_pending(current))) {
		spin_lock(&vnode->lock);
		if (myself.have_lock) {
			spin_unlock(&vnode->lock);
			afs_unlock_for_io(vnode);

Annotation

Implementation Notes