Add a 'lazyio' mount option to the kernel Ceph client that enables
LazyIO globally for all regular file opens on a mount. This is the
kclient equivalent of the 'client_force_lazyio=true' config option
in the ceph-fuse userspace client.
When 'lazyio' is specified, CEPH_FILE_MODE_LAZY is automatically
added to every regular file's fmode at open time in ceph_open() and
ceph_atomic_open(), causing the I/O paths to request
CEPH_CAP_FILE_LAZYIO from the MDS. This permits buffered I/O via
the page cache even when multiple clients have the file open for
write — beneficial for HPC workloads that can tolerate relaxed
cache coherency.
The mount option is exposed as 'lazyio' / 'nolazyio' via the VFS
fsparam_flag_no mechanism and supports remount.
Link: https://tracker.ceph.com/issues/77594
Signed-off-by: Xiubo Li <xiubo.li@clyso.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
ceph_inode_shutdown() purges every cap on the inode but never wakes
i_cap_wq, unlike remove_session_caps_cb() which does so after the same
kind of purge. Anyone blocked in ceph_get_caps() is waiting on that
queue for caps that are now gone for good, so the wait only ends when
the task is killed.
Wake the queue after purging so the waiters get a chance to notice the
shutdown and bail out.
Signed-off-by: Xiubo Li <xiubo.li@clyso.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
parse_reply_info_lease() reads a 32-bit struct_len off the wire and only
checks that many bytes are present, without requiring struct_len to cover
sizeof(struct ceph_mds_reply_lease) (10 bytes). A malicious MDS can
declare a shorter record and still get the pointer published: the
following *p += sizeof(**lease) overshoot is undone by *p = lend, so
nothing downstream rejects the reply. ceph_fill_trace() ->
update_dentry_lease() then reads 10 bytes through that pointer on any
lookup on a mounted CephFS, running past the end of the message front.
Require the record to cover the structure, matching the sibling
parse_reply_info_dir(). A conforming MDS always encodes the full 10
bytes.
BUG: KASAN: slab-out-of-bounds in __update_dentry_lease.constprop.0 (fs/ceph/inode.c:1459)
Read of size 4 at addr ffff888026c63d65 by task kworker/0:3/2366
Workqueue: ceph-msgr ceph_con_workfn
Call Trace:
__update_dentry_lease.constprop.0 (fs/ceph/inode.c:1459)
ceph_fill_trace (fs/ceph/inode.c:1474 fs/ceph/inode.c:1823)
mds_dispatch (fs/ceph/mds_client.c:4229 fs/ceph/mds_client.c:7225)
ceph_con_process_message (net/ceph/messenger.c:1424)
ceph_con_v1_try_read (net/ceph/messenger_v1.c:1430)
ceph_con_workfn (net/ceph/messenger.c:1576)
process_one_work (kernel/workqueue.c:3396)
worker_thread (kernel/workqueue.c:3479 kernel/workqueue.c:3560)
kthread (kernel/kthread.c:436)
ret_from_fork (arch/x86/kernel/process.c:158)
ret_from_fork_asm (arch/x86/entry/entry_64.S:245)
The buggy address is located 357 bytes inside of
allocated 360-byte region [ffff888026c63c00, ffff888026c63d68)
Cc: stable@vger.kernel.org
Fixes: 4ac4c23eaa ("ceph: decode alternate_name in lease info")
Reported-by: co+f92fbe44e3c6df69@bugs.sh
Assisted-by: LLM
Signed-off-by: Xiang Mei <xmei5@asu.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
check_new_map() sizes its export-target bitmap from CEPH_MAX_MDS but walks
it with newmap->possible_max_rank, which comes straight off the wire:
ceph_mdsmap_decode() sets it to max(m_num_active_mds, m_max_mds), then
overwrites it with the size of the "in" set. Neither is bounded by
CEPH_MAX_MDS, only by m_info allocating, so a monitor announcing more ranks
than the bitmap holds makes test_bit() read past the end of targets[]. The
clear_bit() loop above indexes the same bitmap, though it is additionally
bounded by mdsc->max_sessions. The map arrives on the monitor connection,
which is unauthenticated in legacy msgr mode.
CEPH_MAX_MDS is a protocol constant from src/mds/mdstypes.h, and the
reserved inode ranges in super.h are laid out one rank apart over that
span, so a map claiming more ranks is corrupt. Reject it where the rank
space is established rather than letting the count reach check_new_map().
BUG: KASAN: stack-out-of-bounds in check_new_map (fs/ceph/mds_client.c:5968)
Read of size 8 at addr ffffc90000ac7798 by task kworker/1:2/127
Workqueue: ceph-msgr ceph_con_workfn
Call Trace:
<TASK>
dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120)
print_report (mm/kasan/report.c:378 mm/kasan/report.c:482)
kasan_report (mm/kasan/report.c:595)
kasan_check_range (mm/kasan/generic.c:186 mm/kasan/generic.c:200)
check_new_map (fs/ceph/mds_client.c:5968)
ceph_mdsc_handle_mdsmap (fs/ceph/mds_client.c:7060)
extra_mon_dispatch (fs/ceph/super.c:802)
mon_dispatch (net/ceph/mon_client.c:1483)
ceph_con_process_message (net/ceph/messenger.c:1424)
ceph_con_v1_try_read (net/ceph/messenger_v1.c:1430)
ceph_con_workfn (net/ceph/messenger.c:1576)
process_one_work (kernel/workqueue.c:3396)
worker_thread (kernel/workqueue.c:3479 kernel/workqueue.c:3560)
kthread (kernel/kthread.c:436)
ret_from_fork (arch/x86/kernel/process.c:158)
ret_from_fork_asm (arch/x86/entry/entry_64.S:245)
</TASK>
The buggy address belongs to stack of task kworker/1:2/127
and is located at offset 288 in frame:
check_new_map (fs/ceph/mds_client.c:5846)
This frame has 1 object:
[32, 288) 'targets'
Cc: stable@vger.kernel.org
Fixes: d517b3983d ("ceph: reconnect to the export targets on new mdsmaps")
Reported-by: co+f8e3e01d8dda8689@bugs.sh
Assisted-by: LLM
Signed-off-by: Xiang Mei <xmei5@asu.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
decode_encrypted_symlink() allocates enclen + 1 bytes but writes the NUL
terminator at sym[declen + 1] instead of sym[declen]. A malicious MDS can
report symlink_len == 0 for an encrypted inode, and base64_decode() returns
0 for a zero-length input, so the store lands one byte past a kmalloc(1)
allocation.
Terminate at sym[declen], which is always within the allocation.
BUG: KASAN: slab-out-of-bounds in ceph_fill_inode (fs/ceph/inode.c:996)
Write of size 1 at addr ffff888020aad361 by task kworker/0:0/9
Workqueue: ceph-msgr ceph_con_workfn
Call Trace:
kasan_report (mm/kasan/report.c:595)
ceph_fill_inode (fs/ceph/inode.c:996 fs/ceph/inode.c:1277)
ceph_fill_trace (fs/ceph/inode.c:1716)
ceph_con_process_message (net/ceph/messenger.c:1424)
ceph_con_v1_try_read (net/ceph/messenger_v1.c:1430)
ceph_con_workfn (net/ceph/messenger.c:1576)
...
The buggy address belongs to the object at ffff888020aad360
which belongs to the cache kmalloc-8 of size 8
The buggy address is located 0 bytes to the right of
allocated 1-byte region [ffff888020aad360, ffff888020aad361)
Fixes: 79f2f6ad87 ("ceph: create symlinks with encrypted and base64-encoded targets")
Reported-by: co+b0f93e29183ce737@bugs.sh
Assisted-by: LLM
Signed-off-by: Xiang Mei <xmei5@asu.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
The read offset is validated against i_size but never against
inline_len, and the two fields come from the MDS independently. When
a read starts past the end of the inline data, the subtraction
len = min_t(size_t, iinfo->inline_len - subreq->start, subreq->len);
underflows and min_t() ends up with subreq->len, so copy_to_iter()
reads past the end of the inline buffer straight into the user
buffer. A malicious or buggy MDS reporting a short inline payload
together with an inflated i_size can thus leak kernel heap memory to
userspace.
Bail out with -ENODATA when the offset is not within the inline
data.
Cc: stable@vger.kernel.org
Fixes: 5b19f1eba4 ("ceph: make ceph_netfs_issue_op() handle inlined data")
Signed-off-by: Guanglei Zhu <zhugl3@xiaopeng.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
The MDS decides how much inline data to attach to a reply, and the
client parses inline_len without any upper bound: ceph_decode_need()
only verifies that the message actually carries that many bytes.
ceph_fill_inline_data() then copies the data into a single folio
with no length check, so a malicious or buggy MDS returning more
inline data than the folio can hold writes past its end.
Clamp the length to folio_size() so both callers, handle_cap_grant()
and fill_inode(), are covered.
Cc: stable@vger.kernel.org
Fixes: 31c542a199 ("ceph: add inline data to pagecache")
Signed-off-by: Guanglei Zhu <zhugl3@xiaopeng.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Snapshot longname reconstruction formats "_<name>_<inode>" via snprintf()
and memcpy()s the result into oname->name. Checking the length against
NAME_MAX only protects the LOOKUPNAME/export callers, whose buffer is
allocated with fscrypt_fname_alloc_buffer(NAME_MAX). The readdir path
points oname->name straight at the altname in the MDS reply, whose
capacity is altname_len; the reconstructed name can exceed that while
still fitting under NAME_MAX, overflowing the in-place destination.
Save the actual oname->len before the decryption overwrites it, and fail
with -ENAMETOOLONG when the reconstructed name would not fit.
Cc: stable@vger.kernel.org
Fixes: dd66df0053 ("ceph: add support for encrypted snapshot names")
Suggested-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Jiangshan Yi <yijiangshan@kylinos.cn>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
ceph_direct_read_write() builds its bio_vec array with
iov_iter_get_pages2(), which takes a reference on each page rather than
pinning it. As the page is not pinned, fork() does not copy it early for
the child and page migration is free to move it. If a process forks
while a direct read is in flight and the parent then writes to the page,
the parent gets a fresh copy while the read completes into the original,
which now belongs to the child. The read reports success and the parent
never sees the data.
Switch to iov_iter_extract_bvecs(), which pins user pages with FOLL_PIN
and borrows kernel pages without taking a reference. This is the same
conversion the block layer did in commit a7e689dd1c ("block: Convert
bio_iov_iter_get_pages to use iov_iter_extract_pages") and fuse did in
commit 738adade96 ("fuse: Fix missing FOLL_PIN for direct-io").
Since iov_iter_extract_bvecs() coalesces contiguous ranges within a
folio into a single bio_vec, release per folio in put_bvecs() with
unpin_user_folio(). Unpinning is done based on
iov_iter_extract_will_pin().
The bio_vec array no longer needs to be zeroed. put_bvecs() used to walk
all npages entries and skip those with a NULL bv_page.
iov_iter_extract_bvecs() counts the entries it fills, so return that
count instead and don't go past it. The array is still sized by npages,
as that is the worst case of one bio_vec per page. Cap npages at
USHRT_MAX to match the type taken by iov_iter_extract_bvecs().
This also replaces the deprecated set_page_dirty_lock() with
folio_mark_dirty_lock() and drops the on-stack page array.
Tested against a Ceph 19.2.3 cluster with KASAN, lockdep and DEBUG_VM
enabled. A reproducer issues an 8 MiB O_DIRECT read (libaio and blocking
pread, with and without THP), forks while the read is held in flight by
pausing the OSDs, has the parent write to every page of the buffer,
and verifies the result. Without this change the parent loses the read
data in every variant, and with it the data is intact. The AIO and
direct I/O xfstests in the generic group pass as well.
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
ceph_process_folio_batch() assigns the result of
is_write_congestion_happened() to fsc->write_congested for every folio
it collects. The code it replaced only ever set write_congested to true
here, leaving the decrement paths to clear it once writeback_count
drops below CONGESTION_OFF_THRESH. The unconditional assignment means
that a sync writeback that runs while the count sits between the off and
on thresholds clears the flag on its first folio, and background
writeback resumes early.
Only set the flag here, as before.
Fixes: ce80b76dd3 ("ceph: introduce ceph_process_folio_batch() method")
Assisted-by: Claude:fable-5.1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
ceph_process_folio_batch() calls is_write_congestion_happened(), which
increments fsc->writeback_count, before calling
move_dirty_folio_in_page_array(). If the fscrypt bounce page allocation
there fails, the folio is redirtied and never makes it into the page
array, but the count is never dropped.
write_congested is only cleared when a decrement falls below
CONGESTION_OFF_THRESH, so the leaked counts set congestion early and
eventually leave write_congested set for good. Every WB_SYNC_NONE
writeback then returns 0 and background writeback stops entirely.
Bump the count only once the folio is in the page array.
Fixes: d55207717d ("ceph: add encryption support to writepage and writepages")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://sashiko.dev/#/patchset/20260902-remove-wait-on-page-writeback-v5-0-0b512e77e75b%40columbia.edu?part=1
Assisted-by: Claude:fable-5.1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Readahead acquires caps while the folios are locked. This can
deadlock when processing a pending truncate; truncate_pagecache() can
then attempt to a folio that is already locked.
Return -EAGAIN instead when `NON_BLOCKING` is set, causing the
readahead to be abandoned.
Cc: stable@vger.kernel.org
Fixes: 4987005600 ("ceph: convert ceph_readpages to ceph_readahead")
Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
Reviewed-by: Xiubo Li <xiubo.li@clyso.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This function only operates on folios, so rename it accordingly.
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
All callers have been converted to the folio equivalents, so remove
these unused helpers. This also removes a use of page_offset().
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Convert the page cleanup loop in writepages_finish() to work on folios.
Resolve the folio up front and unwrap any fscrypt bounce folio to its
page cache folio, storing the page cache page back into the array.
This removes a use of detach_page_private() and five calls to
compound_head() per page, while adding one back via page_folio().
While at it, remove the BUG_ON() in the num_pages loop, as it cannot be
triggered.
No functional change.
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Use ceph_folio_start_fscache() and only use a struct page pointer at the
osd_req_op_extent_osd_data_pages() boundary, which requires a page
array. This removes a call to compound_head() in
ceph_set_page_fscache().
This was the last user of ceph_set_page_fscache(), so remove it.
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Convert the request assembly loop and error path in ceph_submit_write()
to folios. This drops ceph's uses of the set_page_writeback(),
redirty_page_for_writepage(), and unlock_page() compatibility wrappers
in the writeback submission path.
Add ceph_folio_start_fscache(), a folio counterpart of
ceph_set_page_fscache(). The remaining caller of the latter in
write_folio_nounlock() will be converted separately.
In total, this removes eight calls to compound_head() hidden in the
page-based APIs and one explicit page_folio() call in
ceph_undo_wrbuffer_claim()'s caller, while adding four explicit
page_folio() calls.
Note that get_writepages_data_length() must still be passed the
possibly-bounce folio, not the unwrapped pagecache folio, as it checks
fscrypt_is_bounce_folio() to round encrypted lengths up to the fscrypt
block size.
No functional change.
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Introduce ceph_fscrypt_pagecache_folio() and ceph_fscrypt_folio_offset(),
folio equivalents of ceph_fscrypt_pagecache_page() and
ceph_fscrypt_page_offset(), and use them to convert
get_writepages_data_length() to folios.
This removes the last caller of page_snap_context(), so remove it as
well. This also removes a use of page->private and a call to
fscrypt_is_bounce_page().
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Iterate the writeback batch as folios rather than using
&folios[i]->page. Use ceph_folio_snap_context() for the snap context
check and folio_wait_writeback() instead of wait_on_page_writeback().
This removes one call to compound_head() and the last caller of
wait_on_page_writeback(). No functional change.
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Add a folio-based counterpart to page_snap_context() that reads the
snap context from folio->private directly.
Convert the three writeback paths that passed &folio->page to
page_snap_context() to ceph_folio_snap_context(), removing three
open-coded folio-to-page conversions. No functional change.
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Acked-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
write_folio_nounlock() marks the folio with PG_private_2 via
ceph_set_page_fscache() and starts an async write to the cache via
ceph_fscache_write_to_cache(). PG_private_2 is only cleared once that
write completes.
If the OSD write fails, the error paths return without waiting for the
cache write. On retry, ceph_find_incompatible() would wait for
writeback, but not for PG_private_2, before calling
write_folio_nounlock() again, which would trip the VM_BUG_ON_FOLIO() in
folio_start_private_2().
Wait for any pending cache write before starting writeback on the
folio. Do so before bumping the writeback congestion count and
allocating the possibly mempool-backed OSD request, so that a thread
sleeping on the cache I/O does not hold either while it waits.
Add ceph_folio_wait_fscache(), a wrapper for folio_wait_private_2(), and
use it.
Fixes: 1702e79734 ("ceph: add fscache writeback support")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://sashiko.dev/#/patchset/20260804-remove-wait-on-page-writeback-v2-0-81f0ab065284%40columbia.edu?part=7
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
When ceph_inc_osd_stopping_blocker() fails, ceph_submit_write()
redirties and unlocks the folios remaining in ceph_wbc->fbatch.
However, none of those folios are locked at this point: locked folios
were moved to ceph_wbc->pages[] and removed from the fbatch by
ceph_process_folio_batch(). Unlocking them triggers
VM_BUG_ON_FOLIO(!folio_test_locked(folio)) in folio_unlock(), or
unlocks a folio locked by another task.
This error path also returns -EIO without fully cleaning up the folios in
ceph_wbc->pages[]: their references are never dropped, fscrypt bounce
pages are never freed, the writeback congestion count is never
decremented, and the pages array is leaked. ceph_wbc->locked_pages is
also left non-zero, so ceph_writepages_start() loops back around and
hits BUG_ON(ceph_wbc.locked_pages).
Leave the fbatch folios alone, as ceph_writepages_start() drops their
references when releasing the batch, and unwind ceph_wbc->pages[] the
same way writepages_finish() would have. Abort writeback in
ceph_writepages_start() instead of continuing, matching the handling
of ceph_inc_osd_stopping_blocker() failure on entry, as the OSD
client is being torn down and further writeback cannot make progress.
An LLM was used to verify that the cleanup was comprehensive, and
suggested aborting the writeback instead of continuing.
Fixes: 1551ec61dc ("ceph: introduce ceph_submit_write() method")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://sashiko.dev/#/patchset/20260804-remove-wait-on-page-writeback-v2-0-81f0ab065284%40columbia.edu?part=5
Assisted-by: Claude:fable-5
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Pass a folio through the inline data plumbing: __ceph_do_getattr(),
struct ceph_mds_request, and ceph_fill_inode(). No callers pass a page
anymore, so this removes the &folio->page conversions in the fault and
READ_INLINE paths and the page_folio() call in ceph_fill_inode().
Remove externs from function declarations while at it.
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Convert the internals to folio APIs and pass a folio in from
ceph_fill_inode(). The kmap_atomic()/memcpy() pair becomes
memcpy_to_folio(), which also flushes the dcache, so drop the explicit
flush from the folio creation path. When a locked folio is passed in,
the callers flush after filling it, so the flush in memcpy_to_folio()
is redundant there, but harmless.
This removes the last caller of find_or_create_page() in ceph and saves
six calls to compound_head(). The page_folio() call added in
ceph_fill_inode() goes away once the locked page plumbing is converted.
Remove extern from the function declaration while at it.
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
The inline data is read into a scratch buffer that never enters the page
cache, so allocate it with folio_alloc() instead of
__page_cache_alloc(). This drops the cpuset page spreading that
__page_cache_alloc() applies on NUMA systems, which only makes sense for
page cache pages. The temporary buffer here is better off node local.
The mismatched __free_page()/__free_pages() pair both become
folio_put(). The __ceph_do_getattr() locked page plumbing will be
converted in a later patch, so pass &folio->page for now.
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Convert find_or_create_page() to __filemap_get_folio(), keeping the
existing GFP constraint. Saves three calls to compound_head().
The __ceph_do_getattr() locked page plumbing is converted separately,
so pass &folio->page for now.
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Convert the inline data page cache check to filemap_get_folio(), which
returns an ERR_PTR instead of NULL when no folio is present. Saves two
calls to compound_head().
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
ceph_netfs_issue_read() pins pages with iov_iter_get_pages_alloc2() for
encrypted inodes and attaches them with own_pages=false. If
ceph_inc_osd_stopping_blocker() then fails, the request is dropped
without calling finish_netfs_read(), so the page array and the
references taken on those pages leak: ceph_osd_data_release() only
frees pages when own_pages is true, and __free_pages() would be the
wrong destructor for GUP-pinned pages.
Release the vector with put_page() and kvfree() on that error path,
matching finish_netfs_read(). Unencrypted ITER reads are unaffected.
Fixes: 1464de9f81 ("ceph: wait for OSD requests' callbacks to finish when unmounting")
Signed-off-by: Alex Markuze <amarkuze@redhat.com>
Reviewed-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
ceph_d_delete() drops a dentry once its lease expires. Since ceph uses
inode_just_drop() for ->drop_inode, that last dput also evicts the
inode, and ceph_evict_inode() throws away a page cache that the caps
still vouch for. A buffered write that outlasts the dentry lease (30s
by default on the MDS side) is therefore flushed and closed, and the
reopen re-reads everything from the OSDs even though both the caps and
the pages were still valid.
Commit 52dd0f1b3f ("ceph: use generic_delete_inode() for
->drop_inode") removed the ->drop_inode hook because "positive dentry
and corresponding inode are always accompanied in MDS reply. So no
need to keep inode in the cache after dropping all its aliases". That
holds for the metadata, but it ties the lifetime of the page cache to
the lifetime of a name, and the two are validated by entirely different
things: a dentry is only as good as its lease, while cached pages are
good for as long as the caps that back them.
So bring the hook back and keep a regular file's inode while it still
has cached pages and still holds real caps. The name is unaffected: an
expired dentry is unhashed exactly as before, and the next lookup goes
to the MDS and finds the retained inode via ceph_get_inode() ->
iget5_locked(), which is keyed on the vino from the reply rather than
on any dentry. ceph_fill_inode() then refills it without touching the
mapping.
Retention is bounded by the page cache itself, and reclaim runs in that
order rather than the other way round. A retained inode holds no
reference of its own, but it does not sit on the inode LRU either:
mapping_shrinkable() is false while real folios are present, so the
inode shrinker never sees it. Page reclaim frees its pages like any
other file's; emptying the mapping is what makes it shrinkable and puts
it on the LRU, and only then can the inode shrinker evict it. Unmount
evicts it regardless, as evict_inodes() walks sb->s_inodes rather than
the LRU.
MDS cap trim needs one more thing. trim_caps_cb() releases an unused
cap indirectly, by pruning the inode's aliases and letting the eviction
that follows call __ceph_remove_caps(). Retaining the inode breaks
that chain in both of its cases: an inode whose aliases are already
gone was never reachable that way, and after d_prune_aliases() the
iput() that ceph_iterate_session_caps() owes the inode no longer evicts
it. Give that path an explicit override in
CEPH_I_EVICT_ON_FINAL_IPUT_BIT, which ceph_drop_inode() consumes with
test_and_clear_bit(). Being one-shot is the point: it lets the MDS
force this inode out now without permanently changing how the inode is
cached afterwards, which is why I_DONTCACHE is not used here.
Signed-off-by: Xiubo Li <xiubo.li@clyso.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
ceph_get_tree() calls sget_fc() directly and so never goes through
vfs_get_super(), which is what sets SB_ACTIVE after fill_super for
filesystems that use it. Before commit 82995cc6c5 ("libceph, rbd,
ceph: convert to use the new mount API") the flag used to be set by
get_sb_nodev(), which did this for ceph, but the conversion dropped it.
SB_ACTIVE is required for iput_final() to retain an inode on the
inode LRU instead of evicting it once its last reference goes away.
This has gone unnoticed because ceph sets inode_just_drop() for
->drop_inode, which always asks for eviction, so the retain branch in
iput_final() was never reachable. The next patch makes ->drop_inode()
able to retain inodes, and that needs the flag to actually work.
Set it once the mount is up, like nfs_get_tree() does.
Fixes: 82995cc6c5 ("libceph, rbd, ceph: convert to use the new mount API")
Signed-off-by: Xiubo Li <xiubo.li@clyso.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
The declaration of these return valued (KEEP, DELETE, TOUCH, STOP) and
their use in __dentry_leases_walk() suggests that these are bit flags,
but there is only ever one bit set. Converting these to a
non-anonymous enum expresses the intent more clearly.
[ idryomov: comment on enum lease_check_result isn't a kernel-doc
comment ]
Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Inline data support has been deprecated in the CephFS MDS and is
being formally removed. Existing inline data can be migrated to
data pool objects via MDS scrub (see PR #44359).
Add CONFIG_CEPH_FS_INLINE_DATA (default n) to gate all inline data
code in the kclient. When disabled, CEPH_FEATURE_MDS_INLINE_DATA is
not advertised to the MDS, which will then refuse to open files that
still have inline data, returning -EPERM and preventing silent data
corruption that would occur if the kclient tried to read inline data
from OSD objects that do not contain it.
The conditional compilation is centralized in fs/ceph/super.h, where
static inline helpers make all the inline data code compile out
cleanly when the option is disabled, so that removing the option
later only touches that one place. ceph_inline_version() returns
CEPH_INLINE_NONE when the option is disabled, which makes every
version comparison in the disabled build constant-fold to false;
the stubbed out ceph_uninline_data() and ceph_fill_inline_data() are
then unreachable.
The MDS still carries inline_version + inline_data on the wire, so
the reply and cap grant parsers keep consuming those fields even
with the option disabled, only skipping them, to keep the decode
pointer in sync for the fields that follow.
This config option will be kept for a transitional period to
allow existing CephFS deployments to migrate inline data via
MDS scrub. Once the migration period ends, the option and all
inline data code will be permanently removed.
Users upgrading from an older Ceph release should ensure all inline
data has been migrated before deploying a kclient with this option
disabled:
1. Enable and run MDS scrub to uninline existing data
2. Disable inline_data on the filesystem:
ceph fs set <fs> inline_data false --yes-i-really-really-mean-it
Link: https://tracker.ceph.com/issues/67769
Signed-off-by: Xiubo Li <xiubo.li@clyso.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
On 64 bit systems, ceph_vino_to_ino_t() is a no-op, and inode.i_ino is
the same as ceph_vino.ino.
This reduces the size of `struct ceph_inode_info` by 8 bytes.
Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Some code simplification.
Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This documents that these functions do not modify the parameters.
Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Previously, both `u32` and `u64` was used with implicit casts. All
this does is add useless overhead.
This will allow better struct packing in `struct ceph_cap_snap`.
Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This reduces the size of `struct ceph_inode_xattr` by 8 bytes.
Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This field was added 17 years ago by commit de57606c23 ("ceph:
client types") but it was never used.
This reduces the size of `struct ceph_inode_info` by 8 bytes.
Fixes: de57606c23 ("ceph: client types")
Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
All fixes in drivers (or the tape ULD) and one core fix to bsg (the
block ioctl equivalent of sg_io). The biggest is the race in auth
updates fix in iscsi configfs, but the next biggest one is in bsg but
the generic pieces of that are mostly threading reply_len.
Signed-off-by: James E.J. Bottomley <James.Bottomley@HansenPartnership.com>
-----BEGIN PGP SIGNATURE-----
iLgEABMIAGAWIQTnYEDbdso9F2cI+arnQslM7pishQUCatTZmRsUgAAAAAAEAA5t
YW51MiwyLjUrMS4xMiwyLDImHGphbWVzLmJvdHRvbWxleUBoYW5zZW5wYXJ0bmVy
c2hpcC5jb20ACgkQ50LJTO6YrIWZfAD/ZC6Pwo0OMS8MuYYGwb+fF2YM0Msr+zAG
4gDRU5yDWl0A/jEw1iFbmGyoNTtBTHSE9I38j/nRAaa+UT/JeS4q0g1E
=wBqG
-----END PGP SIGNATURE-----
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI fixes from James Bottomley:
"All fixes in drivers (or the tape ULD) and one core fix to bsg (the
block ioctl equivalent of sg_io).
The biggest is the race in auth updates fix in iscsi configfs, but the
next biggest one is in bsg but the generic pieces of that are mostly
threading reply_len"
* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
scsi: bsg: Pass reply_len to bsg_setup_queue() to fit UFS ARPMB replies
scsi: libsas: Fix SMP IO deadlock during HA resume
scsi: libiscsi: Validate the task named by a management response
scsi: libiscsi: Validate the ITT reflected in a Reject PDU
scsi: libiscsi: Reject a negative task index from parse_pdu_itt
scsi: target: iscsi: Fix race in discovery auth updates
scsi: target: Disable interrupts while holding delayed_cmd_lock
scsi: st: Fix use-after-free race between st_remove() and st_open()
scsi: st: Save the visited block for the partition the drive is in
scsi: xen/scsifront: Check for a NULL shadow entry on a backend response
A small collection of driver specific fixes, all quite important if you
have the relevant hardware.
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQReagvpf3TrrA7BoYYv73Ows9A4iQUCatTACAAKCRAv73Ows9A4
if2lAQDfQLZHMIvrU2wGNFBX2CUe2repS3JyRnmRalP9nXSVkAEAgS4wY/wU8wzQ
o+7ajrnUAZjgx/IK3HKoV0fXMOvlTAw=
=1PL3
-----END PGP SIGNATURE-----
Merge tag 'spi-fix-v7.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi fixes from Mark Brown:
"A small collection of driver specific fixes, all quite important if
you have the relevant hardware"
* tag 'spi-fix-v7.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
spi: spi-fsl-lpspi: directly return ret in fsl_lpspi_transfer_one()
spi: spi-fsl-lpspi: pass struct fsl_lpspi_data instead of struct spi_controller if possible
spi: imx: fix slab corruption from undersized DMA bounce buffers
spi: tegra114: assert CS GPIO for every transfer in a message
The main thing here is a fix for lockdep warnings with MMIO regmaps that
use a raw spinlock and a cache, some other lockdep fixes we'd done for
the benefit of the maple tree on sleeping buses meant that we were doing
allocations for those MMIO regmaps under a raw spinlock. While fixing
that Michael Reeves also noticed that the debugfs files were briefly
available without the cache structures backing them.
There's also a fix for interrupt freeing on error in regmap-irq which
had been hanging around because it's not super urgent.
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQReagvpf3TrrA7BoYYv73Ows9A4iQUCatS/PwAKCRAv73Ows9A4
idqeAP4y6bdFUzY0e9Ntiixana3IyzJ2dxzrjHIFHcOZl02UhwD8D2jWwFIw0CIs
izZUkBabg5UyIeM1NkzZWtmDhkZTaAk=
=AS9J
-----END PGP SIGNATURE-----
Merge tag 'regmap-fix-v7.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
Pull regmap fixes from Mark Brown:
"The main thing here is a fix for lockdep warnings with MMIO regmaps
that use a raw spinlock and a cache, some other lockdep fixes we'd
done for the benefit of the maple tree on sleeping buses meant that we
were doing allocations for those MMIO regmaps under a raw spinlock.
While fixing that Michael Reeves also noticed that the debugfs files
were briefly available without the cache structures backing them.
There's also a fix for interrupt freeing on error in regmap-irq which
had been hanging around because it's not super urgent"
* tag 'regmap-fix-v7.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
regmap: Drop map lock during cache init and exit
regmap: Remove debugfs before cache teardown
regmap: irq: Free the irqdomain we create
Three independent clock management fixes, plus one for a simple
reset mask blunder in the qcom-cci interrupt handler.
- qcom-cci: prevent lost reset requests during interrupt handling
- qcom-geni: preserve the selected source clock
- viai2c-wmt: fix clock reference leak
- xiic: fix clock disable warnings during removal
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQScDfrjQa34uOld1VLaeAVmJtMtbgUCatTkqQAKCRDaeAVmJtMt
bmntAQCohnAvbkYQh6VfaPl5TzQPytHWTMg3AiqyLeDWs7MuAAD/RQS6vFQMyzvj
kD1fK/ocHIs/D59T21JiOzhhiNSSNwo=
=SdHD
-----END PGP SIGNATURE-----
Merge tag 'i2c-fixes-7.3-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux
Pull i2c fixes from Andi Shyti:
"Three independent clock management fixes, plus one for a simple
reset mask blunder in the qcom-cci interrupt handler"
* tag 'i2c-fixes-7.3-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux:
i2c: xiic: restore non-managed runtime PM to fix clk WARN flood
i2c: qcom-cci: Fix HALT_ACK reset request being dropped
i2c: qcom-geni: Restore the source-clock selection policy
i2c: viai2c-wmt: Fix clock leak in wmt_i2c_probe()
Fix a regression introduced in v6.19. It affects cancellation of the
timer for split transaction timeout when handling a response. The issue
is unlikely to occur in practice.
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQQE66IEYNDXNBPeGKSsLtaWM8LwEwUCatQ4OwAKCRCsLtaWM8Lw
E2sNAP49Zw/nOmC9OaYKthJtKUup5Oi+4kxQnNjnDDNIraa/2gEAnhum0sbs/PHt
VCRl5/WMsHPQRgNMrihFO6G+2+KACgQ=
=F+OT
-----END PGP SIGNATURE-----
Merge tag 'firewire-fixes-7.3-final' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394
Pull firewire fix from Takashi Sakamoto:
"Fix a regression introduced in v6.19. It affects cancellation of the
timer for split transaction timeout when handling a response. The
issue is unlikely to occur in practice"
* tag 'firewire-fixes-7.3-final' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394:
firewire: core: fix race condition in split transaction handling
- Emit the FineIBT paranoid "cs" prefix as a byte,
to work around a GNU toolchain build warning (Kees Cook)
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-----BEGIN PGP SIGNATURE-----
iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmrUo24RHG1pbmdvQGtl
cm5lbC5vcmcACgkQEnMQ0APhK1i2PhAAm4V2NsF3knhwSQ2WC55RTZbXmlYLAJAq
57rUJejuVM7eHrNhsT0FJIesMLbIDHz5RzVSllN7ESBB5zEkbiyIxRonaG6WTiKk
G0y/IyPsA4BWFp9Ojq5NyDhD95do0gTc08Oxd8eEeJULBzGAaErGl8ExX15SQJkh
eMVdAN4RcathkVrgKbdTklXkECa9j4I+rfBlkX4g8bJ22mbi8h8nfYNrlkX9vncf
IxWNwUh3eKAamLHnKeqbmDUOUrP7ss/hWGWRG0La7G+8jWoX3YlWQdzJeMtWzdV6
unNeFIjjP4lvBtKDkfUBf0JZN+mKo/Zwl5dWNQ/A26vOJTJmmFx03YsuWYDXR0+Q
Vqvm09PSSPbKdGWT7MmlJNhEdBUPOLmCSOT06hfHYKsk+Qkx8XMUIz/bTbNW5gVP
eeok5YWMBn3dQ2B4+LfBqxwMeu+jripgJjN0bj1JOHwkMzYthRce3SHyWRW6hsIh
oOReFnmxaImkh22ia1RLnPscp2efkV9InL5IpNXIH3MXpvlNiUfd0OiDMSGS6ici
AnErf5LK1aXLI+agmBx+7XovUb7umnWpUyvLy3f93E6i6o3urGJ2Tg9Eq+pLJPOR
OAYkzsdJiLCVZqiFm+S+8xNCmlnOs76rKk9bOElOBXUej80q0zwQXHzJ8Pl+yBU1
zw54ecYyK8A=
=xZLR
-----END PGP SIGNATURE-----
Merge tag 'x86-core-2026-10-18' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/core update from Ingo Molnar:
- Emit the FineIBT paranoid "cs" prefix as a byte,
to work around a GNU toolchain build warning (Kees Cook)
* tag 'x86-core-2026-10-18' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/kcfi: Emit the FineIBT paranoid "cs" prefix as a byte