From nobody Fri Sep 25 09:20:33 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 7F3B53B3C14 for ; Mon, 14 Sep 2026 23:40:05 +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=1789429207; cv=none; b=DkmQk0p0pdBlfqHTC0eFRetJEzp31hqu3XcL35yWVT3M9Kr1ty/QGElVN6GJYAmRmaNZ/1Khw1/1CC09/zzpClQh15RFJscRresd+tR5/dxYHJ7SCqPqFeDo7hID4SmaqvUEQnvz8xl1Pmnm4uRXUtZAdxOAqH9qEf4mb4ayRtE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789429207; c=relaxed/simple; bh=OVJzpWfHSM6a6wCkK3C71K/fLknshrLRt2xkWr7HMRk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XNt4DWt8kIgdqG1LMu2KsZc1RWOYTczseU8ev/q4NoF/KnKBl3aN+mSPcFfOdQjBi/0WnM2bamGCYaOV9fzN8xWSQLbi3UgoR3JviMKr+xvxoWmxYFgy5C+irfY86DDEAyV7PJEIJeA8dkoS4LRHSnBCdSQIsDpO9lftFtVPO8A= 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=r88D3JeQ; 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="r88D3JeQ" Received: by mail-yx2-f12.google.com with SMTP id 956f58d0204a3-66e4aa8d881so2457465d50.1 for ; Mon, 14 Sep 2026 16:40:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20251104.gappssmtp.com; s=20251104; t=1789429204; x=1790034004; 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=r88D3JeQL2P3PXHbbiXZ7raadkNh4voYOcmqymra7LA/7tEtn3kohXpUfTVIVb8eoD 5P1xcVOENJtkxzHusw07f/9oLWSpqD/pZHOwEt9vLarrgG2XNfdH2yUJ39r1SGQjFgUT OwIGoKP9CHO5u/k2VXI5pdp5hd+iZN0odEvMgCb5LO+OhC0d8mJpDiNcEdUNoVlKvKC3 6XZyG2r4R8FtFR3V62vV0QBINPOueOqpLt+Cpy4dFGXQtQOsgVubJWxYFzC0cgCJzD/z 5BcBPKplJRoWiQ7rcv0Q9vZa5ES3XcSwpcxcFHQJ+VT44PX+USL6NogjtTh4lZJDt/Kp LOAA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789429204; x=1790034004; 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=FR7+4mgCW/C7IUshxvw75I2JxhnRIlpo620+CxlvKyVPu91BEA/VqNGSbuqFBY92Pt gDyPB3pzk4+K4lcBMh0tqcrehTtnBubW6fFU5Jo0uCpQV09MrCDsa/djlkWEPleszpVl Dl7ezbfjgckUI2sFTmTHbkKHqahHQZ8k0AztPnk/ppNszlhEUO4MuDE0+9B+gZZhSuZP BnabGjNPtkokYEyWA5Qojr4UZoEanTgGJjB9fokQTw/usVnnf4aWmkOOTrfSSWQ9nbXI 28VMKPCQ+BHx+pr/YBm7cN3/Ij1BrKQQtCl0UUl/IT1Hkm9bGSGZEkE4Iwcdg7vV/Nh7 LULg== X-Forwarded-Encrypted: i=1; AKwUvBwuzCz6hQffVCWP00B49pOtSCvzOvGOLDgWowEYwmcaryXR+T0/l6G8xzS5ptV4zPWh9WC+KXOvEzMhQtc=@vger.kernel.org X-Gm-Message-State: AFuF++k9ug7LSsC0SpogNCdahuO9HQhvxPQyMqt533yq0myXKgfQiBV0 87HUf0pKb0iVG7hfPg+wQFxScs2QLSVB4iG7TnVg3de6CqpefUEDnK9UClUnsSW5Efs= X-Gm-Gg: AYBFou2AHQ/R7+PhlBNnYoBOxUpyHIGY3oFqU1u8Cjgcy8ZkHbKOaZP3RVCzcApHgYn expV1V4EDXQsmXOwm3wkcQUvD4XZ5oODViETQCHJEliX9Jah550vm059WMSPQiRjsUhSv7/tlze +QtQnStzo6b1g4/lEf80N93u65RDBPKAaOhHq+9nxfB//eNmdla/2/39FsnnRt7Cw5MHHvVDQBv rN6nBghFmGl8SZ3AnvUO4o6yj5hcQVC1YLr5k5u43GQQOWBsXPeZ1lmLuGxjH2k9GXwPSEp9La4 wS/xYhk+S2R4agJhcdZmfC9JRfC6D0Qpm6Bg6L3IJ82CjzEeJZazplsDkcPG/Wz+lP4RGiHyVlB 3DyeSejT5uofi6qN1cDH5r/MBVB5zq0rqEmIs0VBA5nfSMVbucfcX/H17jbIocAQ5acQVM03VhY dl03rdQawBGQL9PPuoIpF9Oy/F1SOMMv98KRP/gDes5f+ic3z8+1qvn4FEyunflKOGke9A1b2Q9 lIOTwIaVb5jkuXlB29AAOoAPJ8ux4L5w6I2IKZJj3+6VW9S4DRDDK7HqLABszUmwajXPwB2jVmT jJkqXVRZ+z/JrdtDZBCDhj80r+DXAQ== X-Received: by 2002:a05:690e:bc6:b0:671:1406:95ec with SMTP id 956f58d0204a3-6714dfd35f3mr1369775d50.11.1789429204257; Mon, 14 Sep 2026 16:40:04 -0700 (PDT) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:df87:8743:655b:3824]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-67125e3fa87sm5207804d50.14.2026.09.14.16.40.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Sep 2026 16:40: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 v4 1/7] hfs/hfsplus: exchange hardcoded number of extents on named constants Date: Mon, 14 Sep 2026 16:39:35 -0700 Message-ID: <20260914233941.2966421-2-slava@dubeyko.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260914233941.2966421-1-slava@dubeyko.com> References: <20260914233941.2966421-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 --- 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 09:20:33 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 BBC843B38B5 for ; Mon, 14 Sep 2026 23:40:08 +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=1789429212; cv=none; b=Pu+YXpaXH0lZVe2Bq6IijPCbvUIOO5diW4who3qtsQBSlwVzDIU6ypso00T3wocQLKoZcS1b3GYYdGNfrTaI5ydtbs8iVd9U6vzgJN8bSc7JHwFEnFl8ZSnRFVTzjN3l8dOChS2nCLwOSu4avZbmXByH6UH53iPUXq7eOJFSs9A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789429212; c=relaxed/simple; bh=KQ9TioCk7IAXoYKsbOf3mo0CBYIbu2RGH/UJt8EFt/M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IJycUpk7w05K/BUL8hK9hardtmiomoMuu4t12zXJd/326rtDBI/hO391QJTR/1LrcIsEXfYxxO9oKnKSUaOPRNukPbEINBrfEyrJxu9LPvteeLdykOjdMprey+VUTX3HsnuE9UriC/zq1q58qDfRYkueylyInItW/OW8F6vOFT0= 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=swZ6bKWN; 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="swZ6bKWN" Received: by mail-yx2-f12.google.com with SMTP id 956f58d0204a3-66e4ab20a32so2823847d50.2 for ; Mon, 14 Sep 2026 16:40:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20251104.gappssmtp.com; s=20251104; t=1789429207; x=1790034007; 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=swZ6bKWNREIpHz6S2Q0AJj+n4NIiJsvlNdJR9hKksm3Rbx7hTrcpeKapg5GdCqmspu E7bNogZ000x/Q7z+AkOX862ek2pdoysduEkssEDLslYIiYPKjtRCB360FdO7EtG1rzjg 6Hr/3S0xgrMKYyWKQGLuDKH3MvtTUekzxjCWddES5T3Ji+5atuOcRq9kbjSuDXpaV/fz wmPj6LMR2YyM7tqRdj+DI3AarHvyF2CZXi10UGAcNGbkmTEx59/gjw82l9K+UNePgl1o Ck03IRloD5osrYLGjQNGK35u8hrKvniwmxr/bZkpDTgTONVe+cBHbsPgKoXaLM7Eyw/K bmNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789429207; x=1790034007; 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=2e5kTZ4QDwzTD/fd9aaTfICjxIjuW7kiioLcMnt/izKqrhw0XNcgQvlN6uM9MJy5Pz a4qyzoVLDqIdsrIw9+T/SYijgZTU8jLihaqbNo0+U+8cZWZq94nR1+NaLMnRSfZJ587N wIdxteo3ka9m+OYf+LIg2kVOt8zZUGD3qcL0ZnwVURyXa5I5wPMFHEDCz6Irh2QtMrY4 XVOWRhxkGyHPNjixSf8w0rRLBk4VuDOO7xQ7m1gjASsx8fs9p6PZCxi50jfALkE7EaQE s/CPTV6yErU1R5/j7FIbhXUucQsRZjTsH8DlQIZ1U1ofsPUtOozOCy5oZbmdPtVJjJbU yIPQ== X-Forwarded-Encrypted: i=1; AKwUvBxyelCXxNGReJLzux+YKIjY7u6sC61ZXukuJve7PlhIcsnhYC2cLCRQsSQQQIl02//1jn6Oc0LQCwqCmi4=@vger.kernel.org X-Gm-Message-State: AFuF++lFWZqMVV+4V8nCYxDIFBCgwDiXL607MQvepFN2g09pYqc+qYJp GqR57OTt4gGV3HQcVN5YVBHLRMyyZc3Yxbh8Vjzh2uSS2rD3StGLYVh0lUM4Jh57MzcU9bnsv2e ka13bH0tGfg== X-Gm-Gg: AYBFou2AP8oxcNpRNx78X9rLK1AjHspll/snqvcpLzbAM8wiX4Pui0x9vyHwZr0zQBT 6it/I+B0KyNfC5XZzLlI6G1lwybb1835q6HKLP8bcNkzbGKxZgCSjNK0xLZ5RjlEZ1qQBl+oowh YrFDt0sMhdo0MywSdx1iQz8jINIXBgpYyw3VZadfmiJiYqUY+AbmuXH6fnIIOBHdXu0DLbNN9Tq CbUczCvFyxl8uRzd1x0P4ei79m+PdwIZJiXGuPqPayqvhJI2kHTKUDeud+FCnY3sPV/+RSJZ5gQ OWPmiA50Wt6fz82Rar+VVR9bpf3N7g1qUyf2gytsAIQ9nrwoa95uIAlyH83XnLAu78i3ihHBz2P Nn9u5aTPR/wKBtjjVNiNblL0/MDaJCrDqcPwxLvQHMJkFxUf7F0dB2b2O3yJx3SAjsgnKzvC8ZS cl4drXV6cRgzCedGWGll/HQHX6B0KJb+a+EO2fYCPHZ5NiLeQ79e/Mj/i49S7ffaxwzgBAC2HjJ 2BdOIZ0TLtvVMLm9pLfvvpeeLac0FoT/KLa6RpKEsr9oORERCzkLa+nqBqBci3+ys9waEI4DcbY z0CpXyzHNh+R8fEQfqOQzNGPK+KB X-Received: by 2002:a05:690e:454e:20b0:671:214:30a6 with SMTP id 956f58d0204a3-6714e1a2387mr1003980d50.94.1789429207416; Mon, 14 Sep 2026 16:40:07 -0700 (PDT) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:df87:8743:655b:3824]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-67125e3fa87sm5207804d50.14.2026.09.14.16.40.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Sep 2026 16:40: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 v4 2/7] hfsplus: rework hfsplus_get_block() logic Date: Mon, 14 Sep 2026 16:39:36 -0700 Message-ID: <20260914233941.2966421-3-slava@dubeyko.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260914233941.2966421-1-slava@dubeyko.com> References: <20260914233941.2966421-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 09:20:33 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 643653B42C3 for ; Mon, 14 Sep 2026 23:40:11 +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=1789429213; cv=none; b=fJ0Fza2UVmmOs1K/4eW54vibmwwlzz/dbFNOZu2jbEukknbA4a5BsVtM1wdRN3fZ5bAw7M4zPCuPDnb0qbIHkRaazG8/rnNvcb1ogTuUn8dM/xz8PVeVu5mK8L5E+Rd07pW52d/mbv4YxqC6az1kG6BdUcb4UCIsdbWqZEBhnMU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789429213; c=relaxed/simple; bh=qy7ZBQ3XzWiyLT6IhGtwn66uVeBQnzl1JKqYjhWIOOw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rmfBU0u5STm3ZmINXCFOm/pZRwcx7JngBS3g7Y7HwZjmrcIPKEbi9bPh5BgTGk0jdaoD12+wguYhtAiPKGoaA+in5qiSJ30CYW26ZaQgQXGKPTINgdklqAXlticN0jYtpKyYUtM5JM9zUZhP8rhebh9hP6haM06pamlVdnoYAV8= 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=e9XHJQBR; 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="e9XHJQBR" Received: by mail-yx1-f54.google.com with SMTP id 956f58d0204a3-6714af30a2cso1830693d50.3 for ; Mon, 14 Sep 2026 16:40:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20251104.gappssmtp.com; s=20251104; t=1789429210; x=1790034010; 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=jGnVp+Wdcppn1hNzh9JEPOuRz9gaVRAoKUqUMG8quKI=; b=e9XHJQBRBfysZsqw3anMou650KdRkS/rOeLzlkRtu673X8FH3I8EUgYAQjoOPYrU1E oJIHYg/iHPiUSohw1pw1dihgUUhCiMPKRrP+VJR6Gle4P3aHWybi+fvBhmJZ4bbrjU8k 8JSj6UVUgVUJQDZeD/m88XJyeME1BuNFKjSP+AxZu02D6qxqnAfUWXvplHFmUimWZWQ8 +384Xuph0kN4PhcGIjMojd0CI0xaatb8AYnX42+xFda1JTUde6aR/ROun0lQJNVBVHXX smEyyB+FDZ9Oaq5+wT6aMAo8d++Fe8u439H2AL4dXPSlJ8j1Q5ZUTMmHYsKcI3CFfM8H 4lmA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789429210; x=1790034010; 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=jGnVp+Wdcppn1hNzh9JEPOuRz9gaVRAoKUqUMG8quKI=; b=cD9eh2ArLyLFRbdR5uYlhcZgKJqnfL8BeVv8A1LGvi2kRg9gvIuawhJaHStd6q+eY5 /0yKlLl348rv8lONuYG4qoorRxgP3dqgj7NREfaYkmUPTAcK1gHBC3TuKwPT4uyCJk78 twrR66tZqJTX1UYvciGl9SPrdGweUzOrQMkCcKWxLrwOvgWii8eEqYqUSDN61fCDVwXI S31gSxX11m7o323BXKf/rNJluVwVLYMk8VSh6PZQbYb9KB2ERtALKDnAWrpEjp9j/cg0 Hn/JUQxKpfzB5A7pz9WaFGrj6BwEokrB2kQi1mds8VdsKF6j1kN0ii0BS6RiD9YAwiy6 fG2Q== X-Forwarded-Encrypted: i=1; AKwUvBxvC30soRI1EeCVKF73w19TdgmKpAKul7YBdafsVUrHc1IZAU79cRTlf4bgkryeSDMuFrFunoMPimggeLw=@vger.kernel.org X-Gm-Message-State: AFuF++nOaXG4wNTKq7K10wtLzk/GuW25sNYkQwlKcmvoRCxMQAXqWjRJ QQyOPeCJMUEsraxUoGmjTe6c7NLu4znbnIrxqW/xqeZEoKy9PeBknTBimXiRNDdXcsU= X-Gm-Gg: AYBFou3CU5HRdvOlVjiQbSay2eRXANOvpl0gt17DWeh6UTL3qMGBfEW567EYLq5pno0 zLPC/DxM6USNjkBlEB33ny2fj65ptA9P+kclZYMC8V/pU+UzYSE1tLG0S2lViRLPlMWuUC11XkB 8ZLk5/pOT5JDaNDJoVkvYcojljgwQtmvCJR25wicEklXdkTary9hOeeTKk9G43h20L7FaD/mvtL to25MLytkopF5TV5ekn2nSoZ9yUQKGemAyJNTpYqEquLc7YhHEUsq8SgpQdf4M2YHBiaVNyNFCb wsjRmQW3efZx8jY+bwwB2Y03KCoVhoUoIrLkzhFKCDyHZ98E8MfVqQHe6ab6OSyn4ojdbURK2R1 NQ8OEdmJi6AF03UmM9nTjO20zAm6xK68vhOuXI27AUPfhE63eahif0b1TBfj7Y2ATrn7jCXmN6+ 05B9uPpfss4fLYmbjtkC5vqewYnp8FuHjbsaKf0TUyDzu+TULFER+Ne4X9+IxGFlX7CkxLoLWyj COYF8IDuGz1fN3TF9Q9pSKP3YFuR5Sa5IW9BjYaRv8qqMKP0KpulSO3Kuu6qAFvFpuG6y1oIoJd MCOGye5E6R7gRmN5TEU8PdrYVXGL X-Received: by 2002:a05:690e:43cd:b0:671:2d01:48e3 with SMTP id 956f58d0204a3-6714dff5dd3mr1087542d50.29.1789429209616; Mon, 14 Sep 2026 16:40:09 -0700 (PDT) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:df87:8743:655b:3824]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-67125e3fa87sm5207804d50.14.2026.09.14.16.40.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Sep 2026 16:40: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 v4 3/7] hfsplus: take the bitmap page lock for allocate/free Date: Mon, 14 Sep 2026 16:39:37 -0700 Message-ID: <20260914233941.2966421-4-slava@dubeyko.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260914233941.2966421-1-slava@dubeyko.com> References: <20260914233941.2966421-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 Reviewed-by: Christoph Hellwig --- 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 09:20:33 2026 Received: from mail-yx2-f13.google.com (mail-yx2-f13.google.com [74.125.224.141]) (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 2A5A0397694 for ; Mon, 14 Sep 2026 23:40:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.224.141 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789429216; cv=none; b=inGFzJ7H2Fvw1bRG5vPehhhQOcpJfIZ/6sg8J8IFwF6hErX/teosmyDLD7Rk/8wfRzVeGHqEO8Yy5NldXmKg1HnlyLS/ncxY+KD34V25GwBJm338Botn8CbeZYF8bNn4Eog7zRM8YSlYeiMYEKGAqnAbUY7A4GF0I27HBqLQ7TM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789429216; c=relaxed/simple; bh=3Ulc2WBAKnw9uLMXYN2L0ojgOG0vb99gojQX5iOnUW4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rB/kZCb5BP/HDyXlCGRBi/3iSD9xZ65uJ+FU3Pj+fwO/yM8igWqkPWDcmntIDU7A9hN+LhH60VearwsEMxNxdAqDglbzQAJawQsRJJ/zk5I/jIP2qbagCR14UKFPOXTez93IUhG6djRiMZkRfdgw8bBlhBySug6kH5h2+t0jaFI= 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=rAE8B7uH; arc=none smtp.client-ip=74.125.224.141 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="rAE8B7uH" Received: by mail-yx2-f13.google.com with SMTP id 00721157ae682-85d43ac8d1eso18799257b3.2 for ; Mon, 14 Sep 2026 16:40:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20251104.gappssmtp.com; s=20251104; t=1789429212; x=1790034012; 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=q4Iyv7bHUl+kWGpcVFy7sYXUvGwMMYmygnBiPAZFBG0=; b=rAE8B7uHR/icWInkDwCxM7dcVB2sVXxTDz4LSXrj1It3fRpx6ViuubjmNmIMd7VfKP 6hYiuq6x+JdswyNOBtnEeG7GCjWgd4vjAP/T/w1HfSdJr9brmoK9BWG/AKtcMX10U/lC v+1o0jrNjHhV4IIHC09Az2Z3SWvDRQpr85oMvL+N9ZjvgLW5WBWMZyoVcFkWN654WSJP gMyf3yiw/8XZqLbAP6ocvTt65bNaoTh5QW2UzSq5WCS9skHxKVxPdc9YX+61solQy9HM /QafvhBsuxDdbzs0StEcY6oKjHqMjy4rWJqRnwOaA5uHQd7kWwrqONiQzkatTtwdf+Op V+WA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789429212; x=1790034012; 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=q4Iyv7bHUl+kWGpcVFy7sYXUvGwMMYmygnBiPAZFBG0=; b=lyKZqKRfTIluhqfP/ZzYWGejUYJn5FarAr0S/2CVpImESaIZg/xze1m94OLFn5XKfb MC+kfAcLoGI4+zEA9qCEr2SgxZXjYN8lQKUloEyPxu6gQF8FQmbWLTiDcj/0nO8WwxqN iZ9O/3KJ8yRfu2vLWRfkVR3Gl1DJBTlFawaJh6BU+HTo6KHogeSOzfK2p6VcnY7zoGbl SflFrjwmPMBoDHBn03dZVhgBPLFQ5Pa+CJ5ciBTMdj8ap3J/xt7r4MDpcTrwh2q2RLI7 4cYfjCGZrmhEZtR1J9/tiY0fPA6j/iPCHB7Sa9R51QyJ68M6yjxLi4eR2PDDMWcsI/f3 zo+A== X-Forwarded-Encrypted: i=1; AKwUvBy0TOMjjFrCUwac52LcR3SgYiqisreIq+lUSc7HRsHpUmBFL+dvHlMkulvdCfQgJMfdgd7ir6a9UPunVCQ=@vger.kernel.org X-Gm-Message-State: AFuF++lNgLG1bxwMuJOWb/IYZ2jTCsGWRrhK5LhHZuuFopwTUh37gkT5 083+N9ilQ0qIBSL2D3O3mb5/CPHDVK9nImI89F86htlnWaRhJAaldzRvg0y7wcoM4Zc= X-Gm-Gg: AYBFou2yJ46MDm2r2CqoJ71BotMzOIqTwNgW4UBz9jEKGNtaVmv+GzAyPPOVttqcUpd CVEH1G+4DK9Gto+/jUb1fcYp11vwLg4qFu0Bdrq1piuGNrD2C9omI7z5SOIH14fq/iePkYQV9th qE7TAq6x32KB2aWtTy/7vaB/BItdP85QBOGFuFYoY03LVOYCKTJb5AG/TABAfhCwfsEyxIuvB3r LfeUY73rQi/ScASIah/SQJGj/QXZCBbgkD829nxvS+U9lHv+FZ7AnkYguElDI6BFmIei16s6R4y iLxZATuxj762xLU4DfvJvO3shsuE42ycmnF9Rs+a6VrR5FdDVm7Z2vtZPGib6v6B7Vkh30RM/Gy op5eeRl2x2QF/e2t94cSDTiyTNL/PVKmj9DhUS89m2HdZKMXFMgiv+KoyaeEjVdPxAWwfwEpua/ YyylTpUEPL8Zxqjvrv2sOdkRXH4vaXgo+ihj+Wk/unJ3JKiuAwy8e0sAISkhk9iu3wedMlCvfRb 5GDrIWxVtdN1W0TbfjMQaOR/Y8H77NbsPtCXqpshWTKORkayeq0b7OqaVfCIyko8YhUE9Fcu3Ff aTq6TzPEIBPI6aZKPotRCSjMAsED X-Received: by 2002:a05:690e:43c7:b0:671:1ae4:995a with SMTP id 956f58d0204a3-6714e03f648mr1171893d50.29.1789429211831; Mon, 14 Sep 2026 16:40:11 -0700 (PDT) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:df87:8743:655b:3824]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-67125e3fa87sm5207804d50.14.2026.09.14.16.40.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Sep 2026 16:40:10 -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 v4 4/7] hfsplus: add iomap operations for regular file data Date: Mon, 14 Sep 2026 16:39:38 -0700 Message-ID: <20260914233941.2966421-5-slava@dubeyko.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260914233941.2966421-1-slava@dubeyko.com> References: <20260914233941.2966421-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" --- 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 09:20:33 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 165113B14B7 for ; Mon, 14 Sep 2026 23:40:14 +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=1789429217; cv=none; b=TatqbibiH/TfSUdB5R0tXIB3mEfSgQF9A+ZX02DDMLvs6RIuAPgUXOhLwJSMUeXjGYGLwV3w8ooroKqHasOoPGwuQyQ67y/BtfVsK7NjhHM2wSwxU8S79Sg+9XSoGIqZxtZd0PSeXHzsU9qFRc9U3AD1DWonow3FRaCxm8ZqFZA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789429217; c=relaxed/simple; bh=z8nxWyZBGM2mWMHN3Gb3eNdOXLjX6i/8WNe3N3r6Jjo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KAQi1NaEIjPnNNLGqxY/me2b1gcwfZqJF8LL45xcva6YWdUFPzImclJvJ/sX2OdyvOgItEheimZsfk+tW6hwiV78NF5JPJpK0IYbNArwyryBi0g653vQh6GGbZ3baNpt+A9lmyXx5zxT0h/G3Nd73WhiYUZk4isBwfJlZ7vcFZQ= 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=Fmjwzhnq; 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="Fmjwzhnq" Received: by mail-yx2-f12.google.com with SMTP id 00721157ae682-85d43da99e9so21640507b3.0 for ; Mon, 14 Sep 2026 16:40:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20251104.gappssmtp.com; s=20251104; t=1789429213; x=1790034013; 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=FmjwzhnqYQRblcZX5VpQN6xwDdjnywDtQqFzUr2YbKXsMwHyL7ods1wgZ/FqzxeM6U Q35KLQtS5pTn1cJvJdtoGdnniNkOX6R0sgv1uAYjLyBjfYcMs5kqD9Yd77amm2xxFoMt 7tceEnKi1mDKfKRQDI5Z8uSFKgEfTGbbp8sc8VuJES68f02IZaYGMC4dw+zf2qNZxSHW IANaBSzszIDBlGxwEHy49u+CqTptvVoTR6j2TrZ5MCYR/aLP3eQUj52RSvOuiYyEod5Q pp1XzWz82eWLrK2Pqrgi4ixa5fmGY3V/KUffRc+XhbOKRd8h7ZF0bRF1GUROWi7/RLgu ng4g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789429213; x=1790034013; 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=nf5+Onty3ahZjKYJLIkdv4Ul9ijeaa+jsdBw5faJCrEkKwLNokdJ294JFdOWlGYER+ uINDZ8blklHI4xYSkgvjgxBYh1wTuQ63E9YpBxUm69/5IWmmu04iSOeyjT1plrj+heIC eQD5y3VwqKipjzmk4PVbTXXnA/2VC8EVcUJJD+mRWieaw+kr/Hrl/EOKq53pyG78ZEpc h1jJWP5nA54S501fmJEKtonP2bsa/SIQGy6wi9E7kVnB7dJtMT9LswJ2PcPyREDr3HuV fT7bP0C7Vo1oa0aNk2LGWu86HU8e4QuVTG7HJID0qZXMOZwHUSQehlAlNRNb9L6XhWZI T0ng== X-Forwarded-Encrypted: i=1; AKwUvByTeQdZi15WEj1lmC8vB2KwBFAe7KQQ/SSCbyZGakUSIcqsnaVwzRIFpu+XQ3RIHCFH6P66x1DCLR72aEw=@vger.kernel.org X-Gm-Message-State: AFuF++lC3DWkPNGR7iQCG0pj7QW/mOT2YCqkUPMzjZGsud9UpAYamZ1R OO+AY/0zi9B3Pp2XY/HPiwFsf7KpwE76GHa1zf0HM0OcvSx9RdL7u2ngtxs7fNMaJEo= X-Gm-Gg: AYBFou0lmWq4JtD7k6S2+7CaMPqfyjmscCa8+TiUhqnwlhPMhWs0vD78WJgJxWLKYwe mBW6608d2apxW6UJIdzfYZLH5W+fqAXLMJSj9nOWMBOXtHSj0+VDFQKdmTfyFqDVD74gMmrwvVg nYr6vDpIPBjEDdVAPENnzQ7kHZquqFVQhzE0LVy47Dq6HH03rBm0fibgPTm59wvRGdTMoZK9Z7k foyIx1mNVJUsoSmMT29ZN4lwWHi4kqZK6+CUfX8NdlRsbfpjD26mz4tHR2Q07bzKvpXXRQD6Z+b Sa2ZS27AJ2EzVxKrk64wHF+kDZp1tYQ2lyivipufn9uT28/m3fI7FWEjM5CiYQjQlpbyMFdIWBS ikDsIEhtYvHsSMx8MmO7u1IxhI1AkpB+PtEUIVdRBXIHxG87GJAGqDY5FS89PWUb6DxQboBRJi7 1lmFirSg99FnY7wZbe0Z5wxcoKzAnXSrZ7AUw73xiowKsovmPniQrpHo0ZpeWgLyUPR6acVJhag xbT5y95zP6NmIvQmrekq6gqAcdKD+GeOumz64GEBZr6uWObdBoodVPnw8KdP5bujc4wIJoDFsPE q0oUXrdhv/XRxHzlPbMElVjh9nO/ X-Received: by 2002:a05:690e:4810:b0:671:47a8:e02a with SMTP id 956f58d0204a3-6714e0204demr1004358d50.45.1789429213548; Mon, 14 Sep 2026 16:40:13 -0700 (PDT) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:df87:8743:655b:3824]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-67125e3fa87sm5207804d50.14.2026.09.14.16.40.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Sep 2026 16:40:13 -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 v4 5/7] hfsplus: move file related operations to file.c Date: Mon, 14 Sep 2026 16:39:39 -0700 Message-ID: <20260914233941.2966421-6-slava@dubeyko.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260914233941.2966421-1-slava@dubeyko.com> References: <20260914233941.2966421-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" Reviewed-by: Christoph Hellwig --- 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 09:20:33 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 3169A3B3C18 for ; Mon, 14 Sep 2026 23:40:16 +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=1789429222; cv=none; b=sX/z5e5uAcqod437pO+vKiKxKqT8Ep1G3WH/VNrf4mWxw52bIhR8Jt9ecy/pnqPbJWPvcrLiGu8oBYm2hIdX1k5I06fC0/iESfmRjKcPUb2PQwPMSYyaXTvg29oIY00c3VQ5elbKi8DJmcnIGHZDw17/ts2yVtd7VvVOiDSnpCE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789429222; c=relaxed/simple; bh=/nb6mXNGTQy4ag5i/bNzjOw/1+Npj4A3qICnO0mTcVk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NkNsxr9O+f4JyZtHerfebXC6LFfLt5PuoQI2FITyoFBgGvtr9zqi5NhZEP1WsoZ7FjZIusWkGCzu5JXn7iWO/KgWAH5Y7wPjXaWWpji81R3eP0g6dfx4EN+9RTW/emMQMv1j0zEJp1kFsTZZ/ig3M9k1hmqjzvxr/PjHqKkOjes= 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=HUjdMD+U; 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="HUjdMD+U" Received: by mail-yx2-f12.google.com with SMTP id 956f58d0204a3-66e4ab201ebso2269997d50.3 for ; Mon, 14 Sep 2026 16:40:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20251104.gappssmtp.com; s=20251104; t=1789429215; x=1790034015; 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=GdNpd4ugMDrEQYDnfCzJIGQa0zG8noxMRn5Zjsu3iSw=; b=HUjdMD+UtaSfmiAIc/Ks7uDhRJreg6WxAxkK9eX0fC8iYHTiJgcixTOTweoEiq00ox Pdw0KNOLd7Z/BVdS+yVKJr0iSPuA0fPNaw9YmeWaiiOESGrFvK1AbpBTqVakeFhn6zKi FP8Pyt0PWzE92EknzoL037Czvc6ui2O7LgyEGgK3V/uVE7Yz6Bze0n4V8eQOs2LaRz2G Qoy88A41+/9usJHuaETtqQywqw0N2lVhI5D4DwqL5M9/5dC3gRVGGSV2kgXElUq4gmDG IBxl3b3qQmJNQvfqftITd15NOiiQ2FgTROO9CZ0SHdTgg05EGvJmNVo03fK5P8birebq ck5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789429215; x=1790034015; 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=GdNpd4ugMDrEQYDnfCzJIGQa0zG8noxMRn5Zjsu3iSw=; b=w7h4D5ytSO5oxgGDRdOXAj9g9DSJYpbzRFjPKNFA48yJqLI6ZI1sydnJmxmepy3rmK OOMwQxpoIzA/4XGn3bLCnutPLrkugXuzpb0btQNP11uFSTgd/O4Ff/l+PXttbJdAvKQB tiakUNGMuykOtEmsOhTg3XBd2mbs7EuBnpogCjYD21K7v+syqg0D0idwZ8Bp6VFUMeag nJMccmG/zn+ygHV97q15kpWgxp0qRR+YPDWU41twyLMk3Jc40ZFRwiUe29HDEe0vMJkp +8hGcqlRqzsDSoq0b4h/rqADmLi9PmFID/EuhlurDanbeZ/K0/TDYH+bCnWXKZZnKJQu 4v/w== X-Forwarded-Encrypted: i=1; AKwUvBwc9XTqm2DvBJoQFY+NRPKB+qfz2y6Av9gHG5v/LSnStnKWRYlYbiJnaeuggYvzUISy0Fq3v7q7HG+zDJ0=@vger.kernel.org X-Gm-Message-State: AFuF++lySoVoROY89z+Q0rLTOm2lT5QJRfvV8hwtLkgaYI12Ko1GB4Ab qYH2d+u3ylwuNBojqXw23PmGL/7oC2z8C/lOINnwqy16yigjGY787a4jtWVTM+T+724= X-Gm-Gg: AYBFou0kZhKfea+0PrXRZ0Zjit3cg15Utj6IyzdJvjKw5J+HLK/U/Q+sB64M9wQy04P 2Mmtikew9ya/qT/0QJ8yceVMYjZgmQaPoZuU9FvVaOQYLQrmXQTFvWqvFDFaykYt3mCBNMC+uu1 lNx/5SgsGv0IKYeqCtcwkhnhbYHXom+4l3qwOzn/PDJRH0/xpxdBm3xVKrmPkUIevqw2u16AWRF sNRoyzJAWNwJSAiV+V4wioVcbZwPQsZDtC9RTK5s9rOItGQA6U9ejdea2mbQwfYTIKe0OTkr/5P bmcXv6OPYBDE2V7LR+MZR+MK0JYDq0bPRKEMr9pauBNWtUHBRFewIrrmlycWGdY3va/kUdgoGIK SxFIsBStDJTpYiFqJVhGAf8rsri65G/vXCdz22HotGLINbzqwvCMWJCQAtV9yexBRkgGAfxPBPX 7gb2F5pryl61vM7Xv7LDWa7vJmQxgP3vm56Pg2O5pTd4qxMZS7tCG5oJg8ZwUpD7w9Bh8KJ9AHF 05WeE8PZP5jg5eSFhbL2pWp0DyUEphWhYAELjxCvAPLjzAQ2F20sppyrJHrJrWd1i2FZouVfNki ufjmLvw1c78+ZvfS2VmC9dvGUpkB X-Received: by 2002:a05:690e:12c8:b0:66e:45c8:fc92 with SMTP id 956f58d0204a3-6714dfe90a5mr1488611d50.23.1789429215177; Mon, 14 Sep 2026 16:40:15 -0700 (PDT) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:df87:8743:655b:3824]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-67125e3fa87sm5207804d50.14.2026.09.14.16.40.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Sep 2026 16:40:14 -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 v4 6/7] hfsplus: introduce iomap-based file_operations Date: Mon, 14 Sep 2026 16:39:40 -0700 Message-ID: <20260914233941.2966421-7-slava@dubeyko.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260914233941.2966421-1-slava@dubeyko.com> References: <20260914233941.2966421-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 09:20:33 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 2DF003B6BF4 for ; Mon, 14 Sep 2026 23:40:17 +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=1789429222; cv=none; b=TIoolGx0QKFxyHYAkHFIWkg99B8XZju2aie7xV5QR77Teqer4IbO87N8+sel12DpE8Ka9UIRc9rn98QLp/B+0cHTOZ8pRa22OD85+Bci7sxFh6Qkul+DXK39mhIIJquTNcQ1JXlOKxYtPwePWXLyL76qYZtkTezVNyuVUa1qvNM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789429222; c=relaxed/simple; bh=GYL1c/h3mERA9rjAme10Cpy4XXZ04Z03dWl+e750isQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TbI2/a1ZpJNakKQQoa3KLRyH9KxrlNcY6f/EXC9ZJlCfSCmZZ8e6tOmwjq5hamwNDj59c07LtfCQghW4baMrUaebeBO+JcXqM+nCxAz8VSfh9OnHgpHEEZwwGACxlI/klLWwccg58f71mPpe+UdFDIYNfta3R4bzkMi1BrXJOJQ= 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=nOmcgk9H; 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="nOmcgk9H" Received: by mail-yx2-f12.google.com with SMTP id 956f58d0204a3-66f943b286fso2256050d50.2 for ; Mon, 14 Sep 2026 16:40:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dubeyko-com.20251104.gappssmtp.com; s=20251104; t=1789429217; x=1790034017; 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=HskFOkbkGq+rAPbfNdgMU0TOyICy66VpOWiAOBriSq4=; b=nOmcgk9HtCVoIZB/9M2GKWPwud1wpfRT2S0pnuDPbyGaqbDZyjJwcbXXVYX1faDaIu vrKaWpwUYFuajOBwEzKbQxHGpbD1m9x2dCqAZ5gSJhT+qE5vc1LdTCD8OGAWp4Nsq5rd 1qY34WY32F3wdlX9og2wZvjQO5kBI9377XCoLQi8IJWPEZcCU9/+Z7Zr2EnbIS6rKXEH yekHeBnywzi5N31Set715vvtHj8FUoDRwR+y8QqYDEatGFNnkiHJMWAvCfroC5vz6x+i JV6Kub1D97H86S82EM6mdrxmzz6/yCvMv4b2hIqU5lRDV6AZAADGgmecG+5DN7GhiLP0 4kHg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789429217; x=1790034017; 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=HskFOkbkGq+rAPbfNdgMU0TOyICy66VpOWiAOBriSq4=; b=T0w5NYk33jyKNlxQMbStbmPVAN4tTS8AAzDJQdvBBGyLvoj24fybGNnLnQZPDRHEjl OhVoL4v8XQ2WV5ERQloxhuWrPsbBi2nxDbHc4r+pjVPMPuJoJJOxok6hLxlDURCh6lk8 PLzxMdiC3JF1u3Ez3hH5Mo3nFtI/zt1oSXLZno5qqIorpJPlnrDPx3K/TWuGV9PV2goh osX8vGNLFCAlvAkE1kqjc6epIRvbqXff6xmjevGeudsu21UohLVmMVQ0I1Q9FlcXgcq2 NBLOCUmZrkNN1mCDUD96K1Y0HGLDwyw8XrQaolFAjUXl1RitTaaPPREd3m0ro4n+IMnn nh+w== X-Forwarded-Encrypted: i=1; AKwUvByQkHAq7wvHTIJEoIVK0ca4zdSUxzRK2DG1ZVKrwo0xoXAh3A2MhCnijYp/v/lFdvtNWmDMnwNk9j1hTmM=@vger.kernel.org X-Gm-Message-State: AFuF++kPIDujhv5xLxGO7S5a1yIz9uO40ZeC6PF+otYIigmZjLDiAeUM qr66oz8Ii17cNiD6UdYF6rge5i0Mf0Jf0oSBOTU87XTqARCoo9PqtaxWA6BYEC4alcM= X-Gm-Gg: AYBFou0xJxKXDklbiGA76AbaglToqXkmOH2E4OOkJJ42AXLUHEh/qkWpbKbwzqqcmIo Ff40Wo0yB0vXUgw0Yed3V5A06BwaaN1TLTyk6Pt1CZGtr0JynHBz9rRh0bmAXRuf48LTT/sSldo rXxmh8URW59/vKJWldKV3Jmn10ugf0RaZYN39LGwWFEvgU+0haigSMWhYmgEAzcxTfD4p7ibQhM WI2oUGa6mSqNsh5yyWP1ErkjB+WEtJM9dLDrgMIvxIW7krnXmNs3eV2zNgn7OMaLOIVNEAVZlQm hPHO7hqN5oGRnT3LFybbWeqog+d9HHf+D59nkq94nB+MU7aYfywKBkopcL/ZToMhpIYSbyMaeci +GNXjPZcrr3uSOKAfafkUMYjGPcNtQeO84Z43wxHlil5fml2RrtyDSnLS6LYCd66iVY4V7xtmJJ HCoAgENag64zpUmTMmIbIaKSmVVYQa44pOBgNaMH4Xr5hPG5sdlIVkBfxsMP583ddQ4S6f7VrEJ M4QJ3PFBZfrpk9uiw55c/RfvK8QAVckQs4wWOvVBL3aw8mbC55SQE93tot8OveFKbzE7t4RAknX VhIRFxC0zOpX+dIWIHpYowYc2YbhvZsV0lWZg/gg X-Received: by 2002:a05:690e:4810:b0:671:3aff:c8e6 with SMTP id 956f58d0204a3-6714e1c4994mr932774d50.64.1789429216719; Mon, 14 Sep 2026 16:40:16 -0700 (PDT) Received: from pop-os.attlocal.net ([2600:1700:6476:1430:df87:8743:655b:3824]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-67125e3fa87sm5207804d50.14.2026.09.14.16.40.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Sep 2026 16:40:16 -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 v4 7/7] hfsplus: switch address_space_operations on iomap-based support Date: Mon, 14 Sep 2026 16:39:41 -0700 Message-ID: <20260914233941.2966421-8-slava@dubeyko.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260914233941.2966421-1-slava@dubeyko.com> References: <20260914233941.2966421-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" --- fs/hfsplus/Kconfig | 1 - fs/hfsplus/extents.c | 47 ++++++++---- fs/hfsplus/file.c | 2 +- fs/hfsplus/hfsplus_fs.h | 1 + fs/hfsplus/inode.c | 160 +++++++++++++++++++++------------------- fs/hfsplus/iomap.c | 14 ++-- fs/hfsplus/iomap.h | 2 +- 7 files changed, 127 insertions(+), 100 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..b724cc1ca3e1 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,33 @@ 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, hip->phys_size, + 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/file.c b/fs/hfsplus/file.c index 5a5776881c3e..0b0ae6b6e307 100644 --- a/fs/hfsplus/file.c +++ b/fs/hfsplus/file.c @@ -212,7 +212,7 @@ static ssize_t hfsplus_file_write_iter(struct kiocb *io= cb, loff_t old_size =3D i_size_read(inode); =20 i_size_write(inode, iocb->ki_pos); - err =3D hfsplus_iomap_cont_expand(inode, iocb->ki_pos); + err =3D hfsplus_iomap_cont_expand(inode, old_size, iocb->ki_pos); if (err) { i_size_write(inode, old_size); ret =3D err; 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..1779061dcad5 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,28 @@ 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, old_size, + 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 +409,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 +550,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, diff --git a/fs/hfsplus/iomap.c b/fs/hfsplus/iomap.c index 5723e854e58e..0eb392789126 100644 --- a/fs/hfsplus/iomap.c +++ b/fs/hfsplus/iomap.c @@ -137,18 +137,16 @@ const struct iomap_ops hfsplus_write_iomap_ops =3D { /* * 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(). + * Zero the byte range [from, to) of a file that is being extended, where + * 'from' is the old end-of-file and 'to' the new one. Used by the extendi= ng + * write path, hfsplus_setattr() (truncate up) and hfsplus_file_truncate(). */ -int hfsplus_iomap_cont_expand(struct inode *inode, loff_t size) +int hfsplus_iomap_cont_expand(struct inode *inode, loff_t from, loff_t to) { - struct hfsplus_inode_info *hip =3D HFSPLUS_I(inode); - loff_t start =3D hip->phys_size; - - if (size <=3D start) + if (to <=3D from) return 0; =20 - return iomap_zero_range(inode, start, size - start, NULL, + return iomap_zero_range(inode, from, to - from, NULL, &hfsplus_write_iomap_ops, NULL, NULL); } =20 diff --git a/fs/hfsplus/iomap.h b/fs/hfsplus/iomap.h index dac07a9d25f8..4dd4aca1804f 100644 --- a/fs/hfsplus/iomap.h +++ b/fs/hfsplus/iomap.h @@ -11,7 +11,7 @@ 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; =20 -int hfsplus_iomap_cont_expand(struct inode *inode, loff_t size); +int hfsplus_iomap_cont_expand(struct inode *inode, loff_t from, loff_t to); int hfsplus_iomap_swap_activate(struct swap_info_struct *sis, struct file *file, sector_t *span); =20 --=20 2.43.0