Merge branch 'work.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[platform/kernel/linux-starfive.git] / fs / open.c
index b3c904e..94bef26 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -852,8 +852,17 @@ static int do_dentry_open(struct file *f,
         * XXX: Huge page cache doesn't support writing yet. Drop all page
         * cache for this file before processing writes.
         */
-       if ((f->f_mode & FMODE_WRITE) && filemap_nr_thps(inode->i_mapping))
-               truncate_pagecache(inode, 0);
+       if (f->f_mode & FMODE_WRITE) {
+               /*
+                * Paired with smp_mb() in collapse_file() to ensure nr_thps
+                * is up to date and the update to i_writecount by
+                * get_write_access() is visible. Ensures subsequent insertion
+                * of THPs into the page cache will fail.
+                */
+               smp_mb();
+               if (filemap_nr_thps(inode->i_mapping))
+                       truncate_pagecache(inode, 0);
+       }
 
        return 0;
 
@@ -1002,12 +1011,20 @@ inline struct open_how build_open_how(int flags, umode_t mode)
 
 inline int build_open_flags(const struct open_how *how, struct open_flags *op)
 {
-       int flags = how->flags;
+       u64 flags = how->flags;
+       u64 strip = FMODE_NONOTIFY | O_CLOEXEC;
        int lookup_flags = 0;
        int acc_mode = ACC_MODE(flags);
 
-       /* Must never be set by userspace */
-       flags &= ~(FMODE_NONOTIFY | O_CLOEXEC);
+       BUILD_BUG_ON_MSG(upper_32_bits(VALID_OPEN_FLAGS),
+                        "struct open_flags doesn't yet handle flags > 32 bits");
+
+       /*
+        * Strip flags that either shouldn't be set by userspace like
+        * FMODE_NONOTIFY or that aren't relevant in determining struct
+        * open_flags like O_CLOEXEC.
+        */
+       flags &= ~strip;
 
        /*
         * Older syscalls implicitly clear all of the invalid flags or argument