From: Amir Goldstein <amir7...@gmail.com>

FS_PRE_ACCESS or FS_PRE_MODIFY will be generated on open depending on
file open mode.  The pre-content event will be generated in addition to
FS_OPEN_PERM, but without sb_writers held and after file was truncated
in case file was opened with O_CREAT and/or O_TRUNC.

The event will have a range info of (0..0) to provide an opportunity
to fill entire file content on open.

Signed-off-by: Amir Goldstein <amir7...@gmail.com>
Reviewed-by: Christian Brauner <brau...@kernel.org>
---
 fs/namei.c               |  9 +++++++++
 include/linux/fsnotify.h | 10 +++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/fs/namei.c b/fs/namei.c
index 3a4c40e12f78..c16487e3742d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3735,6 +3735,15 @@ static int do_open(struct nameidata *nd,
        }
        if (do_truncate)
                mnt_drop_write(nd->path.mnt);
+
+       /*
+        * This permission hook is different than fsnotify_open_perm() hook.
+        * This is a pre-content hook that is called without sb_writers held
+        * and after the file was truncated.
+        */
+       if (!error)
+               error = fsnotify_file_perm(file, MAY_OPEN);
+
        return error;
 }
 
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 7600a0c045ba..fb3837b8de4c 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -168,6 +168,10 @@ static inline int fsnotify_file_area_perm(struct file 
*file, int perm_mask,
                fsnotify_mask = FS_PRE_MODIFY;
        else if (perm_mask & (MAY_READ | MAY_ACCESS))
                fsnotify_mask = FS_PRE_ACCESS;
+       else if (perm_mask & MAY_OPEN && file->f_mode & FMODE_WRITER)
+               fsnotify_mask = FS_PRE_MODIFY;
+       else if (perm_mask & MAY_OPEN)
+               fsnotify_mask = FS_PRE_ACCESS;
        else
                return 0;
 
@@ -176,10 +180,14 @@ static inline int fsnotify_file_area_perm(struct file 
*file, int perm_mask,
 
 /*
  * fsnotify_file_perm - permission hook before file access
+ *
+ * Called from read()/write() with perm_mask MAY_READ/MAY_WRITE.
+ * Called from open() with MAY_OPEN without sb_writers held and after the file
+ * was truncated. Note that this is a different event from 
fsnotify_open_perm().
  */
 static inline int fsnotify_file_perm(struct file *file, int perm_mask)
 {
-       return fsnotify_file_area_perm(file, perm_mask, NULL, 0);
+       return fsnotify_file_area_perm(file, perm_mask, &file->f_pos, 0);
 }
 
 /*
-- 
2.43.0


Reply via email to