]> Git Repo - J-linux.git/commitdiff
Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <[email protected]>
Sun, 2 May 2021 16:14:01 +0000 (09:14 -0700)
committerLinus Torvalds <[email protected]>
Sun, 2 May 2021 16:14:01 +0000 (09:14 -0700)
Pull misc vfs updates from Al Viro:
 "Assorted stuff all over the place"

* 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  useful constants: struct qstr for ".."
  hostfs_open(): don't open-code file_dentry()
  whack-a-mole: kill strlen_user() (again)
  autofs: should_expire() argument is guaranteed to be positive
  apparmor:match_mn() - constify devpath argument
  buffer: a small optimization in grow_buffers
  get rid of autofs_getpath()
  constify dentry argument of dentry_path()/dentry_path_raw()

1  2 
arch/riscv/include/asm/uaccess.h
fs/ext2/namei.c
fs/ext4/namei.c
fs/f2fs/namei.c
fs/fuse/inode.c
fs/hostfs/hostfs_kern.c
fs/nilfs2/namei.c

index f944062c9d990e7964358f8c12e218084af14a8c,4297f43e8732355da2544e4854aafd65dc163059..f314ff44c48d1f979079a79b294b86717e6c93e1
@@@ -306,9 -306,7 +306,9 @@@ do {                                                               
   * data types like structures or arrays.
   *
   * @ptr must have pointer-to-simple-variable type, and @x must be assignable
 - * to the result of dereferencing @ptr.
 + * to the result of dereferencing @ptr. The value of @x is copied to avoid
 + * re-ordering where @x is evaluated inside the block that enables user-space
 + * access (thus bypassing user space protection if @x is a function).
   *
   * Caller must check the pointer with access_ok() before calling this
   * function.
  #define __put_user(x, ptr)                                    \
  ({                                                            \
        __typeof__(*(ptr)) __user *__gu_ptr = (ptr);            \
 +      __typeof__(*__gu_ptr) __val = (x);                      \
        long __pu_err = 0;                                      \
                                                                \
        __chk_user_ptr(__gu_ptr);                               \
                                                                \
        __enable_user_access();                                 \
 -      __put_user_nocheck(x, __gu_ptr, __pu_err);              \
 +      __put_user_nocheck(__val, __gu_ptr, __pu_err);          \
        __disable_user_access();                                \
                                                                \
        __pu_err;                                               \
@@@ -375,7 -372,6 +375,6 @@@ raw_copy_to_user(void __user *to, cons
  
  extern long strncpy_from_user(char *dest, const char __user *src, long count);
  
- extern long __must_check strlen_user(const char __user *str);
  extern long __must_check strnlen_user(const char __user *str, long n);
  
  extern
diff --combined fs/ext2/namei.c
index c6b8bba730317b9942d3a8edaa926e5d80ec708a,765fb389550f36ce1d4d6a3491dad4f32f2b634b..1f69b81655b661c7f7c694d0a56b54612234bf56
@@@ -81,11 -81,10 +81,10 @@@ static struct dentry *ext2_lookup(struc
  
  struct dentry *ext2_get_parent(struct dentry *child)
  {
-       struct qstr dotdot = QSTR_INIT("..", 2);
        ino_t ino;
        int res;
  
-       res = ext2_inode_by_name(d_inode(child), &dotdot, &ino);
+       res = ext2_inode_by_name(d_inode(child), &dotdot_name, &ino);
        if (res)
                return ERR_PTR(res);
  
@@@ -281,21 -280,19 +280,21 @@@ static int ext2_unlink(struct inode * d
        struct inode * inode = d_inode(dentry);
        struct ext2_dir_entry_2 * de;
        struct page * page;
 +      void *page_addr;
        int err;
  
        err = dquot_initialize(dir);
        if (err)
                goto out;
  
 -      de = ext2_find_entry(dir, &dentry->d_name, &page);
 +      de = ext2_find_entry(dir, &dentry->d_name, &page, &page_addr);
        if (IS_ERR(de)) {
                err = PTR_ERR(de);
                goto out;
        }
  
        err = ext2_delete_entry (de, page);
 +      ext2_put_page(page, page_addr);
        if (err)
                goto out;
  
@@@ -330,10 -327,8 +329,10 @@@ static int ext2_rename (struct user_nam
        struct inode * old_inode = d_inode(old_dentry);
        struct inode * new_inode = d_inode(new_dentry);
        struct page * dir_page = NULL;
 +      void *dir_page_addr;
        struct ext2_dir_entry_2 * dir_de = NULL;
        struct page * old_page;
 +      void *old_page_addr;
        struct ext2_dir_entry_2 * old_de;
        int err;
  
        if (err)
                goto out;
  
 -      old_de = ext2_find_entry(old_dir, &old_dentry->d_name, &old_page);
 +      old_de = ext2_find_entry(old_dir, &old_dentry->d_name, &old_page,
 +                               &old_page_addr);
        if (IS_ERR(old_de)) {
                err = PTR_ERR(old_de);
                goto out;
  
        if (S_ISDIR(old_inode->i_mode)) {
                err = -EIO;
 -              dir_de = ext2_dotdot(old_inode, &dir_page);
 +              dir_de = ext2_dotdot(old_inode, &dir_page, &dir_page_addr);
                if (!dir_de)
                        goto out_old;
        }
  
        if (new_inode) {
 +              void *page_addr;
                struct page *new_page;
                struct ext2_dir_entry_2 *new_de;
  
                if (dir_de && !ext2_empty_dir (new_inode))
                        goto out_dir;
  
 -              new_de = ext2_find_entry(new_dir, &new_dentry->d_name, &new_page);
 +              new_de = ext2_find_entry(new_dir, &new_dentry->d_name,
 +                                       &new_page, &page_addr);
                if (IS_ERR(new_de)) {
                        err = PTR_ERR(new_de);
                        goto out_dir;
                }
 -              ext2_set_link(new_dir, new_de, new_page, old_inode, 1);
 +              ext2_set_link(new_dir, new_de, new_page, page_addr, old_inode, 1);
 +              ext2_put_page(new_page, page_addr);
                new_inode->i_ctime = current_time(new_inode);
                if (dir_de)
                        drop_nlink(new_inode);
        old_inode->i_ctime = current_time(old_inode);
        mark_inode_dirty(old_inode);
  
 -      ext2_delete_entry (old_de, old_page);
 +      ext2_delete_entry(old_de, old_page);
  
        if (dir_de) {
                if (old_dir != new_dir)
 -                      ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0);
 -              else
 -                      ext2_put_page(dir_page);
 +                      ext2_set_link(old_inode, dir_de, dir_page,
 +                                    dir_page_addr, new_dir, 0);
 +
 +              ext2_put_page(dir_page, dir_page_addr);
                inode_dec_link_count(old_dir);
        }
 -      return 0;
  
 +      ext2_put_page(old_page, old_page_addr);
 +      return 0;
  
  out_dir:
        if (dir_de)
 -              ext2_put_page(dir_page);
 +              ext2_put_page(dir_page, dir_page_addr);
  out_old:
 -      ext2_put_page(old_page);
 +      ext2_put_page(old_page, old_page_addr);
  out:
        return err;
  }
@@@ -437,8 -426,6 +436,8 @@@ const struct inode_operations ext2_dir_
        .get_acl        = ext2_get_acl,
        .set_acl        = ext2_set_acl,
        .tmpfile        = ext2_tmpfile,
 +      .fileattr_get   = ext2_fileattr_get,
 +      .fileattr_set   = ext2_fileattr_set,
  };
  
  const struct inode_operations ext2_special_inode_operations = {
diff --combined fs/ext4/namei.c
index e8100a9a22fe1d05853e4d2c318788637315afb0,a9db885abb8b4f332a7c2c3f13173a4f1083c8cd..afb9d05a99bae5705a6403afbedc726e3c587cc2
@@@ -280,11 -280,9 +280,11 @@@ static int dx_make_map(struct inode *di
                       unsigned blocksize, struct dx_hash_info *hinfo,
                       struct dx_map_entry map[]);
  static void dx_sort_map(struct dx_map_entry *map, unsigned count);
 -static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to,
 -              struct dx_map_entry *offsets, int count, unsigned blocksize);
 -static struct ext4_dir_entry_2* dx_pack_dirents(char *base, unsigned blocksize);
 +static struct ext4_dir_entry_2 *dx_move_dirents(struct inode *dir, char *from,
 +                                      char *to, struct dx_map_entry *offsets,
 +                                      int count, unsigned int blocksize);
 +static struct ext4_dir_entry_2 *dx_pack_dirents(struct inode *dir, char *base,
 +                                              unsigned int blocksize);
  static void dx_insert_block(struct dx_frame *frame,
                                        u32 hash, ext4_lblk_t block);
  static int ext4_htree_next_block(struct inode *dir, __u32 hash,
@@@ -576,9 -574,8 +576,9 @@@ static inline void dx_set_limit(struct 
  
  static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize)
  {
 -      unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) -
 -              EXT4_DIR_REC_LEN(2) - infosize;
 +      unsigned int entry_space = dir->i_sb->s_blocksize -
 +                      ext4_dir_rec_len(1, NULL) -
 +                      ext4_dir_rec_len(2, NULL) - infosize;
  
        if (ext4_has_metadata_csum(dir->i_sb))
                entry_space -= sizeof(struct dx_tail);
  
  static inline unsigned dx_node_limit(struct inode *dir)
  {
 -      unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0);
 +      unsigned int entry_space = dir->i_sb->s_blocksize -
 +                      ext4_dir_rec_len(0, dir);
  
        if (ext4_has_metadata_csum(dir->i_sb))
                entry_space -= sizeof(struct dx_tail);
@@@ -677,10 -673,7 +677,10 @@@ static struct stats dx_show_leaf(struc
                                                name = fname_crypto_str.name;
                                                len = fname_crypto_str.len;
                                        }
 -                                      ext4fs_dirhash(dir, de->name,
 +                                      if (IS_CASEFOLDED(dir))
 +                                              h.hash = EXT4_DIRENT_HASH(de);
 +                                      else
 +                                              ext4fs_dirhash(dir, de->name,
                                                       de->name_len, &h);
                                        printk("%*.s:(E)%x.%u ", len, name,
                                               h.hash, (unsigned) ((char *) de
                                       (unsigned) ((char *) de - base));
  #endif
                        }
 -                      space += EXT4_DIR_REC_LEN(de->name_len);
 +                      space += ext4_dir_rec_len(de->name_len, dir);
                        names++;
                }
                de = ext4_next_entry(de, size);
@@@ -791,34 -784,18 +791,34 @@@ dx_probe(struct ext4_filename *fname, s
        root = (struct dx_root *) frame->bh->b_data;
        if (root->info.hash_version != DX_HASH_TEA &&
            root->info.hash_version != DX_HASH_HALF_MD4 &&
 -          root->info.hash_version != DX_HASH_LEGACY) {
 +          root->info.hash_version != DX_HASH_LEGACY &&
 +          root->info.hash_version != DX_HASH_SIPHASH) {
                ext4_warning_inode(dir, "Unrecognised inode hash code %u",
                                   root->info.hash_version);
                goto fail;
        }
 +      if (ext4_hash_in_dirent(dir)) {
 +              if (root->info.hash_version != DX_HASH_SIPHASH) {
 +                      ext4_warning_inode(dir,
 +                              "Hash in dirent, but hash is not SIPHASH");
 +                      goto fail;
 +              }
 +      } else {
 +              if (root->info.hash_version == DX_HASH_SIPHASH) {
 +                      ext4_warning_inode(dir,
 +                              "Hash code is SIPHASH, but hash not in dirent");
 +                      goto fail;
 +              }
 +      }
        if (fname)
                hinfo = &fname->hinfo;
        hinfo->hash_version = root->info.hash_version;
        if (hinfo->hash_version <= DX_HASH_TEA)
                hinfo->hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned;
        hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed;
 -      if (fname && fname_name(fname))
 +      /* hash is already computed for encrypted casefolded directory */
 +      if (fname && fname_name(fname) &&
 +                              !(IS_ENCRYPTED(dir) && IS_CASEFOLDED(dir)))
                ext4fs_dirhash(dir, fname_name(fname), fname_len(fname), hinfo);
        hash = hinfo->hash;
  
@@@ -979,7 -956,7 +979,7 @@@ static int ext4_htree_next_block(struc
         * If the hash is 1, then continue only if the next page has a
         * continuation hash of any value.  This is used for readdir
         * handling.  Otherwise, check to see if the hash matches the
 -       * desired contiuation hash.  If it doesn't, return since
 +       * desired continuation hash.  If it doesn't, return since
         * there's no point to read in the successive index pages.
         */
        bhash = dx_get_hash(p->at);
@@@ -1020,7 -997,6 +1020,7 @@@ static int htree_dirblock_to_tree(struc
        struct ext4_dir_entry_2 *de, *top;
        int err = 0, count = 0;
        struct fscrypt_str fname_crypto_str = FSTR_INIT(NULL, 0), tmp_str;
 +      int csum = ext4_has_metadata_csum(dir->i_sb);
  
        dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n",
                                                        (unsigned long)block));
                return PTR_ERR(bh);
  
        de = (struct ext4_dir_entry_2 *) bh->b_data;
 +      /* csum entries are not larger in the casefolded encrypted case */
        top = (struct ext4_dir_entry_2 *) ((char *) de +
                                           dir->i_sb->s_blocksize -
 -                                         EXT4_DIR_REC_LEN(0));
 +                                         ext4_dir_rec_len(0,
 +                                                         csum ? NULL : dir));
        /* Check if the directory is encrypted */
        if (IS_ENCRYPTED(dir)) {
                err = fscrypt_prepare_readdir(dir);
                        /* silently ignore the rest of the block */
                        break;
                }
 -              ext4fs_dirhash(dir, de->name, de->name_len, hinfo);
 +              if (ext4_hash_in_dirent(dir)) {
 +                      if (de->name_len && de->inode) {
 +                              hinfo->hash = EXT4_DIRENT_HASH(de);
 +                              hinfo->minor_hash = EXT4_DIRENT_MINOR_HASH(de);
 +                      } else {
 +                              hinfo->hash = 0;
 +                              hinfo->minor_hash = 0;
 +                      }
 +              } else {
 +                      ext4fs_dirhash(dir, de->name, de->name_len, hinfo);
 +              }
                if ((hinfo->hash < start_hash) ||
                    ((hinfo->hash == start_hash) &&
                     (hinfo->minor_hash < start_minor_hash)))
@@@ -1136,11 -1100,7 +1136,11 @@@ int ext4_htree_fill_tree(struct file *d
                       start_hash, start_minor_hash));
        dir = file_inode(dir_file);
        if (!(ext4_test_inode_flag(dir, EXT4_INODE_INDEX))) {
 -              hinfo.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
 +              if (ext4_hash_in_dirent(dir))
 +                      hinfo.hash_version = DX_HASH_SIPHASH;
 +              else
 +                      hinfo.hash_version =
 +                                      EXT4_SB(dir->i_sb)->s_def_hash_version;
                if (hinfo.hash_version <= DX_HASH_TEA)
                        hinfo.hash_version +=
                                EXT4_SB(dir->i_sb)->s_hash_unsigned;
@@@ -1258,10 -1218,7 +1258,10 @@@ static int dx_make_map(struct inode *di
  
        while ((char *) de < base + blocksize) {
                if (de->name_len && de->inode) {
 -                      ext4fs_dirhash(dir, de->name, de->name_len, &h);
 +                      if (ext4_hash_in_dirent(dir))
 +                              h.hash = EXT4_DIRENT_HASH(de);
 +                      else
 +                              ext4fs_dirhash(dir, de->name, de->name_len, &h);
                        map_tail--;
                        map_tail->hash = h.hash;
                        map_tail->offs = ((char *) de - base)>>2;
@@@ -1325,65 -1282,47 +1325,65 @@@ static void dx_insert_block(struct dx_f
   * Returns: 0 if the directory entry matches, more than 0 if it
   * doesn't match or less than zero on error.
   */
 -int ext4_ci_compare(const struct inode *parent, const struct qstr *name,
 -                  const struct qstr *entry, bool quick)
 +static int ext4_ci_compare(const struct inode *parent, const struct qstr *name,
 +                         u8 *de_name, size_t de_name_len, bool quick)
  {
        const struct super_block *sb = parent->i_sb;
        const struct unicode_map *um = sb->s_encoding;
 +      struct fscrypt_str decrypted_name = FSTR_INIT(NULL, de_name_len);
 +      struct qstr entry = QSTR_INIT(de_name, de_name_len);
        int ret;
  
 +      if (IS_ENCRYPTED(parent)) {
 +              const struct fscrypt_str encrypted_name =
 +                              FSTR_INIT(de_name, de_name_len);
 +
 +              decrypted_name.name = kmalloc(de_name_len, GFP_KERNEL);
 +              if (!decrypted_name.name)
 +                      return -ENOMEM;
 +              ret = fscrypt_fname_disk_to_usr(parent, 0, 0, &encrypted_name,
 +                                              &decrypted_name);
 +              if (ret < 0)
 +                      goto out;
 +              entry.name = decrypted_name.name;
 +              entry.len = decrypted_name.len;
 +      }
 +
        if (quick)
 -              ret = utf8_strncasecmp_folded(um, name, entry);
 +              ret = utf8_strncasecmp_folded(um, name, &entry);
        else
 -              ret = utf8_strncasecmp(um, name, entry);
 -
 +              ret = utf8_strncasecmp(um, name, &entry);
        if (ret < 0) {
                /* Handle invalid character sequence as either an error
                 * or as an opaque byte sequence.
                 */
                if (sb_has_strict_encoding(sb))
 -                      return -EINVAL;
 -
 -              if (name->len != entry->len)
 -                      return 1;
 -
 -              return !!memcmp(name->name, entry->name, name->len);
 +                      ret = -EINVAL;
 +              else if (name->len != entry.len)
 +                      ret = 1;
 +              else
 +                      ret = !!memcmp(name->name, entry.name, entry.len);
        }
 -
 +out:
 +      kfree(decrypted_name.name);
        return ret;
  }
  
 -void ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
 -                                struct fscrypt_str *cf_name)
 +int ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
 +                                struct ext4_filename *name)
  {
 +      struct fscrypt_str *cf_name = &name->cf_name;
 +      struct dx_hash_info *hinfo = &name->hinfo;
        int len;
  
        if (!IS_CASEFOLDED(dir) || !dir->i_sb->s_encoding) {
                cf_name->name = NULL;
 -              return;
 +              return 0;
        }
  
        cf_name->name = kmalloc(EXT4_NAME_LEN, GFP_NOFS);
        if (!cf_name->name)
 -              return;
 +              return -ENOMEM;
  
        len = utf8_casefold(dir->i_sb->s_encoding,
                            iname, cf_name->name,
        if (len <= 0) {
                kfree(cf_name->name);
                cf_name->name = NULL;
 -              return;
        }
        cf_name->len = (unsigned) len;
 +      if (!IS_ENCRYPTED(dir))
 +              return 0;
  
 +      hinfo->hash_version = DX_HASH_SIPHASH;
 +      hinfo->seed = NULL;
 +      if (cf_name->name)
 +              ext4fs_dirhash(dir, cf_name->name, cf_name->len, hinfo);
 +      else
 +              ext4fs_dirhash(dir, iname->name, iname->len, hinfo);
 +      return 0;
  }
  #endif
  
   *
   * Return: %true if the directory entry matches, otherwise %false.
   */
 -static inline bool ext4_match(const struct inode *parent,
 +static bool ext4_match(struct inode *parent,
                              const struct ext4_filename *fname,
 -                            const struct ext4_dir_entry_2 *de)
 +                            struct ext4_dir_entry_2 *de)
  {
        struct fscrypt_name f;
 -#ifdef CONFIG_UNICODE
 -      const struct qstr entry = {.name = de->name, .len = de->name_len};
 -#endif
  
        if (!de->inode)
                return false;
                if (fname->cf_name.name) {
                        struct qstr cf = {.name = fname->cf_name.name,
                                          .len = fname->cf_name.len};
 -                      return !ext4_ci_compare(parent, &cf, &entry, true);
 +                      if (IS_ENCRYPTED(parent)) {
 +                              if (fname->hinfo.hash != EXT4_DIRENT_HASH(de) ||
 +                                      fname->hinfo.minor_hash !=
 +                                              EXT4_DIRENT_MINOR_HASH(de)) {
 +
 +                                      return 0;
 +                              }
 +                      }
 +                      return !ext4_ci_compare(parent, &cf, de->name,
 +                                                      de->name_len, true);
                }
 -              return !ext4_ci_compare(parent, fname->usr_fname, &entry,
 -                                      false);
 +              return !ext4_ci_compare(parent, fname->usr_fname, de->name,
 +                                              de->name_len, false);
        }
  #endif
  
@@@ -1814,11 -1739,10 +1814,10 @@@ static struct dentry *ext4_lookup(struc
  struct dentry *ext4_get_parent(struct dentry *child)
  {
        __u32 ino;
-       static const struct qstr dotdot = QSTR_INIT("..", 2);
        struct ext4_dir_entry_2 * de;
        struct buffer_head *bh;
  
-       bh = ext4_find_entry(d_inode(child), &dotdot, &de, NULL);
+       bh = ext4_find_entry(d_inode(child), &dotdot_name, &de, NULL);
        if (IS_ERR(bh))
                return ERR_CAST(bh);
        if (!bh)
   * Returns pointer to last entry moved.
   */
  static struct ext4_dir_entry_2 *
 -dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count,
 +dx_move_dirents(struct inode *dir, char *from, char *to,
 +              struct dx_map_entry *map, int count,
                unsigned blocksize)
  {
        unsigned rec_len = 0;
        while (count--) {
                struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *)
                                                (from + (map->offs<<2));
 -              rec_len = EXT4_DIR_REC_LEN(de->name_len);
 +              rec_len = ext4_dir_rec_len(de->name_len, dir);
 +
                memcpy (to, de, rec_len);
                ((struct ext4_dir_entry_2 *) to)->rec_len =
                                ext4_rec_len_to_disk(rec_len, blocksize);
 +
 +              /* wipe dir_entry excluding the rec_len field */
                de->inode = 0;
 +              memset(&de->name_len, 0, ext4_rec_len_from_disk(de->rec_len,
 +                                                              blocksize) -
 +                                       offsetof(struct ext4_dir_entry_2,
 +                                                              name_len));
 +
                map++;
                to += rec_len;
        }
   * Compact each dir entry in the range to the minimal rec_len.
   * Returns pointer to last entry in range.
   */
 -static struct ext4_dir_entry_2* dx_pack_dirents(char *base, unsigned blocksize)
 +static struct ext4_dir_entry_2 *dx_pack_dirents(struct inode *dir, char *base,
 +                                                      unsigned int blocksize)
  {
        struct ext4_dir_entry_2 *next, *to, *prev, *de = (struct ext4_dir_entry_2 *) base;
        unsigned rec_len = 0;
        while ((char*)de < base + blocksize) {
                next = ext4_next_entry(de, blocksize);
                if (de->inode && de->name_len) {
 -                      rec_len = EXT4_DIR_REC_LEN(de->name_len);
 +                      rec_len = ext4_dir_rec_len(de->name_len, dir);
                        if (de > to)
                                memmove(to, de, rec_len);
                        to->rec_len = ext4_rec_len_to_disk(rec_len, blocksize);
@@@ -1972,9 -1886,9 +1971,9 @@@ static struct ext4_dir_entry_2 *do_spli
                                        hash2, split, count-split));
  
        /* Fancy dance to stay within two buffers */
 -      de2 = dx_move_dirents(data1, data2, map + split, count - split,
 +      de2 = dx_move_dirents(dir, data1, data2, map + split, count - split,
                              blocksize);
 -      de = dx_pack_dirents(data1, blocksize);
 +      de = dx_pack_dirents(dir, data1, blocksize);
        de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) -
                                           (char *) de,
                                           blocksize);
@@@ -2022,7 -1936,7 +2021,7 @@@ int ext4_find_dest_de(struct inode *dir
                      struct ext4_dir_entry_2 **dest_de)
  {
        struct ext4_dir_entry_2 *de;
 -      unsigned short reclen = EXT4_DIR_REC_LEN(fname_len(fname));
 +      unsigned short reclen = ext4_dir_rec_len(fname_len(fname), dir);
        int nlen, rlen;
        unsigned int offset = 0;
        char *top;
                        return -EFSCORRUPTED;
                if (ext4_match(dir, fname, de))
                        return -EEXIST;
 -              nlen = EXT4_DIR_REC_LEN(de->name_len);
 +              nlen = ext4_dir_rec_len(de->name_len, dir);
                rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
                if ((de->inode ? rlen - nlen : rlen) >= reclen)
                        break;
        return 0;
  }
  
 -void ext4_insert_dentry(struct inode *inode,
 +void ext4_insert_dentry(struct inode *dir,
 +                      struct inode *inode,
                        struct ext4_dir_entry_2 *de,
                        int buf_size,
                        struct ext4_filename *fname)
  
        int nlen, rlen;
  
 -      nlen = EXT4_DIR_REC_LEN(de->name_len);
 +      nlen = ext4_dir_rec_len(de->name_len, dir);
        rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
        if (de->inode) {
                struct ext4_dir_entry_2 *de1 =
        ext4_set_de_type(inode->i_sb, de, inode->i_mode);
        de->name_len = fname_len(fname);
        memcpy(de->name, fname_name(fname), fname_len(fname));
 +      if (ext4_hash_in_dirent(dir)) {
 +              struct dx_hash_info *hinfo = &fname->hinfo;
 +
 +              EXT4_DIRENT_HASHES(de)->hash = cpu_to_le32(hinfo->hash);
 +              EXT4_DIRENT_HASHES(de)->minor_hash =
 +                                              cpu_to_le32(hinfo->minor_hash);
 +      }
  }
  
  /*
@@@ -2115,7 -2021,7 +2114,7 @@@ static int add_dirent_to_buf(handle_t *
        }
  
        /* By now the buffer is marked for journaling */
 -      ext4_insert_dentry(inode, de, blocksize, fname);
 +      ext4_insert_dentry(dir, inode, de, blocksize, fname);
  
        /*
         * XXX shouldn't update any times until successful
@@@ -2195,7 -2101,6 +2194,7 @@@ static int make_indexed_dir(handle_t *h
        data2 = bh2->b_data;
  
        memcpy(data2, de, len);
 +      memset(de, 0, len); /* wipe old data */
        de = (struct ext4_dir_entry_2 *) data2;
        top = data2 + len;
        while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top)
  
        /* Initialize the root; the dot dirents already exist */
        de = (struct ext4_dir_entry_2 *) (&root->dotdot);
 -      de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2),
 -                                         blocksize);
 +      de->rec_len = ext4_rec_len_to_disk(
 +                      blocksize - ext4_dir_rec_len(2, NULL), blocksize);
        memset (&root->info, 0, sizeof(root->info));
        root->info.info_length = sizeof(root->info);
 -      root->info.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
 +      if (ext4_hash_in_dirent(dir))
 +              root->info.hash_version = DX_HASH_SIPHASH;
 +      else
 +              root->info.hash_version =
 +                              EXT4_SB(dir->i_sb)->s_def_hash_version;
 +
        entries = root->entries;
        dx_set_block(entries, 1);
        dx_set_count(entries, 1);
        if (fname->hinfo.hash_version <= DX_HASH_TEA)
                fname->hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned;
        fname->hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
 -      ext4fs_dirhash(dir, fname_name(fname), fname_len(fname), &fname->hinfo);
 +
 +      /* casefolded encrypted hashes are computed on fname setup */
 +      if (!ext4_hash_in_dirent(dir))
 +              ext4fs_dirhash(dir, fname_name(fname),
 +                              fname_len(fname), &fname->hinfo);
  
        memset(frames, 0, sizeof(frames));
        frame = frames;
  
        retval = ext4_handle_dirty_dx_node(handle, dir, frame->bh);
        if (retval)
 -              goto out_frames;        
 +              goto out_frames;
        retval = ext4_handle_dirty_dirblock(handle, dir, bh2);
        if (retval)
 -              goto out_frames;        
 +              goto out_frames;
  
        de = do_split(handle,dir, &bh2, frame, &fname->hinfo);
        if (IS_ERR(de)) {
@@@ -2585,27 -2481,15 +2584,27 @@@ int ext4_generic_delete_entry(struct in
                                         entry_buf, buf_size, i))
                        return -EFSCORRUPTED;
                if (de == de_del)  {
 -                      if (pde)
 +                      if (pde) {
                                pde->rec_len = ext4_rec_len_to_disk(
                                        ext4_rec_len_from_disk(pde->rec_len,
                                                               blocksize) +
                                        ext4_rec_len_from_disk(de->rec_len,
                                                               blocksize),
                                        blocksize);
 -                      else
 +
 +                              /* wipe entire dir_entry */
 +                              memset(de, 0, ext4_rec_len_from_disk(de->rec_len,
 +                                                              blocksize));
 +                      } else {
 +                              /* wipe dir_entry excluding the rec_len field */
                                de->inode = 0;
 +                              memset(&de->name_len, 0,
 +                                      ext4_rec_len_from_disk(de->rec_len,
 +                                                              blocksize) -
 +                                      offsetof(struct ext4_dir_entry_2,
 +                                                              name_len));
 +                      }
 +
                        inode_inc_iversion(dir);
                        return 0;
                }
@@@ -2837,7 -2721,7 +2836,7 @@@ struct ext4_dir_entry_2 *ext4_init_dot_
  {
        de->inode = cpu_to_le32(inode->i_ino);
        de->name_len = 1;
 -      de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len),
 +      de->rec_len = ext4_rec_len_to_disk(ext4_dir_rec_len(de->name_len, NULL),
                                           blocksize);
        strcpy(de->name, ".");
        ext4_set_de_type(inode->i_sb, de, S_IFDIR);
        de->name_len = 2;
        if (!dotdot_real_len)
                de->rec_len = ext4_rec_len_to_disk(blocksize -
 -                                      (csum_size + EXT4_DIR_REC_LEN(1)),
 +                                      (csum_size + ext4_dir_rec_len(1, NULL)),
                                        blocksize);
        else
                de->rec_len = ext4_rec_len_to_disk(
 -                              EXT4_DIR_REC_LEN(de->name_len), blocksize);
 +                                      ext4_dir_rec_len(de->name_len, NULL),
 +                                      blocksize);
        strcpy(de->name, "..");
        ext4_set_de_type(inode->i_sb, de, S_IFDIR);
  
@@@ -2985,8 -2868,7 +2984,8 @@@ bool ext4_empty_dir(struct inode *inode
        }
  
        sb = inode->i_sb;
 -      if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2)) {
 +      if (inode->i_size < ext4_dir_rec_len(1, NULL) +
 +                                      ext4_dir_rec_len(2, NULL)) {
                EXT4_ERROR_INODE(inode, "invalid size");
                return true;
        }
@@@ -3489,7 -3371,7 +3488,7 @@@ static int ext4_symlink(struct user_nam
                 * for transaction commit if we are running out of space
                 * and thus we deadlock. So we have to stop transaction now
                 * and restart it when symlink contents is written.
 -               * 
 +               *
                 * To keep fs consistent in case of crash, we have to put inode
                 * to orphan list in the mean time.
                 */
@@@ -3730,31 -3612,6 +3729,31 @@@ static int ext4_setent(handle_t *handle
        return retval;
  }
  
 +static void ext4_resetent(handle_t *handle, struct ext4_renament *ent,
 +                        unsigned ino, unsigned file_type)
 +{
 +      struct ext4_renament old = *ent;
 +      int retval = 0;
 +
 +      /*
 +       * old->de could have moved from under us during make indexed dir,
 +       * so the old->de may no longer valid and need to find it again
 +       * before reset old inode info.
 +       */
 +      old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL);
 +      if (IS_ERR(old.bh))
 +              retval = PTR_ERR(old.bh);
 +      if (!old.bh)
 +              retval = -ENOENT;
 +      if (retval) {
 +              ext4_std_error(old.dir->i_sb, retval);
 +              return;
 +      }
 +
 +      ext4_setent(handle, &old, ino, file_type);
 +      brelse(old.bh);
 +}
 +
  static int ext4_find_delete_entry(handle_t *handle, struct inode *dir,
                                  const struct qstr *d_name)
  {
@@@ -3916,14 -3773,14 +3915,14 @@@ static int ext4_rename(struct user_name
         */
        retval = -ENOENT;
        if (!old.bh || le32_to_cpu(old.de->inode) != old.inode->i_ino)
 -              goto end_rename;
 +              goto release_bh;
  
        new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
                                 &new.de, &new.inlined);
        if (IS_ERR(new.bh)) {
                retval = PTR_ERR(new.bh);
                new.bh = NULL;
 -              goto end_rename;
 +              goto release_bh;
        }
        if (new.bh) {
                if (!new.inode) {
                handle = ext4_journal_start(old.dir, EXT4_HT_DIR, credits);
                if (IS_ERR(handle)) {
                        retval = PTR_ERR(handle);
 -                      handle = NULL;
 -                      goto end_rename;
 +                      goto release_bh;
                }
        } else {
                whiteout = ext4_whiteout_for_rename(mnt_userns, &old, credits, &handle);
                if (IS_ERR(whiteout)) {
                        retval = PTR_ERR(whiteout);
 -                      whiteout = NULL;
 -                      goto end_rename;
 +                      goto release_bh;
                }
        }
  
                retval = ext4_mark_inode_dirty(handle, whiteout);
                if (unlikely(retval))
                        goto end_rename;
 +
        }
        if (!new.bh) {
                retval = ext4_add_entry(handle, new.dentry, old.inode);
                        ext4_fc_track_unlink(handle, new.dentry);
                __ext4_fc_track_link(handle, old.inode, new.dentry);
                __ext4_fc_track_unlink(handle, old.inode, old.dentry);
 +              if (whiteout)
 +                      __ext4_fc_track_create(handle, whiteout, old.dentry);
        }
  
        if (new.inode) {
  end_rename:
        if (whiteout) {
                if (retval) {
 -                      ext4_setent(handle, &old,
 -                              old.inode->i_ino, old_file_type);
 +                      ext4_resetent(handle, &old,
 +                                    old.inode->i_ino, old_file_type);
                        drop_nlink(whiteout);
 +                      ext4_orphan_add(handle, whiteout);
                }
                unlock_new_inode(whiteout);
 +              ext4_journal_stop(handle);
                iput(whiteout);
 -
 +      } else {
 +              ext4_journal_stop(handle);
        }
 +release_bh:
        brelse(old.dir_bh);
        brelse(old.bh);
        brelse(new.bh);
 -      if (handle)
 -              ext4_journal_stop(handle);
        return retval;
  }
  
@@@ -4289,8 -4143,6 +4288,8 @@@ const struct inode_operations ext4_dir_
        .get_acl        = ext4_get_acl,
        .set_acl        = ext4_set_acl,
        .fiemap         = ext4_fiemap,
 +      .fileattr_get   = ext4_fileattr_get,
 +      .fileattr_set   = ext4_fileattr_set,
  };
  
  const struct inode_operations ext4_special_inode_operations = {
diff --combined fs/f2fs/namei.c
index 14bf4f65bcb33ae72f8aa620d47434e5d8dc6047,f2ad7931e9492b179b389719d0918761979838e7..377c6b161b23a9e669fee642062bcb3706a4bea2
@@@ -416,9 -416,8 +416,8 @@@ out
  
  struct dentry *f2fs_get_parent(struct dentry *child)
  {
-       struct qstr dotdot = QSTR_INIT("..", 2);
        struct page *page;
-       unsigned long ino = f2fs_inode_by_name(d_inode(child), &dotdot, &page);
+       unsigned long ino = f2fs_inode_by_name(d_inode(child), &dotdot_name, &page);
        if (!ino) {
                if (IS_ERR(page))
                        return ERR_CAST(page);
@@@ -1327,8 -1326,6 +1326,8 @@@ const struct inode_operations f2fs_dir_
        .set_acl        = f2fs_set_acl,
        .listxattr      = f2fs_listxattr,
        .fiemap         = f2fs_fiemap,
 +      .fileattr_get   = f2fs_fileattr_get,
 +      .fileattr_set   = f2fs_fileattr_set,
  };
  
  const struct inode_operations f2fs_symlink_inode_operations = {
diff --combined fs/fuse/inode.c
index 6c995201cd4d539994772c5c29e6271312756931,8665e4d2469187e33e6300b13664d4696c6c6a5c..393e36b74dc443c6f21c38ad52f612a3bc914c35
@@@ -350,7 -350,7 +350,7 @@@ retry
                inode->i_generation = generation;
                fuse_init_inode(inode, attr);
                unlock_new_inode(inode);
 -      } else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
 +      } else if (inode_wrong_type(inode, attr->mode)) {
                /* Inode has changed type, any I/O on the old should fail */
                fuse_make_bad(inode);
                iput(inode);
@@@ -712,7 -712,6 +712,7 @@@ void fuse_conn_init(struct fuse_conn *f
        fc->pid_ns = get_pid_ns(task_active_pid_ns(current));
        fc->user_ns = get_user_ns(user_ns);
        fc->max_pages = FUSE_DEFAULT_MAX_PAGES_PER_REQ;
 +      fc->max_pages_limit = FUSE_MAX_MAX_PAGES;
  
        INIT_LIST_HEAD(&fc->mounts);
        list_add(&fm->fc_entry, &fc->mounts);
@@@ -873,14 -872,13 +873,13 @@@ static struct dentry *fuse_get_parent(s
        struct inode *inode;
        struct dentry *parent;
        struct fuse_entry_out outarg;
-       const struct qstr name = QSTR_INIT("..", 2);
        int err;
  
        if (!fc->export_support)
                return ERR_PTR(-ESTALE);
  
        err = fuse_lookup_name(child_inode->i_sb, get_node_id(child_inode),
-                              &name, &outarg, &inode);
+                              &dotdot_name, &outarg, &inode);
        if (err) {
                if (err == -ENOENT)
                        return ERR_PTR(-ESTALE);
@@@ -1041,7 -1039,7 +1040,7 @@@ static void process_init_reply(struct f
                                fc->abort_err = 1;
                        if (arg->flags & FUSE_MAX_PAGES) {
                                fc->max_pages =
 -                                      min_t(unsigned int, FUSE_MAX_MAX_PAGES,
 +                                      min_t(unsigned int, fc->max_pages_limit,
                                        max_t(unsigned int, arg->max_pages, 1));
                        }
                        if (IS_ENABLED(CONFIG_FUSE_DAX) &&
                                fc->handle_killpriv_v2 = 1;
                                fm->sb->s_flags |= SB_NOSEC;
                        }
 +                      if (arg->flags & FUSE_SETXATTR_EXT)
 +                              fc->setxattr_ext = 1;
                } else {
                        ra_pages = fc->max_read / PAGE_SIZE;
                        fc->no_lock = 1;
@@@ -1098,7 -1094,7 +1097,7 @@@ void fuse_send_init(struct fuse_mount *
                FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL |
                FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS |
                FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA |
 -              FUSE_HANDLE_KILLPRIV_V2;
 +              FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT;
  #ifdef CONFIG_FUSE_DAX
        if (fm->fc->dax)
                ia->in.flags |= FUSE_MAP_ALIGNMENT;
diff --combined fs/hostfs/hostfs_kern.c
index 7b5e984ff02a79a12ef40e4e56e231760b58d730,fd04e023d91d8c95799f590d1378a9742217100c..7d0c3dbb2898206ab77c54db916c7c70f81baa09
@@@ -144,7 -144,7 +144,7 @@@ static char *follow_link(char *link
        char *name, *resolved, *end;
        int n;
  
 -      name = __getname();
 +      name = kmalloc(PATH_MAX, GFP_KERNEL);
        if (!name) {
                n = -ENOMEM;
                goto out_free;
                goto out_free;
        }
  
 -      __putname(name);
 -      kfree(link);
 +      kfree(name);
        return resolved;
  
   out_free:
 -      __putname(name);
 +      kfree(name);
        return ERR_PTR(n);
  }
  
@@@ -316,7 -317,7 +316,7 @@@ retry
        if (mode & FMODE_WRITE)
                r = w = 1;
  
-       name = dentry_name(d_real(file->f_path.dentry, file->f_inode));
+       name = dentry_name(file_dentry(file));
        if (name == NULL)
                return -ENOMEM;
  
@@@ -711,6 -712,7 +711,6 @@@ static int hostfs_mknod(struct user_nam
        if (name == NULL)
                goto out_put;
  
 -      init_special_inode(inode, mode, dev);
        err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
        if (err)
                goto out_free;
diff --combined fs/nilfs2/namei.c
index 189bd1007a2f6e7cd667878d85263a37dd3b3d75,b2709874ced5ed81f091d4e71e7698d8c207adbe..91eebeb0c48b4c8a0c464257f37d87ac4f697a5c
@@@ -440,10 -440,9 +440,9 @@@ static struct dentry *nilfs_get_parent(
  {
        unsigned long ino;
        struct inode *inode;
-       struct qstr dotdot = QSTR_INIT("..", 2);
        struct nilfs_root *root;
  
-       ino = nilfs_inode_by_name(d_inode(child), &dotdot);
+       ino = nilfs_inode_by_name(d_inode(child), &dotdot_name);
        if (!ino)
                return ERR_PTR(-ENOENT);
  
@@@ -552,8 -551,6 +551,8 @@@ const struct inode_operations nilfs_dir
        .setattr        = nilfs_setattr,
        .permission     = nilfs_permission,
        .fiemap         = nilfs_fiemap,
 +      .fileattr_get   = nilfs_fileattr_get,
 +      .fileattr_set   = nilfs_fileattr_set,
  };
  
  const struct inode_operations nilfs_special_inode_operations = {
This page took 0.114431 seconds and 4 git commands to generate.