]>
Commit | Line | Data |
---|---|---|
58def91c GKH |
1 | From 9e46b840c7053b5f7a245e98cd239b60d189a96c Mon Sep 17 00:00:00 2001 |
2 | From: Amir Goldstein <amir73il@gmail.com> | |
3 | Date: Wed, 27 Feb 2019 13:32:11 +0200 | |
4 | Subject: ovl: support stacked SEEK_HOLE/SEEK_DATA | |
5 | ||
6 | From: Amir Goldstein <amir73il@gmail.com> | |
7 | ||
8 | commit 9e46b840c7053b5f7a245e98cd239b60d189a96c upstream. | |
9 | ||
10 | Overlay file f_pos is the master copy that is preserved | |
11 | through copy up and modified on read/write, but only real | |
12 | fs knows how to SEEK_HOLE/SEEK_DATA and real fs may impose | |
13 | limitations that are more strict than ->s_maxbytes for specific | |
14 | files, so we use the real file to perform seeks. | |
15 | ||
16 | We do not call real fs for SEEK_CUR:0 query and for SEEK_SET:0 | |
17 | requests. | |
18 | ||
19 | Fixes: d1d04ef8572b ("ovl: stack file ops") | |
20 | Reported-by: Eddie Horng <eddiehorng.tw@gmail.com> | |
21 | Signed-off-by: Amir Goldstein <amir73il@gmail.com> | |
22 | Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> | |
23 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
24 | ||
25 | --- | |
26 | fs/overlayfs/file.c | 44 ++++++++++++++++++++++++++++++++++++++++---- | |
27 | 1 file changed, 40 insertions(+), 4 deletions(-) | |
28 | ||
29 | --- a/fs/overlayfs/file.c | |
30 | +++ b/fs/overlayfs/file.c | |
31 | @@ -146,11 +146,47 @@ static int ovl_release(struct inode *ino | |
32 | ||
33 | static loff_t ovl_llseek(struct file *file, loff_t offset, int whence) | |
34 | { | |
35 | - struct inode *realinode = ovl_inode_real(file_inode(file)); | |
36 | + struct inode *inode = file_inode(file); | |
37 | + struct fd real; | |
38 | + const struct cred *old_cred; | |
39 | + ssize_t ret; | |
40 | ||
41 | - return generic_file_llseek_size(file, offset, whence, | |
42 | - realinode->i_sb->s_maxbytes, | |
43 | - i_size_read(realinode)); | |
44 | + /* | |
45 | + * The two special cases below do not need to involve real fs, | |
46 | + * so we can optimizing concurrent callers. | |
47 | + */ | |
48 | + if (offset == 0) { | |
49 | + if (whence == SEEK_CUR) | |
50 | + return file->f_pos; | |
51 | + | |
52 | + if (whence == SEEK_SET) | |
53 | + return vfs_setpos(file, 0, 0); | |
54 | + } | |
55 | + | |
56 | + ret = ovl_real_fdget(file, &real); | |
57 | + if (ret) | |
58 | + return ret; | |
59 | + | |
60 | + /* | |
61 | + * Overlay file f_pos is the master copy that is preserved | |
62 | + * through copy up and modified on read/write, but only real | |
63 | + * fs knows how to SEEK_HOLE/SEEK_DATA and real fs may impose | |
64 | + * limitations that are more strict than ->s_maxbytes for specific | |
65 | + * files, so we use the real file to perform seeks. | |
66 | + */ | |
67 | + inode_lock(inode); | |
68 | + real.file->f_pos = file->f_pos; | |
69 | + | |
70 | + old_cred = ovl_override_creds(inode->i_sb); | |
71 | + ret = vfs_llseek(real.file, offset, whence); | |
72 | + revert_creds(old_cred); | |
73 | + | |
74 | + file->f_pos = real.file->f_pos; | |
75 | + inode_unlock(inode); | |
76 | + | |
77 | + fdput(real); | |
78 | + | |
79 | + return ret; | |
80 | } | |
81 | ||
82 | static void ovl_file_accessed(struct file *file) |