Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/2224718/?format=api
{ "id": 2224718, "url": "http://patchwork.ozlabs.org/api/1.2/patches/2224718/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-ext4/patch/20260417213723.74204-4-artem.blagodarenko@gmail.com/", "project": { "id": 8, "url": "http://patchwork.ozlabs.org/api/1.2/projects/8/?format=api", "name": "Linux ext4 filesystem development", "link_name": "linux-ext4", "list_id": "linux-ext4.vger.kernel.org", "list_email": "linux-ext4@vger.kernel.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260417213723.74204-4-artem.blagodarenko@gmail.com>", "list_archive_url": null, "date": "2026-04-17T21:37:20", "name": "[3/3] ext4: dirdata feature", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "e987e5c906ac8043d183653a10f6e41aece73279", "submitter": { "id": 70973, "url": "http://patchwork.ozlabs.org/api/1.2/people/70973/?format=api", "name": "Artem Blagodarenko", "email": "artem.blagodarenko@gmail.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-ext4/patch/20260417213723.74204-4-artem.blagodarenko@gmail.com/mbox/", "series": [ { "id": 500406, "url": "http://patchwork.ozlabs.org/api/1.2/series/500406/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-ext4/list/?series=500406", "date": "2026-04-17T21:37:18", "name": "Data in direntry (dirdata) feature", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/500406/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2224718/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2224718/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "\n <SRS0=Q5GN=CQ=vger.kernel.org=linux-ext4+bounces-15890-patchwork-incoming=ozlabs.org@ozlabs.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "linux-ext4@vger.kernel.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "patchwork-incoming@ozlabs.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=blEsfkZ0;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=ozlabs.org\n (client-ip=150.107.74.76; helo=mail.ozlabs.org;\n envelope-from=srs0=q5gn=cq=vger.kernel.org=linux-ext4+bounces-15890-patchwork-incoming=ozlabs.org@ozlabs.org;\n receiver=patchwork.ozlabs.org)", "gandalf.ozlabs.org;\n arc=pass smtp.remote-ip=\"2600:3c15:e001:75::12fc:5321\"\n arc.chain=subspace.kernel.org", "gandalf.ozlabs.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com", "gandalf.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=blEsfkZ0;\n\tdkim-atps=neutral", "gandalf.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c15:e001:75::12fc:5321; helo=sin.lore.kernel.org;\n envelope-from=linux-ext4+bounces-15890-patchwork-incoming=ozlabs.org@vger.kernel.org;\n receiver=ozlabs.org)", "smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=\"blEsfkZ0\"", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.128.45", "smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com", "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=gmail.com" ], "Received": [ "from mail.ozlabs.org (gandalf.ozlabs.org [150.107.74.76])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1 raw public key)\n server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fy7XP3tRtz1yDF\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 18 Apr 2026 07:37:57 +1000 (AEST)", "from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3])\n\tby gandalf.ozlabs.org (Postfix) with ESMTP id 4fy7XP3hNpz4wKC\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 18 Apr 2026 07:37:57 +1000 (AEST)", "by gandalf.ozlabs.org (Postfix)\n\tid 4fy7XP3bqmz4wJs; Sat, 18 Apr 2026 07:37:57 +1000 (AEST)", "from sin.lore.kernel.org (sin.lore.kernel.org\n [IPv6:2600:3c15:e001:75::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby gandalf.ozlabs.org (Postfix) with ESMTPS id 4fy7XK6yJcz4wKS\n\tfor <patchwork-incoming@ozlabs.org>; Sat, 18 Apr 2026 07:37:53 +1000 (AEST)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sin.lore.kernel.org (Postfix) with ESMTP id 29CB5301666A\n\tfor <patchwork-incoming@ozlabs.org>; Fri, 17 Apr 2026 21:37:46 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id CE83930EF64;\n\tFri, 17 Apr 2026 21:37:43 +0000 (UTC)", "from mail-wm1-f45.google.com (mail-wm1-f45.google.com\n [209.85.128.45])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 52FFA37CD2F\n\tfor <linux-ext4@vger.kernel.org>; Fri, 17 Apr 2026 21:37:41 +0000 (UTC)", "by mail-wm1-f45.google.com with SMTP id\n 5b1f17b1804b1-4887fd35e60so7306685e9.2\n for <linux-ext4@vger.kernel.org>;\n Fri, 17 Apr 2026 14:37:41 -0700 (PDT)", "from localhost.localdomain\n ([2a00:23c7:90c1:9201:f5b4:1568:453c:b849])\n by smtp.gmail.com with ESMTPSA id\n 5b1f17b1804b1-488fb762f56sm25725645e9.15.2026.04.17.14.37.38\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Fri, 17 Apr 2026 14:37:38 -0700 (PDT)" ], "ARC-Seal": [ "i=2; a=rsa-sha256; d=ozlabs.org; s=201707; t=1776461877; cv=pass;\n\tb=e5GXFTCCyeyPrHqpcUcyxRHPxpVPzrj1XO/1kBN46DMS0ovhfUNV6pyC576nb5zS07C/XheTNdoGQ/pKu9k5ZP/oLCVEonX0K7clV+GHvTz90xh+W+K6wXaqNyJl9dIYcfywv3LWpDJl5nK+IzUXZi3xGbjvqT8XCv1T+Bvvo1omD8R03XZ8EVhAYgbBkxRKErsLRLCHdTOjsrItFST1VaPSzet5sn2fWrBbQn3sCdFl/S0MY6LuplsEgfk4uhHCTJzYhoREkgYbQ3ueb54bXmic8MSRdNGIwqBVWPzDSm+d2lwuwkbFEF4Mg/W1y61wo4Ob1M9QzSxLa+9y79fLPQ==", "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1776461863; cv=none;\n b=CJGQywkxI2Ec24vp8UpKweHtMinVpRvsnMaap/LAEdcnF+VAVPYQUV/092i5Ud9aFUGuLuW4g2LVoowAg+DxNtcXxQbocCP1BwJDuEow7j746UdG4/o9+Yb9nOgg7gelaBPn8IDcyk1aB85PR8LCPha0NkHrhVeisC08AJ6FNrg=" ], "ARC-Message-Signature": [ "i=2; a=rsa-sha256; d=ozlabs.org; s=201707;\n\tt=1776461877; c=relaxed/relaxed;\n\tbh=81rBFMMXVe/MdUhbExIXCzmGWZB3MRuXFLnT+ibcJhc=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=U5IUyoGP67UjK2JWcvt6WkhiSJ3UYfTQZ0LMGDqJNzlckYwYPQuMLF0WCzXCBcP1pTsb/j8lVOafZi3J2UgKdGYoehrKxqAEX7tnFatQOIAJ6I5JpUUjTR18Zty9gX4bn+GvUTFfq92xEx1+iew7Y2wXnnGAd1w1qPh7tU9qps8xq2SRxd23AxGpdNbfi10EexcI1SzhId/1OlqWVFp10QLS0d7M8gXjBmKobOpRdFfUas404RIKupF1S36da2p1OQ4eURHvuZAlPyqGyI+QYRsZjIHuxB6BHM2qhH5C0+fX4AKuhqtL7B7tVeVfWNVbhSBMVKGMb0pvMFLJJrmWWw==", "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1776461863; c=relaxed/simple;\n\tbh=gEm4GekL+CeEFYSr4ZYmEllAm+8MnwLP+JusDakRilY=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=VSOG9zVNJLZ+YLgtxoQPMhwqf0JxIiaez3Cnyx1/c/DizzDQ+lz/BDOQ8OrqNjn+GrAme/9L+mkXMBpH1YSa0k5S3XQSgITlUbDZdplfpd97UfqZCpi2H4LJ7Nd9AXLXjrnYb51MBygJvxq5qb6X4806BphEBmPWh3xD+qyXNPE=" ], "ARC-Authentication-Results": [ "i=2; gandalf.ozlabs.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com; dkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=blEsfkZ0; dkim-atps=neutral;\n spf=pass (client-ip=2600:3c15:e001:75::12fc:5321; helo=sin.lore.kernel.org;\n envelope-from=linux-ext4+bounces-15890-patchwork-incoming=ozlabs.org@vger.kernel.org;\n receiver=ozlabs.org) smtp.mailfrom=vger.kernel.org", "i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com;\n spf=pass smtp.mailfrom=gmail.com;\n dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=blEsfkZ0; arc=none smtp.client-ip=209.85.128.45" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1776461859; x=1777066659;\n darn=vger.kernel.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=81rBFMMXVe/MdUhbExIXCzmGWZB3MRuXFLnT+ibcJhc=;\n b=blEsfkZ0y9XhBWlXznanvI1LJAU920GfDCdTpgAlgZYfRH3NIgpqvwOCjgKXNEGJOq\n zqLrup7Jryg7GQAtWtXC5DAZ5iOQwMR6UCDH7sqP3aQ4dz41HQ4kVVjzqCe/ZP8xtyth\n S/eeac0wXWFYAmwDyixorffBSReK6Sxy8EJ2bErxUKc/EL63T5RmUxPhEP6oO1C5QBM3\n InCLWfdOpnStXqogllzFWwVfFOvB3vNgNV5f9X4L+Mo+0HS2qsatEqbDztks+gy8zX46\n ePBBmLBgGew1UhoSssRNdywYYP0CHfHjoqLwXL9ZrxppYZuDbfTDbzQ/d/hwghVTiVWV\n 4bCw==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1776461859; x=1777066659;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=81rBFMMXVe/MdUhbExIXCzmGWZB3MRuXFLnT+ibcJhc=;\n b=dm9qq5rG7t8LYRJ+QlPjYG6UVoGDpdbc+96pR5+GgSWzRVRKXr1mguhdkXmOPAttMO\n VNadaHlmEdCFRmIn0KKkfMmoQuxKovFuLbqMgWtUe4hZID9YHWiSPj6+2PZ909XDdHlr\n 1eS2b4d8X0RsCF5V48NtGd6OwsQPFvmXXwjG7RlfK2DJIAdX3iZWN6VJido13ymlYCIo\n enstlxtqqhU6tPMm5A3JRn2uiUjCSQ6jGTWipQxFhlrhOTapw6QHC5qIkY311ER/ftF+\n aole2Zk1oxjNL3ArVpfM0sU9ZzQfA6pxFCeDAVs/j3j/i9TIRdgpqeEdHjozezsGMbjZ\n f5sw==", "X-Gm-Message-State": "AOJu0Yz6ABeKAn8jompHr0+Ie39/j5VuuJh1eHRIxUoTmo2Z4j9snk2S\n\tH44Y/u5t6y2tKVqISQSrXHiWcrG2Kub2TKndAbRnQ8SJMQ5Gt7SpFqyigU7lWg==", "X-Gm-Gg": "AeBDietI1MdQdtXhakNIPLrepq1F+hYjDPG5TE+ljSIb3zxKTdYDr+EQir1S/9WyiGT\n\tiurGkYD2aX4XFY8ZaItbuTWdv9yolWCD/BuP95ey35E27EFxQlyRJS2iox3BJscdFBSzk9i/KVu\n\t6KN8XJW/to7F2yelSaAX45DFHCqvW57iM0nNvnETuYuPirQook3V6zPGhy1E5Xfpl3vsqjl87K1\n\tOfjQKBS3DvpRxHEkj1tm/m6XrggZsuTiwVxPcc2eqKBe9XXz8x5c0qJPaZyrp7gfvVGI3Isnlot\n\tBkQnAgmO4PYfCbLvWpAiRKfrWiyE8MeIiYFnQSIUSkHA4UjS1uMYsf3wjJk6F08BS1Axv/H2Hkb\n\tA6LealZppR8yAUOaGhbBOFp6AXC96jADPCIjU8q9YagFw9wI/AukiJsbvxWah8E7S36TkREYDIl\n\trD9rxl7Z1PZTM5MTkRmwWF2mjgRHvJ7heZWjT5iRo803ce1XiUbVxo3HjWKEZtRmlLEBSbaxu1r\n\tBIvKL80VX2rTslpDwqlV8g=", "X-Received": "by 2002:a05:600c:890c:b0:485:3ff1:d5ed with SMTP id\n 5b1f17b1804b1-488fb739cd9mr49005835e9.1.1776461859263;\n Fri, 17 Apr 2026 14:37:39 -0700 (PDT)", "From": "Artem Blagodarenko <artem.blagodarenko@gmail.com>", "To": "linux-ext4@vger.kernel.org", "Cc": "adilger.kernel@dilger.ca,\n\tArtem Blagodarenko <artem.blagodarenko@gmail.com>,\n\tPravin Shelar <pravin.shelar@sun.com>,\n\tAndreas Dilger <adilger@dilger.ca>", "Subject": "[PATCH 3/3] ext4: dirdata feature", "Date": "Fri, 17 Apr 2026 22:37:20 +0100", "Message-ID": "<20260417213723.74204-4-artem.blagodarenko@gmail.com>", "X-Mailer": "git-send-email 2.52.0", "In-Reply-To": "<20260417213723.74204-1-artem.blagodarenko@gmail.com>", "References": "<20260417213723.74204-1-artem.blagodarenko@gmail.com>", "Precedence": "bulk", "X-Mailing-List": "linux-ext4@vger.kernel.org", "List-Id": "<linux-ext4.vger.kernel.org>", "List-Subscribe": "<mailto:linux-ext4+subscribe@vger.kernel.org>", "List-Unsubscribe": "<mailto:linux-ext4+unsubscribe@vger.kernel.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "X-Spam-Status": "No, score=-1.2 required=5.0 tests=ARC_SIGNED,ARC_VALID,\n\tDKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DMARC_PASS,\n\tFREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,\n\tMAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=disabled\n\tversion=4.0.1", "X-Spam-Checker-Version": "SpamAssassin 4.0.1 (2024-03-25) on gandalf.ozlabs.org" }, "content": "When fscrypt and casefold are enabled together for a directory,\nall ext4_dir_entry[_2] in that directory store a n 8-byte hash\nof the filename after 'name' between 'name_len' and 'rec_len'.\n\nHowever, there is no clear indication there is important data\nstored in these bytes, which are only for padding and alignment\nin other directory entries. This adds complexity to code handling\nthe on-disk directory entries, and there is no provision for other\nmetadata to be stored in each dir entry after 'name'.\n\nThe dirdata feature adds a mechanism to store multiple metadata\nentries in each dir entry after 'name' (including the fchash).\nThe unused high 4 bits of 'file_type' are used to indicate whether\nadditional data fields are stored after 'name'. If a bit is set,\nthe corresponding dirdata record is present, starting after a NUL\nfilename terminator. If present, a record starts with a 1-byte\nlength (including the length byte itself) and the data immediately\nfollows the length byte without any alignment.\n\nThis allows up to four different dirdata records to be stored in\neach entry, and allows unhandled record bytes to be skipped without\nhaving to process the contents, providing forward compatibility.\n\nIf and when the fourth and last dirdata record is needed, it is\nrecommended to further subdivide it into sub-records, with\nthe first byte being the total length, and then there being a\nsecond byte that gives the sub-record length, etc. as long as\nthe total record length is less than 255 bytes. However, this\nwould not affect compatibility with the current code since the\nrecord length would allow it to be skipped without processing.\n\nSigned-off-by: Pravin Shelar <pravin.shelar@sun.com>\nSigned-off-by: Artem Blagodarenko <artem.blagodarenko@gmail.com>\nReviewed-by: Andreas Dilger <adilger@dilger.ca>\n---\n fs/ext4/dir.c | 9 +-\n fs/ext4/ext4.h | 50 +++++++++---\n fs/ext4/inline.c | 22 ++---\n fs/ext4/namei.c | 208 ++++++++++++++++++++++++++++++++++++-----------\n fs/ext4/super.c | 4 +-\n fs/ext4/sysfs.c | 2 +\n 6 files changed, 219 insertions(+), 76 deletions(-)", "diff": "diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c\nindex 28b2a3deb954..08833524e499 100644\n--- a/fs/ext4/dir.c\n+++ b/fs/ext4/dir.c\n@@ -89,16 +89,15 @@ int __ext4_check_dir_entry(const char *function, unsigned int line,\n \tbool fake = is_fake_dir_entry(de);\n \tbool has_csum = ext4_has_feature_metadata_csum(dir->i_sb);\n \n-\tif (unlikely(rlen < ext4_dir_rec_len(1, fake ? NULL : dir)))\n+\tif (unlikely(rlen < ext4_dirent_rec_len(1, fake ? NULL : dir)))\n \t\terror_msg = \"rec_len is smaller than minimal\";\n \telse if (unlikely(rlen % 4 != 0))\n \t\terror_msg = \"rec_len % 4 != 0\";\n-\telse if (unlikely(rlen < ext4_dir_rec_len(de->name_len,\n-\t\t\t\t\t\t\tfake ? NULL : dir)))\n+\telse if (unlikely(rlen < ext4_dir_entry_len(de, fake ? NULL : dir)))\n \t\terror_msg = \"rec_len is too small for name_len\";\n \telse if (unlikely(next_offset > size))\n \t\terror_msg = \"directory entry overrun\";\n-\telse if (unlikely(next_offset > size - ext4_dir_rec_len(1,\n+\telse if (unlikely(next_offset > size - ext4_dirent_rec_len(1,\n \t\t\t\t\t\t has_csum ? NULL : dir) &&\n \t\t\t next_offset != size))\n \t\terror_msg = \"directory entry too close to block end\";\n@@ -245,7 +244,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)\n \t\t\t\t * failure will be detected in the\n \t\t\t\t * dirent test below. */\n \t\t\t\tif (ext4_rec_len_from_disk(de->rec_len,\n-\t\t\t\t\tsb->s_blocksize) < ext4_dir_rec_len(1,\n+\t\t\t\t\tsb->s_blocksize) < ext4_dirent_rec_len(1,\n \t\t\t\t\t\t\t\t\tinode))\n \t\t\t\t\tbreak;\n \t\t\t\ti += ext4_rec_len_from_disk(de->rec_len,\ndiff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h\nindex 09d277e24dde..28271d42bfaf 100644\n--- a/fs/ext4/ext4.h\n+++ b/fs/ext4/ext4.h\n@@ -1217,6 +1217,7 @@ struct ext4_inode_info {\n * Mount flags set via mount options or defaults\n */\n #define EXT4_MOUNT_NO_MBCACHE\t\t0x00001 /* Do not use mbcache */\n+#define EXT4_MOUNT_DIRDATA\t\t0x00002 /* Data in directory entries */\n #define EXT4_MOUNT_GRPID\t\t0x00004\t/* Create files with directory's group */\n #define EXT4_MOUNT_DEBUG\t\t0x00008\t/* Some debugging messages */\n #define EXT4_MOUNT_ERRORS_CONT\t\t0x00010\t/* Continue on errors */\n@@ -2253,6 +2254,7 @@ EXT4_FEATURE_INCOMPAT_FUNCS(casefold,\t\tCASEFOLD)\n \t\t\t\t\t EXT4_FEATURE_INCOMPAT_INLINE_DATA | \\\n \t\t\t\t\t EXT4_FEATURE_INCOMPAT_ENCRYPT | \\\n \t\t\t\t\t EXT4_FEATURE_INCOMPAT_CASEFOLD | \\\n+\t\t\t\t\t EXT4_FEATURE_INCOMPAT_DIRDATA | \\\n \t\t\t\t\t EXT4_FEATURE_INCOMPAT_CSUM_SEED | \\\n \t\t\t\t\t EXT4_FEATURE_INCOMPAT_LARGEDIR)\n #define EXT4_FEATURE_RO_COMPAT_SUPP\t(EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \\\n@@ -2937,11 +2939,20 @@ extern void ext4_htree_free_dir_info(struct dir_private_info *p);\n extern int ext4_find_dest_de(struct inode *dir, struct buffer_head *bh,\n \t\t\t void *buf, int buf_size,\n \t\t\t struct ext4_filename *fname,\n-\t\t\t struct ext4_dir_entry_2 **dest_de);\n-void ext4_insert_dentry(struct inode *dir, struct inode *inode,\n-\t\t\tstruct ext4_dir_entry_2 *de,\n-\t\t\tint buf_size,\n-\t\t\tstruct ext4_filename *fname);\n+\t\t\t struct ext4_dir_entry_2 **dest_de,\n+\t\t\t int dlen);\n+void ext4_insert_dentry_data(struct inode *dir, struct inode *inode,\n+\t\t\t struct ext4_dir_entry_2 *de,\n+\t\t\t int buf_size,\n+\t\t\t struct ext4_filename *fname,\n+\t\t\t void *data);\n+static inline void ext4_insert_dentry(struct inode *dir, struct inode *inode,\n+\t\t\t\t struct ext4_dir_entry_2 *de,\n+\t\t\t\t int buf_size,\n+\t\t\t\t struct ext4_filename *fname)\n+{\n+\text4_insert_dentry_data(dir, inode, de, buf_size, fname, NULL);\n+}\n static inline void ext4_update_dx_flag(struct inode *inode)\n {\n \tif (!ext4_has_feature_dir_index(inode->i_sb) &&\n@@ -2955,9 +2966,9 @@ static const unsigned char ext4_filetype_table[] = {\n \tDT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK\n };\n \n-static inline unsigned char get_dtype(struct super_block *sb, int filetype)\n+static inline unsigned char get_dtype(struct super_block *sb, int filetype)\n {\n-\tunsigned char fl_index = filetype & EXT4_FT_MASK;\n+\tunsigned char fl_index = filetype & EXT4_FT_MASK;\n \n \tif (!ext4_has_feature_filetype(sb) || fl_index >= EXT4_FT_MAX)\n \t\treturn DT_UNKNOWN;\n@@ -3186,8 +3197,17 @@ extern int ext4_ext_migrate(struct inode *);\n extern int ext4_ind_migrate(struct inode *inode);\n \n /* namei.c */\n-extern int ext4_init_new_dir(handle_t *handle, struct inode *dir,\n-\t\t\t struct inode *inode);\n+extern int ext4_init_new_dir_data(handle_t *handle, struct inode *dir,\n+\t\t\t\t struct inode *inode,\n+\t\t\t\t const void *data1, const void *data2);\n+static inline int ext4_init_new_dir(handle_t *handle, struct inode *dir,\n+\t\t\t\t struct inode *inode)\n+{\n+\treturn ext4_init_new_dir_data(handle, dir, inode, NULL, NULL);\n+}\n+extern int ext4_add_dot_dotdot(handle_t *handle, struct inode *dir,\n+\t\t\t struct inode *inode,\n+\t\t\t const void *data1, const void *data2);\n extern int ext4_dirblock_csum_verify(struct inode *inode,\n \t\t\t\t struct buffer_head *bh);\n extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,\n@@ -3762,6 +3782,9 @@ extern int __ext4_unlink(struct inode *dir, const struct qstr *d_name,\n \t\t\t struct inode *inode, struct dentry *dentry);\n extern int __ext4_link(struct inode *dir, struct inode *inode,\n \t\t struct dentry *dentry);\n+extern unsigned char ext4_dirdata_get(struct ext4_dir_entry_2 *de,\n+\t\t\t\t struct inode *dir,\n+\t\t\t\t void *data, u32 *hash, u32 *minor_hash);\n \n #define S_SHIFT 12\n static const unsigned char ext4_type_by_mode[(S_IFMT >> S_SHIFT) + 1] = {\n@@ -4007,7 +4030,14 @@ static inline int ext4_dirent_get_data_len(struct ext4_dir_entry_2 *de)\n \n \twhile (extra_data_flags) {\n \t\tif (extra_data_flags & 1) {\n-\t\t\tdlen += ddh->ddh_length + (dlen == 0);\n+\t\t\t/*\n+\t\t\t * The first dirdata field is preceded by a NUL\n+\t\t\t * terminator byte that is already included in ddh's\n+\t\t\t * pointer offset, but must be counted in dlen.\n+\t\t\t */\n+\t\t\tif (dlen == 0)\n+\t\t\t\tdlen = 1; /* NUL terminator */\n+\t\t\tdlen += ddh->ddh_length;\n \t\t\tddh = ext4_dirdata_next(ddh);\n \t\t}\n \t\textra_data_flags >>= 1;\ndiff --git a/fs/ext4/inline.c b/fs/ext4/inline.c\nindex 1f6bc05593df..071a637c8869 100644\n--- a/fs/ext4/inline.c\n+++ b/fs/ext4/inline.c\n@@ -969,7 +969,7 @@ static int ext4_add_dirent_to_inline(handle_t *handle,\n \tstruct ext4_dir_entry_2 *de;\n \n \terr = ext4_find_dest_de(dir, iloc->bh, inline_start,\n-\t\t\t\tinline_size, fname, &de);\n+\t\t\t\tinline_size, fname, &de, 0);\n \tif (err)\n \t\treturn err;\n \n@@ -978,7 +978,7 @@ static int ext4_add_dirent_to_inline(handle_t *handle,\n \t\t\t\t\t EXT4_JTR_NONE);\n \tif (err)\n \t\treturn err;\n-\text4_insert_dentry(dir, inode, de, inline_size, fname);\n+\text4_insert_dentry_data(dir, inode, de, inline_size, fname, NULL);\n \n \text4_show_inline_dir(dir, iloc->bh, inline_start, inline_size);\n \n@@ -1047,7 +1047,7 @@ static int ext4_update_inline_dir(handle_t *handle, struct inode *dir,\n \tint old_size = EXT4_I(dir)->i_inline_size - EXT4_MIN_INLINE_DATA_SIZE;\n \tint new_size = get_max_inline_xattr_value_size(dir, iloc);\n \n-\tif (new_size - old_size <= ext4_dir_rec_len(1, NULL))\n+\tif (new_size - old_size <= ext4_dirent_rec_len(1, NULL))\n \t\treturn -ENOSPC;\n \n \tret = ext4_update_inline_data(handle, dir,\n@@ -1301,7 +1301,7 @@ int ext4_inlinedir_to_tree(struct file *dir_file,\n \t\t\tfake.name_len = 1;\n \t\t\tmemcpy(fake.name, \".\", 2);\n \t\t\tfake.rec_len = ext4_rec_len_to_disk(\n-\t\t\t\t\t ext4_dir_rec_len(fake.name_len, NULL),\n+\t\t\t\t\t ext4_dirent_rec_len(fake.name_len, NULL),\n \t\t\t\t\t inline_size);\n \t\t\text4_set_de_type(inode->i_sb, &fake, S_IFDIR);\n \t\t\tde = &fake;\n@@ -1311,7 +1311,7 @@ int ext4_inlinedir_to_tree(struct file *dir_file,\n \t\t\tfake.name_len = 2;\n \t\t\tmemcpy(fake.name, \"..\", 3);\n \t\t\tfake.rec_len = ext4_rec_len_to_disk(\n-\t\t\t\t\t ext4_dir_rec_len(fake.name_len, NULL),\n+\t\t\t\t\t ext4_dirent_rec_len(fake.name_len, NULL),\n \t\t\t\t\t inline_size);\n \t\t\text4_set_de_type(inode->i_sb, &fake, S_IFDIR);\n \t\t\tde = &fake;\n@@ -1327,9 +1327,9 @@ int ext4_inlinedir_to_tree(struct file *dir_file,\n \t\t\t}\n \t\t}\n \n-\t\tif (ext4_hash_in_dirent(dir)) {\n-\t\t\thinfo->hash = EXT4_DIRENT_HASH(de);\n-\t\t\thinfo->minor_hash = EXT4_DIRENT_MINOR_HASH(de);\n+\t\tif (ext4_dirdata_get(de, dir, NULL, &hinfo->hash,\n+\t\t\t\t &hinfo->minor_hash) & EXT4_DIRENT_CFHASH) {\n+\t\t\t/* hash retrieved from dirdata or inline hash */\n \t\t} else {\n \t\t\terr = ext4fs_dirhash(dir, de->name, de->name_len, hinfo);\n \t\t\tif (err) {\n@@ -1419,8 +1419,8 @@ int ext4_read_inline_dir(struct file *file,\n \t * So we will use extra_offset and extra_size to indicate them\n \t * during the inline dir iteration.\n \t */\n-\tdotdot_offset = ext4_dir_rec_len(1, NULL);\n-\tdotdot_size = dotdot_offset + ext4_dir_rec_len(2, NULL);\n+\tdotdot_offset = ext4_dirent_rec_len(1, NULL);\n+\tdotdot_size = dotdot_offset + ext4_dirent_rec_len(2, NULL);\n \textra_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE;\n \textra_size = extra_offset + inline_size;\n \n@@ -1455,7 +1455,7 @@ int ext4_read_inline_dir(struct file *file,\n \t\t\t * failure will be detected in the\n \t\t\t * dirent test below. */\n \t\t\tif (ext4_rec_len_from_disk(de->rec_len, extra_size)\n-\t\t\t\t< ext4_dir_rec_len(1, NULL))\n+\t\t\t\t< ext4_dirent_rec_len(1, NULL))\n \t\t\t\tbreak;\n \t\t\ti += ext4_rec_len_from_disk(de->rec_len,\n \t\t\t\t\t\t extra_size);\ndiff --git a/fs/ext4/namei.c b/fs/ext4/namei.c\nindex ab2b4bb4a93d..3d478d7ef339 100644\n--- a/fs/ext4/namei.c\n+++ b/fs/ext4/namei.c\n@@ -305,7 +305,6 @@ static struct ext4_dir_entry_tail *get_dirent_tail(struct inode *inode,\n \t\t\t\t\t\t struct buffer_head *bh)\n {\n \tstruct ext4_dir_entry_tail *t;\n-\tint blocksize = EXT4_BLOCK_SIZE(inode->i_sb);\n \n #ifdef PARANOID\n \tstruct ext4_dir_entry *d, *top;\n@@ -402,23 +401,24 @@ static struct dx_countlimit *get_dx_countlimit(struct inode *inode,\n {\n \tstruct ext4_dir_entry_2 *de;\n \tstruct dx_root_info *root;\n-\tint count_offset;\n+\tint count_offset, dot_rec_len, dotdot_rec_len;\n \tint blocksize = EXT4_BLOCK_SIZE(inode->i_sb);\n \tunsigned int rlen = ext4_rec_len_from_disk(dirent->rec_len, blocksize);\n \n-\tif (rlen == blocksize)\n+\tif (rlen == blocksize) {\n \t\tcount_offset = 8;\n-\telse if (rlen == 12) {\n-\t\tde = (struct ext4_dir_entry_2 *)(((void *)dirent) + 12);\n-\t\tif (ext4_rec_len_from_disk(de->rec_len, blocksize) != blocksize - 12)\n+\t} else {\n+\t\tdot_rec_len = le16_to_cpu(dirent->rec_len);\n+\t\tde = (struct ext4_dir_entry_2 *)(((char *)dirent) + dot_rec_len);\n+\t\tif (le16_to_cpu(de->rec_len) != (blocksize - dot_rec_len))\n \t\t\treturn NULL;\n-\t\troot = (struct dx_root_info *)(((void *)de + 12));\n+\t\tdotdot_rec_len = ext4_dir_entry_len((struct ext4_dir_entry_2 *)de, NULL);\n+\t\troot = (struct dx_root_info *)(((char *)de + dotdot_rec_len));\n \t\tif (root->reserved_zero ||\n \t\t root->info_length != sizeof(struct dx_root_info))\n \t\t\treturn NULL;\n-\t\tcount_offset = 32;\n-\t} else\n-\t\treturn NULL;\n+\t\tcount_offset = 8 + dot_rec_len + dotdot_rec_len;\n+\t}\n \n \tif (offset)\n \t\t*offset = count_offset;\n@@ -590,7 +590,7 @@ static inline unsigned dx_root_limit(struct inode *dir,\n static inline unsigned dx_node_limit(struct inode *dir)\n {\n \tunsigned int entry_space = dir->i_sb->s_blocksize -\n-\t\t\text4_dir_rec_len(0, dir);\n+\t\t\text4_dirent_rec_len(0, dir);\n \n \tif (ext4_has_feature_metadata_csum(dir->i_sb))\n \t\tentry_space -= sizeof(struct dx_tail);\n@@ -700,7 +700,7 @@ static struct stats dx_show_leaf(struct inode *dir,\n \t\t\t\t (unsigned) ((char *) de - base));\n #endif\n \t\t\t}\n-\t\t\tspace += ext4_dir_rec_len(de->name_len, dir);\n+\t\t\tspace += ext4_dir_entry_len(de, dir);\n \t\t\tnames++;\n \t\t}\n \t\tde = ext4_next_entry(de, size);\n@@ -1062,7 +1062,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,\n \t/* csum entries are not larger in the casefolded encrypted case */\n \ttop = (struct ext4_dir_entry_2 *) ((char *) de +\n \t\t\t\t\t dir->i_sb->s_blocksize -\n-\t\t\t\t\t ext4_dir_rec_len(0,\n+\t\t\t\t\t ext4_dirent_rec_len(0,\n \t\t\t\t\t\t\t csum ? NULL : dir));\n \t/* Check if the directory is encrypted */\n \tif (IS_ENCRYPTED(dir)) {\n@@ -1087,21 +1087,20 @@ static int htree_dirblock_to_tree(struct file *dir_file,\n \t\t\t/* silently ignore the rest of the block */\n \t\t\tbreak;\n \t\t}\n-\t\tif (ext4_hash_in_dirent(dir)) {\n-\t\t\tif (de->name_len && de->inode) {\n-\t\t\t\thinfo->hash = EXT4_DIRENT_HASH(de);\n-\t\t\t\thinfo->minor_hash = EXT4_DIRENT_MINOR_HASH(de);\n-\t\t\t} else {\n-\t\t\t\thinfo->hash = 0;\n-\t\t\t\thinfo->minor_hash = 0;\n-\t\t\t}\n-\t\t} else {\n+\t\tif (de->name_len && de->inode &&\n+\t\t (ext4_dirdata_get(de, dir, NULL, &hinfo->hash,\n+\t\t\t\t &hinfo->minor_hash) & EXT4_DIRENT_CFHASH)) {\n+\t\t\t/* hash retrieved from dirdata or inline hash */\n+\t\t} else if (de->name_len && de->inode) {\n \t\t\terr = ext4fs_dirhash(dir, de->name,\n \t\t\t\t\t de->name_len, hinfo);\n \t\t\tif (err < 0) {\n \t\t\t\tcount = err;\n \t\t\t\tgoto errout;\n \t\t\t}\n+\t\t} else {\n+\t\t\thinfo->hash = 0;\n+\t\t\thinfo->minor_hash = 0;\n \t\t}\n \t\tif ((hinfo->hash < start_hash) ||\n \t\t ((hinfo->hash == start_hash) &&\n@@ -1280,9 +1279,95 @@ static inline int search_dirblock(struct buffer_head *bh,\n */\n \n /*\n- * Create map of hash values, offsets, and sizes, stored at end of block.\n- * Returns number of entries mapped.\n+ * ext4_dirdata_get() - Read dirdata fields from a directory entry.\n+ * @de: directory entry\n+ * @dir: directory inode (used for fscrypt+casefold hash fallback)\n+ * @data: if non-NULL and EXT4_DIRENT_LUFID is set, LUFID data is copied here\n+ * @hash: if non-NULL, receives the casefold hash\n+ * @minor_hash: if non-NULL, receives the casefold minor hash\n+ *\n+ * Reads any dirdata stored in @de. If the dirdata feature is not enabled,\n+ * falls back to reading the hash stored inline after the filename (for\n+ * compatibility with the older casefold+fscrypt format).\n+ *\n+ * Returns a bitmask of EXT4_DIRENT_* flags indicating which fields were read.\n+ */\n+unsigned char ext4_dirdata_get(struct ext4_dir_entry_2 *de, struct inode *dir,\n+\t\t\t void *data, u32 *hash, u32 *minor_hash)\n+{\n+\tunsigned char ret = 0;\n+\tint data_offset = de->name_len + 1;\n+\n+\t/* compatibility: hash stored inline after filename (no dirdata) */\n+\tif (!ext4_has_feature_dirdata(dir->i_sb) && ext4_hash_in_dirent(dir)) {\n+\t\t*hash = EXT4_DIRENT_HASH(de);\n+\t\t*minor_hash = EXT4_DIRENT_MINOR_HASH(de);\n+\t\tret |= EXT4_DIRENT_CFHASH;\n+\t\treturn ret;\n+\t}\n+\n+\t/* EXT4_DIRENT_* are not expected without flag in i_sb */\n+\tif (de->file_type & EXT4_DIRENT_LUFID) {\n+\t\tif (data) {\n+\t\t\tmemcpy(data, de->name + de->name_len + 1 + 1,\n+\t\t\t de->name[de->name_len + 1]);\n+\t\t\tret |= EXT4_DIRENT_LUFID;\n+\t\t}\n+\t\tdata_offset += de->name[data_offset] + 1;\n+\t}\n+\n+\tif (!hash || !minor_hash)\n+\t\treturn ret;\n+\n+\tif (de->file_type & EXT4_DIRENT_CFHASH) {\n+\t\tstruct ext4_dirent_hash *dh =\n+\t\t\t(struct ext4_dirent_hash *)(de->name + data_offset);\n+\n+\t\t*hash = le32_to_cpu(dh->dh_hash.hash);\n+\t\t*minor_hash = le32_to_cpu(dh->dh_hash.minor_hash);\n+\t\tret |= EXT4_DIRENT_CFHASH;\n+\t\treturn ret;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+/*\n+ * ext4_dirdata_set() - Write dirdata fields into a directory entry.\n+ * @de: directory entry (name must already be set)\n+ * @dir: directory inode\n+ * @data: LUFID data to store (or NULL)\n+ * @fname: filename info carrying the casefold hash\n+ *\n+ * Writes any required dirdata into @de after the filename. If the dirdata\n+ * feature is not enabled, falls back to writing the hash inline after the\n+ * filename (for compatibility with the older casefold+fscrypt format).\n */\n+static void ext4_dirdata_set(struct ext4_dir_entry_2 *de, struct inode *dir,\n+\t\t\t void *data, struct ext4_filename *fname)\n+{\n+\tint data_offset = de->name_len + 1;\n+\n+\tif (data) {\n+\t\tde->name[de->name_len] = 0;\n+\t\tmemcpy(&de->name[de->name_len + 1], data, *(char *)data);\n+\t\tde->file_type |= EXT4_DIRENT_LUFID;\n+\t\tdata_offset += *(char *)data + 1;\n+\t}\n+\n+\tif (ext4_hash_in_dirent(dir)) {\n+\t\tstruct ext4_dirent_hash *dh =\n+\t\t\t(struct ext4_dirent_hash *)(de->name + data_offset);\n+\t\tstruct dx_hash_info *hinfo = &fname->hinfo;\n+\n+\t\tdh->dh_header.ddh_length = sizeof(*dh);\n+\t\tdh->dh_hash.hash = cpu_to_le32(hinfo->hash);\n+\t\tdh->dh_hash.minor_hash = cpu_to_le32(hinfo->minor_hash);\n+\t\tde->file_type |= EXT4_DIRENT_CFHASH;\n+\t}\n+}\n+\n+\n static int dx_make_map(struct inode *dir, struct buffer_head *bh,\n \t\t struct dx_hash_info *hinfo,\n \t\t struct dx_map_entry *map_tail)\n@@ -1302,9 +1387,9 @@ static int dx_make_map(struct inode *dir, struct buffer_head *bh,\n \t\t\t\t\t ((char *)de) - base))\n \t\t\treturn -EFSCORRUPTED;\n \t\tif (de->name_len && de->inode) {\n-\t\t\tif (ext4_hash_in_dirent(dir))\n-\t\t\t\th.hash = EXT4_DIRENT_HASH(de);\n-\t\t\telse {\n+\t\t\tif (!(ext4_dirdata_get(de, dir, NULL, &h.hash,\n+\t\t\t\t\t &h.minor_hash) &\n+\t\t\t\t\t\tEXT4_DIRENT_CFHASH)) {\n \t\t\t\tint err = ext4fs_dirhash(dir, de->name,\n \t\t\t\t\t\t de->name_len, &h);\n \t\t\t\tif (err < 0)\n@@ -1856,7 +1941,7 @@ dx_move_dirents(struct inode *dir, char *from, char *to,\n \twhile (count--) {\n \t\tstruct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *)\n \t\t\t\t\t\t(from + (map->offs<<2));\n-\t\trec_len = ext4_dir_rec_len(de->name_len, dir);\n+\t\trec_len = ext4_dir_entry_len(de, dir);\n \n \t\tmemcpy (to, de, rec_len);\n \t\t((struct ext4_dir_entry_2 *) to)->rec_len =\n@@ -1889,7 +1974,7 @@ static struct ext4_dir_entry_2 *dx_pack_dirents(struct inode *dir, char *base,\n \twhile ((char*)de < base + blocksize) {\n \t\tnext = ext4_next_entry(de, blocksize);\n \t\tif (de->inode && de->name_len) {\n-\t\t\trec_len = ext4_dir_rec_len(de->name_len, dir);\n+\t\t\trec_len = ext4_dir_entry_len(de, dir);\n \t\t\tif (de > to)\n \t\t\t\tmemmove(to, de, rec_len);\n \t\t\tto->rec_len = ext4_rec_len_to_disk(rec_len, blocksize);\n@@ -2041,10 +2126,11 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,\n int ext4_find_dest_de(struct inode *dir, struct buffer_head *bh,\n \t\t void *buf, int buf_size,\n \t\t struct ext4_filename *fname,\n-\t\t struct ext4_dir_entry_2 **dest_de)\n+\t\t struct ext4_dir_entry_2 **dest_de,\n+\t\t int dlen)\n {\n \tstruct ext4_dir_entry_2 *de;\n-\tunsigned short reclen = ext4_dir_rec_len(fname_len(fname), dir);\n+\tunsigned short reclen = ext4_dirent_rec_len(fname_len(fname) + dlen, dir);\n \tint nlen, rlen;\n \tunsigned int offset = 0;\n \tchar *top;\n@@ -2057,7 +2143,7 @@ int ext4_find_dest_de(struct inode *dir, struct buffer_head *bh,\n \t\t\treturn -EFSCORRUPTED;\n \t\tif (ext4_match(dir, fname, de))\n \t\t\treturn -EEXIST;\n-\t\tnlen = ext4_dir_rec_len(de->name_len, dir);\n+\t\tnlen = ext4_dir_entry_len(de, dir);\n \t\trlen = ext4_rec_len_from_disk(de->rec_len, buf_size);\n \t\tif ((de->inode ? rlen - nlen : rlen) >= reclen)\n \t\t\tbreak;\n@@ -2071,16 +2157,17 @@ int ext4_find_dest_de(struct inode *dir, struct buffer_head *bh,\n \treturn 0;\n }\n \n-void ext4_insert_dentry(struct inode *dir,\n-\t\t\tstruct inode *inode,\n-\t\t\tstruct ext4_dir_entry_2 *de,\n-\t\t\tint buf_size,\n-\t\t\tstruct ext4_filename *fname)\n+void ext4_insert_dentry_data(struct inode *dir,\n+\t\t\t struct inode *inode,\n+\t\t\t struct ext4_dir_entry_2 *de,\n+\t\t\t int buf_size,\n+\t\t\t struct ext4_filename *fname,\n+\t\t\t void *data)\n {\n \n \tint nlen, rlen;\n \n-\tnlen = ext4_dir_rec_len(de->name_len, dir);\n+\tnlen = ext4_dir_entry_len(de, dir);\n \trlen = ext4_rec_len_from_disk(de->rec_len, buf_size);\n \tif (de->inode) {\n \t\tstruct ext4_dir_entry_2 *de1 =\n@@ -2094,7 +2181,9 @@ void ext4_insert_dentry(struct inode *dir,\n \text4_set_de_type(inode->i_sb, de, inode->i_mode);\n \tde->name_len = fname_len(fname);\n \tmemcpy(de->name, fname_name(fname), fname_len(fname));\n-\tif (ext4_hash_in_dirent(dir)) {\n+\tif (ext4_has_feature_dirdata(inode->i_sb)) {\n+\t\text4_dirdata_set(de, dir, data, fname);\n+\t} else if (ext4_hash_in_dirent(dir)) {\n \t\tstruct dx_hash_info *hinfo = &fname->hinfo;\n \n \t\tEXT4_DIRENT_HASHES(de)->hash = cpu_to_le32(hinfo->hash);\n@@ -2118,14 +2207,18 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,\n {\n \tunsigned int\tblocksize = dir->i_sb->s_blocksize;\n \tint\t\tcsum_size = 0;\n-\tint\t\terr, err2;\n+\tint\t\terr, err2, dlen = 0;\n+\tunsigned char\t*data = NULL;\n \n+\t/* Deliver data in any appropriate way here. Now it is NULL */\n \tif (ext4_has_feature_metadata_csum(inode->i_sb))\n \t\tcsum_size = sizeof(struct ext4_dir_entry_tail);\n \n \tif (!de) {\n+\t\tif (data)\n+\t\t\tdlen = (*data) + 1;\n \t\terr = ext4_find_dest_de(dir, bh, bh->b_data,\n-\t\t\t\t\tblocksize - csum_size, fname, &de);\n+\t\t\t\t\tblocksize - csum_size, fname, &de, dlen);\n \t\tif (err)\n \t\t\treturn err;\n \t}\n@@ -2138,7 +2231,7 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,\n \t}\n \n \t/* By now the buffer is marked for journaling */\n-\text4_insert_dentry(dir, inode, de, blocksize, fname);\n+\text4_insert_dentry_data(dir, inode, de, blocksize, fname, data);\n \n \t/*\n \t * XXX shouldn't update any times until successful\n@@ -2927,7 +3020,7 @@ int ext4_init_dirblock(handle_t *handle, struct inode *inode,\n \n \tde->inode = cpu_to_le32(inode->i_ino);\n \tde->name_len = 1;\n-\tde->rec_len = ext4_rec_len_to_disk(ext4_dir_rec_len(de->name_len, NULL),\n+\tde->rec_len = ext4_rec_len_to_disk(ext4_dirent_rec_len(de->name_len, NULL),\n \t\t\t\t\t blocksize);\n \tmemcpy(de->name, \".\", 2);\n \text4_set_de_type(inode->i_sb, de, S_IFDIR);\n@@ -2939,7 +3032,7 @@ int ext4_init_dirblock(handle_t *handle, struct inode *inode,\n \text4_set_de_type(inode->i_sb, de, S_IFDIR);\n \tif (inline_buf) {\n \t\tde->rec_len = ext4_rec_len_to_disk(\n-\t\t\t\t\text4_dir_rec_len(de->name_len, NULL),\n+\t\t\t\t\text4_dirent_rec_len(de->name_len, NULL),\n \t\t\t\t\tblocksize);\n \t\tde = ext4_next_entry(de, blocksize);\n \t\theader_size = (char *)de - bh->b_data;\n@@ -2948,7 +3041,7 @@ int ext4_init_dirblock(handle_t *handle, struct inode *inode,\n \t\t\tblocksize - csum_size);\n \t} else {\n \t\tde->rec_len = ext4_rec_len_to_disk(blocksize -\n-\t\t\t\t\t(csum_size + ext4_dir_rec_len(1, NULL)),\n+\t\t\t\t\t(csum_size + ext4_dirent_rec_len(1, NULL)),\n \t\t\t\t\tblocksize);\n \t}\n \n@@ -2960,8 +3053,9 @@ int ext4_init_dirblock(handle_t *handle, struct inode *inode,\n \treturn ext4_handle_dirty_dirblock(handle, inode, bh);\n }\n \n-int ext4_init_new_dir(handle_t *handle, struct inode *dir,\n-\t\t\t struct inode *inode)\n+int ext4_init_new_dir_data(handle_t *handle, struct inode *dir,\n+\t\t\t struct inode *inode,\n+\t\t\t const void *data1, const void *data2)\n {\n \tstruct buffer_head *dir_block = NULL;\n \text4_lblk_t block = 0;\n@@ -2986,6 +3080,22 @@ int ext4_init_new_dir(handle_t *handle, struct inode *dir,\n \treturn err;\n }\n \n+int ext4_add_dot_dotdot(handle_t *handle, struct inode *dir,\n+\t\t\tstruct inode *inode,\n+\t\t\tconst void *data1, const void *data2)\n+{\n+\tstruct buffer_head *dir_block = NULL;\n+\text4_lblk_t block = 0;\n+\tint err;\n+\n+\tdir_block = ext4_append(handle, inode, &block);\n+\tif (IS_ERR(dir_block))\n+\t\treturn PTR_ERR(dir_block);\n+\terr = ext4_init_dirblock(handle, inode, dir_block, dir->i_ino, NULL, 0);\n+\tbrelse(dir_block);\n+\treturn err;\n+}\n+\n static struct dentry *ext4_mkdir(struct mnt_idmap *idmap, struct inode *dir,\n \t\t\t\t struct dentry *dentry, umode_t mode)\n {\n@@ -3071,8 +3181,8 @@ bool ext4_empty_dir(struct inode *inode)\n \t}\n \n \tsb = inode->i_sb;\n-\tif (inode->i_size < ext4_dir_rec_len(1, NULL) +\n-\t\t\t\t\text4_dir_rec_len(2, NULL)) {\n+\tif (inode->i_size < ext4_dirent_rec_len(1, NULL) +\n+\t\t\t\t\text4_dirent_rec_len(2, NULL)) {\n \t\tEXT4_ERROR_INODE(inode, \"invalid size\");\n \t\treturn false;\n \t}\ndiff --git a/fs/ext4/super.c b/fs/ext4/super.c\nindex 43f680c750ae..28151a99e126 100644\n--- a/fs/ext4/super.c\n+++ b/fs/ext4/super.c\n@@ -1673,7 +1673,7 @@ enum {\n \tOpt_data_err_abort, Opt_data_err_ignore, Opt_test_dummy_encryption,\n \tOpt_inlinecrypt,\n \tOpt_usrjquota, Opt_grpjquota, Opt_quota,\n-\tOpt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,\n+\tOpt_noquota, Opt_barrier, Opt_nobarrier, Opt_err, Opt_dirdata,\n \tOpt_usrquota, Opt_grpquota, Opt_prjquota,\n \tOpt_dax, Opt_dax_always, Opt_dax_inode, Opt_dax_never,\n \tOpt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_warn_on_error,\n@@ -1783,6 +1783,7 @@ static const struct fs_parameter_spec ext4_param_specs[] = {\n \tfsparam_u32\t(\"stripe\",\t\tOpt_stripe),\n \tfsparam_flag\t(\"delalloc\",\t\tOpt_delalloc),\n \tfsparam_flag\t(\"nodelalloc\",\t\tOpt_nodelalloc),\n+\tfsparam_flag\t(\"dirdata\",\t\tOpt_dirdata),\n \tfsparam_flag\t(\"warn_on_error\",\tOpt_warn_on_error),\n \tfsparam_flag\t(\"nowarn_on_error\",\tOpt_nowarn_on_error),\n \tfsparam_u32\t(\"debug_want_extra_isize\",\n@@ -1911,6 +1912,7 @@ static const struct mount_opts {\n \t\t\t\t\t\t\tMOPT_CLEAR | MOPT_Q},\n \t{Opt_usrjquota, 0, MOPT_Q},\n \t{Opt_grpjquota, 0, MOPT_Q},\n+\t{Opt_dirdata, EXT4_MOUNT_DIRDATA, MOPT_SET},\n \t{Opt_jqfmt, 0, MOPT_QFMT},\n \t{Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET},\n \t{Opt_no_prefetch_block_bitmaps, EXT4_MOUNT_NO_PREFETCH_BLOCK_BITMAPS,\ndiff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c\nindex b87d7bdab06a..1f5e9627e735 100644\n--- a/fs/ext4/sysfs.c\n+++ b/fs/ext4/sysfs.c\n@@ -362,6 +362,7 @@ EXT4_ATTR_FEATURE(verity);\n #endif\n EXT4_ATTR_FEATURE(metadata_csum_seed);\n EXT4_ATTR_FEATURE(fast_commit);\n+EXT4_ATTR_FEATURE(dirdata);\n #if IS_ENABLED(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)\n EXT4_ATTR_FEATURE(encrypted_casefold);\n #endif\n@@ -385,6 +386,7 @@ static struct attribute *ext4_feat_attrs[] = {\n #endif\n \tATTR_LIST(metadata_csum_seed),\n \tATTR_LIST(fast_commit),\n+\tATTR_LIST(dirdata),\n #if IS_ENABLED(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)\n \tATTR_LIST(encrypted_casefold),\n #endif\n", "prefixes": [ "3/3" ] }