Skip to content

Commit 7d40507

Browse files
committed
Merge tag 'vfs-6.13-rc1.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs fixes from Christian Brauner: - Fix a few iomap bugs - Fix a wrong argument in backing file callback - Fix security mount option retrieval in statmount() - Cleanup how statmount() handles unescaped options - Add a missing inode_owner_or_capable() check for setting write hints - Clear the return value in read_kcore_iter() after a successful iov_iter_zero() - Fix a mount_setattr() selftest - Fix function signature in mount api documentation - Remove duplicate include header in the fscache code * tag 'vfs-6.13-rc1.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: fs/backing_file: fix wrong argument in callback fs_parser: update mount_api doc to match function signature fs: require inode_owner_or_capable for F_SET_RW_HINT fs/proc/kcore.c: Clear ret value in read_kcore_iter after successful iov_iter_zero statmount: fix security option retrieval statmount: clean up unescaped option handling fscache: Remove duplicate included header iomap: elide flush from partial eof zero range iomap: lift zeroed mapping handling into iomap_zero_range() iomap: reset per-iter state on non-error iter advances iomap: warn on zero range of a post-eof folio selftests/mount_setattr: Fix failures on 64K PAGE_SIZE kernels
2 parents b5287c5 + cf87766 commit 7d40507

File tree

9 files changed

+81
-79
lines changed

9 files changed

+81
-79
lines changed

Documentation/filesystems/mount_api.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,8 @@ process the parameters it is given.
770770

771771
* ::
772772

773-
bool fs_validate_description(const struct fs_parameter_description *desc);
773+
bool fs_validate_description(const char *name,
774+
const struct fs_parameter_description *desc);
774775

775776
This performs some validation checks on a parameter description. It
776777
returns true if the description is good and false if it is not. It will

