Implement individual lock for SEEK_END for overlayfs which directly calls
generic_file_llseek_size().

Signed-off-by: Eiichi Tsukata <de...@etsukata.com>
---
 fs/overlayfs/file.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
index 84dd957efa24..57bc6538eea8 100644
--- a/fs/overlayfs/file.c
+++ b/fs/overlayfs/file.c
@@ -146,10 +146,27 @@ static int ovl_release(struct inode *inode, struct file 
*file)
 static loff_t ovl_llseek(struct file *file, loff_t offset, int whence)
 {
        struct inode *realinode = ovl_inode_real(file_inode(file));
+       loff_t ret;
 
-       return generic_file_llseek_size(file, offset, whence,
-                                       realinode->i_sb->s_maxbytes,
-                                       i_size_read(realinode));
+       switch (whence) {
+       default:
+               return generic_file_llseek_size(file, offset, whence,
+                                               realinode->i_sb->s_maxbytes,
+                                               i_size_read(realinode));
+       case SEEK_END:
+       case SEEK_DATA:
+       case SEEK_HOLE:
+               /*
+                * protects against inode size race with write so that llseek
+                * doesn't see inode size being updated in individual fs write
+                */
+               inode_lock(realinode);
+               ret = generic_file_llseek_size(file, offset, whence,
+                                              realinode->i_sb->s_maxbytes,
+                                              i_size_read(realinode));
+               inode_unlock(realinode);
+               return ret;
+       }
 }
 
 static void ovl_file_accessed(struct file *file)
-- 
2.19.1

Reply via email to