diff options
Diffstat (limited to 'fs/overlayfs/file.c')
-rw-r--r-- | fs/overlayfs/file.c | 44 |
1 files changed, 40 insertions, 4 deletions
diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 50e4407398d8..ddfd93f13cc5 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c | |||
@@ -144,11 +144,47 @@ static int ovl_release(struct inode *inode, struct file *file) | |||
144 | 144 | ||
145 | static loff_t ovl_llseek(struct file *file, loff_t offset, int whence) | 145 | static loff_t ovl_llseek(struct file *file, loff_t offset, int whence) |
146 | { | 146 | { |
147 | struct inode *realinode = ovl_inode_real(file_inode(file)); | 147 | struct inode *inode = file_inode(file); |
148 | struct fd real; | ||
149 | const struct cred *old_cred; | ||
150 | ssize_t ret; | ||
151 | |||
152 | /* | ||
153 | * The two special cases below do not need to involve real fs, | ||
154 | * so we can optimizing concurrent callers. | ||
155 | */ | ||
156 | if (offset == 0) { | ||
157 | if (whence == SEEK_CUR) | ||
158 | return file->f_pos; | ||
159 | |||
160 | if (whence == SEEK_SET) | ||
161 | return vfs_setpos(file, 0, 0); | ||
162 | } | ||
163 | |||
164 | ret = ovl_real_fdget(file, &real); | ||
165 | if (ret) | ||
166 | return ret; | ||
148 | 167 | ||
149 | return generic_file_llseek_size(file, offset, whence, | 168 | /* |
150 | realinode->i_sb->s_maxbytes, | 169 | * Overlay file f_pos is the master copy that is preserved |
151 | i_size_read(realinode)); | 170 | * through copy up and modified on read/write, but only real |
171 | * fs knows how to SEEK_HOLE/SEEK_DATA and real fs may impose | ||
172 | * limitations that are more strict than ->s_maxbytes for specific | ||
173 | * files, so we use the real file to perform seeks. | ||
174 | */ | ||
175 | inode_lock(inode); | ||
176 | real.file->f_pos = file->f_pos; | ||
177 | |||
178 | old_cred = ovl_override_creds(inode->i_sb); | ||
179 | ret = vfs_llseek(real.file, offset, whence); | ||
180 | revert_creds(old_cred); | ||
181 | |||
182 | file->f_pos = real.file->f_pos; | ||
183 | inode_unlock(inode); | ||
184 | |||
185 | fdput(real); | ||
186 | |||
187 | return ret; | ||
152 | } | 188 | } |
153 | 189 | ||
154 | static void ovl_file_accessed(struct file *file) | 190 | static void ovl_file_accessed(struct file *file) |