xref: /linux/fs/erofs/ishare.c (revision 1fd1dc41724319406b0aff221a352a400b0ddfc5)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2024, Alibaba Cloud
4  */
5 #include <linux/xxhash.h>
6 #include <linux/mount.h>
7 #include "internal.h"
8 #include "xattr.h"
9 
10 #include "../internal.h"
11 
12 static struct vfsmount *erofs_ishare_mnt;
13 
14 static inline bool erofs_is_ishare_inode(struct inode *inode)
15 {
16 	/* assumed FS_ONDEMAND is excluded with FS_PAGE_CACHE_SHARE feature */
17 	return inode->i_sb->s_type == &erofs_anon_fs_type;
18 }
19 
20 static int erofs_ishare_iget5_eq(struct inode *inode, void *data)
21 {
22 	struct erofs_inode_fingerprint *fp1 = &EROFS_I(inode)->fingerprint;
23 	struct erofs_inode_fingerprint *fp2 = data;
24 
25 	return fp1->size == fp2->size &&
26 		!memcmp(fp1->opaque, fp2->opaque, fp2->size);
27 }
28 
29 static int erofs_ishare_iget5_set(struct inode *inode, void *data)
30 {
31 	struct erofs_inode *vi = EROFS_I(inode);
32 
33 	vi->fingerprint = *(struct erofs_inode_fingerprint *)data;
34 	INIT_LIST_HEAD(&vi->ishare_list);
35 	spin_lock_init(&vi->ishare_lock);
36 	return 0;
37 }
38 
39 bool erofs_ishare_fill_inode(struct inode *inode)
40 {
41 	struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
42 	struct erofs_inode *vi = EROFS_I(inode);
43 	const struct address_space_operations *aops;
44 	struct erofs_inode_fingerprint fp;
45 	struct inode *sharedinode;
46 	unsigned long hash;
47 
48 	aops = erofs_get_aops(inode, true);
49 	if (IS_ERR(aops))
50 		return false;
51 	if (erofs_xattr_fill_inode_fingerprint(&fp, inode, sbi->domain_id))
52 		return false;
53 	hash = xxh32(fp.opaque, fp.size, 0);
54 	sharedinode = iget5_locked(erofs_ishare_mnt->mnt_sb, hash,
55 				   erofs_ishare_iget5_eq, erofs_ishare_iget5_set,
56 				   &fp);
57 	if (!sharedinode) {
58 		kfree(fp.opaque);
59 		return false;
60 	}
61 
62 	if (inode_state_read_once(sharedinode) & I_NEW) {
63 		sharedinode->i_mapping->a_ops = aops;
64 		sharedinode->i_size = vi->vfs_inode.i_size;
65 		unlock_new_inode(sharedinode);
66 	} else {
67 		kfree(fp.opaque);
68 		if (aops != sharedinode->i_mapping->a_ops) {
69 			iput(sharedinode);
70 			return false;
71 		}
72 		if (sharedinode->i_size != vi->vfs_inode.i_size) {
73 			_erofs_printk(inode->i_sb, KERN_WARNING
74 				"size(%lld:%lld) not matches for the same fingerprint\n",
75 				vi->vfs_inode.i_size, sharedinode->i_size);
76 			iput(sharedinode);
77 			return false;
78 		}
79 	}
80 	vi->sharedinode = sharedinode;
81 	INIT_LIST_HEAD(&vi->ishare_list);
82 	spin_lock(&EROFS_I(sharedinode)->ishare_lock);
83 	list_add(&vi->ishare_list, &EROFS_I(sharedinode)->ishare_list);
84 	spin_unlock(&EROFS_I(sharedinode)->ishare_lock);
85 	return true;
86 }
87 
88 void erofs_ishare_free_inode(struct inode *inode)
89 {
90 	struct erofs_inode *vi = EROFS_I(inode);
91 	struct inode *sharedinode = vi->sharedinode;
92 
93 	if (!sharedinode)
94 		return;
95 	spin_lock(&EROFS_I(sharedinode)->ishare_lock);
96 	list_del(&vi->ishare_list);
97 	spin_unlock(&EROFS_I(sharedinode)->ishare_lock);
98 	iput(sharedinode);
99 	vi->sharedinode = NULL;
100 }
101 
102 static int erofs_ishare_file_open(struct inode *inode, struct file *file)
103 {
104 	struct inode *sharedinode = EROFS_I(inode)->sharedinode;
105 	struct file *realfile;
106 
107 	if (file->f_flags & O_DIRECT)
108 		return -EINVAL;
109 	realfile = alloc_empty_backing_file(O_RDONLY|O_NOATIME, current_cred());
110 	if (IS_ERR(realfile))
111 		return PTR_ERR(realfile);
112 	ihold(sharedinode);
113 	realfile->f_op = &erofs_file_fops;
114 	realfile->f_inode = sharedinode;
115 	realfile->f_mapping = sharedinode->i_mapping;
116 	path_get(&file->f_path);
117 	backing_file_set_user_path(realfile, &file->f_path);
118 
119 	file_ra_state_init(&realfile->f_ra, file->f_mapping);
120 	realfile->private_data = EROFS_I(inode);
121 	file->private_data = realfile;
122 	return 0;
123 }
124 
125 static int erofs_ishare_file_release(struct inode *inode, struct file *file)
126 {
127 	struct file *realfile = file->private_data;
128 
129 	iput(realfile->f_inode);
130 	fput(realfile);
131 	file->private_data = NULL;
132 	return 0;
133 }
134 
135 static ssize_t erofs_ishare_file_read_iter(struct kiocb *iocb,
136 					   struct iov_iter *to)
137 {
138 	struct file *realfile = iocb->ki_filp->private_data;
139 	struct kiocb dedup_iocb;
140 	ssize_t nread;
141 
142 	if (!iov_iter_count(to))
143 		return 0;
144 	kiocb_clone(&dedup_iocb, iocb, realfile);
145 	nread = filemap_read(&dedup_iocb, to, 0);
146 	iocb->ki_pos = dedup_iocb.ki_pos;
147 	return nread;
148 }
149 
150 static int erofs_ishare_mmap(struct file *file, struct vm_area_struct *vma)
151 {
152 	struct file *realfile = file->private_data;
153 
154 	vma_set_file(vma, realfile);
155 	return generic_file_readonly_mmap(file, vma);
156 }
157 
158 static int erofs_ishare_fadvise(struct file *file, loff_t offset,
159 				loff_t len, int advice)
160 {
161 	return vfs_fadvise(file->private_data, offset, len, advice);
162 }
163 
164 const struct file_operations erofs_ishare_fops = {
165 	.open		= erofs_ishare_file_open,
166 	.llseek		= generic_file_llseek,
167 	.read_iter	= erofs_ishare_file_read_iter,
168 	.mmap		= erofs_ishare_mmap,
169 	.release	= erofs_ishare_file_release,
170 	.get_unmapped_area = thp_get_unmapped_area,
171 	.splice_read	= filemap_splice_read,
172 	.fadvise	= erofs_ishare_fadvise,
173 };
174 
175 struct inode *erofs_real_inode(struct inode *inode, bool *need_iput)
176 {
177 	struct erofs_inode *vi, *vi_share;
178 	struct inode *realinode;
179 
180 	*need_iput = false;
181 	if (!erofs_is_ishare_inode(inode))
182 		return inode;
183 
184 	vi_share = EROFS_I(inode);
185 	spin_lock(&vi_share->ishare_lock);
186 	/* fetch any one as real inode */
187 	DBG_BUGON(list_empty(&vi_share->ishare_list));
188 	list_for_each_entry(vi, &vi_share->ishare_list, ishare_list) {
189 		realinode = igrab(&vi->vfs_inode);
190 		if (realinode) {
191 			*need_iput = true;
192 			break;
193 		}
194 	}
195 	spin_unlock(&vi_share->ishare_lock);
196 
197 	DBG_BUGON(!realinode);
198 	return realinode;
199 }
200 
201 int __init erofs_init_ishare(void)
202 {
203 	erofs_ishare_mnt = kern_mount(&erofs_anon_fs_type);
204 	return PTR_ERR_OR_ZERO(erofs_ishare_mnt);
205 }
206 
207 void erofs_exit_ishare(void)
208 {
209 	kern_unmount(erofs_ishare_mnt);
210 }
211