diff options
| author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2025-12-12 20:37:22 +0300 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2025-12-12 20:37:22 +0300 |
| commit | afab69dcd2367d658853a3520fb06d356ccabb7f (patch) | |
| tree | eadb66b0176308a9e57480f0675d81ef05b5d776 /fs | |
| parent | 9319aefb0f8805af379d375403b5ba48a0d3ef1b (diff) | |
| parent | 53d3c6ddbb9749ebc06956a13ed6eead31402a7d (diff) | |
| download | linux-rolling-lts.tar.xz | |
Merge v6.12.62linux-rolling-lts
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/bfs/inode.c | 19 | ||||
| -rw-r--r-- | fs/ext4/inline.c | 14 | ||||
| -rw-r--r-- | fs/jbd2/transaction.c | 19 | ||||
| -rw-r--r-- | fs/namespace.c | 7 | ||||
| -rw-r--r-- | fs/nfsd/nfs4state.c | 6 | ||||
| -rw-r--r-- | fs/smb/client/connect.c | 1 | ||||
| -rw-r--r-- | fs/smb/client/fs_context.c | 2 | ||||
| -rw-r--r-- | fs/smb/server/transport_ipc.c | 7 |
8 files changed, 59 insertions, 16 deletions
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index db81570c9637..ecf7f74779c6 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -60,7 +60,19 @@ struct inode *bfs_iget(struct super_block *sb, unsigned long ino) off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK; di = (struct bfs_inode *)bh->b_data + off; - inode->i_mode = 0x0000FFFF & le32_to_cpu(di->i_mode); + /* + * https://martin.hinner.info/fs/bfs/bfs-structure.html explains that + * BFS in SCO UnixWare environment used only lower 9 bits of di->i_mode + * value. This means that, although bfs_write_inode() saves whole + * inode->i_mode bits (which include S_IFMT bits and S_IS{UID,GID,VTX} + * bits), middle 7 bits of di->i_mode value can be garbage when these + * bits were not saved by bfs_write_inode(). + * Since we can't tell whether middle 7 bits are garbage, use only + * lower 12 bits (i.e. tolerate S_IS{UID,GID,VTX} bits possibly being + * garbage) and reconstruct S_IFMT bits for Linux environment from + * di->i_vtype value. + */ + inode->i_mode = 0x00000FFF & le32_to_cpu(di->i_mode); if (le32_to_cpu(di->i_vtype) == BFS_VDIR) { inode->i_mode |= S_IFDIR; inode->i_op = &bfs_dir_inops; @@ -70,6 +82,11 @@ struct inode *bfs_iget(struct super_block *sb, unsigned long ino) inode->i_op = &bfs_file_inops; inode->i_fop = &bfs_file_operations; inode->i_mapping->a_ops = &bfs_aops; + } else { + brelse(bh); + printf("Unknown vtype=%u %s:%08lx\n", + le32_to_cpu(di->i_vtype), inode->i_sb->s_id, ino); + goto error; } BFS_I(inode)->i_sblock = le32_to_cpu(di->i_sblock); diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 9fb5e0f172a7..bb0e46130beb 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -413,7 +413,12 @@ static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, return -ENOSPC; ext4_write_lock_xattr(inode, &no_expand); - + /* + * ei->i_inline_size may have changed since the initial check + * if other xattrs were added. Recalculate to ensure + * ext4_update_inline_data() validates against current capacity. + */ + (void) ext4_find_inline_data_nolock(inode); if (ei->i_inline_off) ret = ext4_update_inline_data(handle, inode, len); else @@ -441,9 +446,13 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle, if (!ei->i_inline_off) return 0; + down_write(&ei->i_data_sem); + error = ext4_get_inode_loc(inode, &is.iloc); - if (error) + if (error) { + up_write(&ei->i_data_sem); return error; + } error = ext4_xattr_ibody_find(inode, &i, &is); if (error) @@ -482,6 +491,7 @@ out: brelse(is.iloc.bh); if (error == -ENODATA) error = 0; + up_write(&ei->i_data_sem); return error; } diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index ae43920ce395..c50bec6e5405 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1288,14 +1288,23 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) * committing transaction's lists, but it HAS to be in Forget state in * that case: the transaction must have deleted the buffer for it to be * reused here. + * In the case of file system data inconsistency, for example, if the + * block bitmap of a referenced block is not set, it can lead to the + * situation where a block being committed is allocated and used again. + * As a result, the following condition will not be satisfied, so here + * we directly trigger a JBD abort instead of immediately invoking + * bugon. */ spin_lock(&jh->b_state_lock); - J_ASSERT_JH(jh, (jh->b_transaction == transaction || - jh->b_transaction == NULL || - (jh->b_transaction == journal->j_committing_transaction && - jh->b_jlist == BJ_Forget))); + if (!(jh->b_transaction == transaction || jh->b_transaction == NULL || + (jh->b_transaction == journal->j_committing_transaction && + jh->b_jlist == BJ_Forget)) || jh->b_next_transaction != NULL) { + err = -EROFS; + spin_unlock(&jh->b_state_lock); + jbd2_journal_abort(journal, err); + goto out; + } - J_ASSERT_JH(jh, jh->b_next_transaction == NULL); J_ASSERT_JH(jh, buffer_locked(jh2bh(jh))); if (jh->b_transaction == NULL) { diff --git a/fs/namespace.c b/fs/namespace.c index 035d6f1f0b6e..c3702f3303a8 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -5345,6 +5345,8 @@ static struct mnt_namespace *grab_requested_mnt_ns(const struct mnt_id_req *kreq if (kreq->mnt_ns_id) { mnt_ns = lookup_mnt_ns(kreq->mnt_ns_id); + if (!mnt_ns) + return ERR_PTR(-ENOENT); } else if (kreq->mnt_ns_fd) { struct ns_common *ns; @@ -5360,13 +5362,12 @@ static struct mnt_namespace *grab_requested_mnt_ns(const struct mnt_id_req *kreq return ERR_PTR(-EINVAL); mnt_ns = to_mnt_ns(ns); + refcount_inc(&mnt_ns->passive); } else { mnt_ns = current->nsproxy->mnt_ns; + refcount_inc(&mnt_ns->passive); } - if (!mnt_ns) - return ERR_PTR(-ENOENT); - refcount_inc(&mnt_ns->passive); return mnt_ns; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e1ab8be40e0f..f7aa63f82bf7 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1984,8 +1984,10 @@ static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn */ scale_factor = max_t(unsigned int, 8, nn->nfsd_serv->sv_nrthreads); - avail = clamp_t(unsigned long, avail, slotsize, - total_avail/scale_factor); + if (avail > total_avail / scale_factor) + avail = total_avail / scale_factor; + else if (avail < slotsize) + avail = slotsize; num = min_t(int, num, avail / slotsize); num = max_t(int, num, 1); nfsd_drc_mem_used += num * slotsize; diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 0d4c811e0334..3b0f63e0a253 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -4227,6 +4227,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) out: kfree(ctx->username); + kfree(ctx->domainname); kfree_sensitive(ctx->password); kfree(origin_fullpath); kfree(ctx); diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index 9a4492106c25..17133adfe798 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -1415,7 +1415,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, break; } - if (strnlen(param->string, CIFS_MAX_USERNAME_LEN) > + if (strnlen(param->string, CIFS_MAX_USERNAME_LEN) == CIFS_MAX_USERNAME_LEN) { pr_warn("username too long\n"); goto cifs_parse_mount_err; diff --git a/fs/smb/server/transport_ipc.c b/fs/smb/server/transport_ipc.c index ce5c50ac987c..52a71775b38e 100644 --- a/fs/smb/server/transport_ipc.c +++ b/fs/smb/server/transport_ipc.c @@ -553,12 +553,16 @@ static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle up_write(&ipc_msg_table_lock); ret = ipc_msg_send(msg); - if (ret) + if (ret) { + down_write(&ipc_msg_table_lock); goto out; + } ret = wait_event_interruptible_timeout(entry.wait, entry.response != NULL, IPC_WAIT_TIMEOUT); + + down_write(&ipc_msg_table_lock); if (entry.response) { ret = ipc_validate_msg(&entry); if (ret) { @@ -567,7 +571,6 @@ static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle } } out: - down_write(&ipc_msg_table_lock); hash_del(&entry.ipc_table_hlist); up_write(&ipc_msg_table_lock); return entry.response; |
