Repository navigation
volumeop/smtclient: release FCPs on VM delete and keep FCP state current - #974
Conversation
|
Review body Review of the new commit only ("Fix FCP release on VM delete and keep FCP state current"); the other commits are from #965. Inline comments are below; two findings sit on lines outside this diff, so they are here: Generated by Claude Code Inline comments zvmsdk/database.py:163 — PRAGMA synchronous=NORMAL In WAL mode, synchronous=NORMAL lets a committed transaction roll back after a power loss or OS crash. Scenario: reserve_fcps or increase_connections commits, z/VM dedicates the FCP, then the LPAR loses power before the WAL is fsynced. After restart the row shows reserved=0, connections=0, so the FCP can be allocated to a second VM while it is still dedicated in the directory. Since this DB tracks allocation of real devices, I'd keep synchronous=FULL. zvmsdk/smtclient.py:2593 — with zvmutils.ignore_errors(): ignore_errors() logs only str(err), with no traceback, and delete_vm still reports success. A "database is locked" or other DB error here leaves the deleted VM's FCPs reserved, the leak this PR sets out to fix, with only one "ignore an error" line in the log. sync_db was changed to LOG.exception in this same PR; please do the same here (catch, LOG.exception naming the userid, continue). zvmsdk/database.py:516 — state='free', owner='none' This sets state='free' on every FCP of the assigner, including ones the sync marked offline or notfound. After the VM is deleted, a missing device then matches the allocator's state='free' AND connections=0 AND reserved=0 filter, and usage reports show it as free until a sync deletes it. Suggest resetting only the assigner fields, or changing state only where it is 'active'. zvmsdk/volumeop.py:2122 — bulk_update_state_in_fcp_table([fcp], 'free', 'none') This path also runs when z/VM returned 404/204 rs=8 ("device not defined"). That means the FCP is not dedicated to this user, not that it is free: it may be offline/notfound, or now dedicated to another user. Writing free/none here can make an offline FCP allocatable, or clear another user's owner, until the next sync. Suggest skipping the write in the rs=8 case (or writing only owner if it still equals this userid). zvmsdk/volumeop.py:1729 — bulk_update_state_in_fcp_table( (dedicate) z/VM reports a dedicated FCP of a logged-off guest as free/NONE. When volumes are attached during provisioning, before power-on, this writes active/, the next sync_with_zvm rewrites it to free/none, and the next dedicate flips it back. Anything that reads state/owner sees values that depend on sync timing. Either align the write with what the sync will compute, or have the sync keep owner for rows with an assigner_id. zvmsdk/database.py:424 — UPDATE fcp SET reserved=0, assigner_id='' Clearing assigner_id on unreserve means later cleanup keyed on it can no longer find rows whose state/owner are stale. Example: the undedicate on detach fails and its best-effort DB write is skipped, so state/owner stay active/USER; release then clears assigner_id; when USER is deleted, reset_fcps_of_assigner(USER) no longer matches that row. It also loses the last assigner for diagnostics. If clearing is kept, consider also resetting state/owner in the same statement. zvmsdk/database.py:161 — PRAGMA journal_mode=WAL This runs on every new connection, outside the get_*_conn try blocks. A user with read-only access (for example running zvmsdk-getpchid) or a read-only mount now fails on open with "attempt to write a readonly database", as a raw sqlite3.OperationalError rather than an SDK exception. Suggest setting WAL once at DB creation (it persists in the file) and wrapping the pragma in the existing error handling. zvmsdk/config.py:539 — Opt('connection_timeout', The new [database] connection_timeout option isn't in doc/source/zvmsdk.conf.sample; this PR adds backend there but not this one. Operators tuning lock waits won't find it. |
d5a7431 to
fb65bc4
Compare
|
Thanks for the detailed review. All points are addressed in the first commit. I also rebased on master, so #965's commits no longer show up here.
I re-tested the changed paths on a z/VM host: VM delete with and without a DB error, dedicate/undedicate, reset with offline and other-owner rows, migration backup with rows still in the WAL, and read-only open. I also re-ran |
fb65bc4 to
813cd3f
Compare
|
New findings (second commit)
|
- delete_vm released a VM's FCPs only after namelist, vswitch and network cleanup, so any earlier failure left them reserved for a VM that no longer exists. They are now released right after the user is deleted; a failure there is logged and the delete goes on. - reset_fcps_of_assigner also sets an FCP that is active for the deleted user to free/none. Other states and owners are left to the next sync. - A successful undedicate sets the FCP free/none at once, so it can be allocated before the next sync. - A failed FCP DB sync with z/VM is logged with a traceback instead of being ignored. - The FCP DB uses WAL and a configurable lock timeout ([database] connection_timeout), so zvmsdk-getpchid and the SDK server don't fail each other with "database is locked". - The md5-to-sha512 migration backs up the DB with the sqlite backup API, so rows still in the WAL file are included. Signed-off-by: Manish Kumar <Manish.Kumar176@ibm.com>
Every z/VM FCP query ran two vmcp commands per FCP device to find its PCHID, so the query got slower with each FCP device. One CHPID whose PCHID could not be found failed the query for all FCP devices: the FCP table was no longer synced and every new FCP allocation on the host failed. zvmsdk-getpchid still exited 0 then, so its caller took the stale FCP usage as current. Look up the PCHID once per CHPID in each query. An FCP device whose PCHID is not found keeps the PCHID in the database, or gets an empty one if it is new. zvmsdk-getpchid exits 1 when its FCP sync with z/VM failed. FCP devices could also stay reserved for a z/VM user that no longer exists, for example after a boot from volume deploy failed before the user was created, and nothing released them. zvmsdk-getpchid --list-held lists the reserved, connected or template-allocated FCP devices per user, with whether the user exists on z/VM and whether it is a guest of the host. --release frees the FCP devices of the given users, but only of a user that does not exist on z/VM and is not a guest of the host. Signed-off-by: Manish Kumar <Manish.Kumar176@ibm.com>
8f15dd6 to
ff1443c
Compare
|
Thanks Rajat, updated (still the same two commits, now rebased on master):
|
Two commits on master.
Why
SMTClient.delete_vm()reset the VM's FCP records only at the end, after namelist removal, vswitch revoke and network cleanup, and each of those re-raises. If any of them failed, the reset never ran and the FCPs stayed reserved for a VM that no longer exists. The free FCP pool shrinks until attach or boot-from-volume fails with "no available FCP".reset_fcps_of_assigner()leftstate='active'andowner=<deleted user>, and undedicate left the old values.FCPManager.sync_db()wrapped the z/VM sync inignore_errors().zvmsdk-getpchidopen the same SQLite file. With the driver's default 5s wait in rollback-journal mode, normal contention could fail azvmsdk-getpchidrun.vmcpcommands per FCP device. One CHPID whose PCHID could not be found failed the query for all FCP devices: the FCP table was no longer synced, and every new FCP allocation on the host failed.zvmsdk-getpchidstill exited 0, so its caller took the stale usage as current.What changes
Fix FCP release on VM delete and keep FCP state current
smtclient.delete_vm: the FCPs are released right afterdelete_userid()succeeds. A failure is logged with a traceback naming the userid, and the delete goes on. The count is logged for every DB backend.reset_fcps_of_assigner: an FCP that isactivefor the deleted user becomesfree/none. Other states and owners are left to the next sync. It returns the number of rows reset.bulk_update_state_in_fcp_table: takes an optionalnew_owner._undedicate_fcpwritesfree/noneonly after a successful undedicate, not when the FCP was already undedicated. The write is best-effort, so a DB error can't fail a z/VM operation that already succeeded.FCPManager.sync_db: logs a failure with a traceback. It still doesn't raise.PRAGMA journal_mode=WAL; it logs a warning if WAL can't be set, for example on read-only access.[database] connection_timeoutoption (default 30s).PRAGMA quick_check.db_interface: contract docstrings updated; the contract tests cover the new behaviour for every backend.test_zvmsdk-getpchid: mocksfcp_ops.get_pchid_usage, which the script reads since database: add a pluggable DB backend and make FCP DB work whole operations #965.Look up FCP PCHIDs once per CHPID, report failed syncs, free leaked FCPs
FCPManager.synced_with_zvmrecords whether the last sync worked.zvmsdk-getpchidexits 1 with an error when it didn't, instead of printing the stale usage.zvmsdk-getpchid --list-held(read-only) lists the FCP devices that are reserved, connected or allocated from a template, per user. For each user it shows whether the user exists on z/VM (exists / missing / unknown; only z/VM's explicit "Invalid option - " reply counts as missing) and whether it is a guest of the host. A known guest isn't queried on z/VM.zvmsdk-getpchid --release USERID[,USERID...]frees the FCP devices of the given users, only of a user that is missing on z/VM and not a guest of the host. It checks again before releasing.