Merge tag 'vfs-6.9.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[linux-block.git] / include / linux / fs.h
index 1fbc72c5f112c750b87e7d752e4d5871258ddabe..2ba751d097c1d110d5a4a4fc2ca4b418765cd142 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/cred.h>
 #include <linux/mnt_idmapping.h>
 #include <linux/slab.h>
+#include <linux/maple_tree.h>
 
 #include <asm/byteorder.h>
 #include <uapi/linux/fs.h>
@@ -484,10 +485,10 @@ struct address_space {
        pgoff_t                 writeback_index;
        const struct address_space_operations *a_ops;
        unsigned long           flags;
-       struct rw_semaphore     i_mmap_rwsem;
        errseq_t                wb_err;
        spinlock_t              i_private_lock;
        struct list_head        i_private_list;
+       struct rw_semaphore     i_mmap_rwsem;
        void *                  i_private_data;
 } __attribute__((aligned(sizeof(long)))) __randomize_layout;
        /*
@@ -909,7 +910,8 @@ static inline loff_t i_size_read(const struct inode *inode)
        preempt_enable();
        return i_size;
 #else
-       return inode->i_size;
+       /* Pairs with smp_store_release() in i_size_write() */
+       return smp_load_acquire(&inode->i_size);
 #endif
 }
 
@@ -931,7 +933,12 @@ static inline void i_size_write(struct inode *inode, loff_t i_size)
        inode->i_size = i_size;
        preempt_enable();
 #else
-       inode->i_size = i_size;
+       /*
+        * Pairs with smp_load_acquire() in i_size_read() to ensure
+        * changes related to inode size (such as page contents) are
+        * visible before we see the changed inode size.
+        */
+       smp_store_release(&inode->i_size, i_size);
 #endif
 }
 
@@ -1080,9 +1087,20 @@ static inline struct inode *file_inode(const struct file *f)
        return f->f_inode;
 }
 
+/*
+ * file_dentry() is a relic from the days that overlayfs was using files with a
+ * "fake" path, meaning, f_path on overlayfs and f_inode on underlying fs.
+ * In those days, file_dentry() was needed to get the underlying fs dentry that
+ * matches f_inode.
+ * Files with "fake" path should not exist nowadays, so use an assertion to make
+ * sure that file_dentry() was not papering over filesystem bugs.
+ */
 static inline struct dentry *file_dentry(const struct file *file)
 {
-       return d_real(file->f_path.dentry, file_inode(file));
+       struct dentry *dentry = file->f_path.dentry;
+
+       WARN_ON_ONCE(d_inode(dentry) != file_inode(file));
+       return dentry;
 }
 
 struct fasync_struct {
@@ -2927,6 +2945,17 @@ extern bool path_is_under(const struct path *, const struct path *);
 
 extern char *file_path(struct file *, char *, int);
 
+/**
+ * is_dot_dotdot - returns true only if @name is "." or ".."
+ * @name: file name to check
+ * @len: length of file name, in bytes
+ */
+static inline bool is_dot_dotdot(const char *name, size_t len)
+{
+       return len && unlikely(name[0] == '.') &&
+               (len == 1 || (len == 2 && name[1] == '.'));
+}
+
 #include <linux/err.h>
 
 /* needed for stackable file system support */
@@ -3259,13 +3288,14 @@ extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
                const void __user *from, size_t count);
 
 struct offset_ctx {
-       struct xarray           xa;
-       u32                     next_offset;
+       struct maple_tree       mt;
+       unsigned long           next_offset;
 };
 
 void simple_offset_init(struct offset_ctx *octx);
 int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry);
 void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry);
+int simple_offset_empty(struct dentry *dentry);
 int simple_offset_rename_exchange(struct inode *old_dir,
                                  struct dentry *old_dentry,
                                  struct inode *new_dir,
@@ -3279,7 +3309,16 @@ extern int generic_file_fsync(struct file *, loff_t, loff_t, int);
 
 extern int generic_check_addressable(unsigned, u64);
 
-extern void generic_set_encrypted_ci_d_ops(struct dentry *dentry);
+extern void generic_set_sb_d_ops(struct super_block *sb);
+
+static inline bool sb_has_encoding(const struct super_block *sb)
+{
+#if IS_ENABLED(CONFIG_UNICODE)
+       return !!sb->s_encoding;
+#else
+       return false;
+#endif
+}
 
 int may_setattr(struct mnt_idmap *idmap, struct inode *inode,
                unsigned int ia_valid);
@@ -3334,6 +3373,8 @@ static inline int kiocb_set_rw_flags(struct kiocb *ki, rwf_t flags)
                return 0;
        if (unlikely(flags & ~RWF_SUPPORTED))
                return -EOPNOTSUPP;
+       if (unlikely((flags & RWF_APPEND) && (flags & RWF_NOAPPEND)))
+               return -EINVAL;
 
        if (flags & RWF_NOWAIT) {
                if (!(ki->ki_filp->f_mode & FMODE_NOWAIT))
@@ -3344,6 +3385,12 @@ static inline int kiocb_set_rw_flags(struct kiocb *ki, rwf_t flags)
        if (flags & RWF_SYNC)
                kiocb_flags |= IOCB_DSYNC;
 
+       if ((flags & RWF_NOAPPEND) && (ki->ki_flags & IOCB_APPEND)) {
+               if (IS_APPEND(file_inode(ki->ki_filp)))
+                       return -EPERM;
+               ki->ki_flags &= ~IOCB_APPEND;
+       }
+
        ki->ki_flags |= kiocb_flags;
        return 0;
 }