fs/backing-file.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ int backing_file_mmap(struct file *file, struct vm_area_struct *vma,
327327
struct backing_file_ctx *ctx)
328328
{
329329
const struct cred *old_cred;
330+
struct file *user_file = vma->vm_file;
330331
int ret;
331332

332333
if (WARN_ON_ONCE(!(file->f_mode & FMODE_BACKING)))
@@ -342,7 +343,7 @@ int backing_file_mmap(struct file *file, struct vm_area_struct *vma,
342343
revert_creds_light(old_cred);
343344

344345
if (ctx->accessed)
345-
ctx->accessed(vma->vm_file);
346+
ctx->accessed(user_file);
346347

347348
return ret;
348349
}

fs/fcntl.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,9 @@ static long fcntl_set_rw_hint(struct file *file, unsigned int cmd,
374374
u64 __user *argp = (u64 __user *)arg;
375375
u64 hint;
376376

377+
if (!inode_owner_or_capable(file_mnt_idmap(file), inode))
378+
return -EPERM;
379+
377380
if (copy_from_user(&hint, argp, sizeof(hint)))
378381
return -EFAULT;
379382
if (!rw_hint_valid(hint))

fs/iomap/buffered-io.c

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,40 +1350,12 @@ static inline int iomap_zero_iter_flush_and_stale(struct iomap_iter *i)
13501350
return filemap_write_and_wait_range(mapping, i->pos, end);
13511351
}
13521352

1353-
static loff_t iomap_zero_iter(struct iomap_iter *iter, bool *did_zero,
1354-
bool *range_dirty)
1353+
static loff_t iomap_zero_iter(struct iomap_iter *iter, bool *did_zero)
13551354
{
1356-
const struct iomap *srcmap = iomap_iter_srcmap(iter);
13571355
loff_t pos = iter->pos;
13581356
loff_t length = iomap_length(iter);
13591357
loff_t written = 0;
13601358

1361-
/*
1362-
* We must zero subranges of unwritten mappings that might be dirty in
1363-
* pagecache from previous writes. We only know whether the entire range
1364-
* was clean or not, however, and dirty folios may have been written
1365-
* back or reclaimed at any point after mapping lookup.
1366-
*
1367-
* The easiest way to deal with this is to flush pagecache to trigger
1368-
* any pending unwritten conversions and then grab the updated extents
1369-
* from the fs. The flush may change the current mapping, so mark it
1370-
* stale for the iterator to remap it for the next pass to handle
1371-
* properly.
1372-
*
1373-
* Note that holes are treated the same as unwritten because zero range
1374-
* is (ab)used for partial folio zeroing in some cases. Hole backed
1375-
* post-eof ranges can be dirtied via mapped write and the flush
1376-
* triggers writeback time post-eof zeroing.
1377-
*/
1378-
if (srcmap->type == IOMAP_HOLE || srcmap->type == IOMAP_UNWRITTEN) {
1379-
if (*range_dirty) {
1380-
*range_dirty = false;
1381-
return iomap_zero_iter_flush_and_stale(iter);
1382-
}
1383-
/* range is clean and already zeroed, nothing to do */
1384-
return length;
1385-
}
1386-
13871359
do {
13881360
struct folio *folio;
13891361
int status;
@@ -1397,6 +1369,8 @@ static loff_t iomap_zero_iter(struct iomap_iter *iter, bool *did_zero,
13971369
if (iter->iomap.flags & IOMAP_F_STALE)
13981370
break;
13991371

1372+
/* warn about zeroing folios beyond eof that won't write back */
1373+
WARN_ON_ONCE(folio_pos(folio) > iter->inode->i_size);
14001374
offset = offset_in_folio(folio, pos);
14011375
if (bytes > folio_size(folio) - offset)
14021376
bytes = folio_size(folio) - offset;
@@ -1429,28 +1403,58 @@ iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero,
14291403
.len = len,
14301404
.flags = IOMAP_ZERO,
14311405
};
1406+
struct address_space *mapping = inode->i_mapping;
1407+
unsigned int blocksize = i_blocksize(inode);
1408+
unsigned int off = pos & (blocksize - 1);
1409+
loff_t plen = min_t(loff_t, len, blocksize - off);
14321410
int ret;
14331411
bool range_dirty;
14341412

14351413
/*
1436-
* Zero range wants to skip pre-zeroed (i.e. unwritten) mappings, but
1437-
* pagecache must be flushed to ensure stale data from previous
1438-
* buffered writes is not exposed. A flush is only required for certain
1439-
* types of mappings, but checking pagecache after mapping lookup is
1440-
* racy with writeback and reclaim.
1414+
* Zero range can skip mappings that are zero on disk so long as
1415+
* pagecache is clean. If pagecache was dirty prior to zero range, the
1416+
* mapping converts on writeback completion and so must be zeroed.
14411417
*
1442-
* Therefore, check the entire range first and pass along whether any
1443-
* part of it is dirty. If so and an underlying mapping warrants it,
1444-
* flush the cache at that point. This trades off the occasional false
1445-
* positive (and spurious flush, if the dirty data and mapping don't
1446-
* happen to overlap) for simplicity in handling a relatively uncommon
1447-
* situation.
1418+
* The simplest way to deal with this across a range is to flush
1419+
* pagecache and process the updated mappings. To avoid excessive
1420+
* flushing on partial eof zeroing, special case it to zero the
1421+
* unaligned start portion if already dirty in pagecache.
1422+
*/
1423+
if (off &&
1424+
filemap_range_needs_writeback(mapping, pos, pos + plen - 1)) {
1425+
iter.len = plen;
1426+
while ((ret = iomap_iter(&iter, ops)) > 0)
1427+
iter.processed = iomap_zero_iter(&iter, did_zero);
1428+
1429+
iter.len = len - (iter.pos - pos);
1430+
if (ret || !iter.len)
1431+
return ret;
1432+
}
1433+
1434+
/*
1435+
* To avoid an unconditional flush, check pagecache state and only flush
1436+
* if dirty and the fs returns a mapping that might convert on
1437+
* writeback.
14481438
*/
14491439
range_dirty = filemap_range_needs_writeback(inode->i_mapping,
1450-
pos, pos + len - 1);
1440+
iter.pos, iter.pos + iter.len - 1);
1441+
while ((ret = iomap_iter(&iter, ops)) > 0) {
1442+
const struct iomap *srcmap = iomap_iter_srcmap(&iter);
14511443

1452-
while ((ret = iomap_iter(&iter, ops)) > 0)
1453-
iter.processed = iomap_zero_iter(&iter, did_zero, &range_dirty);
1444+
if (srcmap->type == IOMAP_HOLE ||
1445+
srcmap->type == IOMAP_UNWRITTEN) {
1446+
loff_t proc = iomap_length(&iter);
1447+
1448+
if (range_dirty) {
1449+
range_dirty = false;
1450+
proc = iomap_zero_iter_flush_and_stale(&iter);
1451+
}
1452+
iter.processed = proc;
1453+
continue;
1454+
}
1455+
1456+
iter.processed = iomap_zero_iter(&iter, did_zero);
1457+
}
14541458
return ret;
14551459
}
14561460
EXPORT_SYMBOL_GPL(iomap_zero_range);

fs/iomap/iter.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,25 @@
2222
static inline int iomap_iter_advance(struct iomap_iter *iter)
2323
{
2424
bool stale = iter->iomap.flags & IOMAP_F_STALE;
25+
int ret = 1;
2526

2627
/* handle the previous iteration (if any) */
2728
if (iter->iomap.length) {
2829
if (iter->processed < 0)
2930
return iter->processed;
30-
if (!iter->processed && !stale)
31-
return 0;
3231
if (WARN_ON_ONCE(iter->processed > iomap_length(iter)))
3332
return -EIO;
3433
iter->pos += iter->processed;
3534
iter->len -= iter->processed;
36-
if (!iter->len)
37-
return 0;
35+
if (!iter->len || (!iter->processed && !stale))
36+
ret = 0;
3837
}
3938

40-
/* clear the state for the next iteration */
39+
/* clear the per iteration state */
4140
iter->processed = 0;
4241
memset(&iter->iomap, 0, sizeof(iter->iomap));
4342
memset(&iter->srcmap, 0, sizeof(iter->srcmap));
44-
return 1;
43+
return ret;
4544
}
4645

4746
static inline void iomap_iter_done(struct iomap_iter *iter)

fs/namespace.c

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5057,21 +5057,32 @@ static int statmount_mnt_opts(struct kstatmount *s, struct seq_file *seq)
50575057
return 0;
50585058
}
50595059

