mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 00:35:01 +00:00
vfs-6.12-rc6.fixes
-----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCZyTGAQAKCRCRxhvAZXjc opd6AQCal4omyfS8FYe4VRRZ/0XHouagq99I0U0TAmKkvoKAsgD/XrdE+pSTEkPX Pv4T9phh1cZRxcyKVu77UoYkuHJEDAg= =Lu9R -----END PGP SIGNATURE----- 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()
This commit is contained in:
commit
d56239a82e
@ -115,7 +115,7 @@ set up cache ready for use. The following script commands are available:
|
||||
|
||||
This mask can also be set through sysfs, eg::
|
||||
|
||||
echo 5 >/sys/modules/cachefiles/parameters/debug
|
||||
echo 5 > /sys/module/cachefiles/parameters/debug
|
||||
|
||||
|
||||
Starting the Cache
|
||||
|
25
fs/afs/dir.c
25
fs/afs/dir.c
@ -12,6 +12,7 @@
|
||||
#include <linux/swap.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/task_io_accounting_ops.h>
|
||||
#include "internal.h"
|
||||
#include "afs_fs.h"
|
||||
@ -1823,6 +1824,8 @@ static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
||||
|
||||
static void afs_rename_success(struct afs_operation *op)
|
||||
{
|
||||
struct afs_vnode *vnode = AFS_FS_I(d_inode(op->dentry));
|
||||
|
||||
_enter("op=%08x", op->debug_id);
|
||||
|
||||
op->ctime = op->file[0].scb.status.mtime_client;
|
||||
@ -1832,6 +1835,22 @@ static void afs_rename_success(struct afs_operation *op)
|
||||
op->ctime = op->file[1].scb.status.mtime_client;
|
||||
afs_vnode_commit_status(op, &op->file[1]);
|
||||
}
|
||||
|
||||
/* If we're moving a subdir between dirs, we need to update
|
||||
* its DV counter too as the ".." will be altered.
|
||||
*/
|
||||
if (S_ISDIR(vnode->netfs.inode.i_mode) &&
|
||||
op->file[0].vnode != op->file[1].vnode) {
|
||||
u64 new_dv;
|
||||
|
||||
write_seqlock(&vnode->cb_lock);
|
||||
|
||||
new_dv = vnode->status.data_version + 1;
|
||||
vnode->status.data_version = new_dv;
|
||||
inode_set_iversion_raw(&vnode->netfs.inode, new_dv);
|
||||
|
||||
write_sequnlock(&vnode->cb_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void afs_rename_edit_dir(struct afs_operation *op)
|
||||
@ -1873,6 +1892,12 @@ static void afs_rename_edit_dir(struct afs_operation *op)
|
||||
&vnode->fid, afs_edit_dir_for_rename_2);
|
||||
}
|
||||
|
||||
if (S_ISDIR(vnode->netfs.inode.i_mode) &&
|
||||
new_dvnode != orig_dvnode &&
|
||||
test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
|
||||
afs_edit_dir_update_dotdot(vnode, new_dvnode,
|
||||
afs_edit_dir_for_rename_sub);
|
||||
|
||||
new_inode = d_inode(new_dentry);
|
||||
if (new_inode) {
|
||||
spin_lock(&new_inode->i_lock);
|
||||
|
@ -127,10 +127,10 @@ static struct folio *afs_dir_get_folio(struct afs_vnode *vnode, pgoff_t index)
|
||||
/*
|
||||
* Scan a directory block looking for a dirent of the right name.
|
||||
*/
|
||||
static int afs_dir_scan_block(union afs_xdr_dir_block *block, struct qstr *name,
|
||||
static int afs_dir_scan_block(const union afs_xdr_dir_block *block, const struct qstr *name,
|
||||
unsigned int blocknum)
|
||||
{
|
||||
union afs_xdr_dirent *de;
|
||||
const union afs_xdr_dirent *de;
|
||||
u64 bitmap;
|
||||
int d, len, n;
|
||||
|
||||
@ -492,3 +492,90 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
|
||||
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
|
||||
goto out_unmap;
|
||||
}
|
||||
|
||||
/*
|
||||
* Edit a subdirectory that has been moved between directories to update the
|
||||
* ".." entry.
|
||||
*/
|
||||
void afs_edit_dir_update_dotdot(struct afs_vnode *vnode, struct afs_vnode *new_dvnode,
|
||||
enum afs_edit_dir_reason why)
|
||||
{
|
||||
union afs_xdr_dir_block *block;
|
||||
union afs_xdr_dirent *de;
|
||||
struct folio *folio;
|
||||
unsigned int nr_blocks, b;
|
||||
pgoff_t index;
|
||||
loff_t i_size;
|
||||
int slot;
|
||||
|
||||
_enter("");
|
||||
|
||||
i_size = i_size_read(&vnode->netfs.inode);
|
||||
if (i_size < AFS_DIR_BLOCK_SIZE) {
|
||||
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
|
||||
return;
|
||||
}
|
||||
nr_blocks = i_size / AFS_DIR_BLOCK_SIZE;
|
||||
|
||||
/* Find a block that has sufficient slots available. Each folio
|
||||
* contains two or more directory blocks.
|
||||
*/
|
||||
for (b = 0; b < nr_blocks; b++) {
|
||||
index = b / AFS_DIR_BLOCKS_PER_PAGE;
|
||||
folio = afs_dir_get_folio(vnode, index);
|
||||
if (!folio)
|
||||
goto error;
|
||||
|
||||
block = kmap_local_folio(folio, b * AFS_DIR_BLOCK_SIZE - folio_pos(folio));
|
||||
|
||||
/* Abandon the edit if we got a callback break. */
|
||||
if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
|
||||
goto invalidated;
|
||||
|
||||
slot = afs_dir_scan_block(block, &dotdot_name, b);
|
||||
if (slot >= 0)
|
||||
goto found_dirent;
|
||||
|
||||
kunmap_local(block);
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
}
|
||||
|
||||
/* Didn't find the dirent to clobber. Download the directory again. */
|
||||
trace_afs_edit_dir(vnode, why, afs_edit_dir_update_nodd,
|
||||
0, 0, 0, 0, "..");
|
||||
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
|
||||
goto out;
|
||||
|
||||
found_dirent:
|
||||
de = &block->dirents[slot];
|
||||
de->u.vnode = htonl(new_dvnode->fid.vnode);
|
||||
de->u.unique = htonl(new_dvnode->fid.unique);
|
||||
|
||||
trace_afs_edit_dir(vnode, why, afs_edit_dir_update_dd, b, slot,
|
||||
ntohl(de->u.vnode), ntohl(de->u.unique), "..");
|
||||
|
||||
kunmap_local(block);
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
inode_set_iversion_raw(&vnode->netfs.inode, vnode->status.data_version);
|
||||
|
||||
out:
|
||||
_leave("");
|
||||
return;
|
||||
|
||||
invalidated:
|
||||
kunmap_local(block);
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
trace_afs_edit_dir(vnode, why, afs_edit_dir_update_inval,
|
||||
0, 0, 0, 0, "..");
|
||||
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
|
||||
goto out;
|
||||
|
||||
error:
|
||||
trace_afs_edit_dir(vnode, why, afs_edit_dir_update_error,
|
||||
0, 0, 0, 0, "..");
|
||||
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
|
||||
goto out;
|
||||
}
|
||||
|
@ -1073,6 +1073,8 @@ extern void afs_check_for_remote_deletion(struct afs_operation *);
|
||||
extern void afs_edit_dir_add(struct afs_vnode *, struct qstr *, struct afs_fid *,
|
||||
enum afs_edit_dir_reason);
|
||||
extern void afs_edit_dir_remove(struct afs_vnode *, struct qstr *, enum afs_edit_dir_reason);
|
||||
void afs_edit_dir_update_dotdot(struct afs_vnode *vnode, struct afs_vnode *new_dvnode,
|
||||
enum afs_edit_dir_reason why);
|
||||
|
||||
/*
|
||||
* dir_silly.c
|
||||
|
@ -110,6 +110,7 @@ static inline void free_dev_ioctl(struct autofs_dev_ioctl *param)
|
||||
*/
|
||||
static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
|
||||
{
|
||||
unsigned int inr = _IOC_NR(cmd);
|
||||
int err;
|
||||
|
||||
err = check_dev_ioctl_version(cmd, param);
|
||||
@ -133,7 +134,7 @@ static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
|
||||
* check_name() return for AUTOFS_DEV_IOCTL_TIMEOUT_CMD.
|
||||
*/
|
||||
err = check_name(param->path);
|
||||
if (cmd == AUTOFS_DEV_IOCTL_TIMEOUT_CMD)
|
||||
if (inr == AUTOFS_DEV_IOCTL_TIMEOUT_CMD)
|
||||
err = err ? 0 : -EINVAL;
|
||||
if (err) {
|
||||
pr_warn("invalid path supplied for cmd(0x%08x)\n",
|
||||
@ -141,8 +142,6 @@ static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
unsigned int inr = _IOC_NR(cmd);
|
||||
|
||||
if (inr == AUTOFS_DEV_IOCTL_OPENMOUNT_CMD ||
|
||||
inr == AUTOFS_DEV_IOCTL_REQUESTER_CMD ||
|
||||
inr == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD) {
|
||||
|
@ -709,7 +709,9 @@ static int erofs_fc_get_tree(struct fs_context *fc)
|
||||
if (IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND) && sbi->fsid)
|
||||
return get_tree_nodev(fc, erofs_fc_fill_super);
|
||||
|
||||
ret = get_tree_bdev(fc, erofs_fc_fill_super);
|
||||
ret = get_tree_bdev_flags(fc, erofs_fc_fill_super,
|
||||
IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) ?
|
||||
GET_TREE_BDEV_QUIET_LOOKUP : 0);
|
||||
#ifdef CONFIG_EROFS_FS_BACKED_BY_FILE
|
||||
if (ret == -ENOTBLK) {
|
||||
if (!fc->source)
|
||||
|
26
fs/super.c
26
fs/super.c
@ -1596,13 +1596,14 @@ int setup_bdev_super(struct super_block *sb, int sb_flags,
|
||||
EXPORT_SYMBOL_GPL(setup_bdev_super);
|
||||
|
||||
/**
|
||||
* get_tree_bdev - Get a superblock based on a single block device
|
||||
* get_tree_bdev_flags - Get a superblock based on a single block device
|
||||
* @fc: The filesystem context holding the parameters
|
||||
* @fill_super: Helper to initialise a new superblock
|
||||
* @flags: GET_TREE_BDEV_* flags
|
||||
*/
|
||||
int get_tree_bdev(struct fs_context *fc,
|
||||
int (*fill_super)(struct super_block *,
|
||||
struct fs_context *))
|
||||
int get_tree_bdev_flags(struct fs_context *fc,
|
||||
int (*fill_super)(struct super_block *sb,
|
||||
struct fs_context *fc), unsigned int flags)
|
||||
{
|
||||
struct super_block *s;
|
||||
int error = 0;
|
||||
@ -1613,10 +1614,10 @@ int get_tree_bdev(struct fs_context *fc,
|
||||
|
||||
error = lookup_bdev(fc->source, &dev);
|
||||
if (error) {
|
||||
errorf(fc, "%s: Can't lookup blockdev", fc->source);
|
||||
if (!(flags & GET_TREE_BDEV_QUIET_LOOKUP))
|
||||
errorf(fc, "%s: Can't lookup blockdev", fc->source);
|
||||
return error;
|
||||
}
|
||||
|
||||
fc->sb_flags |= SB_NOSEC;
|
||||
s = sget_dev(fc, dev);
|
||||
if (IS_ERR(s))
|
||||
@ -1644,6 +1645,19 @@ int get_tree_bdev(struct fs_context *fc,
|
||||
fc->root = dget(s->s_root);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(get_tree_bdev_flags);
|
||||
|
||||
/**
|
||||
* get_tree_bdev - Get a superblock based on a single block device
|
||||
* @fc: The filesystem context holding the parameters
|
||||
* @fill_super: Helper to initialise a new superblock
|
||||
*/
|
||||
int get_tree_bdev(struct fs_context *fc,
|
||||
int (*fill_super)(struct super_block *,
|
||||
struct fs_context *))
|
||||
{
|
||||
return get_tree_bdev_flags(fc, fill_super, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(get_tree_bdev);
|
||||
|
||||
static int test_bdev_super(struct super_block *s, void *data)
|
||||
|
@ -160,6 +160,12 @@ extern int get_tree_keyed(struct fs_context *fc,
|
||||
|
||||
int setup_bdev_super(struct super_block *sb, int sb_flags,
|
||||
struct fs_context *fc);
|
||||
|
||||
#define GET_TREE_BDEV_QUIET_LOOKUP 0x0001
|
||||
int get_tree_bdev_flags(struct fs_context *fc,
|
||||
int (*fill_super)(struct super_block *sb,
|
||||
struct fs_context *fc), unsigned int flags);
|
||||
|
||||
extern int get_tree_bdev(struct fs_context *fc,
|
||||
int (*fill_super)(struct super_block *sb,
|
||||
struct fs_context *fc));
|
||||
|
@ -331,7 +331,11 @@ enum yfs_cm_operation {
|
||||
EM(afs_edit_dir_delete, "delete") \
|
||||
EM(afs_edit_dir_delete_error, "d_err ") \
|
||||
EM(afs_edit_dir_delete_inval, "d_invl") \
|
||||
E_(afs_edit_dir_delete_noent, "d_nent")
|
||||
EM(afs_edit_dir_delete_noent, "d_nent") \
|
||||
EM(afs_edit_dir_update_dd, "u_ddot") \
|
||||
EM(afs_edit_dir_update_error, "u_fail") \
|
||||
EM(afs_edit_dir_update_inval, "u_invl") \
|
||||
E_(afs_edit_dir_update_nodd, "u_nodd")
|
||||
|
||||
#define afs_edit_dir_reasons \
|
||||
EM(afs_edit_dir_for_create, "Create") \
|
||||
@ -340,6 +344,7 @@ enum yfs_cm_operation {
|
||||
EM(afs_edit_dir_for_rename_0, "Renam0") \
|
||||
EM(afs_edit_dir_for_rename_1, "Renam1") \
|
||||
EM(afs_edit_dir_for_rename_2, "Renam2") \
|
||||
EM(afs_edit_dir_for_rename_sub, "RnmSub") \
|
||||
EM(afs_edit_dir_for_rmdir, "RmDir ") \
|
||||
EM(afs_edit_dir_for_silly_0, "S_Ren0") \
|
||||
EM(afs_edit_dir_for_silly_1, "S_Ren1") \
|
||||
|
@ -461,6 +461,8 @@ size_t copy_page_from_iter_atomic(struct page *page, size_t offset,
|
||||
size_t bytes, struct iov_iter *i)
|
||||
{
|
||||
size_t n, copied = 0;
|
||||
bool uses_kmap = IS_ENABLED(CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP) ||
|
||||
PageHighMem(page);
|
||||
|
||||
if (!page_copy_sane(page, offset, bytes))
|
||||
return 0;
|
||||
@ -471,7 +473,7 @@ size_t copy_page_from_iter_atomic(struct page *page, size_t offset,
|
||||
char *p;
|
||||
|
||||
n = bytes - copied;
|
||||
if (PageHighMem(page)) {
|
||||
if (uses_kmap) {
|
||||
page += offset / PAGE_SIZE;
|
||||
offset %= PAGE_SIZE;
|
||||
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,
|
||||
kunmap_atomic(p);
|
||||
copied += n;
|
||||
offset += n;
|
||||
} while (PageHighMem(page) && copied != bytes && n > 0);
|
||||
} while (uses_kmap && copied != bytes && n > 0);
|
||||
|
||||
return copied;
|
||||
}
|
||||
@ -1021,15 +1023,18 @@ static ssize_t iter_folioq_get_pages(struct iov_iter *iter,
|
||||
size_t offset = iov_offset, fsize = folioq_folio_size(folioq, slot);
|
||||
size_t part = PAGE_SIZE - offset % PAGE_SIZE;
|
||||
|
||||
part = umin(part, umin(maxsize - extracted, fsize - offset));
|
||||
count -= part;
|
||||
iov_offset += part;
|
||||
extracted += part;
|
||||
if (offset < fsize) {
|
||||
part = umin(part, umin(maxsize - extracted, fsize - offset));
|
||||
count -= part;
|
||||
iov_offset += part;
|
||||
extracted += part;
|
||||
|
||||
*pages = folio_page(folio, offset / PAGE_SIZE);
|
||||
get_page(*pages);
|
||||
pages++;
|
||||
maxpages--;
|
||||
}
|
||||
|
||||
*pages = folio_page(folio, offset / PAGE_SIZE);
|
||||
get_page(*pages);
|
||||
pages++;
|
||||
maxpages--;
|
||||
if (maxpages == 0 || extracted >= maxsize)
|
||||
break;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user