18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * fs/anon_inodes.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Thanks to Arnd Bergmann for code review and suggestions. 88c2ecf20Sopenharmony_ci * More changes for Thomas Gleixner suggestions. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/cred.h> 138c2ecf20Sopenharmony_ci#include <linux/file.h> 148c2ecf20Sopenharmony_ci#include <linux/poll.h> 158c2ecf20Sopenharmony_ci#include <linux/sched.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/fs.h> 188c2ecf20Sopenharmony_ci#include <linux/mount.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/magic.h> 228c2ecf20Sopenharmony_ci#include <linux/anon_inodes.h> 238c2ecf20Sopenharmony_ci#include <linux/pseudo_fs.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic struct vfsmount *anon_inode_mnt __read_mostly; 288c2ecf20Sopenharmony_cistatic struct inode *anon_inode_inode; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * anon_inodefs_dname() is called from d_path(). 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_cistatic char *anon_inodefs_dname(struct dentry *dentry, char *buffer, int buflen) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci return dynamic_dname(dentry, buffer, buflen, "anon_inode:%s", 368c2ecf20Sopenharmony_ci dentry->d_name.name); 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic const struct dentry_operations anon_inodefs_dentry_operations = { 408c2ecf20Sopenharmony_ci .d_dname = anon_inodefs_dname, 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int anon_inodefs_init_fs_context(struct fs_context *fc) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct pseudo_fs_context *ctx = init_pseudo(fc, ANON_INODE_FS_MAGIC); 468c2ecf20Sopenharmony_ci if (!ctx) 478c2ecf20Sopenharmony_ci return -ENOMEM; 488c2ecf20Sopenharmony_ci ctx->dops = &anon_inodefs_dentry_operations; 498c2ecf20Sopenharmony_ci return 0; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic struct file_system_type anon_inode_fs_type = { 538c2ecf20Sopenharmony_ci .name = "anon_inodefs", 548c2ecf20Sopenharmony_ci .init_fs_context = anon_inodefs_init_fs_context, 558c2ecf20Sopenharmony_ci .kill_sb = kill_anon_super, 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/** 598c2ecf20Sopenharmony_ci * anon_inode_getfile - creates a new file instance by hooking it up to an 608c2ecf20Sopenharmony_ci * anonymous inode, and a dentry that describe the "class" 618c2ecf20Sopenharmony_ci * of the file 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * @name: [in] name of the "class" of the new file 648c2ecf20Sopenharmony_ci * @fops: [in] file operations for the new file 658c2ecf20Sopenharmony_ci * @priv: [in] private data for the new file (will be file's private_data) 668c2ecf20Sopenharmony_ci * @flags: [in] flags 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * Creates a new file by hooking it on a single inode. This is useful for files 698c2ecf20Sopenharmony_ci * that do not need to have a full-fledged inode in order to operate correctly. 708c2ecf20Sopenharmony_ci * All the files created with anon_inode_getfile() will share a single inode, 718c2ecf20Sopenharmony_ci * hence saving memory and avoiding code duplication for the file/inode/dentry 728c2ecf20Sopenharmony_ci * setup. Returns the newly created file* or an error pointer. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_cistruct file *anon_inode_getfile(const char *name, 758c2ecf20Sopenharmony_ci const struct file_operations *fops, 768c2ecf20Sopenharmony_ci void *priv, int flags) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct file *file; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (IS_ERR(anon_inode_inode)) 818c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (fops->owner && !try_module_get(fops->owner)) 848c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* 878c2ecf20Sopenharmony_ci * We know the anon_inode inode count is always greater than zero, 888c2ecf20Sopenharmony_ci * so ihold() is safe. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci ihold(anon_inode_inode); 918c2ecf20Sopenharmony_ci file = alloc_file_pseudo(anon_inode_inode, anon_inode_mnt, name, 928c2ecf20Sopenharmony_ci flags & (O_ACCMODE | O_NONBLOCK), fops); 938c2ecf20Sopenharmony_ci if (IS_ERR(file)) 948c2ecf20Sopenharmony_ci goto err; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci file->f_mapping = anon_inode_inode->i_mapping; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci file->private_data = priv; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return file; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cierr: 1038c2ecf20Sopenharmony_ci iput(anon_inode_inode); 1048c2ecf20Sopenharmony_ci module_put(fops->owner); 1058c2ecf20Sopenharmony_ci return file; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(anon_inode_getfile); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/** 1108c2ecf20Sopenharmony_ci * anon_inode_getfd - creates a new file instance by hooking it up to an 1118c2ecf20Sopenharmony_ci * anonymous inode, and a dentry that describe the "class" 1128c2ecf20Sopenharmony_ci * of the file 1138c2ecf20Sopenharmony_ci * 1148c2ecf20Sopenharmony_ci * @name: [in] name of the "class" of the new file 1158c2ecf20Sopenharmony_ci * @fops: [in] file operations for the new file 1168c2ecf20Sopenharmony_ci * @priv: [in] private data for the new file (will be file's private_data) 1178c2ecf20Sopenharmony_ci * @flags: [in] flags 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci * Creates a new file by hooking it on a single inode. This is useful for files 1208c2ecf20Sopenharmony_ci * that do not need to have a full-fledged inode in order to operate correctly. 1218c2ecf20Sopenharmony_ci * All the files created with anon_inode_getfd() will share a single inode, 1228c2ecf20Sopenharmony_ci * hence saving memory and avoiding code duplication for the file/inode/dentry 1238c2ecf20Sopenharmony_ci * setup. Returns new descriptor or an error code. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ciint anon_inode_getfd(const char *name, const struct file_operations *fops, 1268c2ecf20Sopenharmony_ci void *priv, int flags) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci int error, fd; 1298c2ecf20Sopenharmony_ci struct file *file; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci error = get_unused_fd_flags(flags); 1328c2ecf20Sopenharmony_ci if (error < 0) 1338c2ecf20Sopenharmony_ci return error; 1348c2ecf20Sopenharmony_ci fd = error; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci file = anon_inode_getfile(name, fops, priv, flags); 1378c2ecf20Sopenharmony_ci if (IS_ERR(file)) { 1388c2ecf20Sopenharmony_ci error = PTR_ERR(file); 1398c2ecf20Sopenharmony_ci goto err_put_unused_fd; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci fd_install(fd, file); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return fd; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cierr_put_unused_fd: 1468c2ecf20Sopenharmony_ci put_unused_fd(fd); 1478c2ecf20Sopenharmony_ci return error; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(anon_inode_getfd); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic int __init anon_inode_init(void) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci anon_inode_mnt = kern_mount(&anon_inode_fs_type); 1548c2ecf20Sopenharmony_ci if (IS_ERR(anon_inode_mnt)) 1558c2ecf20Sopenharmony_ci panic("anon_inode_init() kernel mount failed (%ld)\n", PTR_ERR(anon_inode_mnt)); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci anon_inode_inode = alloc_anon_inode(anon_inode_mnt->mnt_sb); 1588c2ecf20Sopenharmony_ci if (IS_ERR(anon_inode_inode)) 1598c2ecf20Sopenharmony_ci panic("anon_inode_init() inode allocation failed (%ld)\n", PTR_ERR(anon_inode_inode)); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cifs_initcall(anon_inode_init); 1658c2ecf20Sopenharmony_ci 166