fs/notify/fanotify/fanotify.c

Source file repositories/reference/linux-study-clean/fs/notify/fanotify/fanotify.c

File Facts

System
Linux kernel
Corpus path
fs/notify/fanotify/fanotify.c
Extension
.c
Size
32547 bytes
Lines
1122
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

if (fanotify_should_merge(old, new)) {
			old->mask |= new->mask;

			if (fanotify_is_error_event(old->mask))
				FANOTIFY_EE(old)->err_count++;

			return 1;
		}
	}

	return 0;
}

/*
 * Wait for response to permission event. The function also takes care of
 * freeing the permission event (or offloads that in case the wait is canceled
 * by a signal). The function returns 0 in case access got allowed by userspace,
 * -EPERM in case userspace disallowed the access, and -ERESTARTSYS in case
 * the wait got interrupted by a signal.
 */
static int fanotify_get_response(struct fsnotify_group *group,
				 struct fanotify_perm_event *event,
				 struct fsnotify_iter_info *iter_info)
{
	int ret, errno;

	pr_debug("%s: group=%p event=%p\n", __func__, group, event);

	ret = wait_event_state(group->fanotify_data.access_waitq,
				  event->state == FAN_EVENT_ANSWERED,
				  (TASK_KILLABLE|TASK_FREEZABLE));

	/* Signal pending? */
	if (ret < 0) {
		spin_lock(&group->notification_lock);
		/* Event reported to userspace and no answer yet? */
		if (event->state == FAN_EVENT_REPORTED) {
			/* Event will get freed once userspace answers to it */
			event->state = FAN_EVENT_CANCELED;
			spin_unlock(&group->notification_lock);
			return ret;
		}
		/* Event not yet reported? Just remove it. */
		if (event->state == FAN_EVENT_INIT) {
			fsnotify_remove_queued_event(group, &event->fae.fse);
			/* Permission events are not supposed to be hashed */
			WARN_ON_ONCE(!hlist_unhashed(&event->fae.merge_list));
		}
		/*
		 * Event may be also answered in case signal delivery raced
		 * with wakeup. In that case we have nothing to do besides
		 * freeing the event and reporting error.
		 */
		spin_unlock(&group->notification_lock);
		goto out;
	}

	/* userspace responded, convert to something usable */
	switch (event->response & FANOTIFY_RESPONSE_ACCESS) {
	case FAN_ALLOW:
		ret = 0;
		break;
	case FAN_DENY:
		/* Check custom errno from pre-content events */
		errno = fanotify_get_response_errno(event->response);
		if (errno) {
			ret = -errno;
			break;
		}
		fallthrough;
	default:
		ret = -EPERM;
	}

	/* Check if the response should be audited */
	if (event->response & FAN_AUDIT) {
		u32 response = event->response &
			(FANOTIFY_RESPONSE_ACCESS | FANOTIFY_RESPONSE_FLAGS);
		audit_fanotify(response & ~FAN_AUDIT, &event->audit_rule);
	}

	pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__,
		 group, event, ret);
out:
	fsnotify_destroy_event(group, &event->fae.fse);

	return ret;
}

/*

Annotation

Implementation Notes