mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-28 16:52:18 +00:00
Merge branch 'mm-nonmm-stable' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
This commit is contained in:
commit
8f850ad6cf
@ -21092,6 +21092,7 @@ M: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
|
||||
S: Maintained
|
||||
F: Documentation/filesystems/vfat.rst
|
||||
F: fs/fat/
|
||||
F: tools/testing/selftests/filesystems/fat/
|
||||
|
||||
VFIO DRIVER
|
||||
M: Alex Williamson <alex.williamson@redhat.com>
|
||||
|
@ -33,24 +33,24 @@ extern void ia64_xchg_called_with_bad_pointer(void);
|
||||
\
|
||||
switch (size) { \
|
||||
case 1: \
|
||||
__xchg_result = ia64_xchg1((__u8 *)ptr, x); \
|
||||
__xchg_result = ia64_xchg1((__u8 __force *)ptr, x); \
|
||||
break; \
|
||||
\
|
||||
case 2: \
|
||||
__xchg_result = ia64_xchg2((__u16 *)ptr, x); \
|
||||
__xchg_result = ia64_xchg2((__u16 __force *)ptr, x); \
|
||||
break; \
|
||||
\
|
||||
case 4: \
|
||||
__xchg_result = ia64_xchg4((__u32 *)ptr, x); \
|
||||
__xchg_result = ia64_xchg4((__u32 __force *)ptr, x); \
|
||||
break; \
|
||||
\
|
||||
case 8: \
|
||||
__xchg_result = ia64_xchg8((__u64 *)ptr, x); \
|
||||
__xchg_result = ia64_xchg8((__u64 __force *)ptr, x); \
|
||||
break; \
|
||||
default: \
|
||||
ia64_xchg_called_with_bad_pointer(); \
|
||||
} \
|
||||
__xchg_result; \
|
||||
(__typeof__ (*(ptr)) __force) __xchg_result; \
|
||||
})
|
||||
|
||||
#ifndef __KERNEL__
|
||||
@ -76,42 +76,42 @@ extern long ia64_cmpxchg_called_with_bad_pointer(void);
|
||||
\
|
||||
switch (size) { \
|
||||
case 1: \
|
||||
_o_ = (__u8) (long) (old); \
|
||||
_o_ = (__u8) (long __force) (old); \
|
||||
break; \
|
||||
case 2: \
|
||||
_o_ = (__u16) (long) (old); \
|
||||
_o_ = (__u16) (long __force) (old); \
|
||||
break; \
|
||||
case 4: \
|
||||
_o_ = (__u32) (long) (old); \
|
||||
_o_ = (__u32) (long __force) (old); \
|
||||
break; \
|
||||
case 8: \
|
||||
_o_ = (__u64) (long) (old); \
|
||||
_o_ = (__u64) (long __force) (old); \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
switch (size) { \
|
||||
case 1: \
|
||||
_r_ = ia64_cmpxchg1_##sem((__u8 *) ptr, new, _o_); \
|
||||
_r_ = ia64_cmpxchg1_##sem((__u8 __force *) ptr, new, _o_); \
|
||||
break; \
|
||||
\
|
||||
case 2: \
|
||||
_r_ = ia64_cmpxchg2_##sem((__u16 *) ptr, new, _o_); \
|
||||
_r_ = ia64_cmpxchg2_##sem((__u16 __force *) ptr, new, _o_); \
|
||||
break; \
|
||||
\
|
||||
case 4: \
|
||||
_r_ = ia64_cmpxchg4_##sem((__u32 *) ptr, new, _o_); \
|
||||
_r_ = ia64_cmpxchg4_##sem((__u32 __force *) ptr, new, _o_); \
|
||||
break; \
|
||||
\
|
||||
case 8: \
|
||||
_r_ = ia64_cmpxchg8_##sem((__u64 *) ptr, new, _o_); \
|
||||
_r_ = ia64_cmpxchg8_##sem((__u64 __force *) ptr, new, _o_); \
|
||||
break; \
|
||||
\
|
||||
default: \
|
||||
_r_ = ia64_cmpxchg_called_with_bad_pointer(); \
|
||||
break; \
|
||||
} \
|
||||
(__typeof__(old)) _r_; \
|
||||
(__typeof__(old) __force) _r_; \
|
||||
})
|
||||
|
||||
#define cmpxchg_acq(ptr, o, n) \
|
||||
|
@ -889,22 +889,57 @@ static int vfat_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int vfat_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
struct dentry *old_dentry, struct inode *new_dir,
|
||||
struct dentry *new_dentry, unsigned int flags)
|
||||
static int vfat_get_dotdot_de(struct inode *inode, struct buffer_head **bh,
|
||||
struct msdos_dir_entry **de)
|
||||
{
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
if (fat_get_dotdot_entry(inode, bh, de))
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfat_sync_ipos(struct inode *dir, struct inode *inode)
|
||||
{
|
||||
if (IS_DIRSYNC(dir))
|
||||
return fat_sync_inode(inode);
|
||||
mark_inode_dirty(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfat_update_dotdot_de(struct inode *dir, struct inode *inode,
|
||||
struct buffer_head *dotdot_bh,
|
||||
struct msdos_dir_entry *dotdot_de)
|
||||
{
|
||||
fat_set_start(dotdot_de, MSDOS_I(dir)->i_logstart);
|
||||
mark_buffer_dirty_inode(dotdot_bh, inode);
|
||||
if (IS_DIRSYNC(dir))
|
||||
return sync_dirty_buffer(dotdot_bh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vfat_update_dir_metadata(struct inode *dir, struct timespec64 *ts)
|
||||
{
|
||||
inode_inc_iversion(dir);
|
||||
fat_truncate_time(dir, ts, S_CTIME | S_MTIME);
|
||||
if (IS_DIRSYNC(dir))
|
||||
(void)fat_sync_inode(dir);
|
||||
else
|
||||
mark_inode_dirty(dir);
|
||||
}
|
||||
|
||||
static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry)
|
||||
{
|
||||
struct buffer_head *dotdot_bh;
|
||||
struct msdos_dir_entry *dotdot_de;
|
||||
struct msdos_dir_entry *dotdot_de = NULL;
|
||||
struct inode *old_inode, *new_inode;
|
||||
struct fat_slot_info old_sinfo, sinfo;
|
||||
struct timespec64 ts;
|
||||
loff_t new_i_pos;
|
||||
int err, is_dir, update_dotdot, corrupt = 0;
|
||||
int err, is_dir, corrupt = 0;
|
||||
struct super_block *sb = old_dir->i_sb;
|
||||
|
||||
if (flags & ~RENAME_NOREPLACE)
|
||||
return -EINVAL;
|
||||
|
||||
old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
|
||||
old_inode = d_inode(old_dentry);
|
||||
new_inode = d_inode(new_dentry);
|
||||
@ -913,15 +948,13 @@ static int vfat_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
is_dir = S_ISDIR(old_inode->i_mode);
|
||||
update_dotdot = (is_dir && old_dir != new_dir);
|
||||
if (update_dotdot) {
|
||||
if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de)) {
|
||||
err = -EIO;
|
||||
if (old_dir != new_dir) {
|
||||
err = vfat_get_dotdot_de(old_inode, &dotdot_bh, &dotdot_de);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
is_dir = S_ISDIR(old_inode->i_mode);
|
||||
ts = current_time(old_dir);
|
||||
if (new_inode) {
|
||||
if (is_dir) {
|
||||
@ -942,21 +975,15 @@ static int vfat_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
|
||||
fat_detach(old_inode);
|
||||
fat_attach(old_inode, new_i_pos);
|
||||
if (IS_DIRSYNC(new_dir)) {
|
||||
err = fat_sync_inode(old_inode);
|
||||
if (err)
|
||||
goto error_inode;
|
||||
} else
|
||||
mark_inode_dirty(old_inode);
|
||||
err = vfat_sync_ipos(new_dir, old_inode);
|
||||
if (err)
|
||||
goto error_inode;
|
||||
|
||||
if (update_dotdot) {
|
||||
fat_set_start(dotdot_de, MSDOS_I(new_dir)->i_logstart);
|
||||
mark_buffer_dirty_inode(dotdot_bh, old_inode);
|
||||
if (IS_DIRSYNC(new_dir)) {
|
||||
err = sync_dirty_buffer(dotdot_bh);
|
||||
if (err)
|
||||
goto error_dotdot;
|
||||
}
|
||||
if (dotdot_de) {
|
||||
err = vfat_update_dotdot_de(new_dir, old_inode, dotdot_bh,
|
||||
dotdot_de);
|
||||
if (err)
|
||||
goto error_dotdot;
|
||||
drop_nlink(old_dir);
|
||||
if (!new_inode)
|
||||
inc_nlink(new_dir);
|
||||
@ -966,12 +993,7 @@ static int vfat_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
old_sinfo.bh = NULL;
|
||||
if (err)
|
||||
goto error_dotdot;
|
||||
inode_inc_iversion(old_dir);
|
||||
fat_truncate_time(old_dir, &ts, S_CTIME|S_MTIME);
|
||||
if (IS_DIRSYNC(old_dir))
|
||||
(void)fat_sync_inode(old_dir);
|
||||
else
|
||||
mark_inode_dirty(old_dir);
|
||||
vfat_update_dir_metadata(old_dir, &ts);
|
||||
|
||||
if (new_inode) {
|
||||
drop_nlink(new_inode);
|
||||
@ -991,10 +1013,9 @@ static int vfat_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
/* data cluster is shared, serious corruption */
|
||||
corrupt = 1;
|
||||
|
||||
if (update_dotdot) {
|
||||
fat_set_start(dotdot_de, MSDOS_I(old_dir)->i_logstart);
|
||||
mark_buffer_dirty_inode(dotdot_bh, old_inode);
|
||||
corrupt |= sync_dirty_buffer(dotdot_bh);
|
||||
if (dotdot_de) {
|
||||
corrupt |= vfat_update_dotdot_de(old_dir, old_inode, dotdot_bh,
|
||||
dotdot_de);
|
||||
}
|
||||
error_inode:
|
||||
fat_detach(old_inode);
|
||||
@ -1021,13 +1042,145 @@ static int vfat_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void vfat_exchange_ipos(struct inode *old_inode, struct inode *new_inode,
|
||||
loff_t old_i_pos, loff_t new_i_pos)
|
||||
{
|
||||
fat_detach(old_inode);
|
||||
fat_detach(new_inode);
|
||||
fat_attach(old_inode, new_i_pos);
|
||||
fat_attach(new_inode, old_i_pos);
|
||||
}
|
||||
|
||||
static void vfat_move_nlink(struct inode *src, struct inode *dst)
|
||||
{
|
||||
drop_nlink(src);
|
||||
inc_nlink(dst);
|
||||
}
|
||||
|
||||
static int vfat_rename_exchange(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry)
|
||||
{
|
||||
struct buffer_head *old_dotdot_bh = NULL, *new_dotdot_bh = NULL;
|
||||
struct msdos_dir_entry *old_dotdot_de = NULL, *new_dotdot_de = NULL;
|
||||
struct inode *old_inode, *new_inode;
|
||||
struct timespec64 ts = current_time(old_dir);
|
||||
loff_t old_i_pos, new_i_pos;
|
||||
int err, corrupt = 0;
|
||||
struct super_block *sb = old_dir->i_sb;
|
||||
|
||||
old_inode = d_inode(old_dentry);
|
||||
new_inode = d_inode(new_dentry);
|
||||
|
||||
/* Acquire super block lock for the operation to be atomic */
|
||||
mutex_lock(&MSDOS_SB(sb)->s_lock);
|
||||
|
||||
/* if directories are not the same, get ".." info to update */
|
||||
if (old_dir != new_dir) {
|
||||
err = vfat_get_dotdot_de(old_inode, &old_dotdot_bh,
|
||||
&old_dotdot_de);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = vfat_get_dotdot_de(new_inode, &new_dotdot_bh,
|
||||
&new_dotdot_de);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
old_i_pos = MSDOS_I(old_inode)->i_pos;
|
||||
new_i_pos = MSDOS_I(new_inode)->i_pos;
|
||||
|
||||
vfat_exchange_ipos(old_inode, new_inode, old_i_pos, new_i_pos);
|
||||
|
||||
err = vfat_sync_ipos(old_dir, new_inode);
|
||||
if (err)
|
||||
goto error_exchange;
|
||||
err = vfat_sync_ipos(new_dir, old_inode);
|
||||
if (err)
|
||||
goto error_exchange;
|
||||
|
||||
/* update ".." directory entry info */
|
||||
if (old_dotdot_de) {
|
||||
err = vfat_update_dotdot_de(new_dir, old_inode, old_dotdot_bh,
|
||||
old_dotdot_de);
|
||||
if (err)
|
||||
goto error_old_dotdot;
|
||||
}
|
||||
if (new_dotdot_de) {
|
||||
err = vfat_update_dotdot_de(old_dir, new_inode, new_dotdot_bh,
|
||||
new_dotdot_de);
|
||||
if (err)
|
||||
goto error_new_dotdot;
|
||||
}
|
||||
|
||||
/* if cross directory and only one is a directory, adjust nlink */
|
||||
if (!old_dotdot_de != !new_dotdot_de) {
|
||||
if (old_dotdot_de)
|
||||
vfat_move_nlink(old_dir, new_dir);
|
||||
else
|
||||
vfat_move_nlink(new_dir, old_dir);
|
||||
}
|
||||
|
||||
vfat_update_dir_metadata(old_dir, &ts);
|
||||
/* if directories are not the same, update new_dir as well */
|
||||
if (old_dir != new_dir)
|
||||
vfat_update_dir_metadata(new_dir, &ts);
|
||||
|
||||
out:
|
||||
brelse(old_dotdot_bh);
|
||||
brelse(new_dotdot_bh);
|
||||
mutex_unlock(&MSDOS_SB(sb)->s_lock);
|
||||
|
||||
return err;
|
||||
|
||||
error_new_dotdot:
|
||||
if (new_dotdot_de) {
|
||||
corrupt |= vfat_update_dotdot_de(new_dir, new_inode,
|
||||
new_dotdot_bh, new_dotdot_de);
|
||||
}
|
||||
|
||||
error_old_dotdot:
|
||||
if (old_dotdot_de) {
|
||||
corrupt |= vfat_update_dotdot_de(old_dir, old_inode,
|
||||
old_dotdot_bh, old_dotdot_de);
|
||||
}
|
||||
|
||||
error_exchange:
|
||||
vfat_exchange_ipos(old_inode, new_inode, new_i_pos, old_i_pos);
|
||||
corrupt |= vfat_sync_ipos(new_dir, new_inode);
|
||||
corrupt |= vfat_sync_ipos(old_dir, old_inode);
|
||||
|
||||
if (corrupt < 0) {
|
||||
fat_fs_error(new_dir->i_sb,
|
||||
"%s: Filesystem corrupted (i_pos %lld, %lld)",
|
||||
__func__, old_i_pos, new_i_pos);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int vfat_rename2(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
struct dentry *old_dentry, struct inode *new_dir,
|
||||
struct dentry *new_dentry, unsigned int flags)
|
||||
{
|
||||
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
|
||||
return -EINVAL;
|
||||
|
||||
if (flags & RENAME_EXCHANGE) {
|
||||
return vfat_rename_exchange(old_dir, old_dentry,
|
||||
new_dir, new_dentry);
|
||||
}
|
||||
|
||||
/* VFS already handled RENAME_NOREPLACE, handle it as a normal rename */
|
||||
return vfat_rename(old_dir, old_dentry, new_dir, new_dentry);
|
||||
}
|
||||
|
||||
static const struct inode_operations vfat_dir_inode_operations = {
|
||||
.create = vfat_create,
|
||||
.lookup = vfat_lookup,
|
||||
.unlink = vfat_unlink,
|
||||
.mkdir = vfat_mkdir,
|
||||
.rmdir = vfat_rmdir,
|
||||
.rename = vfat_rename,
|
||||
.rename = vfat_rename2,
|
||||
.setattr = fat_setattr,
|
||||
.getattr = fat_getattr,
|
||||
.update_time = fat_update_time,
|
||||
|
@ -29,15 +29,15 @@
|
||||
* change between calls to kernel_read_file().
|
||||
*
|
||||
* Returns number of bytes read (no single read will be bigger
|
||||
* than INT_MAX), or negative on error.
|
||||
* than SSIZE_MAX), or negative on error.
|
||||
*
|
||||
*/
|
||||
int kernel_read_file(struct file *file, loff_t offset, void **buf,
|
||||
size_t buf_size, size_t *file_size,
|
||||
enum kernel_read_file_id id)
|
||||
ssize_t kernel_read_file(struct file *file, loff_t offset, void **buf,
|
||||
size_t buf_size, size_t *file_size,
|
||||
enum kernel_read_file_id id)
|
||||
{
|
||||
loff_t i_size, pos;
|
||||
size_t copied;
|
||||
ssize_t copied;
|
||||
void *allocated = NULL;
|
||||
bool whole_file;
|
||||
int ret;
|
||||
@ -58,7 +58,7 @@ int kernel_read_file(struct file *file, loff_t offset, void **buf,
|
||||
goto out;
|
||||
}
|
||||
/* The file is too big for sane activities. */
|
||||
if (i_size > INT_MAX) {
|
||||
if (i_size > SSIZE_MAX) {
|
||||
ret = -EFBIG;
|
||||
goto out;
|
||||
}
|
||||
@ -124,12 +124,12 @@ int kernel_read_file(struct file *file, loff_t offset, void **buf,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kernel_read_file);
|
||||
|
||||
int kernel_read_file_from_path(const char *path, loff_t offset, void **buf,
|
||||
size_t buf_size, size_t *file_size,
|
||||
enum kernel_read_file_id id)
|
||||
ssize_t kernel_read_file_from_path(const char *path, loff_t offset, void **buf,
|
||||
size_t buf_size, size_t *file_size,
|
||||
enum kernel_read_file_id id)
|
||||
{
|
||||
struct file *file;
|
||||
int ret;
|
||||
ssize_t ret;
|
||||
|
||||
if (!path || !*path)
|
||||
return -EINVAL;
|
||||
@ -144,14 +144,14 @@ int kernel_read_file_from_path(const char *path, loff_t offset, void **buf,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kernel_read_file_from_path);
|
||||
|
||||
int kernel_read_file_from_path_initns(const char *path, loff_t offset,
|
||||
void **buf, size_t buf_size,
|
||||
size_t *file_size,
|
||||
enum kernel_read_file_id id)
|
||||
ssize_t kernel_read_file_from_path_initns(const char *path, loff_t offset,
|
||||
void **buf, size_t buf_size,
|
||||
size_t *file_size,
|
||||
enum kernel_read_file_id id)
|
||||
{
|
||||
struct file *file;
|
||||
struct path root;
|
||||
int ret;
|
||||
ssize_t ret;
|
||||
|
||||
if (!path || !*path)
|
||||
return -EINVAL;
|
||||
@ -171,12 +171,12 @@ int kernel_read_file_from_path_initns(const char *path, loff_t offset,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns);
|
||||
|
||||
int kernel_read_file_from_fd(int fd, loff_t offset, void **buf,
|
||||
size_t buf_size, size_t *file_size,
|
||||
enum kernel_read_file_id id)
|
||||
ssize_t kernel_read_file_from_fd(int fd, loff_t offset, void **buf,
|
||||
size_t buf_size, size_t *file_size,
|
||||
enum kernel_read_file_id id)
|
||||
{
|
||||
struct fd f = fdget(fd);
|
||||
int ret = -EBADF;
|
||||
ssize_t ret = -EBADF;
|
||||
|
||||
if (!f.file || !(f.file->f_mode & FMODE_READ))
|
||||
goto out;
|
||||
|
@ -296,17 +296,25 @@ static void dlmfs_evict_inode(struct inode *inode)
|
||||
{
|
||||
int status;
|
||||
struct dlmfs_inode_private *ip;
|
||||
struct user_lock_res *lockres;
|
||||
int teardown;
|
||||
|
||||
clear_inode(inode);
|
||||
|
||||
mlog(0, "inode %lu\n", inode->i_ino);
|
||||
|
||||
ip = DLMFS_I(inode);
|
||||
lockres = &ip->ip_lockres;
|
||||
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
status = user_dlm_destroy_lock(&ip->ip_lockres);
|
||||
if (status < 0)
|
||||
mlog_errno(status);
|
||||
spin_lock(&lockres->l_lock);
|
||||
teardown = !!(lockres->l_flags & USER_LOCK_IN_TEARDOWN);
|
||||
spin_unlock(&lockres->l_lock);
|
||||
if (!teardown) {
|
||||
status = user_dlm_destroy_lock(lockres);
|
||||
if (status < 0)
|
||||
mlog_errno(status);
|
||||
}
|
||||
iput(ip->ip_parent);
|
||||
goto clear_fields;
|
||||
}
|
||||
|
@ -34,12 +34,15 @@ static int copy_bio_to_actor(struct bio *bio,
|
||||
struct squashfs_page_actor *actor,
|
||||
int offset, int req_length)
|
||||
{
|
||||
void *actor_addr = squashfs_first_page(actor);
|
||||
void *actor_addr;
|
||||
struct bvec_iter_all iter_all = {};
|
||||
struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
|
||||
int copied_bytes = 0;
|
||||
int actor_offset = 0;
|
||||
|
||||
squashfs_actor_nobuff(actor);
|
||||
actor_addr = squashfs_first_page(actor);
|
||||
|
||||
if (WARN_ON_ONCE(!bio_next_segment(bio, &iter_all)))
|
||||
return 0;
|
||||
|
||||
@ -49,8 +52,9 @@ static int copy_bio_to_actor(struct bio *bio,
|
||||
|
||||
bytes_to_copy = min_t(int, bytes_to_copy,
|
||||
req_length - copied_bytes);
|
||||
memcpy(actor_addr + actor_offset, bvec_virt(bvec) + offset,
|
||||
bytes_to_copy);
|
||||
if (!IS_ERR(actor_addr))
|
||||
memcpy(actor_addr + actor_offset, bvec_virt(bvec) +
|
||||
offset, bytes_to_copy);
|
||||
|
||||
actor_offset += bytes_to_copy;
|
||||
copied_bytes += bytes_to_copy;
|
||||
|
@ -20,6 +20,7 @@ struct squashfs_decompressor {
|
||||
struct bio *, int, int, struct squashfs_page_actor *);
|
||||
int id;
|
||||
char *name;
|
||||
int alloc_buffer;
|
||||
int supported;
|
||||
};
|
||||
|
||||
|
@ -18,9 +18,6 @@
|
||||
#include "squashfs.h"
|
||||
#include "page_actor.h"
|
||||
|
||||
static int squashfs_read_cache(struct page *target_page, u64 block, int bsize,
|
||||
int pages, struct page **page, int bytes);
|
||||
|
||||
/* Read separately compressed datablock directly into page cache */
|
||||
int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
|
||||
int expected)
|
||||
@ -33,7 +30,7 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
|
||||
int mask = (1 << (msblk->block_log - PAGE_SHIFT)) - 1;
|
||||
int start_index = target_page->index & ~mask;
|
||||
int end_index = start_index | mask;
|
||||
int i, n, pages, missing_pages, bytes, res = -ENOMEM;
|
||||
int i, n, pages, bytes, res = -ENOMEM;
|
||||
struct page **page;
|
||||
struct squashfs_page_actor *actor;
|
||||
void *pageaddr;
|
||||
@ -47,50 +44,38 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
|
||||
if (page == NULL)
|
||||
return res;
|
||||
|
||||
/*
|
||||
* Create a "page actor" which will kmap and kunmap the
|
||||
* page cache pages appropriately within the decompressor
|
||||
*/
|
||||
actor = squashfs_page_actor_init_special(page, pages, 0);
|
||||
if (actor == NULL)
|
||||
goto out;
|
||||
|
||||
/* Try to grab all the pages covered by the Squashfs block */
|
||||
for (missing_pages = 0, i = 0, n = start_index; i < pages; i++, n++) {
|
||||
for (i = 0, n = start_index; n <= end_index; n++) {
|
||||
page[i] = (n == target_page->index) ? target_page :
|
||||
grab_cache_page_nowait(target_page->mapping, n);
|
||||
|
||||
if (page[i] == NULL) {
|
||||
missing_pages++;
|
||||
if (page[i] == NULL)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PageUptodate(page[i])) {
|
||||
unlock_page(page[i]);
|
||||
put_page(page[i]);
|
||||
page[i] = NULL;
|
||||
missing_pages++;
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (missing_pages) {
|
||||
/*
|
||||
* Couldn't get one or more pages, this page has either
|
||||
* been VM reclaimed, but others are still in the page cache
|
||||
* and uptodate, or we're racing with another thread in
|
||||
* squashfs_readpage also trying to grab them. Fall back to
|
||||
* using an intermediate buffer.
|
||||
*/
|
||||
res = squashfs_read_cache(target_page, block, bsize, pages,
|
||||
page, expected);
|
||||
if (res < 0)
|
||||
goto mark_errored;
|
||||
pages = i;
|
||||
|
||||
/*
|
||||
* Create a "page actor" which will kmap and kunmap the
|
||||
* page cache pages appropriately within the decompressor
|
||||
*/
|
||||
actor = squashfs_page_actor_init_special(msblk, page, pages, expected);
|
||||
if (actor == NULL)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Decompress directly into the page cache buffers */
|
||||
res = squashfs_read_data(inode->i_sb, block, bsize, NULL, actor);
|
||||
|
||||
kfree(actor);
|
||||
|
||||
if (res < 0)
|
||||
goto mark_errored;
|
||||
|
||||
@ -99,12 +84,12 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
|
||||
goto mark_errored;
|
||||
}
|
||||
|
||||
/* Last page may have trailing bytes not filled */
|
||||
/* Last page (if present) may have trailing bytes not filled */
|
||||
bytes = res % PAGE_SIZE;
|
||||
if (bytes) {
|
||||
pageaddr = kmap_atomic(page[pages - 1]);
|
||||
if (page[pages - 1]->index == end_index && bytes) {
|
||||
pageaddr = kmap_local_page(page[pages - 1]);
|
||||
memset(pageaddr + bytes, 0, PAGE_SIZE - bytes);
|
||||
kunmap_atomic(pageaddr);
|
||||
kunmap_local(pageaddr);
|
||||
}
|
||||
|
||||
/* Mark pages as uptodate, unlock and release */
|
||||
@ -116,7 +101,6 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
|
||||
put_page(page[i]);
|
||||
}
|
||||
|
||||
kfree(actor);
|
||||
kfree(page);
|
||||
|
||||
return 0;
|
||||
@ -135,40 +119,6 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(actor);
|
||||
kfree(page);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int squashfs_read_cache(struct page *target_page, u64 block, int bsize,
|
||||
int pages, struct page **page, int bytes)
|
||||
{
|
||||
struct inode *i = target_page->mapping->host;
|
||||
struct squashfs_cache_entry *buffer = squashfs_get_datablock(i->i_sb,
|
||||
block, bsize);
|
||||
int res = buffer->error, n, offset = 0;
|
||||
|
||||
if (res) {
|
||||
ERROR("Unable to read page, block %llx, size %x\n", block,
|
||||
bsize);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (n = 0; n < pages && bytes > 0; n++,
|
||||
bytes -= PAGE_SIZE, offset += PAGE_SIZE) {
|
||||
int avail = min_t(int, bytes, PAGE_SIZE);
|
||||
|
||||
if (page[n] == NULL)
|
||||
continue;
|
||||
|
||||
squashfs_fill_page(page[n], buffer, offset, avail);
|
||||
unlock_page(page[n]);
|
||||
if (page[n] != target_page)
|
||||
put_page(page[n]);
|
||||
}
|
||||
|
||||
out:
|
||||
squashfs_cache_put(buffer);
|
||||
return res;
|
||||
}
|
||||
|
@ -119,10 +119,12 @@ static int lz4_uncompress(struct squashfs_sb_info *msblk, void *strm,
|
||||
buff = stream->output;
|
||||
while (data) {
|
||||
if (bytes <= PAGE_SIZE) {
|
||||
memcpy(data, buff, bytes);
|
||||
if (!IS_ERR(data))
|
||||
memcpy(data, buff, bytes);
|
||||
break;
|
||||
}
|
||||
memcpy(data, buff, PAGE_SIZE);
|
||||
if (!IS_ERR(data))
|
||||
memcpy(data, buff, PAGE_SIZE);
|
||||
buff += PAGE_SIZE;
|
||||
bytes -= PAGE_SIZE;
|
||||
data = squashfs_next_page(output);
|
||||
@ -139,5 +141,6 @@ const struct squashfs_decompressor squashfs_lz4_comp_ops = {
|
||||
.decompress = lz4_uncompress,
|
||||
.id = LZ4_COMPRESSION,
|
||||
.name = "lz4",
|
||||
.alloc_buffer = 0,
|
||||
.supported = 1
|
||||
};
|
||||
|
@ -93,10 +93,12 @@ static int lzo_uncompress(struct squashfs_sb_info *msblk, void *strm,
|
||||
buff = stream->output;
|
||||
while (data) {
|
||||
if (bytes <= PAGE_SIZE) {
|
||||
memcpy(data, buff, bytes);
|
||||
if (!IS_ERR(data))
|
||||
memcpy(data, buff, bytes);
|
||||
break;
|
||||
} else {
|
||||
memcpy(data, buff, PAGE_SIZE);
|
||||
if (!IS_ERR(data))
|
||||
memcpy(data, buff, PAGE_SIZE);
|
||||
buff += PAGE_SIZE;
|
||||
bytes -= PAGE_SIZE;
|
||||
data = squashfs_next_page(output);
|
||||
@ -116,5 +118,6 @@ const struct squashfs_decompressor squashfs_lzo_comp_ops = {
|
||||
.decompress = lzo_uncompress,
|
||||
.id = LZO_COMPRESSION,
|
||||
.name = "lzo",
|
||||
.alloc_buffer = 0,
|
||||
.supported = 1
|
||||
};
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "decompressor.h"
|
||||
#include "page_actor.h"
|
||||
|
||||
/*
|
||||
@ -57,29 +59,62 @@ struct squashfs_page_actor *squashfs_page_actor_init(void **buffer,
|
||||
}
|
||||
|
||||
/* Implementation of page_actor for decompressing directly into page cache. */
|
||||
static void *handle_next_page(struct squashfs_page_actor *actor)
|
||||
{
|
||||
int max_pages = (actor->length + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
|
||||
if (actor->returned_pages == max_pages)
|
||||
return NULL;
|
||||
|
||||
if ((actor->next_page == actor->pages) ||
|
||||
(actor->next_index != actor->page[actor->next_page]->index)) {
|
||||
if (actor->alloc_buffer) {
|
||||
void *tmp_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
|
||||
if (tmp_buffer) {
|
||||
actor->tmp_buffer = tmp_buffer;
|
||||
actor->next_index++;
|
||||
actor->returned_pages++;
|
||||
return tmp_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
actor->next_index++;
|
||||
actor->returned_pages++;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
actor->next_index++;
|
||||
actor->returned_pages++;
|
||||
return actor->pageaddr = kmap_local_page(actor->page[actor->next_page++]);
|
||||
}
|
||||
|
||||
static void *direct_first_page(struct squashfs_page_actor *actor)
|
||||
{
|
||||
actor->next_page = 1;
|
||||
return actor->pageaddr = kmap_atomic(actor->page[0]);
|
||||
return handle_next_page(actor);
|
||||
}
|
||||
|
||||
static void *direct_next_page(struct squashfs_page_actor *actor)
|
||||
{
|
||||
if (actor->pageaddr)
|
||||
kunmap_atomic(actor->pageaddr);
|
||||
kunmap_local(actor->pageaddr);
|
||||
|
||||
return actor->pageaddr = actor->next_page == actor->pages ? NULL :
|
||||
kmap_atomic(actor->page[actor->next_page++]);
|
||||
kfree(actor->tmp_buffer);
|
||||
actor->pageaddr = actor->tmp_buffer = NULL;
|
||||
|
||||
return handle_next_page(actor);
|
||||
}
|
||||
|
||||
static void direct_finish_page(struct squashfs_page_actor *actor)
|
||||
{
|
||||
if (actor->pageaddr)
|
||||
kunmap_atomic(actor->pageaddr);
|
||||
kunmap_local(actor->pageaddr);
|
||||
|
||||
kfree(actor->tmp_buffer);
|
||||
}
|
||||
|
||||
struct squashfs_page_actor *squashfs_page_actor_init_special(struct page **page,
|
||||
int pages, int length)
|
||||
struct squashfs_page_actor *squashfs_page_actor_init_special(struct squashfs_sb_info *msblk,
|
||||
struct page **page, int pages, int length)
|
||||
{
|
||||
struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL);
|
||||
|
||||
@ -90,7 +125,11 @@ struct squashfs_page_actor *squashfs_page_actor_init_special(struct page **page,
|
||||
actor->page = page;
|
||||
actor->pages = pages;
|
||||
actor->next_page = 0;
|
||||
actor->returned_pages = 0;
|
||||
actor->next_index = page[0]->index & ~((1 << (msblk->block_log - PAGE_SHIFT)) - 1);
|
||||
actor->pageaddr = NULL;
|
||||
actor->tmp_buffer = NULL;
|
||||
actor->alloc_buffer = msblk->decompressor->alloc_buffer;
|
||||
actor->squashfs_first_page = direct_first_page;
|
||||
actor->squashfs_next_page = direct_next_page;
|
||||
actor->squashfs_finish_page = direct_finish_page;
|
||||
|
@ -45,6 +45,11 @@ static inline void squashfs_finish_page(struct squashfs_page_actor *actor)
|
||||
{
|
||||
/* empty */
|
||||
}
|
||||
|
||||
static inline void squashfs_actor_nobuff(struct squashfs_page_actor *actor)
|
||||
{
|
||||
/* empty */
|
||||
}
|
||||
#else
|
||||
struct squashfs_page_actor {
|
||||
union {
|
||||
@ -52,17 +57,23 @@ struct squashfs_page_actor {
|
||||
struct page **page;
|
||||
};
|
||||
void *pageaddr;
|
||||
void *tmp_buffer;
|
||||
void *(*squashfs_first_page)(struct squashfs_page_actor *);
|
||||
void *(*squashfs_next_page)(struct squashfs_page_actor *);
|
||||
void (*squashfs_finish_page)(struct squashfs_page_actor *);
|
||||
int pages;
|
||||
int length;
|
||||
int next_page;
|
||||
int alloc_buffer;
|
||||
int returned_pages;
|
||||
pgoff_t next_index;
|
||||
};
|
||||
|
||||
extern struct squashfs_page_actor *squashfs_page_actor_init(void **, int, int);
|
||||
extern struct squashfs_page_actor *squashfs_page_actor_init_special(struct page
|
||||
**, int, int);
|
||||
extern struct squashfs_page_actor *squashfs_page_actor_init(void **buffer,
|
||||
int pages, int length);
|
||||
extern struct squashfs_page_actor *squashfs_page_actor_init_special(
|
||||
struct squashfs_sb_info *msblk,
|
||||
struct page **page, int pages, int length);
|
||||
static inline void *squashfs_first_page(struct squashfs_page_actor *actor)
|
||||
{
|
||||
return actor->squashfs_first_page(actor);
|
||||
@ -75,5 +86,9 @@ static inline void squashfs_finish_page(struct squashfs_page_actor *actor)
|
||||
{
|
||||
actor->squashfs_finish_page(actor);
|
||||
}
|
||||
static inline void squashfs_actor_nobuff(struct squashfs_page_actor *actor)
|
||||
{
|
||||
actor->alloc_buffer = 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -131,6 +131,10 @@ static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm,
|
||||
stream->buf.out_pos = 0;
|
||||
stream->buf.out_size = PAGE_SIZE;
|
||||
stream->buf.out = squashfs_first_page(output);
|
||||
if (IS_ERR(stream->buf.out)) {
|
||||
error = PTR_ERR(stream->buf.out);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
enum xz_ret xz_err;
|
||||
@ -156,7 +160,10 @@ static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm,
|
||||
|
||||
if (stream->buf.out_pos == stream->buf.out_size) {
|
||||
stream->buf.out = squashfs_next_page(output);
|
||||
if (stream->buf.out != NULL) {
|
||||
if (IS_ERR(stream->buf.out)) {
|
||||
error = PTR_ERR(stream->buf.out);
|
||||
break;
|
||||
} else if (stream->buf.out != NULL) {
|
||||
stream->buf.out_pos = 0;
|
||||
total += PAGE_SIZE;
|
||||
}
|
||||
@ -171,6 +178,7 @@ static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm,
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
squashfs_finish_page(output);
|
||||
|
||||
return error ? error : total + stream->buf.out_pos;
|
||||
@ -183,5 +191,6 @@ const struct squashfs_decompressor squashfs_xz_comp_ops = {
|
||||
.decompress = squashfs_xz_uncompress,
|
||||
.id = XZ_COMPRESSION,
|
||||
.name = "xz",
|
||||
.alloc_buffer = 1,
|
||||
.supported = 1
|
||||
};
|
||||
|
@ -62,6 +62,11 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
|
||||
stream->next_out = squashfs_first_page(output);
|
||||
stream->avail_in = 0;
|
||||
|
||||
if (IS_ERR(stream->next_out)) {
|
||||
error = PTR_ERR(stream->next_out);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int zlib_err;
|
||||
|
||||
@ -85,7 +90,10 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
|
||||
|
||||
if (stream->avail_out == 0) {
|
||||
stream->next_out = squashfs_next_page(output);
|
||||
if (stream->next_out != NULL)
|
||||
if (IS_ERR(stream->next_out)) {
|
||||
error = PTR_ERR(stream->next_out);
|
||||
break;
|
||||
} else if (stream->next_out != NULL)
|
||||
stream->avail_out = PAGE_SIZE;
|
||||
}
|
||||
|
||||
@ -107,6 +115,7 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
squashfs_finish_page(output);
|
||||
|
||||
if (!error)
|
||||
@ -122,6 +131,7 @@ const struct squashfs_decompressor squashfs_zlib_comp_ops = {
|
||||
.decompress = zlib_uncompress,
|
||||
.id = ZLIB_COMPRESSION,
|
||||
.name = "zlib",
|
||||
.alloc_buffer = 1,
|
||||
.supported = 1
|
||||
};
|
||||
|
||||
|
@ -80,6 +80,10 @@ static int zstd_uncompress(struct squashfs_sb_info *msblk, void *strm,
|
||||
|
||||
out_buf.size = PAGE_SIZE;
|
||||
out_buf.dst = squashfs_first_page(output);
|
||||
if (IS_ERR(out_buf.dst)) {
|
||||
error = PTR_ERR(out_buf.dst);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
size_t zstd_err;
|
||||
@ -104,7 +108,10 @@ static int zstd_uncompress(struct squashfs_sb_info *msblk, void *strm,
|
||||
|
||||
if (out_buf.pos == out_buf.size) {
|
||||
out_buf.dst = squashfs_next_page(output);
|
||||
if (out_buf.dst == NULL) {
|
||||
if (IS_ERR(out_buf.dst)) {
|
||||
error = PTR_ERR(out_buf.dst);
|
||||
break;
|
||||
} else if (out_buf.dst == NULL) {
|
||||
/* Shouldn't run out of pages
|
||||
* before stream is done.
|
||||
*/
|
||||
@ -129,6 +136,8 @@ static int zstd_uncompress(struct squashfs_sb_info *msblk, void *strm,
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
|
||||
squashfs_finish_page(output);
|
||||
|
||||
return error ? error : total_out;
|
||||
@ -140,5 +149,6 @@ const struct squashfs_decompressor squashfs_zstd_comp_ops = {
|
||||
.decompress = zstd_uncompress,
|
||||
.id = ZSTD_COMPRESSION,
|
||||
.name = "zstd",
|
||||
.alloc_buffer = 1,
|
||||
.supported = 1
|
||||
};
|
||||
|
@ -35,21 +35,21 @@ static inline const char *kernel_read_file_id_str(enum kernel_read_file_id id)
|
||||
return kernel_read_file_str[id];
|
||||
}
|
||||
|
||||
int kernel_read_file(struct file *file, loff_t offset,
|
||||
void **buf, size_t buf_size,
|
||||
size_t *file_size,
|
||||
enum kernel_read_file_id id);
|
||||
int kernel_read_file_from_path(const char *path, loff_t offset,
|
||||
void **buf, size_t buf_size,
|
||||
size_t *file_size,
|
||||
enum kernel_read_file_id id);
|
||||
int kernel_read_file_from_path_initns(const char *path, loff_t offset,
|
||||
void **buf, size_t buf_size,
|
||||
size_t *file_size,
|
||||
enum kernel_read_file_id id);
|
||||
int kernel_read_file_from_fd(int fd, loff_t offset,
|
||||
void **buf, size_t buf_size,
|
||||
size_t *file_size,
|
||||
enum kernel_read_file_id id);
|
||||
ssize_t kernel_read_file(struct file *file, loff_t offset,
|
||||
void **buf, size_t buf_size,
|
||||
size_t *file_size,
|
||||
enum kernel_read_file_id id);
|
||||
ssize_t kernel_read_file_from_path(const char *path, loff_t offset,
|
||||
void **buf, size_t buf_size,
|
||||
size_t *file_size,
|
||||
enum kernel_read_file_id id);
|
||||
ssize_t kernel_read_file_from_path_initns(const char *path, loff_t offset,
|
||||
void **buf, size_t buf_size,
|
||||
size_t *file_size,
|
||||
enum kernel_read_file_id id);
|
||||
ssize_t kernel_read_file_from_fd(int fd, loff_t offset,
|
||||
void **buf, size_t buf_size,
|
||||
size_t *file_size,
|
||||
enum kernel_read_file_id id);
|
||||
|
||||
#endif /* _LINUX_KERNEL_READ_FILE_H */
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <vdso/limits.h>
|
||||
|
||||
#define SIZE_MAX (~(size_t)0)
|
||||
#define SSIZE_MAX ((ssize_t)(SIZE_MAX >> 1))
|
||||
#define PHYS_ADDR_MAX (~(phys_addr_t)0)
|
||||
|
||||
#define U8_MAX ((u8)~0U)
|
||||
|
@ -17,9 +17,9 @@
|
||||
#ifndef _LINUX_RBTREE_H
|
||||
#define _LINUX_RBTREE_H
|
||||
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/rbtree_types.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
|
@ -102,7 +102,7 @@ static inline __attribute_const__ __u32 __fswahb32(__u32 val)
|
||||
#define __swab16(x) (__u16)__builtin_bswap16((__u16)(x))
|
||||
#else
|
||||
#define __swab16(x) \
|
||||
(__builtin_constant_p((__u16)(x)) ? \
|
||||
(__u16)(__builtin_constant_p(x) ? \
|
||||
___constant_swab16(x) : \
|
||||
__fswab16(x))
|
||||
#endif
|
||||
@ -115,7 +115,7 @@ static inline __attribute_const__ __u32 __fswahb32(__u32 val)
|
||||
#define __swab32(x) (__u32)__builtin_bswap32((__u32)(x))
|
||||
#else
|
||||
#define __swab32(x) \
|
||||
(__builtin_constant_p((__u32)(x)) ? \
|
||||
(__u32)(__builtin_constant_p(x) ? \
|
||||
___constant_swab32(x) : \
|
||||
__fswab32(x))
|
||||
#endif
|
||||
@ -128,7 +128,7 @@ static inline __attribute_const__ __u32 __fswahb32(__u32 val)
|
||||
#define __swab64(x) (__u64)__builtin_bswap64((__u64)(x))
|
||||
#else
|
||||
#define __swab64(x) \
|
||||
(__builtin_constant_p((__u64)(x)) ? \
|
||||
(__u64)(__builtin_constant_p(x) ? \
|
||||
___constant_swab64(x) : \
|
||||
__fswab64(x))
|
||||
#endif
|
||||
|
@ -31,6 +31,9 @@
|
||||
|
||||
static int kexec_calculate_store_digests(struct kimage *image);
|
||||
|
||||
/* Maximum size in bytes for kernel/initrd files. */
|
||||
#define KEXEC_FILE_SIZE_MAX min_t(s64, 4LL << 30, SSIZE_MAX)
|
||||
|
||||
/*
|
||||
* Currently this is the only default function that is exported as some
|
||||
* architectures need it to do additional handlings.
|
||||
@ -189,11 +192,12 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
|
||||
const char __user *cmdline_ptr,
|
||||
unsigned long cmdline_len, unsigned flags)
|
||||
{
|
||||
int ret;
|
||||
ssize_t ret;
|
||||
void *ldata;
|
||||
|
||||
ret = kernel_read_file_from_fd(kernel_fd, 0, &image->kernel_buf,
|
||||
INT_MAX, NULL, READING_KEXEC_IMAGE);
|
||||
KEXEC_FILE_SIZE_MAX, NULL,
|
||||
READING_KEXEC_IMAGE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
image->kernel_buf_len = ret;
|
||||
@ -213,7 +217,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
|
||||
/* It is possible that there no initramfs is being loaded */
|
||||
if (!(flags & KEXEC_FILE_NO_INITRAMFS)) {
|
||||
ret = kernel_read_file_from_fd(initrd_fd, 0, &image->initrd_buf,
|
||||
INT_MAX, NULL,
|
||||
KEXEC_FILE_SIZE_MAX, NULL,
|
||||
READING_KEXEC_INITRAMFS);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
@ -109,6 +109,13 @@ int __ref profile_init(void)
|
||||
|
||||
/* only text is profiled */
|
||||
prof_len = (_etext - _stext) >> prof_shift;
|
||||
|
||||
if (!prof_len) {
|
||||
pr_warn("profiling shift: %u too large\n", prof_shift);
|
||||
prof_on = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buffer_bytes = prof_len*sizeof(atomic_t);
|
||||
|
||||
if (!alloc_cpumask_var(&prof_cpu_mask, GFP_KERNEL))
|
||||
|
30
lib/btree.c
30
lib/btree.c
@ -238,7 +238,7 @@ static int keyzero(struct btree_geo *geo, unsigned long *key)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *btree_lookup(struct btree_head *head, struct btree_geo *geo,
|
||||
static void *btree_lookup_node(struct btree_head *head, struct btree_geo *geo,
|
||||
unsigned long *key)
|
||||
{
|
||||
int i, height = head->height;
|
||||
@ -257,7 +257,16 @@ void *btree_lookup(struct btree_head *head, struct btree_geo *geo,
|
||||
if (!node)
|
||||
return NULL;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void *btree_lookup(struct btree_head *head, struct btree_geo *geo,
|
||||
unsigned long *key)
|
||||
{
|
||||
int i;
|
||||
unsigned long *node;
|
||||
|
||||
node = btree_lookup_node(head, geo, key);
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
@ -271,23 +280,10 @@ EXPORT_SYMBOL_GPL(btree_lookup);
|
||||
int btree_update(struct btree_head *head, struct btree_geo *geo,
|
||||
unsigned long *key, void *val)
|
||||
{
|
||||
int i, height = head->height;
|
||||
unsigned long *node = head->node;
|
||||
|
||||
if (height == 0)
|
||||
return -ENOENT;
|
||||
|
||||
for ( ; height > 1; height--) {
|
||||
for (i = 0; i < geo->no_pairs; i++)
|
||||
if (keycmp(geo, node, i, key) <= 0)
|
||||
break;
|
||||
if (i == geo->no_pairs)
|
||||
return -ENOENT;
|
||||
node = bval(geo, node, i);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
}
|
||||
int i;
|
||||
unsigned long *node;
|
||||
|
||||
node = btree_lookup_node(head, geo, key);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
|
||||
|
@ -197,24 +197,14 @@ static int ei_seq_show(struct seq_file *m, void *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct seq_operations ei_seq_ops = {
|
||||
static const struct seq_operations ei_sops = {
|
||||
.start = ei_seq_start,
|
||||
.next = ei_seq_next,
|
||||
.stop = ei_seq_stop,
|
||||
.show = ei_seq_show,
|
||||
};
|
||||
|
||||
static int ei_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return seq_open(filp, &ei_seq_ops);
|
||||
}
|
||||
|
||||
static const struct file_operations debugfs_ei_ops = {
|
||||
.open = ei_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
DEFINE_SEQ_ATTRIBUTE(ei);
|
||||
|
||||
static int __init ei_debugfs_init(void)
|
||||
{
|
||||
@ -224,7 +214,7 @@ static int __init ei_debugfs_init(void)
|
||||
if (!dir)
|
||||
return -ENOMEM;
|
||||
|
||||
file = debugfs_create_file("list", 0444, dir, NULL, &debugfs_ei_ops);
|
||||
file = debugfs_create_file("list", 0444, dir, NULL, &ei_fops);
|
||||
if (!file) {
|
||||
debugfs_remove(dir);
|
||||
return -ENOMEM;
|
||||
|
@ -63,18 +63,13 @@ void fprop_global_destroy(struct fprop_global *p)
|
||||
*/
|
||||
bool fprop_new_period(struct fprop_global *p, int periods)
|
||||
{
|
||||
s64 events;
|
||||
unsigned long flags;
|
||||
s64 events = percpu_counter_sum(&p->events);
|
||||
|
||||
local_irq_save(flags);
|
||||
events = percpu_counter_sum(&p->events);
|
||||
/*
|
||||
* Don't do anything if there are no events.
|
||||
*/
|
||||
if (events <= 1) {
|
||||
local_irq_restore(flags);
|
||||
if (events <= 1)
|
||||
return false;
|
||||
}
|
||||
write_seqcount_begin(&p->sequence);
|
||||
if (periods < 64)
|
||||
events -= events >> periods;
|
||||
@ -82,7 +77,6 @@ bool fprop_new_period(struct fprop_global *p, int periods)
|
||||
percpu_counter_add(&p->events, -events);
|
||||
p->period += periods;
|
||||
write_seqcount_end(&p->sequence);
|
||||
local_irq_restore(flags);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -20,7 +20,11 @@
|
||||
bool __list_add_valid(struct list_head *new, struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
if (CHECK_DATA_CORRUPTION(next->prev != prev,
|
||||
if (CHECK_DATA_CORRUPTION(prev == NULL,
|
||||
"list_add corruption. prev is NULL.\n") ||
|
||||
CHECK_DATA_CORRUPTION(next == NULL,
|
||||
"list_add corruption. next is NULL.\n") ||
|
||||
CHECK_DATA_CORRUPTION(next->prev != prev,
|
||||
"list_add corruption. next->prev should be prev (%px), but was %px. (next=%px).\n",
|
||||
prev, next->prev, next) ||
|
||||
CHECK_DATA_CORRUPTION(prev->next != next,
|
||||
@ -42,7 +46,11 @@ bool __list_del_entry_valid(struct list_head *entry)
|
||||
prev = entry->prev;
|
||||
next = entry->next;
|
||||
|
||||
if (CHECK_DATA_CORRUPTION(next == LIST_POISON1,
|
||||
if (CHECK_DATA_CORRUPTION(next == NULL,
|
||||
"list_del corruption, %px->next is NULL\n", entry) ||
|
||||
CHECK_DATA_CORRUPTION(prev == NULL,
|
||||
"list_del corruption, %px->prev is NULL\n", entry) ||
|
||||
CHECK_DATA_CORRUPTION(next == LIST_POISON1,
|
||||
"list_del corruption, %px->next is LIST_POISON1 (%px)\n",
|
||||
entry, LIST_POISON1) ||
|
||||
CHECK_DATA_CORRUPTION(prev == LIST_POISON2,
|
||||
|
@ -1042,7 +1042,8 @@ our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)};
|
||||
our $declaration_macros = qr{(?x:
|
||||
(?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(|
|
||||
(?:$Storage\s+)?[HLP]?LIST_HEAD\s*\(|
|
||||
(?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\(
|
||||
(?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\(|
|
||||
(?:$Storage\s+)?(?:XA_STATE|XA_STATE_ORDER)\s*\(
|
||||
)};
|
||||
|
||||
our %allow_repeated_words = (
|
||||
@ -5720,7 +5721,7 @@ sub process {
|
||||
$var !~ /^(?:[a-z0-9_]*|[A-Z0-9_]*)?_?[a-z][A-Z](?:_[a-z0-9_]+|_[A-Z0-9_]+)?$/ &&
|
||||
#Ignore some three character SI units explicitly, like MiB and KHz
|
||||
$var !~ /^(?:[a-z_]*?)_?(?:[KMGT]iB|[KMGT]?Hz)(?:_[a-z_]+)?$/) {
|
||||
while ($var =~ m{($Ident)}g) {
|
||||
while ($var =~ m{\b($Ident)}g) {
|
||||
my $word = $1;
|
||||
next if ($word !~ /[A-Z][a-z]|[a-z][A-Z]/);
|
||||
if ($check) {
|
||||
|
@ -45,7 +45,6 @@
|
||||
exit(code); \
|
||||
} while (0)
|
||||
|
||||
int done;
|
||||
int rcvbufsz;
|
||||
char name[100];
|
||||
int dbg;
|
||||
@ -285,7 +284,6 @@ int main(int argc, char *argv[])
|
||||
pid_t rtid = 0;
|
||||
|
||||
int fd = 0;
|
||||
int count = 0;
|
||||
int write_file = 0;
|
||||
int maskset = 0;
|
||||
char *logfile = NULL;
|
||||
@ -495,7 +493,6 @@ int main(int argc, char *argv[])
|
||||
len2 = 0;
|
||||
/* For nested attributes, na follows */
|
||||
na = (struct nlattr *) NLA_DATA(na);
|
||||
done = 0;
|
||||
while (len2 < aggr_len) {
|
||||
switch (na->nla_type) {
|
||||
case TASKSTATS_TYPE_PID:
|
||||
@ -509,7 +506,6 @@ int main(int argc, char *argv[])
|
||||
printf("TGID\t%d\n", rtid);
|
||||
break;
|
||||
case TASKSTATS_TYPE_STATS:
|
||||
count++;
|
||||
if (print_delays)
|
||||
print_delayacct((struct taskstats *) NLA_DATA(na));
|
||||
if (print_io_accounting)
|
||||
|
@ -17,6 +17,7 @@ TARGETS += exec
|
||||
TARGETS += filesystems
|
||||
TARGETS += filesystems/binderfs
|
||||
TARGETS += filesystems/epoll
|
||||
TARGETS += filesystems/fat
|
||||
TARGETS += firmware
|
||||
TARGETS += fpu
|
||||
TARGETS += ftrace
|
||||
|
2
tools/testing/selftests/filesystems/fat/.gitignore
vendored
Normal file
2
tools/testing/selftests/filesystems/fat/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
rename_exchange
|
7
tools/testing/selftests/filesystems/fat/Makefile
Normal file
7
tools/testing/selftests/filesystems/fat/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
TEST_PROGS := run_fat_tests.sh
|
||||
TEST_GEN_PROGS_EXTENDED := rename_exchange
|
||||
CFLAGS += -O2 -g -Wall $(KHDR_INCLUDES)
|
||||
|
||||
include ../../lib.mk
|
2
tools/testing/selftests/filesystems/fat/config
Normal file
2
tools/testing/selftests/filesystems/fat/config
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_VFAT_FS=y
|
37
tools/testing/selftests/filesystems/fat/rename_exchange.c
Normal file
37
tools/testing/selftests/filesystems/fat/rename_exchange.c
Normal file
@ -0,0 +1,37 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Program that atomically exchanges two paths using
|
||||
* the renameat2() system call RENAME_EXCHANGE flag.
|
||||
*
|
||||
* Copyright 2022 Red Hat Inc.
|
||||
* Author: Javier Martinez Canillas <javierm@redhat.com>
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void print_usage(const char *program)
|
||||
{
|
||||
printf("Usage: %s [oldpath] [newpath]\n", program);
|
||||
printf("Atomically exchange oldpath and newpath\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (argc != 3) {
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ret = renameat2(AT_FDCWD, argv[1], AT_FDCWD, argv[2], RENAME_EXCHANGE);
|
||||
if (ret) {
|
||||
perror("rename exchange failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
82
tools/testing/selftests/filesystems/fat/run_fat_tests.sh
Normal file
82
tools/testing/selftests/filesystems/fat/run_fat_tests.sh
Normal file
@ -0,0 +1,82 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Run filesystem operations tests on an 1 MiB disk image that is formatted with
|
||||
# a vfat filesystem and mounted in a temporary directory using a loop device.
|
||||
#
|
||||
# Copyright 2022 Red Hat Inc.
|
||||
# Author: Javier Martinez Canillas <javierm@redhat.com>
|
||||
|
||||
set -e
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
BASE_DIR="$(dirname $0)"
|
||||
TMP_DIR="$(mktemp -d /tmp/fat_tests_tmp.XXXX)"
|
||||
IMG_PATH="${TMP_DIR}/fat.img"
|
||||
MNT_PATH="${TMP_DIR}/mnt"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
mountpoint -q "${MNT_PATH}" && unmount_image
|
||||
rm -rf "${TMP_DIR}"
|
||||
}
|
||||
trap cleanup SIGINT SIGTERM EXIT
|
||||
|
||||
create_loopback()
|
||||
{
|
||||
touch "${IMG_PATH}"
|
||||
chattr +C "${IMG_PATH}" >/dev/null 2>&1 || true
|
||||
|
||||
truncate -s 1M "${IMG_PATH}"
|
||||
mkfs.vfat "${IMG_PATH}" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
mount_image()
|
||||
{
|
||||
mkdir -p "${MNT_PATH}"
|
||||
sudo mount -o loop "${IMG_PATH}" "${MNT_PATH}"
|
||||
}
|
||||
|
||||
rename_exchange_test()
|
||||
{
|
||||
local rename_exchange="${BASE_DIR}/rename_exchange"
|
||||
local old_path="${MNT_PATH}/old_file"
|
||||
local new_path="${MNT_PATH}/new_file"
|
||||
|
||||
echo old | sudo tee "${old_path}" >/dev/null 2>&1
|
||||
echo new | sudo tee "${new_path}" >/dev/null 2>&1
|
||||
sudo "${rename_exchange}" "${old_path}" "${new_path}" >/dev/null 2>&1
|
||||
sudo sync -f "${MNT_PATH}"
|
||||
grep new "${old_path}" >/dev/null 2>&1
|
||||
grep old "${new_path}" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
rename_exchange_subdir_test()
|
||||
{
|
||||
local rename_exchange="${BASE_DIR}/rename_exchange"
|
||||
local dir_path="${MNT_PATH}/subdir"
|
||||
local old_path="${MNT_PATH}/old_file"
|
||||
local new_path="${dir_path}/new_file"
|
||||
|
||||
sudo mkdir -p "${dir_path}"
|
||||
echo old | sudo tee "${old_path}" >/dev/null 2>&1
|
||||
echo new | sudo tee "${new_path}" >/dev/null 2>&1
|
||||
sudo "${rename_exchange}" "${old_path}" "${new_path}" >/dev/null 2>&1
|
||||
sudo sync -f "${MNT_PATH}"
|
||||
grep new "${old_path}" >/dev/null 2>&1
|
||||
grep old "${new_path}" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
unmount_image()
|
||||
{
|
||||
sudo umount "${MNT_PATH}" &> /dev/null
|
||||
}
|
||||
|
||||
create_loopback
|
||||
mount_image
|
||||
rename_exchange_test
|
||||
rename_exchange_subdir_test
|
||||
unmount_image
|
||||
|
||||
exit 0
|
Loading…
Reference in New Issue
Block a user