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)
epfs_tmpfile(struct user_namespace *,struct inode * dir,struct dentry * dentry,umode_t mode)26 static int epfs_tmpfile(struct user_namespace *, struct inode *dir,
27 struct dentry *dentry, umode_t mode)
28 #else
29 static int epfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
30 #endif
31 {
32 struct inode *inode = epfs_iget(dir->i_sb, false);
33
34 if (!inode)
35 return -ENOSPC;
36 d_tmpfile(dentry, inode);
37 if (IS_ENABLED(CONFIG_EPFS_DEBUG))
38 epfs_debug("epfs: tmpfile %p", inode);
39 return 0;
40 }
41
42 const struct inode_operations epfs_dir_iops = {
43 .tmpfile = epfs_tmpfile,
44 .lookup = epfs_lookup,
45 };
46
47 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
epfs_getattr(struct user_namespace * mnt_userns,const struct path * path,struct kstat * stat,u32 request_mask,unsigned int flags)48 static int epfs_getattr(struct user_namespace *mnt_userns,
49 const struct path *path, struct kstat *stat,
50 u32 request_mask, unsigned int flags)
51 #else
52 static int epfs_getattr(const struct path *path, struct kstat *stat,
53 u32 request_mask, unsigned int flags)
54 #endif
55 {
56 struct dentry *dentry = path->dentry;
57 struct inode *inode = d_inode(dentry);
58 struct epfs_inode_info *info = epfs_inode_to_private(inode);
59 struct file *origin_file;
60 struct kstat origin_stat;
61 int ret;
62
63 mutex_lock(&info->lock);
64 origin_file = info->origin_file;
65 if (!origin_file) {
66 ret = -ENOENT;
67 goto out_getattr;
68 }
69 ret = vfs_getattr(&(origin_file->f_path), &origin_stat, request_mask,
70 flags);
71 if (ret)
72 goto out_getattr;
73 fsstack_copy_attr_all(inode, file_inode(origin_file));
74 fsstack_copy_inode_size(inode, file_inode(origin_file));
75 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
76 generic_fillattr(mnt_userns, d_inode(dentry), stat);
77 #else
78 generic_fillattr(d_inode(dentry), stat);
79 #endif
80 stat->blocks = origin_stat.blocks;
81
82 out_getattr:
83 mutex_unlock(&info->lock);
84 return ret;
85 }
86
87 const struct inode_operations epfs_file_iops = {
88 .getattr = epfs_getattr,
89 };
90
epfs_iget(struct super_block * sb,bool is_dir)91 struct inode *epfs_iget(struct super_block *sb, bool is_dir)
92 {
93 struct inode *inode = new_inode(sb);
94
95 if (!inode) {
96 epfs_err("Failed to allocate new inode");
97 return NULL;
98 }
99 if (is_dir) {
100 inode->i_op = &epfs_dir_iops;
101 inode->i_fop = &epfs_dir_fops;
102 inode->i_mode = S_IFDIR | 0770;
103 } else {
104 inode->i_op = &epfs_file_iops;
105 inode->i_fop = &epfs_file_fops;
106 inode->i_mode = S_IFREG;
107 }
108 inode->i_uid = USER_DATA_RW_UID;
109 inode->i_gid = USER_DATA_RW_GID;
110 return inode;
111 }
112