From nobody Fri Sep 25 20:02:39 2026 Received: from mail-yx1-f42.google.com (mail-yx1-f42.google.com [74.125.224.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 812633C3C1C for ; Tue, 8 Sep 2026 21:05:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.224.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788901503; cv=none; b=qImX7Pb0135cj7sa1Ag1AeQ8CJQnJrQ07Wq+Y0BAqhJPoPcUaXyvrj89T934en8ssbzWZ7fl54fDw18KQhi2YY0u2OuRQKP8dlQelPwIwYq9dlix77vrjlEm/bY3txwwJNUe72fkgx9auZsmn21fz7IICqL4K4pDDvMTNciavng= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788901503; c=relaxed/simple; bh=OVJzpWfHSM6a6wCkK3C71K/fLknshrLRt2xkWr7HMRk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pji75NKwEZEJfijw9O9hsRPPIU0QXEezpiVf58uSoa/2zPG4vtgKzBnq6mY1F6u01zUDGaZLzQKUFvLFCK+a3tZRH7dJvx4VKZ8+2BzLGIlkeX3bNqVmOWSzxHnp+Ge1Fe5coNWAx4cIZeWGFDI2pU44Bncw9EqEpMehyoHMP28= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com; spf=pass smtp.mailfrom=dubeyko.com; dkim=pass (2048-bit key) header.d=dubeyko-com.20251104.gappssmtp.com header.i=@dubeyko-com.20251104.gappssmtp.com header.b=U8+CWeSh; arc=none smtp.client-ip=74.125.224.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=dubeyko-com.20251104.gappssmtp.com header.i=@dubeyko-com.20251104.gappssmtp.com header.b="U8+CWeSh" Received: by mail-yx1-f42.google.com with SMTP id 956f58d0204a3-66c7127a73dso5602845d50.2 for ; Tue, 08 Sep 2026 14:05:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20251104.gappssmtp.com; s=20251104; t=1788901500; x=1789506300; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=YUa9GDJb+Q4jhCXihDpgFN+RTSjVzxtIFk+RZAxtdhM=; b=U8+CWeShrP14rgd44xgUXmUiojOa1fT3Mhh3nlczkGv1oipwxynmAEQEqNxrMtp4m1 LHp+zbkug6yh1QwpdXbI3+jBIehKxHKKtLaLh+MTKxaQ50cfrDLUfCPUFzxOjho4dnSU 8F08P7LDTRpP5d0leXwrRILcSSYwztvT/eNCMQgbU0NVwLU900vW0bfAjtKjYn7Zob4u egwRy9ZeTOHMkyQRgf8eK2dsIPC668Q6Gicavzx6dBznLxqyJ891EuKeaqpEcWTb0Sue TbfzF+PIxtytl6Sd72GiyQrX9yplM/Iwo7iY/RyTNrgvrVIVjNbLytph4ZfzltSTe1un jpTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788901500; x=1789506300; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=YUa9GDJb+Q4jhCXihDpgFN+RTSjVzxtIFk+RZAxtdhM=; b=DCFbGZUQ4H38HRqXHpb1cPGGxW+j9ngG9f3VFci+A8TI3qEezFFCs0q8ROKXKLvm4Y HXJXEO//2fyXEW2oLNOoZ+D8ARtSvxye/gjmn0uoRvwFpTp/1Lnd1cSRwzU+CiqX7+vk /oDPO2yoUcyV4ovHc7bwUcrftRC0raX+t5qMi67vxF/nKIV22JVOeeUfLQ8tVWmShG/S SI+o/w/+kYydZR3LmDCFO9+COvnmLwdWQmOVDzuTK8qh7G0Ut9puwc3kdnPIQz4zJ9V+ +VNvvzPHeqUSWek0sEHcQgTHgRt5aC9LtZT62rAX1/3/C0T09GIHxTR/osFTJd92W9p3 QeZw== X-Forwarded-Encrypted: i=1; AKwUvBzdpBQU9ts393jWsI87it2sei/rPt0bpzvq4fk3PamiQiInVwk3SYs4C22IxurD0gYvH0mkqElrn3mw67s=@vger.kernel.org X-Gm-Message-State: AFuF++krfG5vhuqKLjXwwbPZ+TRIX/APjeyb96EXPY0SPjBhmlEbsPwe ZeqWNPOHwgMNjBNN+sCLtagRfkwmOfKp0C1tZrmpEMydDjqP1nXGNgUUEfJesSZiXemIAff1NVI T8PiZRnAIAg== X-Gm-Gg: AYBFou0dEDr54t0iSALHwBa1azssYMVj0o51AHjyeEf+9BkPEZe6O/T8vimLOGWwkxa 461hbdZFHtuu3MoMtceNV8YAftnAWjtSo0FKfdgMVi6/YazRPgQLxcTS9TYSnaBPeo/s6DxJHtW Y6IvVqgPXGtfNNtGsRf1cHzVQNy/22rCSi0QpFHCRO2KnJTGqrUYZuCNSt3U4e/+DpFC69//fmK lAI88g6yKJMmik/CUX9lm5+tElB9dG9JPH0EzCyhuSVm9AWUallzGp8O2R9EzToEFFfmLwEdVku rUREtI7t0+HByzz5fj7zOJ9Jv6AhuYU7NgoWoe4tIL7zGTBN5genWT1bHlGLlVJL3LJZ0e4tyxe H874m39NB7y6lX4ChjYOEPNvRskVwj1zOVR+brRxduU6a/hgJiAFrS8ro8RYRCk9yDiwg0T/3Og sZI5HbjKUnFHWFI5agFbdhkjfzZ64/czDV5nT7gUB8Or4554RXsWC7tusXpli13DPdUwBM0UIOE Ka0F5ckgYdgxTD2EXNnq7dtPy7f2B6pZLAI6LlfRihuN7oYa/ly8UQkpdgZ4C6io/0eoWvmF2XE dgTDq1s3yaNgyU3+ X-Received: by 2002:a05:690e:2599:b0:66f:c1be:84c9 with SMTP id 956f58d0204a3-66fc1be8d51mr6688418d50.55.1788901500408; Tue, 08 Sep 2026 14:05:00 -0700 (PDT) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:1eca:212:86d0:4e87]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-66fb495eccesm11078129d50.18.2026.09.08.14.04.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 14:04:59 -0700 (PDT) From: Viacheslav Dubeyko To: glaubitz@physik.fu-berlin.de, frank.li@vivo.com, hch@lst.de Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, vdubeyko@coreweave.com, willy@infradead.org, brauner@kernel.org, djwong@kernel.org, Viacheslav Dubeyko Subject: [PATCH v3 1/7] hfs/hfsplus: exchange hardcoded number of extents on named constants Date: Tue, 8 Sep 2026 14:04:42 -0700 Message-ID: <20260908210448.296772-2-slava@dubeyko.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260908210448.296772-1-slava@dubeyko.com> References: <20260908210448.296772-1-slava@dubeyko.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Replace the magic 8/3 fork extent-count literals with named constants (HFS_FORK_EXTENT_COUNT and HFSPLUS_FORK_EXTENT_COUNT). No functional change. cc: Christoph Hellwig cc: John Paul Adrian Glaubitz cc: Yangtao Li cc: linux-fsdevel@vger.kernel.org Reviewed-by: Christoph Hellwig Signed-off-by: Viacheslav Dubeyko Acked-by: "Darrick J. Wong" --- include/linux/hfs_common.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/linux/hfs_common.h b/include/linux/hfs_common.h index d6a615e74b26..8673933bbee5 100644 --- a/include/linux/hfs_common.h +++ b/include/linux/hfs_common.h @@ -171,18 +171,22 @@ enum { HFS_XATTR_NAME, }; =20 +#define HFS_FORK_EXTENT_COUNT (3) + struct hfs_extent { __be16 block; __be16 count; }; -typedef struct hfs_extent hfs_extent_rec[3]; +typedef struct hfs_extent hfs_extent_rec[HFS_FORK_EXTENT_COUNT]; + +#define HFSPLUS_FORK_EXTENT_COUNT (8) =20 /* A single contiguous area of a file */ struct hfsplus_extent { __be32 start_block; __be32 block_count; } __packed; -typedef struct hfsplus_extent hfsplus_extent_rec[8]; +typedef struct hfsplus_extent hfsplus_extent_rec[HFSPLUS_FORK_EXTENT_COUNT= ]; =20 /* Information for a "Fork" in a file */ struct hfsplus_fork_raw { --=20 2.43.0 From nobody Fri Sep 25 20:02:39 2026 Received: from mail-yx1-f48.google.com (mail-yx1-f48.google.com [74.125.224.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3B90D3D75AD for ; Tue, 8 Sep 2026 21:05:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.224.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788901505; cv=none; b=kQOkG+fmbbMGss5YGnFRaGhkyW3teq+ee3uiarv1pJruIAYq/8ZTNkezV8ZCp4ZQxU9zNKmfAS7Gp/SiIe72dRWUDWYpTpTc1Uify/kPyIy5YniaSz3+sTBd5UjyD/gVyeJ2RiHhjcVMLPDOEtQFF6Opl/DAA307MIirKpDZ8xU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788901505; c=relaxed/simple; bh=KQ9TioCk7IAXoYKsbOf3mo0CBYIbu2RGH/UJt8EFt/M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UAvfN9NPnxWbenXgTg11G2ADJcC0sYL9LQUldmWk7BoCmkFXKszA4J3s8wRzh3iHQEnqlJlp6h7Q4HK1I877An+R5FuTtvvGXoZR0bJQ0u6rcV8rXEd6UzSYUAeS57HT2THunGfudnrLjbMDuqwTDvDx/ENHD/1msOhduMbAu10= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com; spf=pass smtp.mailfrom=dubeyko.com; dkim=pass (2048-bit key) header.d=dubeyko-com.20251104.gappssmtp.com header.i=@dubeyko-com.20251104.gappssmtp.com header.b=t7yO1YTc; arc=none smtp.client-ip=74.125.224.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=dubeyko-com.20251104.gappssmtp.com header.i=@dubeyko-com.20251104.gappssmtp.com header.b="t7yO1YTc" Received: by mail-yx1-f48.google.com with SMTP id 956f58d0204a3-66fc2844f0eso5274499d50.1 for ; Tue, 08 Sep 2026 14:05:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20251104.gappssmtp.com; s=20251104; t=1788901502; x=1789506302; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Hss3hwS5MmprOQZWPrR8lu4oaz0ib++0UrLxiJhoUVs=; b=t7yO1YTc4AtG8rnpyV+YzwuDQ1ANE1oSCBzp9xrmZ0oDoLaPmqdQPAA1Y1eDGKx1Jn BjR1lN8HdsRc2J30tHHUZguq6sTyAzcLwd0qsXKNzRkKBPL0Yfkldw5U5Q73YMlysiw8 HFTOeoUpiWeN7Ty7iOwL3wIKIcIvnxKUsmzgXA9t5W0hkfVmqdNb+sXQ8NuSi/CysLcx Jdr9CQyix3lhO7PLSkeTSWn46jlRnks/gHUHIGTkR9Lo496SfaJ9r6FkgVmTFJ/LfbZ6 5aP1OgkPhYUDUj6dHFuGQQpuMMzZf9YsnvQEw/UcIweEVsnJ2JEOGItoW+EMLPa0RChr CqpA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788901502; x=1789506302; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=Hss3hwS5MmprOQZWPrR8lu4oaz0ib++0UrLxiJhoUVs=; b=A1fLHX4npU3yi3voT8YS2qkIG7XzSfDDgH8EpGlZCsMjnM0x3k9v8uNeHjXGIIazS5 g0kCUtoMoY80GtvKARII3pZMLagJKSQBbC89x0MDoo8Jm6WOoRszk8fHPUwtexV6Mb7K 3h2l9D0Xs4//vAS+rZc0SWXyhGtNeGRLoDFKV2V60YLLReFNmA9WfT8zzZO5ZPwYayvT r3QALsYay+2KJLKUl9WSgsEy9aIpvKhrKivbOeHnLOlwZ9KZA4yMBz+psv7+NlgNTVWG uoY8y7TZnWS9pVsBuclRgM6S1aOvpz6A9qUvSGn69fCyFSiKLJENlGWwVgo1+yuOQ4ke LhCA== X-Forwarded-Encrypted: i=1; AKwUvBypINgmSlCXKJdwGZ6Enr1mbdl0efsW0wXtgHysoNFesuSSUkuOh5lpgJ+ICYGyNuqlm6kSGLeAdbp9hZs=@vger.kernel.org X-Gm-Message-State: AFuF++n0YITi5KPnYrwynXHpkECB3UqtQGx1lH/G9GGoAoMHLUzCEMNI ply5qvD0ESEMZvIda9p17dc0xvtfIFWWnqGPnmbMNc8xFf+Jl05p+29keLjxm6a5jNM= X-Gm-Gg: AYBFou3EufTT9MVdqsedFgzysL8nmleYFUjTCyJqFmkaKFxNU6SYhEyDO3TcL4wYrnL TIK9ZX4ZF5P4w4rorwjFSxFzaMuE1eDLuEV3b+tTrcJYY0DXOg1jG/UE8iSpwXBDMCRQdOoCuo/ GyYP1UhEDbucDIRsO48LaVLAxmbamiEaLAWbRVFWGWtv+Nya6rUt4nUZ9j5bnX0LkaQLoFn2N9N vigkbY71pEIs16gq952nTJB7nfdEYuojBBv6yVVZkuWVxS2qecZOSaiD1lc2fGYHvsJg1J0Id0H oZ9ncGD2ffLvm9KKlLJCJMBkBvqzep7UP5eg9j9v3dEDpaGXMLRmVQ6VytG/MfwNGRvJuqbrCaU ZAThykUkFgWg2/BKrJr9oxChgtLSFLPn32MFUaGL3vRJAol0lkjbyJnJ6SO1nh3SVHWI237Rjxa f4Z2R+YZR6qK+QISCFqAqIdxhewosiH2a/BZ5nJXRp4PC8bKxfD8KhNFaT4XlGaQcer1ax/ETHz 8dz0brGjytuYeFCbFwk3akg1dOsvzcxy7FJ1kXpbJKMtg7JtjrkQuE+FPg7RQtkv82GuWUdljp0 TVwyvhYpyZ6OjPBg X-Received: by 2002:a05:690e:138a:b0:66f:c323:2bbb with SMTP id 956f58d0204a3-66fc32335f3mr7152359d50.74.1788901502034; Tue, 08 Sep 2026 14:05:02 -0700 (PDT) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:1eca:212:86d0:4e87]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-66fb495eccesm11078129d50.18.2026.09.08.14.05.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 14:05:01 -0700 (PDT) From: Viacheslav Dubeyko To: glaubitz@physik.fu-berlin.de, frank.li@vivo.com, hch@lst.de Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, vdubeyko@coreweave.com, willy@infradead.org, brauner@kernel.org, djwong@kernel.org, Viacheslav Dubeyko Subject: [PATCH v3 2/7] hfsplus: rework hfsplus_get_block() logic Date: Tue, 8 Sep 2026 14:04:43 -0700 Message-ID: <20260908210448.296772-3-slava@dubeyko.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260908210448.296772-1-slava@dubeyko.com> References: <20260908210448.296772-1-slava@dubeyko.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Split the extent-lookup/allocate logic out of hfsplus_get_block() into a new hfsplus_map_extent(), which reports the mapping as (dblock, max_blocks, balloc) instead of filling in a buffer_head. hfsplus_get_block() becomes a thin wrapper around it for the buffer_head-based callers (B-tree metadata, symlinks). No functional change to the existing buffer_head path. This is preparation for the iomap-based regular file I/O path added in a later patch, which will call hfsplus_map_extent() directly. cc: Christoph Hellwig cc: John Paul Adrian Glaubitz cc: Yangtao Li cc: linux-fsdevel@vger.kernel.org Reviewed-by: Christoph Hellwig Signed-off-by: Viacheslav Dubeyko Acked-by: "Darrick J. Wong" --- fs/hfsplus/extents.c | 118 +++++++++++++++++++++++++++++----------- fs/hfsplus/hfsplus_fs.h | 2 + 2 files changed, 87 insertions(+), 33 deletions(-) diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index eb7c11524d18..ffd52ad8867c 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c @@ -48,18 +48,29 @@ static void hfsplus_ext_build_key(hfsplus_btree_key *ke= y, u32 cnid, key->ext.pad =3D 0; } =20 -static u32 hfsplus_ext_find_block(struct hfsplus_extent *ext, u32 off) +/* + * hfsplus_ext_find_block() - find contiguous sequence of block + * + * Find the disk allocation block for 'off' within an 8-entry + * extent record, and the number of further allocation blocks + * that are contiguous with it in the same extent entry. + */ +static u32 hfsplus_ext_find_block(struct hfsplus_extent *ext, u32 off, + u32 *dblock) { int i; u32 count; =20 - for (i =3D 0; i < 8; ext++, i++) { + for (i =3D 0; i < HFSPLUS_FORK_EXTENT_COUNT; ext++, i++) { count =3D be32_to_cpu(ext->block_count); - if (off < count) - return be32_to_cpu(ext->start_block) + off; + if (off < count) { + *dblock =3D be32_to_cpu(ext->start_block) + off; + return count - off; + } off -=3D count; } /* panic? */ + *dblock =3D 0; return 0; } =20 @@ -68,7 +79,7 @@ static int hfsplus_ext_block_count(struct hfsplus_extent = *ext) int i; u32 count =3D 0; =20 - for (i =3D 0; i < 8; ext++, i++) + for (i =3D 0; i < HFSPLUS_FORK_EXTENT_COUNT; ext++, i++) count +=3D be32_to_cpu(ext->block_count); return count; } @@ -225,37 +236,46 @@ static int hfsplus_ext_read_extent(struct inode *inod= e, u32 block) return res; } =20 -/* Get a block at iblock for inode, possibly allocating if create */ -int hfsplus_get_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create) +/* + * hfsplus_map_extent() - find or allocate a sequence of allocation blocks + * + * Looks up the allocation block at 'ablock' for inode, extending the + * file (via hfsplus_file_extend(), in clump_blocks-sized chunks) when + * 'create' is set and 'ablock' lies beyond the current allocation. + * + * On success, *dblock is the disk allocation block backing 'ablock', + * and *max_blocks is the number of further allocation blocks that are + * contiguous with it (i.e. the remaining length of the extent entry + * that contains 'ablock'), which may be smaller than the whole file's + * remaining allocation when the fork is fragmented across several + * extent entries. If a new extent had to be allocated to satisfy the + * request, *balloc (when non-NULL) is set to true. + */ +int hfsplus_map_extent(struct inode *inode, u32 ablock, int create, + u32 *dblock, u32 *max_blocks, bool *balloc) { - struct super_block *sb =3D inode->i_sb; - struct hfsplus_sb_info *sbi =3D HFSPLUS_SB(sb); struct hfsplus_inode_info *hip =3D HFSPLUS_I(inode); - int res =3D -EIO; - u32 ablock, dblock, mask; - sector_t sector; - int was_dirty =3D 0; + int was_dirty; + int res; =20 - /* Convert inode block to disk allocation block */ - ablock =3D iblock >> sbi->fs_shift; + if (balloc) + *balloc =3D false; =20 - if (iblock >=3D hip->fs_blocks) { + if (ablock >=3D hip->alloc_blocks) { if (!create) - return 0; - if (iblock > hip->fs_blocks) return -EIO; - if (ablock >=3D hip->alloc_blocks) { - res =3D hfsplus_file_extend(inode, false); - if (res) - return res; - } - } else - create =3D 0; + res =3D hfsplus_file_extend(inode, false); + if (res) + return res; + if (balloc) + *balloc =3D true; + } =20 if (ablock < hip->first_blocks) { - dblock =3D hfsplus_ext_find_block(hip->first_extents, ablock); - goto done; + *max_blocks =3D hfsplus_ext_find_block(hip->first_extents, + ablock, + dblock); + return 0; } =20 if (inode->i_ino =3D=3D HFSPLUS_EXT_CNID) @@ -274,11 +294,44 @@ int hfsplus_get_block(struct inode *inode, sector_t i= block, mutex_unlock(&hip->extents_lock); return -EIO; } - dblock =3D hfsplus_ext_find_block(hip->cached_extents, - ablock - hip->cached_start); + *max_blocks =3D hfsplus_ext_find_block(hip->cached_extents, + ablock - hip->cached_start, + dblock); mutex_unlock(&hip->extents_lock); =20 -done: + if (was_dirty) + mark_inode_dirty(inode); + + return 0; +} + +/* Get a block at iblock for inode, possibly allocating if create */ +int hfsplus_get_block(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create) +{ + struct super_block *sb =3D inode->i_sb; + struct hfsplus_sb_info *sbi =3D HFSPLUS_SB(sb); + struct hfsplus_inode_info *hip =3D HFSPLUS_I(inode); + u32 ablock, dblock, mask, max_blocks; + sector_t sector; + int res; + + /* Convert inode block to disk allocation block */ + ablock =3D iblock >> sbi->fs_shift; + + if (iblock >=3D hip->fs_blocks) { + if (!create) + return 0; + if (iblock > hip->fs_blocks) + return -EIO; + } else + create =3D 0; + + res =3D hfsplus_map_extent(inode, ablock, create, &dblock, &max_blocks, + NULL); + if (res) + return res; + hfs_dbg("ino %llu, iblock %llu - dblock %u\n", inode->i_ino, (long long)iblock, dblock); =20 @@ -292,9 +345,8 @@ int hfsplus_get_block(struct inode *inode, sector_t ibl= ock, hip->phys_size +=3D sb->s_blocksize; hip->fs_blocks++; inode_add_bytes(inode, sb->s_blocksize); - } - if (create || was_dirty) mark_inode_dirty(inode); + } return 0; } =20 diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 1e5b58e6a13f..67586382269b 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -436,6 +436,8 @@ int hfsplus_ext_cmp_key(const hfsplus_btree_key *k1, int hfsplus_ext_write_extent(struct inode *inode); int hfsplus_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create); +int hfsplus_map_extent(struct inode *inode, u32 ablock, int create, + u32 *dblock, u32 *max_blocks, bool *balloc); int hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw *fork, int type); int hfsplus_file_extend(struct inode *inode, bool zeroout); --=20 2.43.0 From nobody Fri Sep 25 20:02:39 2026 Received: from mail-yx2-f12.google.com (mail-yx2-f12.google.com [74.125.224.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E140D4307AA for ; Tue, 8 Sep 2026 21:05:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.224.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788901506; cv=none; b=Z5BWjXc7fAForXKncc7TjlLbFm36rLb2Rf63QHyJYnINHxiz77GZEH59CaXTAMv/HfxVCi+uy/cn8dEkUkIRoWByDJwp0P1d8z/bcuH0fg3oRIo1ggXOXKdusvhjj/bIUlq6+4+8v3XVdhMSmk5+rN/TSioaIrk3TaDD7aRU4Lc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788901506; c=relaxed/simple; bh=JS4es041X9iQ3ww+X8OGRBNQHXimqemFhijw7rmEypM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hyCnY7EacWknq8/XTWVUA7qIJns5T8vXbTl5SNnXtCqK5tXejboE7kqnw3Vhki1w8W26cR6g+V0CObPHrGWD+oPFmTWDtO/KD1aRSwAkDtTltsS3S1v76gHjgs2ZYAy1/OYW0eereA4EvJ7xp1JyAUtpea12DY4uFuagQTDDwlE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com; spf=pass smtp.mailfrom=dubeyko.com; dkim=pass (2048-bit key) header.d=dubeyko-com.20251104.gappssmtp.com header.i=@dubeyko-com.20251104.gappssmtp.com header.b=TgnpThmI; arc=none smtp.client-ip=74.125.224.140 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=dubeyko-com.20251104.gappssmtp.com header.i=@dubeyko-com.20251104.gappssmtp.com header.b="TgnpThmI" Received: by mail-yx2-f12.google.com with SMTP id 956f58d0204a3-66e4aae3147so507252d50.1 for ; Tue, 08 Sep 2026 14:05:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20251104.gappssmtp.com; s=20251104; t=1788901504; x=1789506304; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=+JM2TitCUkHWsoHev5+SihBzZ6SFDmIJWRE6hX8zY3w=; b=TgnpThmIp23oMAZm0vH2L2u1SQYiCA//G0VpRSYTlS16DNKXch4r6QhrGo3uSE3Ufs nxUuHLG9DJIRA+Yl+c5Xjbz5wTCfJCAbak4Ytx8TAFn/xM0hulguYLvgc5qXRJ/uJ+qf vmfOS0pWqTCfZiLdvQKZK3Q+lV4ffTiYD7AXsX+3Zc8biT2eSToycgqbelMqLygq+VMP GNqyxbT0ZtoFGEZx4ZqhVod0IQljxG7KkP/An7DZGfiTTHFa3Afj5wxmBOiffaEmX/Tg 07NJtibWDpsTRQDf2xEfiNTRruB4JX2BF19sfeV6qpImGNuj5htNVBlFb/tTh6986v70 y4yg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788901504; x=1789506304; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=+JM2TitCUkHWsoHev5+SihBzZ6SFDmIJWRE6hX8zY3w=; b=oiN/A+lMmfVE0bY7ydcIWinQHOcSax/1KpxXe0Xs3R2WG1GPae/c2U5Ot0XWcJGfDU QHsa30Jh3Y9cSIPIlgx/0vJzso7TB1l9FKuqeEeuDSZxg9q6p+TFX64YN04rn/o0mIJg ww/e7N1S9UsUlTvMUO+pGhlSwuk9eedCRxHW4mYwqQYyQOkqJ7nFU4Im3bNQ8s84G1MM zM0izmiJP26wccvFsR8hFTbr/3mAGKb+PSlRWbeVkI/zbM/Yg1qUl2IWmmzVZG8igvod vCv9rIEt9udSEjaSGndjqjcaLOpVKhES/i190pAcsKo+rx64gztjBGdWXMK7vab/vkrf uwbA== X-Forwarded-Encrypted: i=1; AKwUvByKNFM6Kv8g/mys4hPTvFuZnlKDJvs9pHjXplWziZuuqC1v3RRzxFe07lFHPxZ0irWhFyPyGjk1w1CNMmU=@vger.kernel.org X-Gm-Message-State: AFuF++kdxnsX2ZzoYKcOvUDxNzNJsykesSCCvc0co1+v4+e3mvMp/J7N DlYWP/w92No0IrZrj4BVVBTrWDGU917GaK/uRsSe+KRDIHfKEnViz2nCeOjLplZD9tk= X-Gm-Gg: AYBFou364ktXqb2Kg4maVecjvMMCGmmADkb6RDCUaTIIiYuFQL1eQUZKkfL6+xI4GZF I5V0x8s4SaqmxVXad9cW0tya/mwP/fuG1RGBkIROTqa7NIOYypI5LKqQMmr+Ng64QHek2gjHwXj bWDiiG/vCRA8aS7Uy5jXIa0JYp+BTDqHcD40kKD+a3x51lWqoTWcH+suezQgxtV6SxzSZNRrExV yTuSfNqZ6PNxycwEip5Y4ciDTQHx0DGrYyyY2+l6zNm+2TrKCmF7/yXXMrinVLlSZDkfjsS9Xr3 z/he385c82Nyi6tGNKf0j9G5Nvuom6cOCLB0ZE0L6VPQcBNlTlVi1QoubDp5RLGojnIPXeMHky3 KizS+ZRszprrbgOv+8kbeXLGKrTnBYX07c0PGlFMTu99+QIbwtcowr49gF3OlQy/6gwkE3ZwMJn lvAiM6h1vL1i95zxZ3PJnTJ6hzTJCkMsNzp0CEr+mt6ljd73kdYqy7bBxiVpthXCsXpMHQICWlb D3gpSNw+Y6FdvMJjA9wK1GG4qyfKWKcgLWJaQYIV+UNkallpepWjkQMhBp9+CQzW64cslaypOWX Nxlj4M7s4sI+foT1 X-Received: by 2002:a05:690e:80d:10b0:66d:1a61:5c6 with SMTP id 956f58d0204a3-671036edcbbmr515226d50.29.1788901503692; Tue, 08 Sep 2026 14:05:03 -0700 (PDT) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:1eca:212:86d0:4e87]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-66fb495eccesm11078129d50.18.2026.09.08.14.05.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 14:05:03 -0700 (PDT) From: Viacheslav Dubeyko To: glaubitz@physik.fu-berlin.de, frank.li@vivo.com, hch@lst.de Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, vdubeyko@coreweave.com, willy@infradead.org, brauner@kernel.org, djwong@kernel.org, Viacheslav Dubeyko Subject: [PATCH v3 3/7] hfsplus: take the bitmap page lock for allocate/free Date: Tue, 8 Sep 2026 14:04:44 -0700 Message-ID: <20260908210448.296772-4-slava@dubeyko.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260908210448.296772-1-slava@dubeyko.com> References: <20260908210448.296772-1-slava@dubeyko.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The hfsplus_block_allocate() and hfsplus_block_free() kmap the allocation bitmap's pages and modify their bits in place under sbi->alloc_mutex, but without holding the page lock. That leaves the read-modify-write of the bitmap bits unprotected against a concurrent writeback of the same page, which can read a partially-updated bitmap word or race with the dirty-bit update. Signed-off-by: Viacheslav Dubeyko cc: Christoph Hellwig cc: John Paul Adrian Glaubitz cc: Yangtao Li cc: linux-fsdevel@vger.kernel.org Acked-by: "Darrick J. Wong" --- v2 Christoph Hellwig has detected that taking the page lock around the kmap/modify/kunmap section is not enough on its own: writeback drops the page lock before the write actually completes, so a mutator that only waits on the lock can still start rewriting a page whose old contents are still in flight to the device. Mark the allocation file's mapping with mapping_set_stable_writes() and call folio_wait_stable() right after taking the page lock in both functions, so a mutator also waits out any writeback that was already in progress when it acquired the lock. v3 Matthew Wilcox recommended to use folio_wait_writeback() instead of folio_wait_stable(). --- fs/hfsplus/bitmap.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/fs/hfsplus/bitmap.c b/fs/hfsplus/bitmap.c index 1b3af8c87cad..30178ea47362 100644 --- a/fs/hfsplus/bitmap.c +++ b/fs/hfsplus/bitmap.c @@ -39,6 +39,8 @@ int hfsplus_block_allocate(struct super_block *sb, u32 si= ze, start =3D size; goto out; } + lock_page(page); + folio_wait_writeback(page_folio(page)); pptr =3D kmap_local_page(page); curr =3D pptr + (offset & (PAGE_CACHE_BITS - 1)) / 32; i =3D offset % 32; @@ -75,6 +77,7 @@ int hfsplus_block_allocate(struct super_block *sb, u32 si= ze, curr++; } kunmap_local(pptr); + unlock_page(page); offset +=3D PAGE_CACHE_BITS; if (offset >=3D size) break; @@ -84,6 +87,8 @@ int hfsplus_block_allocate(struct super_block *sb, u32 si= ze, start =3D size; goto out; } + lock_page(page); + folio_wait_writeback(page_folio(page)); curr =3D pptr =3D kmap_local_page(page); if ((size ^ offset) / PAGE_CACHE_BITS) end =3D pptr + PAGE_CACHE_BITS / 32; @@ -98,6 +103,9 @@ int hfsplus_block_allocate(struct super_block *sb, u32 s= ize, start =3D offset + (curr - pptr) * 32 + i; if (start >=3D size) { hfs_dbg("bitmap full\n"); + kunmap_local(pptr); + unlock_page(page); + start =3D size; goto out; } /* do any partial u32 at the start */ @@ -128,6 +136,7 @@ int hfsplus_block_allocate(struct super_block *sb, u32 = size, } set_page_dirty(page); kunmap_local(pptr); + unlock_page(page); offset +=3D PAGE_CACHE_BITS; page =3D read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL); @@ -135,6 +144,8 @@ int hfsplus_block_allocate(struct super_block *sb, u32 = size, start =3D size; goto out; } + lock_page(page); + folio_wait_writeback(page_folio(page)); pptr =3D kmap_local_page(page); curr =3D pptr; end =3D pptr + PAGE_CACHE_BITS / 32; @@ -152,6 +163,7 @@ int hfsplus_block_allocate(struct super_block *sb, u32 = size, *curr =3D cpu_to_be32(n); set_page_dirty(page); kunmap_local(pptr); + unlock_page(page); *max =3D offset + (curr - pptr) * 32 + i - start; sbi->free_blocks -=3D *max; hfsplus_mark_mdb_dirty(sb); @@ -185,6 +197,8 @@ int hfsplus_block_free(struct super_block *sb, u32 offs= et, u32 count) page =3D read_mapping_page(mapping, pnr, NULL); if (IS_ERR(page)) goto kaboom; + lock_page(page); + folio_wait_writeback(page_folio(page)); pptr =3D kmap_local_page(page); curr =3D pptr + (offset & (PAGE_CACHE_BITS - 1)) / 32; end =3D pptr + PAGE_CACHE_BITS / 32; @@ -216,9 +230,12 @@ int hfsplus_block_free(struct super_block *sb, u32 off= set, u32 count) break; set_page_dirty(page); kunmap_local(pptr); + unlock_page(page); page =3D read_mapping_page(mapping, ++pnr, NULL); if (IS_ERR(page)) goto kaboom; + lock_page(page); + folio_wait_writeback(page_folio(page)); pptr =3D kmap_local_page(page); curr =3D pptr; end =3D pptr + PAGE_CACHE_BITS / 32; @@ -232,6 +249,7 @@ int hfsplus_block_free(struct super_block *sb, u32 offs= et, u32 count) out: set_page_dirty(page); kunmap_local(pptr); + unlock_page(page); sbi->free_blocks +=3D len; hfsplus_mark_mdb_dirty(sb); mutex_unlock(&sbi->alloc_mutex); --=20 2.43.0 From nobody Fri Sep 25 20:02:39 2026 Received: from mail-yx1-f54.google.com (mail-yx1-f54.google.com [74.125.224.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BBA15438493 for ; Tue, 8 Sep 2026 21:05:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.224.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788901508; cv=none; b=VLaZQkTDor62fA8/3lwV7KPhir6Z8RGHlbwde2hXRpjvSNUVyVVmNb8IG5vViIrgvK6gHxG6sWzoX5SMDtUxu98VkAIA4FVJjazVLgWvWA8HNjpSvWwefc+sTOVBWFBM9slsmKL5HnEjRgXY7RJqTU7YzlKq6LMpEmeHEuMyo6o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788901508; c=relaxed/simple; bh=jOzpIQqlYHA2pVFNKY7kzTiGuzamQCH3EM192/ZKawI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nyawL37ykCr8sCTxHcjQx16Js5miiXxWE70j2JkQuD5vi8RduR9gX6VcHkruDvc1Eu12082fnm5r9n9AAJQ8OxIyJJ7g/EnnQbsWba2ZHQBX9x2M0KoyNU0vKXRekG7p6c2FmEwzUoCRzUvshpQ4BNNS2ehIKDyR7jeP+HHtagk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com; spf=pass smtp.mailfrom=dubeyko.com; dkim=pass (2048-bit key) header.d=dubeyko-com.20251104.gappssmtp.com header.i=@dubeyko-com.20251104.gappssmtp.com header.b=yQmbrVEc; arc=none smtp.client-ip=74.125.224.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=dubeyko-com.20251104.gappssmtp.com header.i=@dubeyko-com.20251104.gappssmtp.com header.b="yQmbrVEc" Received: by mail-yx1-f54.google.com with SMTP id 956f58d0204a3-66c70f69d3fso4869815d50.1 for ; Tue, 08 Sep 2026 14:05:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20251104.gappssmtp.com; s=20251104; t=1788901506; x=1789506306; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=p7fqt/xpLD4nMGxuw74g5K5kBibq9QTHLwKBrfOGNM4=; b=yQmbrVEcmdwP6SC5BtG1fnirqIrIjUDL1iXhJQmRv/9HZKyhYn/sBbbOUYuHRXhPDM AekN4DSvj0RyhDedUCVYyNrPZRmF01U7QNhZoaSf0Us18bnRb7IsZEqcGDH9LT7/3Okb pgRSCA+oRvcW9FXzRd1+NIWZINAFDiZpJsNrNIpi7wJvvVv2jLeafEACgNaDYwjNFgrY sFEMNjWyG5IpzKIxCELxnXrfCTMCqkfiA6ETk4su1y9spJiuFxqOqjLKLbzn9m8q668u DegQ7tnFN+fEXAKM0SeX0gJbLGc6Y44ZouKuCEvSuxV073GHkFINdmwIHZpIGOz6TCKi NHNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788901506; x=1789506306; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=p7fqt/xpLD4nMGxuw74g5K5kBibq9QTHLwKBrfOGNM4=; b=eJ+nkDvdPn69gpH4+giM9BXn5evdr+/VF5kapynpTD3YoB4S5eQeRsvqceeqC8wdDg zZZT0o02rpDN0ddanE1NgxyzfzVNB6G0MzEnbvBvdJIZOkgzDWkYLWSzJ3tCjTtDa5pR Vybe/Y7UyztC9ONduG/JPYj3IAhVdjhuYWZFBc90CvUAIopBW2EcJTmp16LYEvcjNpf0 kqeWHw8BvEGgHwzZHx5mLd3I+xpKCwvDgxrQvKWlpavVU3Hw0i2cbeZWywKzfD5T7nZC 54Ky3/2zDcABWm2AapjdPu+vZ/j2wF3DnvP1KrkJ5CJ0RDSb6CH9msHMcI6yW4WT3h17 tW7Q== X-Forwarded-Encrypted: i=1; AKwUvBwWhH1KYIjtzsQkJ1Fpa6oheY2dmpK5LEmDj3BEJvZeaN6GqOUnq5ej96avT3qDCb/Wsg9MK+JtuQwsJQ8=@vger.kernel.org X-Gm-Message-State: AFuF++nh4zaCqgkdRg7NCOm0e1Gyau4CWctCnDb4JBocK7IBUFvAypJp XJ1rDbIa9FALndM81D3tkSd1WY4djNKZWVfnzCEXgVtJ+KeCo4EZzijMFbCTmXG4bFBQw23wsw+ tkRndUBIqfg== X-Gm-Gg: AYBFou2MpDUAxqa89sLykygD9lLokAPTbyFmzpdEyXnGJ+ThBXqiuCWFYrAYoVk5yDv suPlJmnlc3p39aYRSOUWG9Xr/8j3yXQOoM1QKqJgyhYzAksaMta2mbzlVmJR0hHKJu4wQIJ0k6o FrBXd1ouLnQWtFLg0maqrQcB2wxgUb1qUM0PwyeHPmxy52Y0aDUOEq1GCg8kcOirmlEIywOKGhf UyJNJWzJo3nCa17TaydCQPqMn/wc1A9yuBuhoDRDmTHBnssElEJlZwu2K9kdL63blxKE1/G4G7/ oFpNRwOvUKKJkyidxPhT++V+b7mjWfp0l5jSSAe4Kzbr+EkgTTLcnYBtDOG+P2wOuCOlpIMv732 nxtIYXuEWTME377ztqoEdmENHMbzhA3em7dnDOskFi/8SsYeSTSqVx9NXZN+w5lWdtEY3Z+2abf eZAQj7oAuAR8Cz7pcdwr+WDG9yEXwhNimf0tvcsjGnMx3XIYue7xXm8tUP+glkXlxUK+D/LGd+2 Z9+WpJkfGgG/yubfHp1vvjPN4MM3kfPdIbDJfnhjb7BXjvzzbXvU9yPscYddBivwTMAxsmlWtrz GdAoBBEyF4pW//bB X-Received: by 2002:a53:b712:0:b0:66f:9d85:8d6f with SMTP id 956f58d0204a3-66fb59a684cmr7470949d50.19.1788901505438; Tue, 08 Sep 2026 14:05:05 -0700 (PDT) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:1eca:212:86d0:4e87]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-66fb495eccesm11078129d50.18.2026.09.08.14.05.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 14:05:04 -0700 (PDT) From: Viacheslav Dubeyko To: glaubitz@physik.fu-berlin.de, frank.li@vivo.com, hch@lst.de Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, vdubeyko@coreweave.com, willy@infradead.org, brauner@kernel.org, djwong@kernel.org, Viacheslav Dubeyko Subject: [PATCH v3 4/7] hfsplus: add iomap operations for regular file data Date: Tue, 8 Sep 2026 14:04:45 -0700 Message-ID: <20260908210448.296772-5-slava@dubeyko.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260908210448.296772-1-slava@dubeyko.com> References: <20260908210448.296772-1-slava@dubeyko.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch adds iomap.h and iomap.c files. The iomap.h contains declarations of hfsplus_iomap_ops, hfsplus_write_iomap_ops, hfsplus_writeback_ops, and hfsplus_write_dio_ops operations. The iomap.c implements __hfsplus_iomap_begin(), hfsplus_write_iomap_end(), hfsplus_iomap_cont_expand(), hfsplus_writeback_range() methods that become the basis of HFS+ iomap operations. Signed-off-by: Viacheslav Dubeyko cc: Christoph Hellwig cc: John Paul Adrian Glaubitz cc: Yangtao Li cc: linux-fsdevel@vger.kernel.org Acked-by: "Darrick J. Wong" --- v2 Christoph Hellwig suggested to introduce a generalized version of iomap_dio_end_io() that was placed into include/linux/iomap.h. --- fs/hfsplus/Kconfig | 1 + fs/hfsplus/Makefile | 5 +- fs/hfsplus/hfsplus_fs.h | 16 ++++ fs/hfsplus/iomap.c | 192 ++++++++++++++++++++++++++++++++++++++++ fs/hfsplus/iomap.h | 18 ++++ include/linux/iomap.h | 20 +++++ 6 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 fs/hfsplus/iomap.c create mode 100644 fs/hfsplus/iomap.h diff --git a/fs/hfsplus/Kconfig b/fs/hfsplus/Kconfig index ca8401cb6954..865a1966f395 100644 --- a/fs/hfsplus/Kconfig +++ b/fs/hfsplus/Kconfig @@ -6,6 +6,7 @@ config HFSPLUS_FS select NLS select NLS_UTF8 select LEGACY_DIRECT_IO + select FS_IOMAP help If you say Y here, you will be able to mount extended format Macintosh-formatted hard drive partitions with full read-write access. diff --git a/fs/hfsplus/Makefile b/fs/hfsplus/Makefile index f2a9ae697e81..2416dfdc3190 100644 --- a/fs/hfsplus/Makefile +++ b/fs/hfsplus/Makefile @@ -5,8 +5,9 @@ =20 obj-$(CONFIG_HFSPLUS_FS) +=3D hfsplus.o =20 -hfsplus-objs :=3D super.o options.o inode.o ioctl.o extents.o catalog.o di= r.o btree.o \ - bnode.o brec.o bfind.o tables.o unicode.o wrapper.o bitmap.o part_tbl.o \ +hfsplus-objs :=3D super.o options.o inode.o iomap.o ioctl.o extents.o cata= log.o \ + dir.o btree.o bnode.o brec.o bfind.o tables.o unicode.o \ + wrapper.o bitmap.o part_tbl.o \ attributes.o xattr.o xattr_user.o xattr_security.o xattr_trusted.o =20 # KUnit tests diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 67586382269b..0a0df0388e7b 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -175,6 +175,22 @@ static inline struct hfsplus_sb_info *HFSPLUS_SB(struc= t super_block *sb) return sb->s_fs_info; } =20 +/* + * Physical byte offset of allocation block 'dblock' on the volume. + */ +static inline loff_t hfsplus_ablock_to_phys_bytes(struct super_block *sb, + u32 dblock) +{ + struct hfsplus_sb_info *sbi =3D HFSPLUS_SB(sb); + loff_t phys_bytes; + + phys_bytes =3D dblock; + phys_bytes <<=3D sbi->fs_shift; + phys_bytes +=3D sbi->blockoffset; + phys_bytes <<=3D sb->s_blocksize_bits; + + return phys_bytes; +} =20 struct hfsplus_inode_info { atomic_t opencnt; diff --git a/fs/hfsplus/iomap.c b/fs/hfsplus/iomap.c new file mode 100644 index 000000000000..5723e854e58e --- /dev/null +++ b/fs/hfsplus/iomap.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * iomap callback functions for the hfsplus filesystem + */ + +#include +#include + +#include "hfsplus_fs.h" +#include "hfsplus_raw.h" +#include "iomap.h" + +static int __hfsplus_iomap_begin(struct inode *inode, loff_t offset, + loff_t length, unsigned int flags, + struct iomap *iomap, bool may_alloc) +{ + struct super_block *sb =3D inode->i_sb; + struct hfsplus_sb_info *sbi =3D HFSPLUS_SB(sb); + struct hfsplus_inode_info *hip =3D HFSPLUS_I(inode); + u32 ablock, dblock, max_blocks; + loff_t ablock_offset, ablock_bytes; + loff_t block_start; + bool is_new; + int err; + + if (!may_alloc) { + /* Completely beyond EOF. Treat as hole */ + if (i_size_read(inode) <=3D offset) { + iomap->type =3D IOMAP_HOLE; + iomap->addr =3D IOMAP_NULL_ADDR; + iomap->offset =3D offset; + iomap->length =3D length; + return 0; + } + + /* Clamp length if the requested range goes beyond i_size */ + if (offset + length > i_size_read(inode)) { + loff_t i_size =3D i_size_read(inode); + unsigned int blocksize =3D i_blocksize(inode); + + length =3D round_up(i_size, blocksize) - offset; + } + } + + ablock =3D offset >> sbi->alloc_blksz_shift; + + err =3D hfsplus_map_extent(inode, ablock, may_alloc, &dblock, + &max_blocks, NULL); + if (err) + return err; + + ablock_offset =3D offset & (sbi->alloc_blksz - 1); + ablock_bytes =3D (loff_t)max_blocks << sbi->alloc_blksz_shift; + + length =3D min_t(loff_t, length, ablock_bytes - ablock_offset); + block_start =3D round_down(offset, i_blocksize(inode)); + is_new =3D may_alloc && block_start >=3D hip->phys_size; + if (may_alloc && !is_new && offset < hip->phys_size) + length =3D min_t(loff_t, length, hip->phys_size - offset); + + iomap->bdev =3D sb->s_bdev; + iomap->offset =3D offset; + iomap->length =3D length; + iomap->addr =3D hfsplus_ablock_to_phys_bytes(sb, dblock) + ablock_offset; + iomap->type =3D IOMAP_MAPPED; + iomap->flags =3D IOMAP_F_MERGED; + + if (is_new) + iomap->flags |=3D IOMAP_F_NEW; + + return 0; +} + +static int hfsplus_iomap_begin(struct inode *inode, loff_t offset, + loff_t length, unsigned int flags, + struct iomap *iomap, struct iomap *srcmap) +{ + return __hfsplus_iomap_begin(inode, + offset, length, flags, + iomap, false); +} + +static int hfsplus_write_iomap_begin(struct inode *inode, loff_t offset, + loff_t length, unsigned int flags, + struct iomap *iomap, struct iomap *srcmap) +{ + return __hfsplus_iomap_begin(inode, + offset, length, flags, + iomap, true); +} + +const struct iomap_ops hfsplus_iomap_ops =3D { + .iomap_begin =3D hfsplus_iomap_begin, +}; + +/* + * hfsplus_write_iomap_end() + * + * Advance the allocated-and-zeroed high-water mark + * (hip->phys_size / hip->fs_blocks) to cover the newly written range. + */ +static int hfsplus_write_iomap_end(struct inode *inode, loff_t pos, + loff_t length, ssize_t written, + unsigned int flags, struct iomap *iomap) +{ + struct hfsplus_inode_info *hip =3D HFSPLUS_I(inode); + struct super_block *sb =3D inode->i_sb; + loff_t end; + bool dirtied =3D false; + + if (!written) + return 0; + + end =3D pos + written; + + if (iomap->flags & IOMAP_F_NEW) + end =3D round_up(end, sb->s_blocksize); + + if (hip->phys_size < end) { + inode_add_bytes(inode, end - hip->phys_size); + hip->phys_size =3D end; + hip->fs_blocks =3D end >> sb->s_blocksize_bits; + dirtied =3D true; + } + + if (dirtied) + mark_inode_dirty(inode); + + return written; +} + +const struct iomap_ops hfsplus_write_iomap_ops =3D { + .iomap_begin =3D hfsplus_write_iomap_begin, + .iomap_end =3D hfsplus_write_iomap_end, +}; + +/* + * hfsplus_iomap_cont_expand() + * + * Zero-extend the backing store from the current phys_size up to 'size'. + * Used both by hfsplus_setattr() and by hfsplus_file_truncate(). + */ +int hfsplus_iomap_cont_expand(struct inode *inode, loff_t size) +{ + struct hfsplus_inode_info *hip =3D HFSPLUS_I(inode); + loff_t start =3D hip->phys_size; + + if (size <=3D start) + return 0; + + return iomap_zero_range(inode, start, size - start, NULL, + &hfsplus_write_iomap_ops, NULL, NULL); +} + +/* + * hfsplus_writeback_range() - map folio during writeback + * + * Called for each folio during writeback. If the folio falls outside + * the current iomap, remaps by calling __hfsplus_iomap_begin() again. + */ +static ssize_t hfsplus_writeback_range(struct iomap_writepage_ctx *wpc, + struct folio *folio, u64 offset, + unsigned int len, u64 end_pos) +{ + int err; + + if (offset < wpc->iomap.offset || + offset >=3D wpc->iomap.offset + wpc->iomap.length) { + err =3D __hfsplus_iomap_begin(wpc->inode, + offset, len, 0, + &wpc->iomap, false); + if (err) + return err; + } + + return iomap_add_to_ioend(wpc, folio, offset, end_pos, len); +} + +const struct iomap_writeback_ops hfsplus_writeback_ops =3D { + .writeback_range =3D hfsplus_writeback_range, + .writeback_submit =3D iomap_ioend_writeback_submit, +}; + +const struct iomap_dio_ops hfsplus_write_dio_ops =3D { + .end_io =3D iomap_dio_end_io, +}; + +int hfsplus_iomap_swap_activate(struct swap_info_struct *sis, + struct file *file, sector_t *span) +{ + return iomap_swapfile_activate(sis, file, span, &hfsplus_iomap_ops); +} diff --git a/fs/hfsplus/iomap.h b/fs/hfsplus/iomap.h new file mode 100644 index 000000000000..dac07a9d25f8 --- /dev/null +++ b/fs/hfsplus/iomap.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * iomap callback declarations for the hfsplus filesystem + */ + +#ifndef _LINUX_HFSPLUS_IOMAP_H +#define _LINUX_HFSPLUS_IOMAP_H + +extern const struct iomap_ops hfsplus_iomap_ops; +extern const struct iomap_ops hfsplus_write_iomap_ops; +extern const struct iomap_writeback_ops hfsplus_writeback_ops; +extern const struct iomap_dio_ops hfsplus_write_dio_ops; + +int hfsplus_iomap_cont_expand(struct inode *inode, loff_t size); +int hfsplus_iomap_swap_activate(struct swap_info_struct *sis, + struct file *file, sector_t *span); + +#endif /* _LINUX_HFSPLUS_IOMAP_H */ diff --git a/include/linux/iomap.h b/include/linux/iomap.h index bc7ae6327dbf..66a6389c9c74 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -636,6 +636,26 @@ struct iomap_dio_ops { struct bio_set *bio_set; }; =20 +/* + * Direct I/O completion handler + */ +static inline +int iomap_dio_end_io(struct kiocb *iocb, ssize_t size, + int error, unsigned int flags) +{ + struct inode *inode =3D file_inode(iocb->ki_filp); + + if (error) + return error; + + if (size && i_size_read(inode) < iocb->ki_pos + size) { + i_size_write(inode, iocb->ki_pos + size); + mark_inode_dirty(inode); + } + + return 0; +} + /* * Wait for the I/O to complete in iomap_dio_rw even if the kiocb is not * synchronous. --=20 2.43.0 From nobody Fri Sep 25 20:02:39 2026 Received: from mail-yx1-f46.google.com (mail-yx1-f46.google.com [74.125.224.46]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6D82243DA3A for ; Tue, 8 Sep 2026 21:05:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.224.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788901510; cv=none; b=cfodNVB+1h7rbZqu6jZC7+mpr698SUzamZbIYqpFyhlkmvomesNGYbPF/ARZT+MNJkpAWaRKkYxrzVs5gkgIlQuYjPvZcBWZ/vaJPdqMrqnPImbyzaz4d7DhYJBWKC3Gs5PL18rbcpWtzLlH3tdHrRSkwWY6H7DTNUUS1xoLsFQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788901510; c=relaxed/simple; bh=z8nxWyZBGM2mWMHN3Gb3eNdOXLjX6i/8WNe3N3r6Jjo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bg6Jv7+2CVMvnrpPyYuqt2zofKbl9ol0VvGJzLNwHqsrFZ9dmuk7o8UZukCQjkjDPqlWT8mhrUo3lHKdjNEErqOTQYDVoJCKk0QpOHTAsnqM+EHZj+2SNGmdXdmab28ALyBoEYWizNlcOaH7ElXp49Vho4yIS3KcRQZatobfYaI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com; spf=pass smtp.mailfrom=dubeyko.com; dkim=pass (2048-bit key) header.d=dubeyko-com.20251104.gappssmtp.com header.i=@dubeyko-com.20251104.gappssmtp.com header.b=nqzFr5b/; arc=none smtp.client-ip=74.125.224.46 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=dubeyko-com.20251104.gappssmtp.com header.i=@dubeyko-com.20251104.gappssmtp.com header.b="nqzFr5b/" Received: by mail-yx1-f46.google.com with SMTP id 956f58d0204a3-66fa10f35caso4745378d50.3 for ; Tue, 08 Sep 2026 14:05:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20251104.gappssmtp.com; s=20251104; t=1788901507; x=1789506307; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=06j1qeZXVtj7Nz/ZYPnBZzCHEmkktKQWmdPGkPaUsk8=; b=nqzFr5b/pTtjcRg+Jqu0gCaCp4Wu5A69pa2YxpkdUmc2bTVF/LRUnxEHbTZ63PaptX BZd86Z/LAQiNAqf4pC0ljgxT8Kyo7gDqWFjQF0gX+koipfsHIXXzof4APdNwUQlv9168 qHcIinySHa7VtlRcC+m8lUcV/DwxEbKJv7XKNKLuehXgHLvRwqcyJ5c7iShIfTx/Kd8J 73/NqlEpEnsvUBw3ou+iX+beAyAwuZRwJi7RaG8xT64fNRwwe4DlFfb/KR6kYNELqzAo lY/uMsITl6UMFRrrh2qs8F3dPepBguKy1SJPYAxooiLS0+96BSp0UUMwexkK+/rMQlbH PUvA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788901507; x=1789506307; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=06j1qeZXVtj7Nz/ZYPnBZzCHEmkktKQWmdPGkPaUsk8=; b=JXQOJQRjQwAlVlG+Xx/wLyXGrsKBa9qRmAG5iNLj/gpioGRJNbU16VOJYyFwX9BnOd jBsIiOLEFrkpB1kmLt3EFXeIP4YowSsufSBxPgaQ4yW8TiQPwrdkl0MLaRJuSeVGWdpR 1YyYQcQNMvrYYHEy/hm6sZuy1CpPqFF1scQ0DU5n/iRb01wNhz6Lh9jdIGu2inbQWTYg Io+gPUWSykJ2s0ixopauTNZA/Gp/T40Mfwxb8DmFm9qn7TuZGyIZJ9KO/oT38Xihrkxd mdEvvdmFgd9II2kp/V4rk6QTl5RLQN6Tpz40vShT9isrvArZbMoDwaijOULTqi27Vihw H3RQ== X-Forwarded-Encrypted: i=1; AKwUvBxEwABSso6SQwVmkHxLe2155u8JKF/44Rsqwkz+JSN5NCG9QZH7EiFtm2AQCKdZzq1GrMrKuSXRuwysGPs=@vger.kernel.org X-Gm-Message-State: AFuF++k87h/qgVp+66+18F2c3O8Gk1utsMszqi3WN6IczeF2WOJx1QEs 0WfbOeUq63z4yl6Nx72YS33Tec3wD/6uuwSUsLgvY/z5QzGwQVyv1Wfboo9gtg6/OWQ5C5Zfu03 e2yfgfcKAhw== X-Gm-Gg: AYBFou0jdCSfMPMFA+686Yd+oADzxeQl5NvmJFVZaiMNorlUt4F5G3G4s6XPjPm20dV r48kHEgz1T67/+HZqWdXV+mxStnQ3gVYUMr21DYXf2flYHDcVm4eji93DIpW+M1eec5/dF2CLE8 8RbvIgzHFPl4fr4+iPm6pW0e0R6Y9LJR3Z7bhsINVjTERLkQ23r9Vx4Ht7OKwFIHs3gRreJpWu/ 3p59rCtMOC6keVzk0vt6m1ItfI6ZUH/e6aOSZPoIlwN+YOOLYnAdNNPUjb5t4Ar9C7jqu8u8mYw QyZfnKRfUQWV/qwDdlX1YXmQVoCP06GwlQM3NXxg2RZ+Z0CL/ejKSktW78tV4/RrsA12xk6Req2 HtOO1xIG1ajHrSWeAwbNk9kfC5wjlxIiG6H7IXQY5w5WGGYZFrXm9QjmHaKGfMb6rGWtOmTWl2p I/E5SCUCMtrd3nsEoGsEn+rYQQ5LhPtLyD4Js2YHj2wG0clECMW7ipVbsYL9suK6zo1JRO7/B4X G1iCar8bx5Ihfj/tTAYUJA6gJkJ2mbWTywnvlkdA4oXoymqSvBPCVmBk4U2oEGZ39ct2C/LBAHF qDOusyy3o2lWXkB8 X-Received: by 2002:a05:690e:13cf:b0:66f:8731:8d1 with SMTP id 956f58d0204a3-66fb5a646bcmr9702655d50.39.1788901507316; Tue, 08 Sep 2026 14:05:07 -0700 (PDT) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:1eca:212:86d0:4e87]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-66fb495eccesm11078129d50.18.2026.09.08.14.05.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 14:05:06 -0700 (PDT) From: Viacheslav Dubeyko To: glaubitz@physik.fu-berlin.de, frank.li@vivo.com, hch@lst.de Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, vdubeyko@coreweave.com, willy@infradead.org, brauner@kernel.org, djwong@kernel.org, Viacheslav Dubeyko Subject: [PATCH v3 5/7] hfsplus: move file related operations to file.c Date: Tue, 8 Sep 2026 14:04:46 -0700 Message-ID: <20260908210448.296772-6-slava@dubeyko.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260908210448.296772-1-slava@dubeyko.com> References: <20260908210448.296772-1-slava@dubeyko.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch introduces fs/hfsplus/file.c and moves file related operations from fs/hfsplus/inode.c into the new file. Signed-off-by: Viacheslav Dubeyko cc: Christoph Hellwig cc: John Paul Adrian Glaubitz cc: Yangtao Li cc: linux-fsdevel@vger.kernel.org Acked-by: "Darrick J. Wong" --- fs/hfsplus/Makefile | 6 +- fs/hfsplus/file.c | 133 ++++++++++++++++++++++++++++++++++++++++ fs/hfsplus/hfsplus_fs.h | 7 ++- fs/hfsplus/inode.c | 122 ------------------------------------ 4 files changed, 141 insertions(+), 127 deletions(-) create mode 100644 fs/hfsplus/file.c diff --git a/fs/hfsplus/Makefile b/fs/hfsplus/Makefile index 2416dfdc3190..3ddea69a9c69 100644 --- a/fs/hfsplus/Makefile +++ b/fs/hfsplus/Makefile @@ -5,9 +5,9 @@ =20 obj-$(CONFIG_HFSPLUS_FS) +=3D hfsplus.o =20 -hfsplus-objs :=3D super.o options.o inode.o iomap.o ioctl.o extents.o cata= log.o \ - dir.o btree.o bnode.o brec.o bfind.o tables.o unicode.o \ - wrapper.o bitmap.o part_tbl.o \ +hfsplus-objs :=3D super.o options.o inode.o file.o iomap.o ioctl.o extents= .o \ + catalog.o dir.o btree.o bnode.o brec.o bfind.o tables.o \ + unicode.o wrapper.o bitmap.o part_tbl.o \ attributes.o xattr.o xattr_user.o xattr_security.o xattr_trusted.o =20 # KUnit tests diff --git a/fs/hfsplus/file.c b/fs/hfsplus/file.c new file mode 100644 index 000000000000..509046aad0c6 --- /dev/null +++ b/fs/hfsplus/file.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * File operations: open/release/fsync and iomap-based read/write/seek + */ + +#include +#include +#include + +#include "hfsplus_fs.h" +#include "hfsplus_raw.h" + +static int hfsplus_file_open(struct inode *inode, struct file *file) +{ + if (HFSPLUS_IS_RSRC(inode)) + inode =3D HFSPLUS_I(inode)->rsrc_inode; + if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) + return -EOVERFLOW; + atomic_inc(&HFSPLUS_I(inode)->opencnt); + return 0; +} + +static int hfsplus_file_release(struct inode *inode, struct file *file) +{ + struct super_block *sb =3D inode->i_sb; + + if (HFSPLUS_IS_RSRC(inode)) + inode =3D HFSPLUS_I(inode)->rsrc_inode; + if (atomic_dec_and_test(&HFSPLUS_I(inode)->opencnt)) { + inode_lock(inode); + hfsplus_file_truncate(inode); + if (inode->i_flags & S_DEAD) { + hfsplus_delete_cat(inode->i_ino, + HFSPLUS_SB(sb)->hidden_dir, NULL); + hfsplus_delete_inode(inode); + } + inode_unlock(inode); + } + return 0; +} + +int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, + int datasync) +{ + struct inode *inode =3D file->f_mapping->host; + struct hfsplus_inode_info *hip =3D HFSPLUS_I(inode); + struct super_block *sb =3D inode->i_sb; + struct hfsplus_sb_info *sbi =3D HFSPLUS_SB(inode->i_sb); + struct hfsplus_vh *vhdr =3D sbi->s_vhdr; + int error =3D 0, error2; + + hfs_dbg("inode->i_ino %llu, start %llu, end %llu\n", + inode->i_ino, start, end); + + error =3D file_write_and_wait_range(file, start, end); + if (error) + return error; + inode_lock(inode); + + /* + * Sync inode metadata into the catalog and extent trees. + */ + sync_inode_metadata(inode, 1); + + /* + * And explicitly write out the btrees. + */ + if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, + &HFSPLUS_I(HFSPLUS_CAT_TREE_I(sb))->flags)) { + clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags); + error =3D filemap_write_and_wait(sbi->cat_tree->inode->i_mapping); + } + + if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, + &HFSPLUS_I(HFSPLUS_EXT_TREE_I(sb))->flags)) { + clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags); + error2 =3D + filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); + if (!error) + error =3D error2; + } + + if (sbi->attr_tree) { + if (test_and_clear_bit(HFSPLUS_I_ATTR_DIRTY, + &HFSPLUS_I(HFSPLUS_ATTR_TREE_I(sb))->flags)) { + clear_bit(HFSPLUS_I_ATTR_DIRTY, &hip->flags); + error2 =3D + filemap_write_and_wait( + sbi->attr_tree->inode->i_mapping); + if (!error) + error =3D error2; + } + } else { + if (test_and_clear_bit(HFSPLUS_I_ATTR_DIRTY, &hip->flags)) + pr_err("sync non-existent attributes tree\n"); + } + + if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, + &HFSPLUS_I(sbi->alloc_file)->flags)) { + clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags); + error2 =3D filemap_write_and_wait(sbi->alloc_file->i_mapping); + if (!error) + error =3D error2; + } + + mutex_lock(&sbi->vh_mutex); + hfsplus_prepare_volume_header_for_commit(vhdr); + mutex_unlock(&sbi->vh_mutex); + + error2 =3D hfsplus_commit_superblock(inode->i_sb); + if (!error) + error =3D error2; + + if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) + blkdev_issue_flush(inode->i_sb->s_bdev); + + inode_unlock(inode); + + return error; +} + +const struct file_operations hfsplus_file_operations =3D { + .llseek =3D generic_file_llseek, + .read_iter =3D generic_file_read_iter, + .write_iter =3D generic_file_write_iter, + .mmap_prepare =3D generic_file_mmap_prepare, + .splice_read =3D filemap_splice_read, + .splice_write =3D iter_file_splice_write, + .fsync =3D hfsplus_file_fsync, + .open =3D hfsplus_file_open, + .release =3D hfsplus_file_release, + .unlocked_ioctl =3D hfsplus_ioctl, +}; diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 0a0df0388e7b..190c7de704fd 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -446,6 +446,11 @@ int hfsplus_rename_cat(u32 cnid, struct inode *src_dir= , const struct qstr *src_n extern const struct inode_operations hfsplus_dir_inode_operations; extern const struct file_operations hfsplus_dir_operations; =20 +/* file.c */ +extern const struct file_operations hfsplus_file_operations; +int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, + int datasync); + /* extents.c */ int hfsplus_ext_cmp_key(const hfsplus_btree_key *k1, const hfsplus_btree_key *k2); @@ -480,8 +485,6 @@ int hfsplus_cat_write_inode(struct inode *inode); int hfsplus_getattr(struct mnt_idmap *idmap, const struct path *path, struct kstat *stat, u32 request_mask, unsigned int query_flags); -int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync); int hfsplus_fileattr_get(struct dentry *dentry, struct file_kattr *fa); int hfsplus_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, struct file_kattr *fa); diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 2ce6de574fa6..9d25e6224ee5 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -276,35 +276,6 @@ static int hfsplus_get_perms(struct inode *inode, return -EIO; } =20 -static int hfsplus_file_open(struct inode *inode, struct file *file) -{ - if (HFSPLUS_IS_RSRC(inode)) - inode =3D HFSPLUS_I(inode)->rsrc_inode; - if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) - return -EOVERFLOW; - atomic_inc(&HFSPLUS_I(inode)->opencnt); - return 0; -} - -static int hfsplus_file_release(struct inode *inode, struct file *file) -{ - struct super_block *sb =3D inode->i_sb; - - if (HFSPLUS_IS_RSRC(inode)) - inode =3D HFSPLUS_I(inode)->rsrc_inode; - if (atomic_dec_and_test(&HFSPLUS_I(inode)->opencnt)) { - inode_lock(inode); - hfsplus_file_truncate(inode); - if (inode->i_flags & S_DEAD) { - hfsplus_delete_cat(inode->i_ino, - HFSPLUS_SB(sb)->hidden_dir, NULL); - hfsplus_delete_inode(inode); - } - inode_unlock(inode); - } - return 0; -} - static int hfsplus_setattr(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *attr) { @@ -361,86 +332,6 @@ int hfsplus_getattr(struct mnt_idmap *idmap, const str= uct path *path, return 0; } =20 -int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync) -{ - struct inode *inode =3D file->f_mapping->host; - struct hfsplus_inode_info *hip =3D HFSPLUS_I(inode); - struct super_block *sb =3D inode->i_sb; - struct hfsplus_sb_info *sbi =3D HFSPLUS_SB(inode->i_sb); - struct hfsplus_vh *vhdr =3D sbi->s_vhdr; - int error =3D 0, error2; - - hfs_dbg("inode->i_ino %llu, start %llu, end %llu\n", - inode->i_ino, start, end); - - error =3D file_write_and_wait_range(file, start, end); - if (error) - return error; - inode_lock(inode); - - /* - * Sync inode metadata into the catalog and extent trees. - */ - sync_inode_metadata(inode, 1); - - /* - * And explicitly write out the btrees. - */ - if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, - &HFSPLUS_I(HFSPLUS_CAT_TREE_I(sb))->flags)) { - clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags); - error =3D filemap_write_and_wait(sbi->cat_tree->inode->i_mapping); - } - - if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, - &HFSPLUS_I(HFSPLUS_EXT_TREE_I(sb))->flags)) { - clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags); - error2 =3D - filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); - if (!error) - error =3D error2; - } - - if (sbi->attr_tree) { - if (test_and_clear_bit(HFSPLUS_I_ATTR_DIRTY, - &HFSPLUS_I(HFSPLUS_ATTR_TREE_I(sb))->flags)) { - clear_bit(HFSPLUS_I_ATTR_DIRTY, &hip->flags); - error2 =3D - filemap_write_and_wait( - sbi->attr_tree->inode->i_mapping); - if (!error) - error =3D error2; - } - } else { - if (test_and_clear_bit(HFSPLUS_I_ATTR_DIRTY, &hip->flags)) - pr_err("sync non-existent attributes tree\n"); - } - - if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, - &HFSPLUS_I(sbi->alloc_file)->flags)) { - clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags); - error2 =3D filemap_write_and_wait(sbi->alloc_file->i_mapping); - if (!error) - error =3D error2; - } - - mutex_lock(&sbi->vh_mutex); - hfsplus_prepare_volume_header_for_commit(vhdr); - mutex_unlock(&sbi->vh_mutex); - - error2 =3D hfsplus_commit_superblock(inode->i_sb); - if (!error) - error =3D error2; - - if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) - blkdev_issue_flush(inode->i_sb->s_bdev); - - inode_unlock(inode); - - return error; -} - static const struct inode_operations hfsplus_file_inode_operations =3D { .setattr =3D hfsplus_setattr, .getattr =3D hfsplus_getattr, @@ -462,19 +353,6 @@ static const struct inode_operations hfsplus_special_i= node_operations =3D { .listxattr =3D hfsplus_listxattr, }; =20 -static const struct file_operations hfsplus_file_operations =3D { - .llseek =3D generic_file_llseek, - .read_iter =3D generic_file_read_iter, - .write_iter =3D generic_file_write_iter, - .mmap_prepare =3D generic_file_mmap_prepare, - .splice_read =3D filemap_splice_read, - .splice_write =3D iter_file_splice_write, - .fsync =3D hfsplus_file_fsync, - .open =3D hfsplus_file_open, - .release =3D hfsplus_file_release, - .unlocked_ioctl =3D hfsplus_ioctl, -}; - struct inode *hfsplus_new_inode(struct super_block *sb, struct inode *dir, umode_t mode) { --=20 2.43.0 From nobody Fri Sep 25 20:02:39 2026 Received: from mail-yx1-f52.google.com (mail-yx1-f52.google.com [74.125.224.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DED1D397694 for ; Tue, 8 Sep 2026 21:05:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.224.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788901513; cv=none; b=R4qsjeducI3rCHtX0dBYPZ8QBwnZPz03mhYLcxeyhIirs/aS3/X2Tq+R++lm6F5gv4WsQpu/Gztcv9npt4zUqiJqlUI/l7DQd5amU4rJLDSZvP1IxpGbJVoX6j5ZCdeJR5m+Lzd81QtpsI9lYp/hL2imhK92JIIpx3SC33cUJWw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788901513; c=relaxed/simple; bh=42I35uP+T2RKk6zm3JgzNzDDhA62OAJCoQgZDD/A9vg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TflqAupMqm91abRYH7zXFBYmDE5XVSYIne9tNttS4HWP1AfNDIzJr5zGNXo7aFer5lO55eOMVRNsJps4eM2atZ8nEU5ymM0MFP1bcnZCkKapS2qwM3X6/6JcCsve2AVEy0N5fKYqy5DmQNnLBl/0Zm38iH0jGe8I7eti6qok9Lc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com; spf=pass smtp.mailfrom=dubeyko.com; dkim=pass (2048-bit key) header.d=dubeyko-com.20251104.gappssmtp.com header.i=@dubeyko-com.20251104.gappssmtp.com header.b=GJMoyE9O; arc=none smtp.client-ip=74.125.224.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=dubeyko-com.20251104.gappssmtp.com header.i=@dubeyko-com.20251104.gappssmtp.com header.b="GJMoyE9O" Received: by mail-yx1-f52.google.com with SMTP id 956f58d0204a3-66bd7857841so5336080d50.3 for ; Tue, 08 Sep 2026 14:05:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20251104.gappssmtp.com; s=20251104; t=1788901511; x=1789506311; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=qge724P+XpXSfbtGHt9SyIYo0wf5keByX8rsQYDNqZk=; b=GJMoyE9O0H4qJQRaB1oHDK+Twtrzk4EYapBEAYjkZJbuG6Lx8rxZRx6KKot+kREs+s tyJPEaK/3+z+Yiq/bqb9tdzDhBVSOI/fBL87intr+4ZiExkSto/Z7AugEA9iYLjvRgxj TiokpjU60u8/KoGKEVNSXvkI02wru79bmK865Vtmayru0nE4gC0UXBBINmh6X/H6WbfH 5zDKMsJZxQ1mFWA44+ciXO4hnEBJNEkrU0WzIeVa9cErYY8KoOdBsGFMX8LoQl863Lsx Fj4Klz8XpIb8K5+XVJc23XgNgAIftj8b+OOCITE5OCuh2/X1CL2QQ/AbE3PXFQNgC300 n+0w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788901511; x=1789506311; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=qge724P+XpXSfbtGHt9SyIYo0wf5keByX8rsQYDNqZk=; b=Scc/r+On9L9TfQ856KyvFg0CG2N2nMvavIJuHMRseqjcObik6fSgbH81zFVn8ZHNwX 9w1lp5lnbax5rmIEfrg2DN+/BZv70q/6nKTxXUFnWNN+EE42wXllzcen048ptBbnt5IS HF71hqLPVoWCFYUF7XJ8LLWElRPAM0MiXx3vFHIn8XqVp12Hu52GPym29X6PAKyjpElr 68iVr+fOoOuUwAj3Afcsle8ZXbmrrWlpWcUmk/20/DooFDD3TufdNfY/N3OynZhg3Ytc hQQBs5nLJ58tAk8m4zABNgxX1Uvcfg2oo40nCD9FzMJOI176ueXbQRypAJ/z/Q4/54XB eDKg== X-Forwarded-Encrypted: i=1; AKwUvBy6A8pzhmHde+8OLNs8nJbvgk/fAC38VkG3pdNw90keNaDalzM63R7hVXGfkFCDBzK5ewyxAjihzRSh59I=@vger.kernel.org X-Gm-Message-State: AFuF++nkj/e7wdgNOCJpipAvKoVr56pe7cNXWosGZ4pJePexWIkEXW5d PdNVUuDheAYqoFQlnAbQj9u1LuH3HUc0BiUkdO7M5/C9t8o0k63sKB0OhgEqjv5yQf0= X-Gm-Gg: AYBFou2x5FOgDtU6qKPBUNyPMb3LTKfkHxViMmY9F3Y2mXaGBtkCsvIopg0rzIkOM7t O79Al4y6PdfbejSNgCSw5NbExut7cvA8oTUfcLOLeO+nuyVIXxFGQhEcbinBslL+ugMwfHmON60 BrnrhsiRlfbAh/afUYccAGuHSTbYcCjf4InDd14E8gmwlQKJVpjzutxSyDJq46XCRL9owfT6pdo jsSRcabcdmHQfNyB6OaJRNJhH8NyRY5ESK7Q0q+OcvIHlFCbCt/1tsvODyzB/pXXe0VTJLBW2ak RFGRlpGPMtWvpTxryaACd03hANqP0aFSp0Tx2lHp386vXd6iKEPy9JF2rcl0YY1ehzQfbI+h9up sZCdY0sINkqfpv00vZhVYRRKJU5OiLeDba6WCXzAkP84YR4gP0tSux5kd7Pcy/9HlkiIwixb/TC 1bHX+IZbCz4k+li+hhDqcjvVLkxBJZRasAKXlEaT+v9RdWb59qL0nkT+p2GV854cyLubxpoJjBY X4+me0xQs8XpvQzaE1gaIqGYcWveoaDPI5yb69YwyFCOvopbcUJHmsacoVayl9J/VrMFfmqgkEF XddqF1uJ8UrucTxp X-Received: by 2002:a53:a9d2:0:b0:66f:c1bc:c094 with SMTP id 956f58d0204a3-66fc1bcc696mr5739900d50.92.1788901510601; Tue, 08 Sep 2026 14:05:10 -0700 (PDT) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:1eca:212:86d0:4e87]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-66fb495eccesm11078129d50.18.2026.09.08.14.05.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 14:05:09 -0700 (PDT) From: Viacheslav Dubeyko To: glaubitz@physik.fu-berlin.de, frank.li@vivo.com, hch@lst.de Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, vdubeyko@coreweave.com, willy@infradead.org, brauner@kernel.org, djwong@kernel.org, Viacheslav Dubeyko Subject: [PATCH v3 6/7] hfsplus: introduce iomap-based file_operations Date: Tue, 8 Sep 2026 14:04:47 -0700 Message-ID: <20260908210448.296772-7-slava@dubeyko.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260908210448.296772-1-slava@dubeyko.com> References: <20260908210448.296772-1-slava@dubeyko.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch implements specialized iomap-based hfsplus_file_llseek(), hfsplus_file_read_iter(), and hfsplus_file_write_iter() methods. Signed-off-by: Viacheslav Dubeyko cc: Christoph Hellwig cc: John Paul Adrian Glaubitz cc: Yangtao Li cc: linux-fsdevel@vger.kernel.org Acked-by: "Darrick J. Wong" --- fs/hfsplus/file.c | 181 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 176 insertions(+), 5 deletions(-) diff --git a/fs/hfsplus/file.c b/fs/hfsplus/file.c index 509046aad0c6..5a5776881c3e 100644 --- a/fs/hfsplus/file.c +++ b/fs/hfsplus/file.c @@ -6,9 +6,11 @@ #include #include #include +#include =20 #include "hfsplus_fs.h" #include "hfsplus_raw.h" +#include "iomap.h" =20 static int hfsplus_file_open(struct inode *inode, struct file *file) { @@ -17,6 +19,7 @@ static int hfsplus_file_open(struct inode *inode, struct = file *file) if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) return -EOVERFLOW; atomic_inc(&HFSPLUS_I(inode)->opencnt); + file->f_mode |=3D FMODE_CAN_ODIRECT; return 0; } =20 @@ -55,7 +58,6 @@ int hfsplus_file_fsync(struct file *file, loff_t start, l= off_t end, error =3D file_write_and_wait_range(file, start, end); if (error) return error; - inode_lock(inode); =20 /* * Sync inode metadata into the catalog and extent trees. @@ -114,15 +116,184 @@ int hfsplus_file_fsync(struct file *file, loff_t sta= rt, loff_t end, if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) blkdev_issue_flush(inode->i_sb->s_bdev); =20 + return error; +} + +/* + * hfsplus_fallback_buffered_write() - fall back to buffered I/O for the + * tail of a write that iomap_dio_rw() could not perform directly + * (unaligned tail, or no blocks could be mapped without allocation + * outside the direct path). + */ +static ssize_t hfsplus_fallback_buffered_write(struct kiocb *iocb, + struct iov_iter *from) +{ + loff_t offset =3D iocb->ki_pos, end; + ssize_t written; + int ret; + + iocb->ki_flags &=3D ~IOCB_DIRECT; + + written =3D iomap_file_buffered_write(iocb, from, + &hfsplus_write_iomap_ops, + NULL, NULL); + if (written < 0) + return written; + + end =3D iocb->ki_pos + written - 1; + ret =3D filemap_write_and_wait_range(iocb->ki_filp->f_mapping, + offset, end); + if (ret) + return -EIO; + + invalidate_mapping_pages(iocb->ki_filp->f_mapping, + offset >> PAGE_SHIFT, + end >> PAGE_SHIFT); + + return written; +} + +static ssize_t hfsplus_dio_write_iter(struct kiocb *iocb, + struct iov_iter *from, + unsigned int dio_flags) +{ + ssize_t ret; + + ret =3D iomap_dio_rw(iocb, from, + &hfsplus_write_iomap_ops, + &hfsplus_write_dio_ops, + dio_flags, NULL, 0); + if (ret =3D=3D -ENOTBLK) + ret =3D 0; + else if (ret < 0) + return ret; + + if (iov_iter_count(from)) { + ssize_t written; + + written =3D hfsplus_fallback_buffered_write(iocb, from); + if (written < 0) + return written; + ret +=3D written; + } + + return ret; +} + +static ssize_t hfsplus_file_write_iter(struct kiocb *iocb, + struct iov_iter *iter) +{ + struct file *file =3D iocb->ki_filp; + struct inode *inode =3D file_inode(file); + struct hfsplus_sb_info *sbi =3D HFSPLUS_SB(inode->i_sb); + loff_t total_capacity; + ssize_t ret; + int err; + + inode_lock(inode); + + ret =3D generic_write_checks(iocb, iter); + if (ret <=3D 0) + goto unlock; + + total_capacity =3D (loff_t)sbi->total_blocks << sbi->alloc_blksz_shift; + if (iocb->ki_pos >=3D total_capacity) { + ret =3D -EFBIG; + goto unlock; + } + + err =3D file_modified(file); + if (err) { + ret =3D err; + goto unlock; + } + + if (iocb->ki_pos > i_size_read(inode)) { + loff_t old_size =3D i_size_read(inode); + + i_size_write(inode, iocb->ki_pos); + err =3D hfsplus_iomap_cont_expand(inode, iocb->ki_pos); + if (err) { + i_size_write(inode, old_size); + ret =3D err; + goto unlock; + } + mark_inode_dirty(inode); + } + + if (iocb->ki_flags & IOCB_DIRECT) { + unsigned int dio_flags =3D 0; + + if (iocb->ki_pos + iov_iter_count(iter) > + HFSPLUS_I(inode)->phys_size) + dio_flags |=3D IOMAP_DIO_FORCE_WAIT; + + ret =3D hfsplus_dio_write_iter(iocb, iter, dio_flags); + } else { + ret =3D iomap_file_buffered_write(iocb, iter, + &hfsplus_write_iomap_ops, + NULL, NULL); + } + +unlock: inode_unlock(inode); =20 - return error; + if (ret > 0) + ret =3D generic_write_sync(iocb, ret); + + return ret; +} + +static ssize_t hfsplus_file_read_iter(struct kiocb *iocb, + struct iov_iter *iter) +{ + struct inode *inode =3D file_inode(iocb->ki_filp); + ssize_t ret; + + inode_lock_shared(inode); + + if (iocb->ki_flags & IOCB_DIRECT) { + file_accessed(iocb->ki_filp); + ret =3D iomap_dio_rw(iocb, iter, + &hfsplus_iomap_ops, + NULL, 0, NULL, 0); + } else + ret =3D generic_file_read_iter(iocb, iter); + + inode_unlock_shared(inode); + + return ret; +} + +static loff_t hfsplus_file_llseek(struct file *file, loff_t offset, int wh= ence) +{ + struct inode *inode =3D file->f_mapping->host; + + switch (whence) { + case SEEK_HOLE: + inode_lock_shared(inode); + offset =3D iomap_seek_hole(inode, offset, &hfsplus_iomap_ops); + inode_unlock_shared(inode); + break; + case SEEK_DATA: + inode_lock_shared(inode); + offset =3D iomap_seek_data(inode, offset, &hfsplus_iomap_ops); + inode_unlock_shared(inode); + break; + default: + return generic_file_llseek(file, offset, whence); + } + + if (offset < 0) + return offset; + + return vfs_setpos(file, offset, inode->i_sb->s_maxbytes); } =20 const struct file_operations hfsplus_file_operations =3D { - .llseek =3D generic_file_llseek, - .read_iter =3D generic_file_read_iter, - .write_iter =3D generic_file_write_iter, + .llseek =3D hfsplus_file_llseek, + .read_iter =3D hfsplus_file_read_iter, + .write_iter =3D hfsplus_file_write_iter, .mmap_prepare =3D generic_file_mmap_prepare, .splice_read =3D filemap_splice_read, .splice_write =3D iter_file_splice_write, --=20 2.43.0 From nobody Fri Sep 25 20:02:39 2026 Received: from mail-yx1-f45.google.com (mail-yx1-f45.google.com [74.125.224.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 66E97471CE9 for ; Tue, 8 Sep 2026 21:05:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.224.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788901515; cv=none; b=K4fYeUduNFAn/oXKK96RXHkhbw1vpD/ibtM8P+zplOVDGdRjuTwj4nU2az96djERnqZkRr5UOADsvDgZ6YZX0lBNTtyHXTU0r6UvtUK997dI6nYHwv1xmbG1+L1OCJmraMKvSWS5lYTxfYQ+H8davEA8OyWd9GM3dcgQH4AaWxo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788901515; c=relaxed/simple; bh=67SyYzIwQeaVB8qECauKzU1vkj6OlxuDbwBH9VfjrDg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PK+FWsnRYdQOGWcKRby71P1bkIWA3R9JaMSgD3/mNBxJLtYB3tcsAqzyOvsNrwTJPWAk6FHHlx0Xftd3VGEikxh94JnpCAo4IBrNf2/yTwiOzNbBFdNS6wHLmjOQ7dYEhBY+ANQFE1MBAybdssSrK63lHxjIDthOZjIrG/NSrkI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com; spf=pass smtp.mailfrom=dubeyko.com; dkim=pass (2048-bit key) header.d=dubeyko-com.20251104.gappssmtp.com header.i=@dubeyko-com.20251104.gappssmtp.com header.b=H8/ov4IQ; arc=none smtp.client-ip=74.125.224.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=dubeyko.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=dubeyko-com.20251104.gappssmtp.com header.i=@dubeyko-com.20251104.gappssmtp.com header.b="H8/ov4IQ" Received: by mail-yx1-f45.google.com with SMTP id 956f58d0204a3-66f8053e7afso3405602d50.0 for ; Tue, 08 Sep 2026 14:05:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20251104.gappssmtp.com; s=20251104; t=1788901512; x=1789506312; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=b82npGyG+u9YzhjLZY8NY3sClLJXpbhUpD4i89Dp3Kw=; b=H8/ov4IQHoWfy92miFqKjYIsQ5FrXXJqCLZx/Vi2YeE1oUNWx9ALy3IjtqgbDHSI/N aPOl1KuEHfGKpWcd5+3bM4uy5PjCuu8TGg7X6E1YmYcGzWS4lgaExrZ4BeD1OgkdmscW 2vFPhTUR9PUIh6jKUlb3rWukTZqpbdNljIDUJxwFKUg4BllEZO++/GqXY0hJsfDhoFZp jomvNt+qV2IJeX7Pl88RVcSBrS/0mF8DmpEho9N7zDLQU5cAGPaKxA6dH/88i+TAI9sY K25Qbg1fcAlDPUPmOantWGc3vw2wDs50PjW3jP8t94Ps3C6yFBxQ/8fHq0ekw48zebYY alkA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788901512; x=1789506312; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=b82npGyG+u9YzhjLZY8NY3sClLJXpbhUpD4i89Dp3Kw=; b=FHINiSoiBmetMO70cvid+wbUYdxl/HMnD3DyB0wLTdA0+rZFhWBWGI6sOVO9x2DgW0 qB8ldlOPG7ZAsU9OuLlz+ff1eP8Nf3Ni2+H/Lb7jp/NxFEefjucawTpps+ZoMDZPUtYd Q1hp+Wd+Va428O8Yr2Yfuu/q4fVFlb9TNOUxKTpB2O+zv9iCI1t++qkriwH9A4Qv+jMU 9Qxr5pyQoiOyV1HlXJvbdSFhxsqhkbPsM4zh4sl0w/TqRLXO4N3TC3wTh3UAHJ5/ik3m fvvztpZQ0ooTXY2MjusthY+IXqeR0TsWn9m9UlJXNzmjdFYrzx7BBRp16YTai7ly7yto tdzw== X-Forwarded-Encrypted: i=1; AKwUvBztlE6x2R7xlSS31zu4j2lQ00klGQF2QNWdqoAQ0zDa5QH5CNZfeDU1G/H46QtzU6pH/PUvxk/Nc83rveQ=@vger.kernel.org X-Gm-Message-State: AFuF++m0+k+tjkB89R6s6zoRwyilSLtahbKVsWS6VXGjE4qn9zMhNN71 okV6PL9Lp+UKOK/jvwqHKi+qQkI6nXUjWFmC/ZgbXlcruZmSQmDZSpC8BPVM6W455z4In342U1H NJA6jQAEL9A== X-Gm-Gg: AYBFou0hTNFMdg/w49kiqUmNgrDsGgq7KsTcFpFefoj12YCosI3Lw9EEeS1qAvJhtfy 2a79BMh4l5OoCVcuGNHKfZc1yZqite+WkFPXvmfocpqmBDZrFxefaW3lwkENFGapLBASO5fa7rP W/uv58YyTJn5i5TT4jv9VGcory6a2dtLDk1ZdRTul7A28LKnqypGMZeLJVZ2xNMp3TMvFlMFN/G biDLUaJIeM8ja5jbu8AAthcSK+kihNXpCfTH6NjVum2JdzSSjHQ7W4N5v918Ajf/RA2MFoLbpSp GvHzNSbnO3Woq0n7oCIO14mDprOOesJwncslOOU4fReH0fUdw2x6KDxkD6U9sEZtNJLOnKNTgbc P8LQMEAjTygYWeLYcbIAzWr5EOhLFb3bKWWTnZfb74X+FQMXf+HvzduyhegIzRrO8w2Om1+M8Ki cCFb5CmdW7JMQnFaL3cQxt5iiii694vl1vMER+Jjw/dguvmu1dmu8CdP2Y65sLLxNptTd5HHAff xBoKEPQADcyhmsKsLd8qH+hiM5mnNlDSqkO+RI0k0bDBgajSMKYvubfcrdPtc+zqLsTOqK6WRDO 2mBI33r4ovjJ/e73 X-Received: by 2002:a05:690e:2366:b0:66d:632:9afc with SMTP id 956f58d0204a3-66fb5a6f933mr7761340d50.30.1788901512177; Tue, 08 Sep 2026 14:05:12 -0700 (PDT) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:1eca:212:86d0:4e87]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-66fb495eccesm11078129d50.18.2026.09.08.14.05.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 14:05:11 -0700 (PDT) From: Viacheslav Dubeyko To: glaubitz@physik.fu-berlin.de, frank.li@vivo.com, hch@lst.de Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, vdubeyko@coreweave.com, willy@infradead.org, brauner@kernel.org, djwong@kernel.org, Viacheslav Dubeyko Subject: [PATCH v3 7/7] hfsplus: switch address_space_operations on iomap-based support Date: Tue, 8 Sep 2026 14:04:48 -0700 Message-ID: <20260908210448.296772-8-slava@dubeyko.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260908210448.296772-1-slava@dubeyko.com> References: <20260908210448.296772-1-slava@dubeyko.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch switches the regular file operations on iomap-based ones. The hfsplus_aops is redefined as the iomap-based operations. As a result, hfsplus_direct_IO() has been completely removed as a user of blockdev_direct_IO(). Also, unnecessary LEGACY_DIRECT_IO dependency has been removed from Kconfig. Signed-off-by: Viacheslav Dubeyko cc: Christoph Hellwig cc: John Paul Adrian Glaubitz cc: Yangtao Li cc: linux-fsdevel@vger.kernel.org Acked-by: "Darrick J. Wong" --- v2 The hfsplus_btree_aops uses hfsplus_btree_read_folio() and hfsplus_btree_writepages() methods. The hfsplus_symlink_aops uses hfsplus_symlink_read_folio() and hfsplus_symlink_writepages() methods. Also, hfsplus_setattr() doesn't distinguish the regular and not regular file cases anymore. v3 Fix failures in generic/091, generic/521, and generic/551. --- fs/hfsplus/Kconfig | 1 - fs/hfsplus/extents.c | 46 ++++++++---- fs/hfsplus/hfsplus_fs.h | 1 + fs/hfsplus/inode.c | 159 +++++++++++++++++++++------------------- 4 files changed, 117 insertions(+), 90 deletions(-) diff --git a/fs/hfsplus/Kconfig b/fs/hfsplus/Kconfig index 865a1966f395..b4432c64db3b 100644 --- a/fs/hfsplus/Kconfig +++ b/fs/hfsplus/Kconfig @@ -5,7 +5,6 @@ config HFSPLUS_FS select BUFFER_HEAD select NLS select NLS_UTF8 - select LEGACY_DIRECT_IO select FS_IOMAP help If you say Y here, you will be able to mount extended format diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index ffd52ad8867c..fb2b12473cb2 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c @@ -15,6 +15,7 @@ =20 #include "hfsplus_fs.h" #include "hfsplus_raw.h" +#include "iomap.h" =20 /* Compare two extents keys, returns 0 on same, pos/neg for difference */ int hfsplus_ext_cmp_key(const hfsplus_btree_key *k1, @@ -275,6 +276,8 @@ int hfsplus_map_extent(struct inode *inode, u32 ablock,= int create, *max_blocks =3D hfsplus_ext_find_block(hip->first_extents, ablock, dblock); + if (!*max_blocks) + return -EIO; return 0; } =20 @@ -302,6 +305,9 @@ int hfsplus_map_extent(struct inode *inode, u32 ablock,= int create, if (was_dirty) mark_inode_dirty(inode); =20 + if (!*max_blocks) + return -EIO; + return 0; } =20 @@ -342,7 +348,7 @@ int hfsplus_get_block(struct inode *inode, sector_t ibl= ock, =20 if (create) { set_buffer_new(bh_result); - hip->phys_size +=3D sb->s_blocksize; + hip->phys_size =3D (loff_t)(iblock + 1) << sb->s_blocksize_bits; hip->fs_blocks++; inode_add_bytes(inode, sb->s_blocksize); mark_inode_dirty(inode); @@ -607,20 +613,32 @@ void hfsplus_file_truncate(struct inode *inode) inode->i_ino, (long long)hip->phys_size, inode->i_size); =20 if (inode->i_size > hip->phys_size) { - struct address_space *mapping =3D inode->i_mapping; - struct folio *folio; - void *fsdata =3D NULL; - loff_t size =3D inode->i_size; + if (S_ISREG(inode->i_mode)) { + res =3D hfsplus_iomap_cont_expand(inode, inode->i_size); + if (res) + return; + + mark_inode_dirty(inode); + } else { + struct address_space *mapping =3D inode->i_mapping; + struct folio *folio; + void *fsdata =3D NULL; + + res =3D hfsplus_write_begin(NULL, mapping, + inode->i_size, 0, + &folio, &fsdata); + if (res) + return; + + res =3D generic_write_end(NULL, mapping, + inode->i_size, 0, 0, + folio, fsdata); + if (res < 0) + return; + + mark_inode_dirty(inode); + } =20 - res =3D hfsplus_write_begin(NULL, mapping, size, 0, - &folio, &fsdata); - if (res) - return; - res =3D generic_write_end(NULL, mapping, size, 0, 0, - folio, fsdata); - if (res < 0) - return; - mark_inode_dirty(inode); return; } else if (inode->i_size =3D=3D hip->phys_size) return; diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 190c7de704fd..844027679a75 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -466,6 +466,7 @@ void hfsplus_file_truncate(struct inode *inode); =20 /* inode.c */ extern const struct address_space_operations hfsplus_aops; +extern const struct address_space_operations hfsplus_symlink_aops; extern const struct address_space_operations hfsplus_btree_aops; extern const struct dentry_operations hfsplus_dentry_operations; =20 diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 9d25e6224ee5..717831dc5cca 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -18,15 +18,12 @@ #include #include #include +#include =20 #include "hfsplus_fs.h" #include "hfsplus_raw.h" #include "xattr.h" - -static int hfsplus_read_folio(struct file *file, struct folio *folio) -{ - return block_read_full_folio(folio, hfsplus_get_block); -} +#include "iomap.h" =20 static void hfsplus_write_failed(struct address_space *mapping, loff_t to) { @@ -128,67 +125,13 @@ static bool hfsplus_release_folio(struct folio *folio= , gfp_t mask) return res ? try_to_free_buffers(folio) : false; } =20 -static ssize_t hfsplus_direct_IO(struct kiocb *iocb, struct iov_iter *iter) +static int hfsplus_btree_read_folio(struct file *file, struct folio *folio) { - struct file *file =3D iocb->ki_filp; - struct address_space *mapping =3D file->f_mapping; - struct inode *inode =3D mapping->host; - loff_t isize; - size_t count =3D iov_iter_count(iter); - loff_t end =3D iocb->ki_pos + count; - ssize_t ret; - - /* - * The hfsplus_get_block() only allows creating the next sequential block. - * For direct writes beyond EOF, expand the file first. - */ - if (iov_iter_rw(iter) =3D=3D WRITE && iocb->ki_pos > i_size_read(inode)) { - loff_t start_off, end_off; - loff_t start_page, end_page; - - isize =3D i_size_read(inode); - - /* - * Wait for any in-flight DIO on this inode to finish before - * calling generic_cont_expand_simple(). - */ - inode_dio_wait(inode); - - ret =3D generic_cont_expand_simple(inode, iocb->ki_pos); - if (ret) - return ret; - - start_off =3D isize; - end_off =3D (end > 0) ? end - 1 : end; - - ret =3D filemap_write_and_wait_range(mapping, start_off, end_off); - if (ret) - return ret; - - start_page =3D start_off >> PAGE_SHIFT; - end_page =3D end_off >> PAGE_SHIFT; - - invalidate_inode_pages2_range(mapping, start_page, end_page); - } - - ret =3D blockdev_direct_IO(iocb, inode, iter, hfsplus_get_block); - - /* - * In case of error extending write may have instantiated a few - * blocks outside i_size. Trim these off again. - */ - if (unlikely(iov_iter_rw(iter) =3D=3D WRITE && ret < 0)) { - isize =3D i_size_read(inode); - - if (end > isize) - hfsplus_write_failed(mapping, end); - } - - return ret; + return block_read_full_folio(folio, hfsplus_get_block); } =20 -static int hfsplus_writepages(struct address_space *mapping, - struct writeback_control *wbc) +static int hfsplus_btree_writepages(struct address_space *mapping, + struct writeback_control *wbc) { return mpage_writepages(mapping, wbc, hfsplus_get_block); } @@ -196,8 +139,8 @@ static int hfsplus_writepages(struct address_space *map= ping, const struct address_space_operations hfsplus_btree_aops =3D { .dirty_folio =3D block_dirty_folio, .invalidate_folio =3D block_invalidate_folio, - .read_folio =3D hfsplus_read_folio, - .writepages =3D hfsplus_writepages, + .read_folio =3D hfsplus_btree_read_folio, + .writepages =3D hfsplus_btree_writepages, .write_begin =3D hfsplus_write_begin, .write_end =3D generic_write_end, .migrate_folio =3D buffer_migrate_folio, @@ -205,18 +148,70 @@ const struct address_space_operations hfsplus_btree_a= ops =3D { .release_folio =3D hfsplus_release_folio, }; =20 -const struct address_space_operations hfsplus_aops =3D { +static int hfsplus_symlink_read_folio(struct file *file, struct folio *fol= io) +{ + return block_read_full_folio(folio, hfsplus_get_block); +} + +static int hfsplus_symlink_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + return mpage_writepages(mapping, wbc, hfsplus_get_block); +} + +const struct address_space_operations hfsplus_symlink_aops =3D { .dirty_folio =3D block_dirty_folio, .invalidate_folio =3D block_invalidate_folio, - .read_folio =3D hfsplus_read_folio, + .read_folio =3D hfsplus_symlink_read_folio, .write_begin =3D hfsplus_write_begin, .write_end =3D generic_write_end, .bmap =3D hfsplus_bmap, - .direct_IO =3D hfsplus_direct_IO, - .writepages =3D hfsplus_writepages, + .writepages =3D hfsplus_symlink_writepages, .migrate_folio =3D buffer_migrate_folio, }; =20 +static int hfsplus_read_folio(struct file *file, struct folio *folio) +{ + iomap_bio_read_folio(folio, &hfsplus_iomap_ops); + return 0; +} + +static void hfsplus_readahead(struct readahead_control *rac) +{ + iomap_bio_readahead(rac, &hfsplus_iomap_ops); +} + +static int hfsplus_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + struct iomap_writepage_ctx wpc =3D { + .inode =3D mapping->host, + .wbc =3D wbc, + .ops =3D &hfsplus_writeback_ops, + }; + + return iomap_writepages(&wpc); +} + +static sector_t hfsplus_aop_bmap(struct address_space *mapping, sector_t b= lock) +{ + return iomap_bmap(mapping, block, &hfsplus_iomap_ops); +} + +const struct address_space_operations hfsplus_aops =3D { + .read_folio =3D hfsplus_read_folio, + .readahead =3D hfsplus_readahead, + .writepages =3D hfsplus_writepages, + .dirty_folio =3D iomap_dirty_folio, + .bmap =3D hfsplus_aop_bmap, + .migrate_folio =3D filemap_migrate_folio, + .is_partially_uptodate =3D iomap_is_partially_uptodate, + .error_remove_folio =3D generic_error_remove_folio, + .release_folio =3D iomap_release_folio, + .invalidate_folio =3D iomap_invalidate_folio, + .swap_activate =3D hfsplus_iomap_swap_activate, +}; + const struct dentry_operations hfsplus_dentry_operations =3D { .d_hash =3D hfsplus_hash_dentry, .d_compare =3D hfsplus_compare_dentry, @@ -290,13 +285,27 @@ static int hfsplus_setattr(struct mnt_idmap *idmap, attr->ia_size !=3D i_size_read(inode)) { inode_dio_wait(inode); if (attr->ia_size > inode->i_size) { - error =3D generic_cont_expand_simple(inode, - attr->ia_size); + loff_t old_size =3D inode->i_size; + + i_size_write(inode, attr->ia_size); + error =3D hfsplus_iomap_cont_expand(inode, attr->ia_size); + if (error) { + i_size_write(inode, old_size); + return error; + } + truncate_setsize(inode, attr->ia_size); + } else { + bool did_zero =3D false; + + error =3D iomap_truncate_page(inode, attr->ia_size, + &did_zero, + &hfsplus_write_iomap_ops, + NULL, NULL); if (error) return error; + truncate_setsize(inode, attr->ia_size); + hfsplus_file_truncate(inode); } - truncate_setsize(inode, attr->ia_size); - hfsplus_file_truncate(inode); inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); } =20 @@ -399,7 +408,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb,= struct inode *dir, sbi->file_count++; inode->i_op =3D &hfsplus_symlink_inode_operations; inode_nohighmem(inode); - inode->i_mapping->a_ops =3D &hfsplus_aops; + inode->i_mapping->a_ops =3D &hfsplus_symlink_aops; hip->clump_blocks =3D 1; } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { @@ -540,7 +549,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct = hfs_find_data *fd) } else if (S_ISLNK(inode->i_mode)) { inode->i_op =3D &hfsplus_symlink_inode_operations; inode_nohighmem(inode); - inode->i_mapping->a_ops =3D &hfsplus_aops; + inode->i_mapping->a_ops =3D &hfsplus_symlink_aops; } else { inode->i_op =3D &hfsplus_special_inode_operations; init_special_inode(inode, inode->i_mode, --=20 2.43.0