fs/fserror.c

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

File Facts

System
Linux kernel
Corpus path
fs/fserror.c
Extension
.c
Size
5692 bytes
Lines
195
Domain
Core OS
Bucket
VFS And Filesystem Core
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

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (c) 2025 Oracle.  All Rights Reserved.
 * Author: Darrick J. Wong <djwong@kernel.org>
 */
#include <linux/fs.h>
#include <linux/fsnotify.h>
#include <linux/mempool.h>
#include <linux/fserror.h>

#define FSERROR_DEFAULT_EVENT_POOL_SIZE		(32)

static struct mempool fserror_events_pool;

void fserror_mount(struct super_block *sb)
{
	/*
	 * The pending error counter is biased by 1 so that we don't wake_var
	 * until we're actually trying to unmount.
	 */
	refcount_set(&sb->s_pending_errors, 1);
}

void fserror_unmount(struct super_block *sb)
{
	/*
	 * If we don't drop the pending error count to zero, then wait for it
	 * to drop below 1, which means that the pending errors cleared and
	 * hopefully we didn't saturate with 1 billion+ concurrent events.
	 */
	if (!refcount_dec_and_test(&sb->s_pending_errors))
		wait_var_event(&sb->s_pending_errors,
			       refcount_read(&sb->s_pending_errors) < 1);
}

static inline void fserror_pending_dec(struct super_block *sb)
{
	if (refcount_dec_and_test(&sb->s_pending_errors))
		wake_up_var(&sb->s_pending_errors);
}

static inline void fserror_free_event(struct fserror_event *event)
{
	fserror_pending_dec(event->sb);
	mempool_free(event, &fserror_events_pool);
}

static void fserror_worker(struct work_struct *work)
{
	struct fserror_event *event =
			container_of(work, struct fserror_event, work);
	struct super_block *sb = event->sb;

	if (sb->s_flags & SB_ACTIVE) {
		struct fs_error_report report = {
			/* send positive error number to userspace */
			.error = -event->error,
			.inode = event->inode,
			.sb = event->sb,
		};

		if (sb->s_op->report_error)
			sb->s_op->report_error(event);

		fsnotify(FS_ERROR, &report, FSNOTIFY_EVENT_ERROR, NULL, NULL,
			 NULL, 0);
	}

	iput(event->inode);
	fserror_free_event(event);
}

static inline struct fserror_event *fserror_alloc_event(struct super_block *sb,
							gfp_t gfp_flags)
{
	struct fserror_event *event = NULL;

	/*
	 * If pending_errors already reached zero or is no longer active,
	 * the superblock is being deactivated so there's no point in
	 * continuing.
	 *
	 * The order of the check of s_pending_errors and SB_ACTIVE are
	 * mandated by order of accesses in generic_shutdown_super and
	 * fserror_unmount.  Barriers are implicitly provided by the refcount
	 * manipulations in this function and fserror_unmount.
	 */
	if (!refcount_inc_not_zero(&sb->s_pending_errors))
		return NULL;
	if (!(sb->s_flags & SB_ACTIVE))

Annotation

Implementation Notes