From 27600805e62f800bacf990354632eae4e487d34c Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Thu, 3 Sep 2026 10:43:25 -0500 Subject: x86/amd_node: Fix PCI device reference counting in amd_smn_init() The local "root" pointer is a temporary variable used during the device search. Therefore, refcount related to the search iterators should be cleaned up after the search is complete. Use the __free() cleanup macro to ensure the refcount is decremented when the temporary pointer goes out of scope. Additionally, increment the refcount when caching a root pointer. This ensures the in-use refcount is separate from the temporary search refcounting. Finally, drop the redundant "root = NULL" before the second search loop. The pci_get_class() iterator always decrements the refcount of its "from" argument, so the first loop can only fall through with "root" already NULL. Fixes: 0a4b61d9c2e4 ("x86/amd_node: Fix AMD root device caching") Closes: https://sashiko.dev/#/patchset/20260806160159.230453-1-jason.andryuk%40amd.com Reported-by: Sashiko Assisted-by: LLM Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Mario Limonciello (AMD) Cc: Link: https://patch.msgid.link/20260903154325.74343-1-yazen.ghannam@amd.com --- fs/smb/client/reparse.h | 145 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 fs/smb/client/reparse.h (limited to 'fs/smb/client/reparse.h') diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h new file mode 100644 index 000000000..49efd85b1 --- /dev/null +++ b/fs/smb/client/reparse.h @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2024 Paulo Alcantara + */ + +#ifndef _CIFS_REPARSE_H +#define _CIFS_REPARSE_H + +#include +#include +#include +#include "fs_context.h" +#include "cifsglob.h" +#include "../common/smbfsctl.h" + +#define REPARSE_SYM_PATH_MAX 4060 + +/* + * Used only by cifs.ko to ignore reparse points from files when client or + * server doesn't support FSCTL_GET_REPARSE_POINT. + */ +#define IO_REPARSE_TAG_INTERNAL ((__u32)~0U) + +static inline dev_t reparse_mkdev(void *ptr) +{ + u64 v = le64_to_cpu(*(__le64 *)ptr); + + return MKDEV(v & 0xffffffff, v >> 32); +} + +static inline kuid_t wsl_make_kuid(struct cifs_sb_info *cifs_sb, + void *ptr) +{ + u32 uid = le32_to_cpu(*(__le32 *)ptr); + + if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_OVERR_UID) + return cifs_sb->ctx->linux_uid; + return make_kuid(current_user_ns(), uid); +} + +static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb, + void *ptr) +{ + u32 gid = le32_to_cpu(*(__le32 *)ptr); + + if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_OVERR_GID) + return cifs_sb->ctx->linux_gid; + return make_kgid(current_user_ns(), gid); +} + +static inline u64 reparse_mode_nfs_type(mode_t mode) +{ + switch (mode & S_IFMT) { + case S_IFLNK: return NFS_SPECFILE_LNK; + case S_IFBLK: return NFS_SPECFILE_BLK; + case S_IFCHR: return NFS_SPECFILE_CHR; + case S_IFIFO: return NFS_SPECFILE_FIFO; + case S_IFSOCK: return NFS_SPECFILE_SOCK; + } + return 0; +} + +static inline u32 reparse_mode_wsl_tag(mode_t mode) +{ + switch (mode & S_IFMT) { + case S_IFLNK: return IO_REPARSE_TAG_LX_SYMLINK; + case S_IFBLK: return IO_REPARSE_TAG_LX_BLK; + case S_IFCHR: return IO_REPARSE_TAG_LX_CHR; + case S_IFIFO: return IO_REPARSE_TAG_LX_FIFO; + case S_IFSOCK: return IO_REPARSE_TAG_AF_UNIX; + } + return 0; +} + +/* + * Match a reparse point inode if reparse tag and ctime haven't changed. + * + * Windows Server updates ctime of reparse points when their data have changed. + * The server doesn't allow changing reparse tags from existing reparse points, + * though it's worth checking. + */ +static inline bool reparse_inode_match(struct inode *inode, + struct cifs_fattr *fattr) +{ + struct cifsInodeInfo *cinode = CIFS_I(inode); + struct timespec64 ctime = inode_get_ctime(inode); + + /* + * Do not match reparse tags when client or server doesn't support + * FSCTL_GET_REPARSE_POINT. @fattr->cf_cifstag should contain correct + * reparse tag from query dir response but the client won't be able to + * read the reparse point data anyway. This spares us a revalidation. + */ + if (cinode->reparse_tag != IO_REPARSE_TAG_INTERNAL && + cinode->reparse_tag != fattr->cf_cifstag) + return false; + return (cinode->cifsAttrs & ATTR_REPARSE_POINT) && + timespec64_equal(&ctime, &fattr->cf_ctime); +} + +static inline u32 cifs_open_data_attrs(const struct cifs_open_info_data *data) +{ + if (data->contains_posix_file_info) + return le32_to_cpu(data->posix_fi.DosAttributes); + + return le32_to_cpu(data->fi.Attributes); +} + +static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data) +{ + u32 attrs = cifs_open_data_attrs(data); + + if (data->contains_posix_file_info) { + struct smb311_posix_qinfo *fi = &data->posix_fi; + + if (data->reparse_point) { + attrs |= ATTR_REPARSE_POINT; + fi->DosAttributes = cpu_to_le32(attrs); + } + + } else { + struct smb2_file_all_info *fi = &data->fi; + + if (data->reparse_point) { + attrs |= ATTR_REPARSE_POINT; + fi->Attributes = cpu_to_le32(attrs); + } + } + + return attrs & ATTR_REPARSE_POINT; +} + +bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, + struct cifs_fattr *fattr, + struct cifs_open_info_data *data); +int create_reparse_symlink(const unsigned int xid, struct inode *inode, + struct dentry *dentry, struct cifs_tcon *tcon, + const char *full_path, const char *symname); +int mknod_reparse(unsigned int xid, struct inode *inode, struct dentry *dentry, + struct cifs_tcon *tcon, const char *full_path, umode_t mode, + dev_t dev); +struct reparse_data_buffer *smb2_get_reparse_point_buffer(const struct kvec *rsp_iov, + u32 *plen); + +#endif /* _CIFS_REPARSE_H */ -- cgit v1.3.1