• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * fs/sharefs/file.c
4  *
5  * Copyright (c) 1998-2022 Erez Zadok
6  * Copyright (c) 2009	   Shrikar Archak
7  * Copyright (c) 2003-2022 Stony Brook University
8  * Copyright (c) 2003-2022 The Research Foundation of SUNY
9  * Copyright (c) 2023 Huawei Device Co., Ltd.
10  */
11 
12 #include "sharefs.h"
13 
sharefs_open(struct inode * inode,struct file * file)14 static int sharefs_open(struct inode *inode, struct file *file)
15 {
16 	int err = 0;
17 	struct file *lower_file = NULL;
18 	struct path lower_path;
19 
20 	/* don't open unhashed/deleted files */
21 	if (d_unhashed(file->f_path.dentry)) {
22 		err = -ENOENT;
23 		goto out_err;
24 	}
25 
26 	file->private_data =
27 		kzalloc(sizeof(struct sharefs_file_info), GFP_KERNEL);
28 	if (!SHAREFS_F(file)) {
29 		err = -ENOMEM;
30 		goto out_err;
31 	}
32 
33 	/* open lower object and link sharefs's file struct to lower's */
34 	sharefs_get_lower_path(file->f_path.dentry, &lower_path);
35 	lower_file = dentry_open(&lower_path, file->f_flags, current_cred());
36 	path_put(&lower_path);
37 	if (IS_ERR(lower_file)) {
38 		err = PTR_ERR(lower_file);
39 		lower_file = sharefs_lower_file(file);
40 		if (lower_file) {
41 			sharefs_set_lower_file(file, NULL);
42 			fput(lower_file); /* fput calls dput for lower_dentry */
43 		}
44 	} else {
45 		sharefs_set_lower_file(file, lower_file);
46 	}
47 
48 	if (err) {
49 		kfree(SHAREFS_F(file));
50 	} else {
51 		kuid_t uid = inode->i_uid;
52 		kgid_t gid = inode->i_gid;
53 		mode_t mode = inode->i_mode;
54 		fsstack_copy_attr_all(inode, sharefs_lower_inode(inode));
55 		inode->i_uid = uid;
56 		inode->i_gid = gid;
57 		inode->i_mode = mode;
58 	}
59 out_err:
60 	return err;
61 }
62 
sharefs_flush(struct file * file,fl_owner_t id)63 static int sharefs_flush(struct file *file, fl_owner_t id)
64 {
65 	int err = 0;
66 	struct file *lower_file = NULL;
67 
68 	lower_file = sharefs_lower_file(file);
69 	if (lower_file && lower_file->f_op && lower_file->f_op->flush) {
70 		filemap_write_and_wait(file->f_mapping);
71 		err = lower_file->f_op->flush(lower_file, id);
72 	}
73 
74 	return err;
75 }
76 
77 /* release all lower object references & free the file info structure */
sharefs_file_release(struct inode * inode,struct file * file)78 static int sharefs_file_release(struct inode *inode, struct file *file)
79 {
80 	struct file *lower_file;
81 
82 	lower_file = sharefs_lower_file(file);
83 	if (lower_file) {
84 		sharefs_set_lower_file(file, NULL);
85 		fput(lower_file);
86 	}
87 
88 	kfree(SHAREFS_F(file));
89 	return 0;
90 }
91 
sharefs_fsync(struct file * file,loff_t start,loff_t end,int datasync)92 static int sharefs_fsync(struct file *file, loff_t start, loff_t end,
93 			int datasync)
94 {
95 	int err;
96 	struct file *lower_file;
97 	struct path lower_path;
98 	struct dentry *dentry = file->f_path.dentry;
99 
100 	err = __generic_file_fsync(file, start, end, datasync);
101 	if (err)
102 		goto out;
103 	lower_file = sharefs_lower_file(file);
104 	sharefs_get_lower_path(dentry, &lower_path);
105 	err = vfs_fsync_range(lower_file, start, end, datasync);
106 	sharefs_put_lower_path(dentry, &lower_path);
107 out:
108 	return err;
109 }
110 
sharefs_fasync(int fd,struct file * file,int flag)111 static int sharefs_fasync(int fd, struct file *file, int flag)
112 {
113 	int err = 0;
114 	struct file *lower_file = NULL;
115 
116 	lower_file = sharefs_lower_file(file);
117 	if (lower_file->f_op && lower_file->f_op->fasync)
118 		err = lower_file->f_op->fasync(fd, lower_file, flag);
119 
120 	return err;
121 }
122 
123 /*
124  * Sharefs cannot use generic_file_llseek as ->llseek, because it would
125  * only set the offset of the upper file.  So we have to implement our
126  * own method to set both the upper and lower file offsets
127  * consistently.
128  */
sharefs_file_llseek(struct file * file,loff_t offset,int whence)129 static loff_t sharefs_file_llseek(struct file *file, loff_t offset, int whence)
130 {
131 	int err;
132 	struct file *lower_file;
133 
134 	err = generic_file_llseek(file, offset, whence);
135 	if (err < 0)
136 		goto out;
137 
138 	lower_file = sharefs_lower_file(file);
139 	err = generic_file_llseek(lower_file, offset, whence);
140 
141 out:
142 	return err;
143 }
144 
145 /*
146  * Sharefs read_iter, redirect modified iocb to lower read_iter
147  */
148 ssize_t
sharefs_read_iter(struct kiocb * iocb,struct iov_iter * iter)149 sharefs_read_iter(struct kiocb *iocb, struct iov_iter *iter)
150 {
151 	int err;
152 	struct file *file = iocb->ki_filp;
153 	struct file *lower_file;
154 
155 	lower_file = sharefs_lower_file(file);
156 	if (!lower_file->f_op->read_iter) {
157 		err = -EINVAL;
158 		goto out;
159 	}
160 
161 	/* prevent lower_file from being released */
162 	get_file(lower_file);
163 	iocb->ki_filp = lower_file;
164 	err = lower_file->f_op->read_iter(iocb, iter);
165 	iocb->ki_filp = file;
166 	fput(lower_file);
167 
168 	/* update upper inode atime as needed */
169 	if (err >= 0 || err == -EIOCBQUEUED)
170 		fsstack_copy_attr_atime(d_inode(file->f_path.dentry),
171 					file_inode(lower_file));
172 out:
173 	return err;
174 }
175 
176 /*
177  * Sharefs write_iter, redirect modified iocb to lower write_iter
178  */
179 ssize_t
sharefs_write_iter(struct kiocb * iocb,struct iov_iter * iter)180 sharefs_write_iter(struct kiocb *iocb, struct iov_iter *iter)
181 {
182 	int err;
183 	struct file *file = iocb->ki_filp;
184 	struct file *lower_file;
185 
186 	lower_file = sharefs_lower_file(file);
187 	if (!lower_file->f_op->write_iter) {
188 		err = -EINVAL;
189 		goto out;
190 	}
191 
192 	get_file(lower_file); /* prevent lower_file from being released */
193 	iocb->ki_filp = lower_file;
194 	err = lower_file->f_op->write_iter(iocb, iter);
195 	iocb->ki_filp = file;
196 	fput(lower_file);
197 	/* update upper inode times/sizes as needed */
198 	if (err >= 0 || err == -EIOCBQUEUED) {
199 		fsstack_copy_inode_size(d_inode(file->f_path.dentry),
200 					file_inode(lower_file));
201 		fsstack_copy_attr_times(d_inode(file->f_path.dentry),
202 					file_inode(lower_file));
203 	}
204 out:
205 	return err;
206 }
207 
sharefs_file_mmap(struct file * file,struct vm_area_struct * vma)208 int sharefs_file_mmap(struct file *file, struct vm_area_struct *vma)
209 {
210 	int err = 0;
211 	struct file *lower_file;
212 
213 	lower_file = sharefs_lower_file(file);
214 	if (!lower_file)
215 		return -EINVAL;
216 
217 	if (!lower_file->f_op->mmap)
218 		return -ENODEV;
219 
220 	if (WARN_ON(file != vma->vm_file))
221 		return -EIO;
222 
223 	vma->vm_file = get_file(lower_file);
224 	err = call_mmap(vma->vm_file, vma);
225 	if (err)
226 		fput(lower_file);
227 	else
228 		fput(file);
229 
230 	file_accessed(file);
231 
232 	return err;
233 }
234 
235 const struct file_operations sharefs_main_fops = {
236 	.llseek		= sharefs_file_llseek,
237 	.open		= sharefs_open,
238 	.flush		= sharefs_flush,
239 	.release	= sharefs_file_release,
240 	.fsync		= sharefs_fsync,
241 	.fasync		= sharefs_fasync,
242 	.read_iter	= sharefs_read_iter,
243 	.write_iter	= sharefs_write_iter,
244 	.mmap		= sharefs_file_mmap,
245 };
246 
247 /* trimmed directory options */
248 const struct file_operations sharefs_dir_fops = {
249 	.llseek		= sharefs_file_llseek,
250 	.open		= sharefs_open,
251 	.release	= sharefs_file_release,
252 	.flush		= sharefs_flush,
253 	.fsync		= sharefs_fsync,
254 	.fasync		= sharefs_fasync,
255 };
256