Linux 6.9-rc1
[linux-2.6-microblaze.git] / fs / libfs.c
index 31b0ddf..3a6f2cb 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/mutex.h>
 #include <linux/namei.h>
 #include <linux/exportfs.h>
+#include <linux/iversion.h>
 #include <linux/writeback.h>
 #include <linux/buffer_head.h> /* sync_mapping_buffers */
 #include <linux/fs_context.h>
 #include <linux/fsnotify.h>
 #include <linux/unicode.h>
 #include <linux/fscrypt.h>
+#include <linux/pidfs.h>
 
 #include <linux/uaccess.h>
 
 #include "internal.h"
 
-int simple_getattr(struct user_namespace *mnt_userns, const struct path *path,
+int simple_getattr(struct mnt_idmap *idmap, const struct path *path,
                   struct kstat *stat, u32 request_mask,
                   unsigned int query_flags)
 {
        struct inode *inode = d_inode(path->dentry);
-       generic_fillattr(&init_user_ns, inode, stat);
+       generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
        stat->blocks = inode->i_mapping->nrpages << (PAGE_SHIFT - 9);
        return 0;
 }
@@ -40,6 +42,9 @@ EXPORT_SYMBOL(simple_getattr);
 
 int simple_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
+       u64 id = huge_encode_dev(dentry->d_sb->s_dev);
+
+       buf->f_fsid = u64_to_fsid(id);
        buf->f_type = dentry->d_sb->s_magic;
        buf->f_bsize = PAGE_SIZE;
        buf->f_namelen = NAME_MAX;
@@ -100,15 +105,16 @@ EXPORT_SYMBOL(dcache_dir_close);
  * If no such element exists, NULL is returned.
  */
 static struct dentry *scan_positives(struct dentry *cursor,
-                                       struct list_head *p,
+                                       struct hlist_node **p,
                                        loff_t count,
                                        struct dentry *last)
 {
        struct dentry *dentry = cursor->d_parent, *found = NULL;
 
        spin_lock(&dentry->d_lock);
-       while ((p = p->next) != &dentry->d_subdirs) {
-               struct dentry *d = list_entry(p, struct dentry, d_child);
+       while (*p) {
+               struct dentry *d = hlist_entry(*p, struct dentry, d_sib);
+               p = &d->d_sib.next;
                // we must at least skip cursors, to avoid livelocks
                if (d->d_flags & DCACHE_DENTRY_CURSOR)
                        continue;
@@ -122,8 +128,10 @@ static struct dentry *scan_positives(struct dentry *cursor,
                        count = 1;
                }
                if (need_resched()) {
-                       list_move(&cursor->d_child, p);
-                       p = &cursor->d_child;
+                       if (!hlist_unhashed(&cursor->d_sib))
+                               __hlist_del(&cursor->d_sib);
+                       hlist_add_behind(&cursor->d_sib, &d->d_sib);
+                       p = &cursor->d_sib.next;
                        spin_unlock(&dentry->d_lock);
                        cond_resched();
                        spin_lock(&dentry->d_lock);
@@ -155,13 +163,12 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)
                inode_lock_shared(dentry->d_inode);
 
                if (offset > 2)
-                       to = scan_positives(cursor, &dentry->d_subdirs,
+                       to = scan_positives(cursor, &dentry->d_children.first,
                                            offset - 2, NULL);
                spin_lock(&dentry->d_lock);
+               hlist_del_init(&cursor->d_sib);
                if (to)
-                       list_move(&cursor->d_child, &to->d_child);
-               else
-                       list_del_init(&cursor->d_child);
+                       hlist_add_behind(&cursor->d_sib, &to->d_sib);
                spin_unlock(&dentry->d_lock);
                dput(to);
 
@@ -173,12 +180,6 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)
 }
 EXPORT_SYMBOL(dcache_dir_lseek);
 
-/* Relationship between i_mode and the DT_xxx types */
-static inline unsigned char dt_type(struct inode *inode)
-{
-       return (inode->i_mode >> 12) & 15;
-}
-
 /*
  * Directory is locked and all positive dentries in it are safe, since
  * for ramfs-type trees they can't go away without unlink() or rmdir(),
@@ -189,32 +190,29 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
 {
        struct dentry *dentry = file->f_path.dentry;
        struct dentry *cursor = file->private_data;
-       struct list_head *anchor = &dentry->d_subdirs;
        struct dentry *next = NULL;
-       struct list_head *p;
+       struct hlist_node **p;
 
        if (!dir_emit_dots(file, ctx))
                return 0;
 
        if (ctx->pos == 2)
-               p = anchor;
-       else if (!list_empty(&cursor->d_child))
-               p = &cursor->d_child;
+               p = &dentry->d_children.first;
        else
-               return 0;
+               p = &cursor->d_sib.next;
 
        while ((next = scan_positives(cursor, p, 1, next)) != NULL) {
                if (!dir_emit(ctx, next->d_name.name, next->d_name.len,
-                             d_inode(next)->i_ino, dt_type(d_inode(next))))
+                             d_inode(next)->i_ino,
+                             fs_umode_to_dtype(d_inode(next)->i_mode)))
                        break;
                ctx->pos++;
-               p = &next->d_child;
+               p = &next->d_sib.next;
        }
        spin_lock(&dentry->d_lock);
+       hlist_del_init(&cursor->d_sib);
        if (next)
-               list_move_tail(&cursor->d_child, &next->d_child);
-       else
-               list_del_init(&cursor->d_child);
+               hlist_add_before(&cursor->d_sib, &next->d_sib);
        spin_unlock(&dentry->d_lock);
        dput(next);
 
@@ -243,14 +241,303 @@ const struct inode_operations simple_dir_inode_operations = {
 };
 EXPORT_SYMBOL(simple_dir_inode_operations);
 
+/* 0 is '.', 1 is '..', so always start with offset 2 or more */
+enum {
+       DIR_OFFSET_MIN  = 2,
+};
+
+static void offset_set(struct dentry *dentry, long offset)
+{
+       dentry->d_fsdata = (void *)offset;
+}
+
+static long dentry2offset(struct dentry *dentry)
+{
+       return (long)dentry->d_fsdata;
+}
+
+static struct lock_class_key simple_offset_lock_class;
+
+/**
+ * simple_offset_init - initialize an offset_ctx
+ * @octx: directory offset map to be initialized
+ *
+ */
+void simple_offset_init(struct offset_ctx *octx)
+{
+       mt_init_flags(&octx->mt, MT_FLAGS_ALLOC_RANGE);
+       lockdep_set_class(&octx->mt.ma_lock, &simple_offset_lock_class);
+       octx->next_offset = DIR_OFFSET_MIN;
+}
+
+/**
+ * simple_offset_add - Add an entry to a directory's offset map
+ * @octx: directory offset ctx to be updated
+ * @dentry: new dentry being added
+ *
+ * Returns zero on success. @octx and the dentry's offset are updated.
+ * Otherwise, a negative errno value is returned.
+ */
+int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry)
+{
+       unsigned long offset;
+       int ret;
+
+       if (dentry2offset(dentry) != 0)
+               return -EBUSY;
+
+       ret = mtree_alloc_cyclic(&octx->mt, &offset, dentry, DIR_OFFSET_MIN,
+                                LONG_MAX, &octx->next_offset, GFP_KERNEL);
+       if (ret < 0)
+               return ret;
+
+       offset_set(dentry, offset);
+       return 0;
+}
+
+/**
+ * simple_offset_remove - Remove an entry to a directory's offset map
+ * @octx: directory offset ctx to be updated
+ * @dentry: dentry being removed
+ *
+ */
+void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry)
+{
+       long offset;
+
+       offset = dentry2offset(dentry);
+       if (offset == 0)
+               return;
+
+       mtree_erase(&octx->mt, offset);
+       offset_set(dentry, 0);
+}
+
+/**
+ * simple_offset_empty - Check if a dentry can be unlinked
+ * @dentry: dentry to be tested
+ *
+ * Returns 0 if @dentry is a non-empty directory; otherwise returns 1.
+ */
+int simple_offset_empty(struct dentry *dentry)
+{
+       struct inode *inode = d_inode(dentry);
+       struct offset_ctx *octx;
+       struct dentry *child;
+       unsigned long index;
+       int ret = 1;
+
+       if (!inode || !S_ISDIR(inode->i_mode))
+               return ret;
+
+       index = DIR_OFFSET_MIN;
+       octx = inode->i_op->get_offset_ctx(inode);
+       mt_for_each(&octx->mt, child, index, LONG_MAX) {
+               spin_lock(&child->d_lock);
+               if (simple_positive(child)) {
+                       spin_unlock(&child->d_lock);
+                       ret = 0;
+                       break;
+               }
+               spin_unlock(&child->d_lock);
+       }
+
+       return ret;
+}
+
+/**
+ * simple_offset_rename_exchange - exchange rename with directory offsets
+ * @old_dir: parent of dentry being moved
+ * @old_dentry: dentry being moved
+ * @new_dir: destination parent
+ * @new_dentry: destination dentry
+ *
+ * Returns zero on success. Otherwise a negative errno is returned and the
+ * rename is rolled back.
+ */
+int simple_offset_rename_exchange(struct inode *old_dir,
+                                 struct dentry *old_dentry,
+                                 struct inode *new_dir,
+                                 struct dentry *new_dentry)
+{
+       struct offset_ctx *old_ctx = old_dir->i_op->get_offset_ctx(old_dir);
+       struct offset_ctx *new_ctx = new_dir->i_op->get_offset_ctx(new_dir);
+       long old_index = dentry2offset(old_dentry);
+       long new_index = dentry2offset(new_dentry);
+       int ret;
+
+       simple_offset_remove(old_ctx, old_dentry);
+       simple_offset_remove(new_ctx, new_dentry);
+
+       ret = simple_offset_add(new_ctx, old_dentry);
+       if (ret)
+               goto out_restore;
+
+       ret = simple_offset_add(old_ctx, new_dentry);
+       if (ret) {
+               simple_offset_remove(new_ctx, old_dentry);
+               goto out_restore;
+       }
+
+       ret = simple_rename_exchange(old_dir, old_dentry, new_dir, new_dentry);
+       if (ret) {
+               simple_offset_remove(new_ctx, old_dentry);
+               simple_offset_remove(old_ctx, new_dentry);
+               goto out_restore;
+       }
+       return 0;
+
+out_restore:
+       offset_set(old_dentry, old_index);
+       mtree_store(&old_ctx->mt, old_index, old_dentry, GFP_KERNEL);
+       offset_set(new_dentry, new_index);
+       mtree_store(&new_ctx->mt, new_index, new_dentry, GFP_KERNEL);
+       return ret;
+}
+
+/**
+ * simple_offset_destroy - Release offset map
+ * @octx: directory offset ctx that is about to be destroyed
+ *
+ * During fs teardown (eg. umount), a directory's offset map might still
+ * contain entries. xa_destroy() cleans out anything that remains.
+ */
+void simple_offset_destroy(struct offset_ctx *octx)
+{
+       mtree_destroy(&octx->mt);
+}
+
+/**
+ * offset_dir_llseek - Advance the read position of a directory descriptor
+ * @file: an open directory whose position is to be updated
+ * @offset: a byte offset
+ * @whence: enumerator describing the starting position for this update
+ *
+ * SEEK_END, SEEK_DATA, and SEEK_HOLE are not supported for directories.
+ *
+ * Returns the updated read position if successful; otherwise a
+ * negative errno is returned and the read position remains unchanged.
+ */
+static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence)
+{
+       switch (whence) {
+       case SEEK_CUR:
+               offset += file->f_pos;
+               fallthrough;
+       case SEEK_SET:
+               if (offset >= 0)
+                       break;
+               fallthrough;
+       default:
+               return -EINVAL;
+       }
+
+       /* In this case, ->private_data is protected by f_pos_lock */
+       file->private_data = NULL;
+       return vfs_setpos(file, offset, LONG_MAX);
+}
+
+static struct dentry *offset_find_next(struct offset_ctx *octx, loff_t offset)
+{
+       MA_STATE(mas, &octx->mt, offset, offset);
+       struct dentry *child, *found = NULL;
+
+       rcu_read_lock();
+       child = mas_find(&mas, LONG_MAX);
+       if (!child)
+               goto out;
+       spin_lock(&child->d_lock);
+       if (simple_positive(child))
+               found = dget_dlock(child);
+       spin_unlock(&child->d_lock);
+out:
+       rcu_read_unlock();
+       return found;
+}
+
+static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry)
+{
+       struct inode *inode = d_inode(dentry);
+       long offset = dentry2offset(dentry);
+
+       return ctx->actor(ctx, dentry->d_name.name, dentry->d_name.len, offset,
+                         inode->i_ino, fs_umode_to_dtype(inode->i_mode));
+}
+
+static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
+{
+       struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode);
+       struct dentry *dentry;
+
+       while (true) {
+               dentry = offset_find_next(octx, ctx->pos);
+               if (!dentry)
+                       return ERR_PTR(-ENOENT);
+
+               if (!offset_dir_emit(ctx, dentry)) {
+                       dput(dentry);
+                       break;
+               }
+
+               ctx->pos = dentry2offset(dentry) + 1;
+               dput(dentry);
+       }
+       return NULL;
+}
+
+/**
+ * offset_readdir - Emit entries starting at offset @ctx->pos
+ * @file: an open directory to iterate over
+ * @ctx: directory iteration context
+ *
+ * Caller must hold @file's i_rwsem to prevent insertion or removal of
+ * entries during this call.
+ *
+ * On entry, @ctx->pos contains an offset that represents the first entry
+ * to be read from the directory.
+ *
+ * The operation continues until there are no more entries to read, or
+ * until the ctx->actor indicates there is no more space in the caller's
+ * output buffer.
+ *
+ * On return, @ctx->pos contains an offset that will read the next entry
+ * in this directory when offset_readdir() is called again with @ctx.
+ *
+ * Return values:
+ *   %0 - Complete
+ */
+static int offset_readdir(struct file *file, struct dir_context *ctx)
+{
+       struct dentry *dir = file->f_path.dentry;
+
+       lockdep_assert_held(&d_inode(dir)->i_rwsem);
+
+       if (!dir_emit_dots(file, ctx))
+               return 0;
+
+       /* In this case, ->private_data is protected by f_pos_lock */
+       if (ctx->pos == DIR_OFFSET_MIN)
+               file->private_data = NULL;
+       else if (file->private_data == ERR_PTR(-ENOENT))
+               return 0;
+       file->private_data = offset_iterate_dir(d_inode(dir), ctx);
+       return 0;
+}
+
+const struct file_operations simple_offset_dir_operations = {
+       .llseek         = offset_dir_llseek,
+       .iterate_shared = offset_readdir,
+       .read           = generic_read_dir,
+       .fsync          = noop_fsync,
+};
+
 static struct dentry *find_next_child(struct dentry *parent, struct dentry *prev)
 {
-       struct dentry *child = NULL;
-       struct list_head *p = prev ? &prev->d_child : &parent->d_subdirs;
+       struct dentry *child = NULL, *d;
 
        spin_lock(&parent->d_lock);
-       while ((p = p->next) != &parent->d_subdirs) {
-               struct dentry *d = container_of(p, struct dentry, d_child);
+       d = prev ? d_next_sibling(prev) : d_first_child(parent);
+       hlist_for_each_entry_from(d, d_sib) {
                if (simple_positive(d)) {
                        spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
                        if (simple_positive(d))
@@ -279,7 +566,7 @@ void simple_recursive_removal(struct dentry *dentry,
                while ((child = find_next_child(this, victim)) == NULL) {
                        // kill and ascend
                        // update metadata while it's still locked
-                       inode->i_ctime = current_time(inode);
+                       inode_set_ctime_current(inode);
                        clear_nlink(inode);
                        inode_unlock(inode);
                        victim = this;
@@ -297,8 +584,8 @@ void simple_recursive_removal(struct dentry *dentry,
                                dput(victim);           // unpin it
                        }
                        if (victim == dentry) {
-                               inode->i_ctime = inode->i_mtime =
-                                       current_time(inode);
+                               inode_set_mtime_to_ts(inode,
+                                                     inode_set_ctime_current(inode));
                                if (d_is_dir(dentry))
                                        drop_nlink(inode);
                                inode_unlock(inode);
@@ -339,7 +626,7 @@ static int pseudo_fs_fill_super(struct super_block *s, struct fs_context *fc)
         */
        root->i_ino = 1;
        root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
-       root->i_atime = root->i_mtime = root->i_ctime = current_time(root);
+       simple_inode_init_ts(root);
        s->s_root = d_make_root(root);
        if (!s->s_root)
                return -ENOMEM;
@@ -395,7 +682,8 @@ int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *den
 {
        struct inode *inode = d_inode(old_dentry);
 
-       inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode);
+       inode_set_mtime_to_ts(dir,
+                             inode_set_ctime_to_ts(dir, inode_set_ctime_current(inode)));
        inc_nlink(inode);
        ihold(inode);
        dget(dentry);
@@ -410,7 +698,7 @@ int simple_empty(struct dentry *dentry)
        int ret = 0;
 
        spin_lock(&dentry->d_lock);
-       list_for_each_entry(child, &dentry->d_subdirs, d_child) {
+       hlist_for_each_entry(child, &dentry->d_children, d_sib) {
                spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
                if (simple_positive(child)) {
                        spin_unlock(&child->d_lock);
@@ -429,7 +717,8 @@ int simple_unlink(struct inode *dir, struct dentry *dentry)
 {
        struct inode *inode = d_inode(dentry);
 
-       inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode);
+       inode_set_mtime_to_ts(dir,
+                             inode_set_ctime_to_ts(dir, inode_set_ctime_current(inode)));
        drop_nlink(inode);
        dput(dentry);
        return 0;
@@ -448,6 +737,32 @@ int simple_rmdir(struct inode *dir, struct dentry *dentry)
 }
 EXPORT_SYMBOL(simple_rmdir);
 
+/**
+ * simple_rename_timestamp - update the various inode timestamps for rename
+ * @old_dir: old parent directory
+ * @old_dentry: dentry that is being renamed
+ * @new_dir: new parent directory
+ * @new_dentry: target for rename
+ *
+ * POSIX mandates that the old and new parent directories have their ctime and
+ * mtime updated, and that inodes of @old_dentry and @new_dentry (if any), have
+ * their ctime updated.
+ */
+void simple_rename_timestamp(struct inode *old_dir, struct dentry *old_dentry,
+                            struct inode *new_dir, struct dentry *new_dentry)
+{
+       struct inode *newino = d_inode(new_dentry);
+
+       inode_set_mtime_to_ts(old_dir, inode_set_ctime_current(old_dir));
+       if (new_dir != old_dir)
+               inode_set_mtime_to_ts(new_dir,
+                                     inode_set_ctime_current(new_dir));
+       inode_set_ctime_current(d_inode(old_dentry));
+       if (newino)
+               inode_set_ctime_current(newino);
+}
+EXPORT_SYMBOL_GPL(simple_rename_timestamp);
+
 int simple_rename_exchange(struct inode *old_dir, struct dentry *old_dentry,
                           struct inode *new_dir, struct dentry *new_dentry)
 {
@@ -463,20 +778,15 @@ int simple_rename_exchange(struct inode *old_dir, struct dentry *old_dentry,
                        inc_nlink(old_dir);
                }
        }
-       old_dir->i_ctime = old_dir->i_mtime =
-       new_dir->i_ctime = new_dir->i_mtime =
-       d_inode(old_dentry)->i_ctime =
-       d_inode(new_dentry)->i_ctime = current_time(old_dir);
-
+       simple_rename_timestamp(old_dir, old_dentry, new_dir, new_dentry);
        return 0;
 }
 EXPORT_SYMBOL_GPL(simple_rename_exchange);
 
-int simple_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
+int simple_rename(struct mnt_idmap *idmap, struct inode *old_dir,
                  struct dentry *old_dentry, struct inode *new_dir,
                  struct dentry *new_dentry, unsigned int flags)
 {
-       struct inode *inode = d_inode(old_dentry);
        int they_are_dirs = d_is_dir(old_dentry);
 
        if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
@@ -499,16 +809,14 @@ int simple_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
                inc_nlink(new_dir);
        }
 
-       old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime =
-               new_dir->i_mtime = inode->i_ctime = current_time(old_dir);
-
+       simple_rename_timestamp(old_dir, old_dentry, new_dir, new_dentry);
        return 0;
 }
 EXPORT_SYMBOL(simple_rename);
 
 /**
  * simple_setattr - setattr for simple filesystem
- * @mnt_userns: user namespace of the target mount
+ * @idmap: idmap of the target mount
  * @dentry: dentry
  * @iattr: iattr structure
  *
@@ -521,19 +829,19 @@ EXPORT_SYMBOL(simple_rename);
  * on simple regular filesystems.  Anything that needs to change on-disk
  * or wire state on size changes needs its own setattr method.
  */
-int simple_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
+int simple_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
                   struct iattr *iattr)
 {
        struct inode *inode = d_inode(dentry);
        int error;
 
-       error = setattr_prepare(mnt_userns, dentry, iattr);
+       error = setattr_prepare(idmap, dentry, iattr);
        if (error)
                return error;
 
        if (iattr->ia_valid & ATTR_SIZE)
                truncate_setsize(inode, iattr->ia_size);
-       setattr_copy(mnt_userns, inode, iattr);
+       setattr_copy(idmap, inode, iattr);
        mark_inode_dirty(inode);
        return 0;
 }
@@ -552,21 +860,20 @@ int simple_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len,
                        struct page **pagep, void **fsdata)
 {
-       struct page *page;
-       pgoff_t index;
+       struct folio *folio;
 
-       index = pos >> PAGE_SHIFT;
+       folio = __filemap_get_folio(mapping, pos / PAGE_SIZE, FGP_WRITEBEGIN,
+                       mapping_gfp_mask(mapping));
+       if (IS_ERR(folio))
+               return PTR_ERR(folio);
 
-       page = grab_cache_page_write_begin(mapping, index);
-       if (!page)
-               return -ENOMEM;
+       *pagep = &folio->page;
 
-       *pagep = page;
+       if (!folio_test_uptodate(folio) && (len != folio_size(folio))) {
+               size_t from = offset_in_folio(folio, pos);
 
-       if (!PageUptodate(page) && (len != PAGE_SIZE)) {
-               unsigned from = pos & (PAGE_SIZE - 1);
-
-               zero_user_segments(page, 0, from, from + len, PAGE_SIZE);
+               folio_zero_segments(folio, 0, from,
+                               from + len, folio_size(folio));
        }
        return 0;
 }
@@ -598,17 +905,18 @@ static int simple_write_end(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned copied,
                        struct page *page, void *fsdata)
 {
-       struct inode *inode = page->mapping->host;
+       struct folio *folio = page_folio(page);
+       struct inode *inode = folio->mapping->host;
        loff_t last_pos = pos + copied;
 
-       /* zero the stale part of the page if we did a short copy */
-       if (!PageUptodate(page)) {
+       /* zero the stale part of the folio if we did a short copy */
+       if (!folio_test_uptodate(folio)) {
                if (copied < len) {
-                       unsigned from = pos & (PAGE_SIZE - 1);
+                       size_t from = offset_in_folio(folio, pos);
 
-                       zero_user(page, from + copied, len - copied);
+                       folio_zero_range(folio, from + copied, len - copied);
                }
-               SetPageUptodate(page);
+               folio_mark_uptodate(folio);
        }
        /*
         * No need to use i_size_read() here, the i_size
@@ -617,9 +925,9 @@ static int simple_write_end(struct file *file, struct address_space *mapping,
        if (last_pos > inode->i_size)
                i_size_write(inode, last_pos);
 
-       set_page_dirty(page);
-       unlock_page(page);
-       put_page(page);
+       folio_mark_dirty(folio);
+       folio_unlock(folio);
+       folio_put(folio);
 
        return copied;
 }
@@ -644,7 +952,6 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
                      const struct tree_descr *files)
 {
        struct inode *inode;
-       struct dentry *root;
        struct dentry *dentry;
        int i;
 
@@ -663,12 +970,12 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
         */
        inode->i_ino = 1;
        inode->i_mode = S_IFDIR | 0755;
-       inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
+       simple_inode_init_ts(inode);
        inode->i_op = &simple_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
        set_nlink(inode, 2);
-       root = d_make_root(inode);
-       if (!root)
+       s->s_root = d_make_root(inode);
+       if (!s->s_root)
                return -ENOMEM;
        for (i = 0; !files->name || files->name[0]; i++, files++) {
                if (!files->name)
@@ -680,27 +987,21 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
                                "with an index of 1!\n", __func__,
                                s->s_type->name);
 
-               dentry = d_alloc_name(root, files->name);
+               dentry = d_alloc_name(s->s_root, files->name);
                if (!dentry)
-                       goto out;
+                       return -ENOMEM;
                inode = new_inode(s);
                if (!inode) {
                        dput(dentry);
-                       goto out;
+                       return -ENOMEM;
                }
                inode->i_mode = S_IFREG | files->mode;
-               inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
+               simple_inode_init_ts(inode);
                inode->i_fop = files->ops;
                inode->i_ino = i;
                d_add(dentry, inode);
        }
-       s->s_root = root;
        return 0;
-out:
-       d_genocide(root);
-       shrink_dcache_parent(root);
-       dput(root);
-       return -ENOMEM;
 }
 EXPORT_SYMBOL(simple_fill_super);
 
@@ -994,8 +1295,8 @@ out:
 EXPORT_SYMBOL_GPL(simple_attr_read);
 
 /* interpret the buffer as a number to call the set function with */
-ssize_t simple_attr_write(struct file *file, const char __user *buf,
-                         size_t len, loff_t *ppos)
+static ssize_t simple_attr_write_xsigned(struct file *file, const char __user *buf,
+                         size_t len, loff_t *ppos, bool is_signed)
 {
        struct simple_attr *attr;
        unsigned long long val;
@@ -1016,7 +1317,10 @@ ssize_t simple_attr_write(struct file *file, const char __user *buf,
                goto out;
 
        attr->set_buf[size] = '\0';
-       ret = kstrtoull(attr->set_buf, 0, &val);
+       if (is_signed)
+               ret = kstrtoll(attr->set_buf, 0, &val);
+       else
+               ret = kstrtoull(attr->set_buf, 0, &val);
        if (ret)
                goto out;
        ret = attr->set(attr->data, val);
@@ -1026,8 +1330,62 @@ out:
        mutex_unlock(&attr->mutex);
        return ret;
 }
+
+ssize_t simple_attr_write(struct file *file, const char __user *buf,
+                         size_t len, loff_t *ppos)
+{
+       return simple_attr_write_xsigned(file, buf, len, ppos, false);
+}
 EXPORT_SYMBOL_GPL(simple_attr_write);
 
+ssize_t simple_attr_write_signed(struct file *file, const char __user *buf,
+                         size_t len, loff_t *ppos)
+{
+       return simple_attr_write_xsigned(file, buf, len, ppos, true);
+}
+EXPORT_SYMBOL_GPL(simple_attr_write_signed);
+
+/**
+ * generic_encode_ino32_fh - generic export_operations->encode_fh function
+ * @inode:   the object to encode
+ * @fh:      where to store the file handle fragment
+ * @max_len: maximum length to store there (in 4 byte units)
+ * @parent:  parent directory inode, if wanted
+ *
+ * This generic encode_fh function assumes that the 32 inode number
+ * is suitable for locating an inode, and that the generation number
+ * can be used to check that it is still valid.  It places them in the
+ * filehandle fragment where export_decode_fh expects to find them.
+ */
+int generic_encode_ino32_fh(struct inode *inode, __u32 *fh, int *max_len,
+                           struct inode *parent)
+{
+       struct fid *fid = (void *)fh;
+       int len = *max_len;
+       int type = FILEID_INO32_GEN;
+
+       if (parent && (len < 4)) {
+               *max_len = 4;
+               return FILEID_INVALID;
+       } else if (len < 2) {
+               *max_len = 2;
+               return FILEID_INVALID;
+       }
+
+       len = 2;
+       fid->i32.ino = inode->i_ino;
+       fid->i32.gen = inode->i_generation;
+       if (parent) {
+               fid->i32.parent_ino = parent->i_ino;
+               fid->i32.parent_gen = parent->i_generation;
+               len = 4;
+               type = FILEID_INO32_GEN_PARENT;
+       }
+       *max_len = len;
+       return type;
+}
+EXPORT_SYMBOL_GPL(generic_encode_ino32_fh);
+
 /**
  * generic_fh_to_dentry - generic helper for the fh_to_dentry export operation
  * @sb:                filesystem to do the file handle conversion on
@@ -1241,7 +1599,7 @@ struct inode *alloc_anon_inode(struct super_block *s)
        inode->i_uid = current_fsuid();
        inode->i_gid = current_fsgid();
        inode->i_flags |= S_PRIVATE;
-       inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
+       simple_inode_init_ts(inode);
        return inode;
 }
 EXPORT_SYMBOL(alloc_anon_inode);
@@ -1257,7 +1615,7 @@ EXPORT_SYMBOL(alloc_anon_inode);
  * All arguments are ignored and it just returns -EINVAL.
  */
 int
-simple_nosetlease(struct file *filp, long arg, struct file_lock **flp,
+simple_nosetlease(struct file *filp, int arg, struct file_lease **flp,
                  void **priv)
 {
        return -EINVAL;
@@ -1298,16 +1656,16 @@ static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry,
        return ERR_PTR(-ENOENT);
 }
 
-static int empty_dir_getattr(struct user_namespace *mnt_userns,
+static int empty_dir_getattr(struct mnt_idmap *idmap,
                             const struct path *path, struct kstat *stat,
                             u32 request_mask, unsigned int query_flags)
 {
        struct inode *inode = d_inode(path->dentry);
-       generic_fillattr(&init_user_ns, inode, stat);
+       generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
        return 0;
 }
 
-static int empty_dir_setattr(struct user_namespace *mnt_userns,
+static int empty_dir_setattr(struct mnt_idmap *idmap,
                             struct dentry *dentry, struct iattr *attr)
 {
        return -EPERM;
@@ -1369,16 +1727,6 @@ bool is_empty_dir_inode(struct inode *inode)
 }
 
 #if IS_ENABLED(CONFIG_UNICODE)
-/*
- * Determine if the name of a dentry should be casefolded.
- *
- * Return: if names will need casefolding
- */
-static bool needs_casefold(const struct inode *dir)
-{
-       return IS_CASEFOLDED(dir) && dir->i_sb->s_encoding;
-}
-
 /**
  * generic_ci_d_compare - generic d_compare implementation for casefolding filesystems
  * @dentry:    dentry whose name we are checking against
@@ -1391,16 +1739,28 @@ static bool needs_casefold(const struct inode *dir)
 static int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
                                const char *str, const struct qstr *name)
 {
-       const struct dentry *parent = READ_ONCE(dentry->d_parent);
-       const struct inode *dir = READ_ONCE(parent->d_inode);
-       const struct super_block *sb = dentry->d_sb;
-       const struct unicode_map *um = sb->s_encoding;
-       struct qstr qstr = QSTR_INIT(str, len);
+       const struct dentry *parent;
+       const struct inode *dir;
        char strbuf[DNAME_INLINE_LEN];
-       int ret;
+       struct qstr qstr;
+
+       /*
+        * Attempt a case-sensitive match first. It is cheaper and
+        * should cover most lookups, including all the sane
+        * applications that expect a case-sensitive filesystem.
+        *
+        * This comparison is safe under RCU because the caller
+        * guarantees the consistency between str and len. See
+        * __d_lookup_rcu_op_compare() for details.
+        */
+       if (len == name->len && !memcmp(str, name->name, len))
+               return 0;
+
+       parent = READ_ONCE(dentry->d_parent);
+       dir = READ_ONCE(parent->d_inode);
+       if (!dir || !IS_CASEFOLDED(dir))
+               return 1;
 
-       if (!dir || !needs_casefold(dir))
-               goto fallback;
        /*
         * If the dentry name is stored in-line, then it may be concurrently
         * modified by a rename.  If this happens, the VFS will eventually retry
@@ -1411,20 +1771,14 @@ static int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
        if (len <= DNAME_INLINE_LEN - 1) {
                memcpy(strbuf, str, len);
                strbuf[len] = 0;
-               qstr.name = strbuf;
+               str = strbuf;
                /* prevent compiler from optimizing out the temporary buffer */
                barrier();
        }
-       ret = utf8_strncasecmp(um, name, &qstr);
-       if (ret >= 0)
-               return ret;
+       qstr.len = len;
+       qstr.name = str;
 
-       if (sb_has_strict_encoding(sb))
-               return -EINVAL;
-fallback:
-       if (len != name->len)
-               return 1;
-       return !!memcmp(str, name->name, len);
+       return utf8_strncasecmp(dentry->d_sb->s_encoding, name, &qstr);
 }
 
 /**
@@ -1439,9 +1793,9 @@ static int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str)
        const struct inode *dir = READ_ONCE(dentry->d_inode);
        struct super_block *sb = dentry->d_sb;
        const struct unicode_map *um = sb->s_encoding;
-       int ret = 0;
+       int ret;
 
-       if (!dir || !needs_casefold(dir))
+       if (!dir || !IS_CASEFOLDED(dir))
                return 0;
 
        ret = utf8_casefold_hash(um, dentry, str);
@@ -1453,70 +1807,326 @@ static int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str)
 static const struct dentry_operations generic_ci_dentry_ops = {
        .d_hash = generic_ci_d_hash,
        .d_compare = generic_ci_d_compare,
-};
-#endif
-
 #ifdef CONFIG_FS_ENCRYPTION
-static const struct dentry_operations generic_encrypted_dentry_ops = {
        .d_revalidate = fscrypt_d_revalidate,
+#endif
 };
 #endif
 
-#if defined(CONFIG_FS_ENCRYPTION) && IS_ENABLED(CONFIG_UNICODE)
-static const struct dentry_operations generic_encrypted_ci_dentry_ops = {
-       .d_hash = generic_ci_d_hash,
-       .d_compare = generic_ci_d_compare,
+#ifdef CONFIG_FS_ENCRYPTION
+static const struct dentry_operations generic_encrypted_dentry_ops = {
        .d_revalidate = fscrypt_d_revalidate,
 };
 #endif
 
 /**
- * generic_set_encrypted_ci_d_ops - helper for setting d_ops for given dentry
- * @dentry:    dentry to set ops on
- *
- * Casefolded directories need d_hash and d_compare set, so that the dentries
- * contained in them are handled case-insensitively.  Note that these operations
- * are needed on the parent directory rather than on the dentries in it, and
- * while the casefolding flag can be toggled on and off on an empty directory,
- * dentry_operations can't be changed later.  As a result, if the filesystem has
- * casefolding support enabled at all, we have to give all dentries the
- * casefolding operations even if their inode doesn't have the casefolding flag
- * currently (and thus the casefolding ops would be no-ops for now).
+ * generic_set_sb_d_ops - helper for choosing the set of
+ * filesystem-wide dentry operations for the enabled features
+ * @sb: superblock to be configured
  *
- * Encryption works differently in that the only dentry operation it needs is
- * d_revalidate, which it only needs on dentries that have the no-key name flag.
- * The no-key flag can't be set "later", so we don't have to worry about that.
- *
- * Finally, to maximize compatibility with overlayfs (which isn't compatible
- * with certain dentry operations) and to avoid taking an unnecessary
- * performance hit, we use custom dentry_operations for each possible
- * combination rather than always installing all operations.
+ * Filesystems supporting casefolding and/or fscrypt can call this
+ * helper at mount-time to configure sb->s_d_op to best set of dentry
+ * operations required for the enabled features. The helper must be
+ * called after these have been configured, but before the root dentry
+ * is created.
  */
-void generic_set_encrypted_ci_d_ops(struct dentry *dentry)
+void generic_set_sb_d_ops(struct super_block *sb)
 {
-#ifdef CONFIG_FS_ENCRYPTION
-       bool needs_encrypt_ops = dentry->d_flags & DCACHE_NOKEY_NAME;
-#endif
 #if IS_ENABLED(CONFIG_UNICODE)
-       bool needs_ci_ops = dentry->d_sb->s_encoding;
-#endif
-#if defined(CONFIG_FS_ENCRYPTION) && IS_ENABLED(CONFIG_UNICODE)
-       if (needs_encrypt_ops && needs_ci_ops) {
-               d_set_d_op(dentry, &generic_encrypted_ci_dentry_ops);
+       if (sb->s_encoding) {
+               sb->s_d_op = &generic_ci_dentry_ops;
                return;
        }
 #endif
 #ifdef CONFIG_FS_ENCRYPTION
-       if (needs_encrypt_ops) {
-               d_set_d_op(dentry, &generic_encrypted_dentry_ops);
+       if (sb->s_cop) {
+               sb->s_d_op = &generic_encrypted_dentry_ops;
                return;
        }
 #endif
-#if IS_ENABLED(CONFIG_UNICODE)
-       if (needs_ci_ops) {
-               d_set_d_op(dentry, &generic_ci_dentry_ops);
-               return;
+}
+EXPORT_SYMBOL(generic_set_sb_d_ops);
+
+/**
+ * inode_maybe_inc_iversion - increments i_version
+ * @inode: inode with the i_version that should be updated
+ * @force: increment the counter even if it's not necessary?
+ *
+ * Every time the inode is modified, the i_version field must be seen to have
+ * changed by any observer.
+ *
+ * If "force" is set or the QUERIED flag is set, then ensure that we increment
+ * the value, and clear the queried flag.
+ *
+ * In the common case where neither is set, then we can return "false" without
+ * updating i_version.
+ *
+ * If this function returns false, and no other metadata has changed, then we
+ * can avoid logging the metadata.
+ */
+bool inode_maybe_inc_iversion(struct inode *inode, bool force)
+{
+       u64 cur, new;
+
+       /*
+        * The i_version field is not strictly ordered with any other inode
+        * information, but the legacy inode_inc_iversion code used a spinlock
+        * to serialize increments.
+        *
+        * Here, we add full memory barriers to ensure that any de-facto
+        * ordering with other info is preserved.
+        *
+        * This barrier pairs with the barrier in inode_query_iversion()
+        */
+       smp_mb();
+       cur = inode_peek_iversion_raw(inode);
+       do {
+               /* If flag is clear then we needn't do anything */
+               if (!force && !(cur & I_VERSION_QUERIED))
+                       return false;
+
+               /* Since lowest bit is flag, add 2 to avoid it */
+               new = (cur & ~I_VERSION_QUERIED) + I_VERSION_INCREMENT;
+       } while (!atomic64_try_cmpxchg(&inode->i_version, &cur, new));
+       return true;
+}
+EXPORT_SYMBOL(inode_maybe_inc_iversion);
+
+/**
+ * inode_query_iversion - read i_version for later use
+ * @inode: inode from which i_version should be read
+ *
+ * Read the inode i_version counter. This should be used by callers that wish
+ * to store the returned i_version for later comparison. This will guarantee
+ * that a later query of the i_version will result in a different value if
+ * anything has changed.
+ *
+ * In this implementation, we fetch the current value, set the QUERIED flag and
+ * then try to swap it into place with a cmpxchg, if it wasn't already set. If
+ * that fails, we try again with the newly fetched value from the cmpxchg.
+ */
+u64 inode_query_iversion(struct inode *inode)
+{
+       u64 cur, new;
+
+       cur = inode_peek_iversion_raw(inode);
+       do {
+               /* If flag is already set, then no need to swap */
+               if (cur & I_VERSION_QUERIED) {
+                       /*
+                        * This barrier (and the implicit barrier in the
+                        * cmpxchg below) pairs with the barrier in
+                        * inode_maybe_inc_iversion().
+                        */
+                       smp_mb();
+                       break;
+               }
+
+               new = cur | I_VERSION_QUERIED;
+       } while (!atomic64_try_cmpxchg(&inode->i_version, &cur, new));
+       return cur >> I_VERSION_QUERIED_SHIFT;
+}
+EXPORT_SYMBOL(inode_query_iversion);
+
+ssize_t direct_write_fallback(struct kiocb *iocb, struct iov_iter *iter,
+               ssize_t direct_written, ssize_t buffered_written)
+{
+       struct address_space *mapping = iocb->ki_filp->f_mapping;
+       loff_t pos = iocb->ki_pos - buffered_written;
+       loff_t end = iocb->ki_pos - 1;
+       int err;
+
+       /*
+        * If the buffered write fallback returned an error, we want to return
+        * the number of bytes which were written by direct I/O, or the error
+        * code if that was zero.
+        *
+        * Note that this differs from normal direct-io semantics, which will
+        * return -EFOO even if some bytes were written.
+        */
+       if (unlikely(buffered_written < 0)) {
+               if (direct_written)
+                       return direct_written;
+               return buffered_written;
        }
-#endif
+
+       /*
+        * We need to ensure that the page cache pages are written to disk and
+        * invalidated to preserve the expected O_DIRECT semantics.
+        */
+       err = filemap_write_and_wait_range(mapping, pos, end);
+       if (err < 0) {
+               /*
+                * We don't know how much we wrote, so just return the number of
+                * bytes which were direct-written
+                */
+               iocb->ki_pos -= buffered_written;
+               if (direct_written)
+                       return direct_written;
+               return err;
+       }
+       invalidate_mapping_pages(mapping, pos >> PAGE_SHIFT, end >> PAGE_SHIFT);
+       return direct_written + buffered_written;
+}
+EXPORT_SYMBOL_GPL(direct_write_fallback);
+
+/**
+ * simple_inode_init_ts - initialize the timestamps for a new inode
+ * @inode: inode to be initialized
+ *
+ * When a new inode is created, most filesystems set the timestamps to the
+ * current time. Add a helper to do this.
+ */
+struct timespec64 simple_inode_init_ts(struct inode *inode)
+{
+       struct timespec64 ts = inode_set_ctime_current(inode);
+
+       inode_set_atime_to_ts(inode, ts);
+       inode_set_mtime_to_ts(inode, ts);
+       return ts;
+}
+EXPORT_SYMBOL(simple_inode_init_ts);
+
+static inline struct dentry *get_stashed_dentry(struct dentry *stashed)
+{
+       struct dentry *dentry;
+
+       guard(rcu)();
+       dentry = READ_ONCE(stashed);
+       if (!dentry)
+               return NULL;
+       if (!lockref_get_not_dead(&dentry->d_lockref))
+               return NULL;
+       return dentry;
+}
+
+static struct dentry *prepare_anon_dentry(struct dentry **stashed,
+                                         struct super_block *sb,
+                                         void *data)
+{
+       struct dentry *dentry;
+       struct inode *inode;
+       const struct stashed_operations *sops = sb->s_fs_info;
+       int ret;
+
+       inode = new_inode_pseudo(sb);
+       if (!inode) {
+               sops->put_data(data);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       inode->i_flags |= S_IMMUTABLE;
+       inode->i_mode = S_IFREG;
+       simple_inode_init_ts(inode);
+
+       ret = sops->init_inode(inode, data);
+       if (ret < 0) {
+               iput(inode);
+               return ERR_PTR(ret);
+       }
+
+       /* Notice when this is changed. */
+       WARN_ON_ONCE(!S_ISREG(inode->i_mode));
+       WARN_ON_ONCE(!IS_IMMUTABLE(inode));
+
+       dentry = d_alloc_anon(sb);
+       if (!dentry) {
+               iput(inode);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       /* Store address of location where dentry's supposed to be stashed. */
+       dentry->d_fsdata = stashed;
+
+       /* @data is now owned by the fs */
+       d_instantiate(dentry, inode);
+       return dentry;
+}
+
+static struct dentry *stash_dentry(struct dentry **stashed,
+                                  struct dentry *dentry)
+{
+       guard(rcu)();
+       for (;;) {
+               struct dentry *old;
+
+               /* Assume any old dentry was cleared out. */
+               old = cmpxchg(stashed, NULL, dentry);
+               if (likely(!old))
+                       return dentry;
+
+               /* Check if somebody else installed a reusable dentry. */
+               if (lockref_get_not_dead(&old->d_lockref))
+                       return old;
+
+               /* There's an old dead dentry there, try to take it over. */
+               if (likely(try_cmpxchg(stashed, &old, dentry)))
+                       return dentry;
+       }
+}
+
+/**
+ * path_from_stashed - create path from stashed or new dentry
+ * @stashed:    where to retrieve or stash dentry
+ * @mnt:        mnt of the filesystems to use
+ * @data:       data to store in inode->i_private
+ * @path:       path to create
+ *
+ * The function tries to retrieve a stashed dentry from @stashed. If the dentry
+ * is still valid then it will be reused. If the dentry isn't able the function
+ * will allocate a new dentry and inode. It will then check again whether it
+ * can reuse an existing dentry in case one has been added in the meantime or
+ * update @stashed with the newly added dentry.
+ *
+ * Special-purpose helper for nsfs and pidfs.
+ *
+ * Return: On success zero and on failure a negative error is returned.
+ */
+int path_from_stashed(struct dentry **stashed, struct vfsmount *mnt, void *data,
+                     struct path *path)
+{
+       struct dentry *dentry;
+       const struct stashed_operations *sops = mnt->mnt_sb->s_fs_info;
+
+       /* See if dentry can be reused. */
+       path->dentry = get_stashed_dentry(*stashed);
+       if (path->dentry) {
+               sops->put_data(data);
+               goto out_path;
+       }
+
+       /* Allocate a new dentry. */
+       dentry = prepare_anon_dentry(stashed, mnt->mnt_sb, data);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
+
+       /* Added a new dentry. @data is now owned by the filesystem. */
+       path->dentry = stash_dentry(stashed, dentry);
+       if (path->dentry != dentry)
+               dput(dentry);
+
+out_path:
+       WARN_ON_ONCE(path->dentry->d_fsdata != stashed);
+       WARN_ON_ONCE(d_inode(path->dentry)->i_private != data);
+       path->mnt = mntget(mnt);
+       return 0;
+}
+
+void stashed_dentry_prune(struct dentry *dentry)
+{
+       struct dentry **stashed = dentry->d_fsdata;
+       struct inode *inode = d_inode(dentry);
+
+       if (WARN_ON_ONCE(!stashed))
+               return;
+
+       if (!inode)
+               return;
+
+       /*
+        * Only replace our own @dentry as someone else might've
+        * already cleared out @dentry and stashed their own
+        * dentry in there.
+        */
+       cmpxchg(stashed, dentry, NULL);
 }
-EXPORT_SYMBOL(generic_set_encrypted_ci_d_ops);