blob: c47b9e91016807ab0a7808b74076b3db6a0826b4 [file] [log] [blame]
Daniel Campello3a703812015-07-20 16:23:50 -07001/*
2 * fs/sdcardfs/file.c
3 *
4 * Copyright (c) 2013 Samsung Electronics Co. Ltd
5 * Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun,
6 * Sunghwan Yun, Sungjong Seo
7 *
8 * This program has been developed as a stackable file system based on
9 * the WrapFS which written by
10 *
11 * Copyright (c) 1998-2011 Erez Zadok
12 * Copyright (c) 2009 Shrikar Archak
13 * Copyright (c) 2003-2011 Stony Brook University
14 * Copyright (c) 2003-2011 The Research Foundation of SUNY
15 *
16 * This file is dual licensed. It may be redistributed and/or modified
17 * under the terms of the Apache 2.0 License OR version 2 of the GNU
18 * General Public License.
19 */
20
21#include "sdcardfs.h"
22#ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE
23#include <linux/backing-dev.h>
24#endif
25
26static ssize_t sdcardfs_read(struct file *file, char __user *buf,
27 size_t count, loff_t *ppos)
28{
29 int err;
30 struct file *lower_file;
31 struct dentry *dentry = file->f_path.dentry;
32#ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE
33 struct backing_dev_info *bdi;
34#endif
35
36 lower_file = sdcardfs_lower_file(file);
37
38#ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE
39 if (file->f_mode & FMODE_NOACTIVE) {
40 if (!(lower_file->f_mode & FMODE_NOACTIVE)) {
41 bdi = lower_file->f_mapping->backing_dev_info;
42 lower_file->f_ra.ra_pages = bdi->ra_pages * 2;
43 spin_lock(&lower_file->f_lock);
44 lower_file->f_mode |= FMODE_NOACTIVE;
45 spin_unlock(&lower_file->f_lock);
46 }
47 }
48#endif
49
50 err = vfs_read(lower_file, buf, count, ppos);
51 /* update our inode atime upon a successful lower read */
52 if (err >= 0)
53 fsstack_copy_attr_atime(dentry->d_inode,
54 lower_file->f_path.dentry->d_inode);
55
56 return err;
57}
58
59static ssize_t sdcardfs_write(struct file *file, const char __user *buf,
60 size_t count, loff_t *ppos)
61{
62 int err = 0;
63 struct file *lower_file;
64 struct dentry *dentry = file->f_path.dentry;
Daniel Rosenberg690f2882018-02-20 20:25:45 -080065 struct inode *inode = dentry->d_inode;
Daniel Campello3a703812015-07-20 16:23:50 -070066
67 /* check disk space */
68 if (!check_min_free_space(dentry, count, 0)) {
Daniel Rosenberg720f8572017-03-16 17:46:13 -070069 pr_err("No minimum free space.\n");
Daniel Campello3a703812015-07-20 16:23:50 -070070 return -ENOSPC;
71 }
72
73 lower_file = sdcardfs_lower_file(file);
74 err = vfs_write(lower_file, buf, count, ppos);
75 /* update our inode times+sizes upon a successful lower write */
76 if (err >= 0) {
Daniel Rosenberg690f2882018-02-20 20:25:45 -080077 if (sizeof(loff_t) > sizeof(long))
78 mutex_lock(&inode->i_mutex);
79 fsstack_copy_inode_size(inode, lower_file->f_path.dentry->d_inode);
80 fsstack_copy_attr_times(inode, lower_file->f_path.dentry->d_inode);
81 if (sizeof(loff_t) > sizeof(long))
82 mutex_unlock(&inode->i_mutex);
Daniel Campello3a703812015-07-20 16:23:50 -070083 }
84
85 return err;
86}
87
88static int sdcardfs_readdir(struct file *file, void *dirent, filldir_t filldir)
89{
90 int err = 0;
91 struct file *lower_file = NULL;
92 struct dentry *dentry = file->f_path.dentry;
93
94 lower_file = sdcardfs_lower_file(file);
95
96 lower_file->f_pos = file->f_pos;
97 err = vfs_readdir(lower_file, filldir, dirent);
98 file->f_pos = lower_file->f_pos;
99 if (err >= 0) /* copy the atime */
100 fsstack_copy_attr_atime(dentry->d_inode,
101 lower_file->f_path.dentry->d_inode);
102 return err;
103}
104
105static long sdcardfs_unlocked_ioctl(struct file *file, unsigned int cmd,
106 unsigned long arg)
107{
108 long err = -ENOTTY;
109 struct file *lower_file;
Jaegeuk Kimba32e492017-07-06 19:12:22 -0700110 const struct cred *saved_cred = NULL;
111 struct dentry *dentry = file->f_path.dentry;
112 struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
Daniel Campello3a703812015-07-20 16:23:50 -0700113
114 lower_file = sdcardfs_lower_file(file);
115
116 /* XXX: use vfs_ioctl if/when VFS exports it */
117 if (!lower_file || !lower_file->f_op)
118 goto out;
Jaegeuk Kimba32e492017-07-06 19:12:22 -0700119
120 /* save current_cred and override it */
Daniel Rosenberg0b9f6012018-07-19 18:08:35 -0700121 saved_cred = override_fsids(sbi, SDCARDFS_I(file->f_path.dentry->d_inode)->data);
Bharath453f14d2020-09-10 13:36:38 +0530122 if (!saved_cred) {
Karsten Tausche3a212e22020-04-07 18:25:49 +0200123 err = -ENOMEM;
124 goto out;
Bharath453f14d2020-09-10 13:36:38 +0530125 }
Jaegeuk Kimba32e492017-07-06 19:12:22 -0700126
Daniel Campello3a703812015-07-20 16:23:50 -0700127 if (lower_file->f_op->unlocked_ioctl)
128 err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
129
Daniel Rosenberg893f3af2017-03-09 21:24:58 -0800130 /* some ioctls can change inode attributes (EXT2_IOC_SETFLAGS) */
131 if (!err)
132 sdcardfs_copy_and_fix_attrs(file->f_path.dentry->d_inode,
133 lower_file->f_path.dentry->d_inode);
Daniel Rosenberg0b9f6012018-07-19 18:08:35 -0700134 revert_fsids(saved_cred);
Daniel Campello3a703812015-07-20 16:23:50 -0700135out:
136 return err;
137}
138
139#ifdef CONFIG_COMPAT
140static long sdcardfs_compat_ioctl(struct file *file, unsigned int cmd,
141 unsigned long arg)
142{
143 long err = -ENOTTY;
144 struct file *lower_file;
Jaegeuk Kimba32e492017-07-06 19:12:22 -0700145 const struct cred *saved_cred = NULL;
146 struct dentry *dentry = file->f_path.dentry;
147 struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
Daniel Campello3a703812015-07-20 16:23:50 -0700148
149 lower_file = sdcardfs_lower_file(file);
150
151 /* XXX: use vfs_ioctl if/when VFS exports it */
152 if (!lower_file || !lower_file->f_op)
153 goto out;
Jaegeuk Kimba32e492017-07-06 19:12:22 -0700154
155 /* save current_cred and override it */
Daniel Rosenberg0b9f6012018-07-19 18:08:35 -0700156 saved_cred = override_fsids(sbi, SDCARDFS_I(file->f_path.dentry->d_inode)->data);
157 if (!saved_cred)
158 return -ENOMEM;
Jaegeuk Kimba32e492017-07-06 19:12:22 -0700159
Daniel Campello3a703812015-07-20 16:23:50 -0700160 if (lower_file->f_op->compat_ioctl)
161 err = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
162
Daniel Rosenberg0b9f6012018-07-19 18:08:35 -0700163 revert_fsids(saved_cred);
Daniel Campello3a703812015-07-20 16:23:50 -0700164out:
165 return err;
166}
167#endif
168
169static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma)
170{
171 int err = 0;
172 bool willwrite;
173 struct file *lower_file;
174 const struct vm_operations_struct *saved_vm_ops = NULL;
175
176 /* this might be deferred to mmap's writepage */
177 willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags);
178
179 /*
180 * File systems which do not implement ->writepage may use
181 * generic_file_readonly_mmap as their ->mmap op. If you call
182 * generic_file_readonly_mmap with VM_WRITE, you'd get an -EINVAL.
183 * But we cannot call the lower ->mmap op, so we can't tell that
184 * writeable mappings won't work. Therefore, our only choice is to
185 * check if the lower file system supports the ->writepage, and if
186 * not, return EINVAL (the same error that
187 * generic_file_readonly_mmap returns in that case).
188 */
189 lower_file = sdcardfs_lower_file(file);
190 if (willwrite && !lower_file->f_mapping->a_ops->writepage) {
191 err = -EINVAL;
Daniel Rosenberg720f8572017-03-16 17:46:13 -0700192 pr_err("sdcardfs: lower file system does not support writeable mmap\n");
Daniel Campello3a703812015-07-20 16:23:50 -0700193 goto out;
194 }
195
196 /*
197 * find and save lower vm_ops.
198 *
199 * XXX: the VFS should have a cleaner way of finding the lower vm_ops
200 */
201 if (!SDCARDFS_F(file)->lower_vm_ops) {
202 err = lower_file->f_op->mmap(lower_file, vma);
203 if (err) {
Daniel Rosenberg720f8572017-03-16 17:46:13 -0700204 pr_err("sdcardfs: lower mmap failed %d\n", err);
Daniel Campello3a703812015-07-20 16:23:50 -0700205 goto out;
206 }
207 saved_vm_ops = vma->vm_ops; /* save: came from lower ->mmap */
Daniel Campello3a703812015-07-20 16:23:50 -0700208 }
209
210 /*
211 * Next 3 lines are all I need from generic_file_mmap. I definitely
212 * don't want its test for ->readpage which returns -ENOEXEC.
213 */
214 file_accessed(file);
215 vma->vm_ops = &sdcardfs_vm_ops;
216 vma->vm_flags |= VM_CAN_NONLINEAR;
217
218 file->f_mapping->a_ops = &sdcardfs_aops; /* set our aops */
219 if (!SDCARDFS_F(file)->lower_vm_ops) /* save for our ->fault */
220 SDCARDFS_F(file)->lower_vm_ops = saved_vm_ops;
Daniel Rosenberg23f21512017-04-10 20:54:30 -0700221 vma->vm_private_data = file;
222 get_file(lower_file);
223 vma->vm_file = lower_file;
Daniel Campello3a703812015-07-20 16:23:50 -0700224
225out:
226 return err;
227}
228
229static int sdcardfs_open(struct inode *inode, struct file *file)
230{
231 int err = 0;
232 struct file *lower_file = NULL;
233 struct path lower_path;
234 struct dentry *dentry = file->f_path.dentry;
235 struct dentry *parent = dget_parent(dentry);
236 struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
237 const struct cred *saved_cred = NULL;
Daniel Campello3a703812015-07-20 16:23:50 -0700238
239 /* don't open unhashed/deleted files */
240 if (d_unhashed(dentry)) {
241 err = -ENOENT;
242 goto out_err;
243 }
244
Daniel Rosenbergbeb00302017-03-16 17:42:58 -0700245 if (!check_caller_access_to_name(parent->d_inode, &dentry->d_name)) {
Daniel Campello3a703812015-07-20 16:23:50 -0700246 err = -EACCES;
247 goto out_err;
248 }
249
250 /* save current_cred and override it */
Daniel Rosenberg0b9f6012018-07-19 18:08:35 -0700251 saved_cred = override_fsids(sbi, SDCARDFS_I(inode)->data);
252 if (!saved_cred) {
253 err = -ENOMEM;
254 goto out_err;
255 }
Daniel Campello3a703812015-07-20 16:23:50 -0700256
257 file->private_data =
258 kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL);
259 if (!SDCARDFS_F(file)) {
260 err = -ENOMEM;
261 goto out_revert_cred;
262 }
263
264 /* open lower object and link sdcardfs's file struct to lower's */
265 sdcardfs_get_lower_path(file->f_path.dentry, &lower_path);
266 lower_file = dentry_open(lower_path.dentry, lower_path.mnt,
267 file->f_flags, current_cred());
268 if (IS_ERR(lower_file)) {
269 err = PTR_ERR(lower_file);
270 lower_file = sdcardfs_lower_file(file);
271 if (lower_file) {
272 sdcardfs_set_lower_file(file, NULL);
273 fput(lower_file); /* fput calls dput for lower_dentry */
274 }
275 } else {
276 sdcardfs_set_lower_file(file, lower_file);
277 }
278
279 if (err)
280 kfree(SDCARDFS_F(file));
Daniel Rosenbergbeb00302017-03-16 17:42:58 -0700281 else
Daniel Rosenberg5c09ef42016-02-03 21:08:21 -0800282 sdcardfs_copy_and_fix_attrs(inode, sdcardfs_lower_inode(inode));
Daniel Campello3a703812015-07-20 16:23:50 -0700283
284out_revert_cred:
Daniel Rosenberg0b9f6012018-07-19 18:08:35 -0700285 revert_fsids(saved_cred);
Daniel Campello3a703812015-07-20 16:23:50 -0700286out_err:
287 dput(parent);
288 return err;
289}
290
291static int sdcardfs_flush(struct file *file, fl_owner_t id)
292{
293 int err = 0;
294 struct file *lower_file = NULL;
295
296 lower_file = sdcardfs_lower_file(file);
297 if (lower_file && lower_file->f_op && lower_file->f_op->flush)
298 err = lower_file->f_op->flush(lower_file, id);
299
300 return err;
301}
302
303/* release all lower object references & free the file info structure */
304static int sdcardfs_file_release(struct inode *inode, struct file *file)
305{
306 struct file *lower_file;
307
308 lower_file = sdcardfs_lower_file(file);
309 if (lower_file) {
310 sdcardfs_set_lower_file(file, NULL);
311 fput(lower_file);
312 }
313
314 kfree(SDCARDFS_F(file));
315 return 0;
316}
317
fluxidd0f23e2016-07-29 18:52:13 +0200318static int sdcardfs_fsync(struct file *file, loff_t start, loff_t end,
319 int datasync)
Daniel Campello3a703812015-07-20 16:23:50 -0700320{
321 int err;
322 struct file *lower_file;
323 struct path lower_path;
324 struct dentry *dentry = file->f_path.dentry;
325
fluxidd0f23e2016-07-29 18:52:13 +0200326 err = generic_file_fsync(file, start, end, datasync);
327 if (err)
328 goto out;
329
Daniel Campello3a703812015-07-20 16:23:50 -0700330 lower_file = sdcardfs_lower_file(file);
331 sdcardfs_get_lower_path(dentry, &lower_path);
fluxidd0f23e2016-07-29 18:52:13 +0200332 err = vfs_fsync_range(lower_file, start, end, datasync);
Daniel Campello3a703812015-07-20 16:23:50 -0700333 sdcardfs_put_lower_path(dentry, &lower_path);
334
fluxidd0f23e2016-07-29 18:52:13 +0200335out:
Daniel Campello3a703812015-07-20 16:23:50 -0700336 return err;
337}
338
339static int sdcardfs_fasync(int fd, struct file *file, int flag)
340{
341 int err = 0;
342 struct file *lower_file = NULL;
343
344 lower_file = sdcardfs_lower_file(file);
345 if (lower_file->f_op && lower_file->f_op->fasync)
346 err = lower_file->f_op->fasync(fd, lower_file, flag);
347
348 return err;
349}
350
Daniel Rosenberg2d6d1b62017-03-09 21:42:01 -0800351/*
352 * Sdcardfs cannot use generic_file_llseek as ->llseek, because it would
353 * only set the offset of the upper file. So we have to implement our
354 * own method to set both the upper and lower file offsets
355 * consistently.
356 */
357static loff_t sdcardfs_file_llseek(struct file *file, loff_t offset, int whence)
358{
359 int err;
360 struct file *lower_file;
361
362 err = generic_file_llseek(file, offset, whence);
363 if (err < 0)
364 goto out;
365
366 lower_file = sdcardfs_lower_file(file);
367 err = generic_file_llseek(lower_file, offset, whence);
368
369out:
370 return err;
371}
372
373
Daniel Campello3a703812015-07-20 16:23:50 -0700374const struct file_operations sdcardfs_main_fops = {
375 .llseek = generic_file_llseek,
376 .read = sdcardfs_read,
377 .write = sdcardfs_write,
378 .unlocked_ioctl = sdcardfs_unlocked_ioctl,
379#ifdef CONFIG_COMPAT
380 .compat_ioctl = sdcardfs_compat_ioctl,
381#endif
382 .mmap = sdcardfs_mmap,
383 .open = sdcardfs_open,
384 .flush = sdcardfs_flush,
385 .release = sdcardfs_file_release,
386 .fsync = sdcardfs_fsync,
387 .fasync = sdcardfs_fasync,
388};
389
390/* trimmed directory options */
391const struct file_operations sdcardfs_dir_fops = {
Daniel Rosenberg2d6d1b62017-03-09 21:42:01 -0800392 .llseek = sdcardfs_file_llseek,
Daniel Campello3a703812015-07-20 16:23:50 -0700393 .read = generic_read_dir,
394 .readdir = sdcardfs_readdir,
395 .unlocked_ioctl = sdcardfs_unlocked_ioctl,
396#ifdef CONFIG_COMPAT
397 .compat_ioctl = sdcardfs_compat_ioctl,
398#endif
399 .open = sdcardfs_open,
400 .release = sdcardfs_file_release,
401 .flush = sdcardfs_flush,
402 .fsync = sdcardfs_fsync,
403 .fasync = sdcardfs_fasync,
404};