5060-
static inline int statmount_opt_unescape(struct seq_file *seq, char *buf_start)
5060+
static inline int statmount_opt_process(struct seq_file *seq, size_t start)
50615061
{
5062-
char *buf_end, *opt_start, *opt_end;
5062+
char *buf_end, *opt_end, *src, *dst;
50635063
int count = 0;
50645064

5065+
if (unlikely(seq_has_overflowed(seq)))
5066+
return -EAGAIN;
5067+
50655068
buf_end = seq->buf + seq->count;
5069+
dst = seq->buf + start;
5070+
src = dst + 1; /* skip initial comma */
5071+
5072+
if (src >= buf_end) {
5073+
seq->count = start;
5074+
return 0;
5075+
}
5076+
50665077
*buf_end = '\0';
5067-
for (opt_start = buf_start + 1; opt_start < buf_end; opt_start = opt_end + 1) {
5068-
opt_end = strchrnul(opt_start, ',');
5078+
for (; src < buf_end; src = opt_end + 1) {
5079+
opt_end = strchrnul(src, ',');
50695080
*opt_end = '\0';
5070-
buf_start += string_unescape(opt_start, buf_start, 0, UNESCAPE_OCTAL) + 1;
5081+
dst += string_unescape(src, dst, 0, UNESCAPE_OCTAL) + 1;
50715082
if (WARN_ON_ONCE(++count == INT_MAX))
50725083
return -EOVERFLOW;
50735084
}
5074-
seq->count = buf_start - 1 - seq->buf;
5085+
seq->count = dst - 1 - seq->buf;
50755086
return count;
50765087
}
50775088

@@ -5080,24 +5091,16 @@ static int statmount_opt_array(struct kstatmount *s, struct seq_file *seq)
50805091
struct vfsmount *mnt = s->mnt;
50815092
struct super_block *sb = mnt->mnt_sb;
50825093
size_t start = seq->count;
5083-
char *buf_start;
50845094
int err;
50855095

50865096
if (!sb->s_op->show_options)
50875097
return 0;
50885098

5089-
buf_start = seq->buf + start;
50905099
err = sb->s_op->show_options(seq, mnt->mnt_root);
50915100
if (err)
50925101
return err;
50935102

5094-
if (unlikely(seq_has_overflowed(seq)))
5095-
return -EAGAIN;
5096-
5097-
if (seq->count == start)
5098-
return 0;
5099-
5100-
err = statmount_opt_unescape(seq, buf_start);
5103+
err = statmount_opt_process(seq, start);
51015104
if (err < 0)
51025105
return err;
51035106

@@ -5110,22 +5113,13 @@ static int statmount_opt_sec_array(struct kstatmount *s, struct seq_file *seq)
51105113
struct vfsmount *mnt = s->mnt;
51115114
struct super_block *sb = mnt->mnt_sb;
51125115
size_t start = seq->count;
5113-
char *buf_start;
51145116
int err;
51155117

5116-
buf_start = seq->buf + start;
5117-
51185118
err = security_sb_show_options(seq, sb);
5119-
if (!err)
5119+
if (err)
51205120
return err;
51215121

5122-
if (unlikely(seq_has_overflowed(seq)))
5123-
return -EAGAIN;
5124-
5125-
if (seq->count == start)
5126-
return 0;
5127-
5128-
err = statmount_opt_unescape(seq, buf_start);
5122+
err = statmount_opt_process(seq, start);
51295123
if (err < 0)
51305124
return err;
51315125

fs/netfs/fscache_io.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#include <linux/uio.h>
1010
#include <linux/bvec.h>
1111
#include <linux/slab.h>
12-
#include <linux/uio.h>
1312
#include "internal.h"
1413

1514
/**

fs/proc/kcore.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,7 @@ static ssize_t read_kcore_iter(struct kiocb *iocb, struct iov_iter *iter)
600600
ret = -EFAULT;
601601
goto out;
602602
}
603+
ret = 0;
603604
/*
604605
* We know the bounce buffer is safe to copy from, so
605606
* use _copy_to_iter() directly.

tools/testing/selftests/mount_setattr/mount_setattr_test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1026,7 +1026,7 @@ FIXTURE_SETUP(mount_setattr_idmapped)
10261026
"size=100000,mode=700"), 0);
10271027

10281028
ASSERT_EQ(mount("testing", "/mnt", "tmpfs", MS_NOATIME | MS_NODEV,
1029-
"size=100000,mode=700"), 0);
1029+
"size=2m,mode=700"), 0);
10301030

10311031
ASSERT_EQ(mkdir("/mnt/A", 0777), 0);
10321032

0 commit comments

Comments
 (0)