Skip to content

Commit fcd0bb8

Browse files
committed
Merge tag 'vfs-6.16-rc2.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs fixes from Christian Brauner: - Fix the AT_HANDLE_CONNECTABLE option so filesystems that don't know how to decode a connected non-dir dentry fail the request - Use repr(transparent) to ensure identical layout between the C and Rust implementation of struct file - Add a missing xas_pause() into the dax code employing wait_entry_unlocked_exclusive() - Fix FOP_DONTCACHE which we disabled for v6.15. A folio could get redirtied and/or scheduled for writeback after the initial dropbehind test. Change the test accordingly to handle these cases so we can re-enable FOP_DONTCACHE again * tag 'vfs-6.16-rc2.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: exportfs: require ->fh_to_parent() to encode connectable file handles rust: file: improve safety comments rust: file: mark `LocalFile` as `repr(transparent)` fs/dax: Fix "don't skip locked entries when scanning entries" iomap: don't lose folio dropbehind state for overwrites mm/filemap: unify dropbehind flag testing and clearing mm/filemap: unify read/write dropbehind naming Revert "Disable FOP_DONTCACHE for now due to bugs" mm/filemap: use filemap_end_dropbehind() for read invalidation mm/filemap: gate dropbehind invalidate on folio !dirty && !writeback
2 parents 7f9039c + 5402c4d commit fcd0bb8

File tree

8 files changed

+68
-24
lines changed

8 files changed

+68
-24
lines changed

fs/dax.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ static void *wait_entry_unlocked_exclusive(struct xa_state *xas, void *entry)
257257
wq = dax_entry_waitqueue(xas, entry, &ewait.key);
258258
prepare_to_wait_exclusive(wq, &ewait.wait,
259259
TASK_UNINTERRUPTIBLE);
260-
xas_pause(xas);
260+
xas_reset(xas);
261261
xas_unlock_irq(xas);
262262
schedule();
263263
finish_wait(wq, &ewait.wait);

