mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/
synced 2026-04-18 06:33:43 -04:00
Merge tag 'mm-nonmm-stable-2025-10-02-15-29' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
Pull non-MM updates from Andrew Morton: - "ida: Remove the ida_simple_xxx() API" from Christophe Jaillet completes the removal of this legacy IDR API - "panic: introduce panic status function family" from Jinchao Wang provides a number of cleanups to the panic code and its various helpers, which were rather ad-hoc and scattered all over the place - "tools/delaytop: implement real-time keyboard interaction support" from Fan Yu adds a few nice user-facing usability changes to the delaytop monitoring tool - "efi: Fix EFI boot with kexec handover (KHO)" from Evangelos Petrongonas fixes a panic which was happening with the combination of EFI and KHO - "Squashfs: performance improvement and a sanity check" from Phillip Lougher teaches squashfs's lseek() about SEEK_DATA/SEEK_HOLE. A mere 150x speedup was measured for a well-chosen microbenchmark - plus another 50-odd singleton patches all over the place * tag 'mm-nonmm-stable-2025-10-02-15-29' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (75 commits) Squashfs: reject negative file sizes in squashfs_read_inode() kallsyms: use kmalloc_array() instead of kmalloc() MAINTAINERS: update Sibi Sankar's email address Squashfs: add SEEK_DATA/SEEK_HOLE support Squashfs: add additional inode sanity checking lib/genalloc: fix device leak in of_gen_pool_get() panic: remove CONFIG_PANIC_ON_OOPS_VALUE ocfs2: fix double free in user_cluster_connect() checkpatch: suppress strscpy warnings for userspace tools cramfs: fix incorrect physical page address calculation kernel: prevent prctl(PR_SET_PDEATHSIG) from racing with parent process exit Squashfs: fix uninit-value in squashfs_get_parent kho: only fill kimage if KHO is finalized ocfs2: avoid extra calls to strlen() after ocfs2_sprintf_system_inode_name() kernel/sys.c: fix the racy usage of task_lock(tsk->group_leader) in sys_prlimit64() paths sched/task.h: fix the wrong comment on task_lock() nesting with tasklist_lock coccinelle: platform_no_drv_owner: handle also built-in drivers coccinelle: of_table: handle SPI device ID tables lib/decompress: use designated initializers for struct compress_format efi: support booting with kexec handover (KHO) ...
This commit is contained in:
@@ -307,7 +307,8 @@ static int fill_meta_index(struct inode *inode, int index,
|
||||
all_done:
|
||||
*index_block = cur_index_block;
|
||||
*index_offset = cur_offset;
|
||||
*data_block = cur_data_block;
|
||||
if (data_block)
|
||||
*data_block = cur_data_block;
|
||||
|
||||
/*
|
||||
* Scale cache index (cache slot entry) to index
|
||||
@@ -324,17 +325,15 @@ failed:
|
||||
* Get the on-disk location and compressed size of the datablock
|
||||
* specified by index. Fill_meta_index() does most of the work.
|
||||
*/
|
||||
static int read_blocklist(struct inode *inode, int index, u64 *block)
|
||||
static int read_blocklist_ptrs(struct inode *inode, int index, u64 *start,
|
||||
int *offset, u64 *block)
|
||||
{
|
||||
u64 start;
|
||||
long long blks;
|
||||
int offset;
|
||||
__le32 size;
|
||||
int res = fill_meta_index(inode, index, &start, &offset, block);
|
||||
int res = fill_meta_index(inode, index, start, offset, block);
|
||||
|
||||
TRACE("read_blocklist: res %d, index %d, start 0x%llx, offset"
|
||||
" 0x%x, block 0x%llx\n", res, index, start, offset,
|
||||
*block);
|
||||
TRACE("read_blocklist: res %d, index %d, start 0x%llx, offset 0x%x, block 0x%llx\n",
|
||||
res, index, *start, *offset, block ? *block : 0);
|
||||
|
||||
if (res < 0)
|
||||
return res;
|
||||
@@ -346,22 +345,31 @@ static int read_blocklist(struct inode *inode, int index, u64 *block)
|
||||
* extra block indexes needed.
|
||||
*/
|
||||
if (res < index) {
|
||||
blks = read_indexes(inode->i_sb, index - res, &start, &offset);
|
||||
blks = read_indexes(inode->i_sb, index - res, start, offset);
|
||||
if (blks < 0)
|
||||
return (int) blks;
|
||||
*block += blks;
|
||||
if (block)
|
||||
*block += blks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read length of block specified by index.
|
||||
*/
|
||||
res = squashfs_read_metadata(inode->i_sb, &size, &start, &offset,
|
||||
res = squashfs_read_metadata(inode->i_sb, &size, start, offset,
|
||||
sizeof(size));
|
||||
if (res < 0)
|
||||
return res;
|
||||
return squashfs_block_size(size);
|
||||
}
|
||||
|
||||
static inline int read_blocklist(struct inode *inode, int index, u64 *block)
|
||||
{
|
||||
u64 start;
|
||||
int offset;
|
||||
|
||||
return read_blocklist_ptrs(inode, index, &start, &offset, block);
|
||||
}
|
||||
|
||||
static bool squashfs_fill_page(struct folio *folio,
|
||||
struct squashfs_cache_entry *buffer, size_t offset,
|
||||
size_t avail)
|
||||
@@ -658,7 +666,114 @@ skip_pages:
|
||||
kfree(pages);
|
||||
}
|
||||
|
||||
static loff_t seek_hole_data(struct file *file, loff_t offset, int whence)
|
||||
{
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
u64 start, index = offset >> msblk->block_log;
|
||||
u64 file_end = (i_size_read(inode) + msblk->block_size - 1) >> msblk->block_log;
|
||||
int s_offset, length;
|
||||
__le32 *blist = NULL;
|
||||
|
||||
/* reject offset if negative or beyond file end */
|
||||
if ((unsigned long long)offset >= i_size_read(inode))
|
||||
return -ENXIO;
|
||||
|
||||
/* is offset within tailend and is tailend packed into a fragment? */
|
||||
if (index + 1 == file_end &&
|
||||
squashfs_i(inode)->fragment_block != SQUASHFS_INVALID_BLK) {
|
||||
if (whence == SEEK_DATA)
|
||||
return offset;
|
||||
|
||||
/* there is an implicit hole at the end of any file */
|
||||
return i_size_read(inode);
|
||||
}
|
||||
|
||||
length = read_blocklist_ptrs(inode, index, &start, &s_offset, NULL);
|
||||
if (length < 0)
|
||||
return length;
|
||||
|
||||
/* nothing more to do if offset matches desired whence value */
|
||||
if ((length == 0 && whence == SEEK_HOLE) ||
|
||||
(length && whence == SEEK_DATA))
|
||||
return offset;
|
||||
|
||||
/* skip scanning forwards if we're at file end */
|
||||
if (++ index == file_end)
|
||||
goto not_found;
|
||||
|
||||
blist = kmalloc(SQUASHFS_SCAN_INDEXES << 2, GFP_KERNEL);
|
||||
if (blist == NULL) {
|
||||
ERROR("%s: Failed to allocate block_list\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
while (index < file_end) {
|
||||
int i, indexes = min(file_end - index, SQUASHFS_SCAN_INDEXES);
|
||||
|
||||
offset = squashfs_read_metadata(sb, blist, &start, &s_offset, indexes << 2);
|
||||
if (offset < 0)
|
||||
goto finished;
|
||||
|
||||
for (i = 0; i < indexes; i++) {
|
||||
length = squashfs_block_size(blist[i]);
|
||||
if (length < 0) {
|
||||
offset = length;
|
||||
goto finished;
|
||||
}
|
||||
|
||||
/* does this block match desired whence value? */
|
||||
if ((length == 0 && whence == SEEK_HOLE) ||
|
||||
(length && whence == SEEK_DATA)) {
|
||||
offset = (index + i) << msblk->block_log;
|
||||
goto finished;
|
||||
}
|
||||
}
|
||||
|
||||
index += indexes;
|
||||
}
|
||||
|
||||
not_found:
|
||||
/* whence value determines what happens */
|
||||
if (whence == SEEK_DATA)
|
||||
offset = -ENXIO;
|
||||
else
|
||||
/* there is an implicit hole at the end of any file */
|
||||
offset = i_size_read(inode);
|
||||
|
||||
finished:
|
||||
kfree(blist);
|
||||
return offset;
|
||||
}
|
||||
|
||||
static loff_t squashfs_llseek(struct file *file, loff_t offset, int whence)
|
||||
{
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
|
||||
switch (whence) {
|
||||
default:
|
||||
return generic_file_llseek(file, offset, whence);
|
||||
case SEEK_DATA:
|
||||
case SEEK_HOLE:
|
||||
offset = seek_hole_data(file, offset, whence);
|
||||
break;
|
||||
}
|
||||
|
||||
if (offset < 0)
|
||||
return offset;
|
||||
|
||||
return vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
|
||||
}
|
||||
|
||||
const struct address_space_operations squashfs_aops = {
|
||||
.read_folio = squashfs_read_folio,
|
||||
.readahead = squashfs_readahead
|
||||
};
|
||||
|
||||
const struct file_operations squashfs_file_operations = {
|
||||
.llseek = squashfs_llseek,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.mmap_prepare = generic_file_readonly_mmap_prepare,
|
||||
.splice_read = filemap_splice_read
|
||||
};
|
||||
|
||||
@@ -68,6 +68,10 @@ static int squashfs_new_inode(struct super_block *sb, struct inode *inode,
|
||||
inode->i_mode = le16_to_cpu(sqsh_ino->mode);
|
||||
inode->i_size = 0;
|
||||
|
||||
/* File type must not be set at this moment, for it will later be set by the caller. */
|
||||
if (inode->i_mode & S_IFMT)
|
||||
err = -EIO;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -140,8 +144,17 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
inode->i_size = le32_to_cpu(sqsh_ino->file_size);
|
||||
frag = le32_to_cpu(sqsh_ino->fragment);
|
||||
if (frag != SQUASHFS_INVALID_FRAG) {
|
||||
/*
|
||||
* the file cannot have a fragment (tailend) and have a
|
||||
* file size a multiple of the block size
|
||||
*/
|
||||
if ((inode->i_size & (msblk->block_size - 1)) == 0) {
|
||||
err = -EINVAL;
|
||||
goto failed_read;
|
||||
}
|
||||
frag_offset = le32_to_cpu(sqsh_ino->offset);
|
||||
frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
|
||||
if (frag_size < 0) {
|
||||
@@ -155,8 +168,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
}
|
||||
|
||||
set_nlink(inode, 1);
|
||||
inode->i_size = le32_to_cpu(sqsh_ino->file_size);
|
||||
inode->i_fop = &generic_ro_fops;
|
||||
inode->i_fop = &squashfs_file_operations;
|
||||
inode->i_mode |= S_IFREG;
|
||||
inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
|
||||
squashfs_i(inode)->fragment_block = frag_blk;
|
||||
@@ -165,6 +177,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
|
||||
squashfs_i(inode)->block_list_start = block;
|
||||
squashfs_i(inode)->offset = offset;
|
||||
squashfs_i(inode)->parent = 0;
|
||||
inode->i_data.a_ops = &squashfs_aops;
|
||||
|
||||
TRACE("File inode %x:%x, start_block %llx, block_list_start "
|
||||
@@ -183,8 +196,21 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
inode->i_size = le64_to_cpu(sqsh_ino->file_size);
|
||||
if (inode->i_size < 0) {
|
||||
err = -EINVAL;
|
||||
goto failed_read;
|
||||
}
|
||||
frag = le32_to_cpu(sqsh_ino->fragment);
|
||||
if (frag != SQUASHFS_INVALID_FRAG) {
|
||||
/*
|
||||
* the file cannot have a fragment (tailend) and have a
|
||||
* file size a multiple of the block size
|
||||
*/
|
||||
if ((inode->i_size & (msblk->block_size - 1)) == 0) {
|
||||
err = -EINVAL;
|
||||
goto failed_read;
|
||||
}
|
||||
frag_offset = le32_to_cpu(sqsh_ino->offset);
|
||||
frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
|
||||
if (frag_size < 0) {
|
||||
@@ -199,9 +225,8 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
|
||||
xattr_id = le32_to_cpu(sqsh_ino->xattr);
|
||||
set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
|
||||
inode->i_size = le64_to_cpu(sqsh_ino->file_size);
|
||||
inode->i_op = &squashfs_inode_ops;
|
||||
inode->i_fop = &generic_ro_fops;
|
||||
inode->i_fop = &squashfs_file_operations;
|
||||
inode->i_mode |= S_IFREG;
|
||||
inode->i_blocks = (inode->i_size -
|
||||
le64_to_cpu(sqsh_ino->sparse) + 511) >> 9;
|
||||
@@ -212,6 +237,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
squashfs_i(inode)->start = le64_to_cpu(sqsh_ino->start_block);
|
||||
squashfs_i(inode)->block_list_start = block;
|
||||
squashfs_i(inode)->offset = offset;
|
||||
squashfs_i(inode)->parent = 0;
|
||||
inode->i_data.a_ops = &squashfs_aops;
|
||||
|
||||
TRACE("File inode %x:%x, start_block %llx, block_list_start "
|
||||
@@ -292,6 +318,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
inode->i_mode |= S_IFLNK;
|
||||
squashfs_i(inode)->start = block;
|
||||
squashfs_i(inode)->offset = offset;
|
||||
squashfs_i(inode)->parent = 0;
|
||||
|
||||
if (type == SQUASHFS_LSYMLINK_TYPE) {
|
||||
__le32 xattr;
|
||||
@@ -329,6 +356,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
|
||||
rdev = le32_to_cpu(sqsh_ino->rdev);
|
||||
init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
|
||||
squashfs_i(inode)->parent = 0;
|
||||
|
||||
TRACE("Device inode %x:%x, rdev %x\n",
|
||||
SQUASHFS_INODE_BLK(ino), offset, rdev);
|
||||
@@ -353,6 +381,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
|
||||
rdev = le32_to_cpu(sqsh_ino->rdev);
|
||||
init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
|
||||
squashfs_i(inode)->parent = 0;
|
||||
|
||||
TRACE("Device inode %x:%x, rdev %x\n",
|
||||
SQUASHFS_INODE_BLK(ino), offset, rdev);
|
||||
@@ -373,6 +402,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
inode->i_mode |= S_IFSOCK;
|
||||
set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
|
||||
init_special_inode(inode, inode->i_mode, 0);
|
||||
squashfs_i(inode)->parent = 0;
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LFIFO_TYPE:
|
||||
@@ -392,6 +422,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
inode->i_op = &squashfs_inode_ops;
|
||||
set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
|
||||
init_special_inode(inode, inode->i_mode, 0);
|
||||
squashfs_i(inode)->parent = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -107,6 +107,7 @@ extern const struct address_space_operations squashfs_aops;
|
||||
|
||||
/* inode.c */
|
||||
extern const struct inode_operations squashfs_inode_ops;
|
||||
extern const struct file_operations squashfs_file_operations;
|
||||
|
||||
/* namei.c */
|
||||
extern const struct inode_operations squashfs_dir_inode_ops;
|
||||
|
||||
@@ -208,6 +208,7 @@ static inline int squashfs_block_size(__le32 raw)
|
||||
#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
|
||||
#define SQUASHFS_META_ENTRIES 127
|
||||
#define SQUASHFS_META_SLOTS 8
|
||||
#define SQUASHFS_SCAN_INDEXES 1024
|
||||
|
||||
struct meta_entry {
|
||||
u64 data_block;
|
||||
|
||||
@@ -16,6 +16,7 @@ struct squashfs_inode_info {
|
||||
u64 xattr;
|
||||
unsigned int xattr_size;
|
||||
int xattr_count;
|
||||
int parent;
|
||||
union {
|
||||
struct {
|
||||
u64 fragment_block;
|
||||
@@ -27,7 +28,6 @@ struct squashfs_inode_info {
|
||||
u64 dir_idx_start;
|
||||
int dir_idx_offset;
|
||||
int dir_idx_cnt;
|
||||
int parent;
|
||||
};
|
||||
};
|
||||
struct inode vfs_inode;
|
||||
|
||||
Reference in New Issue
Block a user