%-------------------------------------------------------------------------------
% linux_storage_stack.tex - renders the storage stack of the Linux kernel
%-------------------------------------------------------------------------------
% author   : Manuel Bentele
% date     : Aug 29, 2019
% copyright: (c) 2019 Manuel Bentele
%-------------------------------------------------------------------------------

\begin{tikzpicture}[
        box/.style = {rectangle, draw, minimum height = 0.75cm, align = center},
        largeb/.style = {minimum width = 0.7\textwidth},
        smallb/.style = {minimum width = 0.225\textwidth},
        arrow/.style = {-triangle 45},
        desc/.style = {font = \footnotesize},
        node distance = 0.06\textwidth
    ]
    
    \node[box, largeb, fill = hdr] (apps) {Applications};
    \node[box, largeb, fill = ret, below = of apps] (vfs)
        {Virtual file system (VFS)};
    \node[box, smallb, fill = gray!15, left = of vfs] (dio) {Direct IO};
    \node[box, smallb, fill = gray!15, right = of vfs] (pgc) {Page cache};
    
    \draw[arrow] ([xshift=-0.3\textwidth]apps.south) -- node[right,desc] {read}
        ([xshift=-0.3\textwidth]vfs.north);
    \draw[arrow] ([xshift=-0.1\textwidth]apps.south) -- node[right,desc] {write}
        ([xshift=-0.1\textwidth]vfs.north);
    \draw[arrow] ([xshift=0.1\textwidth]apps.south) -- node[right,desc] {open}
        ([xshift=0.1\textwidth]vfs.north);
    \draw[arrow] ([xshift=0.3\textwidth]apps.south) -- node[right,desc] {\dots}
        ([xshift=0.3\textwidth]vfs.north);
    
    \draw[line width = 2pt] (vfs) -- (dio);
    \draw[line width = 2pt] (vfs) -- (pgc);
    \draw[arrow] (apps) -| node[above, align = center, desc]
        {mmap\\malloc} (pgc);
    
    \node[box, largeb, below = of vfs, fill = dat] (dmp)
        {Device mapper (optional)};
    \node[box, largeb, below = of dmp, fill = l2t] (blk)
        {Block layer\\\scriptsize (maps BIOs to requests)};
    
    \draw[arrow] (pgc) |- node[desc, below] {BIOs (block IOs)} (dmp);
    \draw[arrow] (dio) |- node[desc, below] {BIOs (block IOs)} (dmp);
    \draw[arrow] (dmp) -- node[desc, left] {BIOs} (blk);
    \draw[arrow] ([xshift=-0.05\textwidth]dmp.north) -- 
        node[desc, left, pos = 1.0] {stackable} ++(0, 0.03\textwidth) --
            ++(0.1\textwidth, 0) -- ++(0, -0.03\textwidth);
    
    \node[box, largeb, fill = reb, below = of blk] (drvrq)
        {Block drivers\\\scriptsize (request based)};
    \node[box, smallb, fill = reb, right = of drvrq] (drvbio)
        {Block drivers\\\scriptsize (BIO based)};
    
    \draw[arrow] (blk) -- node[desc, right] {Requests} (drvrq);
    \draw[arrow] (dmp.south)++(0, -0.03\textwidth) -|
        node[desc, right, pos=0.725] {BIOs} (drvbio);
    
    \node[box, fill = gray!15, below = of drvrq.south west, anchor = north west,
        minimum width = 0.9865\textwidth] (hw) {Physical or virtual devices};
    
    \draw[arrow] (drvrq) -- (drvrq |- hw.north);
    \draw[arrow] (drvbio) -- (drvbio |- hw.north);
\end{tikzpicture}