kernel/watch_queue.c

Source file repositories/reference/linux-study-clean/kernel/watch_queue.c

File Facts

System
Linux kernel
Corpus path
kernel/watch_queue.c
Extension
.c
Size
17893 bytes
Lines
707
Domain
Core OS
Bucket
Scheduler, Processes, Timers, Sync, And Syscalls
Inferred role
Core OS: exported/initcall integration point
Status
integration 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

if (lock_wqueue(wqueue)) {
			post_one_notification(wqueue, n);
			unlock_wqueue(wqueue);
		}
	}

	rcu_read_unlock();
}
EXPORT_SYMBOL(__post_watch_notification);

/*
 * Allocate sufficient pages to preallocation for the requested number of
 * notifications.
 */
long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes)
{
	struct watch_queue *wqueue = pipe->watch_queue;
	struct page **pages;
	unsigned long *bitmap;
	unsigned long user_bufs;
	int ret, i, nr_pages;

	if (!wqueue)
		return -ENODEV;
	if (wqueue->notes)
		return -EBUSY;

	if (nr_notes < 1 ||
	    nr_notes > 512) /* TODO: choose a better hard limit */
		return -EINVAL;

	nr_pages = (nr_notes + WATCH_QUEUE_NOTES_PER_PAGE - 1);
	nr_pages /= WATCH_QUEUE_NOTES_PER_PAGE;
	user_bufs = account_pipe_buffers(pipe->user, pipe->nr_accounted, nr_pages);

	if (nr_pages > pipe->max_usage &&
	    (too_many_pipe_buffers_hard(user_bufs) ||
	     too_many_pipe_buffers_soft(user_bufs)) &&
	    pipe_is_unprivileged_user()) {
		ret = -EPERM;
		goto error;
	}

	nr_notes = nr_pages * WATCH_QUEUE_NOTES_PER_PAGE;
	ret = pipe_resize_ring(pipe, roundup_pow_of_two(nr_notes));
	if (ret < 0)
		goto error;

	/*
	 * pipe_resize_ring() does not update nr_accounted for watch_queue
	 * pipes, because the above vastly overprovisions. Set nr_accounted on
	 * and max_usage this pipe to the number that was actually charged to
	 * the user above via account_pipe_buffers.
	 */
	pipe->max_usage = nr_pages;
	pipe->nr_accounted = nr_pages;

	ret = -ENOMEM;
	pages = kzalloc_objs(struct page *, nr_pages);
	if (!pages)
		goto error;

	for (i = 0; i < nr_pages; i++) {
		pages[i] = alloc_page(GFP_KERNEL);
		if (!pages[i])
			goto error_p;
		pages[i]->private = i * WATCH_QUEUE_NOTES_PER_PAGE;
	}

	bitmap = bitmap_alloc(nr_notes, GFP_KERNEL);
	if (!bitmap)
		goto error_p;

	bitmap_fill(bitmap, nr_notes);
	wqueue->notes = pages;
	wqueue->notes_bitmap = bitmap;
	wqueue->nr_pages = nr_pages;
	wqueue->nr_notes = nr_notes;
	return 0;

error_p:
	while (--i >= 0)
		__free_page(pages[i]);
	kfree(pages);
error:
	(void) account_pipe_buffers(pipe->user, nr_pages, pipe->nr_accounted);
	return ret;
}

/*

Annotation

Implementation Notes