OpenSSD
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Help
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    1
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    --- tags: David, OpenSSD, Cosmos+, Arch --- # Cosmos+ Architecture 1. Jaewook Kwak, Sangjin Lee, Kibin Park, Jinwoo Jeong, and Yong Ho Song. 2020. Cosmos+ OpenSSD: Rapid Prototype for Flash Storage Systems. ACM Trans. Storage 16, 3, Article 15 (August 2020), 35 pages. https://doi.org/10.1145/3385073 2. NVM Express, Inc. 2022. *NVM Express Base Specification, revision 2.0b*. NVM Express. <https://nvmexpress.org/wp-content/uploads/NVM-Express-Base-Specification-2.0b-2021.12.18-Ratified.pdf> 3. Cosmos+ Guide 4. PCIe Protocol :::warning 以下筆記中的圖片若沒有特別注記來源的話,皆擷取於 1.。 ::: # Overview > ![Overview](https://i.imgur.com/sA0ugq1.png) > > ![layers](https://i.imgur.com/dhQGOD8.png) > > source # Hardware Arch Cosmos+ Platform 的硬體架構與一般記憶體的架構相同,能夠分成五個區塊: - CPU - RAM - Host Interface Controller - Flash Channel Controllers - Flash Array 各區塊的細節以及區塊間的關係如下圖所示: ![HW Arch](https://i.imgur.com/1b1wrm9.png) ![HW Arch Prototype](https://i.imgur.com/Zehc9A8.png) Cosmos+ 作為一個儲存系統,最主要的目的就是讓 Host System 能夠對 Flash Memory 進行讀寫,而要使兩個硬體裝置間能夠進行資料傳輸,就需要有能夠操作硬體的 Controller,即上圖中的 Host Interface Controller 與 Storage Controller,而兩個 Controller 資料傳遞的細節處理則是由在 CPU 中執行的 Firmware 來處理。 :::warning 雖然架構上與一般記憶體相似,不過上圖中的 CPU、RAM 等硬體單元都不是透過 Flash Memory Module 上的硬體進行處理,而是使用燒錄在 FPGA 上的邏輯電路來處理,也因此 Host Interface Controller 與 Storage Controller 的實作都可以重新設計。 ::: ## Host Interface Controller 在 Cosmos+ Project 中,負責與 Host System 進行溝通的 Host Interface Controller 在 [PCIe 協定](https://en.wikipedia.org/wiki/PCI_Express)上實作了 [NVMe 協定](https://en.wikipedia.org/wiki/NVM_Express),讓 Host System 在對 Flash Memory 進行存取時,能夠有 High Bandwidth 與 Performance Scalability 的優點。 :::warning PCIe 與 NVMe 間的關係在概念上類似於 IP 與 TCP 的關係? 當 Flash Device 要與 Host System 進行溝通時,相關的 Command、Data、NVMe Control Info 都會被包裝成 PCIe Packet,然後再依據 PCIe 協定進行傳輸。 ::: #### PCIe Controller 而在 Host Interface Controller 中將任務分成了數個階段來完成,其中負責與 Host System 進行直接溝通的就是 PCIe Controller。而其作為 Host Interface Controller 的最底層,除了完成 PCIe 協定中定義的任務之外,還需負責: :::danger - initialize PCIe lane - flow control - end-to-end data transmission - 處理完 PCIe Packet 之後? - 沒有詳細說明,可能需要讀 code/spec ::: #### NVMe Protocol Controller 與 PCIe Controller 相似,當 Host System 傳來的 PCIe Packet 的初步處理完成後,接著要透過 NVMe Protocol Controller 對建立於 PCIe 協定上的 NVMe 協定進行處理,而 NVMe 協定的通訊概念主要是透過 Queue 來完成: > NVMe Spec: https://nvmexpress.org/developers/nvme-specification/ > > The NVM Express interface is based on a **paired Submission and Completion Queue** mechanism. Commands are placed by host software into a Submission Queue. Completions are placed into the associated Completion Queue by the controller. Host System 發出的 Commands 會先被暫存在 Host System 的 Submission Queue**s** 中,當 Flash Device 有能力執行 Command 時,就可以**根據實作的「特定策略」** 從 Submission Queue**s** 中取出 Command 到 Flash Device 中進行處理。 :::warning NVMe Protocol Controller 會根據「特定策略」取出 Commands,而這個「特定策略」可以根據需求進行實作,例如可以仿照 CPU 排程器為不同的 Submission Queue 設定優先度,讓特定類型的 Commands 能夠優先存取 SSD。 ::: 這些 Submission Queue 都有一個對應的 Completion Queue,當 Flash Device 處理完 Command 後,Flash Device 的 Controller 就會將==完成的任務==存到對應的 Completion Queue 中、告知 Host System 該 Command 已經完成了。 :::danger - completion 要如何處理,同樣由 NVMe Protocol Controller 處理? - 為什麼需要多個 Submission Queue - Completion Queue 中要存什麼? - Host 最多能有 64 K 個深度(大小)為 64 K 的 I/O Submission Queue ::: ![Command Queue](https://i.imgur.com/y6QJvSp.png) 上圖是從 Host System 讀取 Command 的概念圖,其中應特別注意到最左側的 **Admin Submission Queue**,這個 但這些 Commands 也不是放到 Host Command Queue 後就可以被執行,還需要先透過 Firmware 進行 Translation,將 Host Command 轉換成 Flash Device 能看懂的 Command,而 Translation 的細節則會在後面的 **[Firmware Arch](#Firmware-Arch)** 中說明。 :::danger - only one admin queue? ::: #### Host DMA (Direct Memory Access) Engine 除了 Command 之外,也需要處理 Host System 與 Flash Device 間的資料傳輸,而 Host Interface Controller 負責這個工作的就是 Host DMA Engine。 在後面 **[NVMe Manager](#NVMe-Manager)** 的部份會提到傳輸資料的 Command 最終可以對應到以 Data Buffer 作為暫存的兩種 DMA 操作,其中的 **Host DMA Opertaion** 就是用於 Host Memory 與 Data Buffer 間的資料傳輸,而==實際上與 Host 進行資料傳遞的就是這個 Host DMA Engine?==,它可以透過 **Physical Region Page (PRP)** 直接存取 Host Memory。 :::danger - PRP? - 詳細的 DMA 原理? ::: ## Storage Controller (Flash Channel Controllers) 當 Host System 傳來的 Command 都被 Firmware 轉換成 Flash Memory 能夠理解的操作後,最後需要的就剩下實際對 Flash Memory 進行讀寫了,而負責這個就是Storage Controller。 Storage Controller 在 Host Interface Controller 和 flash 之間提供訪問路徑,內部有多個 Flash Channel Controllers,每一個控制器負責管理連接到同一 channel 的閃存操作,每個 Flash Channel Controllers 都有自己的 flash driver 與各個閃存設備交換 physical signals 。 下圖顯示 Flash Channel Controllers 的組織結構,每個控制器都有兩條內部訊息路徑分為 Control path 跟 Data path。 當 frimware 需要對閃存進行存取數據、獲得操作狀態、統計數據時,他將向 Control path 發送一個適當的 Flash Control Word (FCW)。FCW 是用於 Storage Controller 和 firmware 之間通訊的控制訊息。FCW 經過 Command Filter 傳送到 Command Dispatcher。每一個 Command Filter 對 FCW 會執行自己的功能。Command Dispatcher 從 control word queue 檢索 FCW 並把他翻譯成閃存命令。 :::danger - control word queue 是甚麼 ? - 又是如何去檢索FCW的 ? ::: ![](https://i.imgur.com/kB8aL5w.png) #### ECC ![](https://i.imgur.com/LRe6iA9.png) :::danger - ECC pipeline - share ECC hw ::: --- # Firmware Arch ![Firmware Arch](https://i.imgur.com/nWkvqW0.png) Cosmos+ Platform 的 Firmware 架構如上圖所示,Firmware 的主要任務就是在 Host Interface Controller 與 Storage Controller 間進行「一些處理」,以便控制 SSD 的行為。 而這些處理在 Firmware 中被切割成數個階段,Host System 送出的 Commands 會大致從 Host Interface Controller Driver 依序執行到 Storage Controller;而 Storage Device 取出的資料則以相同路徑返回給 Host Interface Controller Driver,因此各個階段間的箭頭是雙向的。 不過可以注意到其中的例外:Low Level Scheduler 與 Host Interface Controller Driver 間也有雙向箭頭,指向 Low Level Schedule 的箭頭會在 ==???== 說明,而指向 Host Interface Controller Driver 的箭頭則會在後面的 **[Low Level Scheduler](#Low-Level-Scheduler)** 中說明。 而在 Firmware 的這 5 個階段中,==最底層的兩個 Driver 則沒有詳細的說明==,因此後面只會針對其餘三個階段進行說明: ### NVMe Manager 如前面 Submission Queue 部份提到的,當 Host 要對 SSD 存取時,會以 Command 的形式傳遞給 SSD,然後由 Firmware 進行 Translation,實際上這個 Translation 會將 Commands 細分成不同層級的操作,各層級操作間的關係如下圖所示: ![Command Interpret](https://i.imgur.com/kqlQRqP.png) :::danger > [NVMe Command Sets](https://i.imgur.com/FnyTAVE.png) > > source: NVMe Base Spec ::: 從上圖可以看到 Host System 傳來的 Command 可以再被分成兩類: - Admin Command 負責進行管理相關的操作,像是:修改 Host Interface 的參數、檢查當前 Operation 的狀態,這類的 Command 會直接由 NVMe Manager 進行處理。 :::info - 什麼情況下需要修改 Host Interfacee 的參數? ::: - NVM Command NVM Command 負責處理 Host System 與 Flash Device 間的資料傳輸,像是,而這類的 Command 不會由 NVMe Manager 進行處理,而會轉交給後面的 FTL 進行進一步的處理。 ### FTL - Flash Translation Layer 上面提到的 NVMe Manager 將 Host System 傳來的 Command 分類成 Admin Command 與 NVM Command 後,NVM Commands 會被傳來 FTL 進行 Translation,將 NVM Command 轉換成 Flash Device 能看懂的操作,最後再交給 Low Level Scheduler 執行。 但這個 Translation 並不是一個步驟就能完成,依據任務可以切割成四個步驟來處理: ![Command Translation Flow](https://i.imgur.com/CZvXJ08.png) :::danger - 以 pipeline 的概念進行? ::: - NVM Command Manager:產生 Slice Commands 並暫存至 Slice Command Queue 由於 Flash Memory 的操作都是以 Page 為單位進行,但 NVM Command 卻可能會一次對多個 Page 進行操作,因此首先需要由 NVM Command Manager **將 NVM Command 分成以 Page 為單位的 Slice Commands、並放到 Slice Command Queue 中暫存**,直到被下一步的 Data Buffer Manager 取出(預設的取出機制為 FIFO)。 :::warning 雖然在 NVM Command Manager 中只負責將 NVM Commands 切割成數個 Slice Commands,但實際上這些 Slice Commands 根據類型,**之後**還會在不同階段再各自**產生**一個對應的基本操作: - Host DMA Operation Host Memory 與 **Data Buffer** 間的資料讀寫操作,像是:將 Data Buffer 中的資料移動到 Host Memory 裝置、將 Host Memory 中的資料移動到 Data Buffer。 - Flash DMA Operation 負責 **Data Buffer** 與 Flash **Device** 間資料傳輸相關的處理,像是:將 Data Buffer 中的資料移動到 Flash 裝置、將 Flash 裝置中的資料移動到 Data Buffer。 - Flash Operation 實際負責 Flash Memory 讀寫的相關操作。 雖然這三種基礎操作都不是由 NVM Manager 負責產生,而是**在後面由不同階段產生**,而之後階段中的部份操作會以這三種基礎操作來處理,而不是直接使用 Slice Command。 ::: :::danger - erase 屬於哪種?flash ops? - flash device 中有暫存空間? ::: :::info TODO: nvm command -> slice comamnds example ::: - Data Buffer Manager:分配 Data Buffer Entries 並產生 Host DMA Ops 在前面的 NVM Command Manager 中提到的兩種 **DMA Operation**,都是以 Data Buffer 作為一端、分別對 Host Memory 或 Flash Memory 進行資料傳輸,因此 Data Buffer 實際上就是 Flash Memory 與 Host Memory 資料傳輸過程中的**暫存空間**而已,而 Data Buffer Manager 就是負責管理這個暫存空間。 這個 Data Buffer 是 DRAM 中的一塊空間,在 NVM Command Manager 中產生的每個 Slice Command 都會被 Data Buffer Manager 分配成 **Data Buffer Entry**,然後儲存在 Data Buffer 中,但 Data Buffer 也是有限的,因此當空間不足時,就會透過 LRU 的策略回收舊的 Command、騰出可用空間。 然而這些 Slice Commands 也不是單純的放進 Data Buffer 中,若 Data Buffer Manager 發現負責與 Host System 進行資料傳輸的 Slice Command 的話,會生成 **Host DMA Opertaions**(這些 Host DMA Operation 中包含對應的 Slice Command 在 Data Buffer 中的 Entry Number)、**然後跳過 Address Translator 直接傳給 Dependency Checker**。 :::danger - 尚未執行的 Command 有沒有可能被 LRU 機制移除? ::: - Address Translator:將 Logical Address 轉換成 Location Vector (Physical Address) 在所有 Command 都被切割成以 page 為單位的 Slice Command 之後,接著需要透過 Mapping Table 將 Logical Address 轉成 Physical Address、後面的處理才能正確的定位到實際上資料在 Flash Memory 中的儲存位置。 :::danger - location vector - flash memory 的儲存機制 - generate flash DMA/OP ::: 回顧 [Flash Memory 的儲存架構](#),若需要表示一個資料的實際儲存位置的話,需要有 Channel, Way, Plane, Block, Page 等資訊才夠。 **Location Vector** ![Location Vector](https://i.imgur.com/TMu6IlH.png) 將 Logical Page Number :::success TODO: ::: ![Address Translation](https://i.imgur.com/VvESS8n.png) - Dependency Checker 這階段的主要任務是確保前面提到的三種基礎操作的執行順序不會影響結果 :::warning 文件中未提及為什麼會亂掉,以下為推測: ::: 如同前面 NVM Command Manager 中提到的,三種基礎的 Operation 會在不同階段被生成: - Data Buffer Manager 生成 Host DMA Operations - Address Translator 生成 Flash DMA 與 Flash Operations 因此即使 Slice Commands 是按照順序處理,也可能會造成 Host DMA Operation 提早被送到 Dependency Checker 中、造成順序更動。 此外,如同前面 **[NVMe Manager](#NVMe-Manager)** 中的架構所示,所有 Slice Command 本質上都是來自 Host Command,而 **[NVMe Protocol Controller](#NVMe-Protocol-Controller)** 中則有提到 Host System 中可能會有多個 Submission Queue,且從 Submission Queue 取出 Command 的策略可以任意實作,因此 Host Command Queue 中可能有來自不同 Submission Queue 的 Command、產生可以透過調整 Command 順序來進行最佳化的機會。 :::danger - Host System 中相同來源(例如同個執行緒)發出的 Host Command 有沒有可能分配到不同的 Submission Queue 中? - 這階段會不會重排 ::: ### Low Level Scheduler 這階段的主要工作是將 FTL 產生的 Operations 依據類型(Host 相關還是 Flash 相關)分送給 Host DMA Engine 與 Storage Controller,讓 Operations 能夠被特定的硬體執行。 除了分配三種操作給兩個 Controller 之外,Low Level Scheduler 還會根據操作的類型分配不同的優先度,並透過排程讓高優先度的操作能夠排在低優先度的操作前執行,不同類型操作的優先度如下圖所示,數值越小的優先度越高: ![](https://i.imgur.com/XK2f6It.png) 在 Host Interface Controller 方面,從表中可以看到 Host DMA 的讀寫操作優先度最高,這代表只要 Host Interface Controller 一有能力執行新的 Operation,Low Level Scheduler 就會送出 Operation 讓它執行,這能夠讓 Host Operation 的 **latency 降低**。 :::warning 可能是因為 Host System 通常執行能力較強,因此要避免 Flash Device 變成效能瓶頸? ::: 而在 Storage Controller 方面,由於 Flash DMA 的讀寫會**長時間**佔用 Channel、且會干擾到 Flash Operations,因此為了讓 Low Level Scheduler 更有效率,Flash DMA 的讀寫是三種 Operation 中優先度最低的。 :::danger - Flash Op 原理?可以平行處理? - 為什麼 Flash DMA 會干擾到其他 Flash Ops? - 平均執行時間? ::: 而這個排程的操作被拆成數個步驟執行,執行的順序如下圖所示: ![](https://i.imgur.com/kiJlZib.png) - Reservation Station 首先,當 FTL 的 Dependency Checker 檢查完 Operations 間的 Dependency 後會被送到 Low Level Schedule 中的 **Reservation Station** 中暫存,如上圖所示。 Reservation Station 由 1 個暫存 Host DMA Opertaion 的佇列以及 $nWays \times nChannels$ 個暫存 Flash/Flash DMA Operations 的佇列所組成,從 FTL 送進來的 Operation 都會暫存在此,直到下一步的 **State Manager** 從這些佇列中取出。 - State Manager 而 State Manager 則會**追蹤 Host Interface Controller 與 Storage Controller** 執行 Operations 的狀況,當 Controller 進入到**有能力**執行下一個 Operation 的狀態時,State Manager 就會從 Host DMA Operation Queue 或是對應的 $ChannelX-WayY$ Flash Operation Queue 中取出新的 Operation,並傳給下一步的 Priority Manager 做進一步的處理。 - State Checker 而, :::success now here ::: ![](https://i.imgur.com/XauLIq4.png) - Priority Manager 接著則是由 Priority Manager 進行前面提到的排程管理,這階段會參考前面 Table 2 中的優先度來**決定 Operations 的執行順序**,若是有數個 Operation 的**優先度相同**的話,則會採用 **Round-Robin** 的機制處理。 - Issuer 最後則是透過 Issuer 將 Operations 發送到對應的 Controller。而其中的 Host DMA Operation 會被發送到 Host Interface Controller Driver,因此前面 **[Firmware 架構圖](#Firmware-Arch)** 中的 Low Level Scheduler 才會有指向 Host Interface Controller Driver 的箭頭。 而由於 Issuer 是負責與 Controller 溝通的階段,且不會再對 Operations 進行重排,因此前面提到的 **State Checker** 也會在這階段向 Issuer 檢查 Operations 的執行狀態。 ## Summary > ![FW Workflow](https://i.imgur.com/gFU8qxk.png) > > source?

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully