1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * fs/epfs/inode.c
4 *
5 * Copyright (c) 2022 Huawei Technologies Co., Ltd.
6 * Author: weilongping@huawei.com
7 * Create: 2022-06-10
8 */
9 #include <linux/fs.h>
10 #include <linux/fs_stack.h>
11 #include <linux/version.h>
12
13 #include "internal.h"
14
15 #define USER_DATA_RW 1008
16 #define USER_DATA_RW_UID KUIDT_INIT(USER_DATA_RW)
17 #define USER_DATA_RW_GID KGIDT_INIT(USER_DATA_RW)
18
epfs_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)19 struct dentry *epfs_lookup(struct inode *dir, struct dentry *dentry,
20 unsigned int flags)
21 {
22 return ERR_PTR(-ENOENT);
23 }
24
25 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
26 #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
epfs_tmpfile(struct mnt_idmap * idmap,struct inode * dir,struct file * file,umode_t mode)27 static int epfs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
28 struct file *file, umode_t mode)
29 #else
30 static int epfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
31 struct file *file, umode_t mode)
32 #endif
33 #else
34 static int epfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
35 #endif
36 {
37 struct inode *inode = epfs_iget(dir->i_sb, false);
38
39 if (!inode)
40 return -ENOSPC;
41 d_tmpfile(file, inode);
42 if (IS_ENABLED(CONFIG_EPFS_DEBUG))
43 epfs_debug("epfs: tmpfile %p", inode);
44 return finish_open_simple(file, 0);;
45 }
46
47 const struct inode_operations epfs_dir_iops = {
48 .tmpfile = epfs_tmpfile,
49 .lookup = epfs_lookup,
50 };
51
52 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
53 #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
epfs_getattr(struct mnt_idmap * idmap,const struct path * path,struct kstat * stat,u32 request_mask,unsigned int flags)54 static int epfs_getattr(struct mnt_idmap *idmap,
55 const struct path *path, struct kstat *stat,
56 u32 request_mask, unsigned int flags)
57 #else
58 static int epfs_getattr(struct user_namespace *mnt_userns,
59 const struct path *path, struct kstat *stat,
60 u32 request_mask, unsigned int flags)
61 #endif
62 #else
63 static int epfs_getattr(const struct path *path, struct kstat *stat,
64 u32 request_mask, unsigned int flags)
65 #endif
66 {
67 struct dentry *dentry = path->dentry;
68 struct inode *inode = d_inode(dentry);
69 struct epfs_inode_info *info = epfs_inode_to_private(inode);
70 struct file *origin_file;
71 struct kstat origin_stat;
72 int ret;
73
74 mutex_lock(&info->lock);
75 origin_file = info->origin_file;
76 if (!origin_file) {
77 ret = -ENOENT;
78 goto out_getattr;
79 }
80 ret = vfs_getattr(&(origin_file->f_path), &origin_stat, request_mask,
81 flags);
82 if (ret)
83 goto out_getattr;
84 fsstack_copy_attr_all(inode, file_inode(origin_file));
85 fsstack_copy_inode_size(inode, file_inode(origin_file));
86 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
87 #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
88 generic_fillattr(idmap, request_mask, d_inode(dentry), stat);
89 #else
90 generic_fillattr(mnt_userns, d_inode(dentry), stat);
91 #endif
92 #else
93 generic_fillattr(d_inode(dentry), stat);
94 #endif
95 stat->blocks = origin_stat.blocks;
96
97 out_getattr:
98 mutex_unlock(&info->lock);
99 return ret;
100 }
101
102 const struct inode_operations epfs_file_iops = {
103 .getattr = epfs_getattr,
104 };
105
epfs_iget(struct super_block * sb,bool is_dir)106 struct inode *epfs_iget(struct super_block *sb, bool is_dir)
107 {
108 struct inode *inode = new_inode(sb);
109
110 if (!inode) {
111 epfs_err("Failed to allocate new inode");
112 return NULL;
113 }
114 if (is_dir) {
115 inode->i_op = &epfs_dir_iops;
116 inode->i_fop = &epfs_dir_fops;
117 inode->i_mode = S_IFDIR | 0770;
118 } else {
119 inode->i_op = &epfs_file_iops;
120 inode->i_fop = &epfs_file_fops;
121 inode->i_mode = S_IFREG;
122 }
123 inode->i_uid = USER_DATA_RW_UID;
124 inode->i_gid = USER_DATA_RW_GID;
125 return inode;
126 }
127