mm/swapfile.c

Source file repositories/reference/linux-study-clean/mm/swapfile.c

File Facts

System
Linux kernel
Corpus path
mm/swapfile.c
Extension
.c
Size
106039 bytes
Lines
3933
Domain
Core OS
Bucket
Memory Management
Inferred role
Core OS: syscall or user/kernel boundary
Status
core 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

SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
{
	struct swap_info_struct *p = NULL;
	struct swap_cluster_info *cluster_info;
	struct file *swap_file, *victim;
	struct address_space *mapping;
	struct inode *inode;
	unsigned int maxpages;
	int err, found = 0;

	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;

	BUG_ON(!current->mm);

	CLASS(filename, pathname)(specialfile);
	victim = file_open_name(pathname, O_RDWR|O_LARGEFILE, 0);
	if (IS_ERR(victim))
		return PTR_ERR(victim);

	mapping = victim->f_mapping;
	spin_lock(&swap_lock);
	plist_for_each_entry(p, &swap_active_head, list) {
		if (p->flags & SWP_WRITEOK) {
			if (p->swap_file->f_mapping == mapping) {
				found = 1;
				break;
			}
		}
	}
	if (!found) {
		err = -EINVAL;
		spin_unlock(&swap_lock);
		goto out_dput;
	}

	/* Refuse swapoff while the device is pinned for hibernation */
	if (p->flags & SWP_HIBERNATION) {
		err = -EBUSY;
		spin_unlock(&swap_lock);
		goto out_dput;
	}

	if (!security_vm_enough_memory_mm(current->mm, p->pages))
		vm_unacct_memory(p->pages);
	else {
		err = -ENOMEM;
		spin_unlock(&swap_lock);
		goto out_dput;
	}
	spin_lock(&p->lock);
	del_from_avail_list(p, true);
	plist_del(&p->list, &swap_active_head);
	atomic_long_sub(p->pages, &nr_swap_pages);
	total_swap_pages -= p->pages;
	spin_unlock(&p->lock);
	spin_unlock(&swap_lock);

	wait_for_allocation(p);

	set_current_oom_origin();
	err = try_to_unuse(p->type);
	clear_current_oom_origin();

	if (err) {
		/* re-insert swap space back into swap_list */
		reinsert_swap_info(p);
		goto out_dput;
	}

	/*
	 * Wait for swap operations protected by get/put_swap_device()
	 * to complete.  Because of synchronize_rcu() here, all swap
	 * operations protected by RCU reader side lock (including any
	 * spinlock) will be waited too.  This makes it easy to
	 * prevent folio_test_swapcache() and the following swap cache
	 * operations from racing with swapoff.
	 */
	percpu_ref_kill(&p->users);
	synchronize_rcu();
	wait_for_completion(&p->comp);

	flush_work(&p->discard_work);
	flush_work(&p->reclaim_work);
	flush_percpu_swap_cluster(p);

	destroy_swap_extents(p, p->swap_file);

	if (!(p->flags & SWP_SOLIDSTATE))
		atomic_dec(&nr_rotate_swap);

Annotation

Implementation Notes