Merge branch 'work.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[sfrench/cifs-2.6.git] / fs / open.c
index e53af13b5835f3459b2ce7eafdc3697e874e40c3..94bef26ff1b616a23544da9e0d9232ef97aca034 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
@@ -1156,7 +1173,7 @@ struct file *filp_open(const char *filename, int flags, umode_t mode)
 }
 EXPORT_SYMBOL(filp_open);
 
-struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
+struct file *file_open_root(const struct path *root,
                            const char *filename, int flags, umode_t mode)
 {
        struct open_flags op;
@@ -1164,7 +1181,7 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
        int err = build_open_flags(&how, &op);
        if (err)
                return ERR_PTR(err);
-       return do_file_open_root(dentry, mnt, filename, &op);
+       return do_file_open_root(root, filename, &op);
 }
 EXPORT_SYMBOL(file_open_root);