mm/madvise.c

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

File Facts

System
Linux kernel
Corpus path
mm/madvise.c
Extension
.c
Size
59867 bytes
Lines
2239
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_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior)
{
	return do_madvise(current->mm, start, len_in, behavior);
}

/* Perform an madvise operation over a vector of addresses and lengths. */
static ssize_t vector_madvise(struct mm_struct *mm, struct iov_iter *iter,
			      int behavior)
{
	ssize_t ret = 0;
	size_t total_len;
	struct mmu_gather tlb;
	struct madvise_behavior madv_behavior = {
		.mm = mm,
		.behavior = behavior,
		.tlb = &tlb,
	};

	total_len = iov_iter_count(iter);

	ret = madvise_lock(&madv_behavior);
	if (ret)
		return ret;
	madvise_init_tlb(&madv_behavior);

	while (iov_iter_count(iter)) {
		unsigned long start = (unsigned long)iter_iov_addr(iter);
		size_t len_in = iter_iov_len(iter);
		int error;

		error = check_input_range(start, len_in);
		if (error || !len_in)
			ret = error;
		else
			ret = madvise_do_behavior(start, len_in, &madv_behavior);
		/*
		 * An madvise operation is attempting to restart the syscall,
		 * but we cannot proceed as it would not be correct to repeat
		 * the operation in aggregate, and would be surprising to the
		 * user.
		 *
		 * We drop and reacquire locks so it is safe to just loop and
		 * try again. We check for fatal signals in case we need exit
		 * early anyway.
		 */
		if (ret == -ERESTARTNOINTR) {
			if (fatal_signal_pending(current)) {
				ret = -EINTR;
				break;
			}

			/* Drop and reacquire lock to unwind race. */
			madvise_finish_tlb(&madv_behavior);
			madvise_unlock(&madv_behavior);
			ret = madvise_lock(&madv_behavior);
			if (ret)
				goto out;
			madvise_init_tlb(&madv_behavior);
			continue;
		}
		if (ret < 0)
			break;
		iov_iter_advance(iter, iter_iov_len(iter));
	}
	madvise_finish_tlb(&madv_behavior);
	madvise_unlock(&madv_behavior);

out:
	ret = (total_len - iov_iter_count(iter)) ? : ret;

	return ret;
}

SYSCALL_DEFINE5(process_madvise, int, pidfd, const struct iovec __user *, vec,
		size_t, vlen, int, behavior, unsigned int, flags)
{
	ssize_t ret;
	struct iovec iovstack[UIO_FASTIOV];
	struct iovec *iov = iovstack;
	struct iov_iter iter;
	struct task_struct *task;
	struct mm_struct *mm;
	unsigned int f_flags;

	if (flags != 0) {
		ret = -EINVAL;
		goto out;
	}

	ret = import_iovec(ITER_DEST, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);

Annotation

Implementation Notes