xref: /linux/fs/erofs/ishare.c (revision f4d0ec0aa20d49f09dc01d82894ce80d72de0560)
15ef3208eSHongzhen Luo // SPDX-License-Identifier: GPL-2.0-or-later
25ef3208eSHongzhen Luo /*
35ef3208eSHongzhen Luo  * Copyright (C) 2024, Alibaba Cloud
45ef3208eSHongzhen Luo  */
55ef3208eSHongzhen Luo #include <linux/xxhash.h>
65ef3208eSHongzhen Luo #include <linux/mount.h>
75ef3208eSHongzhen Luo #include "internal.h"
85ef3208eSHongzhen Luo #include "xattr.h"
95ef3208eSHongzhen Luo 
105ef3208eSHongzhen Luo #include "../internal.h"
115ef3208eSHongzhen Luo 
125ef3208eSHongzhen Luo static struct vfsmount *erofs_ishare_mnt;
135ef3208eSHongzhen Luo 
erofs_is_ishare_inode(struct inode * inode)1434096ba9SHongbo Li static inline bool erofs_is_ishare_inode(struct inode *inode)
1534096ba9SHongbo Li {
1634096ba9SHongbo Li 	/* assumed FS_ONDEMAND is excluded with FS_PAGE_CACHE_SHARE feature */
1734096ba9SHongbo Li 	return inode->i_sb->s_type == &erofs_anon_fs_type;
1834096ba9SHongbo Li }
1934096ba9SHongbo Li 
erofs_ishare_iget5_eq(struct inode * inode,void * data)205ef3208eSHongzhen Luo static int erofs_ishare_iget5_eq(struct inode *inode, void *data)
215ef3208eSHongzhen Luo {
225ef3208eSHongzhen Luo 	struct erofs_inode_fingerprint *fp1 = &EROFS_I(inode)->fingerprint;
235ef3208eSHongzhen Luo 	struct erofs_inode_fingerprint *fp2 = data;
245ef3208eSHongzhen Luo 
255ef3208eSHongzhen Luo 	return fp1->size == fp2->size &&
265ef3208eSHongzhen Luo 		!memcmp(fp1->opaque, fp2->opaque, fp2->size);
275ef3208eSHongzhen Luo }
285ef3208eSHongzhen Luo 
erofs_ishare_iget5_set(struct inode * inode,void * data)295ef3208eSHongzhen Luo static int erofs_ishare_iget5_set(struct inode *inode, void *data)
305ef3208eSHongzhen Luo {
315ef3208eSHongzhen Luo 	struct erofs_inode *vi = EROFS_I(inode);
325ef3208eSHongzhen Luo 
335ef3208eSHongzhen Luo 	vi->fingerprint = *(struct erofs_inode_fingerprint *)data;
345ef3208eSHongzhen Luo 	INIT_LIST_HEAD(&vi->ishare_list);
355ef3208eSHongzhen Luo 	spin_lock_init(&vi->ishare_lock);
365ef3208eSHongzhen Luo 	return 0;
375ef3208eSHongzhen Luo }
385ef3208eSHongzhen Luo 
erofs_ishare_fill_inode(struct inode * inode)395ef3208eSHongzhen Luo bool erofs_ishare_fill_inode(struct inode *inode)
405ef3208eSHongzhen Luo {
415ef3208eSHongzhen Luo 	struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
425ef3208eSHongzhen Luo 	struct erofs_inode *vi = EROFS_I(inode);
43*03c0d030SHongbo Li 	const struct address_space_operations *aops;
445ef3208eSHongzhen Luo 	struct erofs_inode_fingerprint fp;
455ef3208eSHongzhen Luo 	struct inode *sharedinode;
465ef3208eSHongzhen Luo 	unsigned long hash;
475ef3208eSHongzhen Luo 
48*03c0d030SHongbo Li 	aops = erofs_get_aops(inode, true);
49*03c0d030SHongbo Li 	if (IS_ERR(aops))
50*03c0d030SHongbo Li 		return false;
515ef3208eSHongzhen Luo 	if (erofs_xattr_fill_inode_fingerprint(&fp, inode, sbi->domain_id))
525ef3208eSHongzhen Luo 		return false;
535ef3208eSHongzhen Luo 	hash = xxh32(fp.opaque, fp.size, 0);
545ef3208eSHongzhen Luo 	sharedinode = iget5_locked(erofs_ishare_mnt->mnt_sb, hash,
555ef3208eSHongzhen Luo 				   erofs_ishare_iget5_eq, erofs_ishare_iget5_set,
565ef3208eSHongzhen Luo 				   &fp);
575ef3208eSHongzhen Luo 	if (!sharedinode) {
585ef3208eSHongzhen Luo 		kfree(fp.opaque);
595ef3208eSHongzhen Luo 		return false;
605ef3208eSHongzhen Luo 	}
615ef3208eSHongzhen Luo 
625ef3208eSHongzhen Luo 	if (inode_state_read_once(sharedinode) & I_NEW) {
63*03c0d030SHongbo Li 		sharedinode->i_mapping->a_ops = aops;
645ef3208eSHongzhen Luo 		sharedinode->i_size = vi->vfs_inode.i_size;
655ef3208eSHongzhen Luo 		unlock_new_inode(sharedinode);
665ef3208eSHongzhen Luo 	} else {
675ef3208eSHongzhen Luo 		kfree(fp.opaque);
68*03c0d030SHongbo Li 		if (aops != sharedinode->i_mapping->a_ops) {
69*03c0d030SHongbo Li 			iput(sharedinode);
70*03c0d030SHongbo Li 			return false;
71*03c0d030SHongbo Li 		}
725ef3208eSHongzhen Luo 		if (sharedinode->i_size != vi->vfs_inode.i_size) {
735ef3208eSHongzhen Luo 			_erofs_printk(inode->i_sb, KERN_WARNING
745ef3208eSHongzhen Luo 				"size(%lld:%lld) not matches for the same fingerprint\n",
755ef3208eSHongzhen Luo 				vi->vfs_inode.i_size, sharedinode->i_size);
765ef3208eSHongzhen Luo 			iput(sharedinode);
775ef3208eSHongzhen Luo 			return false;
785ef3208eSHongzhen Luo 		}
795ef3208eSHongzhen Luo 	}
805ef3208eSHongzhen Luo 	vi->sharedinode = sharedinode;
815ef3208eSHongzhen Luo 	INIT_LIST_HEAD(&vi->ishare_list);
825ef3208eSHongzhen Luo 	spin_lock(&EROFS_I(sharedinode)->ishare_lock);
835ef3208eSHongzhen Luo 	list_add(&vi->ishare_list, &EROFS_I(sharedinode)->ishare_list);
845ef3208eSHongzhen Luo 	spin_unlock(&EROFS_I(sharedinode)->ishare_lock);
855ef3208eSHongzhen Luo 	return true;
865ef3208eSHongzhen Luo }
875ef3208eSHongzhen Luo 
erofs_ishare_free_inode(struct inode * inode)885ef3208eSHongzhen Luo void erofs_ishare_free_inode(struct inode *inode)
895ef3208eSHongzhen Luo {
905ef3208eSHongzhen Luo 	struct erofs_inode *vi = EROFS_I(inode);
915ef3208eSHongzhen Luo 	struct inode *sharedinode = vi->sharedinode;
925ef3208eSHongzhen Luo 
935ef3208eSHongzhen Luo 	if (!sharedinode)
945ef3208eSHongzhen Luo 		return;
955ef3208eSHongzhen Luo 	spin_lock(&EROFS_I(sharedinode)->ishare_lock);
965ef3208eSHongzhen Luo 	list_del(&vi->ishare_list);
975ef3208eSHongzhen Luo 	spin_unlock(&EROFS_I(sharedinode)->ishare_lock);
985ef3208eSHongzhen Luo 	iput(sharedinode);
995ef3208eSHongzhen Luo 	vi->sharedinode = NULL;
1005ef3208eSHongzhen Luo }
1015ef3208eSHongzhen Luo 
erofs_ishare_file_open(struct inode * inode,struct file * file)1025ef3208eSHongzhen Luo static int erofs_ishare_file_open(struct inode *inode, struct file *file)
1035ef3208eSHongzhen Luo {
1045ef3208eSHongzhen Luo 	struct inode *sharedinode = EROFS_I(inode)->sharedinode;
1055ef3208eSHongzhen Luo 	struct file *realfile;
1065ef3208eSHongzhen Luo 
1075ef3208eSHongzhen Luo 	if (file->f_flags & O_DIRECT)
1085ef3208eSHongzhen Luo 		return -EINVAL;
1095ef3208eSHongzhen Luo 	realfile = alloc_empty_backing_file(O_RDONLY|O_NOATIME, current_cred());
1105ef3208eSHongzhen Luo 	if (IS_ERR(realfile))
1115ef3208eSHongzhen Luo 		return PTR_ERR(realfile);
1125ef3208eSHongzhen Luo 	ihold(sharedinode);
1135ef3208eSHongzhen Luo 	realfile->f_op = &erofs_file_fops;
1145ef3208eSHongzhen Luo 	realfile->f_inode = sharedinode;
1155ef3208eSHongzhen Luo 	realfile->f_mapping = sharedinode->i_mapping;
1165ef3208eSHongzhen Luo 	path_get(&file->f_path);
1175ef3208eSHongzhen Luo 	backing_file_set_user_path(realfile, &file->f_path);
1185ef3208eSHongzhen Luo 
1195ef3208eSHongzhen Luo 	file_ra_state_init(&realfile->f_ra, file->f_mapping);
1205ef3208eSHongzhen Luo 	realfile->private_data = EROFS_I(inode);
1215ef3208eSHongzhen Luo 	file->private_data = realfile;
1225ef3208eSHongzhen Luo 	return 0;
1235ef3208eSHongzhen Luo }
1245ef3208eSHongzhen Luo 
erofs_ishare_file_release(struct inode * inode,struct file * file)1255ef3208eSHongzhen Luo static int erofs_ishare_file_release(struct inode *inode, struct file *file)
1265ef3208eSHongzhen Luo {
1275ef3208eSHongzhen Luo 	struct file *realfile = file->private_data;
1285ef3208eSHongzhen Luo 
1295ef3208eSHongzhen Luo 	iput(realfile->f_inode);
1305ef3208eSHongzhen Luo 	fput(realfile);
1315ef3208eSHongzhen Luo 	file->private_data = NULL;
1325ef3208eSHongzhen Luo 	return 0;
1335ef3208eSHongzhen Luo }
1345ef3208eSHongzhen Luo 
erofs_ishare_file_read_iter(struct kiocb * iocb,struct iov_iter * to)1355ef3208eSHongzhen Luo static ssize_t erofs_ishare_file_read_iter(struct kiocb *iocb,
1365ef3208eSHongzhen Luo 					   struct iov_iter *to)
1375ef3208eSHongzhen Luo {
1385ef3208eSHongzhen Luo 	struct file *realfile = iocb->ki_filp->private_data;
1395ef3208eSHongzhen Luo 	struct kiocb dedup_iocb;
1405ef3208eSHongzhen Luo 	ssize_t nread;
1415ef3208eSHongzhen Luo 
1425ef3208eSHongzhen Luo 	if (!iov_iter_count(to))
1435ef3208eSHongzhen Luo 		return 0;
1445ef3208eSHongzhen Luo 	kiocb_clone(&dedup_iocb, iocb, realfile);
1455ef3208eSHongzhen Luo 	nread = filemap_read(&dedup_iocb, to, 0);
1465ef3208eSHongzhen Luo 	iocb->ki_pos = dedup_iocb.ki_pos;
1475ef3208eSHongzhen Luo 	return nread;
1485ef3208eSHongzhen Luo }
1495ef3208eSHongzhen Luo 
erofs_ishare_mmap(struct file * file,struct vm_area_struct * vma)1505ef3208eSHongzhen Luo static int erofs_ishare_mmap(struct file *file, struct vm_area_struct *vma)
1515ef3208eSHongzhen Luo {
1525ef3208eSHongzhen Luo 	struct file *realfile = file->private_data;
1535ef3208eSHongzhen Luo 
1545ef3208eSHongzhen Luo 	vma_set_file(vma, realfile);
1555ef3208eSHongzhen Luo 	return generic_file_readonly_mmap(file, vma);
1565ef3208eSHongzhen Luo }
1575ef3208eSHongzhen Luo 
erofs_ishare_fadvise(struct file * file,loff_t offset,loff_t len,int advice)158d86d7817SHongzhen Luo static int erofs_ishare_fadvise(struct file *file, loff_t offset,
159d86d7817SHongzhen Luo 				loff_t len, int advice)
160d86d7817SHongzhen Luo {
161d86d7817SHongzhen Luo 	return vfs_fadvise(file->private_data, offset, len, advice);
162d86d7817SHongzhen Luo }
163d86d7817SHongzhen Luo 
1645ef3208eSHongzhen Luo const struct file_operations erofs_ishare_fops = {
1655ef3208eSHongzhen Luo 	.open		= erofs_ishare_file_open,
1665ef3208eSHongzhen Luo 	.llseek		= generic_file_llseek,
1675ef3208eSHongzhen Luo 	.read_iter	= erofs_ishare_file_read_iter,
1685ef3208eSHongzhen Luo 	.mmap		= erofs_ishare_mmap,
1695ef3208eSHongzhen Luo 	.release	= erofs_ishare_file_release,
1705ef3208eSHongzhen Luo 	.get_unmapped_area = thp_get_unmapped_area,
1715ef3208eSHongzhen Luo 	.splice_read	= filemap_splice_read,
172d86d7817SHongzhen Luo 	.fadvise	= erofs_ishare_fadvise,
1735ef3208eSHongzhen Luo };
1745ef3208eSHongzhen Luo 
erofs_real_inode(struct inode * inode,bool * need_iput)17534096ba9SHongbo Li struct inode *erofs_real_inode(struct inode *inode, bool *need_iput)
17634096ba9SHongbo Li {
17734096ba9SHongbo Li 	struct erofs_inode *vi, *vi_share;
17834096ba9SHongbo Li 	struct inode *realinode;
17934096ba9SHongbo Li 
18034096ba9SHongbo Li 	*need_iput = false;
18134096ba9SHongbo Li 	if (!erofs_is_ishare_inode(inode))
18234096ba9SHongbo Li 		return inode;
18334096ba9SHongbo Li 
18434096ba9SHongbo Li 	vi_share = EROFS_I(inode);
18534096ba9SHongbo Li 	spin_lock(&vi_share->ishare_lock);
18634096ba9SHongbo Li 	/* fetch any one as real inode */
18734096ba9SHongbo Li 	DBG_BUGON(list_empty(&vi_share->ishare_list));
18834096ba9SHongbo Li 	list_for_each_entry(vi, &vi_share->ishare_list, ishare_list) {
18934096ba9SHongbo Li 		realinode = igrab(&vi->vfs_inode);
19034096ba9SHongbo Li 		if (realinode) {
19134096ba9SHongbo Li 			*need_iput = true;
19234096ba9SHongbo Li 			break;
19334096ba9SHongbo Li 		}
19434096ba9SHongbo Li 	}
19534096ba9SHongbo Li 	spin_unlock(&vi_share->ishare_lock);
19634096ba9SHongbo Li 
19734096ba9SHongbo Li 	DBG_BUGON(!realinode);
19834096ba9SHongbo Li 	return realinode;
19934096ba9SHongbo Li }
20034096ba9SHongbo Li 
erofs_init_ishare(void)2015ef3208eSHongzhen Luo int __init erofs_init_ishare(void)
2025ef3208eSHongzhen Luo {
2035ef3208eSHongzhen Luo 	erofs_ishare_mnt = kern_mount(&erofs_anon_fs_type);
2045ef3208eSHongzhen Luo 	return PTR_ERR_OR_ZERO(erofs_ishare_mnt);
2055ef3208eSHongzhen Luo }
2065ef3208eSHongzhen Luo 
erofs_exit_ishare(void)2075ef3208eSHongzhen Luo void erofs_exit_ishare(void)
2085ef3208eSHongzhen Luo {
2095ef3208eSHongzhen Luo 	kern_unmount(erofs_ishare_mnt);
2105ef3208eSHongzhen Luo }
211