fs/xfs/xfs_healthmon.c

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

File Facts

System
Linux kernel
Corpus path
fs/xfs/xfs_healthmon.c
Extension
.c
Size
31142 bytes
Lines
1261
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: operation-table or driver-model contract
Status
pattern 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

static const struct file_operations xfs_healthmon_fops = {
	.owner		= THIS_MODULE,
	.show_fdinfo	= xfs_healthmon_show_fdinfo,
	.read_iter	= xfs_healthmon_read_iter,
	.poll		= xfs_healthmon_poll,
	.release	= xfs_healthmon_release,
	.unlocked_ioctl	= xfs_healthmon_ioctl,
};

/*
 * Create a health monitoring file.  Returns an index to the fd table or a
 * negative errno.
 */
long
xfs_ioc_health_monitor(
	struct file			*file,
	struct xfs_health_monitor __user *arg)
{
	struct xfs_health_monitor	hmo;
	struct xfs_healthmon_event	*running_event;
	struct xfs_healthmon		*hm;
	struct xfs_inode		*ip = XFS_I(file_inode(file));
	struct xfs_mount		*mp = ip->i_mount;
	int				ret;

	/*
	 * The only intended user of the health monitoring system should be the
	 * xfs_healer daemon running on behalf of the whole filesystem in the
	 * initial user namespace.  IOWs, we don't allow unprivileged userspace
	 * (they can use fsnotify) nor do we allow containers.
	 */
	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;
	if (I_INO(ip) != mp->m_sb.sb_rootino)
		return -EPERM;
	if (current_user_ns() != &init_user_ns)
		return -EPERM;

	if (copy_from_user(&hmo, arg, sizeof(hmo)))
		return -EFAULT;

	if (!xfs_healthmon_validate(&hmo))
		return -EINVAL;

	hm = kzalloc_obj(*hm);
	if (!hm)
		return -ENOMEM;
	hm->dev = mp->m_super->s_dev;
	refcount_set(&hm->ref, 1);

	mutex_init(&hm->lock);
	init_waitqueue_head(&hm->wait);

	if (hmo.flags & XFS_HEALTH_MONITOR_VERBOSE)
		hm->verbose = true;

	/* Queue up the first event that lets the client know we're running. */
	running_event = kzalloc_obj(struct xfs_healthmon_event, GFP_NOFS);
	if (!running_event) {
		ret = -ENOMEM;
		goto out_hm;
	}
	running_event->type = XFS_HEALTHMON_RUNNING;
	running_event->domain = XFS_HEALTHMON_MOUNT;
	__xfs_healthmon_insert(hm, running_event);

	/*
	 * Preallocate the unmount event so that we can't fail to notify the
	 * filesystem later.  This is key for triggering fast exit of the
	 * xfs_healer daemon.
	 */
	hm->unmount_event = kzalloc_obj(struct xfs_healthmon_event, GFP_NOFS);
	if (!hm->unmount_event) {
		ret = -ENOMEM;
		goto out_hm;
	}
	hm->unmount_event->type = XFS_HEALTHMON_UNMOUNT;
	hm->unmount_event->domain = XFS_HEALTHMON_MOUNT;

	/*
	 * Try to attach this health monitor to the xfs_mount.  The monitor is
	 * considered live and will receive events if this succeeds.
	 */
	ret = xfs_healthmon_attach(mp, hm);
	if (ret)
		goto out_hm;

	/*
	 * Create the anonymous file and install a fd for it.  If it succeeds,
	 * the file owns hm and can go away at any time, so we must not access

Annotation

Implementation Notes