Skip to content

Commit d56239a

Browse files
committed
Merge tag 'vfs-6.12-rc6.fixes' of gitolite.kernel.org:pub/scm/linux/kernel/git/vfs/vfs
Pull filesystem fixes from Christian Brauner: "VFS: - Fix copy_page_from_iter_atomic() if KMAP_LOCAL_FORCE_MAP=y is set - Add a get_tree_bdev_flags() helper that allows to modify e.g., whether errors are logged into the filesystem context during superblock creation. This is used by erofs to fix a userspace regression where an error is currently logged when its used on a regular file which is an new allowed mode in erofs. netfs: - Fix the sysfs debug path in the documentation. - Fix iov_iter_get_pages*() for folio queues by skipping the page extracation if we're at the end of a folio. afs: - Fix moving subdirectories to different parent directory. autofs: - Fix handling of AUTOFS_DEV_IOCTL_TIMEOUT_CMD ioctl in validate_dev_ioctl(). The actual ioctl number, not the ioctl command needs to be checked for autofs" * tag 'vfs-6.12-rc6.fixes' of gitolite.kernel.org:pub/scm/linux/kernel/git/vfs/vfs: iov_iter: fix copy_page_from_iter_atomic() if KMAP_LOCAL_FORCE_MAP autofs: fix thinko in validate_dev_ioctl() iov_iter: Fix iov_iter_get_pages*() for folio_queue afs: Fix missing subdir edit when renamed between parent dirs doc: correcting the debug path for cachefiles erofs: use get_tree_bdev_flags() to avoid misleading messages fs/super.c: introduce get_tree_bdev_flags()
2 parents 6b49264 + c749d9b commit d56239a

File tree

10 files changed

+169
-24
lines changed

10 files changed

+169
-24
lines changed

Documentation/filesystems/caching/cachefiles.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ set up cache ready for use. The following script commands are available:
115115

116116
This mask can also be set through sysfs, eg::
117117

118-
echo 5 >/sys/modules/cachefiles/parameters/debug
118+
echo 5 > /sys/module/cachefiles/parameters/debug
119119

120120

121121
Starting the Cache

fs/afs/dir.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/swap.h>
1313
#include <linux/ctype.h>
1414
#include <linux/sched.h>
15+
#include <linux/iversion.h>
1516
#include <linux/task_io_accounting_ops.h>
1617
#include "internal.h"
1718
#include "afs_fs.h"
@@ -1823,6 +1824,8 @@ static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir,
18231824

18241825
static void afs_rename_success(struct afs_operation *op)
18251826
{
1827+
struct afs_vnode *vnode = AFS_FS_I(d_inode(op->dentry));
1828+
18261829
_enter("op=%08x", op->debug_id);
18271830

18281831
op->ctime = op->file[0].scb.status.mtime_client;
@@ -1832,6 +1835,22 @@ static void afs_rename_success(struct afs_operation *op)
18321835
op->ctime = op->file[1].scb.status.mtime_client;
18331836
afs_vnode_commit_status(op, &op->file[1]);
18341837
}
1838+
1839+
/* If we're moving a subdir between dirs, we need to update
1840+
* its DV counter too as the ".." will be altered.
1841+
*/
1842+
if (S_ISDIR(vnode->netfs.inode.i_mode) &&
1843+
op->file[0].vnode != op->file[1].vnode) {
1844+
u64 new_dv;
1845+
1846+
write_seqlock(&vnode->cb_lock);
1847+
1848+
new_dv = vnode->status.data_version + 1;
1849+
vnode->status.data_version = new_dv;
1850+
inode_set_iversion_raw(&vnode->netfs.inode, new_dv);
1851+
1852+
write_sequnlock(&vnode->cb_lock);
1853+
}
18351854
}
18361855

18371856
static void afs_rename_edit_dir(struct afs_operation *op)
@@ -1873,6 +1892,12 @@ static void afs_rename_edit_dir(struct afs_operation *op)
18731892
&vnode->fid, afs_edit_dir_for_rename_2);
18741893
}
18751894

