From 4248d3d5bb21f081174957c754b6a7baac69a6c1 Mon Sep 17 00:00:00 2001 From: almalinux-bot-kernel Date: Thu, 12 Mar 2026 04:35:23 +0000 Subject: [PATCH] Import of kernel-4.18.0-553.111.1.el8_10 --- Makefile.rhelver | 2 +- drivers/net/macvlan.c | 21 ++++++++++++++------- drivers/video/fbdev/core/fbcon.c | 3 +++ fs/fs_struct.c | 26 +++++++++++++++++++++----- fs/namespace.c | 8 ++++++++ fs/nfs/pnfs.c | 3 ++- include/linux/fs_struct.h | 28 ++++++++++++++++++++++++++++ kernel/auditsc.c | 7 +++++-- net/ipv6/calipso.c | 3 ++- 9 files changed, 84 insertions(+), 17 deletions(-) diff --git a/Makefile.rhelver b/Makefile.rhelver index 9a7274c2ad..4ad74d2e67 100644 --- a/Makefile.rhelver +++ b/Makefile.rhelver @@ -12,7 +12,7 @@ RHEL_MINOR = 10 # # Use this spot to avoid future merge conflicts. # Do not trim this comment. -RHEL_RELEASE = 553.109.1 +RHEL_RELEASE = 553.111.1 # # ZSTREAM diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index cd792205a6..def83a317a 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -62,7 +62,7 @@ struct macvlan_port { struct macvlan_source_entry { struct hlist_node hlist; - struct macvlan_dev *vlan; + struct macvlan_dev __rcu *vlan; unsigned char addr[6+2] __aligned(sizeof(u16)); struct rcu_head rcu; }; @@ -150,7 +150,7 @@ static struct macvlan_source_entry *macvlan_hash_lookup_source( hlist_for_each_entry_rcu(entry, h, hlist, lockdep_rtnl_is_held()) { if (ether_addr_equal_64bits(entry->addr, addr) && - entry->vlan == vlan) + rcu_access_pointer(entry->vlan) == vlan) return entry; } return NULL; @@ -172,7 +172,7 @@ static int macvlan_hash_add_source(struct macvlan_dev *vlan, return -ENOMEM; ether_addr_copy(entry->addr, addr); - entry->vlan = vlan; + RCU_INIT_POINTER(entry->vlan, vlan); h = &port->vlan_source_hash[macvlan_eth_hash(addr)]; hlist_add_head_rcu(&entry->hlist, h); vlan->macaddr_count++; @@ -191,6 +191,7 @@ static void macvlan_hash_add(struct macvlan_dev *vlan) static void macvlan_hash_del_source(struct macvlan_source_entry *entry) { + RCU_INIT_POINTER(entry->vlan, NULL); hlist_del_rcu(&entry->hlist); kfree_rcu(entry, rcu); } @@ -402,7 +403,7 @@ static void macvlan_flush_sources(struct macvlan_port *port, entry = hlist_entry(h, struct macvlan_source_entry, hlist); - if (entry->vlan == vlan) + if (rcu_access_pointer(entry->vlan) == vlan) macvlan_hash_del_source(entry); } } @@ -444,8 +445,14 @@ static void macvlan_forward_source(struct sk_buff *skb, struct hlist_head *h = &port->vlan_source_hash[idx]; hlist_for_each_entry_rcu(entry, h, hlist) { - if (ether_addr_equal_64bits(entry->addr, addr)) - macvlan_forward_source_one(skb, entry->vlan); + if (ether_addr_equal_64bits(entry->addr, addr)) { + struct macvlan_dev *vlan = rcu_dereference(entry->vlan); + + if (!vlan) + continue; + + macvlan_forward_source_one(skb, vlan); + } } } @@ -1677,7 +1684,7 @@ static int macvlan_fill_info_macaddr(struct sk_buff *skb, struct macvlan_source_entry *entry; hlist_for_each_entry_rcu(entry, h, hlist, lockdep_rtnl_is_held()) { - if (entry->vlan != vlan) + if (rcu_access_pointer(entry->vlan) != vlan) continue; if (nla_put(skb, IFLA_MACVLAN_MACADDR, ETH_ALEN, entry->addr)) return 1; diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 062a18ecb8..916517a912 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -1016,6 +1016,7 @@ static void fbcon_init(struct vc_data *vc, int init) fvc->vc_font.data); vc->vc_font.width = fvc->vc_font.width; vc->vc_font.height = fvc->vc_font.height; + vc->vc_font.charcount = fvc->vc_font.charcount; p->userfont = t->userfont; if (p->userfont) @@ -1346,6 +1347,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, vc->vc_font.data = (void *)(p->fontdata = t->fontdata); vc->vc_font.width = (*default_mode)->vc_font.width; vc->vc_font.height = (*default_mode)->vc_font.height; + vc->vc_font.charcount = (*default_mode)->vc_font.charcount; p->userfont = t->userfont; if (p->userfont) REFCOUNT(p->fontdata)++; @@ -2397,6 +2399,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, REFCOUNT(data)++; vc->vc_font.width = w; vc->vc_font.height = h; + vc->vc_font.charcount = cnt; if (vc->vc_hi_font_mask && cnt == 256) set_vc_hi_font(vc, false); else if (!vc->vc_hi_font_mask && cnt == 512) diff --git a/fs/fs_struct.c b/fs/fs_struct.c index 087f7ffda2..9adf39f33c 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c @@ -35,17 +35,21 @@ void set_fs_root(struct fs_struct *fs, const struct path *path) void set_fs_pwd(struct fs_struct *fs, const struct path *path) { struct path old_pwd; + int count; path_get(path); spin_lock(&fs->lock); write_seqcount_begin(&fs->seq); old_pwd = fs->pwd; fs->pwd = *path; + count = fs->pwd_refs + 1; + fs->pwd_refs = 0; write_seqcount_end(&fs->seq); spin_unlock(&fs->lock); if (old_pwd.dentry) - path_put(&old_pwd); + while (count--) + path_put(&old_pwd); } static inline int replace_path(struct path *p, const struct path *old, const struct path *new) @@ -67,11 +71,16 @@ void chroot_fs_refs(const struct path *old_root, const struct path *new_root) task_lock(p); fs = p->fs; if (fs) { - int hits = 0; + int hits; + spin_lock(&fs->lock); write_seqcount_begin(&fs->seq); + hits = replace_path(&fs->pwd, old_root, new_root); + if (hits && fs->pwd_refs) { + count += fs->pwd_refs; + fs->pwd_refs = 0; + } hits += replace_path(&fs->root, old_root, new_root); - hits += replace_path(&fs->pwd, old_root, new_root); write_seqcount_end(&fs->seq); while (hits--) { count++; @@ -88,8 +97,11 @@ void chroot_fs_refs(const struct path *old_root, const struct path *new_root) void free_fs_struct(struct fs_struct *fs) { + int count = fs->pwd_refs + 1; + path_put(&fs->root); - path_put(&fs->pwd); + while (count--) + path_put(&fs->pwd); kmem_cache_free(fs_cachep, fs); } @@ -117,6 +129,7 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old) if (fs) { fs->users = 1; fs->in_exec = 0; + fs->pwd_refs = 0; spin_lock_init(&fs->lock); seqcount_init(&fs->seq); fs->umask = old->umask; @@ -125,7 +138,10 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old) fs->root = old->root; path_get(&fs->root); fs->pwd = old->pwd; - path_get(&fs->pwd); + if (old->pwd_refs) + old->pwd_refs--; + else + path_get(&fs->pwd); spin_unlock(&old->lock); } return fs; diff --git a/fs/namespace.c b/fs/namespace.c index 5fa6f0a8d1..35196b9e45 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -3302,6 +3302,14 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, * as belonging to new namespace. We have already acquired a private * fs_struct, so tsk->fs->lock is not needed. */ + if (new_fs) + WARN_ON_ONCE(new_fs->users != 1); + + /* Release the extra pwd references of new_fs, if present. */ + while (new_fs && new_fs->pwd_refs) { + path_put(&new_fs->pwd); + new_fs->pwd_refs--; + } p = old; q = new; while (p) { diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index abd4e8c52b..ad6ea767d3 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -464,7 +464,8 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, }; struct pnfs_layout_segment *lseg, *next; - set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); + if (test_and_set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) + return !list_empty(&lo->plh_segs); clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags); list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) pnfs_clear_lseg_state(lseg, lseg_list); diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h index cf1015abfb..22e47d6f3c 100644 --- a/include/linux/fs_struct.h +++ b/include/linux/fs_struct.h @@ -12,6 +12,7 @@ struct fs_struct { seqcount_t seq; int umask; int in_exec; + RH_KABI_FILL_HOLE(int pwd_refs) /* A pool of extra pwd references */ struct path root, pwd; } __randomize_layout; @@ -40,6 +41,33 @@ static inline void get_fs_pwd(struct fs_struct *fs, struct path *pwd) spin_unlock(&fs->lock); } +/* Acquire a pwd reference from the pwd_refs pool, if available */ +static inline void get_fs_pwd_pool(struct fs_struct *fs, struct path *pwd) +{ + spin_lock(&fs->lock); + *pwd = fs->pwd; + if (fs->pwd_refs) + fs->pwd_refs--; + else + path_get(pwd); + spin_unlock(&fs->lock); +} + +/* Release a pwd reference back to the pwd_refs pool, if appropriate */ +static inline void put_fs_pwd_pool(struct fs_struct *fs, struct path *pwd) +{ + bool put = false; + + spin_lock(&fs->lock); + if ((fs->pwd.dentry == pwd->dentry) && (fs->pwd.mnt == pwd->mnt)) + fs->pwd_refs++; + else + put = true; + spin_unlock(&fs->lock); + if (put) + path_put(pwd); +} + extern bool current_chrooted(void); #endif /* _LINUX_FS_STRUCT_H */ diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 2e85698c02..127f16a762 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -887,6 +887,9 @@ static inline void audit_free_names(struct audit_context *context) { struct audit_names *n, *next; + if (!context->name_count) + return; /* audit_alloc_name() has not been called */ + list_for_each_entry_safe(n, next, &context->names_list, list) { list_del(&n->list); if (n->name) @@ -895,7 +898,7 @@ static inline void audit_free_names(struct audit_context *context) kfree(n); } context->name_count = 0; - path_put(&context->pwd); + put_fs_pwd_pool(current->fs, &context->pwd); context->pwd.dentry = NULL; context->pwd.mnt = NULL; } @@ -2000,7 +2003,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context, context->name_count++; if (!context->pwd.dentry) - get_fs_pwd(current->fs, &context->pwd); + get_fs_pwd_pool(current->fs, &context->pwd); return aname; } diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c index afc76062e1..ee0963a08e 100644 --- a/net/ipv6/calipso.c +++ b/net/ipv6/calipso.c @@ -1336,7 +1336,8 @@ static int calipso_skbuff_setattr(struct sk_buff *skb, /* At this point new_end aligns to 4n, so (new_end & 4) pads to 8n */ pad = ((new_end & 4) + (end & 7)) & 7; len_delta = new_end - (int)end + pad; - ret_val = skb_cow(skb, skb_headroom(skb) + len_delta); + ret_val = skb_cow(skb, + skb_headroom(skb) + (len_delta > 0 ? len_delta : 0)); if (ret_val < 0) return ret_val;