Keguang Xu kxu · review.whamcloud.com
Needs your action
2 new · 6 longstanding
69762
master
J –B ✓T ✓R +2/2
LU-20287 lov: don't block setattr on unavailable OST
mine Verified -1 veto by Oleg Drokin
Verified -1
218_review_prioritypw_shepherdpt_ecro
master-next
1 unresolved
L +319 −25
1h
LU-20287 lov: don't block setattr on unavailable OST
mine Verified -1 veto by Oleg Drokin
Verified -1
218_review_prioritypw_shepherdpt_ecro
master-next
1 unresolved
L +319 −25
1h
Verified -1 veto by Oleg Drokin
1 reviewer comment(s) to address if a respin is needed — last from Andreas Dilger
build #134595 SUCCESS · tests all Maloo sessions
reviews:
Ronnie Sahlberg +1 · Andreas Dilger +1
no vote yet: Marc Vef, Oleg Drokin
patchsets:
PS3 10-22
PS4 10-25
PS5 10-27
PS6 10-27 Marc Vef
PS7 10-28
+2 earlier
PS1 10-17 PS2 10-18threads: 1 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Andreas Dilger cl_object.h:2567 — seems reasonable if patch is refreshed
Gerrit AI review for Lustre
(minor) The new mtime and the new atime are both compared with one shared baseline, max(ctime, sa_cur_time). sa_cur_time is the max of the old mtime and atime, the cached OST mtime and atime, and the inode mtime and atime that vvp_attr_get() reads at iter_init. ll_md_setattr() has already written the new values into the inode by then. ll_merge_attr() merges each field on its own (atime with atime, mtime with mtime), so a newer value in the *other* field can never win the max() for this one.
With the shared baseline:
touch -m -d '+1 hour' f # mtime ahead, no lock (new >= ctime)
touch -a f # atime = now < base (mtime +1h)
The second command now counts as backward. vvp_io_setattr_lock() takes a CLM_WRITE [0, EOF] lock, which revokes other clients' extent locks even when every OST is up. If an OST is down, the command also blocks. Before this patch it took no lock. touch -m behaves the same way when the atime is ahead. So does utimensat() with atime < mtime when both are later than ctime, because the new mtime is already in the inode.
Would it be safer to keep separate mtime and atime baselines (sa_cur_mtime / sa_cur_atime), so that each new time is compared only with its own field? The comments on sa_cur_time, in cl_setattr_ost() and in vvp_io_setattr_iter_init() would then also match what is actually collected.
Andreas Dilger
seems reasonable if patch is refreshed
tags: 218_review_priority pw_shepherd pt_ecro
owner Keguang Xu · uploader Keguang Xu · PS7 uploaded 8d ago · NEW · open in Gerrit ↗
commit message
LU-20287 lov: don't block setattr on unavailable OST chown/chgrp/chmod/touch wait in cl_setattr_ost() when a stripe OST is down: VFS sets ATTR_CTIME and the client sends OST_SETATTR to every stripe. That RPC only carries times/flags; UID/GID/PROJID are authoritative on the MDT and are pushed by MDS osp_sync (persistent llog, retried until the OST returns). Skipping the client RPC therefore does not leave stale ownership on OST objects. For non-truncate/non-fallocate setattr on any layout, mark LOV sub-IOs ci_ndelay so OSC sends OST_SETATTR with rq_no_delay and rq_no_resend (plus a 5s delay limit for idle import reconnect), and ignore -EAGAIN/-ENOTCONN/-ESHUTDOWN/-ETIMEDOUT for such sub-IOs in osc_io_setattr_end(). Ndelay applies only when the new mtime/atime are >= max(ctime, sa_cur_time), where sa_cur_time is the known prior inode/cached OST times: ll_merge_attr() takes max(MDT, OST), so skipping an OST that already holds a newer time would leave that value visible. Missed updates are not repaired later, and on a slow but connected OST the client update may also be dropped. The CLM_WRITE [0, EOF] lock in vvp_io_setattr_lock() uses that same baseline, not ctime alone. Plain touch/utime(NULL) therefore takes the lock when sa_cur_time is ahead of the client clock (writer clock skew, or a future timestamp) and revokes other clients' cached extent locks; that path does not set ndelay. That is intentional: without it ndelay would skip the newer OST and max() would keep the wrong time. Still block when: - mtime/atime moves earlier than that baseline; - OP_XVALID_FLAGS is set (chattr, encryption flag): MDS never pushes flags to OSTs. This only unblocks the setattr RPC itself (including chmod(2)). stat/glimpse can still hang when no usable stripe/mirror is reachable: e.g. coreutils chmod stats via FTS before chmod(2), so the command may block on plain files even though the syscall would not. That is unchanged here (see LU-11962 for MDT SOM). Also re-push UID/GID/PROJID from the MDT inode on FLR RESYNC_DONE in lod_layout_change() with the layout version update. osp_sync normally retries ownership pushes; this is belt-and-suspenders if an MDS->OST ownership setattr was skipped (e.g. exercised with OBD_FAIL_LFSCK_BAD_OWNER; layout LFSCK can also repair that). Add sanity 39v (plain file) and sanity-flr 100a/100b. Test-Parameters: testlist=sanity env=ONLY=39v Test-Parameters: testlist=sanity-flr Assisted-by: Cursor:Grok-4.6/Opus5.5 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: I5005451e10f293279c441c1fc6d012fb5337d95d
67700
master
J –B ✓T ✓R 0/2
LU-20354 quota: cache per-slave DT usage on QMT
mine 10 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
11 unresolved
L +754 −11
6d
LU-20354 quota: cache per-slave DT usage on QMT
mine 10 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
11 unresolved
L +754 −11
6d
10 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
CI green — no vote yet from Sergey Cheremencev, Andreas Dilger, Hongchao Zhang
1 thread(s) waiting on others
build #133862 SUCCESS · tests all Maloo sessions
no vote yet: Sergey Cheremencev, Andreas Dilger, Hongchao Zhang
patchsets:
PS13 09-02
PS14 09-29
PS15 10-05
PS16 10-12
PS17 10-15 kg.xu
+12 earlier
PS1 08-03 PS2 08-04 PS3 08-05 PS4 08-06 PS5 08-10 PS6 08-18 PS7 08-24 PS8 08-24 PS9 08-26 PS10 08-28 PS11 08-29 PS12 08-30threads: 10 need your reply · 1 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre COMMIT_MSG:10 — (minor) The subject and this sentence scope the cache to DT / block usage, but nothing in the code restricts it to LQUOTA_RES_DT.
Gerrit AI review for Lustre
(minor) The subject and this sentence scope the cache to DT / block usage, but nothing in the code restricts it to LQUOTA_RES_DT. qmt_pool_new_conn() is called once per global index FID, so qmt_usg_extend_sites() also runs on the LQUOTA_RES_MD global pool, and the warming loop in qmt_dqacq0() runs for whatever qti_lqes(env) holds - which is the MD pool lqe on an inode DQACQ, with qb_usage being an inode count. So MD lqes get an lqe_usg_data and per-MDT slots too. Is that intended (in which case the message could say so), or should the warming and the extend be gated on LQUOTA_RES_DT until the inode side is ready?
reply Andreas Dilger COMMIT_MSG:10 — ... block and inode usage ..., I hope? It should be possible to cache the MDT usage as well, in case it is temporarily offline.
Andreas Dilger
... block and inode usage ..., I hope? It should be possible to cache the MDT usage as well, in case it is temporarily offline.
reply kg.xu patchset comment — Updated
kg.xu
Hi, some tips on this change, which might be helpful in review,
Focus: Build QMT per-slave DT usage cache only. qmt_usg_serve=0 — GETQUOTA still leaves usage unset (legacy client fan-out).
Read order: qmt_internal.h → qmt_pool.c (DOM/dom_mdts) → qmt_entry.c (update/sum/refresh) → qmt_dqacq0 warm → mdt_qmt_fetch_usage.
Call chains:
```
# warm (live)
QSD DQACQ/REL (+QUOTA_DQACQ_FL_USAGE, qb_usage)
→ qmt_dqacq → qmt_dqacq0 → qmt_update_lqe_usg()
# pool membership → slots
connect/add → qmt_usg_extend_cb | qmt_pool_dom_add → empty slot
shrink → qmt_usg_shrink_cb → qmt_del_lqe_usg()
# refresh (wired, gated off)
qmt_quotactl(GETQUOTA) → qmt_get_usage()
→ (!qmt_usg_serve) -EAGAIN
→ [later] sum → refresh → mdt_qmt_fetch_usage
→ local MDT: lquotactl_slv | OST: OSP Q_GETOQUOTA
→ fail: keep cache | fallback granted
```
kg.xu
Updated
Focus: Build QMT per-slave DT usage cache only.
Read order:
qmt_internal.h / lquota_internal.h (lqu_xa) →
qmt_pool.c (DOM / extend / shrink) →
qmt_entry.c (update / del / sum) →
qmt_dqacq0 warm → qsd_handler.c (QUOTA_DQACQ_FL_USAGE).
Call chains:
```
QSD DQACQ/REL (+QUOTA_DQACQ_FL_USAGE, qb_usage)
→ qmt_dqacq → qmt_dqacq0 → qmt_update_lqe_usg_entry
(also on REPORT; skip shared LQA lqe)
# pool membership → slots
OST/MDT connect/add
→ qmt_usg_extend_cb → empty OST (or MD primary) slot
DOM MDT connect (global DT only)
→ qmt_pool_dom_add → qmt_usg_dom_extend_cb → empty MDT slot
shrink (snapshot then delete; not under cfs_hash_for_each)
→ qmt_usg_shrink_hash → qmt_del_lqe_usg_entry()
(waits lqu_fetching for follow-on refresh)
```
reply Andreas Dilger wiretest.c:4945 — (style) please use `unsigned int` even though the script currently generates `unsigned` so that we have fewer places to fix in the future.
Andreas Dilger
(style) please use `unsigned int` even though the script currently generates `unsigned` so that we have fewer places to fix in the future.
reply Andreas Dilger lquota_internal.h:182 — seems reasonable to fix if patch is refreshed, or a later patch in this series..
Gerrit AI review for Lustre
(suggestion) This isn't a bug, but the comment says the field is QMT-only, yet it sits outside the `u.me`/`u.se` union. That adds 16 bytes to every `lquota_entry`, including all the QSD entries on every OST and MDT, which never use it. Could it go into `struct lquota_mst_entry` as `lme_usg_xa`, with a `#define lqe_usg_xa u.me.lme_usg_xa` like `lqe_sem`? On a non-debug build `lquota_mst_entry` is smaller than `lquota_slv_entry`, so the union should not grow. `lqe_ref_free()` would then call `qmt_lqe_usg_fini()` only when `lqe_is_master(lqe)` is true, rather than relying on QSD entries having a zeroed xarray.
Andreas Dilger
seems reasonable to fix if patch is refreshed, or a later patch in this series..
reply Andreas Dilger qmt_dev.c:58 — (minor) other parameters like this are named "maxage"
Andreas Dilger
(minor) other parameters like this are named "maxage"
reply Andreas Dilger qmt_dev.c:83 — I don't see the man4 page for this?
wc-checkpatch
(style) 'LPROC_SEQ_FOPS' may be misspelled - perhaps 'LUSTRE_RW_ATTR and create Documentation/man4/ page for param'?
Andreas Dilger
I don't see the man4 page for this?
reply Gerrit AI review for Lustre qmt_handler.c:1195 — (style) This isn't a bug, but qmt_update_lqe_usg_entry() opens with the identical `qpi_lqa || qpi_rtype != LQUOTA_RES_DT` test and returns 0
Gerrit AI review for Lustre
(style) This isn't a bug, but qmt_update_lqe_usg_entry() opens with the identical `qpi_lqa || qpi_rtype != LQUOTA_RES_DT` test and returns 0, so the filter here is duplicated. Dropping one of the two would keep the rule in a single place.
reply Andreas Dilger qmt_internal.h:394 — Presumably this is cached so long only if the target is offline? Otherwise it should be maximum a few seconds.
Andreas Dilger
Presumably this is cached so long only if the target is offline? Otherwise it should be maximum a few seconds.
reply Andreas Dilger sanity-quota.sh:8310 — Adding tests at the end of the file is conflict-intensive. If doing so, add a larger gap like test_350() so there is more room for future g
Andreas Dilger
Adding tests at the end of the file is conflict-intensive. If doing so, add a larger gap like test_350() so there is more room for future growth without conflicts (search for open patches modifying sanity-quota.sh to check). Otherwise, use a gap between 98 and 300, like 200.
owner Keguang Xu · uploader kg.xu · PS17 uploaded 21d ago · NEW · open in Gerrit ↗
commit message
LU-20354 quota: cache per-slave DT usage on QMT Build an in-memory per-slave DT usage cache on the global pool lqe so QMT can track block usage reported by slaves. Named pools do not keep their own slots; qmt_sum_lqe_usg() sums the global entries for the pool's current sarr members. LQA and MD are not cached. Refresh from MDT/OSP and serving the sum on GETQUOTA stay in a follow-on. DQACQ and REL piggyback on-disk usage in qb_usage with QUOTA_DQACQ_FL_USAGE, set by qsd_qbody_set_usage(). REPORT already carries that usage and is left unchanged. qmt_dqacq0() drops the lqe write lock, then qmt_update_lqe_usg_entry() stores the value on the global lqe. A missing slot is created there. The slot stores the update time; a ttl of 0 always misses. The sum holds op_rw_sem (read) across each member array. Slot fields are written with WRITE_ONCE and read with READ_ONCE, with no second lock. Callers must not hold lqe_sem: the recalc thread takes op_rw_sem and then lqe_sem, so the other order deadlocks with a queued pool writer. A missing or expired member, or a pool with no members, returns -ESTALE. An all-zero fresh sum is a valid idle ID. DOM MDTs are recorded only in the global DT pool tgts[MDT] and stay out of lgd and recalc. A slave connect adds the target once; disconnect does not remove it. qmt.*.usage_cache_ttl is in seconds (default 3600, max one day). Zero makes every lookup miss. The cache is freed with the lqe. qmt_usg_test covers update and sum by pool sarr, a named pool sharing the global cache, and TTL. sanity-quota/305 loads it on the MDS. It does not exercise MDT/OSP refresh. Assisted-by: Cursor:Grok-4.7/Opus5.5 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: I9acd2b938c45ba9c62d5a2c03ba86af24ddbe90d
▶Longstanding (signal older than a week)
(6)
66567
master
J –B ✓T ✗10R 0/2
LU-20212 lov: skip invalid OST mirrors for aggregate I/O
mine enforced failed: review-dne-part-4, review-dne-part-7, review-dne-subtest-change, review-dne-zfs-part-4, review-dne-zfs-part-5, review-dne-zfs-part-7, review-dne-zfs-subtest-change, review-zfs
4 unresolved
L +216 −39
8d
LU-20212 lov: skip invalid OST mirrors for aggregate I/O
mine enforced failed: review-dne-part-4, review-dne-part-7, review-dne-subtest-change, review-dne-zfs-part-4, review-dne-zfs-part-5, review-dne-zfs-part-7, review-dne-zfs-subtest-change, review-zfs
4 unresolved
L +216 −39
8d
enforced failed: review-dne-part-4, review-dne-part-7, review-dne-subtest-change, review-dne-zfs-part-4, review-dne-zfs-part-5, review-dne-zfs-part-7, review-dne-zfs-subtest-change, review-zfs
4 unresolved thread(s) await your reply — last from kg.xu
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-part-4 | RHEL 9.7 / x86_64 | ran 11 tests. 1 tests failed: sanity-flr. | session |
| review-dne-part-4 | RHEL 10.1 / x86_64 | ran 11 tests. 1 tests failed: sanity-flr. | session |
| review-dne-part-7 | RHEL 9.8 / x86_64 | ran 6 tests. 1 tests failed: sanity-ec. | session |
| review-dne-subtest-change | RHEL 9.7 / x86_64 | ran 3 tests. 1 tests failed: sanity-flr. | session |
| review-dne-zfs-part-4 | RHEL 9.8 / x86_64 | ran 11 tests. 1 tests failed: sanity-flr. | session |
| review-dne-zfs-part-4 | RHEL 10.1 / x86_64 | ran 11 tests. 1 tests failed: sanity-flr. | session |
| review-dne-zfs-part-5 | RHEL 9.7 / x86_64 | ran 5 tests. 1 tests failed: sanityn. | session |
| review-dne-zfs-part-7 | RHEL 9.8 / x86_64 | ran 6 tests. 1 tests failed: sanity-ec. | session |
| review-dne-zfs-subtest-change | RHEL 9.7 / x86_64 | ran 3 tests. 1 tests failed: sanity-flr. | session |
| review-zfs | RHEL 8.10 / x86_64 | ran 10 tests. 1 tests failed: sanity-flr. | session |
build #134448 SUCCESS · tests all Maloo sessions
no vote yet: Qian Yingjin, Marc Vef, Andreas Dilger
patchsets:
PS3 06-11
PS4 06-13
PS5 06-16
PS6 06-22
PS7 10-26
+2 earlier
PS1 06-10 PS2 06-10threads: 4 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply kg.xu patchset comment — I reused `lovsub_import_inactive()` from the EC series and incorporated logic to skip parity for `CIT_GLIMPSE`. Given these dependencies...S
Keguang Xu
Hi, this patch is part of 'FLR-ECRO: verify non-write RPCs do not block client': I was wondering if the `fail fast` logic on `stat()` should actually be a generic feature for all PFL components, instead of being scoped exclusively to EC files. If that makes sense, I'd prefer to rebase this against master and relocate the tests under sanity.sh. Thoughts?
kg.xu
I reused `lovsub_import_inactive()` from the EC series and incorporated logic to skip parity for `CIT_GLIMPSE`. Given these dependencies...So, let's keep it within this series.
reply kg.xu patchset comment — I reused `lovsub_import_inactive()` from the EC series and incorporated logic to skip parity for `CIT_GLIMPSE`. Given these dependencies...S
Andreas Dilger
This patch should probably go directly on master, since I don't think it depends on any functionality that hasn't landed yet?
kg.xu
I reused `lovsub_import_inactive()` from the EC series and incorporated logic to skip parity for `CIT_GLIMPSE`. Given these dependencies...So, let's keep it within this series.
reply kg.xu patchset comment — In lov_io_mirror_init(), if `ci_designated_mirror` is set, we can also check lov_mirror_has_inactive_stripe for `CIT_GLIMPSE/LSEEK/DATA_VERS
kg.xu
In lov_io_mirror_init(), if `ci_designated_mirror` is set, we can also check lov_mirror_has_inactive_stripe for `CIT_GLIMPSE/LSEEK/DATA_VERSION`. Since these io types all trigger OST aggregation, this check allows us to skip unnecessary RPCs. In current impl, we only check `CIT_GLIMPSE` during mirror selection (where `ci_designated_mirror` is false).
reply kg.xu sanity-ec.sh:3899 — An error returned:
wc-checkpatch
(style) line length of 81 exceeds 80 columns
Andreas Dilger
How does this behave for a non-EC file with a deactivated OST stripe? Does that return an error or just calculate the size without the stripe (which seems wrong)?
kg.xu
An error returned: `stat: cannot statx '/mnt/lustre/f42c.sanity-ec': Cannot send after transport endpoint shutdown` So the old code itself is correct already. New change only avoid sending unnecessary glimpse to mirrors with invalid OSTs.
owner Keguang Xu · uploader Keguang Xu · PS7 uploaded 9d ago · NEW · open in Gerrit ↗
commit message
LU-20212 lov: skip invalid OST mirrors for aggregate I/O I/O that aggregates stripe-local results into one logical answer (glimpse, lseek, data_version) cannot succeed on a mirror while any relevant OST import is deactivated or invalid. In lov_io_mirror_init(), skip mirrors with unreachable OSTs in the I/O extent during FLR selection for aggregate I/O. When every mirror is skipped, glimpse (ndelay) returns -EAGAIN after backoff so the caller retries, and -EIO once it has tried all mirrors several rounds; lseek and data_version fail with -EIO at once. For designated-mirror I/O, apply the same extent-scoped check after resolving ci_designated_mirror; there is no alternate mirror to try, so return -EIO immediately. Detect unreachable stripes with lov_mirror_extent_unreachable(), limited to stripes intersecting the current I/O extent, via lov_sub_unreachable(). Skip parity mirrors for glimpse and data_version as well, so they never return parity object size or version. Size FLR ndelay rounds by the data mirrors that can serve the I/O, not lo_mirror_count, for I/O types that skip parity; this also excludes stale mirrors from the round of a plain FLR read. CIT_EC_RD skips that rotation. Add sanity-flr 31b. Test-Parameters: fortestonly Assisted-by: Cursor:Grok-4.6/Opus5.5 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: Iac1c6415127d46fd958016a998ceab68663e0d42
68073
master
J –B ✓T ✓R 0/2
LU-20354 quota: refresh QMT usage cache via MDT/OSP proxy
mine 3 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
3 unresolved
L +759 −66
18d
LU-20354 quota: refresh QMT usage cache via MDT/OSP proxy
mine 3 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
3 unresolved
L +759 −66
18d
3 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
CI green — no vote yet from Sergey Cheremencev, Andreas Dilger, Hongchao Zhang
build #133812 SUCCESS · tests all Maloo sessions
no vote yet: Sergey Cheremencev, Andreas Dilger, Hongchao Zhang
patchsets:
PS2 09-02
PS3 09-04
PS5 09-10
PS6 10-14
PS7 10-16
+1 earlier
PS1 08-18threads: 3 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre mdt_handler.c:6122 — (typo) Missing space before `*/`.
Gerrit AI review for Lustre
(typo) Missing space before `*/`.
reply Gerrit AI review for Lustre qmt_entry.c:1344 — (minor) The extra members don't really wait for a later refresh. After qmt_refresh_lqe_usg() returns 0, qmt_get_usage() re-sums with check_t
Gerrit AI review for Lustre
(minor) The extra members don't really wait for a later refresh. After qmt_refresh_lqe_usg() returns 0, qmt_get_usage() re-sums with check_ttl=false over the live sarr, not over the copied idxs. So a member added during the walk is summed at whatever age its slot has. Example: `lctl pool_add` adds OST N to a named pool while the serial Q_GETOQUOTA walk is running. OST N already has a slot on the global lqe from an old DQACQ (slots are only freed with the lqe), but that slot expired long ago. Refresh never touches N, and the following sum serves N's old value as part of a fresh aggregate. A member with no slot gets -ESTALE, which is fine. This only matters once qmt_usg_serve is enabled, and the result is one stale reply, not corruption. But either the comment or the post-refresh sum should change, e.g. sum only the idxs that refresh handled, or redo the refresh if op_count changed.
reply Gerrit AI review for Lustre qmt_handler.c:776 — (style) This isn't a bug, but the comment sits directly above an assignment that runs for every command in this case group, while the text o
Gerrit AI review for Lustre
(style) This isn't a bug, but the comment sits directly above an assignment that runs for every command in this case group, while the text only describes the two commands handled by the condition below it. The old comment explained the assignment itself. Moving this line down onto the `if` would read better.
owner Keguang Xu · uploader Keguang Xu · PS7 uploaded 20d ago · NEW · open in Gerrit ↗
commit message
LU-20354 quota: refresh QMT usage cache via MDT/OSP proxy Wire qmt_refresh_lqe_usg() to pull stale or missing per-slave usage through MDT: local OSD for the DOM MDT, OSP Q_GETOQUOTA for OSTs. The cache stays on the global DT lqe. The caller passes that lqe and the pool; refresh walks the pool sarr (alloc outside the lock, copy under it). Fresh slots, including DQACQ-warmed zeros, are left alone. Remote MDT DOM fetch is still TODO. On fetch failure, keep a cached value when the slot exists, otherwise fall back to granted from that slave's index. Degraded values are back-dated to expire after about 60s so the next refresh retries soon. qmt_sum_lqe_usg() takes check_ttl: true for a cache lookup, false after refresh so freshly stored slots are served even when ttl is 0. qc_id is already a filesystem ID. MDS/OSS NIDs belong in a trusted nodemap, so OFD's CLIENT_TO_FS map is identity and no skip-idmap handshake is needed. qmt_get_usage() sums and refreshes only when qmt_usg_serve is on. The flag stays off, so GETQUOTA still leaves usage unset. qmt_usg_fallback counts a granted fallback or a failed serve. Expose qmt.*.usage_cache_stats (hit/miss/fetch_rpc/fallback). Add sanity-quota/310, skipped until qmt_usg_serve is on. Extend qmt_usg_test for ttl 0 with check_ttl true/false. Test-Parameters: trivial testlist=sanity-quota Assisted-by: Cursor:Grok-4.6 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: Ied2f4f1e3c7ee6611a69a57e8064d46a59ba845f
62497
master
J !B ✓T ✗5R -1/2−
LU-7266 ldlm: introduce pressure-based SLV
carrying kg.xu · needs rebase — checkpatch: cannot be cherry-picked
needs rebase
11 unresolved
XL +2191 −68
29d
LU-7266 ldlm: introduce pressure-based SLV
carrying kg.xu · needs rebase — checkpatch: cannot be cherry-picked
needs rebase
11 unresolved
XL +2191 −68
29d
needs rebase — checkpatch: cannot be cherry-picked
enforced failed: review-dne-zfs-part-4, review-dne-zfs-part-6, review-ldiskfs, review-ldiskfs-arm
11 unresolved thread(s) await your reply — last from kg.xu
janitor run: 1 failing config(s), none unique to this patch — janitor results
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-zfs-part-4 | RHEL 10.1 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-6 | RHEL 9.7 / x86_64 | ran 4 tests. 1 tests failed: ost-pools. | session |
| review-ldiskfs | RHEL 8.10 / x86_64 | ran 5 tests. 1 tests failed: sanity. | session |
| review-ldiskfs | RHEL 8.10 / x86_64, RHEL 9.7 / x86_64 | ran 5 tests. 1 tests failed: sanity. | session |
| review-ldiskfs-arm | RHEL 8.10 / x86_64, Rocky 9.5 / aarch64 | ran 6 tests. 1 tests failed: sanity. | session |
build #129438 SUCCESS · tests all Maloo sessions
no vote yet: Qian Yingjin, Andreas Dilger, Vitaly Fertman, Timothy Day, Patrick Farrell
patchsets:
PS24 07-14 Keguang Xu
PS25 08-08 Keguang Xu
PS26 08-09 Keguang Xu
PS27 08-15 Keguang Xu
PS28 08-15 Keguang Xu
+15 earlier
PS1 11-12 PS4 11-19 PS6 11-26 PS10 02-27 PS13 05-11 PS14 05-11 PS15 05-26 PS16 05-29 PS17 06-11 PS18 06-13 Keguang Xu PS19 06-22 Keguang Xu PS20 06-27 Keguang Xu PS21 07-13 Keguang Xu PS22 07-13 Keguang Xu PS23 07-13 Keguang Xuthreads: 11 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply kg.xu patchset comment — hhh, answer back.
Andreas Dilger
I haven't yet looked into the details of this patch, but I'm wondering if the same effect could be approximated by changing the existing SLV mechanism and values returned to the client without implementing a new protocol? I'm not against a new protocol, but having a "partial" implementation that turns on (or potentially *off*) based on the number of clients could be quite difficult to test and measure the effects. I read the concern about the new mechanism imposing more lock pressure on a small number of new clients, but it seems possible that this could still co-exist with older clients that use the existing SLV mechanism (with fixes).
Andreas Dilger
Unfortunately this comment was marked resolved without an answer.
kg.xu
hhh, answer back. > Can the same effect be approximated by changing the existing SLV values, without a new protocol? Partially yes, on the server side, we can try to drive the legacy scalar SLV from pool occupancy (pressure high → SLV lower), still returning a scalar value rather than a ratio, so existing clients can trigger cancellation without any wire-format change. However, this is only a best-effort approximation. As Wenzhao noted in the earlier discussion, the fundamental limitation of the legacy path is that each client compares its own CLV against a `single server-provided threshold`. There is no notion of reclaiming a fraction of the client's unused cache. In practice, clients with similar lock ages tend to keep similar numbers of locks, regardless of how large or active they are — a small client and a large client receive the same SLV and apply the same cutoff logic locally. Conclusion We do need the new contract: one OBD_CONNECT2 flag and reuse of the existing 64-bit slv field to carry packed pool pressure, with client-side eviction driven by a configurable curve over the client's own unused locks. That is what gives bounded, paced, proportional reclamation. At the same time, the old clients could/should participate in backpressure without waiting for a rollout threshold: - clients that negotiate OBD_CONNECT2_POOL_SLV_PACKED always receive packed pressure; - legacy clients continue to receive a scalar SLV, optionally occupancy-driven as a fallback; - both paths respond to the same underlying pool pressure, without a coverage-based switch. We accept the known limitations of the legacy fallback (equal-threshold behavior across clients of different sizes). The new contract addresses those limitations; the legacy path is there so mixed-version clusters still get timely cancellation, not to replace the pressure mechanism.
reply kg.xu patchset comment — Review note:
kg.xu
Review note: The patch is large because of negotiation, dual SLV, rollout, and tests. The new logic is small: server pressure is essentially granted/limit; the client maps pressure to an evict quota and uses a quota-based LRU policy instead of per-lock CLV arithmetic. Suggested review order: 1) lustre/include/lustre_dlm.h, lustre_idl.h — packed SLV layout and pool fields 2) ldlm_pool_calc_slv_by_pressure(), ldlm_pool_pressure_evict_*() — core math (~100 lines) 3) ldlm_cancel_pressure_policy(), ldlm_cancel_lru_policy() — reclaim behavior 4) connect, rollout, sysfs, tests — compatibility and rollout (bulk of the diff)
reply Gerrit AI review for Lustre ldlm.namespaces.pool.slv_mode.4:174 — Not a bug, but the MDT name in this sample output is missing the UUID suffix. mdt_init0() builds the namespace name as "%s-%s" of LUSTRE_MDT
Gerrit AI review for Lustre
Not a bug, but the MDT name in this sample output is missing the UUID suffix. mdt_init0() builds the namespace name as "%s-%s" of LUSTRE_MDT_NAME and obd_uuid.uuid, so it reads mdt-testfs-MDT0000_UUID, matching the filter-testfs-OST0000_UUID line just below.
reply kg.xu ldlm_pool.c:309 — Currently, `ldlm_pool` tracks metrics at the per-target level (e.g., 'fsname-target'). I propose aggregating these metrics by 'fsname' inste
kg.xu
Currently, `ldlm_pool` tracks metrics at the per-target level (e.g., 'fsname-target'). I propose aggregating these metrics by 'fsname' instead. Furthermore, we should discuss whether resources should be allocated equally across all file systems, or if we need a weighted policy.
reply Gerrit AI review for Lustre ldlm_pool.c:212 — (style) Not a bug, but with `pressure_adjust == true` this just returns `L` unchanged, and the only caller passing true is the CDEBUG in ldl
Gerrit AI review for Lustre
(style) Not a bug, but with `pressure_adjust == true` this just returns `L` unchanged, and the only caller passing true is the CDEBUG in ldlm_pool_calc_slv_by_pressure(). A boolean that turns the function into the identity is hard to follow - would printing `limit` directly there be clearer?
reply Gerrit AI review for Lustre ldlm_pool.c:1856 — (style) These six new helpers are the only EXPORT_SYMBOL()s in this file; ldlm_pool_get_slv(), ldlm_pool_init() and friends aren't exported.
Gerrit AI review for Lustre
(style) These six new helpers are the only EXPORT_SYMBOL()s in this file; ldlm_pool_get_slv(), ldlm_pool_init() and friends aren't exported. ldlm_lib.c and ldlm_request.c build into the same ptlrpc module (lustre/ldlm/Makefile), so none of them need exporting, and this one is used only inside ldlm_pool.c so it could be static.
reply Gerrit AI review for Lustre ldlm_pool.c:497 — Once the pool is pressure-ready these two limits diverge by roughly 5x, and the legacy scalar looks like it collapses to the floor.
Gerrit AI review for Lustre
Once the pool is pressure-ready these two limits diverge by roughly 5x, and the legacy scalar looks like it collapses to the floor.
ldlm_pools_recalc_task() sets pl_limit = ldlm_ratio2locknr(30)/nr_ns for a ready pool but pl_legacy_limit = LDLM_POOL_HOST_L/nr_ns. HOST_L is 50 locks per MB of RAM, i.e. RAM/20971 locks; ldlm_ratio2locknr(30) is 0.30*RAM/LDLM_LOCK_MEM_OVERHEAD. Packed clients only start evicting at 50% of pl_limit (default curve), so granted settles well above pl_legacy_limit.
With granted > limit here:
grant_usage = max_t(int, limit - (granted - grant_plan), 1); /* -> 1 */
slv_factor = (grant_usage << 10); do_div(slv_factor, limit); /* -> 0 */
slv = slv * slv_factor; /* -> 0 */
and the clamp below lifts it to ldlm_pool_slv_min() == 1. In ldlm_cancel_lrur_policy() slv == 1 means every lock with lv >= 1 (any lock idle for a second or more) is cancelled, so a non-packed client drops essentially its whole LRU on each recalc, and the drop also trips the ns_recalc_pct urgent-recalc path in ldlm_cli_update_pool().
That hits up to 30% of client exports at the default threshold, plus every MDT OSC on an OST since lod never negotiates OBD_CONNECT2_POOL_SLV_PACKED. Does "keep legacy behavior for old clients" still hold once the pool flips, or should the legacy scalar be derived from the limit the pool is actually being filled to?
reply Gerrit AI review for Lustre ldlm_pool.c:1535 — pl_slv_mode is set to pressure_rollout two lines up, so this branch always runs and a brand new server pool gets the pressure budget before
Gerrit AI review for Lustre
pl_slv_mode is set to pressure_rollout two lines up, so this branch always runs and a brand new server pool gets the pressure budget before any client has negotiated packed SLV and before ldlm_pool_fallback_legacy_on_multi_fs_register() has had a chance to force the pool back to legacy_slv. It is also the whole-node budget: ldlm_pools_recalc_task() divides ldlm_ratio2locknr() by ldlm_namespace_nr_read(LDLM_NAMESPACE_SERVER), this does not. The neighbouring initialisers (pl_legacy_limit, pl_grant_plan) still use LDLM_POOL_HOST_L, so pl_server_lock_volume is seeded from one basis and decayed against another until the first recalc pass. Would it be simpler to seed with LDLM_POOL_HOST_L here and let ldlm_pools_recalc_task() apply the pressure budget when the readiness gate says so?
reply Qian Yingjin sanity-ldlm-pool.sh:195 — This could be:
Qian Yingjin
This could be: for ((batch = 0; batch < BATCH_COUNT; batch++)) ...
reply Gerrit AI review for Lustre sanity-ldlm-pool.sh:190 — (style) This commented-out curve set/restore block looks like leftover scaffolding - drop it, or enable it if the suite is meant to cover a
Gerrit AI review for Lustre
(style) This commented-out curve set/restore block looks like leftover scaffolding - drop it, or enable it if the suite is meant to cover a non-default curve?
reply Gerrit AI review for Lustre sanity-ldlm-pool.sh:260 — (style) Carried over from patchset 9 and still open: this reads more naturally as `for ((batch = 0; batch < BATCH_COUNT; batch++))`, with su
Gerrit AI review for Lustre
(style) Carried over from patchset 9 and still open: this reads more naturally as `for ((batch = 0; batch < BATCH_COUNT; batch++))`, with subdir_idx computed from batch directly.
owner kg.xu · uploader Keguang Xu · PS28 uploaded 82d ago · NEW · open in Gerrit ↗
commit message
LU-7266 ldlm: introduce pressure-based SLV Legacy SLV/CLV reacts to server pressure indirectly and can delay lock reclaim. This change introduces a pressure-based SLV path: server sends packed pressure in SLV, and client converts it to evict quota. Packed SLV Format: * Bits 63..60: format version (current 0x1). Legacy SLV leaves these bits clear. * Bits 59..16: reserved for future use. * Bits 15..0: pressure in hundredths of a percent, where 10000 means 100.00%. Here pressure is total-grant-lock/total-limit. Unlike the previous grant-plan-based scalar SLV. Rationale: - Percentage-based eviction scales with client lock footprint, so larger lock holders evict more locks under pressure while smaller clients are not over-penalized. - Gradual rollout is gated by packed-capable export coverage, avoiding a mixed-upgrade case where only a small subset of new clients absorbs repeated reclaim pressure. - Client eviction uses segmented pressure-to-evict mapping, so reclaim is mild at low pressure and stronger at high pressure. At relatively low pressure, clients react faster to keep pressure in a healthy range; at higher pressure, clients use a longer evict interval because each round evicts more locks, reducing oscillation and avoiding over-evicting locks that should be retained; at or above the last curve point the interval shortens so high-pressure reclaim stays frequent. Key updates: - add OBD_CONNECT2_POOL_SLV_PACKED negotiation and packed SLV helpers - add slv_mode (legacy_slv / pressure_rollout), rollout threshold, and client evict-curve sysfs controls - pressure_rollout pools use ldlm.lock_pool_limit_mem_pct (default 30% of RAM / LDLM_LOCK_MEM_OVERHEAD) instead of LDLM_POOL_HOST_L - keep dual SLV state (legacy scalar + pressure scalar) for compatibility, where in pressure path; add quota-based client reclaim policy: ldlm_cancel_pressure_policy - fall back to legacy_slv on mixed-filesystem server nodes - keep legacy behavior for old clients and pre-threshold rollout stages - add sanity-ldlm-pool.sh, sanity 124aa, and man pages for the new pool parameters Performance impact: CPU overhead should be negligible. - The server recomputes pressure once per second per pool. On the client, pool recalc runs on the ~10s timer and when unused locks are decrefed. - On the packed pressure path, reclaim no longer performs per-lock arithmetic during LRU scanning, so lock-heavy workloads should see unchanged or slightly lower CPU usage. Assisted-by: Cursor:auto/codex5.5 Signed-off-by: Keguang Xu <squalfof@gmail.com> Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: If8a6f247127576965ae45c349a4ab04fb286615a
68600
master
J ✗45B ✓T ✗11R 0/2
LU-20354 quota: serve LQA usage from QMT cache
mine janitor: 45 test failures unique to this patch — sanity-quota@ldiskfs+DNE:test_1j, sanity-quota@ldiskfs+DNE:test_3a, sanity-quota@ldiskfs+DNE:test_3b +42 more
45 unique failures
11 unresolved
XL +1391 −198
45d
LU-20354 quota: serve LQA usage from QMT cache
mine janitor: 45 test failures unique to this patch — sanity-quota@ldiskfs+DNE:test_1j, sanity-quota@ldiskfs+DNE:test_3a, sanity-quota@ldiskfs+DNE:test_3b +42 more
45 unique failures
11 unresolved
XL +1391 −198
45d
janitor: 45 test failures unique to this patch — sanity-quota@ldiskfs+DNE:test_1j, sanity-quota@ldiskfs+DNE:test_3a, sanity-quota@ldiskfs+DNE:test_3b +42 more
enforced failed: review-dne-ipv6, review-dne-part-4, review-dne-part-5, review-dne-zfs-part-3, review-dne-zfs-part-4, review-dne-zfs-part-5, review-dne-zfs-part-7, review-zfs
11 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
janitor flagged test failures unique to this patch — full janitor results
| unique failing test | history |
|---|---|
| sanity-quota@ldiskfs+DNE:test_1j | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@ldiskfs+DNE:test_3a | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_3b | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_3c | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_5 | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@ldiskfs+DNE:test_6 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_7a | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@ldiskfs+DNE:test_7b | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@ldiskfs+DNE:test_7c | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@ldiskfs+DNE:test_17 | seen in 6 other reviews |
| sanity-quota@ldiskfs+DNE:test_25 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_33 | seen in 4 other reviews |
| sanity-quota@ldiskfs+DNE:test_34 | seen in 4 other reviews |
| sanity-quota@ldiskfs+DNE:test_35 | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@ldiskfs+DNE:test_37 | seen in 4 other reviews |
| sanity-quota@ldiskfs+DNE:test_38 | seen in 4 other reviews |
| sanity-quota@ldiskfs+DNE:test_40c | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_64 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_67 | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@ldiskfs+DNE:test_71a | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_71b | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_72 | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_73a | seen in 6 other reviews |
| sanity-quota@ldiskfs+DNE:test_75 | seen in 6 other reviews |
| sanity-quota@ldiskfs+DNE:test_80 | seen in 1 other review |
| sanity-quota@zfs:test_1j | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_3a | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_3b | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_3c | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_5 | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_6 | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_7a | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_7b | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_7c | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_17 | seen in 34 other reviews |
| sanity-quota@zfs:test_25 | seen in 27 other reviews |
| sanity-quota@zfs:test_33 | seen in 33 other reviews |
| sanity-quota@zfs:test_34 | seen in 33 other reviews |
| sanity-quota@zfs:test_35 | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_37 | seen in 33 other reviews |
| sanity-quota@zfs:test_38 | seen in 33 other reviews |
| sanity-quota@zfs:test_64 | seen in 1 other review |
| sanity-quota@zfs:test_72 | seen in 14 other reviews |
| sanity-quota@zfs:test_73a | seen in 17 other reviews |
| sanity-quota@zfs:test_75 | seen in 7 other reviews |
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-ipv6 | RHEL 9.8 / x86_64 | ran 4 tests. 1 tests failed: sanity-lnet. | session |
| review-dne-part-4 | RHEL 9.7 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-part-4 | RHEL 10.1 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-part-5 | RHEL 9.7 / x86_64 | ran 5 tests. 1 tests failed: lustre-rsync-test. | session |
| review-dne-zfs-part-3 | RHEL 9.8 / x86_64 | ran 3 tests. 1 tests failed: conf-sanity. | session |
| review-dne-zfs-part-3 | RHEL 10.1 / x86_64 | ran 3 tests. 1 tests failed: conf-sanity. | session |
| review-dne-zfs-part-4 | RHEL 9.8 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-4 | RHEL 10.1 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-5 | RHEL 9.7 / x86_64 | ran 5 tests. 1 tests failed: lustre-rsync-test. | session |
| review-dne-zfs-part-7 | RHEL 9.8 / x86_64 | ran 6 tests. 1 tests failed: sanity-ec. | session |
| review-zfs | RHEL 8.10 / x86_64 | ran 8 tests. 1 tests failed: sanity-quota. | session |
build #132033 SUCCESS · tests all Maloo sessions
patchsets:
PS3 09-13
PS4 09-14
PS5 09-16
PS6 09-17
PS7 09-20
+2 earlier
PS1 09-03 PS2 09-11threads: 11 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre COMMIT_MSG:41 — (suggestion) This adds a new quotactl command and two new request formats on the MDS-to-OSS/MDT path, and changes what `lfs quota --lqa` pri
Gerrit AI review for Lustre
(suggestion) This adds a new quotactl command and two new request formats on the MDS-to-OSS/MDT path, and changes what `lfs quota --lqa` prints. A `Test-Parameters:` line asking for an interop run against a released server would cover the rolling-upgrade case where the slave does not know LUSTRE_Q_GETOUSAGES, e.g.
Test-Parameters: serverversion=2.16 testlist=sanity-quota
reply Gerrit AI review for Lustre COMMIT_MSG:39 — (minor) The body covers the LQA work well, but two hunks outside it are not mentioned.
Gerrit AI review for Lustre
(minor) The body covers the LQA work well, but two hunks outside it are not mentioned. qmt_dqacq0() now warms the cache with `qb_usage != 0` instead of an unconditional `true`. That changes the non-LQA per-ID path: a slave that legitimately reports zero usage no longer marks its slot fresh, so the next GETQUOTA misses and pays a full refresh round instead of hitting the cache. The inline comment gives the motivation (an on-disk 0 racing the first inode), but a reader of the commit message would not expect a per-ID behaviour change in an LQA patch. qmt_usg_test_init() also switches every `return rc` to `return -EINVAL`, which drops the specific failure code from the insmod error. Could both get a line in the body, or should the dqacq0 change be split out since it stands on its own?
reply Gerrit AI review for Lustre qmt.usage_cache_ttl.4:67 — (minor) This paragraph now sits directly under the new LQA text but describes only the per-ID behaviour. For LQA there is no "previously val
Gerrit AI review for Lustre
(minor) This paragraph now sits directly under the new LQA text but describes only the per-ID behaviour. For LQA there is no "previously valid cached value" kept and no granted substitution - qmt_lqa_refresh_lqe_usg() resets every slot to QMT_USG_UNSET and returns the error - and the 120s degraded TTL never applies either, since qmt_apply_usg_fetch() is not on that path. qmt.usage_cache_stats(4) already carries the "LQA has no granted substitution" caveat; the same note would fit here.
reply Gerrit AI review for Lustre lustre_quota.h:372 — (minor) The kdoc opens with "GETOUSAGES is server-internal", but this second test is what decides whether a non-server export gets in.
Gerrit AI review for Lustre
(minor) The kdoc opens with "GETOUSAGES is server-internal", but this second test is what decides whether a non-server export gets in. The connect-flag test above already matches every MDS/OSS export on its own: lod_add_device() requests OBD_CONNECT_MDS for OSP-to-OST and OBD_CONNECT_MDS_MDS for OSP-to-MDT, and both survive connect negotiation (ofd_obd.c reads exp_connect_flags(exp) & OBD_CONNECT_MDS the same way). So the nodemap clause is not needed for the MDS/OSS case the kdoc uses to justify it; what it does add is every ordinary client that happens to sit in a nodemap with trust_client_ids set, which is a common setting for compute nodes and says nothing about the client being privileged. A client in that nodemap can then read bspace/ispace for up to LQUOTA_IDS_MAX arbitrary IDs per RPC from any OST or MDT. Is that intended, or should the check be the connect flags alone?
reply Gerrit AI review for Lustre mdt_handler.c:6324 — (minor) GETOUSAGES is dispatched to every OST/MDT without any capability check. There is no OBD_CONNECT* bit for it, and nothing here looks
Gerrit AI review for Lustre
(minor) GETOUSAGES is dispatched to every OST/MDT without any capability check. There is no OBD_CONNECT* bit for it, and nothing here looks at exp_connect_flags before sending. Against a peer that predates the opcode the reply is an error rather than data: lquotactl_slv() rejects any qc_cmd other than Q_GETOQUOTA/LUSTRE_Q_ITEROQUOTA with -EOPNOTSUPP, and an older mdt_quotactl() falls into its `default:` case with -EFAULT. That becomes items[i].ufi_rc, which aborts qmt_lqa_refresh_lqe_usg() and wipes the cache, so in a mixed-version cluster every GETQUOTALQA pays the full glb-index walk and RPC fan-out and still ends with usage unknown. Should this be gated on a negotiated connect flag so the QMT can skip the refresh entirely when a slave cannot serve it?
reply Gerrit AI review for Lustre osp_dev.c:1549 — (minor) The comment above promises a length check that req_capsule_server_sized_get() does not perform for this field.
Gerrit AI review for Lustre
(minor) The comment above promises a length check that req_capsule_server_sized_get() does not perform for this field.
RMF_OBD_QUOTA_ACCT is RMF_F_STRUCT_ARRAY, and __req_capsule_get() takes that branch:
len = lustre_msg_buflen(msg, offset);
if (len % field->rmf_size) return NULL;
value = getter(msg, offset, len);
so the rc_area size that server_sized_get() just stored is discarded and lustre_msg_buf() is called with min_size equal to the buffer's own length. Any reply whose ACCT buffer is a non-zero multiple of sizeof(struct lquota_acct_rec) comes back non-NULL, including one shorter than qcb_replen, and the memcpy() then reads past it.
In-tree slaves size the reply from the ID list they received, so this needs a peer that answers rc = 0 with a short array. Would an explicit req_capsule_get_size(pill, &RMF_OBD_QUOTA_ACCT, RCL_SERVER) == qcb_replen test be worth keeping here, or at least a comment that matches what sized_get actually guarantees?
reply Gerrit AI review for Lustre qmt_entry.c:1495 — (style) This isn't a bug, but `qpi` is now available one line up, so `qpi->qpi_qmt->qmt_usg_ttl` would avoid evaluating lqe2qpi() twice. Wor
Gerrit AI review for Lustre
(style) This isn't a bug, but `qpi` is now available one line up, so `qpi->qpi_qmt->qmt_usg_ttl` would avoid evaluating lqe2qpi() twice. Worth folding in if the patch is refreshed.
reply Gerrit AI review for Lustre qmt_entry.c:1712 — (defect) A waiter that just slept on lqu_waitq re-enters here and redoes the whole refresh, even when the previous owner already filled ever
Gerrit AI review for Lustre
(defect) A waiter that just slept on lqu_waitq re-enters here and redoes the whole refresh, even when the previous owner already filled every slot. The per-ID path below is protected against this: after `goto again` its gather loop skips slots with `!qmt_usg_expired(...)`, so `nstale == 0` and it breaks out with zero RPCs. qmt_lqa_refresh_lqe_usg() has no equivalent test - it always calls qmt_lqa_collect_ids() (full walk of the glb index) and then re-fetches every slot. So with the default ttl of 3600, two concurrent `lfs quota --lqa` for the same name serialize on lqu_fetching and then each pay a complete index walk plus a GETOUSAGES fan-out, on an MDS service thread. N concurrent callers give N full refreshes. Would a `qmt_sum_lqe_usg(lqe, &tmp, now, true) == 0` check at the top of qmt_lqa_refresh_lqe_usg() (or before re-taking lqu_fetching) be enough to make the waiters cheap?
reply Gerrit AI review for Lustre qmt_handler.c:1297 — (minor) "LQA no-ops" doesn't quite match qmt_update_lqe_usg_entry_with_ttl(): its early return only fires for `usage_valid && !lqa_store`. q
Gerrit AI review for Lustre
(minor) "LQA no-ops" doesn't quite match qmt_update_lqe_usg_entry_with_ttl(): its early return only fires for `usage_valid && !lqa_store`. qmt_lqe_lookup() substitutes lqa_qid so the LQA entry here always has qid_uid == QMT_LQA_QID, and when the usage being reported is zero the call falls through and inserts/keeps a slot on the shared lqe. Harmless, but the comment reads as if nothing happens at all.
reply Gerrit AI review for Lustre qmt_internal.h:479 — (minor) QMT_USG_SNAP_NONE has no users - qmt_apply_usg_fetch() still compares its snap_usage against QMT_USG_UNSET, and this change is the t
Gerrit AI review for Lustre
(minor) QMT_USG_SNAP_NONE has no users - qmt_apply_usg_fetch() still compares its snap_usage against QMT_USG_UNSET, and this change is the tip of the relation chain, so nothing later picks it up. It is also the same value as QMT_USG_UNSET, which makes two names for one sentinel. Drop it on the next refresh?
reply Gerrit AI review for Lustre qmt_lqa.c:1330 — (suggestion) Any single slave error discards every slot, including ones that were still valid from an earlier successful refresh.
Gerrit AI review for Lustre
(suggestion) Any single slave error discards every slot, including ones that were still valid from an earlier successful refresh. An administratively deactivated OST is enough to reach this: lod_tgt_quotactl_async() returns -ENETDOWN for `!ltd_active || ltd_reap`, mdt_qmt_fetch_usgs_batch() propagates it, and the whole refresh unwinds here. From then on `lfs quota --lqa` reports usage as unknown for as long as that target stays down, while plain `lfs quota` for the same IDs keeps working because qmt_apply_usg_fetch() keeps the cached value or substitutes granted. The commit message presents the all-or-nothing abort as deliberate, so this is a design question rather than a claim that it is wrong: is a target the admin took offline on purpose really a reason to stop reporting LQA usage entirely, rather than reusing that slave's last cached value the way the per-ID path does?
owner Keguang Xu · uploader Keguang Xu · PS7 uploaded 46d ago · NEW · open in Gerrit ↗
commit message
LU-20354 quota: serve LQA usage from QMT cache GETQUOTALQA previously returned limits only. Wire it through the usage cache so lfs quota --lqa can set QIF_SPACE/QIF_INODES from the LQA shared lqe (qid=1). LQA has no llite fan-out and no per-slave DQACQ piggyback, so a miss collects glb IDs in the current ranges and batch-fetches each slave with LUSTRE_Q_GETOUSAGES. Per-slave range sums land on the shared lqe. A slave or setup failure aborts the refresh (no granted fallback, no partial sum) and leaves usage unknown; GETQUOTALQA still returns limits. QIF_SPACE follows DT alone and QIF_INODES follows MD alone. Missing QIF_USAGE is unknown in lfs, not -EIO. lfs quota --lqa accepts -U/-G/-P before or after --lqa, and prints "Disk quotas for <type> LQA <name>:". Range add/remove bumps qpi_lqa_gen with the rbtree update. Later GETQUOTALQA sees lqu_lqa_gen != qpi_lqa_gen, treats the slots as stale, and refreshes. The bump stays under the same write_lock as insert/erase so the new tree and new generation become visible together. GETOUSAGES carries a swabbed __u32 ID list (RMF_OBD_QUOTA_IDS) and lquota_acct_rec reply array (RMF_OBD_QUOTA_ACCT), not the opaque ITER blob used by ITEROQUOTA. A second qtype adding the same DOM MDT still increments LQA DT qpi_slv_nr on -EEXIST. LQA TTL follows usage_cache_ttl, including 0 (refetch on every GETQUOTALQA, same as per-ID GETQUOTA). Add MDT/OFD GETOUSAGES handlers, OSP/LOD iobuf async, and mdt_qmt_fetch_usgs_batch. Cover with kunit and sanity-quota/312. Document LQA behavior in the usage_cache_* man pages. Assisted-by: Cursor:Grok-4.6 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: I63f53ba1d21f2bb6cc419c3d09b3f9337eaa1f17
68598
master
J ✗17B ✓T ✗8R 0/2
LU-20354 quota: aggregate MD inode usage for GETQUOTA
mine janitor: 17 test failures unique to this patch — sanity-quota@ldiskfs+DNE:test_16a, sanity-quota@ldiskfs+DNE:test_17, sanity-quota@ldiskfs+DNE:test_33 +14 more
17 unique failures
11 unresolved
XL +813 −225
45d
LU-20354 quota: aggregate MD inode usage for GETQUOTA
mine janitor: 17 test failures unique to this patch — sanity-quota@ldiskfs+DNE:test_16a, sanity-quota@ldiskfs+DNE:test_17, sanity-quota@ldiskfs+DNE:test_33 +14 more
17 unique failures
11 unresolved
XL +813 −225
45d
janitor: 17 test failures unique to this patch — sanity-quota@ldiskfs+DNE:test_16a, sanity-quota@ldiskfs+DNE:test_17, sanity-quota@ldiskfs+DNE:test_33 +14 more
enforced failed: review-dne-part-4, review-dne-zfs-part-3, review-dne-zfs-part-4, review-dne-zfs-part-7, review-zfs
11 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
janitor flagged test failures unique to this patch — full janitor results
| unique failing test | history |
|---|---|
| sanity-quota@ldiskfs+DNE:test_16a | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_17 | seen in 7 other reviews |
| sanity-quota@ldiskfs+DNE:test_33 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_34 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_35 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_37 | seen in 3 other reviews |
| sanity-quota@ldiskfs+DNE:test_40c | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_64 | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_78A | seen in 4 other reviews |
| sanity-quota@ldiskfs+DNE:test_78a | seen in 3 other reviews |
| sanity-quota@zfs:test_17 | NEW unique failure for this branch in the last 30 days, and was seen 1 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_33 | seen in 1 other review |
| sanity-quota@zfs:test_34 | seen in 1 other review |
| sanity-quota@zfs:test_35 | seen in 1 other review |
| sanity-quota@zfs:test_37 | seen in 1 other review |
| sanity-quota@zfs:test_64 | seen in 2 other reviews |
| sanity-quota@zfs:test_75 | seen in 1 other review |
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-part-4 | RHEL 9.7 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-part-4 | RHEL 10.1 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-3 | RHEL 9.8 / x86_64 | ran 3 tests. 1 tests failed: conf-sanity. | session |
| review-dne-zfs-part-3 | RHEL 10.1 / x86_64 | ran 3 tests. 1 tests failed: conf-sanity. | session |
| review-dne-zfs-part-4 | RHEL 9.8 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-4 | RHEL 10.1 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-7 | RHEL 9.8 / x86_64 | ran 6 tests. 1 tests failed: sanity-ec. | session |
| review-zfs | RHEL 8.10 / x86_64 | ran 8 tests. 1 tests failed: sanity-quota. | session |
build #132032 SUCCESS · tests all Maloo sessions
patchsets:
PS1 09-03
PS3 09-14
PS4 09-17
PS5 09-20
threads: 11 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre COMMIT_MSG:40 — (minor) The `nrpc` out-parameter added to `quf_fetch_batch()` (lustre_quota.h, mdt_handler.c, qmt_entry.c) also changes what `usage_cache_st
Gerrit AI review for Lustre
(minor) The `nrpc` out-parameter added to `quf_fetch_batch()` (lustre_quota.h, mdt_handler.c, qmt_entry.c) also changes what `usage_cache_stats fetch_rpc` counts. It used to be `atomic64_add(nstale, ...)` issued before the fetch, so it counted every stale slot, including the local MDT slot that never produces an RPC; it is now only the OSP requests actually queued. That looks like an improvement, but it is a visible change to an existing counter and the body only mentions the degraded/fallback split. Worth a sentence here, since sanity-quota 310/311 now key off the new meaning.
reply Gerrit AI review for Lustre lustre_quota.h:131 — (style) Not a bug, but now that this also carries KEY_MDT_QUOTACTL, the `ost_` / `oqi_` naming reads as OST-only: `mdt_qmt_fetch_usage_batch
Gerrit AI review for Lustre
(style) Not a bug, but now that this also carries KEY_MDT_QUOTACTL, the `ost_` / `oqi_` naming reads as OST-only: `mdt_qmt_fetch_usage_batch()` declares `struct ost_qctl_info oqi` for the remote-MDT case. `lod_ost_quotactl()` got renamed to `lod_tgt_quotactl()` in this patch for exactly that reason; `struct tgt_qctl_info` with `tqi_*` fields would match, if the patch is refreshed anyway.
reply Misc Code Checks Robot (Gatekeeper helper) osp_dev.c:1571 — error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
Misc Code Checks Robot (Gatekeeper helper)
error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
reply Misc Code Checks Robot (Gatekeeper helper) osp_dev.c:1571 — error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
Misc Code Checks Robot (Gatekeeper helper)
error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
reply Misc Code Checks Robot (Gatekeeper helper) osp_dev.c:1571 — error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
Misc Code Checks Robot (Gatekeeper helper)
error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
reply Misc Code Checks Robot (Gatekeeper helper) osp_dev.c:1571 — error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
Misc Code Checks Robot (Gatekeeper helper)
error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
reply Gerrit AI review for Lustre qmt_entry.c:1601 — (minor) Was promoting these from LQUOTA_DEBUG to LQUOTA_WARN intended? D_WARNING is in D_CANTMASK, so both of these now reach the console (r
Gerrit AI review for Lustre
(minor) Was promoting these from LQUOTA_DEBUG to LQUOTA_WARN intended? D_WARNING is in D_CANTMASK, so both of these now reach the console (rate-limited by the cdls, but still console output). A slave that is briefly unavailable is routine - an OST in recovery answers -EAGAIN, an inactive target gives -ENETDOWN out of lod_tgt_quotactl_async() - and with usage_cache_enabled defaulting to 1 this path is now taken on ordinary `lfs quota` calls, where it previously produced nothing on the console. The degraded counter and qmt.usage_cache_stats(4) already cover the same condition for anyone watching for it. If the console message is wanted, it is probably worth a line in the commit message, since it is new output on a healthy filesystem.
reply Gerrit AI review for Lustre qmt_entry.c:1699 — (minor) The comment that this replaces said the rescan from key 0 was needed because "slots may be added while the lock was dropped for fetc
Gerrit AI review for Lustre
(minor) The comment that this replaces said the rescan from key 0 was needed because "slots may be added while the lock was dropped for fetch/apply". Resuming from the last key drops that property: qmt_usg_extend_sites() -> qmt_update_lqe_usg_entry() only takes lqe_usg_data_lock, it does not wait on lqu_fetching the way qmt_del_lqe_usg_entry() does, so a slave connecting mid-refresh can insert a slot whose key sorts below resume (MDT keys are below OST keys, and a pool add can bring in a lower OST index). That slot stays QMT_USG_UNSET, so the following qmt_sum_lqe_usg(..., check_ttl=false) returns -ESTALE and the whole GETQUOTA falls back to client fan-out. It self-heals on the next call, so this is not a correctness problem, but the commit message presents the resume as a pure optimization. Would a final pass that only looks for lue_usage == QMT_USG_UNSET work here? It still terminates, since a fetched slot is no longer UNSET.
reply Gerrit AI review for Lustre qmt_handler.c:104 — (defect) With `usage_cache_enabled` defaulting to 1, this refresh now runs for every quota ID a client asks about, including IDs that have n
Gerrit AI review for Lustre
(defect) With `usage_cache_enabled` defaulting to 1, this refresh now runs for every quota ID a client asks about, including IDs that have no limits at all and have never been seen before.
`check_owner()` in `ll_quotactl()` only owner-checks USRQUOTA and GRPQUOTA; PRJQUOTA falls through, so an unprivileged user on any client can run `lfs quota -p <projid>` for arbitrary project IDs. Each unseen ID then does, on the MDT0 service thread:
qmt_pool_lqe_lookup() -> lqe_locate_find() /* creates + hashes an lqe */
qmt_get_usage(DT) -> qmt_setup_lqe_usg() + this refresh
qmt_get_usage(MD) -> qmt_setup_lqe_usg() + this refresh
so two full Q_GETOQUOTA fan-outs to every OST/MDT plus a per-slave `lqe_usg_data` attached to the new lqe. QMT lqes are only dropped at site teardown, so the cache grows with the number of distinct IDs queried.
The lqe-per-queried-ID part is pre-existing, but until this patch `qmt_usg_serve` was hard-wired to 0 with no tunable, so `qmt_get_usage()` returned -EAGAIN and neither the slave RPCs nor the per-slave allocation happened; the fan-out ran on the client, in the client's own context and in parallel.
Would it work to skip the refresh when `!lqe->lqe_enforced`, leaving usage unset so the client keeps the legacy fan-out for IDs with no limits? That would cover the enumeration case and still serve the IDs that matter. Otherwise, is defaulting the tunable to 0 the safer landing state?
reply Gerrit AI review for Lustre qmt_handler.c:113 — (minor) `qmt_quotactl()` calls `qmt_get_usage()` twice now, once for DT and once for MD, so `hit`, `miss` and `fallback` became per-resource
Gerrit AI review for Lustre
(minor) `qmt_quotactl()` calls `qmt_get_usage()` twice now, once for DT and once for MD, so `hit`, `miss` and `fallback` became per-resource rather than per-GETQUOTA. One request where both aggregates fail bumps `fallback` twice, and a request where only DT fails bumps it even though `QIF_INODES` was served. The `qmt_usg_fallback` comment in qmt_internal.h (`GETQUOTA unserved`) and the `fallback` text in qmt.usage_cache_stats.4 (`GETQUOTA leaves usage unset so the client fans out`) both read as per-request. If the patch is refreshed, either move the counting up into qmt_quotactl() or reword both to say per-resource.
reply Gerrit AI review for Lustre sanity-quota.sh:8105 — (suggestion) The commit message says 310 is extended "for inode serve", but the test only ever reads --space; nothing asserts the value that
Gerrit AI review for Lustre
(suggestion) The commit message says 310 is extended "for inode serve", but the test only ever reads --space; nothing asserts the value that the MD aggregate produces. The QIF_SPACE gate means a passing space check proves rc_md was 0, so it shows MD *succeeded*, but not that dqb_curinodes is right.
311 does assert the inode count, but it is gated on MDSCOUNT >= 2, so a single-MDT run - the common sanity-quota config - never checks the headline behavior of this patch.
A second line next to this one would close that, e.g.
used=$($LFS quota -u $TSTUSR --inodes -q $DIR | tr -d '*')
(( used > 0 )) || quota_error u $TSTUSR "expected non-zero inode usage, got $used"
owner Keguang Xu · uploader Keguang Xu · PS5 uploaded 46d ago · NEW · open in Gerrit ↗
commit message
LU-20354 quota: aggregate MD inode usage for GETQUOTA Turn on the usage cache (qmt.*.usage_cache_enabled, default on) so GETQUOTA sums both DT and MD from the per-slave cache. Set QIF_INODES from the MD aggregate and require both DT and MD before QIF_SPACE so llite still fans out when inode usage is unavailable. A slave fetch failure substitutes granted (or keeps a prior cache) and still serves: granted may overstate usage, but one unreachable target must not force every client to fan out. Clearing the tunable leaves usage unset and clients keep legacy fan-out. Drop the DT-only usage-cache gates so MD-pool lqes get slots: qmt_setup_lqe_usg / qmt_update_lqe_usg_entry / qmt_usg_extend_sites and DQACQ warming now apply to LQUOTA_RES_MD (LQA still skipped). MD-pool slots return dqb_curinodes; DT (incl. DOM) stays stoqb(dqb_curspace). Fetch remote MDTs via MDT-OSP MDS_QUOTACTL (KEY_MDT_QUOTACTL). MDS/OSS NIDs belong in a trusted nodemap, so CLIENT_TO_FS map is identity and no skip-idmap handshake is needed. usage_cache_ttl=0 means no cache: each GETQUOTA misses and refetches. Unfilled slots use lue_usage=QMT_USG_UNSET; expire=0 is zero freshness (same as ttl=0) so a queued waiter walks again instead of skipping as still fresh. Resume xa_for_each_start across GETOQUOTA batches of QMT_USG_FETCH_PARALLEL 32 (was 16) instead of rescanning from key 0. A cold-cache GETQUOTA on a large filesystem runs the slave fan-out synchronously on MDT0 (DT then MD), serialized per id. That can be slower than legacy client-side parallel fan-out until the cache is warm. Split usage_cache_stats so degraded counts per-slave granted substitution (still served) and fallback counts an unusable aggregate (client fans out). Add kunit coverage for MD-pool sum and ttl-0 miss vs post-refresh sum. Extend sanity-quota/310 for inode serve, no OST fan-out while enabled, and legacy fan-out when disabled. Add 311 for multi-MDT remote fetch (ttl=0; wait for MDT1 get_dqblk before the OSP refresh). Document usage_cache_enabled, usage_cache_ttl, and usage_cache_stats. Assisted-by: Cursor:Grok-4.6 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: Ic3864474ec2bf5619ccaf2a0c22c190c0c34a25a
67810
master
J !B ✓T ✗5R 0/2
LU-20354 quota: parallelize usage-cache GETOQUOTA
mine enforced failed: review-dne-ipv6, review-dne-part-5, review-dne-zfs-part-4, review-dne-zfs-part-7
1 unresolved
L +439 −172
52d
LU-20354 quota: parallelize usage-cache GETOQUOTA
mine enforced failed: review-dne-ipv6, review-dne-part-5, review-dne-zfs-part-4, review-dne-zfs-part-7
1 unresolved
L +439 −172
52d
enforced failed: review-dne-ipv6, review-dne-part-5, review-dne-zfs-part-4, review-dne-zfs-part-7
1 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
janitor run: 7 failing config(s), none unique to this patch — janitor results
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-ipv6 | RHEL 9.7 / x86_64 | ran 4 tests. 1 tests failed: sanity. | session |
| review-dne-part-5 | RHEL 9.7 / x86_64 | ran 5 tests. 1 tests failed: lustre-rsync-test. | session |
| review-dne-zfs-part-4 | RHEL 9.8 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-7 | RHEL 9.8 / x86_64 | ran 6 tests. 1 tests failed: sanity-ec. | session |
| review-dne-zfs-part-7 | RHEL 9.7 / x86_64 | ran 6 tests. 1 tests failed: sanity-ec. | session |
build #131507 SUCCESS · tests all Maloo sessions
patchsets:
PS1 08-07
PS5 09-02
PS6 09-08
PS7 09-10
threads: 1 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre lod_dev.c:2468 — (style) This isn't a bug, but the function uses GOTO() while having no ENTRY and returning with a plain return. On a CDEBUG_ENTRY_EXIT build
Gerrit AI review for Lustre
(style) This isn't a bug, but the function uses GOTO() while having no ENTRY and returning with a plain return. On a CDEBUG_ENTRY_EXIT build that logs "Process leaving via out_put" with no matching entry, and the success path logs nothing at all. lod_ost_quotactl() right above uses ENTRY/RETURN - worth matching it if the patch is refreshed.
owner Keguang Xu · uploader Keguang Xu · PS7 uploaded 55d ago · NEW · open in Gerrit ↗
commit message
LU-20354 quota: parallelize usage-cache GETOQUOTA Refresh stale per-slave usage in parallel batches via quf_fetch_batch. MDT queues remote OST Q_GETOQUOTA on a ptlrpc_set through LOD/OSP o_quotactl_async. Local MDT (DOM) stays a synchronous lquotactl_slv in the same batch; remote MDT remains -EOPNOTSUPP. On fetch failure keep the pre-fetch snap_usage when the slot was previously populated, otherwise fall back to granted. Re-lookup the slot by key after the unlocked fetch; shrink waits on lqu_fetching so the entry is still present. This cuts cold-miss / TTL-expire latency on large OST counts without changing GETQUOTA fallback semantics for OST slaves. Assisted-by: Cursor:Grok-4.6 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: I700aec594310b9ae2e1cbab0fa460fee15b7f3d3
Mentions
0 waiting on you · 0 openUnresolved threads where someone @-mentioned you (username, email or full name) — the pings that drown in Gerrit's email. Red: you have not replied since the ping. Muted: you replied, but the thread is still open, so it stays on the list until someone resolves it. Both clear on the refresh after the thread is resolved.
No unanswered pings — nobody is waiting on a mention.
0 watched
Nothing watched. Add a change above — e.g. after rebasing someone's patch — and its build/test state shows up here.
19 open
▶Failed / broken
(5)
69762
master
J –B ✓T ✓R +2/2
LU-20287 lov: don't block setattr on unavailable OST
Verified -1 veto by Oleg Drokin
Verified -1
218_review_prioritypw_shepherdpt_ecro
master-next
1 unresolved
L +319 −25
1h
LU-20287 lov: don't block setattr on unavailable OST
Verified -1 veto by Oleg Drokin
Verified -1
218_review_prioritypw_shepherdpt_ecro
master-next
1 unresolved
L +319 −25
1h
Verified -1 veto by Oleg Drokin
1 reviewer comment(s) to address if a respin is needed — last from Andreas Dilger
build #134595 SUCCESS · tests all Maloo sessions
reviews:
Ronnie Sahlberg +1 · Andreas Dilger +1
no vote yet: Marc Vef, Oleg Drokin
patchsets:
PS3 10-22
PS4 10-25
PS5 10-27
PS6 10-27 Marc Vef
PS7 10-28
+2 earlier
PS1 10-17 PS2 10-18threads: 1 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Andreas Dilger cl_object.h:2567 — seems reasonable if patch is refreshed
Gerrit AI review for Lustre
(minor) The new mtime and the new atime are both compared with one shared baseline, max(ctime, sa_cur_time). sa_cur_time is the max of the old mtime and atime, the cached OST mtime and atime, and the inode mtime and atime that vvp_attr_get() reads at iter_init. ll_md_setattr() has already written the new values into the inode by then. ll_merge_attr() merges each field on its own (atime with atime, mtime with mtime), so a newer value in the *other* field can never win the max() for this one.
With the shared baseline:
touch -m -d '+1 hour' f # mtime ahead, no lock (new >= ctime)
touch -a f # atime = now < base (mtime +1h)
The second command now counts as backward. vvp_io_setattr_lock() takes a CLM_WRITE [0, EOF] lock, which revokes other clients' extent locks even when every OST is up. If an OST is down, the command also blocks. Before this patch it took no lock. touch -m behaves the same way when the atime is ahead. So does utimensat() with atime < mtime when both are later than ctime, because the new mtime is already in the inode.
Would it be safer to keep separate mtime and atime baselines (sa_cur_mtime / sa_cur_atime), so that each new time is compared only with its own field? The comments on sa_cur_time, in cl_setattr_ost() and in vvp_io_setattr_iter_init() would then also match what is actually collected.
Andreas Dilger
seems reasonable if patch is refreshed
tags: 218_review_priority pw_shepherd pt_ecro
owner Keguang Xu · uploader Keguang Xu · PS7 uploaded 8d ago · NEW · open in Gerrit ↗
commit message
LU-20287 lov: don't block setattr on unavailable OST chown/chgrp/chmod/touch wait in cl_setattr_ost() when a stripe OST is down: VFS sets ATTR_CTIME and the client sends OST_SETATTR to every stripe. That RPC only carries times/flags; UID/GID/PROJID are authoritative on the MDT and are pushed by MDS osp_sync (persistent llog, retried until the OST returns). Skipping the client RPC therefore does not leave stale ownership on OST objects. For non-truncate/non-fallocate setattr on any layout, mark LOV sub-IOs ci_ndelay so OSC sends OST_SETATTR with rq_no_delay and rq_no_resend (plus a 5s delay limit for idle import reconnect), and ignore -EAGAIN/-ENOTCONN/-ESHUTDOWN/-ETIMEDOUT for such sub-IOs in osc_io_setattr_end(). Ndelay applies only when the new mtime/atime are >= max(ctime, sa_cur_time), where sa_cur_time is the known prior inode/cached OST times: ll_merge_attr() takes max(MDT, OST), so skipping an OST that already holds a newer time would leave that value visible. Missed updates are not repaired later, and on a slow but connected OST the client update may also be dropped. The CLM_WRITE [0, EOF] lock in vvp_io_setattr_lock() uses that same baseline, not ctime alone. Plain touch/utime(NULL) therefore takes the lock when sa_cur_time is ahead of the client clock (writer clock skew, or a future timestamp) and revokes other clients' cached extent locks; that path does not set ndelay. That is intentional: without it ndelay would skip the newer OST and max() would keep the wrong time. Still block when: - mtime/atime moves earlier than that baseline; - OP_XVALID_FLAGS is set (chattr, encryption flag): MDS never pushes flags to OSTs. This only unblocks the setattr RPC itself (including chmod(2)). stat/glimpse can still hang when no usable stripe/mirror is reachable: e.g. coreutils chmod stats via FTS before chmod(2), so the command may block on plain files even though the syscall would not. That is unchanged here (see LU-11962 for MDT SOM). Also re-push UID/GID/PROJID from the MDT inode on FLR RESYNC_DONE in lod_layout_change() with the layout version update. osp_sync normally retries ownership pushes; this is belt-and-suspenders if an MDS->OST ownership setattr was skipped (e.g. exercised with OBD_FAIL_LFSCK_BAD_OWNER; layout LFSCK can also repair that). Add sanity 39v (plain file) and sanity-flr 100a/100b. Test-Parameters: testlist=sanity env=ONLY=39v Test-Parameters: testlist=sanity-flr Assisted-by: Cursor:Grok-4.6/Opus5.5 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: I5005451e10f293279c441c1fc6d012fb5337d95d
66567
master
J –B ✓T ✗10R 0/2
LU-20212 lov: skip invalid OST mirrors for aggregate I/O
enforced failed: review-dne-part-4, review-dne-part-7, review-dne-subtest-change, review-dne-zfs-part-4, review-dne-zfs-part-5, review-dne-zfs-part-7, review-dne-zfs-subtest-change, review-zfs
4 unresolved
L +216 −39
8d
LU-20212 lov: skip invalid OST mirrors for aggregate I/O
enforced failed: review-dne-part-4, review-dne-part-7, review-dne-subtest-change, review-dne-zfs-part-4, review-dne-zfs-part-5, review-dne-zfs-part-7, review-dne-zfs-subtest-change, review-zfs
4 unresolved
L +216 −39
8d
enforced failed: review-dne-part-4, review-dne-part-7, review-dne-subtest-change, review-dne-zfs-part-4, review-dne-zfs-part-5, review-dne-zfs-part-7, review-dne-zfs-subtest-change, review-zfs
4 unresolved thread(s) await your reply — last from kg.xu
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-part-4 | RHEL 9.7 / x86_64 | ran 11 tests. 1 tests failed: sanity-flr. | session |
| review-dne-part-4 | RHEL 10.1 / x86_64 | ran 11 tests. 1 tests failed: sanity-flr. | session |
| review-dne-part-7 | RHEL 9.8 / x86_64 | ran 6 tests. 1 tests failed: sanity-ec. | session |
| review-dne-subtest-change | RHEL 9.7 / x86_64 | ran 3 tests. 1 tests failed: sanity-flr. | session |
| review-dne-zfs-part-4 | RHEL 9.8 / x86_64 | ran 11 tests. 1 tests failed: sanity-flr. | session |
| review-dne-zfs-part-4 | RHEL 10.1 / x86_64 | ran 11 tests. 1 tests failed: sanity-flr. | session |
| review-dne-zfs-part-5 | RHEL 9.7 / x86_64 | ran 5 tests. 1 tests failed: sanityn. | session |
| review-dne-zfs-part-7 | RHEL 9.8 / x86_64 | ran 6 tests. 1 tests failed: sanity-ec. | session |
| review-dne-zfs-subtest-change | RHEL 9.7 / x86_64 | ran 3 tests. 1 tests failed: sanity-flr. | session |
| review-zfs | RHEL 8.10 / x86_64 | ran 10 tests. 1 tests failed: sanity-flr. | session |
build #134448 SUCCESS · tests all Maloo sessions
no vote yet: Qian Yingjin, Marc Vef, Andreas Dilger
patchsets:
PS3 06-11
PS4 06-13
PS5 06-16
PS6 06-22
PS7 10-26
+2 earlier
PS1 06-10 PS2 06-10threads: 4 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply kg.xu patchset comment — I reused `lovsub_import_inactive()` from the EC series and incorporated logic to skip parity for `CIT_GLIMPSE`. Given these dependencies...S
Keguang Xu
Hi, this patch is part of 'FLR-ECRO: verify non-write RPCs do not block client': I was wondering if the `fail fast` logic on `stat()` should actually be a generic feature for all PFL components, instead of being scoped exclusively to EC files. If that makes sense, I'd prefer to rebase this against master and relocate the tests under sanity.sh. Thoughts?
kg.xu
I reused `lovsub_import_inactive()` from the EC series and incorporated logic to skip parity for `CIT_GLIMPSE`. Given these dependencies...So, let's keep it within this series.
reply kg.xu patchset comment — I reused `lovsub_import_inactive()` from the EC series and incorporated logic to skip parity for `CIT_GLIMPSE`. Given these dependencies...S
Andreas Dilger
This patch should probably go directly on master, since I don't think it depends on any functionality that hasn't landed yet?
kg.xu
I reused `lovsub_import_inactive()` from the EC series and incorporated logic to skip parity for `CIT_GLIMPSE`. Given these dependencies...So, let's keep it within this series.
reply kg.xu patchset comment — In lov_io_mirror_init(), if `ci_designated_mirror` is set, we can also check lov_mirror_has_inactive_stripe for `CIT_GLIMPSE/LSEEK/DATA_VERS
kg.xu
In lov_io_mirror_init(), if `ci_designated_mirror` is set, we can also check lov_mirror_has_inactive_stripe for `CIT_GLIMPSE/LSEEK/DATA_VERSION`. Since these io types all trigger OST aggregation, this check allows us to skip unnecessary RPCs. In current impl, we only check `CIT_GLIMPSE` during mirror selection (where `ci_designated_mirror` is false).
reply kg.xu sanity-ec.sh:3899 — An error returned:
wc-checkpatch
(style) line length of 81 exceeds 80 columns
Andreas Dilger
How does this behave for a non-EC file with a deactivated OST stripe? Does that return an error or just calculate the size without the stripe (which seems wrong)?
kg.xu
An error returned: `stat: cannot statx '/mnt/lustre/f42c.sanity-ec': Cannot send after transport endpoint shutdown` So the old code itself is correct already. New change only avoid sending unnecessary glimpse to mirrors with invalid OSTs.
owner Keguang Xu · uploader Keguang Xu · PS7 uploaded 9d ago · NEW · open in Gerrit ↗
commit message
LU-20212 lov: skip invalid OST mirrors for aggregate I/O I/O that aggregates stripe-local results into one logical answer (glimpse, lseek, data_version) cannot succeed on a mirror while any relevant OST import is deactivated or invalid. In lov_io_mirror_init(), skip mirrors with unreachable OSTs in the I/O extent during FLR selection for aggregate I/O. When every mirror is skipped, glimpse (ndelay) returns -EAGAIN after backoff so the caller retries, and -EIO once it has tried all mirrors several rounds; lseek and data_version fail with -EIO at once. For designated-mirror I/O, apply the same extent-scoped check after resolving ci_designated_mirror; there is no alternate mirror to try, so return -EIO immediately. Detect unreachable stripes with lov_mirror_extent_unreachable(), limited to stripes intersecting the current I/O extent, via lov_sub_unreachable(). Skip parity mirrors for glimpse and data_version as well, so they never return parity object size or version. Size FLR ndelay rounds by the data mirrors that can serve the I/O, not lo_mirror_count, for I/O types that skip parity; this also excludes stale mirrors from the round of a plain FLR read. CIT_EC_RD skips that rotation. Add sanity-flr 31b. Test-Parameters: fortestonly Assisted-by: Cursor:Grok-4.6/Opus5.5 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: Iac1c6415127d46fd958016a998ceab68663e0d42
68600
master
J ✗45B ✓T ✗11R 0/2
LU-20354 quota: serve LQA usage from QMT cache
janitor: 45 test failures unique to this patch — sanity-quota@ldiskfs+DNE:test_1j, sanity-quota@ldiskfs+DNE:test_3a, sanity-quota@ldiskfs+DNE:test_3b +42 more
45 unique failures
11 unresolved
XL +1391 −198
45d
LU-20354 quota: serve LQA usage from QMT cache
janitor: 45 test failures unique to this patch — sanity-quota@ldiskfs+DNE:test_1j, sanity-quota@ldiskfs+DNE:test_3a, sanity-quota@ldiskfs+DNE:test_3b +42 more
45 unique failures
11 unresolved
XL +1391 −198
45d
janitor: 45 test failures unique to this patch — sanity-quota@ldiskfs+DNE:test_1j, sanity-quota@ldiskfs+DNE:test_3a, sanity-quota@ldiskfs+DNE:test_3b +42 more
enforced failed: review-dne-ipv6, review-dne-part-4, review-dne-part-5, review-dne-zfs-part-3, review-dne-zfs-part-4, review-dne-zfs-part-5, review-dne-zfs-part-7, review-zfs
11 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
janitor flagged test failures unique to this patch — full janitor results
| unique failing test | history |
|---|---|
| sanity-quota@ldiskfs+DNE:test_1j | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@ldiskfs+DNE:test_3a | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_3b | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_3c | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_5 | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@ldiskfs+DNE:test_6 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_7a | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@ldiskfs+DNE:test_7b | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@ldiskfs+DNE:test_7c | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@ldiskfs+DNE:test_17 | seen in 6 other reviews |
| sanity-quota@ldiskfs+DNE:test_25 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_33 | seen in 4 other reviews |
| sanity-quota@ldiskfs+DNE:test_34 | seen in 4 other reviews |
| sanity-quota@ldiskfs+DNE:test_35 | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@ldiskfs+DNE:test_37 | seen in 4 other reviews |
| sanity-quota@ldiskfs+DNE:test_38 | seen in 4 other reviews |
| sanity-quota@ldiskfs+DNE:test_40c | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_64 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_67 | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@ldiskfs+DNE:test_71a | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_71b | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_72 | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_73a | seen in 6 other reviews |
| sanity-quota@ldiskfs+DNE:test_75 | seen in 6 other reviews |
| sanity-quota@ldiskfs+DNE:test_80 | seen in 1 other review |
| sanity-quota@zfs:test_1j | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_3a | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_3b | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_3c | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_5 | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_6 | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_7a | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_7b | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_7c | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_17 | seen in 34 other reviews |
| sanity-quota@zfs:test_25 | seen in 27 other reviews |
| sanity-quota@zfs:test_33 | seen in 33 other reviews |
| sanity-quota@zfs:test_34 | seen in 33 other reviews |
| sanity-quota@zfs:test_35 | NEW unique failure for this branch in the last 30 days, and was seen 2 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_37 | seen in 33 other reviews |
| sanity-quota@zfs:test_38 | seen in 33 other reviews |
| sanity-quota@zfs:test_64 | seen in 1 other review |
| sanity-quota@zfs:test_72 | seen in 14 other reviews |
| sanity-quota@zfs:test_73a | seen in 17 other reviews |
| sanity-quota@zfs:test_75 | seen in 7 other reviews |
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-ipv6 | RHEL 9.8 / x86_64 | ran 4 tests. 1 tests failed: sanity-lnet. | session |
| review-dne-part-4 | RHEL 9.7 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-part-4 | RHEL 10.1 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-part-5 | RHEL 9.7 / x86_64 | ran 5 tests. 1 tests failed: lustre-rsync-test. | session |
| review-dne-zfs-part-3 | RHEL 9.8 / x86_64 | ran 3 tests. 1 tests failed: conf-sanity. | session |
| review-dne-zfs-part-3 | RHEL 10.1 / x86_64 | ran 3 tests. 1 tests failed: conf-sanity. | session |
| review-dne-zfs-part-4 | RHEL 9.8 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-4 | RHEL 10.1 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-5 | RHEL 9.7 / x86_64 | ran 5 tests. 1 tests failed: lustre-rsync-test. | session |
| review-dne-zfs-part-7 | RHEL 9.8 / x86_64 | ran 6 tests. 1 tests failed: sanity-ec. | session |
| review-zfs | RHEL 8.10 / x86_64 | ran 8 tests. 1 tests failed: sanity-quota. | session |
build #132033 SUCCESS · tests all Maloo sessions
patchsets:
PS3 09-13
PS4 09-14
PS5 09-16
PS6 09-17
PS7 09-20
+2 earlier
PS1 09-03 PS2 09-11threads: 11 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre COMMIT_MSG:41 — (suggestion) This adds a new quotactl command and two new request formats on the MDS-to-OSS/MDT path, and changes what `lfs quota --lqa` pri
Gerrit AI review for Lustre
(suggestion) This adds a new quotactl command and two new request formats on the MDS-to-OSS/MDT path, and changes what `lfs quota --lqa` prints. A `Test-Parameters:` line asking for an interop run against a released server would cover the rolling-upgrade case where the slave does not know LUSTRE_Q_GETOUSAGES, e.g.
Test-Parameters: serverversion=2.16 testlist=sanity-quota
reply Gerrit AI review for Lustre COMMIT_MSG:39 — (minor) The body covers the LQA work well, but two hunks outside it are not mentioned.
Gerrit AI review for Lustre
(minor) The body covers the LQA work well, but two hunks outside it are not mentioned. qmt_dqacq0() now warms the cache with `qb_usage != 0` instead of an unconditional `true`. That changes the non-LQA per-ID path: a slave that legitimately reports zero usage no longer marks its slot fresh, so the next GETQUOTA misses and pays a full refresh round instead of hitting the cache. The inline comment gives the motivation (an on-disk 0 racing the first inode), but a reader of the commit message would not expect a per-ID behaviour change in an LQA patch. qmt_usg_test_init() also switches every `return rc` to `return -EINVAL`, which drops the specific failure code from the insmod error. Could both get a line in the body, or should the dqacq0 change be split out since it stands on its own?
reply Gerrit AI review for Lustre qmt.usage_cache_ttl.4:67 — (minor) This paragraph now sits directly under the new LQA text but describes only the per-ID behaviour. For LQA there is no "previously val
Gerrit AI review for Lustre
(minor) This paragraph now sits directly under the new LQA text but describes only the per-ID behaviour. For LQA there is no "previously valid cached value" kept and no granted substitution - qmt_lqa_refresh_lqe_usg() resets every slot to QMT_USG_UNSET and returns the error - and the 120s degraded TTL never applies either, since qmt_apply_usg_fetch() is not on that path. qmt.usage_cache_stats(4) already carries the "LQA has no granted substitution" caveat; the same note would fit here.
reply Gerrit AI review for Lustre lustre_quota.h:372 — (minor) The kdoc opens with "GETOUSAGES is server-internal", but this second test is what decides whether a non-server export gets in.
Gerrit AI review for Lustre
(minor) The kdoc opens with "GETOUSAGES is server-internal", but this second test is what decides whether a non-server export gets in. The connect-flag test above already matches every MDS/OSS export on its own: lod_add_device() requests OBD_CONNECT_MDS for OSP-to-OST and OBD_CONNECT_MDS_MDS for OSP-to-MDT, and both survive connect negotiation (ofd_obd.c reads exp_connect_flags(exp) & OBD_CONNECT_MDS the same way). So the nodemap clause is not needed for the MDS/OSS case the kdoc uses to justify it; what it does add is every ordinary client that happens to sit in a nodemap with trust_client_ids set, which is a common setting for compute nodes and says nothing about the client being privileged. A client in that nodemap can then read bspace/ispace for up to LQUOTA_IDS_MAX arbitrary IDs per RPC from any OST or MDT. Is that intended, or should the check be the connect flags alone?
reply Gerrit AI review for Lustre mdt_handler.c:6324 — (minor) GETOUSAGES is dispatched to every OST/MDT without any capability check. There is no OBD_CONNECT* bit for it, and nothing here looks
Gerrit AI review for Lustre
(minor) GETOUSAGES is dispatched to every OST/MDT without any capability check. There is no OBD_CONNECT* bit for it, and nothing here looks at exp_connect_flags before sending. Against a peer that predates the opcode the reply is an error rather than data: lquotactl_slv() rejects any qc_cmd other than Q_GETOQUOTA/LUSTRE_Q_ITEROQUOTA with -EOPNOTSUPP, and an older mdt_quotactl() falls into its `default:` case with -EFAULT. That becomes items[i].ufi_rc, which aborts qmt_lqa_refresh_lqe_usg() and wipes the cache, so in a mixed-version cluster every GETQUOTALQA pays the full glb-index walk and RPC fan-out and still ends with usage unknown. Should this be gated on a negotiated connect flag so the QMT can skip the refresh entirely when a slave cannot serve it?
reply Gerrit AI review for Lustre osp_dev.c:1549 — (minor) The comment above promises a length check that req_capsule_server_sized_get() does not perform for this field.
Gerrit AI review for Lustre
(minor) The comment above promises a length check that req_capsule_server_sized_get() does not perform for this field.
RMF_OBD_QUOTA_ACCT is RMF_F_STRUCT_ARRAY, and __req_capsule_get() takes that branch:
len = lustre_msg_buflen(msg, offset);
if (len % field->rmf_size) return NULL;
value = getter(msg, offset, len);
so the rc_area size that server_sized_get() just stored is discarded and lustre_msg_buf() is called with min_size equal to the buffer's own length. Any reply whose ACCT buffer is a non-zero multiple of sizeof(struct lquota_acct_rec) comes back non-NULL, including one shorter than qcb_replen, and the memcpy() then reads past it.
In-tree slaves size the reply from the ID list they received, so this needs a peer that answers rc = 0 with a short array. Would an explicit req_capsule_get_size(pill, &RMF_OBD_QUOTA_ACCT, RCL_SERVER) == qcb_replen test be worth keeping here, or at least a comment that matches what sized_get actually guarantees?
reply Gerrit AI review for Lustre qmt_entry.c:1495 — (style) This isn't a bug, but `qpi` is now available one line up, so `qpi->qpi_qmt->qmt_usg_ttl` would avoid evaluating lqe2qpi() twice. Wor
Gerrit AI review for Lustre
(style) This isn't a bug, but `qpi` is now available one line up, so `qpi->qpi_qmt->qmt_usg_ttl` would avoid evaluating lqe2qpi() twice. Worth folding in if the patch is refreshed.
reply Gerrit AI review for Lustre qmt_entry.c:1712 — (defect) A waiter that just slept on lqu_waitq re-enters here and redoes the whole refresh, even when the previous owner already filled ever
Gerrit AI review for Lustre
(defect) A waiter that just slept on lqu_waitq re-enters here and redoes the whole refresh, even when the previous owner already filled every slot. The per-ID path below is protected against this: after `goto again` its gather loop skips slots with `!qmt_usg_expired(...)`, so `nstale == 0` and it breaks out with zero RPCs. qmt_lqa_refresh_lqe_usg() has no equivalent test - it always calls qmt_lqa_collect_ids() (full walk of the glb index) and then re-fetches every slot. So with the default ttl of 3600, two concurrent `lfs quota --lqa` for the same name serialize on lqu_fetching and then each pay a complete index walk plus a GETOUSAGES fan-out, on an MDS service thread. N concurrent callers give N full refreshes. Would a `qmt_sum_lqe_usg(lqe, &tmp, now, true) == 0` check at the top of qmt_lqa_refresh_lqe_usg() (or before re-taking lqu_fetching) be enough to make the waiters cheap?
reply Gerrit AI review for Lustre qmt_handler.c:1297 — (minor) "LQA no-ops" doesn't quite match qmt_update_lqe_usg_entry_with_ttl(): its early return only fires for `usage_valid && !lqa_store`. q
Gerrit AI review for Lustre
(minor) "LQA no-ops" doesn't quite match qmt_update_lqe_usg_entry_with_ttl(): its early return only fires for `usage_valid && !lqa_store`. qmt_lqe_lookup() substitutes lqa_qid so the LQA entry here always has qid_uid == QMT_LQA_QID, and when the usage being reported is zero the call falls through and inserts/keeps a slot on the shared lqe. Harmless, but the comment reads as if nothing happens at all.
reply Gerrit AI review for Lustre qmt_internal.h:479 — (minor) QMT_USG_SNAP_NONE has no users - qmt_apply_usg_fetch() still compares its snap_usage against QMT_USG_UNSET, and this change is the t
Gerrit AI review for Lustre
(minor) QMT_USG_SNAP_NONE has no users - qmt_apply_usg_fetch() still compares its snap_usage against QMT_USG_UNSET, and this change is the tip of the relation chain, so nothing later picks it up. It is also the same value as QMT_USG_UNSET, which makes two names for one sentinel. Drop it on the next refresh?
reply Gerrit AI review for Lustre qmt_lqa.c:1330 — (suggestion) Any single slave error discards every slot, including ones that were still valid from an earlier successful refresh.
Gerrit AI review for Lustre
(suggestion) Any single slave error discards every slot, including ones that were still valid from an earlier successful refresh. An administratively deactivated OST is enough to reach this: lod_tgt_quotactl_async() returns -ENETDOWN for `!ltd_active || ltd_reap`, mdt_qmt_fetch_usgs_batch() propagates it, and the whole refresh unwinds here. From then on `lfs quota --lqa` reports usage as unknown for as long as that target stays down, while plain `lfs quota` for the same IDs keeps working because qmt_apply_usg_fetch() keeps the cached value or substitutes granted. The commit message presents the all-or-nothing abort as deliberate, so this is a design question rather than a claim that it is wrong: is a target the admin took offline on purpose really a reason to stop reporting LQA usage entirely, rather than reusing that slave's last cached value the way the per-ID path does?
owner Keguang Xu · uploader Keguang Xu · PS7 uploaded 46d ago · NEW · open in Gerrit ↗
commit message
LU-20354 quota: serve LQA usage from QMT cache GETQUOTALQA previously returned limits only. Wire it through the usage cache so lfs quota --lqa can set QIF_SPACE/QIF_INODES from the LQA shared lqe (qid=1). LQA has no llite fan-out and no per-slave DQACQ piggyback, so a miss collects glb IDs in the current ranges and batch-fetches each slave with LUSTRE_Q_GETOUSAGES. Per-slave range sums land on the shared lqe. A slave or setup failure aborts the refresh (no granted fallback, no partial sum) and leaves usage unknown; GETQUOTALQA still returns limits. QIF_SPACE follows DT alone and QIF_INODES follows MD alone. Missing QIF_USAGE is unknown in lfs, not -EIO. lfs quota --lqa accepts -U/-G/-P before or after --lqa, and prints "Disk quotas for <type> LQA <name>:". Range add/remove bumps qpi_lqa_gen with the rbtree update. Later GETQUOTALQA sees lqu_lqa_gen != qpi_lqa_gen, treats the slots as stale, and refreshes. The bump stays under the same write_lock as insert/erase so the new tree and new generation become visible together. GETOUSAGES carries a swabbed __u32 ID list (RMF_OBD_QUOTA_IDS) and lquota_acct_rec reply array (RMF_OBD_QUOTA_ACCT), not the opaque ITER blob used by ITEROQUOTA. A second qtype adding the same DOM MDT still increments LQA DT qpi_slv_nr on -EEXIST. LQA TTL follows usage_cache_ttl, including 0 (refetch on every GETQUOTALQA, same as per-ID GETQUOTA). Add MDT/OFD GETOUSAGES handlers, OSP/LOD iobuf async, and mdt_qmt_fetch_usgs_batch. Cover with kunit and sanity-quota/312. Document LQA behavior in the usage_cache_* man pages. Assisted-by: Cursor:Grok-4.6 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: I63f53ba1d21f2bb6cc419c3d09b3f9337eaa1f17
68598
master
J ✗17B ✓T ✗8R 0/2
LU-20354 quota: aggregate MD inode usage for GETQUOTA
janitor: 17 test failures unique to this patch — sanity-quota@ldiskfs+DNE:test_16a, sanity-quota@ldiskfs+DNE:test_17, sanity-quota@ldiskfs+DNE:test_33 +14 more
17 unique failures
11 unresolved
XL +813 −225
45d
LU-20354 quota: aggregate MD inode usage for GETQUOTA
janitor: 17 test failures unique to this patch — sanity-quota@ldiskfs+DNE:test_16a, sanity-quota@ldiskfs+DNE:test_17, sanity-quota@ldiskfs+DNE:test_33 +14 more
17 unique failures
11 unresolved
XL +813 −225
45d
janitor: 17 test failures unique to this patch — sanity-quota@ldiskfs+DNE:test_16a, sanity-quota@ldiskfs+DNE:test_17, sanity-quota@ldiskfs+DNE:test_33 +14 more
enforced failed: review-dne-part-4, review-dne-zfs-part-3, review-dne-zfs-part-4, review-dne-zfs-part-7, review-zfs
11 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
janitor flagged test failures unique to this patch — full janitor results
| unique failing test | history |
|---|---|
| sanity-quota@ldiskfs+DNE:test_16a | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_17 | seen in 7 other reviews |
| sanity-quota@ldiskfs+DNE:test_33 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_34 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_35 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_37 | seen in 3 other reviews |
| sanity-quota@ldiskfs+DNE:test_40c | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_64 | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_78A | seen in 4 other reviews |
| sanity-quota@ldiskfs+DNE:test_78a | seen in 3 other reviews |
| sanity-quota@zfs:test_17 | NEW unique failure for this branch in the last 30 days, and was seen 1 times across 1 other branches 1 reviews |
| sanity-quota@zfs:test_33 | seen in 1 other review |
| sanity-quota@zfs:test_34 | seen in 1 other review |
| sanity-quota@zfs:test_35 | seen in 1 other review |
| sanity-quota@zfs:test_37 | seen in 1 other review |
| sanity-quota@zfs:test_64 | seen in 2 other reviews |
| sanity-quota@zfs:test_75 | seen in 1 other review |
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-part-4 | RHEL 9.7 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-part-4 | RHEL 10.1 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-3 | RHEL 9.8 / x86_64 | ran 3 tests. 1 tests failed: conf-sanity. | session |
| review-dne-zfs-part-3 | RHEL 10.1 / x86_64 | ran 3 tests. 1 tests failed: conf-sanity. | session |
| review-dne-zfs-part-4 | RHEL 9.8 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-4 | RHEL 10.1 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-7 | RHEL 9.8 / x86_64 | ran 6 tests. 1 tests failed: sanity-ec. | session |
| review-zfs | RHEL 8.10 / x86_64 | ran 8 tests. 1 tests failed: sanity-quota. | session |
build #132032 SUCCESS · tests all Maloo sessions
patchsets:
PS1 09-03
PS3 09-14
PS4 09-17
PS5 09-20
threads: 11 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre COMMIT_MSG:40 — (minor) The `nrpc` out-parameter added to `quf_fetch_batch()` (lustre_quota.h, mdt_handler.c, qmt_entry.c) also changes what `usage_cache_st
Gerrit AI review for Lustre
(minor) The `nrpc` out-parameter added to `quf_fetch_batch()` (lustre_quota.h, mdt_handler.c, qmt_entry.c) also changes what `usage_cache_stats fetch_rpc` counts. It used to be `atomic64_add(nstale, ...)` issued before the fetch, so it counted every stale slot, including the local MDT slot that never produces an RPC; it is now only the OSP requests actually queued. That looks like an improvement, but it is a visible change to an existing counter and the body only mentions the degraded/fallback split. Worth a sentence here, since sanity-quota 310/311 now key off the new meaning.
reply Gerrit AI review for Lustre lustre_quota.h:131 — (style) Not a bug, but now that this also carries KEY_MDT_QUOTACTL, the `ost_` / `oqi_` naming reads as OST-only: `mdt_qmt_fetch_usage_batch
Gerrit AI review for Lustre
(style) Not a bug, but now that this also carries KEY_MDT_QUOTACTL, the `ost_` / `oqi_` naming reads as OST-only: `mdt_qmt_fetch_usage_batch()` declares `struct ost_qctl_info oqi` for the remote-MDT case. `lod_ost_quotactl()` got renamed to `lod_tgt_quotactl()` in this patch for exactly that reason; `struct tgt_qctl_info` with `tqi_*` fields would match, if the patch is refreshed anyway.
reply Misc Code Checks Robot (Gatekeeper helper) osp_dev.c:1571 — error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
Misc Code Checks Robot (Gatekeeper helper)
error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
reply Misc Code Checks Robot (Gatekeeper helper) osp_dev.c:1571 — error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
Misc Code Checks Robot (Gatekeeper helper)
error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
reply Misc Code Checks Robot (Gatekeeper helper) osp_dev.c:1571 — error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
Misc Code Checks Robot (Gatekeeper helper)
error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
reply Misc Code Checks Robot (Gatekeeper helper) osp_dev.c:1571 — error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
Misc Code Checks Robot (Gatekeeper helper)
error: osp_quotactl_prep():'osp' dereferencing possible ERR_PTR()
reply Gerrit AI review for Lustre qmt_entry.c:1601 — (minor) Was promoting these from LQUOTA_DEBUG to LQUOTA_WARN intended? D_WARNING is in D_CANTMASK, so both of these now reach the console (r
Gerrit AI review for Lustre
(minor) Was promoting these from LQUOTA_DEBUG to LQUOTA_WARN intended? D_WARNING is in D_CANTMASK, so both of these now reach the console (rate-limited by the cdls, but still console output). A slave that is briefly unavailable is routine - an OST in recovery answers -EAGAIN, an inactive target gives -ENETDOWN out of lod_tgt_quotactl_async() - and with usage_cache_enabled defaulting to 1 this path is now taken on ordinary `lfs quota` calls, where it previously produced nothing on the console. The degraded counter and qmt.usage_cache_stats(4) already cover the same condition for anyone watching for it. If the console message is wanted, it is probably worth a line in the commit message, since it is new output on a healthy filesystem.
reply Gerrit AI review for Lustre qmt_entry.c:1699 — (minor) The comment that this replaces said the rescan from key 0 was needed because "slots may be added while the lock was dropped for fetc
Gerrit AI review for Lustre
(minor) The comment that this replaces said the rescan from key 0 was needed because "slots may be added while the lock was dropped for fetch/apply". Resuming from the last key drops that property: qmt_usg_extend_sites() -> qmt_update_lqe_usg_entry() only takes lqe_usg_data_lock, it does not wait on lqu_fetching the way qmt_del_lqe_usg_entry() does, so a slave connecting mid-refresh can insert a slot whose key sorts below resume (MDT keys are below OST keys, and a pool add can bring in a lower OST index). That slot stays QMT_USG_UNSET, so the following qmt_sum_lqe_usg(..., check_ttl=false) returns -ESTALE and the whole GETQUOTA falls back to client fan-out. It self-heals on the next call, so this is not a correctness problem, but the commit message presents the resume as a pure optimization. Would a final pass that only looks for lue_usage == QMT_USG_UNSET work here? It still terminates, since a fetched slot is no longer UNSET.
reply Gerrit AI review for Lustre qmt_handler.c:104 — (defect) With `usage_cache_enabled` defaulting to 1, this refresh now runs for every quota ID a client asks about, including IDs that have n
Gerrit AI review for Lustre
(defect) With `usage_cache_enabled` defaulting to 1, this refresh now runs for every quota ID a client asks about, including IDs that have no limits at all and have never been seen before.
`check_owner()` in `ll_quotactl()` only owner-checks USRQUOTA and GRPQUOTA; PRJQUOTA falls through, so an unprivileged user on any client can run `lfs quota -p <projid>` for arbitrary project IDs. Each unseen ID then does, on the MDT0 service thread:
qmt_pool_lqe_lookup() -> lqe_locate_find() /* creates + hashes an lqe */
qmt_get_usage(DT) -> qmt_setup_lqe_usg() + this refresh
qmt_get_usage(MD) -> qmt_setup_lqe_usg() + this refresh
so two full Q_GETOQUOTA fan-outs to every OST/MDT plus a per-slave `lqe_usg_data` attached to the new lqe. QMT lqes are only dropped at site teardown, so the cache grows with the number of distinct IDs queried.
The lqe-per-queried-ID part is pre-existing, but until this patch `qmt_usg_serve` was hard-wired to 0 with no tunable, so `qmt_get_usage()` returned -EAGAIN and neither the slave RPCs nor the per-slave allocation happened; the fan-out ran on the client, in the client's own context and in parallel.
Would it work to skip the refresh when `!lqe->lqe_enforced`, leaving usage unset so the client keeps the legacy fan-out for IDs with no limits? That would cover the enumeration case and still serve the IDs that matter. Otherwise, is defaulting the tunable to 0 the safer landing state?
reply Gerrit AI review for Lustre qmt_handler.c:113 — (minor) `qmt_quotactl()` calls `qmt_get_usage()` twice now, once for DT and once for MD, so `hit`, `miss` and `fallback` became per-resource
Gerrit AI review for Lustre
(minor) `qmt_quotactl()` calls `qmt_get_usage()` twice now, once for DT and once for MD, so `hit`, `miss` and `fallback` became per-resource rather than per-GETQUOTA. One request where both aggregates fail bumps `fallback` twice, and a request where only DT fails bumps it even though `QIF_INODES` was served. The `qmt_usg_fallback` comment in qmt_internal.h (`GETQUOTA unserved`) and the `fallback` text in qmt.usage_cache_stats.4 (`GETQUOTA leaves usage unset so the client fans out`) both read as per-request. If the patch is refreshed, either move the counting up into qmt_quotactl() or reword both to say per-resource.
reply Gerrit AI review for Lustre sanity-quota.sh:8105 — (suggestion) The commit message says 310 is extended "for inode serve", but the test only ever reads --space; nothing asserts the value that
Gerrit AI review for Lustre
(suggestion) The commit message says 310 is extended "for inode serve", but the test only ever reads --space; nothing asserts the value that the MD aggregate produces. The QIF_SPACE gate means a passing space check proves rc_md was 0, so it shows MD *succeeded*, but not that dqb_curinodes is right.
311 does assert the inode count, but it is gated on MDSCOUNT >= 2, so a single-MDT run - the common sanity-quota config - never checks the headline behavior of this patch.
A second line next to this one would close that, e.g.
used=$($LFS quota -u $TSTUSR --inodes -q $DIR | tr -d '*')
(( used > 0 )) || quota_error u $TSTUSR "expected non-zero inode usage, got $used"
owner Keguang Xu · uploader Keguang Xu · PS5 uploaded 46d ago · NEW · open in Gerrit ↗
commit message
LU-20354 quota: aggregate MD inode usage for GETQUOTA Turn on the usage cache (qmt.*.usage_cache_enabled, default on) so GETQUOTA sums both DT and MD from the per-slave cache. Set QIF_INODES from the MD aggregate and require both DT and MD before QIF_SPACE so llite still fans out when inode usage is unavailable. A slave fetch failure substitutes granted (or keeps a prior cache) and still serves: granted may overstate usage, but one unreachable target must not force every client to fan out. Clearing the tunable leaves usage unset and clients keep legacy fan-out. Drop the DT-only usage-cache gates so MD-pool lqes get slots: qmt_setup_lqe_usg / qmt_update_lqe_usg_entry / qmt_usg_extend_sites and DQACQ warming now apply to LQUOTA_RES_MD (LQA still skipped). MD-pool slots return dqb_curinodes; DT (incl. DOM) stays stoqb(dqb_curspace). Fetch remote MDTs via MDT-OSP MDS_QUOTACTL (KEY_MDT_QUOTACTL). MDS/OSS NIDs belong in a trusted nodemap, so CLIENT_TO_FS map is identity and no skip-idmap handshake is needed. usage_cache_ttl=0 means no cache: each GETQUOTA misses and refetches. Unfilled slots use lue_usage=QMT_USG_UNSET; expire=0 is zero freshness (same as ttl=0) so a queued waiter walks again instead of skipping as still fresh. Resume xa_for_each_start across GETOQUOTA batches of QMT_USG_FETCH_PARALLEL 32 (was 16) instead of rescanning from key 0. A cold-cache GETQUOTA on a large filesystem runs the slave fan-out synchronously on MDT0 (DT then MD), serialized per id. That can be slower than legacy client-side parallel fan-out until the cache is warm. Split usage_cache_stats so degraded counts per-slave granted substitution (still served) and fallback counts an unusable aggregate (client fans out). Add kunit coverage for MD-pool sum and ttl-0 miss vs post-refresh sum. Extend sanity-quota/310 for inode serve, no OST fan-out while enabled, and legacy fan-out when disabled. Add 311 for multi-MDT remote fetch (ttl=0; wait for MDT1 get_dqblk before the OSP refresh). Document usage_cache_enabled, usage_cache_ttl, and usage_cache_stats. Assisted-by: Cursor:Grok-4.6 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: Ic3864474ec2bf5619ccaf2a0c22c190c0c34a25a
67810
master
J !B ✓T ✗5R 0/2
LU-20354 quota: parallelize usage-cache GETOQUOTA
enforced failed: review-dne-ipv6, review-dne-part-5, review-dne-zfs-part-4, review-dne-zfs-part-7
1 unresolved
L +439 −172
52d
LU-20354 quota: parallelize usage-cache GETOQUOTA
enforced failed: review-dne-ipv6, review-dne-part-5, review-dne-zfs-part-4, review-dne-zfs-part-7
1 unresolved
L +439 −172
52d
enforced failed: review-dne-ipv6, review-dne-part-5, review-dne-zfs-part-4, review-dne-zfs-part-7
1 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
janitor run: 7 failing config(s), none unique to this patch — janitor results
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-ipv6 | RHEL 9.7 / x86_64 | ran 4 tests. 1 tests failed: sanity. | session |
| review-dne-part-5 | RHEL 9.7 / x86_64 | ran 5 tests. 1 tests failed: lustre-rsync-test. | session |
| review-dne-zfs-part-4 | RHEL 9.8 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-7 | RHEL 9.8 / x86_64 | ran 6 tests. 1 tests failed: sanity-ec. | session |
| review-dne-zfs-part-7 | RHEL 9.7 / x86_64 | ran 6 tests. 1 tests failed: sanity-ec. | session |
build #131507 SUCCESS · tests all Maloo sessions
patchsets:
PS1 08-07
PS5 09-02
PS6 09-08
PS7 09-10
threads: 1 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre lod_dev.c:2468 — (style) This isn't a bug, but the function uses GOTO() while having no ENTRY and returning with a plain return. On a CDEBUG_ENTRY_EXIT build
Gerrit AI review for Lustre
(style) This isn't a bug, but the function uses GOTO() while having no ENTRY and returning with a plain return. On a CDEBUG_ENTRY_EXIT build that logs "Process leaving via out_put" with no matching entry, and the success path logs nothing at all. lod_ost_quotactl() right above uses ENTRY/RETURN - worth matching it if the patch is refreshed.
owner Keguang Xu · uploader Keguang Xu · PS7 uploaded 55d ago · NEW · open in Gerrit ↗
commit message
LU-20354 quota: parallelize usage-cache GETOQUOTA Refresh stale per-slave usage in parallel batches via quf_fetch_batch. MDT queues remote OST Q_GETOQUOTA on a ptlrpc_set through LOD/OSP o_quotactl_async. Local MDT (DOM) stays a synchronous lquotactl_slv in the same batch; remote MDT remains -EOPNOTSUPP. On fetch failure keep the pre-fetch snap_usage when the slot was previously populated, otherwise fall back to granted. Re-lookup the slot by key after the unlocked fetch; shrink waits on lqu_fetching so the entry is still present. This cuts cold-miss / TTL-expire latency on large OST counts without changing GETQUOTA fallback semantics for OST slaves. Assisted-by: Cursor:Grok-4.6 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: I700aec594310b9ae2e1cbab0fa460fee15b7f3d3
▶Review feedback — your turn
(2)
67700
master
J –B ✓T ✓R 0/2
LU-20354 quota: cache per-slave DT usage on QMT
10 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
11 unresolved
L +754 −11
6d
LU-20354 quota: cache per-slave DT usage on QMT
10 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
11 unresolved
L +754 −11
6d
10 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
CI green — no vote yet from Sergey Cheremencev, Andreas Dilger, Hongchao Zhang
1 thread(s) waiting on others
build #133862 SUCCESS · tests all Maloo sessions
no vote yet: Sergey Cheremencev, Andreas Dilger, Hongchao Zhang
patchsets:
PS13 09-02
PS14 09-29
PS15 10-05
PS16 10-12
PS17 10-15 kg.xu
+12 earlier
PS1 08-03 PS2 08-04 PS3 08-05 PS4 08-06 PS5 08-10 PS6 08-18 PS7 08-24 PS8 08-24 PS9 08-26 PS10 08-28 PS11 08-29 PS12 08-30threads: 10 need your reply · 1 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre COMMIT_MSG:10 — (minor) The subject and this sentence scope the cache to DT / block usage, but nothing in the code restricts it to LQUOTA_RES_DT.
Gerrit AI review for Lustre
(minor) The subject and this sentence scope the cache to DT / block usage, but nothing in the code restricts it to LQUOTA_RES_DT. qmt_pool_new_conn() is called once per global index FID, so qmt_usg_extend_sites() also runs on the LQUOTA_RES_MD global pool, and the warming loop in qmt_dqacq0() runs for whatever qti_lqes(env) holds - which is the MD pool lqe on an inode DQACQ, with qb_usage being an inode count. So MD lqes get an lqe_usg_data and per-MDT slots too. Is that intended (in which case the message could say so), or should the warming and the extend be gated on LQUOTA_RES_DT until the inode side is ready?
reply Andreas Dilger COMMIT_MSG:10 — ... block and inode usage ..., I hope? It should be possible to cache the MDT usage as well, in case it is temporarily offline.
Andreas Dilger
... block and inode usage ..., I hope? It should be possible to cache the MDT usage as well, in case it is temporarily offline.
reply kg.xu patchset comment — Updated
kg.xu
Hi, some tips on this change, which might be helpful in review,
Focus: Build QMT per-slave DT usage cache only. qmt_usg_serve=0 — GETQUOTA still leaves usage unset (legacy client fan-out).
Read order: qmt_internal.h → qmt_pool.c (DOM/dom_mdts) → qmt_entry.c (update/sum/refresh) → qmt_dqacq0 warm → mdt_qmt_fetch_usage.
Call chains:
```
# warm (live)
QSD DQACQ/REL (+QUOTA_DQACQ_FL_USAGE, qb_usage)
→ qmt_dqacq → qmt_dqacq0 → qmt_update_lqe_usg()
# pool membership → slots
connect/add → qmt_usg_extend_cb | qmt_pool_dom_add → empty slot
shrink → qmt_usg_shrink_cb → qmt_del_lqe_usg()
# refresh (wired, gated off)
qmt_quotactl(GETQUOTA) → qmt_get_usage()
→ (!qmt_usg_serve) -EAGAIN
→ [later] sum → refresh → mdt_qmt_fetch_usage
→ local MDT: lquotactl_slv | OST: OSP Q_GETOQUOTA
→ fail: keep cache | fallback granted
```
kg.xu
Updated
Focus: Build QMT per-slave DT usage cache only.
Read order:
qmt_internal.h / lquota_internal.h (lqu_xa) →
qmt_pool.c (DOM / extend / shrink) →
qmt_entry.c (update / del / sum) →
qmt_dqacq0 warm → qsd_handler.c (QUOTA_DQACQ_FL_USAGE).
Call chains:
```
QSD DQACQ/REL (+QUOTA_DQACQ_FL_USAGE, qb_usage)
→ qmt_dqacq → qmt_dqacq0 → qmt_update_lqe_usg_entry
(also on REPORT; skip shared LQA lqe)
# pool membership → slots
OST/MDT connect/add
→ qmt_usg_extend_cb → empty OST (or MD primary) slot
DOM MDT connect (global DT only)
→ qmt_pool_dom_add → qmt_usg_dom_extend_cb → empty MDT slot
shrink (snapshot then delete; not under cfs_hash_for_each)
→ qmt_usg_shrink_hash → qmt_del_lqe_usg_entry()
(waits lqu_fetching for follow-on refresh)
```
reply Andreas Dilger wiretest.c:4945 — (style) please use `unsigned int` even though the script currently generates `unsigned` so that we have fewer places to fix in the future.
Andreas Dilger
(style) please use `unsigned int` even though the script currently generates `unsigned` so that we have fewer places to fix in the future.
reply Andreas Dilger lquota_internal.h:182 — seems reasonable to fix if patch is refreshed, or a later patch in this series..
Gerrit AI review for Lustre
(suggestion) This isn't a bug, but the comment says the field is QMT-only, yet it sits outside the `u.me`/`u.se` union. That adds 16 bytes to every `lquota_entry`, including all the QSD entries on every OST and MDT, which never use it. Could it go into `struct lquota_mst_entry` as `lme_usg_xa`, with a `#define lqe_usg_xa u.me.lme_usg_xa` like `lqe_sem`? On a non-debug build `lquota_mst_entry` is smaller than `lquota_slv_entry`, so the union should not grow. `lqe_ref_free()` would then call `qmt_lqe_usg_fini()` only when `lqe_is_master(lqe)` is true, rather than relying on QSD entries having a zeroed xarray.
Andreas Dilger
seems reasonable to fix if patch is refreshed, or a later patch in this series..
reply Andreas Dilger qmt_dev.c:58 — (minor) other parameters like this are named "maxage"
Andreas Dilger
(minor) other parameters like this are named "maxage"
reply Andreas Dilger qmt_dev.c:83 — I don't see the man4 page for this?
wc-checkpatch
(style) 'LPROC_SEQ_FOPS' may be misspelled - perhaps 'LUSTRE_RW_ATTR and create Documentation/man4/ page for param'?
Andreas Dilger
I don't see the man4 page for this?
reply Gerrit AI review for Lustre qmt_handler.c:1195 — (style) This isn't a bug, but qmt_update_lqe_usg_entry() opens with the identical `qpi_lqa || qpi_rtype != LQUOTA_RES_DT` test and returns 0
Gerrit AI review for Lustre
(style) This isn't a bug, but qmt_update_lqe_usg_entry() opens with the identical `qpi_lqa || qpi_rtype != LQUOTA_RES_DT` test and returns 0, so the filter here is duplicated. Dropping one of the two would keep the rule in a single place.
reply Andreas Dilger qmt_internal.h:394 — Presumably this is cached so long only if the target is offline? Otherwise it should be maximum a few seconds.
Andreas Dilger
Presumably this is cached so long only if the target is offline? Otherwise it should be maximum a few seconds.
reply Andreas Dilger sanity-quota.sh:8310 — Adding tests at the end of the file is conflict-intensive. If doing so, add a larger gap like test_350() so there is more room for future g
Andreas Dilger
Adding tests at the end of the file is conflict-intensive. If doing so, add a larger gap like test_350() so there is more room for future growth without conflicts (search for open patches modifying sanity-quota.sh to check). Otherwise, use a gap between 98 and 300, like 200.
owner Keguang Xu · uploader kg.xu · PS17 uploaded 21d ago · NEW · open in Gerrit ↗
commit message
LU-20354 quota: cache per-slave DT usage on QMT Build an in-memory per-slave DT usage cache on the global pool lqe so QMT can track block usage reported by slaves. Named pools do not keep their own slots; qmt_sum_lqe_usg() sums the global entries for the pool's current sarr members. LQA and MD are not cached. Refresh from MDT/OSP and serving the sum on GETQUOTA stay in a follow-on. DQACQ and REL piggyback on-disk usage in qb_usage with QUOTA_DQACQ_FL_USAGE, set by qsd_qbody_set_usage(). REPORT already carries that usage and is left unchanged. qmt_dqacq0() drops the lqe write lock, then qmt_update_lqe_usg_entry() stores the value on the global lqe. A missing slot is created there. The slot stores the update time; a ttl of 0 always misses. The sum holds op_rw_sem (read) across each member array. Slot fields are written with WRITE_ONCE and read with READ_ONCE, with no second lock. Callers must not hold lqe_sem: the recalc thread takes op_rw_sem and then lqe_sem, so the other order deadlocks with a queued pool writer. A missing or expired member, or a pool with no members, returns -ESTALE. An all-zero fresh sum is a valid idle ID. DOM MDTs are recorded only in the global DT pool tgts[MDT] and stay out of lgd and recalc. A slave connect adds the target once; disconnect does not remove it. qmt.*.usage_cache_ttl is in seconds (default 3600, max one day). Zero makes every lookup miss. The cache is freed with the lqe. qmt_usg_test covers update and sum by pool sarr, a named pool sharing the global cache, and TTL. sanity-quota/305 loads it on the MDS. It does not exercise MDT/OSP refresh. Assisted-by: Cursor:Grok-4.7/Opus5.5 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: I9acd2b938c45ba9c62d5a2c03ba86af24ddbe90d
68073
master
J –B ✓T ✓R 0/2
LU-20354 quota: refresh QMT usage cache via MDT/OSP proxy
3 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
3 unresolved
L +759 −66
18d
LU-20354 quota: refresh QMT usage cache via MDT/OSP proxy
3 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
3 unresolved
L +759 −66
18d
3 unresolved thread(s) await your reply — last from Gerrit AI review for Lustre
CI green — no vote yet from Sergey Cheremencev, Andreas Dilger, Hongchao Zhang
build #133812 SUCCESS · tests all Maloo sessions
no vote yet: Sergey Cheremencev, Andreas Dilger, Hongchao Zhang
patchsets:
PS2 09-02
PS3 09-04
PS5 09-10
PS6 10-14
PS7 10-16
+1 earlier
PS1 08-18threads: 3 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre mdt_handler.c:6122 — (typo) Missing space before `*/`.
Gerrit AI review for Lustre
(typo) Missing space before `*/`.
reply Gerrit AI review for Lustre qmt_entry.c:1344 — (minor) The extra members don't really wait for a later refresh. After qmt_refresh_lqe_usg() returns 0, qmt_get_usage() re-sums with check_t
Gerrit AI review for Lustre
(minor) The extra members don't really wait for a later refresh. After qmt_refresh_lqe_usg() returns 0, qmt_get_usage() re-sums with check_ttl=false over the live sarr, not over the copied idxs. So a member added during the walk is summed at whatever age its slot has. Example: `lctl pool_add` adds OST N to a named pool while the serial Q_GETOQUOTA walk is running. OST N already has a slot on the global lqe from an old DQACQ (slots are only freed with the lqe), but that slot expired long ago. Refresh never touches N, and the following sum serves N's old value as part of a fresh aggregate. A member with no slot gets -ESTALE, which is fine. This only matters once qmt_usg_serve is enabled, and the result is one stale reply, not corruption. But either the comment or the post-refresh sum should change, e.g. sum only the idxs that refresh handled, or redo the refresh if op_count changed.
reply Gerrit AI review for Lustre qmt_handler.c:776 — (style) This isn't a bug, but the comment sits directly above an assignment that runs for every command in this case group, while the text o
Gerrit AI review for Lustre
(style) This isn't a bug, but the comment sits directly above an assignment that runs for every command in this case group, while the text only describes the two commands handled by the condition below it. The old comment explained the assignment itself. Moving this line down onto the `if` would read better.
owner Keguang Xu · uploader Keguang Xu · PS7 uploaded 20d ago · NEW · open in Gerrit ↗
commit message
LU-20354 quota: refresh QMT usage cache via MDT/OSP proxy Wire qmt_refresh_lqe_usg() to pull stale or missing per-slave usage through MDT: local OSD for the DOM MDT, OSP Q_GETOQUOTA for OSTs. The cache stays on the global DT lqe. The caller passes that lqe and the pool; refresh walks the pool sarr (alloc outside the lock, copy under it). Fresh slots, including DQACQ-warmed zeros, are left alone. Remote MDT DOM fetch is still TODO. On fetch failure, keep a cached value when the slot exists, otherwise fall back to granted from that slave's index. Degraded values are back-dated to expire after about 60s so the next refresh retries soon. qmt_sum_lqe_usg() takes check_ttl: true for a cache lookup, false after refresh so freshly stored slots are served even when ttl is 0. qc_id is already a filesystem ID. MDS/OSS NIDs belong in a trusted nodemap, so OFD's CLIENT_TO_FS map is identity and no skip-idmap handshake is needed. qmt_get_usage() sums and refreshes only when qmt_usg_serve is on. The flag stays off, so GETQUOTA still leaves usage unset. qmt_usg_fallback counts a granted fallback or a failed serve. Expose qmt.*.usage_cache_stats (hit/miss/fetch_rpc/fallback). Add sanity-quota/310, skipped until qmt_usg_serve is on. Extend qmt_usg_test for ttl 0 with check_ttl true/false. Test-Parameters: trivial testlist=sanity-quota Assisted-by: Cursor:Grok-4.6 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: Ied2f4f1e3c7ee6611a69a57e8064d46a59ba845f
▶In CI
(4)
70490
master
J –B ✓T …R 0/2
LU-21103 lov: move EC raid set code out of lov_io.c
build OK — testing in progress (typically 6–14h)
L +479 −443
18m
LU-21103 lov: move EC raid set code out of lov_io.c
build OK — testing in progress (typically 6–14h)
L +479 −443
18m
owner Keguang Xu · uploader Keguang Xu · PS1 uploaded 52m ago · NEW · open in Gerrit ↗
commit message
LU-21103 lov: move EC raid set code out of lov_io.c The policy that decides which stripes of an erasure coded read to avoid is spread through lov_io_mirror_init() and lov_ecio_add_data_sub(), and the raid set helpers it uses sit in lov_io.c with the rest of the IO code. Later patches give the raid set decision a single implementation and let mirror selection use the same OST availability checks, so move the code they build on to where it can be shared first. Move the OST availability predicates lov_sub_unreachable(), lov_sub_slow(), lov_sub_unavailable() and lov_sub_loaded() to lovsub_object.c, next to the sub-object they query. Move the raid set helpers and lov_ec_io_route() to a new file lov_ec.c, and enum lov_ec_route to lov_cl_internal.h. Functions still used from lov_io.c are no longer static; the others stay static in their new file. No functional change. Test-Parameters: testlist=sanity-ec ostcount=8 Test-Parameters: testlist=sanity-flr ostcount=8 Signed-off-by: Keguang Xu <kxu@ddn.com> Assisted-by: Augment Agent:Claude Opus 5.5 Change-Id: I916aca81ede957bd1f317b0b36575e7aa1ff1c4e
68361
master
J –B ✓T ↻R +2/2
LU-20690 ec: store EC parity like RAID10
review-dne-selinux-ssk-part-2 failed — auto-retest in flight (often self-heals)
ec2
218_review_prioritypw_shepherdraid10-likept_ecro
12 unresolved
XL +2329 −745
21m
LU-20690 ec: store EC parity like RAID10
review-dne-selinux-ssk-part-2 failed — auto-retest in flight (often self-heals)
ec2
218_review_prioritypw_shepherdraid10-likept_ecro
12 unresolved
XL +2329 −745
21m
review-dne-selinux-ssk-part-2 failed — auto-retest in flight (often self-heals)
1 thread(s) waiting on others
11 reviewer comment(s) to address if a respin is needed — last from Gerrit AI review for Lustre
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-selinux-ssk-part-2 retesting failed 2× | RHEL 8.10 / x86_64 | ran 7 tests. 1 tests failed: sanity-sec. | session |
build #135358 SUCCESS · tests all Maloo sessions
reviews:
Ronnie Sahlberg +1 · Andreas Dilger +1
no vote yet: Marc Vef
patchsets:
PS22 11-03 Andreas Dilger
PS23 11-03 Andreas Dilger
PS24 11-03 Andreas Dilger
PS25 11-04 Andreas Dilger
PS26 11-04 Andreas Dilger
+13 earlier
PS1 08-26 PS7 09-03 PS8 09-07 PS9 09-10 PS10 09-11 PS11 09-23 PS12 10-08 PS13 10-08 PS17 10-23 PS18 10-29 PS19 10-29 Ronnie Sahlberg PS20 10-30 Ronnie Sahlberg PS21 11-01threads: 11 need your reply · 1 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre COMMIT_MSG:174 — (minor) The patch also fixes the raid set mapping in degraded reads and resync, which counted rows and raid sets from e_start instead of fil
Gerrit AI review for Lustre
(minor) The patch also fixes the raid set mapping in degraded reads and resync, which counted rows and raid sets from e_start instead of file offset 0 (the wrong-parity rebuild described above). That counting came from landed commits, so a Fixes: line would help with tracking, even though EC has not shipped:
Fixes: 783c13bb0b ("LU-12669 ec: recover data from parity")
The resync side of the same problem dates from 03191be6f4 ("LU-12668 ec: add support to resync stale ec comps").
reply Gerrit AI review for Lustre lfs-mirror-read.1:30 — (minor) llapi_layout_parity_pos_to_io() starts each component's dump at the slot of the raid set that holds e_start, not at raid set 0. Take
Gerrit AI review for Lustre
(minor) llapi_layout_parity_pos_to_io() starts each component's dump at the slot of the raid set that holds e_start, not at raid set 0. Take -E 4M -c 1 -E eof -S 1M -c 8 --ec 4+1: the second component has O = 3M, e_start is in raid set 1, and its dump begins with the parity object of raid set 1, followed by raid set 0 of the next row. The order matches getstripe only when e_start is a multiple of the stripe width. lfs-getstripe.1 has the same issue ("dumps this RAID0 of all parity stripes"). If the patch is refreshed, could both pages say that the first row starts at the raid set of e_start?
reply Gerrit AI review for Lustre lustre_user.h:3527 — (style) This isn't a bug, but three __u32 fields ahead of this __u64 leave a 4-byte hole on 64-bit, and this is a uapi header. The struct is
Gerrit AI review for Lustre
(style) This isn't a bug, but three __u32 fields ahead of this __u64 leave a 4-byte hole on 64-bit, and this is a uapi header. The struct is not passed across the ABI, so nothing breaks. If the patch is refreshed, moving epg_row0 up next to epg_origin would remove the hole.
reply Ronnie Sahlberg cl_object.h:2022 — not part of this change any more. And don't want to touch 69517 where this now lives as that one has passed testing.
Andreas Dilger
(minor) "stripe" is not a good name for this, since it is potentially conflated with the data stripe number if we want to do single-stripe read/write for replacement. Maybe "_parity_index" or similar?
Ronnie Sahlberg
not part of this change any more. And don't want to touch 69517 where this now lives as that one has passed testing.
reply Misc Code Checks Robot (Gatekeeper helper) lod_internal.h:751 — warn: lod_comp_shrink_to_extent():always true condition '(lod_comp->llc_stripe_count <= 65535) => (0-u16max <= u16max)'
Misc Code Checks Robot (Gatekeeper helper)
warn: lod_comp_shrink_to_extent():always true condition '(lod_comp->llc_stripe_count <= 65535) => (0-u16max <= u16max)'
reply Andreas Dilger lov_internal.h:160 — With RAID0|PARITY gone, lsme_parity_slots_per_raidset() is always 1 for parity and only multiplies poff at two places in lov_io.c. The six
Andreas Dilger
With RAID0|PARITY gone, lsme_parity_slots_per_raidset() is always 1 for parity and only multiplies poff at two places in lov_io.c. The six geometry helpers (lsme_stripe_origin, lsme_stripes_per_slot, lsme_parity_single_slot, lsme_slot_count, lsme_stripe_slot, lsme_parity_slots_per_raidset) reduce to one rule: for parity, origin = e_start, width = (stripe_count / p) * stripe_size, slot = stripe / p; otherwise RAID0. Two helpers would do, and the single-slot case can become an invalid entry. About 25 lines.
reply Ronnie Sahlberg lfs.c:4629 — Silent fallback is addressed. But not the quoting as raid0,overstriped should already be treated by yaml as a single string so quoting shoul
Andreas Dilger
This only matches the exact string "parity", but "lfs getstripe -y" prints "parity,overstriped" for a -C EC component, so "lfs setstripe --yaml" of that output silently falls back to the default pattern. When the pattern has multiple flags, please quote it in the YAML output (pattern: "parity,overstriped") so it is a single scalar, and parse the comma-separated flags here instead of comparing whole strings, which would also cover "raid0,overstriped" and any later flag combinations.
Ronnie Sahlberg
Silent fallback is addressed. But not the quoting as raid0,overstriped should already be treated by yaml as a single string so quoting should not be needed here.
reply Gerrit AI review for Lustre lfs.c:4553 — (suggestion) This isn't a bug, but the ignored[] list repeats the names in lov_pattern_names[] in liblustreapi_layout.c, and llapi_lov_strin
Gerrit AI review for Lustre
(suggestion) This isn't a bug, but the ignored[] list repeats the names in lov_pattern_names[] in liblustreapi_layout.c, and llapi_lov_string_pattern() already parses the comma-separated getstripe form. The copy will drift when a new pattern name is added. If the patch is refreshed, consider calling llapi_lov_string_pattern() and mapping LOV_PATTERN_MDT and LOV_PATTERN_OVERSTRIPING to the LLAPI_LAYOUT_* values. The "unknown_" prefix would still need handling here.
reply Gerrit AI review for Lustre lfs.c:17032 — (nit) This isn't a bug, but the dash here is a non-ASCII character. If the patch is refreshed, a plain "-" or ":" would keep the source ASCI
Gerrit AI review for Lustre
(nit) This isn't a bug, but the dash here is a non-ASCII character. If the patch is refreshed, a plain "-" or ":" would keep the source ASCII.
reply Gerrit AI review for Lustre lfs.c:17932 — (minor) Can this read still work for a stale parity mirror? print_stale_mirrors() walks every stale component, parity included, and calls ll
Gerrit AI review for Lustre
(minor) Can this read still work for a stale parity mirror? print_stale_mirrors() walks every stale component, parity included, and calls llapi_mirror_read() with no parity stripe set. Parity components now use LOV_PATTERN_PARITY, so the read fails:
llapi_mirror_read() -> pread()
-> lov_io_iter_init()
-> lov_io_designated_stripe_valid() -> -EINVAL
Parity goes stale on any write to an EC file, so `lfs mirror verify` on a file awaiting resync now prints "Mirror N: (stale - read error)" where it used to print a CRC. The exit status stays -ESTALE, but this suggests an I/O problem on a healthy mirror. It also contradicts the new llapi_mirror_read() comment, which calls it the non-parity path. If the patch is refreshed, could this skip the read for LCME_FL_PARITY components and print just the stale state, as the chunk verify path already skips parity?
reply Gerrit AI review for Lustre liblustreapi_layout.c:3229 — (minor) Carried over from the PS17 comment on liblustreapi_mirror.c, which asked for the parity-dump helpers to be static in lfs.c rather th
Gerrit AI review for Lustre
(minor) Carried over from the PS17 comment on liblustreapi_mirror.c, which asked for the parity-dump helpers to be static in lfs.c rather than new public API. mirror_dump_parity() moved, but llapi_layout_parity_pos_to_io() is still a global llapi_* function. liblustreapi.map exports `llapi_*`, so it is still in liblustreapi.so's ABI even though only lustreapi_internal.h declares it. If the patch is refreshed, could it move into lfs.c and use the public layout getters, or at least lose the llapi_ prefix so the map doesn't export it?
tags: 218_review_priority pw_shepherd raid10-like pt_ecro
owner Keguang Xu · uploader Andreas Dilger · PS26 uploaded 1d ago · NEW · open in Gerrit ↗
commit message
LU-20690 ec: store EC parity like RAID10
The k >= p restriction is not a Cauchy/ISA-L limit. It comes from
storing parity as RAID0|PARITY: the p parity objects of a raidset are
concatenated along the file offset, so raidset_count * p * stripe_size
does not fit in a finite PFL extent when p > k (for example
--ec 2+3 -E 2M). This patch changes the parity layout; the p <= k
checks in lfs and llapi stay until a following patch removes them.
Store EC parity as LOV_PATTERN_PARITY instead. A raidset is an EC
split of the stripe set, and the layout is like RAID10 in that it has
the same two axes:
- across the raidsets of one stripe set: like RAID0, one
stripe_size per raidset;
- within one raidset: like RAID1, the p parity stripes share one
file offset (the same object_off).
The RAID1 axis comes from recovery. A raidset of k data and p parity
stripes survives the loss of any p of its k + p stripes, just as a
RAID1 of p + 1 copies survives the loss of any p copies. RAID1 is the
k == 1 case, where each parity is a copy of the data (--ec 1+N). The
p parities protect the same data, so they share its offset: the
offset says which data is protected, the parity index says which
redundancy unit it is.
What differs from RAID1 is I/O, not the role. For k > 1 the parities
are not replicas: each holds a different parity, and a lost stripe is
rebuilt from any k survivors rather than copied from one. The parity
uses the extent of the data component.
RAID0 places data rows from file offset 0, whereas counting EC rows
and raidsets from e_start groups the wrong k stripes when e_start is
not a multiple of the data stripe width: the stripes EC groups as one
raidset are not the objects lod paired with that raidset's parity
OSTs, and a degraded read rebuilds a lost stripe from the wrong
parity. For example -E 4M -c 1 -E eof -S 1M -c 8 --ec 4+1 puts offset
4M on object 4 (raidset 1), which counting from e_start encodes into
the parity of raidset 0. When e_start is not a multiple of
stripe_size, as after a 64K DoM component, counting stripe_size
parity slots from e_start also splits stripes at
e_start + n * stripe_size and overflows e_end.
Count rows and raidsets from file offset 0, as RAID0 maps the data
objects:
row = off / (stripe_count * stripe_size)
ec_off = O
+ (row - row of e_start) * raidset_count * stripe_size
+ raidset * stripe_size + off % stripe_size
Data before e_start is taken as zero, and so is its parity, which is
not stored: the origin O moves back from e_start over the raidsets of
the first row that end before e_start, and over the part of the
raidset of e_start below e_start % stripe_size when e_start is in its
last data stripe. slot % raidset_count stays the raidset, so the
parity OSTs lod pairs are unchanged, and every stored parity byte has
data in the component. Common DoM and PFL layouts with an unaligned
e_start are supported and keep their parity within [e_start, e_end),
such as:
- -E 64K -L mdt -E 1M -c 1 -S 1M -E eof -c 4 -S 4M --ec 4+2;
- -E 64K -L mdt -E 16M -c 2 -S 1M -E eof -c 4 -S 4M --ec 2+2;
- -E 64K -L mdt -E eof -c 4 -S 1M --ec 2+2;
- -E 1M -c 1 -S 1M -E 64M -c 1 -S 4M -E eof -c 4 -S 4M --ec 4+2.
When every raidset has one data stripe (--ec 1+N, or one data
stripe), there is one parity slot per data stripe and nothing to
pack, so rows and O count from file offset 0, as RAID0 does: ec_off
is the data offset, and each parity object is a copy of its data
object at the same object offsets, so it can stand in for it.
Otherwise O depends only on e_start, the data stripe count, k and the
stripe size, not on e_end, and when e_start is a multiple of the
stripe width, O is e_start.
Add ec_raidset_count(), ec_raidset_first(), ec_stripe_to_raidset()
and ec_off_to_raidset_offset() next to ec_split_stripes() in
lustre_user.h, and struct ec_parity_geom with ec_parity_geom_init(),
ec_data_to_parity() and its inverse ec_parity_to_data(), with
ec_parity_width() for the parity bytes of one stripe set, and use
them in lov, lod and llapi instead of open-coding the k0 * n0 split.
ec_parity_geom_init() also records the data row of parity slot 0 in
epg_row0 (0 for 1-data raidsets).
lov caches O in lsme_parity_origin when the layout is unpacked and
returns it from lsme_stripe_origin(), and lov_parity_geom_init()
fails a degraded read whose pair does not match in stripe size,
raidsets or origin; the parity mirror EOF of such a pair is also
bounded by one parity row per stripe set from e_start. Raidset
objects before e_start read as zero in degraded reads and resync.
A read is widened to whole raid sets, but not past the e_end of its
component, so a read ending there does not start an empty recovery
cycle for the next component's first raid set, which may begin before
its e_start.
lsme_parity_raid10() now just returns lsme_is_parity(), as every
parity component is LOV_PATTERN_PARITY, and
lsme_parity_slots_per_raidset() is dropped.
A component shorter than one stripe (e_end < e_start + stripe_size)
whose raidset continues past e_end (e.g. [64K, 1M) with -S 1M -c 2
--ec 2+2, or [1M, 4M) with -S 4M -c 2 --ec 2+2, where the second
stripe is never reached) still has no room for a full stripe_size
parity slot from e_start. ec_parity_fits() detects it:
llapi_layout_sanity() refuses it with LSE_EC_PARITY_FIT,
llapi_ec_check_comp_match() refuses to resync or verify it, and
lod_comp_prep_create() checks it again with the final data stripe
count, also for lfs mirror extend --ec.
The lov slot geometry, the STRIPE I/O scope and the per-stripe llapi
helpers were added by the previous patches and only take effect for
LOV_PATTERN_PARITY. This patch switches the encoding so they apply:
llapi_pattern_to_lov() and llapi_layout_to_lum() emit
LOV_PATTERN_PARITY, lov_pattern_supported() accepts it in place of
RAID0|PARITY (and lov_pattern_available() via that), and lod allocates
and verifies parity components with it. EC has not shipped, so the old
combination is not kept. Finite-extent stripe-count shrinking, now in
one lod_comp_shrink_to_extent() helper instead of three copies, is
skipped for parity components. lsm_unpackmd_comp_md_v1() and
lod_verify_striping() reject a component whose LCME_FL_PARITY flag and
LOV_PATTERN_PARITY disagree, since the parity geometry follows the
flag.
vvp_prep_size() no longer writes KMS into i_size for parity I/O.
ci_parity_eof is derived from i_size, and KMS is only a lower bound
of the data size, so a parity read within KMS shrank ci_parity_eof
for later parity I/O.
Userspace resync and verify move to the RAID10 offsets: one
stripe_size per raidset, each parity addressed by its stripe index,
leaving the part of the first parity slot below e_start alone. The
punch, zero-fill and hole verify of a parity slot are bounded by the
e_end of its component; no slot runs past e_end while
ec_parity_fits() holds, so this is only a defensive bound. Hole
punch-or-clear and hole verify loop over the p parity stripes that
share an offset when they fall back to zero-fill or zero-content
reads.
lfs setstripe --yaml parses the pattern as the comma-separated flags
lfs getstripe -y prints, so "parity,overstriped" keeps overstriping.
lfs mirror read of a parity mirror still dumps every parity object in
RAID0 order, through mirror_dump_parity() in lfs, from e_start. The
dump of a component stops at its e_end: when the extent is not a
multiple of the data stripe set, the raid sets of the last row past
e_end hold the data of the next component. The glimpse lock of such
a read spans every component, so lov_lock_sub_init() no longer
rejects a glimpse because a component the I/O does not cover has
fewer parity stripes than the designated one; lov_io_iter_init()
checks the components the I/O covers.
Example: -E 128M -c 11 -S 1M --ec 4+2
data/parity extent [0, 128M)
raidsets [4,2], [4,2], [3,2] (raidset_count=3)
parity has 6 OST objects
one data stripe set = 11M
one parity stripe set = 3M (not 1M flat, not 6M concat)
stripeset raidset data_pos ec_off concat objects
--------- ------- ----------- ------- ------- -------
0 0 [0, 4M) 0 0 0,1
0 1 [4M, 8M) 1M 2M 2,3
0 2 [8M, 11M) 2M 4M 4,5
1 0 [11M, 15M) 3M 6M 0,1
1 1 [15M, 19M) 4M 8M 2,3
1 2 [19M, 22M) 5M 10M 4,5
The concat column is what RAID0|PARITY would have used, and is what
overflows a finite extent when p > k.
Tests: sanity-ec 12c/12d/34c cover
holes and multi-raidset offsets, 30d and 31b-31e check the parity dump
size, 34d dumps a mixed-p mirror whose first extent is not a multiple
of the stripe set, 63d recovers reads from parity of raidset 1 in a
PFL component that does not start at 0, 301 covers an e_start that
stripe_size does not divide and checks that a component whose parity
would pass e_end is refused for that reason, 302 resyncs, verifies and
reads degraded common PFL layouts with an unaligned e_start, 303
recovers reads when e_start is not a multiple of the stripe width,
with equal and unequal raidsets, 304 covers zero-fill before e_start,
305 truncates at raidset and unaligned component boundaries, and 306
reads degraded across a component boundary where the raid set of the
first component runs into the next one.
llapi_layout_test asserts the component pattern is LLAPI_LAYOUT_PARITY
and 68 checks the parity placement over a range of geometries and
extents, and that 1-data raidset copies are at the data object
offsets.
Test-Parameters: testlist=sanity-ec ostcount=8
Test-Parameters: testlist=sanity-ec ostcount=8 fstype=zfs
Signed-off-by: Keguang Xu <kxu@ddn.com>
Signed-off-by: Ronnie Sahlberg <rsahlberg@whamcloud.com>
Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com>
Assisted-by: Cursor:Composer/Opus5.5 llm_code_and_review_tools
Assisted-by: ClaudeCode:claude-opus-5-5 ltvm llm_code_and_review_tools
Assisted-by: ClaudeCode:claude-fable-5-1 llm_code_and_review_tools
Change-Id: I9574df44969ddd40776f028b3c326d150ea08eb5
70489
master
J –B ✓T …R 0/2
LU-20690 lov: check designated stripe in mirror init
build OK — testing in progress (typically 6–14h)
pt_ecro
M +33 −22
31m
LU-20690 lov: check designated stripe in mirror init
build OK — testing in progress (typically 6–14h)
pt_ecro
M +33 −22
31m
tags: pt_ecro
owner Keguang Xu · uploader Keguang Xu · PS1 uploaded 1h ago · NEW · open in Gerrit ↗
commit message
LU-20690 lov: check designated stripe in mirror init Designated-stripe validation for RAID10-like EC parity was repeated in lov_io_iter_init(), lov_io_lru_reserve() and lov_lock_sub_init(), and rejected CIT_FAULT wholesale. Check covered components once in lov_io_mirror_init(). Reject buffered designated parity I/O in lov_page_init_composite() because the page cache is shared with data. Test-Parameters: testlist=sanity-ec ostcount=8 Assisted-by: Cursor:Composer Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: Ie52af72d7afbf4943259c2c8e84078ee73c8942a
69703
master
J –B ✓T …R +2/2
LU-20690 ec: verify parity against data, allow p > k
build OK — testing in progress (typically 6–14h)
raid10-like218_review_prioritypw_shepherdpt_ecro
L +456 −218
3h
LU-20690 ec: verify parity against data, allow p > k
build OK — testing in progress (typically 6–14h)
raid10-like218_review_prioritypw_shepherdpt_ecro
L +456 −218
3h
reviews:
Ronnie Sahlberg +1 · Andreas Dilger +1
no vote yet: Marc Vef
patchsets:
PS2 10-15
PS3 10-26
PS4 11-02
PS5 11-04
PS6 11-04 Andreas Dilger
+1 earlier
PS1 10-15tags: raid10-like 218_review_priority pw_shepherd pt_ecro
owner Keguang Xu · uploader Andreas Dilger · PS6 uploaded 9h ago · NEW · open in Gerrit ↗
commit message
LU-20690 ec: verify parity against data, allow p > k With the RAID10-like parity layout the p parities of a raidset share one offset, so the parity of a component fits in its extent whatever p is. Remove the p <= k checks in lfs and llapi; k+p <= 256 and p <= 15 remain. Also drop the mirror-extend stripe_count < p guard in ec_check_data_comp() so --ec 2+3 works on a two-stripe target. An instantiated parity is checked against its data component in lod_verify_ec_parity_comps(), using lod_comp_find_linked() for the same pairing rule as the allocator. A parity with linked data needs a bidirectional link, matching k/p and stripe size, and parity stripe count ec_raidset_count() * p. A parity whose data mirror was split off or deleted has no linked data and is skipped. A mismatch fails a layout from the user or replay in lod_use_defined_striping(), but is only logged for a layout loaded from disk by lod_parse_striping(), so an existing file with a bad parity can still be opened and removed. lod_verify_striping() checks k/p and rejects an instantiated parity with stripe_count == 0 before DEFINED object init. Also skip instantiating a parity in lod_declare_instantiate_components() when its linked data is still uninit and not in the same instantiate list. A mirror-targeted RESYNC lease walks every component of the named mirror, and would otherwise leave INIT parity over uninit PFL data that lod_verify_ec_parity_comps() then rejects. Tests: sanity-ec 4a and 10 accept p > k, and 4b rejects k == 0 and k > 255. 8d no longer expects narrow components or -c 5 --ec 4+3 to be refused. 8m covers mirror extend --ec 2+3 on a two-stripe target. 8n covers a mirror-targeted RESYNC lease that must not INIT parity over uninit PFL data. 8o covers PFL -E 2M --ec 2+3 create/resync/verify, and 8p covers p > k multi-raidset create/resync/verify. llapi_layout_test test47 allows 3+4. Test-Parameters: testlist=sanity-ec ostcount=8 Signed-off-by: Keguang Xu <kxu@ddn.com> Assisted-by: Cursor:Composer llm_code_and_review_tools Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com> Assisted-by: ClaudeCode:claude-opus-5-5 ltvm llm_code_and_review_tools Change-Id: I3878502e8ff739cb5ed420ff359e2008376303e7
▶Needs reviewers
(1)
69074
master
J ✗47B ✓T ✓R 0/2
LU-20354 tests: extra QMT usage-cache coverage
CI green, no reviews yet — add reviewers
M +218 −0
45d
LU-20354 tests: extra QMT usage-cache coverage
CI green, no reviews yet — add reviewers
M +218 −0
45d
janitor flagged test failures unique to this patch — superseded (tests have since passed) — full janitor results
| unique failing test | history |
|---|---|
| sanity-quota@ldiskfs+DNE:test_1j | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_3a | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_3b | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_3c | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_5 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_6 | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_7a | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_7b | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_7c | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_17 | seen in 7 other reviews |
| sanity-quota@ldiskfs+DNE:test_25 | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_33 | seen in 5 other reviews |
| sanity-quota@ldiskfs+DNE:test_34 | seen in 5 other reviews |
| sanity-quota@ldiskfs+DNE:test_35 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_37 | seen in 5 other reviews |
| sanity-quota@ldiskfs+DNE:test_38 | seen in 5 other reviews |
| sanity-quota@ldiskfs+DNE:test_40c | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_64 | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_67 | seen in 1 other review |
| sanity-quota@ldiskfs+DNE:test_71a | seen in 3 other reviews |
| sanity-quota@ldiskfs+DNE:test_71b | seen in 3 other reviews |
| sanity-quota@ldiskfs+DNE:test_72 | seen in 3 other reviews |
| sanity-quota@ldiskfs+DNE:test_73a | seen in 7 other reviews |
| sanity-quota@ldiskfs+DNE:test_75 | seen in 7 other reviews |
| sanity-quota@ldiskfs+DNE:test_78A | NEW unique failure for this branch in the last 30 days, and was seen 0 times across 0 other branches 0 reviews |
| sanity-quota@ldiskfs+DNE:test_80 | seen in 2 other reviews |
| sanity-quota@zfs:test_1j | seen in 1 other review |
| sanity-quota@zfs:test_3a | seen in 1 other review |
| sanity-quota@zfs:test_3b | seen in 1 other review |
| sanity-quota@zfs:test_3c | seen in 1 other review |
| sanity-quota@zfs:test_5 | seen in 1 other review |
| sanity-quota@zfs:test_6 | seen in 1 other review |
| sanity-quota@zfs:test_7a | seen in 1 other review |
| sanity-quota@zfs:test_7b | seen in 1 other review |
| sanity-quota@zfs:test_7c | seen in 1 other review |
| sanity-quota@zfs:test_16a | seen in 2 other reviews |
| sanity-quota@zfs:test_17 | seen in 35 other reviews |
| sanity-quota@zfs:test_25 | seen in 28 other reviews |
| sanity-quota@zfs:test_33 | seen in 34 other reviews |
| sanity-quota@zfs:test_34 | seen in 34 other reviews |
| sanity-quota@zfs:test_35 | seen in 1 other review |
| sanity-quota@zfs:test_37 | seen in 34 other reviews |
| sanity-quota@zfs:test_38 | seen in 34 other reviews |
| sanity-quota@zfs:test_64 | seen in 2 other reviews |
| sanity-quota@zfs:test_72 | seen in 15 other reviews |
| sanity-quota@zfs:test_73a | seen in 18 other reviews |
| sanity-quota@zfs:test_75 | seen in 8 other reviews |
patchsets:
PS1 09-20
PS2 09-20
owner Keguang Xu · uploader Keguang Xu · PS2 uploaded 46d ago · NEW · open in Gerrit ↗
commit message
LU-20354 tests: extra QMT usage-cache coverage Add sanity-quota 313-316 on top of the LQA GETOUSAGES path in 312. 313 covers per-ID TTL hit/expire/ttl=0. 314 reconciles QMT aggregates with per-slave GETOQUOTA. 315 checks granted fallback versus LQA abort when an OSP is down. 316 invalidates LQA cache after range add/remove. Test-Parameters: trivial Assisted-by: Cursor:Grok-4.6 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: I36ced70e821e49d7376c21705122c8e9ba6ffbad
▶Waiting on reviewers
(0)
nothing here right now
▶Ready to land
(3)
69517
master
J –B ✓T ✓R +2/2
LU-20690 ec: implement STRIPE I/O scope
all green — ready to land (not in master-next yet)
raid10-like218_review_blockerpt_ecro218_review_prioritypw_shepherd
2 unresolved
L +455 −99
1h
LU-20690 ec: implement STRIPE I/O scope
all green — ready to land (not in master-next yet)
raid10-like218_review_blockerpt_ecro218_review_prioritypw_shepherd
2 unresolved
L +455 −99
1h
all green — ready to land (not in master-next yet)
2 reviewer comment(s) to address if a respin is needed — last from Marc Vef
build #134549 SUCCESS · tests all Maloo sessions
reviews:
Ronnie Sahlberg +1 · Andreas Dilger +1
no vote yet: Marc Vef, Zhenyu Xu
patchsets:
PS5 10-17
PS6 10-22 Marc Vef
PS7 10-23
PS8 10-27
PS9 10-27
+4 earlier
PS1 10-08 PS2 10-10 PS3 10-13 PS4 10-14threads: 2 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Marc Vef patchset comment — I think there is a slight misunderstanding. The diagram puts each raidset's parity at the data offset of the raidset's first stripe. So, (0,
Ronnie Sahlberg
I attach an ASCII diagram of the layout, I this should go into ec.txt : === -c 8 -S ss --ec 4x2 Stripe size is ss 8 stripes per Stripe Set 2 Raid Sets, each 4 data stripes. 2 Parities, each with 2 stripes The SCOPE_STRIPE objects are conceptually sparse. Parity data is aligned to the same offset as the first data stripe in the raidset they protect. +-----------+----------+-----------------+-----------------+ | OFFSET | DATA | PARITY P0 | PARITY P1 | | | (1 obj | ci_designated_ | ci_designated_ | | | each) | stripe = 0 | stripe = 1 | +-----------+----------+-----------------+-----------------+ | 0 | d0 | phys stripe 0 | phys stripe 1 | \ \ | ss | d1 | | | | R 0 | | 2*ss | d2 | | | | | | 3*ss | d3 | | | / | +-----------+----------+-----------------+-----------------+ | S 0 | 4*ss | d4 | phys stripe 2 | phys stripe 3 | \ | | 5*ss | d5 | | | | R 1 | | 6*ss | d6 | | | | | | 7*ss | d7 | | | / / +-----------+----------+-----------------+-----------------+ | 8*ss | d0 | phys stripe 0 | phys stripe 1 | \ \ | 9*ss | d1 | | | | R 0 | | 10*ss | d2 | | | | | S 1 | 11*ss | d3 | | | / | +-----------+----------+-----------------+-----------------+ ... === I like that you align the parity stripe offset into the SCOPE_STRIPE P* "mirror" to the same offset as the first data stripe of the raidset it protects. That makes it trivial to map between a raidset offset and where the corresponding parity data is laid out. But it does however also mean that if an application wants to read all the parity data it would have to be aware of the ec geometry so that it could compute the stride between the individual parity stripes. You can't just "open, SCOPE_STRIPE(P0) then read all the data from offset 0 to eof and you have all the parity data for P0. Should it perhaps in the future also plug into faking SEEK_DATA/SEEK_HOLE for this so [0, ss[ would be DATA and [ss,4*ss[ would be HOLE ? I think that would be very useful for applications that would like to use this API as it would somewhat reduce the need to be ec-geometry-aware when reading from SCOPE_STRIPE. But that could be added much later.
Marc Vef
I think there is a slight misunderstanding. The diagram puts each raidset's parity at the data offset of the raidset's first stripe. So, (0, 4·ss, 8·ss) with holes.
But, the code packs them one stripe size apart (0, 1·ss, 2·ss). Keguang described this in more detail in LU-20690 ec: like-RAID10 parity layout | https://review.whamcloud.com/c/fs/lustre-release/+/68361 where he updated ec.txt. And Section 3 (of ec.txt) describes this. This matches what `lov_offset.c` does in 69516 (previous patch).
from ec.txt in 68361:
```
parity-offset = stripeset * raidset-count * stripe-size
+ raid-set * stripe-size
parity-object = raid-set * number-of-parities
```
This means a reader with a fixed index gets all of that parity back to back without holes
reply Gerrit AI review for Lustre lov_io.c:1319 — (style) Carried over from patchset 8, where it was Acknowledged: this isn't a bug, but this branch runs only for truncate. A truncate is nev
Gerrit AI review for Lustre
(style) Carried over from patchset 8, where it was Acknowledged: this isn't a bug, but this branch runs only for truncate. A truncate is never CIT_READ/CIT_WRITE, so lov_foreach_io_stripe() always visits every stripe here. If the patch is refreshed, the plain `for (stripe = 0; stripe < r0->lo_nr; stripe++)` loop would keep the churn, and conflicts with the EC read patches, smaller.
tags: raid10-like 218_review_blocker pt_ecro 218_review_priority pw_shepherd
owner Keguang Xu · uploader Keguang Xu · PS9 uploaded 8d ago · NEW · open in Gerrit ↗
commit message
LU-20690 ec: implement STRIPE I/O scope In the RAID10-like EC parity layout the p stripes of a raidset share one file offset but hold different data, so read and write must name one of them. Implement LL_IO_SCOPE_STRIPE for that. ll_io_scope_validate() accepts STRIPE with ios_mirror_id in [1, MIRROR_ID_MAX] and ios_stripe_idx below LOV_EC_MAX_CODING_STRIPES. ios_stripe_idx must be 0 for FILE and MIRROR. It is not checked against p here: the scope outlives the layout and the I/O type is not known yet. ll_io_scope_init() handles STRIPE like MIRROR and, for STRIPE, copies ios_stripe_idx into cl_io::ci_designated_stripe and sets ci_designated_stripe_set. OBJECT stays reserved. ci_designated_stripe is an unsigned index. 0 is a valid stripe, so ci_designated_stripe_set says whether it is in use. A zeroed cl_io is unset. The index is meaningful only with ci_designated_mirror set. lov visits only the stripes an I/O touches through lov_foreach_io_stripe(), and maps an offset to a stripe through lov_io_stripe_number(). On a parity component, read and write use only the designated stripe of each raidset and fail with -EINVAL if it is unset or not less than p. Punch, truncate, fallocate and lseek reach every stripe and ignore the index, so a leftover STRIPE scope does not fail them. These helpers target the bare LOV_PATTERN_PARITY encoding for stripe picking. lov_page_init_composite() also refuses CPT_CACHEABLE pages when ci_designated_mirror is set on any parity component (lsm_entry_is_parity()), including RAID0|PARITY. That covers MIRROR and STRIPE scopes and LL_IOC_FLR_SET_MIRROR: a designated parity read that falls back to the page cache (fcntl clears O_DIRECT, or a short O_DIRECT read finished through the cache) returns -EINVAL. sanity-ec test_312 checks that case. llapi_io_scope_set(3) and the uapi comment document STRIPE, and that ios_layout_version 0 uses the fd version from the last lease release or resync lease. LL_IOC_SET_IO_SCOPE reuses nr 177 with LL_IOC_FLR_SET_MIRROR (different size) to save an ioctl number. sanity-flr test_213a checks the ioctl limits for FILE, MIRROR and STRIPE, that OBJECT stays reserved, that mirror resync still goes through the SET_MIRROR alias, and that a STRIPE read of a non-parity mirror ignores the index. sanity-ec test_311 checks that lseek, truncate and fallocate succeed for any index, and skips below 6 OSTs. io_scope gains -b, -x, -r, -t, -f and -l for that. Test-Parameters: testlist=sanity-flr Test-Parameters: testlist=sanity-ec ostcount=8 Assisted-by: Cursor:Composer-2 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: Ia8c9e729df4f8651ac4f9dad88d4aef8b056100d
66882
master
J –B ✓T ✓R +2/2
LU-20211 mdt: trunc(0) layout replace on inactive stripes
all green — ready to land (not in master-next yet)
218_review_prioritypw_shepherdpt_ecro
3 unresolved
XL +1320 −64
11h
LU-20211 mdt: trunc(0) layout replace on inactive stripes
all green — ready to land (not in master-next yet)
218_review_prioritypw_shepherdpt_ecro
3 unresolved
XL +1320 −64
11h
all green — ready to land (not in master-next yet)
3 reviewer comment(s) to address if a respin is needed — last from Ronnie Sahlberg
build #135174 SUCCESS · tests all Maloo sessions
reviews:
Andreas Dilger +1 · Zhenyu Xu +1
no vote yet: Ronnie Sahlberg, Qian Yingjin, Marc Vef
patchsets:
PS41 10-28
PS42 10-30
PS43 11-02 Andreas Dilger
PS44 11-02 Andreas Dilger
PS45 11-02 Andreas Dilger
+29 earlier
PS1 06-26 PS13 07-27 PS14 07-28 PS15 07-31 PS16 08-05 PS17 08-06 PS18 08-07 PS19 08-12 PS20 08-20 PS21 08-25 PS22 08-25 PS23 09-02 PS24 09-08 PS25 09-08 PS26 09-09 PS27 09-11 PS28 09-17 PS29 10-08 Andreas Dilger PS30 10-08 Andreas Dilger PS31 10-08 Andreas Dilger PS32 10-12 PS33 10-12 PS34 10-13 Andreas Dilger PS35 10-15 Andreas Dilger PS36 10-15 Andreas Dilger PS37 10-16 Andreas Dilger PS38 10-19 Andreas Dilger PS39 10-22 Andreas Dilger PS40 10-26 Andreas Dilgerthreads: 3 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Ronnie Sahlberg cl_object.h:226 — Or change CL_FSYNC_LOCAL = 0 and a BUILD_BUG_ON(CL_FSYNC_LOCAL != 0) would make it safe if future code blindly clears the conf where t
Ronnie Sahlberg
The risk is for future code. A new layout-change caller that just zeroes conf would get CL_FSYNC_NONE without anyone noticing. Prune would start writeback but not wait for it, and the old layout would be torn down while dirty pages were still being written to its objects. The likely result is lost or misdirected writes, or crashes and assertion failures during cleanup. The code compiles fine and nothing warns, so this would be hard to trace back to the missing field.
Ronnie Sahlberg
Or change CL_FSYNC_LOCAL = 0 and a BUILD_BUG_ON(CL_FSYNC_LOCAL != 0) would make it safe if future code blindly clears the conf where this enum is embedded.
reply Gerrit AI review for Lustre mdd_object.c:4453 — (style) This isn't a bug, but the kernel-doc for this non-static function does not describe @env, @obj or @mlc, and has no Return: section.
Gerrit AI review for Lustre
(style) This isn't a bug, but the kernel-doc for this non-static function does not describe @env, @obj or @mlc, and has no Return: section. `kernel-doc -v` warns about all three parameters. If the patch is refreshed, consider adding them.
reply Gerrit AI review for Lustre mdt_reint.c:955 — (defect) Can the victim's new layout land on the same OST that lod_ost_offline() just reported as offline?
Gerrit AI review for Lustre
(defect) Can the victim's new layout land on the same OST that lod_ost_offline() just reported as offline?
The template keeps the source stripe count as an assigned count, so lod_stripe_count_min() requires all of it. A stopped OST is not excluded by the allocator. osp_statfs() returns -EAGAIN for a DISCON import, lod_statfs_and_check() keeps it active, and the last RR pass accepts it:
lod_ost_alloc_qos() -> -EAGAIN (too few good OSTs)
lod_ost_alloc_rr(): speed == 2, connecting -> rc = 0
osp_precreate_reserve(): opd_pre_status -ENODEV, objects still in the pool -> success
The reserve hands out a precreated object without contacting the OST. Take 4 OSTs, a file created with `-c -1` and OST0 stopped. trunc(0) instantiates 4 stripes with one on OST0, swaps, bumps the generation and replies MS_LAYOUT_REPLACED. The client's punch of the new object then blocks on OST0, the same hang this patch is meant to avoid. The swap and the new objects are wasted as well. The comment in sanity-flr test_50e ("RR last-resort may place on the DISCONN OST") suggests this was seen in testing.
Would it work to run mo_layout_check(MD_LAYOUT_UNAVAILABLE) on the victim after mo_layout_change() and skip the swap if it still reports an unavailable stripe? setattr would then fall back to the normal trunc(0), as the commit message describes for allocation failures.
tags: 218_review_priority pw_shepherd pt_ecro
owner Keguang Xu · uploader Andreas Dilger · PS45 uploaded 3d ago · NEW · open in Gerrit ↗
commit message
LU-20211 mdt: trunc(0) layout replace on inactive stripes When truncate(0) hits a file whose layout references deactivated or disconnected OSTs, and the client advertises OBD_CONNECT2_LAYOUT_REPLACE, replace the layout: move the old layout onto a volatile victim and instantiate a fresh layout on the file from the existing pattern via QoS/RR. A full or read-only OST is still usable and does not trigger this. If the new layout cannot be allocated, keep the old layout and do a normal trunc(0). Skip it for a lease holder (MDS_TRUNC_KEEP_LEASE): lfs mirror resync and copy truncate only one mirror, and the in-sync mirror must stay. An OST is offline if it was deactivated or its OSP import is not connected, which is checked directly since LOD only learns of the disconnection at its next statfs refresh. After the layout swap, do not update the parent FID of the volatile victim's objects, which are destroyed on close, nor of any object on an offline OST. That update reads the object's filter_fid first, and the RPC would wait for an unreachable OST while LAYOUT EX is held. An OST that reconnects between the declare and execute passes is also skipped at execute, since no OSP sub-transaction was declared for it. Skip replace when any component has LCME_FL_NOSYNC. That flag freezes the mirror's existing objects; swap would discard the snapshot. The NOSYNC test runs once, inside mdt_replace_unavailable_layout(), which returns 0 so setattr falls through to a normal trunc(0). mdt_reint_setattr() does not check NOSYNC. It probes for an unavailable layout before mdt_attr_set() and without a DLM lock, so a healthy trunc(0) skips LAYOUT EX. If the probe finds one, mdt_attr_set() takes UPDATE|LAYOUT|XATTR EX in a single enqueue and replaces the layout under it. A second lock on the file while the saved UPDATE lock is held could queue behind a setxattr waiting for both, and deadlock (LU-3601). The unavailable-stripe result is re-checked under the lock, so a concurrent trunc(0) that already replaced the layout does not allocate a second set of objects. Extend the layout API with MD_LAYOUT_UNAVAILABLE (detect stripes on offline OSTs) and MD_LAYOUT_INSTANTIATE (allocate from a source pattern). Add lod_generate_lovea_template() to emit uninstantiated LOVEA templates that omit placement hints so new stripes use QoS/RR, and trigger replacement from mdt_reint_setattr() via mdt_replace_unavailable_layout(). Layout-type handling for templates / instantiate: - DoM: never carries OST objects; force stripe_count to 0 and skip the OST object array so LOVEA size matches INIT DoM. - PFL/DoM: keep the DoM component and replace only OST components. - SEL: coerce LOV_MAGIC_SEL to COMP_V1 for lod_qos_parse_config(); keep LCME_FL_EXTENSION and restamp SEL when LOVEA is written. - EC: re-emit bound data/parity as unbound (IS_LINK_ID + shared link id) so lod_qos_prep_create() can pair before component IDs exist. Layout replace creates a volatile victim via mdt_orphan_open(). Set mlc_no_inherit on MD_LAYOUT_INSTANTIATE so the new layout does not inherit the local ROOT default pool from the orphan parent. Zero mti_spec first defensively before the volatile create; mdt_thread_info_reset() already clears it per request, and setattr does not leave create state there. After a successful swap, sync the object before replying so the new layout is durable; replay skips replace. On success, return MS_LAYOUT_REPLACED (with OBD_MD_FLEASIZE) in the setattr reply so the client applies the new LOVEA. Before applying it, the client discards its dirty pages past the returned size (all of them for trunc(0)), so prune does not write them back to unavailable OSTs. This lets a later server replace only the OST objects past a non-zero truncate size. The client reserves the default layout size in the setattr reply buffer of any truncate. A resent trunc(0) setattr (lost or truncated reply) returns the current layout with MS_LAYOUT_REPLACED, whether or not the original request replaced it; the client ignores a layout whose generation is unchanged. Add sanity/test_27xt (plain, PFL/DoM, SEL), sanity-ec/test_74b (EC), and sanity-flr/test_50e (mirrors, resync), which stop the OST. Add sanity/test_27xv, which holds the replace with OBD_FAIL_MDS_LAYOUT_REPLACE_PAUSE while a setxattr from a second mount waits for the file, with sync_lock_cancel=never so the saved UPDATE lock stays PW, to check for the deadlock. Test-Parameters: testlist=sanity serverversion=2.17 env=SANITY_EXCEPT="24D 27D" Test-Parameters: testlist=sanity-flr ostcount=5 serverversion=2.17 env=SANITY_FLR_EXCEPT="0a 34b" Test-Parameters: testlist=sanity clientversion=2.17 Assisted-by: Cursor:Grok-4.6 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com> Assisted-by: ClaudeCode:claude-opus-5.5 ltvm,llm_code_and_review_tools Assisted-by: Cursor:Composer Change-Id: I07e0792a51e144d935cece4b028e17f659e4ccfd
69575
master
J –B ✓T ✓R +2/2
LU-20690 utils: add EC parity-stripe I/O helpers
all green — ready to land (not in master-next yet)
218_review_priorityraid10-like218_review_blockerpt_ecro
1 unresolved
L +244 −115
2d
LU-20690 utils: add EC parity-stripe I/O helpers
all green — ready to land (not in master-next yet)
218_review_priorityraid10-like218_review_blockerpt_ecro
1 unresolved
L +244 −115
2d
all green — ready to land (not in master-next yet)
1 reviewer comment(s) to address if a respin is needed — last from Gerrit AI review for Lustre
build #134756 SUCCESS · tests all Maloo sessions
reviews:
Ronnie Sahlberg +1 · Andreas Dilger +1
no vote yet: Marc Vef
patchsets:
PS4 10-23
PS5 10-23
PS6 10-23
PS7 10-29 Ronnie Sahlberg
PS8 10-29 Ronnie Sahlberg
+3 earlier
PS1 10-11 PS2 10-13 PS3 10-14threads: 1 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre lfs.c:17527 — (suggestion) 'lfs mirror write' now refuses a parity mirror, but 'lfs mirror copy' still writes into one. 'lfs mirror copy -i1 -o<parity_id>
Gerrit AI review for Lustre
(suggestion) 'lfs mirror write' now refuses a parity mirror, but 'lfs mirror copy' still writes into one. 'lfs mirror copy -i1 -o<parity_id>' does, and so does the documented '-o -1' form, because get_other_mirror_ids() collects every mirror including parity. The path is llapi_mirror_copy_many() -> llapi_mirror_write(), which overwrites the parity with raw data. LL_LEASE_RESYNC_DONE then marks that mirror in sync, so it is the same corruption the new write check prevents. This predates the patch. verify_mirror_id_by_fd() now returns is_parity, though, so this call site could reject an explicit parity target, and the -1 case could skip parity mirrors. If the patch is refreshed, or in a follow-on, consider doing that.
tags: 218_review_priority raid10-like 218_review_blocker pt_ecro
owner Keguang Xu · uploader Ronnie Sahlberg · PS8 uploaded 7d ago · NEW · open in Gerrit ↗
commit message
LU-20690 utils: add EC parity-stripe I/O helpers Prepare userspace for the RAID10-like EC parity layout, where the p parity stripes of a raidset share one file offset and must be addressed by (pos, parity index) through LL_IO_SCOPE_STRIPE. Add internal llapi_mirror_read_parity() and llapi_mirror_write_parity() (lustreapi_internal.h, not lustreapi.h), which pin the I/O to one parity stripe with LL_IO_SCOPE_STRIPE. They share the pread/pwrite loop of llapi_mirror_read() and llapi_mirror_write(). llapi_ec_write_parities() and llapi_ec_verify_parities() take the parity component instead of stripe size and id, and do parity I/O through the _parity helpers. Offsets are unchanged: parity i is still at ec_pos + i * stripe_size. With the current RAID0|PARITY encoding lov ignores the designated stripe, so resync and verify behave as before. The zero-fill fallback of parity punch, the hole check of verify, and 'lfs mirror read' and 'lfs mirror copy' of a parity mirror still use mirror I/O; they need the same change before the RAID10 layout is enabled. Add llapi_layout_is_parity_mirror() to the public API and use it in lfs in place of its own is_parity_mirror() and mirror id lookup. 'lfs mirror write' now refuses a parity mirror and points to 'lfs mirror resync'. Test-Parameters: testlist=sanity-ec ostcount=8 Signed-off-by: Keguang Xu <kxu@ddn.com> Signed-off-by: Ronnie Sahlberg <rsahlberg@whamcloud.com> Assisted-by: Cursor:Grok-4.6/Opus5.5 llm_code_and_review_tools Assisted-by: ClaudeCode:claude-opus-5-5 Change-Id: I58eae79087e99eb6a5751919a9da17970074c215
▶Parked (WIP / self-blocked)
(4)
67998
master
J !B ✗T –R -1/2−
LU-20566 ec: reuse surviving DIO bounce pages on EC recovery
work in progress
WIP
2 unresolved
L +735 −23
11h
LU-20566 ec: reuse surviving DIO bounce pages on EC recovery
work in progress
WIP
2 unresolved
L +735 −23
11h
janitor run: 1 failing config(s), none unique to this patch — janitor results
build #129341 FAILURE
reviews:
Andreas Dilger -1
threads: 2 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Misc Code Checks Robot (Gatekeeper helper) lov_io.c:2117 — warn: lov_ec_read_stripe_pages():variable dereferenced before check 'inode' (see line 2094)
Misc Code Checks Robot (Gatekeeper helper)
warn: lov_ec_read_stripe_pages():variable dereferenced before check 'inode' (see line 2094)
reply Misc Code Checks Robot (Gatekeeper helper) cl_io.c:1462 — warn: cl_ec_reuse_take():missing conversion: 'seg->crs_index + seg->crs_npages' 'unit_page + unit_array_size'
Misc Code Checks Robot (Gatekeeper helper)
warn: cl_ec_reuse_take():missing conversion: 'seg->crs_index + seg->crs_npages' 'unit_page + unit_array_size'
owner Keguang Xu · uploader Keguang Xu · PS1 uploaded 83d ago · NEW · open in Gerrit ↗
commit message
LU-20566 ec: reuse surviving DIO bounce pages on EC recovery When llite.*.ec_dio_reuse is enabled, preserve successfully filled unaligned DIO bounce pages across the CIT_EC_RD restart and adopt them as EC_DPG_UPTODATE so healthy stripes are not re-fetched. Layout generation is checked after locks are held; on mismatch the container is dropped and full recovery proceeds. Default off. Encrypted files, aligned DIO, and AIO are excluded from reuse. Test-Parameters: trivial Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: I2ff8c2bfc7de81ebd44aefc34fd627d8f2e630ea
67878
master
J !B ✗T –R -1/2−
LU-20566 ec: recover O_DIRECT reads with transient pages
work in progress
WIP
3 unresolved
L +649 −241
11h
LU-20566 ec: recover O_DIRECT reads with transient pages
work in progress
WIP
3 unresolved
L +649 −241
11h
janitor run: 1 failing config(s), none unique to this patch — janitor results
build #129151 FAILURE
reviews:
Andreas Dilger -1
threads: 3 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Misc Code Checks Robot (Gatekeeper helper) lov_io.c:2053 — warn: lov_ec_read_stripe_pages():variable dereferenced before check 'inode' (see line 2004)
Misc Code Checks Robot (Gatekeeper helper)
warn: lov_ec_read_stripe_pages():variable dereferenced before check 'inode' (see line 2004)
reply Misc Code Checks Robot (Gatekeeper helper) lov_io.c:3738 — warn: lov_io_ec_rd_start():potentially one past the end of array 'recov_ptrs[k]'
Misc Code Checks Robot (Gatekeeper helper)
warn: lov_io_ec_rd_start():potentially one past the end of array 'recov_ptrs[k]'
reply Misc Code Checks Robot (Gatekeeper helper) lov_io.c:3675 — warn: lov_io_ec_rd_start():potentially one past the end of array 'recov_ptrs[k]'
Misc Code Checks Robot (Gatekeeper helper)
warn: lov_io_ec_rd_start():potentially one past the end of array 'recov_ptrs[k]'
owner Keguang Xu · uploader Keguang Xu · PS2 uploaded 85d ago · NEW · open in Gerrit ↗
commit message
LU-20566 ec: recover O_DIRECT reads with transient pages Keep sync DIO EC recovery off the page cache: reconstruct into CPT_TRANSIENT pages and copy_page_to_iter() to the caller. Fall back to the buffered path when native allocation or encryption bounce pages are unavailable. AIO EC recovery remains unsupported. Successful and failed data-stripe submits keep non-owning out_pages[] aliases for reconstruction; ownership stays on the page list and lov_ec_forget_listed_pages() drops the aliases in rg_cleanup (buffered and DIO share this rule). Test-Parameters: trivial Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: I396daeda49c8a522b6b67f9fe618f4be9130b6d6
69511
master
J –B ✗T –R -1/2−
LU-20802 lov: add OBJECT I/O scope read and lseek
work in progress
needs rebase
WIP
2 unresolved
XL +1103 −63
4d
LU-20802 lov: add OBJECT I/O scope read and lseek
work in progress
needs rebase
WIP
2 unresolved
XL +1103 −63
4d
build #133120 FAILURE
threads: 2 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Ronnie Sahlberg patchset comment — Aside from READ and LSEEK, should this also modify fstat and friends?
Ronnie Sahlberg
Aside from READ and LSEEK, should this also modify fstat and friends? It feels like at least block-size and eof of the object would be usefule to retreive, possibly the timestamps as well.
reply Ronnie Sahlberg lov_io.c:871 — Should we check here if the object has been administratively deactivated, like osc.active=0 and fail early?
Ronnie Sahlberg
Should we check here if the object has been administratively deactivated, like osc.active=0 and fail early?
owner Keguang Xu · uploader Keguang Xu · PS2 uploaded 28d ago · NEW · open in Gerrit ↗
commit message
LU-20802 lov: add OBJECT I/O scope read and lseek Open LL_IO_SCOPE_OBJECT for O_DIRECT pread and lseek (SEEK_DATA, SEEK_HOLE, SEEK_END). The caller names one OST object by (ios_comp_id, ios_stripe_idx); pos is an offset on that object. ios_comp_id must be non-zero and stripe index 0 is valid. A non-zero ios_obj_fid only checks that the pair still names that object. FID alone is rejected. The ioctl only checks the arguments; the target is resolved on each I/O. Add ci_obj_io / ci_obj_target and a separate lov_obj_io_ops table so OBJECT I/O is one identity sub-IO. File-offset helpers (lov_io_rw_iter_init, lov_io_iter_init, lov_io_lseek_end, lov_offset.c) are unchanged. EOF is the target object's kms, a third case beside i_size and ci_parity_eof. Do not copy the FLR layout generation into ci_layout_version; ios_layout_version is checked when the caller sets it. Reject mmap, buffered read, write, truncate, and fallocate on an OBJECT-scope fd. Dead objects return -EIO without CIT_EC_RD. OBJECT is checked before the scope switch, so STRIPE can update that switch on its own. sanity-flr test_213a and test_214 cover the ioctl and object read/lseek. Test-Parameters: ignore forjanitoronly Assisted-by: Cursor:Grok-4.6/Opus5.5 llm_code_and_review_tools Assisted-by: Cursor:Grok-4.6 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: If4dd254f6d2d50a300d9c31d575565daacb89873
69075
master
J ✗46B ✓T ✗8R 0/2
LU-20354 quota: add usage_cache_clear for uid/gid/pid/LQA
work in progress
46 unique failures
WIP
1 unresolved
L +613 −0
40d
LU-20354 quota: add usage_cache_clear for uid/gid/pid/LQA
work in progress
46 unique failures
WIP
1 unresolved
L +613 −0
40d
janitor flagged test failures unique to this patch — full janitor results
| unique failing test | history |
|---|---|
| sanity-quota@ldiskfs+DNE:test_1j | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_3a | seen in 3 other reviews |
| sanity-quota@ldiskfs+DNE:test_3b | seen in 3 other reviews |
| sanity-quota@ldiskfs+DNE:test_3c | seen in 3 other reviews |
| sanity-quota@ldiskfs+DNE:test_5 | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_6 | seen in 3 other reviews |
| sanity-quota@ldiskfs+DNE:test_7a | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_7b | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_7c | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_16a | seen in 3 other reviews |
| sanity-quota@ldiskfs+DNE:test_17 | seen in 8 other reviews |
| sanity-quota@ldiskfs+DNE:test_25 | seen in 3 other reviews |
| sanity-quota@ldiskfs+DNE:test_33 | seen in 6 other reviews |
| sanity-quota@ldiskfs+DNE:test_34 | seen in 6 other reviews |
| sanity-quota@ldiskfs+DNE:test_35 | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_37 | seen in 6 other reviews |
| sanity-quota@ldiskfs+DNE:test_38 | seen in 6 other reviews |
| sanity-quota@ldiskfs+DNE:test_40c | seen in 3 other reviews |
| sanity-quota@ldiskfs+DNE:test_64 | seen in 3 other reviews |
| sanity-quota@ldiskfs+DNE:test_67 | seen in 2 other reviews |
| sanity-quota@ldiskfs+DNE:test_71a | seen in 4 other reviews |
| sanity-quota@ldiskfs+DNE:test_71b | seen in 4 other reviews |
| sanity-quota@ldiskfs+DNE:test_72 | seen in 4 other reviews |
| sanity-quota@ldiskfs+DNE:test_73a | seen in 8 other reviews |
| sanity-quota@ldiskfs+DNE:test_75 | seen in 8 other reviews |
| sanity-quota@ldiskfs+DNE:test_80 | seen in 3 other reviews |
| sanity-quota@zfs:test_1j | seen in 2 other reviews |
| sanity-quota@zfs:test_3a | seen in 2 other reviews |
| sanity-quota@zfs:test_3b | seen in 2 other reviews |
| sanity-quota@zfs:test_3c | seen in 2 other reviews |
| sanity-quota@zfs:test_5 | seen in 2 other reviews |
| sanity-quota@zfs:test_6 | seen in 2 other reviews |
| sanity-quota@zfs:test_7a | seen in 2 other reviews |
| sanity-quota@zfs:test_7b | seen in 2 other reviews |
| sanity-quota@zfs:test_7c | seen in 2 other reviews |
| sanity-quota@zfs:test_17 | seen in 36 other reviews |
| sanity-quota@zfs:test_25 | seen in 29 other reviews |
| sanity-quota@zfs:test_33 | seen in 35 other reviews |
| sanity-quota@zfs:test_34 | seen in 35 other reviews |
| sanity-quota@zfs:test_35 | seen in 2 other reviews |
| sanity-quota@zfs:test_37 | seen in 35 other reviews |
| sanity-quota@zfs:test_38 | seen in 35 other reviews |
| sanity-quota@zfs:test_64 | seen in 3 other reviews |
| sanity-quota@zfs:test_72 | seen in 16 other reviews |
| sanity-quota@zfs:test_73a | seen in 19 other reviews |
| sanity-quota@zfs:test_75 | seen in 9 other reviews |
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-part-4 | RHEL 9.7 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-part-4 | RHEL 10.1 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-3 | RHEL 9.8 / x86_64 | ran 3 tests. 1 tests failed: conf-sanity. | session |
| review-dne-zfs-part-3 | RHEL 10.1 / x86_64 | ran 3 tests. 1 tests failed: conf-sanity. | session |
| review-dne-zfs-part-4 | RHEL 9.8 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-4 | RHEL 10.1 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-7 | RHEL 9.8 / x86_64 | ran 6 tests. 1 tests failed: sanity-ec. | session |
| review-zfs | RHEL 8.10 / x86_64 | ran 8 tests. 1 tests failed: sanity-quota. | session |
build #132036 SUCCESS · tests all Maloo sessions
threads: 1 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Andreas Dilger COMMIT_MSG:16 — This is repeatedly failing sanity-quota testing, enough that the sanity-quota 33, 34, 35, ... failures are the top failing subtests in the p
Andreas Dilger
This is repeatedly failing sanity-quota testing, enough that the sanity-quota 33, 34, 35, ... failures are the top failing subtests in the past week: https://testing.whamcloud.com/search?client_branch=master&server_branch=master&status%5B%5D=FAIL&status%5B%5D=TIMEOUT&status%5B%5D=CRASH&test_set_script_id=61149410-4a46-11e0-a7f6-52540025f9af&sub_test_script_id=0ffc6336-df89-11e0-9909-52540025f9af&start_date=2026-09-14&end_date=2026-09-20&source=sub_tests#redirect For more experimental patches, please use `Test-Parameters: fortestonly testlist=sanity-quota` to run only a single session and/or `Test-Parameters: ignore forjanitoronly` so that Jenkins skips the builds and Autotest does not run at all. The Autotest queues are 2000 sessions deep, so we need to pay attention to our testing requests...
owner Keguang Xu · uploader Keguang Xu · PS1 uploaded 46d ago · NEW · open in Gerrit ↗
commit message
LU-20354 quota: add usage_cache_clear for uid/gid/pid/LQA Allow invalidating per-slave usage-cache values without dropping slots or restarting QMT, so tests and admins can force a refresh of stale ID or LQA aggregates via a write-only lprocfs parameter. LQA clear targets the shared LQA lqe (qid=1) on the DT and MD pools. Slots are marked QMT_USG_UNSET so a later sum still misses. Assisted-by: Cursor:Grok-4.6 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: Id5cbf1304ac5f200f49e184373e79ebc66a9c93e
Carrying — uploaded by me, owned by others
1 open▶Failed / broken
(1)
62497
master
J !B ✓T ✗5R -1/2−
LU-7266 ldlm: introduce pressure-based SLV
carrying kg.xu · needs rebase — checkpatch: cannot be cherry-picked
needs rebase
11 unresolved
XL +2191 −68
29d
LU-7266 ldlm: introduce pressure-based SLV
carrying kg.xu · needs rebase — checkpatch: cannot be cherry-picked
needs rebase
11 unresolved
XL +2191 −68
29d
needs rebase — checkpatch: cannot be cherry-picked
enforced failed: review-dne-zfs-part-4, review-dne-zfs-part-6, review-ldiskfs, review-ldiskfs-arm
11 unresolved thread(s) await your reply — last from kg.xu
janitor run: 1 failing config(s), none unique to this patch — janitor results
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-zfs-part-4 | RHEL 10.1 / x86_64 | ran 9 tests. 1 tests failed: sanity-quota. | session |
| review-dne-zfs-part-6 | RHEL 9.7 / x86_64 | ran 4 tests. 1 tests failed: ost-pools. | session |
| review-ldiskfs | RHEL 8.10 / x86_64 | ran 5 tests. 1 tests failed: sanity. | session |
| review-ldiskfs | RHEL 8.10 / x86_64, RHEL 9.7 / x86_64 | ran 5 tests. 1 tests failed: sanity. | session |
| review-ldiskfs-arm | RHEL 8.10 / x86_64, Rocky 9.5 / aarch64 | ran 6 tests. 1 tests failed: sanity. | session |
build #129438 SUCCESS · tests all Maloo sessions
no vote yet: Qian Yingjin, Andreas Dilger, Vitaly Fertman, Timothy Day, Patrick Farrell
patchsets:
PS24 07-14 Keguang Xu
PS25 08-08 Keguang Xu
PS26 08-09 Keguang Xu
PS27 08-15 Keguang Xu
PS28 08-15 Keguang Xu
+15 earlier
PS1 11-12 PS4 11-19 PS6 11-26 PS10 02-27 PS13 05-11 PS14 05-11 PS15 05-26 PS16 05-29 PS17 06-11 PS18 06-13 Keguang Xu PS19 06-22 Keguang Xu PS20 06-27 Keguang Xu PS21 07-13 Keguang Xu PS22 07-13 Keguang Xu PS23 07-13 Keguang Xuthreads: 11 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply kg.xu patchset comment — hhh, answer back.
Andreas Dilger
I haven't yet looked into the details of this patch, but I'm wondering if the same effect could be approximated by changing the existing SLV mechanism and values returned to the client without implementing a new protocol? I'm not against a new protocol, but having a "partial" implementation that turns on (or potentially *off*) based on the number of clients could be quite difficult to test and measure the effects. I read the concern about the new mechanism imposing more lock pressure on a small number of new clients, but it seems possible that this could still co-exist with older clients that use the existing SLV mechanism (with fixes).
Andreas Dilger
Unfortunately this comment was marked resolved without an answer.
kg.xu
hhh, answer back. > Can the same effect be approximated by changing the existing SLV values, without a new protocol? Partially yes, on the server side, we can try to drive the legacy scalar SLV from pool occupancy (pressure high → SLV lower), still returning a scalar value rather than a ratio, so existing clients can trigger cancellation without any wire-format change. However, this is only a best-effort approximation. As Wenzhao noted in the earlier discussion, the fundamental limitation of the legacy path is that each client compares its own CLV against a `single server-provided threshold`. There is no notion of reclaiming a fraction of the client's unused cache. In practice, clients with similar lock ages tend to keep similar numbers of locks, regardless of how large or active they are — a small client and a large client receive the same SLV and apply the same cutoff logic locally. Conclusion We do need the new contract: one OBD_CONNECT2 flag and reuse of the existing 64-bit slv field to carry packed pool pressure, with client-side eviction driven by a configurable curve over the client's own unused locks. That is what gives bounded, paced, proportional reclamation. At the same time, the old clients could/should participate in backpressure without waiting for a rollout threshold: - clients that negotiate OBD_CONNECT2_POOL_SLV_PACKED always receive packed pressure; - legacy clients continue to receive a scalar SLV, optionally occupancy-driven as a fallback; - both paths respond to the same underlying pool pressure, without a coverage-based switch. We accept the known limitations of the legacy fallback (equal-threshold behavior across clients of different sizes). The new contract addresses those limitations; the legacy path is there so mixed-version clusters still get timely cancellation, not to replace the pressure mechanism.
reply kg.xu patchset comment — Review note:
kg.xu
Review note: The patch is large because of negotiation, dual SLV, rollout, and tests. The new logic is small: server pressure is essentially granted/limit; the client maps pressure to an evict quota and uses a quota-based LRU policy instead of per-lock CLV arithmetic. Suggested review order: 1) lustre/include/lustre_dlm.h, lustre_idl.h — packed SLV layout and pool fields 2) ldlm_pool_calc_slv_by_pressure(), ldlm_pool_pressure_evict_*() — core math (~100 lines) 3) ldlm_cancel_pressure_policy(), ldlm_cancel_lru_policy() — reclaim behavior 4) connect, rollout, sysfs, tests — compatibility and rollout (bulk of the diff)
reply Gerrit AI review for Lustre ldlm.namespaces.pool.slv_mode.4:174 — Not a bug, but the MDT name in this sample output is missing the UUID suffix. mdt_init0() builds the namespace name as "%s-%s" of LUSTRE_MDT
Gerrit AI review for Lustre
Not a bug, but the MDT name in this sample output is missing the UUID suffix. mdt_init0() builds the namespace name as "%s-%s" of LUSTRE_MDT_NAME and obd_uuid.uuid, so it reads mdt-testfs-MDT0000_UUID, matching the filter-testfs-OST0000_UUID line just below.
reply kg.xu ldlm_pool.c:309 — Currently, `ldlm_pool` tracks metrics at the per-target level (e.g., 'fsname-target'). I propose aggregating these metrics by 'fsname' inste
kg.xu
Currently, `ldlm_pool` tracks metrics at the per-target level (e.g., 'fsname-target'). I propose aggregating these metrics by 'fsname' instead. Furthermore, we should discuss whether resources should be allocated equally across all file systems, or if we need a weighted policy.
reply Gerrit AI review for Lustre ldlm_pool.c:212 — (style) Not a bug, but with `pressure_adjust == true` this just returns `L` unchanged, and the only caller passing true is the CDEBUG in ldl
Gerrit AI review for Lustre
(style) Not a bug, but with `pressure_adjust == true` this just returns `L` unchanged, and the only caller passing true is the CDEBUG in ldlm_pool_calc_slv_by_pressure(). A boolean that turns the function into the identity is hard to follow - would printing `limit` directly there be clearer?
reply Gerrit AI review for Lustre ldlm_pool.c:1856 — (style) These six new helpers are the only EXPORT_SYMBOL()s in this file; ldlm_pool_get_slv(), ldlm_pool_init() and friends aren't exported.
Gerrit AI review for Lustre
(style) These six new helpers are the only EXPORT_SYMBOL()s in this file; ldlm_pool_get_slv(), ldlm_pool_init() and friends aren't exported. ldlm_lib.c and ldlm_request.c build into the same ptlrpc module (lustre/ldlm/Makefile), so none of them need exporting, and this one is used only inside ldlm_pool.c so it could be static.
reply Gerrit AI review for Lustre ldlm_pool.c:497 — Once the pool is pressure-ready these two limits diverge by roughly 5x, and the legacy scalar looks like it collapses to the floor.
Gerrit AI review for Lustre
Once the pool is pressure-ready these two limits diverge by roughly 5x, and the legacy scalar looks like it collapses to the floor.
ldlm_pools_recalc_task() sets pl_limit = ldlm_ratio2locknr(30)/nr_ns for a ready pool but pl_legacy_limit = LDLM_POOL_HOST_L/nr_ns. HOST_L is 50 locks per MB of RAM, i.e. RAM/20971 locks; ldlm_ratio2locknr(30) is 0.30*RAM/LDLM_LOCK_MEM_OVERHEAD. Packed clients only start evicting at 50% of pl_limit (default curve), so granted settles well above pl_legacy_limit.
With granted > limit here:
grant_usage = max_t(int, limit - (granted - grant_plan), 1); /* -> 1 */
slv_factor = (grant_usage << 10); do_div(slv_factor, limit); /* -> 0 */
slv = slv * slv_factor; /* -> 0 */
and the clamp below lifts it to ldlm_pool_slv_min() == 1. In ldlm_cancel_lrur_policy() slv == 1 means every lock with lv >= 1 (any lock idle for a second or more) is cancelled, so a non-packed client drops essentially its whole LRU on each recalc, and the drop also trips the ns_recalc_pct urgent-recalc path in ldlm_cli_update_pool().
That hits up to 30% of client exports at the default threshold, plus every MDT OSC on an OST since lod never negotiates OBD_CONNECT2_POOL_SLV_PACKED. Does "keep legacy behavior for old clients" still hold once the pool flips, or should the legacy scalar be derived from the limit the pool is actually being filled to?
reply Gerrit AI review for Lustre ldlm_pool.c:1535 — pl_slv_mode is set to pressure_rollout two lines up, so this branch always runs and a brand new server pool gets the pressure budget before
Gerrit AI review for Lustre
pl_slv_mode is set to pressure_rollout two lines up, so this branch always runs and a brand new server pool gets the pressure budget before any client has negotiated packed SLV and before ldlm_pool_fallback_legacy_on_multi_fs_register() has had a chance to force the pool back to legacy_slv. It is also the whole-node budget: ldlm_pools_recalc_task() divides ldlm_ratio2locknr() by ldlm_namespace_nr_read(LDLM_NAMESPACE_SERVER), this does not. The neighbouring initialisers (pl_legacy_limit, pl_grant_plan) still use LDLM_POOL_HOST_L, so pl_server_lock_volume is seeded from one basis and decayed against another until the first recalc pass. Would it be simpler to seed with LDLM_POOL_HOST_L here and let ldlm_pools_recalc_task() apply the pressure budget when the readiness gate says so?
reply Qian Yingjin sanity-ldlm-pool.sh:195 — This could be:
Qian Yingjin
This could be: for ((batch = 0; batch < BATCH_COUNT; batch++)) ...
reply Gerrit AI review for Lustre sanity-ldlm-pool.sh:190 — (style) This commented-out curve set/restore block looks like leftover scaffolding - drop it, or enable it if the suite is meant to cover a
Gerrit AI review for Lustre
(style) This commented-out curve set/restore block looks like leftover scaffolding - drop it, or enable it if the suite is meant to cover a non-default curve?
reply Gerrit AI review for Lustre sanity-ldlm-pool.sh:260 — (style) Carried over from patchset 9 and still open: this reads more naturally as `for ((batch = 0; batch < BATCH_COUNT; batch++))`, with su
Gerrit AI review for Lustre
(style) Carried over from patchset 9 and still open: this reads more naturally as `for ((batch = 0; batch < BATCH_COUNT; batch++))`, with subdir_idx computed from batch directly.
owner kg.xu · uploader Keguang Xu · PS28 uploaded 82d ago · NEW · open in Gerrit ↗
commit message
LU-7266 ldlm: introduce pressure-based SLV Legacy SLV/CLV reacts to server pressure indirectly and can delay lock reclaim. This change introduces a pressure-based SLV path: server sends packed pressure in SLV, and client converts it to evict quota. Packed SLV Format: * Bits 63..60: format version (current 0x1). Legacy SLV leaves these bits clear. * Bits 59..16: reserved for future use. * Bits 15..0: pressure in hundredths of a percent, where 10000 means 100.00%. Here pressure is total-grant-lock/total-limit. Unlike the previous grant-plan-based scalar SLV. Rationale: - Percentage-based eviction scales with client lock footprint, so larger lock holders evict more locks under pressure while smaller clients are not over-penalized. - Gradual rollout is gated by packed-capable export coverage, avoiding a mixed-upgrade case where only a small subset of new clients absorbs repeated reclaim pressure. - Client eviction uses segmented pressure-to-evict mapping, so reclaim is mild at low pressure and stronger at high pressure. At relatively low pressure, clients react faster to keep pressure in a healthy range; at higher pressure, clients use a longer evict interval because each round evicts more locks, reducing oscillation and avoiding over-evicting locks that should be retained; at or above the last curve point the interval shortens so high-pressure reclaim stays frequent. Key updates: - add OBD_CONNECT2_POOL_SLV_PACKED negotiation and packed SLV helpers - add slv_mode (legacy_slv / pressure_rollout), rollout threshold, and client evict-curve sysfs controls - pressure_rollout pools use ldlm.lock_pool_limit_mem_pct (default 30% of RAM / LDLM_LOCK_MEM_OVERHEAD) instead of LDLM_POOL_HOST_L - keep dual SLV state (legacy scalar + pressure scalar) for compatibility, where in pressure path; add quota-based client reclaim policy: ldlm_cancel_pressure_policy - fall back to legacy_slv on mixed-filesystem server nodes - keep legacy behavior for old clients and pre-threshold rollout stages - add sanity-ldlm-pool.sh, sanity 124aa, and man pages for the new pool parameters Performance impact: CPU overhead should be negligible. - The server recomputes pressure once per second per pool. On the client, pool recalc runs on the ~10s timer and when unused locks are decrefed. - On the packed pressure path, reclaim no longer performs per-lock arithmetic during LRU scanning, so lock-heavy workloads should see unchanged or slightly lower CPU usage. Assisted-by: Cursor:auto/codex5.5 Signed-off-by: Keguang Xu <squalfof@gmail.com> Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: If8a6f247127576965ae45c349a4ab04fb286615a
▶Review feedback — your turn
(0)
nothing here right now
▶In CI
(0)
nothing here right now
▶Needs reviewers
(0)
nothing here right now
▶Waiting on reviewers
(0)
nothing here right now
▶Ready to land
(0)
nothing here right now
▶Parked (WIP / self-blocked)
(0)
nothing here right now
36 open
▶Re-review needed — new patchset since your vote
(3)
69392
master
J –B ✓T ✓R -1/2−
LU-12669 ec: wait for stripes that parity cannot rebuild
reviewing Andreas Dilger · PS2→PS3 since your +1
218_review_prioritypt_ecro
2 unresolved
L +289 −36
5m
LU-12669 ec: wait for stripes that parity cannot rebuild
reviewing Andreas Dilger · PS2→PS3 since your +1
218_review_prioritypt_ecro
2 unresolved
L +289 −36
5m
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-zfs-part-1 | RHEL 9.8 / x86_64 | ran 3 tests. 1 tests failed: sanity. | session |
build #134706 SUCCESS · tests all Maloo sessions
reviews:
Marc Vef -1
no vote yet: Ronnie Sahlberg, Zhenyu Xu
patchsets:
PS1 10-03
PS2 10-14
PS3 10-28
your previous vote: +1 on PS2 (2026-10-15 12:31) — now at PS3
threads: 2 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Marc Vef patchset comment — Conflicts with master-next: Conflicts with #69350 LU-12669 ec: create lock placeholder for reconstructed pages, number 54 in the queue: lust
Marc Vef
Conflicts with master-next: Conflicts with #69350 LU-12669 ec: create lock placeholder for reconstructed pages, number 54 in the queue: lustre/include/cl_object.h
reply Marc Vef patchset comment — needs rebase or address the conflict with the placeholder patch
Marc Vef
needs rebase or address the conflict with the placeholder patch
tags: 218_review_priority pt_ecro
owner Andreas Dilger · uploader Andreas Dilger · PS3 uploaded 7d ago · NEW · open in Gerrit ↗
commit message
LU-12669 ec: wait for stripes that parity cannot rebuild
A read of an EC file whose raid set has more data stripes on stopped
OSTs than parity can rebuild fails with -EAGAIN or -EIO, while the
same read of a file without parity waits for the OSTs to return,
e.g. after an OSS failover. Adding parity to a file should not make
it less available than a plain striped file.
When CIT_EC_RD finds too many unavailable stripes or too little
parity, set the new cl_io::ci_ec_wait, which cl_io_loop() turns into
a restart, and record that raid set's range. Restart the read up to
the start of that raid set as CIT_EC_RD, so earlier raid sets are
still rebuilt from parity, then read that raid set as a plain read
without the no-delay flag, which waits for the stripes' OSTs. The
rest of the read goes back to the no-delay read, so later raid sets
are also rebuilt from parity. A synchronous direct read whose aio
was freed for the CIT_EC_RD restart gets a new one. A read of a
deactivated OST still fails at once. Since waiting for the OSTs is
not an error, print a debug message instead of a console warning.
Change sanity-ec test_29a to check that such a buffered or direct
read waits for its OSTs and then returns the right data, and add
test_29b and test_29c for reads whose second or first raid set is
rebuilt from parity.
Test-Parameters: testlist=sanity-ec ostcount=8
Fixes: 783c13bb0b8f ("LU-12669 ec: recover data from parity")
Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com>
Assisted-by: ClaudeCode:claude-opus-5-5 ltvm llm_code_and_review_tools
Change-Id: I9956bab1b63744d0b52d03268b95c78ca73ebbe5
69422
master
J –B ✓T ✓R 0/2
LU-8933 lod: leave inactive targets out of the RR array
reviewing Andreas Dilger · PS3→PS10 since your +1
218_review_prioritypt_ecro
CI@PS9
2 unresolved
L +675 −128
2d
LU-8933 lod: leave inactive targets out of the RR array
reviewing Andreas Dilger · PS3→PS10 since your +1
218_review_prioritypt_ecro
CI@PS9
2 unresolved
L +675 −128
2d
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-part-1 | RHEL 9.8 / x86_64 | ran 3 tests. 1 tests failed: sanity. | session |
build #135075 SUCCESS · tests all Maloo sessions
no vote yet: patrick bot, Ronnie Sahlberg
patchsets:
PS6 10-31 patrick bot
PS7 11-01 patrick bot
PS8 11-01 patrick bot
PS9 11-01
PS10 11-03
+5 earlier
PS1 10-05 PS2 10-10 PS3 10-13 PS4 10-31 patrick bot PS5 10-31your previous vote: +1 on PS3 (2026-10-31 11:49) — now at PS10
threads: 2 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre COMMIT_MSG:22 — (minor) Is "full" the right example here? A full MDT was already skipped before this patch: lod_mdt_alloc_rr() and lod_mdt_alloc_qos() call
Gerrit AI review for Lustre
(minor) Is "full" the right example here? A full MDT was already skipped before this patch: lod_mdt_alloc_rr() and lod_mdt_alloc_qos() call lod_statfs_check() on the same cached ltd_statfs that made lod_statfs_and_check() mark it inactive, and that rejects OS_STATFS_ENOSPC/ENOINO for MDTs. The case that is really new seems to be "deactivated by config" (or a statfs error other than -ENOTCONN). This can be fixed whenever the patch is next refreshed.
reply Gerrit AI review for Lustre sanity.sh:7262 — (suggestion) Would this subtest pass without the patch too? "lctl --device %osp deactivate" goes ptlrpc_set_import_active(0) -> IMP_EVENT_IN
Gerrit AI review for Lustre
(suggestion) Would this subtest pass without the patch too? "lctl --device %osp deactivate" goes ptlrpc_set_import_active(0) -> IMP_EVENT_INACTIVE -> opd_imp_active = 0. After that, osp_statfs() returns -ENOTCONN, and lod_statfs_and_check() sets ltd_discon = 1 along with ltd_active = 0. Before this patch, lod_mdt_alloc_rr() and lod_mdt_alloc_qos() already skipped ltd_discon MDTs. With MDSCOUNT=3, the old RR loop also gives MDSCOUNT - 1 stripes: the deactivated MDT is skipped, and the use_degraded pass finds the other remote MDT already used. So the stripe count and "not on MDT0001" checks seem to hold on the old code as well. The new `!mdt->ltd_active` checks only matter for an MDT that is inactive but not ltd_discon, e.g. the lod_process_config() "osp.*.active=0" path before the next statfs, or a statfs error other than -ENOTCONN. If the patch is refreshed, could the test reach one of those, or check its result against an unpatched MDS, so that it fails without the fix?
tags: 218_review_priority pt_ecro
build/test results are from PS9 — PS10…PS10 changed only the commit message (votes copied, CI not re-run)
owner Andreas Dilger · uploader Andreas Dilger · PS10 uploaded 2d ago · NEW · open in Gerrit ↗
commit message
LU-8933 lod: leave inactive targets out of the RR array
Inactive OSTs stayed in the round-robin array, so every layout that
reached one skipped it and used up an index, and the OST after it in
the array got its share of first stripes as well as its own.
Leave inactive targets out of the array built by lod_qos_calc_rr(),
unless all of them are inactive, and rebuild the arrays when a target
becomes active or inactive, counted in lq_rr_gen along with failure
domain changes. The RR allocators index the array by its own size
rather than the pool's. The periodic statfs update still checks the
inactive targets, and notices when they become active again. OSTs
that are full, read-only, or have max_create_count=0 are inactive for
this too, so they also leave the array until they can be used again.
This also stops directory stripes being allocated on an inactive MDT
that is not disconnected, e.g. one that is full or deactivated by
config, which lod_mdt_alloc_rr() and lod_mdt_alloc_qos() did not check
for. Keep returning -EINPROGRESS when no target could be used and a
target of the pool is disconnected, or one left out of the array
became active since it was built, and don't let the smaller array
raise the rounds of an overstriped directory above
lod_max_stripes_per_mdt. Overstriped OST layouts from the RR
allocator are likewise spread over the active OSTs only, e.g. "lfs
setstripe -C 8" with 1 of 8 OSTs inactive gets 8 stripes with 2 on one
OST, instead of 7 stripes.
Rebuilding the arrays after a target becomes active or inactive only
tries to take lq_rw_sem, and the allocators keep using the old array,
so creates don't wait behind allocators sleeping in precreate
(LU-15393). Failure domain changes are now rebuilt the same way.
Only if the array stays stale for 10 * qos_maxage, or at once and then
every qos_maxage after an omitted target becomes active, does one
thread wait at most 2s for it, as QoS allocation does. Move that
timed wait to lu_down_write_timeout() for both, and the backoff to
lu_rr_should_wait() and lu_rr_wait_failed(), which lod_rr_test checks.
Count the targets that become active in lq_active_gen for this.
Also avoid a static checker warning about lrfs_count - 1 underflowing
in lu_rr_fdoms_init().
Add sanity test_51i to check the first stripe balance and overstriping
with OST0001 deactivated, and test_51k to check that RR and QoS
directory stripes skip a deactivated MDT. test_51i waits until every
OST has enough precreated objects, using up the short FID sequence
tail of any OST that has too few. With 8 OSTs and 800 2-stripe files
test_51i gives these first stripes per active OST:
before 50-200
after 113-115
Check up to 32 OSTs in sanity test_51g, or 64 with SLOW=yes, and
check the OSSs used by other mirrors once per layout in lod_rr_test
rather than once per OST, so that test_51g takes about 20s.
Use the renamed timer cleanup API where available, with a fallback for
older kernels.
Fixes: ced540165ef5 ("LU-16623 lod: handle object allocation consistently")
Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com>
Assisted-by: ClaudeCode:claude-opus-5.5 ltvm,llm_code_and_review_tools
Assisted-by: Codex:gpt-6.1-sol
Change-Id: I8361eea7d707559ba65a9377fa642ca7833ebbe5
68889
master
J –B ✓T ✓R 0/2
LU-20749 obdclass: be more robust to OSD module load fail
reviewing Sebastien Buisson · PS12→PS14 since your +1
M +224 −10
8d
LU-20749 obdclass: be more robust to OSD module load fail
reviewing Sebastien Buisson · PS12→PS14 since your +1
M +224 −10
8d
build #134438 SUCCESS · tests all Maloo sessions
no vote yet: Alex Zhuravlev, Oleg Drokin, Timothy Day
patchsets:
PS10 10-07
PS11 10-14
PS12 10-15
PS13 10-23
PS14 10-26
+9 earlier
PS1 09-14 PS2 09-14 PS3 09-15 PS4 09-16 PS5 09-17 PS6 09-30 PS7 10-02 PS8 10-05 PS9 10-06your previous vote: +1 on PS12 (2026-10-16 02:23) — now at PS14
owner Sebastien Buisson · uploader Sebastien Buisson · PS14 uploaded 9d ago · NEW · open in Gerrit ↗
commit message
LU-20749 obdclass: be more robust to OSD module load fail When a server target is mounted, the OSD type is looked up with class_get_type(), which asks the kernel to load the matching module with request_module() if that type is not registered yet. request_module() runs modprobe through call_usermodehelper(), which discards its error output, and class_get_type() discards the return code as well, so the only trace left of a failure is: LustreError: Can't load module 'osd-ldiskfs' and ENODEV from the mount, which mount.lustre reports as "Are the lustre modules loaded?". Every cause looks the same that way: the module not being installed, a kABI or relocation mismatch, a rejected signature, or modprobe just not being runnable at that moment. Report the return code of request_module(), and try once more before giving up, since the failure can be transient: modprobe may fail to run, or the previous instance of the module may still be going away. Also load the backend OSD module from mount.lustre, where the mount type is already known from the on-disk data and modprobe can report on its own why it failed, the same way zfs_init() already loads zfs for a ZFS target. Name that module in the ENODEV hint of mount.lustre, so that it no longer points only at the Lustre modules, which are loaded in that case. Add conf-sanity test_167, which makes every attempt to load the OSD module fail and checks that both mount.lustre and the kernel say why, that the load is retried, and that the filesystem starts again once the module can be loaded. Add conf-sanity test_168, which reproduces the sequence a server goes through when it is restarted with its modules reloaded, and leaves the servers without their OSD module so that mounting a target is what has to load it. Also fix fail_loc in conf-sanity test_102 to not be a FAIL_ONCE. Test-Parameters: testlist=conf-sanity env=ONLY=167,ONLY_REPEAT=40 serverdistro=el10.1 Test-Parameters: testlist=conf-sanity env=ONLY=167,ONLY_REPEAT=40 serverdistro=el10.2 Test-Parameters: testlist=conf-sanity env=ONLY=168,ONLY_REPEAT=40 serverdistro=el10.1 Test-Parameters: testlist=conf-sanity env=ONLY=168,ONLY_REPEAT=40 serverdistro=el10.2 Signed-off-by: Sebastien Buisson <sbuisson@ddn.com> Change-Id: I09b4a96d2193435c6fced81edd4f507305155c55
▶Awaiting your review — CI green
(8)
69825
master
J –B ✓T ✓R 0/2
LU-12668 utils: resync EC parity with mirror resync API
reviewing Andreas Dilger · CI green — awaiting your review
218_review_prioritypt_ecro
4 unresolved
L +653 −238
10h
LU-12668 utils: resync EC parity with mirror resync API
reviewing Andreas Dilger · CI green — awaiting your review
218_review_prioritypt_ecro
4 unresolved
L +653 −238
10h
build #134523 SUCCESS · tests all Maloo sessions
no vote yet: Ronnie Sahlberg
patchsets:
PS1 10-19
PS2 10-21
PS3 10-21
threads: 4 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre llapi_mirror_find_stale.3:123 — (nit) The if has only a comment as its body, so the start = comps[0].lrc_start line becomes the conditional statement and start is left unse
Gerrit AI review for Lustre
(nit) The if has only a comment as its body, so the start = comps[0].lrc_start line becomes the conditional statement and start is left unset when count > 0. Maybe add a return or goto here if the page is refreshed.
reply Gerrit AI review for Lustre lfs.c:16560 — (minor) Before the patch [start, end) covered only the stale data components. This loop now also covers the parity entries. The comment says
Gerrit AI review for Lustre
(minor) Before the patch [start, end) covered only the stale data components. This loop now also covers the parity entries. The comment says that is harmless because parity covers the same extents, but that only holds for the data components a parity protects, not for the data components that happen to be stale. This patch makes the two diverge: if the parity resync fails, the data entries are still cleared and the parity stays stale. Take a later write that stales only M2 [0, 1M). The next resync gets data [0, 1M) plus parity [1M, EOF), so llapi_mirror_resync_data() reads the whole file from the source mirror and writes nothing beyond 1M. It also counts those reads in --stats. Should the range be taken from the non-parity entries only? The man page EXAMPLES do the same min/max over every entry.
reply Gerrit AI review for Lustre liblustreapi_layout.c:4102 — (suggestion) Nothing in the tree passes LCME_FL_NOSYNC, and no test covers it, but it becomes part of the public API and the man page. Is th
Gerrit AI review for Lustre
(suggestion) Nothing in the tree passes LCME_FL_NOSYNC, and no test covers it, but it becomes part of the public API and the man page. Is there a planned user? If not, it might be simpler to support only LCME_FL_PARITY for now and add NOSYNC once something needs it. The -EINVAL check on unknown flags keeps it easy to add later.
reply Gerrit AI review for Lustre liblustreapi_layout.c:6054 — (defect) llapi_mirror_find_stale_flags() and lfs_mirror_force_resync() fill every entry with lrc_synced = true. Some early failures return b
Gerrit AI review for Lustre
(defect) llapi_mirror_find_stale_flags() and lfs_mirror_force_resync() fill every entry with lrc_synced = true. Some early failures return before any copy and leave it set: - this calloc() failing returns -ENOMEM; - the fstat() below takes goto out; - in llapi_mirror_resync_data(), the fstat(), sysconf() and the 64MB posix_memalign() failures return directly. They skip the out_free path that clears lrc_synced of the data entries. Before this patch that was harmless, because lfs dropped the lease on rc < 0. Now lfs_mirror_resync_file() collects every entry with lrc_synced set and sends LL_LEASE_RESYNC_DONE with those ids. lod_declare_update_sync_pending() then clears LCME_FL_STALE on them. So a posix_memalign() ENOMEM (a strict overcommit or RLIMIT_AS setting is enough) leaves the stale data mirror marked in sync without being written. With has_parity set it gets worse. llapi_ec_resync_parity() still sees the data entries as synced, so it recomputes the parity from the stale data and reports that synced too. Could these early returns clear lrc_synced first, for every entry here and for the data entries in llapi_mirror_resync_data()? That matches the contract in the header comment and the man page.
tags: 218_review_priority pt_ecro
owner Andreas Dilger · uploader Andreas Dilger · PS3 uploaded 14d ago · NEW · open in Gerrit ↗
commit message
LU-12668 utils: resync EC parity with mirror resync API
'lfs mirror resync' would resync stale data components with
llapi_mirror_resync_many_params() and then stale parity components
with a separate llapi_ec_resync_many_params(). Other callers of the
generic resync functions would never resync parity, and parity
components passed to llapi_mirror_resync_many_params() would have
file data copied into them. Running `lfs mirror resync --only' on
a data mirror would also leave the stale parity protecting it, as
only the parity mirror's own id selected parity components.
Instead, resync parity components in llapi_mirror_resync_many_params()
from the data components they protect, after the data components have
been copied, and skip a parity component whose data component failed
in the same call. Count --stats and bandwidth progress once over
both, with the EC struct llapi_resync_progress. Replace
llapi_ec_resync_many_params() and llapi_ec_find_stale(), which are not
yet included in a release, with llapi_mirror_find_stale_flags(), which
collects the stale data components and, with LCME_FL_PARITY, then the
stale parity components, also those protecting a mirror given in
@mirror_ids, and resync both kinds of component in one call from
lfs. With LCME_FL_NOSYNC it also collects the components of NOSYNC
mirrors without listing them in @mirror_ids.
llapi_mirror_find_stale() still returns only data components, for
callers that copy data themselves.
An error in one component no longer undoes the others: lrc_synced
stays set for each component that was synced, and lfs still clears
LCME_FL_STALE from those before returning the error.
'lfs mirror resync --force-resync' now marks components to be synced
as llapi_mirror_find_stale() does, not after.
Add man pages for llapi_mirror_find_stale(3), covering the new
llapi_mirror_find_stale_flags(), and llapi_mirror_resync_many(3).
Add sanity-ec test_12i.
Test-Parameters: testlist=sanity-ec,sanity-flr
Fixes: 03191be6f459 ("LU-12668 ec: add support to resync stale ec comps")
Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com>
Assisted-by: ClaudeCode:claude-opus-5.5 ltvm,llm_code_and_review_tools
Change-Id: Ic40b61c233d1898cd75b30afe01adb45e23ebbe5
69578
master
J –B ✓T ✓R +1/2
LU-19908 quota: don't refetch a valid slave index on reint
reviewing Patrick Farrell · CI green — awaiting your review
testfixpw_own
S +11 −1
1d
LU-19908 quota: don't refetch a valid slave index on reint
reviewing Patrick Farrell · CI green — awaiting your review
testfixpw_own
S +11 −1
1d
6 optional test failure(s) — informational
build #133389 SUCCESS · tests all Maloo sessions
reviews:
Hongchao Zhang +1
no vote yet: Sergey Cheremencev, Andreas Dilger, Timothy Day
tags: testfix pw_own
owner Patrick Farrell · uploader Patrick Farrell · PS1 uploaded 24d ago · NEW · open in Gerrit ↗
commit message
LU-19908 quota: don't refetch a valid slave index on reint
Since LU-19136 a quota slave starts reintegration when a
DQACQ reply carries a newer global index version. With the
global lock already held, that reintegration also transfers
the slave index, while DQACQs resume as soon as the global
index is reintegrated. An acquire granted by the master
after the slave index was read is then overwritten when the
stale record is applied to lqe_granted, so the master keeps
quota space the slave no longer knows it owns. A later limit
for that ID is exhausted early: sanity-quota test_12a and
test_13 fail with EDQUOT when an earlier test, such as
test_7f, has left such a grant behind.
Only transfer the slave index when the slave copy has been
invalidated: at setup, on loss of the global lock and on
force_reint.
Fixes: f33ac875cafc ("LU-19136 quota: sync quota setting periodically")
Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Patrick Farrell <patrick@thelustrecollective.com>
Change-Id: I9f2fe9b6ef634f61f32b6bc22916cc278bbf731a
65798
master
J –B ✓T ✓R +1/2
LU-20238 ec: GFNI-accelerated EC primitives
reviewing Hiroshi Nishida · CI green — awaiting your review
pt_ecropw_smallfix
CI@PS23
XL +3332 −38
2d
LU-20238 ec: GFNI-accelerated EC primitives
reviewing Hiroshi Nishida · CI green — awaiting your review
pt_ecropw_smallfix
CI@PS23
XL +3332 −38
2d
build #134847 SUCCESS · tests all Maloo sessions
reviews:
Andreas Dilger +1
no vote yet: patrick bot, Ronnie Sahlberg, Patrick Farrell, Marc Vef, Maximilian Dilger, Zhenyu Xu, Oleg Drokin
patchsets:
PS20 10-21 patrick bot
PS21 10-21
PS22 10-24 patrick bot
PS23 10-30 patrick bot
PS24 11-03 Andreas Dilger
+19 earlier
PS1 05-11 PS2 05-11 PS3 05-11 PS4 05-12 PS5 05-12 PS6 05-13 PS7 05-13 PS8 05-17 PS9 06-08 PS10 06-17 PS11 07-10 PS12 07-10 PS13 08-05 PS14 08-06 PS15 08-07 PS16 10-01 patrick bot PS17 10-02 PS18 10-05 patrick bot PS19 10-13tags: pt_ecro pw_smallfix
build/test results are from PS23 — PS24…PS24 changed only the commit message (votes copied, CI not re-run)
owner Hiroshi Nishida · uploader Andreas Dilger · PS24 uploaded 2d ago · NEW · open in Gerrit ↗
commit message
LU-20238 ec: GFNI-accelerated EC primitives
Add a runtime-dispatched GFNI fast path to libec.a (LU-19465).
On x86_64 with GFNI, ec_encode_data(), ec_encode_data_update(),
ec_init_tables(), gf_vect_dot_prod() and gf_vect_mad() route to
AVX-512 or AVX2 GFNI kernels; everywhere else the existing
ec_*_base() path is used unchanged.
The kernels are C intrinsics (_mm{256,512}_gf2p8affine_epi64_epi8)
gated per-function with __attribute__((target(...))), so the build
needs only GCC >= 10 / clang >= 8 and no NASM. They use only the
GF(2^8) affine instruction and XOR/load/store, not the PSHUFB
nibble-table lookup the ISA-L AVX2/SSE kernels rely on.
The multi-output AVX-512 dot_prod kernels take the coefficient as
an EVEX {1to8} embedded broadcast to keep it off Port5; compilers
will not emit {1to8} from intrinsics, so a short inline-asm macro
is used. The mad kernels use _mm512_set1_epi64(), the coefficient
being loop-invariant there.
Against ISA-L's NASM kernels this reaches parity on AVX-512 (+1%
to -5%) and matches or beats NASM on 4 of 5 AVX2 benchmarks, the
one slower case by 6%.
A configure probe (EC_GFNI_SUPPORT) compile-tests the intrinsic
and defines LUSTRE_EC_GFNI for the libec.a build only. It rejects
GCC 8 and 9, which mark GF2P8AFFINEQB commutative and can swap its
data and matrix operands, giving wrong parity. Every
dispatch block is guarded by the pair defined(LUSTRE_EC_GFNI) &&
!defined(__KERNEL__), so no shipped consumer reaches a GFNI kernel
yet: ec.ko and liblustreapi both take the base path, and the
numbers above compare kernels directly rather than describing a
user-visible speedup. Follow-on patches add the Kbuild plumbing
and the liblustreapi wiring.
gfni_ec_test checks that the GFNI and base paths produce identical
output, and exits 77 without GFNI so a caller can skip instead of
recording a base-against-base pass. It installs with the test
suite; sanity-ec.sh test_0 sweeps geometries and lengths through
it. -i picks the kernel family directly, because the runtime
dispatch always prefers AVX-512 and would otherwise leave the
AVX2 kernels untested on any CPU that has both.
The vendored gf_*_gfni.c kernels are reflowed for lustre
checkpatch; see lustre/utils/erasurecode/GFNI_VENDORED.md.
Test-Parameters: trivial testlist=sanity-ec
Signed-off-by: Hiroshi Nishida <hnishida@thelustrecollective.com>
Assisted-by: Claude:Opus-5 claude-code
Change-Id: Ia40a743c8e47c018250728668090215c7bd8365b
67599
master
J –B ✓T ✓R -1/2−
LU-20531 mdc: do not delay MDS_CLOSE for import recovery
reviewing Vandana Rungta · CI green — awaiting your review (needs rebase first)
needs rebase
5 unresolved
M +110 −0
4d
LU-20531 mdc: do not delay MDS_CLOSE for import recovery
reviewing Vandana Rungta · CI green — awaiting your review (needs rebase first)
needs rebase
5 unresolved
M +110 −0
4d
CI green — awaiting your review (needs rebase first)
blocked on the owner: needs rebase — checkpatch: cannot be cherry-picked
2 optional test failure(s) — informational
build #135009 SUCCESS · tests all Maloo sessions
no vote yet: Qian Yingjin, Andreas Dilger, Alex Zhuravlev, Duncan Vogel, Timothy Day
patchsets:
PS12 08-15
PS13 08-15
PS14 10-29 patrick bot
PS15 10-30
PS16 10-31
+11 earlier
PS1 07-28 PS2 07-28 PS3 08-04 PS4 08-04 PS5 08-04 PS6 08-14 PS7 08-14 PS8 08-14 PS9 08-14 PS10 08-15 PS11 08-15threads: 5 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre COMMIT_MSG:46 — Not quite accurate: a close that overtakes its open's replay carries the old handle and always gets -ESTALE from mdt_close_internal(). That
Gerrit AI review for Lustre
Not quite accurate: a close that overtakes its open's replay carries the old handle and always gets -ESTALE from mdt_close_internal(). That is mapped to success only when the open is committed. Either way, the open is then recreated on the MDT by its replay and never closed. See the comment on mdc_request.c.
reply Gerrit AI review for Lustre COMMIT_MSG:66 — The earlier reproducer (OBD_FAIL_LDLM_REPLAY_PAUSE plus opencache on a remote directory, then checking that the MDC import reaches FULL) did
Gerrit AI review for Lustre
The earlier reproducer (OBD_FAIL_LDLM_REPLAY_PAUSE plus opencache on a remote directory, then checking that the MDC import reaches FULL) did observe the hang through a stable interface: the import state stays in REPLAY_LOCKS. Could test_171 use that, so it fails without the fix, rather than adding a test that passes either way?
reply Gerrit AI review for Lustre mdc_request.c:941 — (style) This isn't a bug, but the 27-line comment largely repeats the commit message and the ticket. If the patch is refreshed, a few lines
Gerrit AI review for Lustre
(style) This isn't a bug, but the 27-line comment largely repeats the commit message and the ticket. If the patch is refreshed, a few lines on why the close must not be delayed, with a pointer to LU-20531, would be enough.
reply Gerrit AI review for Lustre mdc_request.c:966 — (defect) Does this send the close with a stale open handle when the import is still in LUSTRE_IMP_REPLAY?
Gerrit AI review for Lustre
(defect) Does this send the close with a stale open handle when the import is still in LUSTRE_IMP_REPLAY? This flag applies to every close, not only the one issued from ldlm_cancel_unused_locks_for_replay(). Any close(2) or ll_clear_inode() during REPLAY now goes out right away, packed with the pre-failover handle. The old code parked it in imp_delayed_list. Then mdc_replay_open() rewrote epoch->mio_open_handle through mod->mod_close_req, so the close went out with the new handle once the import was FULL. mdt_close_internal() calls mdt_open_handle2mfd() with req_is_replay() false, so the old cookie is only looked up with class_handle2object(). After the MDS restarts that lookup fails, even if the open has already been replayed, because the new mfd keeps the old cookie only in mfd_open_handle_old. The result is -ESTALE: - uncommitted open (still on imp_replay_list): mdc_close() returns -ESTALE and clears mod_close_req. ptlrpc_replay_next() then replays the open anyway, because it doesn't check rq_replay. The MDT ends up holding an mfd that is never closed. - committed open whose replay is already in flight: -ESTALE is turned into 0, but the replayed open leaves the same leaked mfd. The leaked open lasts until the client disconnects. It keeps unlinked files as orphans and raises mot_open_count, which makes leases, HSM release and swap_layouts return -EBUSY. The note in this comment about -ESTALE on a committed open covers only part of this.
reply Gerrit AI review for Lustre mdc_request.c:966 — (defect) What transno does the MDT give this close if it reaches a target that is still replaying other clients' requests?
Gerrit AI review for Lustre
(defect) What transno does the MDT give this close if it reaches a target that is still replaying other clients' requests? target_queue_recovery_request() processes a request with no transno right away. If mdt_mfd_close() opens a transaction (atime/mtime update through mo_attr_set(), mdt_lsom_update(), orphan destroy in mdd_close()), tgt_last_rcvd_update() assigns ++lut_last_transno. During recovery lut_last_transno is the highest transno replayed so far, so the new number can equal one that another client still has to replay. The reply's transno is above last_committed, so ptlrpc_retain_replayable_request() puts the close on this client's imp_replay_list. While the import is in REPLAY, ptlrpc_replay_next() can then replay it in the same recovery. Two replays with the same transno hit "dropping replay: transno has been claimed by another client" in target_queue_recovery_request(). One of them gets no reply, and that client has to time out and reconnect. Version-based recovery (VBR) can also fail if the close updated the version of an object another client's replay depends on. This also applies to the REPLAY_LOCKS case this patch targets: one client can be replaying locks while the target is still replaying other clients' transnos. Until now a recovering client never sent a fresh modifying request before its import was FULL, which avoided this. The ldlm_cli_cancel_req() precedent is an LDLM_CANCEL, which creates no transaction.
owner Vandana Rungta · uploader Vandana Rungta · PS16 uploaded 4d ago · NEW · open in Gerrit ↗
commit message
LU-20531 mdc: do not delay MDS_CLOSE for import recovery
Ten ldlm_bl threads on an MDS that also carries a client mount were
reported blocked for over 122 seconds, all with the same stack:
obd_get_mod_rpc_slot <- ptlrpc_get_mod_rpc_slot <- mdc_close
<- lmv_close <- ll_close_inode_openhandle <- ll_md_real_close
<- ll_clear_inode <- ll_delete_inode <- evict <- iput
<- d_prune_aliases <- ll_prune_aliases <- ll_lock_cancel_bits
<- ll_md_blocking_ast <- ldlm_cancel_callback
<- ldlm_cli_cancel_local <- ldlm_cli_cancel_list_local
<- ldlm_bl_thread_blwi
A close can be driven from lock cancellation, and that path is also
walked inline on the import's own lock replay thread, by
ldlm_cancel_unused_locks_for_replay(). Cancelling a LOOKUP or PERM
lock runs ll_prune_aliases(), which can drop the last dentry of an
inode whose open handle is still cached by an OPEN lock, so the inode
is evicted and ll_clear_inode() has to issue MDS_CLOSE.
MDS_CLOSE keeps the default rq_send_state of LUSTRE_IMP_FULL, so
ptlrpc_import_delay_req() parks it on imp_delayed_list. That is a
deadlock: mdc_close() holds the reserved close modify-RPC slot across
ptlrpc_queue_wait(), and the import cannot leave recovery until the
same thread returns, so the close waits for a recovery that is waiting
for the close. It cannot time out either - a non-FULL import is not
pinged, ptlrpc_set_import_discon() requires FULL, and
ptlrpc_abort_inflight() skips requests of the current generation.
Every other close then blocks in obd_get_mod_rpc_slot(), which waits
uninterruptibly with no timeout, so each ldlm_bl thread that picks up
an LRU cancel batch is consumed and lock revocation on the node stops.
A target already handles MDS_CLOSE while it is recovering:
tgt_filter_recovery_request() lists it, and
target_queue_recovery_request() processes rather than queues a request
with no transno, which a fresh close has. So set rq_allow_replay on
the close, as ldlm_cli_cancel_req() already does for a cross-MDT
LDLM_CANCEL to avoid an analogous deadlock; that guard is gated on
OBD_CONNECT_MDS_MDS and so never covers a close issued through llite.
Should a close ever overtake its own open's replay, mdc_close()
already maps -ESTALE on a committed open to success.
Measured with a matched A/B on real hardware, same harness, this one
line as the only variable:
unpatched patched
o35 "req waiting for recovery" 1 0
o35 "allow during recovery" 0 26
ldlm_bl parked (state S) 727 samples 0 of 730
imp_replay_inflight stuck at 10 drained to 0
recovery outcome COMPLETE COMPLETE
This removes the demonstrated trigger, not the whole class: the
untimed wait in obd_get_mod_rpc_slot() and the inline Data-on-MDT
flush in ll_lock_cancel_bits() are unchanged and remain separate
blocking points.
The new subtest is a regression guard, not a reproducer. It passes
with and without the fix. See the ticket for why there is no
reproducer: the condition is not observable through any stable
interface, so a test would have to assert on the debug text emitted by
the two branches of the very "if" that rq_allow_replay controls.
Test-Parameters: mdscount=2 testlist=recovery-small
Signed-off-by: Vandana Rungta <vrungta@amazon.com>
Change-Id: I88beb57e6fe4ee49cc7741187ea5fc9f85117dbf
69710
master
J –B ✓T ✓R 0/2
LU-12669 lov: split EC reads at a raid set parity cannot cover
reviewing Andreas Dilger · CI green — awaiting your review
218_review_prioritypt_ecro
3 unresolved
M +202 −17
7d
LU-12669 lov: split EC reads at a raid set parity cannot cover
reviewing Andreas Dilger · CI green — awaiting your review
218_review_prioritypt_ecro
3 unresolved
M +202 −17
7d
build #134400 SUCCESS · tests all Maloo sessions
no vote yet: Ronnie Sahlberg
patchsets:
PS1 10-15
PS2 10-24
threads: 3 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Andreas Dilger lov_io.c:857 — This counts rows from the component start (cstart + n * row_size + first * ssize), but data object "first" is at file offset row * row_size
Andreas Dilger
This counts rows from the component start (cstart + n * row_size + first * ssize), but data object "first" is at file offset row * row_size + first * ssize counted from offset 0 (RAID0 striping is absolute). When e_start is not a multiple of stripe_count * stripe_size (e.g. "-E 4M -c 1 -E -1 -S 1M -c 8 --ec 4+1") the split lands at the wrong raid set. lov_ec_io_route() groups objects with lov_ec_raid_set() by object index, as LOD allocates them (and as the per raid set failure domains in 69493 apply to), while the CIT_EC_RD reconstruction it routes to groups by offset - e_start, so for such components the route can decide a set is rebuildable while the reconstruction works on a different set of objects. Both come from the offset mapping bug in https://review.whamcloud.com/68361 (see the lov_io.c:2926 thread there), which proposes shared ec_unit_raidset()/ec_data_to_parity() helpers in lustre_user.h using the absolute geometry. When this series is rebased onto the fixed 68361, please compute the split offset from the absolute row (row = pos / row_size, offset of object "first" in that row = row * row_size + first * ssize, clipped to the component extent) through those helpers, and add a 72a variant with an EC component whose e_start is not a multiple of the stripe width.
reply Gerrit AI review for Lustre lov_io.c:894 — (minor) If the patch is refreshed: the Return: description still says LOV_EC_RECONSTRUCT means rebuild the unavailable stripes and LOV_EC_WA
Gerrit AI review for Lustre
(minor) If the patch is refreshed: the Return: description still says LOV_EC_RECONSTRUCT means rebuild the unavailable stripes and LOV_EC_WAIT means parity cannot stand in for them. With @split, RECONSTRUCT is now also returned when a later set cannot be rebuilt, and WAIT when a later set can. Maybe add "up to @split" to both, so a caller doesn't ignore @split the way the RECONSTRUCT branch in lov_io_mirror_init() safely can.
reply Gerrit AI review for Lustre lov_io.c:1272 — (minor) This stops the CIT_READ itself at the split, but the readahead window doesn't stop there. vvp_io_read_start() sets vui_ra_pages from
Gerrit AI review for Lustre
(minor) This stops the CIT_READ itself at the split, but the readahead window doesn't stop there. vvp_io_read_start() sets vui_ra_pages from vui_tot_bytes, which covers the whole remaining request, and ll_readahead() widens the window to that ("Enlarge the RA window to encompass the full read"). Nothing in lov_io_read_ahead_prep() checks lis_io_endpos or whether the stripe is unreachable.
So with readahead on (the default) and a PR lock still cached on the dead data stripe of the next, rebuildable set, the following looks possible:
CIT_READ (waits, ci_ndelay=0) -> ll_readahead()
-> osc_io_read_ahead_prep() finds the cached lock
-> pages past the split go out with no OBD_BRW_NDELAY
and stay locked until that OST recovers
restart -> CIT_EC_RD -> lov_ec_read_stripe_pages()
-> get_folio_grab(FGP_LOCK) on one of those pages blocks
The read would then still wait for the dead OST of the set that parity can rebuild, which is what this patch is meant to avoid. test_72a runs with ec_readahead_off, so it wouldn't catch this. Should readahead in the waiting read be capped at lis_io_endpos, or could the test also run with readahead enabled?
tags: 218_review_priority pt_ecro
owner Andreas Dilger · uploader Andreas Dilger · PS2 uploaded 12d ago · NEW · open in Gerrit ↗
commit message
LU-12669 lov: split EC reads at a raid set parity cannot cover A read of an EC file that touches a raid set with more dead stripes than its parity can stand in for waits for their OSTs, even for the dead stripes of raid sets that parity could rebuild, so the whole read waits for every dead OST. Reconstructing the whole read instead fails on that set with -EIO, as a CIT_EC_RD cycle covers all raid sets of a row at once. Stop the read where the first raid set of the other kind starts, and restart the rest there: a reconstruction stops before a set that cannot be rebuilt (cl_io::ci_ec_split), and ll_file_io_generic() restarts the rest as a CIT_READ, which waits for that set; a read that waits stops before a set that can be rebuilt. A failed direct read whose DIO state is already freed keeps restarting as CIT_EC_RD. A large read() across many rows with alternating raid sets uses three restarts per row, as going back to reconstruction restarts once more as CIT_READ and then as CIT_EC_RD, so it returns short after about 333 such rows, once RETRY_ATTEMPTS restarts are used up. Add sanity-ec test_72a, which reads two rows and brings back only the raid set that cannot be rebuilt, and checks that the read completes with the data stripe of the other set still down. Test-Parameters: testlist=sanity-ec ostcount=8 Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com> Assisted-by: ClaudeCode:claude-opus-5.5 ltvm,llm_code_and_review_tools Change-Id: I21a023db83276919086acb9bc75cbf3d733ebbe5
69949
master
J –B ✓T ✓R +1/2
LU-21020 lov: wait for mirror once all were tried
reviewing Markus Hilger · CI green — awaiting your review
M +65 −6
7d
LU-21020 lov: wait for mirror once all were tried
reviewing Markus Hilger · CI green — awaiting your review
M +65 −6
7d
build #134487 SUCCESS · tests all Maloo sessions
reviews:
Andreas Dilger +1
no vote yet: Zhenyu Xu
patchsets:
PS1 10-22
PS2 10-24
PS3 10-26
owner Markus Hilger · uploader Markus Hilger · PS3 uploaded 9d ago · NEW · open in Gerrit ↗
commit message
LU-21020 lov: wait for mirror once all were tried
When fast mirror switching has tried all mirrors of a file,
lov_io_mirror_init() sets ci_tried_all_mirrors but leaves ci_ndelay
set, so the lock enqueue and BRW of the next try still carry
LDLM_FL_NDELAY and OBD_BRW_NDELAY. They fail at once with -EAGAIN,
and cl_io_loop() returns -EIO. A read of a mirrored file fails while
its OSTs are in failover, where a read of a file with one mirror
waits for them.
Clear ci_ndelay once ci_tried_all_mirrors is set, so that every user
of it waits for the OSTs in that round. This includes the glimpse of
stat(), which now waits as well instead of failing. EC IO keeps
ci_ndelay: it rebuilds a failed stripe from parity and decides on its
own when to wait.
ll_file_io_generic() carried ci_ndelay_tried across every restart of
a read, also those that moved data, so ci_tried_all_mirrors came up
in a long read while a mirror could still serve it. Carry it only
across restarts that moved no data, so that it means all mirrors
failed.
cl_io_loop() mapped -EAGAIN to -EIO in that round only while
ci_ndelay was set. Check ci_tried_all_mirrors first, so that an
-EAGAIN which does not come from the non-delay flags, e.g. from a
component that is not valid, still ends as -EIO and not -EAGAIN.
Add sanity-flr test_33f.
Test-Parameters: testlist=sanity-flr env=ONLY=33,ONLY_REPEAT=5
Fixes: f5564c35ede1 ("LU-16935 llite: avoid hopeless i/o repeats")
Signed-off-by: Markus Hilger <markus.hilger@megware.com>
Change-Id: I22d9f3b989e655add8a5fc8d69fe6eae34445e4f
69702
master
J –B ✓T ✓R +1/2
LU-20708 llite: rebuild faulting EC pages from parity
reviewing Andreas Dilger · CI green — awaiting your review
pt_ecro218_review_priority
5 unresolved
M +220 −15
7d
LU-20708 llite: rebuild faulting EC pages from parity
reviewing Andreas Dilger · CI green — awaiting your review
pt_ecro218_review_priority
5 unresolved
M +220 −15
7d
build #133745 SUCCESS · tests all Maloo sessions
reviews:
Zhenyu Xu +1
no vote yet: Patrick Farrell
threads: 3 need your reply · 0 waiting on others · 2 own notes · 0 bot
reply Gerrit AI review for Lustre llite_mmap.c:77 — (style) This isn't a bug, but the kernel-doc block above ll_fault_io_init() doesn't describe the new @ndelay_tried and @ndelay parameters, s
Gerrit AI review for Lustre
(style) This isn't a bug, but the kernel-doc block above ll_fault_io_init() doesn't describe the new @ndelay_tried and @ndelay parameters, so `contrib/scripts/kernel-doc -v -none` now warns twice for this file.
reply Gerrit AI review for Lustre llite_mmap.c:160 — (suggestion) Only the fast fault path finds the rebuilt page on the retry. With llite.*.fast_read=0, or while the layout lock is not held (C
Gerrit AI review for Lustre
(suggestion) Only the fast fault path finds the rebuilt page on the retry. With llite.*.fast_read=0, or while the layout lock is not held (CL_LAYOUT_GEN_NONE), the retried fault takes the slow path. Its CIT_FAULT lock enqueue never matches the EC placeholder, since osc_match_base() skips LDLM_FL_PLACEHOLDER except for page-coverage tests. The no-delay enqueue fails again, ll_fault_ec_read() returns false because FAULT_FLAG_TRIED is set, and the fault ends up waiting for the OST after already doing the parity rebuild. Should the commit message mention the fast_read dependency, or should the slow path handle this case?
note Keguang Xu llite_mmap.c:179 — (defect?) the 1MiB round-down prefetch in ll_fault_ec_read() can make a
Keguang Xu
(defect?) the 1MiB round-down prefetch in ll_fault_ec_read() can make a recoverable fault unrecoverable. For non-VM_RAND_READ faults, ll_fault_ec_read() expands the read to an aligned 1MiB window (llite_mmap.c:177-179). That range is what CIT_EC_RD passes to lov_find_comp_with_ec(). If the window overlaps any stale parity component on the mirror, that helper clears the match and breaks out of the mirror walk, so a later valid parity component in the same mirror is never considered (lov_io.c:375-380). The whole CIT_EC_RD then fails with -EIO even when the fault page itself could have been rebuilt. Example: - stripe size 64KiB - components [0, 512KiB) and [512KiB, EOF) - parity for the first component is stale; parity for the second is valid - the offline data OST holds data at the start of both components - fault at offset 512KiB The target page sits only in the second component and could be restored from its valid parity. ll_fault_ec_read() instead starts at round_down(512KiB, 1MiB) == 0 and reads [0, 1MiB). That extent overlaps the stale first parity, lov_find_comp_with_ec() rejects the parity mirror, and the read fails before the target page is rebuilt. ll_fault_ec_read() ignores the read result and still returns true, so the fault returns VM_FAULT_RETRY. On the next entry FAULT_FLAG_TRIED makes fault_flag_allow_retry_first() fail, recovery is not retried, and the fault waits for the OST. Please restore the fault page first (or clamp the prefetch window to the target component) before prefetching neighbouring pages, and do not treat a failed EC read as success.
note Keguang Xu llite_mmap.c:362 — (defect?) after a successful EC rebuild, the fault can still hang waiting for the offline OST ll_fault_ec_read() fills the page cache under
Keguang Xu
(defect?) after a successful EC rebuild, the fault can still hang waiting for the offline OST ll_fault_ec_read() fills the page cache under an EC placeholder and returns VM_FAULT_RETRY, but completing the kernel retry still depends on one opportunistic fast-path hit in __ll_fault() (llite_mmap.c around the ll_filemap_fault() call). That is not reliable.
Example 1 — fast_read enabled, folio lock contention:
1. First fault: OST down, ndelay/mirror path ends in ll_fault_ec_read(),
pages are Uptodate in cache, return VM_FAULT_RETRY.
2. Kernel re-enters ->fault with FAULT_FLAG_TRIED.
3. Fast path sets FAULT_FLAG_RETRY_NOWAIT and calls ll_filemap_fault().
Another thread briefly holds the folio lock, so filemap_fault() returns
VM_FAULT_RETRY immediately without waiting.
4. __ll_fault() treats that as a fast-path miss and falls through to the
slow CIT_FAULT path in the same call.
5. CIT_FAULT enqueues a normal data lock before filemap_fault(). Placeholder
locks are skipped by ordinary match in osc_match_base() (only page-coverage
TEST_LOCK may match them), so this enqueues against the dead data OST.
6. Recovery is attempted again, but ll_fault_ec_read() bails out because
fault_flag_allow_retry_first() is false under FAULT_FLAG_TRIED, then
ndelay is cleared and the fault waits for the OST.
At step 6 the rebuilt pages are already in cache. A later folio unlock does not unblock the LDLM wait.
Example 2 — fast_read disabled (no contention required):
Same as above after step 1, but the retry never takes the fast path, so it
goes straight to CIT_FAULT and the same placeholder/OST wait problem.
The intended model is "rebuild once, then the retried fault consumes cache via the fast path". Any miss of that single NOWAIT lookup leaves a fault that cannot complete while the OST is still down.
Please make cache consume on retry reliable — for example match/use the placeholder for coverage, or skip dead-OST enqueue when the fault page is already Uptodate under a placeholder — rather than depending on one NOWAIT fast-path lookup.
reply Gerrit AI review for Lustre llite_mmap.c:402 — (minor) ll_fault_io_init() returns ERR_PTR(-ENODATA) for the EC switch, but also returns cl_io_init()'s own rc unchanged, and an HSM-release
Gerrit AI review for Lustre
(minor) ll_fault_io_init() returns ERR_PTR(-ENODATA) for the EC switch, but also returns cl_io_init()'s own rc unchanged, and an HSM-released file returns -ENODATA too. lov_io_init_released() sets ci_restore_needed, and vvp_io_fini() leaves ci_need_restart clear when ll_layout_restore() fails ("if restore registration failed, no restart, we will return -ENODATA").
So a fault on a released file whose restore can't be registered now goes into the parity path. ll_fault_ec_read() drops the mmap lock and runs a 1MiB read_iter() (another restore attempt) and returns VM_FAULT_RETRY. The retried fault fails twice more before the SIGBUS that used to happen right away. That is about four restore requests instead of one, plus an "EC read" debug message for a non-EC file.
Could the EC switch be reported with its own signal, e.g. a `bool *switch_ec` out parameter, rather than overloading -ENODATA?
tags: pt_ecro 218_review_priority
owner Andreas Dilger · uploader Andreas Dilger · PS1 uploaded 21d ago · NEW · open in Gerrit ↗
commit message
LU-20708 llite: rebuild faulting EC pages from parity
A page fault on an EC file with a data stripe on an unavailable OST,
e.g. during an OSS failover, waits for the OST in the fault's lock
enqueue, while read() of the same page is rebuilt from parity at once.
So mmap readers of the file, such as git or executables, hang.
Do the lock enqueues of read faults without delay like reads, so they
fail over to another mirror, and switch to CIT_EC_RD after the mirror
rounds as reads do. The fault then drops the mmap lock, as
filemap_fault() does for IO, rebuilds the page, with the rest of the
aligned 1MiB around it unless the mapping is read randomly, into the
page cache with a CIT_EC_RD read, where the EC placeholder lock keeps
the pages Uptodate, and retries, which finds the page through the fast
fault path. A fault that cannot be retried, one under a read() or
write() of the same file, which holds lli_trunc_sem, and one whose
every mirror has been tried wait for the OST as before.
The read RPC of a fault is not sent without delay, since a fault
cannot be restarted once the read fails, so a fault on a page whose
extent lock is still cached also waits for the OST.
Add sanity-ec test_41o, which stops the OST of a stripe.
Test-Parameters: testlist=sanity-ec ostcount=8
Fixes: 783c13bb0b8f ("LU-12669 ec: recover data from parity")
Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com>
Assisted-by: ClaudeCode:claude-opus-5.5 ltvm,llm_code_and_review_tools
Change-Id: I8d565cbf7d643f026a5fb5e9428b5612e63ebbe5
67279
master
J !B ✓T ✓R -1/2−
LU-16518 ldlm: remove unused extent rbtree helpers
reviewing Timothy Day · CI green — awaiting your review
stalled 100d
1 unresolved
S +0 −37
100d
LU-16518 ldlm: remove unused extent rbtree helpers
reviewing Timothy Day · CI green — awaiting your review
stalled 100d
1 unresolved
S +0 −37
100d
janitor run: 6 failing config(s), none unique to this patch — janitor results
build #127655 SUCCESS · tests all Maloo sessions
reviews:
Yang Sheng -1
no vote yet: James Simmons
threads: 1 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Timothy Day patchset comment — It triggers a custom static checker I use: https://github.com/tim-day-387/ktest/tree/master/cplugin. But if I mark it unused, I can update t
Yang Sheng
I agree extent_replace should be removed. But please keep extent_prev_lock.
Timothy Day
I can mark it unused. But why keep it?
Yang Sheng
Does it trigger the unused warning? It may be used for some cases for optimization.
Timothy Day
It triggers a custom static checker I use: https://github.com/tim-day-387/ktest/tree/master/cplugin. But if I mark it unused, I can update the check to ignore __maybe_unused functions.
owner Timothy Day · uploader Timothy Day · PS1 uploaded 112d ago · NEW · open in Gerrit ↗
commit message
LU-16518 ldlm: remove unused extent rbtree helpers
... since they are no longer used. extent_prev_lock() and
extent_replace() were never called after being introduced.
Fixes: 0cf356c4e427 ("LU-11085 ldlm: optimise extent locks with identical extent")
Test-Parameters: trivial
Signed-off-by: Timothy Day <timday@thelustrecollective.com>
Change-Id: Ie1f7162b1023c0e396951136b45da532520a742e
▶Awaiting review — CI not green yet
(4)
64086
master
J –B ✓T …R -1/2−
LU-20958 lov: handle unavailable EC stripes in lseek
reviewing Patrick Farrell · awaiting review (CI not green yet)
ec2
pt_ecro218_review_priority
6 unresolved
L +453 −12
7h
LU-20958 lov: handle unavailable EC stripes in lseek
reviewing Patrick Farrell · awaiting review (CI not green yet)
ec2
pt_ecro218_review_priority
6 unresolved
L +453 −12
7h
reviews:
Ronnie Sahlberg -1
no vote yet: Marc Vef, Andreas Dilger, Zhenyu Xu
patchsets:
PS45 10-14 Andreas Dilger
PS46 10-16 Andreas Dilger
PS47 10-21 Andreas Dilger
PS48 10-29 Andreas Dilger
PS49 11-04 patrick bot
+44 earlier
PS1 02-17 PS2 03-29 PS3 03-29 PS4 03-29 PS5 03-29 Ronnie Sahlberg PS6 03-30 Ronnie Sahlberg PS7 03-31 Ronnie Sahlberg PS8 03-31 PS9 03-31 Ronnie Sahlberg PS10 04-01 Ronnie Sahlberg PS11 04-01 Ronnie Sahlberg PS12 04-07 Ronnie Sahlberg PS13 04-08 PS14 04-09 PS15 04-09 PS16 04-09 PS17 04-09 PS18 04-09 PS19 04-09 PS20 04-09 PS21 04-09 PS22 04-10 PS23 04-10 PS24 04-10 PS25 04-10 PS26 04-10 PS27 04-14 PS28 04-14 PS29 04-14 PS30 04-15 PS31 04-15 PS32 04-15 PS33 04-25 PS34 05-20 Marc Vef PS35 06-04 Ronnie Sahlberg PS36 07-13 Marc Vef PS37 07-13 Marc Vef PS38 07-13 Marc Vef PS39 07-15 Marc Vef PS40 07-16 Marc Vef PS41 07-26 Marc Vef PS42 07-26 Marc Vef PS43 08-17 Marc Vef PS44 08-19 Maximilian Dilgerthreads: 6 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Marc Vef patchset comment — Highlighting a conflict with 69111. This patch (and the parent) needs to be refreshed due to 68361 since the code is no longer compatible. (
Marc Vef
Highlighting a conflict with 69111. This patch (and the parent) needs to be refreshed due to 68361 since the code is no longer compatible. (-1) Does this patch need the current parent patches or can it be rebased and updatd for the RAID10 patch now?
reply Marc Vef patchset comment — Conflicts with #69694: it sits on ps3 of #69694, and the current patch set (ps5) conflicts with it in lustre/lov/lov_io.c, lustre/tests/sani
Marc Vef
Conflicts with #69694: it sits on ps3 of #69694, and the current patch set (ps5) conflicts with it in lustre/lov/lov_io.c, lustre/tests/sanity-ec.sh. It needs a rebase onto #69694 before it can land.
reply Gerrit AI review for Lustre file.c:5435 — (defect) The code here depends on lli_attr_valid losing OBD_MD_FLSIZE when the UPDATE lock is cancelled. That clearing is added by 69828 ("L
Gerrit AI review for Lustre
(defect) The code here depends on lli_attr_valid losing OBD_MD_FLSIZE when the UPDATE lock is cancelled. That clearing is added by 69828 ("LU-20958 llite: drop strict SOM size with the UPDATE lock"), but 69828 is not an ancestor of this patch set. The parent is 8bef60849e (an older patch set of 69694), which sits directly on 40b80bc048 on master. In this tree, lli_attr_valid is written only in ll_update_inode(), and nothing clears it in ll_md_blocking_ast().
Without 69828, this sequence goes wrong:
client A: open/stat while the file is in sync -> OBD_MD_FLSIZE, i_size = S
client B: writes the file up to T > S (MDS revokes LAYOUT|UPDATE, marks the SOM stale)
an OST of a data stripe becomes unavailable
client A: lseek(SEEK_DATA, S) -> ci_ec_unavail, but FLSIZE is still set
-> no revalidate; vvp_io_lseek_start() skips ll_merge_attr()
-> eof = S, so the result is -ENXIO although [S, T) has data
Because ll_merge_attr() is skipped, this also misses B's data on the stripes that are available. Should this patch be rebased onto 69828 so that the two cannot land in the wrong order?
reply Andreas Dilger lov_io.c:3833 — Not yet in PS48: 68361 is still at PS17 and its stack does not apply to master. This will be done when 64086 is rebased onto the refreshed
Andreas Dilger
This needs to be updated for the LU-20690 parity layout in https://review.whamcloud.com/68361 ("LU-20690 ec: like-RAID10 parity layout"), which removes RAID0|PARITY: parity components become LOV_PATTERN_PARITY with the p parity objects of a raid set sharing one offset. Once that lands, this check returns -EOPNOTSUPP for every EC file and the parity SEEK_DATA/SEEK_HOLE path is never used. Please check for the parity flag/pattern instead and use the new mapping below.
Andreas Dilger
Not yet in PS48: 68361 is still at PS17 and its stack does not apply to master. This will be done when 64086 is rebased onto the refreshed 68361.
reply Andreas Dilger lov_io.c:3862 — Not yet in PS48, for the same reason. The slot helpers and absolute-offset row/set mapping will be used once 68361 is refreshed.
Andreas Dilger
The parity offset needs to change with 68361 in two ways: 1. RAID10 layout: one stripe_size per raid set per row, and the parity index selects the object rather than the offset, i.e. poff = e_start + (row * R + set) * ss + intra, pstripe = (stripe of that slot) + pi with R = esc_n0 + esc_n1, via the 69516/68361 slot helpers (lsme_parity_slots_per_raidset()) rather than lov_stripe_number() on the concatenated offset. 2. The row/set must come from the absolute data offset, not offset - e_start (see my lov_io.c comment on 68361 PS17): row = off / (c * ss), offset_i = (off / ss) % c, and poff relative to row0 = e_start / (c * ss). Otherwise when e_start is not a multiple of the stripe width this looks at the parity of a different raid set than the one holding the data. Ideally use the shared helper that 68361 adds for this mapping so the kernel recovery, llapi resync, hedge (64919) and lseek all agree. Rebase onto that series once it is updated.
Andreas Dilger
Not yet in PS48, for the same reason. The slot helpers and absolute-offset row/set mapping will be used once 68361 is refreshed.
reply Gerrit AI review for Lustre lov_io.c:3865 — (minor) lov_parity_mirror_index_from_data() looks up the parity link from the data component at lio->lis_pos, which is the lseek start, not
Gerrit AI review for Lustre
(minor) lov_parity_mirror_index_from_data() looks up the parity link from the data component at lio->lis_pos, which is the lseek start, not from dsub's component dindex. If the seek starts in an earlier component of the mirror that has no parity link (e.g. a non-EC first PFL component), pmirror is < 0, and the stripe is reported as all data even though in-sync parity exists. The result is still correct, only less precise. If this is changed to use lsm_entries[dindex]->lsme_mirror_link_id, note that the LASSERTF in lov_io_sub_init() does the same lis_pos lookup, so it would need to stay in step for lov_sub_get() on the parity stripe.
tags: pt_ecro 218_review_priority
owner Patrick Farrell · uploader patrick bot · PS49 uploaded 12h ago · NEW · open in Gerrit ↗
commit message
LU-20958 lov: handle unavailable EC stripes in lseek
SEEK_DATA/SEEK_HOLE on an EC file with a data stripe on an OST that
was deactivated would fail with -ESHUTDOWN, and with an OST that was
down, e.g. during an OSS failover, the lseek would wait for the OST to
return, although reads of the file are rebuilt from parity at once.
Do the lseek with no-delay lock enqueues, as reads do. When the
sub-lock enqueue of a stripe in an EC data component fails, mark it in
this IO's lov_io_sub::sub_ec_err and do not start its sub-IO. Retry
with blocking enqueues once every mirror has been tried. The
unavailable stripe leaves its size out of the merged stripe
attributes, so take EOF from the strict SOM size from the MDS instead,
fetched again as stat() does if the UPDATE lock was dropped. Without
one, wait for the OST, or return -EIO if it stays unavailable, rather
than miss data past a smaller EOF. A stripe whose extent lock is
still cached is locked locally, so its OST_SEEK still waits for the
OST.
Resync writes parity only where a data stripe of its raid set has
data, page aligned, and punches the rest, so a hole in an in-sync
parity stripe is a hole in every data stripe of the raid set. Seek an
available parity stripe of the unavailable stripe's raid set from the
matching offset, and map the result back, for the RAID0|PARITY parity
layout. Each row of a raid set holds one stripe_size chunk in every
data and parity object, so offsets in the two objects advance
together. The result can report data where only another stripe of the
raid set has data, but never a hole where the stripe may have data.
With no parity stripe that can answer, report the stripe as data from
where the IO starts in it, with no hole before its end, which is
always correct: a seek must not skip data, but may report a hole as
data. Since such a stripe has no hole at its end, report the hole at
EOF for SEEK_HOLE if nothing before it is found, and -ENXIO for
SEEK_DATA at EOF.
The parity object is not covered by the lseek lock, so seek it with a
server lock, and do not trust the LVB size of an unlocked object in
osc_io_lseek_start(). Seek parity without delay, failing at once if
its OST is disconnected; an idle import still reconnects for the seek.
Add sanity-ec test_79a, which stops the OST of a stripe, and
test_79b, which checks holes found from parity, and that the stripe
is reported as data when the parity OSTs are stopped too.
Test-Parameters: testlist=sanity-ec ostcount=8
Fixes: 783c13bb0b8f ("LU-12669 ec: recover data from parity")
Signed-off-by: Patrick Farrell <patrick@thelustrecollective.com>
Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com>
Assisted-by: ClaudeCode:claude-opus-5-5 ltvm llm_code_and_review_tools
Change-Id: I5cce4e0ea51c68b0c6fda1d83b694af19cad57bd
70381
master
J –B ✓T …R 0/2
LU-20690 lod: write 1+N EC data around a lost OST
reviewing Andreas Dilger · awaiting review (CI not green yet)
pt_ecro
2 unresolved
L +289 −0
1d
LU-20690 lod: write 1+N EC data around a lost OST
reviewing Andreas Dilger · awaiting review (CI not green yet)
pt_ecro
2 unresolved
L +289 −0
1d
no vote yet: Ronnie Sahlberg
threads: 2 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Misc Code Checks Robot (Gatekeeper helper) lod_object.c:8137 — error: lod_ec_swap_stripe():'lod' dereferencing possible ERR_PTR()
Misc Code Checks Robot (Gatekeeper helper)
error: lod_ec_swap_stripe():'lod' dereferencing possible ERR_PTR()
reply Misc Code Checks Robot (Gatekeeper helper) lod_object.c:8137 — error: lod_ec_swap_stripe():'lod' dereferencing possible ERR_PTR()
Misc Code Checks Robot (Gatekeeper helper)
error: lod_ec_swap_stripe():'lod' dereferencing possible ERR_PTR()
tags: pt_ecro
owner Andreas Dilger · uploader Andreas Dilger · PS2 uploaded 1d ago · NEW · open in Gerrit ↗
commit message
LU-20690 lod: write 1+N EC data around a lost OST A write to an EC file would fail while the OST of a data stripe in a component of 1-data raid sets (--ec 1+N, or one data stripe) was unavailable: the data mirror is the only mirror that can be the write primary, and its object could not be written. Yet each of the N parity objects of such a raid set holds a copy of the data object at the same object offsets. When a write era starts (RDONLY -> WRITE_PENDING) the parity is still in sync, so lod_ec_swap_unavail() swaps each unavailable data object of such a component in the write extent with a parity object of the same raid set on an available OST. The data mirror stays a complete write primary, and the parity component, which the write stales as before, holds the unavailable object until the next resync rewrites it. The filter_fid of a swapped object is updated from the layout that the next write to it carries; until then LFSCK reports an unmatched pair and repairs the filter_fid. The swapped-in object may be outside the pool or OST list of the data component. The swap needs each parity copy to be as large as the data object. A copy written by resync with O_DIRECT ended on a page boundary, past a file size that is not page aligned, and ended at the last data when the file had a trailing hole, so a swapped-in copy would change the file size. The EC resync now truncates the parity mirror to the file size when EOF is inside a component of 1-data raid sets, as FLR resync does for a mirror. Parity resynced by an older lfs is not trimmed. Swapping only happens at the start of a write era, while the parity component is in sync. An OST lost during a write era, and a 1-data raid set in a component with larger raid sets, whose parity is not at the data offsets, still need the OST to return. Add sanity-ec test_313 to write 1+2 files with a data OST unavailable, for an unaligned size, a sparse tail, a second PFL component and the second stripe of a 2-stripe component, and check the swap, the file size and the data before and after resync. Test-Parameters: trivial testlist=sanity-ec,sanity-flr ostcount=8 Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com> Assisted-by: ClaudeCode:claude-opus-5-5 ltvm llm_code_and_review_tools Change-Id: Iab02681175f14e69d78441647d6f1bd3b53ebbe5
62859
master
J ✓B ✓T ✗12R -1/2−
LU-12668 ec: Add tests for computing the parity coverage
reviewing Ronnie Sahlberg · blocked on the owner: needs rebase — checkpatch: cannot be cherry-picked; enforced tests failed
needs rebase
ec2
pt_ecro
L +460 −0
47d
LU-12668 ec: Add tests for computing the parity coverage
reviewing Ronnie Sahlberg · blocked on the owner: needs rebase — checkpatch: cannot be cherry-picked; enforced tests failed
needs rebase
ec2
pt_ecro
L +460 −0
47d
blocked on the owner: needs rebase — checkpatch: cannot be cherry-picked; enforced tests failed
awaiting review (CI not green yet)
| failed enforced test | platform | detail | |
|---|---|---|---|
| custom-1001 | RHEL 8.10 / x86_64 | ran 3 tests. 1 tests failed: sanity-ec. | session |
| custom-1002 | RHEL 8.10 / x86_64 | ran 3 tests. 1 tests failed: sanity-ec. | session |
| review-dne-subtest-change | RHEL 8.10 / x86_64 | ran 3 tests. 1 tests failed: sanity-ec. | session |
| review-dne-subtest-change | RHEL 8.10 / x86_64 | ran 3 tests. 1 tests failed: sanity-ec. | session |
| review-dne-zfs-subtest-change | RHEL 8.10 / x86_64 | ran 3 tests. 1 tests failed: sanity-ec. | session |
| review-dne-zfs-subtest-change | RHEL 8.10 / x86_64 | ran 3 tests. 1 tests failed: sanity-ec. | session |
| review-dne-zfs-subtest-change | RHEL 8.10 / x86_64 | ran 3 tests. 1 tests failed: sanity-ec. | session |
| review-dne-zfs-subtest-change | RHEL 8.10 / x86_64 | ran 3 tests. 1 tests failed: sanity-ec. | session |
| review-dne-zfs-subtest-change | RHEL 8.10 / x86_64 | ran 3 tests. 1 tests failed: sanity-ec. | session |
| review-dne-zfs-subtest-change | RHEL 8.10 / x86_64 | ran 3 tests. 1 tests failed: sanity-ec. | session |
| review-dne-zfs-subtest-change | RHEL 8.10 / x86_64 | ran 3 tests. 1 tests failed: sanity-ec. | session |
| review-ldiskfs-dne-arm | RHEL 8.10 / x86_64, Rocky 9.5 / aarch64 | ran 5 tests. 1 tests failed: sanity. | session |
build #127014 SUCCESS · tests all Maloo sessions
no vote yet: Qian Yingjin, Marc Vef, Maximilian Dilger
patchsets:
PS43 05-06
PS44 05-14 Marc Vef
PS45 05-20 Marc Vef
PS46 06-22 Marc Vef
PS47 06-26 Marc Vef
+42 earlier
PS1 12-03 PS2 12-03 PS3 12-03 PS4 12-03 PS5 12-03 Patrick Farrell PS6 12-03 Patrick Farrell PS7 12-03 Patrick Farrell PS8 12-04 Patrick Farrell PS9 12-04 PS10 12-04 Patrick Farrell PS11 12-04 Patrick Farrell PS12 12-05 PS13 12-05 PS14 12-05 PS15 12-05 PS16 12-06 PS17 12-09 PS18 12-09 Patrick Farrell PS19 12-09 Patrick Farrell PS20 12-10 PS21 12-10 Patrick Farrell PS22 12-10 PS23 12-10 PS24 12-11 PS25 12-12 Patrick Farrell PS26 12-15 PS27 12-15 PS28 12-16 Patrick Farrell PS29 01-13 Patrick Farrell PS30 01-13 Patrick Farrell PS31 01-14 Patrick Farrell PS32 01-15 Patrick Farrell PS33 01-16 Patrick Farrell PS34 01-29 Patrick Farrell PS35 03-29 Patrick Farrell PS36 03-29 Patrick Farrell PS37 03-31 Patrick Farrell PS38 04-08 Patrick Farrell PS39 04-09 Patrick Farrell PS40 04-10 Patrick Farrell PS41 04-21 Zhenyu Xu PS42 05-05 Patrick Farrelltags: pt_ecro
owner Ronnie Sahlberg · uploader Marc Vef · PS47 uploaded 131d ago · NEW · open in Gerrit ↗
commit message
LU-12668 ec: Add tests for computing the parity coverage When we write or verify the parities we no longer use the whole stripe, instead we compute the coverage of what ranges of parity is important and what can be ignored. This is based on SEEK_DATA/SEEK_HOLE and EOF. Add tests that we compute these ranges correctly. Test-Parameters: trivial Test-Parameters: testlist=sanity-ec Test-Parameters: testlist=sanity-ec fstype=zfs Signed-off-by: Ronnie Sahlberg <rsahlberg@whamcloud.com> Change-Id: Iaee9d0ccb0875f6d515a8adc322fa3cd37bfe0f6
65863
master
J ✗8B ✓T ✗13R -1/2−
LU-20253 mdt: implement RENAME_EXCHANGE support
reviewing Timothy Day · blocked on the owner: janitor: test failures unique to this patch; enforced tests failed
8 unique failures
10 unresolved
L +672 −12
90d
LU-20253 mdt: implement RENAME_EXCHANGE support
reviewing Timothy Day · blocked on the owner: janitor: test failures unique to this patch; enforced tests failed
8 unique failures
10 unresolved
L +672 −12
90d
blocked on the owner: janitor: test failures unique to this patch; enforced tests failed
awaiting review (CI not green yet)
janitor flagged test failures unique to this patch — full janitor results
| unique failing test | history |
|---|---|
| sanity1@ldiskfs+DNE:test_24Ka | seen in 1 other review |
| sanity1@ldiskfs+DNE:test_24Kb | seen in 1 other review |
| sanity1@ldiskfs+DNE:test_24La | NEW unique failure for this branch in the last 30 days, and was seen 0 times across 0 other branches 0 reviews |
| sanity2@ldiskfs+DNE:test_160k | seen in 2 other reviews |
| sanity2@ldiskfs+DNE:test_160w | seen in 2 other reviews |
| sanity1@zfs:test_24Ka | seen in 1 other review |
| sanity2@zfs:test_160k | seen in 3 other reviews |
| sanity2@zfs:test_160w | seen in 2 other reviews |
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-part-1 | RHEL 9.7 / x86_64 | ran 3 tests. 1 tests failed: sanity. | session |
| review-dne-part-1 | RHEL 10.1 / x86_64 | ran 3 tests. 1 tests failed: sanity. | session |
| review-dne-part-5 | RHEL 9.7 / x86_64 | ran 5 tests. 1 tests failed: lustre-rsync-test. | session |
| review-dne-selinux-ssk-part-1 | RHEL 8.10 / x86_64 | ran 3 tests. 1 tests failed: sanity. | session |
| review-dne-subtest-change | RHEL 9.7 / x86_64 | ran 3 tests. 1 tests failed: sanity. | session |
| review-dne-zfs-part-1 | RHEL 9.7 / x86_64 | ran 3 tests. 1 tests failed: sanity. | session |
| review-dne-zfs-part-1 | RHEL 10.1 / x86_64 | ran 3 tests. 1 tests failed: sanity. | session |
| review-dne-zfs-part-5 | RHEL 9.7 / x86_64 | ran 5 tests. 1 tests failed: lustre-rsync-test. | session |
| review-dne-zfs-subtest-change | RHEL 9.7 / x86_64 | ran 3 tests. 1 tests failed: sanity. | session |
| review-ldiskfs | RHEL 8.10 / x86_64 | ran 5 tests. 1 tests failed: sanity. | session |
| review-ldiskfs | RHEL 8.10 / x86_64, RHEL 9.7 / x86_64 | ran 5 tests. 1 tests failed: sanity. | session |
| review-ldiskfs-arm | RHEL 8.10 / x86_64, Rocky 9.5 / aarch64 | ran 6 tests. 1 tests failed: sanity. | session |
| review-ldiskfs-ubuntu | RHEL 8.10 / x86_64, Ubuntu 24.04 / x86_64 | ran 6 tests. 1 tests failed: sanity. | session |
build #128744 SUCCESS · tests all Maloo sessions
no vote yet: Andreas Dilger
patchsets:
PS1 05-13
PS2 05-13
PS3 08-05
threads: 10 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Andreas Dilger COMMIT_MSG:14 — We definitely do not want multiple operations for such an operation, as that makes it much more complex to recover from.
Andreas Dilger
We definitely do not want multiple operations for such an operation, as that makes it much more complex to recover from. The MDS can already do atomic cross-MDT renames with a distributed transaction, so the same should be possible in this case.
reply Gerrit AI review for Lustre COMMIT_MSG:23 — The patch set 2 comment that the MDS should handle this cross-MDT with a distributed transaction, the way cross-MDT rename already does, doe
Gerrit AI review for Lustre
The patch set 2 comment that the MDS should handle this cross-MDT with a distributed transaction, the way cross-MDT rename already does, does not look addressed: mdd_rename_exchange() is still local-only and mdt_reint_rename() returns -EOPNOTSUPP for any remote object. Requiring all overlayfs layers on a single MDT is a fairly large constraint to bake into the feature. Is the distributed case planned as a follow-on, or is the intent that it stays unsupported?
reply Gerrit AI review for Lustre COMMIT_MSG:38 — (minor) This adds a new on-wire bias bit, so a Test-Parameters: line asking for interop coverage against an older peer (serverjob/serverbuil
Gerrit AI review for Lustre
(minor) This adds a new on-wire bias bit, so a Test-Parameters: line asking for interop coverage against an older peer (serverjob/serverbuildno, or clientjob/clientbuildno) would help confirm the old-peer behaviour is what is expected.
reply Andreas Dilger dcache.h:21 — (minor) can we either name the compat function `d_exchange()` or `#define d_exchange(d1, d2) compat_d_exchange(d1, d2)` so that the code is
Andreas Dilger
(minor) can we either name the compat function `d_exchange()` or `#define d_exchange(d1, d2) compat_d_exchange(d1, d2)` so that the code is only using `d_exchange()` directly?
reply Gerrit AI review for Lustre lustre_idl.h:2122 — (defect) wirecheck.c carries CHECK_VALUE_X(MDS_RENAME_WHITEOUT) and both wiretest.c copies assert its value; the new bit gets neither. Shoul
Gerrit AI review for Lustre
(defect) wirecheck.c carries CHECK_VALUE_X(MDS_RENAME_WHITEOUT) and both wiretest.c copies assert its value; the new bit gets neither. Should CHECK_VALUE_X(MDS_RENAME_EXCHANGE) and the regenerated LASSERTF() be added here too? Separately, the patch set 2 request to carry the renameat2 flags in one of the unused struct mdt_rec_rename fields (or a separate opcode) instead of overloading rn_bias still looks open - this takes the enum to 1 << 30 and leaves a single free bit in the __u32.
reply Andreas Dilger namei.c:2533 — Fortunately, we also control the MDS so can change it to do what we want. AFAICS, these should all use the regular `MDS_REINT:REINT_RENAME`
Andreas Dilger
Fortunately, we also control the MDS so can change it to do what we want. AFAICS, these should all use the regular `MDS_REINT:REINT_RENAME` opcode with a new flag that passes `RENAME_EXCHANGE`, `RENAME_NOREPLACE`, and `RENAME_WHITEOUT` flags in one of the unused fields in `struct mdt_rec_rename` (there are many unused ones for rename) instead of adding more flags to `rn_bias` which is overloaded for other operations. Once the MDS reply is successful, then the client would also update its local state to match. It could also potentially be a different `REINT_RENAME_*` opcodes, but I'm not sure that this is needed. An old MDS would spew errors for every time this is tried, but maybe that combination wouldn't be very common?
reply Gerrit AI review for Lustre namei.c:2585 — (defect) OBD_CONNECT2_RENAMEAT2 is a single flag covering all three renameat2 behaviours, so it cannot distinguish an MDS that only has RENA
Gerrit AI review for Lustre
(defect) OBD_CONNECT2_RENAMEAT2 is a single flag covering all three renameat2 behaviours, so it cannot distinguish an MDS that only has RENAME_WHITEOUT from one that also has RENAME_EXCHANGE. mdt_rename_unpack() simply masks out the bits it knows, so such an MDS ignores MDS_RENAME_EXCHANGE and performs a plain rename: the target object is unlinked, the RPC returns 0, and ll_rename_exchange() then calls d_exchange() on a dcache state the server never created. The three patches land together on master, but that mix is reachable via a partial backport. Is there a way to probe for exchange support specifically (a second connect flag, or the separate field/opcode suggested on patch set 2)?
reply Gerrit AI review for Lustre mdd_dir.c:4031 — (defect) This ".." update is not tracked the way the sdir one is - there is no tobj_dotdot flag to match sobj_dotdot, so fixup: never restor
Gerrit AI review for Lustre
(defect) This ".." update is not tracked the way the sdir one is - there is no tobj_dotdot flag to match sobj_dotdot, so fixup: never restores it. If this block succeeds and a later step fails (any of the four mdd_update_time() calls below can return -EIO/-ENOSPC/quota errors), fixup: puts both name entries back but leaves mdd_tobj's ".." pointing at the source parent while mdd_tobj is back under mdd_tpobj. osd_trans_stop() ignores th_result, so that partial state is committed and only LFSCK can repair it. The function comment says the fixup paths "only unwind operations already applied to the running transaction handle", which is what makes the omission easy to miss.
reply Gerrit AI review for Lustre mdd_dir.c:4088 — (defect) Two CL_RENAME records do not describe an exchange to a consumer that applies them in order. lustre_rsync's lr_move() issues a plain
Gerrit AI review for Lustre
(defect) Two CL_RENAME records do not describe an exchange to a consumer that applies them in order. lustre_rsync's lr_move() issues a plain rename() per record:
rename(spobj/lsname, tpobj/ltname) /* replica's tobj is overwritten */
rename(tpobj/ltname, spobj/lsname) /* sobj moves straight back */
The replica ends up with sobj still under the original source name, tpobj/ltname gone, and its copy of tobj destroyed.
Both calls also pass target == NULL, so cr_tfid is zero - the same shape a plain rename onto a non-existent target produces - and there is nothing for a consumer to key off to recognise the pair. Should these carry a new CLF_RENAME_* flag (or a distinct record type) so changelog readers can tell an exchange from two renames?
reply Gerrit AI review for Lustre mdt_reint.c:3080 — (defect) The check being bypassed here is not a POSIX type check - the comment right above it says it exists to avoid a deadlock with link.
Gerrit AI review for Lustre
(defect) The check being bypassed here is not a POSIX type check - the comment right above it says it exists to avoid a deadlock with link.
With mold a non-dir and mnew a directory, the exchange now falls through and locks both children in FID order:
mdt_rename_source_lock(mold) EX LOOKUP|XATTR
mdt_object_check_lock(mnew) EX LOOKUP|UPDATE|XATTR
mdt_reint_link() takes those same two objects in the opposite order:
mdt_parent_lock(mp = mnew) PW UPDATE
mdt_object_lock(ms = mold) EX UPDATE|XATTR
So for lu_fid_cmp(mold, mnew) < 0, a concurrent link(/p1/f, /p2/d/x) and renameat2(/p1/f, /p2/d, RENAME_EXCHANGE) grab f-then-d and d-then-f. Neither path uses a trylock, and link never takes the BFL, so the BFL the exchange takes for a directory does not serialise them.
That is exactly the overlayfs pattern - ovl_cleanup_and_whiteout() exchanges a whiteout char device with an upper directory. Can the exchange path lock the two children in an order consistent with link, or use mdt_object_lock_try() plus restart here?
owner Timothy Day · uploader Timothy Day · PS3 uploaded 91d ago · NEW · open in Gerrit ↗
commit message
LU-20253 mdt: implement RENAME_EXCHANGE support To support overlayfs, we need RENAME_EXCHANGE [1] to clear whiteouts when removing a directory that has been copied up (see ovl_clear_empty() and ovl_cleanup_and_whiteout()). Without this, these operations will fail with EINVAL. Implement an atomic exchange on the MDS: the client sends a rename RPC with the new MDS_RENAME_EXCHANGE bias and mdd_rename_exchange() swaps the two directory entries in a single transaction, updating ".." and the parent nlink counts for cross-directory exchanges of directories. Unlike a plain rename, nothing is unlinked, so exchanging objects of different types (e.g. a directory with a whiteout, as overlayfs does) is legal. The exchange is recorded as two CL_RENAME changelog records in the same transaction. Only the local case is implemented: if any involved object is on another MDT, the MDS returns -EOPNOTSUPP. Currently, all overlayfs layers must be placed on a single MDT on DNE filesystems. Add ll_md_rename_one() to issue a single rename RPC for the exchange path. The client must call d_exchange() itself on success. d_exchange() is only exported since Linux 6.18; on older kernels it is resolved with a kallsyms lookup in lustre_symbols_init(). Reject RENAME_EXCHANGE combined with RENAME_WHITEOUT or RENAME_NOREPLACE as invalid: do_renameat2() rejects these combinations, but in-kernel callers of vfs_rename() do not re-check them. [1] https://www.man7.org/linux/man-pages/man2/rename.2.html Signed-off-by: Timothy Day <timday@thelustrecollective.com> Change-Id: I80c0c6f64aa8e6cfeb7d5ffc81fdce54f6a9acae
▶Voted on current patchset
(21)
70067
master
J –B ✓T ↻R +3/2
LU-20690 ec: copy parity in 1+N recovery reads
reviewing Zhenyu Xu · you voted +1 on current PS
pw_shepherd218_review_prioritypt_ecro
1 unresolved
M +87 −14
5m
LU-20690 ec: copy parity in 1+N recovery reads
reviewing Zhenyu Xu · you voted +1 on current PS
pw_shepherd218_review_prioritypt_ecro
1 unresolved
M +87 −14
5m
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-part-5 retesting crashed | RHEL 10.2 / x86_64 | ran 5 tests. 1 tests failed: sanityn. %% THIS TEST SESSION CRASHED %% | session |
build #135384 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1 · Ronnie Sahlberg +1 · Andreas Dilger +1
no vote yet: Marc Vef
patchsets:
PS1 10-27
PS2 11-03 Andreas Dilger
PS3 11-04 Andreas Dilger
your previous vote: +1 on PS1 (2026-10-27 12:11) — now at PS3
threads: 1 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Andreas Dilger COMMIT_MSG:29 — Correction to my comment above: EC is not in any release. 2.17.0 has only the format definitions (LCME_FL_PARITY) and the EC library, not th
Gerrit AI review for Lustre
(minor) This fixes data corruption on degraded reads, so should it carry a Fixes: line? The wrong decode for a single-data-stripe raidset goes back to the original recovery code, not only to --ec 1+N:
Fixes: 783c13bb0b8f ("LU-12669 ec: recover data from parity")
lov_io_ec_rd_start() has always used the per-raidset dcount (sc.esc_k1 for the tail raidsets). llapi_ec_compute_parities() is also called with the per-raidset k, so it memcpy()s for those raidsets. ec_split_stripes(5, 2) gives n0=2 k0=2 n1=1 k1=1, so a `-c 5 --ec 2+2` file (and the same for -c 7, -c 9, ...) has a 1+2 tail raidset. Before this patch, losing that raidset's data stripe and parity 0 returned data * 2. That layout was valid before LU-20568 allowed --ec 1+N.
If the patch is refreshed, it may help to say in the body that this case is fixed as well, since it affects released layouts and matters when deciding on backports.
Andreas Dilger
Agreed, this is not only --ec 1+N. ec_split_stripes() gives a raidset with one data stripe in several layouts that were already valid before --ec 1+N was allowed: - the tail raidset of an odd stripe count with --ec 2+N: ec_split_stripes(5, 2) gives 2 raidsets of 2 and 1 of 1, so `lfs setstripe -c 5 --ec 2+2` (likewise -c 7, -c 9, ...) has a 1+2 tail raidset - any -c 1 component with an EC layout, since ec_split_stripes(1, k) always gives k = 1 llapi_ec_compute_parities() is called with the per-raidset k, so it memcpy()s the parity for these raidsets, and lov_io_ec_rd_start() uses the per-raidset dcount. Losing the data stripe and parity 0 of such a raidset thus returned data * gf_inv(2) on released versions too. That makes this a data corruption fix that needs to be backported, so please add the Fixes: line and describe these cases in the commit message. It would also be good to have a test for the released-layout case, e.g. a variant of test_40e with `-c 5 --ec 2+2` that fails the data OST of the 1+2 tail raidset and its parity 0, and checks the md5sum. The fix keys on the per-raidset dcount, so it should already cover this.
Andreas Dilger
Correction to my comment above: EC is not in any release. 2.17.0 has only the format definitions (LCME_FL_PARITY) and the EC library, not the client recovery read or the llapi parity code, so no released files have these layouts and no Fixes: or backport is needed. The rest still applies to master: the fix also covers raidsets with one data stripe that are not --ec 1+N (the tail raidset of `-c 5 --ec 2+2`, and -c 1 components), so the commit message could say so, and a `-c 5 --ec 2+2` variant of test_40e would cover the tail raidset case.
tags: pw_shepherd 218_review_priority pt_ecro
owner Zhenyu Xu · uploader Andreas Dilger · PS3 uploaded 1d ago · NEW · open in Gerrit ↗
commit message
LU-20690 ec: copy parity in 1+N recovery reads A raidset with one data stripe stores a copy of that stripe in each of its p parity objects: llapi_ec_compute_parities() memcpy()s the data instead of calling ec_encode_data() when k == 1, so --ec 1+N writes p identical copies. The client recovery path did not know this and always ran the Cauchy decode, where the coefficient of parity stripe i is gf_inv(i + 1). Only parity stripe 0 has coefficient 1, matching what is on disk. A read that lost the data stripe and parity stripe 0, and fell back to any other parity, thus returned data * 2, * 3, ... rather than the data. Copy the first parity page that could be read over the error page when the raidset has one data stripe, in lov_ec_recover_page(). The RS setup is of no use in that case either, so skip the encode matrix in lov_ec_bufs_alloc() and the scratch matrices, GF tables, matrix inversion and ec_init_tables() in lov_ec_recover_init() when dcount is 1. Add sanity-ec test 40e, which fails the data OST and the OST of parity stripe 0 in a 1+2 layout, so the read has to be rebuilt from parity stripe 1. Test-Parameters: testlist=sanity-ec ostcount=8 Signed-off-by: Bobi Jam <bobijam@whamcloud.com> Assisted-by: AugmentAgent:DeepSeek-V4.1-Flash Change-Id: Idbe55e61f464d1e91bb5093bf1c41442dc588f72
69694
master
J –B ✓T ✓R +1/2
LU-20958 llite: only update blocks after a flush
reviewing Andreas Dilger · you voted +1 on current PS
pt_ecro218_review_priority
1 unresolved
M +116 −10
6m
LU-20958 llite: only update blocks after a flush
reviewing Andreas Dilger · you voted +1 on current PS
pt_ecro218_review_priority
1 unresolved
M +116 −10
6m
build #135070 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1
no vote yet: Zhenyu Xu
patchsets:
PS1 10-14
PS2 10-21 patrick bot
PS3 10-29
PS4 10-29
PS5 11-01
threads: 1 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre vvp_io.c:1412 — (minor) If the patch is refreshed: this says i_size is not shrunk, but ll_merge_attr_try() -> ll_merge_attr_nolock(..., true) still shrinks
Gerrit AI review for Lustre
(minor) If the patch is refreshed: this says i_size is not shrunk, but ll_merge_attr_try() -> ll_merge_attr_nolock(..., true) still shrinks i_size when cat_kms_partial is clear, i.e. once every stripe has had a lock granted (the truncate-on-another-client case described in the commit message). Maybe "so i_size is not shrunk while some stripe size is unknown", to match the ll_merge_attr_nolock() kernel-doc.
tags: pt_ecro 218_review_priority
owner Andreas Dilger · uploader Andreas Dilger · PS5 uploaded 4d ago · NEW · open in Gerrit ↗
commit message
LU-20958 llite: only update blocks after a flush
vvp_io_fsync_end() merges the stripe attributes into the inode after
every flush and OST sync, to update the blocks for LSOM. Neither
takes a lock on the stripes, so the merged size and blocks are only
what this client last cached for each stripe. That replaces a valid
i_size, e.g. a strict SOM size from the MDS, with a smaller one, down
to 0, for example in the local flush before lseek(SEEK_DATA). An
lseek of an EC file with a stripe on an unavailable OST then finds no
data before this EOF.
Only update i_blocks there, which is what LSOM needed, and not while
i_size and i_blocks came from the MDS.
A write only locks the stripes it covers, and a stripe that this
client never held a lock on only has the size last cached for it, 0
if never seen, so the merge after a write, an O_SYNC write or a tiny
write could also shrink i_size, e.g. to 1MiB after a write at offset
0 of a 3MiB file with three 1MiB stripes whose size came from the
MDS. Have lov_merge_lvb_kms() report such a stripe in the new
cl_attr::cat_kms_partial, and since a write never makes a file
shorter, let these merges only grow i_size then. When the size of
every stripe is known, they may still shrink i_size, e.g. after a
truncate on another client. If that truncate changed the layout, a
write merge can keep a stale larger i_size until a glimpse, which
only affects the lazy SOM size sent at close.
Add sanity-flr test_44j, which checks that an fsync does not
shrink the strict SOM size of a mirrored file.
Test-Parameters: testlist=sanity-flr
Fixes: dfb08bbf77a1 ("LU-16465 llite: fix LSOM blocks for ftruncate and close")
Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com>
Assisted-by: ClaudeCode:claude-opus-5-5 ltvm llm_code_and_review_tools
Change-Id: Id5561dd9af3aec5f966ae4db4bc055bb213ebbe5
70150
master
J –B ✓T …R +1/2
LU-19823 lod: fit EC raid sets to the OSTs without domains
reviewing Andreas Dilger · you voted +1 on current PS
pt_ecro218_review_prioritypw_shepherd
3 unresolved
L +339 −124
2h
LU-19823 lod: fit EC raid sets to the OSTs without domains
reviewing Andreas Dilger · you voted +1 on current PS
pt_ecro218_review_prioritypw_shepherd
3 unresolved
L +339 −124
2h
reviews:
Keguang Xu +1
no vote yet: Ronnie Sahlberg
patchsets:
PS1 10-29
PS2 11-05
threads: 1 need your reply · 0 waiting on others · 2 own notes · 0 bot
note Keguang Xu ec.txt:95 — Only in `ec_split_stripes(5, 2)` we'd have *{3+2, 2+2}*, while with `lfs -c 5 --ec 2+2` we'd have *{2+2, 2+2}* as the final outcome?
Keguang Xu
Only in `ec_split_stripes(5, 2)` we'd have *{3+2, 2+2}*, while with `lfs -c 5 --ec 2+2` we'd have *{2+2, 2+2}* as the final outcome?
reply Andreas Dilger lfs-setstripe.1:419 — Yes, the floor only applies when the stripe count fits the OSTs. I will reword this sentence at the next refresh.
Gerrit AI review for Lustre
(minor) Following the lod_ec_fit_fdoms() question: when STRIPE_COUNT is larger than the available OSTs, the raid sets can end up below 3/4 of DATA_STRIPES (e.g. `-c 12 --ec 6+3` on 7 OSTs gives 4+3 and 3+3). If that is intended, could this sentence say the floor only applies when the stripe count fits the OSTs?
Andreas Dilger
Yes, the floor only applies when the stripe count fits the OSTs. I will reword this sentence at the next refresh.
note Keguang Xu lod_qos.c:3879 — (discussion) We've already considered *failover* besides *failure domain* in RR allocation array `lqr_pool.op_array` in previous patches, sh
Keguang Xu
(discussion) We've already considered *failover* besides *failure domain* in RR allocation array `lqr_pool.op_array` in previous patches, should we consider it here as well in the future?
tags: pt_ecro 218_review_priority pw_shepherd
owner Andreas Dilger · uploader Andreas Dilger · PS2 uploaded 4h ago · NEW · open in Gerrit ↗
commit message
LU-19823 lod: fit EC raid sets to the OSTs without domains
With "lfs setstripe -c 6 --ec 6+3" on 8 OSTs, QoS shrank the single
raid set to 5+3 so that its parity fit, while RR placed all 6 data
stripes and then failed with ENOSPC when it found only 2 OSTs left
for the parity. Which one ran depended on the free space balance of
the OSTs, so sanity-ec test_27h passed or failed depending on the
earlier tests.
lod_ec_fit_fdoms() already fits the raid sets to the failure domains
before either allocator places the data. Without failure domains,
count each active OST as a domain of its own, so RR and QoS fit the
same K. A -c component wider than the active OSTs is fitted by the
stripes it can place, and keeps that stripe count. If its raid sets
must shrink, it is still to at least 3/4 of the requested K. As with
domains, a layout may be stored with the smaller K of its raid sets.
Describe this in lfs-setstripe.1.
ec_split_stripes() split an odd number of data stripes with K=2 into
raid sets of 2 and one set with a single data stripe, e.g. {2, 2, 1}
for 5 stripes. The parity of that set is only a copy of its one data
stripe, but it needs as many parity stripes as a full raid set, and
the extra set made layouts such as "-c 5 --ec 2+2" fail the check that
the parity stripes fit in the data stripe count. Use one raid set
fewer in this case, so the residual stripe goes into the first raid
set, {3, 2} for 5 stripes and {3, 2, 2} for 7. K=2 with an odd total
of 5 or more stripes is the only case that made a single-stripe raid
set, other splits are unchanged. All users of the split size their
buffers from esc_k0 rather than K, as a 3-stripe file with K=2 already
gives one raid set of 3. The split is computed from the layout rather
than stored in it, so it has to change before EC layouts are in use.
A 3-stripe raid set needs one more OST or failure domain than the
others. If there are only enough for K=2, lod_ec_fit_fdoms() leaves
out one data stripe, so "-c 5 --ec 2+2" with 4 failure domains is
two raid sets of 2+2, and with 5 it is 3+2 and 2+2.
lod_ec_shrink_data_geometry() reduced the split one data stripe at a
time when fewer OSTs were available, which could leave a single-stripe
raid set, e.g. {2, 2, 1} for 5 of 6 stripes, unlike the split that
clients compute from the layout. Use ec_split_stripes() for the
reduced count instead, also for the RR shrink to 75% of the stripes.
Since the fitted raid sets were checked against the failure domains,
never make a raid set larger when shrinking: use the largest raid set
as K if a single raid set of K would be larger, and leave out one more
stripe if an odd count with K=2 would make a raid set of 3. Move
lod_ec_shrink_data_geometry() after lod_comp_find_linked(), which it
now uses to set the smaller K in the parity component too.
lod_stripe_count_min() counted every kept raid set as esc_k0 stripes,
so "-c 9 --ec 2+1", {3, 2, 2, 2}, could not shrink at all. Leave out
the smallest raid sets instead.
Have sanity-ec test_27h check that a layout which can't fit fails, and
one that can gets fewer data stripes, with both the RR and QoS
allocators. Add test_31h to check the new raid sets with --ec-map and
that "-c 5 --ec 2+2" works, test_31i for "-c 5 --ec 2+2" with 4 and 5
failure domains, and test_65e for recovery of a 3-stripe raid set.
Test-Parameters: trivial testlist=sanity-ec
Fixes: c53abca9f9ee ("LU-19852 lod: raidset aware stripe allocator")
Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com>
Assisted-by: ClaudeCode:claude-opus-5-5 ltvm llm_code_and_review_tools
Change-Id: Ief45b5df095e03fd96065b85eb6b1008bd3ebbe5
70212
master
J –B ✓T ✓R +2/2
LU-20565 tests: remove duplicate sanity-ec subtests
reviewing Andreas Dilger · you voted +1 on current PS
pt_ecrotestfix
L +7 −716
7h
LU-20565 tests: remove duplicate sanity-ec subtests
reviewing Andreas Dilger · you voted +1 on current PS
pt_ecrotestfix
L +7 −716
7h
build #134845 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1 · Marc Vef +1
tags: pt_ecro testfix
owner Andreas Dilger · uploader Andreas Dilger · PS1 uploaded 6d ago · NEW · open in Gerrit ↗
commit message
LU-20565 tests: remove duplicate sanity-ec subtests Many sanity-ec degraded-read subtests repeated the same layout, write, resync and fault as another subtest. They would add run time and setup cost without testing anything the other subtest did not. Remove each subtest whose checks another subtest already makes: - 11 (create 2+2): 12a creates the same layout and checks parity - 30a (write stales parity, resync): 23a and 28a check the same ro/wp/stale transitions, 6b checks the data across the resync - 41f (DIO read after buffered write): 41i does that after a buffered degraded read of the same file - 43c, 44c (EIO when all reads fail): 44a, which also reads the file again after the fault is cleared - 43d (fail 1, then 2 stripes): 63c fails 1, then 2, then 1 again - 44b (repeat a 1-OST fault): 63a and 63c fail and clear faults repeatedly on the same file - 45a (fail stripes 0 and 1): 43b is the same test - 45c (fail only parity OSTs): 75a, which now fails every parity OST that holds no data rather than one, and also checks stat and getstripe - 47a (2+1 then 4+2 PFL): 68d, which fails each safe OST in turn - 47c (1M then 4M stripe PFL): 46d - 47d (read across a PFL boundary): 42d - 63b (every pair of safe OSTs): 58a is the same test - 64b (stale parity read, then resync): 48c - 64c (3 rewrite/resync rounds from mount2): 64a does 2 rounds - 65a (3-component PFL): 65b uses 4 components of mixed geometry and stripe size - 67b (rewrite and resync 3 times): 75b repeats overwrite, resync and degraded read 50 times, and 64a covers truncating rewrites Test-Parameters: trivial testlist=sanity-ec Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com> Assisted-by: ClaudeCode:claude-opus-5-5 ltvm llm_code_and_review_tools Change-Id: I8d081a238b2ef8f7d0b84b96514092ec773ebbe5
70469
master
J –B ✓T …R +2/2
LU-20287 tests: handle IDIF FIDs in ost_fid2_objpath()
reviewing Andreas Dilger · you voted +1 on current PS
pt_ecro218_review_priority
XS +9 −0
7h
LU-20287 tests: handle IDIF FIDs in ost_fid2_objpath()
reviewing Andreas Dilger · you voted +1 on current PS
pt_ecro218_review_priority
XS +9 −0
7h
reviews:
Keguang Xu +1 · Ronnie Sahlberg +1
no vote yet: Marc Vef
tags: pt_ecro 218_review_priority
owner Andreas Dilger · uploader Andreas Dilger · PS1 uploaded 9h ago · NEW · open in Gerrit ↗
commit message
LU-20287 tests: handle IDIF FIDs in ost_fid2_objpath() sanity test_39v failed in every interop session with 2.15 servers with "OST0 uid:gid : != 500:500". A 2.15 OST gives MDT0 objects IDIF FIDs like [0x100000000:0x42e:0x0], which ost_fid2_objpath() turned into O/100000000/d14/42e, so debugfs could not find the object to check its owner. An IDIF FID holds the OST index and the high 16 bits of a 48-bit object id in its sequence, and the object is stored in O/0 under its decimal object id. Return that path for an IDIF FID, so 39v and the other callers of ost_fid2_objpath() work with such OSTs. Test-Parameters: trivial Test-Parameters: testlist=sanity serverversion=2.15 env=ONLY=39v Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com> Assisted-by: ClaudeCode:claude-opus-5-5 ltvm llm_code_and_review_tools Change-Id: Id9e222f5ad61e75162ecfe2f5d8981dc543ebbe5
66481
master
J –B ✓T …R +2/2
LU-12669 ec: fix EC recovery read for encrypted files
reviewing Zhenyu Xu · you voted +1 on current PS
ec2
pt_ecro218_review_blocker
L +344 −29
7h
LU-12669 ec: fix EC recovery read for encrypted files
reviewing Zhenyu Xu · you voted +1 on current PS
ec2
pt_ecro218_review_blocker
L +344 −29
7h
reviews:
Keguang Xu +1 · Andreas Dilger +1
no vote yet: Marc Vef
patchsets:
PS21 08-19
PS22 08-20
PS23 10-08 Andreas Dilger
PS24 10-28 Andreas Dilger
PS25 11-04 Andreas Dilger
+20 earlier
PS1 06-05 PS2 06-06 PS3 06-06 PS4 06-06 PS5 06-07 PS6 06-08 PS7 06-11 PS8 06-11 PS9 06-11 PS10 06-12 PS11 06-30 PS12 07-16 Marc Vef PS13 07-26 Marc Vef PS14 07-26 Marc Vef PS15 08-01 Marc Vef PS16 08-10 Keguang Xu PS17 08-10 PS18 08-10 PS19 08-11 PS20 08-11tags: pt_ecro 218_review_blocker
owner Zhenyu Xu · uploader Andreas Dilger · PS25 uploaded 11h ago · NEW · open in Gerrit ↗
commit message
LU-12669 ec: fix EC recovery read for encrypted files
The parity of an encrypted file is computed from its data as stored
on the OSTs, but an EC recovery read rebuilds a stripe from data
pages that OSC has already decrypted, together with the parity as
stored, and returns garbage.
Rebuild the stripe from the data as stored instead: have OSC leave
the data pages read for the recovery encrypted and not uptodate,
rebuild the missing pages from them and the parity, then decrypt the
pages read and rebuilt. Leave each all-zero encryption unit (a hole)
as it is, including one followed by data in a page larger than the
unit. A data page already in the page cache holds the plaintext, so
read the stripe again from the OST for the positions being rebuilt,
rather than encrypting the plaintext, which cannot recreate the
stored data of a hole. Without the key, leave the pages encrypted,
as a normal read does. Keep these pages out of extents that OSC
decrypts, and send the encryption flag with the parity reads. If
the recovery fails, delete the data pages that were not decrypted,
so that a readahead page does not later return the ciphertext.
Add sanity-ec test_56a to recover an encrypted file with a hole in
a surviving stripe, both from the OSTs and with that stripe cached.
Fixes: 783c13bb0b8f ("LU-12669 ec: recover data from parity")
Signed-off-by: Bobi Jam <bobijam@whamcloud.com>
Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com>
Assisted-by: ClaudeCode:claude-opus-5.5 ltvm llm_code_and_review_tools
Change-Id: Ida4722d05d79bcbee4e680e75e94b005579adcac
64919
master
J –B ✓T …R +1/2
LU-12669 lov: slow and dead OST detection for degraded reads
reviewing Maximilian Dilger · you voted +1 on current PS
218_review_prioritypw_shepherdpt_ecro
5 unresolved
XL +2385 −77
7h
LU-12669 lov: slow and dead OST detection for degraded reads
reviewing Maximilian Dilger · you voted +1 on current PS
218_review_prioritypw_shepherdpt_ecro
5 unresolved
XL +2385 −77
7h
reviews:
Keguang Xu +1
no vote yet: Ronnie Sahlberg, Andreas Dilger, Zhenyu Xu
patchsets:
PS49 10-05 Andreas Dilger
PS50 10-05 Andreas Dilger
PS51 10-15 Andreas Dilger
PS52 10-24 Andreas Dilger
PS53 11-04
+48 earlier
PS1 03-26 PS2 03-26 PS3 03-29 Andreas Dilger PS4 03-29 Patrick Farrell PS5 03-29 Patrick Farrell PS6 03-29 Patrick Farrell PS7 03-29 Ronnie Sahlberg PS8 03-30 Ronnie Sahlberg PS9 03-31 Ronnie Sahlberg PS10 03-31 Patrick Farrell PS11 03-31 Ronnie Sahlberg PS12 04-01 Ronnie Sahlberg PS13 04-01 Ronnie Sahlberg PS14 04-07 Ronnie Sahlberg PS15 04-08 Patrick Farrell PS16 04-09 Patrick Farrell PS17 04-09 Patrick Farrell PS18 04-09 Patrick Farrell PS19 04-09 Patrick Farrell PS20 04-09 Patrick Farrell PS21 04-09 Patrick Farrell PS22 04-09 Patrick Farrell PS23 04-09 Patrick Farrell PS24 04-10 Patrick Farrell PS25 04-10 Patrick Farrell PS26 04-10 Patrick Farrell PS27 04-10 Patrick Farrell PS28 04-10 Patrick Farrell PS29 04-14 Patrick Farrell PS30 04-14 Patrick Farrell PS31 04-14 Patrick Farrell PS32 04-15 Patrick Farrell PS33 04-15 Patrick Farrell PS34 04-15 Patrick Farrell PS35 04-21 PS36 04-25 PS37 05-04 PS38 05-20 Marc Vef PS39 06-04 Ronnie Sahlberg PS40 07-13 Marc Vef PS41 07-13 Marc Vef PS42 07-13 Marc Vef PS43 07-15 Marc Vef PS44 07-26 Marc Vef PS45 07-26 Marc Vef PS46 08-04 PS47 08-19 PS48 09-26your previous vote: +1 on PS52 (2026-11-03 01:33) — now at PS53
threads: 5 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre COMMIT_MSG:62 — (minor) Earlier review agreed to keep the lov_io_set_range(), readahead and via_hybrid_switched fixes in this patch. The io_latency_stats ar
Gerrit AI review for Lustre
(minor) Earlier review agreed to keep the lov_io_set_range(), readahead and via_hybrid_switched fixes in this patch. The io_latency_stats array fix is newer, though, and is a different case. The arrays are allocated with PTLRPC_MAX_BRW_BITS - PAGE_SHIFT entries, but brw_interpret() indexes them with fls(page_count) - 1. A maximum-size RPC therefore writes one histogram past the end of the allocation. d67cf23fb18a is already in 2.17.0, so this heap overflow needs to reach b2_17, and the EC degraded-read feature will not be backported there. Could the OSC_LAT_BUCKETS change go in a separate patch with its own Fixes: line, so it can be cherry-picked on its own?
reply Marc Vef patchset comment — Conflicts with master: Does not apply after the 1 change below it: lustre/osc/osc_cache.c
Marc Vef
Conflicts with master: Does not apply after the 1 change below it: lustre/osc/osc_cache.c
reply Gerrit AI review for Lustre lov_io.c:3631 — (defect) lov_sub_unavailable() is evaluated again for every parity stripe on each pass, and the answer can change between the passes. Pass 0
Gerrit AI review for Lustre
(defect) lov_sub_unavailable() is evaluated again for every parity stripe on each pass, and the answer can change between the passes. Pass 0 does a synchronous lov_ec_read_parity_stripe() (cl_sync_io_wait(), no soft deadline) for each available stripe, and a slow mark is time-bound, so cl_read_slow_until can expire while pass 0 is reading. Example, err_nr == 2, pcount == 2, parity p0 slow-marked: pass 0 skips p0 and reads p1. p0's mark expires during that read. Pass 1 now sees p0 as available, so `lov_sub_unavailable(los) != pass` skips it again, par_stripes_used stays 1, and the read fails with "not enough parity stripes" -EIO. Before this patch the single loop would have read p0 and recovered. The opposite flip (a stripe already read in pass 0 gets marked slow by another reader's soft timeout) would read it again and put the same index twice into ecr_parity_used[], which makes the decode matrix singular (-EIO from gf_invert_matrix()). Could the availability of each parity stripe be sampled once before the passes (e.g. a small bitmap of pcount bits) so each stripe is tried exactly once?
reply Gerrit AI review for Lustre lov_lock.c:238 — (minor) Is it intended that this also matches stripes that have no sub-IO only because they are past EOF? lov_ecio_add_data_sub() caps data_
Gerrit AI review for Lustre
(minor) Is it intended that this also matches stripes that have no sub-IO only because they are past EOF? lov_ecio_add_data_sub() caps data_ext at ec_inode_size, so in a small file the other data stripes of the expanded raid set get no sub-IO, while io_ext here is the uncapped [lis_pos, lis_endpos). Those sub-locks on healthy OSTs are then turned into placeholders instead of being enqueued.
That may well be harmless (no pages are rebuilt there), but it is not what the comment says ("as it routes around the OST, is rebuilt"), and it widens the placeholder use from unavailable OSTs to every stripe past EOF of a degraded read. If the patch is refreshed, either intersect with the EOF-capped extent here, or document the past-EOF case in the comment and commit message.
reply Gerrit AI review for Lustre osc_request.c:4231 — (minor) osc_setup_common() is also called by mdc_setup(), and DoM reads go through the same osc_queue_sync_pages()/osc_build_rpc() path, so
Gerrit AI review for Lustre
(minor) osc_setup_common() is also called by mdc_setup(), and DoM reads go through the same osc_queue_sync_pages()/osc_build_rpc() path, so a mirrored file with a DoM component gets soft deadlines on its MDT reads with slow_read_pct=300. But slow_read_pct, slow_read_min_ms and slow_read_stats are only registered for osc, so an admin cannot see or turn this off for the MDC (`osc.*.slow_read_pct=0` does not cover it). Should MDC either get the same tunables, or start with cl_slow_read_pct = 0?
tags: 218_review_priority pw_shepherd pt_ecro
owner Maximilian Dilger · uploader Maximilian Dilger · PS53 uploaded 11h ago · NEW · open in Gerrit ↗
commit message
LU-12669 lov: slow and dead OST detection for degraded reads
A read of an EC file whose data stripe is on a dead OST waits for
the RPC's adaptive timeout, 7 s in production, before it is
reconstructed from parity; a slow OSS extends that with early
replies, and even a dead import costs the FLR retry rounds first.
Give such reads a soft deadline and route around the OST. A
request past it fails with -ETIMEDOUT without failing the import or
touching the adaptive timeout. Each OSC keeps a smoothed OST_READ
latency and deviation per RPC size, as for the TCP retransmission
timer, and a top-level no-delay read of an EC or mirrored file gets
a deadline, counted from its send, of the largest of
osc.*.slow_read_pct (default 300) percent of the smoothed latency,
that latency plus four deviations, and osc.*.slow_read_min_ms
(default 250 ms for a non-rotational OST, 2 s otherwise). An
abandoned read marks the import slow for four times its deadline;
each further soft timeout before a successful read doubles the
deadline and the mark, up to the adaptive timeout.
LOV treats a deactivated, invalid, disconnected or slow-marked import
as unavailable, but not one reconnecting from idle. A read of a dead
stripe is reconstructed at once when its raid set's own parity covers
its dead stripes, and of a slow-marked one only when it covers all of
its unavailable stripes; otherwise the read waits for them, e.g. until
an OSS failover completes. A read spanning several raid sets waits if
any of them cannot be rebuilt. With no in-sync parity the file reads
like a plain mirror. A read of part of a raid set, whose
reconstruction reads many times its size, gets no soft deadline and is
not reconstructed around a slow stripe when most of the set's other
stripes are on OSTs running at over twice their median latency since
mount and over an eighth of slow_read_min_ms. A plain mirror's
buffered reads get the same deadline and rotate mirrors on expiry,
unless no other mirror can serve the read. An EC read skips the lock
and read of a stripe it reconstructs by having no sub-IO for it,
rather than through the lso_status shared with other readers.
osc.*.slow_read_stats shows the estimates and counters.
A 1MiB read of stripe 0 of a 4+2 EC file on an 8-OST VM, with one
30s stall of its OST (OBD_FAIL_OST_BRW_PAUSE_BULK), then 200 1MiB
direct and 200 4KiB buffered random reads while 4 writers load all
OSTs:
slow_read_pct 0 (off) 300 (default)
direct read, stall 30053ms 2069ms
buffered read, stall 30055ms 2048ms
reads under load: 0 soft timeouts, no extra parity or survivor reads
Also fix lov_io_set_range() rounding the reconstruction range end
past its component, which LBUGged "uncovered page!"; the
ra_cur_pages leak in ll_readahead_handle_work() when
cl_io_rw_init() fails, which stopped readahead for the mount; and
do_file_read_iter() never clearing via_hybrid_switched, which ran
later O_DIRECT AIO reads on the same lu_env synchronously. Also fix
ll_readahead_handle_work() passing a page index and count to
cl_io_rw_init() as bytes, which routed async readahead of FLR and EC
files by the wrong extent, and the client io_latency_stats arrays
being one size short for a maximum-size RPC.
Add sanity-ec 54a-54k, and change test_29a to check that a read with
more stripes lost than parity waits for their OSTs.
Test-Parameters: testlist=sanity-ec ostcount=8
Test-Parameters: testlist=sanity-ec ostcount=8 fstype=zfs
Test-Parameters: testlist=sanity,sanity-flr ostcount=8
Fixes: c2791674260b ("LU-12043 llite: improve single-thread read performance")
Fixes: 3fc4243da7ef ("LU-13802 llite: tag switched hybrid IOs")
Fixes: 783c13bb0b8f ("LU-12669 ec: recover data from parity")
Fixes: d67cf23fb18a ("LU-18993 osc: Add IO RPC latency statistics by size")
Signed-off-by: Maximilian Dilger <mdilger@whamcloud.com>
Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com>
Assisted-by: ClaudeCode:claude-opus-5.5 ltvm,llm_code_and_review_tools
Change-Id: I0913e1ee977c9850193c92835edb185b0aedc6d4
69493
master
J –B ✓T ✓R +3/2
LU-19823 lod: unique failure domains per EC raid set
reviewing Andreas Dilger · you voted +1 on current PS
pt_ecropw_shepherd218_review_blocker218_review_priority
L +464 −119
10h
LU-19823 lod: unique failure domains per EC raid set
reviewing Andreas Dilger · you voted +1 on current PS
pt_ecropw_shepherd218_review_blocker218_review_priority
L +464 −119
10h
build #134652 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1 · Ronnie Sahlberg +1 · Maximilian Dilger +1
no vote yet: Marc Vef, kg.xu, Oleg Drokin
patchsets:
PS1 10-07
PS2 10-13
PS3 10-24
PS4 10-27
PS5 10-28
your previous vote: +1 on PS3 (2026-10-26 09:23) — now at PS5
tags: pt_ecro pw_shepherd 218_review_blocker 218_review_priority
owner Andreas Dilger · uploader Andreas Dilger · PS5 uploaded 7d ago · NEW · open in Gerrit ↗
commit message
LU-19823 lod: unique failure domains per EC raid set
With "lfs setstripe -c N --ec K+M" the allocator required every data
and parity stripe of the component to be in a different failure
domain, while with -C this was only needed within each raid set.
A wide file such as "-c 40 --ec 8+2" on 40 OSTs needs 10 domains
per raid set but 50 for the component, so it failed with ENOSPC
unless the file was overstriped.
Each raid set is protected on its own, so require different failure
domains only within each raid set, for both -c and -C. With -c the
data stripes are still on different OSTs, so the file can use the
bandwidth of all OSTs, and parity shares OSTs with the data of other
raid sets. A -c component short of OSTs is split into raid sets
again after its stripes are placed, so keep each run of consecutive
data stripes as long as the largest possible raid set in different
domains. QoS no longer trims the data stripes of a -c component with
several raid sets to leave separate OSTs for its parity.
Each raid set still needs its data and parity stripes in different
failure domains, but the data stripes of a -c component need fewer, so
with too few domains the data could be placed and the RR allocator
then accepted a parity component with too few stripes. Check the
domains before placing the data, and use raid sets of fewer data
stripes, down to K - K/4 as in lod_stripe_count_min(), or fail with
ENOSPC. A single raid set gets fewer data stripes, so "-c 3 --ec 2+1"
with 3 domains becomes "-c 2 --ec 2+1". Also fail a parity component
that RR could not place completely, as QoS does, since other mirrors
can use up domains that this check does not see.
An EC file is also two mirrors, so the FLR check required different
domains for all stripes of the data component too. Leave the domains
within an EC component to the EC check.
Also fix lod_comp_find_linked() matching a plain mirror component to
the parity of an EC mirror, which let the plain mirror share a failure
domain with that parity, and restore the count of OSTs available to
mirrors when QoS gives up, so the RR fallback can place EC stripes.
Rename lod_fd_check_*() to lod_fdom_check_*() so "fd" is not read as a
file descriptor. Describe the mirror rules in
obdfilter.failure_domain.4 and reference it from lfs-setstripe.1,
lfs-mirror-create.1 and lfs-mirror-extend.1.
Fixes: 026de09ead3d ("LU-19823 lod: Make the stripe allocators failure domain aware.")
Fixes: c53abca9f9ee ("LU-19852 lod: raidset aware stripe allocator")
Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com>
Assisted-by: ClaudeCode:claude-opus-5.5 ltvm,llm_code_and_review_tools
Change-Id: Ic197df8fba1a9e0a313442cc435d1959763ebbe5
69614
master
J –B ✓T ✓R +2/2
LU-20935 llite: reject unaligned punch on encrypted files
reviewing Zhenyu Xu · you voted +1 on current PS
pw_shepherd
master-next
2 unresolved
M +68 −0
11h
LU-20935 llite: reject unaligned punch on encrypted files
reviewing Zhenyu Xu · you voted +1 on current PS
pw_shepherd
master-next
2 unresolved
M +68 −0
11h
build #133757 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1 · Sebastien Buisson +1
no vote yet: Oleg Drokin
patchsets:
PS1 10-12
PS2 10-14
PS3 10-15
threads: 1 need your reply · 0 waiting on others · 1 own notes · 0 bot
reply Oleg Drokin patchset comment — sanity-sec test_48c, added by this patch, fails on an aarch64 64KiB PAGE_SIZE
Oleg Drokin
sanity-sec test_48c, added by this patch, fails on an aarch64 64KiB PAGE_SIZE
client in lustre-master-next 1020 ("aligned punch corrupted file"), while it
passes on all 56 x86_64 sessions:
https://testing.whamcloud.com/test_sets/ca88e97b-1aa8-4d19-8042-a44ab2eee271
The aligned 4KiB punch lands inside a single 64KiB page, which needs the
sub-page hole decryption fix in 69680, and 69680 is not in this -next build.
Please make this change depend on 69680, or skip 48c when PAGE_SIZE > 4096
until 69680 lands.
note Keguang Xu sanity-sec.sh:5995 — could use stack_trap to remove these files? if a refresh later needed
Keguang Xu
could use stack_trap to remove these files? if a refresh later needed
tags: pw_shepherd
owner Zhenyu Xu · uploader Zhenyu Xu · PS3 uploaded 21d ago · NEW · open in Gerrit ↗
commit message
LU-20935 llite: reject unaligned punch on encrypted files
An encrypted file is stored on the OST as ciphertext, one whole
LUSTRE_ENCRYPTION_UNIT_SIZE (4KB) encryption unit at a time, and the
client encrypts and decrypts a whole unit at once. ll_fallocate()
already refuses FALLOC_FL_COLLAPSE_RANGE, FALLOC_FL_INSERT_RANGE and
FALLOC_FL_ZERO_RANGE on encrypted files (LU-12275), but it still
forwarded fallocate(FALLOC_FL_PUNCH_HOLE) with an offset or length
that is not aligned to the encryption unit to the OST.
For such a partial-unit punch the OST only clears the requested byte
sub-range of the ciphertext unit and leaves the rest of the unit
intact. A later read decrypts the whole unit, so a partially zeroed
ciphertext unit decrypts to garbage: both the punched bytes and the
bytes around them are silently corrupted on disk, and the corruption
is visible from another client that has the key. Page-aligned punches
are unaffected.
Refuse a punch that is not aligned to LUSTRE_ENCRYPTION_UNIT_SIZE on
an encrypted file with -EOPNOTSUPP, instead of corrupting the file.
Add sanity-sec test_48c to check that an unaligned punch is refused
and leaves the file unchanged, and that an aligned punch zeroes
exactly the requested encryption unit and no more.
Test-Parameters: testlist=sanity-sec env=ONLY=48c
Fixes: cb037f305c ("LU-14160 fallocate: Add punch mode to fallocate")
Signed-off-by: Bobi Jam <bobijam@whamcloud.com>
Change-Id: Ieaf7c3d2dbdc4303744dc6b2f4c808e53124bc40
69350
master
J –B ✓T ✓R +2/2
LU-12669 ec: create lock placeholder for reconstructed pages
reviewing Andreas Dilger · you voted +1 on current PS
218_review_prioritypt_ecropw_shepherd
master-next
4 unresolved
L +532 −68
11h
LU-12669 ec: create lock placeholder for reconstructed pages
reviewing Andreas Dilger · you voted +1 on current PS
218_review_prioritypt_ecropw_shepherd
master-next
4 unresolved
L +532 −68
11h
build #134472 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1 · Zhenyu Xu +1
no vote yet: Marc Vef, Patrick Farrell
patchsets:
PS3 10-13
PS4 10-13
PS5 10-14
PS6 10-14
PS7 10-26
+2 earlier
PS1 10-01 PS2 10-01your previous vote: +1 on PS6 (2026-10-18 11:53) — now at PS7
threads: 4 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre ldlm_request.c:583 — (minor) If the patch is refreshed: this says matchers must skip LDLM_FL_PLACEHOLDER unless they only test page coverage, but osc_lock_to_pla
Gerrit AI review for Lustre
(minor) If the patch is refreshed: this says matchers must skip LDLM_FL_PLACEHOLDER unless they only test page coverage, but osc_lock_to_placeholder() matches with skip_flags 0 and without LDLM_FL_TEST_LOCK, taking a reader reference so it can reuse an existing placeholder:
mode = ldlm_lock_match_with_skip(ns, LDLM_FL_BLOCK_GRANTED, 0, ...
LCK_PR, LDLM_MATCH_AST, &lockh);
The same "only matched by page coverage tests" wording appears in the osc_lock_to_placeholder() comment and in the commit message. Maybe mention placeholder reuse as the second allowed match, so a future caller doesn't treat the reuse match as a contract violation, or copy it as a precedent for a generic match?
reply Gerrit AI review for Lustre vvp_io.c:494 — (minor) If the patch is refreshed: this comment says the LOV layer uses a placeholder for these mmap-buffer locks, but vvp_mode_from_vma() r
Gerrit AI review for Lustre
(minor) If the patch is refreshed: this comment says the LOV layer uses a placeholder for these mmap-buffer locks, but vvp_mode_from_vma() returns CLM_WRITE for a shared writable mapping, and osc_lock_to_placeholder() refuses anything but LCK_PR. For such a buffer the stripe is only tolerated, and the reconstructed pages are dropped after the read through ec_unprotected_recovery. Maybe say "a placeholder for a read-mode lock"?
reply Andreas Dilger vvp_io.c:1583 — Right, the kept pages never leave cl_lru_busy. This is fixed by https://review.whamcloud.com/69908 ("LU-12669 ec: fix degraded read page le
Gerrit AI review for Lustre
(defect) Do the pages kept here ever reach the OSC LRU list? A reconstructed page is created by cl_page_find(CPT_CACHEABLE) in lov_ec_read_stripe_pages(), so osc_page_init()->osc_lru_alloc() reserves a cache slot for it (ops_in_lru = 1, cl_lru_busy++). A page only moves from "busy" onto cl_lru_list in osc_extent_finish()->osc_lru_add_batch(), after a BRW. A rebuilt page never goes through a BRW, so it stays counted in cl_lru_busy and takes a ccc_lru_left slot. osc_lru_shrink() only scans cl_lru_list, so it cannot reclaim the page. Before this change, cl_page_delete() here always returned the slot through osc_page_delete()->osc_lru_del(). Now the slot is held until the placeholder (or the granted lock) is cancelled, or until kernel memory reclaim calls ll_release_folio(). A large degraded read can pin max_cached_mb this way, e.g. one dead stripe of a 4+2 file several times larger than the cache. osc_lru_alloc() callers for any file on the mount then sleep in l_wait_event_abortable(osc_lru_waitq, cl_lru_left > 0), and readahead gets -EBUSY. This lasts until the placeholder ages out of the ldlm LRU. Should the kept pages be added to the client LRU when they are marked Uptodate, like osc_lru_add_batch() does after a read?
Andreas Dilger
Right, the kept pages never leave cl_lru_busy. This is fixed by https://review.whamcloud.com/69908 ("LU-12669 ec: fix degraded read page leak and short read"), which adds the kept pages to the client LRU with cl_page_lru_add(). That fix will be merged into this patch the next time it is refreshed.
reply Gerrit AI review for Lustre osc_lock.c:1268 — (suggestion) This isn't a bug, but exporting ldlm_lock_create() and ldlm_lock_enqueue() means osc now builds an ldlm_lock by hand: it sets l
Gerrit AI review for Lustre
(suggestion) This isn't a bug, but exporting ldlm_lock_create() and ldlm_lock_enqueue() means osc now builds an ldlm_lock by hand: it sets l_conn_export, l_flags, l_policy_data and l_req_extent, and takes the addref before the grant. ldlm_cli_enqueue_local() does the same steps but asserts on a client namespace. Would a small exported client-side helper in ldlm (or a relaxed ldlm_cli_enqueue_local()) keep these lock-construction details inside ldlm, instead of making the two internals public API?
tags: 218_review_priority pt_ecro pw_shepherd
owner Andreas Dilger · uploader Andreas Dilger · PS7 uploaded 9d ago · NEW · open in Gerrit ↗
commit message
LU-12669 ec: create lock placeholder for reconstructed pages Pages that CIT_EC_RD reconstructs from parity for a stripe on an unavailable OST are not covered by a DLM lock, so they are dropped after each read, and every later read rebuilds them from parity again. Grant a client-only LDLM_FL_PLACEHOLDER ldlm_lock over the whole stripe object locally, without an RPC, and keep the reconstructed pages Uptodate under it. A stripe gets a placeholder when its target is inactive, or when its sub-lock enqueue fails. If the conversion fails, drop the pages after the read as before. Add cl_lock_operations::clo_to_placeholder() and ldlm_cli_enqueue_placeholder() for this. The pages stay valid while the parity they were rebuilt from is not STALE. Any write or truncate of the file must stale the parity with a layout write intent first, which revokes the layout lock on every client. When a client loses the layout lock, cancel the placeholder locks of the file with LCF_PLACEHOLDER, which discards their pages under the page lock as a server lock cancel does, and cancel one that a read creates meanwhile once that read is done. Fast reads from the page cache already wait for the next IO to refresh the layout, so make the mmap fast fault do the same. So the placeholder needs no server state: it is neither replayed nor dropped before a lock replay, is only matched by page coverage tests, does not hold up the KMS, and otherwise leaves the cache through the LRU like any unused lock. Only PR locks are converted, since a PW placeholder could satisfy a later write without a server lock. Also cancel initialized sub-locks on the lov_lock_sub_init() error path, and in lov_lock_cancel() when the sub-lock env is not found, so a placeholder reference is not leaked, and free the lov_lock with the size it was allocated with. Drop lov_lock_sub::sub_initialized, as every sub-lock is now initialized. Add sanity-ec test_49f to check that a second degraded read sends no read RPCs, that the placeholder survives OST recovery, and that the cached pages do not hide a later write from another client from either read() or an existing mmap. Test-Parameters: testlist=sanity-ec Test-Parameters: testlist=sanity-ec fstype=zfs Signed-off-by: Bobi Jam <bobijam@whamcloud.com> Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com> Assisted-by: Augment Agent:DeepSeek V4.1 Flash Assisted-by: ClaudeCode:claude-opus-5.5 ltvm,llm_code_and_review_tools Change-Id: Idbad18031562d5cef02ab16aadcd4818ec3ebbe5
70175
master
J –B ✓T ✓R +2/2
LU-20565 tests: run sanity-ec with fewer OSTs
reviewing Andreas Dilger · you voted +1 on current PS
pt_ecro
4 unresolved
M +31 −29
13h
LU-20565 tests: run sanity-ec with fewer OSTs
reviewing Andreas Dilger · you voted +1 on current PS
pt_ecro
4 unresolved
M +31 −29
13h
build #134789 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1 · Marc Vef +1
no vote yet: Ronnie Sahlberg
threads: 4 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Andreas Dilger sanity-ec.sh:1501 — Strange. There was a full session with `testlist=sanity-ec ostcount=4` that passed, so either this subtest is not being run, or the stripe c
Gerrit AI review for Lustre
(minor) test_5a isn't in the list, but it seems to hit the same ENOSPC on 4 OSTs. It hard-codes `-c 4 --ec 4+1` with no OSTCOUNT gate, and a 4+1 raidset needs 5 distinct OSTs. For a single raidset, lod_stripe_count_min() gives the parity component its own cstripe count of unique OSTs, and the reuse/shrink fallbacks in lod_qos.c only run when ec_raidset_count(sc) > 1. None of the later LU-20565 patches in the relation chain touch 5a either. Will the `ostcount=4` session still fail here? If so, 5a could use `-c $EC_DSTRIPE $EC_ARG` like the other subtests, or get a `(( OSTCOUNT >= 5 )) || skip` gate.
Andreas Dilger
Strange. There was a full session with `testlist=sanity-ec ostcount=4` that passed, so either this subtest is not being run, or the stripe count for this component is being shrunk to 3+1 or similar with 4 OSTs? Either way I don't think this is a regression in this patch. It could be fixed if refreshed.
reply Andreas Dilger sanity-ec.sh:1510 — Hmm, this is also checking stripe_count=4, so it isn't clear how this could pass with OSTCOUNT=4?
Andreas Dilger
Hmm, this is also checking stripe_count=4, so it isn't clear how this could pass with OSTCOUNT=4?
reply Andreas Dilger sanity-ec.sh:1558 — I think that is an anti-feature of the tests that all of the components are aligned on raidset boundaries. That isn't always possible (eg.
Gerrit AI review for Lustre
(suggestion) This isn't a bug, but with the scaled geometry the 128M and 1G boundaries are no longer a multiple of the row width when EC_DSTRIPE is 3, 5 or 6 (4, 5, 7 and 8+ OSTs, with 1M stripes). For example, 128M % 3M = 2M. The later patches in this series put each PFL boundary in front of an EC component on a multiple of the row width. If the patch is refreshed, should 5b do the same, e.g. `$((32 * EC_DSTRIPE))M` and `$((256 * EC_DSTRIPE))M`, with the second write's seek moved to match?
Andreas Dilger
I think that is an anti-feature of the tests that all of the components are aligned on raidset boundaries. That isn't always possible (eg. a 64KiB DoM first component with an EC second component). The EC calculations should work properly in this case.
reply Andreas Dilger sanity-ec.sh:4496 — Partial-raidset overwrites should also work properly.
Gerrit AI review for Lustre
(minor) The seek is scaled to the start of row 2, but count=4 isn't scaled. The old test overwrote exactly one full row (seek=8 count=4 with 4x1M rows). Now that only happens when EC_DSTRIPE is 4 or 2, and with 3, 5 or 6 data stripes it is a partial-row overwrite. If the full-row case was intended, count=$EC_DSTRIPE would keep it. Otherwise the commit message's "overwrite from EC_DSTRIPE" could say that only the offset is scaled.
Andreas Dilger
Partial-raidset overwrites should also work properly.
tags: pt_ecro
owner Andreas Dilger · uploader Andreas Dilger · PS1 uploaded 6d ago · NEW · open in Gerrit ↗
commit message
LU-20565 tests: run sanity-ec with fewer OSTs On a filesystem with 4 OSTs, sanity-ec subtests 4e, 5b, 6d, 6e, 6f, 7a, 23a, 23b, 23c, 24a, 25a, 26a and 28a would fail in "lfs setstripe" with "No space left on device (28)", because they hard-code an EC 4+2 geometry and the raidset allocator needs 6 distinct OSTs for it. None of these subtests depends on that geometry, so use the EC_ARG, EC_DSTRIPE and EC_CSTRIPE defaults that enable_ec() scales to OSTCOUNT for the layout and the expected stripe counts. Size the sanity-ec/26a file and overwrite from EC_DSTRIPE so it still covers 5 full rows. Test-Parameters: trivial testlist=sanity-ec Test-Parameters: testlist=sanity-ec ostcount=4 Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com> Assisted-by: ClaudeCode:claude-opus-5-5 ltvm llm_code_and_review_tools Change-Id: Ie76079973f5ee62cb77888d448194913693ebbe5
69950
master
J –B ✓T ✓R +1/2
LU-21021 llite: refresh layout in getxattr of lustre.lov
reviewing Markus Hilger · you voted +1 on current PS
M +137 −3
1d
LU-21021 llite: refresh layout in getxattr of lustre.lov
reviewing Markus Hilger · you voted +1 on current PS
M +137 −3
1d
build #134671 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1
no vote yet: Andreas Dilger
patchsets:
PS1 10-22
PS2 10-24
PS3 10-24
PS4 10-26
PS5 10-28
owner Markus Hilger · uploader Markus Hilger · PS5 uploaded 7d ago · NEW · open in Gerrit ↗
commit message
LU-21021 llite: refresh layout in getxattr of lustre.lov ll_getxattr_lov() packs the cached layout without taking the layout lock. After another client changed the layout, fgetxattr() on an open file, and so llapi_layout_get_by_fd(), returns the old layout until some other operation refreshes it. Call ll_layout_refresh() in getxattr of a regular file before packing its layout. While the client holds the layout lock, the refresh returns without an RPC. listxattr, which only needs to know that there is a layout, does not refresh, nor does getxattr while a group lock is held on the file: a new layout would wait for the group lock's I/O, which the caller may hold itself, or during an HSM restore, whose layout lock the coordinator holds until the copytool is done. If the refresh fails, the cached layout is returned. Add multiop command Xg, which prints the layout generation of a composite file, sanityn test_124, and test60 to swap_lock_test (sanity test_405), which reads the layout of a group-locked file after a layout swap. Test-Parameters: testlist=sanity env=ONLY=405 Signed-off-by: Markus Hilger <markus.hilger@megware.com> Change-Id: Iad7a31b97417c8ee697e3f5e5a3860427136155c
69426
master
J –B ✓T ✓R +2/2
LU-19823 lod: spread failover groups over the RR array
reviewing Andreas Dilger · you voted +1 on current PS
218_review_prioritypt_ecro
5 unresolved
M +203 −11
1d
LU-19823 lod: spread failover groups over the RR array
reviewing Andreas Dilger · you voted +1 on current PS
218_review_prioritypt_ecro
5 unresolved
M +203 −11
1d
build #135076 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1 · Ronnie Sahlberg +1
no vote yet: Marc Vef
patchsets:
PS2 10-06
PS3 10-07
PS4 10-10
PS5 10-13
PS6 11-01
+1 earlier
PS1 10-05threads: 5 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre lu_tgt_alloc.h:26 — (nit) ltd_rr_failover_order() stores lu_rr_group_order() + 1 here, so 0 still means "not set". Maybe "failure domain, or failover group orde
Gerrit AI review for Lustre
(nit) ltd_rr_failover_order() stores lu_rr_group_order() + 1 here, so 0 still means "not set". Maybe "failure domain, or failover group order + 1, 0 if not set"?
reply Gerrit AI review for Lustre lod_qos.c:294 — (minor) If the patch is refreshed, could this kernel-doc also say that, without failure domains, the targets are ordered by failover group (
Gerrit AI review for Lustre
(minor) If the patch is refreshed, could this kernel-doc also say that, without failure domains, the targets are ordered by failover group (ltd_rr_failover_order())? It would also help to note that a change to the import's connection list doesn't trigger a resort and only takes effect at the next rebuild for another reason.
reply Andreas Dilger lod_qos.c:440 — This should be a very uncommon config. I don't want to make the code increasingly complex to handle theoretical corner cases. 99% of systems
Gerrit AI review for Lustre
(minor) With failover groups set as lrt_fd, lu_rr_fill() takes the by_fd path. In that path a server's targets are only spaced within their group, not across the whole array. When the OSSs of a pair have different OST counts, this can put two OSTs of the same OSS next to each other where the old by-server order did not.
I ran lu_rr_fill() in userspace (the lod_rr_test harness) with 6 OSSs in 3 pairs (oss/2) and OST counts 2,3 | 2,4 | 3,4 (18 OSTs). OSS sequence of the array:
old: 3 5 1 4 0 2 3 5 1 4 3 5 0 2 1 4 3 5
new: 5 3 1 4 2 0 5 3 1 4 3 5 0 2 4 1 3 5
The old order has no adjacent same-OSS slots and one same-pair slot. The new order has one adjacent pair of slots, and it is on a single OSS (5 at the end wraps to 5 at the start). Over 4-OSS configs with 1-8 OSTs per OSS, 972 of 4096 have more same-OSS adjacencies than before. The smallest is 2,4 | 4,3, where the old order had none. Equal pairs, and pairs that differ by one OST (e.g. one inactive OST), are fine.
Is that trade-off intended? If not, one option is to use the failover order only when it doesn't increase same-server adjacency, or to keep server spacing as the primary key and use the group only to break ties. Either way, it would help to mention it in the commit message.
Andreas Dilger
This should be a very uncommon config. I don't want to make the code increasingly complex to handle theoretical corner cases. 99% of systems will have totally uniform OSS nodes. A fraction will have maybe 2-3 different OSS configs, likely in different pools that would not be in the same allocation.
reply Andreas Dilger lod_qos.c:443 — I don't think this is _worse_ than before the patch. There are more patches in this series, and it could be further improved in a later pat
Gerrit AI review for Lustre
(defect) When any OST has ltq_failure_domain set, fdoms is allocated, and lu_rr_fdoms_init() now makes one lu_rr_fdom per inferred failover group instead of one per server. For FLR and EC layouts (fdom_rr in lod_ost_alloc_rr()), each slot of such a group now hands out the targets of both OSSs of the pair in turn from the shared lrf_next/lrf_next0 counters, and the lod_oss_avoided() retries skip through the pair's targets. Is that intended? The commit message says this "only orders the array, and does not limit where the stripes of a layout or its mirrors may go", but it also changes which OST each slot gives.
I checked this with lod_rr_test changed so that -u leaves the first half of the OSSs without a domain (pairs 0/1, 2/3, ... as with -F), and compared runs with and without -F:
lod_rr_test -o 10 -s 4 -d 4 -u -c 2 -M -F
OST1 has 560 objects, OST2 has 81
OST0 has 300 #0 objects, OST2 has 1
(without -F: 467 vs 366, and 200 #0 objects on each OST)
Over -o 8-64 -s 4-16 -d 2-8 -u -c 1-4:
- with -M, failed combinations go from 360 to 980 of 9399, and layouts with two stripes on one OSS from 1233 to 65633
- with -e 2, failed combinations go from 305 to 969 of 10467, and layouts with two stripes on one OSS from 100 to 116724
One option is to keep a separate lu_rr_fdom per server for the inferred groups and use the group only to order the array. Another is to skip ltd_rr_failover_order() when the array has explicit failure domains.
Andreas Dilger
I don't think this is _worse_ than before the patch. There are more patches in this series, and it could be further improved in a later patch.
reply Andreas Dilger sanity.sh:7000 — Can be done in a later patch. Mixed fdom and non-fdom configs _should_ be rare, but it should try to do a reasonable job if that happens. We
Gerrit AI review for Lustre
(suggestion) With -u, only OSS 0 has no domain, so its inferred group holds just that one OSS. This case doesn't cover an inferred group of two OSSs next to explicit domains, which is the case lrrt_inferred exists for. The -U line below covers it only with -c 1, without mirrors or parity. Could a case with an HA pair that has no domain, along with -M and -e, be added? That would also cover the lu_rr_fdom_tgt() imbalance described in lod_qos.c.
Andreas Dilger
Can be done in a later patch. Mixed fdom and non-fdom configs _should_ be rare, but it should try to do a reasonable job if that happens. We can refine this further, but it is not the common case.
tags: 218_review_priority pt_ecro
owner Andreas Dilger · uploader Andreas Dilger · PS6 uploaded 4d ago · NEW · open in Gerrit ↗
commit message
LU-19823 lod: spread failover groups over the RR array Without failure domains, the round-robin array only keeps the targets of each server apart. The targets of the two servers of an HA pair can still be next to each other in the array, so consecutive stripes of a file are on servers that can fail together, or be unavailable together while one of them fails over to the other. For the targets without a failure domain, ltd_rr_failover_order() groups them by the lowest NID of their primary and failover connections, which is the same for all the targets that can fail over to each other, and orders the array by group as for failure domains. lrrt_inferred keeps these groups apart from explicit failure domains with the same number, also when only some targets have a domain. All the targets of a server go in the group of its lowest NID, since the array is ordered only by server if a server is in several groups. The groups are ranked by NID, first by network and then by address, and lu_rr_group_order() orders them by the reversed bits of their rank, so groups with close NIDs, likely in the same network or rack, are mostly far apart in the array. Unlike failure domains, this does not limit where the stripes of a layout or its mirrors may go, but when other OSTs have failure domains, a slot of a failover group gives the OSTs of both servers of the group in turn to EC and FLR layouts. The MDT round-robin array, used for striped directories, is ordered the same way. The failover NIDs are read from the import at each rebuild of the array, so add_conn and del_conn take effect at the next rebuild. Add a -F option to lod_rr_test to put the OSSs without a failure domain in HA pairs, and check that consecutive OSTs in the array are on different pairs, and a -U option to leave every other OST without a failure domain. Without the ordering, "lod_rr_test -f -o 4-64 -s 2-16 -F" finds OSTs of one HA pair next to each other in 1852 of 30512 combinations, and in none with it. Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com> Assisted-by: ClaudeCode:claude-opus-5.5 ltvm,llm_code_and_review_tools Change-Id: I39eae90881b61feee2e9b2aa20978a38e93ebbe5
69828
master
J –B ✓T ✓R +2/2
LU-20958 llite: drop strict SOM size with the UPDATE lock
reviewing Andreas Dilger · you voted +1 on current PS
218_review_prioritypt_ecro
2 unresolved
S +35 −1
2d
LU-20958 llite: drop strict SOM size with the UPDATE lock
reviewing Andreas Dilger · you voted +1 on current PS
218_review_prioritypt_ecro
2 unresolved
S +35 −1
2d
build #134055 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1 · Ronnie Sahlberg +1
no vote yet: Zhenyu Xu, Patrick Farrell
patchsets:
PS1 10-19
PS2 10-19
threads: 2 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Andreas Dilger sanity-flr.sh:2570 — This should be fixed, but I'm reluctant to refresh the patch just for this. Will push a separate patch on top to fix, can be merged in if t
Gerrit AI review for Lustre
(style) This gate and skip message were copied from test_44e, which uses the enable_strict_som tunable. test_44i never touches that tunable, so the "for SOM tunable" reason doesn't fit here. If the patch is refreshed, could the message say what this test actually needs from the MDS?
Keguang Xu
Or should we use the recent version like 2.17.59?
Andreas Dilger
Agreed, the gate and skip message come from test_44e. If this patch is refreshed, the message will say what the test needs (strict SOM after resync) and use the 2.17.59 version.
Andreas Dilger
This should be fixed, but I'm reluctant to refresh the patch just for this. Will push a separate patch on top to fix, can be merged in if this needs to be refreshed for another reason.
reply Andreas Dilger sanity-flr.sh:2591 — The test cases are verified before/after to detect the failure, so this _should_ be enough to detect an issue.
Keguang Xu
(suggestion) Should we use 2 clients? cli1 `dd + stats` then cli2 `dd` which would revoke the `UPDATE` lock from cli1?
Andreas Dilger
One client is enough: strict SOM is only set on an FLR file after a resync, and the first write from the same client sends a layout write intent, which takes LAYOUT|UPDATE in EX mode on the MDS and cancels this client's own UPDATE lock too. The test of the bits will be in 64086, as above.
Andreas Dilger
The test cases are verified before/after to detect the failure, so this _should_ be enough to detect an issue.
tags: 218_review_priority pt_ecro
owner Andreas Dilger · uploader Andreas Dilger · PS2 uploaded 16d ago · NEW · open in Gerrit ↗
commit message
LU-20958 llite: drop strict SOM size with the UPDATE lock A strict SOM size and blocks from the MDS are only valid under the MDS UPDATE lock: a write or truncate of the file takes LAYOUT|UPDATE in EX mode before the MDS marks the SOM stale. The client kept OBD_MD_FLSIZE|OBD_MD_FLBLOCKS in lli_attr_valid after that lock was cancelled, so anything trusting them without a getattr would use a size from before another client's write. stat() was not affected, since ll_getattr() revalidates first, but EC lseek and the fsync blocks update are about to rely on these bits. Clear them from lli_attr_valid when the UPDATE lock is cancelled, so the next getattr fetches them again. Add sanity-flr test_44i, which writes a mirrored file with a strict SOM size and checks the blocks stored at close. Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com> Assisted-by: ClaudeCode:claude-opus-5.5 ltvm,llm_code_and_review_tools Change-Id: Ice12d7b03bb2b78e4f6b1f839d4b8ac4b03ebbe5
69305
master
J –B ✓T ✓R +2/2
LU-8933 lod: balance round-robin first stripe start
reviewing Andreas Dilger · you voted +1 on current PS
218_review_prioritytestfix
master-next
2 unresolved
L +400 −66
4d
LU-8933 lod: balance round-robin first stripe start
reviewing Andreas Dilger · you voted +1 on current PS
218_review_prioritytestfix
master-next
2 unresolved
L +400 −66
4d
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-part-1 | RHEL 9.8 / x86_64 | ran 3 tests. 1 tests failed: sanity. | session |
build #134287 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1 · Ronnie Sahlberg +1
no vote yet: Lai Siyao, Oleg Drokin
patchsets:
PS2 09-30
PS3 10-02
PS4 10-05
PS5 10-10
PS6 10-22
+1 earlier
PS1 09-29your previous vote: +1 on PS5 (2026-10-18 03:36) — now at PS6
threads: 1 need your reply · 0 waiting on others · 1 own notes · 0 bot
reply Andreas Dilger lod_qos.c:1013 — seems reasonable if patch needs to be refreshed for some other reason
Gerrit AI review for Lustre
(suggestion) This isn't a bug, but the only caller passes `stripes` as `stripe_count`, which lod_ost_alloc_rr() has just set from `lod_comp->llc_stripe_count`. The mirror/EC branch then replaces it with `comp->llc_stripe_count`, and when no earlier match is found `comp == lod_comp`, so that is the same value again. Because the argument never changes the result, it reads as if the caller could pass some other count here. If the patch is refreshed, could lod_rr_key() use `comp->llc_stripe_count` in both cases and drop the parameter?
Andreas Dilger
seems reasonable if patch needs to be refreshed for some other reason
note Keguang Xu lod_qos.c:1448 — (discussion) whether set key as `key = e_start | ((u64)stripe_count << 48)` be more clear and explicit compared with this implicit addition?
Keguang Xu
(discussion) whether set key as `key = e_start | ((u64)stripe_count << 48)` be more clear and explicit compared with this implicit addition?
tags: 218_review_priority testfix
owner Andreas Dilger · uploader Andreas Dilger · PS6 uploaded 13d ago · NEW · open in Gerrit ↗
commit message
LU-8933 lod: balance round-robin first stripe start
With qos_threshold_rr=100, some OST/stripe count combinations give
some OSTs twice as many first stripes (#0 objects) as others, e.g.
6 OSTs with 4 stripes, or two OSSs with 12 OSTs each and 16 stripes,
where the OSTs of one OSS got 75 and the other OSS 125 per 100.
Each layout starts where the previous one ended, so layouts start
only on OSTs gcd(stripes, OSTs) apart in the RR array, and the start
index wraps after an uneven number of layouts. Advancing the start
offset by one on every wrap then visits some of those OST sets more
often than others, and lod_qos_calc_rr() interleaves the OSSs in the
array, so the imbalance can follow the OSS boundary. The components
of PFL layouts, allocated in turn, advance the same start index, so
a fixed sequence of stripe counts can also leave the start of each
component on only a few OSTs. Overstriped layouts with more stripes
than OSTs advance the start index by more than the OST count, but it
was only wrapped by one OST count, so the same OSTs got the extra
stripes of every layout until the next reseed.
Keep a separate start index for each stripe count and component
extent, in struct lu_qos_rr_stream, for the 16 (LQR_STREAMS) most
recently used. A new one continues from the start index of the one it
replaces, so using more of them in turn is no worse than before. The
mirrors and EC parity of one extent share the start index of the first
of them, and when they are allocated one after the other they continue
from each other without advancing the start offset, so they are still
on different OSSs. Advance the start offset once every N/gcd(stride,
N) layouts, where the stride is the stripes of a layout and of the
mirrors or parity that continue from it, after every OST in the
current set has been used as a start, so each run of N layouts with
the same stripe count starts once on each of N OSTs. Count layouts
rather than wraps, since OSTs that are skipped change the stride
between layouts. Wrap the start index fully for overstriped layouts.
This also fixes the same imbalance for directory stripes over remote
MDTs.
Make sanity test_51g check the first stripe balance, overstriped, PFL,
mirrored and EC layouts, and keep the test_51d exceptions only for
older MDSs. Before this patch, lod_rr_test finds that these fail the
test_51d first stripe check (for some component):
before after
3-256 OSTs, 1-8 OSSs, 1-256 stripes 50777/263079 0/263079
3-32 OSTs, up to 4 stripes per OST 2511/8388 0/8388
3-64 OSTs, PFL with 1, 4, all stripes 25/247 0/247
3-64 OSTs, PFL with 8, 4, 2, 1 stripes 68/247 0/247
562 of the overstriped combinations also fail it for total objects
before this patch. With one unusable OST that is skipped, 3544 of
4500 combinations of 4-48 OSTs have more than 3x the #0 objects on
some OST than another before this patch, and 853 after.
Objects per OST from sanity test_51d, 6 OSTs, 600 files -C 4:
OST0 OST1 OST2 OST3 OST4 OST5
before #0 133 67 133 67 135 67
after #0 100 100 101 101 100 100
total ~402 ~402 ~402 ~402 ~402 ~402
Fixes: c7f2e70a27e8 ("LU-1303 lod: QoS allocation policy")
Fixes: fa34a15f619c ("LU-15282 lod: less spinlock on the alloc rr")
Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com>
Assisted-by: ClaudeCode:claude-opus-5.5 ltvm,llm_code_and_review_tools
Change-Id: I9c0157db12c09c5ff5d75cfac31a9abf3e3ebbe5
69338
master
J –B ✓T ✓R +1/2
LU-20856 llite: do not force commits on background writeback
reviewing Patrick Farrell · you voted +1 on current PS
pw_own
M +85 −13
6d
LU-20856 llite: do not force commits on background writeback
reviewing Patrick Farrell · you voted +1 on current PS
pw_own
M +85 −13
6d
build #134186 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1
no vote yet: Qian Yingjin, Andreas Dilger, Zhenyu Xu, Timothy Day
patchsets:
PS1 09-30
PS2 10-21 patrick bot
your previous vote: +1 on PS1 (2026-10-08 04:35) — now at PS2
tags: pw_own
owner Patrick Farrell · uploader patrick bot · PS2 uploaded 14d ago · NEW · open in Gerrit ↗
commit message
LU-20856 llite: do not force commits on background writeback
Background writeback runs whenever a client's dirty pages pass the
background threshold, which is normal for any client that is
writing. Since LU-16713 it is treated as memory reclaim, so every
background writeback pass sent an OST_SYNC for each stripe of
every file it visited, and busy clients produced storms of
forced journal commits on the OSTs.
Force a commit only for writeback started for page reclaim, which
LU-16713 added at the same time. Memory-limited cgroups do not
depend on the background commit: writers that write several times
their cgroup's limit with no fsync are not OOM-killed on cgroup v1
or v2 without it. Background writeback keeps the priority it gets
when the writer is over its dirty limit, so the active extent
flush from LU-19014 is unchanged.
Add sanity test 411c: with background writeback running for the
whole of a buffered write that never calls fsync, the client must
send far fewer OST_SYNC than OST_WRITE.
Fixes: 8aa231a99468 ("LU-16713 llite: writeback/commit pages under memory pressure")
Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Patrick Farrell <patrick@thelustrecollective.com>
Change-Id: I4b68f32e4939d16a56e06d2d2e39fe53b967bece
69916
master
J –B ✓T ✓R +2/2
LU-21014 lod: keep EC raid sets on distinct OSTs in RR
reviewing Ronnie Sahlberg · you voted +1 on current PS
ec2
pt_ecro
CI@PS2
master-next
5 unresolved
S +8 −2
7d
LU-21014 lod: keep EC raid sets on distinct OSTs in RR
reviewing Ronnie Sahlberg · you voted +1 on current PS
ec2
pt_ecro
CI@PS2
master-next
5 unresolved
S +8 −2
7d
build #134322 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1 · Andreas Dilger +1
no vote yet: Marc Vef
patchsets:
PS1 10-22
PS2 10-23
PS3 10-27 Andreas Dilger
threads: 4 need your reply · 1 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre COMMIT_MSG:19 — (minor) This fixes a placement bug from the commit that added the EC RR reuse path, lod_ec_add_data() and the lag_ost_avail gate in lod_chec
Gerrit AI review for Lustre
(minor) This fixes a placement bug from the commit that added the EC RR reuse path, lod_ec_add_data() and the lag_ost_avail gate in lod_check_and_reserve_ost(). That commit's message promises "-C: require unique OSTs within each raidset", which the RR loop reuse did not keep. Should this carry:
Fixes: c53abca9f9ee ("LU-19852 lod: raidset aware stripe allocator")
reply Andreas Dilger lod_qos.c:779 — This says where EC reuse happens but not why it can't happen here. Please add that lag_ost_avail counts OSTs that RR skips (inactive, degra
Andreas Dilger
This says where EC reuse happens but not why it can't happen here. Please add that lag_ost_avail counts OSTs that RR skips (inactive, degraded), so the loop could reuse an OST before every usable OST was placed. Can go in the follow-on patch.
reply Andreas Dilger lod_qos.c:1463 — Pre-existing and not critical for this release: lod_ec_add_data() only checks failure domains within the raid set, not OST identity. An OST
Andreas Dilger
Pre-existing and not critical for this release: lod_ec_add_data() only checks failure domains within the raid set, not OST identity. An OST with failure domain 0 skips the check entirely. When the list mixes domain 0 and non-zero domain OSTs, a "continue" here for a domain collision shifts the cyclic order, so a domain 0 OST can be placed twice in one raid set. Separately, if lod_ec_add_data() returns short, the parity split is computed from the reduced stripe count, which may not keep the uniqueness the original split had. Something for a later patch.
reply Andreas Dilger lod_qos.c:1768 — With this change EC components never set overstriped in the RR loop, so LOV_PATTERN_OVERSTRIPING is always cleared, even when lod_ec_add_dat
Andreas Dilger
With this change EC components never set overstriped in the RR loop, so LOV_PATTERN_OVERSTRIPING is always cleared, even when lod_ec_add_data()/lod_ec_add_parities() do reuse OSTs afterward. "lfs getstripe" then shows a -C EC layout with repeated OSTs but no overstriping. This already happened with all OSTs active, and now also with an OST down. Setting overstriped when lod_ec_add_data()/lod_ec_add_parities() place a reused OST would fix it. Also, clearing the flag before an error return means the reserve=0 retry runs as a -c layout. Not critical, could go in the follow-on patch.
tags: pt_ecro
build/test results are from PS2 — PS3…PS3 changed only the commit message (votes copied, CI not re-run)
owner Ronnie Sahlberg · uploader Andreas Dilger · PS3 uploaded 9d ago · NEW · open in Gerrit ↗
commit message
LU-21014 lod: keep EC raid sets on distinct OSTs in RR
With overstriping, lod_check_and_reserve_ost() lets the RR loop reuse
an OST while lag_ost_avail says unique OSTs remain. That count includes
OSTs RR skips, such as inactive or degraded ones, so an EC data
component can reuse an OST before lod_ec_add_data() takes over, which
repeats the placed stripes assuming they are unique and so puts two
stripes of a raid set on one OST, e.g. -C 13 --ec 5+2 on 8 OSTs with
one down.
Leave all OST reuse for EC components to lod_ec_add_data() and
lod_ec_add_parities(), which keep each raid set on distinct OSTs.
Test-Parameters: trivial testlist=sanity-ec ostcount=8
Fixes: c53abca9f9ee ("LU-19852 lod: raidset aware stripe allocator")
Signed-off-by: Ronnie Sahlberg <rsahlberg@whamcloud.com>
Assisted-by: ClaudeCode:claude-opus-5.5
Change-Id: I8fe6431de113351e92653780fe17db2e8a180697
69421
master
J –B ✓T ✓R +2/2
LU-19823 lod: balance RR allocation across failure domains
reviewing Andreas Dilger · you voted +1 on current PS
218_review_prioritypt_ecro
master-next
7 unresolved
XL +982 −177
7d
LU-19823 lod: balance RR allocation across failure domains
reviewing Andreas Dilger · you voted +1 on current PS
218_review_prioritypt_ecro
master-next
7 unresolved
XL +982 −177
7d
build #134288 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1 · Ronnie Sahlberg +1
no vote yet: Marc Vef
patchsets:
PS1 10-05
PS2 10-10
PS3 10-10
PS4 10-13
PS5 10-22
threads: 3 need your reply · 0 waiting on others · 4 own notes · 0 bot
reply Gerrit AI review for Lustre lod_qos.c:1665 — (defect) What happens when every OST that lu_rr_fdom_tgt() offers is rejected? This loop then calls lu_rr_fdom_tgt() exactly lrf_count times
Gerrit AI review for Lustre
(defect) What happens when every OST that lu_rr_fdom_tgt() offers is rejected? This loop then calls lu_rr_fdom_tgt() exactly lrf_count times. The domain counter advances by a full cycle and ends up where it started. The OST returned is the last one tried, which is lrfs_tgts[(next - 1) % lrf_count]: the OST most recently handed out from that counter. So the rotation doesn't move, and each such stripe lands on the same OST as the previous consumer of the counter.
This happens whenever all OSTs of a domain are on OSSs in lag_oss_avoid_array. lod_collect_avoidance() doesn't skip components whose llc_id is still LCME_ID_INVAL at create time. So for EC parity, the avoid list holds the OSSs of the file's own data stripes, not just those of other FLR mirrors. Some cases:
- one OSS with several domains, FLR or EC
- an HA pair whose OSTs share enclosures as domains, with EC data stripes on both OSSs
With the patch's own lod_rr_test harness, which has the same loop:
-f -o 4-16 -s 1 -d 2-4 -D -M 43 of 52 combinations fail
(last OST of each domain gets 5x the others)
-f -o 6-16 -s 1 -d 3-4 -D -e 1 47 of 55 fail
-o 12 -s 2 -d 3 -D -e 1 -c 2 OST7 450 objects, OST4 200, same domain
This looks different from LU-20925. That ticket covers the skew when only some of a domain's OSTs are avoided, while here the rotation stops completely, and it also hits EC parity, which has no mirrors. In the harness, taking one more lu_rr_fdom_tgt() after the loop when nothing qualified (so the counter advances by one net) brings the first two runs to 0 failures. It also leaves the existing -d, -d -M and -d -D -M results unchanged or better. Another option is to pass an offset to lu_rr_fdom_tgt(), so the probe doesn't touch the shared counter.
note Keguang Xu lod_qos.c:616 — (style) lod_oss_avoid_some -> lod_flr_has_unused_oss?
Keguang Xu
(style) lod_oss_avoid_some -> lod_flr_has_unused_oss?
note Keguang Xu lod_qos.c:632 — (style) lod_oss_avoided -> lod_flr_oss_used_by_peer ?
Keguang Xu
(style) lod_oss_avoided -> lod_flr_oss_used_by_peer ?
note Keguang Xu lod_qos.c:645 — (style) lod_fdom_tgt_skip -> lod_rr_fdom_ost_unusable?
Keguang Xu
(style) lod_fdom_tgt_skip -> lod_rr_fdom_ost_unusable?
note Keguang Xu lod_qos.c:1587 — (style) slot_ost_fallback?
Keguang Xu
(style) slot_ost_fallback?
reply Andreas Dilger lod_rr_test.c:245 — This is only the test so efficiency is not the primary concern, but could be updated if patch is refreshed.
Gerrit AI review for Lustre
(minor) This loop calls oss_used(), which itself scans every OST, once for every OST, on every rr_alloc() call. It doesn't stop at the first unused OSS, and it also runs without failure domains (lqr_fdoms == NULL), where oss_avoid is never used. So every lod_rr_test invocation now does O(OSTs^2) work per layout, including the ones that existed before this patch.
Built locally with gcc -O2:
-o 3-64 -s 1-4 5.8s -> 93s
-o 3-48 -s 2-8 -M 2.9s -> 31s
pre-existing 8 runs 22s -> 245s
full test_51g ~9 min
That will take much longer on CI VMs, and much longer still when the subtest-change sessions loop test_51g.
Gating the loop as lod_ost_alloc_rr() does, and stopping at the first match, brings each run back to about 5-10s with the same results (0 failed combinations for each test_51g case I reran):
if (!rt->no_first && lqr->lqr_fdoms)
for (i = 0; i < rt->ost_count && !oss_avoid; i++)
Andreas Dilger
This is only the test so efficiency is not the primary concern, but could be updated if patch is refreshed.
reply Andreas Dilger sanity-ec.sh:5693 — Can be fixed if patch needs to be refreshed.
wc-checkpatch
(style) 'comma_list $(mdts_nodes' may be misspelled - perhaps 'mdts_nodes'?
Andreas Dilger
Can be fixed if patch needs to be refreshed.
tags: 218_review_priority pt_ecro
owner Andreas Dilger · uploader Andreas Dilger · PS5 uploaded 13d ago · NEW · open in Gerrit ↗
commit message
LU-19823 lod: balance RR allocation across failure domains
The RR array interleaves OSTs only by OSS, and EC and FLR layouts
that need their stripes in different failure domains skip the OSTs
of domains they already use. Each skip advances the shared start
index, so the layouts lock into a pattern that uses some OSTs much
more than others and some not at all, e.g. 24 OSTs on 6 OSSs in 3
failure domains with 3-stripe EC layouts get 0-401 objects per OST.
Order the RR array in lu_rr_fill() by failure domain, then by OSS in
each domain, so that consecutive OSTs are in different failure
domains, unless OSSs have OSTs in several domains, when it is ordered
by OSS as before so consecutive OSTs are still on different OSSs.
Stagger OSSs and domains with the same OST count so that their OSTs do
not fall next to each other, and swap apart any OSTs still next to one
of their own OSS or domain, as with OSSs of different sizes. Domains
of different sizes still need skips, so layouts that need distinct
domains now scan from a start reserved by lu_rr_reserve() without
advancing the shared index, use each array slot only to pick a failure
domain, and take the OSTs of each domain in turn in lu_rr_fdom_tgt(),
separately for the first stripes of each stripe count and component,
and likewise for the OSTs of each OSS without a failure domain,
skipping any the layout already uses. Layouts that use several OSTs
of an OSS without a failure domain can still be up to about 1.3x
unbalanced within it, but a failure domain should be set for all OSTs.
A domain offers only one of its OSTs per slot, so if a layout is still
short of stripes, try the slot OSTs themselves before accepting fewer.
EC parity takes the OSTs of each domain like the later stripes, so it
does not shift the first stripes of the data. FLR mirrors prefer the
OSTs of a domain on an OSS that the other mirrors do not use yet,
which can unbalance domains whose OSTs are on several OSSs (LU-20925).
Rebuild the RR arrays when an OST failure domain changes, counted in
lq_rr_gen, since it is only known once the OST has reported statfs.
Add failure domains to lod_rr_test and sanity test_51g, and add
sanity-ec test_35c to check RR balance with unequal domains. Test
of lod_rr_test with 3-64 OSTs, 1-16 OSSs, 1-8 failure domains and
up to one stripe per domain, comparing OSTs in the same domain:
combinations 24 OSTs, 6 OSSs, 3 domains, 3 stripes
failed objects per OST #0 objects per OST
before 16344/22165 0-401 0-399
after 0/22165 300 100
sanity-ec test_35c, 8 OSTs in domains 1,1,1,1,2,3,2,3, 160 EC 2+1
files with qos_threshold_rr=100, objects per OST:
OST0 OST1 OST2 OST3 OST4 OST5 OST6 OST7
before 80 79 1 0 81 81 79 79
after 41 41 39 39 80 80 80 80
Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com>
Assisted-by: ClaudeCode:claude-opus-5.5 ltvm,llm_code_and_review_tools
Change-Id: I7111ce7a05f6431ceeaba20213d3c3921e3ebbe5
69648
master
J –B ✓T ✗1R +3/2
LU-20890 quota: don't panic on ENOSPC in lquota_disk_write
reviewing Sergey Cheremencev · blocked on the owner: enforced tests failed
CI@PS3
1 unresolved
S +31 −12
9d
LU-20890 quota: don't panic on ENOSPC in lquota_disk_write
reviewing Sergey Cheremencev · blocked on the owner: enforced tests failed
CI@PS3
1 unresolved
S +31 −12
9d
blocked on the owner: enforced tests failed
you voted +1 on current PS
| failed enforced test | platform | detail | |
|---|---|---|---|
| review-dne-part-5 | RHEL 9.7 / x86_64 | ran 7 tests. 1 tests failed: lustre-rsync-test. | session |
build #134376 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1 · Andreas Dilger +1 · Alex Zhuravlev +1
patchsets:
PS1 10-13
PS2 10-20
PS3 10-23
PS4 10-23
PS5 10-23
threads: 1 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre COMMIT_MSG:38 — (style) This fixes the LBUG that came in with the original quota disk code, so a Fixes: line would help with backport decisions:
Gerrit AI review for Lustre
(style) This fixes the LBUG that came in with the original quota disk code, so a Fixes: line would help with backport decisions:
Fixes: 752c69506c45 ("LU-1842 quota: add quota disk operations")
build/test results are from PS3 — PS4…PS5 changed only the commit message (votes copied, CI not re-run)
owner Sergey Cheremencev · uploader Sergey Cheremencev · PS5 uploaded 12d ago · NEW · open in Gerrit ↗
commit message
LU-20890 quota: don't panic on ENOSPC in lquota_disk_write
Replace ASSERTION in lquota_disk_write with CERROR. Even if we are
unable to insert a new or old record, the old one has already been
removed. At this step kernel panic can not restore anything and the
best we can do is to print an error with the ID needs to be repaired.
Below is an example of a panic in case of ENOSPC at the MDT. Note, the
same ASSERTION might be triggered at the OST side as well.
LustreError: 105341:0:(lquota_disk.c:680:lquota_disk_write())
ASSERTION( rc == 0 ) failed: failed to insert record in quota
index [0x200000006:0x2020000:0x0]
LustreError: 105341:0:(lquota_disk.c:680:lquota_disk_write()) LBUG
...
Call Trace:
dump_stack+0x41/0x60
lbug_with_loc.cold.8+0x5/0x43 [libcfs]
lquota_disk_write+0x9cf/0x9d0 [lquota]
qmt_glb_write+0x166/0x400 [lquota]
qmt_set_with_lqe+0x739/0xe60 [lquota]
qmt_lqe_set_default+0x1f7/0x240 [lquota]
qmt_lqe_read+0x2f7/0x350 [lquota]
lqe_locate_find+0x32e/0x790 [lquota]
qmt_pool_lqe_lookup_lqa+0xd0/0x260 [lquota]
qmt_get+0x5f/0x410 [lquota]
qmt_quotactl+0x81e/0xce0 [lquota]
mdt_quotactl+0x7c3/0x9e0 [mdt]
tgt_request_handle+0xc09/0x1b90 [ptlrpc]
ptlrpc_server_handle_request+0x27f/0x1200 [ptlrpc]
ptlrpc_main+0xb6f/0x13d0 [ptlrpc]
kthread+0x134/0x150
Also replace LBUG in qmt_dqacq0. It can be hit on the same error
(ENOSPC, ENOMEM, EIO, etc.) when lquota_disk_write returns an error
and the slave index is rolled back.
Fixes: 752c69506c45 ("LU-1842 quota: add quota disk operations")
Signed-off-by: Sergey Cheremencev <scherementsev@ddn.com>
Change-Id: I0e882698d7aa7d7ea4635c1076ccdd10063eba25
58255
master
J –B ✓T ✓R +1/2
LU-18431 tests: valid DD fail in saniy-quota_80
reviewing Sergey Cheremencev · you voted +1 on current PS
5 unresolved
S +11 −5
13d
LU-18431 tests: valid DD fail in saniy-quota_80
reviewing Sergey Cheremencev · you voted +1 on current PS
5 unresolved
S +11 −5
13d
build #132874 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1
no vote yet: Andreas Dilger, Hongchao Zhang
patchsets:
PS3 02-28
PS4 02-28
PS5 03-03
PS6 03-03
PS7 10-05
+2 earlier
PS1 02-27 PS2 02-27threads: 5 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Gerrit AI review for Lustre COMMIT_MSG:7 — (typo) "saniy-quota_80" should be "sanity-quota test_80". If the patch is refreshed, an imperative summary would also read better, e.g. "LU-
Gerrit AI review for Lustre
(typo) "saniy-quota_80" should be "sanity-quota test_80". If the patch is refreshed, an imperative summary would also read better, e.g. "LU-18431 tests: allow dd failure in sanity-quota test_80".
reply Gerrit AI review for Lustre COMMIT_MSG:10 — (minor) "write up to the QP limit(10MB)" undersells it. The test writes 3MB + 7MB + 1MB = 11MB to OSTs in qpool1, which is more than the 10M
Gerrit AI review for Lustre
(minor) "write up to the QP limit(10MB)" undersells it. The test writes 3MB + 7MB + 1MB = 11MB to OSTs in qpool1, which is more than the 10MB pool limit. Saying that directly would make it clearer why EDQUOT on the 7MB or 1MB write is legitimate. Also (typo) "In a such rare incident" should be "In such a rare case".
reply Gerrit AI review for Lustre sanity-quota.sh:6743 — (typo) behvaiour -> behaviour
Gerrit AI review for Lustre
(typo) behvaiour -> behaviour
reply Gerrit AI review for Lustre sanity-quota.sh:6747 — (suggestion) Since a failure here may mean the run doesn't reproduce the problem (and the subtest then passes trivially), it might be worth
Gerrit AI review for Lustre
(suggestion) Since a failure here may mean the run doesn't reproduce the problem (and the subtest then passes trivially), it might be worth recording it instead of discarding it silently, e.g.
$RUNAS $DD of=$TESTFILE2 count=7 ||
quota_log u $TSTUSR "write failed, may not reproduce"
quota_log() already exists in this file and dumps the quota state. That way, a pass that didn't really test anything can be told apart in the logs.
reply Gerrit AI review for Lustre sanity-quota.sh:6761 — (typo) "un update" -> "an update"
Gerrit AI review for Lustre
(typo) "un update" -> "an update"
owner Sergey Cheremencev · uploader Sergey Cheremencev · PS7 uploaded 30d ago · NEW · open in Gerrit ↗
commit message
LU-18431 tests: valid DD fail in saniy-quota_80
1 or 7MB write fail are valid cases as we write up to
the QP limit(10MB). In a such rare incident it is possible
that the problem this test aimed to demonstrate would not
be reproduced.
Test-Parameters: trivial testlist=sanity-quota,sanity-quota,sanity-quota
Test-Parameters: trivial testlist=sanity-quota env=ONLY=80,ONLY_REPEAT=10
Fixes: 61ec1e0f2c ("LU-15031 quota: reseed glbe in qmt_lvbo_udate")
Signed-off-by: Sergey Cheremencev <scherementsev@ddn.com>
Change-Id: Ib367ab8cf5cdfe197b41c45dbf491643e27e7a63
65862
master
J !B ✓T ✓R -1/2−
LU-20253 mdt: implement RENAME_WHITEOUT support
reviewing Timothy Day · blocked on the owner: needs rebase — checkpatch: cannot be cherry-picked
needs rebase
13 unresolved
L +451 −12
23d
LU-20253 mdt: implement RENAME_WHITEOUT support
reviewing Timothy Day · blocked on the owner: needs rebase — checkpatch: cannot be cherry-picked
needs rebase
13 unresolved
L +451 −12
23d
blocked on the owner: needs rebase — checkpatch: cannot be cherry-picked
you voted +1 on current PS
janitor run: 1 failing config(s), none unique to this patch — janitor results
6 optional test failure(s) — informational
build #128951 SUCCESS · tests all Maloo sessions
reviews:
Keguang Xu +1 · Andreas Dilger -1
no vote yet: Qian Yingjin, Lai Siyao
patchsets:
PS7 07-07
PS8 07-16
PS9 08-03
PS10 08-03
PS11 08-08
+6 earlier
PS1 05-13 PS2 06-08 PS3 06-09 PS4 06-10 PS5 06-19 PS6 06-26your previous vote: +1 on PS6 (2026-06-27 01:29) — now at PS11
threads: 13 need your reply · 0 waiting on others · 0 own notes · 0 bot
reply Andreas Dilger COMMIT_MSG:22 — This still doesn't preclude using `Test-Parameters:` to run interop testing with the relevant sessions against 2.17 (though be aware there a
Gerrit AI review for Lustre
(suggestion) This changes on-wire behavior (new mds_op_bias value sent in rn_bias). Consider adding a Test-Parameters: line requesting interop coverage against an older server (e.g. serverversion=...) so the new-client/old-server path is exercised.
Andreas Dilger
Agreed. This testing can be requested on an existing patch via its "Maloo Results" page posted in a comment at the start of every test run, as long as the build is still available. Even better is to split the patch into client and server components to ensure that each half runs a full set of tests in "interop" mode with a peer that does not have the feature.
Timothy Day
I think that'd only work if the patches were not in a series. Otherwise, the second patch wouldn't get interop testing. It seems odd that we don't have one last-LTS test session on the normal patch review.
Andreas Dilger
This still doesn't preclude using `Test-Parameters:` to run interop testing with the relevant sessions against 2.17 (though be aware there are some existing interop test failures that still need to be fixed).
reply Gerrit AI review for Lustre COMMIT_MSG:7 — The component tag is `mdt:` but the bulk of the change is in lustre/mdd/ (166 of 449 added lines), with lustre/mdt/ getting 5 lines. Would `
Gerrit AI review for Lustre
The component tag is `mdt:` but the bulk of the change is in lustre/mdd/ (166 of 449 added lines), with lustre/mdt/ getting 5 lines. Would `mdd:` be a better fit, or a feature tag since this also spans llite/lod/tests?
reply Gerrit AI review for Lustre COMMIT_MSG:26 — Two behavior changes to shared code don't seem to be accounted for by the body:
Gerrit AI review for Lustre
Two behavior changes to shared code don't seem to be accounted for by the body: - `lod_fid_alloc()` gains a new `lu_object_remote(parent)` branch, changing FID placement for any caller that passes a plain remote parent, not just the whiteout. - `mdi_chlog_declared` changes from a boolean to a `BIT(CL_*)` mask, which changes the gating in `mdd_changelog_ns_store()` for every namespace operation, not only rename. Could the body call these out (and say why the changelog gating has to change), so neither hunk reads as accidental?
reply Andreas Dilger lustre_idl.h:859 — The other patches should also be landed in the 2.18.0 release.
Gerrit AI review for Lustre
(suggestion) The name and comment claim the whole renameat2() flag set, but the server side only implements RENAME_WHITEOUT; ll_rename() rejects everything else with -EINVAL. Since ll_rename() gates on `flags && !exp_connect_renameat2()`, a later client that adds RENAME_EXCHANGE or RENAME_NOREPLACE will read this bit on a 2.17-era server as "supports those too" and will have to spend another connect bit (or a version check) to tell them apart. Connect bits are scarce, and the meaning of this one is frozen once it ships. Would naming it for what it actually advertises - e.g. OBD_CONNECT2_RENAME_WHITEOUT - keep the door open, or is the intent that the follow-on patches extend the meaning of this same bit?
Andreas Dilger
The other patches should also be landed in the 2.18.0 release.
reply Andreas Dilger lustre_idl.h:859 — The OBD_CONNECT2_RENAMEAT2 reservation is now its own patch, https://review.whamcloud.com/69528 (LU-20253 idl: reserve OBD_CONNECT2_RENAMEAT
Andreas Dilger
The OBD_CONNECT2_RENAMEAT2 reservation is now its own patch, https://review.whamcloud.com/69528 (LU-20253 idl: reserve OBD_CONNECT2_RENAMEAT2 flag), in a chain of connect flag reservations in bit order so they can land ahead of the feature patches. Please rebase this patch onto 69528 and drop the flag definition, its obd_connect_names[] entry and the wiretest/wirecheck lines from here.
reply Gerrit AI review for Lustre mdd_dir.c:3721 — (minor) The return values of mdd_linkea_prepare() and mdd_links_add() are discarded. If linkea_data_new() returns -ENOMEM, `wh_ldata.ld_leh`
Gerrit AI review for Lustre
(minor) The return values of mdd_linkea_prepare() and mdd_links_add() are discarded. If linkea_data_new() returns -ENOMEM, `wh_ldata.ld_leh` stays NULL, mdd_links_write() returns 0 immediately, and the whiteout is left with no linkEA (no fid2path, and LFSCK sees it as missing). A CDEBUG/CERROR on failure would at least make that visible.
reply Andreas Dilger mdd_dir.c:1407 — (defect) This seems like a significant issue, not just a nice-to-have change.
Gerrit AI review for Lustre
Turning this into a per-type check makes the gate depend on the declared type matching the stored type exactly, and the unlink path doesn't match.
`mdd_declare_unlink()` always declares `CL_UNLINK`:
rc = mdd_declare_changelog_store(env, mdd, CL_UNLINK, name,
NULL, handle);
but `mdd_unlink()` stores `is_dir ? CL_RMDIR : CL_UNLINK`. For an rmdir only `BIT(CL_UNLINK)` is ever set, so this test fails and the record is dropped. `mdd_trans_create()` zeroes the mask per transaction, so nothing else can set `BIT(CL_RMDIR)`.
That would mean every directory removal loses its changelog entry, which changelog consumers rely on. Should `mdd_declare_unlink()` declare the same type it will store?
Andreas Dilger
(defect) This seems like a significant issue, not just a nice-to-have change.
reply Gerrit AI review for Lustre mdd_dir.c:3835 — This is reached after the cross-MDT symlink shortcut above, so `MDS_RENAME_WHITEOUT` is dropped there:
Gerrit AI review for Lustre
This is reached after the cross-MDT symlink shortcut above, so `MDS_RENAME_WHITEOUT` is dropped there:
if (mdd_object_remote(mdd_sobj) && S_ISLNK(sattr->la_mode) &&
sattr->la_nlink == 1 && !tobj) {
...
rc = mdd_migrate_object(...);
GOTO(out_pending, rc);
}
With srcdir on MDT0 and tgtdir on MDT1 the rename runs on MDT1, so a symlink in srcdir is remote and single-linked, and `renameat2(RENAME_WHITEOUT)` returns 0 with no whiteout at the source name. For overlayfs that is the silent inconsistency the connect-flag gating was added to avoid. Should the migrate path also create the whiteout, or should the whiteout flag force the non-migrate path?
reply Andreas Dilger mdd_dir.c:3679 — (minor) this should be fixed if the patch is refreshed, but I don't think it is critical since the whiteout should normally not be visible a
Gerrit AI review for Lustre
(minor) The whiteout attributes are built by hand here, so they skip the project ID inheritance that every other create gets from mdd_create_sanity_check():
if (pattr->la_flags & LUSTRE_PROJINHERIT_FL) {
cattr->la_projid = pattr->la_projid;
cattr->la_valid |= LA_PROJID;
}
With LA_PROJID absent from mw_attr.la_valid and la_projid left at 0 by the memset, a whiteout created in a `chattr +P` directory is charged to project 0 instead of the parent's project, and `lfs project -r -c` on that directory will report it as non-conforming. mdd_rename() already re-stamps the renamed object's projid a few lines further down (change_projid), so the source-parent side looks inconsistent. Should the parent's projid be copied in when spattr has LUSTRE_PROJINHERIT_FL?
Andreas Dilger
(minor) this should be fixed if the patch is refreshed, but I don't think it is critical since the whiteout should normally not be visible at all in the places where it is used? That said, it would still account whiteouts to the wrong PROJID.
reply Andreas Dilger mdd_dir.c:4127 — Seems reasonable?
Gerrit AI review for Lustre
(minor) This drops the whiteout with the nocache variant on every path, including the success path. lu_object_put_nocache() sets LU_OBJECT_HEARD_BANSHEE, so a whiteout that was just created and committed is torn down instead of staying cached - and the next thing overlayfs does after renameat2() is look that name up again, forcing a full re-instantiation. Only the paths where the object was destroyed (or never created) need nocache. Could this use mdd_object_put() when the whiteout survived, e.g. keyed off wh_created && !rc?
Andreas Dilger
Seems reasonable?
reply Gerrit AI review for Lustre replay-dual.sh:1365 — This check can't fail, so the whiteout placement isn't actually verified.
Gerrit AI review for Lustre
This check can't fail, so the whiteout placement isn't actually verified. `lfs getstripe -m` on a non-directory goes through `cb_get_mdt_index()`, which does `open(path, O_RDONLY | O_NOCTTY)` before `LL_IOC_GET_MDTIDX`. Opening a 0:0 character device returns -ENXIO (no cdev registered at major 0), so `lfs` prints to stderr and stdout is empty, leaving `mdtidx` unset. In `(( ))` an empty variable evaluates to 0, so the comparison is always true. Since this is the only coverage for the new `lod_fid_alloc()` remote-parent branch, could the index be read another way, e.g. from the FID sequence via `$LFS path2fid` on the whiteout plus `$LFS fid2path`, or by checking the parent's `getdirstripe`?
reply Andreas Dilger replay-dual.sh:1356 — (style) prefer `==` for comparison in `[[ ... ]]`
Andreas Dilger
(style) prefer `==` for comparison in `[[ ... ]]`
owner Timothy Day · uploader Timothy Day · PS11 uploaded 88d ago · NEW · open in Gerrit ↗
commit message
LU-20253 mdt: implement RENAME_WHITEOUT support We must support RENAME_WHITEOUT for overlayfs support on Lustre. Quoting from the man page [1]: This operation makes sense only for overlay/union filesystem implementations. Specifying RENAME_WHITEOUT creates a "whiteout" object at the source of the rename at the same time as performing the rename. The whole operation is atomic, so that if the rename succeeds then the whiteout will also have been created. [1] https://www.man7.org/linux/man-pages/man2/rename.2.html Implement RENAME_WHITEOUT as an optional flag to mdd_rename(). Add tests to sanity.sh and replay-dual.sh to test this support and ensure that it's crash-consistent. Add a new renameat2 helper program. Negotiate support via a new OBD_CONNECT2_RENAMEAT2 connect flag. The client only sends RENAME_WHITEOUT (as the MDS_RENAME_WHITEOUT op_bias) when the MDS advertises the flag, and fails renameat2() with -EINVAL otherwise, so new clients interoperate safely with servers that do not support renameat2() flags. Signed-off-by: Timothy Day <timday@thelustrecollective.com> Change-Id: Iefb381cb12950c8751a0ecfcdfdcf4dedaa4b033
CC'd — on your radar, review not requested
(0)You are not CC'd on any open changes.
Merged — last 30 days
(6)
69699
master
J –B ✓T ✓R +4/2
LU-20963 lod: use a reconnecting OST only when needed
mine
pt_ecro218_review_priority
2 unresolved
M +132 −12
2d
LU-20963 lod: use a reconnecting OST only when needed
mine
pt_ecro218_review_priority
2 unresolved
M +132 −12
2d
reviews:
Ronnie Sahlberg +1 · Andreas Dilger +1 · Oleg Drokin +2
patchsets:
PS1 10-15
PS2 10-15
PS3 10-19 Andreas Dilger
PS4 10-22 Andreas Dilger
PS5 10-26 Andreas Dilger
tags: pt_ecro 218_review_priority
owner Keguang Xu · uploader Oleg Drokin · PS6 uploaded 4d ago · MERGED · open in Gerrit ↗
commit message
LU-20963 lod: use a reconnecting OST only when needed OST umount (OSS failover) only raises IMP_EVENT_DISCON: opd_imp_active stays set, so osp_statfs() kept returning cached statfs and LOD could not tell that the OST was gone, and used it as before. osp_statfs() now returns -EAGAIN while the import is disconnected (opd_imp_connected), and still returns -ENOTCONN for an inactive or deactivated OSP. Do not use opd_pre_status for this: it stays -ENODEV after reconnect until orphan cleanup is done. lod_statfs_and_check() keeps a reconnecting OST active and returns -EAGAIN if its cached statfs data is still usable (not full or read-only), so the active target count (and the stripe count limit derived from it), ltd_discon, lod_sync() and lod_obd_set_info_async() (e.g. evict_client by NID) are not changed by a transient disconnect. lod_ost_alloc_qos() leaves a reconnecting OST out, and lod_ost_alloc_rr() and lod_ost_alloc_specific() skip it in their first passes, but use it in their last, blocking pass, which only runs if too few stripes were found, and wait in osp_precreate_reserve() as before. The specific allocator also waits for a reconnecting OST requested with "-i", but not again after a reconnecting OST timed out, and an OST listed with "-o" is waited for. A create during OSS failover or right after an OST restart then still waits for the OST instead of failing with -ENOSPC or getting fewer stripes than lod_stripe_count_min(). osp_statfs() still fills in the cached data for a reconnecting OST, and lod_statfs() counts it, so that client df does not lose the space of an OST during failover. lod_trans_space_check() checks a reconnecting target with its cached state, so that a distributed transaction (e.g. migrate) does not fail with -EAGAIN. lod target_obd shows a reconnecting OST as INACTIVE, and a SEL component is not extended onto it. Move opd_imp_connected out of the osp_device bitfield, since LOD allocation now depends on it, and osp_import_event() writes it without a lock while the precreate thread updates other bits in the same word. Refresh ltd_discon from every statfs result while the target is already inactive (e.g. ENOSPC then deactivated), not only on the active-to-inactive transition. Add sanity.sh test_27ya to verify that target_obd shows the OST as INACTIVE after umount and setstripe avoids the disconnected OST when the other OSTs can provide all stripes. Create its directory on MDT0000, whose OSP import the test checks. Add test_27yb to verify that a create in a two-OST pool still gets both stripes when one OST is disconnected. Assisted-by: Cursor:Grok-4.6 llm_code_and_review_tools Assisted-by: Augment:Opus5.5 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Signed-off-by: Andreas Dilger <adilger@thelustrecollective.com> Assisted-by: ClaudeCode:claude-opus-5.5 ltvm,llm_code_and_review_tools Change-Id: I5cc15d4a719a9a0874fcffdbc6e2481a64e36d7e Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/69699 Tested-by: jenkins <devops@whamcloud.com> Reviewed-by: Oleg Drokin <green@whamcloud.com> Reviewed-by: Ronnie Sahlberg <rsahlberg@whamcloud.com> Tested-by: Maloo <maloo@whamcloud.com>
69516
master
J –B ✓T ✓R +4/2
LU-20690 lov: slot-based stripe geometry for EC parity
mine
raid10-like218_review_prioritypt_ecro
L +456 −125
2d
LU-20690 lov: slot-based stripe geometry for EC parity
mine
raid10-like218_review_prioritypt_ecro
L +456 −125
2d
reviews:
Ronnie Sahlberg +1 · Marc Vef +1 · Oleg Drokin +2
patchsets:
PS3 10-10
PS4 10-12
PS5 10-22 Marc Vef
PS6 10-22 Marc Vef
PS7 10-23
+1 earlier
PS1 10-08tags: raid10-like 218_review_priority pt_ecro
owner Keguang Xu · uploader Oleg Drokin · PS8 uploaded 4d ago · MERGED · open in Gerrit ↗
commit message
LU-20690 lov: slot-based stripe geometry for EC parity Prepare lov for a parity layout where the p parity objects of a raidset share one offset. Add slot helpers to lov_internal.h: lsme_stripe_origin(), lsme_stripes_per_slot(), lsme_slot_count() and lsme_stripe_slot(). A slot is one RAID0 stripe, or one parity raidset counted from e_start. The helpers take effect only for parity with a bare LOV_PATTERN_PARITY pattern. The current RAID0|PARITY parity keeps origin 0 and one stripe per slot, so the slot helpers leave existing layouts unchanged. - lov_offset.c maps offsets and sizes through the slot helpers, and clamps parity to e_end. - lov_stripe_chunk_end() counts from the stripe origin, for lov_io_rw_iter_init() and DIO appends. - Truncate (LU-14128) treats every stripe of the previous slot as "prev" in lov_io_iter_init() and lov_lock_sub_init(). - lseek merges sub-io results per slot. A SEEK_HOLE whose stripes disagree is returned as ls_unconfirmed, and ll_lseek() confirms it with SEEK_DATA. - EC recovery reads and lov_io_parity_size_comp() locate parity through lsme_parity_slots_per_raidset(), and the parity sub-io range in lov_ecio_add_parity_sub() counts from the stripe origin. - lov_entry_type() and lov_init_composite() accept both parity encodings. lov_object_fiemap() skips parity components, which it reported as unknown extents: parity is not part of the file logical map. lod_ec_parity_valid() adds to the k and p checks of lod_verify_striping(): p is at most 15, and an instantiated parity has a stripe count that is a multiple of p. sanity-ec test_310 checks that FIEMAP reports only data OSTs. Test-Parameters: testlist=sanity-ec ostcount=8 Assisted-by: Cursor:Grok-4.7/Opus5.5 llm_code_and_review_tools Assisted-by: ClaudeCode:claude-opus-5-5 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Signed-off-by: Marc Vef <mvef@whamcloud.com> Change-Id: I8ea125c36e119754bc26bf66ae8c28730ac4b5bf Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/69516 Tested-by: jenkins <devops@whamcloud.com> Tested-by: Maloo <maloo@whamcloud.com> Reviewed-by: Ronnie Sahlberg <rsahlberg@whamcloud.com> Reviewed-by: Oleg Drokin <green@whamcloud.com>
69111
master
J –B ✓T ✓R +4/2
LU-20797 llite: add SET I/O scope ioctl
mine
218_review_prioritypt_ecroraid10-like
3 unresolved
L +692 −33
2d
LU-20797 llite: add SET I/O scope ioctl
mine
218_review_prioritypt_ecroraid10-like
3 unresolved
L +692 −33
2d
reviews:
Ronnie Sahlberg +1 · Marc Vef +1 · Oleg Drokin +2
patchsets:
PS10 10-21 Marc Vef
PS11 10-26 Marc Vef
PS12 10-27 Ronnie Sahlberg
PS13 10-27 Ronnie Sahlberg
PS14 10-27 Marc Vef
+8 earlier
PS1 09-22 PS3 09-23 PS4 09-30 PS5 10-01 PS6 10-07 PS7 10-08 PS8 10-08 PS9 10-09tags: 218_review_priority pt_ecro raid10-like
owner Keguang Xu · uploader Oleg Drokin · PS15 uploaded 4d ago · MERGED · open in Gerrit ↗
commit message
LU-20797 llite: add SET I/O scope ioctl
FLR designated-mirror I/O is tied to LL_IOC_FLR_SET_MIRROR(long)
and cannot name a stripe or an object. Add LL_IOC_SET_IO_SCOPE and
struct ll_ioc_io_scope.
The enum defines FILE, MIRROR, STRIPE, and OBJECT. This patch
implements FILE and MIRROR. STRIPE and OBJECT return -EOPNOTSUPP
and are not stored. Clearing is a SET of an all-zero FILE scope,
the same as SET_MIRROR(0). llapi_io_scope_clear() is that SET.
SET_MIRROR remains an alias for {MIRROR, id}, so llapi_mirror_set()
is unchanged. It now rejects ids above MIRROR_ID_MAX at ioctl time
instead of failing later at I/O. Non-FILE scopes require O_DIRECT.
SET_MIRROR(0) and llapi_io_scope_clear() no longer require O_DIRECT,
since clearing does not issue mirror I/O.
Unused identity fields, flags, and padding must be 0.
fd_io_scope replaces fd_designated_mirror. ll_io_scope_init()
copies a MIRROR scope into ci_designated_mirror.
A caller-supplied layout version is sent only for an FLR file, where
lov_io_mirror_init() checks it against lsm_layout_gen. On a non-FLR
file the version is cleared, so it is not stored in the OST object.
llapi_io_scope_set(3) documents the user interface.
llapi_io_scope_clear(3) is a link to that page.
sanity-flr test_213a covers the reserved scopes, a FILE set, and
mirror resync through the SET_MIRROR alias. test_213b writes a
non-FLR file with a caller-supplied layout version and checks that
the OST object does not record it.
ll_file_io_scope_set() and the LL_IOC_FLR_SET_MIRROR handler both
memset() a struct ll_ioc_io_scope to 0 to represent LL_IO_SCOPE_FILE,
instead of assigning the enumerator explicitly. A BUILD_BUG_ON()
guards that assumption so a future renumbering of enum ll_io_scope
fails to compile instead of silently storing the wrong scope.
Test-Parameters: testlist=sanity-flr
Assisted-by: Cursor:Grok-4.6/Opus5.5 llm_code_and_review_tools
Signed-off-by: Keguang Xu <kxu@ddn.com>
Signed-off-by: Ronnie Sahlberg <rsahlberg@whamcloud.com>
Change-Id: I107e18a7e51f1a503872acc8e05447aa419bc5a4
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/69111
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Reviewed-by: Marc Vef <mvef@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
68204
master
J –B ✓T ✓R +4/2
LU-19631 tests: enable sanity-ec 12a
mine
pt_ecro
1 unresolved
XS +0 −2
7d
LU-19631 tests: enable sanity-ec 12a
mine
pt_ecro
1 unresolved
XS +0 −2
7d
reviews:
Marc Vef +1 · Maximilian Dilger +1 · Oleg Drokin +2
patchsets:
PS1 08-21
PS2 08-21 kg.xu
PS3 10-13 Marc Vef
tags: pt_ecro
owner Keguang Xu · uploader Oleg Drokin · PS4 uploaded 7d ago · MERGED · open in Gerrit ↗
commit message
LU-19631 tests: enable sanity-ec 12a EC parity calculation is fixed, so drop the always_except skip for test 12a. Test-Parameters: trivial testlist=sanity-ec env=ONLY=12a Test-Parameters: trivial testlist=sanity-ec env=ONLY=12a fstype=zfs Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: Ibcf58223101ce927dadedaba59bc404223fa7496 Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/68204 Reviewed-by: Marc Vef <mvef@whamcloud.com> Reviewed-by: Maximilian Dilger <mdilger@whamcloud.com> Tested-by: Maloo <maloo@whamcloud.com> Reviewed-by: Oleg Drokin <green@whamcloud.com> Tested-by: jenkins <devops@whamcloud.com>
69468
master
J –B ✓T ✓R +6/2
LU-7266 idl: reserve OBD_CONNECT2_POOL_SLV_PACKED flag
mine
CI@PS4
XS +7 −0
14d
LU-7266 idl: reserve OBD_CONNECT2_POOL_SLV_PACKED flag
mine
CI@PS4
XS +7 −0
14d
build #133492 SUCCESS · tests all Maloo sessions
reviews:
Ronnie Sahlberg +1 · Marc Vef +1 · Andreas Dilger +1 · Sebastien Buisson +1 · Oleg Drokin +2
patchsets:
PS1 10-07
PS2 10-08 Andreas Dilger
PS3 10-08 Andreas Dilger
PS4 10-13 Arshad Hussain
build/test results are from PS4 — PS5…PS5 changed only the commit message (votes copied, CI not re-run)
owner Keguang Xu · uploader Oleg Drokin · PS5 uploaded 14d ago · MERGED · open in Gerrit ↗
commit message
LU-7266 idl: reserve OBD_CONNECT2_POOL_SLV_PACKED flag Reserve OBD_CONNECT2_POOL_SLV_PACKED at 0x200000000000ULL for packed pool SLV. Only the flag, obd_connect_names[], and the wire checks are added here so the value can land before the pressure-based SLV patch. Test-Parameters: trivial Assisted-by: Cursor:Grok-4.7 llm_code_and_review_tools Signed-off-by: Keguang Xu <kxu@ddn.com> Change-Id: I79ceaa5de313cfb5a3d9a0ac7965b1fdc3ecff44 Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/69468 Tested-by: Maloo <maloo@whamcloud.com> Reviewed-by: Ronnie Sahlberg <rsahlberg@whamcloud.com> Reviewed-by: Oleg Drokin <green@whamcloud.com> Reviewed-by: Sebastien Buisson <sbuisson@ddn.com> Reviewed-by: Marc Vef <mvef@whamcloud.com> Tested-by: jenkins <devops@whamcloud.com> Reviewed-by: Andreas Dilger <adilger@thelustrecollective.com>
66672
master
J –B ✓T ✓R +4/2
LU-12668 ec: allow SEEK_DATA/HOLE on parity mirror lseek
mine
ec2
pt_ecro
1 unresolved
M +136 −43
21d
LU-12668 ec: allow SEEK_DATA/HOLE on parity mirror lseek
mine
ec2
pt_ecro
1 unresolved
M +136 −43
21d
reviews:
Marc Vef +1 · Andreas Dilger +1 · Oleg Drokin +2
patchsets:
PS12 08-28
PS13 08-29
PS14 08-29
PS15 09-03
PS16 09-20
+9 earlier
PS1 06-16 PS2 06-23 PS3 06-23 PS4 06-24 PS5 06-24 PS8 07-26 Marc Vef PS9 07-31 PS10 07-31 kg.xu PS11 08-07tags: pt_ecro
owner Keguang Xu · uploader Oleg Drokin · PS17 uploaded 23d ago · MERGED · open in Gerrit ↗
commit message
LU-12668 ec: allow SEEK_DATA/HOLE on parity mirror lseek
Parity mirror lseek was rejected at VVP with -ENXIO because
vvp_io_lseek_start() and vvp_io_lseek_end() clamped against
inode i_size. Parity components do not contribute to cat_size,
so i_size only reflects the data mirror and cannot serve as
parity EOF.
ci_parity_eof is computed in lov_io_mirror_init() from the
cached i_size, before locks are taken. Designated parity
lseek then locks only parity stripes, so the later
ll_merge_attr() cannot refresh data size and ci_parity_eof
stays stale. Glimpse the preferred data mirror once after
cl_io_init() sets ci_parity_io, then re-init so mirror
init recomputes ci_parity_eof from a current i_size.
Data-mirror SEEK_DATA/HOLE pays no extra glimpse: its
stripe locks already refresh i_size via ll_merge_attr().
ll_file_seek
-> ll_lseek
-> cl_io_init
lov_io_mirror_init # ci_parity_eof from cached i_size
-> ll_glimpse_size # refresh data i_size
-> cl_io_init (re-init)
lov_io_mirror_init # recompute ci_parity_eof
-> cl_io_loop
lock: parity stripes only
start: ll_merge_attr; eof = ci_parity_eof
end: eof = ci_parity_eof
Non-designated lseek now skips parity mirrors like
read and fault; if only parity covers the offset,
lseek fails with -EINVAL.
Extend lseek_test with -m for designated mirror I/O, and switch
sanity-ec 12c-12f from check_parity_read to SEEK_DATA/HOLE
checks that verify hole range boundaries instead of sampling
4k at fixed offsets.
Fixes: e21b93b5f7b4 ("LU-19631 llite: fix EOF handling for EC parity mirrors")
Test-Parameters: testlist=sanity-ec
Test-Parameters: testlist=sanity-ec fstype=zfs
Assisted-by: Cursor:Grok-4.6 llm_code_and_review_tools
Signed-off-by: Keguang Xu <kxu@ddn.com>
Change-Id: I26eb4c19d26f01e38ababf303de1df5492056193
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/66672
Reviewed-by: Andreas Dilger <adilger@thelustrecollective.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Reviewed-by: Marc Vef <mvef@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>