1895+
if (S_ISDIR(vnode->netfs.inode.i_mode) &&
1896+
new_dvnode != orig_dvnode &&
1897+
test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
1898+
afs_edit_dir_update_dotdot(vnode, new_dvnode,
1899+
afs_edit_dir_for_rename_sub);
1900+
18761901
new_inode = d_inode(new_dentry);
18771902
if (new_inode) {
18781903
spin_lock(&new_inode->i_lock);

fs/afs/dir_edit.c

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,10 @@ static struct folio *afs_dir_get_folio(struct afs_vnode *vnode, pgoff_t index)
127127
/*
128128
* Scan a directory block looking for a dirent of the right name.
129129
*/
130-
static int afs_dir_scan_block(union afs_xdr_dir_block *block, struct qstr *name,
130+
static int afs_dir_scan_block(const union afs_xdr_dir_block *block, const struct qstr *name,
131131
unsigned int blocknum)
132132
{
133-
union afs_xdr_dirent *de;
133+
const union afs_xdr_dirent *de;
134134
u64 bitmap;
135135
int d, len, n;
136136

@@ -492,3 +492,90 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
492492
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
493493
goto out_unmap;
494494
}
495+
496+
/*
497+
* Edit a subdirectory that has been moved between directories to update the
498+
* ".." entry.
499+
*/
500+
void afs_edit_dir_update_dotdot(struct afs_vnode *vnode, struct afs_vnode *new_dvnode,
501+
enum afs_edit_dir_reason why)
502+
{
503+
union afs_xdr_dir_block *block;
504+
union afs_xdr_dirent *de;
505+
struct folio *folio;
506+
unsigned int nr_blocks, b;
507+
pgoff_t index;
508+
loff_t i_size;
509+
int slot;
510+
511+
_enter("");
512+
513+
i_size = i_size_read(&vnode->netfs.inode);
514+
if (i_size < AFS_DIR_BLOCK_SIZE) {
515+
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
516+
return;
517+
}
518+
nr_blocks = i_size / AFS_DIR_BLOCK_SIZE;
519+
520+
/* Find a block that has sufficient slots available. Each folio
521+
* contains two or more directory blocks.
522+
*/
523+
for (b = 0; b < nr_blocks; b++) {
524+
index = b / AFS_DIR_BLOCKS_PER_PAGE;
525+
folio = afs_dir_get_folio(vnode, index);
526+
if (!folio)
527+
goto error;
528+
529+
block = kmap_local_folio(folio, b * AFS_DIR_BLOCK_SIZE - folio_pos(folio));
530+
531+
/* Abandon the edit if we got a callback break. */
532+
if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
533+
goto invalidated;
534+
535+
slot = afs_dir_scan_block(block, &dotdot_name, b);
536+
if (slot >= 0)
537+
goto found_dirent;
538+
539+
kunmap_local(block);
540+
folio_unlock(folio);
541+
folio_put(folio);
542+
}
543+
544+
/* Didn't find the dirent to clobber. Download the directory again. */
545+
trace_afs_edit_dir(vnode, why, afs_edit_dir_update_nodd,
546+
0, 0, 0, 0, "..");
547+
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
548+
goto out;
549+
550+
found_dirent:
551+
de = &block->dirents[slot];
552+
de->u.vnode = htonl(new_dvnode->fid.vnode);
553+
de->u.unique = htonl(new_dvnode->fid.unique);
554+
555+
trace_afs_edit_dir(vnode, why, afs_edit_dir_update_dd, b, slot,
556+
ntohl(de->u.vnode), ntohl(de->u.unique), "..");
557+
558+
kunmap_local(block);
559+
folio_unlock(folio);
560+
folio_put(folio);
561+
inode_set_iversion_raw(&vnode->netfs.inode, vnode->status.data_version);
562+
563+
out:
564+
_leave("");
565+
return;
566+
567+
invalidated:
568+
kunmap_local(block);
569+
folio_unlock(folio);
570+
folio_put(folio);
571+
trace_afs_edit_dir(vnode, why, afs_edit_dir_update_inval,
572+
0, 0, 0, 0, "..");
573+
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
574+
goto out;
575+
576+
error:
577+
trace_afs_edit_dir(vnode, why, afs_edit_dir_update_error,
578+
0, 0, 0, 0, "..");
579+
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
580+
goto out;
581+
}

fs/afs/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,8 @@ extern void afs_check_for_remote_deletion(struct afs_operation *);
10731073
extern void afs_edit_dir_add(struct afs_vnode *, struct qstr *, struct afs_fid *,
10741074
enum afs_edit_dir_reason);
10751075
extern void afs_edit_dir_remove(struct afs_vnode *, struct qstr *, enum afs_edit_dir_reason);
1076+
void afs_edit_dir_update_dotdot(struct afs_vnode *vnode, struct afs_vnode *new_dvnode,
1077+
enum afs_edit_dir_reason why);
10761078

10771079
/*
10781080
* dir_silly.c

fs/autofs/dev-ioctl.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ static inline void free_dev_ioctl(struct autofs_dev_ioctl *param)
110110
*/
111111
static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
112112
{
113+
unsigned int inr = _IOC_NR(cmd);
113114
int err;
114115

115116
err = check_dev_ioctl_version(cmd, param);
@@ -133,16 +134,14 @@ static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
133134
* check_name() return for AUTOFS_DEV_IOCTL_TIMEOUT_CMD.
134135
*/
135136
err = check_name(param->path);
136-
if (cmd == AUTOFS_DEV_IOCTL_TIMEOUT_CMD)
137+
if (inr == AUTOFS_DEV_IOCTL_TIMEOUT_CMD)
137138
err = err ? 0 : -EINVAL;
138139
if (err) {
139140
pr_warn("invalid path supplied for cmd(0x%08x)\n",
140141
cmd);
141142
goto out;
142143
}
143144
} else {
144-
unsigned int inr = _IOC_NR(cmd);
145-
146145
if (inr == AUTOFS_DEV_IOCTL_OPENMOUNT_CMD ||
147146
inr == AUTOFS_DEV_IOCTL_REQUESTER_CMD ||
148147
inr == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD) {

fs/erofs/super.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,9 @@ static int erofs_fc_get_tree(struct fs_context *fc)
709709
if (IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND) && sbi->fsid)
710710
return get_tree_nodev(fc, erofs_fc_fill_super);
711711

712-
ret = get_tree_bdev(fc, erofs_fc_fill_super);
712+
ret = get_tree_bdev_flags(fc, erofs_fc_fill_super,
713+
IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) ?
714+
GET_TREE_BDEV_QUIET_LOOKUP : 0);
713715
#ifdef CONFIG_EROFS_FS_BACKED_BY_FILE
714716
if (ret == -ENOTBLK) {
715717
if (!fc->source)

fs/super.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,13 +1596,14 @@ int setup_bdev_super(struct super_block *sb, int sb_flags,
15961596
EXPORT_SYMBOL_GPL(setup_bdev_super);
15971597

15981598
/**
1599-
* get_tree_bdev - Get a superblock based on a single block device
1599+
* get_tree_bdev_flags - Get a superblock based on a single block device
16001600
* @fc: The filesystem context holding the parameters
16011601
* @fill_super: Helper to initialise a new superblock
1602+
* @flags: GET_TREE_BDEV_* flags
16021603
*/
1603-
int get_tree_bdev(struct fs_context *fc,
1604-
int (*fill_super)(struct super_block *,
1605-
struct fs_context *))
1604+
int get_tree_bdev_flags(struct fs_context *fc,
1605+
int (*fill_super)(struct super_block *sb,
1606+
struct fs_context *fc), unsigned int flags)
16061607
{
16071608
struct super_block *s;
16081609
int error = 0;
@@ -1613,10 +1614,10 @@ int get_tree_bdev(struct fs_context *fc,
16131614

16141615
error = lookup_bdev(fc->source, &dev);
16151616
if (error) {
1616-
errorf(fc, "%s: Can't lookup blockdev", fc->source);
1617+
if (!(flags & GET_TREE_BDEV_QUIET_LOOKUP))
1618+
errorf(fc, "%s: Can't lookup blockdev", fc->source);
16171619
return error;
16181620
}
1619-
16201621
fc->sb_flags |= SB_NOSEC;
16211622
s = sget_dev(fc, dev);
16221623
if (IS_ERR(s))
@@ -1644,6 +1645,19 @@ int get_tree_bdev(struct fs_context *fc,
16441645
fc->root = dget(s->s_root);
16451646
return 0;
16461647
}
1648+
EXPORT_SYMBOL_GPL(get_tree_bdev_flags);
1649+
1650+
/**
1651+
* get_tree_bdev - Get a superblock based on a single block device
1652+
* @fc: The filesystem context holding the parameters
1653+
* @fill_super: Helper to initialise a new superblock
1654+
*/
1655+
int get_tree_bdev(struct fs_context *fc,
1656+
int (*fill_super)(struct super_block *,
1657+
struct fs_context *))
1658+
{
1659+
return get_tree_bdev_flags(fc, fill_super, 0);
1660+
}
16471661
EXPORT_SYMBOL(get_tree_bdev);
16481662

16491663
static int test_bdev_super(struct super_block *s, void *data)

include/linux/fs_context.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,12 @@ extern int get_tree_keyed(struct fs_context *fc,
160160

161161
int setup_bdev_super(struct super_block *sb, int sb_flags,
162162
struct fs_context *fc);
163+
164+
#define GET_TREE_BDEV_QUIET_LOOKUP 0x0001
165+
int get_tree_bdev_flags(struct fs_context *fc,
166+
int (*fill_super)(struct super_block *sb,
167+
struct fs_context *fc), unsigned int flags);
168+
163169
extern int get_tree_bdev(struct fs_context *fc,
164170
int (*fill_super)(struct super_block *sb,
165171
struct fs_context *fc));

include/trace/events/afs.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,11 @@ enum yfs_cm_operation {
331331
EM(afs_edit_dir_delete, "delete") \
332332
EM(afs_edit_dir_delete_error, "d_err ") \
333333
EM(afs_edit_dir_delete_inval, "d_invl") \
334-
E_(afs_edit_dir_delete_noent, "d_nent")
334+
EM(afs_edit_dir_delete_noent, "d_nent") \
335+
EM(afs_edit_dir_update_dd, "u_ddot") \
336+
EM(afs_edit_dir_update_error, "u_fail") \
337+
EM(afs_edit_dir_update_inval, "u_invl") \
338+
E_(afs_edit_dir_update_nodd, "u_nodd")
335339

336340
#define afs_edit_dir_reasons \
337341
EM(afs_edit_dir_for_create, "Create") \
@@ -340,6 +344,7 @@ enum yfs_cm_operation {
340344
EM(afs_edit_dir_for_rename_0, "Renam0") \
341345
EM(afs_edit_dir_for_rename_1, "Renam1") \
342346
EM(afs_edit_dir_for_rename_2, "Renam2") \
347+
EM(afs_edit_dir_for_rename_sub, "RnmSub") \
343348
EM(afs_edit_dir_for_rmdir, "RmDir ") \
344349
EM(afs_edit_dir_for_silly_0, "S_Ren0") \
345350
EM(afs_edit_dir_for_silly_1, "S_Ren1") \

lib/iov_iter.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,8 @@ size_t copy_page_from_iter_atomic(struct page *page, size_t offset,
461461
size_t bytes, struct iov_iter *i)
462462
{
463463
size_t n, copied = 0;
464+
bool uses_kmap = IS_ENABLED(CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP) ||
465+
PageHighMem(page);
464466

465467
if (!page_copy_sane(page, offset, bytes))
466468
return 0;
@@ -471,7 +473,7 @@ size_t copy_page_from_iter_atomic(struct page *page, size_t offset,
471473
char *p;
472474

473475
n = bytes - copied;
474-
if (PageHighMem(page)) {
476+
if (uses_kmap) {
475477
page += offset / PAGE_SIZE;
476478
offset %= PAGE_SIZE;
477479
n = min_t(size_t, n, PAGE_SIZE - offset);
@@ -482,7 +484,7 @@ size_t copy_page_from_iter_atomic(struct page *page, size_t offset,
482484
kunmap_atomic(p);
483485
copied += n;
484486
offset += n;
485-
} while (PageHighMem(page) && copied != bytes && n > 0);
487+
} while (uses_kmap && copied != bytes && n > 0);
486488

487489
return copied;
488490
}
@@ -1021,15 +1023,18 @@ static ssize_t iter_folioq_get_pages(struct iov_iter *iter,
10211023
size_t offset = iov_offset, fsize = folioq_folio_size(folioq, slot);
10221024
size_t part = PAGE_SIZE - offset % PAGE_SIZE;
10231025

1024-
part = umin(part, umin(maxsize - extracted, fsize - offset));
1025-
count -= part;
1026-
iov_offset += part;
1027-
extracted += part;
1026+
if (offset < fsize) {
1027+
part = umin(part, umin(maxsize - extracted, fsize - offset));
1028+
count -= part;
1029+
iov_offset += part;
1030+
extracted += part;
1031+
1032+
*pages = folio_page(folio, offset / PAGE_SIZE);
1033+
get_page(*pages);
1034+
pages++;
1035+
maxpages--;
1036+
}
10281037

1029-
*pages = folio_page(folio, offset / PAGE_SIZE);
1030-
get_page(*pages);
1031-
pages++;
1032-
maxpages--;
10331038
if (maxpages == 0 || extracted >= maxsize)
10341039
break;
10351040

0 commit comments

Comments
 (0)