fs/debugfs/file.c

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

File Facts

System
Linux kernel
Corpus path
fs/debugfs/file.c
Extension
.c
Size
44274 bytes
Lines
1436
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

const struct file_operations debugfs_noop_file_operations = {
	.read =		default_read_file,
	.write =	default_write_file,
	.open =		simple_open,
	.llseek =	noop_llseek,
};

#define F_DENTRY(filp) ((filp)->f_path.dentry)

void *debugfs_get_aux(const struct file *file)
{
	return DEBUGFS_I(file_inode(file))->aux;
}
EXPORT_SYMBOL_GPL(debugfs_get_aux);

enum dbgfs_get_mode {
	DBGFS_GET_ALREADY,
	DBGFS_GET_REGULAR,
	DBGFS_GET_SHORT,
};

static int __debugfs_file_get(struct dentry *dentry, enum dbgfs_get_mode mode)
{
	struct debugfs_fsdata *fsd;
	void *d_fsd;

	/*
	 * This could only happen if some debugfs user erroneously calls
	 * debugfs_file_get() on a dentry that isn't even a file, let
	 * them know about it.
	 */
	if (WARN_ON(!d_is_reg(dentry)))
		return -EINVAL;

	d_fsd = READ_ONCE(dentry->d_fsdata);
	if (d_fsd) {
		fsd = d_fsd;
	} else {
		struct inode *inode = dentry->d_inode;
		unsigned int methods = 0;

		if (WARN_ON(mode == DBGFS_GET_ALREADY))
			return -EINVAL;

		fsd = kmalloc_obj(*fsd);
		if (!fsd)
			return -ENOMEM;

		if (mode == DBGFS_GET_SHORT) {
			const struct debugfs_short_fops *ops;
			ops = fsd->short_fops = DEBUGFS_I(inode)->short_fops;
			if (ops->llseek)
				methods |= HAS_LSEEK;
			if (ops->read)
				methods |= HAS_READ;
			if (ops->write)
				methods |= HAS_WRITE;
			fsd->real_fops = NULL;
		} else {
			const struct file_operations *ops;
			ops = fsd->real_fops = DEBUGFS_I(inode)->real_fops;
			if (ops->llseek)
				methods |= HAS_LSEEK;
			if (ops->read)
				methods |= HAS_READ;
			if (ops->write)
				methods |= HAS_WRITE;
			if (ops->unlocked_ioctl)
				methods |= HAS_IOCTL;
			if (ops->poll)
				methods |= HAS_POLL;
			fsd->short_fops = NULL;
		}
		fsd->methods = methods;
		refcount_set(&fsd->active_users, 1);
		init_completion(&fsd->active_users_drained);
		INIT_LIST_HEAD(&fsd->cancellations);
		mutex_init(&fsd->cancellations_mtx);

		d_fsd = cmpxchg(&dentry->d_fsdata, NULL, fsd);
		if (d_fsd) {
			mutex_destroy(&fsd->cancellations_mtx);
			kfree(fsd);
			fsd = d_fsd;
		}
	}

	/*
	 * In case of a successful cmpxchg() above, this check is
	 * strictly necessary and must follow it, see the comment in

Annotation

Implementation Notes