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::
|
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
|
Starting the Cache
|
||||||
|
25
fs/afs/dir.c
25
fs/afs/dir.c
@ -12,6 +12,7 @@
|
|||||||
#include <linux/swap.h>
|
#include <linux/swap.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
#include <linux/iversion.h>
|
||||||
#include <linux/task_io_accounting_ops.h>
|
#include <linux/task_io_accounting_ops.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "afs_fs.h"
|
#include "afs_fs.h"
|
||||||
@ -1823,6 +1824,8 @@ error:
|
|||||||
|
|
||||||
static void afs_rename_success(struct afs_operation *op)
|
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);
|
_enter("op=%08x", op->debug_id);
|
||||||
|
|
||||||
op->ctime = op->file[0].scb.status.mtime_client;
|
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;
|
op->ctime = op->file[1].scb.status.mtime_client;
|
||||||
afs_vnode_commit_status(op, &op->file[1]);
|
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)
|
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);
|
&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);
|
new_inode = d_inode(new_dentry);
|
||||||
if (new_inode) {
|
if (new_inode) {
|
||||||
spin_lock(&new_inode->i_lock);
|
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.
|
* 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)
|
unsigned int blocknum)
|
||||||
{
|
{
|
||||||
union afs_xdr_dirent *de;
|
const union afs_xdr_dirent *de;
|
||||||
u64 bitmap;
|
u64 bitmap;
|
||||||
int d, len, n;
|
int d, len, n;
|
||||||
|
|
||||||
@ -492,3 +492,90 @@ error:
|
|||||||
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
|
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
|
||||||
goto out_unmap;
|
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 *,
|
extern void afs_edit_dir_add(struct afs_vnode *, struct qstr *, struct afs_fid *,
|
||||||
enum afs_edit_dir_reason);
|
enum afs_edit_dir_reason);
|
||||||
extern void afs_edit_dir_remove(struct afs_vnode *, struct qstr *, 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
|
* 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)
|
static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
|
||||||
{
|
{
|
||||||
|
unsigned int inr = _IOC_NR(cmd);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = check_dev_ioctl_version(cmd, param);
|
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.
|
* check_name() return for AUTOFS_DEV_IOCTL_TIMEOUT_CMD.
|
||||||
*/
|
*/
|
||||||
err = check_name(param->path);
|
err = check_name(param->path);
|
||||||
if (cmd == AUTOFS_DEV_IOCTL_TIMEOUT_CMD)
|
if (inr == AUTOFS_DEV_IOCTL_TIMEOUT_CMD)
|
||||||
err = err ? 0 : -EINVAL;
|
err = err ? 0 : -EINVAL;
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_warn("invalid path supplied for cmd(0x%08x)\n",
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned int inr = _IOC_NR(cmd);
|
|
||||||
|
|
||||||
if (inr == AUTOFS_DEV_IOCTL_OPENMOUNT_CMD ||
|
if (inr == AUTOFS_DEV_IOCTL_OPENMOUNT_CMD ||
|
||||||
inr == AUTOFS_DEV_IOCTL_REQUESTER_CMD ||
|
inr == AUTOFS_DEV_IOCTL_REQUESTER_CMD ||
|
||||||
inr == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_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)
|
if (IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND) && sbi->fsid)
|
||||||
return get_tree_nodev(fc, erofs_fc_fill_super);
|
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
|
#ifdef CONFIG_EROFS_FS_BACKED_BY_FILE
|
||||||
if (ret == -ENOTBLK) {
|
if (ret == -ENOTBLK) {
|
||||||
if (!fc->source)
|
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);
|
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
|
* @fc: The filesystem context holding the parameters
|
||||||
* @fill_super: Helper to initialise a new superblock
|
* @fill_super: Helper to initialise a new superblock
|
||||||
|
* @flags: GET_TREE_BDEV_* flags
|
||||||
*/
|
*/
|
||||||
int get_tree_bdev(struct fs_context *fc,
|
int get_tree_bdev_flags(struct fs_context *fc,
|
||||||
int (*fill_super)(struct super_block *,
|
int (*fill_super)(struct super_block *sb,
|
||||||
struct fs_context *))
|
struct fs_context *fc), unsigned int flags)
|
||||||
{
|
{
|
||||||
struct super_block *s;
|
struct super_block *s;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
@ -1613,10 +1614,10 @@ int get_tree_bdev(struct fs_context *fc,
|
|||||||
|
|
||||||
error = lookup_bdev(fc->source, &dev);
|
error = lookup_bdev(fc->source, &dev);
|
||||||
if (error) {
|
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;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
fc->sb_flags |= SB_NOSEC;
|
fc->sb_flags |= SB_NOSEC;
|
||||||
s = sget_dev(fc, dev);
|
s = sget_dev(fc, dev);
|
||||||
if (IS_ERR(s))
|
if (IS_ERR(s))
|
||||||
@ -1644,6 +1645,19 @@ int get_tree_bdev(struct fs_context *fc,
|
|||||||
fc->root = dget(s->s_root);
|
fc->root = dget(s->s_root);
|
||||||
return 0;
|
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);
|
EXPORT_SYMBOL(get_tree_bdev);
|
||||||
|
|
||||||
static int test_bdev_super(struct super_block *s, void *data)
|
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,
|
int setup_bdev_super(struct super_block *sb, int sb_flags,
|
||||||
struct fs_context *fc);
|
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,
|
extern int get_tree_bdev(struct fs_context *fc,
|
||||||
int (*fill_super)(struct super_block *sb,
|
int (*fill_super)(struct super_block *sb,
|
||||||
struct fs_context *fc));
|
struct fs_context *fc));
|
||||||
|
@ -331,7 +331,11 @@ enum yfs_cm_operation {
|
|||||||
EM(afs_edit_dir_delete, "delete") \
|
EM(afs_edit_dir_delete, "delete") \
|
||||||
EM(afs_edit_dir_delete_error, "d_err ") \
|
EM(afs_edit_dir_delete_error, "d_err ") \
|
||||||
EM(afs_edit_dir_delete_inval, "d_invl") \
|
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 \
|
#define afs_edit_dir_reasons \
|
||||||
EM(afs_edit_dir_for_create, "Create") \
|
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_0, "Renam0") \
|
||||||
EM(afs_edit_dir_for_rename_1, "Renam1") \
|
EM(afs_edit_dir_for_rename_1, "Renam1") \
|
||||||
EM(afs_edit_dir_for_rename_2, "Renam2") \
|
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_rmdir, "RmDir ") \
|
||||||
EM(afs_edit_dir_for_silly_0, "S_Ren0") \
|
EM(afs_edit_dir_for_silly_0, "S_Ren0") \
|
||||||
EM(afs_edit_dir_for_silly_1, "S_Ren1") \
|
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 bytes, struct iov_iter *i)
|
||||||
{
|
{
|
||||||
size_t n, copied = 0;
|
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))
|
if (!page_copy_sane(page, offset, bytes))
|
||||||
return 0;
|
return 0;
|
||||||
@ -471,7 +473,7 @@ size_t copy_page_from_iter_atomic(struct page *page, size_t offset,
|
|||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
n = bytes - copied;
|
n = bytes - copied;
|
||||||
if (PageHighMem(page)) {
|
if (uses_kmap) {
|
||||||
page += offset / PAGE_SIZE;
|
page += offset / PAGE_SIZE;
|
||||||
offset %= PAGE_SIZE;
|
offset %= PAGE_SIZE;
|
||||||
n = min_t(size_t, n, PAGE_SIZE - offset);
|
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);
|
kunmap_atomic(p);
|
||||||
copied += n;
|
copied += n;
|
||||||
offset += n;
|
offset += n;
|
||||||
} while (PageHighMem(page) && copied != bytes && n > 0);
|
} while (uses_kmap && copied != bytes && n > 0);
|
||||||
|
|
||||||
return copied;
|
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 offset = iov_offset, fsize = folioq_folio_size(folioq, slot);
|
||||||
size_t part = PAGE_SIZE - offset % PAGE_SIZE;
|
size_t part = PAGE_SIZE - offset % PAGE_SIZE;
|
||||||
|
|
||||||
part = umin(part, umin(maxsize - extracted, fsize - offset));
|
if (offset < fsize) {
|
||||||
count -= part;
|
part = umin(part, umin(maxsize - extracted, fsize - offset));
|
||||||
iov_offset += part;
|
count -= part;
|
||||||
extracted += 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)
|
if (maxpages == 0 || extracted >= maxsize)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user