From nobody Tue Apr 7 13:28:14 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AB534ECAAD2 for ; Sat, 27 Aug 2022 07:48:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231629AbiH0Hsm (ORCPT ); Sat, 27 Aug 2022 03:48:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55044 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233119AbiH0Hsg (ORCPT ); Sat, 27 Aug 2022 03:48:36 -0400 Received: from mail-pl1-x633.google.com (mail-pl1-x633.google.com [IPv6:2607:f8b0:4864:20::633]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 73DD15070D for ; Sat, 27 Aug 2022 00:48:35 -0700 (PDT) Received: by mail-pl1-x633.google.com with SMTP id u22so3442257plq.12 for ; Sat, 27 Aug 2022 00:48:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=references:in-reply-to:references:in-reply-to:message-id:date :subject:cc:to:from:from:to:cc; bh=k4xOaCJXR13lMOpKa8KBEBvxrHZTljSJsyP8ZiT7jOE=; b=R0ELpqCjrsYaqO/7g3nQd5LYZgbXeKZI2ZSbQ5bovwxqA8ASQ4fGIe23pOappKXsW4 BBje2Q+FRxY/u3bOF6mxm+kQrdn8bwCU0UMvYtxW5Fx/ibcRMFeqQGhiSsIyv5uuhuUn objrh6OJ7Pk4s2YfUWc2J4Xt79l+pMTQPiTiJeag8RnGtlX7sMFGs9L7ugHq/RczAtON A9YIuofw7xZKuYmXJ6Y2qnUJxFxr0VXSP73EPlp5q/huahkV5zuSn8P9uD15vCnw2Vci 42H62nMnzl2EPd/HJGUQnI7yLpzJXXFpDL3WXR3L11vQLZ/m1kSpYaDaDoW/jRdRdRSZ 6oqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=references:in-reply-to:references:in-reply-to:message-id:date :subject:cc:to:from:x-gm-message-state:from:to:cc; bh=k4xOaCJXR13lMOpKa8KBEBvxrHZTljSJsyP8ZiT7jOE=; b=clrs09uG+fk2Qtz3ndCmTWrt1q7h91cAnG3m3v3BNb3w/xYyHjCnh8imHyIzRVYLZk FDlmAq5g8y/kTp89XNdPLk3gf7oDK1HoCoDh/6CtatXasrZtT5DUpkyeM23+urGotJPd pHiubuuDDMJAiTPaXUWeOVa+ChsuXLTNr2NdgQJ7dJzVl1KnjReCpKDye4zo8RW8hSsk Du6E1XFahWIpCREvMyHYgyxdRrBxMTxynuEzIHsvdNc4wfBFVPGPcFtkymS43GSrWjrL xJRyBuAqDQCnGosKI42ro2FjkINUV0NOcAibAh8Ge+W3OHJW+wY6QXlzFyjEQslNr8+J aT5g== X-Gm-Message-State: ACgBeo2s32bFZWd06jHlfbMwaeRvx3/KaXtb8q5TJ0SmGqNlzFJjY+45 SiINGrYYcjsnYCCnHyo3MhE= X-Google-Smtp-Source: AA6agR6HIkTg+FLYs2FEJWzVTEf40XbCuU/Hh6tLVt36rql5TChqT3b0a7AjnR+jCgYZgkl3AcXP/g== X-Received: by 2002:a17:902:e80e:b0:173:23e:d5a6 with SMTP id u14-20020a170902e80e00b00173023ed5a6mr6996841plg.85.1661586514951; Sat, 27 Aug 2022 00:48:34 -0700 (PDT) Received: from localhost.localdomain ([156.236.96.165]) by smtp.gmail.com with ESMTPSA id q4-20020a656844000000b0042aaaf6e2d9sm2632006pgt.49.2022.08.27.00.48.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 27 Aug 2022 00:48:34 -0700 (PDT) From: Yue Hu To: xiang@kernel.org, chao@kernel.org Cc: linux-erofs@lists.ozlabs.org, linux-kernel@vger.kernel.org, zhangwen@coolpad.com, shaojunjun@coolpad.com, Yue Hu Subject: [RFC PATCH v2 1/2] erofs: support interlaced uncompressed data for compressed files Date: Sat, 27 Aug 2022 15:47:56 +0800 Message-Id: <014ae4b2548bb318a4f187c7dad59867721bf418.1661584151.git.huyue2@coolpad.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Yue Hu Currently, there is no start offset when writing uncompressed data to disk blocks for compressed files. However, we are using in-place I/O which will decrease the number of memory copies a lot if we write it just from an offset of 'pageofs_out'. So, let's support it. Signed-off-by: Yue Hu --- fs/erofs/compress.h | 3 +++ fs/erofs/decompressor.c | 12 +++++++----- fs/erofs/erofs_fs.h | 2 ++ fs/erofs/zdata.c | 11 ++++++++++- fs/erofs/zdata.h | 3 +++ 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/fs/erofs/compress.h b/fs/erofs/compress.h index 26fa170090b8..cef26c63d6b1 100644 --- a/fs/erofs/compress.h +++ b/fs/erofs/compress.h @@ -15,6 +15,9 @@ struct z_erofs_decompress_req { unsigned short pageofs_in, pageofs_out; unsigned int inputsize, outputsize; =20 + /* cut point of interlaced uncompressed data */ + unsigned int interlaced_offset; + /* indicate the algorithm will be used for decompression */ unsigned int alg; bool inplace_io, partial_decoding, fillgaps; diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c index 2d55569f96ac..e5dc8eb992b1 100644 --- a/fs/erofs/decompressor.c +++ b/fs/erofs/decompressor.c @@ -340,18 +340,20 @@ static int z_erofs_shifted_transform(struct z_erofs_d= ecompress_req *rq, src =3D kmap_atomic(*rq->in) + rq->pageofs_in; if (rq->out[0]) { dst =3D kmap_atomic(rq->out[0]); - memcpy(dst + rq->pageofs_out, src, righthalf); + memcpy(dst + rq->pageofs_out, src + rq->interlaced_offset, + righthalf); kunmap_atomic(dst); } =20 if (nrpages_out =3D=3D 2) { DBG_BUGON(!rq->out[1]); - if (rq->out[1] =3D=3D *rq->in) { - memmove(src, src + righthalf, lefthalf); - } else { + if (rq->out[1] !=3D *rq->in) { dst =3D kmap_atomic(rq->out[1]); - memcpy(dst, src + righthalf, lefthalf); + memcpy(dst, rq->interlaced_offset ? src : + (src + righthalf), lefthalf); kunmap_atomic(dst); + } else if (!rq->interlaced_offset) { + memmove(src, src + righthalf, lefthalf); } } kunmap_atomic(src); diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h index 2b48373f690b..5c1de6d7ad71 100644 --- a/fs/erofs/erofs_fs.h +++ b/fs/erofs/erofs_fs.h @@ -295,11 +295,13 @@ struct z_erofs_lzma_cfgs { * bit 1 : HEAD1 big pcluster (0 - off; 1 - on) * bit 2 : HEAD2 big pcluster (0 - off; 1 - on) * bit 3 : tailpacking inline pcluster (0 - off; 1 - on) + * bit 4 : interlaced plain pcluster (0 - off; 1 - on) */ #define Z_EROFS_ADVISE_COMPACTED_2B 0x0001 #define Z_EROFS_ADVISE_BIG_PCLUSTER_1 0x0002 #define Z_EROFS_ADVISE_BIG_PCLUSTER_2 0x0004 #define Z_EROFS_ADVISE_INLINE_PCLUSTER 0x0008 +#define Z_EROFS_ADVISE_INTERLACED_PCLUSTER 0x0010 =20 struct z_erofs_map_header { __le16 h_reserved1; diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c index 5792ca9e0d5e..4863d9d960d5 100644 --- a/fs/erofs/zdata.c +++ b/fs/erofs/zdata.c @@ -481,6 +481,7 @@ static void z_erofs_try_to_claim_pcluster(struct z_erof= s_decompress_frontend *f) =20 static int z_erofs_register_pcluster(struct z_erofs_decompress_frontend *f= e) { + struct erofs_inode *const vi =3D EROFS_I(fe->inode); struct erofs_map_blocks *map =3D &fe->map; bool ztailpacking =3D map->m_flags & EROFS_MAP_META; struct z_erofs_pcluster *pcl; @@ -508,6 +509,11 @@ static int z_erofs_register_pcluster(struct z_erofs_de= compress_frontend *fe) pcl->pageofs_out =3D map->m_la & ~PAGE_MASK; fe->mode =3D Z_EROFS_PCLUSTER_FOLLOWED; =20 + pcl->interlaced =3D false; + if ((vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER) && + pcl->algorithmformat =3D=3D Z_EROFS_COMPRESSION_SHIFTED) + pcl->interlaced =3D true; + /* * lock all primary followed works before visible to others * and mutex_trylock *never* fails for a new pcluster. @@ -972,7 +978,7 @@ static int z_erofs_decompress_pcluster(struct z_erofs_d= ecompress_backend *be, struct erofs_sb_info *const sbi =3D EROFS_SB(be->sb); struct z_erofs_pcluster *pcl =3D be->pcl; unsigned int pclusterpages =3D z_erofs_pclusterpages(pcl); - unsigned int i, inputsize; + unsigned int i, inputsize, interlaced_offset; int err2; struct page *page; bool overlapped; @@ -1015,6 +1021,8 @@ static int z_erofs_decompress_pcluster(struct z_erofs= _decompress_backend *be, else inputsize =3D pclusterpages * PAGE_SIZE; =20 + interlaced_offset =3D pcl->interlaced ? pcl->pageofs_out : 0; + err =3D z_erofs_decompress(&(struct z_erofs_decompress_req) { .sb =3D be->sb, .in =3D be->compressed_pages, @@ -1023,6 +1031,7 @@ static int z_erofs_decompress_pcluster(struct z_erofs= _decompress_backend *be, .pageofs_out =3D pcl->pageofs_out, .inputsize =3D inputsize, .outputsize =3D pcl->length, + .interlaced_offset =3D interlaced_offset, .alg =3D pcl->algorithmformat, .inplace_io =3D overlapped, .partial_decoding =3D pcl->partial, diff --git a/fs/erofs/zdata.h b/fs/erofs/zdata.h index e7f04c4fbb81..75f3a52fc66f 100644 --- a/fs/erofs/zdata.h +++ b/fs/erofs/zdata.h @@ -87,6 +87,9 @@ struct z_erofs_pcluster { /* L: indicate several pageofs_outs or not */ bool multibases; =20 + /* I: whether interlaced uncompressed data or not */ + bool interlaced; + /* A: compressed bvecs (can be cached or inplaced pages) */ struct z_erofs_bvec compressed_bvecs[]; }; --=20 2.17.1 From nobody Tue Apr 7 13:28:14 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4FA7AC0502E for ; Sat, 27 Aug 2022 07:48:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232904AbiH0Hss (ORCPT ); Sat, 27 Aug 2022 03:48:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55114 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1345336AbiH0Hsl (ORCPT ); Sat, 27 Aug 2022 03:48:41 -0400 Received: from mail-pj1-x1031.google.com (mail-pj1-x1031.google.com [IPv6:2607:f8b0:4864:20::1031]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 498BC52FC3 for ; Sat, 27 Aug 2022 00:48:39 -0700 (PDT) Received: by mail-pj1-x1031.google.com with SMTP id o4so3527383pjp.4 for ; Sat, 27 Aug 2022 00:48:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=references:in-reply-to:references:in-reply-to:message-id:date :subject:cc:to:from:from:to:cc; bh=tundwHpQyZSXXnKLI0HgJZiYKq+AyCa3XHgpCYBoF2U=; b=Utq4zj4OiXp/uKEk8owSMzTghM07CVPoV2gsQHbcA6ewoBqCodCiWJGM+RaKFR/2Fi 5VG/U4VZix05HaruT0ERyUC2ZnlsFrEQEdMFof4zvoAvH0/RANQl8Ph+PmgBeuJXEav2 VKRP73pYG8S/FUqdZwo5yq8c4su3fPIYNZJpMIiWrSyGW0BhMum9O3mg9PDmbLLXe5Bb Kh5/GQ65y4QFOD33PDGLjYCCZ83LL/lausR2IPeqVWNW3Ki18/kVsajRIbaO/r3rco3g kWE05hCmgjzA8t/a5OiO9SBg8rgrjbQ3iXMK61iaUYLfIrh45lGuDbqyo1B4XDY5Z5BE eQoA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=references:in-reply-to:references:in-reply-to:message-id:date :subject:cc:to:from:x-gm-message-state:from:to:cc; bh=tundwHpQyZSXXnKLI0HgJZiYKq+AyCa3XHgpCYBoF2U=; b=44+/1WEJ2rM8bJSCKZU2woS0VDFWSp4/WwTXJlyEjm2kvfo4eL4yCCaySo+7gGNvz4 HSUdYWIHkj58BeMz87Rn78jY++n8SCSlP+liW/hJn01PymwlI/XrP9We8/Hw5l2ChFmo Qs3DExtkDF5IWlnVqb3Ycz15RZueznwFwpCxKvqhy+dGz5lAE3Ma6w35rArkQx4QLaor Sc7oTEn8wZU0Cg/5ocTUV2y7E0REEytH763brQ+YSIxGPofq11QlPgUJCXvOhFKOpb7n FNsOqVERMEJtu5TRS8waWFOgw9E4qSdSXnAJFLayIAxNyP821qXxNTDc42MZJ6aIRNep dY4g== X-Gm-Message-State: ACgBeo1pRhBzcfNw+zYRMLQfVHkEMP0bY40RNeOexvRGH/0g/EPTMx9d A3c0xmAZxjElB4E7dgBGpUI= X-Google-Smtp-Source: AA6agR6NKKZ9FBFeMCJ++uaQLr5XDXAr70UIoEexsKF3Jp6KNoujE01nG8XxXWYGb2yPDublMF0VoA== X-Received: by 2002:a17:90a:9309:b0:1fa:d28b:3751 with SMTP id p9-20020a17090a930900b001fad28b3751mr8052273pjo.189.1661586518671; Sat, 27 Aug 2022 00:48:38 -0700 (PDT) Received: from localhost.localdomain ([156.236.96.165]) by smtp.gmail.com with ESMTPSA id q4-20020a656844000000b0042aaaf6e2d9sm2632006pgt.49.2022.08.27.00.48.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 27 Aug 2022 00:48:38 -0700 (PDT) From: Yue Hu To: xiang@kernel.org, chao@kernel.org Cc: linux-erofs@lists.ozlabs.org, linux-kernel@vger.kernel.org, zhangwen@coolpad.com, shaojunjun@coolpad.com, Yue Hu Subject: [RFC PATCH v2 2/2] erofs: support on-disk compressed fragments data Date: Sat, 27 Aug 2022 15:47:57 +0800 Message-Id: <6940e10fd52e49a1659e728a0b44245d85a03f84.1661584151.git.huyue2@coolpad.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Yue Hu Introduce on-disk compressed fragments data feature. This approach adds a new field called `h_fragmentoff' in the per-file compression header to indicate the fragment offset of each tail pcluster or the whole file in the special packed inode. Like ztailpacking, it will also find and record the 'headlcn' of the tail pcluster when initializing per-inode zmap for making follow-on requests more easy. Signed-off-by: Yue Hu --- fs/erofs/erofs_fs.h | 26 ++++++++++++++++++------ fs/erofs/internal.h | 16 ++++++++++++--- fs/erofs/super.c | 15 ++++++++++++++ fs/erofs/sysfs.c | 2 ++ fs/erofs/zdata.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- fs/erofs/zmap.c | 35 +++++++++++++++++++++++++++++++-- 6 files changed, 130 insertions(+), 12 deletions(-) diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h index 5c1de6d7ad71..340fb980fe03 100644 --- a/fs/erofs/erofs_fs.h +++ b/fs/erofs/erofs_fs.h @@ -25,6 +25,7 @@ #define EROFS_FEATURE_INCOMPAT_DEVICE_TABLE 0x00000008 #define EROFS_FEATURE_INCOMPAT_COMPR_HEAD2 0x00000008 #define EROFS_FEATURE_INCOMPAT_ZTAILPACKING 0x00000010 +#define EROFS_FEATURE_INCOMPAT_FRAGMENTS 0x00000020 #define EROFS_ALL_FEATURE_INCOMPAT \ (EROFS_FEATURE_INCOMPAT_ZERO_PADDING | \ EROFS_FEATURE_INCOMPAT_COMPR_CFGS | \ @@ -32,7 +33,8 @@ EROFS_FEATURE_INCOMPAT_CHUNKED_FILE | \ EROFS_FEATURE_INCOMPAT_DEVICE_TABLE | \ EROFS_FEATURE_INCOMPAT_COMPR_HEAD2 | \ - EROFS_FEATURE_INCOMPAT_ZTAILPACKING) + EROFS_FEATURE_INCOMPAT_ZTAILPACKING | \ + EROFS_FEATURE_INCOMPAT_FRAGMENTS) =20 #define EROFS_SB_EXTSLOT_SIZE 16 =20 @@ -71,7 +73,9 @@ struct erofs_super_block { } __packed u1; __le16 extra_devices; /* # of devices besides the primary device */ __le16 devt_slotoff; /* startoff =3D devt_slotoff * devt_slotsize */ - __u8 reserved2[38]; + __u8 reserved[6]; + __le64 packed_nid; /* nid of the special packed inode */ + __u8 reserved2[24]; }; =20 /* @@ -296,17 +300,26 @@ struct z_erofs_lzma_cfgs { * bit 2 : HEAD2 big pcluster (0 - off; 1 - on) * bit 3 : tailpacking inline pcluster (0 - off; 1 - on) * bit 4 : interlaced plain pcluster (0 - off; 1 - on) + * bit 5 : fragment pcluster (0 - off; 1 - on) */ #define Z_EROFS_ADVISE_COMPACTED_2B 0x0001 #define Z_EROFS_ADVISE_BIG_PCLUSTER_1 0x0002 #define Z_EROFS_ADVISE_BIG_PCLUSTER_2 0x0004 #define Z_EROFS_ADVISE_INLINE_PCLUSTER 0x0008 #define Z_EROFS_ADVISE_INTERLACED_PCLUSTER 0x0010 +#define Z_EROFS_ADVISE_FRAGMENT_PCLUSTER 0x0020 =20 +#define Z_EROFS_FRAGMENT_INODE_BIT 7 struct z_erofs_map_header { - __le16 h_reserved1; - /* indicates the encoded size of tailpacking data */ - __le16 h_idata_size; + union { + /* direct addressing for fragment offset */ + __le32 h_fragmentoff; + struct { + __le16 h_reserved1; + /* indicates the encoded size of tailpacking data */ + __le16 h_idata_size; + }; + }; __le16 h_advise; /* * bit 0-3 : algorithm type of head 1 (logical cluster type 01); @@ -315,7 +328,8 @@ struct z_erofs_map_header { __u8 h_algorithmtype; /* * bit 0-2 : logical cluster bits - 12, e.g. 0 for 4096; - * bit 3-7 : reserved. + * bit 3-6 : reserved; + * bit 7 : move the whole file into packed inode or not. */ __u8 h_clusterbits; }; diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index cfee49d33b95..7b9d31bab928 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -120,6 +120,7 @@ struct erofs_sb_info { struct inode *managed_cache; =20 struct erofs_sb_lz4_info lz4; + struct inode *packed_inode; #endif /* CONFIG_EROFS_FS_ZIP */ struct erofs_dev_context *devs; struct dax_device *dax_dev; @@ -306,6 +307,7 @@ EROFS_FEATURE_FUNCS(chunked_file, incompat, INCOMPAT_CH= UNKED_FILE) EROFS_FEATURE_FUNCS(device_table, incompat, INCOMPAT_DEVICE_TABLE) EROFS_FEATURE_FUNCS(compr_head2, incompat, INCOMPAT_COMPR_HEAD2) EROFS_FEATURE_FUNCS(ztailpacking, incompat, INCOMPAT_ZTAILPACKING) +EROFS_FEATURE_FUNCS(fragments, incompat, INCOMPAT_FRAGMENTS) EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM) =20 /* atomic flag definitions */ @@ -341,8 +343,13 @@ struct erofs_inode { unsigned char z_algorithmtype[2]; unsigned char z_logical_clusterbits; unsigned long z_tailextent_headlcn; - erofs_off_t z_idataoff; - unsigned short z_idata_size; + union { + struct { + erofs_off_t z_idataoff; + unsigned short z_idata_size; + }; + erofs_off_t z_fragmentoff; + }; }; #endif /* CONFIG_EROFS_FS_ZIP */ }; @@ -400,6 +407,7 @@ extern const struct address_space_operations z_erofs_ao= ps; enum { BH_Encoded =3D BH_PrivateStart, BH_FullMapped, + BH_Fragment, }; =20 /* Has a disk mapping */ @@ -410,6 +418,8 @@ enum { #define EROFS_MAP_ENCODED (1 << BH_Encoded) /* The length of extent is full */ #define EROFS_MAP_FULL_MAPPED (1 << BH_FullMapped) +/* Located in the special packed inode */ +#define EROFS_MAP_FRAGMENT (1 << BH_Fragment) =20 struct erofs_map_blocks { struct erofs_buf buf; @@ -431,7 +441,7 @@ struct erofs_map_blocks { #define EROFS_GET_BLOCKS_FIEMAP 0x0002 /* Used to map the whole extent if non-negligible data is requested for LZ= MA */ #define EROFS_GET_BLOCKS_READMORE 0x0004 -/* Used to map tail extent for tailpacking inline pcluster */ +/* Used to map tail extent for tailpacking inline or fragment pcluster */ #define EROFS_GET_BLOCKS_FINDTAIL 0x0008 =20 enum { diff --git a/fs/erofs/super.c b/fs/erofs/super.c index 3173debeaa5a..8170c0d8ab92 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -381,6 +381,17 @@ static int erofs_read_superblock(struct super_block *s= b) #endif sbi->islotbits =3D ilog2(sizeof(struct erofs_inode_compact)); sbi->root_nid =3D le16_to_cpu(dsb->root_nid); +#ifdef CONFIG_EROFS_FS_ZIP + sbi->packed_inode =3D NULL; + if (erofs_sb_has_fragments(sbi)) { + sbi->packed_inode =3D + erofs_iget(sb, le64_to_cpu(dsb->packed_nid), false); + if (IS_ERR(sbi->packed_inode)) { + ret =3D PTR_ERR(sbi->packed_inode); + goto out; + } + } +#endif sbi->inos =3D le64_to_cpu(dsb->inos); =20 sbi->build_time =3D le64_to_cpu(dsb->build_time); @@ -411,6 +422,8 @@ static int erofs_read_superblock(struct super_block *sb) erofs_info(sb, "EXPERIMENTAL compressed inline data feature in use. Use = at your own risk!"); if (erofs_is_fscache_mode(sb)) erofs_info(sb, "EXPERIMENTAL fscache-based on-demand read feature in use= . Use at your own risk!"); + if (erofs_sb_has_fragments(sbi)) + erofs_info(sb, "EXPERIMENTAL compressed fragments feature in use. Use at= your own risk!"); out: erofs_put_metabuf(&buf); return ret; @@ -908,6 +921,8 @@ static void erofs_put_super(struct super_block *sb) #ifdef CONFIG_EROFS_FS_ZIP iput(sbi->managed_cache); sbi->managed_cache =3D NULL; + iput(sbi->packed_inode); + sbi->packed_inode =3D NULL; #endif erofs_fscache_unregister_cookie(&sbi->s_fscache); } diff --git a/fs/erofs/sysfs.c b/fs/erofs/sysfs.c index c1383e508bbe..1b52395be82a 100644 --- a/fs/erofs/sysfs.c +++ b/fs/erofs/sysfs.c @@ -76,6 +76,7 @@ EROFS_ATTR_FEATURE(device_table); EROFS_ATTR_FEATURE(compr_head2); EROFS_ATTR_FEATURE(sb_chksum); EROFS_ATTR_FEATURE(ztailpacking); +EROFS_ATTR_FEATURE(fragments); =20 static struct attribute *erofs_feat_attrs[] =3D { ATTR_LIST(zero_padding), @@ -86,6 +87,7 @@ static struct attribute *erofs_feat_attrs[] =3D { ATTR_LIST(compr_head2), ATTR_LIST(sb_chksum), ATTR_LIST(ztailpacking), + ATTR_LIST(fragments), NULL, }; ATTRIBUTE_GROUPS(erofs_feat); diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c index 4863d9d960d5..409a868df8bb 100644 --- a/fs/erofs/zdata.c +++ b/fs/erofs/zdata.c @@ -656,6 +656,33 @@ static bool should_alloc_managed_pages(struct z_erofs_= decompress_frontend *fe, la < fe->headoffset; } =20 +static int z_erofs_read_fragment_data(struct page *page, unsigned int page= ofs, + loff_t start, unsigned int len) +{ + struct inode *const inode =3D page->mapping->host; + erofs_off_t offset =3D EROFS_I(inode)->z_fragmentoff + start; + struct erofs_buf buf =3D __EROFS_BUF_INITIALIZER; + u8 *src, *dst; + unsigned int i, cnt; + + for (i =3D 0; i < len; i +=3D cnt) { + cnt =3D min(EROFS_BLKSIZ - (unsigned int)erofs_blkoff(offset), + len - i); + src =3D erofs_bread(&buf, EROFS_I_SB(inode)->packed_inode, + erofs_blknr(offset), EROFS_KMAP); + if (IS_ERR(src)) + return PTR_ERR(src); + + dst =3D kmap_local_page(page); + memcpy(dst + pageofs + i, src + erofs_blkoff(offset), cnt); + kunmap_local(dst); + + offset +=3D cnt; + } + erofs_put_metabuf(&buf); + return 0; +} + static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe, struct page *page, struct page **pagepool) { @@ -694,7 +721,8 @@ static int z_erofs_do_read_page(struct z_erofs_decompre= ss_frontend *fe, /* didn't get a valid pcluster previously (very rare) */ } =20 - if (!(map->m_flags & EROFS_MAP_MAPPED)) + if (!(map->m_flags & EROFS_MAP_MAPPED) || + map->m_flags & EROFS_MAP_FRAGMENT) goto hitted; =20 err =3D z_erofs_collector_begin(fe); @@ -741,6 +769,24 @@ static int z_erofs_do_read_page(struct z_erofs_decompr= ess_frontend *fe, zero_user_segment(page, cur, end); goto next_part; } + if (map->m_flags & EROFS_MAP_FRAGMENT) { + unsigned int pageofs, skip, len; + + if (map->m_la < offset) { + pageofs =3D 0; + skip =3D offset - map->m_la; + } else { + pageofs =3D map->m_la & ~PAGE_MASK; + skip =3D 0; + } + len =3D min((unsigned int)(map->m_llen - skip), end - cur); + err =3D z_erofs_read_fragment_data(page, pageofs, skip, len); + if (err) + goto out; + ++spiltted; + tight =3D false; + goto next_part; + } =20 exclusive =3D (!cur && (!spiltted || tight)); if (cur) diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c index d58549ca1df9..81313434ed3c 100644 --- a/fs/erofs/zmap.c +++ b/fs/erofs/zmap.c @@ -123,6 +123,23 @@ static int z_erofs_fill_inode_lazy(struct inode *inode) if (err < 0) goto out_unlock; } + if (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER) { + vi->z_fragmentoff =3D le32_to_cpu(h->h_fragmentoff); + + if (h->h_clusterbits >> Z_EROFS_FRAGMENT_INODE_BIT) { + vi->z_tailextent_headlcn =3D 0; + } else { + struct erofs_map_blocks map =3D { + .buf =3D __EROFS_BUF_INITIALIZER + }; + + err =3D z_erofs_do_map_blocks(inode, &map, + EROFS_GET_BLOCKS_FINDTAIL); + erofs_put_metabuf(&map.buf); + if (err < 0) + goto out_unlock; + } + } /* paired with smp_mb() at the beginning of the function */ smp_mb(); set_bit(EROFS_I_Z_INITED_BIT, &vi->flags); @@ -598,6 +615,7 @@ static int z_erofs_do_map_blocks(struct inode *inode, { struct erofs_inode *const vi =3D EROFS_I(inode); bool ztailpacking =3D vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER; + bool inpacked =3D vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER; struct z_erofs_maprecorder m =3D { .inode =3D inode, .map =3D map, @@ -672,6 +690,9 @@ static int z_erofs_do_map_blocks(struct inode *inode, map->m_flags |=3D EROFS_MAP_META; map->m_pa =3D vi->z_idataoff; map->m_plen =3D vi->z_idata_size; + } else if (inpacked && m.lcn =3D=3D vi->z_tailextent_headlcn) { + map->m_flags |=3D EROFS_MAP_FRAGMENT; + DBG_BUGON(!map->m_la); } else { map->m_pa =3D blknr_to_addr(m.pblk); err =3D z_erofs_get_extent_compressedlen(&m, initial_lcn); @@ -709,6 +730,7 @@ int z_erofs_map_blocks_iter(struct inode *inode, struct erofs_map_blocks *map, int flags) { + struct erofs_inode *const vi =3D EROFS_I(inode); int err =3D 0; =20 trace_z_erofs_map_blocks_iter_enter(inode, map, flags); @@ -725,11 +747,19 @@ int z_erofs_map_blocks_iter(struct inode *inode, if (err) goto out; =20 + if ((vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER) && + !vi->z_tailextent_headlcn) { + map->m_llen =3D map->m_la + 1; + map->m_la =3D 0; + map->m_flags =3D EROFS_MAP_MAPPED | EROFS_MAP_FRAGMENT; + goto out; + } + err =3D z_erofs_do_map_blocks(inode, map, flags); out: trace_z_erofs_map_blocks_iter_exit(inode, map, flags, err); =20 - /* aggressively BUG_ON iff CONFIG_EROFS_FS_DEBUG is on */ + /* aggressively BUG_ON if CONFIG_EROFS_FS_DEBUG is on */ DBG_BUGON(err < 0 && err !=3D -ENOMEM); return err; } @@ -751,7 +781,8 @@ static int z_erofs_iomap_begin_report(struct inode *ino= de, loff_t offset, iomap->length =3D map.m_llen; if (map.m_flags & EROFS_MAP_MAPPED) { iomap->type =3D IOMAP_MAPPED; - iomap->addr =3D map.m_pa; + iomap->addr =3D map.m_flags & EROFS_MAP_FRAGMENT ? + IOMAP_NULL_ADDR : map.m_pa; } else { iomap->type =3D IOMAP_HOLE; iomap->addr =3D IOMAP_NULL_ADDR; --=20 2.17.1