fs: fork splice_file_range() from do_splice_direct()
[linux-2.6-block.git] / include / linux / fs.h
index 562f2623c9c9f4a440d81ed4a0dc1bbe269d06fb..04422a0eccddd59f962a30b947ded81f685baddf 100644 (file)
@@ -67,7 +67,7 @@ struct swap_info_struct;
 struct seq_file;
 struct workqueue_struct;
 struct iov_iter;
-struct fscrypt_info;
+struct fscrypt_inode_info;
 struct fscrypt_operations;
 struct fsverity_info;
 struct fsverity_operations;
@@ -338,6 +338,20 @@ enum rw_hint {
 #define IOCB_NOIO              (1 << 20)
 /* can use bio alloc cache */
 #define IOCB_ALLOC_CACHE       (1 << 21)
+/*
+ * IOCB_DIO_CALLER_COMP can be set by the iocb owner, to indicate that the
+ * iocb completion can be passed back to the owner for execution from a safe
+ * context rather than needing to be punted through a workqueue. If this
+ * flag is set, the bio completion handling may set iocb->dio_complete to a
+ * handler function and iocb->private to context information for that handler.
+ * The issuer should call the handler with that context information from task
+ * context to complete the processing of the iocb. Note that while this
+ * provides a task context for the dio_complete() callback, it should only be
+ * used on the completion side for non-IO generating completions. It's fine to
+ * call blocking functions from this callback, but they should not wait for
+ * unrelated IO (like cache flushing, new IO generation, etc).
+ */
+#define IOCB_DIO_CALLER_COMP   (1 << 22)
 
 /* for use in trace events */
 #define TRACE_IOCB_STRINGS \
@@ -351,7 +365,8 @@ enum rw_hint {
        { IOCB_WRITE,           "WRITE" }, \
        { IOCB_WAITQ,           "WAITQ" }, \
        { IOCB_NOIO,            "NOIO" }, \
-       { IOCB_ALLOC_CACHE,     "ALLOC_CACHE" }
+       { IOCB_ALLOC_CACHE,     "ALLOC_CACHE" }, \
+       { IOCB_DIO_CALLER_COMP, "CALLER_COMP" }
 
 struct kiocb {
        struct file             *ki_filp;
@@ -360,7 +375,23 @@ struct kiocb {
        void                    *private;
        int                     ki_flags;
        u16                     ki_ioprio; /* See linux/ioprio.h */
-       struct wait_page_queue  *ki_waitq; /* for async buffered IO */
+       union {
+               /*
+                * Only used for async buffered reads, where it denotes the
+                * page waitqueue associated with completing the read. Valid
+                * IFF IOCB_WAITQ is set.
+                */
+               struct wait_page_queue  *ki_waitq;
+               /*
+                * Can be used for O_DIRECT IO, where the completion handling
+                * is punted back to the issuer of the IO. May only be set
+                * if IOCB_DIO_CALLER_COMP is set by the issuer, and the issuer
+                * must then check for presence of this handler when ki_complete
+                * is invoked. The data passed in to this handler must be
+                * assigned to ->private when dio_complete is assigned.
+                */
+               ssize_t (*dio_complete)(void *data);
+       };
 };
 
 static inline bool is_sync_kiocb(struct kiocb *kiocb)
@@ -423,7 +454,7 @@ extern const struct address_space_operations empty_aops;
  *   It is also used to block modification of page cache contents through
  *   memory mappings.
  * @gfp_mask: Memory allocation flags to use for allocating pages.
- * @i_mmap_writable: Number of VM_SHARED mappings.
+ * @i_mmap_writable: Number of VM_SHARED, VM_MAYWRITE mappings.
  * @nr_thps: Number of THPs in the pagecache (non-shmem only).
  * @i_mmap: Tree of private and shared mappings.
  * @i_mmap_rwsem: Protects @i_mmap and @i_mmap_writable.
@@ -447,11 +478,11 @@ struct address_space {
        atomic_t                nr_thps;
 #endif
        struct rb_root_cached   i_mmap;
-       struct rw_semaphore     i_mmap_rwsem;
        unsigned long           nrpages;
        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              private_lock;
        struct list_head        private_list;
@@ -526,7 +557,7 @@ static inline int mapping_mapped(struct address_space *mapping)
 
 /*
  * Might pages of this file have been modified in userspace?
- * Note that i_mmap_writable counts all VM_SHARED vmas: do_mmap
+ * Note that i_mmap_writable counts all VM_SHARED, VM_MAYWRITE vmas: do_mmap
  * marks vma as VM_SHARED if it is shared, and the file was opened for
  * writing i.e. vma may be mprotected writable even if now readonly.
  *
@@ -640,9 +671,9 @@ struct inode {
        };
        dev_t                   i_rdev;
        loff_t                  i_size;
-       struct timespec64       i_atime;
-       struct timespec64       i_mtime;
-       struct timespec64       i_ctime;
+       struct timespec64       __i_atime;
+       struct timespec64       __i_mtime;
+       struct timespec64       __i_ctime; /* use inode_*_ctime accessors! */
        spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
        unsigned short          i_bytes;
        u8                      i_blkbits;
@@ -707,7 +738,7 @@ struct inode {
 #endif
 
 #ifdef CONFIG_FS_ENCRYPTION
-       struct fscrypt_info     *i_crypt_info;
+       struct fscrypt_inode_info       *i_crypt_info;
 #endif
 
 #ifdef CONFIG_FS_VERITY
@@ -1011,7 +1042,10 @@ static inline struct file *get_file(struct file *f)
        atomic_long_inc(&f->f_count);
        return f;
 }
-#define get_file_rcu(x) atomic_long_inc_not_zero(&(x)->f_count)
+
+struct file *get_file_rcu(struct file __rcu **f);
+struct file *get_file_active(struct file **f);
+
 #define file_count(x)  atomic_long_read(&(x)->f_count)
 
 #define        MAX_NON_LFS     ((1UL<<31) - 1)
@@ -1069,7 +1103,7 @@ extern void fasync_free(struct fasync_struct *);
 extern void kill_fasync(struct fasync_struct **, int, int);
 
 extern void __f_setown(struct file *filp, struct pid *, enum pid_type, int force);
-extern int f_setown(struct file *filp, unsigned long arg, int force);
+extern int f_setown(struct file *filp, int who, int force);
 extern void f_delown(struct file *filp);
 extern pid_t f_getown(struct file *filp);
 extern int send_sigurg(struct fown_struct *fown);
@@ -1088,13 +1122,15 @@ extern int send_sigurg(struct fown_struct *fown);
 #define SB_NOATIME      BIT(10)        /* Do not update access times. */
 #define SB_NODIRATIME   BIT(11)        /* Do not update directory access times */
 #define SB_SILENT       BIT(15)
-#define SB_POSIXACL     BIT(16)        /* VFS does not apply the umask */
+#define SB_POSIXACL     BIT(16)        /* Supports POSIX ACLs */
 #define SB_INLINECRYPT  BIT(17)        /* Use blk-crypto for encrypted files */
 #define SB_KERNMOUNT    BIT(22)        /* this is a kern_mount call */
 #define SB_I_VERSION    BIT(23)        /* Update inode I_version field */
 #define SB_LAZYTIME     BIT(25)        /* Update the on-disk [acm]times lazily */
 
 /* These sb flags are internal to the kernel */
+#define SB_DEAD         BIT(21)
+#define SB_DYING        BIT(24)
 #define SB_SUBMOUNT     BIT(26)
 #define SB_FORCE        BIT(27)
 #define SB_NOSEC        BIT(28)
@@ -1133,6 +1169,7 @@ extern int send_sigurg(struct fown_struct *fown);
 #define SB_I_PERSB_BDI 0x00000200      /* has a per-sb bdi */
 #define SB_I_TS_EXPIRY_WARNED 0x00000400 /* warned about timestamp range expiry */
 #define SB_I_RETIRED   0x00000800      /* superblock shouldn't be reused */
+#define SB_I_NOUMASK   0x00001000      /* VFS does not apply umask */
 
 /* Possible states of 'frozen' field */
 enum {
@@ -1147,7 +1184,8 @@ enum {
 #define SB_FREEZE_LEVELS (SB_FREEZE_COMPLETE - 1)
 
 struct sb_writers {
-       int                             frozen;         /* Is sb frozen? */
+       unsigned short                  frozen;         /* Is sb frozen? */
+       unsigned short                  freeze_holders; /* Who froze fs? */
        struct percpu_rw_semaphore      rw_sem[SB_FREEZE_LEVELS];
 };
 
@@ -1172,7 +1210,7 @@ struct super_block {
 #ifdef CONFIG_SECURITY
        void                    *s_security;
 #endif
-       const struct xattr_handler **s_xattr;
+       const struct xattr_handler * const *s_xattr;
 #ifdef CONFIG_FS_ENCRYPTION
        const struct fscrypt_operations *s_cop;
        struct fscrypt_keyring  *s_master_keys; /* master crypto keys in use */
@@ -1187,6 +1225,7 @@ struct super_block {
        struct hlist_bl_head    s_roots;        /* alternate root dentries for NFS */
        struct list_head        s_mounts;       /* list of mounts; _not_ for fs use */
        struct block_device     *s_bdev;
+       struct bdev_handle      *s_bdev_handle;
        struct backing_dev_info *s_bdi;
        struct mtd_info         *s_mtd;
        struct hlist_node       s_instances;
@@ -1231,7 +1270,7 @@ struct super_block {
 
        const struct dentry_operations *s_d_op; /* default d_op for dentries */
 
-       struct shrinker s_shrink;       /* per-sb shrinker handle */
+       struct shrinker *s_shrink;      /* per-sb shrinker handle */
 
        /* Number of inodes with nlink == 0 but still referenced */
        atomic_long_t s_remove_count;
@@ -1474,7 +1513,109 @@ static inline bool fsuidgid_has_mapping(struct super_block *sb,
               kgid_has_mapping(fs_userns, kgid);
 }
 
-extern struct timespec64 current_time(struct inode *inode);
+struct timespec64 current_time(struct inode *inode);
+struct timespec64 inode_set_ctime_current(struct inode *inode);
+
+static inline time64_t inode_get_atime_sec(const struct inode *inode)
+{
+       return inode->__i_atime.tv_sec;
+}
+
+static inline long inode_get_atime_nsec(const struct inode *inode)
+{
+       return inode->__i_atime.tv_nsec;
+}
+
+static inline struct timespec64 inode_get_atime(const struct inode *inode)
+{
+       return inode->__i_atime;
+}
+
+static inline struct timespec64 inode_set_atime_to_ts(struct inode *inode,
+                                                     struct timespec64 ts)
+{
+       inode->__i_atime = ts;
+       return ts;
+}
+
+static inline struct timespec64 inode_set_atime(struct inode *inode,
+                                               time64_t sec, long nsec)
+{
+       struct timespec64 ts = { .tv_sec  = sec,
+                                .tv_nsec = nsec };
+       return inode_set_atime_to_ts(inode, ts);
+}
+
+static inline time64_t inode_get_mtime_sec(const struct inode *inode)
+{
+       return inode->__i_mtime.tv_sec;
+}
+
+static inline long inode_get_mtime_nsec(const struct inode *inode)
+{
+       return inode->__i_mtime.tv_nsec;
+}
+
+static inline struct timespec64 inode_get_mtime(const struct inode *inode)
+{
+       return inode->__i_mtime;
+}
+
+static inline struct timespec64 inode_set_mtime_to_ts(struct inode *inode,
+                                                     struct timespec64 ts)
+{
+       inode->__i_mtime = ts;
+       return ts;
+}
+
+static inline struct timespec64 inode_set_mtime(struct inode *inode,
+                                               time64_t sec, long nsec)
+{
+       struct timespec64 ts = { .tv_sec  = sec,
+                                .tv_nsec = nsec };
+       return inode_set_mtime_to_ts(inode, ts);
+}
+
+static inline time64_t inode_get_ctime_sec(const struct inode *inode)
+{
+       return inode->__i_ctime.tv_sec;
+}
+
+static inline long inode_get_ctime_nsec(const struct inode *inode)
+{
+       return inode->__i_ctime.tv_nsec;
+}
+
+static inline struct timespec64 inode_get_ctime(const struct inode *inode)
+{
+       return inode->__i_ctime;
+}
+
+static inline struct timespec64 inode_set_ctime_to_ts(struct inode *inode,
+                                                     struct timespec64 ts)
+{
+       inode->__i_ctime = ts;
+       return ts;
+}
+
+/**
+ * inode_set_ctime - set the ctime in the inode
+ * @inode: inode in which to set the ctime
+ * @sec: tv_sec value to set
+ * @nsec: tv_nsec value to set
+ *
+ * Set the ctime in @inode to { @sec, @nsec }
+ */
+static inline struct timespec64 inode_set_ctime(struct inode *inode,
+                                               time64_t sec, long nsec)
+{
+       struct timespec64 ts = { .tv_sec  = sec,
+                                .tv_nsec = nsec };
+
+       return inode_set_ctime_to_ts(inode, ts);
+}
+
+struct timespec64 simple_inode_init_ts(struct inode *inode);
 
 /*
  * Snapshotting support.
@@ -1504,9 +1645,70 @@ static inline bool __sb_start_write_trylock(struct super_block *sb, int level)
 #define __sb_writers_release(sb, lev)  \
        percpu_rwsem_release(&(sb)->s_writers.rw_sem[(lev)-1], 1, _THIS_IP_)
 
+/**
+ * __sb_write_started - check if sb freeze level is held
+ * @sb: the super we write to
+ * @level: the freeze level
+ *
+ * > 0 sb freeze level is held
+ *   0 sb freeze level is not held
+ * < 0 !CONFIG_LOCKDEP/LOCK_STATE_UNKNOWN
+ */
+static inline int __sb_write_started(const struct super_block *sb, int level)
+{
+       return lockdep_is_held_type(sb->s_writers.rw_sem + level - 1, 1);
+}
+
+/**
+ * sb_write_started - check if SB_FREEZE_WRITE is held
+ * @sb: the super we write to
+ *
+ * May be false positive with !CONFIG_LOCKDEP/LOCK_STATE_UNKNOWN.
+ */
 static inline bool sb_write_started(const struct super_block *sb)
 {
-       return lockdep_is_held_type(sb->s_writers.rw_sem + SB_FREEZE_WRITE - 1, 1);
+       return __sb_write_started(sb, SB_FREEZE_WRITE);
+}
+
+/**
+ * sb_write_not_started - check if SB_FREEZE_WRITE is not held
+ * @sb: the super we write to
+ *
+ * May be false positive with !CONFIG_LOCKDEP/LOCK_STATE_UNKNOWN.
+ */
+static inline bool sb_write_not_started(const struct super_block *sb)
+{
+       return __sb_write_started(sb, SB_FREEZE_WRITE) <= 0;
+}
+
+/**
+ * file_write_started - check if SB_FREEZE_WRITE is held
+ * @file: the file we write to
+ *
+ * May be false positive with !CONFIG_LOCKDEP/LOCK_STATE_UNKNOWN.
+ * May be false positive with !S_ISREG, because file_start_write() has
+ * no effect on !S_ISREG.
+ */
+static inline bool file_write_started(const struct file *file)
+{
+       if (!S_ISREG(file_inode(file)->i_mode))
+               return true;
+       return sb_write_started(file_inode(file)->i_sb);
+}
+
+/**
+ * file_write_not_started - check if SB_FREEZE_WRITE is not held
+ * @file: the file we write to
+ *
+ * May be false positive with !CONFIG_LOCKDEP/LOCK_STATE_UNKNOWN.
+ * May be false positive with !S_ISREG, because file_start_write() has
+ * no effect on !S_ISREG.
+ */
+static inline bool file_write_not_started(const struct file *file)
+{
+       if (!S_ISREG(file_inode(file)->i_mode))
+               return true;
+       return sb_write_not_started(file_inode(file)->i_sb);
 }
 
 /**
@@ -1770,6 +1972,7 @@ struct dir_context {
 
 struct iov_iter;
 struct io_uring_cmd;
+struct offset_ctx;
 
 struct file_operations {
        struct module *owner;
@@ -1798,7 +2001,7 @@ struct file_operations {
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
        ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
        void (*splice_eof)(struct file *file);
-       int (*setlease)(struct file *, long, struct file_lock **, void **);
+       int (*setlease)(struct file *, int, struct file_lock **, void **);
        long (*fallocate)(struct file *file, int mode, loff_t offset,
                          loff_t len);
        void (*show_fdinfo)(struct seq_file *m, struct file *f);
@@ -1850,7 +2053,7 @@ struct inode_operations {
        ssize_t (*listxattr) (struct dentry *, char *, size_t);
        int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
                      u64 len);
-       int (*update_time)(struct inode *, struct timespec64 *, int);
+       int (*update_time)(struct inode *, int);
        int (*atomic_open)(struct inode *, struct dentry *,
                           struct file *, unsigned open_flag,
                           umode_t create_mode);
@@ -1863,6 +2066,7 @@ struct inode_operations {
        int (*fileattr_set)(struct mnt_idmap *idmap,
                            struct dentry *dentry, struct fileattr *fa);
        int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa);
+       struct offset_ctx *(*get_offset_ctx)(struct inode *inode);
 } ____cacheline_aligned;
 
 static inline ssize_t call_read_iter(struct file *file, struct kiocb *kio,
@@ -1908,6 +2112,10 @@ extern loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
                                        struct file *dst_file, loff_t dst_pos,
                                        loff_t len, unsigned int remap_flags);
 
+enum freeze_holder {
+       FREEZE_HOLDER_KERNEL    = (1U << 0),
+       FREEZE_HOLDER_USERSPACE = (1U << 1),
+};
 
 struct super_operations {
        struct inode *(*alloc_inode)(struct super_block *sb);
@@ -1920,9 +2128,9 @@ struct super_operations {
        void (*evict_inode) (struct inode *);
        void (*put_super) (struct super_block *);
        int (*sync_fs)(struct super_block *sb, int wait);
-       int (*freeze_super) (struct super_block *);
+       int (*freeze_super) (struct super_block *, enum freeze_holder who);
        int (*freeze_fs) (struct super_block *);
-       int (*thaw_super) (struct super_block *);
+       int (*thaw_super) (struct super_block *, enum freeze_holder who);
        int (*unfreeze_fs) (struct super_block *);
        int (*statfs) (struct dentry *, struct kstatfs *);
        int (*remount_fs) (struct super_block *, int *, char *);
@@ -1998,7 +2206,12 @@ static inline bool sb_rdonly(const struct super_block *sb) { return sb->s_flags
 #define IS_NOQUOTA(inode)      ((inode)->i_flags & S_NOQUOTA)
 #define IS_APPEND(inode)       ((inode)->i_flags & S_APPEND)
 #define IS_IMMUTABLE(inode)    ((inode)->i_flags & S_IMMUTABLE)
+
+#ifdef CONFIG_FS_POSIX_ACL
 #define IS_POSIXACL(inode)     __IS_FLG(inode, SB_POSIXACL)
+#else
+#define IS_POSIXACL(inode)     0
+#endif
 
 #define IS_DEADDIR(inode)      ((inode)->i_flags & S_DEAD)
 #define IS_NOCMTIME(inode)     ((inode)->i_flags & S_NOCMTIME)
@@ -2200,7 +2413,7 @@ enum file_time_flags {
 
 extern bool atime_needs_update(const struct path *, struct inode *);
 extern void touch_atime(const struct path *);
-int inode_update_time(struct inode *inode, struct timespec64 *time, int flags);
+int inode_update_time(struct inode *inode, int flags);
 
 static inline void file_accessed(struct file *file)
 {
@@ -2273,6 +2486,7 @@ struct super_block *sget(struct file_system_type *type,
                        int (*test)(struct super_block *,void *),
                        int (*set)(struct super_block *,void *),
                        int flags, void *data);
+struct super_block *sget_dev(struct fs_context *fc, dev_t dev);
 
 /* Alas, no aliases. Too much hassle with bringing module.h everywhere */
 #define fops_get(fops) \
@@ -2296,8 +2510,8 @@ extern int unregister_filesystem(struct file_system_type *);
 extern int vfs_statfs(const struct path *, struct kstatfs *);
 extern int user_statfs(const char __user *, struct kstatfs *);
 extern int fd_statfs(int, struct kstatfs *);
-extern int freeze_super(struct super_block *super);
-extern int thaw_super(struct super_block *super);
+int freeze_super(struct super_block *super, enum freeze_holder who);
+int thaw_super(struct super_block *super, enum freeze_holder who);
 extern __printf(2, 3)
 int super_setup_bdi_name(struct super_block *sb, char *fmt, ...);
 extern int super_setup_bdi(struct super_block *sb);
@@ -2306,7 +2520,8 @@ extern int current_umask(void);
 
 extern void ihold(struct inode * inode);
 extern void iput(struct inode *);
-extern int generic_update_time(struct inode *, struct timespec64 *, int);
+int inode_update_timestamps(struct inode *inode, int flags);
+int generic_update_time(struct inode *, int);
 
 /* /sys/fs */
 extern struct kobject *fs_kobj;
@@ -2318,13 +2533,13 @@ struct audit_names;
 struct filename {
        const char              *name;  /* pointer to actual string */
        const __user char       *uptr;  /* original userland pointer */
-       int                     refcnt;
+       atomic_t                refcnt;
        struct audit_names      *aname;
        const char              iname[];
 };
 static_assert(offsetof(struct filename, iname) % sizeof(long) == 0);
 
-static inline struct mnt_idmap *file_mnt_idmap(struct file *file)
+static inline struct mnt_idmap *file_mnt_idmap(const struct file *file)
 {
        return mnt_idmap(file->f_path.mnt);
 }
@@ -2363,24 +2578,24 @@ struct file *dentry_open(const struct path *path, int flags,
                         const struct cred *creds);
 struct file *dentry_create(const struct path *path, int flags, umode_t mode,
                           const struct cred *cred);
-struct file *backing_file_open(const struct path *path, int flags,
+struct file *backing_file_open(const struct path *user_path, int flags,
                               const struct path *real_path,
                               const struct cred *cred);
-struct path *backing_file_real_path(struct file *f);
+struct path *backing_file_user_path(struct file *f);
 
 /*
- * file_real_path - get the path corresponding to f_inode
+ * file_user_path - get the path to display for memory mapped file
  *
- * When opening a backing file for a stackable filesystem (e.g.,
- * overlayfs) f_path may be on the stackable filesystem and f_inode on
- * the underlying filesystem.  When the path associated with f_inode is
- * needed, this helper should be used instead of accessing f_path
- * directly.
-*/
-static inline const struct path *file_real_path(struct file *f)
+ * When mmapping a file on a stackable filesystem (e.g., overlayfs), the file
+ * stored in ->vm_file is a backing file whose f_inode is on the underlying
+ * filesystem.  When the mapped file path is displayed to user (e.g. via
+ * /proc/<pid>/maps), this helper should be used to get the path to display
+ * to the user, which is the path of the fd that user has requested to map.
+ */
+static inline const struct path *file_user_path(struct file *f)
 {
        if (unlikely(f->f_mode & FMODE_BACKING))
-               return backing_file_real_path(f);
+               return backing_file_user_path(f);
        return &f->f_path;
 }
 
@@ -2545,6 +2760,13 @@ static inline bool inode_wrong_type(const struct inode *inode, umode_t mode)
        return (inode->i_mode ^ mode) & S_IFMT;
 }
 
+/**
+ * file_start_write - get write access to a superblock for regular file io
+ * @file: the file we want to write to
+ *
+ * This is a variant of sb_start_write() which is a noop on non-regualr file.
+ * Should be matched with a call to file_end_write().
+ */
 static inline void file_start_write(struct file *file)
 {
        if (!S_ISREG(file_inode(file)->i_mode))
@@ -2559,11 +2781,53 @@ static inline bool file_start_write_trylock(struct file *file)
        return sb_start_write_trylock(file_inode(file)->i_sb);
 }
 
+/**
+ * file_end_write - drop write access to a superblock of a regular file
+ * @file: the file we wrote to
+ *
+ * Should be matched with a call to file_start_write().
+ */
 static inline void file_end_write(struct file *file)
 {
        if (!S_ISREG(file_inode(file)->i_mode))
                return;
-       __sb_end_write(file_inode(file)->i_sb, SB_FREEZE_WRITE);
+       sb_end_write(file_inode(file)->i_sb);
+}
+
+/**
+ * kiocb_start_write - get write access to a superblock for async file io
+ * @iocb: the io context we want to submit the write with
+ *
+ * This is a variant of sb_start_write() for async io submission.
+ * Should be matched with a call to kiocb_end_write().
+ */
+static inline void kiocb_start_write(struct kiocb *iocb)
+{
+       struct inode *inode = file_inode(iocb->ki_filp);
+
+       sb_start_write(inode->i_sb);
+       /*
+        * Fool lockdep by telling it the lock got released so that it
+        * doesn't complain about the held lock when we return to userspace.
+        */
+       __sb_writers_release(inode->i_sb, SB_FREEZE_WRITE);
+}
+
+/**
+ * kiocb_end_write - drop write access to a superblock after async file io
+ * @iocb: the io context we sumbitted the write with
+ *
+ * Should be matched with a call to kiocb_start_write().
+ */
+static inline void kiocb_end_write(struct kiocb *iocb)
+{
+       struct inode *inode = file_inode(iocb->ki_filp);
+
+       /*
+        * Tell lockdep we inherited freeze protection from submission thread.
+        */
+       __sb_writers_acquired(inode->i_sb, SB_FREEZE_WRITE);
+       sb_end_write(inode->i_sb);
 }
 
 /*
@@ -2613,8 +2877,7 @@ static inline bool inode_is_open_for_write(const struct inode *inode)
 #if defined(CONFIG_IMA) || defined(CONFIG_FILE_LOCKING)
 static inline void i_readcount_dec(struct inode *inode)
 {
-       BUG_ON(!atomic_read(&inode->i_readcount));
-       atomic_dec(&inode->i_readcount);
+       BUG_ON(atomic_dec_return(&inode->i_readcount) < 0);
 }
 static inline void i_readcount_inc(struct inode *inode)
 {
@@ -2789,8 +3052,6 @@ ssize_t copy_splice_read(struct file *in, loff_t *ppos,
                         size_t len, unsigned int flags);
 extern ssize_t iter_file_splice_write(struct pipe_inode_info *,
                struct file *, loff_t *, size_t, unsigned int);
-extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
-               loff_t *opos, size_t len, unsigned int flags);
 
 
 extern void
@@ -2880,7 +3141,7 @@ extern void page_put_link(void *);
 extern int page_symlink(struct inode *inode, const char *symname, int len);
 extern const struct inode_operations page_symlink_inode_operations;
 extern void kfree_link(void *);
-void generic_fillattr(struct mnt_idmap *, struct inode *, struct kstat *);
+void generic_fillattr(struct mnt_idmap *, u32, struct inode *, struct kstat *);
 void generic_fill_statx_attr(struct inode *inode, struct kstat *stat);
 extern int vfs_getattr_nosec(const struct path *, struct kstat *, u32, unsigned int);
 extern int vfs_getattr(const struct path *, struct kstat *, u32, unsigned int);
@@ -2919,7 +3180,6 @@ extern int vfs_readlink(struct dentry *, char __user *, int);
 extern struct file_system_type *get_filesystem(struct file_system_type *fs);
 extern void put_filesystem(struct file_system_type *fs);
 extern struct file_system_type *get_fs_type(const char *name);
-extern struct super_block *get_super(struct block_device *);
 extern struct super_block *get_active_super(struct block_device *bdev);
 extern void drop_super(struct super_block *sb);
 extern void drop_super_exclusive(struct super_block *sb);
@@ -2940,6 +3200,8 @@ extern int simple_open(struct inode *inode, struct file *file);
 extern int simple_link(struct dentry *, struct inode *, struct dentry *);
 extern int simple_unlink(struct inode *, struct dentry *);
 extern int simple_rmdir(struct inode *, struct dentry *);
+void simple_rename_timestamp(struct inode *old_dir, struct dentry *old_dentry,
+                            struct inode *new_dir, struct dentry *new_dentry);
 extern int simple_rename_exchange(struct inode *old_dir, struct dentry *old_dentry,
                                  struct inode *new_dir, struct dentry *new_dentry);
 extern int simple_rename(struct mnt_idmap *, struct inode *,
@@ -2956,7 +3218,7 @@ extern int simple_write_begin(struct file *file, struct address_space *mapping,
 extern const struct address_space_operations ram_aops;
 extern int always_delete_dentry(const struct dentry *);
 extern struct inode *alloc_anon_inode(struct super_block *);
-extern int simple_nosetlease(struct file *, long, struct file_lock **, void **);
+extern int simple_nosetlease(struct file *, int, struct file_lock **, void **);
 extern const struct dentry_operations simple_dentry_operations;
 
 extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags);
@@ -2977,6 +3239,22 @@ extern ssize_t simple_read_from_buffer(void __user *to, size_t count,
 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;
+};
+
+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_rename_exchange(struct inode *old_dir,
+                                 struct dentry *old_dentry,
+                                 struct inode *new_dir,
+                                 struct dentry *new_dentry);
+void simple_offset_destroy(struct offset_ctx *octx);
+
+extern const struct file_operations simple_offset_dir_operations;
+
 extern int __generic_file_fsync(struct file *, loff_t, loff_t, int);
 extern int generic_file_fsync(struct file *, loff_t, loff_t, int);