iommu系列之---概念解释篇
本文会对iommu中的一些容易引起疑惑的概念进行阐述,内核版本为4.19.
先上简写:
- DMAR - DMA remapping
- DRHD - DMA Remapping Hardware Unit Definition
- RMRR - Reserved memory Region Reporting Structure
- ZLR - Zero length reads from PCI devices
- IOVA - IO Virtual address.
- SMMU -System Memory Management Unit,就是arm的iommu
1、为什么会有一个iommu_group的概念,直接将device和iommu_domain关联不香吗?
假设我们通过iommu提供设备的DMA能力,当发起dma_map的时候,设备设置了streamid, 但是多个设备的streamid有可能是一样的。
那么这时候修改其中一个设备的页表体系,就影响了相同streamid的其他设备。
所以,修改页表的最小单位不是设备,而是streamid。这个streamid大家可能觉得比较抽象,先知道这个是用来索引的就行。
因此,为了避免这种情况,增加了一个iommu_group的概念,iommu_group代表共享同一个streamid的一组device(表述在/sys/kernel/iommu_group中)。
有了iommu_group, 设备发起dma_map操作时,会定位streamid和iommu_group, group定位了iommu_device和iommu_domain,
iommu_domain定位了asid。group 里面的设备既然公用一套iova的页表,那么只能透传给一个虚机,不能分开透传。
一个iommu_group里面既可能只有一个device,也可能有多个device。
arm smmu-v3中的 iommugroup 类型为2类
//caq:arm中针对iommu,有两类group,如果是pci的设备,用一个默认group,否则用系统的默认group,注意是两类,不是两个,个数可以建很多个。
static struct iommu_group *arm_smmu_device_group(struct device *dev)
{
struct iommu_group *group;
/*
* We don't support devices sharing stream IDs other than PCI RID
* aliases, since the necessary ID-to-device lookup becomes rather
* impractical given a potential sparse 32-bit stream ID space.
*/
if (dev_is_pci(dev))
group = pci_device_group(dev);//caq:pci 的group
else
group = generic_device_group(dev);//caq:generic 的group
return group;
}
2、resv_regions
有些保留的区域,是不能dma映射的,将这些区域管理起来,避免映射。
对于arm smmu-v3来说,保存区域为 MSI_IOVA_BASE,长度为 MSI_IOVA_LENGTH,还有保留类型为IOMMU_RESV_MSI,它是硬件的 msi 区域 。
对于intel 来说,保留区域为 IOMMU_RESV_DIRECT 和 IOMMU_RESV_MSI类型的 IOAPIC_RANGE_START 区域。
3、iommu_group 和dev 之间的关系
# for d in /sys/kernel/iommu_groups/*/devices/*; do n=${d#*/iommu_groups/*}; n=${n%%/*}; printf 'IOMMU Group %s ' "$n"; lspci -nns "${d##*/}"; done;
IOMMU Group 0 00:00.0 Host bridge [0600]: Intel Corporation Sky Lake-E DMI3 Registers [8086:2020] (rev 07)
IOMMU Group 10 00:05.2 System peripheral [0880]: Intel Corporation Device [8086:2025] (rev 07)
IOMMU Group 11 00:05.4 PIC [0800]: Intel Corporation Device [8086:2026] (rev 07)
IOMMU Group 12 00:08.0 System peripheral [0880]: Intel Corporation Sky Lake-E Ubox Registers [8086:2014] (rev 07)
IOMMU Group 13 00:08.1 Performance counters [1101]: Intel Corporation Sky Lake-E Ubox Registers [8086:2015] (rev 07)
IOMMU Group 14 00:08.2 System peripheral [0880]: Intel Corporation Sky Lake-E Ubox Registers [8086:2016] (rev 07)
IOMMU Group 15 00:11.0 Unassigned class [ff00]: Intel Corporation C620 Series Chipset Family MROM 0 [8086:a1ec] (rev 09)
IOMMU Group 15 00:11.5 SATA controller [0106]: Intel Corporation C620 Series Chipset Family SSATA Controller [AHCI mode] [8086:a1d2] (rev 09)
IOMMU Group 16 00:14.0 USB controller [0c03]: Intel Corporation C620 Series Chipset Family USB 3.0 xHCI Controller [8086:a1af] (rev 09)
IOMMU Group 16 00:14.2 Signal processing controller [1180]: Intel Corporation C620 Series Chipset Family Thermal Subsystem [8086:a1b1] (rev 09)
IOMMU Group 17 00:16.0 Communication controller [0780]: Intel Corporation C620 Series Chipset Family MEI Controller #1 [8086:a1ba] (rev 09)
IOMMU Group 17 00:16.1 Communication controller [0780]: Intel Corporation C620 Series Chipset Family MEI Controller #2 [8086:a1bb] (rev 09)
IOMMU Group 17 00:16.4 Communication controller [0780]: Intel Corporation C620 Series Chipset Family MEI Controller #3 [8086:a1be] (rev 09)
IOMMU Group 18 00:17.0 SATA controller [0106]: Intel Corporation C620 Series Chipset Family SATA Controller [AHCI mode] [8086:a182] (rev 09)
IOMMU Group 19 00:1c.0 PCI bridge [0604]: Intel Corporation C620 Series Chipset Family PCI Express Root Port #1 [8086:a190] (rev f9)
IOMMU Group 1 00:04.0 System peripheral [0880]: Intel Corporation Sky Lake-E CBDMA Registers [8086:2021] (rev 07)
IOMMU Group 20 00:1c.1 PCI bridge [0604]: Intel Corporation C620 Series Chipset Family PCI Express Root Port #2 [8086:a191] (rev f9)
IOMMU Group 21 00:1c.2 PCI bridge [0604]: Intel Corporation C620 Series Chipset Family PCI Express Root Port #3 [8086:a192] (rev f9)
IOMMU Group 22 00:1c.3 PCI bridge [0604]: Intel Corporation C620 Series Chipset Family PCI Express Root Port #4 [8086:a193] (rev f9)
IOMMU Group 23 00:1c.5 PCI bridge [0604]: Intel Corporation C620 Series Chipset Family PCI Express Root Port #6 [8086:a195] (rev f9)
从打印可以看出,/sys/kernel/iommu_groups/ 这个kset 下有所有的iommu_group 信息,然后 对应的某个group下目前暴露两个信息,一个是归属在这个group的设备,一个是他的reserved_regions.
root@G3:/sys/kernel/iommu_groups# ls
0 10 12 14 16 18 2 21 23 25 27 29 30 32 34 36 38 4 41 43 45 47 49 50 52 54 56 58 6 61 63 65 67 69 70 72 74 76 78 8 81 83 85 87 89 90 92 94 96
1 11 13 15 17 19 20 22 24 26 28 3 31 33 35 37 39 40 42 44 46 48 5 51 53 55 57 59 60 62 64 66 68 7 71 73 75 77 79 80 82 84 86 88 9 91 93 95
root@G3:/sys/kernel/iommu_groups# cd 2
root@G3:/sys/kernel/iommu_groups/2# ls
devices reserved_regions type
root@G3:/sys/kernel/iommu_groups/2# ll
total 0
drwxr-xr-x 3 root root 0 10月 25 09:23 ./
drwxr-xr-x 99 root root 0 10月 25 03:40 ../
drwxr-xr-x 2 root root 0 10月 29 10:43 devices/
-r--r--r-- 1 root root 4096 10月 30 10:15 reserved_regions
-r--r--r-- 1 root root 4096 10月 30 10:15 type
root@G3:/sys/kernel/iommu_groups/2# ls devices/
0000:00:04.1
root@G3:/sys/kernel/iommu_groups/2# pwd
/sys/kernel/iommu_groups/2
root@G3:/sys/kernel/iommu_groups/2# ls devices/
0000:00:04.1
root@G3:/sys/kernel/iommu_groups/2# ls reserved_regions
reserved_regions
root@G3:/sys/kernel/iommu_groups/2# cat reserved_regions
0x00000000fee00000 0x00000000feefffff msi
root@G3:/sys/kernel/iommu_groups/2# ls ../3/
devices/ reserved_regions type
root@G3:/sys/kernel/iommu_groups/2# ls ../3/devices/
0000:00:04.2
root@G3:/sys/kernel/iommu_groups/2# cat ../3/reserved_regions/
cat: ../3/reserved_regions/: Not a directory
root@G3:/sys/kernel/iommu_groups/2# cat ../3/reserved_regions
0x00000000fee00000 0x00000000feefffff msi
4、总线地址是个什么概念
以pci总线举例,BAR读取到的是PCI地址空间中的地址,不等同于CPU认识的内存地址。虽然在x86上如果没有开启IOMMU时,它们的值一般是相同的,但是对于其他构架的CPU如PowerPC就可以是不一样的。
所以正确的使用BAR空间的方法:
pciaddr=pci_resource_start(pdev,1);
if(pciaddr!=NULL)
{
ioremap(pciaddr,xx_SIZE);
}
而不是下面这样错误的方法:
pci_read_config_dword(pdev,1,&pciaddr);
ioremap(pciaddr,xx_SIZE);
对于内核态cpu的地址来说,它只关心内核态 虚拟地址 通过mmu 转为 物理地址,在设备驱动通知设备做dma操作的时候,直接给设备传递没有经过dma_map的地址,是会有问题的。
5、如何确认iommu的硬件加载情况
[root@localhost dma]# dmesg -T|grep -i dmar
[Sat Oct 9 08:56:54 2021] ACPI: DMAR 000000006fffd000 00200 (v01 DELL PE_SC3 00000001 DELL 00000001)----------linux启动时扫描acpi的table
[Sat Oct 9 08:57:01 2021] DMAR: Host address width 46
[Sat Oct 9 08:57:01 2021] DMAR: DRHD base: 0x000000d37fc000 flags: 0x0
[Sat Oct 9 08:57:01 2021] DMAR: dmar0: reg_base_addr d37fc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
[Sat Oct 9 08:57:01 2021] DMAR: DRHD base: 0x000000e0ffc000 flags: 0x0
[Sat Oct 9 08:57:01 2021] DMAR: dmar1: reg_base_addr e0ffc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
[Sat Oct 9 08:57:01 2021] DMAR: DRHD base: 0x000000ee7fc000 flags: 0x0
[Sat Oct 9 08:57:01 2021] DMAR: dmar2: reg_base_addr ee7fc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
[Sat Oct 9 08:57:01 2021] DMAR: DRHD base: 0x000000fbffc000 flags: 0x0
[Sat Oct 9 08:57:01 2021] DMAR: dmar3: reg_base_addr fbffc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
[Sat Oct 9 08:57:01 2021] DMAR: DRHD base: 0x000000aaffc000 flags: 0x0
[Sat Oct 9 08:57:01 2021] DMAR: dmar4: reg_base_addr aaffc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
[Sat Oct 9 08:57:01 2021] DMAR: DRHD base: 0x000000b87fc000 flags: 0x0
[Sat Oct 9 08:57:01 2021] DMAR: dmar5: reg_base_addr b87fc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
[Sat Oct 9 08:57:01 2021] DMAR: DRHD base: 0x000000c5ffc000 flags: 0x0
[Sat Oct 9 08:57:01 2021] DMAR: dmar6: reg_base_addr c5ffc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
[Sat Oct 9 08:57:01 2021] DMAR: DRHD base: 0x0000009d7fc000 flags: 0x1
[Sat Oct 9 08:57:01 2021] DMAR: dmar7: reg_base_addr 9d7fc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
[Sat Oct 9 08:57:01 2021] DMAR: RMRR base: 0x000000402f8000 end: 0x000000482fffff
[Sat Oct 9 08:57:01 2021] DMAR: RMRR base: 0x0000006ef60000 end: 0x0000006ef62fff
[Sat Oct 9 08:57:01 2021] DMAR: ATSR flags: 0x0
[Sat Oct 9 08:57:01 2021] DMAR: ATSR flags: 0x0
//caq:下面是ir部分的开始打印,见 ir_parse_one_ioapic_scope 函数:
[Sat Oct 9 08:57:01 2021] DMAR-IR: IOAPIC id 12 under DRHD base 0xc5ffc000 IOMMU 6//caq:注意,ir是interrupt remapping 的简写,
[Sat Oct 9 08:57:01 2021] DMAR-IR: IOAPIC id 11 under DRHD base 0xb87fc000 IOMMU 5//caq:最后的数字是 intel_iommu.seq_id
[Sat Oct 9 08:57:01 2021] DMAR-IR: IOAPIC id 10 under DRHD base 0xaaffc000 IOMMU 4//caq: IOAPIC id是指 enumeration_id
[Sat Oct 9 08:57:01 2021] DMAR-IR: IOAPIC id 18 under DRHD base 0xfbffc000 IOMMU 3
[Sat Oct 9 08:57:01 2021] DMAR-IR: IOAPIC id 17 under DRHD base 0xee7fc000 IOMMU 2
[Sat Oct 9 08:57:01 2021] DMAR-IR: IOAPIC id 16 under DRHD base 0xe0ffc000 IOMMU 1
[Sat Oct 9 08:57:01 2021] DMAR-IR: IOAPIC id 15 under DRHD base 0xd37fc000 IOMMU 0
[Sat Oct 9 08:57:01 2021] DMAR-IR: IOAPIC id 8 under DRHD base 0x9d7fc000 IOMMU 7
[Sat Oct 9 08:57:01 2021] DMAR-IR: IOAPIC id 9 under DRHD base 0x9d7fc000 IOMMU 7
[Sat Oct 9 08:57:01 2021] DMAR-IR: HPET id 0 under DRHD base 0x9d7fc000
[Sat Oct 9 08:57:01 2021] DMAR-IR: Queued invalidation will be enabled to support x2apic and Intr-remapping.
[Sat Oct 9 08:57:01 2021] DMAR-IR: Enabled IRQ remapping in x2apic mode---------------关键打印,表明irq的remapping 的工作模式是 x2apic 还是 xapic
[Sat Oct 9 08:57:02 2021] DMAR: [Firmware Bug]: RMRR entry for device 1a:00.0 is broken - applying workaround
6、iommu_domain 与 iommu 硬件之间的关系:
以intel 为例,我们先来看 iommu_domain 的数据结构:
struct dmar_domain {//caq:这个直接继承 iommu_domain
int nid; /* node id */
unsigned iommu_refcnt[DMAR_UNITS_SUPPORTED];//caq:每个domain 在 对应intel_iommu硬件中的引用计数
/* Refcount of devices per iommu *///caq:说明一个domain 可以包含多个iommu,特别是vm场景
u16 iommu_did[DMAR_UNITS_SUPPORTED];//这个domain 在 对应intel_iommu 中的id
/* Domain ids per IOMMU. Use u16 since
* domain ids are 16 bit wide according
* to VT-d spec, section 9.3 */
bool has_iotlb_device;//caq:表示这个Domain里是否有具备IO-TLB的设备
struct list_head devices; /* all devices' list */
struct iova_domain iovad; /* iova's that belong to this domain *///caq:属于这个dmar_domain的iova_domain
struct dma_pte *pgd; /* virtual address *///caq:指向了IOMMU页表的基地址是IOMMU页表的入口
int gaw; /* max guest address width */
/* adjusted guest address width, 0 is level 2 30-bit */
int agaw;//caq:0代表level 2,
int flags; /* flags to find out type of domain *///caq:dmain 的类型也存放在这
int iommu_coherency;/* indicate coherency of iommu access *///caq:一致性
int iommu_snooping; /* indicate snooping control feature*///caq:是否嗅探总线的控制feature
int iommu_count; /* reference count of iommu */
int iommu_superpage;/* Level of superpages supported:
0 == 4KiB (no superpages), 1 == 2MiB,
2 == 1GiB, 3 == 512GiB, 4 == 1TiB *///caq:各种大页的标志,0就是代表普通4k页
u64 max_addr; /* maximum mapped address *///caq:最大映射的addr
struct iommu_domain domain; /* generic domain data structure for
iommu core */
};
iommu_refcnt 成员的数组形式,对于 DOMAIN_FLAG_VIRTUAL_MACHINE 类型的 ,一个iommu_domain 可以有多个 iommu的硬件,而对于
其他类型,则一般是一对一的关系。
7.iommu 设备的 attr,是指该iommu 设备抽象出来的属性,比如是否支持二级转换,pgsize 的值等
enum iommu_attr {
DOMAIN_ATTR_GEOMETRY,
DOMAIN_ATTR_PAGING,
DOMAIN_ATTR_WINDOWS,
DOMAIN_ATTR_FSL_PAMU_STASH,
DOMAIN_ATTR_FSL_PAMU_ENABLE,
DOMAIN_ATTR_FSL_PAMUV1,
DOMAIN_ATTR_NESTING, /* two stages of translation */
DOMAIN_ATTR_MAX,
};
8.iommu的 reserve type,是对dev 保留不需要映射的区域的一个类型划分。
/* These are the possible reserved region types */
enum iommu_resv_type {
/* Memory regions which must be mapped 1:1 at all times */
IOMMU_RESV_DIRECT,//caq:1:1 直接映射
/* Arbitrary "never map this or give it to a device" address ranges */
IOMMU_RESV_RESERVED,//caq:保留的,不要映射
/* Hardware MSI region (untranslated) */
IOMMU_RESV_MSI,//caq:硬件的 msi 区域
/* Software-managed MSI translation window */
IOMMU_RESV_SW_MSI,//caq:软件保留的msi 区域
};
9.对于iommu设备,虽然抽象出一个iommu_device,但是intel 对这个的实现是 分开的,dmar_rmrr_unit 用来描述一个iommu的硬件部分,而用 intel_iommu 来实现iommu_device,
当然, intel_iommu 不能是空中楼阁,它会有一个指向 dmar_rmrr_unit 的指针,如下示例:
struct intel_iommu {
void __iomem *reg; /* Pointer to hardware regs, virtual addr *///caq:这个是寄存器组的虚拟地址,通过ioremap而来
......
struct **iommu_device **iommu; /* IOMMU core code handle *///caq:intel_iommu首先是一个 iommu_device,核心的是ops
struct dmar_drhd_unit *drhd;//caq:也有一个指向 dmar_drhd_unit 的指针,1对1------------------intel对iommu
};
10、如果没有iommu,能透传设备给虚机么?
一般来说,在没有IOMMU的情况下,设备必须访问真实的物理地址HPA,而虚机可见的是GPA,
如果让虚机填入真正的HPA,那样的话相当于虚机可以直接访问物理地址,会有安全隐患。
所以针对没有IOMMU的情况,不能用透传的方式,对于设备的直接访问都会有VMM接管,这样就不会对虚机暴露HPA。
11、iova_domain 是干嘛的
iova就是va针对dma领域的一个虚拟地址的抽象,那怎么管理这些地址呢?比如哪些地址被映射过,就需要一个记录的地方,
/* holds all the iova translations for a domain */
struct iova_domain {//caq:用一棵红黑树来记录iova->hpa的地址翻译关系
spinlock_t iova_rbtree_lock; /* Lock to protect update of rbtree *///caq:全局锁
struct rb_root rbroot; /* iova domain rbtree root */
struct rb_node *cached_node; /* Save last alloced node *///caq:最后申请的一个node
struct rb_node *cached32_node; /* Save last 32-bit alloced node *///caq:最后申请的32bit一个node
unsigned long granule; /* pfn granularity for this domain *///caq:pfn粒度
unsigned long start_pfn; /* Lower limit for this domain *///caq:域内起始的pfn
unsigned long dma_32bit_pfn;
struct iova anchor; /* rbtree lookup anchor */
struct iova_rcache rcaches[IOVA_RANGE_CACHE_MAX_SIZE]; /* IOVA range caches *///caq:iova的rang先从这个cache 中申请
//caq:数组内是2的N次方大小的range
iova_flush_cb flush_cb; /* Call-Back function to flush IOMMU
TLBs */
iova_entry_dtor entry_dtor; /* IOMMU driver specific destructor for
iova entry */
struct iova_fq __percpu *fq; /* Flush Queue *///caq:下面这部分都是关于flush相关的
atomic64_t fq_flush_start_cnt; /* Number of TLB flushes that
have been started */
atomic64_t fq_flush_finish_cnt; /* Number of TLB flushes that
have been finished */
struct timer_list fq_timer; /* Timer to regularily empty the
flush-queues *///caq:定时器用来刷掉fq中的cmd
atomic_t fq_timer_on; /* 1 when timer is active, 0
when not */
};
很显然,不同的iommu_domain都有这么一个iova_domain,两者是1:1的关系。
一般来说,当 iommu_domain 的类型是 IOMMU_DOMAIN_DMA 的话,从iommu_domain索引 iova_domain是放在 iova_cookie
//caq:从驱动的dma api请求过来,完成iova的分配
static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain,
size_t size, dma_addr_t dma_limit, struct device *dev)
{
struct iommu_dma_cookie *cookie = domain->iova_cookie;
struct iova_domain *iovad = &cookie->iovad;//caq:iova_domain 在此
11、dev怎么关联对应的 iommu 设备呢?
不同的arch有不同的实现,对于arm smmuv3来说,
//caq:将设备dev关联到 iommu_domain
static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
{
int ret = 0;
struct arm_smmu_device *smmu;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);//caq:从iommu_domain 中得到arm_smmu_domain
struct arm_smmu_master_data *master;
struct arm_smmu_strtab_ent *ste;
if (!dev->iommu_fwspec)
return -ENOENT;
** master = dev->iommu_fwspec->iommu_priv;**
** smmu = master->smmu;**
对于intel来说,比较复杂,可以参照 device_to_iommu 函数的实现:
//caq:bus和devfn是出参
static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
{
struct dmar_drhd_unit *drhd = NULL;
struct intel_iommu *iommu;
struct device *tmp;
struct pci_dev *ptmp, *pdev = NULL;
u16 segment = 0;
int i;
if (iommu_dummy(dev))//caq:该设备没有关联归属iommu,
return NULL;
if (dev_is_pci(dev)) {//caq:pci设备,也就是他的bus type 是pci_bus_type
struct pci_dev *pf_pdev;
pdev = to_pci_dev(dev);
#ifdef CONFIG_X86
/* VMD child devices currently cannot be handled individually */
if (is_vmd(pdev->bus))//caq:VMD:Intel Volume Management Device
return NULL;
#endif
/* VFs aren't listed in scope tables; we need to look up
* the PF instead to find the IOMMU. */
pf_pdev = pci_physfn(pdev);**//caq:以 pf 为dev,在drhd管理的dev中,是看不到vf的**
dev = &pf_pdev->dev;
segment = pci_domain_nr(pdev->bus);//caq:segment其实就是bus归属的domain
} else if (has_acpi_companion(dev))
dev = &ACPI_COMPANION(dev)->dev;
rcu_read_lock();
for_each_active_iommu(iommu, drhd) {//caq:除掉ignored 的所有 intel_iommu
if (pdev && segment != drhd->segment)
continue;
for_each_active_dev_scope(drhd->devices,
drhd->devices_cnt, i, tmp) {
if (tmp == dev) {
iommu系列之---概念解释篇的更多相关文章
- ReactiveCocoa概念解释篇
1.ReactiveCocoa简介 ReactiveCocoa(简称为RAC),是由Github开源的一个应用于iOS和OS开发的新框架,Cocoa是苹果整套框架的简称,因此很多苹果框架喜欢以Coco ...
- JavaScript--我发现,原来你是这样的JS(基础概念--灵魂篇,一起来学js吧)
介绍 这是红宝书(JavaScript高级程序设计 3版)的读书笔记第三篇(灵魂篇介绍),有着剩下的第三章的知识内容,当然其中还有我个人的理解.红宝书这本书可以说是难啃的,要看完不容易,挺厚的,要看懂 ...
- HBase之CF持久化系列(续3——完结篇)
相信大家在看了该系列的前两篇文章就已经对其中的持久化有比较深入的了解.相对而言,本节内容只是对前两节的一个巩固.与持久化相对应的是打开文件并将其内容读入到内存变量中.而在本节,我就来介绍这一点. 本节 ...
- JS--我发现,原来你是这样的JS(三)(基础概念--灵魂篇)
一.介绍 这是红宝书(JavaScript高级程序设计 3版)的读书笔记第三篇(灵魂篇介绍),有着剩下的第三章的知识内容. 红宝书这本书可以说是难啃的,要看完不容易,挺厚的,要看懂更不容易,要熟练js ...
- Spark系列-核心概念
Spark系列-初体验(数据准备篇) Spark系列-核心概念 一. Spark核心概念 Master,也就是架构图中的Cluster Manager.Spark的Master和Workder节点分别 ...
- 【转】手摸手,带你用vue撸后台 系列二(登录权限篇)
前言 拖更有点严重,过了半个月才写了第二篇教程.无奈自己是一个业务猿,每天被我司的产品虐的死去活来,之前又病了一下休息了几天,大家见谅. 进入正题,做后台项目区别于做其它的项目,权限验证与安全性是非常 ...
- openssl之EVP系列之5---EVP_Encrypt系列函数具体解释(二)
openssl之EVP系列之5---EVP_Encrypt系列函数详细解释(二) ---依据openssl doc/crypto/EVP_EncryptInit.pod和doc/ssleay.t ...
- spring cloud系列教程第四篇-Eureka基础知识
通过前三篇文章学习,我们搭建好了两个微服务工程.即:order80和payment8001这两个服务.有了这两个基础的框架之后,我们将要开始往里面添加东西了.还记得分布式架构的几个维度吗?我们要通过一 ...
- Spring cloud系列教程第十篇- Spring cloud整合Eureka总结篇
Spring cloud系列教程第十篇- Spring cloud整合Eureka总结篇 本文主要内容: 1:spring cloud整合Eureka总结 本文是由凯哥(凯哥Java:kagejava ...
随机推荐
- Docker容器编译安装Nginx
Docker容器编译安装Nginx,最简单的Nginx配置. 创建容器&进入容器 宿主机2080映射容器的80端口 [root@localhost ~]# docker run -i -d - ...
- 一些好用的javascript/typescript方法封装分享
1.数字格式化 JS版-直接写到原型链上 /** * @author: silencetea * @name: * @description: 数字格式化,默认每三位用英文逗号分隔 * @param ...
- 在jupyter中配置c++内核
安装 xeus-cling conda install xeus-cling -c conda-forg xeus-cling 是一个用于编译解释于C++的Jupyter内核目前,支持Mac与Linu ...
- 使用nodejs的wxmnode模块,开发一个微信自动监控提醒功能,做个天气预报。
这个模块是一个公众号的模块,名字叫"帮你看着". 原本这个公众号是做股票监控提醒的,我也没炒股.因为接口支持写入任何内容,所以可以有其他的用处.比如做成天气预报定时提醒. 我们去n ...
- Vue开发组件之替代marquee标签,超出宽度文字横向滚动效果
一.npm 安装 如果你想安装插件(自己写的)安装 install dependencies npm i marquee-components 使用 在main.js引入 import marquee ...
- MongoDB 的内存使用限制
本文将简述一下MongoDB的内存限制问题 1. 使用Docker限制 当我们使用docker创建mongo 容器时,可通过使用以下参数,对mongo可以使用的资源进行限制 内存限制 参数 简介 -m ...
- UiPathExcel写入操作
一.Excel 写操作 1.写一个单元格 (1)控件介绍 Write Cell: 使用Write Cell控件,在指定单元格写入内容 常用属性介绍: Destination: Cell: 要写 ...
- Java:如何打印整个字符串数组?
例: public static void main(String[] args) { String prodName = "雇员姓名,雇员唯一号"; String[] prodN ...
- idea 内置tomcat jersey 跨服务器 上传文件报400错误
报错内容 com.sun.jersey.api.client.UniformInterfaceException: PUT http://.jpg returned a response status ...
- 虚拟机win7系统安装
win7 x64虚拟机安装步骤 1.点击创建新虚拟机,选择典型 2.选择客户机操作系统:windows 7 x64 3.命名虚拟机 4.指定磁盘容量 5.点击完成 6.编辑此虚拟机设置 7.内存设置 ...