fs/iomap/buffered-io.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,6 +1691,8 @@ static int iomap_add_to_ioend(struct iomap_writepage_ctx *wpc,
16911691
ioend_flags |= IOMAP_IOEND_UNWRITTEN;
16921692
if (wpc->iomap.flags & IOMAP_F_SHARED)
16931693
ioend_flags |= IOMAP_IOEND_SHARED;
1694+
if (folio_test_dropbehind(folio))
1695+
ioend_flags |= IOMAP_IOEND_DONTCACHE;
16941696
if (pos == wpc->iomap.offset && (wpc->iomap.flags & IOMAP_F_BOUNDARY))
16951697
ioend_flags |= IOMAP_IOEND_BOUNDARY;
16961698

fs/xfs/xfs_aops.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,25 @@ xfs_map_blocks(
436436
return 0;
437437
}
438438

439+
static bool
440+
xfs_ioend_needs_wq_completion(
441+
struct iomap_ioend *ioend)
442+
{
443+
/* Changing inode size requires a transaction. */
444+
if (xfs_ioend_is_append(ioend))
445+
return true;
446+
447+
/* Extent manipulation requires a transaction. */
448+
if (ioend->io_flags & (IOMAP_IOEND_UNWRITTEN | IOMAP_IOEND_SHARED))
449+
return true;
450+
451+
/* Page cache invalidation cannot be done in irq context. */
452+
if (ioend->io_flags & IOMAP_IOEND_DONTCACHE)
453+
return true;
454+
455+
return false;
456+
}
457+
439458
static int
440459
xfs_submit_ioend(
441460
struct iomap_writepage_ctx *wpc,
@@ -460,8 +479,7 @@ xfs_submit_ioend(
460479
memalloc_nofs_restore(nofs_flag);
461480

462481
/* send ioends that might require a transaction to the completion wq */
463-
if (xfs_ioend_is_append(ioend) ||
464-
(ioend->io_flags & (IOMAP_IOEND_UNWRITTEN | IOMAP_IOEND_SHARED)))
482+
if (xfs_ioend_needs_wq_completion(ioend))
465483
ioend->io_bio.bi_end_io = xfs_end_bio;
466484

467485
if (status)

include/linux/exportfs.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,13 +314,23 @@ static inline bool exportfs_can_decode_fh(const struct export_operations *nop)
314314
static inline bool exportfs_can_encode_fh(const struct export_operations *nop,
315315
int fh_flags)
316316
{
317+
if (!nop)
318+
return false;
319+
317320
/*
318321
* If a non-decodeable file handle was requested, we only need to make
319322
* sure that filesystem did not opt-out of encoding fid.
320323
*/
321324
if (fh_flags & EXPORT_FH_FID)
322325
return exportfs_can_encode_fid(nop);
323326

327+
/*
328+
* If a connectable file handle was requested, we need to make sure that
329+
* filesystem can also decode connected file handles.
330+
*/
331+
if ((fh_flags & EXPORT_FH_CONNECTABLE) && !nop->fh_to_parent)
332+
return false;
333+
324334
/*
325335
* If a decodeable file handle was requested, we need to make sure that
326336
* filesystem can also decode file handles.

include/linux/fs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2207,7 +2207,7 @@ struct file_operations {
22072207
/* Supports asynchronous lock callbacks */
22082208
#define FOP_ASYNC_LOCK ((__force fop_flags_t)(1 << 6))
22092209
/* File system supports uncached read/write buffered IO */
2210-
#define FOP_DONTCACHE 0 /* ((__force fop_flags_t)(1 << 7)) */
2210+
#define FOP_DONTCACHE ((__force fop_flags_t)(1 << 7))
22112211

22122212
/* Wrap a directory iterator that needs exclusive inode access */
22132213
int wrap_directory_iterator(struct file *, struct dir_context *,

include/linux/iomap.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,13 +377,16 @@ sector_t iomap_bmap(struct address_space *mapping, sector_t bno,
377377
#define IOMAP_IOEND_BOUNDARY (1U << 2)
378378
/* is direct I/O */
379379
#define IOMAP_IOEND_DIRECT (1U << 3)
380+
/* is DONTCACHE I/O */
381+
#define IOMAP_IOEND_DONTCACHE (1U << 4)
380382

381383
/*
382384
* Flags that if set on either ioend prevent the merge of two ioends.
383385
* (IOMAP_IOEND_BOUNDARY also prevents merges, but only one-way)
384386
*/
385387
#define IOMAP_IOEND_NOMERGE_FLAGS \
386-
(IOMAP_IOEND_SHARED | IOMAP_IOEND_UNWRITTEN | IOMAP_IOEND_DIRECT)
388+
(IOMAP_IOEND_SHARED | IOMAP_IOEND_UNWRITTEN | IOMAP_IOEND_DIRECT | \
389+
IOMAP_IOEND_DONTCACHE)
387390

388391
/*
389392
* Structure for writeback I/O completions.

mm/filemap.c

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,13 +1589,30 @@ int folio_wait_private_2_killable(struct folio *folio)
15891589
}
15901590
EXPORT_SYMBOL(folio_wait_private_2_killable);
15911591

1592+
static void filemap_end_dropbehind(struct folio *folio)
1593+
{
1594+
struct address_space *mapping = folio->mapping;
1595+
1596+
VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);
1597+
1598+
if (folio_test_writeback(folio) || folio_test_dirty(folio))
1599+
return;
1600+
if (!folio_test_clear_dropbehind(folio))
1601+
return;
1602+
if (mapping)
1603+
folio_unmap_invalidate(mapping, folio, 0);
1604+
}
1605+
15921606
/*
15931607
* If folio was marked as dropbehind, then pages should be dropped when writeback
15941608
* completes. Do that now. If we fail, it's likely because of a big folio -
15951609
* just reset dropbehind for that case and latter completions should invalidate.
15961610
*/
1597-
static void folio_end_dropbehind_write(struct folio *folio)
1611+
static void filemap_end_dropbehind_write(struct folio *folio)
15981612
{
1613+
if (!folio_test_dropbehind(folio))
1614+
return;
1615+
15991616
/*
16001617
* Hitting !in_task() should not happen off RWF_DONTCACHE writeback,
16011618
* but can happen if normal writeback just happens to find dirty folios
@@ -1604,8 +1621,7 @@ static void folio_end_dropbehind_write(struct folio *folio)
16041621
* invalidation in that case.
16051622
*/
16061623
if (in_task() && folio_trylock(folio)) {
1607-
if (folio->mapping)
1608-
folio_unmap_invalidate(folio->mapping, folio, 0);
1624+
filemap_end_dropbehind(folio);
16091625
folio_unlock(folio);
16101626
}
16111627
}
@@ -1620,8 +1636,6 @@ static void folio_end_dropbehind_write(struct folio *folio)
16201636
*/
16211637
void folio_end_writeback(struct folio *folio)
16221638
{
1623-
bool folio_dropbehind = false;
1624-
16251639
VM_BUG_ON_FOLIO(!folio_test_writeback(folio), folio);
16261640

16271641
/*
@@ -1643,14 +1657,11 @@ void folio_end_writeback(struct folio *folio)
16431657
* reused before the folio_wake_bit().
16441658
*/
16451659
folio_get(folio);
1646-
if (!folio_test_dirty(folio))
1647-
folio_dropbehind = folio_test_clear_dropbehind(folio);
16481660
if (__folio_end_writeback(folio))
16491661
folio_wake_bit(folio, PG_writeback);
1650-
acct_reclaim_writeback(folio);
16511662

1652-
if (folio_dropbehind)
1653-
folio_end_dropbehind_write(folio);
1663+
filemap_end_dropbehind_write(folio);
1664+
acct_reclaim_writeback(folio);
16541665
folio_put(folio);
16551666
}
16561667
EXPORT_SYMBOL(folio_end_writeback);
@@ -2635,16 +2646,14 @@ static inline bool pos_same_folio(loff_t pos1, loff_t pos2, struct folio *folio)
26352646
return (pos1 >> shift == pos2 >> shift);
26362647
}
26372648

2638-
static void filemap_end_dropbehind_read(struct address_space *mapping,
2639-
struct folio *folio)
2649+
static void filemap_end_dropbehind_read(struct folio *folio)
26402650
{
26412651
if (!folio_test_dropbehind(folio))
26422652
return;
26432653
if (folio_test_writeback(folio) || folio_test_dirty(folio))
26442654
return;
26452655
if (folio_trylock(folio)) {
2646-
if (folio_test_clear_dropbehind(folio))
2647-
folio_unmap_invalidate(mapping, folio, 0);
2656+
filemap_end_dropbehind(folio);
26482657
folio_unlock(folio);
26492658
}
26502659
}
@@ -2765,7 +2774,7 @@ ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter,
27652774
for (i = 0; i < folio_batch_count(&fbatch); i++) {
27662775
struct folio *folio = fbatch.folios[i];
27672776

2768-
filemap_end_dropbehind_read(mapping, folio);
2777+
filemap_end_dropbehind_read(folio);
27692778
folio_put(folio);
27702779
}
27712780
folio_batch_init(&fbatch);

rust/kernel/fs/file.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,12 +219,13 @@ unsafe impl AlwaysRefCounted for File {
219219
/// must be on the same thread as this file.
220220
///
221221
/// [`assume_no_fdget_pos`]: LocalFile::assume_no_fdget_pos
222+
#[repr(transparent)]
222223
pub struct LocalFile {
223224
inner: Opaque<bindings::file>,
224225
}
225226

226227
// SAFETY: The type invariants guarantee that `LocalFile` is always ref-counted. This implementation
227-
// makes `ARef<File>` own a normal refcount.
228+
// makes `ARef<LocalFile>` own a normal refcount.
228229
unsafe impl AlwaysRefCounted for LocalFile {
229230
#[inline]
230231
fn inc_ref(&self) {
@@ -235,7 +236,8 @@ unsafe impl AlwaysRefCounted for LocalFile {
235236
#[inline]
236237
unsafe fn dec_ref(obj: ptr::NonNull<LocalFile>) {
237238
// SAFETY: To call this method, the caller passes us ownership of a normal refcount, so we
238-
// may drop it. The cast is okay since `File` has the same representation as `struct file`.
239+
// may drop it. The cast is okay since `LocalFile` has the same representation as
240+
// `struct file`.
239241
unsafe { bindings::fput(obj.cast().as_ptr()) }
240242
}
241243
}
@@ -273,7 +275,7 @@ impl LocalFile {
273275
#[inline]
274276
pub unsafe fn from_raw_file<'a>(ptr: *const bindings::file) -> &'a LocalFile {
275277
// SAFETY: The caller guarantees that the pointer is not dangling and stays valid for the
276-
// duration of 'a. The cast is okay because `File` is `repr(transparent)`.
278+
// duration of `'a`. The cast is okay because `LocalFile` is `repr(transparent)`.
277279
//
278280
// INVARIANT: The caller guarantees that there are no problematic `fdget_pos` calls.
279281
unsafe { &*ptr.cast() }
@@ -347,7 +349,7 @@ impl File {
347349
#[inline]
348350
pub unsafe fn from_raw_file<'a>(ptr: *const bindings::file) -> &'a File {
349351
// SAFETY: The caller guarantees that the pointer is not dangling and stays valid for the
350-
// duration of 'a. The cast is okay because `File` is `repr(transparent)`.
352+
// duration of `'a`. The cast is okay because `File` is `repr(transparent)`.
351353
//
352354
// INVARIANT: The caller guarantees that there are no problematic `fdget_pos` calls.
353355
unsafe { &*ptr.cast() }

0 commit comments

Comments
 (0)